summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/CMakeLists.txt2
-rw-r--r--src/createinstancedialog.cpp9
-rw-r--r--src/createinstancedialog.h6
-rw-r--r--src/createinstancedialogpages.cpp5
-rw-r--r--src/instancemanagerdialog.cpp2
-rw-r--r--src/main.cpp27
-rw-r--r--src/mainwindow.cpp4
-rw-r--r--src/modlist.cpp41
-rw-r--r--src/modlist.h14
-rw-r--r--src/nexusinterface.cpp28
-rw-r--r--src/nexusinterface.h6
-rw-r--r--src/nxmaccessmanager.cpp37
-rw-r--r--src/nxmaccessmanager.h11
-rw-r--r--src/organizercore.cpp4
-rw-r--r--src/organizerproxy.cpp212
-rw-r--r--src/organizerproxy.h59
-rw-r--r--src/plugincontainer.cpp88
-rw-r--r--src/pluginlist.cpp60
-rw-r--r--src/pluginlist.h18
-rw-r--r--src/settings.cpp62
-rw-r--r--src/settings.h36
-rw-r--r--src/settingsdialognexus.cpp18
-rw-r--r--src/settingsdialognexus.h4
23 files changed, 623 insertions, 130 deletions
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::CreateInstanceDialog> ui;
const PluginContainer& m_pc;
+ Settings* m_settings;
std::vector<std::unique_ptr<cid::Page>> 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 <http://www.gnu.org/licenses/>.
#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> 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<QString, int> 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<unsigned int>(), 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<void(const QString&, ModStates)> &func)
+{
+ return true;
+}
+
+bool DummyModList::onModMoved(const std::function<void (const QString &, int, int)> &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<void(const QString&, ModStates)> &func) override;
+ bool onModMoved(const std::function<void (const QString &, int, int)> &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 <http://www.gnu.org/licenses/>.
#include "nxmaccessmanager.h"
#include "selectiondialog.h"
#include "bbcode.h"
+#include "settings.h"
#include <utility.h>
#include "shared/util.h"
#include <log.h>
@@ -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<QNetworkReply::RawHeaderPair>& 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<NXMRequestInfo>::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<std::chrono::seconds> 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 <http://www.gnu.org/licenses/>.
namespace MOBase { class IPluginGame; }
namespace Ui { class ValidationProgressDialog; }
class NXMAccessManager;
+class Settings;
class NexusSSOLogin
{
@@ -146,7 +147,7 @@ public:
std::function<FinishedCallback> finished;
std::function<void (const ValidationAttempt&)> 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<std::unique_ptr<ValidationAttempt>> m_attempts;
void createAttempts(const std::vector<std::chrono::seconds>& timeouts);
+ std::vector<std::chrono::seconds> 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::ValidationProgressDialog> 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<ValidationProgressDialog> 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<void ()> 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::function<void(QString const&, c
// Always call this one, otherwise plugin cannot detect they are being enabled / disabled:
return m_Proxied->onPluginSettingChanged(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<QString> &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<bool (const QString &)> &func)
+{
+ return true;
+}
+
+bool DummyOrganizerProxy::onFinishedRun(const std::function<void (const QString &, unsigned int)> &func)
+{
+ return true;
+}
+
+bool DummyOrganizerProxy::onModInstalled(const std::function<void (const QString &)> &func)
+{
+ return true;
+}
+
+bool DummyOrganizerProxy::onUserInterfaceInitialized(std::function<void(QMainWindow*)> const& func)
+{
+ return true;
+}
+
+bool DummyOrganizerProxy::onProfileChanged(std::function<void(MOBase::IProfile*, MOBase::IProfile*)> const& func)
+{
+ return true;
+}
+
+bool DummyOrganizerProxy::onPluginSettingChanged(std::function<void(QString const&, const QString& key, const QVariant&, const QVariant&)> 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<bool(const QString&)> &filter) const
+{
+ return {};
+}
+
+QStringList DummyOrganizerProxy::findFiles(const QString& path, const QStringList& globFilters) const
+{
+ return {};
+}
+
+QStringList DummyOrganizerProxy::getFileOrigins(const QString &fileName) const
+{
+ return {};
+}
+
+QList<MOBase::IOrganizer::FileInfo> DummyOrganizerProxy::findFileInfos(const QString &path, const std::function<bool (const MOBase::IOrganizer::FileInfo &)> &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<QString> &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<bool(const QString &)> &filter) const override;
+ virtual QStringList findFiles(const QString &path, const QStringList &globFilters) const override;
+ virtual QStringList getFileOrigins(const QString &fileName) const;
+ virtual QList<FileInfo> findFileInfos(const QString &path, const std::function<bool(const FileInfo&)> &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<bool(const QString&)> &func);
+ virtual bool onFinishedRun(const std::function<void (const QString&, unsigned int)> &func);
+ virtual bool onModInstalled(const std::function<void (const QString&)> &func);
+ virtual bool onUserInterfaceInitialized(std::function<void(QMainWindow*)> const& func);
+ virtual bool onProfileChanged(std::function<void(MOBase::IProfile*, MOBase::IProfile*)> const& func);
+ virtual bool onPluginSettingChanged(std::function<void(QString const&, const QString& key, const QVariant&, const QVariant&)> const& func);
+
+ virtual MOBase::IPluginGame const *managedGame() const;
+
+ virtual QStringList modsSortedByProfilePriority() const;
+
+private:
+ const QString &m_PluginName;
+ std::unique_ptr<MOBase::IPluginList> m_plugins;
+ std::unique_ptr<MOBase::IModList> 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<IPluginInstaller*>(plugin);
if (verifyPlugin(installer)) {
bf::at_key<IPluginInstaller>(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<QPluginLoader> 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<IPluginDiagnose>(m_Plugins).push_back(m_Organizer);
bf::at_key<IPluginDiagnose>(m_Plugins).push_back(this);
- m_Organizer->connectPlugins(this);
+ if (m_Organizer) {
+ bf::at_key<IPluginDiagnose>(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<void()> &callback)
+{
+ return true;
+}
+
+bool DummyPluginList::onPluginMoved(const std::function<void (const QString &, int, int)> &func)
+{
+ return true;
+}
+
+bool DummyPluginList::onPluginStateChanged(const std::function<void (const QString &, PluginStates)> &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<void()> &callback) override;
+ bool onPluginMoved(const std::function<void (const QString &, int, int)> &func) override;
+ bool onPluginStateChanged(const std::function<void (const QString &, PluginStates)> &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<bool>(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;