From b1d0ee1f1b54878625d091b4ef53a5dd0262e64e Mon Sep 17 00:00:00 2001 From: elsid Date: Wed, 11 Jan 2023 23:19:50 +0100 Subject: [PATCH 1/2] Load only launcher.cfg from user folder There is no other launcher.cfg. --- apps/launcher/maindialog.cpp | 50 ++++++++++++++++++------------------ 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index 44c8a30be2..c7ae2cc588 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -1,10 +1,13 @@ #include "maindialog.hpp" +#include +#include +#include #include +#include #include #include -#include #include #include #include @@ -288,33 +291,31 @@ bool Launcher::MainDialog::setupLauncherSettings() mLauncherSettings.setMultiValueEnabled(true); - QStringList paths; - paths.append(QString(Config::LauncherSettings::sLauncherConfigFileName)); - paths.append(Files::pathToQString(mCfgMgr.getUserConfigPath() / Config::LauncherSettings::sLauncherConfigFileName)); + const QString path + = Files::pathToQString(mCfgMgr.getUserConfigPath() / Config::LauncherSettings::sLauncherConfigFileName); - for (const QString& path : paths) - { - qDebug() << "Loading config file:" << path.toUtf8().constData(); - QFile file(path); - if (file.exists()) - { - if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) - { - cfgError(tr("Error opening OpenMW configuration file"), - tr("
Could not open %0 for reading

\ - Please make sure you have the right permissions \ - and try again.
") - .arg(file.fileName())); - return false; - } - QTextStream stream(&file); - Misc::ensureUtf8Encoding(stream); + if (!QFile::exists(path)) + return true; - mLauncherSettings.readFile(stream); - } - file.close(); + Log(Debug::Verbose) << "Loading config file: " << path.toUtf8().constData(); + + QFile file(path); + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) + { + cfgError(tr("Error opening OpenMW configuration file"), + tr("
Could not open %0 for reading:

%1

