From c4df6b8ec98feb34cc9b9785e6d4d0eac6b3f571 Mon Sep 17 00:00:00 2001 From: isanae <14251494+isanae@users.noreply.github.com> Date: Thu, 30 Jul 2020 00:48:46 -0400 Subject: split nexus connection stuff into NexusConnectionUI so it can be reused in the instance creation dialog removed the PluginContainer* parameter from NexusInterface::instance() - it's a singleton, so it only needs to be given once, not every time - it doesn't even matter because the first time instance() is called, it creates the singleton, but the plugin container is always null - and setPluginContainer() is called much later from OrganizerCore with the correct value added non functional nexus page to instance creation dialog --- src/nexusinterface.cpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'src/nexusinterface.cpp') diff --git a/src/nexusinterface.cpp b/src/nexusinterface.cpp index 9eb1540a..396cec11 100644 --- a/src/nexusinterface.cpp +++ b/src/nexusinterface.cpp @@ -26,6 +26,7 @@ along with Mod Organizer. If not, see . #include #include "shared/util.h" #include +#include #include #include @@ -50,7 +51,7 @@ void throttledWarning(const APIUserAccount& user) NexusBridge::NexusBridge(PluginContainer *pluginContainer, const QString &subModule) - : m_Interface(NexusInterface::instance(pluginContainer)) + : m_Interface(&NexusInterface::instance()) , m_SubModule(subModule) { } @@ -234,8 +235,8 @@ APILimits NexusInterface::parseLimits( } -NexusInterface::NexusInterface(PluginContainer *pluginContainer) - : m_PluginContainer(pluginContainer) +NexusInterface::NexusInterface() + : m_PluginContainer(nullptr) { m_User.limits(defaultAPILimits()); m_MOVersion = createVersionInfo(); @@ -255,10 +256,10 @@ NexusInterface::~NexusInterface() cleanup(); } -NexusInterface *NexusInterface::instance(PluginContainer *pluginContainer) +NexusInterface& NexusInterface::instance() { - static NexusInterface s_Instance(pluginContainer); - return &s_Instance; + static NexusInterface ni; + return ni; } void NexusInterface::setCacheDirectory(const QString &directory) @@ -284,7 +285,7 @@ void NexusInterface::interpretNexusFileName(const QString &fileName, QString &mo static const QRegularExpression complex(R"(^([a-zA-Z0-9_'"\-.() ]*?)([-_ ][VvRr]+[0-9]+(?:(?:[\.][0-9]+){0,2}|(?:[_][0-9]+){0,2}|(?:[-.][0-9]+){0,2})?[ab]?)??-([1-9][0-9]+)?-.*?\.(zip|rar|7z))"); //complex regex explanation: //group 1: modname. - //group 2: optional version, + //group 2: optional version, // assumed to start with v (empty most of the time). //group 3: NexusId, // assumed wrapped in "-", will miss single digit IDs for better accuracy. -- cgit v1.3.1 From 4c5e3da2334a1d0c474148be8881b46d6ca6d3fa Mon Sep 17 00:00:00 2001 From: isanae <14251494+isanae@users.noreply.github.com> Date: Mon, 17 Aug 2020 05:06:26 -0400 Subject: moved nexus api stuff to GlobalSettings pass a pointer to Settings around for things that can be called without settings, when creating the first instance added dummy plugin list, mod list and iorganizer to initialize plugins without an instance moved PluginContainer into the core filter, had nothing to do with the plugins list NexusInterface is now created manually instead of being a static singleton because it needs to know if the settings are available --- src/CMakeLists.txt | 2 +- src/createinstancedialog.cpp | 9 +- src/createinstancedialog.h | 6 +- src/createinstancedialogpages.cpp | 5 +- src/instancemanagerdialog.cpp | 2 +- src/main.cpp | 27 +++-- src/mainwindow.cpp | 4 +- src/modlist.cpp | 41 ++++++++ src/modlist.h | 14 +++ src/nexusinterface.cpp | 28 +++-- src/nexusinterface.h | 6 +- src/nxmaccessmanager.cpp | 37 +++++-- src/nxmaccessmanager.h | 11 +- src/organizercore.cpp | 4 +- src/organizerproxy.cpp | 212 ++++++++++++++++++++++++++++++++++++++ src/organizerproxy.h | 59 +++++++++++ src/plugincontainer.cpp | 88 ++++++++++------ src/pluginlist.cpp | 60 +++++++++++ src/pluginlist.h | 18 ++++ src/settings.cpp | 62 +++++------ src/settings.h | 36 +++---- src/settingsdialognexus.cpp | 18 ++-- src/settingsdialognexus.h | 4 +- 23 files changed, 623 insertions(+), 130 deletions(-) (limited to 'src/nexusinterface.cpp') diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 844f5e19..eec33460 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -33,6 +33,7 @@ add_filter(NAME src/core GROUPS nexusinterface nxmaccessmanager organizercore + plugincontainer apiuseraccount processrunner qdirfiletree @@ -136,7 +137,6 @@ add_filter(NAME src/modlist GROUPS ) add_filter(NAME src/plugins GROUPS - plugincontainer pluginlist pluginlistsortproxy pluginlistview diff --git a/src/createinstancedialog.cpp b/src/createinstancedialog.cpp index f4140e01..0f62fcf6 100644 --- a/src/createinstancedialog.cpp +++ b/src/createinstancedialog.cpp @@ -11,8 +11,8 @@ using namespace MOBase; CreateInstanceDialog::CreateInstanceDialog( - const PluginContainer& pc, QWidget *parent) : - QDialog(parent), ui(new Ui::CreateInstanceDialog), m_pc(pc), + const PluginContainer& pc, Settings* s, QWidget *parent) : + QDialog(parent), ui(new Ui::CreateInstanceDialog), m_pc(pc), m_settings(s), m_switching(false) { using namespace cid; @@ -55,6 +55,11 @@ const PluginContainer& CreateInstanceDialog::pluginContainer() return m_pc; } +Settings* CreateInstanceDialog::settings() +{ + return m_settings; +} + bool CreateInstanceDialog::isOnLastPage() const { for (int i=ui->pages->currentIndex() + 1; i < ui->pages->count(); ++i) { diff --git a/src/createinstancedialog.h b/src/createinstancedialog.h index 95d4fa68..0841ef29 100644 --- a/src/createinstancedialog.h +++ b/src/createinstancedialog.h @@ -8,6 +8,7 @@ namespace Ui { class CreateInstanceDialog; }; namespace cid { class Page; } class PluginContainer; +class Settings; class CreateInstanceDialog : public QDialog { @@ -47,12 +48,14 @@ public: explicit CreateInstanceDialog( - const PluginContainer& pc, QWidget *parent = nullptr); + const PluginContainer& pc, Settings* s, QWidget *parent = nullptr); ~CreateInstanceDialog(); Ui::CreateInstanceDialog* getUI(); + const PluginContainer& pluginContainer(); + Settings* settings(); void next(); void back(); @@ -77,6 +80,7 @@ public: private: std::unique_ptr ui; const PluginContainer& m_pc; + Settings* m_settings; std::vector> m_pages; QString m_originalNext; bool m_switching; diff --git a/src/createinstancedialogpages.cpp b/src/createinstancedialogpages.cpp index 73b265c8..d809079d 100644 --- a/src/createinstancedialogpages.cpp +++ b/src/createinstancedialogpages.cpp @@ -964,7 +964,8 @@ NexusPage::NexusPage(CreateInstanceDialog& dlg) : Page(dlg), m_skip(false) { m_connectionUI.reset(new NexusConnectionUI( - Settings::instance(), &m_dlg, + &m_dlg, + dlg.settings(), ui->nexusConnect, nullptr, ui->nexusManual, @@ -972,7 +973,7 @@ NexusPage::NexusPage(CreateInstanceDialog& dlg) // just check it once, or connecting and then going back and forth would skip // the page, which would be unexpected - m_skip = Settings::instance().nexus().hasApiKey(); + m_skip = GlobalSettings::hasNexusApiKey(); } NexusPage::~NexusPage() = default; diff --git a/src/instancemanagerdialog.cpp b/src/instancemanagerdialog.cpp index 3b9dd344..7b8522ee 100644 --- a/src/instancemanagerdialog.cpp +++ b/src/instancemanagerdialog.cpp @@ -718,7 +718,7 @@ void InstanceManagerDialog::onSelection() void InstanceManagerDialog::createNew() { - CreateInstanceDialog dlg(m_pc, this); + CreateInstanceDialog dlg(m_pc, &Settings::instance(), this); if (dlg.exec() != QDialog::Accepted) { return; } diff --git a/src/main.cpp b/src/main.cpp index 93580931..fd5a47c9 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -26,6 +26,7 @@ along with Mod Organizer. If not, see . #include "nxmaccessmanager.h" #include "instancemanager.h" #include "instancemanagerdialog.h" +#include "createinstancedialog.h" #include "organizercore.h" #include "env.h" #include "envmodule.h" @@ -329,6 +330,9 @@ int runApplication( // this must outlive `organizer` std::unique_ptr pluginContainer; + log::debug("initializing nexus interface"); + NexusInterface ni(&settings); + log::debug("initializing core"); OrganizerCore organizer(settings); if (!organizer.bootstrap()) { @@ -394,8 +398,8 @@ int runApplication( auto splash = createSplash(settings, dataPath, game); QString apiKey; - if (settings.nexus().apiKey(apiKey)) { - NexusInterface::instance().getAccessManager()->apiCheck(apiKey); + if (GlobalSettings::nexusApiKey(apiKey)) { + ni.getAccessManager()->apiCheck(apiKey); } log::debug("initializing tutorials"); @@ -415,8 +419,7 @@ int runApplication( // set up main window and its data structures MainWindow mainWindow(settings, organizer, *pluginContainer); - NexusInterface::instance() - .getAccessManager()->setTopLevelWidget(&mainWindow); + ni.getAccessManager()->setTopLevelWidget(&mainWindow); QObject::connect(&mainWindow, SIGNAL(styleChanged(QString)), &application, SLOT(setStyleFile(QString))); @@ -443,8 +446,7 @@ int runApplication( res = application.exec(); mainWindow.close(); - NexusInterface::instance() - .getAccessManager()->setTopLevelWidget(nullptr); + ni.getAccessManager()->setTopLevelWidget(nullptr); } settings.geometry().resetIfNeeded(); @@ -507,6 +509,7 @@ QString determineDataPath(const cl::CommandLine& cl) } } + int doOneRun( cl::CommandLine& cl, MOApplication& application, SingleInstance& instance) { @@ -515,6 +518,18 @@ int doOneRun( // resets things when MO is "restarted" resetForRestart(cl); + + //{ + // NexusInterface ni(nullptr); + // + // PluginContainer pc(nullptr); + // pc.loadPlugins(); + // + // CreateInstanceDialog dlg(pc, nullptr); + // dlg.exec(); + //} + + const QString dataPath = determineDataPath(cl); if (dataPath.isEmpty()) { return 1; diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 3ef34e93..9ad51510 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -4226,7 +4226,7 @@ void MainWindow::checkModsForUpdates() NexusInterface::instance().requestTrackingInfo(this, QVariant(), QString()); } else { QString apiKey; - if (m_OrganizerCore.settings().nexus().apiKey(apiKey)) { + if (GlobalSettings::nexusApiKey(apiKey)) { m_OrganizerCore.doAfterLogin([this] () { this->checkModsForUpdates(); }); NexusInterface::instance().getAccessManager()->apiCheck(apiKey); } else { @@ -5434,7 +5434,7 @@ void MainWindow::modUpdateCheck(std::multimap IDs) ModInfo::manualUpdateCheck(this, IDs); } else { QString apiKey; - if (m_OrganizerCore.settings().nexus().apiKey(apiKey)) { + if (GlobalSettings::nexusApiKey(apiKey)) { m_OrganizerCore.doAfterLogin([=]() { this->modUpdateCheck(IDs); }); NexusInterface::instance().getAccessManager()->apiCheck(apiKey); } else diff --git a/src/modlist.cpp b/src/modlist.cpp index 1f845999..bf9aef83 100644 --- a/src/modlist.cpp +++ b/src/modlist.cpp @@ -1528,3 +1528,44 @@ void ModList::disableSelected(const QItemSelectionModel *selectionModel) m_Profile->setModsEnabled(QList(), modsToDisable); } } + + +QString DummyModList::displayName(const QString &internalName) const +{ + return {}; +} + +QStringList DummyModList::allMods() const +{ + return {}; +} + +IModList::ModStates DummyModList::state(const QString &name) const +{ + return 0; +} + +bool DummyModList::setActive(const QString &name, bool active) +{ + return true; +} + +int DummyModList::priority(const QString &name) const +{ + return -1; +} + +bool DummyModList::setPriority(const QString &name, int newPriority) +{ + return true; +} + +bool DummyModList::onModStateChanged(const std::function &func) +{ + return true; +} + +bool DummyModList::onModMoved(const std::function &func) +{ + return true; +} diff --git a/src/modlist.h b/src/modlist.h index 385ca04c..3ab486c9 100644 --- a/src/modlist.h +++ b/src/modlist.h @@ -397,5 +397,19 @@ private: }; + +class DummyModList : public MOBase::IModList +{ +public: + QString displayName(const QString &internalName) const override; + QStringList allMods() const override; + ModStates state(const QString &name) const override; + bool setActive(const QString &name, bool active) override; + int priority(const QString &name) const override; + bool setPriority(const QString &name, int newPriority) override; + bool onModStateChanged(const std::function &func) override; + bool onModMoved(const std::function &func) override; +}; + #endif // MODLIST_H diff --git a/src/nexusinterface.cpp b/src/nexusinterface.cpp index 396cec11..1364d7e1 100644 --- a/src/nexusinterface.cpp +++ b/src/nexusinterface.cpp @@ -23,6 +23,7 @@ along with Mod Organizer. If not, see . #include "nxmaccessmanager.h" #include "selectiondialog.h" #include "bbcode.h" +#include "settings.h" #include #include "shared/util.h" #include @@ -235,31 +236,42 @@ APILimits NexusInterface::parseLimits( } -NexusInterface::NexusInterface() +static NexusInterface* g_instance = nullptr; + +NexusInterface::NexusInterface(Settings* s) : m_PluginContainer(nullptr) { + MO_ASSERT(!g_instance); + g_instance = this; + m_User.limits(defaultAPILimits()); m_MOVersion = createVersionInfo(); - m_AccessManager = new NXMAccessManager(this, m_MOVersion.displayString(3)); + m_AccessManager = new NXMAccessManager( + this, s, m_MOVersion.displayString(3)); + m_DiskCache = new QNetworkDiskCache(this); + connect(m_AccessManager, SIGNAL(requestNXMDownload(QString)), this, SLOT(downloadRequestedNXM(QString))); } -NXMAccessManager *NexusInterface::getAccessManager() +NexusInterface::~NexusInterface() { - return m_AccessManager; + cleanup(); + + MO_ASSERT(g_instance == this); + g_instance = nullptr; } -NexusInterface::~NexusInterface() +NXMAccessManager *NexusInterface::getAccessManager() { - cleanup(); + return m_AccessManager; } NexusInterface& NexusInterface::instance() { - static NexusInterface ni; - return ni; + MO_ASSERT(g_instance); + return *g_instance; } void NexusInterface::setCacheDirectory(const QString &directory) diff --git a/src/nexusinterface.h b/src/nexusinterface.h index 72f30a38..cf365b2e 100644 --- a/src/nexusinterface.h +++ b/src/nexusinterface.h @@ -40,7 +40,7 @@ namespace MOBase { class IPluginGame; } class NexusInterface; class NXMAccessManager; - +class Settings; /** * @brief convenience class to make nxm requests easier @@ -153,7 +153,9 @@ public: static APILimits parseLimits(const QNetworkReply* reply); static APILimits parseLimits(const QList& headers); + NexusInterface(Settings* s); ~NexusInterface(); + static NexusInterface& instance(); /** @@ -533,8 +535,6 @@ private: static const int MAX_ACTIVE_DOWNLOADS = 6; private: - - NexusInterface(); void nextRequest(); void requestFinished(std::list::iterator iter); MOBase::IPluginGame *getGame(QString gameName) const; diff --git a/src/nxmaccessmanager.cpp b/src/nxmaccessmanager.cpp index 2fe676ba..6c8b9054 100644 --- a/src/nxmaccessmanager.cpp +++ b/src/nxmaccessmanager.cpp @@ -48,8 +48,8 @@ const QString NexusSSO("wss://sso.nexusmods.com"); const QString NexusSSOPage("https://www.nexusmods.com/sso?id=%1&application=modorganizer2"); -ValidationProgressDialog::ValidationProgressDialog(NexusKeyValidator& v) - : m_validator(v), m_updateTimer(nullptr), m_first(true) +ValidationProgressDialog::ValidationProgressDialog(Settings* s, NexusKeyValidator& v) + : m_settings(s), m_validator(v), m_updateTimer(nullptr), m_first(true) { ui.reset(new Ui::ValidationProgressDialog); ui->setupUi(this); @@ -98,7 +98,10 @@ void ValidationProgressDialog::stop() void ValidationProgressDialog::showEvent(QShowEvent* e) { if (m_first) { - Settings::instance().geometry().centerOnMainWindowMonitor(this); + if (m_settings) { + m_settings->geometry().centerOnMainWindowMonitor(this); + } + m_first = false; } } @@ -592,8 +595,8 @@ void ValidationAttempt::cleanup() } -NexusKeyValidator::NexusKeyValidator(NXMAccessManager& am) - : m_manager(am) +NexusKeyValidator::NexusKeyValidator(Settings* s, NXMAccessManager& am) + : m_settings(s), m_manager(am) { } @@ -602,6 +605,15 @@ NexusKeyValidator::~NexusKeyValidator() cancel(); } +std::vector NexusKeyValidator::getTimeouts() const +{ + if (m_settings) { + return m_settings->nexus().validationTimeouts(); + } else { + return {10s, 15s, 20s}; + } +} + void NexusKeyValidator::start(const QString& key, Behaviour b) { if (isActive()) { @@ -611,7 +623,7 @@ void NexusKeyValidator::start(const QString& key, Behaviour b) m_key = key; - const auto timeouts = Settings::instance().nexus().validationTimeouts(); + const auto timeouts = getTimeouts(); switch (b) { @@ -755,10 +767,11 @@ void NexusKeyValidator::setFinished( } -NXMAccessManager::NXMAccessManager(QObject *parent, const QString &moVersion) +NXMAccessManager::NXMAccessManager(QObject *parent, Settings* s, const QString &moVersion) : QNetworkAccessManager(parent) + , m_Settings(s) , m_MOVersion(moVersion) - , m_validator(*this) + , m_validator(s, *this) , m_validationState(NotChecked) { m_validator.finished = [&](auto&& r, auto&& m, auto&& u) { @@ -769,8 +782,10 @@ NXMAccessManager::NXMAccessManager(QObject *parent, const QString &moVersion) onValidatorAttemptFinished(a); }; - setCookieJar(new PersistentCookieJar(QDir::fromNativeSeparators( - Settings::instance().paths().cache() + "/nexus_cookies.dat"))); + if (m_Settings) { + setCookieJar(new PersistentCookieJar(QDir::fromNativeSeparators( + m_Settings->paths().cache() + "/nexus_cookies.dat"))); + } if (networkAccessible() == QNetworkAccessManager::UnknownAccessibility) { // why is this necessary all of a sudden? @@ -963,7 +978,7 @@ void NXMAccessManager::clearApiKey() void NXMAccessManager::startProgress() { if (!m_ProgressDialog) { - m_ProgressDialog.reset(new ValidationProgressDialog(m_validator)); + m_ProgressDialog.reset(new ValidationProgressDialog(m_Settings, m_validator)); } m_ProgressDialog->start(); diff --git a/src/nxmaccessmanager.h b/src/nxmaccessmanager.h index 6a45d880..60100467 100644 --- a/src/nxmaccessmanager.h +++ b/src/nxmaccessmanager.h @@ -33,6 +33,7 @@ along with Mod Organizer. If not, see . namespace MOBase { class IPluginGame; } namespace Ui { class ValidationProgressDialog; } class NXMAccessManager; +class Settings; class NexusSSOLogin { @@ -146,7 +147,7 @@ public: std::function finished; std::function attemptFinished; - NexusKeyValidator(NXMAccessManager& am); + NexusKeyValidator(Settings* s, NXMAccessManager& am); ~NexusKeyValidator(); void start(const QString& key, Behaviour b); @@ -157,11 +158,13 @@ public: const ValidationAttempt* currentAttempt() const; private: + Settings* m_settings; NXMAccessManager& m_manager; QString m_key; std::vector> m_attempts; void createAttempts(const std::vector& timeouts); + std::vector getTimeouts() const; bool nextTry(); void onAttemptSuccess(const ValidationAttempt& a, const APIUserAccount& u); @@ -178,7 +181,7 @@ class ValidationProgressDialog : public QDialog Q_OBJECT; public: - ValidationProgressDialog(NexusKeyValidator& v); + ValidationProgressDialog(Settings* s, NexusKeyValidator& v); void setParentWidget(QWidget* w); @@ -191,6 +194,7 @@ protected: private: std::unique_ptr ui; + Settings* m_settings; NexusKeyValidator& m_validator; QTimer* m_updateTimer; bool m_first; @@ -209,7 +213,7 @@ class NXMAccessManager : public QNetworkAccessManager { Q_OBJECT public: - NXMAccessManager(QObject *parent, const QString &moVersion); + NXMAccessManager(QObject *parent, Settings* s, const QString &moVersion); void setTopLevelWidget(QWidget* w); @@ -264,6 +268,7 @@ private: }; QWidget* m_TopLevel; + Settings* m_Settings; mutable std::unique_ptr m_ProgressDialog; QString m_MOVersion; NexusKeyValidator m_validator; diff --git a/src/organizercore.cpp b/src/organizercore.cpp index 7fd8c33b..0d561581 100644 --- a/src/organizercore.cpp +++ b/src/organizercore.cpp @@ -339,7 +339,7 @@ bool OrganizerCore::nexusApi(bool retry) return false; } else { QString apiKey; - if (m_Settings.nexus().apiKey(apiKey)) { + if (GlobalSettings::nexusApiKey(apiKey)) { // credentials stored or user entered them manually log::debug("attempt to verify nexus api key"); accessManager->apiCheck(apiKey); @@ -1426,7 +1426,7 @@ void OrganizerCore::loggedInAction(QWidget* parent, std::function f) f(); } else { QString apiKey; - if (settings().nexus().apiKey(apiKey)) { + if (GlobalSettings::nexusApiKey(apiKey)) { doAfterLogin([f]{ f(); }); NexusInterface::instance().getAccessManager()->apiCheck(apiKey); } else { diff --git a/src/organizerproxy.cpp b/src/organizerproxy.cpp index 45efc00c..8cc95a8b 100644 --- a/src/organizerproxy.cpp +++ b/src/organizerproxy.cpp @@ -287,3 +287,215 @@ bool OrganizerProxy::onPluginSettingChanged(std::functiononPluginSettingChanged(func); } + + + +DummyOrganizerProxy::DummyOrganizerProxy(const QString &pluginName) : + m_PluginName(pluginName), + m_mods(new DummyModList), m_plugins(new DummyPluginList) +{ +} + +DummyOrganizerProxy::~DummyOrganizerProxy() = default; + +IModRepositoryBridge *DummyOrganizerProxy::createNexusBridge() const +{ + return nullptr; +} + +QString DummyOrganizerProxy::profileName() const +{ + return {}; +} + +QString DummyOrganizerProxy::profilePath() const +{ + return {}; +} + +QString DummyOrganizerProxy::downloadsPath() const +{ + return {}; +} + +QString DummyOrganizerProxy::overwritePath() const +{ + return {}; +} + +QString DummyOrganizerProxy::basePath() const +{ + return {}; +} + +QString DummyOrganizerProxy::modsPath() const +{ + return {}; +} + +VersionInfo DummyOrganizerProxy::appVersion() const +{ + return {}; +} + +IModInterface *DummyOrganizerProxy::getMod(const QString &name) const +{ + return nullptr; +} + +IPluginGame *DummyOrganizerProxy::getGame(const QString &gameName) const +{ + return nullptr; +} + +IModInterface *DummyOrganizerProxy::createMod(MOBase::GuessedValue &name) +{ + return nullptr; +} + +bool DummyOrganizerProxy::removeMod(IModInterface *mod) +{ + return true; +} + +void DummyOrganizerProxy::modDataChanged(IModInterface *mod) +{ +} + +QVariant DummyOrganizerProxy::pluginSetting(const QString &pluginName, const QString &key) const +{ + if (key == "enabled") { + return true; + } + + return {}; +} + +void DummyOrganizerProxy::setPluginSetting(const QString &pluginName, const QString &key, const QVariant &value) +{ +} + +QVariant DummyOrganizerProxy::persistent(const QString &pluginName, const QString &key, const QVariant &def) const +{ + return {}; +} + +void DummyOrganizerProxy::setPersistent(const QString &pluginName, const QString &key, const QVariant &value, bool sync) +{ +} + +QString DummyOrganizerProxy::pluginDataPath() const +{ + return qApp->applicationDirPath() + "/" + ToQString(AppConfig::pluginPath()) + "/data"; +} + +HANDLE DummyOrganizerProxy::startApplication( + const QString& exe, const QStringList& args, const QString &cwd, + const QString& profile, const QString &overwrite, bool ignoreOverwrite) +{ + return INVALID_HANDLE_VALUE; +} + +bool DummyOrganizerProxy::waitForApplication(HANDLE handle, LPDWORD exitCode) const +{ + return true; +} + +bool DummyOrganizerProxy::onAboutToRun(const std::function &func) +{ + return true; +} + +bool DummyOrganizerProxy::onFinishedRun(const std::function &func) +{ + return true; +} + +bool DummyOrganizerProxy::onModInstalled(const std::function &func) +{ + return true; +} + +bool DummyOrganizerProxy::onUserInterfaceInitialized(std::function const& func) +{ + return true; +} + +bool DummyOrganizerProxy::onProfileChanged(std::function const& func) +{ + return true; +} + +bool DummyOrganizerProxy::onPluginSettingChanged(std::function const& func) +{ + return true; +} + +void DummyOrganizerProxy::refreshModList(bool saveChanges) +{ +} + +IModInterface *DummyOrganizerProxy::installMod(const QString &fileName, const QString &nameSuggestion) +{ + return nullptr; +} + +QString DummyOrganizerProxy::resolvePath(const QString &fileName) const +{ + return {}; +} + +QStringList DummyOrganizerProxy::listDirectories(const QString &directoryName) const +{ + return {}; +} + +QStringList DummyOrganizerProxy::findFiles(const QString &path, const std::function &filter) const +{ + return {}; +} + +QStringList DummyOrganizerProxy::findFiles(const QString& path, const QStringList& globFilters) const +{ + return {}; +} + +QStringList DummyOrganizerProxy::getFileOrigins(const QString &fileName) const +{ + return {}; +} + +QList DummyOrganizerProxy::findFileInfos(const QString &path, const std::function &filter) const +{ + return {}; +} + +MOBase::IDownloadManager *DummyOrganizerProxy::downloadManager() const +{ + return nullptr; +} + +MOBase::IPluginList *DummyOrganizerProxy::pluginList() const +{ + return m_plugins.get(); +} + +MOBase::IModList *DummyOrganizerProxy::modList() const +{ + return m_mods.get(); +} + +MOBase::IProfile *DummyOrganizerProxy::profile() const +{ + return nullptr; +} + +MOBase::IPluginGame const *DummyOrganizerProxy::managedGame() const +{ + return nullptr; +} + +QStringList DummyOrganizerProxy::modsSortedByProfilePriority() const +{ + return {}; +} diff --git a/src/organizerproxy.h b/src/organizerproxy.h index 6690d612..3bd70113 100644 --- a/src/organizerproxy.h +++ b/src/organizerproxy.h @@ -81,4 +81,63 @@ private: }; + +class DummyOrganizerProxy : public MOBase::IOrganizer +{ +public: + DummyOrganizerProxy(const QString &pluginName); + ~DummyOrganizerProxy(); + + virtual MOBase::IModRepositoryBridge *createNexusBridge() const; + virtual QString profileName() const; + virtual QString profilePath() const; + virtual QString downloadsPath() const; + virtual QString overwritePath() const; + virtual QString basePath() const; + virtual QString modsPath() const; + virtual MOBase::VersionInfo appVersion() const; + virtual MOBase::IModInterface *getMod(const QString &name) const; + virtual MOBase::IPluginGame *getGame(const QString &gameName) const; + virtual MOBase::IModInterface *createMod(MOBase::GuessedValue &name); + virtual bool removeMod(MOBase::IModInterface *mod); + virtual void modDataChanged(MOBase::IModInterface *mod); + virtual QVariant pluginSetting(const QString &pluginName, const QString &key) const; + virtual void setPluginSetting(const QString &pluginName, const QString &key, const QVariant &value); + virtual QVariant persistent(const QString &pluginName, const QString &key, const QVariant &def = QVariant()) const; + virtual void setPersistent(const QString &pluginName, const QString &key, const QVariant &value, bool sync = true); + virtual QString pluginDataPath() const; + virtual MOBase::IModInterface *installMod(const QString &fileName, const QString &nameSuggestion = QString()); + virtual QString resolvePath(const QString &fileName) const; + virtual QStringList listDirectories(const QString &directoryName) const; + virtual QStringList findFiles(const QString &path, const std::function &filter) const override; + virtual QStringList findFiles(const QString &path, const QStringList &globFilters) const override; + virtual QStringList getFileOrigins(const QString &fileName) const; + virtual QList findFileInfos(const QString &path, const std::function &filter) const; + + virtual MOBase::IDownloadManager *downloadManager() const; + virtual MOBase::IPluginList *pluginList() const; + virtual MOBase::IModList *modList() const; + virtual MOBase::IProfile *profile() const override; + virtual HANDLE startApplication(const QString &executable, const QStringList &args = QStringList(), const QString &cwd = "", + const QString &profile = "", const QString &forcedCustomOverwrite = "", bool ignoreCustomOverwrite = false); + virtual bool waitForApplication(HANDLE handle, LPDWORD exitCode = nullptr) const; + virtual void refreshModList(bool saveChanges); + + virtual bool onAboutToRun(const std::function &func); + virtual bool onFinishedRun(const std::function &func); + virtual bool onModInstalled(const std::function &func); + virtual bool onUserInterfaceInitialized(std::function const& func); + virtual bool onProfileChanged(std::function const& func); + virtual bool onPluginSettingChanged(std::function const& func); + + virtual MOBase::IPluginGame const *managedGame() const; + + virtual QStringList modsSortedByProfilePriority() const; + +private: + const QString &m_PluginName; + std::unique_ptr m_plugins; + std::unique_ptr m_mods; +}; + #endif // ORGANIZERPROXY_H diff --git a/src/plugincontainer.cpp b/src/plugincontainer.cpp index 4771359d..6f2670dd 100644 --- a/src/plugincontainer.cpp +++ b/src/plugincontainer.cpp @@ -173,10 +173,21 @@ bool PluginContainer::verifyPlugin(IPlugin *plugin) { if (plugin == nullptr) { return false; - } else if (!plugin->init(new OrganizerProxy(m_Organizer, this, plugin))) { + } + + IOrganizer* proxy = nullptr; + + if (m_Organizer) { + proxy = new OrganizerProxy(m_Organizer, this, plugin); + } else { + proxy = new DummyOrganizerProxy(plugin); + } + + if (!plugin->init(proxy)) { log::warn("plugin failed to initialize"); return false; } + return true; } @@ -200,7 +211,9 @@ bool PluginContainer::registerPlugin(QObject *plugin, const QString &fileName) return false; } plugin->setProperty("filename", fileName); - m_Organizer->settings().plugins().registerPlugin(pluginObj); + if (m_Organizer) { + m_Organizer->settings().plugins().registerPlugin(pluginObj); + } } { // diagnosis plugin @@ -244,7 +257,9 @@ bool PluginContainer::registerPlugin(QObject *plugin, const QString &fileName) IPluginInstaller *installer = qobject_cast(plugin); if (verifyPlugin(installer)) { bf::at_key(m_Plugins).push_back(installer); - m_Organizer->installationManager()->registerInstaller(installer); + if (m_Organizer) { + m_Organizer->installationManager()->registerInstaller(installer); + } return true; } } @@ -317,7 +332,7 @@ void PluginContainer::unloadPlugins() } // disconnect all slots before unloading plugins so plugins don't have to take care of that - if (m_Organizer != nullptr) { + if (m_Organizer) { m_Organizer->disconnectPlugins(); } @@ -363,24 +378,28 @@ void PluginContainer::loadPlugins() registerPlugin(plugin, ""); } - QFile loadCheck(qApp->property("dataPath").toString() + "/plugin_loadcheck.tmp"); - if (loadCheck.exists() && loadCheck.open(QIODevice::ReadOnly)) { - // oh, there was a failed plugin load last time. Find out which plugin was loaded last - QString fileName; - while (!loadCheck.atEnd()) { - fileName = QString::fromUtf8(loadCheck.readLine().constData()).trimmed(); - } - if (QMessageBox::question(nullptr, QObject::tr("Plugin error"), - QObject::tr("It appears the plugin \"%1\" failed to load last startup and caused MO to crash. Do you want to disable it?\n" - "(Please note: If this is the first time you see this message for this plugin you may want to give it another try. " - "The plugin may be able to recover from the problem)").arg(fileName), - QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes) == QMessageBox::Yes) { - m_Organizer->settings().plugins().addBlacklist(fileName); + QFile loadCheck; + + if (m_Organizer) { + loadCheck.setFileName(qApp->property("dataPath").toString() + "/plugin_loadcheck.tmp"); + if (loadCheck.exists() && loadCheck.open(QIODevice::ReadOnly)) { + // oh, there was a failed plugin load last time. Find out which plugin was loaded last + QString fileName; + while (!loadCheck.atEnd()) { + fileName = QString::fromUtf8(loadCheck.readLine().constData()).trimmed(); + } + if (QMessageBox::question(nullptr, QObject::tr("Plugin error"), + QObject::tr("It appears the plugin \"%1\" failed to load last startup and caused MO to crash. Do you want to disable it?\n" + "(Please note: If this is the first time you see this message for this plugin you may want to give it another try. " + "The plugin may be able to recover from the problem)").arg(fileName), + QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes) == QMessageBox::Yes) { + m_Organizer->settings().plugins().addBlacklist(fileName); + } + loadCheck.close(); } - loadCheck.close(); - } - loadCheck.open(QIODevice::WriteOnly); + loadCheck.open(QIODevice::WriteOnly); + } QString pluginPath = qApp->applicationDirPath() + "/" + ToQString(AppConfig::pluginPath()); log::debug("looking for plugins in {}", QDir::toNativeSeparators(pluginPath)); @@ -388,13 +407,20 @@ void PluginContainer::loadPlugins() while (iter.hasNext()) { iter.next(); - if (m_Organizer->settings().plugins().blacklisted(iter.fileName())) { - log::debug("plugin \"{}\" blacklisted", iter.fileName()); - continue; + + if (m_Organizer) { + if (m_Organizer->settings().plugins().blacklisted(iter.fileName())) { + log::debug("plugin \"{}\" blacklisted", iter.fileName()); + continue; + } } - loadCheck.write(iter.fileName().toUtf8()); - loadCheck.write("\n"); - loadCheck.flush(); + + if (loadCheck.isOpen()) { + loadCheck.write(iter.fileName().toUtf8()); + loadCheck.write("\n"); + loadCheck.flush(); + } + QString pluginName = iter.filePath(); if (QLibrary::isLibrary(pluginName)) { std::unique_ptr pluginLoader(new QPluginLoader(pluginName, this)); @@ -416,12 +442,16 @@ void PluginContainer::loadPlugins() } // remove the load check file on success - loadCheck.remove(); + if (loadCheck.isOpen()) { + loadCheck.remove(); + } - bf::at_key(m_Plugins).push_back(m_Organizer); bf::at_key(m_Plugins).push_back(this); - m_Organizer->connectPlugins(this); + if (m_Organizer) { + bf::at_key(m_Plugins).push_back(m_Organizer); + m_Organizer->connectPlugins(this); + } } diff --git a/src/pluginlist.cpp b/src/pluginlist.cpp index a4c1ec6d..7134d246 100644 --- a/src/pluginlist.cpp +++ b/src/pluginlist.cpp @@ -1671,3 +1671,63 @@ void PluginList::managedGameChanged(const IPluginGame *gamePlugin) { m_GamePlugin = gamePlugin; } + + + +QStringList DummyPluginList::pluginNames() const +{ + return {}; +} + +IPluginList::PluginStates DummyPluginList::state(const QString &name) const +{ + return 0; +} + +void DummyPluginList::setState(const QString &name, PluginStates state) +{ +} + +int DummyPluginList::priority(const QString &name) const +{ + return -1; +} + +int DummyPluginList::loadOrder(const QString &name) const +{ + return -1; +} + +void DummyPluginList::setLoadOrder(const QStringList &pluginList) +{ +} + +bool DummyPluginList::isMaster(const QString &name) const +{ + return false; +} + +QStringList DummyPluginList::masters(const QString &name) const +{ + return {}; +} + +QString DummyPluginList::origin(const QString &name) const +{ + return {}; +} + +bool DummyPluginList::onRefreshed(const std::function &callback) +{ + return true; +} + +bool DummyPluginList::onPluginMoved(const std::function &func) +{ + return true; +} + +bool DummyPluginList::onPluginStateChanged(const std::function &func) +{ + return true; +} diff --git a/src/pluginlist.h b/src/pluginlist.h index 0b49b86f..bfadaf4f 100644 --- a/src/pluginlist.h +++ b/src/pluginlist.h @@ -410,6 +410,24 @@ private: bool hasInfo(const ESPInfo& esp, const AdditionalInfo* info) const; }; + +class DummyPluginList : public MOBase::IPluginList +{ +public: + QStringList pluginNames() const override; + PluginStates state(const QString &name) const override; + void setState(const QString &name, PluginStates state) override; + int priority(const QString &name) const override; + int loadOrder(const QString &name) const override; + void setLoadOrder(const QStringList &pluginList) override; + bool isMaster(const QString &name) const override; + QStringList masters(const QString &name) const override; + QString origin(const QString &name) const override; + bool onRefreshed(const std::function &callback) override; + bool onPluginMoved(const std::function &func) override; + bool onPluginStateChanged(const std::function &func) override; +}; + #pragma warning(pop) #endif // PLUGINLIST_H diff --git a/src/settings.cpp b/src/settings.cpp index b286510d..593d66bf 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -1812,37 +1812,6 @@ NexusSettings::NexusSettings(Settings& parent, QSettings& settings) { } -bool NexusSettings::apiKey(QString& apiKey) const -{ - QString tempKey = getWindowsCredential("APIKEY"); - if (tempKey.isEmpty()) - return false; - - apiKey = tempKey; - return true; -} - -bool NexusSettings::setApiKey(const QString& apiKey) -{ - if (!setWindowsCredential("APIKEY", apiKey)) { - const auto e = GetLastError(); - log::error("Storing API key failed: {}", formatSystemMessage(e)); - return false; - } - - return true; -} - -bool NexusSettings::clearApiKey() -{ - return setApiKey(""); -} - -bool NexusSettings::hasApiKey() const -{ - return !getWindowsCredential("APIKEY").isEmpty(); -} - bool NexusSettings::endorsementIntegration() const { return get(m_Settings, "Settings", "endorsement_integration", true); @@ -2224,6 +2193,37 @@ void GlobalSettings::setHideTutorialQuestion(bool b) settings().setValue("HideTutorialQuestion", b); } +bool GlobalSettings::nexusApiKey(QString& apiKey) +{ + QString tempKey = getWindowsCredential("APIKEY"); + if (tempKey.isEmpty()) + return false; + + apiKey = tempKey; + return true; +} + +bool GlobalSettings::setNexusApiKey(const QString& apiKey) +{ + if (!setWindowsCredential("APIKEY", apiKey)) { + const auto e = GetLastError(); + log::error("Storing API key failed: {}", formatSystemMessage(e)); + return false; + } + + return true; +} + +bool GlobalSettings::clearNexusApiKey() +{ + return setNexusApiKey(""); +} + +bool GlobalSettings::hasNexusApiKey() +{ + return !getWindowsCredential("APIKEY").isEmpty(); +} + void GlobalSettings::resetDialogs() { setHideCreateInstanceIntro(false); diff --git a/src/settings.h b/src/settings.h index a9501b9d..f71949d2 100644 --- a/src/settings.h +++ b/src/settings.h @@ -498,24 +498,6 @@ class NexusSettings public: NexusSettings(Settings& parent, QSettings& settings); - // if the key exists from the credentials store, puts it in `apiKey` and - // returns true; otherwise, returns false and leaves `apiKey` untouched - // - bool apiKey(QString& apiKey) const; - - // sets the api key in the credentials store, removes it if empty; returns - // false on errors - // - bool setApiKey(const QString& apiKey); - - // removes the api key from the credentials store; returns false on errors - // - bool clearApiKey(); - - // returns whether an API key is currently stored - // - bool hasApiKey() const; - // returns whether endorsement integration is enabled // bool endorsementIntegration() const; @@ -844,6 +826,24 @@ public: static bool hideTutorialQuestion(); static void setHideTutorialQuestion(bool b); + // if the key exists from the credentials store, puts it in `apiKey` and + // returns true; otherwise, returns false and leaves `apiKey` untouched + // + static bool nexusApiKey(QString& apiKey); + + // sets the api key in the credentials store, removes it if empty; returns + // false on errors + // + static bool setNexusApiKey(const QString& apiKey); + + // removes the api key from the credentials store; returns false on errors + // + static bool clearNexusApiKey(); + + // returns whether an API key is currently stored + // + static bool hasNexusApiKey(); + // resets anything that the user can disable static void resetDialogs(); diff --git a/src/settingsdialognexus.cpp b/src/settingsdialognexus.cpp index 54af9b59..1ed4c58f 100644 --- a/src/settingsdialognexus.cpp +++ b/src/settingsdialognexus.cpp @@ -72,13 +72,14 @@ private: NexusConnectionUI::NexusConnectionUI( - Settings& s, QWidget* parent, + Settings* s, QAbstractButton* connectButton, QAbstractButton* disconnectButton, QAbstractButton* manualButton, QListWidget* logList) : - m_parent(parent), m_settings(s), + m_parent(parent), + m_settings(s), m_connect(connectButton), m_disconnect(disconnectButton), m_manual(manualButton), @@ -96,7 +97,7 @@ NexusConnectionUI::NexusConnectionUI( QObject::connect(manualButton, &QPushButton::clicked, [&]{ manual(); }); } - if (m_settings.nexus().hasApiKey()) { + if (GlobalSettings::hasNexusApiKey()) { addLog(tr("Connected.")); } else { addLog(tr("Not connected.")); @@ -162,7 +163,7 @@ void NexusConnectionUI::validateKey(const QString& key) { if (!m_nexusValidator) { m_nexusValidator.reset(new NexusKeyValidator( - *NexusInterface::instance().getAccessManager())); + m_settings, *NexusInterface::instance().getAccessManager())); m_nexusValidator->finished = [&](auto&& r, auto&& m, auto&& u) { onValidatorFinished(r, m, u); @@ -231,7 +232,7 @@ void NexusConnectionUI::addLog(const QString& s) bool NexusConnectionUI::setKey(const QString& key) { - const bool ret = m_settings.nexus().setApiKey(key); + const bool ret = GlobalSettings::setNexusApiKey(key); updateState(); emit keyChanged(); @@ -241,7 +242,7 @@ bool NexusConnectionUI::setKey(const QString& key) bool NexusConnectionUI::clearKey() { - const auto ret = m_settings.nexus().clearApiKey(); + const auto ret = GlobalSettings::clearNexusApiKey(); NexusInterface::instance().getAccessManager()->clearApiKey(); updateState(); @@ -274,7 +275,7 @@ void NexusConnectionUI::updateState() setButton(m_disconnect, false); setButton(m_manual, true, QObject::tr("Cancel")); } - else if (m_settings.nexus().hasApiKey()) { + else if (GlobalSettings::hasNexusApiKey()) { // api key is present setButton(m_connect, false, QObject::tr("Connect to Nexus")); setButton(m_disconnect, true); @@ -327,7 +328,8 @@ NexusSettingsTab::NexusSettingsTab(Settings& s, SettingsDialog& d) } m_connectionUI.reset(new NexusConnectionUI( - settings(), &dialog(), + &dialog(), + &settings(), ui->nexusConnect, ui->nexusDisconnect, ui->nexusManualKey, diff --git a/src/settingsdialognexus.h b/src/settingsdialognexus.h index a2d6a4f8..c915accf 100644 --- a/src/settingsdialognexus.h +++ b/src/settingsdialognexus.h @@ -13,8 +13,8 @@ class NexusConnectionUI : public QObject public: NexusConnectionUI( - Settings& s, QWidget* parent, + Settings* s, QAbstractButton* connectButton, QAbstractButton* disconnectButton, QAbstractButton* manualButton, @@ -30,7 +30,7 @@ signals: private: QWidget* m_parent; - Settings& m_settings; + Settings* m_settings; QAbstractButton* m_connect; QAbstractButton* m_disconnect; QAbstractButton* m_manual; -- cgit v1.3.1