From b6b01a52db1877b16531137289641fb9be9833aa Mon Sep 17 00:00:00 2001 From: isanae <14251494+isanae@users.noreply.github.com> Date: Fri, 2 Aug 2019 23:24:27 -0400 Subject: removed mentions of QSettings from main.cpp added necessary member functions in Settings --- src/main.cpp | 185 +++++++++++++++++++++++++++-------------------------------- 1 file changed, 83 insertions(+), 102 deletions(-) (limited to 'src/main.cpp') diff --git a/src/main.cpp b/src/main.cpp index 911f11c3..720ecbf9 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -245,9 +245,10 @@ static bool HaveWriteAccess(const std::wstring &path) } -QString determineProfile(QStringList &arguments, const QSettings &settings) +QString determineProfile(QStringList &arguments, const Settings &settings) { - QString selectedProfileName = QString::fromUtf8(settings.value("selected_profile", "").toByteArray()); + QString selectedProfileName = settings.getSelectedProfileName(); + { // see if there is a profile on the command line int profileIndex = arguments.indexOf("-p", 1); if ((profileIndex != -1) && (profileIndex < arguments.size() - 1)) { @@ -257,6 +258,7 @@ QString determineProfile(QStringList &arguments, const QSettings &settings) arguments.removeAt(profileIndex); arguments.removeAt(profileIndex); } + if (selectedProfileName.isEmpty()) { log::debug("no configured profile"); selectedProfileName = "Default"; @@ -267,46 +269,50 @@ QString determineProfile(QStringList &arguments, const QSettings &settings) return selectedProfileName; } -MOBase::IPluginGame *selectGame(QSettings &settings, QDir const &gamePath, MOBase::IPluginGame *game) +MOBase::IPluginGame *selectGame( + Settings &settings, QDir const &gamePath, MOBase::IPluginGame *game) { - settings.setValue("gameName", game->gameName()); - //Sadly, hookdll needs gamePath in order to run. So following code block is - //commented out - /*if (gamePath == game->gameDirectory()) { - settings.remove("gamePath"); - } else*/ { - QString gameDir = gamePath.absolutePath(); - game->setGamePath(gameDir); - settings.setValue("gamePath", QDir::toNativeSeparators(gameDir).toUtf8().constData()); - } - return game; //Woot + settings.setManagedGameName(game->gameName()); + + QString gameDir = gamePath.absolutePath(); + game->setGamePath(gameDir); + + settings.setManagedGameDirectory(gameDir); + + return game; } -MOBase::IPluginGame *determineCurrentGame(QString const &moPath, QSettings &settings, PluginContainer const &plugins) +MOBase::IPluginGame *determineCurrentGame( + QString const &moPath, Settings &settings, PluginContainer const &plugins) { //Determine what game we are running where. Be very paranoid in case the //user has done something odd. //If the game name has been set up, try to use that. - QString gameName = settings.value("gameName", "").toString(); + const QString gameName = settings.getManagedGameName(); bool gameConfigured = !gameName.isEmpty(); + if (gameConfigured) { MOBase::IPluginGame *game = plugins.managedGame(gameName); if (game == nullptr) { reportError(QObject::tr("Plugin to handle %1 no longer installed").arg(gameName)); return nullptr; } - QString gamePath = QString::fromUtf8(settings.value("gamePath", "").toByteArray()); + + QString gamePath = settings.getManagedGameDirectory(); if (gamePath == "") { gamePath = game->gameDirectory().absolutePath(); } + QDir gameDir(gamePath); QFileInfo directoryInfo(gameDir.path()); + if (directoryInfo.isSymLink()) { reportError(QObject::tr("The configured path to the game directory (%1) appears to be a symbolic (or other) link. " "This setup is incompatible with MO2's VFS and will not run correctly.").arg(gamePath)); } + if (game->looksValid(gameDir)) { return selectGame(settings, gameDir, game); } @@ -315,7 +321,7 @@ MOBase::IPluginGame *determineCurrentGame(QString const &moPath, QSettings &sett //If we've made it this far and the instance is already configured for a game, something has gone wrong. //Tell the user about it. if (gameConfigured) { - QString gamePath = QString::fromUtf8(settings.value("gamePath", "").toByteArray()); + const QString gamePath = settings.getManagedGameDirectory(); reportError(QObject::tr("Could not use configuration settings for game \"%1\", path \"%2\"."). arg(gameName).arg(gamePath)); } @@ -480,27 +486,6 @@ static QString getVersionDisplayString() return createVersionInfo().displayString(3); } -void dumpSettings(QSettings& settings) -{ - static const QStringList ignore({ - "username", "password", "nexus_api_key" - }); - - log::debug("settings:"); - - settings.beginGroup("Settings"); - - for (auto k : settings.allKeys()) { - if (ignore.contains(k, Qt::CaseInsensitive)) { - continue; - } - - log::debug(" . {}={}", k, settings.value(k).toString()); - } - - settings.endGroup(); -} - void checkMissingFiles() { // files that are likely to be eaten @@ -557,7 +542,7 @@ int runApplication(MOApplication &application, SingleInstance &instance, log::warn("no ssl support"); } - QString dataPath = application.property("dataPath").toString(); + const QString dataPath = application.property("dataPath").toString(); log::info("data path: {}", dataPath); if (!bootstrap()) { @@ -573,11 +558,7 @@ int runApplication(MOApplication &application, SingleInstance &instance, try { log::info("working directory: {}", QDir::currentPath()); - QSettings initSettings( - dataPath + "/" + QString::fromStdWString(AppConfig::iniFileName()), - QSettings::IniFormat); - - Settings settings(initSettings); + Settings settings(dataPath + "/" + QString::fromStdWString(AppConfig::iniFileName())); log::getDefault().setLevel(settings.logLevel()); // global crashDumpType sits in OrganizerCore to make a bit less ugly to @@ -587,7 +568,7 @@ int runApplication(MOApplication &application, SingleInstance &instance, env::Environment env; env.dump(); - dumpSettings(initSettings); + settings.dump(); sanityChecks(env); log::debug("initializing core"); @@ -602,7 +583,8 @@ int runApplication(MOApplication &application, SingleInstance &instance, pluginContainer.loadPlugins(); MOBase::IPluginGame *game = determineCurrentGame( - application.applicationDirPath(), initSettings, pluginContainer); + application.applicationDirPath(), settings, pluginContainer); + if (game == nullptr) { InstanceManager &instance = InstanceManager::instance(); QString instanceName = instance.currentInstance(); @@ -612,6 +594,7 @@ int runApplication(MOApplication &application, SingleInstance &instance, } return 1; } + if (splashPath.startsWith(':')) { // currently using MO splash, see if the plugin contains one QString pluginSplash @@ -625,7 +608,7 @@ int runApplication(MOApplication &application, SingleInstance &instance, organizer.setManagedGame(game); organizer.createDefaultProfile(); - if (!initSettings.contains("game_edition")) { + if (settings.getManagedGameEdition() == "") { QStringList editions = game->gameVariants(); if (editions.size() > 1) { SelectionDialog selection( @@ -641,78 +624,76 @@ int runApplication(MOApplication &application, SingleInstance &instance, if (selection.exec() == QDialog::Rejected) { return 1; } else { - initSettings.setValue("game_edition", selection.getChoiceString()); + settings.setManagedGameEdition(selection.getChoiceString()); } } } - game->setGameVariant(initSettings.value("game_edition").toString()); + + game->setGameVariant(settings.getManagedGameEdition()); log::info("managing game at {}", game->gameDirectory().absolutePath()); - organizer.updateExecutablesList(initSettings); + organizer.updateExecutablesList(); - QString selectedProfileName = determineProfile(arguments, initSettings); + QString selectedProfileName = determineProfile(arguments, settings); organizer.setCurrentProfile(selectedProfileName); // if we have a command line parameter, it is either a nxm link or // a binary to start - if (arguments.size() > 1) { - if (MOShortcut shortcut{ arguments.at(1) }) { - if (shortcut.hasExecutable()) { - try { - organizer.runShortcut(shortcut); - return 0; - } - catch (const std::exception &e) { - reportError( - QObject::tr("failed to start shortcut: %1").arg(e.what())); - return 1; - } - } - } - else if (OrganizerCore::isNxmLink(arguments.at(1))) { - log::debug("starting download from command line: {}", arguments.at(1)); - organizer.externalMessage(arguments.at(1)); - } - else { - QString exeName = arguments.at(1); - log::debug("starting {} from command line", exeName); - arguments.removeFirst(); // remove application name (ModOrganizer.exe) - arguments.removeFirst(); // remove binary name - // pass the remaining parameters to the binary - try { - organizer.startApplication(exeName, arguments, QString(), QString()); - return 0; - } - catch (const std::exception &e) { - reportError( - QObject::tr("failed to start application: %1").arg(e.what())); - return 1; - } - } - } + if (arguments.size() > 1) { + if (MOShortcut shortcut{ arguments.at(1) }) { + if (shortcut.hasExecutable()) { + try { + organizer.runShortcut(shortcut); + return 0; + } + catch (const std::exception &e) { + reportError( + QObject::tr("failed to start shortcut: %1").arg(e.what())); + return 1; + } + } + } + else if (OrganizerCore::isNxmLink(arguments.at(1))) { + log::debug("starting download from command line: {}", arguments.at(1)); + organizer.externalMessage(arguments.at(1)); + } + else { + QString exeName = arguments.at(1); + log::debug("starting {} from command line", exeName); + arguments.removeFirst(); // remove application name (ModOrganizer.exe) + arguments.removeFirst(); // remove binary name + // pass the remaining parameters to the binary + try { + organizer.startApplication(exeName, arguments, QString(), QString()); + return 0; + } + catch (const std::exception &e) { + reportError( + QObject::tr("failed to start application: %1").arg(e.what())); + return 1; + } + } + } QPixmap pixmap(splashPath); QSplashScreen splash(pixmap); - if (initSettings.contains("window_monitor")) { - const int monitor = initSettings.value("window_monitor").toInt(); - - if (monitor != -1 && QGuiApplication::screens().size() > monitor) { - QGuiApplication::screens().at(monitor)->geometry().center(); - const QPoint center = QGuiApplication::screens().at(monitor)->geometry().center(); - splash.move(center - splash.rect().center()); - } else { - const QPoint center = QGuiApplication::primaryScreen()->geometry().center(); - splash.move(center - splash.rect().center()); - } + const int monitor = settings.getMainWindowMonitor(); + if (monitor != -1 && QGuiApplication::screens().size() > monitor) { + QGuiApplication::screens().at(monitor)->geometry().center(); + const QPoint center = QGuiApplication::screens().at(monitor)->geometry().center(); + splash.move(center - splash.rect().center()); + } else { + const QPoint center = QGuiApplication::primaryScreen()->geometry().center(); + splash.move(center - splash.rect().center()); } splash.show(); splash.activateWindow(); QString apiKey; - if (organizer.settings().getNexusApiKey(apiKey)) { + if (settings.getNexusApiKey(apiKey)) { NexusInterface::instance(&pluginContainer)->getAccessManager()->apiCheck(apiKey); } @@ -722,15 +703,15 @@ int runApplication(MOApplication &application, SingleInstance &instance, + QString::fromStdWString(AppConfig::tutorialsPath()) + "/", &organizer); - if (!application.setStyleFile(initSettings.value("Settings/style", "").toString())) { + if (!application.setStyleFile(settings.getStyleName())) { // disable invalid stylesheet - initSettings.setValue("Settings/style", ""); + settings.setStyleName(""); } int res = 1; { // scope to control lifetime of mainwindow // set up main window and its data structures - MainWindow mainWindow(initSettings, organizer, pluginContainer); + MainWindow mainWindow(settings, organizer, pluginContainer); NexusInterface::instance(&pluginContainer) ->getAccessManager()->setTopLevelWidget(&mainWindow); -- cgit v1.3.1 From 07f1ac7a96dcf4c91a24bb1d30af92851ecda78f Mon Sep 17 00:00:00 2001 From: isanae <14251494+isanae@users.noreply.github.com> Date: Sat, 3 Aug 2019 01:55:21 -0400 Subject: split into GeometrySettings removed most of storeSettings() from OrganizerCore: QSettings handles saving by itself, no need for that removed topLevelSplitter from ui, unused since the log widget is in a dock removed QSettings from MainWindow::readSettings() replaced return values for some of the new getters in Settings to std::optional --- src/executableslist.cpp | 9 ++- src/executableslist.h | 5 +- src/filedialogmemory.cpp | 8 ++- src/filedialogmemory.h | 5 +- src/iuserinterface.h | 4 +- src/main.cpp | 96 +++++++++++++++---------- src/mainwindow.cpp | 116 ++++++++++++++---------------- src/mainwindow.h | 4 +- src/mainwindow.ui | 5 -- src/organizercore.cpp | 90 +++++------------------- src/organizercore.h | 4 -- src/settings.cpp | 180 +++++++++++++++++++++++++++++++++++++++++++---- src/settings.h | 55 ++++++++++++--- 13 files changed, 359 insertions(+), 222 deletions(-) (limited to 'src/main.cpp') diff --git a/src/executableslist.cpp b/src/executableslist.cpp index 3f76bb6f..2b3219df 100644 --- a/src/executableslist.cpp +++ b/src/executableslist.cpp @@ -21,6 +21,7 @@ along with Mod Organizer. If not, see . #include "iplugingame.h" #include "utility.h" +#include "settings.h" #include #include @@ -64,7 +65,7 @@ bool ExecutablesList::empty() const return m_Executables.empty(); } -void ExecutablesList::load(const MOBase::IPluginGame* game, QSettings& settings) +void ExecutablesList::load(const MOBase::IPluginGame* game, const Settings& s) { log::debug("loading executables"); @@ -74,6 +75,8 @@ void ExecutablesList::load(const MOBase::IPluginGame* game, QSettings& settings) // executables from 2.2.0, see upgradeFromCustom() bool needsUpgrade = false; + auto& settings = const_cast(s.directInterface()); + int numCustomExecutables = settings.beginReadArray("customExecutables"); for (int i = 0; i < numCustomExecutables; ++i) { settings.setArrayIndex(i); @@ -108,8 +111,10 @@ void ExecutablesList::load(const MOBase::IPluginGame* game, QSettings& settings) dump(); } -void ExecutablesList::store(QSettings& settings) +void ExecutablesList::store(Settings& s) { + auto& settings = s.directInterface(); + settings.remove("customExecutables"); settings.beginWriteArray("customExecutables"); diff --git a/src/executableslist.h b/src/executableslist.h index eda2034e..23cf3cfe 100644 --- a/src/executableslist.h +++ b/src/executableslist.h @@ -29,6 +29,7 @@ along with Mod Organizer. If not, see . #include namespace MOBase { class IPluginGame; class ExecutableInfo; } +class Settings; /*! * @brief Information about an executable @@ -103,7 +104,7 @@ public: /** * @brief initializes the list from the settings and the given plugin **/ - void load(const MOBase::IPluginGame* game, QSettings& settings); + void load(const MOBase::IPluginGame* game, const Settings& settings); /** * @brief re-adds all the executables from the plugin and renames existing @@ -114,7 +115,7 @@ public: /** * @brief writes the current list to the settings */ - void store(QSettings& settings); + void store(Settings& settings); /** * @brief get an executable by name diff --git a/src/filedialogmemory.cpp b/src/filedialogmemory.cpp index 308a175e..48828563 100644 --- a/src/filedialogmemory.cpp +++ b/src/filedialogmemory.cpp @@ -27,8 +27,10 @@ FileDialogMemory::FileDialogMemory() } -void FileDialogMemory::save(QSettings &settings) +void FileDialogMemory::save(Settings& s) { + auto& settings = s.directInterface(); + settings.remove("recentDirectories"); settings.beginWriteArray("recentDirectories"); int index = 0; @@ -42,8 +44,10 @@ void FileDialogMemory::save(QSettings &settings) } -void FileDialogMemory::restore(QSettings &settings) +void FileDialogMemory::restore(const Settings& s) { + auto& settings = const_cast(s.directInterface()); + int size = settings.beginReadArray("recentDirectories"); for (int i = 0; i < size; ++i) { settings.setArrayIndex(i); diff --git a/src/filedialogmemory.h b/src/filedialogmemory.h index 1a72b289..d214a8e6 100644 --- a/src/filedialogmemory.h +++ b/src/filedialogmemory.h @@ -23,7 +23,6 @@ along with Mod Organizer. If not, see . #include #include -#include #include class Settings; @@ -31,8 +30,8 @@ class Settings; class FileDialogMemory { public: - static void save(QSettings &settings); - static void restore(QSettings &settings); + static void save(Settings& settings); + static void restore(const Settings& settings); static QString getOpenFileName( const QString &dirID, QWidget *parent = 0, const QString &caption = QString(), diff --git a/src/iuserinterface.h b/src/iuserinterface.h index bba8de2b..7205f982 100644 --- a/src/iuserinterface.h +++ b/src/iuserinterface.h @@ -10,13 +10,13 @@ #include -class QSettings; +class Settings; class IUserInterface { public: - virtual void storeSettings(QSettings &settings) = 0; + virtual void storeSettings(Settings &settings) = 0; virtual void registerPluginTool(MOBase::IPluginTool *tool, QString name = QString(), QMenu *menu = nullptr) = 0; virtual void registerPluginTools(std::vector toolPlugins) = 0; diff --git a/src/main.cpp b/src/main.cpp index 720ecbf9..3e26ea17 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -62,7 +62,6 @@ along with Mod Organizer. If not, see . #include #include #include -#include #include #include #include @@ -116,7 +115,7 @@ bool bootstrap() shellDelete(QStringList(backupDirectory)); } - // cycle logfile + // cycle log file removeOldFiles(qApp->property("dataPath").toString() + "/" + QString::fromStdWString(AppConfig::logPath()), "usvfs*.log", 5, QDir::Name); @@ -247,7 +246,7 @@ static bool HaveWriteAccess(const std::wstring &path) QString determineProfile(QStringList &arguments, const Settings &settings) { - QString selectedProfileName = settings.getSelectedProfileName(); + auto selectedProfileName = settings.getSelectedProfileName(); { // see if there is a profile on the command line int profileIndex = arguments.indexOf("-p", 1); @@ -259,14 +258,14 @@ QString determineProfile(QStringList &arguments, const Settings &settings) arguments.removeAt(profileIndex); } - if (selectedProfileName.isEmpty()) { + if (!selectedProfileName) { log::debug("no configured profile"); selectedProfileName = "Default"; } else { - log::debug("configured profile: {}", selectedProfileName); + log::debug("configured profile: {}", *selectedProfileName); } - return selectedProfileName; + return *selectedProfileName; } MOBase::IPluginGame *selectGame( @@ -290,27 +289,27 @@ MOBase::IPluginGame *determineCurrentGame( //user has done something odd. //If the game name has been set up, try to use that. - const QString gameName = settings.getManagedGameName(); - bool gameConfigured = !gameName.isEmpty(); + const auto gameName = settings.getManagedGameName(); + const bool gameConfigured = (gameName.has_value() && *gameName != ""); if (gameConfigured) { - MOBase::IPluginGame *game = plugins.managedGame(gameName); + MOBase::IPluginGame *game = plugins.managedGame(*gameName); if (game == nullptr) { - reportError(QObject::tr("Plugin to handle %1 no longer installed").arg(gameName)); + reportError(QObject::tr("Plugin to handle %1 no longer installed").arg(*gameName)); return nullptr; } - QString gamePath = settings.getManagedGameDirectory(); - if (gamePath == "") { + auto gamePath = settings.getManagedGameDirectory(); + if (!gamePath || *gamePath == "") { gamePath = game->gameDirectory().absolutePath(); } - QDir gameDir(gamePath); + QDir gameDir(*gamePath); QFileInfo directoryInfo(gameDir.path()); if (directoryInfo.isSymLink()) { reportError(QObject::tr("The configured path to the game directory (%1) appears to be a symbolic (or other) link. " - "This setup is incompatible with MO2's VFS and will not run correctly.").arg(gamePath)); + "This setup is incompatible with MO2's VFS and will not run correctly.").arg(*gamePath)); } if (game->looksValid(gameDir)) { @@ -321,17 +320,20 @@ MOBase::IPluginGame *determineCurrentGame( //If we've made it this far and the instance is already configured for a game, something has gone wrong. //Tell the user about it. if (gameConfigured) { - const QString gamePath = settings.getManagedGameDirectory(); - reportError(QObject::tr("Could not use configuration settings for game \"%1\", path \"%2\"."). - arg(gameName).arg(gamePath)); + const auto gamePath = settings.getManagedGameDirectory(); + + reportError( + QObject::tr("Could not use configuration settings for game \"%1\", path \"%2\".") + .arg(*gameName).arg(gamePath ? *gamePath : "")); } - SelectionDialog selection(gameConfigured ? QObject::tr("Please select the installation of %1 to manage").arg(gameName) - : QObject::tr("Please select the game to manage"), nullptr, QSize(32, 32)); + SelectionDialog selection(gameConfigured ? + QObject::tr("Please select the installation of %1 to manage").arg(*gameName) : + QObject::tr("Please select the game to manage"), nullptr, QSize(32, 32)); for (IPluginGame *game : plugins.plugins()) { //If a game is already configured, skip any plugins that are not for that game - if (gameConfigured && gameName.compare(game->gameName(), Qt::CaseInsensitive) != 0) + if (gameConfigured && gameName->compare(game->gameName(), Qt::CaseInsensitive) != 0) continue; //Only add games that are installed @@ -355,9 +357,11 @@ MOBase::IPluginGame *determineCurrentGame( return selectGame(settings, game->gameDirectory(), game); } - gamePath = QFileDialog::getExistingDirectory(nullptr, gameConfigured ? QObject::tr("Please select the installation of %1 to manage").arg(gameName) - : QObject::tr("Please select the game to manage"), - QString(), QFileDialog::ShowDirsOnly); + gamePath = QFileDialog::getExistingDirectory(nullptr, gameConfigured ? + QObject::tr("Please select the installation of %1 to manage").arg(*gameName) : + QObject::tr("Please select the game to manage"), + QString(), QFileDialog::ShowDirsOnly); + if (!gamePath.isEmpty()) { QDir gameDir(gamePath); QFileInfo directoryInfo(gamePath); @@ -368,7 +372,7 @@ MOBase::IPluginGame *determineCurrentGame( QList possibleGames; for (IPluginGame * const game : plugins.plugins()) { //If a game is already configured, skip any plugins that are not for that game - if (gameConfigured && gameName.compare(game->gameName(), Qt::CaseInsensitive) != 0) + if (gameConfigured && gameName->compare(game->gameName(), Qt::CaseInsensitive) != 0) continue; //Only try plugins that look valid for this directory @@ -376,24 +380,31 @@ MOBase::IPluginGame *determineCurrentGame( possibleGames.append(game); } } + if (possibleGames.count() > 1) { - SelectionDialog browseSelection(gameConfigured ? QObject::tr("Please select the installation of %1 to manage").arg(gameName) - : QObject::tr("Please select the game to manage"), - nullptr, QSize(32, 32)); + SelectionDialog browseSelection(gameConfigured ? + QObject::tr("Please select the installation of %1 to manage").arg(*gameName) : + QObject::tr("Please select the game to manage"), + nullptr, QSize(32, 32)); + for (IPluginGame *game : possibleGames) { browseSelection.addChoice(game->gameIcon(), game->gameName(), gamePath, QVariant::fromValue(game)); } + if (browseSelection.exec() == QDialog::Accepted) { return selectGame(settings, gameDir, browseSelection.getChoiceData().value()); } else { - reportError(gameConfigured ? QObject::tr("Canceled finding %1 in \"%2\".").arg(gameName).arg(gamePath) - : QObject::tr("Canceled finding game in \"%1\".").arg(gamePath)); + reportError(gameConfigured ? + QObject::tr("Canceled finding %1 in \"%2\".").arg(*gameName).arg(gamePath) : + QObject::tr("Canceled finding game in \"%1\".").arg(gamePath)); } } else if(possibleGames.count() == 1) { return selectGame(settings, gameDir, possibleGames[0]); } else { if (gameConfigured) { - reportError(QObject::tr("%1 not identified in \"%2\". The directory is required to contain the game binary.").arg(gameName).arg(gamePath)); + reportError( + QObject::tr("%1 not identified in \"%2\". The directory is required to contain the game binary.") + .arg(*gameName).arg(gamePath)); } else { QString supportedGames; @@ -608,7 +619,11 @@ int runApplication(MOApplication &application, SingleInstance &instance, organizer.setManagedGame(game); organizer.createDefaultProfile(); - if (settings.getManagedGameEdition() == "") { + QString edition; + + if (auto v=settings.getManagedGameEdition()) { + edition = *v; + } else { QStringList editions = game->gameVariants(); if (editions.size() > 1) { SelectionDialog selection( @@ -624,12 +639,15 @@ int runApplication(MOApplication &application, SingleInstance &instance, if (selection.exec() == QDialog::Rejected) { return 1; } else { - settings.setManagedGameEdition(selection.getChoiceString()); + edition = selection.getChoiceString(); + settings.setManagedGameEdition(edition); } } } - game->setGameVariant(settings.getManagedGameEdition()); + Q_ASSERT(!edition.isEmpty()); + + game->setGameVariant(edition); log::info("managing game at {}", game->gameDirectory().absolutePath()); @@ -679,10 +697,10 @@ int runApplication(MOApplication &application, SingleInstance &instance, QPixmap pixmap(splashPath); QSplashScreen splash(pixmap); - const int monitor = settings.getMainWindowMonitor(); - if (monitor != -1 && QGuiApplication::screens().size() > monitor) { - QGuiApplication::screens().at(monitor)->geometry().center(); - const QPoint center = QGuiApplication::screens().at(monitor)->geometry().center(); + const auto monitor = settings.geometry().getMainWindowMonitor(); + if (monitor && QGuiApplication::screens().size() > *monitor) { + QGuiApplication::screens().at(*monitor)->geometry().center(); + const QPoint center = QGuiApplication::screens().at(*monitor)->geometry().center(); splash.move(center - splash.rect().center()); } else { const QPoint center = QGuiApplication::primaryScreen()->geometry().center(); @@ -703,7 +721,7 @@ int runApplication(MOApplication &application, SingleInstance &instance, + QString::fromStdWString(AppConfig::tutorialsPath()) + "/", &organizer); - if (!application.setStyleFile(settings.getStyleName())) { + if (!application.setStyleFile(settings.getStyleName().value_or(""))) { // disable invalid stylesheet settings.setStyleName(""); } @@ -726,7 +744,7 @@ int runApplication(MOApplication &application, SingleInstance &instance, // this must be before readSettings(), see DockFixer in mainwindow.cpp splash.finish(&mainWindow); - mainWindow.readSettings(); + mainWindow.readSettings(settings); log::debug("displaying main window"); mainWindow.show(); diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 7f7ded80..e77d08b1 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -216,26 +216,24 @@ const QSize LargeToolbarSize(42, 36); class DockFixer { public: - static void save(MainWindow* mw, QSettings& settings) + static void save(MainWindow* mw, Settings& settings) { - const auto docks = mw->findChildren(); - // saves the size of each dock - for (int i=0; ifindChildren()) { int size = 0; // save the width for horizontal docks, or the height for vertical - if (orientation(mw, docks[i]) == Qt::Horizontal) { - size = docks[i]->size().width(); + if (orientation(mw, dock) == Qt::Horizontal) { + size = dock->size().width(); } else { - size = docks[i]->size().height(); + size = dock->size().height(); } - settings.setValue(settingName(docks[i]), size); + settings.geometry().setDockSize(dock->objectName(), size); } } - static void restore(MainWindow* mw, const QSettings& settings) + static void restore(MainWindow* mw, const Settings& settings) { struct DockInfo { @@ -246,16 +244,11 @@ public: std::vector dockInfos; - const auto docks = mw->findChildren(); - // for each dock - for (int i=0; ifindChildren()) { + if (auto size=settings.geometry().getDockSize(dock->objectName())) { // remember this dock, its size and orientation - const auto size = settings.value(name).toInt(); - dockInfos.push_back({docks[i], size, orientation(mw, docks[i])}); + dockInfos.push_back({dock, *size, orientation(mw, dock)}); } } @@ -264,30 +257,25 @@ public: // // some people said a single processEvents() call is enough, but it doesn't // look like it - QTimer::singleShot(1, [=] { + QTimer::singleShot(5, [=] { for (const auto& info : dockInfos) { mw->resizeDocks({info.d}, {info.size}, info.ori); } - }); + }); } - static Qt::Orientation orientation(QMainWindow* mw, QDockWidget* d) + static Qt::Orientation orientation(QMainWindow* mw, const QDockWidget* d) { // docks in these areas are horizontal const auto horizontalAreas = Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea; - if (mw->dockWidgetArea(d) & horizontalAreas) { + if (mw->dockWidgetArea(const_cast(d)) & horizontalAreas) { return Qt::Horizontal; } else { return Qt::Vertical; } } - - static QString settingName(QDockWidget* d) - { - return "geometry/" + d->objectName() + "_size"; - } }; @@ -359,9 +347,6 @@ MainWindow::MainWindow(Settings &settings ui->logList->setCore(m_OrganizerCore); - int splitterSize = this->size().height(); // actually total window size, but the splitter doesn't seem to return the true value - ui->topLevelSplitter->setSizes(QList() << splitterSize - 100 << 100); - updateProblemsButton(); setupToolbar(); @@ -540,8 +525,7 @@ MainWindow::MainWindow(Settings &settings connect(&m_SaveMetaTimer, SIGNAL(timeout()), this, SLOT(saveModMetas())); m_SaveMetaTimer.start(5000); - setCategoryListVisible(settings.isCategoryListVisible()); - FileDialogMemory::restore(settings.directInterface()); + FileDialogMemory::restore(settings); fixCategories(); @@ -2247,52 +2231,50 @@ void MainWindow::activateProxy(bool activate) busyDialog.hide(); } -void MainWindow::readSettings() +void MainWindow::readSettings(const Settings& settings) { - QSettings settings(qApp->property("dataPath").toString() + "/" + QString::fromStdWString(AppConfig::iniFileName()), QSettings::IniFormat); - - if (settings.contains("window_geometry")) { - restoreGeometry(settings.value("window_geometry").toByteArray()); + if (auto v=settings.geometry().getMainWindow()) { + restoreGeometry(*v); } - if (settings.contains("window_state")) { - restoreState(settings.value("window_state").toByteArray()); + if (auto v=settings.geometry().getMainWindowState()) { + restoreState(*v); } - if (settings.contains("toolbar_size")) { - setToolbarSize(settings.value("toolbar_size").toSize()); + if (auto v=settings.geometry().getToolbarSize()) { + setToolbarSize(*v); } - if (settings.contains("toolbar_button_style")) { - setToolbarButtonStyle(static_cast( - settings.value("toolbar_button_style").toInt())); + if (auto v=settings.geometry().getToolbarButtonStyle()) { + setToolbarButtonStyle(*v); } - if (settings.contains("menubar_visible")) { - showMenuBar(settings.value("menubar_visible").toBool()); + if (auto v=settings.geometry().getMenubarVisible()) { + showMenuBar(*v); } - if (settings.contains("statusbar_visible")) { - showStatusBar(settings.value("statusbar_visible").toBool()); + if (auto v=settings.geometry().getStatusbarVisible()) { + showStatusBar(*v); } - if (settings.contains("window_split")) { - ui->splitter->restoreState(settings.value("window_split").toByteArray()); + if (auto v=settings.geometry().getMainSplitterState()) { + ui->splitter->restoreState(*v); } - if (settings.contains("log_split")) { - ui->topLevelSplitter->restoreState(settings.value("log_split").toByteArray()); + { + auto v = settings.geometry().getFiltersVisible().value_or(false); + setCategoryListVisible(v); + ui->displayCategoriesBtn->setChecked(v); } - bool filtersVisible = settings.value("filters_visible", false).toBool(); - setCategoryListVisible(filtersVisible); - ui->displayCategoriesBtn->setChecked(filtersVisible); - - int selectedExecutable = settings.value("selected_executable").toInt(); - setExecutableIndex(selectedExecutable); + if (auto v=settings.getSelectedExecutable()) { + setExecutableIndex(*v); + } - if (settings.value("Settings/use_proxy", false).toBool()) { - activateProxy(true); + if (auto v=settings.getUseProxy()) { + if (*v) { + activateProxy(true); + } } DockFixer::restore(this, settings); @@ -2335,6 +2317,12 @@ void MainWindow::processUpdates() { ui->downloadView->header()->hideSection(i); } } + if (lastVersion < QVersionNumber(2, 2, 2)) { + QSettings &instance = Settings::instance().directInterface(); + + // log splitter is gone, it's a dock now + instance.remove("log_split"); + } } if (currentVersion > lastVersion) { @@ -2354,7 +2342,9 @@ void MainWindow::processUpdates() { settings.setValue("version", currentVersion.toString()); } -void MainWindow::storeSettings(QSettings &settings) { +void MainWindow::storeSettings(Settings& s) { + auto& settings = s.directInterface(); + settings.setValue("group_state", ui->groupCombo->currentIndex()); settings.setValue("selected_executable", ui->executablesListBox->currentIndex()); @@ -2367,7 +2357,6 @@ void MainWindow::storeSettings(QSettings &settings) { settings.remove("menubar_visible"); settings.remove("window_split"); settings.remove("window_monitor"); - settings.remove("log_split"); settings.remove("filters_visible"); settings.remove("browser_geometry"); settings.remove("geometry"); @@ -2383,7 +2372,6 @@ void MainWindow::storeSettings(QSettings &settings) { QScreen *screen = this->window()->windowHandle()->screen(); int screenId = QGuiApplication::screens().indexOf(screen); settings.setValue("window_monitor", screenId); - settings.setValue("log_split", ui->topLevelSplitter->saveState()); settings.setValue("browser_geometry", m_IntegratedBrowser.saveGeometry()); settings.setValue("filters_visible", ui->displayCategoriesBtn->isChecked()); @@ -2392,7 +2380,7 @@ void MainWindow::storeSettings(QSettings &settings) { settings.setValue(key, kv.second->saveState()); } - DockFixer::save(this, settings); + DockFixer::save(this, s); } } @@ -5213,7 +5201,7 @@ void MainWindow::on_actionSettings_triggered() QString oldModDirectory(settings.getModDirectory()); QString oldCacheDirectory(settings.getCacheDirectory()); QString oldProfilesDirectory(settings.getProfileDirectory()); - QString oldManagedGameDirectory(settings.getManagedGameDirectory()); + QString oldManagedGameDirectory(settings.getManagedGameDirectory().value_or("")); bool oldDisplayForeign(settings.displayForeign()); bool proxy = settings.useProxy(); DownloadManager *dlManager = m_OrganizerCore.downloadManager(); diff --git a/src/mainwindow.h b/src/mainwindow.h index 7326425a..d4513c0f 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -119,8 +119,8 @@ public: QWidget *parent = 0); ~MainWindow(); - void storeSettings(QSettings &settings) override; - void readSettings(); + void storeSettings(Settings& settings) override; + void readSettings(const Settings& settings); void processUpdates(); virtual ILockedWaitingForProcess* lock() override; diff --git a/src/mainwindow.ui b/src/mainwindow.ui index 6c6d0bca..e9910b83 100644 --- a/src/mainwindow.ui +++ b/src/mainwindow.ui @@ -47,10 +47,6 @@ 0 - - - Qt::Vertical - @@ -1286,7 +1282,6 @@ p, li { white-space: pre-wrap; } - diff --git a/src/organizercore.cpp b/src/organizercore.cpp index 72c8dab5..a64d93b4 100644 --- a/src/organizercore.cpp +++ b/src/organizercore.cpp @@ -94,15 +94,6 @@ static bool isOnline() return false; } -static bool renameFile(const QString &oldName, const QString &newName, - bool overwrite = true) -{ - if (overwrite && QFile::exists(newName)) { - QFile::remove(newName); - } - return QFile::rename(oldName, newName); -} - static std::wstring getProcessName(HANDLE process) { wchar_t buffer[MAX_PATH]; @@ -342,80 +333,37 @@ OrganizerCore::~OrganizerCore() delete m_DirectoryStructure; } -QString OrganizerCore::commitSettings(const QString &iniFile) -{ - if (!shellRename(iniFile + ".new", iniFile, true, qApp->activeWindow())) { - DWORD err = ::GetLastError(); - // make a second attempt using qt functions but if that fails print the - // error from the first attempt - if (!renameFile(iniFile + ".new", iniFile)) { - return QString::fromStdWString(formatSystemMessage(err)); - } - } - return QString(); -} - -QSettings::Status OrganizerCore::storeSettings(const QString &fileName) +void OrganizerCore::storeSettings() { - QSettings settings(fileName, QSettings::IniFormat); - if (m_UserInterface != nullptr) { - m_UserInterface->storeSettings(settings); + m_UserInterface->storeSettings(m_Settings); } if (m_CurrentProfile != nullptr) { - settings.setValue("selected_profile", - m_CurrentProfile->name().toUtf8().constData()); + m_Settings.setSelectedProfileName(m_CurrentProfile->name()); } - m_ExecutablesList.store(settings); - - FileDialogMemory::save(settings); + m_ExecutablesList.store(m_Settings); - settings.sync(); - return settings.status(); -} - -void OrganizerCore::storeSettings() -{ - QString iniFile = qApp->property("dataPath").toString() + "/" - + QString::fromStdWString(AppConfig::iniFileName()); - if (QFileInfo(iniFile).exists()) { - if (!shellCopy(iniFile, iniFile + ".new", true, qApp->activeWindow())) { - const auto e = GetLastError(); - QMessageBox::critical( - qApp->activeWindow(), tr("Failed to write settings"), - tr("An error occurred trying to update MO settings to %1: %2") - .arg(iniFile) - .arg(QString::fromStdWString(formatSystemMessage(e)))); - return; - } - } + FileDialogMemory::save(m_Settings); - QString writeTarget = iniFile + ".new"; + const auto result = m_Settings.sync(); - QSettings::Status result = storeSettings(writeTarget); + if (result != QSettings::NoError) { + QString reason; - if (result == QSettings::NoError) { - QString errMsg = commitSettings(iniFile); - if (!errMsg.isEmpty()) { - log::warn( - "settings file not writable, may be locked by another " - "application, trying direct write"); - writeTarget = iniFile; - result = storeSettings(iniFile); + if (result == QSettings::AccessError) { + reason = tr("File is write protected"); + } else if (result == QSettings::FormatError) { + reason = tr("Invalid file format (probably a bug)"); + } else { + reason = tr("Unknown error %1").arg(result); } - } - if (result != QSettings::NoError) { - QString reason = result == QSettings::AccessError - ? tr("File is write protected") - : result == QSettings::FormatError - ? tr("Invalid file format (probably a bug)") - : tr("Unknown error %1").arg(result); + QMessageBox::critical( - qApp->activeWindow(), tr("Failed to write settings"), - tr("An error occurred trying to write back MO settings to %1: %2") - .arg(writeTarget, reason)); + qApp->activeWindow(), tr("Failed to write settings"), + tr("An error occurred trying to write back MO settings to %1: %2") + .arg(m_Settings.getFilename(), reason)); } } @@ -487,7 +435,7 @@ void OrganizerCore::updateExecutablesList() return; } - m_ExecutablesList.load(managedGame(), m_Settings.directInterface()); + m_ExecutablesList.load(managedGame(), m_Settings); // TODO this has nothing to do with executables list move to an appropriate // function! diff --git a/src/organizercore.h b/src/organizercore.h index 926a21f0..4bcfe745 100644 --- a/src/organizercore.h +++ b/src/organizercore.h @@ -288,10 +288,6 @@ private: void storeSettings(); - QSettings::Status storeSettings(const QString &fileName); - - QString commitSettings(const QString &iniFile); - bool queryApi(QString &apiKey); void updateModActiveState(int index, bool active); diff --git a/src/settings.cpp b/src/settings.cpp index 5d103267..d843a0db 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -26,10 +26,56 @@ along with Mod Organizer. If not, see . using namespace MOBase; +template +T convertVariant(const QVariant& v); + +template <> +QByteArray convertVariant(const QVariant& v) +{ + return v.toByteArray(); +} + +template <> +QString convertVariant(const QVariant& v) +{ + return v.toString(); +} + +template <> +int convertVariant(const QVariant& v) +{ + return v.toInt(); +} + +template <> +bool convertVariant(const QVariant& v) +{ + return v.toBool(); +} + +template <> +QSize convertVariant(const QVariant& v) +{ + return v.toSize(); +} + + + +template +std::optional getOptional(const QSettings& s, const QString& name) +{ + if (s.contains(name)) { + return convertVariant(s.value(name)); + } + + return {}; +} + + Settings *Settings::s_Instance = nullptr; Settings::Settings(const QString& path) - : m_Settings(path, QSettings::IniFormat) + : m_Settings(path, QSettings::IniFormat), m_Geometry(m_Settings) { if (s_Instance != nullptr) { throw std::runtime_error("second instance of \"Settings\" created"); @@ -51,6 +97,11 @@ Settings &Settings::instance() return *s_Instance; } +QString Settings::getFilename() const +{ + return m_Settings.fileName(); +} + void Settings::clearPlugins() { m_Plugins.clear(); @@ -278,9 +329,13 @@ QString Settings::getModDirectory(bool resolve) const return getConfigurablePath("mod_directory", ToQString(AppConfig::modsPath()), resolve); } -QString Settings::getManagedGameDirectory() const +std::optional Settings::getManagedGameDirectory() const { - return QString::fromUtf8(m_Settings.value("gamePath", "").toByteArray()); + if (auto v=getOptional(m_Settings, "gamePath")) { + return QString::fromUtf8(*v); + } + + return {}; } void Settings::setManagedGameDirectory(const QString& path) @@ -288,9 +343,9 @@ void Settings::setManagedGameDirectory(const QString& path) m_Settings.setValue("gamePath", QDir::toNativeSeparators(path).toUtf8()); } -QString Settings::getManagedGameName() const +std::optional Settings::getManagedGameName() const { - return m_Settings.value("gameName", "").toString(); + return getOptional(m_Settings, "gameName"); } void Settings::setManagedGameName(const QString& name) @@ -298,9 +353,9 @@ void Settings::setManagedGameName(const QString& name) m_Settings.setValue("gameName", name); } -QString Settings::getManagedGameEdition() const +std::optional Settings::getManagedGameEdition() const { - return m_Settings.value("game_edition", "").toString(); + return getOptional(m_Settings, "game_edition"); } void Settings::setManagedGameEdition(const QString& name) @@ -308,19 +363,23 @@ void Settings::setManagedGameEdition(const QString& name) m_Settings.setValue("game_edition", name); } -QString Settings::getSelectedProfileName() const +std::optional Settings::getSelectedProfileName() const { - return QString::fromUtf8(m_Settings.value("selected_profile", "").toByteArray()); + if (auto v=getOptional(m_Settings, "selected_profile")) { + return QString::fromUtf8(*v); + } + + return {}; } -int Settings::getMainWindowMonitor() const +void Settings::setSelectedProfileName(const QString& name) { - return m_Settings.value("window_monitor", -1).toInt(); + m_Settings.setValue("selected_profile", name.toUtf8()); } -QString Settings::getStyleName() const +std::optional Settings::getStyleName() const { - return m_Settings.value("Settings/style", "").toString(); + return getOptional(m_Settings, "Settings/style"); } void Settings::setStyleName(const QString& name) @@ -328,9 +387,14 @@ void Settings::setStyleName(const QString& name) m_Settings.setValue("Settings/style", name); } -bool Settings::isCategoryListVisible() const +std::optional Settings::getSelectedExecutable() const { - return m_Settings.value("categorylist_visible", true).toBool(); + return getOptional(m_Settings, "selected_executable"); +} + +std::optional Settings::getUseProxy() const +{ + return getOptional(m_Settings, "Settings/use_proxy"); } QString Settings::getProfileDirectory(bool resolve) const @@ -659,6 +723,22 @@ void Settings::writePluginBlacklist() m_Settings.endArray(); } +GeometrySettings& Settings::geometry() +{ + return m_Geometry; +} + +const GeometrySettings& Settings::geometry() const +{ + return m_Geometry; +} + +QSettings::Status Settings::sync() const +{ + m_Settings.sync(); + return m_Settings.status(); +} + void Settings::dump() const { static const QStringList ignore({ @@ -679,3 +759,73 @@ void Settings::dump() const m_Settings.endGroup(); } + + +GeometrySettings::GeometrySettings(QSettings& s) + : m_Settings(s) +{ +} + +std::optional GeometrySettings::getMainWindow() const +{ + return getOptional(m_Settings, "window_geometry"); +} + +std::optional GeometrySettings::getMainWindowState() const +{ + return getOptional(m_Settings, "window_state"); +} + +std::optional GeometrySettings::getToolbarSize() const +{ + return getOptional(m_Settings, "toolbar_size"); +} + +std::optional GeometrySettings::getToolbarButtonStyle() const +{ + if (auto v=getOptional(m_Settings, "toolbar_button_style")) { + return static_cast(*v); + } + + return {}; +} + +std::optional GeometrySettings::getMenubarVisible() const +{ + return getOptional(m_Settings, "menubar_visible"); +} + +std::optional GeometrySettings::getStatusbarVisible() const +{ + return getOptional(m_Settings, "statusbar_visible"); +} + +std::optional GeometrySettings::getMainSplitterState() const +{ + return getOptional(m_Settings, "window_split"); +} + +std::optional GeometrySettings::getFiltersVisible() const +{ + return getOptional(m_Settings, "filters_visible"); +} + +std::optional GeometrySettings::getMainWindowMonitor() const +{ + return getOptional(m_Settings, "window_monitor"); +} + +void GeometrySettings::setDockSize(const QString& name, int size) +{ + m_Settings.setValue("geometry/" + name + "_size", size); +} + +std::optional GeometrySettings::getDockSize(const QString& name) const +{ + return getOptional(m_Settings, "geometry/" + name + "_size"); +} + +std::optional GeometrySettings::isCategoryListVisible() const +{ + return getOptional(m_Settings, "categorylist_visible"); +} diff --git a/src/settings.h b/src/settings.h index f06aece9..066843c2 100644 --- a/src/settings.h +++ b/src/settings.h @@ -31,13 +31,40 @@ namespace MOBase { class PluginContainer; struct ServerInfo; + +class GeometrySettings +{ +public: + GeometrySettings(QSettings& s); + + std::optional getMainWindow() const; + std::optional getMainWindowState() const; + std::optional getToolbarSize() const; + std::optional getToolbarButtonStyle() const; + std::optional getMenubarVisible() const; + std::optional getStatusbarVisible() const; + std::optional getMainSplitterState() const; + std::optional getFiltersVisible() const; + + std::optional getMainWindowMonitor() const; + void setDockSize(const QString& name, int size); + + std::optional getDockSize(const QString& name) const; + + std::optional isCategoryListVisible() const; + +private: + QSettings& m_Settings; +}; + + /** * manages the settings for Mod Organizer. The settings are not cached * inside the class but read/written directly from/to disc **/ class Settings : public QObject { - Q_OBJECT + Q_OBJECT; public: Settings(const QString& path); @@ -45,6 +72,8 @@ public: static Settings &instance(); + QString getFilename() const; + /** * unregister all plugins from settings */ @@ -122,25 +151,26 @@ public: /** * retrieve the directory where the managed game is stored (with native separators) **/ - QString getManagedGameDirectory() const; + std::optional getManagedGameDirectory() const; void setManagedGameDirectory(const QString& path); - QString getManagedGameName() const; + std::optional getManagedGameName() const; void setManagedGameName(const QString& name); - QString getManagedGameEdition() const; + std::optional getManagedGameEdition() const; void setManagedGameEdition(const QString& name); - QString getSelectedProfileName() const; - - // returns -1 if not set - // - int getMainWindowMonitor() const; + std::optional getSelectedProfileName() const; + void setSelectedProfileName(const QString& name); - QString getStyleName() const; + std::optional getStyleName() const; void setStyleName(const QString& name); - bool isCategoryListVisible() const; + std::optional getSelectedExecutable() const; + std::optional getUseProxy() const; + + GeometrySettings& geometry(); + const GeometrySettings& geometry() const; /** * retrieve the directory where profiles stored (with native separators) @@ -388,6 +418,8 @@ public: MOBase::IPluginGame const *gamePlugin() { return m_GamePlugin; } const LoadMechanism& loadMechanism() const { return m_LoadMechanism; } + QSettings::Status sync() const; + void dump() const; // temp @@ -407,6 +439,7 @@ private: static Settings *s_Instance; MOBase::IPluginGame const *m_GamePlugin; mutable QSettings m_Settings; + GeometrySettings m_Geometry; LoadMechanism m_LoadMechanism; std::vector m_Plugins; -- cgit v1.3.1 From e4418b95fa24f9caea32adfe9d957ce37e46f127 Mon Sep 17 00:00:00 2001 From: isanae <14251494+isanae@users.noreply.github.com> Date: Sat, 3 Aug 2019 02:30:20 -0400 Subject: moved settings updates to Settings::processUpdates() --- src/main.cpp | 2 +- src/mainwindow.cpp | 44 ++++++++++++-------------------------------- src/mainwindow.h | 2 +- src/settings.cpp | 46 ++++++++++++++++++++++++++++++++++++++++++++++ src/settings.h | 7 +++++++ 5 files changed, 67 insertions(+), 34 deletions(-) (limited to 'src/main.cpp') diff --git a/src/main.cpp b/src/main.cpp index 3e26ea17..506c6270 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -739,7 +739,7 @@ int runApplication(MOApplication &application, SingleInstance &instance, QObject::connect(&instance, SIGNAL(messageSent(QString)), &organizer, SLOT(externalMessage(QString))); - mainWindow.processUpdates(); + mainWindow.processUpdates(settings); // this must be before readSettings(), see DockFixer in mainwindow.cpp splash.finish(&mainWindow); diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index e77d08b1..0618f949 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -2280,11 +2280,15 @@ void MainWindow::readSettings(const Settings& settings) DockFixer::restore(this, settings); } -void MainWindow::processUpdates() { - QSettings settings(qApp->property("dataPath").toString() + "/" + QString::fromStdWString(AppConfig::iniFileName()), QSettings::IniFormat); - QVersionNumber lastVersion = QVersionNumber::fromString(settings.value("version", "2.1.2").toString()).normalized(); - QVersionNumber currentVersion = QVersionNumber::fromString(m_OrganizerCore.getVersion().displayString()).normalized(); - if (!m_OrganizerCore.settings().directInterface().value("first_start", true).toBool()) { +void MainWindow::processUpdates(Settings& settings) { + const auto earliest = QVersionNumber::fromString("2.1.2").normalized(); + + const auto lastVersion = settings.getVersion().value_or(earliest); + const auto currentVersion = m_OrganizerCore.getVersion().asQVersionNumber(); + + settings.processUpdates(currentVersion, lastVersion); + + if (!settings.getFirstStart()) { if (lastVersion < QVersionNumber(2, 1, 3)) { bool lastHidden = true; for (int i = ModList::COL_GAME; i < ui->modList->model()->columnCount(); ++i) { @@ -2293,41 +2297,20 @@ void MainWindow::processUpdates() { lastHidden = hidden; } } + if (lastVersion < QVersionNumber(2, 1, 6)) { ui->modList->header()->setSectionHidden(ModList::COL_NOTES, true); } - if (lastVersion < QVersionNumber(2, 2, 0)) { - QSettings &instance = Settings::instance().directInterface(); - instance.beginGroup("Settings"); - instance.remove("steam_password"); - instance.remove("nexus_username"); - instance.remove("nexus_password"); - instance.remove("nexus_login"); - instance.remove("nexus_api_key"); - instance.remove("ask_for_nexuspw"); - instance.remove("nmm_version"); - instance.endGroup(); - instance.beginGroup("Servers"); - instance.remove(""); - instance.endGroup(); - } + if (lastVersion < QVersionNumber(2, 2, 1)) { // hide new columns by default for (int i=DownloadList::COL_MODNAME; idownloadView->header()->hideSection(i); } } - if (lastVersion < QVersionNumber(2, 2, 2)) { - QSettings &instance = Settings::instance().directInterface(); - - // log splitter is gone, it's a dock now - instance.remove("log_split"); - } } - if (currentVersion > lastVersion) { - //NOP - } else if (currentVersion < lastVersion) { + if (currentVersion < lastVersion) { const auto text = tr( "Notice: Your current MO version (%1) is lower than the previously used one (%2). " "The GUI may not downgrade gracefully, so you may experience oddities. " @@ -2337,9 +2320,6 @@ void MainWindow::processUpdates() { log::warn("{}", text); } - - //save version in all case - settings.setValue("version", currentVersion.toString()); } void MainWindow::storeSettings(Settings& s) { diff --git a/src/mainwindow.h b/src/mainwindow.h index d4513c0f..e8f60211 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -121,7 +121,7 @@ public: void storeSettings(Settings& settings) override; void readSettings(const Settings& settings); - void processUpdates(); + void processUpdates(Settings& settings); virtual ILockedWaitingForProcess* lock() override; virtual void unlock() override; diff --git a/src/settings.cpp b/src/settings.cpp index d843a0db..35be1298 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -97,6 +97,38 @@ Settings &Settings::instance() return *s_Instance; } +void Settings::processUpdates( + const QVersionNumber& currentVersion, const QVersionNumber& lastVersion) +{ + if (getFirstStart()) { + return; + } + + if (lastVersion < QVersionNumber(2, 2, 0)) { + m_Settings.beginGroup("Settings"); + m_Settings.remove("steam_password"); + m_Settings.remove("nexus_username"); + m_Settings.remove("nexus_password"); + m_Settings.remove("nexus_login"); + m_Settings.remove("nexus_api_key"); + m_Settings.remove("ask_for_nexuspw"); + m_Settings.remove("nmm_version"); + m_Settings.endGroup(); + + m_Settings.beginGroup("Servers"); + m_Settings.remove(""); + m_Settings.endGroup(); + } + + if (lastVersion < QVersionNumber(2, 2, 2)) { + // log splitter is gone, it's a dock now + m_Settings.remove("log_split"); + } + + //save version in all case + m_Settings.setValue("version", currentVersion.toString()); +} + QString Settings::getFilename() const { return m_Settings.fileName(); @@ -397,6 +429,20 @@ std::optional Settings::getUseProxy() const return getOptional(m_Settings, "Settings/use_proxy"); } +std::optional Settings::getVersion() const +{ + if (auto v=getOptional(m_Settings, "version")) { + return QVersionNumber::fromString(*v).normalized(); + } + + return {}; +} + +bool Settings::getFirstStart() const +{ + return getOptional(m_Settings, "first_start").value_or(true); +} + QString Settings::getProfileDirectory(bool resolve) const { return getConfigurablePath("profiles_directory", ToQString(AppConfig::profilesPath()), resolve); diff --git a/src/settings.h b/src/settings.h index 066843c2..bf66c0dd 100644 --- a/src/settings.h +++ b/src/settings.h @@ -72,6 +72,9 @@ public: static Settings &instance(); + void processUpdates( + const QVersionNumber& currentVersion, const QVersionNumber& lastVersion); + QString getFilename() const; /** @@ -169,9 +172,13 @@ public: std::optional getSelectedExecutable() const; std::optional getUseProxy() const; + std::optional getVersion() const; + bool getFirstStart() const; + GeometrySettings& geometry(); const GeometrySettings& geometry() const; + /** * retrieve the directory where profiles stored (with native separators) **/ -- cgit v1.3.1 From 3f487a5a6c9c23824298fdde3d76dc82edf3ca46 Mon Sep 17 00:00:00 2001 From: isanae <14251494+isanae@users.noreply.github.com> Date: Fri, 16 Aug 2019 07:03:52 -0400 Subject: merged toolbars into restoreToolbars() and saveToolbars() added centerOnMainWindowMonitor(), now also used by validation dialog added overloads for splitter, used by main splitter fixed saveState() for QMainWindow calling the wrong function --- src/main.cpp | 11 +------ src/mainwindow.cpp | 28 +++++----------- src/nxmaccessmanager.cpp | 13 ++++++-- src/nxmaccessmanager.h | 2 ++ src/pch.h | 1 + src/settings.cpp | 86 ++++++++++++++++++++++++++++++++++++++++++------ src/settings.h | 19 ++++++++--- 7 files changed, 114 insertions(+), 46 deletions(-) (limited to 'src/main.cpp') diff --git a/src/main.cpp b/src/main.cpp index 506c6270..8eee41e4 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -697,16 +697,7 @@ int runApplication(MOApplication &application, SingleInstance &instance, QPixmap pixmap(splashPath); QSplashScreen splash(pixmap); - const auto monitor = settings.geometry().getMainWindowMonitor(); - if (monitor && QGuiApplication::screens().size() > *monitor) { - QGuiApplication::screens().at(*monitor)->geometry().center(); - const QPoint center = QGuiApplication::screens().at(*monitor)->geometry().center(); - splash.move(center - splash.rect().center()); - } else { - const QPoint center = QGuiApplication::primaryScreen()->geometry().center(); - splash.move(center - splash.rect().center()); - } - + settings.geometry().centerOnMainWindowMonitor(&splash); splash.show(); splash.activateWindow(); diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 85be8563..6e6e3d22 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -2261,14 +2261,8 @@ void MainWindow::readSettings(const Settings& settings) { settings.restoreGeometry(this); settings.restoreState(this); - - if (auto v=settings.geometry().getToolbarSize()) { - setToolbarSize(*v); - } - - if (auto v=settings.geometry().getToolbarButtonStyle()) { - setToolbarButtonStyle(*v); - } + settings.geometry().restoreToolbars(this); + settings.restoreState(ui->splitter); if (auto v=settings.geometry().getMenubarVisible()) { showMenuBar(*v); @@ -2278,10 +2272,6 @@ void MainWindow::readSettings(const Settings& settings) showStatusBar(*v); } - if (auto v=settings.geometry().getMainSplitterState()) { - ui->splitter->restoreState(*v); - } - { auto v = settings.geometry().getFiltersVisible().value_or(false); setCategoryListVisible(v); @@ -2366,14 +2356,12 @@ void MainWindow::storeSettings(Settings& s) { s.saveState(this); s.saveGeometry(this); - settings.setValue("toolbar_size", ui->toolBar->iconSize()); - settings.setValue("toolbar_button_style", static_cast(ui->toolBar->toolButtonStyle())); - settings.setValue("menubar_visible", m_menuBarVisible); - settings.setValue("statusbar_visible", m_statusBarVisible); - settings.setValue("window_split", ui->splitter->saveState()); - QScreen *screen = this->window()->windowHandle()->screen(); - int screenId = QGuiApplication::screens().indexOf(screen); - settings.setValue("window_monitor", screenId); + s.geometry().setMenubarVisible(m_menuBarVisible); + s.geometry().saveToolbars(this); + s.geometry().setStatusbarVisible(m_statusBarVisible); + s.saveState(ui->splitter); + s.geometry().saveMainWindowMonitor(this); + settings.setValue("browser_geometry", m_IntegratedBrowser.saveGeometry()); settings.setValue("filters_visible", ui->displayCategoriesBtn->isChecked()); diff --git a/src/nxmaccessmanager.cpp b/src/nxmaccessmanager.cpp index fd1dc0c1..16190ca4 100644 --- a/src/nxmaccessmanager.cpp +++ b/src/nxmaccessmanager.cpp @@ -48,8 +48,9 @@ const QString NexusSSO("wss://sso.nexusmods.com"); const QString NexusSSOPage("https://www.nexusmods.com/sso?id=%1&application=modorganizer2"); -ValidationProgressDialog::ValidationProgressDialog(std::chrono::seconds t) - : m_timeout(t), m_bar(nullptr), m_buttons(nullptr), m_timer(nullptr) +ValidationProgressDialog::ValidationProgressDialog(std::chrono::seconds t) : + m_timeout(t), m_bar(nullptr), m_buttons(nullptr), m_timer(nullptr), + m_first(true) { m_bar = new QProgressBar; m_bar->setTextVisible(false); @@ -103,6 +104,14 @@ void ValidationProgressDialog::stop() hide(); } +void ValidationProgressDialog::showEvent(QShowEvent* e) +{ + if (m_first) { + Settings::instance().geometry().centerOnMainWindowMonitor(this); + m_first = false; + } +} + void ValidationProgressDialog::closeEvent(QCloseEvent* e) { hide(); diff --git a/src/nxmaccessmanager.h b/src/nxmaccessmanager.h index eed7c1c9..0c85153b 100644 --- a/src/nxmaccessmanager.h +++ b/src/nxmaccessmanager.h @@ -48,6 +48,7 @@ public: using QDialog::show; protected: + void showEvent(QShowEvent* e) override; void closeEvent(QCloseEvent* e) override; private: @@ -56,6 +57,7 @@ private: QDialogButtonBox* m_buttons; QTimer* m_timer; QElapsedTimer m_elapsed; + bool m_first; void onButton(QAbstractButton* b); void onTimer(); diff --git a/src/pch.h b/src/pch.h index 504ef8f1..dd65efbe 100644 --- a/src/pch.h +++ b/src/pch.h @@ -189,6 +189,7 @@ #include #include #include +#include #include #include #include diff --git a/src/settings.cpp b/src/settings.cpp index 91e667d5..a3d12070 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -958,7 +958,7 @@ bool Settings::restoreGeometry(QWidget* w) const void Settings::saveState(const QMainWindow* w) { - m_Settings.setValue(stateSettingName(w), w->saveGeometry()); + m_Settings.setValue(stateSettingName(w), w->saveState()); } bool Settings::restoreState(QMainWindow* w) const @@ -986,24 +986,61 @@ bool Settings::restoreState(QHeaderView* w) const return false; } +void Settings::saveState(const QSplitter* w) +{ + m_Settings.setValue(stateSettingName(w), w->saveState()); +} + +bool Settings::restoreState(QSplitter* w) const +{ + if (auto v=getOptional(m_Settings, stateSettingName(w))) { + w->restoreState(*v); + return true; + } + + return false; +} + GeometrySettings::GeometrySettings(QSettings& s) : m_Settings(s) { } -std::optional GeometrySettings::getToolbarSize() const +bool GeometrySettings::restoreToolbars(QMainWindow* w) const { - return getOptional(m_Settings, "toolbar_size"); + const auto size = getOptional(m_Settings, "toolbar_size"); + const auto style = getOptional(m_Settings, "toolbar_button_style"); + + if (!size && !style) { + return false; + } + + for (auto* tb : w->findChildren()) { + if (size) { + tb->setIconSize(*size); + } + + if (style) { + tb->setToolButtonStyle(static_cast(*style)); + } + } + + return true; } -std::optional GeometrySettings::getToolbarButtonStyle() const +void GeometrySettings::saveToolbars(const QMainWindow* w) { - if (auto v=getOptional(m_Settings, "toolbar_button_style")) { - return static_cast(*v); + // all toolbars are identical, just save the first one + const auto tbs = w->findChildren(); + if (tbs.isEmpty()) { + return; } - return {}; + const auto* tb = tbs[0]; + + m_Settings.setValue("toolbar_size", tb->iconSize()); + m_Settings.setValue("toolbar_button_style", static_cast(tb->toolButtonStyle())); } std::optional GeometrySettings::getMenubarVisible() const @@ -1011,14 +1048,19 @@ std::optional GeometrySettings::getMenubarVisible() const return getOptional(m_Settings, "menubar_visible"); } +void GeometrySettings::setMenubarVisible(bool b) +{ + m_Settings.setValue("menubar_visible", b); +} + std::optional GeometrySettings::getStatusbarVisible() const { return getOptional(m_Settings, "statusbar_visible"); } -std::optional GeometrySettings::getMainSplitterState() const +void GeometrySettings::setStatusbarVisible(bool b) { - return getOptional(m_Settings, "window_split"); + m_Settings.setValue("statusbar_visible", b); } std::optional GeometrySettings::getFiltersVisible() const @@ -1064,7 +1106,31 @@ void GeometrySettings::setModInfoTabOrder(const QString& names) std::optional GeometrySettings::getMainWindowMonitor() const { - return getOptional(m_Settings, "window_monitor"); + return getOptional(m_Settings, "geometry/window_monitor"); +} + +void GeometrySettings::centerOnMainWindowMonitor(QWidget* w) +{ + const auto monitor = getMainWindowMonitor(); + QPoint center; + + if (monitor && QGuiApplication::screens().size() > *monitor) { + center = QGuiApplication::screens().at(*monitor)->geometry().center(); + } else { + center = QGuiApplication::primaryScreen()->geometry().center(); + } + + w->move(center - w->rect().center()); +} + +void GeometrySettings::saveMainWindowMonitor(const QMainWindow* w) +{ + if (auto* handle=w->windowHandle()) { + if (auto* screen = handle->screen()) { + const int screenId = QGuiApplication::screens().indexOf(screen); + m_Settings.setValue("geometry/window_monitor", screenId); + } + } } void GeometrySettings::setDockSize(const QString& name, int size) diff --git a/src/settings.h b/src/settings.h index 1575b3cd..bbf008f0 100644 --- a/src/settings.h +++ b/src/settings.h @@ -28,6 +28,8 @@ namespace MOBase { class IPluginGame; } +class QSplitter; + class PluginContainer; struct ServerInfo; class Settings; @@ -49,18 +51,24 @@ class GeometrySettings public: GeometrySettings(QSettings& s); - std::optional getToolbarSize() const; - std::optional getToolbarButtonStyle() const; - std::optional getMenubarVisible() const; + void setMenubarVisible(bool b); + + bool restoreToolbars(QMainWindow* w) const; + void saveToolbars(const QMainWindow* w); + std::optional getStatusbarVisible() const; - std::optional getMainSplitterState() const; + void setStatusbarVisible(bool b); + std::optional getFiltersVisible() const; QStringList getModInfoTabOrder() const; void setModInfoTabOrder(const QString& names); std::optional getMainWindowMonitor() const; + void centerOnMainWindowMonitor(QWidget* w); + void saveMainWindowMonitor(const QMainWindow* w); + void setDockSize(const QString& name, int size); std::optional getDockSize(const QString& name) const; @@ -215,6 +223,9 @@ public: void saveState(const QToolBar* toolbar); bool restoreState(QToolBar* toolbar) const; + void saveState(const QSplitter* splitter); + bool restoreState(QSplitter* splitter) const; + /** * retrieve the directory where profiles stored (with native separators) -- cgit v1.3.1 From a5cb39aaf44b1f84003fb2ec2d36f07bf28916e4 Mon Sep 17 00:00:00 2001 From: isanae <14251494+isanae@users.noreply.github.com> Date: Fri, 16 Aug 2019 08:02:14 -0400 Subject: moved all geometry save, restore and reset to GeometrySettings changed reset button in settings to restart immediately --- src/browserdialog.cpp | 3 +- src/main.cpp | 12 ++++-- src/mainwindow.cpp | 75 +++++++++++-------------------------- src/mainwindow.h | 1 - src/overwriteinfodialog.cpp | 4 +- src/settings.cpp | 79 ++++++++++++++++++++++++++------------- src/settings.h | 39 +++++++++---------- src/settingsdialog.cpp | 11 +----- src/settingsdialog.h | 2 - src/settingsdialog.ui | 3 -- src/settingsdialogworkarounds.cpp | 16 ++++++-- 11 files changed, 121 insertions(+), 124 deletions(-) (limited to 'src/main.cpp') diff --git a/src/browserdialog.cpp b/src/browserdialog.cpp index 73a6a2d0..70da0b9c 100644 --- a/src/browserdialog.cpp +++ b/src/browserdialog.cpp @@ -72,7 +72,7 @@ BrowserDialog::~BrowserDialog() void BrowserDialog::closeEvent(QCloseEvent *event) { -// m_AccessManager->showCookies(); + Settings::instance().geometry().saveGeometry(this); QDialog::closeEvent(event); } @@ -126,6 +126,7 @@ void BrowserDialog::urlChanged(const QUrl &url) void BrowserDialog::openUrl(const QUrl &url) { if (isHidden()) { + Settings::instance().geometry().restoreGeometry(this); show(); } openInNewTab(url); diff --git a/src/main.cpp b/src/main.cpp index 8eee41e4..6d4108fa 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -718,6 +718,7 @@ int runApplication(MOApplication &application, SingleInstance &instance, } int res = 1; + { // scope to control lifetime of mainwindow // set up main window and its data structures MainWindow mainWindow(settings, organizer, pluginContainer); @@ -743,17 +744,20 @@ int runApplication(MOApplication &application, SingleInstance &instance, splash.finish(&mainWindow); - const auto ret = application.exec(); + res = application.exec(); NexusInterface::instance(&pluginContainer) ->getAccessManager()->setTopLevelWidget(nullptr); - - return ret; } + + settings.geometry().resetIfNeeded(); + return res; + } catch (const std::exception &e) { reportError(e.what()); - return 1; } + + return 1; } int doCoreDump(env::CoreDumpTypes type) diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 6e6e3d22..28e1de2e 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -366,9 +366,11 @@ MainWindow::MainWindow(Settings &settings initDownloadView(); - const bool pluginListAdjusted = settings.restoreState(ui->espList->header()); - settings.restoreState(ui->dataTree->header()); - settings.restoreState(ui->downloadView->header()); + const bool pluginListAdjusted = + settings.geometry().restoreState(ui->espList->header()); + + settings.geometry().restoreState(ui->dataTree->header()); + settings.geometry().restoreState(ui->downloadView->header()); ui->splitter->setStretchFactor(0, 3); ui->splitter->setStretchFactor(1, 2); @@ -575,7 +577,7 @@ void MainWindow::setupModList() ui->modList->header()->installEventFilter(m_OrganizerCore.modList()); - if (m_OrganizerCore.settings().restoreState(ui->modList->header())) { + if (m_OrganizerCore.settings().geometry().restoreState(ui->modList->header())) { // hack: force the resize-signal to be triggered because restoreState doesn't seem to do that for (int column = 0; column <= ModList::COL_LASTCOLUMN; ++column) { int sectionSize = ui->modList->header()->sectionSize(column); @@ -1417,12 +1419,6 @@ void MainWindow::cleanup() m_MetaSave.waitForFinished(); } - -void MainWindow::setBrowserGeometry(const QByteArray &geometry) -{ - m_IntegratedBrowser.restoreGeometry(geometry); -} - void MainWindow::displaySaveGameInfo(QListWidgetItem *newItem) { // don't display the widget if the main window doesn't have focus @@ -2259,10 +2255,10 @@ void MainWindow::activateProxy(bool activate) void MainWindow::readSettings(const Settings& settings) { - settings.restoreGeometry(this); - settings.restoreState(this); + settings.geometry().restoreGeometry(this); + settings.geometry().restoreState(this); settings.geometry().restoreToolbars(this); - settings.restoreState(ui->splitter); + settings.geometry().restoreState(ui->splitter); if (auto v=settings.geometry().getMenubarVisible()) { showMenuBar(*v); @@ -2340,38 +2336,22 @@ void MainWindow::storeSettings(Settings& s) { settings.setValue("selected_executable", ui->executablesListBox->currentIndex()); - if (settings.value("reset_geometry", false).toBool()) { - settings.remove("window_geometry"); - settings.remove("window_state"); - settings.remove("toolbar_size"); - settings.remove("toolbar_button_style"); - settings.remove("menubar_visible"); - settings.remove("window_split"); - settings.remove("window_monitor"); - settings.remove("filters_visible"); - settings.remove("browser_geometry"); - settings.remove("geometry"); - settings.remove("reset_geometry"); - } else { - s.saveState(this); - s.saveGeometry(this); - - s.geometry().setMenubarVisible(m_menuBarVisible); - s.geometry().saveToolbars(this); - s.geometry().setStatusbarVisible(m_statusBarVisible); - s.saveState(ui->splitter); - s.geometry().saveMainWindowMonitor(this); + s.geometry().saveState(this); + s.geometry().saveGeometry(this); - settings.setValue("browser_geometry", m_IntegratedBrowser.saveGeometry()); - settings.setValue("filters_visible", ui->displayCategoriesBtn->isChecked()); + s.geometry().setMenubarVisible(m_menuBarVisible); + s.geometry().saveToolbars(this); + s.geometry().setStatusbarVisible(m_statusBarVisible); + s.geometry().saveState(ui->splitter); + s.geometry().saveMainWindowMonitor(this); + s.geometry().setFiltersVisible(ui->displayCategoriesBtn->isChecked()); - s.saveState(ui->espList->header()); - s.saveState(ui->dataTree->header()); - s.saveState(ui->downloadView->header()); - s.saveState(ui->modList->header()); + s.geometry().saveState(ui->espList->header()); + s.geometry().saveState(ui->dataTree->header()); + s.geometry().saveState(ui->downloadView->header()); + s.geometry().saveState(ui->modList->header()); - DockFixer::save(this, s); - } + DockFixer::save(this, s); } ILockedWaitingForProcess* MainWindow::lock() @@ -6489,7 +6469,6 @@ void MainWindow::processLOOTOut(const std::string &lootOut, std::string &errorMe void MainWindow::on_bossButton_clicked() { - std::string reportURL; std::string errorMessages; //m_OrganizerCore.currentProfile()->writeModlistNow(); @@ -6637,16 +6616,6 @@ void MainWindow::on_bossButton_clicked() if (success) { m_DidUpdateMasterList = true; - if (reportURL.length() > 0) { - m_IntegratedBrowser.setWindowTitle("LOOT Report"); - QString report(reportURL.c_str()); - QStringList temp = report.split("?"); - QUrl url = QUrl::fromLocalFile(temp.at(0)); - if (temp.size() > 1) { - url.setQuery(temp.at(1).toUtf8()); - } - m_IntegratedBrowser.openUrl(url); - } m_OrganizerCore.refreshESPList(false); m_OrganizerCore.savePluginList(); } diff --git a/src/mainwindow.h b/src/mainwindow.h index 946a341b..8542dc8a 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -293,7 +293,6 @@ private: static void setupNetworkProxy(bool activate); void activateProxy(bool activate); - void setBrowserGeometry(const QByteArray &geometry); bool createBackup(const QString &filePath, const QDateTime &time); QString queryRestore(const QString &filePath); diff --git a/src/overwriteinfodialog.cpp b/src/overwriteinfodialog.cpp index 47416311..fe1d8825 100644 --- a/src/overwriteinfodialog.cpp +++ b/src/overwriteinfodialog.cpp @@ -106,13 +106,13 @@ OverwriteInfoDialog::~OverwriteInfoDialog() void OverwriteInfoDialog::showEvent(QShowEvent* e) { - Settings::instance().restoreGeometry(this); + Settings::instance().geometry().restoreGeometry(this); QDialog::showEvent(e); } void OverwriteInfoDialog::done(int r) { - Settings::instance().saveGeometry(this); + Settings::instance().geometry().saveGeometry(this); QDialog::done(r); } diff --git a/src/settings.cpp b/src/settings.cpp index a3d12070..db6cecdf 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -884,6 +884,7 @@ void Settings::dump() const m_Settings.endGroup(); } + QString widgetNameWithTopLevel(const QWidget* widget) { QStringList components; @@ -941,12 +942,46 @@ QString stateSettingName(const Widget* widget) return "geometry/" + widgetName(widget) + "_state"; } -void Settings::saveGeometry(const QWidget* w) + +GeometrySettings::GeometrySettings(QSettings& s) + : m_Settings(s), m_Reset(false) +{ +} + +void GeometrySettings::requestReset() +{ + m_Reset = true; +} + +void GeometrySettings::resetIfNeeded() +{ + if (!m_Reset) { + return; + } + + m_Settings.beginGroup("geometry"); + m_Settings.remove(""); + m_Settings.endGroup(); + + /*settings.remove("window_geometry"); + settings.remove("window_state"); + settings.remove("toolbar_size"); + settings.remove("toolbar_button_style"); + settings.remove("menubar_visible"); + settings.remove("window_split"); + settings.remove("window_monitor"); + settings.remove("filters_visible"); + settings.remove("browser_geometry"); + settings.remove("geometry"); + settings.remove("reset_geometry");*/ +} + +void GeometrySettings::saveGeometry(const QWidget* w) { m_Settings.setValue(geoSettingName(w), w->saveGeometry()); } -bool Settings::restoreGeometry(QWidget* w) const +bool GeometrySettings::restoreGeometry(QWidget* w) const { if (auto v=getOptional(m_Settings, geoSettingName(w))) { w->restoreGeometry(*v); @@ -956,12 +991,12 @@ bool Settings::restoreGeometry(QWidget* w) const return false; } -void Settings::saveState(const QMainWindow* w) +void GeometrySettings::saveState(const QMainWindow* w) { m_Settings.setValue(stateSettingName(w), w->saveState()); } -bool Settings::restoreState(QMainWindow* w) const +bool GeometrySettings::restoreState(QMainWindow* w) const { if (auto v=getOptional(m_Settings, stateSettingName(w))) { w->restoreState(*v); @@ -971,12 +1006,12 @@ bool Settings::restoreState(QMainWindow* w) const return false; } -void Settings::saveState(const QHeaderView* w) +void GeometrySettings::saveState(const QHeaderView* w) { m_Settings.setValue(stateSettingName(w), w->saveState()); } -bool Settings::restoreState(QHeaderView* w) const +bool GeometrySettings::restoreState(QHeaderView* w) const { if (auto v=getOptional(m_Settings, stateSettingName(w))) { w->restoreState(*v); @@ -986,12 +1021,12 @@ bool Settings::restoreState(QHeaderView* w) const return false; } -void Settings::saveState(const QSplitter* w) +void GeometrySettings::saveState(const QSplitter* w) { m_Settings.setValue(stateSettingName(w), w->saveState()); } -bool Settings::restoreState(QSplitter* w) const +bool GeometrySettings::restoreState(QSplitter* w) const { if (auto v=getOptional(m_Settings, stateSettingName(w))) { w->restoreState(*v); @@ -1001,12 +1036,6 @@ bool Settings::restoreState(QSplitter* w) const return false; } - -GeometrySettings::GeometrySettings(QSettings& s) - : m_Settings(s) -{ -} - bool GeometrySettings::restoreToolbars(QMainWindow* w) const { const auto size = getOptional(m_Settings, "toolbar_size"); @@ -1068,6 +1097,11 @@ std::optional GeometrySettings::getFiltersVisible() const return getOptional(m_Settings, "filters_visible"); } +void GeometrySettings::setFiltersVisible(bool b) +{ + m_Settings.setValue("filters_visible", b); +} + QStringList GeometrySettings::getModInfoTabOrder() const { QStringList v; @@ -1106,7 +1140,7 @@ void GeometrySettings::setModInfoTabOrder(const QString& names) std::optional GeometrySettings::getMainWindowMonitor() const { - return getOptional(m_Settings, "geometry/window_monitor"); + return getOptional(m_Settings, "geometry/MainWindow_monitor"); } void GeometrySettings::centerOnMainWindowMonitor(QWidget* w) @@ -1128,34 +1162,29 @@ void GeometrySettings::saveMainWindowMonitor(const QMainWindow* w) if (auto* handle=w->windowHandle()) { if (auto* screen = handle->screen()) { const int screenId = QGuiApplication::screens().indexOf(screen); - m_Settings.setValue("geometry/window_monitor", screenId); + m_Settings.setValue("geometry/MainWindow_monitor", screenId); } } } void GeometrySettings::setDockSize(const QString& name, int size) { - m_Settings.setValue("geometry/" + name + "_size", size); + m_Settings.setValue("geometry/MainWindow_docks_" + name + "_size", size); } std::optional GeometrySettings::getDockSize(const QString& name) const { - return getOptional(m_Settings, "geometry/" + name + "_size"); -} - -std::optional GeometrySettings::isCategoryListVisible() const -{ - return getOptional(m_Settings, "categorylist_visible"); + return getOptional(m_Settings, "geometry/MainWindow_docks_" + name + "_size"); } GeometrySaver::GeometrySaver(Settings& s, QDialog* dialog) : m_settings(s), m_dialog(dialog) { - m_settings.restoreGeometry(m_dialog); + m_settings.geometry().restoreGeometry(m_dialog); } GeometrySaver::~GeometrySaver() { - m_settings.saveGeometry(m_dialog); + m_settings.geometry().saveGeometry(m_dialog); } diff --git a/src/settings.h b/src/settings.h index bbf008f0..9ae58803 100644 --- a/src/settings.h +++ b/src/settings.h @@ -51,6 +51,24 @@ class GeometrySettings public: GeometrySettings(QSettings& s); + void requestReset(); + void resetIfNeeded(); + + void saveGeometry(const QWidget* w); + bool restoreGeometry(QWidget* w) const; + + void saveState(const QMainWindow* window); + bool restoreState(QMainWindow* window) const; + + void saveState(const QHeaderView* header); + bool restoreState(QHeaderView* header) const; + + void saveState(const QToolBar* toolbar); + bool restoreState(QToolBar* toolbar) const; + + void saveState(const QSplitter* splitter); + bool restoreState(QSplitter* splitter) const; + std::optional getMenubarVisible() const; void setMenubarVisible(bool b); @@ -61,6 +79,7 @@ public: void setStatusbarVisible(bool b); std::optional getFiltersVisible() const; + void setFiltersVisible(bool b); QStringList getModInfoTabOrder() const; void setModInfoTabOrder(const QString& names); @@ -73,10 +92,9 @@ public: std::optional getDockSize(const QString& name) const; - std::optional isCategoryListVisible() const; - private: QSettings& m_Settings; + bool m_Reset; }; @@ -210,23 +228,6 @@ public: GeometrySettings& geometry(); const GeometrySettings& geometry() const; - - void saveGeometry(const QWidget* w); - bool restoreGeometry(QWidget* w) const; - - void saveState(const QMainWindow* window); - bool restoreState(QMainWindow* window) const; - - void saveState(const QHeaderView* header); - bool restoreState(QHeaderView* header) const; - - void saveState(const QToolBar* toolbar); - bool restoreState(QToolBar* toolbar) const; - - void saveState(const QSplitter* splitter); - bool restoreState(QSplitter* splitter) const; - - /** * retrieve the directory where profiles stored (with native separators) **/ diff --git a/src/settingsdialog.cpp b/src/settingsdialog.cpp index fbd9ecd1..d74507c9 100644 --- a/src/settingsdialog.cpp +++ b/src/settingsdialog.cpp @@ -34,7 +34,6 @@ SettingsDialog::SettingsDialog(PluginContainer *pluginContainer, Settings* setti , ui(new Ui::SettingsDialog) , m_settings(settings) , m_PluginContainer(pluginContainer) - , m_GeometriesReset(false) , m_keyChanged(false) { ui->setupUi(this); @@ -101,10 +100,7 @@ int SettingsDialog::exec() if (getApiKeyChanged()) { restartNeeded = true; } - if (getResetGeometries()) { - restartNeeded = true; - qsettings.setValue("reset_geometry", true); - } + if (restartNeeded) { if (QMessageBox::question(nullptr, tr("Restart Mod Organizer?"), @@ -156,11 +152,6 @@ void SettingsDialog::accept() TutorableDialog::accept(); } -bool SettingsDialog::getResetGeometries() -{ - return ui->resetGeometryBtn->isChecked(); -} - bool SettingsDialog::getApiKeyChanged() { return m_keyChanged; diff --git a/src/settingsdialog.h b/src/settingsdialog.h index 03bba7cf..efc4a095 100644 --- a/src/settingsdialog.h +++ b/src/settingsdialog.h @@ -71,7 +71,6 @@ public: // temp Ui::SettingsDialog *ui; bool m_keyChanged; - bool m_GeometriesReset; PluginContainer *m_PluginContainer; int exec() override; @@ -81,7 +80,6 @@ public slots: public: bool getApiKeyChanged(); - bool getResetGeometries(); private: Settings* m_settings; diff --git a/src/settingsdialog.ui b/src/settingsdialog.ui index e011542e..e7676387 100644 --- a/src/settingsdialog.ui +++ b/src/settingsdialog.ui @@ -1233,9 +1233,6 @@ programs you are intentionally running. Reset Window Geometries - - true - diff --git a/src/settingsdialogworkarounds.cpp b/src/settingsdialogworkarounds.cpp index 9ac46ac1..fc859289 100644 --- a/src/settingsdialogworkarounds.cpp +++ b/src/settingsdialogworkarounds.cpp @@ -26,8 +26,6 @@ WorkaroundsSettingsTab::WorkaroundsSettingsTab(Settings *m_parent, SettingsDialo ui->lockGUIBox->setChecked(m_parent->lockGUI()); ui->enableArchiveParsingBox->setChecked(m_parent->archiveParsing()); - ui->resetGeometryBtn->setChecked(m_parent->directInterface().value("reset_geometry", false).toBool()); - setExecutableBlacklist(m_parent->executablesBlacklist()); QObject::connect(ui->bsaDateBtn, &QPushButton::clicked, [&]{ on_bsaDateBtn_clicked(); }); @@ -89,6 +87,16 @@ void WorkaroundsSettingsTab::on_bsaDateBtn_clicked() void WorkaroundsSettingsTab::on_resetGeometryBtn_clicked() { - m_dialog.m_GeometriesReset = true; - ui->resetGeometryBtn->setChecked(true); + const auto caption = QObject::tr("Restart Mod Organizer?"); + const auto text = QObject::tr( + "In order to reset the geometry, Mod Organizer must be restarted.\n" + "Restart now?"); + + const auto res = QMessageBox::question( + nullptr, caption, text, QMessageBox::Yes | QMessageBox::Cancel); + + if (res == QMessageBox::Yes) { + m_parent->geometry().requestReset(); + qApp->exit(INT_MAX); + } } -- cgit v1.3.1 From 0374291a3451c464fb27e53077da42ad21c27cd6 Mon Sep 17 00:00:00 2001 From: isanae <14251494+isanae@users.noreply.github.com> Date: Fri, 16 Aug 2019 09:00:31 -0400 Subject: StatusBar now inherits from QStatusBar to handle hide/show events merged settings into saveVisibility() and restoreVisibility() call MainWindow::storeSettings() earlier so widget visibility is still valid --- src/iuserinterface.h | 5 - src/main.cpp | 2 - src/mainwindow.cpp | 78 +- src/mainwindow.h | 15 +- src/mainwindow.ui | 2129 +++++++++++++++++++++++++------------------------ src/organizercore.cpp | 4 - src/settings.cpp | 96 +-- src/settings.h | 13 +- src/statusbar.cpp | 65 +- src/statusbar.h | 14 +- 10 files changed, 1200 insertions(+), 1221 deletions(-) (limited to 'src/main.cpp') diff --git a/src/iuserinterface.h b/src/iuserinterface.h index 7205f982..a309ed9b 100644 --- a/src/iuserinterface.h +++ b/src/iuserinterface.h @@ -10,14 +10,9 @@ #include -class Settings; - class IUserInterface { public: - - virtual void storeSettings(Settings &settings) = 0; - virtual void registerPluginTool(MOBase::IPluginTool *tool, QString name = QString(), QMenu *menu = nullptr) = 0; virtual void registerPluginTools(std::vector toolPlugins) = 0; virtual void registerModPage(MOBase::IPluginModPage *modPage) = 0; diff --git a/src/main.cpp b/src/main.cpp index 6d4108fa..aa781c19 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -736,8 +736,6 @@ int runApplication(MOApplication &application, SingleInstance &instance, // this must be before readSettings(), see DockFixer in mainwindow.cpp splash.finish(&mainWindow); - mainWindow.readSettings(settings); - log::debug("displaying main window"); mainWindow.show(); mainWindow.activateWindow(); diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 28e1de2e..7e471d24 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -285,8 +285,6 @@ MainWindow::MainWindow(Settings &settings : QMainWindow(parent) , ui(new Ui::MainWindow) , m_WasVisible(false) - , m_menuBarVisible(true) - , m_statusBarVisible(true) , m_linksSeparator(nullptr) , m_Tutorial(this, "MainWindow") , m_OldProfileIndex(-1) @@ -312,7 +310,7 @@ MainWindow::MainWindow(Settings &settings QWebEngineProfile::defaultProfile()->setPersistentStoragePath(settings.getCacheDirectory()); ui->setupUi(this); - m_statusBar.reset(new StatusBar(statusBar(), ui)); + ui->statusBar->setup(ui); { auto* ni = NexusInterface::instance(&m_PluginContainer); @@ -336,7 +334,7 @@ MainWindow::MainWindow(Settings &settings // in the rare case where the user restarts MO through the settings, this // will correctly pick up the previous values updateWindowTitle(ni->getAPIUserAccount()); - m_statusBar->setAPI(ni->getAPIStats(), ni->getAPIUserAccount()); + ui->statusBar->setAPI(ni->getAPIStats(), ni->getAPIUserAccount()); } languageChange(settings.language()); @@ -708,7 +706,7 @@ void MainWindow::updateWindowTitle(const APIUserAccount& user) void MainWindow::onRequestsChanged(const APIStats& stats, const APIUserAccount& user) { - m_statusBar->setAPI(stats, user); + ui->statusBar->setAPI(stats, user); } @@ -902,7 +900,7 @@ QMenu* MainWindow::createPopupMenu() void MainWindow::on_actionMainMenuToggle_triggered() { - showMenuBar(!ui->menuBar->isVisible()); + ui->menuBar->setVisible(!ui->menuBar->isVisible()); } void MainWindow::on_actionToolBarMainToggle_triggered() @@ -912,7 +910,7 @@ void MainWindow::on_actionToolBarMainToggle_triggered() void MainWindow::on_actionStatusBarToggle_triggered() { - showStatusBar(!ui->statusBar->isVisible()); + ui->statusBar->setVisible(!ui->statusBar->isVisible()); } void MainWindow::on_actionToolBarSmallIcons_triggered() @@ -964,36 +962,6 @@ void MainWindow::setToolbarButtonStyle(Qt::ToolButtonStyle s) } } -void MainWindow::showMenuBar(bool b) -{ - ui->menuBar->setVisible(b); - m_menuBarVisible = b; -} - -void MainWindow::showStatusBar(bool b) -{ - ui->statusBar->setVisible(b); - m_statusBarVisible = b; - - // the central widget typically has no bottom padding because the status bar - // is more than enough, but when it's hidden, the bottom widget (currently - // the log) touches the bottom border of the window, which looks ugly - // - // when hiding the statusbar, the central widget is given the same border - // margin as it has on the top (which is typically 6, as it's the default from - // the qt designer) - - auto m = ui->centralWidget->layout()->contentsMargins(); - - if (b) { - m.setBottom(0); - } else { - m.setBottom(m.top()); - } - - ui->centralWidget->layout()->setContentsMargins(m); -} - void MainWindow::on_centralWidget_customContextMenuRequested(const QPoint &pos) { // this allows for getting the context menu even if both the menubar and all @@ -1075,8 +1043,8 @@ void MainWindow::updateProblemsButton() } // updating the status bar, may be null very early when MO is starting - if (m_statusBar) { - m_statusBar->setNotifications(numProblems > 0); + if (ui->statusBar) { + ui->statusBar->setNotifications(numProblems > 0); } } @@ -1319,6 +1287,8 @@ void MainWindow::hookUpWindowTutorials() void MainWindow::showEvent(QShowEvent *event) { + readSettings(m_OrganizerCore.settings()); + refreshFilters(); QMainWindow::showEvent(event); @@ -1378,7 +1348,10 @@ void MainWindow::closeEvent(QCloseEvent* event) { if (!confirmExit()) { event->ignore(); + return; } + + storeSettings(m_OrganizerCore.settings()); } bool MainWindow::confirmExit() @@ -2259,17 +2232,12 @@ void MainWindow::readSettings(const Settings& settings) settings.geometry().restoreState(this); settings.geometry().restoreToolbars(this); settings.geometry().restoreState(ui->splitter); - - if (auto v=settings.geometry().getMenubarVisible()) { - showMenuBar(*v); - } - - if (auto v=settings.geometry().getStatusbarVisible()) { - showStatusBar(*v); - } + settings.geometry().restoreVisibility(ui->menuBar); + settings.geometry().restoreVisibility(ui->statusBar); { - auto v = settings.geometry().getFiltersVisible().value_or(false); + settings.geometry().restoreVisibility(ui->categoriesGroup, false); + const auto v = ui->categoriesGroup->isVisible(); setCategoryListVisible(v); ui->displayCategoriesBtn->setChecked(v); } @@ -2339,12 +2307,12 @@ void MainWindow::storeSettings(Settings& s) { s.geometry().saveState(this); s.geometry().saveGeometry(this); - s.geometry().setMenubarVisible(m_menuBarVisible); + s.geometry().saveVisibility(ui->menuBar); + s.geometry().saveVisibility(ui->statusBar); s.geometry().saveToolbars(this); - s.geometry().setStatusbarVisible(m_statusBarVisible); s.geometry().saveState(ui->splitter); s.geometry().saveMainWindowMonitor(this); - s.geometry().setFiltersVisible(ui->displayCategoriesBtn->isChecked()); + s.geometry().saveVisibility(ui->categoriesGroup); s.geometry().saveState(ui->espList->header()); s.geometry().saveState(ui->dataTree->header()); @@ -2606,7 +2574,7 @@ void MainWindow::setESPListSorting(int index) void MainWindow::refresher_progress(int percent) { setEnabled(percent == 100); - m_statusBar->setProgress(percent); + ui->statusBar->setProgress(percent); } void MainWindow::directory_refreshed() @@ -5216,7 +5184,7 @@ void MainWindow::on_actionSettings_triggered() activateProxy(settings.useProxy()); } - m_statusBar->checkSettings(m_OrganizerCore.settings()); + ui->statusBar->checkSettings(m_OrganizerCore.settings()); updateDownloadView(); m_OrganizerCore.setLogLevel(settings.logLevel()); @@ -5525,7 +5493,7 @@ void MainWindow::updateAvailable() { ui->actionUpdate->setEnabled(true); ui->actionUpdate->setToolTip(tr("Update available")); - m_statusBar->setUpdateAvailable(true); + ui->statusBar->setUpdateAvailable(true); } @@ -6858,7 +6826,7 @@ void MainWindow::keyReleaseEvent(QKeyEvent *event) // if the menubar is hidden, pressing Alt will make it visible if (event->key() == Qt::Key_Alt) { if (!ui->menuBar->isVisible()) { - showMenuBar(true); + ui->menuBar->show(); } } diff --git a/src/mainwindow.h b/src/mainwindow.h index 8542dc8a..a905a163 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -40,7 +40,6 @@ class Executable; class CategoryFactory; class LockedDialogBase; class OrganizerCore; -class StatusBar; class PluginListSortProxy; namespace BSA { class Archive; } @@ -118,8 +117,6 @@ public: QWidget *parent = 0); ~MainWindow(); - void storeSettings(Settings& settings) override; - void readSettings(const Settings& settings); void processUpdates(Settings& settings); virtual ILockedWaitingForProcess* lock() override; @@ -331,12 +328,6 @@ private: bool m_WasVisible; - // this has to be remembered because by the time storeSettings() is called, - // the window is closed and the all bars are hidden - bool m_menuBarVisible, m_statusBarVisible; - - std::unique_ptr m_statusBar; - // last separator on the toolbar, used to add spacer for right-alignment and // as an insert point for executables QAction* m_linksSeparator; @@ -685,11 +676,9 @@ private slots: // ui slots void on_categoriesOrBtn_toggled(bool checked); void on_managedArchiveLabel_linkHovered(const QString &link); + void storeSettings(Settings& settings); + void readSettings(const Settings& settings); void setupModList(); - void showMenuBar(bool b); - void showStatusBar(bool b); }; - - #endif // MAINWINDOW_H diff --git a/src/mainwindow.ui b/src/mainwindow.ui index e9910b83..02c6dec0 100644 --- a/src/mainwindow.ui +++ b/src/mainwindow.ui @@ -48,1239 +48,1239 @@ - + + + - - - - - Categories - - - + + + Categories + + + + 0 + + + 3 + + + 7 + + + 3 + + + 1 + + + + + + 120 + 0 + + + + + 214 + 16777215 + + + + Qt::CustomContextMenu + + + QAbstractItemView::ExtendedSelection + + 0 - - 3 + + true - - 7 + + false + + + + 1 + + + + + + + + false - - 3 + + + 0 + 0 + - - 1 + + + 0 + 25 + - - - - - 120 - 0 - - - - - 214 - 16777215 - - - - Qt::CustomContextMenu - - - QAbstractItemView::ExtendedSelection - - - 0 - - - true - - - false - - - - 1 - - - - - - - - false - - - - 0 - 0 - - - - - 0 - 25 - - - - Clear - - - true - - - - - - - - 0 - 0 - - - - - - - If checked, only mods that match all selected categories are displayed. - - - And - - - true - - - - - - - If checked, all mods that match at least one of the selected categories are displayed. - - - Or - - - - - - - - - - - - - - - - 0 - 0 - - - - Qt::Horizontal - - - - - 2 - - - - - - - - 0 - 0 - - - - Profile - - - profileBox - - - - - - - Pick a module collection - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Create profiles here. Each profile contains its own list of active mods and esps. This way you can quickly switch between setups for different playthroughs.</span></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Please note that right now your esp load order is not kept separate for different profiles.</span></p></body></html> - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - 16777215 - 16777215 - - - - Open list options... - - - Refresh list. This is usually not necessary unless you modified data outside the program. - - - - - - - :/MO/gui/settings:/MO/gui/settings - - - - 16 - 16 - - - - - - - - Show Open Folders menu... - - - - - - - :/MO/gui/open_folder:/MO/gui/open_folder - - - + + Clear + + + true + + + + + + + + 0 + 0 + + + - + - Restore Backup... + If checked, only mods that match all selected categories are displayed. - + And - - - :/MO/gui/restore:/MO/gui/restore + + true - + - Create Backup - - - - - - - :/MO/gui/backup:/MO/gui/backup + If checked, all mods that match at least one of the selected categories are displayed. - - - - - Active: - - - - - - - - 0 - 26 - - - - This provides statistics about the mod list. The total number of active mod is normally displayed. Other statistics may be accessed with the tooltip of this counter. - - - QFrame::Sunken - - - 5 - - - QLCDNumber::Flat + Or + + + + + + + + + + + + 0 + 0 + + + + Qt::Horizontal + + + + + 2 + + + + + + + + 0 + 0 + + + + Profile + + + profileBox + + - - + + + Pick a module collection + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Create profiles here. Each profile contains its own list of active mods and esps. This way you can quickly switch between setups for different playthroughs.</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Please note that right now your esp load order is not kept separate for different profiles.</span></p></body></html> + + + + + + + Qt::Horizontal + + - 330 - 400 + 40 + 20 - - Qt::CustomContextMenu + + + + + + + 16777215 + 16777215 + - List of available mods. + Open list options... - This is a list of installed mods. Use the checkboxes to activate/deactivate mods and drag & drop mods to change their "installation" orders. + Refresh list. This is usually not necessary unless you modified data outside the program. - + + + + + + :/MO/gui/settings:/MO/gui/settings + + + + 16 + 16 + + + + + + + + Show Open Folders menu... + + + + + + + :/MO/gui/open_folder:/MO/gui/open_folder + + + + + + + Restore Backup... + + - - QAbstractItemView::EditKeyPressed|QAbstractItemView::SelectedClicked + + + :/MO/gui/restore:/MO/gui/restore - - true + + + + + + Create Backup - - true + + - - QAbstractItemView::DragDrop + + + :/MO/gui/backup:/MO/gui/backup - - Qt::MoveAction + + + + + + Active: - - true + + + + + + + 0 + 26 + - - QAbstractItemView::ExtendedSelection + + This provides statistics about the mod list. The total number of active mod is normally displayed. Other statistics may be accessed with the tooltip of this counter. - - QAbstractItemView::SelectRows + + QFrame::Sunken - - 20 + + 5 - - true + + QLCDNumber::Flat - - true + + + + + + + + + 330 + 400 + + + + Qt::CustomContextMenu + + + List of available mods. + + + This is a list of installed mods. Use the checkboxes to activate/deactivate mods and drag & drop mods to change their "installation" orders. + + + + + + QAbstractItemView::EditKeyPressed|QAbstractItemView::SelectedClicked + + + true + + + true + + + QAbstractItemView::DragDrop + + + Qt::MoveAction + + + true + + + QAbstractItemView::ExtendedSelection + + + QAbstractItemView::SelectRows + + + 20 + + + true + + + true + + + true + + + false + + + 35 + + + true + + + false + + + + + + + + + + 20 + 16777215 + - - true + + x - - false + + + 20 + 20 + - - 35 - - + true - - + + + + + + + + 0 + 0 + + + + Filter + + + + + + + + 8 + true + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + 0 + + + + + 0 + 22 + + + + + 95 + 0 + + + false - + + + Qt::RightToLeft + + + border:1px solid #ff0000; + + + Clear all Filters + + + + :/MO/gui/edit_clear:/MO/gui/edit_clear + + + + 12 + 12 + + - - - - - - 20 - 16777215 - - - - x - - - - 20 - 20 - - - - true - - - - - - - - 0 - 0 - - - - Filter - - - - - - - - 8 - true - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - 0 - 0 - - - - - 0 - 22 - - - - - 95 - 0 - - - - false - - - Qt::RightToLeft - - - border:1px solid #ff0000; - - - Clear all Filters - - - - :/MO/gui/edit_clear:/MO/gui/edit_clear - - - - 12 - 12 - - - + + + + 220 + 0 + + + + Qt::ClickFocus + + + + No groups + - - - - 220 - 0 - - - - Qt::ClickFocus - - - - No groups - - - - - Categories - - - - - Nexus IDs - - - + + Categories + - - - - 220 - 0 - - - - Filter - - + + Nexus IDs + - + - - - - - - + + + + 220 + 0 + + + + Filter + + + + + + + + + + + + + + + + + 0 + 0 + + + + + 0 + 40 + + + + + 9 + 75 + true + + + + Pick a program to run. + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Choose the program to run. Once you start using ModOrganizer, you should always run your game and tools from here or through shortcuts created here, otherwise mods installed through MO will not be visible.</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">You can add new Tools to this list, but I can't promise tools I haven't tested will work.</span></p></body></html> + + + + 32 + 32 + + + + false + + + + + - + - + 0 0 - 0 - 40 + 120 + 0 + + + + + 16777215 + 16777215 - 9 + 10 75 true - Pick a program to run. + Run program <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Choose the program to run. Once you start using ModOrganizer, you should always run your game and tools from here or through shortcuts created here, otherwise mods installed through MO will not be visible.</span></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">You can add new Tools to this list, but I can't promise tools I haven't tested will work.</span></p></body></html> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Run the selected program with ModOrganizer enabled.</span></p></body></html> + + + + + + Run + + + + :/MO/gui/run:/MO/gui/run - 32 - 32 + 36 + 36 - - false - - - - - - - 0 - 0 - - - - - 120 - 0 - - - - - 16777215 - 16777215 - - - - - 10 - 75 - true - - - - Run program - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Run the selected program with ModOrganizer enabled.</span></p></body></html> - - - - - - Run - - - - :/MO/gui/run:/MO/gui/run - - - - 36 - 36 - - - - - - - - - 0 - 0 - - - - - 140 - 0 - - - - - 16777215 - 16777215 - - - - - 0 - 0 - - - - Create a shortcut in your start menu or on the desktop to the specified program - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> + + + + 0 + 0 + + + + + 140 + 0 + + + + + 16777215 + 16777215 + + + + + 0 + 0 + + + + Create a shortcut in your start menu or on the desktop to the specified program + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">This creates a start menu shortcut that directly starts the selected program with the MO active.</span></p></body></html> - - - Shortcut - - - - :/MO/gui/link:/MO/gui/link - - - - + + + Shortcut + + + + :/MO/gui/link:/MO/gui/link + + - - - - - - - 340 - 250 - - - - - 16777215 - 16777215 - + + + + + + + + + 340 + 250 + + + + + 16777215 + 16777215 + + + + Qt::NoContextMenu + + + QTabWidget::Rounded + + + 0 + + + + + 0 + 0 + + + + + 16777215 + 16777215 + + + + Plugins + + + + 6 - - Qt::NoContextMenu + + 6 - - QTabWidget::Rounded + + 6 - + 0 - - - - 0 - 0 - - - - - 16777215 - 16777215 - - - - Plugins - - - - 6 + + + + + + true + + + Sort + + + + :/MO/gui/sort:/MO/gui/sort + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Restore Backup... + + + + + + + :/MO/gui/restore:/MO/gui/restore + + + + 16 + 16 + + + + + + + + Create Backup + + + + + + + :/MO/gui/backup:/MO/gui/backup + + + + + + + Active: + + + + + + + + 0 + 26 + + + + This provides statistics about the plugin list. The total number of active plugins is normally displayed. Other statistics may be accessed with the tooltip of this counter. + + + QFrame::Sunken + + + 4 + + + QLCDNumber::Flat + + + + + + + + + + 250 + 250 + + + + Qt::CustomContextMenu + + + List of available esp/esm files + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">This list contains the esps, esms, and esls contained in the active mods. These require their own load order. Use drag&amp;drop to modify this load order. Please note that MO will only save the load order for mods that are active/checked.<br />There is a great tool named &quot;BOSS&quot; to automatically sort these files.</span></p></body></html> + + + QAbstractItemView::EditKeyPressed|QAbstractItemView::SelectedClicked + + + true + + + false + + + QAbstractItemView::InternalMove + + + Qt::MoveAction + + + true + + + QAbstractItemView::ExtendedSelection + + + QAbstractItemView::SelectRows + + + 0 + + + true - - 6 + + false - - 6 + + true - - 0 + + false + + false + + + + + - - - - - true - - - Sort - - - - :/MO/gui/sort:/MO/gui/sort - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Restore Backup... - - - - - - - :/MO/gui/restore:/MO/gui/restore - - - - 16 - 16 - - - - - - - - Create Backup - - - - - - - :/MO/gui/backup:/MO/gui/backup - - - - - - - Active: - - - - - - - - 0 - 26 - - - - This provides statistics about the plugin list. The total number of active plugins is normally displayed. Other statistics may be accessed with the tooltip of this counter. - - - QFrame::Sunken - - - 4 - - - QLCDNumber::Flat - - - - - - - - - - 250 - 250 - + + + - - Qt::CustomContextMenu + + Filter + + + + + + + + + false + + + Archives + + + + 6 + + + 6 + + + 6 + + + 6 + + + + + - List of available esp/esm files - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">This list contains the esps, esms, and esls contained in the active mods. These require their own load order. Use drag&amp;drop to modify this load order. Please note that MO will only save the load order for mods that are active/checked.<br />There is a great tool named &quot;BOSS&quot; to automatically sort these files.</span></p></body></html> - - - QAbstractItemView::EditKeyPressed|QAbstractItemView::SelectedClicked - - - true - - - false - - - QAbstractItemView::InternalMove - - - Qt::MoveAction - - - true - - - QAbstractItemView::ExtendedSelection - - - QAbstractItemView::SelectRows - - - 0 - - - true + <html><head/><body><p>BSAs / BA2s are bundles of game assets (textures, scripts, etc.). By default, the engine loads these bundles in a separate step from loose files. <p>Their load order is specified by the priority of the corresponding plugin (right pane, plugins tab).</p><p>If there is a matching plugin, the game will load them no matter what.</p></body></html> - - false + + <html><head/><body><p>Currently detected archives. (<a href="#"><span style=" text-decoration: underline; color:#0000ff;">What is an archive?</span></a>)</p></body></html> - + true - - false - - - false - - - - - - - - - - Filter - - - - - - - - - false - - - Archives - - - - 6 + + + + + Qt::CustomContextMenu - - 6 + + List of available BS Archives. Archives not checked here are not managed by MO and ignore installation order. - - 6 + + BSA files are archives (comparable to .zip files) that contain data assets (meshes, textures, ...) to be used by the game. As such they "compete" with loose files in your data directory over which is loaded. + By default, BSAs that share their base name with an enabled ESP (i.e. plugin.esp and plugin.bsa) are automatically loaded and will have precedence over all loose files, the installation order you set up to the left is then ignored! + + BSAs checked here are loaded in such a way that your installation order is obeyed properly. - - 6 + + false + + false + + + false + + + 20 + + + true + + + 1 + + + + + + + + Data + + + + 6 + + + 6 + + + 6 + + + 6 + + + + + refresh data-directory overview + + + Refresh the overview. This may take a moment. + + + Refresh + + + + :/MO/gui/resources/view-refresh.png:/MO/gui/resources/view-refresh.png + + + + + - - - - - <html><head/><body><p>BSAs / BA2s are bundles of game assets (textures, scripts, etc.). By default, the engine loads these bundles in a separate step from loose files. <p>Their load order is specified by the priority of the corresponding plugin (right pane, plugins tab).</p><p>If there is a matching plugin, the game will load them no matter what.</p></body></html> - - - <html><head/><body><p>Currently detected archives. (<a href="#"><span style=" text-decoration: underline; color:#0000ff;">What is an archive?</span></a>)</p></body></html> - - - true - - - - - - - + Qt::CustomContextMenu - - List of available BS Archives. Archives not checked here are not managed by MO and ignore installation order. - - BSA files are archives (comparable to .zip files) that contain data assets (meshes, textures, ...) to be used by the game. As such they "compete" with loose files in your data directory over which is loaded. - By default, BSAs that share their base name with an enabled ESP (i.e. plugin.esp and plugin.bsa) are automatically loaded and will have precedence over all loose files, the installation order you set up to the left is then ignored! - - BSAs checked here are loaded in such a way that your installation order is obeyed properly. - - - false - - - false - - - false + This is an overview of your data directory as visible to the game (and tools). - - 20 - - + true - - 1 + + true + + 400 + + + + File + + + + + Mod + + - - - - Data - - - - 6 - - - 6 - - - 6 - - - 6 - + + + - + - refresh data-directory overview + Filters the above list so that only conflicts are displayed. - Refresh the overview. This may take a moment. + Filters the above list so that only conflicts are displayed. - Refresh - - - - :/MO/gui/resources/view-refresh.png:/MO/gui/resources/view-refresh.png + Show only conflicts - - - - - Qt::CustomContextMenu - - - This is an overview of your data directory as visible to the game (and tools). - - - true - - - true - - - 400 - - - - File - - - - - Mod - - - - - - - - - - - - Filters the above list so that only conflicts are displayed. - - - Filters the above list so that only conflicts are displayed. - - - Show only conflicts - - - - - - - Filters the above list so that files from archives are not shown - - - - - - Filters the above list so that files from archives are not shown - - - Show files from Archives - - - - + + + Filters the above list so that files from archives are not shown + + + + + + Filters the above list so that files from archives are not shown + + + Show files from Archives + + - - - - Saves - - - - 6 + + + + + + Saves + + + + 6 + + + 6 + + + 6 + + + 6 + + + + + Qt::CustomContextMenu + + + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">This is a list of all save games for this game. Hover over a list entry to get detailed information about the save including a list of esps/esms that were used at the time this save was created but aren't active now.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:8pt;"></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">If you click &quot;Fix Mods...&quot; in the context menu, MO will try to activate all mods and esps to fix those missing esps. It will not disable anything!</span></p></body></html> + + + QAbstractItemView::ExtendedSelection + + + QAbstractItemView::SelectRows - - 6 + + + + + + + Downloads + + + + 2 + + + 2 + + + 2 + + + 2 + + + + + Refresh downloads view - - 6 + + Refresh - - 6 + + + :/MO/gui/resources/view-refresh.png:/MO/gui/resources/view-refresh.png + + + + - + + + + 320 + 0 + + Qt::CustomContextMenu + + true + - + - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">This is a list of all save games for this game. Hover over a list entry to get detailed information about the save including a list of esps/esms that were used at the time this save was created but aren't active now.</span></p> -<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:8pt;"></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">If you click &quot;Fix Mods...&quot; in the context menu, MO will try to activate all mods and esps to fix those missing esps. It will not disable anything!</span></p></body></html> + This is a list of mods you downloaded from Nexus. Double click one to install it. You can also drag an archive into here. + + + Qt::ScrollBarAlwaysOn + + + true + + + QAbstractItemView::DragDrop + + + Qt::MoveAction + + + true + + + QAbstractItemView::ScrollPerPixel + + + 0 - - QAbstractItemView::ExtendedSelection + + false - - QAbstractItemView::SelectRows + + true - - - - Downloads - - - - 2 - - - 2 - - - 2 - - - 2 - + + + - - - Refresh downloads view - + - Refresh - - - - :/MO/gui/resources/view-refresh.png:/MO/gui/resources/view-refresh.png + Show Hidden - - - - - - 320 - 0 - - - - Qt::CustomContextMenu - - - true - - - - - - This is a list of mods you downloaded from Nexus. Double click one to install it. You can also drag an archive into here. - - - Qt::ScrollBarAlwaysOn - - - true - - - QAbstractItemView::DragDrop - - - Qt::MoveAction - - - true - - - QAbstractItemView::ScrollPerPixel - - - 0 - - - false - - - true - - - - + + + Qt::Horizontal + + + + 40 + 20 + + + - - - - - Show Hidden - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Filter - - - - + + + Filter + + - - - - - - - - + + + + + + + + + + @@ -1320,7 +1320,7 @@ p, li { white-space: pre-wrap; } - + @@ -1790,6 +1790,11 @@ p, li { white-space: pre-wrap; } QTreeView
loglist.h
+ + StatusBar + QStatusBar +
statusbar.h
+
diff --git a/src/organizercore.cpp b/src/organizercore.cpp index 2d11dafd..a2b0fd69 100644 --- a/src/organizercore.cpp +++ b/src/organizercore.cpp @@ -335,10 +335,6 @@ OrganizerCore::~OrganizerCore() void OrganizerCore::storeSettings() { - if (m_UserInterface != nullptr) { - m_UserInterface->storeSettings(m_Settings); - } - if (m_CurrentProfile != nullptr) { m_Settings.setSelectedProfileName(m_CurrentProfile->name()); } diff --git a/src/settings.cpp b/src/settings.cpp index db6cecdf..06b4446a 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -942,6 +942,12 @@ QString stateSettingName(const Widget* widget) return "geometry/" + widgetName(widget) + "_state"; } +template +QString visibilitySettingName(const Widget* widget) +{ + return "geometry/" + widgetName(widget) + "_visibility"; +} + GeometrySettings::GeometrySettings(QSettings& s) : m_Settings(s), m_Reset(false) @@ -962,18 +968,6 @@ void GeometrySettings::resetIfNeeded() m_Settings.beginGroup("geometry"); m_Settings.remove(""); m_Settings.endGroup(); - - /*settings.remove("window_geometry"); - settings.remove("window_state"); - settings.remove("toolbar_size"); - settings.remove("toolbar_button_style"); - settings.remove("menubar_visible"); - settings.remove("window_split"); - settings.remove("window_monitor"); - settings.remove("filters_visible"); - settings.remove("browser_geometry"); - settings.remove("geometry"); - settings.remove("reset_geometry");*/ } void GeometrySettings::saveGeometry(const QWidget* w) @@ -1036,15 +1030,32 @@ bool GeometrySettings::restoreState(QSplitter* w) const return false; } -bool GeometrySettings::restoreToolbars(QMainWindow* w) const +void GeometrySettings::saveVisibility(const QWidget* w) { - const auto size = getOptional(m_Settings, "toolbar_size"); - const auto style = getOptional(m_Settings, "toolbar_button_style"); + m_Settings.setValue(visibilitySettingName(w), w->isVisible()); +} - if (!size && !style) { - return false; +bool GeometrySettings::restoreVisibility(QWidget* w, std::optional def) const +{ + auto v = getOptional(m_Settings, visibilitySettingName(w)); + if (!v) { + v = def; + } + + if (v) { + w->setVisible(*v); + return true; } + return false; +} + +void GeometrySettings::restoreToolbars(QMainWindow* w) const +{ + // all toolbars have the same size and button style settings + const auto size = getOptional(m_Settings, "toolbar_size"); + const auto style = getOptional(m_Settings, "toolbar_button_style"); + for (auto* tb : w->findChildren()) { if (size) { tb->setIconSize(*size); @@ -1053,53 +1064,28 @@ bool GeometrySettings::restoreToolbars(QMainWindow* w) const if (style) { tb->setToolButtonStyle(static_cast(*style)); } - } - return true; + restoreVisibility(tb); + } } void GeometrySettings::saveToolbars(const QMainWindow* w) { - // all toolbars are identical, just save the first one const auto tbs = w->findChildren(); - if (tbs.isEmpty()) { - return; - } - - const auto* tb = tbs[0]; - - m_Settings.setValue("toolbar_size", tb->iconSize()); - m_Settings.setValue("toolbar_button_style", static_cast(tb->toolButtonStyle())); -} - -std::optional GeometrySettings::getMenubarVisible() const -{ - return getOptional(m_Settings, "menubar_visible"); -} - -void GeometrySettings::setMenubarVisible(bool b) -{ - m_Settings.setValue("menubar_visible", b); -} - -std::optional GeometrySettings::getStatusbarVisible() const -{ - return getOptional(m_Settings, "statusbar_visible"); -} -void GeometrySettings::setStatusbarVisible(bool b) -{ - m_Settings.setValue("statusbar_visible", b); -} + // save visibility for all + for (auto* tb : tbs) { + saveVisibility(tb); + } -std::optional GeometrySettings::getFiltersVisible() const -{ - return getOptional(m_Settings, "filters_visible"); -} + // all toolbars have the same size and button style settings, just save the + // first one + if (!tbs.isEmpty()) { + const auto* tb = tbs[0]; -void GeometrySettings::setFiltersVisible(bool b) -{ - m_Settings.setValue("filters_visible", b); + m_Settings.setValue("toolbar_size", tb->iconSize()); + m_Settings.setValue("toolbar_button_style", static_cast(tb->toolButtonStyle())); + } } QStringList GeometrySettings::getModInfoTabOrder() const diff --git a/src/settings.h b/src/settings.h index 9ae58803..072b4066 100644 --- a/src/settings.h +++ b/src/settings.h @@ -54,6 +54,7 @@ public: void requestReset(); void resetIfNeeded(); + void saveGeometry(const QWidget* w); bool restoreGeometry(QWidget* w) const; @@ -69,17 +70,13 @@ public: void saveState(const QSplitter* splitter); bool restoreState(QSplitter* splitter) const; - std::optional getMenubarVisible() const; - void setMenubarVisible(bool b); - bool restoreToolbars(QMainWindow* w) const; - void saveToolbars(const QMainWindow* w); + void saveVisibility(const QWidget* w); + bool restoreVisibility(QWidget* w, std::optional defaultValue={}) const; - std::optional getStatusbarVisible() const; - void setStatusbarVisible(bool b); - std::optional getFiltersVisible() const; - void setFiltersVisible(bool b); + void saveToolbars(const QMainWindow* w); + void restoreToolbars(QMainWindow* w) const; QStringList getModInfoTabOrder() const; void setModInfoTabOrder(const QString& names); diff --git a/src/statusbar.cpp b/src/statusbar.cpp index e9a6e658..d22010a5 100644 --- a/src/statusbar.cpp +++ b/src/statusbar.cpp @@ -3,26 +3,32 @@ #include "settings.h" #include "ui_mainwindow.h" -StatusBar::StatusBar(QStatusBar* bar, Ui::MainWindow* ui) : - m_bar(bar), m_progress(new QProgressBar), - m_notifications(new StatusBarAction(ui->actionNotifications)), - m_update(new StatusBarAction(ui->actionUpdate)), - m_api(new QLabel) +StatusBar::StatusBar(QWidget* parent) : + QStatusBar(parent), ui(nullptr), m_progress(new QProgressBar), + m_notifications(nullptr), m_update(nullptr), m_api(new QLabel) { +} + +void StatusBar::setup(Ui::MainWindow* mainWindowUI) +{ + ui = mainWindowUI; + m_notifications = new StatusBarAction(ui->actionNotifications); + m_update = new StatusBarAction(ui->actionUpdate); + QWidget* spacer1 = new QWidget; spacer1->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); spacer1->setHidden(true); spacer1->setVisible(true); - m_bar->addPermanentWidget(spacer1, 0); - m_bar->addPermanentWidget(m_progress); + addPermanentWidget(spacer1, 0); + addPermanentWidget(m_progress); QWidget* spacer2 = new QWidget; spacer2->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); spacer2->setHidden(true); spacer2->setVisible(true); - m_bar->addPermanentWidget(spacer2,0); - m_bar->addPermanentWidget(m_notifications); - m_bar->addPermanentWidget(m_update); - m_bar->addPermanentWidget(m_api); + addPermanentWidget(spacer2,0); + addPermanentWidget(m_notifications); + addPermanentWidget(m_update); + addPermanentWidget(m_api); m_progress->setTextVisible(true); @@ -42,7 +48,7 @@ StatusBar::StatusBar(QStatusBar* bar, Ui::MainWindow* ui) : "be unable to queue downloads, check updates, parse mod info, or even log " "in. Both pools must be consumed before this happens.")); - m_bar->clearMessage(); + clearMessage(); setProgress(-1); setAPI({}, {}); } @@ -50,10 +56,10 @@ StatusBar::StatusBar(QStatusBar* bar, Ui::MainWindow* ui) : void StatusBar::setProgress(int percent) { if (percent < 0 || percent >= 100) { - m_bar->clearMessage(); + clearMessage(); m_progress->setVisible(false); } else { - m_bar->showMessage(QObject::tr("Loading...")); + showMessage(QObject::tr("Loading...")); m_progress->setVisible(true); m_progress->setValue(percent); } @@ -126,6 +132,37 @@ void StatusBar::checkSettings(const Settings& settings) m_api->setVisible(!settings.hideAPICounter()); } +void StatusBar::showEvent(QShowEvent*) +{ + visibilityChanged(true); +} + +void StatusBar::hideEvent(QHideEvent*) +{ + visibilityChanged(false); +} + +void StatusBar::visibilityChanged(bool visible) +{ + // the central widget typically has no bottom padding because the status bar + // is more than enough, but when it's hidden, the bottom widget (currently + // the log) touches the bottom border of the window, which looks ugly + // + // when hiding the statusbar, the central widget is given the same border + // margin as it has on the top (which is typically 6, as it's the default from + // the qt designer) + + auto m = ui->centralWidget->layout()->contentsMargins(); + + if (visible) { + m.setBottom(0); + } else { + m.setBottom(m.top()); + } + + ui->centralWidget->layout()->setContentsMargins(m); +} + StatusBarAction::StatusBarAction(QAction* action) : m_action(action), m_icon(new QLabel), m_text(new QLabel) diff --git a/src/statusbar.h b/src/statusbar.h index 2baf12ee..442b9acf 100644 --- a/src/statusbar.h +++ b/src/statusbar.h @@ -29,10 +29,12 @@ private: }; -class StatusBar +class StatusBar : public QStatusBar { public: - StatusBar(QStatusBar* bar, Ui::MainWindow* ui); + StatusBar(QWidget* parent=nullptr); + + void setup(Ui::MainWindow* ui); void setProgress(int percent); void setNotifications(bool hasNotifications); @@ -40,12 +42,18 @@ public: void setUpdateAvailable(bool b); void checkSettings(const Settings& settings); +protected: + void showEvent(QShowEvent* e); + void hideEvent(QHideEvent* e); + private: - QStatusBar* m_bar; + Ui::MainWindow* ui; QProgressBar* m_progress; StatusBarAction* m_notifications; StatusBarAction* m_update; QLabel* m_api; + + void visibilityChanged(bool visible); }; #endif // MO_STATUSBAR_H -- cgit v1.3.1 From e9dba260cb9548dd5863ac66da18c295f6499b92 Mon Sep 17 00:00:00 2001 From: isanae <14251494+isanae@users.noreply.github.com> Date: Mon, 2 Sep 2019 14:52:02 -0400 Subject: split settings into a bunch of classes removed "get" from the getters that had it --- src/browserdialog.cpp | 2 +- src/downloadlistsortproxy.cpp | 2 +- src/downloadmanager.cpp | 2 +- src/executableslist.cpp | 2 +- src/filedialogmemory.cpp | 4 +- src/main.cpp | 26 +- src/mainwindow.cpp | 121 +-- src/modinfodialog.cpp | 2 +- src/modinfodialogconflicts.cpp | 16 +- src/modinfodialogimages.cpp | 4 +- src/modinfodialognexus.cpp | 2 +- src/modinfooverwrite.cpp | 2 +- src/modinforegular.cpp | 2 +- src/modlist.cpp | 8 +- src/nxmaccessmanager.cpp | 2 +- src/organizercore.cpp | 112 +- src/pluginlist.cpp | 2 +- src/profile.cpp | 8 +- src/profilesdialog.cpp | 4 +- src/settings.cpp | 2075 ++++++++++++++++++++----------------- src/settings.h | 569 ++++++---- src/settingsdialog.cpp | 6 +- src/settingsdialogdiagnostics.cpp | 13 +- src/settingsdialoggeneral.cpp | 28 +- src/settingsdialognexus.cpp | 32 +- src/settingsdialogpaths.cpp | 52 +- src/settingsdialogsteam.cpp | 4 +- src/settingsdialogworkarounds.cpp | 30 +- src/statusbar.cpp | 2 +- src/usvfsconnector.cpp | 4 +- 30 files changed, 1712 insertions(+), 1426 deletions(-) (limited to 'src/main.cpp') diff --git a/src/browserdialog.cpp b/src/browserdialog.cpp index 70da0b9c..72cb8862 100644 --- a/src/browserdialog.cpp +++ b/src/browserdialog.cpp @@ -49,7 +49,7 @@ BrowserDialog::BrowserDialog(QWidget *parent) ui->setupUi(this); m_AccessManager->setCookieJar(new PersistentCookieJar( - QDir::fromNativeSeparators(Settings::instance().getCacheDirectory() + "/cookies.dat"))); + QDir::fromNativeSeparators(Settings::instance().paths().cache() + "/cookies.dat"))); Qt::WindowFlags flags = windowFlags() | Qt::WindowMaximizeButtonHint | Qt::WindowMinimizeButtonHint; Qt::WindowFlags helpFlag = Qt::WindowContextHelpButtonHint; diff --git a/src/downloadlistsortproxy.cpp b/src/downloadlistsortproxy.cpp index 7bda139b..a69993c0 100644 --- a/src/downloadlistsortproxy.cpp +++ b/src/downloadlistsortproxy.cpp @@ -110,7 +110,7 @@ bool DownloadListSortProxy::filterAcceptsRow(int sourceRow, const QModelIndex&) if (m_CurrentFilter.length() == 0) { return true; } else if (sourceRow < m_Manager->numTotalDownloads()) { - QString displayedName = Settings::instance().metaDownloads() + QString displayedName = Settings::instance().interface().metaDownloads() ? m_Manager->getDisplayName(sourceRow) : m_Manager->getFileName(sourceRow); return displayedName.contains(m_CurrentFilter, Qt::CaseInsensitive); diff --git a/src/downloadmanager.cpp b/src/downloadmanager.cpp index a5dc164c..56238ef3 100644 --- a/src/downloadmanager.cpp +++ b/src/downloadmanager.cpp @@ -1731,7 +1731,7 @@ void DownloadManager::nxmDownloadURLsAvailable(QString gameName, int modID, int return; } - const auto servers = m_OrganizerCore->settings().getServers(); + const auto servers = m_OrganizerCore->settings().network().servers(); std::sort( resultList.begin(), diff --git a/src/executableslist.cpp b/src/executableslist.cpp index f2df2d6d..dce9181b 100644 --- a/src/executableslist.cpp +++ b/src/executableslist.cpp @@ -75,7 +75,7 @@ void ExecutablesList::load(const MOBase::IPluginGame* game, const Settings& s) // executables from 2.2.0, see upgradeFromCustom() bool needsUpgrade = false; - for (auto& map : s.getExecutables()) { + for (auto& map : s.executables()) { Executable::Flags flags; if (map["toolbar"].toBool()) diff --git a/src/filedialogmemory.cpp b/src/filedialogmemory.cpp index 96587ac7..8cfeb6b5 100644 --- a/src/filedialogmemory.cpp +++ b/src/filedialogmemory.cpp @@ -25,12 +25,12 @@ static std::map g_Cache; void FileDialogMemory::save(Settings& s) { - s.setRecentDirectories(g_Cache); + s.paths().setRecent(g_Cache); } void FileDialogMemory::restore(const Settings& s) { - g_Cache = s.getRecentDirectories(); + g_Cache = s.paths().recent(); } QString FileDialogMemory::getOpenFileName( diff --git a/src/main.cpp b/src/main.cpp index aa781c19..b5568fec 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -246,7 +246,7 @@ static bool HaveWriteAccess(const std::wstring &path) QString determineProfile(QStringList &arguments, const Settings &settings) { - auto selectedProfileName = settings.getSelectedProfileName(); + auto selectedProfileName = settings.game().selectedProfileName(); { // see if there is a profile on the command line int profileIndex = arguments.indexOf("-p", 1); @@ -271,12 +271,12 @@ QString determineProfile(QStringList &arguments, const Settings &settings) MOBase::IPluginGame *selectGame( Settings &settings, QDir const &gamePath, MOBase::IPluginGame *game) { - settings.setManagedGameName(game->gameName()); + settings.game().setName(game->gameName()); QString gameDir = gamePath.absolutePath(); game->setGamePath(gameDir); - settings.setManagedGameDirectory(gameDir); + settings.game().setDirectory(gameDir); return game; } @@ -289,7 +289,7 @@ MOBase::IPluginGame *determineCurrentGame( //user has done something odd. //If the game name has been set up, try to use that. - const auto gameName = settings.getManagedGameName(); + const auto gameName = settings.game().name(); const bool gameConfigured = (gameName.has_value() && *gameName != ""); if (gameConfigured) { @@ -299,7 +299,7 @@ MOBase::IPluginGame *determineCurrentGame( return nullptr; } - auto gamePath = settings.getManagedGameDirectory(); + auto gamePath = settings.game().directory(); if (!gamePath || *gamePath == "") { gamePath = game->gameDirectory().absolutePath(); } @@ -320,7 +320,7 @@ MOBase::IPluginGame *determineCurrentGame( //If we've made it this far and the instance is already configured for a game, something has gone wrong. //Tell the user about it. if (gameConfigured) { - const auto gamePath = settings.getManagedGameDirectory(); + const auto gamePath = settings.game().directory(); reportError( QObject::tr("Could not use configuration settings for game \"%1\", path \"%2\".") @@ -570,11 +570,11 @@ int runApplication(MOApplication &application, SingleInstance &instance, log::info("working directory: {}", QDir::currentPath()); Settings settings(dataPath + "/" + QString::fromStdWString(AppConfig::iniFileName())); - log::getDefault().setLevel(settings.logLevel()); + log::getDefault().setLevel(settings.diagnostics().logLevel()); // global crashDumpType sits in OrganizerCore to make a bit less ugly to // update it when the settings are changed during runtime - OrganizerCore::setGlobalCrashDumpsType(settings.crashDumpsType()); + OrganizerCore::setGlobalCrashDumpsType(settings.diagnostics().crashDumpsType()); env::Environment env; @@ -621,7 +621,7 @@ int runApplication(MOApplication &application, SingleInstance &instance, QString edition; - if (auto v=settings.getManagedGameEdition()) { + if (auto v=settings.game().edition()) { edition = *v; } else { QStringList editions = game->gameVariants(); @@ -640,7 +640,7 @@ int runApplication(MOApplication &application, SingleInstance &instance, return 1; } else { edition = selection.getChoiceString(); - settings.setManagedGameEdition(edition); + settings.game().setEdition(edition); } } } @@ -702,7 +702,7 @@ int runApplication(MOApplication &application, SingleInstance &instance, splash.activateWindow(); QString apiKey; - if (settings.getNexusApiKey(apiKey)) { + if (settings.nexus().apiKey(apiKey)) { NexusInterface::instance(&pluginContainer)->getAccessManager()->apiCheck(apiKey); } @@ -712,9 +712,9 @@ int runApplication(MOApplication &application, SingleInstance &instance, + QString::fromStdWString(AppConfig::tutorialsPath()) + "/", &organizer); - if (!application.setStyleFile(settings.getStyleName().value_or(""))) { + if (!application.setStyleFile(settings.interface().styleName().value_or(""))) { // disable invalid stylesheet - settings.setStyleName(""); + settings.interface().setStyleName(""); } int res = 1; diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 42b19cb7..657c1a27 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -222,8 +222,8 @@ MainWindow::MainWindow(Settings &settings { QWebEngineProfile::defaultProfile()->setPersistentCookiesPolicy(QWebEngineProfile::NoPersistentCookies); QWebEngineProfile::defaultProfile()->setHttpCacheMaximumSize(52428800); - QWebEngineProfile::defaultProfile()->setCachePath(settings.getCacheDirectory()); - QWebEngineProfile::defaultProfile()->setPersistentStoragePath(settings.getCacheDirectory()); + QWebEngineProfile::defaultProfile()->setCachePath(settings.paths().cache()); + QWebEngineProfile::defaultProfile()->setPersistentStoragePath(settings.paths().cache()); ui->setupUi(this); ui->statusBar->setup(ui); @@ -253,7 +253,7 @@ MainWindow::MainWindow(Settings &settings ui->statusBar->setAPI(ni->getAPIStats(), ni->getAPIUserAccount()); } - languageChange(settings.language()); + languageChange(settings.interface().language()); m_CategoryFactory.loadCategories(); @@ -1194,7 +1194,7 @@ void MainWindow::hookUpWindowTutorials() QString firstLine = QString::fromUtf8(file.readLine()); if (firstLine.startsWith("//WIN")) { QString windowName = firstLine.mid(6).trimmed(); - if (!m_OrganizerCore.settings().isTutorialCompleted(windowName)) { + if (!m_OrganizerCore.settings().interface().isTutorialCompleted(windowName)) { TutorialManager::instance().activateTutorial(windowName, fileName); } } @@ -1225,7 +1225,7 @@ void MainWindow::showEvent(QShowEvent *event) hookUpWindowTutorials(); - if (m_OrganizerCore.settings().getFirstStart()) { + if (m_OrganizerCore.settings().firstStart()) { QString firstStepsTutorial = ToQString(AppConfig::firstStepsTutorial()); if (TutorialManager::instance().hasTutorial(firstStepsTutorial)) { if (QMessageBox::question(this, tr("Show tutorial?"), @@ -1247,11 +1247,11 @@ void MainWindow::showEvent(QShowEvent *event) m_OrganizerCore.settings().setFirstStart(false); } - m_OrganizerCore.settings().restoreIndex(ui->groupCombo); + m_OrganizerCore.settings().widgets().restoreIndex(ui->groupCombo); allowListResize(); - m_OrganizerCore.settings().registerAsNXMHandler(false); + m_OrganizerCore.settings().nexus().registerAsNXMHandler(false); m_WasVisible = true; updateProblemsButton(); } @@ -1751,7 +1751,7 @@ bool MainWindow::refreshProfiles(bool selectProfile) profileBox->clear(); profileBox->addItem(QObject::tr("")); - QDir profilesDir(Settings::instance().getProfileDirectory()); + QDir profilesDir(Settings::instance().paths().profiles()); profilesDir.setFilter(QDir::AllDirs | QDir::NoDotAndDotDot); QDirIterator profileIter(profilesDir); @@ -1990,7 +1990,7 @@ void MainWindow::updateBSAList(const QStringList &defaultArchives, const QString newItem->setFlags(newItem->flags() & ~(Qt::ItemIsDropEnabled | Qt::ItemIsUserCheckable)); newItem->setCheckState(0, (index != -1) ? Qt::Checked : Qt::Unchecked); newItem->setData(0, Qt::UserRole, false); - if (m_OrganizerCore.settings().forceEnableCoreFiles() + if (m_OrganizerCore.settings().game().forceEnableCoreFiles() && defaultArchives.contains(fileInfo.fileName())) { newItem->setCheckState(0, Qt::Checked); newItem->setDisabled(true); @@ -2140,7 +2140,7 @@ void MainWindow::readSettings(const Settings& settings) { // special case in case someone puts 0 in the INI - auto v = settings.getIndex(ui->executablesListBox); + auto v = settings.widgets().index(ui->executablesListBox); if (!v || v == 0) { v = 1; } @@ -2148,7 +2148,7 @@ void MainWindow::readSettings(const Settings& settings) ui->executablesListBox->setCurrentIndex(*v); } - settings.restoreIndex(ui->groupCombo); + settings.widgets().restoreIndex(ui->groupCombo); { settings.geometry().restoreVisibility(ui->categoriesGroup, false); @@ -2157,7 +2157,7 @@ void MainWindow::readSettings(const Settings& settings) ui->displayCategoriesBtn->setChecked(v); } - if (settings.getUseProxy()) { + if (settings.network().useProxy()) { activateProxy(true); } } @@ -2165,12 +2165,12 @@ void MainWindow::readSettings(const Settings& settings) void MainWindow::processUpdates(Settings& settings) { const auto earliest = QVersionNumber::fromString("2.1.2").normalized(); - const auto lastVersion = settings.getVersion().value_or(earliest); + const auto lastVersion = settings.version().value_or(earliest); const auto currentVersion = m_OrganizerCore.getVersion().asQVersionNumber(); settings.processUpdates(currentVersion, lastVersion); - if (!settings.getFirstStart()) { + if (!settings.firstStart()) { if (lastVersion < QVersionNumber(2, 1, 3)) { bool lastHidden = true; for (int i = ModList::COL_GAME; i < ui->modList->model()->columnCount(); ++i) { @@ -2222,8 +2222,8 @@ void MainWindow::storeSettings(Settings& s) s.geometry().saveState(ui->downloadView->header()); s.geometry().saveState(ui->modList->header()); - s.saveIndex(ui->groupCombo); - s.saveIndex(ui->executablesListBox); + s.widgets().saveIndex(ui->groupCombo); + s.widgets().saveIndex(ui->executablesListBox); } ILockedWaitingForProcess* MainWindow::lock() @@ -2751,7 +2751,7 @@ void MainWindow::restoreBackup_clicked() ModInfo::Ptr modInfo = ModInfo::getByIndex(m_ContextRow); if (backupRegEx.indexIn(modInfo->name()) != -1) { QString regName = backupRegEx.cap(1); - QDir modDir(QDir::fromNativeSeparators(m_OrganizerCore.settings().getModDirectory())); + QDir modDir(QDir::fromNativeSeparators(m_OrganizerCore.settings().paths().mods())); if (!modDir.exists(regName) || (QMessageBox::question(this, tr("Overwrite?"), tr("This will replace the existing mod \"%1\". Continue?").arg(regName), @@ -2759,7 +2759,7 @@ void MainWindow::restoreBackup_clicked() if (modDir.exists(regName) && !shellDelete(QStringList(modDir.absoluteFilePath(regName)))) { reportError(tr("failed to remove mod \"%1\"").arg(regName)); } else { - QString destinationPath = QDir::fromNativeSeparators(m_OrganizerCore.settings().getModDirectory()) + "/" + regName; + QString destinationPath = QDir::fromNativeSeparators(m_OrganizerCore.settings().paths().mods()) + "/" + regName; if (!modDir.rename(modInfo->absolutePath(), destinationPath)) { reportError(tr("failed to rename \"%1\" to \"%2\"").arg(modInfo->absolutePath()).arg(destinationPath)); } @@ -3015,7 +3015,7 @@ void MainWindow::untrack_clicked() void MainWindow::windowTutorialFinished(const QString &windowName) { - m_OrganizerCore.settings().setTutorialCompleted(windowName); + m_OrganizerCore.settings().interface().setTutorialCompleted(windowName); } void MainWindow::overwriteClosed(int) @@ -3645,7 +3645,7 @@ void MainWindow::createSeparator_clicked() m_OrganizerCore.modList()->changeModPriority(ModInfo::getIndex(name), newPriority); } - if (auto c=m_OrganizerCore.settings().getPreviousSeparatorColor()) { + if (auto c=m_OrganizerCore.settings().colors().previousSeparatorColor()) { ModInfo::getByIndex(ModInfo::getIndex(name))->setColor(*c); } } @@ -3662,7 +3662,7 @@ void MainWindow::setColor_clicked() if (currentColor.isValid()) { dialog.setCurrentColor(currentColor); } - else if (auto c=settings.getPreviousSeparatorColor()) { + else if (auto c=settings.colors().previousSeparatorColor()) { dialog.setCurrentColor(*c); } @@ -3673,7 +3673,7 @@ void MainWindow::setColor_clicked() if (!currentColor.isValid()) return; - settings.setPreviousSeparatorColor(currentColor); + settings.colors().setPreviousSeparatorColor(currentColor); QItemSelectionModel *selection = ui->modList->selectionModel(); if (selection->hasSelection() && selection->selectedRows().count() > 1) { @@ -3710,7 +3710,7 @@ void MainWindow::resetColor_clicked() modInfo->setColor(color); } - m_OrganizerCore.settings().removePreviousSeparatorColor(); + m_OrganizerCore.settings().colors().removePreviousSeparatorColor(); } void MainWindow::createModFromOverwrite() @@ -4184,7 +4184,7 @@ void MainWindow::checkModsForUpdates() NexusInterface::instance(&m_PluginContainer)->requestTrackingInfo(this, QVariant(), QString()); } else { QString apiKey; - if (m_OrganizerCore.settings().getNexusApiKey(apiKey)) { + if (m_OrganizerCore.settings().nexus().apiKey(apiKey)) { m_OrganizerCore.doAfterLogin([this] () { this->checkModsForUpdates(); }); NexusInterface::instance(&m_PluginContainer)->getAccessManager()->apiCheck(apiKey); } else { @@ -4387,12 +4387,12 @@ void MainWindow::openIniFolder() void MainWindow::openDownloadsFolder() { - shell::ExploreFile(m_OrganizerCore.settings().getDownloadDirectory()); + shell::ExploreFile(m_OrganizerCore.settings().paths().downloads()); } void MainWindow::openModsFolder() { - shell::ExploreFile(m_OrganizerCore.settings().getModDirectory()); + shell::ExploreFile(m_OrganizerCore.settings().paths().mods()); } void MainWindow::openGameFolder() @@ -4758,7 +4758,7 @@ void MainWindow::on_modList_customContextMenuRequested(const QPoint &pos) menu.addSeparator(); - if (info->getNexusID() > 0 && Settings::instance().endorsementIntegration()) { + if (info->getNexusID() > 0 && Settings::instance().nexus().endorsementIntegration()) { switch (info->endorsedState()) { case ModInfo::ENDORSED_TRUE: { menu.addAction(tr("Un-Endorse"), this, SLOT(unendorse_clicked())); @@ -5007,19 +5007,19 @@ void MainWindow::on_actionSettings_triggered() { Settings &settings = m_OrganizerCore.settings(); - QString oldModDirectory(settings.getModDirectory()); - QString oldCacheDirectory(settings.getCacheDirectory()); - QString oldProfilesDirectory(settings.getProfileDirectory()); - QString oldManagedGameDirectory(settings.getManagedGameDirectory().value_or("")); - bool oldDisplayForeign(settings.displayForeign()); - bool proxy = settings.getUseProxy(); + QString oldModDirectory(settings.paths().mods()); + QString oldCacheDirectory(settings.paths().cache()); + QString oldProfilesDirectory(settings.paths().profiles()); + QString oldManagedGameDirectory(settings.game().directory().value_or("")); + bool oldDisplayForeign(settings.interface().displayForeign()); + bool proxy = settings.network().useProxy(); DownloadManager *dlManager = m_OrganizerCore.downloadManager(); SettingsDialog dialog(&m_PluginContainer, settings, this); dialog.exec(); - if (oldManagedGameDirectory != settings.getManagedGameDirectory()) { + if (oldManagedGameDirectory != settings.game().directory()) { QMessageBox::about(this, tr("Restarting MO"), tr("Changing the managed game directory requires restarting MO.\n" "Any pending downloads will be paused.\n\n" @@ -5029,28 +5029,28 @@ void MainWindow::on_actionSettings_triggered() } InstallationManager *instManager = m_OrganizerCore.installationManager(); - instManager->setModsDirectory(settings.getModDirectory()); - instManager->setDownloadDirectory(settings.getDownloadDirectory()); + instManager->setModsDirectory(settings.paths().mods()); + instManager->setDownloadDirectory(settings.paths().downloads()); fixCategories(); refreshFilters(); - if (settings.getProfileDirectory() != oldProfilesDirectory) { + if (settings.paths().profiles() != oldProfilesDirectory) { refreshProfiles(); } - if (dlManager->getOutputDirectory() != settings.getDownloadDirectory()) { + if (dlManager->getOutputDirectory() != settings.paths().downloads()) { if (dlManager->downloadsInProgress()) { MessageDialog::showMessage(tr("Can't change download directory while " "downloads are in progress!"), this); } else { - dlManager->setOutputDirectory(settings.getDownloadDirectory()); + dlManager->setOutputDirectory(settings.paths().downloads()); } } - if ((settings.getModDirectory() != oldModDirectory) - || (settings.displayForeign() != oldDisplayForeign)) { + if ((settings.paths().mods() != oldModDirectory) + || (settings.interface().displayForeign() != oldDisplayForeign)) { m_OrganizerCore.profileRefresh(); } @@ -5075,18 +5075,19 @@ void MainWindow::on_actionSettings_triggered() m_OrganizerCore.refreshLists(); } - if (settings.getCacheDirectory() != oldCacheDirectory) { - NexusInterface::instance(&m_PluginContainer)->setCacheDirectory(settings.getCacheDirectory()); + if (settings.paths().cache() != oldCacheDirectory) { + NexusInterface::instance(&m_PluginContainer)->setCacheDirectory( + settings.paths().cache()); } - if (proxy != settings.getUseProxy()) { - activateProxy(settings.getUseProxy()); + if (proxy != settings.network().useProxy()) { + activateProxy(settings.network().useProxy()); } ui->statusBar->checkSettings(m_OrganizerCore.settings()); updateDownloadView(); - m_OrganizerCore.setLogLevel(settings.logLevel()); + m_OrganizerCore.setLogLevel(settings.diagnostics().logLevel()); m_OrganizerCore.cycleDiagnostics(); toggleMO2EndorseState(); @@ -5402,10 +5403,10 @@ void MainWindow::motdReceived(const QString &motd) // internet connection is faster next time if (m_StartTime.secsTo(QTime::currentTime()) < 5) { uint hash = qHash(motd); - if (hash != m_OrganizerCore.settings().getMotDHash()) { + if (hash != m_OrganizerCore.settings().motdHash()) { MotDDialog dialog(motd); dialog.exec(); - m_OrganizerCore.settings().setMotDHash(hash); + m_OrganizerCore.settings().setMotdHash(hash); } } } @@ -5528,7 +5529,7 @@ void MainWindow::initDownloadView() void MainWindow::updateDownloadView() { // set the view attribute and default row sizes - if (m_OrganizerCore.settings().compactDownloads()) { + if (m_OrganizerCore.settings().interface().compactDownloads()) { ui->downloadView->setProperty("downloadView", "compact"); setStyleSheet("DownloadListWidget::item { padding: 4px 2px; }"); } else { @@ -5541,7 +5542,7 @@ void MainWindow::updateDownloadView() // reapply global stylesheet on the widget level (!) to override the defaults //ui->downloadView->setStyleSheet(styleSheet()); - ui->downloadView->setMetaDisplay(m_OrganizerCore.settings().metaDownloads()); + ui->downloadView->setMetaDisplay(m_OrganizerCore.settings().interface().metaDownloads()); ui->downloadView->style()->unpolish(ui->downloadView); ui->downloadView->style()->polish(ui->downloadView); qobject_cast(ui->downloadView->header())->customResizeSections(); @@ -5554,7 +5555,7 @@ void MainWindow::modUpdateCheck(std::multimap IDs) ModInfo::manualUpdateCheck(&m_PluginContainer, this, IDs); } else { QString apiKey; - if (m_OrganizerCore.settings().getNexusApiKey(apiKey)) { + if (m_OrganizerCore.settings().nexus().apiKey(apiKey)) { m_OrganizerCore.doAfterLogin([=]() { this->modUpdateCheck(IDs); }); NexusInterface::instance(&m_PluginContainer)->getAccessManager()->apiCheck(apiKey); } else @@ -5566,7 +5567,7 @@ void MainWindow::toggleMO2EndorseState() { const auto& s = m_OrganizerCore.settings(); - if (!s.endorsementIntegration()) { + if (!s.nexus().endorsementIntegration()) { ui->actionEndorseMO->setVisible(false); return; } @@ -5576,7 +5577,7 @@ void MainWindow::toggleMO2EndorseState() bool enabled = false; QString text; - switch (s.endorsementState()) + switch (s.nexus().endorsementState()) { case EndorsementState::Accepted: { @@ -5631,9 +5632,9 @@ void MainWindow::nxmEndorsementsAvailable(QVariant userData, QVariant resultData mod->setIsEndorsed(false); } - if (Settings::instance().endorsementIntegration()) { + if (Settings::instance().nexus().endorsementIntegration()) { if (result->first == "skyrimspecialedition" && result->second.first == gamePlugin->nexusModOrganizerID()) { - m_OrganizerCore.settings().setEndorsementState( + m_OrganizerCore.settings().nexus().setEndorsementState( endorsementStateFromString(result->second.second)); toggleMO2EndorseState(); @@ -5642,13 +5643,13 @@ void MainWindow::nxmEndorsementsAvailable(QVariant userData, QVariant resultData } } - if (!searchedMO2NexusGame && Settings::instance().endorsementIntegration()) { + if (!searchedMO2NexusGame && Settings::instance().nexus().endorsementIntegration()) { auto gamePlugin = m_OrganizerCore.getGame("SkyrimSE"); if (gamePlugin) { auto iter = sorted.equal_range(gamePlugin->gameNexusName()); for (auto result = iter.first; result != iter.second; ++result) { if (result->second.first == gamePlugin->nexusModOrganizerID()) { - m_OrganizerCore.settings().setEndorsementState( + m_OrganizerCore.settings().nexus().setEndorsementState( endorsementStateFromString(result->second.second)); toggleMO2EndorseState(); @@ -5862,7 +5863,7 @@ void MainWindow::nxmEndorsementToggled(QString, int, QVariant, QVariant resultDa } } - m_OrganizerCore.settings().setEndorsementState(s); + m_OrganizerCore.settings().nexus().setEndorsementState(s); toggleMO2EndorseState(); if (!disconnect(sender(), SIGNAL(nxmEndorsementToggled(QString, int, QVariant, QVariant, int)), @@ -5901,7 +5902,7 @@ void MainWindow::nxmTrackedModsAvailable(QVariant userData, QVariant resultData, void MainWindow::nxmDownloadURLs(QString, int, int, QVariant, QVariant resultData, int) { - auto servers = m_OrganizerCore.settings().getServers(); + auto servers = m_OrganizerCore.settings().network().servers(); for (const QVariant &var : resultData.toList()) { const QVariantMap map = var.toMap(); @@ -5929,7 +5930,7 @@ void MainWindow::nxmDownloadURLs(QString, int, int, QVariant, QVariant resultDat } } - m_OrganizerCore.settings().updateServers(servers); + m_OrganizerCore.settings().network().updateServers(servers); } diff --git a/src/modinfodialog.cpp b/src/modinfodialog.cpp index f3840230..2178ef34 100644 --- a/src/modinfodialog.cpp +++ b/src/modinfodialog.cpp @@ -381,7 +381,7 @@ void ModInfoDialog::reAddTabs( Q_ASSERT(visibility.size() == m_tabs.size()); // ordered tab names from settings - const auto orderedNames = m_core->settings().geometry().getModInfoTabOrder(); + const auto orderedNames = m_core->settings().geometry().modInfoTabOrder(); // whether the tabs can be sorted; if the object name of a tab widget is not // found in orderedNames, the list cannot be sorted safely diff --git a/src/modinfodialogconflicts.cpp b/src/modinfodialogconflicts.cpp index 7840269d..3a71b405 100644 --- a/src/modinfodialogconflicts.cpp +++ b/src/modinfodialogconflicts.cpp @@ -409,7 +409,7 @@ void ConflictsTab::clear() void ConflictsTab::saveState(Settings& s) { - s.saveIndex(ui->tabConflictsTabs); + s.widgets().saveIndex(ui->tabConflictsTabs); m_general.saveState(s); m_advanced.saveState(s); @@ -417,7 +417,7 @@ void ConflictsTab::saveState(Settings& s) void ConflictsTab::restoreState(const Settings& s) { - s.restoreIndex(ui->tabConflictsTabs, 0); + s.widgets().restoreIndex(ui->tabConflictsTabs, 0); m_general.restoreState(s); m_advanced.restoreState(s); @@ -1014,17 +1014,17 @@ void AdvancedConflictsTab::clear() void AdvancedConflictsTab::saveState(Settings& s) { s.geometry().saveState(ui->conflictsAdvancedList->header()); - s.saveChecked(ui->conflictsAdvancedShowNoConflict); - s.saveChecked(ui->conflictsAdvancedShowAll); - s.saveChecked(ui->conflictsAdvancedShowNearest); + s.widgets().saveChecked(ui->conflictsAdvancedShowNoConflict); + s.widgets().saveChecked(ui->conflictsAdvancedShowAll); + s.widgets().saveChecked(ui->conflictsAdvancedShowNearest); } void AdvancedConflictsTab::restoreState(const Settings& s) { s.geometry().restoreState(ui->conflictsAdvancedList->header()); - s.restoreChecked(ui->conflictsAdvancedShowNoConflict); - s.restoreChecked(ui->conflictsAdvancedShowAll); - s.restoreChecked(ui->conflictsAdvancedShowNearest); + s.widgets().restoreChecked(ui->conflictsAdvancedShowNoConflict); + s.widgets().restoreChecked(ui->conflictsAdvancedShowAll); + s.widgets().restoreChecked(ui->conflictsAdvancedShowNearest); } void AdvancedConflictsTab::update() diff --git a/src/modinfodialogimages.cpp b/src/modinfodialogimages.cpp index 38c12d8a..9d347f57 100644 --- a/src/modinfodialogimages.cpp +++ b/src/modinfodialogimages.cpp @@ -130,13 +130,13 @@ void ImagesTab::update() void ImagesTab::saveState(Settings& s) { - s.saveChecked(ui->imagesShowDDS); + s.widgets().saveChecked(ui->imagesShowDDS); s.geometry().saveState(ui->tabImagesSplitter); } void ImagesTab::restoreState(const Settings& s) { - s.restoreChecked(ui->imagesShowDDS); + s.widgets().restoreChecked(ui->imagesShowDDS); s.geometry().restoreState(ui->tabImagesSplitter); } diff --git a/src/modinfodialognexus.cpp b/src/modinfodialognexus.cpp index 6d28cbe3..95e62328 100644 --- a/src/modinfodialognexus.cpp +++ b/src/modinfodialognexus.cpp @@ -19,7 +19,7 @@ NexusTab::NexusTab(ModInfoDialogTabContext cx) : ModInfoDialogTab(std::move(cx)), m_requestStarted(false), m_loading(false) { ui->modID->setValidator(new QIntValidator(ui->modID)); - ui->endorse->setVisible(core().settings().endorsementIntegration()); + ui->endorse->setVisible(core().settings().nexus().endorsementIntegration()); connect(ui->modID, &QLineEdit::editingFinished, [&]{ onModIDChanged(); }); connect( diff --git a/src/modinfooverwrite.cpp b/src/modinfooverwrite.cpp index 37c8c650..fb110abb 100644 --- a/src/modinfooverwrite.cpp +++ b/src/modinfooverwrite.cpp @@ -23,7 +23,7 @@ bool ModInfoOverwrite::isEmpty() const QString ModInfoOverwrite::absolutePath() const { - return Settings::instance().getOverwriteDirectory(); + return Settings::instance().paths().overwrite(); } std::vector ModInfoOverwrite::getFlags() const diff --git a/src/modinforegular.cpp b/src/modinforegular.cpp index ce29e11e..3cff914a 100644 --- a/src/modinforegular.cpp +++ b/src/modinforegular.cpp @@ -631,7 +631,7 @@ std::vector ModInfoRegular::getFlags() const std::vector result = ModInfoWithConflictInfo::getFlags(); if ((m_NexusID > 0) && (endorsedState() == ENDORSED_FALSE) && - Settings::instance().endorsementIntegration()) { + Settings::instance().nexus().endorsementIntegration()) { result.push_back(ModInfo::FLAG_NOTENDORSED); } if ((m_NexusID > 0) && diff --git a/src/modlist.cpp b/src/modlist.cpp index 94b4a387..6018d3d4 100644 --- a/src/modlist.cpp +++ b/src/modlist.cpp @@ -390,7 +390,7 @@ QVariant ModList::data(const QModelIndex &modelIndex, int role) const return QVariant(); } else if (role == Qt::ForegroundRole) { if (modInfo->hasFlag(ModInfo::FLAG_SEPARATOR) && modInfo->getColor().isValid()) { - return Settings::getIdealTextColor(modInfo->getColor()); + return ColorSettings::idealTextColor(modInfo->getColor()); } else if (column == COL_NAME) { int highlight = modInfo->getHighlight(); if (highlight & ModInfo::HIGHLIGHT_IMPORTANT) @@ -428,7 +428,7 @@ QVariant ModList::data(const QModelIndex &modelIndex, int role) const } else if (modInfo->hasFlag(ModInfo::FLAG_SEPARATOR) && modInfo->getColor().isValid() && ((role != ViewMarkingScrollBar::DEFAULT_ROLE) - || Settings::instance().colorSeparatorScrollbar())) { + || Settings::instance().colors().colorSeparatorScrollbar())) { return modInfo->getColor(); } else { return QVariant(); @@ -999,8 +999,8 @@ bool ModList::dropURLs(const QMimeData *mimeData, int row, const QModelIndex &pa ModInfo::Ptr modInfo = ModInfo::getByIndex(row); QDir modDir = QDir(modInfo->absolutePath()); - QDir allModsDir(Settings::instance().getModDirectory()); - QDir overwriteDir(Settings::instance().getOverwriteDirectory()); + QDir allModsDir(Settings::instance().paths().mods()); + QDir overwriteDir(Settings::instance().paths().overwrite()); QStringList sourceList; QStringList targetList; diff --git a/src/nxmaccessmanager.cpp b/src/nxmaccessmanager.cpp index 16190ca4..c6ef7bc7 100644 --- a/src/nxmaccessmanager.cpp +++ b/src/nxmaccessmanager.cpp @@ -572,7 +572,7 @@ NXMAccessManager::NXMAccessManager(QObject *parent, const QString &moVersion) m_validator.finished = [&](auto&& user){ onValidatorFinished(user); }; setCookieJar(new PersistentCookieJar(QDir::fromNativeSeparators( - Settings::instance().getCacheDirectory() + "/nexus_cookies.dat"))); + Settings::instance().paths().cache() + "/nexus_cookies.dat"))); if (networkAccessible() == QNetworkAccessManager::UnknownAccessibility) { // why is this necessary all of a sudden? diff --git a/src/organizercore.cpp b/src/organizercore.cpp index af0cf969..1a89641d 100644 --- a/src/organizercore.cpp +++ b/src/organizercore.cpp @@ -146,7 +146,7 @@ static void startSteam(QWidget *widget) QStringList args; QString username; QString password; - if (Settings::instance().getSteamLogin(username, password)) { + if (Settings::instance().steam().login(username, password)) { args << "-login"; args << username; if (password != "") { @@ -275,12 +275,13 @@ OrganizerCore::OrganizerCore(Settings &settings) , m_ArchivesInit(false) , m_PluginListsWriter(std::bind(&OrganizerCore::savePluginList, this)) { - m_DownloadManager.setOutputDirectory(m_Settings.getDownloadDirectory()); + m_DownloadManager.setOutputDirectory(m_Settings.paths().downloads()); - NexusInterface::instance(m_PluginContainer)->setCacheDirectory(m_Settings.getCacheDirectory()); + NexusInterface::instance(m_PluginContainer)->setCacheDirectory( + m_Settings.paths().cache()); - m_InstallationManager.setModsDirectory(m_Settings.getModDirectory()); - m_InstallationManager.setDownloadDirectory(m_Settings.getDownloadDirectory()); + m_InstallationManager.setModsDirectory(m_Settings.paths().mods()); + m_InstallationManager.setDownloadDirectory(m_Settings.paths().downloads()); connect(&m_DownloadManager, SIGNAL(downloadSpeed(QString, int)), this, SLOT(downloadSpeed(QString, int))); @@ -333,7 +334,7 @@ OrganizerCore::~OrganizerCore() void OrganizerCore::storeSettings() { if (m_CurrentProfile != nullptr) { - m_Settings.setSelectedProfileName(m_CurrentProfile->name()); + m_Settings.game().setSelectedProfileName(m_CurrentProfile->name()); } m_ExecutablesList.store(m_Settings); @@ -356,7 +357,7 @@ void OrganizerCore::storeSettings() QMessageBox::critical( qApp->activeWindow(), tr("Failed to write settings"), tr("An error occurred trying to write back MO settings to %1: %2") - .arg(m_Settings.getFilename(), reason)); + .arg(m_Settings.filename(), reason)); } } @@ -432,8 +433,9 @@ void OrganizerCore::updateExecutablesList() // TODO this has nothing to do with executables list move to an appropriate // function! - ModInfo::updateFromDisc(m_Settings.getModDirectory(), &m_DirectoryStructure, - m_PluginContainer, m_Settings.displayForeign(), managedGame()); + ModInfo::updateFromDisc( + m_Settings.paths().mods(), &m_DirectoryStructure, + m_PluginContainer, m_Settings.interface().displayForeign(), managedGame()); } void OrganizerCore::setUserInterface(IUserInterface *userInterface, @@ -478,7 +480,7 @@ void OrganizerCore::setUserInterface(IUserInterface *userInterface, if (userInterface != nullptr) { // this currently wouldn't work reliably if the ui isn't initialized yet to // display the result - if (isOnline() && !m_Settings.offlineMode()) { + if (isOnline() && !m_Settings.network().offlineMode()) { m_Updater.testForUpdate(); } else { log::debug("user doesn't seem to be connected to the internet"); @@ -541,7 +543,7 @@ bool OrganizerCore::nexusApi(bool retry) return false; } else { QString apiKey; - if (m_Settings.getNexusApiKey(apiKey)) { + if (m_Settings.nexus().apiKey(apiKey)) { // credentials stored or user entered them manually log::debug("attempt to verify nexus api key"); accessManager->apiCheck(apiKey); @@ -608,7 +610,7 @@ void OrganizerCore::removeOrigin(const QString &name) void OrganizerCore::downloadSpeed(const QString &serverName, int bytesPerSecond) { - m_Settings.setDownloadSpeed(serverName, bytesPerSecond); + m_Settings.network().setDownloadSpeed(serverName, bytesPerSecond); } InstallationManager *OrganizerCore::installationManager() @@ -629,9 +631,9 @@ bool OrganizerCore::createDirectory(const QString &path) { } bool OrganizerCore::checkPathSymlinks() { - bool hasSymlink = (QFileInfo(m_Settings.getProfileDirectory()).isSymLink() || - QFileInfo(m_Settings.getModDirectory()).isSymLink() || - QFileInfo(m_Settings.getOverwriteDirectory()).isSymLink()); + bool hasSymlink = (QFileInfo(m_Settings.paths().profiles()).isSymLink() || + QFileInfo(m_Settings.paths().mods()).isSymLink() || + QFileInfo(m_Settings.paths().overwrite()).isSymLink()); if (hasSymlink) { QMessageBox::critical(nullptr, QObject::tr("Error"), QObject::tr("One of the configured MO2 directories (profiles, mods, or overwrite) " @@ -643,17 +645,17 @@ bool OrganizerCore::checkPathSymlinks() { } bool OrganizerCore::bootstrap() { - return createDirectory(m_Settings.getProfileDirectory()) && - createDirectory(m_Settings.getModDirectory()) && - createDirectory(m_Settings.getDownloadDirectory()) && - createDirectory(m_Settings.getOverwriteDirectory()) && + return createDirectory(m_Settings.paths().profiles()) && + createDirectory(m_Settings.paths().mods()) && + createDirectory(m_Settings.paths().downloads()) && + createDirectory(m_Settings.paths().overwrite()) && createDirectory(QString::fromStdWString(crashDumpsPath())) && checkPathSymlinks() && cycleDiagnostics(); } void OrganizerCore::createDefaultProfile() { - QString profilesPath = settings().getProfileDirectory(); + QString profilesPath = settings().paths().profiles(); if (QDir(profilesPath).entryList(QDir::AllDirs | QDir::NoDotAndDotDot).size() == 0) { Profile newProf("Default", managedGame(), false); @@ -674,18 +676,18 @@ void OrganizerCore::updateVFSParams( void OrganizerCore::setLogLevel(log::Levels level) { - m_Settings.setLogLevel(level); + m_Settings.diagnostics().setLogLevel(level); updateVFSParams( - m_Settings.logLevel(), - m_Settings.crashDumpsType(), + m_Settings.diagnostics().logLevel(), + m_Settings.diagnostics().crashDumpsType(), m_Settings.executablesBlacklist()); - log::getDefault().setLevel(m_Settings.logLevel()); + log::getDefault().setLevel(m_Settings.diagnostics().logLevel()); } bool OrganizerCore::cycleDiagnostics() { - if (int maxDumps = settings().crashDumpsMax()) + if (int maxDumps = settings().diagnostics().crashDumpsMax()) removeOldFiles(QString::fromStdWString(crashDumpsPath()), "*.dmp", maxDumps, QDir::Time|QDir::Reversed); return true; } @@ -720,7 +722,7 @@ void OrganizerCore::setCurrentProfile(const QString &profileName) return; } - QDir profileBaseDir(settings().getProfileDirectory()); + QDir profileBaseDir(settings().paths().profiles()); QString profileDir = profileBaseDir.absoluteFilePath(profileName); if (!QDir(profileDir).exists()) { @@ -744,7 +746,7 @@ void OrganizerCore::setCurrentProfile(const QString &profileName) m_CurrentProfile->deactivateInvalidation(); } - m_Settings.setSelectedProfileName(m_CurrentProfile->name()); + m_Settings.game().setSelectedProfileName(m_CurrentProfile->name()); connect(m_CurrentProfile, SIGNAL(modStatusChanged(uint)), this, SLOT(modStatusChanged(uint))); connect(m_CurrentProfile, SIGNAL(modStatusChanged(QList)), this, SLOT(modStatusChanged(QList))); @@ -776,22 +778,22 @@ QString OrganizerCore::profilePath() const QString OrganizerCore::downloadsPath() const { - return QDir::fromNativeSeparators(m_Settings.getDownloadDirectory()); + return QDir::fromNativeSeparators(m_Settings.paths().downloads()); } QString OrganizerCore::overwritePath() const { - return QDir::fromNativeSeparators(m_Settings.getOverwriteDirectory()); + return QDir::fromNativeSeparators(m_Settings.paths().overwrite()); } QString OrganizerCore::basePath() const { - return QDir::fromNativeSeparators(m_Settings.getBaseDirectory()); + return QDir::fromNativeSeparators(m_Settings.paths().base()); } QString OrganizerCore::modsPath() const { - return QDir::fromNativeSeparators(m_Settings.getModDirectory()); + return QDir::fromNativeSeparators(m_Settings.paths().mods()); } MOBase::VersionInfo OrganizerCore::appVersion() const @@ -821,10 +823,10 @@ MOBase::IModInterface *OrganizerCore::createMod(GuessedValue &name) return nullptr; } - m_InstallationManager.setModsDirectory(m_Settings.getModDirectory()); + m_InstallationManager.setModsDirectory(m_Settings.paths().mods()); QString targetDirectory - = QDir::fromNativeSeparators(m_Settings.getModDirectory()) + = QDir::fromNativeSeparators(m_Settings.paths().mods()) .append("/") .append(name); @@ -912,7 +914,7 @@ MOBase::IModInterface *OrganizerCore::installMod(const QString &fileName, modName.update(initModName, GUESS_USER); } m_CurrentProfile->writeModlistNow(); - m_InstallationManager.setModsDirectory(m_Settings.getModDirectory()); + m_InstallationManager.setModsDirectory(m_Settings.paths().mods()); if (m_InstallationManager.install(fileName, modName, hasIniTweaks)) { MessageDialog::showMessage(tr("Installation successful"), qApp->activeWindow()); @@ -977,7 +979,7 @@ void OrganizerCore::installDownload(int index) m_CurrentProfile->writeModlistNow(); bool hasIniTweaks = false; - m_InstallationManager.setModsDirectory(m_Settings.getModDirectory()); + m_InstallationManager.setModsDirectory(m_Settings.paths().mods()); if (m_InstallationManager.install(fileName, modName, hasIniTweaks)) { MessageDialog::showMessage(tr("Installation successful"), qApp->activeWindow()); @@ -1270,7 +1272,7 @@ bool OrganizerCore::previewFileWithAlternatives( else { // crude: we search for the next slash after the base mod directory to skip // everything up to the data-relative directory - int offset = settings().getModDirectory().size() + 1; + int offset = settings().paths().mods().size() + 1; offset = fileName.indexOf("/", offset); fileName = fileName.mid(offset + 1); } @@ -1412,7 +1414,7 @@ HANDLE OrganizerCore::spawnBinaryDirect(const QFileInfo &binary, LPDWORD exitCode) { HANDLE processHandle = spawnBinaryProcess(binary, arguments, profileName, currentDirectory, steamAppID, customOverwrite, forcedLibraries); - if (Settings::instance().lockGUI() && processHandle != INVALID_HANDLE_VALUE) { + if (Settings::instance().interface().lockGUI() && processHandle != INVALID_HANDLE_VALUE) { std::unique_ptr dlg; ILockedWaitingForProcess* uilock = nullptr; @@ -1461,7 +1463,7 @@ HANDLE OrganizerCore::spawnBinaryProcess(const QFileInfo &binary, ::SetEnvironmentVariableW(L"SteamAPPId", ToWString(steamAppID).c_str()); } else { ::SetEnvironmentVariableW(L"SteamAPPId", - ToWString(m_Settings.getSteamAppID()).c_str()); + ToWString(m_Settings.steam().appID()).c_str()); } QWidget *window = qApp->activeWindow(); @@ -1477,7 +1479,7 @@ HANDLE OrganizerCore::spawnBinaryProcess(const QFileInfo &binary, || QFileInfo(managedGame()->gameDirectory().absoluteFilePath( "steam_api64.dll")) .exists()) - && (m_Settings.getLoadMechanism() == LoadMechanism::LOAD_MODORGANIZER)) { + && (m_Settings.game().loadMechanismType() == LoadMechanism::LOAD_MODORGANIZER)) { bool steamFound = true; bool steamAccess = true; @@ -1592,7 +1594,7 @@ HANDLE OrganizerCore::spawnBinaryProcess(const QFileInfo &binary, } } - QString modsPath = settings().getModDirectory(); + QString modsPath = settings().paths().mods(); // Check if this a request with either an executable or a working directory under our mods folder // then will start the process in a virtualized "environment" with the appropriate paths fixed: @@ -1749,7 +1751,7 @@ HANDLE OrganizerCore::startApplication(const QString &executable, bool OrganizerCore::waitForApplication(HANDLE handle, LPDWORD exitCode) { - if (!Settings::instance().lockGUI()) + if (!Settings::instance().interface().lockGUI()) return true; ILockedWaitingForProcess* uilock = nullptr; @@ -1960,8 +1962,10 @@ void OrganizerCore::refreshModList(bool saveChanges) if (saveChanges) { m_CurrentProfile->writeModlistNow(true); } - ModInfo::updateFromDisc(m_Settings.getModDirectory(), &m_DirectoryStructure, - m_PluginContainer, m_Settings.displayForeign(), managedGame()); + + ModInfo::updateFromDisc( + m_Settings.paths().mods(), &m_DirectoryStructure, + m_PluginContainer, m_Settings.interface().displayForeign(), managedGame()); m_CurrentProfile->refreshModStatus(); @@ -2130,7 +2134,7 @@ void OrganizerCore::updateModsInDirectoryStructure(QMaparchivesWriter().writeImmediately(false); @@ -2156,7 +2160,7 @@ void OrganizerCore::loggedInAction(QWidget* parent, std::function f) f(); } else { QString apiKey; - if (settings().getNexusApiKey(apiKey)) { + if (settings().nexus().apiKey(apiKey)) { doAfterLogin([f]{ f(); }); NexusInterface::instance(m_PluginContainer)->getAccessManager()->apiCheck(apiKey); } else { @@ -2295,8 +2299,10 @@ void OrganizerCore::profileRefresh() { // have to refresh mods twice (again in refreshModList), otherwise the refresh // isn't complete. Not sure why - ModInfo::updateFromDisc(m_Settings.getModDirectory(), &m_DirectoryStructure, - m_PluginContainer, m_Settings.displayForeign(), managedGame()); + ModInfo::updateFromDisc( + m_Settings.paths().mods(), &m_DirectoryStructure, + m_PluginContainer, m_Settings.interface().displayForeign(), managedGame()); + m_CurrentProfile->refreshModStatus(); refreshModList(); @@ -2463,7 +2469,7 @@ void OrganizerCore::syncOverwrite() SyncOverwriteDialog syncDialog(modInfo->absolutePath(), m_DirectoryStructure, qApp->activeWindow()); if (syncDialog.exec() == QDialog::Accepted) { - syncDialog.apply(QDir::fromNativeSeparators(m_Settings.getModDirectory())); + syncDialog.apply(QDir::fromNativeSeparators(m_Settings.paths().mods())); modInfo->testValid(); refreshDirectoryStructure(); } @@ -2486,7 +2492,7 @@ std::vector OrganizerCore::activeProblems() const const auto& hookdll = oldMO1HookDll(); if (!hookdll.isEmpty()) { // This warning will now be shown every time the problems are checked, which is a bit - // of a "log spam". But since this is a sevre error which will most likely make the + // of a "log spam". But since this is a sever error which will most likely make the // game crash/freeze/etc. and is very hard to diagnose, this "log spam" will make it // easier for the user to notice the warning. log::warn("hook.dll found in game folder: {}", hookdll); @@ -2562,7 +2568,7 @@ void OrganizerCore::savePluginList() } m_PluginList.saveTo(m_CurrentProfile->getLockedOrderFileName(), m_CurrentProfile->getDeleterFileName(), - m_Settings.hideUncheckedPlugins()); + m_Settings.game().hideUncheckedPlugins()); m_PluginList.saveLoadOrder(*m_DirectoryStructure); } @@ -2574,7 +2580,7 @@ void OrganizerCore::prepareStart() m_CurrentProfile->writeModlist(); m_CurrentProfile->createTweakedIniFile(); saveCurrentLists(); - m_Settings.setupLoadMechanism(); + m_Settings.game().setupLoadMechanism(); storeSettings(); } @@ -2588,7 +2594,7 @@ std::vector OrganizerCore::fileMapping(const QString &profileName, } IPluginGame *game = qApp->property("managed_game").value(); - Profile profile(QDir(m_Settings.getProfileDirectory() + "/" + profileName), + Profile profile(QDir(m_Settings.paths().profiles() + "/" + profileName), game); MappingType result; @@ -2634,7 +2640,7 @@ std::vector OrganizerCore::fileMapping(const QString &profileName, } result.insert(result.end(), { - QDir::toNativeSeparators(m_Settings.getOverwriteDirectory()), + QDir::toNativeSeparators(m_Settings.paths().overwrite()), dataPath, true, customOverwrite.isEmpty() diff --git a/src/pluginlist.cpp b/src/pluginlist.cpp index ddfe492e..33423225 100644 --- a/src/pluginlist.cpp +++ b/src/pluginlist.cpp @@ -191,7 +191,7 @@ void PluginList::refresh(const QString &profileName continue; } - bool forceEnabled = Settings::instance().forceEnableCoreFiles() && + bool forceEnabled = Settings::instance().game().forceEnableCoreFiles() && primaryPlugins.contains(filename, Qt::CaseInsensitive); //(std::find(primaryPlugins.begin(), primaryPlugins.end(), filename.toLower()) != primaryPlugins.end()); diff --git a/src/profile.cpp b/src/profile.cpp index 7f4ebcaa..e76060b9 100644 --- a/src/profile.cpp +++ b/src/profile.cpp @@ -73,7 +73,7 @@ Profile::Profile(const QString &name, IPluginGame const *gamePlugin, bool useDef : m_ModListWriter(std::bind(&Profile::doWriteModlist, this)) , m_GamePlugin(gamePlugin) { - QString profilesDir = Settings::instance().getProfileDirectory(); + QString profilesDir = Settings::instance().paths().profiles(); QDir profileBase(profilesDir); QString fixedName = name; if (!fixDirectoryName(fixedName)) { @@ -299,7 +299,7 @@ void Profile::createTweakedIniFile() // static void Profile::renameModInAllProfiles(const QString& oldName, const QString& newName) { - QDir profilesDir(Settings::instance().getProfileDirectory()); + QDir profilesDir(Settings::instance().paths().profiles()); profilesDir.setFilter(QDir::AllDirs | QDir::NoDotAndDotDot); QDirIterator profileIter(profilesDir); while (profileIter.hasNext()) { @@ -655,7 +655,7 @@ void Profile::setModPriority(unsigned int index, int &newPriority) Profile *Profile::createPtrFrom(const QString &name, const Profile &reference, MOBase::IPluginGame const *gamePlugin) { - QString profileDirectory = Settings::instance().getProfileDirectory() + "/" + name; + QString profileDirectory = Settings::instance().paths().profiles() + "/" + name; reference.copyFilesTo(profileDirectory); return new Profile(QDir(profileDirectory), gamePlugin); } @@ -906,7 +906,7 @@ QString Profile::savePath() const void Profile::rename(const QString &newName) { - QDir profileDir(Settings::instance().getProfileDirectory()); + QDir profileDir(Settings::instance().paths().profiles()); profileDir.rename(name(), newName); m_Directory.setPath(profileDir.absoluteFilePath(newName)); } diff --git a/src/profilesdialog.cpp b/src/profilesdialog.cpp index 2f1bd059..c91f48f4 100644 --- a/src/profilesdialog.cpp +++ b/src/profilesdialog.cpp @@ -57,7 +57,7 @@ ProfilesDialog::ProfilesDialog(const QString &profileName, MOBase::IPluginGame c { ui->setupUi(this); - QDir profilesDir(Settings::instance().getProfileDirectory()); + QDir profilesDir(Settings::instance().paths().profiles()); profilesDir.setFilter(QDir::AllDirs | QDir::NoDotAndDotDot); QDirIterator profileIter(profilesDir); @@ -203,7 +203,7 @@ void ProfilesDialog::on_removeProfileButton_clicked() if (confirmBox.exec() == QMessageBox::Yes) { QString profilePath; if (profileToDelete.get() == nullptr) { - profilePath = Settings::instance().getProfileDirectory() + profilePath = Settings::instance().paths().profiles() + "/" + ui->profilesList->currentItem()->text(); if (QMessageBox::question(this, tr("Profile broken"), tr("This profile you're about to delete seems to be broken or the path is invalid. " diff --git a/src/settings.cpp b/src/settings.cpp index 71288950..8b063efb 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -150,7 +150,7 @@ std::optional getOptional( template T get( const QSettings& settings, - const QString& section, const QString& key, T def={}) + const QString& section, const QString& key, T def) { if (auto v=getOptional(settings, section, key)) { return *v; @@ -453,22 +453,74 @@ void warnIfNotCheckable(const QAbstractButton* b) } +bool setWindowsCredential(const QString key, const QString data) +{ + QString finalKey("ModOrganizer2_" + key); + wchar_t* keyData = new wchar_t[finalKey.size()+1]; + finalKey.toWCharArray(keyData); + keyData[finalKey.size()] = L'\0'; + bool result = false; + if (data.isEmpty()) { + result = CredDeleteW(keyData, CRED_TYPE_GENERIC, 0); + if (!result) + if (GetLastError() == ERROR_NOT_FOUND) + result = true; + } else { + wchar_t* charData = new wchar_t[data.size()]; + data.toWCharArray(charData); + + CREDENTIALW cred = {}; + cred.Flags = 0; + cred.Type = CRED_TYPE_GENERIC; + cred.TargetName = keyData; + cred.CredentialBlob = (LPBYTE)charData; + cred.CredentialBlobSize = sizeof(wchar_t) * data.size(); + cred.Persist = CRED_PERSIST_LOCAL_MACHINE; + + result = CredWriteW(&cred, 0); + delete[] charData; + } + delete[] keyData; + return result; +} + +QString getWindowsCredential(const QString key) +{ + QString result; + QString finalKey("ModOrganizer2_" + key); + wchar_t* keyData = new wchar_t[finalKey.size()+1]; + finalKey.toWCharArray(keyData); + keyData[finalKey.size()] = L'\0'; + PCREDENTIALW creds; + if (CredReadW(keyData, 1, 0, &creds)) { + wchar_t *charData = (wchar_t *)creds->CredentialBlob; + result = QString::fromWCharArray(charData, creds->CredentialBlobSize / sizeof(wchar_t)); + CredFree(creds); + } else { + const auto e = GetLastError(); + if (e != ERROR_NOT_FOUND) { + log::error("Retrieving encrypted data failed: {}", formatSystemMessage(e)); + } + } + delete[] keyData; + return result; +} + + Settings *Settings::s_Instance = nullptr; Settings::Settings(const QString& path) : m_Settings(path, QSettings::IniFormat), - m_Geometry(m_Settings), m_Colors(m_Settings), m_Plugins(m_Settings) + m_Game(m_Settings), m_Geometry(m_Settings), m_Widgets(m_Settings), + m_Colors(m_Settings), m_Plugins(m_Settings), m_Paths(m_Settings), + m_Network(m_Settings), m_Nexus(*this, m_Settings), m_Steam(*this, m_Settings), + m_Interface(m_Settings), m_Diagnostics(m_Settings) { if (s_Instance != nullptr) { throw std::runtime_error("second instance of \"Settings\" created"); } else { s_Instance = this; } - - MOBase::QuestionBoxMemory::setCallbacks( - [this](auto&& w, auto&& f){ return getQuestionButton(w, f); }, - [this](auto&& w, auto&& b){ setQuestionWindowButton(w, b); }, - [this](auto&& w, auto&& f, auto&& b){ setQuestionFileButton(w, f, b); }); } Settings::~Settings() @@ -488,7 +540,7 @@ Settings &Settings::instance() void Settings::processUpdates( const QVersionNumber& currentVersion, const QVersionNumber& lastVersion) { - if (getFirstStart()) { + if (firstStart()) { return; } @@ -523,1569 +575,1670 @@ void Settings::processUpdates( set(m_Settings, "General", "version", currentVersion.toString()); } -QString Settings::getFilename() const +QString Settings::filename() const { return m_Settings.fileName(); } -void Settings::registerAsNXMHandler(bool force) +bool Settings::usePrereleases() const { - const auto nxmPath = QCoreApplication::applicationDirPath() + "/nxmhandler.exe"; - const auto executable = QCoreApplication::applicationFilePath(); - - QString mode = force ? "forcereg" : "reg"; - QString parameters = mode + " " + m_GamePlugin->gameShortName(); - for (const QString& altGame : m_GamePlugin->validShortNames()) { - parameters += "," + altGame; - } - parameters += " \"" + executable + "\""; - - if (!shell::Execute(nxmPath, parameters)) { - QMessageBox::critical( - nullptr, tr("Failed"), tr("Failed to start the helper application")); - } + return get(m_Settings, "Settings", "use_prereleases", false); } -bool Settings::colorSeparatorScrollbar() const +void Settings::setUsePrereleases(bool b) { - return get(m_Settings, "Settings", "colorSeparatorScrollbars", true); + set(m_Settings, "Settings", "use_prereleases", b); } -void Settings::setColorSeparatorScrollbar(bool b) +std::optional Settings::version() const { - set(m_Settings, "Settings", "colorSeparatorScrollbars", b); + if (auto v=getOptional(m_Settings, "General", "version")) { + return QVersionNumber::fromString(*v).normalized(); + } + + return {}; } -void Settings::managedGameChanged(IPluginGame const *gamePlugin) +bool Settings::firstStart() const { - m_GamePlugin = gamePlugin; + return get(m_Settings, "General", "first_start", true); } -bool Settings::obfuscate(const QString key, const QString data) +void Settings::setFirstStart(bool b) { - QString finalKey("ModOrganizer2_" + key); - wchar_t* keyData = new wchar_t[finalKey.size()+1]; - finalKey.toWCharArray(keyData); - keyData[finalKey.size()] = L'\0'; - bool result = false; - if (data.isEmpty()) { - result = CredDeleteW(keyData, CRED_TYPE_GENERIC, 0); - if (!result) - if (GetLastError() == ERROR_NOT_FOUND) - result = true; - } else { - wchar_t* charData = new wchar_t[data.size()]; - data.toWCharArray(charData); + set(m_Settings, "General", "first_start", b); +} - CREDENTIALW cred = {}; - cred.Flags = 0; - cred.Type = CRED_TYPE_GENERIC; - cred.TargetName = keyData; - cred.CredentialBlob = (LPBYTE)charData; - cred.CredentialBlobSize = sizeof(wchar_t) * data.size(); - cred.Persist = CRED_PERSIST_LOCAL_MACHINE; +QString Settings::executablesBlacklist() const +{ + static const QString def = (QStringList() + << "Chrome.exe" + << "Firefox.exe" + << "TSVNCache.exe" + << "TGitCache.exe" + << "Steam.exe" + << "GameOverlayUI.exe" + << "Discord.exe" + << "GalaxyClient.exe" + << "Spotify.exe" + ).join(";"); - result = CredWriteW(&cred, 0); - delete[] charData; - } - delete[] keyData; - return result; + return get(m_Settings, "Settings", "executable_blacklist", def); } -QString Settings::deObfuscate(const QString key) +void Settings::setExecutablesBlacklist(const QString& s) { - QString result; - QString finalKey("ModOrganizer2_" + key); - wchar_t* keyData = new wchar_t[finalKey.size()+1]; - finalKey.toWCharArray(keyData); - keyData[finalKey.size()] = L'\0'; - PCREDENTIALW creds; - if (CredReadW(keyData, 1, 0, &creds)) { - wchar_t *charData = (wchar_t *)creds->CredentialBlob; - result = QString::fromWCharArray(charData, creds->CredentialBlobSize / sizeof(wchar_t)); - CredFree(creds); - } else { - const auto e = GetLastError(); - if (e != ERROR_NOT_FOUND) { - log::error("Retrieving encrypted data failed: {}", formatSystemMessage(e)); - } - } - delete[] keyData; - return result; + set(m_Settings, "Settings", "executable_blacklist", s); } -QColor Settings::getIdealTextColor(const QColor& rBackgroundColor) +void Settings::setMotdHash(uint hash) { - if (rBackgroundColor.alpha() == 0) - return QColor(Qt::black); - - const int THRESHOLD = 106 * 255.0f / rBackgroundColor.alpha(); - int BackgroundDelta = (rBackgroundColor.red() * 0.299) + (rBackgroundColor.green() * 0.587) + (rBackgroundColor.blue() * 0.114); - return QColor((255 - BackgroundDelta <= THRESHOLD) ? Qt::black : Qt::white); + set(m_Settings, "General", "motd_hash", hash); } - -bool Settings::hideUncheckedPlugins() const +unsigned int Settings::motdHash() const { - return get(m_Settings, "Settings", "hide_unchecked_plugins", false); + return get(m_Settings, "General", "motd_hash", 0); } -void Settings::setHideUncheckedPlugins(bool b) +bool Settings::archiveParsing() const { - set(m_Settings, "Settings", "hide_unchecked_plugins", b); + return get(m_Settings, "Settings", "archive_parsing_experimental", false); } -bool Settings::forceEnableCoreFiles() const +void Settings::setArchiveParsing(bool b) { - return get(m_Settings, "Settings", "force_enable_core_files", true); + set(m_Settings, "Settings", "archive_parsing_experimental", b); } -void Settings::setForceEnableCoreFiles(bool b) +std::vector> Settings::executables() const { - set(m_Settings, "Settings", "force_enable_core_files", b); + ScopedReadArray sra(m_Settings, "customExecutables"); + std::vector> v; + + sra.for_each([&]{ + std::map map; + + for (auto&& key : sra.keys()) { + map[key] = m_Settings.value(key); + } + + v.push_back(map); + }); + + return v; } -bool Settings::lockGUI() const +void Settings::setExecutables(const std::vector>& v) { - return get(m_Settings, "Settings", "lock_gui", true); + removeSection(m_Settings, "customExecutables"); + + ScopedWriteArray swa(m_Settings, "customExecutables"); + + for (const auto& map : v) { + swa.next(); + + for (auto&& p : map) { + swa.set(p.first, p.second); + } + } } -void Settings::setLockGUI(bool b) +bool Settings::keepBackupOnInstall() const { - set(m_Settings, "Settings", "lock_gui", b); + return get(m_Settings, "General", "backup_install", false); } -bool Settings::automaticLoginEnabled() const +void Settings::setKeepBackupOnInstall(bool b) { - return get(m_Settings, "Settings", "nexus_login", false); + set(m_Settings, "General", "backup_install", b); } -QString Settings::getSteamAppID() const +GameSettings& Settings::game() { - return get(m_Settings, "Settings", "app_id", m_GamePlugin->steamAPPId()); + return m_Game; } -void Settings::setSteamAppID(const QString& id) +const GameSettings& Settings::game() const { - if (id.isEmpty()) { - remove(m_Settings, "Settings", "app_id"); - } else { - set(m_Settings, "Settings", "app_id", id); - } + return m_Game; } -bool Settings::usePrereleases() const +GeometrySettings& Settings::geometry() { - return get(m_Settings, "Settings", "use_prereleases", false); + return m_Geometry; } -void Settings::setUsePrereleases(bool b) +const GeometrySettings& Settings::geometry() const { - set(m_Settings, "Settings", "use_prereleases", b); + return m_Geometry; } -QString Settings::getConfigurablePath(const QString &key, - const QString &def, - bool resolve) const +WidgetSettings& Settings::widgets() { - QString result = QDir::fromNativeSeparators( - get(m_Settings, "Settings", key, QString("%BASE_DIR%/") + def)); - - if (resolve) { - result.replace("%BASE_DIR%", getBaseDirectory()); - } - - return result; + return m_Widgets; } -void Settings::setConfigurablePath(const QString &key, const QString& path) +const WidgetSettings& Settings::widgets() const { - if (path.isEmpty()) { - remove(m_Settings, "Settings", key); - } else { - set(m_Settings, "Settings", key, path); - } + return m_Widgets; } -QString Settings::getBaseDirectory() const +ColorSettings& Settings::colors() { - return QDir::fromNativeSeparators(get(m_Settings, - "Settings", "base_directory", qApp->property("dataPath").toString())); + return m_Colors; } -QString Settings::getDownloadDirectory(bool resolve) const +const ColorSettings& Settings::colors() const { - return getConfigurablePath( - "download_directory", - ToQString(AppConfig::downloadPath()), - resolve); + return m_Colors; } -QString Settings::getCacheDirectory(bool resolve) const +PluginSettings& Settings::plugins() { - return getConfigurablePath( - "cache_directory", - ToQString(AppConfig::cachePath()), - resolve); + return m_Plugins; } -QString Settings::getModDirectory(bool resolve) const +const PluginSettings& Settings::plugins() const { - return getConfigurablePath( - "mod_directory", - ToQString(AppConfig::modsPath()), - resolve); + return m_Plugins; } -QString Settings::getProfileDirectory(bool resolve) const +PathSettings& Settings::paths() { - return getConfigurablePath( - "profiles_directory", - ToQString(AppConfig::profilesPath()), - resolve); + return m_Paths; } -QString Settings::getOverwriteDirectory(bool resolve) const +const PathSettings& Settings::paths() const { - return getConfigurablePath( - "overwrite_directory", - ToQString(AppConfig::overwritePath()), - resolve); + return m_Paths; } -void Settings::setBaseDirectory(const QString& path) +NetworkSettings& Settings::network() { - if (path.isEmpty()) { - remove(m_Settings, "Settings", "base_directory"); - } else { - set(m_Settings, "Settings", "base_directory", path); - } + return m_Network; } -void Settings::setDownloadDirectory(const QString& path) +const NetworkSettings& Settings::network() const { - setConfigurablePath("download_directory", path); + return m_Network; } -void Settings::setModDirectory(const QString& path) +NexusSettings& Settings::nexus() { - setConfigurablePath("mod_directory", path); + return m_Nexus; } -void Settings::setCacheDirectory(const QString& path) +const NexusSettings& Settings::nexus() const { - setConfigurablePath("cache_directory", path); + return m_Nexus; } -void Settings::setProfileDirectory(const QString& path) +SteamSettings& Settings::steam() { - setConfigurablePath("profiles_directory", path); + return m_Steam; } -void Settings::setOverwriteDirectory(const QString& path) +const SteamSettings& Settings::steam() const { - setConfigurablePath("overwrite_directory", path); + return m_Steam; } -std::optional Settings::getManagedGameDirectory() const +InterfaceSettings& Settings::interface() { - if (auto v=getOptional(m_Settings, "General", "gamePath")) { - return QString::fromUtf8(*v); - } - - return {}; + return m_Interface; } -void Settings::setManagedGameDirectory(const QString& path) +const InterfaceSettings& Settings::interface() const { - set(m_Settings, "General", "gamePath", QDir::toNativeSeparators(path).toUtf8()); + return m_Interface; } -std::optional Settings::getManagedGameName() const +DiagnosticsSettings& Settings::diagnostics() { - return getOptional(m_Settings, "General", "gameName"); + return m_Diagnostics; } -void Settings::setManagedGameName(const QString& name) +const DiagnosticsSettings& Settings::diagnostics() const { - set(m_Settings, "General", "gameName", name); + return m_Diagnostics; } -std::optional Settings::getManagedGameEdition() const +QSettings::Status Settings::sync() const { - return getOptional(m_Settings, "General", "game_edition"); + m_Settings.sync(); + return m_Settings.status(); } -void Settings::setManagedGameEdition(const QString& name) +void Settings::dump() const { - set(m_Settings, "General", "game_edition", name); -} + static const QStringList ignore({ + "username", "password", "nexus_api_key" + }); -std::optional Settings::getSelectedProfileName() const -{ - if (auto v=getOptional(m_Settings, "General", "selected_profile")) { - return QString::fromUtf8(*v); + log::debug("settings:"); + + { + ScopedGroup sg(m_Settings, "Settings"); + + for (auto k : m_Settings.allKeys()) { + if (ignore.contains(k, Qt::CaseInsensitive)) { + continue; + } + + log::debug(" . {}={}", k, m_Settings.value(k).toString()); + } } - return {}; + m_Network.dump(); } -void Settings::setSelectedProfileName(const QString& name) +void Settings::managedGameChanged(IPluginGame const *gamePlugin) { - set(m_Settings, "General", "selected_profile", name.toUtf8()); + m_Game.setPlugin(gamePlugin); } -std::optional Settings::getStyleName() const + +GameSettings::GameSettings(QSettings& settings) + : m_Settings(settings), m_GamePlugin(nullptr) { - return getOptional(m_Settings, "Settings", "style"); } -void Settings::setStyleName(const QString& name) +const MOBase::IPluginGame* GameSettings::plugin() { - set(m_Settings, "Settings", "style", name); + return m_GamePlugin; } -bool Settings::getUseProxy() const +void GameSettings::setPlugin(const MOBase::IPluginGame* gamePlugin) { - return get(m_Settings, "Settings", "use_proxy", false); + m_GamePlugin = gamePlugin; } -void Settings::setUseProxy(bool b) +bool GameSettings::forceEnableCoreFiles() const { - set(m_Settings, "Settings", "use_proxy", b); + return get(m_Settings, "Settings", "force_enable_core_files", true); } -std::optional Settings::getVersion() const +void GameSettings::setForceEnableCoreFiles(bool b) { - if (auto v=getOptional(m_Settings, "General", "version")) { - return QVersionNumber::fromString(*v).normalized(); - } - - return {}; + set(m_Settings, "Settings", "force_enable_core_files", b); } -bool Settings::getFirstStart() const +std::optional GameSettings::directory() const { - return get(m_Settings, "General", "first_start", true); + if (auto v=getOptional(m_Settings, "General", "gamePath")) { + return QString::fromUtf8(*v); + } + + return {}; } -void Settings::setFirstStart(bool b) +void GameSettings::setDirectory(const QString& path) { - set(m_Settings, "General", "first_start", b); + set(m_Settings, "General", "gamePath", QDir::toNativeSeparators(path).toUtf8()); } -std::optional Settings::getPreviousSeparatorColor() const +std::optional GameSettings::name() const { - const auto c = getOptional(m_Settings, "General", "previousSeparatorColor"); - if (c && c->isValid()) { - return c; - } - - return {}; + return getOptional(m_Settings, "General", "gameName"); } -void Settings::setPreviousSeparatorColor(const QColor& c) const +void GameSettings::setName(const QString& name) { - set(m_Settings, "General", "previousSeparatorColor", c); + set(m_Settings, "General", "gameName", name); } -void Settings::removePreviousSeparatorColor() +std::optional GameSettings::edition() const { - remove(m_Settings, "General", "previousSeparatorColor"); + return getOptional(m_Settings, "General", "game_edition"); } -bool Settings::getNexusApiKey(QString &apiKey) const +void GameSettings::setEdition(const QString& name) { - QString tempKey = deObfuscate("APIKEY"); - if (tempKey.isEmpty()) - return false; - - apiKey = tempKey; - return true; + set(m_Settings, "General", "game_edition", name); } -bool Settings::setNexusApiKey(const QString& apiKey) +std::optional GameSettings::selectedProfileName() const { - if (!obfuscate("APIKEY", apiKey)) { - const auto e = GetLastError(); - log::error("Storing API key failed: {}", formatSystemMessage(e)); - return false; + if (auto v=getOptional(m_Settings, "General", "selected_profile")) { + return QString::fromUtf8(*v); } - return true; + return {}; } -bool Settings::clearNexusApiKey() +void GameSettings::setSelectedProfileName(const QString& name) { - return setNexusApiKey(""); + set(m_Settings, "General", "selected_profile", name.toUtf8()); } -bool Settings::hasNexusApiKey() const +LoadMechanism::EMechanism GameSettings::loadMechanismType() const { - return !deObfuscate("APIKEY").isEmpty(); -} + const auto def = LoadMechanism::LOAD_MODORGANIZER; -bool Settings::getSteamLogin(QString &username, QString &password) const -{ - username = get(m_Settings, "Settings", "steam_username", ""); - password = deObfuscate("steam_password"); + const auto i = get(m_Settings, + "Settings", "load_mechanism", def); - return !username.isEmpty() && !password.isEmpty(); -} + switch (i) + { + // ok + case LoadMechanism::LOAD_MODORGANIZER: // fall-through + { + break; + } -bool Settings::compactDownloads() const -{ - return get(m_Settings, "Settings", "compact_downloads", false); -} + default: + { + log::error( + "invalid load mechanism {}, reverting to {}", + static_cast(i), toString(def)); -void Settings::setCompactDownloads(bool b) -{ - set(m_Settings, "Settings", "compact_downloads", b); -} + set(m_Settings, "Settings", "load_mechanism", def); -bool Settings::metaDownloads() const -{ - return get(m_Settings, "Settings", "meta_downloads", false); -} + return def; + } + } -void Settings::setMetaDownloads(bool b) -{ - set(m_Settings, "Settings", "meta_downloads", b); + return i; } -bool Settings::offlineMode() const +void GameSettings::setLoadMechanism(LoadMechanism::EMechanism m) { - return get(m_Settings, "Settings/offline_mode", false); + set(m_Settings, "Settings", "load_mechanism", m); } -void Settings::setOfflineMode(bool b) +const LoadMechanism& GameSettings::loadMechanism() const { - set(m_Settings, "Settings", "offline_mode", b); + return m_LoadMechanism; } -log::Levels Settings::logLevel() const +void GameSettings::setupLoadMechanism() { - return get(m_Settings, "Settings", "log_level", log::Levels::Info); + m_LoadMechanism.activate(loadMechanismType()); } -void Settings::setLogLevel(log::Levels level) +bool GameSettings::hideUncheckedPlugins() const { - set(m_Settings, "Settings", "log_level", level); + return get(m_Settings, "Settings", "hide_unchecked_plugins", false); } -CrashDumpsType Settings::crashDumpsType() const +void GameSettings::setHideUncheckedPlugins(bool b) { - return get(m_Settings, - "Settings", "crash_dumps_type", CrashDumpsType::Mini); + set(m_Settings, "Settings", "hide_unchecked_plugins", b); } -void Settings::setCrashDumpsType(CrashDumpsType type) -{ - set(m_Settings, "Settings", "crash_dumps_type", type); -} -int Settings::crashDumpsMax() const +GeometrySettings::GeometrySettings(QSettings& s) + : m_Settings(s), m_Reset(false) { - return get(m_Settings, "Settings", "crash_dumps_max", 5); } -void Settings::setCrashDumpsMax(int n) +void GeometrySettings::requestReset() { - set(m_Settings, "Settings", "crash_dumps_max", n); + m_Reset = true; } -QString Settings::executablesBlacklist() const +void GeometrySettings::resetIfNeeded() { - static const QString def = (QStringList() - << "Chrome.exe" - << "Firefox.exe" - << "TSVNCache.exe" - << "TGitCache.exe" - << "Steam.exe" - << "GameOverlayUI.exe" - << "Discord.exe" - << "GalaxyClient.exe" - << "Spotify.exe" - ).join(";"); + if (!m_Reset) { + return; + } - return get(m_Settings, "Settings", "executable_blacklist", def); + removeSection(m_Settings, "Geometry"); } -void Settings::setExecutablesBlacklist(const QString& s) +void GeometrySettings::saveGeometry(const QWidget* w) { - set(m_Settings, "Settings", "executable_blacklist", s); + set(m_Settings, "Geometry", geoSettingName(w), w->saveGeometry()); } -void Settings::setSteamLogin(QString username, QString password) +bool GeometrySettings::restoreGeometry(QWidget* w) const { - if (username == "") { - remove(m_Settings, "Settings", "steam_username"); - password = ""; - } else { - set(m_Settings, "Settings", "steam_username", username); + if (auto v=getOptional(m_Settings, "Geometry", geoSettingName(w))) { + w->restoreGeometry(*v); + return true; } - if (!obfuscate("steam_password", password)) { - const auto e = GetLastError(); - log::error("Storing or deleting password failed: {}", formatSystemMessage(e)); - } + return false; } -LoadMechanism::EMechanism Settings::getLoadMechanism() const +void GeometrySettings::saveState(const QMainWindow* w) { - const auto def = LoadMechanism::LOAD_MODORGANIZER; - - const auto i = get(m_Settings, - "Settings", "load_mechanism", def); - - switch (i) - { - // ok - case LoadMechanism::LOAD_MODORGANIZER: // fall-through - { - break; - } - - default: - { - log::error( - "invalid load mechanism {}, reverting to {}", - static_cast(i), toString(def)); - - set(m_Settings, "Settings", "load_mechanism", def); - - return def; - } - } - - return i; + set(m_Settings, "Geometry", stateSettingName(w), w->saveState()); } -void Settings::setLoadMechanism(LoadMechanism::EMechanism m) +bool GeometrySettings::restoreState(QMainWindow* w) const { - set(m_Settings, "Settings", "load_mechanism", m); -} + if (auto v=getOptional(m_Settings, "Geometry", stateSettingName(w))) { + w->restoreState(*v); + return true; + } -void Settings::setupLoadMechanism() -{ - m_LoadMechanism.activate(getLoadMechanism()); + return false; } -bool Settings::endorsementIntegration() const +void GeometrySettings::saveState(const QHeaderView* w) { - return get(m_Settings, "Settings", "endorsement_integration", true); + set(m_Settings, "Geometry", stateSettingName(w), w->saveState()); } -void Settings::setEndorsementIntegration(bool b) const +bool GeometrySettings::restoreState(QHeaderView* w) const { - set(m_Settings, "Settings", "endorsement_integration", b); + if (auto v=getOptional(m_Settings, "Geometry", stateSettingName(w))) { + w->restoreState(*v); + return true; + } + + return false; } -EndorsementState Settings::endorsementState() const +void GeometrySettings::saveState(const QSplitter* w) { - return endorsementStateFromString( - get(m_Settings, "General", "endorse_state", "")); + set(m_Settings, "Geometry", stateSettingName(w), w->saveState()); } -void Settings::setEndorsementState(EndorsementState s) +bool GeometrySettings::restoreState(QSplitter* w) const { - const auto v = toString(s); - - if (v.isEmpty()) { - remove(m_Settings, "General", "endorse_state"); - } else { - set(m_Settings, "General", "endorse_state", v); + if (auto v=getOptional(m_Settings, "Geometry", stateSettingName(w))) { + w->restoreState(*v); + return true; } -} -bool Settings::hideAPICounter() const -{ - return get(m_Settings, "Settings", "hide_api_counter", false); + return false; } -void Settings::setHideAPICounter(bool b) +void GeometrySettings::saveState(const ExpanderWidget* expander) { - set(m_Settings, "Settings", "hide_api_counter", b); + set(m_Settings, "Geometry", stateSettingName(expander), expander->saveState()); } -bool Settings::displayForeign() const +bool GeometrySettings::restoreState(ExpanderWidget* expander) const { - return get(m_Settings, "Settings", "display_foreign", true); -} + if (auto v=getOptional(m_Settings, "Geometry", stateSettingName(expander))) { + expander->restoreState(*v); + return true; + } -void Settings::setDisplayForeign(bool b) -{ - set(m_Settings, "Settings", "display_foreign", b); + return false; } -void Settings::setMotDHash(uint hash) +void GeometrySettings::saveVisibility(const QWidget* w) { - set(m_Settings, "General", "motd_hash", hash); + set(m_Settings, "Geometry", visibilitySettingName(w), w->isVisible()); } -unsigned int Settings::getMotDHash() const +bool GeometrySettings::restoreVisibility(QWidget* w, std::optional def) const { - return get(m_Settings, "motd_hash", 0); -} + if (auto v=getOptional(m_Settings, "Geometry", visibilitySettingName(w), def)) { + w->setVisible(*v); + return true; + } -bool Settings::archiveParsing() const -{ - return get(m_Settings, "Settings", "archive_parsing_experimental", false); + return false; } -void Settings::setArchiveParsing(bool b) +void GeometrySettings::restoreToolbars(QMainWindow* w) const { - set(m_Settings, "Settings", "archive_parsing_experimental", b); -} + // all toolbars have the same size and button style settings + const auto size = getOptional(m_Settings, "Geometry", "toolbar_size"); + const auto style = getOptional(m_Settings, "Geometry", "toolbar_button_style"); -QString Settings::language() + for (auto* tb : w->findChildren()) { + if (size) { + tb->setIconSize(*size); + } + + if (style) { + tb->setToolButtonStyle(static_cast(*style)); + } + + restoreVisibility(tb); + } +} + +void GeometrySettings::saveToolbars(const QMainWindow* w) { - QString result = get(m_Settings, "Settings", "language", ""); + const auto tbs = w->findChildren(); - if (result.isEmpty()) { - QStringList languagePreferences = QLocale::system().uiLanguages(); + // save visibility for all + for (auto* tb : tbs) { + saveVisibility(tb); + } - if (languagePreferences.length() > 0) { - // the users most favoritest language - result = languagePreferences.at(0); - } else { - // fallback system locale - result = QLocale::system().name(); + // all toolbars have the same size and button style settings, just save the + // first one + if (!tbs.isEmpty()) { + const auto* tb = tbs[0]; + + set(m_Settings, "Geometry", "toolbar_size", tb->iconSize()); + set(m_Settings, "Geometry", "toolbar_button_style", static_cast(tb->toolButtonStyle())); + } +} + +QStringList GeometrySettings::modInfoTabOrder() const +{ + QStringList v; + + if (m_Settings.contains("mod_info_tabs")) { + // old byte array from 2.2.0 + QDataStream stream(m_Settings.value("mod_info_tabs").toByteArray()); + + int count = 0; + stream >> count; + + for (int i=0; i> s; + v.push_back(s); + } + } else { + // string list since 2.2.1 + QString string = m_Settings.value("mod_info_tab_order").toString(); + QTextStream stream(&string); + + while (!stream.atEnd()) { + QString s; + stream >> s; + v.push_back(s); } } - return result; + return v; } -void Settings::setLanguage(const QString& name) +void GeometrySettings::setModInfoTabOrder(const QString& names) { - set(m_Settings, "Settings", "language", name); + set(m_Settings, "Geometry", "mod_info_tab_order", names); } -void Settings::setDownloadSpeed(const QString& name, int bytesPerSecond) +void GeometrySettings::centerOnMainWindowMonitor(QWidget* w) { - auto servers = getServers(); + const auto monitor = getOptional( + m_Settings, "Geometry", "MainWindow_monitor"); - for (auto& server : servers) { - if (server.name() == name) { - server.addDownload(bytesPerSecond); - updateServers(servers); - return; + QPoint center; + + if (monitor && QGuiApplication::screens().size() > *monitor) { + center = QGuiApplication::screens().at(*monitor)->geometry().center(); + } else { + center = QGuiApplication::primaryScreen()->geometry().center(); + } + + w->move(center - w->rect().center()); +} + +void GeometrySettings::saveMainWindowMonitor(const QMainWindow* w) +{ + if (auto* handle=w->windowHandle()) { + if (auto* screen = handle->screen()) { + const int screenId = QGuiApplication::screens().indexOf(screen); + set(m_Settings, "Geometry", "MainWindow_monitor", screenId); } } +} - log::error( - "server '{}' not found while trying to add a download with bps {}", - name, bytesPerSecond); +Qt::Orientation dockOrientation(const QMainWindow* mw, const QDockWidget* d) +{ + // docks in these areas are horizontal + const auto horizontalAreas = + Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea; + + if (mw->dockWidgetArea(const_cast(d)) & horizontalAreas) { + return Qt::Horizontal; + } else { + return Qt::Vertical; + } } -ServerList Settings::getServers() const +void GeometrySettings::saveDocks(const QMainWindow* mw) { - // servers used to be a map of byte arrays until 2.2.1, it's now an array of - // individual values instead + // this attempts to fix https://bugreports.qt.io/browse/QTBUG-46620 where dock + // sizes are not restored when the main window is maximized; it is used in + // MainWindow::readSettings() and MainWindow::storeSettings() + // + // there's also https://stackoverflow.com/questions/44005852, which has what + // seems to be a popular fix, but it breaks the restored size of the window + // by setting it to the desktop's resolution, so that doesn't work + // + // the only fix I could find is to remember the sizes of the docks and manually + // setting them back; saving is straightforward, but restoring is messy + // + // this also depends on the window being visible before the timer in restore() + // is fired and the timer must be processed by application.exec(); therefore, + // the splash screen _must_ be closed before readSettings() is called, because + // it has its own event loop, which seems to interfere with this + // + // all of this should become unnecessary when QTBUG-46620 is fixed // - // so post 2.2.1, only one key is returned: "size", the size of the arrays; - // in 2.2.1, one key per server is returned - { - const QStringList keys = ScopedGroup(m_Settings, "Servers").keys(); - if (!keys.empty() && keys[0] != "size") { - // old format - return getServersFromOldMap(); + // saves the size of each dock + for (const auto* dock : mw->findChildren()) { + int size = 0; + + // save the width for horizontal docks, or the height for vertical + if (dockOrientation(mw, dock) == Qt::Horizontal) { + size = dock->size().width(); + } else { + size = dock->size().height(); } + + set(m_Settings, "Geometry", dockSettingName(dock), size); } +} +void GeometrySettings::restoreDocks(QMainWindow* mw) const +{ + struct DockInfo + { + QDockWidget* d; + int size = 0; + Qt::Orientation ori; + }; - // post 2.2.1 format, array of values + std::vector dockInfos; - ServerList list; + // for each dock + for (auto* dock : mw->findChildren()) { + if (auto size=getOptional(m_Settings, "Geometry", dockSettingName(dock))) { + // remember this dock, its size and orientation + dockInfos.push_back({dock, *size, dockOrientation(mw, dock)}); + } + } - { - ScopedReadArray sra(m_Settings, "Servers"); + // the main window must have had time to process the settings from + // readSettings() or it seems to override whatever is set here + // + // some people said a single processEvents() call is enough, but it doesn't + // look like it + QTimer::singleShot(5, [=] { + for (const auto& info : dockInfos) { + mw->resizeDocks({info.d}, {info.size}, info.ori); + } + }); +} - sra.for_each([&] { - ServerInfo::SpeedList lastDownloads; - const auto lastDownloadsString = sra.get("lastDownloads", ""); +WidgetSettings::WidgetSettings(QSettings& s) + : m_Settings(s) +{ + MOBase::QuestionBoxMemory::setCallbacks( + [this](auto&& w, auto&& f){ return questionButton(w, f); }, + [this](auto&& w, auto&& b){ setQuestionWindowButton(w, b); }, + [this](auto&& w, auto&& f, auto&& b){ setQuestionFileButton(w, f, b); }); +} - for (const auto& s : lastDownloadsString.split(" ")) { - const auto bytesPerSecond = s.toInt(); - if (bytesPerSecond > 0) { - lastDownloads.push_back(bytesPerSecond); - } - } +std::optional WidgetSettings::index(const QComboBox* cb) const +{ + return getOptional(m_Settings, "Widgets", indexSettingName(cb)); +} - ServerInfo server( - sra.get("name", ""), - sra.get("premium", false), - QDate::fromString(sra.get("lastSeen", ""), Qt::ISODate), - sra.get("preferred", 0), - lastDownloads); +void WidgetSettings::saveIndex(const QComboBox* cb) +{ + set(m_Settings, "Widgets", indexSettingName(cb), cb->currentIndex()); +} - list.add(std::move(server)); - }); +void WidgetSettings::restoreIndex(QComboBox* cb, std::optional def) const +{ + if (auto v=getOptional(m_Settings, "Widgets", indexSettingName(cb), def)) { + cb->setCurrentIndex(*v); } - - return list; } -ServerList Settings::getServersFromOldMap() const +std::optional WidgetSettings::index(const QTabWidget* w) const { - // for 2.2.1 and before + return getOptional(m_Settings, "Widgets", indexSettingName(w)); +} - ServerList list; - const ScopedGroup sg(m_Settings, "Servers"); +void WidgetSettings::saveIndex(const QTabWidget* w) +{ + set(m_Settings, "Widgets", indexSettingName(w), w->currentIndex()); +} - sg.for_each([&](auto&& serverKey) { - QVariantMap data = sg.get(serverKey); +void WidgetSettings::restoreIndex(QTabWidget* w, std::optional def) const +{ + if (auto v=getOptional(m_Settings, "Widgets", indexSettingName(w), def)) { + w->setCurrentIndex(*v); + } +} - ServerInfo server( - serverKey, - data["premium"].toBool(), - data["lastSeen"].toDate(), - data["preferred"].toInt(), - {}); +std::optional WidgetSettings::checked(const QAbstractButton* w) const +{ + warnIfNotCheckable(w); + return getOptional(m_Settings, "Widgets", checkedSettingName(w)); +} - // ignoring download count and speed, it's now a list of values instead of - // a total +void WidgetSettings::saveChecked(const QAbstractButton* w) +{ + warnIfNotCheckable(w); + set(m_Settings, "Widgets", checkedSettingName(w), w->isChecked()); +} - list.add(std::move(server)); - }); +void WidgetSettings::restoreChecked(QAbstractButton* w, std::optional def) const +{ + warnIfNotCheckable(w); - return list; + if (auto v=getOptional(m_Settings, "Widgets", checkedSettingName(w), def)) { + w->setChecked(*v); + } } -void Settings::updateServers(ServerList servers) +QuestionBoxMemory::Button WidgetSettings::questionButton( + const QString& windowName, const QString& filename) const { - // clean up unavailable servers - servers.cleanup(); - - removeSection(m_Settings, "Servers"); + const QString sectionName("DialogChoices"); - { - ScopedWriteArray swa(m_Settings, "Servers"); + if (!filename.isEmpty()) { + const auto fileSetting = windowName + "/" + filename; + if (auto v=getOptional(m_Settings, sectionName, filename)) { + return static_cast(*v); + } + } - for (const auto& server : servers) { - swa.next(); + if (auto v=getOptional(m_Settings, sectionName, windowName)) { + return static_cast(*v); + } - swa.set("name", server.name()); - swa.set("premium", server.isPremium()); - swa.set("lastSeen", server.lastSeen().toString(Qt::ISODate)); - swa.set("preferred", server.preferred()); + return QuestionBoxMemory::NoButton; +} - QString lastDownloads; - for (const auto& speed : server.lastDownloads()) { - if (speed > 0) { - lastDownloads += QString("%1 ").arg(speed); - } - } +void WidgetSettings::setQuestionWindowButton( + const QString& windowName, QuestionBoxMemory::Button button) +{ + const QString sectionName("DialogChoices"); - swa.set("lastDownloads", lastDownloads.trimmed()); - } + if (button == QuestionBoxMemory::NoButton) { + remove(m_Settings, sectionName, windowName); + } else { + set(m_Settings, sectionName, windowName, button); } } -std::map Settings::getRecentDirectories() const +void WidgetSettings::setQuestionFileButton( + const QString& windowName, const QString& filename, + QuestionBoxMemory::Button button) { - std::map map; + const QString sectionName("DialogChoices"); + const QString settingName(windowName + "/" + filename); - ScopedReadArray sra(m_Settings, "RecentDirectories"); + if (button == QuestionBoxMemory::NoButton) { + remove(m_Settings, sectionName, settingName); + } else { + set(m_Settings, sectionName, settingName, button); + } +} - sra.for_each([&] { - const QVariant name = sra.get("name"); - const QVariant dir = sra.get("directory"); +void WidgetSettings::resetQuestionButtons() +{ + removeSection(m_Settings, "DialogChoices"); +} - if (name.isValid() && dir.isValid()) { - map.emplace(name.toString(), dir.toString()); - } - }); - return map; +ColorSettings::ColorSettings(QSettings& s) + : m_Settings(s) +{ } -void Settings::setRecentDirectories(const std::map& map) +QColor ColorSettings::modlistOverwrittenLoose() const { - removeSection(m_Settings, "RecentDirectories"); + return get( + m_Settings, "Settings", "overwrittenLooseFilesColor", + QColor(0, 255, 0, 64)); +} - ScopedWriteArray swa(m_Settings, "recentDirectories"); +void ColorSettings::setModlistOverwrittenLoose(const QColor& c) +{ + set(m_Settings, "Settings", "overwrittenLooseFilesColor", c); +} - for (auto&& p : map) { - swa.next(); +QColor ColorSettings::modlistOverwritingLoose() const +{ + return get( + m_Settings, "Settings", "overwritingLooseFilesColor", + QColor(255, 0, 0, 64)); +} - swa.set("name", p.first); - swa.set("directory", p.second); - } +void ColorSettings::setModlistOverwritingLoose(const QColor& c) +{ + set(m_Settings, "Settings", "overwritingLooseFilesColor", c); } -std::vector> Settings::getExecutables() const +QColor ColorSettings::modlistOverwrittenArchive() const { - ScopedReadArray sra(m_Settings, "customExecutables"); - std::vector> v; + return get( + m_Settings, "Settings", "overwrittenArchiveFilesColor", + QColor(0, 255, 255, 64)); +} - sra.for_each([&]{ - std::map map; +void ColorSettings::setModlistOverwrittenArchive(const QColor& c) +{ + set(m_Settings, "Settings", "overwrittenArchiveFilesColor", c); +} - for (auto&& key : sra.keys()) { - map[key] = m_Settings.value(key); - } +QColor ColorSettings::modlistOverwritingArchive() const +{ + return get( + m_Settings, "Settings", "overwritingArchiveFilesColor", + QColor(255, 0, 255, 64)); +} - v.push_back(map); - }); +void ColorSettings::setModlistOverwritingArchive(const QColor& c) +{ + set(m_Settings, "Settings", "overwritingArchiveFilesColor", c); +} - return v; +QColor ColorSettings::modlistContainsPlugin() const +{ + return get( + m_Settings, "Settings", "containsPluginColor", + QColor(0, 0, 255, 64)); } -void Settings::setExecutables(const std::vector>& v) +void ColorSettings::setModlistContainsPlugin(const QColor& c) { - removeSection(m_Settings, "customExecutables"); + set(m_Settings, "Settings", "containsPluginColor", c); +} - ScopedWriteArray swa(m_Settings, "customExecutables"); +QColor ColorSettings::pluginListContained() const +{ + return get( + m_Settings, "Settings", "containedColor", + QColor(0, 0, 255, 64)); +} - for (const auto& map : v) { - swa.next(); +void ColorSettings::setPluginListContained(const QColor& c) +{ + set(m_Settings, "Settings", "containedColor", c); +} - for (auto&& p : map) { - swa.set(p.first, p.second); - } +std::optional ColorSettings::previousSeparatorColor() const +{ + const auto c = getOptional(m_Settings, "General", "previousSeparatorColor"); + if (c && c->isValid()) { + return c; } + + return {}; } -bool Settings::isTutorialCompleted(const QString& windowName) const +void ColorSettings::setPreviousSeparatorColor(const QColor& c) const { - return get(m_Settings, "CompletedWindowTutorials", windowName, false); + set(m_Settings, "General", "previousSeparatorColor", c); } -void Settings::setTutorialCompleted(const QString& windowName, bool b) +void ColorSettings::removePreviousSeparatorColor() { - set(m_Settings, "CompletedWindowTutorials", windowName, b); + remove(m_Settings, "General", "previousSeparatorColor"); } -bool Settings::keepBackupOnInstall() const +bool ColorSettings::colorSeparatorScrollbar() const { - return get(m_Settings, "backup_install", false); + return get(m_Settings, "Settings", "colorSeparatorScrollbars", true); } -void Settings::setKeepBackupOnInstall(bool b) +void ColorSettings::setColorSeparatorScrollbar(bool b) { - set(m_Settings, "General", "backup_install", b); + set(m_Settings, "Settings", "colorSeparatorScrollbars", b); } -QuestionBoxMemory::Button Settings::getQuestionButton( - const QString& windowName, const QString& filename) const +QColor ColorSettings::idealTextColor(const QColor& rBackgroundColor) { - const QString sectionName("DialogChoices"); + if (rBackgroundColor.alpha() == 0) + return QColor(Qt::black); - if (!filename.isEmpty()) { - const auto fileSetting = windowName + "/" + filename; - if (auto v=getOptional(m_Settings, sectionName, filename)) { - return static_cast(*v); + const int THRESHOLD = 106 * 255.0f / rBackgroundColor.alpha(); + int BackgroundDelta = (rBackgroundColor.red() * 0.299) + (rBackgroundColor.green() * 0.587) + (rBackgroundColor.blue() * 0.114); + return QColor((255 - BackgroundDelta <= THRESHOLD) ? Qt::black : Qt::white); +} + + + +PluginSettings::PluginSettings(QSettings& settings) + : m_Settings(settings) +{ +} + +void PluginSettings::clearPlugins() +{ + m_Plugins.clear(); + m_PluginSettings.clear(); + + m_PluginBlacklist.clear(); + + ScopedReadArray sra(m_Settings, "pluginBlacklist"); + sra.for_each([&]{ + m_PluginBlacklist.insert(sra.get("name")); + }); +} + +void PluginSettings::registerPlugin(IPlugin *plugin) +{ + m_Plugins.push_back(plugin); + m_PluginSettings.insert(plugin->name(), QVariantMap()); + m_PluginDescriptions.insert(plugin->name(), QVariantMap()); + + for (const PluginSetting &setting : plugin->settings()) { + const QString settingName = plugin->name() + "/" + setting.key; + + QVariant temp = get( + m_Settings, "Plugins", settingName, setting.defaultValue); + + if (!temp.convert(setting.defaultValue.type())) { + log::warn( + "failed to interpret \"{}\" as correct type for \"{}\" in plugin \"{}\", using default", + temp.toString(), setting.key, plugin->name()); + + temp = setting.defaultValue; } - } - if (auto v=getOptional(m_Settings, sectionName, windowName)) { - return static_cast(*v); + m_PluginSettings[plugin->name()][setting.key] = temp; + + m_PluginDescriptions[plugin->name()][setting.key] = QString("%1 (default: %2)") + .arg(setting.description) + .arg(setting.defaultValue.toString()); } +} - return QuestionBoxMemory::NoButton; +bool PluginSettings::pluginBlacklisted(const QString &fileName) const +{ + return m_PluginBlacklist.contains(fileName); } -void Settings::setQuestionWindowButton( - const QString& windowName, QuestionBoxMemory::Button button) +QVariant PluginSettings::pluginSetting(const QString &pluginName, const QString &key) const { - const QString sectionName("DialogChoices/"); + auto iterPlugin = m_PluginSettings.find(pluginName); + if (iterPlugin == m_PluginSettings.end()) { + return QVariant(); + } - if (button == QuestionBoxMemory::NoButton) { - remove(m_Settings, sectionName, windowName); - } else { - set(m_Settings, sectionName, windowName, button); + auto iterSetting = iterPlugin->find(key); + if (iterSetting == iterPlugin->end()) { + return QVariant(); } + + return *iterSetting; } -void Settings::setQuestionFileButton( - const QString& windowName, const QString& filename, - QuestionBoxMemory::Button button) +void PluginSettings::setPluginSetting(const QString &pluginName, const QString &key, const QVariant &value) { - const QString sectionName("DialogChoices"); - const QString settingName(windowName + "/" + filename); + auto iterPlugin = m_PluginSettings.find(pluginName); - if (button == QuestionBoxMemory::NoButton) { - remove(m_Settings, sectionName, settingName); - } else { - set(m_Settings, sectionName, settingName, button); + if (iterPlugin == m_PluginSettings.end()) { + throw MyException( + QObject::tr("attempt to store setting for unknown plugin \"%1\"") + .arg(pluginName)); } + + // store the new setting both in memory and in the ini + m_PluginSettings[pluginName][key] = value; + set(m_Settings, "Plugins", pluginName + "/" + key, value); } -void Settings::resetQuestionButtons() +QVariant PluginSettings::pluginPersistent(const QString &pluginName, const QString &key, const QVariant &def) const { - removeSection(m_Settings, "DialogChoices"); + if (!m_PluginSettings.contains(pluginName)) { + return def; + } + + return get(m_Settings, "PluginPersistance", pluginName + "/" + key, def); } -std::optional Settings::getIndex(const QComboBox* cb) const +void PluginSettings::setPluginPersistent( + const QString &pluginName, const QString &key, const QVariant &value, bool sync) { - return getOptional(m_Settings, "Widgets", indexSettingName(cb)); + if (!m_PluginSettings.contains(pluginName)) { + throw MyException( + QObject::tr("attempt to store setting for unknown plugin \"%1\"") + .arg(pluginName)); + } + + set(m_Settings, "PluginPersistance", pluginName + "/" + key, value); + + if (sync) { + m_Settings.sync(); + } } -void Settings::saveIndex(const QComboBox* cb) +void PluginSettings::addBlacklistPlugin(const QString &fileName) { - set(m_Settings, "Widgets", indexSettingName(cb), cb->currentIndex()); + m_PluginBlacklist.insert(fileName); + writePluginBlacklist(); } -void Settings::restoreIndex(QComboBox* cb, std::optional def) const +void PluginSettings::writePluginBlacklist() { - if (auto v=getOptional(m_Settings, "Widgets", indexSettingName(cb), def)) { - cb->setCurrentIndex(*v); + removeSection(m_Settings, "PluginBlacklist"); + + ScopedWriteArray swa(m_Settings, "PluginBlacklist"); + + for (const QString &plugin : m_PluginBlacklist) { + swa.next(); + swa.set("name", plugin); } } -std::optional Settings::getIndex(const QTabWidget* w) const +QVariantMap PluginSettings::pluginSettings(const QString &pluginName) const { - return getOptional(m_Settings, "Widgets", indexSettingName(w)); + return m_PluginSettings[pluginName]; } -void Settings::saveIndex(const QTabWidget* w) +void PluginSettings::setPluginSettings(const QString &pluginName, const QVariantMap& map) { - set(m_Settings, "Widgets", indexSettingName(w), w->currentIndex()); + m_PluginSettings[pluginName] = map; } -void Settings::restoreIndex(QTabWidget* w, std::optional def) const +QVariantMap PluginSettings::pluginDescriptions(const QString &pluginName) const { - if (auto v=getOptional(m_Settings, "Widgets", indexSettingName(w), def)) { - w->setCurrentIndex(*v); - } + return m_PluginDescriptions[pluginName]; } -std::optional Settings::getChecked(const QAbstractButton* w) const +void PluginSettings::pluginDescriptions(const QString &pluginName, const QVariantMap& map) { - warnIfNotCheckable(w); - return getOptional(m_Settings, "Widgets", checkedSettingName(w)); + m_PluginDescriptions[pluginName] = map; } -void Settings::saveChecked(const QAbstractButton* w) +const QSet& PluginSettings::pluginBlacklist() const { - warnIfNotCheckable(w); - set(m_Settings, "Widgets", checkedSettingName(w), w->isChecked()); + return m_PluginBlacklist; } -void Settings::restoreChecked(QAbstractButton* w, std::optional def) const +void PluginSettings::setPluginBlacklist(const QStringList& pluginNames) { - warnIfNotCheckable(w); + m_PluginBlacklist.clear(); - if (auto v=getOptional(m_Settings, "Widgets", checkedSettingName(w), def)) { - w->setChecked(*v); + for (const auto& name : pluginNames) { + m_PluginBlacklist.insert(name); } } -GeometrySettings& Settings::geometry() +void PluginSettings::save() { - return m_Geometry; -} + for (auto iterPlugins=m_PluginSettings.begin(); iterPlugins!=m_PluginSettings.end(); ++iterPlugins) { + for (auto iterSettings=iterPlugins->begin(); iterSettings!=iterPlugins->end(); ++iterSettings) { + const auto key = iterPlugins.key() + "/" + iterSettings.key(); + set(m_Settings, "Plugins", key, iterSettings.value()); + } + } -const GeometrySettings& Settings::geometry() const -{ - return m_Geometry; + writePluginBlacklist(); } -ColorSettings& Settings::colors() -{ - return m_Colors; -} -const ColorSettings& Settings::colors() const +PathSettings::PathSettings(QSettings& settings) + : m_Settings(settings) { - return m_Colors; } -PluginSettings& Settings::plugins() +std::map PathSettings::recent() const { - return m_Plugins; -} + std::map map; -const PluginSettings& Settings::plugins() const -{ - return m_Plugins; -} + ScopedReadArray sra(m_Settings, "RecentDirectories"); -QSettings::Status Settings::sync() const -{ - m_Settings.sync(); - return m_Settings.status(); -} + sra.for_each([&] { + const QVariant name = sra.get("name"); + const QVariant dir = sra.get("directory"); -void Settings::dump() const -{ - static const QStringList ignore({ - "username", "password", "nexus_api_key" + if (name.isValid() && dir.isValid()) { + map.emplace(name.toString(), dir.toString()); + } }); - log::debug("settings:"); + return map; +} - { - ScopedGroup sg(m_Settings, "Settings"); +void PathSettings::setRecent(const std::map& map) +{ + removeSection(m_Settings, "RecentDirectories"); - for (auto k : m_Settings.allKeys()) { - if (ignore.contains(k, Qt::CaseInsensitive)) { - continue; - } + ScopedWriteArray swa(m_Settings, "recentDirectories"); - log::debug(" . {}={}", k, m_Settings.value(k).toString()); - } - } + for (auto&& p : map) { + swa.next(); - log::debug("servers:"); + swa.set("name", p.first); + swa.set("directory", p.second); + } +} - for (const auto& server : getServers()) { - QString lastDownloads; - for (auto speed : server.lastDownloads()) { - lastDownloads += QString("%1 ").arg(speed); - } +QString PathSettings::getConfigurablePath(const QString &key, + const QString &def, + bool resolve) const +{ + QString result = QDir::fromNativeSeparators( + get(m_Settings, "Settings", key, QString("%BASE_DIR%/") + def)); - log::debug( - " . {} premium={} lastSeen={} preferred={} lastDownloads={}", - server.name(), - server.isPremium() ? "yes" : "no", - server.lastSeen().toString(Qt::ISODate), - server.preferred(), - lastDownloads.trimmed()); + if (resolve) { + result.replace("%BASE_DIR%", base()); } -} + return result; +} -GeometrySettings::GeometrySettings(QSettings& s) - : m_Settings(s), m_Reset(false) +void PathSettings::setConfigurablePath(const QString &key, const QString& path) { + if (path.isEmpty()) { + remove(m_Settings, "Settings", key); + } else { + set(m_Settings, "Settings", key, path); + } } -void GeometrySettings::requestReset() +QString PathSettings::base() const { - m_Reset = true; + return QDir::fromNativeSeparators(get(m_Settings, + "Settings", "base_directory", qApp->property("dataPath").toString())); } -void GeometrySettings::resetIfNeeded() +QString PathSettings::downloads(bool resolve) const { - if (!m_Reset) { - return; - } - - removeSection(m_Settings, "Geometry"); + return getConfigurablePath( + "download_directory", + ToQString(AppConfig::downloadPath()), + resolve); } -void GeometrySettings::saveGeometry(const QWidget* w) +QString PathSettings::cache(bool resolve) const { - set(m_Settings, "Geometry", geoSettingName(w), w->saveGeometry()); + return getConfigurablePath( + "cache_directory", + ToQString(AppConfig::cachePath()), + resolve); } -bool GeometrySettings::restoreGeometry(QWidget* w) const +QString PathSettings::mods(bool resolve) const { - if (auto v=getOptional(m_Settings, "Geometry", geoSettingName(w))) { - w->restoreGeometry(*v); - return true; - } + return getConfigurablePath( + "mod_directory", + ToQString(AppConfig::modsPath()), + resolve); +} - return false; +QString PathSettings::profiles(bool resolve) const +{ + return getConfigurablePath( + "profiles_directory", + ToQString(AppConfig::profilesPath()), + resolve); } -void GeometrySettings::saveState(const QMainWindow* w) +QString PathSettings::overwrite(bool resolve) const { - set(m_Settings, "Geometry", stateSettingName(w), w->saveState()); + return getConfigurablePath( + "overwrite_directory", + ToQString(AppConfig::overwritePath()), + resolve); } -bool GeometrySettings::restoreState(QMainWindow* w) const +void PathSettings::setBase(const QString& path) { - if (auto v=getOptional(m_Settings, "Geometry", stateSettingName(w))) { - w->restoreState(*v); - return true; + if (path.isEmpty()) { + remove(m_Settings, "Settings", "base_directory"); + } else { + set(m_Settings, "Settings", "base_directory", path); } - - return false; } -void GeometrySettings::saveState(const QHeaderView* w) +void PathSettings::setDownloads(const QString& path) { - set(m_Settings, "Geometry", stateSettingName(w), w->saveState()); + setConfigurablePath("download_directory", path); } -bool GeometrySettings::restoreState(QHeaderView* w) const +void PathSettings::setMods(const QString& path) { - if (auto v=getOptional(m_Settings, "Geometry", stateSettingName(w))) { - w->restoreState(*v); - return true; - } - - return false; + setConfigurablePath("mod_directory", path); } -void GeometrySettings::saveState(const QSplitter* w) +void PathSettings::setCache(const QString& path) { - set(m_Settings, "Geometry", stateSettingName(w), w->saveState()); + setConfigurablePath("cache_directory", path); } -bool GeometrySettings::restoreState(QSplitter* w) const +void PathSettings::setProfiles(const QString& path) { - if (auto v=getOptional(m_Settings, "Geometry", stateSettingName(w))) { - w->restoreState(*v); - return true; - } - - return false; + setConfigurablePath("profiles_directory", path); } -void GeometrySettings::saveState(const ExpanderWidget* expander) +void PathSettings::setOverwrite(const QString& path) { - set(m_Settings, "Geometry", stateSettingName(expander), expander->saveState()); + setConfigurablePath("overwrite_directory", path); } -bool GeometrySettings::restoreState(ExpanderWidget* expander) const -{ - if (auto v=getOptional(m_Settings, "Geometry", stateSettingName(expander))) { - expander->restoreState(*v); - return true; - } - return false; +NetworkSettings::NetworkSettings(QSettings& settings) + : m_Settings(settings) +{ } -void GeometrySettings::saveVisibility(const QWidget* w) +bool NetworkSettings::offlineMode() const { - set(m_Settings, "Geometry", visibilitySettingName(w), w->isVisible()); + return get(m_Settings, "Settings", "offline_mode", false); } -bool GeometrySettings::restoreVisibility(QWidget* w, std::optional def) const +void NetworkSettings::setOfflineMode(bool b) { - if (auto v=getOptional(m_Settings, "Geometry", visibilitySettingName(w), def)) { - w->setVisible(*v); - return true; - } + set(m_Settings, "Settings", "offline_mode", b); +} - return false; +bool NetworkSettings::useProxy() const +{ + return get(m_Settings, "Settings", "use_proxy", false); } -void GeometrySettings::restoreToolbars(QMainWindow* w) const +void NetworkSettings::setUseProxy(bool b) { - // all toolbars have the same size and button style settings - const auto size = getOptional(m_Settings, "Geometry", "toolbar_size"); - const auto style = getOptional(m_Settings, "Geometry", "toolbar_button_style"); + set(m_Settings, "Settings", "use_proxy", b); +} - for (auto* tb : w->findChildren()) { - if (size) { - tb->setIconSize(*size); - } +void NetworkSettings::setDownloadSpeed(const QString& name, int bytesPerSecond) +{ + auto current = servers(); - if (style) { - tb->setToolButtonStyle(static_cast(*style)); + for (auto& server : current) { + if (server.name() == name) { + server.addDownload(bytesPerSecond); + updateServers(current); + return; } - - restoreVisibility(tb); } + + log::error( + "server '{}' not found while trying to add a download with bps {}", + name, bytesPerSecond); } -void GeometrySettings::saveToolbars(const QMainWindow* w) +ServerList NetworkSettings::servers() const { - const auto tbs = w->findChildren(); + // servers used to be a map of byte arrays until 2.2.1, it's now an array of + // individual values instead + // + // so post 2.2.1, only one key is returned: "size", the size of the arrays; + // in 2.2.1, one key per server is returned + { + const QStringList keys = ScopedGroup(m_Settings, "Servers").keys(); - // save visibility for all - for (auto* tb : tbs) { - saveVisibility(tb); + if (!keys.empty() && keys[0] != "size") { + // old format + return serversFromOldMap(); + } } - // all toolbars have the same size and button style settings, just save the - // first one - if (!tbs.isEmpty()) { - const auto* tb = tbs[0]; - set(m_Settings, "Geometry", "toolbar_size", tb->iconSize()); - set(m_Settings, "Geometry", "toolbar_button_style", static_cast(tb->toolButtonStyle())); - } -} + // post 2.2.1 format, array of values -QStringList GeometrySettings::getModInfoTabOrder() const -{ - QStringList v; + ServerList list; - if (m_Settings.contains("mod_info_tabs")) { - // old byte array from 2.2.0 - QDataStream stream(m_Settings.value("mod_info_tabs").toByteArray()); + { + ScopedReadArray sra(m_Settings, "Servers"); - int count = 0; - stream >> count; + sra.for_each([&] { + ServerInfo::SpeedList lastDownloads; - for (int i=0; i> s; - v.push_back(s); - } - } else { - // string list since 2.2.1 - QString string = m_Settings.value("mod_info_tab_order").toString(); - QTextStream stream(&string); + const auto lastDownloadsString = sra.get("lastDownloads", ""); - while (!stream.atEnd()) { - QString s; - stream >> s; - v.push_back(s); - } + for (const auto& s : lastDownloadsString.split(" ")) { + const auto bytesPerSecond = s.toInt(); + if (bytesPerSecond > 0) { + lastDownloads.push_back(bytesPerSecond); + } + } + + ServerInfo server( + sra.get("name", ""), + sra.get("premium", false), + QDate::fromString(sra.get("lastSeen", ""), Qt::ISODate), + sra.get("preferred", 0), + lastDownloads); + + list.add(std::move(server)); + }); } - return v; + return list; } -void GeometrySettings::setModInfoTabOrder(const QString& names) +ServerList NetworkSettings::serversFromOldMap() const { - set(m_Settings, "Geometry", "mod_info_tab_order", names); -} + // for 2.2.1 and before -void GeometrySettings::centerOnMainWindowMonitor(QWidget* w) -{ - const auto monitor = getOptional( - m_Settings, "Geometry", "MainWindow_monitor"); + ServerList list; + const ScopedGroup sg(m_Settings, "Servers"); - QPoint center; + sg.for_each([&](auto&& serverKey) { + QVariantMap data = sg.get(serverKey); - if (monitor && QGuiApplication::screens().size() > *monitor) { - center = QGuiApplication::screens().at(*monitor)->geometry().center(); - } else { - center = QGuiApplication::primaryScreen()->geometry().center(); - } + ServerInfo server( + serverKey, + data["premium"].toBool(), + data["lastSeen"].toDate(), + data["preferred"].toInt(), + {}); - w->move(center - w->rect().center()); -} + // ignoring download count and speed, it's now a list of values instead of + // a total -void GeometrySettings::saveMainWindowMonitor(const QMainWindow* w) -{ - if (auto* handle=w->windowHandle()) { - if (auto* screen = handle->screen()) { - const int screenId = QGuiApplication::screens().indexOf(screen); - set(m_Settings, "Geometry", "MainWindow_monitor", screenId); - } - } + list.add(std::move(server)); + }); + + return list; } -Qt::Orientation dockOrientation(const QMainWindow* mw, const QDockWidget* d) +void NetworkSettings::updateServers(ServerList servers) { - // docks in these areas are horizontal - const auto horizontalAreas = - Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea; + // clean up unavailable servers + servers.cleanup(); - if (mw->dockWidgetArea(const_cast(d)) & horizontalAreas) { - return Qt::Horizontal; - } else { - return Qt::Vertical; - } -} + removeSection(m_Settings, "Servers"); -void GeometrySettings::saveDocks(const QMainWindow* mw) -{ - // this attempts to fix https://bugreports.qt.io/browse/QTBUG-46620 where dock - // sizes are not restored when the main window is maximized; it is used in - // MainWindow::readSettings() and MainWindow::storeSettings() - // - // there's also https://stackoverflow.com/questions/44005852, which has what - // seems to be a popular fix, but it breaks the restored size of the window - // by setting it to the desktop's resolution, so that doesn't work - // - // the only fix I could find is to remember the sizes of the docks and manually - // setting them back; saving is straightforward, but restoring is messy - // - // this also depends on the window being visible before the timer in restore() - // is fired and the timer must be processed by application.exec(); therefore, - // the splash screen _must_ be closed before readSettings() is called, because - // it has its own event loop, which seems to interfere with this - // - // all of this should become unnecessary when QTBUG-46620 is fixed - // + { + ScopedWriteArray swa(m_Settings, "Servers"); - // saves the size of each dock - for (const auto* dock : mw->findChildren()) { - int size = 0; + for (const auto& server : servers) { + swa.next(); - // save the width for horizontal docks, or the height for vertical - if (dockOrientation(mw, dock) == Qt::Horizontal) { - size = dock->size().width(); - } else { - size = dock->size().height(); - } + swa.set("name", server.name()); + swa.set("premium", server.isPremium()); + swa.set("lastSeen", server.lastSeen().toString(Qt::ISODate)); + swa.set("preferred", server.preferred()); - set(m_Settings, "Geometry", dockSettingName(dock), size); + QString lastDownloads; + for (const auto& speed : server.lastDownloads()) { + if (speed > 0) { + lastDownloads += QString("%1 ").arg(speed); + } + } + + swa.set("lastDownloads", lastDownloads.trimmed()); + } } } -void GeometrySettings::restoreDocks(QMainWindow* mw) const +void NetworkSettings::dump() const { - struct DockInfo - { - QDockWidget* d; - int size = 0; - Qt::Orientation ori; - }; - - std::vector dockInfos; + log::debug("servers:"); - // for each dock - for (auto* dock : mw->findChildren()) { - if (auto size=getOptional(m_Settings, "Geometry", dockSettingName(dock))) { - // remember this dock, its size and orientation - dockInfos.push_back({dock, *size, dockOrientation(mw, dock)}); + for (const auto& server : servers()) { + QString lastDownloads; + for (auto speed : server.lastDownloads()) { + lastDownloads += QString("%1 ").arg(speed); } - } - // the main window must have had time to process the settings from - // readSettings() or it seems to override whatever is set here - // - // some people said a single processEvents() call is enough, but it doesn't - // look like it - QTimer::singleShot(5, [=] { - for (const auto& info : dockInfos) { - mw->resizeDocks({info.d}, {info.size}, info.ori); - } - }); + log::debug( + " . {} premium={} lastSeen={} preferred={} lastDownloads={}", + server.name(), + server.isPremium() ? "yes" : "no", + server.lastSeen().toString(Qt::ISODate), + server.preferred(), + lastDownloads.trimmed()); + } } -ColorSettings::ColorSettings(QSettings& s) - : m_Settings(s) +NexusSettings::NexusSettings(Settings& parent, QSettings& settings) + : m_Parent(parent), m_Settings(settings) { } -QColor ColorSettings::modlistOverwrittenLoose() const +bool NexusSettings::automaticLoginEnabled() const { - return get( - m_Settings, "Settings", "overwrittenLooseFilesColor", - QColor(0, 255, 0, 64)); + return get(m_Settings, "Settings", "nexus_login", false); } -void ColorSettings::setModlistOverwrittenLoose(const QColor& c) +bool NexusSettings::apiKey(QString &apiKey) const { - set(m_Settings, "Settings", "overwrittenLooseFilesColor", c); + QString tempKey = getWindowsCredential("APIKEY"); + if (tempKey.isEmpty()) + return false; + + apiKey = tempKey; + return true; } -QColor ColorSettings::modlistOverwritingLoose() const +bool NexusSettings::setApiKey(const QString& apiKey) { - return get( - m_Settings, "Settings", "overwritingLooseFilesColor", - QColor(255, 0, 0, 64)); + if (!setWindowsCredential("APIKEY", apiKey)) { + const auto e = GetLastError(); + log::error("Storing API key failed: {}", formatSystemMessage(e)); + return false; + } + + return true; } -void ColorSettings::setModlistOverwritingLoose(const QColor& c) +bool NexusSettings::clearApiKey() { - set(m_Settings, "Settings", "overwritingLooseFilesColor", c); + return setApiKey(""); } -QColor ColorSettings::modlistOverwrittenArchive() const +bool NexusSettings::hasApiKey() const { - return get( - m_Settings, "Settings", "overwrittenArchiveFilesColor", - QColor(0, 255, 255, 64)); + return !getWindowsCredential("APIKEY").isEmpty(); } -void ColorSettings::setModlistOverwrittenArchive(const QColor& c) +bool NexusSettings::endorsementIntegration() const { - set(m_Settings, "Settings", "overwrittenArchiveFilesColor", c); + return get(m_Settings, "Settings", "endorsement_integration", true); } -QColor ColorSettings::modlistOverwritingArchive() const +void NexusSettings::setEndorsementIntegration(bool b) const { - return get( - m_Settings, "Settings", "overwritingArchiveFilesColor", - QColor(255, 0, 255, 64)); + set(m_Settings, "Settings", "endorsement_integration", b); } -void ColorSettings::setModlistOverwritingArchive(const QColor& c) +EndorsementState NexusSettings::endorsementState() const { - set(m_Settings, "Settings", "overwritingArchiveFilesColor", c); + return endorsementStateFromString( + get(m_Settings, "General", "endorse_state", "")); } -QColor ColorSettings::modlistContainsPlugin() const +void NexusSettings::setEndorsementState(EndorsementState s) { - return get( - m_Settings, "Settings", "containsPluginColor", - QColor(0, 0, 255, 64)); + const auto v = toString(s); + + if (v.isEmpty()) { + remove(m_Settings, "General", "endorse_state"); + } else { + set(m_Settings, "General", "endorse_state", v); + } } -void ColorSettings::setModlistContainsPlugin(const QColor& c) +void NexusSettings::registerAsNXMHandler(bool force) { - set(m_Settings, "Settings", "containsPluginColor", c); + const auto nxmPath = QCoreApplication::applicationDirPath() + "/nxmhandler.exe"; + const auto executable = QCoreApplication::applicationFilePath(); + + QString mode = force ? "forcereg" : "reg"; + QString parameters = mode + " " + m_Parent.game().plugin()->gameShortName(); + for (const QString& altGame : m_Parent.game().plugin()->validShortNames()) { + parameters += "," + altGame; + } + parameters += " \"" + executable + "\""; + + if (!shell::Execute(nxmPath, parameters)) { + QMessageBox::critical( + nullptr, QObject::tr("Failed"), + QObject::tr("Failed to start the helper application")); + } } -QColor ColorSettings::pluginListContained() const + +SteamSettings::SteamSettings(Settings& parent, QSettings& settings) + : m_Parent(parent), m_Settings(settings) { - return get( - m_Settings, "Settings", "containedColor", - QColor(0, 0, 255, 64)); } -void ColorSettings::setPluginListContained(const QColor& c) +QString SteamSettings::appID() const { - set(m_Settings, "Settings", "containedColor", c); + return get( + m_Settings, "Settings", "app_id", m_Parent.game().plugin()->steamAPPId()); } - -PluginSettings::PluginSettings(QSettings& settings) - : m_Settings(settings) +void SteamSettings::setAppID(const QString& id) { + if (id.isEmpty()) { + remove(m_Settings, "Settings", "app_id"); + } else { + set(m_Settings, "Settings", "app_id", id); + } } -void PluginSettings::clearPlugins() +bool SteamSettings::login(QString &username, QString &password) const { - m_Plugins.clear(); - m_PluginSettings.clear(); - - m_PluginBlacklist.clear(); + username = get(m_Settings, "Settings", "steam_username", ""); + password = getWindowsCredential("steam_password"); - ScopedReadArray sra(m_Settings, "pluginBlacklist"); - sra.for_each([&]{ - m_PluginBlacklist.insert(sra.get("name")); - }); + return !username.isEmpty() && !password.isEmpty(); } -void PluginSettings::registerPlugin(IPlugin *plugin) +void SteamSettings::setLogin(QString username, QString password) { - m_Plugins.push_back(plugin); - m_PluginSettings.insert(plugin->name(), QVariantMap()); - m_PluginDescriptions.insert(plugin->name(), QVariantMap()); + if (username == "") { + remove(m_Settings, "Settings", "steam_username"); + password = ""; + } else { + set(m_Settings, "Settings", "steam_username", username); + } - for (const PluginSetting &setting : plugin->settings()) { - const QString settingName = plugin->name() + "/" + setting.key; + if (!setWindowsCredential("steam_password", password)) { + const auto e = GetLastError(); + log::error("Storing or deleting password failed: {}", formatSystemMessage(e)); + } +} - QVariant temp = get( - m_Settings, "Plugins", settingName, setting.defaultValue); - if (!temp.convert(setting.defaultValue.type())) { - log::warn( - "failed to interpret \"{}\" as correct type for \"{}\" in plugin \"{}\", using default", - temp.toString(), setting.key, plugin->name()); +InterfaceSettings::InterfaceSettings(QSettings& settings) + : m_Settings(settings) +{ +} - temp = setting.defaultValue; - } +bool InterfaceSettings::lockGUI() const +{ + return get(m_Settings, "Settings", "lock_gui", true); +} - m_PluginSettings[plugin->name()][setting.key] = temp; +void InterfaceSettings::setLockGUI(bool b) +{ + set(m_Settings, "Settings", "lock_gui", b); +} - m_PluginDescriptions[plugin->name()][setting.key] = QString("%1 (default: %2)") - .arg(setting.description) - .arg(setting.defaultValue.toString()); - } +std::optional InterfaceSettings::styleName() const +{ + return getOptional(m_Settings, "Settings", "style"); } -bool PluginSettings::pluginBlacklisted(const QString &fileName) const +void InterfaceSettings::setStyleName(const QString& name) { - return m_PluginBlacklist.contains(fileName); + set(m_Settings, "Settings", "style", name); } -QVariant PluginSettings::pluginSetting(const QString &pluginName, const QString &key) const +bool InterfaceSettings::compactDownloads() const { - auto iterPlugin = m_PluginSettings.find(pluginName); - if (iterPlugin == m_PluginSettings.end()) { - return QVariant(); - } + return get(m_Settings, "Settings", "compact_downloads", false); +} - auto iterSetting = iterPlugin->find(key); - if (iterSetting == iterPlugin->end()) { - return QVariant(); - } +void InterfaceSettings::setCompactDownloads(bool b) +{ + set(m_Settings, "Settings", "compact_downloads", b); +} - return *iterSetting; +bool InterfaceSettings::metaDownloads() const +{ + return get(m_Settings, "Settings", "meta_downloads", false); } -void PluginSettings::setPluginSetting(const QString &pluginName, const QString &key, const QVariant &value) +void InterfaceSettings::setMetaDownloads(bool b) { - auto iterPlugin = m_PluginSettings.find(pluginName); + set(m_Settings, "Settings", "meta_downloads", b); +} - if (iterPlugin == m_PluginSettings.end()) { - throw MyException( - QObject::tr("attempt to store setting for unknown plugin \"%1\"") - .arg(pluginName)); - } +bool InterfaceSettings::hideAPICounter() const +{ + return get(m_Settings, "Settings", "hide_api_counter", false); +} - // store the new setting both in memory and in the ini - m_PluginSettings[pluginName][key] = value; - set(m_Settings, "Plugins", pluginName + "/" + key, value); +void InterfaceSettings::setHideAPICounter(bool b) +{ + set(m_Settings, "Settings", "hide_api_counter", b); } -QVariant PluginSettings::pluginPersistent(const QString &pluginName, const QString &key, const QVariant &def) const +bool InterfaceSettings::displayForeign() const { - if (!m_PluginSettings.contains(pluginName)) { - return def; - } + return get(m_Settings, "Settings", "display_foreign", true); +} - return get(m_Settings, "PluginPersistance", pluginName + "/" + key, def); +void InterfaceSettings::setDisplayForeign(bool b) +{ + set(m_Settings, "Settings", "display_foreign", b); } -void PluginSettings::setPluginPersistent( - const QString &pluginName, const QString &key, const QVariant &value, bool sync) +QString InterfaceSettings::language() { - if (!m_PluginSettings.contains(pluginName)) { - throw MyException( - QObject::tr("attempt to store setting for unknown plugin \"%1\"") - .arg(pluginName)); - } + QString result = get(m_Settings, "Settings", "language", ""); - set(m_Settings, "PluginPersistance", pluginName + "/" + key, value); + if (result.isEmpty()) { + QStringList languagePreferences = QLocale::system().uiLanguages(); - if (sync) { - m_Settings.sync(); + if (languagePreferences.length() > 0) { + // the users most favoritest language + result = languagePreferences.at(0); + } else { + // fallback system locale + result = QLocale::system().name(); + } } + + return result; } -void PluginSettings::addBlacklistPlugin(const QString &fileName) +void InterfaceSettings::setLanguage(const QString& name) { - m_PluginBlacklist.insert(fileName); - writePluginBlacklist(); + set(m_Settings, "Settings", "language", name); } -void PluginSettings::writePluginBlacklist() +bool InterfaceSettings::isTutorialCompleted(const QString& windowName) const { - removeSection(m_Settings, "PluginBlacklist"); - - ScopedWriteArray swa(m_Settings, "PluginBlacklist"); - - for (const QString &plugin : m_PluginBlacklist) { - swa.next(); - swa.set("name", plugin); - } + return get(m_Settings, "CompletedWindowTutorials", windowName, false); } -QVariantMap PluginSettings::pluginSettings(const QString &pluginName) const +void InterfaceSettings::setTutorialCompleted(const QString& windowName, bool b) { - return m_PluginSettings[pluginName]; + set(m_Settings, "CompletedWindowTutorials", windowName, b); } -void PluginSettings::setPluginSettings(const QString &pluginName, const QVariantMap& map) + +DiagnosticsSettings::DiagnosticsSettings(QSettings& settings) + : m_Settings(settings) { - m_PluginSettings[pluginName] = map; } -QVariantMap PluginSettings::pluginDescriptions(const QString &pluginName) const +log::Levels DiagnosticsSettings::logLevel() const { - return m_PluginDescriptions[pluginName]; + return get(m_Settings, "Settings", "log_level", log::Levels::Info); } -void PluginSettings::pluginDescriptions(const QString &pluginName, const QVariantMap& map) +void DiagnosticsSettings::setLogLevel(log::Levels level) { - m_PluginDescriptions[pluginName] = map; + set(m_Settings, "Settings", "log_level", level); } -const QSet& PluginSettings::pluginBlacklist() const +CrashDumpsType DiagnosticsSettings::crashDumpsType() const { - return m_PluginBlacklist; + return get(m_Settings, + "Settings", "crash_dumps_type", CrashDumpsType::Mini); } -void PluginSettings::setPluginBlacklist(const QStringList& pluginNames) +void DiagnosticsSettings::setCrashDumpsType(CrashDumpsType type) { - m_PluginBlacklist.clear(); - - for (const auto& name : pluginNames) { - m_PluginBlacklist.insert(name); - } + set(m_Settings, "Settings", "crash_dumps_type", type); } -void PluginSettings::save() +int DiagnosticsSettings::crashDumpsMax() const { - for (auto iterPlugins=m_PluginSettings.begin(); iterPlugins!=m_PluginSettings.end(); ++iterPlugins) { - for (auto iterSettings=iterPlugins->begin(); iterSettings!=iterPlugins->end(); ++iterSettings) { - const auto key = iterPlugins.key() + "/" + iterSettings.key(); - set(m_Settings, "Plugins", key, iterSettings.value()); - } - } + return get(m_Settings, "Settings", "crash_dumps_max", 5); +} - writePluginBlacklist(); +void DiagnosticsSettings::setCrashDumpsMax(int n) +{ + set(m_Settings, "Settings", "crash_dumps_max", n); } diff --git a/src/settings.h b/src/settings.h index 403c2d71..5c0a2542 100644 --- a/src/settings.h +++ b/src/settings.h @@ -25,6 +25,10 @@ along with Mod Organizer. If not, see . #include #include +#ifdef interface + #undef interface +#endif + namespace MOBase { class IPlugin; class IPluginGame; @@ -50,6 +54,58 @@ private: }; +class GameSettings +{ +public: + GameSettings(QSettings& setting); + + const MOBase::IPluginGame* plugin(); + void setPlugin(const MOBase::IPluginGame* gamePlugin); + + /** + * whether files of the core game are forced-enabled so the user can't + * accidentally disable them + */ + bool forceEnableCoreFiles() const; + void setForceEnableCoreFiles(bool b); + + /** + * the directory where the managed game is stored (with native separators) + **/ + std::optional directory() const; + void setDirectory(const QString& path); + + std::optional name() const; + void setName(const QString& name); + + std::optional edition() const; + void setEdition(const QString& name); + + std::optional selectedProfileName() const; + void setSelectedProfileName(const QString& name); + + /** + * @return the load mechanism to be used + **/ + LoadMechanism::EMechanism loadMechanismType() const; + void setLoadMechanism(LoadMechanism::EMechanism m); + const LoadMechanism& loadMechanism() const; + void setupLoadMechanism(); + + /** + * @return true if the user wants unchecked plugins (esp, esm) should be hidden from + * the virtual data directory + **/ + bool hideUncheckedPlugins() const; + void setHideUncheckedPlugins(bool b); + +private: + QSettings& m_Settings; + const MOBase::IPluginGame* m_GamePlugin; + LoadMechanism m_LoadMechanism; +}; + + class GeometrySettings { public: @@ -83,7 +139,7 @@ public: void saveDocks(const QMainWindow* w); void restoreDocks(QMainWindow* w) const; - QStringList getModInfoTabOrder() const; + QStringList modInfoTabOrder() const; void setModInfoTabOrder(const QString& names); void centerOnMainWindowMonitor(QWidget* w); @@ -95,6 +151,40 @@ private: }; +class WidgetSettings +{ +public: + WidgetSettings(QSettings& s); + + std::optional index(const QComboBox* cb) const; + void saveIndex(const QComboBox* cb); + void restoreIndex(QComboBox* cb, std::optional def={}) const; + + std::optional index(const QTabWidget* w) const; + void saveIndex(const QTabWidget* w); + void restoreIndex(QTabWidget* w, std::optional def={}) const; + + std::optional checked(const QAbstractButton* w) const; + void saveChecked(const QAbstractButton* w); + void restoreChecked(QAbstractButton* w, std::optional def={}) const; + + MOBase::QuestionBoxMemory::Button questionButton( + const QString& windowName, const QString& filename) const; + + void setQuestionWindowButton( + const QString& windowName, MOBase::QuestionBoxMemory::Button button); + + void setQuestionFileButton( + const QString& windowName, const QString& filename, + MOBase::QuestionBoxMemory::Button choice); + + void resetQuestionButtons(); + +private: + QSettings& m_Settings; +}; + + class ColorSettings { public: @@ -120,6 +210,19 @@ public: QColor pluginListContained() const; void setPluginListContained(const QColor& c) ; + std::optional previousSeparatorColor() const; + void setPreviousSeparatorColor(const QColor& c) const; + void removePreviousSeparatorColor(); + + /** + * @brief color the scrollbar of the mod list for custom separator colors? + * @return the state of the setting + */ + bool colorSeparatorScrollbar() const; + void setColorSeparatorScrollbar(bool b); + + static QColor idealTextColor(const QColor& rBackgroundColor); + private: QSettings& m_Settings; }; @@ -165,210 +268,229 @@ private: }; -enum class EndorsementState -{ - Accepted = 1, - Refused, - NoDecision -}; - -EndorsementState endorsementStateFromString(const QString& s); -QString toString(EndorsementState s); - - -/** - * manages the settings for Mod Organizer. The settings are not cached - * inside the class but read/written directly from/to disc - **/ -class Settings : public QObject +class PathSettings { - Q_OBJECT; - public: - Settings(const QString& path); - ~Settings(); + PathSettings(QSettings& settings); - static Settings &instance(); + QString base() const; + QString downloads(bool resolve = true) const; + QString mods(bool resolve = true) const; + QString cache(bool resolve = true) const; + QString profiles(bool resolve = true) const; + QString overwrite(bool resolve = true) const; - void processUpdates( - const QVersionNumber& currentVersion, const QVersionNumber& lastVersion); + void setBase(const QString& path); + void setDownloads(const QString& path); + void setMods(const QString& path); + void setCache(const QString& path); + void setProfiles(const QString& path); + void setOverwrite(const QString& path); - QString getFilename() const; + std::map recent() const; + void setRecent(const std::map& map); - /** - * @return true if the user wants unchecked plugins (esp, esm) should be hidden from - * the virtual dat adirectory - **/ - bool hideUncheckedPlugins() const; - void setHideUncheckedPlugins(bool b); +private: + QSettings& m_Settings; - /** - * @return true if files of the core game are forced-enabled so the user can't accidentally disable them - */ - bool forceEnableCoreFiles() const; - void setForceEnableCoreFiles(bool b); + QString getConfigurablePath(const QString &key, const QString &def, bool resolve) const; + void setConfigurablePath(const QString &key, const QString& path); +}; - /** - * @return true if the GUI should be locked when running executables - */ - bool lockGUI() const; - void setLockGUI(bool b); - /** - * the steam appid is assigned by the steam platform to each product sold there. - * The appid may differ between different versions of a game so it may be impossible - * for Mod Organizer to automatically recognize it, though usually it does - * @return the steam appid for the game - **/ - QString getSteamAppID() const; - void setSteamAppID(const QString& id); - - QString getBaseDirectory() const; - QString getDownloadDirectory(bool resolve = true) const; - QString getModDirectory(bool resolve = true) const; - QString getCacheDirectory(bool resolve = true) const; - QString getProfileDirectory(bool resolve = true) const; - QString getOverwriteDirectory(bool resolve = true) const; - - void setBaseDirectory(const QString& path); - void setDownloadDirectory(const QString& path); - void setModDirectory(const QString& path); - void setCacheDirectory(const QString& path); - void setProfileDirectory(const QString& path); - void setOverwriteDirectory(const QString& path); +class NetworkSettings +{ +public: + NetworkSettings(QSettings& settings); /** - * retrieve the directory where the managed game is stored (with native separators) - **/ - std::optional getManagedGameDirectory() const; - void setManagedGameDirectory(const QString& path); - - std::optional getManagedGameName() const; - void setManagedGameName(const QString& name); - - std::optional getManagedGameEdition() const; - void setManagedGameEdition(const QString& name); + * @return true if the user disabled internet features + */ + bool offlineMode() const; + void setOfflineMode(bool b); - std::optional getSelectedProfileName() const; - void setSelectedProfileName(const QString& name); + /** + * @return true if the user configured the use of a network proxy + */ + bool useProxy() const; + void setUseProxy(bool b); - std::optional getStyleName() const; - void setStyleName(const QString& name); + void setDownloadSpeed(const QString &serverName, int bytesPerSecond); + ServerList servers() const; + void updateServers(ServerList servers); - std::optional getVersion() const; + void dump() const; - bool getFirstStart() const; - void setFirstStart(bool b); +private: + QSettings& m_Settings; - std::optional getPreviousSeparatorColor() const; - void setPreviousSeparatorColor(const QColor& c) const; - void removePreviousSeparatorColor(); + ServerList serversFromOldMap() const; +}; - std::map getRecentDirectories() const; - void setRecentDirectories(const std::map& map); - std::vector> getExecutables() const; - void setExecutables(const std::vector>& v); +enum class EndorsementState +{ + Accepted = 1, + Refused, + NoDecision +}; - bool isTutorialCompleted(const QString& windowName) const; - void setTutorialCompleted(const QString& windowName, bool b=true); +EndorsementState endorsementStateFromString(const QString& s); +QString toString(EndorsementState s); - bool keepBackupOnInstall() const; - void setKeepBackupOnInstall(bool b); +class NexusSettings +{ +public: + NexusSettings(Settings& parent, QSettings& settings); - MOBase::QuestionBoxMemory::Button getQuestionButton( - const QString& windowName, const QString& filename) const; + /** + * @return true if the user has set up automatic login to nexus + **/ + bool automaticLoginEnabled() const; - void setQuestionWindowButton( - const QString& windowName, MOBase::QuestionBoxMemory::Button button); + /** + * @brief retrieve the login information for nexus + * + * @param username (out) receives the user name for nexus + * @param password (out) received the password for nexus + * @return true if automatic login is active, false otherwise + **/ + bool apiKey(QString &apiKey) const; - void setQuestionFileButton( - const QString& windowName, const QString& filename, - MOBase::QuestionBoxMemory::Button choice); + /** + * @brief set the nexus login information + * + * @param username username + * @param password password + */ + bool setApiKey(const QString& apiKey); - void resetQuestionButtons(); + /** + * @brief clears the nexus login information + */ + bool clearApiKey(); - std::optional getIndex(const QComboBox* cb) const; - void saveIndex(const QComboBox* cb); - void restoreIndex(QComboBox* cb, std::optional def={}) const; + /** + * @brief returns whether an API key is currently stored + */ + bool hasApiKey() const; - std::optional getIndex(const QTabWidget* w) const; - void saveIndex(const QTabWidget* w); - void restoreIndex(QTabWidget* w, std::optional def={}) const; + /** + * @return true if endorsement integration is enabled + */ + bool endorsementIntegration() const; + void setEndorsementIntegration(bool b) const; - std::optional getChecked(const QAbstractButton* w) const; - void saveChecked(const QAbstractButton* w); - void restoreChecked(QAbstractButton* w, std::optional def={}) const; + EndorsementState endorsementState() const; + void setEndorsementState(EndorsementState s); - GeometrySettings& geometry(); - const GeometrySettings& geometry() const; + /** + * @brief register MO as the handler for nxm links + * @param force set to true to enforce the registration dialog to show up, + * even if the user said earlier not to + */ + void registerAsNXMHandler(bool force); - ColorSettings& colors(); - const ColorSettings& colors() const; +private: + Settings& m_Parent; + QSettings& m_Settings; +}; - PluginSettings& plugins(); - const PluginSettings& plugins() const; +class SteamSettings +{ +public: + SteamSettings(Settings& parent, QSettings& settings); /** - * @return true if the user has set up automatic login to nexus - **/ - bool automaticLoginEnabled() const; + * the steam appid is assigned by the steam platform to each product sold there. + * The appid may differ between different versions of a game so it may be impossible + * for Mod Organizer to automatically recognize it, though usually it does + * @return the steam appid for the game + **/ + QString appID() const; + void setAppID(const QString& id); /** - * @brief retrieve the login information for nexus - * - * @param username (out) receives the user name for nexus - * @param password (out) received the password for nexus - * @return true if automatic login is active, false otherwise - **/ - bool getNexusApiKey(QString &apiKey) const; + * @brief retrieve the login information for steam + * + * @param username (out) receives the user name for nexus + * @param password (out) received the password for nexus + * @return true if a username has been specified, false otherwise + **/ + bool login(QString &username, QString &password) const; /** - * @brief set the nexus login information + * @brief set the steam login information * * @param username username * @param password password */ - bool setNexusApiKey(const QString& apiKey); + void setLogin(QString username, QString password); - /** - * @brief clears the nexus login information - */ - bool clearNexusApiKey(); +private: + Settings& m_Parent; + QSettings& m_Settings; +}; - /** - * @brief returns whether an API key is currently stored - */ - bool hasNexusApiKey() const; - /** - * @brief retrieve the login information for steam - * - * @param username (out) receives the user name for nexus - * @param password (out) received the password for nexus - * @return true if a username has been specified, false otherwise - **/ - bool getSteamLogin(QString &username, QString &password) const; +class InterfaceSettings +{ +public: + InterfaceSettings(QSettings& settings); /** - * @return true if the user disabled internet features - */ - bool offlineMode() const; - void setOfflineMode(bool b); + * @return true if the GUI should be locked when running executables + */ + bool lockGUI() const; + void setLockGUI(bool b); + + std::optional styleName() const; + void setStyleName(const QString& name); /** - * @return true if the user chose compact downloads - */ + * @return true if the user chose compact downloads + */ bool compactDownloads() const; void setCompactDownloads(bool b); /** - * @return true if the user chose meta downloads - */ + * @return true if the user chose meta downloads + */ bool metaDownloads() const; void setMetaDownloads(bool b); + /** + * @return true if the API counter should be hidden + */ + bool hideAPICounter() const; + void setHideAPICounter(bool b); + + /** + * @return true if the user wants to see non-official plugins installed outside MO in his mod list + */ + bool displayForeign() const; + void setDisplayForeign(bool b); + + /** + * @return short code of the configured language (corresponding to the translation files) + */ + QString language(); + void setLanguage(const QString& name); + + bool isTutorialCompleted(const QString& windowName) const; + void setTutorialCompleted(const QString& windowName, bool b=true); + +private: + QSettings& m_Settings; +}; + + +class DiagnosticsSettings +{ +public: + DiagnosticsSettings(QSettings& settings); + MOBase::log::Levels logLevel() const; void setLogLevel(MOBase::log::Levels level); @@ -378,60 +500,48 @@ public: int crashDumpsMax() const; void setCrashDumpsMax(int n); - QString executablesBlacklist() const; - void setExecutablesBlacklist(const QString& s); +private: + QSettings& m_Settings; +}; - /** - * @brief set the steam login information - * - * @param username username - * @param password password - */ - void setSteamLogin(QString username, QString password); - /** - * @return the load mechanism to be used - **/ - LoadMechanism::EMechanism getLoadMechanism() const; - void setLoadMechanism(LoadMechanism::EMechanism m); - /** - * @brief activate the load mechanism selected by the user - **/ - void setupLoadMechanism(); +/** + * manages the settings for Mod Organizer. The settings are not cached + * inside the class but read/written directly from/to disc + **/ +class Settings : public QObject +{ + Q_OBJECT; - /** - * @return true if the user configured the use of a network proxy - */ - bool getUseProxy() const; - void setUseProxy(bool b); +public: + Settings(const QString& path); + ~Settings(); - /** - * @return true if endorsement integration is enabled - */ - bool endorsementIntegration() const; - void setEndorsementIntegration(bool b) const; + static Settings &instance(); - EndorsementState endorsementState() const; - void setEndorsementState(EndorsementState s); + QString filename() const; - /** - * @return true if the API counter should be hidden - */ - bool hideAPICounter() const; - void setHideAPICounter(bool b); + std::optional version() const; + void processUpdates(const QVersionNumber& current, const QVersionNumber& last); - /** - * @return true if the user wants to see non-official plugins installed outside MO in his mod list - */ - bool displayForeign() const; - void setDisplayForeign(bool b); + bool firstStart() const; + void setFirstStart(bool b); + + std::vector> executables() const; + void setExecutables(const std::vector>& v); + + bool keepBackupOnInstall() const; + void setKeepBackupOnInstall(bool b); + + QString executablesBlacklist() const; + void setExecutablesBlacklist(const QString& s); /** * @brief sets the new motd hash **/ - unsigned int getMotDHash() const; - void setMotDHash(unsigned int hash); + unsigned int motdHash() const; + void setMotdHash(unsigned int hash); /** * @return true if the user wants to have archives being parsed to show conflicts and contents @@ -439,41 +549,45 @@ public: bool archiveParsing() const; void setArchiveParsing(bool b); - /** - * @return short code of the configured language (corresponding to the translation files) - */ - QString language(); - void setLanguage(const QString& name); - - void setDownloadSpeed(const QString &serverName, int bytesPerSecond); - ServerList getServers() const; - ServerList getServersFromOldMap() const; - void updateServers(ServerList servers); - bool usePrereleases() const; void setUsePrereleases(bool b); - /** - * @brief register MO as the handler for nxm links - * @param force set to true to enforce the registration dialog to show up, - * even if the user said earlier not to - */ - void registerAsNXMHandler(bool force); - /** - * @brief color the scrollbar of the mod list for custom separator colors? - * @return the state of the setting - */ - bool colorSeparatorScrollbar() const; - void setColorSeparatorScrollbar(bool b); + GameSettings& game(); + const GameSettings& game() const; + + GeometrySettings& geometry(); + const GeometrySettings& geometry() const; - static QColor getIdealTextColor(const QColor& rBackgroundColor); + WidgetSettings& widgets(); + const WidgetSettings& widgets() const; - MOBase::IPluginGame const *gamePlugin() { return m_GamePlugin; } - const LoadMechanism& loadMechanism() const { return m_LoadMechanism; } + ColorSettings& colors(); + const ColorSettings& colors() const; - QSettings::Status sync() const; + PluginSettings& plugins(); + const PluginSettings& plugins() const; + + PathSettings& paths(); + const PathSettings& paths() const; + + NetworkSettings& network(); + const NetworkSettings& network() const; + + NexusSettings& nexus(); + const NexusSettings& nexus() const; + + SteamSettings& steam(); + const SteamSettings& steam() const; + InterfaceSettings& interface(); + const InterfaceSettings& interface() const; + + DiagnosticsSettings& diagnostics(); + const DiagnosticsSettings& diagnostics() const; + + + QSettings::Status sync() const; void dump() const; public slots: @@ -485,18 +599,19 @@ signals: private: static Settings *s_Instance; - MOBase::IPluginGame const *m_GamePlugin; mutable QSettings m_Settings; + + GameSettings m_Game; GeometrySettings m_Geometry; + WidgetSettings m_Widgets; ColorSettings m_Colors; PluginSettings m_Plugins; - LoadMechanism m_LoadMechanism; - - static bool obfuscate(const QString key, const QString data); - static QString deObfuscate(const QString key); - - QString getConfigurablePath(const QString &key, const QString &def, bool resolve) const; - void setConfigurablePath(const QString &key, const QString& path); + PathSettings m_Paths; + NetworkSettings m_Network; + NexusSettings m_Nexus; + SteamSettings m_Steam; + InterfaceSettings m_Interface; + DiagnosticsSettings m_Diagnostics; }; #endif // SETTINGS_H diff --git a/src/settingsdialog.cpp b/src/settingsdialog.cpp index 35d14644..1d3d4a39 100644 --- a/src/settingsdialog.cpp +++ b/src/settingsdialog.cpp @@ -51,11 +51,11 @@ int SettingsDialog::exec() { GeometrySaver gs(m_settings, this); - m_settings.restoreIndex(ui->tabWidget); + m_settings.widgets().restoreIndex(ui->tabWidget); auto ret = TutorableDialog::exec(); - m_settings.saveIndex(ui->tabWidget); + m_settings.widgets().saveIndex(ui->tabWidget); if (ret == QDialog::Accepted) { for (auto&& tab : m_tabs) { @@ -109,7 +109,7 @@ void SettingsDialog::accept() if ((QDir::fromNativeSeparators(newModPath) != QDir::fromNativeSeparators( - Settings::instance().getModDirectory(true))) && + Settings::instance().paths().mods(true))) && (QMessageBox::question( nullptr, tr("Confirm"), tr("Changing the mod directory affects all your profiles! " diff --git a/src/settingsdialogdiagnostics.cpp b/src/settingsdialogdiagnostics.cpp index 278da0bf..386c7425 100644 --- a/src/settingsdialogdiagnostics.cpp +++ b/src/settingsdialogdiagnostics.cpp @@ -12,7 +12,7 @@ DiagnosticsSettingsTab::DiagnosticsSettingsTab(Settings& s, SettingsDialog& d) setLevelsBox(); setCrashDumpTypesBox(); - ui->dumpsMaxEdit->setValue(settings().crashDumpsMax()); + ui->dumpsMaxEdit->setValue(settings().diagnostics().crashDumpsMax()); QString logsPath = qApp->property("dataPath").toString() + "/" + QString::fromStdWString(AppConfig::logPath()); @@ -36,7 +36,7 @@ void DiagnosticsSettingsTab::setLevelsBox() ui->logLevelBox->addItem(QObject::tr("Error"), log::Error); for (int i=0; ilogLevelBox->count(); ++i) { - if (ui->logLevelBox->itemData(i) == settings().logLevel()) { + if (ui->logLevelBox->itemData(i) == settings().diagnostics().logLevel()) { ui->logLevelBox->setCurrentIndex(i); break; } @@ -56,7 +56,8 @@ void DiagnosticsSettingsTab::setCrashDumpTypesBox() add(QObject::tr("Data"), CrashDumpsType::Data); add(QObject::tr("Full"), CrashDumpsType::Full); - const auto current = static_cast(settings().crashDumpsType()); + const auto current = static_cast( + settings().diagnostics().crashDumpsType()); for (int i=0; idumpsTypeBox->count(); ++i) { if (ui->dumpsTypeBox->itemData(i) == current) { @@ -68,11 +69,11 @@ void DiagnosticsSettingsTab::setCrashDumpTypesBox() void DiagnosticsSettingsTab::update() { - settings().setLogLevel( + settings().diagnostics().setLogLevel( static_cast(ui->logLevelBox->currentData().toInt())); - settings().setCrashDumpsType( + settings().diagnostics().setCrashDumpsType( static_cast(ui->dumpsTypeBox->currentData().toInt())); - settings().setCrashDumpsMax(ui->dumpsMaxEdit->value()); + settings().diagnostics().setCrashDumpsMax(ui->dumpsMaxEdit->value()); } diff --git a/src/settingsdialoggeneral.cpp b/src/settingsdialoggeneral.cpp index e3d73037..3f7ece38 100644 --- a/src/settingsdialoggeneral.cpp +++ b/src/settingsdialoggeneral.cpp @@ -11,7 +11,7 @@ GeneralSettingsTab::GeneralSettingsTab(Settings& s, SettingsDialog& d) { addLanguages(); { - QString languageCode = settings().language(); + QString languageCode = settings().interface().language(); int currentID = ui->languageBox->findData(languageCode); // I made a mess. :( Most languages are stored with only the iso country // code (2 characters like "de") but chinese @@ -29,7 +29,7 @@ GeneralSettingsTab::GeneralSettingsTab(Settings& s, SettingsDialog& d) { const int currentID = ui->styleBox->findData( - settings().getStyleName().value_or("")); + settings().interface().styleName().value_or("")); if (currentID != -1) { ui->styleBox->setCurrentIndex(currentID); @@ -51,10 +51,10 @@ GeneralSettingsTab::GeneralSettingsTab(Settings& s, SettingsDialog& d) setContainsColor(settings().colors().modlistContainsPlugin()); setContainedColor(settings().colors().pluginListContained()); - ui->compactBox->setChecked(settings().compactDownloads()); - ui->showMetaBox->setChecked(settings().metaDownloads()); + ui->compactBox->setChecked(settings().interface().compactDownloads()); + ui->showMetaBox->setChecked(settings().interface().metaDownloads()); ui->usePrereleaseBox->setChecked(settings().usePrereleases()); - ui->colorSeparatorsBox->setChecked(settings().colorSeparatorScrollbar()); + ui->colorSeparatorsBox->setChecked(settings().colors().colorSeparatorScrollbar()); QObject::connect(ui->overwritingArchiveBtn, &QPushButton::clicked, [&]{ on_overwritingArchiveBtn_clicked(); }); QObject::connect(ui->overwritingBtn, &QPushButton::clicked, [&]{ on_overwritingBtn_clicked(); }); @@ -69,18 +69,18 @@ GeneralSettingsTab::GeneralSettingsTab(Settings& s, SettingsDialog& d) void GeneralSettingsTab::update() { - const QString oldLanguage = settings().language(); + const QString oldLanguage = settings().interface().language(); const QString newLanguage = ui->languageBox->itemData(ui->languageBox->currentIndex()).toString(); if (newLanguage != oldLanguage) { - settings().setLanguage(newLanguage); + settings().interface().setLanguage(newLanguage); emit settings().languageChanged(newLanguage); } - const QString oldStyle = settings().getStyleName().value_or(""); + const QString oldStyle = settings().interface().styleName().value_or(""); const QString newStyle = ui->styleBox->itemData(ui->styleBox->currentIndex()).toString(); if (oldStyle != newStyle) { - settings().setStyleName(newStyle); + settings().interface().setStyleName(newStyle); emit settings().styleChanged(newStyle); } @@ -91,10 +91,10 @@ void GeneralSettingsTab::update() settings().colors().setModlistContainsPlugin(getContainsColor()); settings().colors().setPluginListContained(getContainedColor()); - settings().setCompactDownloads(ui->compactBox->isChecked()); - settings().setMetaDownloads(ui->showMetaBox->isChecked()); + settings().interface().setCompactDownloads(ui->compactBox->isChecked()); + settings().interface().setMetaDownloads(ui->showMetaBox->isChecked()); settings().setUsePrereleases(ui->usePrereleaseBox->isChecked()); - settings().setColorSeparatorScrollbar(ui->colorSeparatorsBox->isChecked()); + settings().colors().setColorSeparatorScrollbar(ui->colorSeparatorsBox->isChecked()); } void GeneralSettingsTab::addLanguages() @@ -145,7 +145,7 @@ void GeneralSettingsTab::addStyles() void GeneralSettingsTab::resetDialogs() { - settings().resetQuestionButtons(); + settings().widgets().resetQuestionButtons(); } void GeneralSettingsTab::setButtonColor(QPushButton *button, const QColor &color) @@ -161,7 +161,7 @@ void GeneralSettingsTab::setButtonColor(QPushButton *button, const QColor &color .arg(color.green()) .arg(color.blue()) .arg(color.alpha()) - .arg(Settings::getIdealTextColor(color).name()) + .arg(ColorSettings::idealTextColor(color).name()) ); }; diff --git a/src/settingsdialognexus.cpp b/src/settingsdialognexus.cpp index 8822200e..0b08f13f 100644 --- a/src/settingsdialognexus.cpp +++ b/src/settingsdialognexus.cpp @@ -74,13 +74,13 @@ private: NexusSettingsTab::NexusSettingsTab(Settings& s, SettingsDialog& d) : SettingsTab(s, d) { - ui->offlineBox->setChecked(settings().offlineMode()); - ui->proxyBox->setChecked(settings().getUseProxy()); - ui->endorsementBox->setChecked(settings().endorsementIntegration()); - ui->hideAPICounterBox->setChecked(settings().hideAPICounter()); + ui->offlineBox->setChecked(settings().network().offlineMode()); + ui->proxyBox->setChecked(settings().network().useProxy()); + ui->endorsementBox->setChecked(settings().nexus().endorsementIntegration()); + ui->hideAPICounterBox->setChecked(settings().interface().hideAPICounter()); // display server preferences - for (const auto& server : s.getServers()) { + for (const auto& server : s.network().servers()) { QString descriptor = server.name(); if (!descriptor.compare("CDN", Qt::CaseInsensitive)) { @@ -117,12 +117,12 @@ NexusSettingsTab::NexusSettingsTab(Settings& s, SettingsDialog& d) void NexusSettingsTab::update() { - settings().setOfflineMode(ui->offlineBox->isChecked()); - settings().setUseProxy(ui->proxyBox->isChecked()); - settings().setEndorsementIntegration(ui->endorsementBox->isChecked()); - settings().setHideAPICounter(ui->hideAPICounterBox->isChecked()); + settings().network().setOfflineMode(ui->offlineBox->isChecked()); + settings().network().setUseProxy(ui->proxyBox->isChecked()); + settings().nexus().setEndorsementIntegration(ui->endorsementBox->isChecked()); + settings().interface().setHideAPICounter(ui->hideAPICounterBox->isChecked()); - auto servers = settings().getServers(); + auto servers = settings().network().servers(); // store server preference for (int i = 0; i < ui->knownServersList->count(); ++i) { @@ -167,7 +167,7 @@ void NexusSettingsTab::update() } } - settings().updateServers(servers); + settings().network().updateServers(servers); } void NexusSettingsTab::on_nexusConnect_clicked() @@ -225,13 +225,13 @@ void NexusSettingsTab::on_nexusDisconnect_clicked() void NexusSettingsTab::on_clearCacheButton_clicked() { - QDir(Settings::instance().getCacheDirectory()).removeRecursively(); + QDir(Settings::instance().paths().cache()).removeRecursively(); NexusInterface::instance(dialog().m_PluginContainer)->clearCache(); } void NexusSettingsTab::on_associateButton_clicked() { - Settings::instance().registerAsNXMHandler(true); + Settings::instance().nexus().registerAsNXMHandler(true); } void NexusSettingsTab::validateKey(const QString& key) @@ -312,7 +312,7 @@ void NexusSettingsTab::addNexusLog(const QString& s) bool NexusSettingsTab::setKey(const QString& key) { dialog().m_keyChanged = true; - const bool ret = settings().setNexusApiKey(key); + const bool ret = settings().nexus().setApiKey(key); updateNexusState(); return ret; } @@ -320,7 +320,7 @@ bool NexusSettingsTab::setKey(const QString& key) bool NexusSettingsTab::clearKey() { dialog().m_keyChanged = true; - const auto ret = settings().clearNexusApiKey(); + const auto ret = settings().nexus().clearApiKey(); NexusInterface::instance(dialog().m_PluginContainer)->getAccessManager()->clearApiKey(); updateNexusState(); @@ -352,7 +352,7 @@ void NexusSettingsTab::updateNexusButtons() ui->nexusManualKey->setText(QObject::tr("Cancel")); ui->nexusManualKey->setEnabled(true); } - else if (settings().hasNexusApiKey()) { + else if (settings().nexus().hasApiKey()) { // api key is present ui->nexusConnect->setText(QObject::tr("Connect to Nexus")); ui->nexusConnect->setEnabled(false); diff --git a/src/settingsdialogpaths.cpp b/src/settingsdialogpaths.cpp index 32aaf4bf..aeb4dd5d 100644 --- a/src/settingsdialogpaths.cpp +++ b/src/settingsdialogpaths.cpp @@ -6,17 +6,23 @@ PathsSettingsTab::PathsSettingsTab(Settings& s, SettingsDialog& d) : SettingsTab(s, d) { - ui->baseDirEdit->setText(settings().getBaseDirectory()); - ui->managedGameDirEdit->setText(settings().gamePlugin()->gameDirectory().absoluteFilePath(settings().gamePlugin()->binaryName())); - QString basePath = settings().getBaseDirectory(); + ui->baseDirEdit->setText(settings().paths().base()); + + ui->managedGameDirEdit->setText( + settings().game().plugin()->gameDirectory().absoluteFilePath( + settings().game().plugin()->binaryName())); + + QString basePath = settings().paths().base(); QDir baseDir(basePath); + for (const auto &dir : { - std::make_pair(ui->downloadDirEdit, settings().getDownloadDirectory(false)), - std::make_pair(ui->modDirEdit, settings().getModDirectory(false)), - std::make_pair(ui->cacheDirEdit, settings().getCacheDirectory(false)), - std::make_pair(ui->profilesDirEdit, settings().getProfileDirectory(false)), - std::make_pair(ui->overwriteDirEdit, settings().getOverwriteDirectory(false)) + std::make_pair(ui->downloadDirEdit, settings().paths().downloads(false)), + std::make_pair(ui->modDirEdit, settings().paths().mods(false)), + std::make_pair(ui->cacheDirEdit, settings().paths().cache(false)), + std::make_pair(ui->profilesDirEdit, settings().paths().profiles(false)), + std::make_pair(ui->overwriteDirEdit, settings().paths().overwrite(false)) }) { + QString storePath = baseDir.relativeFilePath(dir.second); storePath = dir.second; dir.first->setText(storePath); @@ -40,17 +46,17 @@ PathsSettingsTab::PathsSettingsTab(Settings& s, SettingsDialog& d) void PathsSettingsTab::update() { - using Setter = void (Settings::*)(const QString&); + using Setter = void (PathSettings::*)(const QString&); using Directory = std::tuple; - QString basePath = settings().getBaseDirectory(); + QString basePath = settings().paths().base(); for (const Directory &dir :{ - Directory{ui->downloadDirEdit->text(), &Settings::setDownloadDirectory, AppConfig::downloadPath()}, - Directory{ui->cacheDirEdit->text(), &Settings::setCacheDirectory, AppConfig::cachePath()}, - Directory{ui->modDirEdit->text(), &Settings::setModDirectory, AppConfig::modsPath()}, - Directory{ui->overwriteDirEdit->text(), &Settings::setOverwriteDirectory, AppConfig::overwritePath()}, - Directory{ui->profilesDirEdit->text(), &Settings::setProfileDirectory, AppConfig::profilesPath()} + Directory{ui->downloadDirEdit->text(), &PathSettings::setDownloads, AppConfig::downloadPath()}, + Directory{ui->cacheDirEdit->text(), &PathSettings::setCache, AppConfig::cachePath()}, + Directory{ui->modDirEdit->text(), &PathSettings::setMods, AppConfig::modsPath()}, + Directory{ui->overwriteDirEdit->text(), &PathSettings::setOverwrite, AppConfig::overwritePath()}, + Directory{ui->profilesDirEdit->text(), &PathSettings::setProfiles, AppConfig::profilesPath()} }) { QString path; Setter setter; @@ -70,22 +76,26 @@ void PathsSettingsTab::update() } if (QFileInfo(realPath) != QFileInfo(basePath + "/" + QString::fromStdWString(defaultName))) { - (settings().*setter)(path); + (settings().paths().*setter)(path); } else { - (settings().*setter)(""); + (settings().paths().*setter)(""); } } if (QFileInfo(ui->baseDirEdit->text()) != QFileInfo(qApp->property("dataPath").toString())) { - settings().setBaseDirectory(ui->baseDirEdit->text()); + settings().paths().setBase(ui->baseDirEdit->text()); } else { - settings().setBaseDirectory(""); + settings().paths().setBase(""); } - QFileInfo oldGameExe(settings().gamePlugin()->gameDirectory().absoluteFilePath(settings().gamePlugin()->binaryName())); + QFileInfo oldGameExe( + settings().game().plugin()->gameDirectory().absoluteFilePath( + settings().game().plugin()->binaryName())); + QFileInfo newGameExe(ui->managedGameDirEdit->text()); + if (oldGameExe != newGameExe) { - settings().setManagedGameDirectory(newGameExe.absolutePath()); + settings().game().setDirectory(newGameExe.absolutePath()); } } diff --git a/src/settingsdialogsteam.cpp b/src/settingsdialogsteam.cpp index 9ed93e47..3c4c5de6 100644 --- a/src/settingsdialogsteam.cpp +++ b/src/settingsdialogsteam.cpp @@ -5,7 +5,7 @@ SteamSettingsTab::SteamSettingsTab(Settings& s, SettingsDialog& d) : SettingsTab(s, d) { QString username, password; - settings().getSteamLogin(username, password); + settings().steam().login(username, password); ui->steamUserEdit->setText(username); ui->steamPassEdit->setText(password); @@ -13,5 +13,5 @@ SteamSettingsTab::SteamSettingsTab(Settings& s, SettingsDialog& d) void SteamSettingsTab::update() { - settings().setSteamLogin(ui->steamUserEdit->text(), ui->steamPassEdit->text()); + settings().steam().setLogin(ui->steamUserEdit->text(), ui->steamPassEdit->text()); } diff --git a/src/settingsdialogworkarounds.cpp b/src/settingsdialogworkarounds.cpp index b06bd77c..4d811e40 100644 --- a/src/settingsdialogworkarounds.cpp +++ b/src/settingsdialogworkarounds.cpp @@ -6,12 +6,12 @@ WorkaroundsSettingsTab::WorkaroundsSettingsTab(Settings& s, SettingsDialog& d) : SettingsTab(s, d) { - ui->appIDEdit->setText(settings().getSteamAppID()); + ui->appIDEdit->setText(settings().steam().appID()); - LoadMechanism::EMechanism mechanismID = settings().getLoadMechanism(); + LoadMechanism::EMechanism mechanismID = settings().game().loadMechanismType(); int index = 0; - if (settings().loadMechanism().isDirectLoadingSupported()) { + if (settings().game().loadMechanism().isDirectLoadingSupported()) { ui->mechanismBox->addItem(QObject::tr("Mod Organizer"), LoadMechanism::LOAD_MODORGANIZER); if (mechanismID == LoadMechanism::LOAD_MODORGANIZER) { index = ui->mechanismBox->count() - 1; @@ -20,10 +20,10 @@ WorkaroundsSettingsTab::WorkaroundsSettingsTab(Settings& s, SettingsDialog& d) ui->mechanismBox->setCurrentIndex(index); - ui->hideUncheckedBox->setChecked(settings().hideUncheckedPlugins()); - ui->forceEnableBox->setChecked(settings().forceEnableCoreFiles()); - ui->displayForeignBox->setChecked(settings().displayForeign()); - ui->lockGUIBox->setChecked(settings().lockGUI()); + ui->hideUncheckedBox->setChecked(settings().game().hideUncheckedPlugins()); + ui->forceEnableBox->setChecked(settings().game().forceEnableCoreFiles()); + ui->displayForeignBox->setChecked(settings().interface().displayForeign()); + ui->lockGUIBox->setChecked(settings().interface().lockGUI()); ui->enableArchiveParsingBox->setChecked(settings().archiveParsing()); setExecutableBlacklist(settings().executablesBlacklist()); @@ -35,19 +35,19 @@ WorkaroundsSettingsTab::WorkaroundsSettingsTab(Settings& s, SettingsDialog& d) void WorkaroundsSettingsTab::update() { - if (ui->appIDEdit->text() != settings().gamePlugin()->steamAPPId()) { - settings().setSteamAppID(ui->appIDEdit->text()); + if (ui->appIDEdit->text() != settings().game().plugin()->steamAPPId()) { + settings().steam().setAppID(ui->appIDEdit->text()); } else { - settings().setSteamAppID(""); + settings().steam().setAppID(""); } - settings().setLoadMechanism(static_cast( + settings().game().setLoadMechanism(static_cast( ui->mechanismBox->itemData(ui->mechanismBox->currentIndex()).toInt())); - settings().setHideUncheckedPlugins(ui->hideUncheckedBox->isChecked()); - settings().setForceEnableCoreFiles(ui->forceEnableBox->isChecked()); - settings().setDisplayForeign(ui->displayForeignBox->isChecked()); - settings().setLockGUI(ui->lockGUIBox->isChecked()); + settings().game().setHideUncheckedPlugins(ui->hideUncheckedBox->isChecked()); + settings().game().setForceEnableCoreFiles(ui->forceEnableBox->isChecked()); + settings().interface().setDisplayForeign(ui->displayForeignBox->isChecked()); + settings().interface().setLockGUI(ui->lockGUIBox->isChecked()); settings().setArchiveParsing(ui->enableArchiveParsingBox->isChecked()); settings().setExecutablesBlacklist(getExecutableBlacklist()); } diff --git a/src/statusbar.cpp b/src/statusbar.cpp index d22010a5..3734aa87 100644 --- a/src/statusbar.cpp +++ b/src/statusbar.cpp @@ -129,7 +129,7 @@ void StatusBar::setUpdateAvailable(bool b) void StatusBar::checkSettings(const Settings& settings) { - m_api->setVisible(!settings.hideAPICounter()); + m_api->setVisible(!settings.interface().hideAPICounter()); } void StatusBar::showEvent(QShowEvent*) diff --git a/src/usvfsconnector.cpp b/src/usvfsconnector.cpp index 41f58308..4315ed92 100644 --- a/src/usvfsconnector.cpp +++ b/src/usvfsconnector.cpp @@ -163,8 +163,8 @@ QString toString(CrashDumpsType t) UsvfsConnector::UsvfsConnector() { USVFSParameters params; - LogLevel level = toUsvfsLogLevel(Settings::instance().logLevel()); - CrashDumpsType dumpType = Settings::instance().crashDumpsType(); + LogLevel level = toUsvfsLogLevel(Settings::instance().diagnostics().logLevel()); + CrashDumpsType dumpType = Settings::instance().diagnostics().crashDumpsType(); std::string dumpPath = MOShared::ToString(OrganizerCore::crashDumpsPath(), true); USVFSInitParameters(¶ms, SHMID, false, level, dumpType, dumpPath.c_str()); -- cgit v1.3.1