\ + Please make sure you have the right permissions \ + and try again.
") + .arg(file.fileName()) + .arg(file.errorString())); + return false; } + QTextStream stream(&file); + Misc::ensureUtf8Encoding(stream); + + mLauncherSettings.readFile(stream); + return true; } @@ -326,7 +327,6 @@ bool Launcher::MainDialog::setupGameSettings() auto loadFile = [&](const QString& path, bool (Config::GameSettings::*reader)(QTextStream&, bool), bool ignoreContent = false) -> std::optional { - qDebug() << "Loading config file:" << path.toUtf8().constData(); file.setFileName(path); if (file.exists()) { From cf753632903fd15817b12750b6f1e34a90603224 Mon Sep 17 00:00:00 2001 From: elsid Date: Sun, 8 Jan 2023 19:02:03 +0100 Subject: [PATCH 2/2] Typed launcher settings QMultiMap is not clear about what settings exist and it's not efficient way to access them after they are loaded. --- apps/launcher/datafilespage.cpp | 5 +- apps/launcher/maindialog.cpp | 35 +-- apps/wizard/mainwizard.cpp | 2 +- components/CMakeLists.txt | 1 - components/config/gamesettings.cpp | 15 +- components/config/launchersettings.cpp | 375 ++++++++++++++++--------- components/config/launchersettings.hpp | 93 ++++-- components/config/settingsbase.hpp | 110 -------- 8 files changed, 334 insertions(+), 302 deletions(-) delete mode 100644 components/config/settingsbase.hpp diff --git a/apps/launcher/datafilespage.cpp b/apps/launcher/datafilespage.cpp index bd674c9fd7..eb7917613f 100644 --- a/apps/launcher/datafilespage.cpp +++ b/apps/launcher/datafilespage.cpp @@ -202,8 +202,7 @@ bool Launcher::DataFilesPage::loadSettings() if (!currentProfile.isEmpty()) addProfile(currentProfile, true); - QString language(mLauncherSettings.value(QLatin1String("Settings/language"))); - int index = mSelector->languageBox()->findText(language); + const int index = mSelector->languageBox()->findText(mLauncherSettings.getLanguage()); if (index != -1) mSelector->languageBox()->setCurrentIndex(index); @@ -352,7 +351,7 @@ void Launcher::DataFilesPage::saveSettings(const QString& profile) QString language(mSelector->languageBox()->currentText()); - mLauncherSettings.setValue(QLatin1String("Settings/language"), language); + mLauncherSettings.setLanguage(language); if (language == QLatin1String("Polish")) { diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index c7ae2cc588..8e0754e999 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -132,7 +132,7 @@ Launcher::FirstRunDialogResult Launcher::MainDialog::showFirstRunDialog() } } - if (mLauncherSettings.value(QString("General/firstrun"), QString("true")) == QLatin1String("true")) + if (mLauncherSettings.isFirstRun()) { QMessageBox msgBox; msgBox.setWindowTitle(tr("First run")); @@ -289,8 +289,6 @@ bool Launcher::MainDialog::setupLauncherSettings() { mLauncherSettings.clear(); - mLauncherSettings.setMultiValueEnabled(true); - const QString path = Files::pathToQString(mCfgMgr.getUserConfigPath() / Config::LauncherSettings::sLauncherConfigFileName); @@ -438,31 +436,20 @@ bool Launcher::MainDialog::setupGraphicsSettings() void Launcher::MainDialog::loadSettings() { - int width = mLauncherSettings.value(QString("General/MainWindow/width")).toInt(); - int height = mLauncherSettings.value(QString("General/MainWindow/height")).toInt(); - - int posX = mLauncherSettings.value(QString("General/MainWindow/posx")).toInt(); - int posY = mLauncherSettings.value(QString("General/MainWindow/posy")).toInt(); - - resize(width, height); - move(posX, posY); + const auto& mainWindow = mLauncherSettings.getMainWindow(); + resize(mainWindow.mWidth, mainWindow.mHeight); + move(mainWindow.mPosX, mainWindow.mPosY); } void Launcher::MainDialog::saveSettings() { - QString width = QString::number(this->width()); - QString height = QString::number(this->height()); - - mLauncherSettings.setValue(QString("General/MainWindow/width"), width); - mLauncherSettings.setValue(QString("General/MainWindow/height"), height); - - QString posX = QString::number(this->pos().x()); - QString posY = QString::number(this->pos().y()); - - mLauncherSettings.setValue(QString("General/MainWindow/posx"), posX); - mLauncherSettings.setValue(QString("General/MainWindow/posy"), posY); - - mLauncherSettings.setValue(QString("General/firstrun"), QString("false")); + mLauncherSettings.setMainWindow(Config::LauncherSettings::MainWindow{ + .mWidth = width(), + .mHeight = height(), + .mPosX = pos().x(), + .mPosY = pos().y(), + }); + mLauncherSettings.resetFirstRun(); } bool Launcher::MainDialog::writeSettings() diff --git a/apps/wizard/mainwizard.cpp b/apps/wizard/mainwizard.cpp index c0fd1b16e1..9abb61cfd7 100644 --- a/apps/wizard/mainwizard.cpp +++ b/apps/wizard/mainwizard.cpp @@ -393,7 +393,7 @@ void Wizard::MainWizard::writeSettings() { // Write the encoding and language settings QString language(field(QLatin1String("installation.language")).toString()); - mLauncherSettings.setValue(QLatin1String("Settings/language"), language); + mLauncherSettings.setLanguage(language); if (language == QLatin1String("Polish")) { diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 405c36b18e..2357351d6e 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -370,7 +370,6 @@ if (USE_QT) add_component_qt_dir (config gamesettings launchersettings - settingsbase ) add_component_qt_dir (process diff --git a/components/config/gamesettings.cpp b/components/config/gamesettings.cpp index 67b4ed173f..00329aaa0c 100644 --- a/components/config/gamesettings.cpp +++ b/components/config/gamesettings.cpp @@ -12,6 +12,15 @@ const char Config::GameSettings::sArchiveKey[] = "fallback-archive"; const char Config::GameSettings::sContentKey[] = "content"; const char Config::GameSettings::sDirectoryKey[] = "data"; +namespace +{ + QStringList reverse(QStringList values) + { + std::reverse(values.begin(), values.end()); + return values; + } +} + Config::GameSettings::GameSettings(Files::ConfigurationManager& cfg) : mCfgMgr(cfg) { @@ -501,19 +510,19 @@ void Config::GameSettings::setContentList( QStringList Config::GameSettings::getDataDirs() const { - return Config::LauncherSettings::reverse(mDataDirs); + return reverse(mDataDirs); } QStringList Config::GameSettings::getArchiveList() const { // QMap returns multiple rows in LIFO order, so need to reverse - return Config::LauncherSettings::reverse(values(sArchiveKey)); + return reverse(values(sArchiveKey)); } QStringList Config::GameSettings::getContentList() const { // QMap returns multiple rows in LIFO order, so need to reverse - return Config::LauncherSettings::reverse(values(sContentKey)); + return reverse(values(sContentKey)); } void Config::GameSettings::clear() diff --git a/components/config/launchersettings.cpp b/components/config/launchersettings.cpp index 02a5202857..0239f2d334 100644 --- a/components/config/launchersettings.cpp +++ b/components/config/launchersettings.cpp @@ -4,104 +4,220 @@ #include #include #include +#include #include +#include #include -const char Config::LauncherSettings::sCurrentContentListKey[] = "Profiles/currentprofile"; -const char Config::LauncherSettings::sLauncherConfigFileName[] = "launcher.cfg"; -const char Config::LauncherSettings::sContentListsSectionPrefix[] = "Profiles/"; -const char Config::LauncherSettings::sDirectoryListSuffix[] = "/data"; -const char Config::LauncherSettings::sArchiveListSuffix[] = "/fallback-archive"; -const char Config::LauncherSettings::sContentListSuffix[] = "/content"; +#include "gamesettings.hpp" -QStringList Config::LauncherSettings::subKeys(const QString& key) +namespace Config { - QMultiMap settings = SettingsBase::getSettings(); - QStringList keys = settings.uniqueKeys(); + namespace + { + constexpr char sSettingsSection[] = "Settings"; + constexpr char sGeneralSection[] = "General"; + constexpr char sProfilesSection[] = "Profiles"; + constexpr char sLanguageKey[] = "language"; + constexpr char sCurrentProfileKey[] = "currentprofile"; + constexpr char sDataKey[] = "data"; + constexpr char sArchiveKey[] = "fallback-archive"; + constexpr char sContentKey[] = "content"; + constexpr char sFirstRunKey[] = "firstrun"; + constexpr char sMainWindowWidthKey[] = "MainWindow/width"; + constexpr char sMainWindowHeightKey[] = "MainWindow/height"; + constexpr char sMainWindowPosXKey[] = "MainWindow/posx"; + constexpr char sMainWindowPosYKey[] = "MainWindow/posy"; + + QString makeNewContentListName() + { + // basically, use date and time as the name e.g. YYYY-MM-DDThh:mm:ss + const std::time_t rawtime = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()); + tm timeinfo{}; +#ifdef _WIN32 + (void)localtime_s(&timeinfo, &rawtime); +#else + (void)localtime_r(&rawtime, &timeinfo); +#endif + constexpr int base = 10; + QChar zeroPad('0'); + return QString("%1-%2-%3T%4:%5:%6") + .arg(timeinfo.tm_year + 1900, 4) + .arg(timeinfo.tm_mon + 1, 2, base, zeroPad) + .arg(timeinfo.tm_mday, 2, base, zeroPad) + .arg(timeinfo.tm_hour, 2, base, zeroPad) + .arg(timeinfo.tm_min, 2, base, zeroPad) + .arg(timeinfo.tm_sec, 2, base, zeroPad); + } - QRegularExpression keyRe("(.+)/"); + bool parseBool(const QString& value, bool& out) + { + if (value == "false") + { + out = false; + return true; + } + if (value == "true") + { + out = true; + return true; + } - QStringList result; + return false; + } - for (const QString& currentKey : keys) - { - QRegularExpressionMatch match = keyRe.match(currentKey); - if (match.hasMatch()) + bool parseInt(const QString& value, int& out) { - QString prefixedKey = match.captured(1); + bool ok = false; + const int converted = value.toInt(&ok); + if (ok) + out = converted; + return ok; + } - if (prefixedKey.startsWith(key)) + bool parseProfilePart( + const QString& key, const QString& value, std::map& profiles) + { + const int separator = key.lastIndexOf('/'); + if (separator == -1) + return false; + + const QString profileName = key.mid(0, separator); + + if (key.endsWith(sArchiveKey)) { - QString subKey = prefixedKey.remove(key); - if (!subKey.isEmpty()) - result.append(subKey); + profiles[profileName].mArchives.append(value); + return true; } + if (key.endsWith(sDataKey)) + { + profiles[profileName].mData.append(value); + return true; + } + if (key.endsWith(sContentKey)) + { + profiles[profileName].mContent.append(value); + return true; + } + + return false; } - } - result.removeDuplicates(); - return result; -} + bool parseSettingsSection(const QString& key, const QString& value, LauncherSettings::Settings& settings) + { + if (key == sLanguageKey) + { + settings.mLanguage = value; + return true; + } -bool Config::LauncherSettings::writeFile(QTextStream& stream) -{ - QString sectionPrefix; - QRegularExpression sectionRe("^([^/]+)/(.+)$"); - QMultiMap settings = SettingsBase::getSettings(); + return false; + } - auto i = settings.end(); - while (i != settings.begin()) - { - i--; + bool parseProfilesSection(const QString& key, const QString& value, LauncherSettings::Profiles& profiles) + { + if (key == sCurrentProfileKey) + { + profiles.mCurrentProfile = value; + return true; + } - QString prefix; - QString key; + return parseProfilePart(key, value, profiles.mValues); + } - QRegularExpressionMatch match = sectionRe.match(i.key()); - if (match.hasMatch()) + bool parseGeneralSection(const QString& key, const QString& value, LauncherSettings::General& general) { - prefix = match.captured(1); - key = match.captured(2); + if (key == sFirstRunKey) + return parseBool(value, general.mFirstRun); + if (key == sMainWindowWidthKey) + return parseInt(value, general.mMainWindow.mWidth); + if (key == sMainWindowHeightKey) + return parseInt(value, general.mMainWindow.mHeight); + if (key == sMainWindowPosXKey) + return parseInt(value, general.mMainWindow.mPosX); + if (key == sMainWindowPosYKey) + return parseInt(value, general.mMainWindow.mPosY); + + return false; } - // Get rid of legacy settings - if (key.contains(QChar('\\'))) - continue; + template + void writeSectionHeader(const char (&name)[size], QTextStream& stream) + { + stream << "\n[" << name << "]\n"; + } - if (key == QLatin1String("CurrentProfile")) - continue; + template + void writeKeyValue(const char (&key)[size], const QString& value, QTextStream& stream) + { + stream << key << '=' << value << '\n'; + } - if (sectionPrefix != prefix) + template + void writeKeyValue(const char (&key)[size], bool value, QTextStream& stream) { - sectionPrefix = prefix; - stream << "\n[" << prefix << "]\n"; + stream << key << '=' << (value ? "true" : "false") << '\n'; } - stream << key << "=" << i.value() << "\n"; - } + template + void writeKeyValue(const char (&key)[size], int value, QTextStream& stream) + { + stream << key << '=' << value << '\n'; + } - return true; -} + template + void writeKeyValues( + const QString& prefix, const char (&suffix)[size], const QStringList& values, QTextStream& stream) + { + for (const auto& v : values) + stream << prefix << '/' << suffix << '=' << v << '\n'; + } -QStringList Config::LauncherSettings::getContentLists() -{ - return subKeys(QString(sContentListsSectionPrefix)); -} + void writeSettings(const LauncherSettings::Settings& value, QTextStream& stream) + { + writeSectionHeader(sSettingsSection, stream); + writeKeyValue(sLanguageKey, value.mLanguage, stream); + } -QString Config::LauncherSettings::makeDirectoryListKey(const QString& contentListName) -{ - return QString(sContentListsSectionPrefix) + contentListName + QString(sDirectoryListSuffix); + void writeProfiles(const LauncherSettings::Profiles& value, QTextStream& stream) + { + writeSectionHeader(sProfilesSection, stream); + writeKeyValue(sCurrentProfileKey, value.mCurrentProfile, stream); + for (auto it = value.mValues.rbegin(); it != value.mValues.rend(); ++it) + { + writeKeyValues(it->first, sArchiveKey, it->second.mArchives, stream); + writeKeyValues(it->first, sDataKey, it->second.mData, stream); + writeKeyValues(it->first, sContentKey, it->second.mContent, stream); + } + } + + void writeGeneral(const LauncherSettings::General& value, QTextStream& stream) + { + writeSectionHeader(sGeneralSection, stream); + writeKeyValue(sFirstRunKey, value.mFirstRun, stream); + writeKeyValue(sMainWindowWidthKey, value.mMainWindow.mWidth, stream); + writeKeyValue(sMainWindowPosYKey, value.mMainWindow.mPosY, stream); + writeKeyValue(sMainWindowPosXKey, value.mMainWindow.mPosX, stream); + writeKeyValue(sMainWindowHeightKey, value.mMainWindow.mHeight, stream); + } + } } -QString Config::LauncherSettings::makeArchiveListKey(const QString& contentListName) +void Config::LauncherSettings::writeFile(QTextStream& stream) const { - return QString(sContentListsSectionPrefix) + contentListName + QString(sArchiveListSuffix); + writeSettings(mSettings, stream); + writeProfiles(mProfiles, stream); + writeGeneral(mGeneral, stream); } -QString Config::LauncherSettings::makeContentListKey(const QString& contentListName) +QStringList Config::LauncherSettings::getContentLists() { - return QString(sContentListsSectionPrefix) + contentListName + QString(sContentListSuffix); + QStringList result; + result.reserve(mProfiles.mValues.size()); + for (const auto& [k, v] : mProfiles.mValues) + result.push_back(k); + return result; } void Config::LauncherSettings::setContentList(const GameSettings& gameSettings) @@ -126,8 +242,8 @@ void Config::LauncherSettings::setContentList(const GameSettings& gameSettings) // if any existing profile in launcher matches the content list, make that profile the default for (const QString& listName : getContentLists()) { - if (isEqual(files, getContentListFiles(listName)) && isEqual(archives, getArchiveList(listName)) - && isEqual(dirs, getDataDirectoryList(listName))) + if (files == getContentListFiles(listName) && archives == getArchiveList(listName) + && dirs == getDataDirectoryList(listName)) { setCurrentContentListName(listName); return; @@ -140,99 +256,98 @@ void Config::LauncherSettings::setContentList(const GameSettings& gameSettings) setContentList(newContentListName, dirs, archives, files); } -void Config::LauncherSettings::removeContentList(const QString& contentListName) -{ - remove(makeDirectoryListKey(contentListName)); - remove(makeArchiveListKey(contentListName)); - remove(makeContentListKey(contentListName)); -} - -void Config::LauncherSettings::setCurrentContentListName(const QString& contentListName) -{ - remove(QString(sCurrentContentListKey)); - setValue(QString(sCurrentContentListKey), contentListName); -} - void Config::LauncherSettings::setContentList(const QString& contentListName, const QStringList& dirNames, const QStringList& archiveNames, const QStringList& fileNames) { - auto const assign = [this](const QString key, const QStringList& list) { - for (auto const& item : list) - setMultiValue(key, item); - }; - - removeContentList(contentListName); - assign(makeDirectoryListKey(contentListName), dirNames); - assign(makeArchiveListKey(contentListName), archiveNames); - assign(makeContentListKey(contentListName), fileNames); -} - -QString Config::LauncherSettings::getCurrentContentListName() const -{ - return value(QString(sCurrentContentListKey)); + Profile& profile = mProfiles.mValues[contentListName]; + profile.mData = dirNames; + profile.mArchives = archiveNames; + profile.mContent = fileNames; } QStringList Config::LauncherSettings::getDataDirectoryList(const QString& contentListName) const { - // QMap returns multiple rows in LIFO order, so need to reverse - return reverse(getSettings().values(makeDirectoryListKey(contentListName))); + const Profile* profile = findProfile(contentListName); + if (profile == nullptr) + return {}; + return profile->mData; } QStringList Config::LauncherSettings::getArchiveList(const QString& contentListName) const { - // QMap returns multiple rows in LIFO order, so need to reverse - return reverse(getSettings().values(makeArchiveListKey(contentListName))); + const Profile* profile = findProfile(contentListName); + if (profile == nullptr) + return {}; + return profile->mArchives; } + QStringList Config::LauncherSettings::getContentListFiles(const QString& contentListName) const { - // QMap returns multiple rows in LIFO order, so need to reverse - return reverse(getSettings().values(makeContentListKey(contentListName))); + const Profile* profile = findProfile(contentListName); + if (profile == nullptr) + return {}; + return profile->mContent; } -QStringList Config::LauncherSettings::reverse(const QStringList& toReverse) +bool Config::LauncherSettings::setValue(const QString& sectionPrefix, const QString& key, const QString& value) { - QStringList result; - result.reserve(toReverse.size()); - std::reverse_copy(toReverse.begin(), toReverse.end(), std::back_inserter(result)); - return result; + if (sectionPrefix == sSettingsSection) + return parseSettingsSection(key, value, mSettings); + if (sectionPrefix == sProfilesSection) + return parseProfilesSection(key, value, mProfiles); + if (sectionPrefix == sGeneralSection) + return parseGeneralSection(key, value, mGeneral); + + return false; } -bool Config::LauncherSettings::isEqual(const QStringList& list1, const QStringList& list2) +void Config::LauncherSettings::readFile(QTextStream& stream) { - if (list1.count() != list2.count()) - { - return false; - } + const QRegExp sectionRe("^\\[([^]]+)\\]"); + const QRegExp keyRe("^([^=]+)\\s*=\\s*(.+)$"); + + QString section; - for (int i = 0; i < list1.count(); ++i) + while (!stream.atEnd()) { - if (list1.at(i) != list2.at(i)) + const QString line = stream.readLine(); + + if (line.isEmpty() || line.startsWith("#")) + continue; + + if (sectionRe.exactMatch(line)) { - return false; + section = sectionRe.cap(1); + continue; } + + if (section.isEmpty()) + continue; + + if (keyRe.indexIn(line) == -1) + continue; + + const QString key = keyRe.cap(1).trimmed(); + const QString value = keyRe.cap(2).trimmed(); + + if (!setValue(section, key, value)) + Log(Debug::Warning) << "Unsupported setting in the launcher config file: section: " + << section.toUtf8().constData() << " key: " << key.toUtf8().constData() + << " value: " << value.toUtf8().constData(); } +} - // if get here, lists are same - return true; +const Config::LauncherSettings::Profile* Config::LauncherSettings::findProfile(const QString& name) const +{ + const auto it = mProfiles.mValues.find(name); + if (it == mProfiles.mValues.end()) + return nullptr; + return &it->second; } -QString Config::LauncherSettings::makeNewContentListName() +void Config::LauncherSettings::clear() { - // basically, use date and time as the name e.g. YYYY-MM-DDThh:mm:ss - auto rawtime = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()); - tm timeinfo{}; -#ifdef _WIN32 - (void)localtime_s(&timeinfo, &rawtime); -#else - (void)localtime_r(&rawtime, &timeinfo); -#endif - int base = 10; - QChar zeroPad('0'); - return QString("%1-%2-%3T%4:%5:%6") - .arg(timeinfo.tm_year + 1900, 4) - .arg(timeinfo.tm_mon + 1, 2, base, zeroPad) - .arg(timeinfo.tm_mday, 2, base, zeroPad) - .arg(timeinfo.tm_hour, 2, base, zeroPad) - .arg(timeinfo.tm_min, 2, base, zeroPad) - .arg(timeinfo.tm_sec, 2, base, zeroPad); + mSettings = Settings{}; + mGeneral = General{}; + mProfiles = Profiles{}; } diff --git a/components/config/launchersettings.hpp b/components/config/launchersettings.hpp index 8c2dc0d545..09f2218549 100644 --- a/components/config/launchersettings.hpp +++ b/components/config/launchersettings.hpp @@ -1,15 +1,59 @@ #ifndef LAUNCHERSETTINGS_HPP #define LAUNCHERSETTINGS_HPP -#include "gamesettings.hpp" -#include "settingsbase.hpp" +#include +#include + +#include + +class QTextStream; namespace Config { - class LauncherSettings : public SettingsBase> + class GameSettings; + + class LauncherSettings { public: - bool writeFile(QTextStream& stream); + static constexpr char sLauncherConfigFileName[] = "launcher.cfg"; + + struct Settings + { + QString mLanguage; + }; + + struct MainWindow + { + int mWidth = 0; + int mHeight = 0; + int mPosX = 0; + int mPosY = 0; + }; + + struct General + { + bool mFirstRun = true; + MainWindow mMainWindow; + }; + + struct Profile + { + QStringList mArchives; + QStringList mData; + QStringList mContent; + }; + + struct Profiles + { + QString mCurrentProfile; + std::map mValues; + }; + + void readFile(QTextStream& stream); + + void clear(); + + void writeFile(QTextStream& stream) const; /// \return names of all Content Lists in the launcher's .cfg file. QStringList getContentLists(); @@ -21,47 +65,36 @@ namespace Config void setContentList(const QString& contentListName, const QStringList& dirNames, const QStringList& archiveNames, const QStringList& fileNames); - void removeContentList(const QString& contentListName); + void removeContentList(const QString& value) { mProfiles.mValues.erase(value); } - void setCurrentContentListName(const QString& contentListName); + void setCurrentContentListName(const QString& value) { mProfiles.mCurrentProfile = value; } - QString getCurrentContentListName() const; + QString getCurrentContentListName() const { return mProfiles.mCurrentProfile; } QStringList getDataDirectoryList(const QString& contentListName) const; QStringList getArchiveList(const QString& contentListName) const; QStringList getContentListFiles(const QString& contentListName) const; - /// \return new list that is reversed order of input - static QStringList reverse(const QStringList& toReverse); + bool isFirstRun() const { return mGeneral.mFirstRun; } - static const char sLauncherConfigFileName[]; + void resetFirstRun() { mGeneral.mFirstRun = false; } - private: - /// \return key to use to get/set the files in the specified data Directory List - static QString makeDirectoryListKey(const QString& contentListName); + QString getLanguage() const { return mSettings.mLanguage; } - /// \return key to use to get/set the files in the specified Archive List - static QString makeArchiveListKey(const QString& contentListName); + void setLanguage(const QString& value) { mSettings.mLanguage = value; } - /// \return key to use to get/set the files in the specified Content List - static QString makeContentListKey(const QString& contentListName); + MainWindow getMainWindow() const { return mGeneral.mMainWindow; } - /// \return true if both lists are same - static bool isEqual(const QStringList& list1, const QStringList& list2); + void setMainWindow(const MainWindow& value) { mGeneral.mMainWindow = value; } - static QString makeNewContentListName(); - - QStringList subKeys(const QString& key); - - /// name of entry in launcher.cfg that holds name of currently selected Content List - static const char sCurrentContentListKey[]; + private: + Settings mSettings; + Profiles mProfiles; + General mGeneral; - /// section of launcher.cfg holding the Content Lists - static const char sContentListsSectionPrefix[]; + bool setValue(const QString& sectionPrefix, const QString& key, const QString& value); - static const char sDirectoryListSuffix[]; - static const char sArchiveListSuffix[]; - static const char sContentListSuffix[]; + const Profile* findProfile(const QString& name) const; }; } #endif // LAUNCHERSETTINGS_HPP diff --git a/components/config/settingsbase.hpp b/components/config/settingsbase.hpp deleted file mode 100644 index 068fc68d91..0000000000 --- a/components/config/settingsbase.hpp +++ /dev/null @@ -1,110 +0,0 @@ -#ifndef SETTINGSBASE_HPP -#define SETTINGSBASE_HPP - -#include -#include -#include -#include - -namespace Config -{ - template - class SettingsBase - { - - public: - SettingsBase() { mMultiValue = false; } - ~SettingsBase() = default; - - inline QString value(const QString& key, const QString& defaultValue = QString()) const - { - return mSettings.value(key).isEmpty() ? defaultValue : mSettings.value(key); - } - - inline void setValue(const QString& key, const QString& value) { mSettings.replace(key, value); } - - inline void setMultiValue(const QString& key, const QString& value) - { - QStringList values = mSettings.values(key); - if (!values.contains(value)) - mSettings.insert(key, value); - } - - inline void setMultiValueEnabled(bool enable) { mMultiValue = enable; } - - inline void remove(const QString& key) { mSettings.remove(key); } - - Map getSettings() const { return mSettings; } - - bool readFile(QTextStream& stream) - { - Map cache; - - QString sectionPrefix; - - QRegularExpression sectionRe("^\\[([^]]+)\\]$"); - QRegularExpression keyRe("^([^=]+)\\s*=\\s*(.+)$"); - - while (!stream.atEnd()) - { - QString line = stream.readLine(); - - if (line.isEmpty() || line.startsWith("#")) - continue; - - QRegularExpressionMatch sectionMatch = sectionRe.match(line); - if (sectionMatch.hasMatch()) - { - sectionPrefix = sectionMatch.captured(1); - sectionPrefix.append("/"); - continue; - } - - QRegularExpressionMatch match = keyRe.match(line); - if (match.hasMatch()) - { - QString key = match.captured(1).trimmed(); - QString value = match.captured(2).trimmed(); - - if (!sectionPrefix.isEmpty()) - key.prepend(sectionPrefix); - - mSettings.remove(key); - - QStringList values = cache.values(key); - - if (!values.contains(value)) - { - if (mMultiValue) - { - cache.insert(key, value); - } - else - { - cache.remove(key); - cache.insert(key, value); - } - } - } - } - - if (mSettings.isEmpty()) - { - mSettings = cache; // This is the first time we read a file - return true; - } - - // Merge the changed keys with those which didn't - mSettings.unite(cache); - return true; - } - - void clear() { mSettings.clear(); } - - private: - Map mSettings; - - bool mMultiValue; - }; -} -#endif // SETTINGSBASE_HPP