diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 4c538a949..49f4aa8e4 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -24,8 +24,8 @@ jobs: - name: Install Qt uses: jurplel/install-qt-action@v3 with: - version: 6.7.0 - modules: + version: 6.7.1 + modules: qtpositioning qtwebchannel qtwebengine qtwebsockets cache: true - uses: actions/checkout@v4 diff --git a/src/env.cpp b/src/env.cpp index 9e67ef884..5dab489ed 100644 --- a/src/env.cpp +++ b/src/env.cpp @@ -1081,7 +1081,7 @@ std::wstring safeVersion() { try { // this can throw - return MOShared::createVersionInfo().displayString(3).toStdWString() + L"-"; + return MOShared::createVersionInfo().string().toStdWString() + L"-"; } catch (...) { return {}; } diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index cb6031ed1..20a849f49 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -639,9 +639,10 @@ MainWindow::~MainWindow() void MainWindow::updateWindowTitle(const APIUserAccount& user) { //"\xe2\x80\x93" is an "em dash", a longer "-" - QString title = QString("%1 \xe2\x80\x93 Mod Organizer v%2") - .arg(m_OrganizerCore.managedGame()->displayGameName(), - m_OrganizerCore.getVersion().displayString(3)); + QString title = + QString("%1 \xe2\x80\x93 Mod Organizer v%2") + .arg(m_OrganizerCore.managedGame()->displayGameName(), + m_OrganizerCore.getVersion().string(Version::FormatCondensed)); if (!user.name().isEmpty()) { const QString premium = (user.type() == APIUserAccountTypes::Premium ? "*" : ""); @@ -1039,7 +1040,8 @@ void MainWindow::checkForProblemsImpl() void MainWindow::about() { - AboutDialog(m_OrganizerCore.getVersion().displayString(3), this).exec(); + AboutDialog(m_OrganizerCore.getVersion().string(Version::FormatCondensed), this) + .exec(); } void MainWindow::createEndorseMenu() @@ -2163,8 +2165,9 @@ void MainWindow::processUpdates() auto& settings = m_OrganizerCore.settings(); const auto earliest = QVersionNumber::fromString("2.1.2").normalized(); - const auto lastVersion = settings.version().value_or(earliest); - const auto currentVersion = m_OrganizerCore.getVersion().asQVersionNumber(); + const auto lastVersion = settings.version().value_or(earliest); + const auto currentVersion = + QVersionNumber::fromString(m_OrganizerCore.getVersion().string()).normalized(); m_LastVersion = lastVersion; @@ -2967,8 +2970,7 @@ void MainWindow::actionEndorseMO() QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) { NexusInterface::instance().requestToggleEndorsement( game->gameShortName(), game->nexusModOrganizerID(), - m_OrganizerCore.getVersion().canonicalString(), true, this, QVariant(), - QString()); + m_OrganizerCore.getVersion().string(), true, this, QVariant(), QString()); } } @@ -2989,8 +2991,7 @@ void MainWindow::actionWontEndorseMO() QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) { NexusInterface::instance().requestToggleEndorsement( game->gameShortName(), game->nexusModOrganizerID(), - m_OrganizerCore.getVersion().canonicalString(), false, this, QVariant(), - QString()); + m_OrganizerCore.getVersion().string(), false, this, QVariant(), QString()); } } diff --git a/src/moapplication.cpp b/src/moapplication.cpp index bf6a40747..9558aa6b2 100644 --- a/src/moapplication.cpp +++ b/src/moapplication.cpp @@ -203,8 +203,8 @@ int MOApplication::setup(MOMultiProcess& multiProcess, bool forceSelect) log::debug("command line: '{}'", QString::fromWCharArray(GetCommandLineW())); log::info("starting Mod Organizer version {} revision {} in {}, usvfs: {}", - createVersionInfo().displayString(3), GITID, - QCoreApplication::applicationDirPath(), MOShared::getUsvfsVersionString()); + createVersionInfo().string(), GITID, QCoreApplication::applicationDirPath(), + MOShared::getUsvfsVersionString()); if (multiProcess.secondary()) { log::debug("another instance of MO is running but --multiple was given"); diff --git a/src/modinfo.h b/src/modinfo.h index d9e87ae05..bbb1aae3c 100644 --- a/src/modinfo.h +++ b/src/modinfo.h @@ -732,7 +732,7 @@ class ModInfo : public QObject, public MOBase::IModInterface * * @note Currently, this changes the color of the cell under the "Notes" column. */ - virtual void setColor(QColor color) {} + virtual void setColor([[maybe_unused]] QColor color) {} /** * @brief Adds the information that a file has been installed into this mod. diff --git a/src/nexusinterface.cpp b/src/nexusinterface.cpp index 359b7e413..ecd33cb67 100644 --- a/src/nexusinterface.cpp +++ b/src/nexusinterface.cpp @@ -274,9 +274,8 @@ NexusInterface::NexusInterface(Settings* s) : m_PluginContainer(nullptr) g_instance = this; m_User.limits(defaultAPILimits()); - m_MOVersion = createVersionInfo(); - m_AccessManager = new NXMAccessManager(this, s, m_MOVersion.displayString(3)); + m_AccessManager = new NXMAccessManager(this, s, createVersionInfo().string()); m_DiskCache = new QNetworkDiskCache(this); diff --git a/src/nexusinterface.h b/src/nexusinterface.h index 5fab222f1..f6efef1d9 100644 --- a/src/nexusinterface.h +++ b/src/nexusinterface.h @@ -681,7 +681,6 @@ private slots: NXMAccessManager* m_AccessManager; std::list m_ActiveRequest; QQueue m_RequestQueue; - MOBase::VersionInfo m_MOVersion; PluginContainer* m_PluginContainer; APIUserAccount m_User; }; diff --git a/src/organizer_en.ts b/src/organizer_en.ts index 46169a5ad..5715889bd 100644 --- a/src/organizer_en.ts +++ b/src/organizer_en.ts @@ -2164,43 +2164,6 @@ Right now the only case I know of where this needs to be overwritten is for the - - FindDialog - - - Find - - - - - Find what: - - - - - - Search term - - - - - - Find next occurence from current file position. - - - - - &Find Next - - - - - - - Close - - - ForcedLoadDialog @@ -2280,139 +2243,6 @@ Right now the only case I know of where this needs to be overwritten is for the - - GamebryoModDataContent - - - Plugins (ESP/ESM/ESL) - - - - - Optional Plugins - - - - - Interface - - - - - Meshes - - - - - Bethesda Archive - - - - - Scripts (Papyrus) - - - - - Script Extender Plugin - - - - - Script Extender Files - - - - - SkyProc Patcher - - - - - Sound or Music - - - - - Textures - - - - - MCM Configuration - - - - - INI Files - - - - - FaceGen Data - - - - - ModGroup Files - - - - - GamebryoSaveGameInfoWidget - - - Save # - - - - - Character - - - - - Level - - - - - Location - - - - - Date - - - - - Has Script Extender Data - - - - - Missing ESPs - - - - - - - None - - - - - Missing ESHs - - - - - Missing ESLs - - - GeneralConflictsTab @@ -2936,100 +2766,6 @@ This is likely due to a corrupted or incompatible download or unrecognized archi - - MOBase::FilterWidget - - - Filter options - - - - - Use regular expressions - - - - - Use regular expressions in filters - - - - - Case sensitive - - - - - Make regular expressions case sensitive (/i) - leave "(/i)" verbatim - - - - - Extended - - - - - Ignores unescaped whitespace in regular expressions (/x) - leave "(/x)" verbatim - - - - - Keep selection in view - - - - - Scroll to keep the current selection in view after filtering - - - - - MOBase::TextViewer - - - Save changes? - - - - - Do you want to save changes to %1? - - - - - failed to write to %1 - - - - - file not found: %1 - - - - - Save - - - - - MOBase::TutorialControl - - - Tutorial failed to start, please check "mo_interface.log" for details. - - - - - MOBase::TutorialManager - - - tutorial manager not set up yet - - - MOMultiProcess @@ -3267,7 +3003,7 @@ This is likely due to a corrupted or incompatible download or unrecognized archi - + Sort the plugins using LOOT. @@ -3401,7 +3137,7 @@ This is likely due to a corrupted or incompatible download or unrecognized archi - + Name @@ -3659,7 +3395,7 @@ This is likely due to a corrupted or incompatible download or unrecognized archi - + Endorse Mod Organizer @@ -3770,142 +3506,142 @@ Error: %1 - + There are notifications to read - + There are no notifications - + Endorse - + Won't Endorse - + First Steps Translation strings for tutorial names - + Conflict Resolution - + Overview - + Help on UI - + Documentation - - + + Game Support Wiki - + Chat on Discord - + Report Issue - + Tutorials - + About - + About Qt - + Please enter a name for the new profile - + failed to create profile: %1 - + Show tutorial? - + You are starting Mod Organizer for the first time. Do you want to show a tutorial of its basic features? If you choose no you can always start the tutorial from the "Help" menu. - + Never ask to show tutorials - + Do you know how to mod this game? Do you need to learn? There's a game support wiki available! Click OK to open the wiki. In the future, you can access this link from the "Help" menu. - + Category Setup - + Please choose how to handle the default category setup. If you've already connected to Nexus, you can automatically import Nexus categories for this game (if applicable). Otherwise, use the old Mod Organizer default category structure, or leave the categories blank (for manual setup). - - + + &Import Nexus Categories - + Use &Old Category Defaults - + Do &Nothing - + This is your first time running version 2.5 or higher with an old MO2 instance. The category system now relies on an updated system to map Nexus categories. In order to assign Nexus categories automatically, you will need to import the Nexus categories for the currently managed game and map them to your preferred category structure. @@ -3916,321 +3652,321 @@ As a final option, you can disable Nexus category mapping altogether, which can - + &Open Categories Dialog - + &Disable Nexus Mappings - + &Close - + &Don't show this again - + Downloads in progress - + There are still downloads in progress, do you really want to quit? - + Plugin "%1" failed: %2 - + Plugin "%1" failed - + <Edit...> - + (no executables) - + This bsa is enabled in the ini file so it may be required! - + Activating Network Proxy - + Notice: Your current MO version (%1) is lower than the previously used one (%2). The GUI may not downgrade gracefully, so you may experience oddities. However, there should be no serious issues. - + failed to change origin name: %1 - + failed to move "%1" from mod "%2" to "%3": %4 - + Open Game folder - + Open MyGames folder - + Open INIs folder - + Open Instance folder - + Open Mods folder - + Open Profile folder - + Open Downloads folder - + Open MO2 Install folder - + Open MO2 Plugins folder - + Open MO2 Stylesheets folder - + Open MO2 Logs folder - + Restart Mod Organizer - + Mod Organizer must restart to finish configuration changes - + Restart - + Continue - + Some things might be weird. - + Can't change download directory while downloads are in progress! - + Update available - + Do you want to endorse Mod Organizer on %1 now? - + Abstain from Endorsing Mod Organizer - + Are you sure you want to abstain from endorsing Mod Organizer 2? You will have to visit the mod page on the %1 Nexus site to change your mind. - + Thank you for endorsing MO2! :) - + Please reconsider endorsing MO2 on Nexus! - + There is no supported sort mechanism for this game. You will probably have to use a third-party tool. - + None of your %1 mods appear to have had recent file updates. - + All of your mods have been checked recently. We restrict update checks to help preserve your available API requests. - + Thank you! - + Thank you for your endorsement! - + Mod ID %1 no longer seems to be available on Nexus. - + Error %1: Request to Nexus failed: %2 - - + + failed to read %1: %2 - + Error - + failed to extract %1 (errorcode %2) - + Extract BSA - + This archive contains invalid hashes. Some files may be broken. - + Extract... - + Remove '%1' from the toolbar - + Backup of load order created - + Choose backup to restore - + No Backups - + There are no backups to restore - - + + Restore failed - - + + Failed to restore the backup. Errorcode: %1 - + Backup of mod list created - + A file with the same name has already been downloaded. What would you like to do? - + Overwrite - + Rename new file - + Ignore file @@ -5774,32 +5510,32 @@ Please enter a name: NexusInterface - + Please pick the mod ID for "%1" - + You must authorize MO2 in Settings -> Nexus to use the Nexus API. - + You've exceeded the Nexus API rate limit and requests are now being throttled. Your next batch of requests will be available in approximately %1 minutes and %2 seconds. - + Aborting download: Either you clicked on a premium-only link and your account is not premium, or the download link was generated by a different account than the one stored in Mod Organizer. - + empty response - + invalid response @@ -6266,168 +6002,168 @@ Continue? PluginList - + Name - + Priority - + Mod Index - + Flags - - + + unknown - + Name of the plugin - + Emblems to highlight things that might require attention. - + Load priority of plugins. The higher, the more "important" it is and thus overwrites data from plugins with lower priority. - + Determines the formids of objects originating from this mods. - + failed to update esp info for file %1 (source id: %2), error: %3 - + Plugin not found: %1 - + Origin - + This plugin can't be disabled or moved (enforced by the game). - + This plugin can't be disabled (enforced by the game). - + Author - + Description - + Missing Masters - + Enabled Masters - + Loads Archives - + There are Archives connected to this plugin. Their assets will be added to your game, overwriting in case of conflicts following the plugin order. Loose files will always overwrite assets from Archives. (This flag only checks for Archives from the same mod as the plugin) - + Loads INI settings - + There is an ini file connected to this plugin. Its settings will be added to your game settings, overwriting in case of conflicts. - + This %1 is flagged as a light plugin (ESL). It will adhere to the %1 load order but the records will be loaded in ESL space (FE/FF). You can have up to 4096 light plugins in addition to other plugin types. - + This ESM is flagged as a medium plugin (ESH). It adheres to the ESM load order but loads records in ESH space (FD). You can have 256 medium plugins in addition to other plugin types. - + WARNING: This plugin is both light and medium flagged. This could indicate that the file was saved improperly and may have mismatched record references. Use it at your own risk. - + This is a dummy plugin. It contains no records and is typically used to load a paired archive file. - + Light plugins (ESL) are not supported by this game. - + This game does not currently permit custom plugin loading. There may be manual workarounds. - + Incompatible with %1 - + Depends on missing %1 - + Warning - + Error - + failed to restore load order for %1 @@ -7249,13 +6985,13 @@ p, li { white-space: pre-wrap; } - - - - - - - + + + + + + + Cancel @@ -7504,8 +7240,6 @@ Destination: - - Error @@ -7618,23 +7352,23 @@ Destination: - + Please use "Help" from the toolbar to get usage instructions to all elements - + Visit %1 on Nexus - - + + <Manage...> - + failed to parse profile %1: %2 @@ -7782,12 +7516,12 @@ Destination: - + failed to access %1 - + failed to set file time %1 @@ -8089,196 +7823,196 @@ Example: - + This error typically happens because an antivirus has deleted critical files from Mod Organizer's installation folder or has made them generally inaccessible. Add an exclusion for Mod Organizer's installation folder in your antivirus, reinstall Mod Organizer and try again. - + This error typically happens because an antivirus is preventing Mod Organizer from starting programs. Add an exclusion for Mod Organizer's installation folder in your antivirus and try again. - + The file '%1' does not exist. - + The working directory '%1' does not exist. + - + - Cannot start Steam - + The path to the Steam executable cannot be found. You might try reinstalling Steam. - - - + + + Continue without starting Steam - - + + The program may fail to launch. - + Cannot launch program - - - + + + Cannot start %1 - + Cannot launch helper - - + + Elevation required - + This program is requesting to run as administrator but Mod Organizer itself is not running as administrator. Running programs as administrator is typically unnecessary as long as the game and Mod Organizer have been installed outside "Program Files". You can restart Mod Organizer as administrator and try launching the program again. - - + + Restart Mod Organizer as administrator - - + + You must allow "helper.exe" to make changes to the system. - + Launch Steam - + This program requires Steam - + Mod Organizer has detected that this program likely requires Steam to be running to function properly. - + Start Steam - - + + The program might fail to run. - + Steam is running as administrator - + Running Steam as administrator is typically unnecessary and can cause problems when Mod Organizer itself is not running as administrator. You can restart Mod Organizer as administrator and try launching the program again. - - - + + + Continue - + Event Log not running - + The Event Log service is not running - + The Windows Event Log service is not running. This can prevent USVFS from running properly and your mods may not be recognized by the program being launched. - - + + Your mods might not work. - + Blacklisted program - + The program %1 is blacklisted - + The program you are attempting to launch is blacklisted in the virtual filesystem. This will likely prevent it from seeing any mods, INI files or any other virtualized files. - + Change the blacklist - + Waiting - + Please press OK once you're logged into steam. - + Select binary - + Binary @@ -8337,217 +8071,6 @@ You can restart Mod Organizer as administrator and try launching the program aga Exit Now - - - - Some of your plugins have invalid names! These plugins can not be loaded by the game. Please see mo_interface.log for a list of affected plugins and rename them. - - - - - %1, #%2, Level %3, %4 - - - - - failed to open %1 - - - - - wrong file format - expected %1 got '%2' for %3 - - - - - failed to query registry path (preflight): %1 - - - - - failed to query registry path (read): %1 - - - - - invalid nxm-link: %1 - - - - - Filter - - - - - One of the following plugins must be enabled: %1. - - - - - This plugin can only be enabled if the '%1' plugin is installed and enabled. - - - - - This plugin can only be enabled for the following game(s): %1. - - - - - - - - - - - INI file is read-only - - - - - - Mod Organizer is attempting to write to "%1" which is currently set to read-only. - - - - - - Clear the read-only flag - - - - - - Allow the write once - - - - - - The file will be set to read-only again. - - - - - - Skip this file - - - - - You can reset these choices by clicking "Reset Dialog Choices" in the General tab of the Settings - - - - - Always ask - - - - - - Remember my choice - - - - - Remember my choice for %1 - - - - - removal of "%1" failed: %2 - - - - - removal of "%1" failed - - - - - "%1" doesn't exist (remove) - - - - - Error %1 - - - - - - You have an invalid custom browser command in the settings. - - - - - - failed to create directory "%1" - - - - - - failed to copy "%1" to "%2" - - - - - %1 B - - - - - %1 KB - - - - - %1 MB - - - - - %1 GB - - - - - %1 TB - - - - - %1 B/s - - - - - %1 KB/s - - - - - %1 MB/s - - - - - %1 GB/s - - - - - %1 TB/s - - - - - Failed to save '%1', could not create a temporary file: %2 (error %3) - - QueryOverwriteDialog @@ -8594,19 +8117,6 @@ p, li { white-space: pre-wrap; } - - QuestionBoxMemory - - - Remember selection - - - - - Remember selection only for %1 - - - SaveTextAsDialog @@ -8705,42 +8215,42 @@ p, li { white-space: pre-wrap; } SelfUpdater - + Download failed - + Failed to find correct download, please try again later. - + Update - + Download in progress - + Download failed: %1 - + Failed to install update: %1 - + Failed to start %1: %2 - + Error @@ -9722,62 +9232,6 @@ programs you are intentionally running. - - TaskDialog - - - Dialog - - - - - icon - - - - - dummy main text - - - - - dummy content text - - - - - dummy button - - - - - dummy checkbox - - - - - Details - - - - - TextViewer - - - Log Viewer - - - - - Placeholder - - - - - Show Whitespace - - - TransferSavesDialog @@ -10526,25 +9980,4 @@ Please open the "Nexus" tab. - - uibase - - - h - Time remaining hours - - - - - m - Time remaining minutes - - - - - s - Time remaining seconds - - - diff --git a/src/organizercore.cpp b/src/organizercore.cpp index a8926dc65..88166c8e6 100644 --- a/src/organizercore.cpp +++ b/src/organizercore.cpp @@ -646,7 +646,7 @@ QString OrganizerCore::modsPath() const return QDir::fromNativeSeparators(m_Settings.paths().mods()); } -MOBase::VersionInfo OrganizerCore::appVersion() const +MOBase::Version OrganizerCore::version() const { return m_Updater.getVersion(); } diff --git a/src/organizercore.h b/src/organizercore.h index 923adc12d..fe80da240 100644 --- a/src/organizercore.h +++ b/src/organizercore.h @@ -1,14 +1,32 @@ #ifndef ORGANIZERCORE_H #define ORGANIZERCORE_H +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + #include "downloadmanager.h" #include "envdump.h" -#include "executableinfo.h" #include "executableslist.h" -#include "guessedvalue.h" #include "installationmanager.h" -#include "memoizedlock.h" -#include "moddatacontent.h" #include "modinfo.h" #include "modlist.h" #include "moshortcut.h" @@ -18,22 +36,6 @@ #include "settings.h" #include "uilocker.h" #include "usvfsconnector.h" -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include class ModListSortProxy; class PluginListSortProxy; @@ -270,7 +272,7 @@ class OrganizerCore : public QObject, public MOBase::IPluginDiagnose std::vector enabledArchives(); - MOBase::VersionInfo getVersion() const { return m_Updater.getVersion(); } + MOBase::Version getVersion() const { return m_Updater.getVersion(); } // return the plugin container // @@ -358,7 +360,7 @@ class OrganizerCore : public QObject, public MOBase::IPluginDiagnose QString overwritePath() const; QString basePath() const; QString modsPath() const; - MOBase::VersionInfo appVersion() const; + MOBase::Version version() const; MOBase::IPluginGame* getGame(const QString& gameName) const; MOBase::IModInterface* createMod(MOBase::GuessedValue& name); void modDataChanged(MOBase::IModInterface* mod); diff --git a/src/organizerproxy.cpp b/src/organizerproxy.cpp index 6edbdbab7..22a8a0234 100644 --- a/src/organizerproxy.cpp +++ b/src/organizerproxy.cpp @@ -114,9 +114,53 @@ QString OrganizerProxy::modsPath() const return m_Proxied->modsPath(); } +Version OrganizerProxy::version() const +{ + return m_Proxied->version(); +} + VersionInfo OrganizerProxy::appVersion() const { - return m_Proxied->appVersion(); + const auto version = m_Proxied->version(); + const int major = version.major(), minor = version.minor(), + subminor = version.patch(); + int subsubminor = 0; + VersionInfo::ReleaseType infoReleaseType = VersionInfo::RELEASE_FINAL; + + // make a copy + auto prereleases = version.preReleases(); + + if (!prereleases.empty()) { + // check if the first pre-release entry is a number + if (prereleases.front().index() == 0) { + subsubminor = std::get(prereleases.front()); + prereleases.erase(prereleases.begin()); + } + + if (!prereleases.empty()) { + const auto releaseType = std::get(prereleases.front()); + switch (releaseType) { + case Version::Development: + infoReleaseType = VersionInfo::RELEASE_PREALPHA; + break; + case Version::Alpha: + infoReleaseType = VersionInfo::RELEASE_ALPHA; + break; + case Version::Beta: + infoReleaseType = VersionInfo::RELEASE_BETA; + break; + case Version::ReleaseCandidate: + infoReleaseType = VersionInfo::RELEASE_CANDIDATE; + break; + default: + infoReleaseType = VersionInfo::RELEASE_PREALPHA; + } + } + + // there is no way to differentiate two pre-releases? + } + + return VersionInfo(major, minor, subminor, subsubminor, infoReleaseType); } IPluginGame* OrganizerProxy::getGame(const QString& gameName) const diff --git a/src/organizerproxy.h b/src/organizerproxy.h index fbae7cde6..2c70cb2c3 100644 --- a/src/organizerproxy.h +++ b/src/organizerproxy.h @@ -29,69 +29,67 @@ class OrganizerProxy : public MOBase::IOrganizer MOBase::IPlugin* plugin() const { return m_Plugin; } public: // IOrganizer interface - 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::IPluginGame* getGame(const QString& gameName) const; - virtual MOBase::IModInterface* createMod(MOBase::GuessedValue& name); - virtual void modDataChanged(MOBase::IModInterface* mod); - 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 + MOBase::IModRepositoryBridge* createNexusBridge() const override; + QString profileName() const override; + QString profilePath() const override; + QString downloadsPath() const override; + QString overwritePath() const override; + QString basePath() const override; + QString modsPath() const override; + MOBase::Version version() const override; + MOBase::VersionInfo appVersion() const override; + MOBase::IPluginGame* getGame(const QString& gameName) const override; + MOBase::IModInterface* createMod(MOBase::GuessedValue& name) override; + void modDataChanged(MOBase::IModInterface* mod) override; + QVariant persistent(const QString& pluginName, const QString& key, + const QVariant& def = QVariant()) const override; + void setPersistent(const QString& pluginName, const QString& key, + const QVariant& value, bool sync = true) override; + QString pluginDataPath() const override; + MOBase::IModInterface* installMod(const QString& fileName, + const QString& nameSuggestion = QString()); + QString resolvePath(const QString& fileName) const override; + QStringList listDirectories(const QString& directoryName) const override; + 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 override; - virtual QList + QStringList findFiles(const QString& path, + const QStringList& globFilters) const override; + QStringList getFileOrigins(const QString& fileName) const override; + QList findFileInfos(const QString& path, const std::function& filter) const override; - virtual std::shared_ptr virtualFileTree() const override; - - virtual MOBase::IDownloadManager* downloadManager() const override; - virtual MOBase::IPluginList* pluginList() const override; - virtual MOBase::IModList* modList() const override; - virtual MOBase::IProfile* profile() const override; - virtual MOBase::IGameFeatures* gameFeatures() 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, bool refresh = true, - LPDWORD exitCode = nullptr) const; - virtual void refresh(bool saveChanges); - - virtual bool onAboutToRun(const std::function& func) override; - virtual bool onAboutToRun(const std::function& func) override; - virtual bool + std::shared_ptr virtualFileTree() const override; + + MOBase::IDownloadManager* downloadManager() const override; + MOBase::IPluginList* pluginList() const override; + MOBase::IModList* modList() const override; + MOBase::IProfile* profile() const override; + MOBase::IGameFeatures* gameFeatures() const override; + + HANDLE startApplication(const QString& executable, + const QStringList& args = QStringList(), + const QString& cwd = "", const QString& profile = "", + const QString& forcedCustomOverwrite = "", + bool ignoreCustomOverwrite = false) override; + bool waitForApplication(HANDLE handle, bool refresh = true, + LPDWORD exitCode = nullptr) const override; + void refresh(bool saveChanges) override; + + bool onAboutToRun(const std::function& func) override; + bool onAboutToRun(const std::function& func) override; + bool onFinishedRun(const std::function& func) override; - virtual bool + bool onUserInterfaceInitialized(std::function const& func) override; - virtual bool onNextRefresh(const std::function& func, - bool immediateIfPossible) override; - virtual bool - onProfileCreated(std::function const& func) override; - virtual bool onProfileRenamed( - std::function const& - func) override; - virtual bool - onProfileRemoved(std::function const& func) override; - virtual bool onProfileChanged( + bool onNextRefresh(const std::function& func, + bool immediateIfPossible) override; + bool onProfileCreated(std::function const& func) override; + bool onProfileRenamed(std::function const& func) override; + bool onProfileRemoved(std::function const& func) override; + bool onProfileChanged( std::function const& func) override; // Plugin related: diff --git a/src/selfupdater.cpp b/src/selfupdater.cpp index 7762c9004..43992e707 100644 --- a/src/selfupdater.cpp +++ b/src/selfupdater.cpp @@ -69,10 +69,9 @@ using namespace MOBase; using namespace MOShared; SelfUpdater::SelfUpdater(NexusInterface* nexusInterface) - : m_Parent(nullptr), m_Interface(nexusInterface), m_Reply(nullptr), m_Attempts(3) -{ - m_MOVersion = createVersionInfo(); -} + : m_Parent(nullptr), m_MOVersion(createVersionInfo()), m_Interface(nexusInterface), + m_Reply(nullptr), m_Attempts(3) +{} SelfUpdater::~SelfUpdater() {} @@ -115,7 +114,8 @@ void SelfUpdater::testForUpdate(const Settings& settings) QJsonObject release = releaseVal.toObject(); if (!release["draft"].toBool() && (Settings::instance().usePrereleases() || !release["prerelease"].toBool())) { - auto version = VersionInfo(release["tag_name"].toString()); + auto version = Version::parse(release["tag_name"].toString(), + Version::ParseMode::MO2); mreleases[version] = release; } } @@ -132,14 +132,13 @@ void SelfUpdater::testForUpdate(const Settings& settings) m_UpdateCandidates.insert(p); } } - log::info("update available: {} -> {}", - this->m_MOVersion.displayString(3), lastKey.displayString(3)); + log::info("update available: {} -> {}", this->m_MOVersion, lastKey); emit updateAvailable(); } else if (lastKey < this->m_MOVersion) { // this could happen if the user switches from using prereleases to // stable builds. Should we downgrade? log::debug("This version is newer than the latest released one: {} -> {}", - this->m_MOVersion.displayString(3), lastKey.displayString(3)); + this->m_MOVersion, lastKey); } } }); @@ -158,7 +157,7 @@ void SelfUpdater::startUpdate() auto latestRelease = m_UpdateCandidates.begin()->second; UpdateDialog dialog(m_Parent); - dialog.setVersions(MOShared::createVersionInfo().displayString(3), + dialog.setVersions(MOShared::createVersionInfo().string(), latestRelease["tag_name"].toString()); // We concatenate release details. We only include pre-release if those are diff --git a/src/selfupdater.h b/src/selfupdater.h index 612e70238..b39340849 100644 --- a/src/selfupdater.h +++ b/src/selfupdater.h @@ -22,8 +22,6 @@ along with Mod Organizer. If not, see . #include -#include - class Archive; class NexusInterface; class PluginContainer; @@ -42,6 +40,8 @@ class QNetworkReply; class QProgressDialog; class Settings; +#include + #include "github.h" /** @@ -99,7 +99,7 @@ class SelfUpdater : public QObject /** * @return current version of Mod Organizer **/ - MOBase::VersionInfo getVersion() const { return m_MOVersion; } + MOBase::Version getVersion() const { return m_MOVersion; } signals: @@ -135,7 +135,7 @@ private slots: private: QWidget* m_Parent; - MOBase::VersionInfo m_MOVersion; + MOBase::Version m_MOVersion; NexusInterface* m_Interface; QFile m_UpdateFile; QNetworkReply* m_Reply; @@ -147,7 +147,7 @@ private slots: // Map from version to release, in decreasing order (first element is the latest // release): - using CandidatesMap = std::map>; + using CandidatesMap = std::map>; CandidatesMap m_UpdateCandidates; }; diff --git a/src/settingsdialoggeneral.cpp b/src/settingsdialoggeneral.cpp index 7acaa190b..265c9db90 100644 --- a/src/settingsdialoggeneral.cpp +++ b/src/settingsdialoggeneral.cpp @@ -111,7 +111,7 @@ void GeneralSettingsTab::addLanguages() QString languageString = QString("%1 (%2)") .arg(locale.nativeLanguageName()) - .arg(locale.nativeCountryName()); + .arg(locale.nativeTerritoryName()); if (locale.language() == QLocale::Chinese) { if (languageCode == "zh_TW") { diff --git a/src/shared/util.cpp b/src/shared/util.cpp index d3c6e2011..0d9788a29 100644 --- a/src/shared/util.cpp +++ b/src/shared/util.cpp @@ -208,10 +208,12 @@ std::wstring GetFileVersionString(const std::wstring& fileName) } } -VersionInfo createVersionInfo() +Version createVersionInfo() { VS_FIXEDFILEINFO version = GetFileVersion(env::thisProcessPath().native()); + std::optional releaseType; + if (version.dwFileFlags & VS_FF_PRERELEASE) { // Pre-release builds need annotating QString versionString = @@ -227,21 +229,29 @@ VersionInfo createVersionInfo() } } + if (!noLetters) { + // trust the string to make sense + return Version::parse(versionString, Version::ParseMode::MO2); + } + if (noLetters) { - // Default to pre-alpha when release type is unspecified - return VersionInfo( - version.dwFileVersionMS >> 16, version.dwFileVersionMS & 0xFFFF, - version.dwFileVersionLS >> 16, version.dwFileVersionLS & 0xFFFF, - VersionInfo::RELEASE_PREALPHA); + // default to development when release type is unspecified + releaseType = Version::Development; } else { - // Trust the string to make sense - return VersionInfo(versionString); } - } else { - // Non-pre-release builds just need their version numbers reading - return VersionInfo(version.dwFileVersionMS >> 16, version.dwFileVersionMS & 0xFFFF, - version.dwFileVersionLS >> 16, version.dwFileVersionLS & 0xFFFF); } + + const int major = version.dwFileVersionMS >> 16, + minor = version.dwFileVersionMS & 0xFFFF, + patch = version.dwFileVersionLS >> 16, + subpatch = version.dwFileVersionLS & 0xFFFF; + + std::vector> prereleases; + if (releaseType) { + prereleases.push_back(*releaseType); + } + + return Version(major, minor, patch, subpatch, std::move(prereleases)); } QString getUsvfsDLLVersion() diff --git a/src/shared/util.h b/src/shared/util.h index 1bc6bd47a..4764643e1 100644 --- a/src/shared/util.h +++ b/src/shared/util.h @@ -21,9 +21,10 @@ along with Mod Organizer. If not, see . #define UTIL_H #include -#include #include -#include + +#include +#include class Executable; @@ -48,7 +49,7 @@ std::wstring ToLowerCopy(std::wstring_view text); bool CaseInsensitiveEqual(const std::wstring& lhs, const std::wstring& rhs); -MOBase::VersionInfo createVersionInfo(); +MOBase::Version createVersionInfo(); QString getUsvfsVersionString(); void SetThisThreadName(const QString& s); diff --git a/vcpkg-configuration.json b/vcpkg-configuration.json index 0f3cef6ea..6a56decd9 100644 --- a/vcpkg-configuration.json +++ b/vcpkg-configuration.json @@ -14,7 +14,7 @@ { "kind": "git", "repository": "https://github.com/ModOrganizer2/vcpkg-registry", - "baseline": "210f6e8f6eaefd6abfdf685f7deeb6dabdc78512", + "baseline": "a1cd2ddbf1afb836419a5f1a9f70d6378fc41df2", "packages": ["mo2-*", "7zip", "usvfs"] } ]