From 3bca0e761597f590fa3b1c6a57ee325e774e3f49 Mon Sep 17 00:00:00 2001 From: isanae <14251494+isanae@users.noreply.github.com> Date: Sun, 10 Jan 2021 22:06:38 -0500 Subject: split run() into setup() and run() this is so command line processing can happen outside of MOApplication many important objects were local to run(), so they're not members of MOApplication instead --- src/instancemanager.cpp | 10 +-- src/instancemanager.h | 4 +- src/main.cpp | 60 ++++++++++++++++- src/moapplication.cpp | 174 +++++++++++++++++++----------------------------- src/moapplication.h | 27 +++++--- 5 files changed, 152 insertions(+), 123 deletions(-) (limited to 'src') diff --git a/src/instancemanager.cpp b/src/instancemanager.cpp index 18604bf1..a9905b75 100644 --- a/src/instancemanager.cpp +++ b/src/instancemanager.cpp @@ -544,7 +544,7 @@ void InstanceManager::clearOverrides() m_overrideProfileName = {}; } -std::optional InstanceManager::currentInstance() const +std::unique_ptr InstanceManager::currentInstance() const { const QString profile = m_overrideProfileName ? *m_overrideProfileName : ""; @@ -555,20 +555,20 @@ std::optional InstanceManager::currentInstance() const if (!allowedToChangeInstance()) { // force portable instance - return Instance(portablePath(), true, profile); + return std::make_unique(portablePath(), true, profile); } if (name.isEmpty()) { if (portableInstanceExists()) { // use portable - return Instance(portablePath(), true, profile); + return std::make_unique(portablePath(), true, profile); } else { // no instance set return {}; } } - return Instance(instancePath(name), false, profile); + return std::make_unique(instancePath(name), false, profile); } void InstanceManager::clearCurrentInstance() @@ -772,7 +772,7 @@ bool InstanceManager::validInstanceName(const QString& instanceName) const -std::optional selectInstance() +std::unique_ptr selectInstance() { auto& m = InstanceManager::singleton(); diff --git a/src/instancemanager.h b/src/instancemanager.h index 73082da2..893b88e4 100644 --- a/src/instancemanager.h +++ b/src/instancemanager.h @@ -264,7 +264,7 @@ public: // instance name in the registry is empty or non-existent and there is no // portable instance set up // - std::optional currentInstance() const; + std::unique_ptr currentInstance() const; // sets the instance name in the registry so the same instance is opened next // time MO runs @@ -359,7 +359,7 @@ enum class SetupInstanceResults // instance manager dialog and returns the selected instance or empty if the // user cancelled // -std::optional selectInstance(); +std::unique_ptr selectInstance(); // calls instance.setup() tries to handle problems by itself: // diff --git a/src/main.cpp b/src/main.cpp index 877236e1..362caaad 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4,8 +4,10 @@ #include "organizercore.h" #include "commandline.h" #include "env.h" +#include "instancemanager.h" #include "thread_utils.h" #include "shared/util.h" +#include #include using namespace MOBase; @@ -31,7 +33,7 @@ int main(int argc, char *argv[]) TimeThis tt("main()"); QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); - MOApplication app(cl, argc, argv); + MOApplication app(argc, argv); MOMultiProcess multiProcess(cl.multiple()); if (multiProcess.ephemeral()) { @@ -40,7 +42,61 @@ int main(int argc, char *argv[]) tt.stop(); - return app.run(multiProcess); + + // MO runs in a loop because it can be restarted in several ways, such as + // when switching instances or changing some settings + for (;;) + { + try + { + auto& m = InstanceManager::singleton(); + + if (cl.instance()) { + m.overrideInstance(*cl.instance()); + } + + if (cl.profile()) { + m.overrideProfile(*cl.profile()); + } + + { + const auto r = app.setup(multiProcess); + + if (r == RestartExitCode) { + // resets things when MO is "restarted" + app.resetForRestart(); + + // don't reprocess command line + cl.clear(); + + continue; + } + } + + if (auto r=cl.setupCore(app.core())) { + return *r; + } + + const auto r = app.run(multiProcess); + + if (r == RestartExitCode) { + // resets things when MO is "restarted" + app.resetForRestart(); + + // don't reprocess command line + cl.clear(); + + continue; + } + + return r; + } + catch (const std::exception &e) + { + reportError(e.what()); + return 1; + } + } } int forwardToPrimary(MOMultiProcess& multiProcess, const cl::CommandLine& cl) diff --git a/src/moapplication.cpp b/src/moapplication.cpp index 9a77c17e..d1622d59 100644 --- a/src/moapplication.cpp +++ b/src/moapplication.cpp @@ -155,77 +155,43 @@ void addDllsToPath() } -MOApplication::MOApplication(cl::CommandLine& cl, int& argc, char** argv) - : QApplication(argc, argv), m_cl(cl) +MOApplication::MOApplication(int& argc, char** argv) + : QApplication(argc, argv) { TimeThis tt("MOApplication()"); - connect(&m_StyleWatcher, &QFileSystemWatcher::fileChanged, [&](auto&& file){ + connect(&m_styleWatcher, &QFileSystemWatcher::fileChanged, [&](auto&& file){ log::debug("style file '{}' changed, reloading", file); updateStyle(file); }); - m_DefaultStyle = style()->objectName(); + m_defaultStyle = style()->objectName(); setStyle(new ProxyStyle(style())); addDllsToPath(); } -int MOApplication::run(MOMultiProcess& multiProcess) +OrganizerCore& MOApplication::core() { - TimeThis tt("MOApplication run() to doOneRun()"); - - auto& m = InstanceManager::singleton(); - - if (m_cl.instance()) - m.overrideInstance(*m_cl.instance()); + return *m_core; +} - if (m_cl.profile()) { - m.overrideProfile(*m_cl.profile()); - } +int MOApplication::setup(MOMultiProcess& multiProcess) +{ + TimeThis tt("MOApplication setup()"); // makes plugin data path available to plugins, see // IOrganizer::getPluginDataPath() MOBase::details::setPluginDataPath(OrganizerCore::pluginDataPath()); - // MO runs in a loop because it can be restarted in several ways, such as - // when switching instances or changing some settings - for (;;) - { - try - { - tt.stop(); - - const auto r = doOneRun(multiProcess); - - if (r == RestartExitCode) { - // resets things when MO is "restarted" - resetForRestart(); - continue; - } - - return r; - } - catch (const std::exception &e) - { - reportError(e.what()); - return 1; - } - } -} - -int MOApplication::doOneRun(MOMultiProcess& multiProcess) -{ - TimeThis tt("MOApplication::doOneRun() instances"); - // figuring out the current instance - auto currentInstance = getCurrentInstance(); - if (!currentInstance) { + m_instance = getCurrentInstance(); + if (!m_instance) { return 1; } // first time the data path is available, set the global property and log // directory, then log a bunch of debug stuff - const QString dataPath = currentInstance->directory(); + const QString dataPath = m_instance->directory(); setProperty("dataPath", dataPath); if (!setLogDirectory(dataPath)) { @@ -245,7 +211,7 @@ int MOApplication::doOneRun(MOMultiProcess& multiProcess) log::debug("another instance of MO is running but --multiple was given"); } - log::info("data path: {}", currentInstance->directory()); + log::info("data path: {}", m_instance->directory()); log::info("working directory: {}", QDir::currentPath()); @@ -261,44 +227,41 @@ int MOApplication::doOneRun(MOMultiProcess& multiProcess) // loading settings - Settings settings(currentInstance->iniPath(), true); - log::getDefault().setLevel(settings.diagnostics().logLevel()); - log::debug("using ini at '{}'", settings.filename()); + m_settings.reset(new Settings(m_instance->iniPath(), true)); + log::getDefault().setLevel(m_settings->diagnostics().logLevel()); + log::debug("using ini at '{}'", m_settings->filename()); - OrganizerCore::setGlobalCoreDumpType(settings.diagnostics().coreDumpType()); + OrganizerCore::setGlobalCoreDumpType(m_settings->diagnostics().coreDumpType()); tt.start("MOApplication::doOneRun() log and checks"); // logging and checking env::Environment env; - env.dump(settings); - settings.dump(); + env.dump(*m_settings); + m_settings->dump(); sanity::checkEnvironment(env); - const auto moduleNotification = env.onModuleLoaded(qApp, [](auto&& m) { + m_modules = std::move(env.onModuleLoaded(qApp, [](auto&& m) { if (m.interesting()) { log::debug("loaded module {}", m.toString()); } sanity::checkIncompatibleModule(m); - }); + })); - // this must outlive `organizer` - std::unique_ptr pluginContainer; - // nexus interface tt.start("MOApplication::doOneRun() NexusInterface"); log::debug("initializing nexus interface"); - NexusInterface ni(&settings); + m_nexus.reset(new NexusInterface(m_settings.get())); // organizer core tt.start("MOApplication::doOneRun() OrganizerCore"); log::debug("initializing core"); - OrganizerCore organizer(settings); - if (!organizer.bootstrap()) { + m_core.reset(new OrganizerCore(*m_settings)); + if (!m_core->bootstrap()) { reportError("failed to set up data paths"); InstanceManager::singleton().clearCurrentInstance(); return 1; @@ -308,58 +271,59 @@ int MOApplication::doOneRun(MOMultiProcess& multiProcess) tt.start("MOApplication::doOneRun() plugins"); log::debug("initializing plugins"); - pluginContainer = std::make_unique(&organizer); - pluginContainer->loadPlugins(); + m_plugins = std::make_unique(m_core.get()); + m_plugins->loadPlugins(); // instance - if (auto r=setupInstanceLoop(*currentInstance, *pluginContainer)) { + if (auto r=setupInstanceLoop(*m_instance, *m_plugins)) { return *r; } - if (currentInstance->isPortable()) { + if (m_instance->isPortable()) { log::debug("this is a portable instance"); } tt.start("MOApplication::doOneRun() OrganizerCore setup"); - sanity::checkPaths(*currentInstance->gamePlugin(), settings); + sanity::checkPaths(*m_instance->gamePlugin(), *m_settings); // setting up organizer core - organizer.setManagedGame(currentInstance->gamePlugin()); - organizer.createDefaultProfile(); + m_core->setManagedGame(m_instance->gamePlugin()); + m_core->createDefaultProfile(); log::info( "using game plugin '{}' ('{}', variant {}, steam id '{}') at {}", - currentInstance->gamePlugin()->gameName(), - currentInstance->gamePlugin()->gameShortName(), - (settings.game().edition().value_or("").isEmpty() ? - "(none)" : *settings.game().edition()), - currentInstance->gamePlugin()->steamAPPId(), - currentInstance->gamePlugin()->gameDirectory().absolutePath()); + m_instance->gamePlugin()->gameName(), + m_instance->gamePlugin()->gameShortName(), + (m_settings->game().edition().value_or("").isEmpty() ? + "(none)" : *m_settings->game().edition()), + m_instance->gamePlugin()->steamAPPId(), + m_instance->gamePlugin()->gameDirectory().absolutePath()); CategoryFactory::instance().loadCategories(); - organizer.updateExecutablesList(); - organizer.updateModInfoFromDisc(); - organizer.setCurrentProfile(currentInstance->profileName()); + m_core->updateExecutablesList(); + m_core->updateModInfoFromDisc(); + m_core->setCurrentProfile(m_instance->profileName()); + + return 0; +} +int MOApplication::run(MOMultiProcess& multiProcess) +{ // checking command line - tt.start("MOApplication::doOneRun() command line"); - if (auto r=m_cl.setupCore(organizer)) { - return *r; - } + TimeThis tt("MOApplication::run()"); // show splash tt.start("MOApplication::doOneRun() splash"); - MOSplash splash( - settings, currentInstance->directory(), currentInstance->gamePlugin()); + MOSplash splash(*m_settings, m_instance->directory(), m_instance->gamePlugin()); tt.start("MOApplication::doOneRun() finishing"); // start an api check QString apiKey; if (GlobalSettings::nexusApiKey(apiKey)) { - ni.getAccessManager()->apiCheck(apiKey); + m_nexus->getAccessManager()->apiCheck(apiKey); } // tutorials @@ -367,12 +331,12 @@ int MOApplication::doOneRun(MOMultiProcess& multiProcess) TutorialManager::init( qApp->applicationDirPath() + "/" + QString::fromStdWString(AppConfig::tutorialsPath()) + "/", - &organizer); + m_core.get()); // styling - if (!setStyleFile(settings.interface().styleName().value_or(""))) { + if (!setStyleFile(m_settings->interface().styleName().value_or(""))) { // disable invalid stylesheet - settings.interface().setStyleName(""); + m_settings->interface().setStyleName(""); } @@ -380,16 +344,16 @@ int MOApplication::doOneRun(MOMultiProcess& multiProcess) { tt.start("MOApplication::doOneRun() MainWindow setup"); - MainWindow mainWindow(settings, organizer, *pluginContainer); + MainWindow mainWindow(*m_settings, *m_core, *m_plugins); // the nexus interface can show dialogs, make sure they're parented to the // main window - ni.getAccessManager()->setTopLevelWidget(&mainWindow); + m_nexus->getAccessManager()->setTopLevelWidget(&mainWindow); QObject::connect(&mainWindow, SIGNAL(styleChanged(QString)), this, SLOT(setStyleFile(QString))); - QObject::connect(&multiProcess, SIGNAL(messageSent(QString)), &organizer, + QObject::connect(&multiProcess, SIGNAL(messageSent(QString)), m_core.get(), SLOT(externalMessage(QString))); @@ -404,16 +368,16 @@ int MOApplication::doOneRun(MOMultiProcess& multiProcess) mainWindow.close(); // main window is about to be destroyed - ni.getAccessManager()->setTopLevelWidget(nullptr); + m_nexus->getAccessManager()->setTopLevelWidget(nullptr); } // reset geometry if the flag was set from the settings dialog - settings.geometry().resetIfNeeded(); + m_settings->geometry().resetIfNeeded(); return res; } -std::optional MOApplication::getCurrentInstance() +std::unique_ptr MOApplication::getCurrentInstance() { auto& m = InstanceManager::singleton(); auto currentInstance = m.currentInstance(); @@ -422,8 +386,6 @@ std::optional MOApplication::getCurrentInstance() { // clear any overrides that might have been given on the command line m.clearOverrides(); - m_cl.clear(); - currentInstance = selectInstance(); } else @@ -433,7 +395,6 @@ std::optional MOApplication::getCurrentInstance() // clear any overrides that might have been given on the command line m.clearOverrides(); - m_cl.clear(); if (m.hasAnyInstances()) { MOShared::criticalOnTop(QObject::tr( @@ -496,31 +457,34 @@ void MOApplication::resetForRestart() // the previous instance gets deleted log::getDefault().setFile({}); - // don't reprocess command line - m_cl.clear(); - // clear instance and profile overrides InstanceManager::singleton().clearOverrides(); + + m_core = {}; + m_plugins = {}; + m_nexus = {}; + m_settings = {}; + m_instance = {}; } bool MOApplication::setStyleFile(const QString& styleName) { // remove all files from watch - QStringList currentWatch = m_StyleWatcher.files(); + QStringList currentWatch = m_styleWatcher.files(); if (currentWatch.count() != 0) { - m_StyleWatcher.removePaths(currentWatch); + m_styleWatcher.removePaths(currentWatch); } // set new stylesheet or clear it if (styleName.length() != 0) { QString styleSheetName = applicationDirPath() + "/" + MOBase::ToQString(AppConfig::stylesheetsPath()) + "/" + styleName; if (QFile::exists(styleSheetName)) { - m_StyleWatcher.addPath(styleSheetName); + m_styleWatcher.addPath(styleSheetName); updateStyle(styleSheetName); } else { updateStyle(styleName); } } else { - setStyle(new ProxyStyle(QStyleFactory::create(m_DefaultStyle))); + setStyle(new ProxyStyle(QStyleFactory::create(m_defaultStyle))); setStyleSheet(""); } return true; @@ -551,7 +515,7 @@ void MOApplication::updateStyle(const QString& fileName) setStyleSheet(""); setStyle(new ProxyStyle(QStyleFactory::create(fileName))); } else { - setStyle(new ProxyStyle(QStyleFactory::create(m_DefaultStyle))); + setStyle(new ProxyStyle(QStyleFactory::create(m_defaultStyle))); if (QFile::exists(fileName)) { setStyleSheet(QString("file:///%1").arg(fileName)); } else { diff --git a/src/moapplication.h b/src/moapplication.h index 91b8023a..7e427ca8 100644 --- a/src/moapplication.h +++ b/src/moapplication.h @@ -27,20 +27,24 @@ class Settings; class MOMultiProcess; class Instance; class PluginContainer; +class OrganizerCore; +class NexusInterface; namespace MOBase { class IPluginGame; } -namespace cl { class CommandLine; } +namespace env { class ModuleNotification; } class MOApplication : public QApplication { Q_OBJECT public: - MOApplication(cl::CommandLine& cl, int& argc, char** argv); + MOApplication(int& argc, char** argv); - // sets up everything, creates the main window and runs it - // + int setup(MOMultiProcess& multiProcess); int run(MOMultiProcess& multiProcess); + void resetForRestart(); + + OrganizerCore& core(); virtual bool notify(QObject* receiver, QEvent* event); @@ -51,16 +55,21 @@ private slots: void updateStyle(const QString& fileName); private: - QFileSystemWatcher m_StyleWatcher; - QString m_DefaultStyle; - cl::CommandLine& m_cl; + QFileSystemWatcher m_styleWatcher; + QString m_defaultStyle; + std::unique_ptr m_modules; + + std::unique_ptr m_instance; + std::unique_ptr m_settings; + std::unique_ptr m_nexus; + std::unique_ptr m_plugins; + std::unique_ptr m_core; int doOneRun(MOMultiProcess& multiProcess); - std::optional getCurrentInstance(); + std::unique_ptr getCurrentInstance(); std::optional setupInstanceLoop(Instance& currentInstance, PluginContainer& pc); void purgeOldFiles(); - void resetForRestart(); }; -- cgit v1.3.1