From 58b6e0eb48b4d4b201613f1062796a9af68fe454 Mon Sep 17 00:00:00 2001 From: Mikaël Capelle Date: Wed, 20 Jan 2021 18:16:20 +0100 Subject: Increase robustness of mods priority in profile. --- src/modinfo.h | 15 ++-- src/modinfobackup.h | 1 - src/modinfoforeign.h | 1 - src/modinfooverwrite.h | 1 - src/modinforegular.h | 6 -- src/modlist.cpp | 60 +++++++-------- src/modlistview.cpp | 7 +- src/profile.cpp | 200 ++++++++++++++++++++++++++++++------------------- src/profile.h | 32 ++++---- 9 files changed, 177 insertions(+), 146 deletions(-) (limited to 'src') diff --git a/src/modinfo.h b/src/modinfo.h index c9b74a66..621a0443 100644 --- a/src/modinfo.h +++ b/src/modinfo.h @@ -103,6 +103,12 @@ public: // Type definitions: MOD_CC }; + // the priority of backups and overwrite from a mod list point of + // view, these do not correspond to the actual priority in the profile + // + static constexpr int BACKUP_PRIORITY = -1; + static constexpr int OVERWRITE_PRIORITY = std::numeric_limits::max(); + public: // Static functions: @@ -602,12 +608,9 @@ public: // Methods after this do not come from IModInterface: */ virtual void ignoreUpdate(bool ignore) = 0; - /** - * @return the fixed priority of mods of this type or INT_MIN if the priority of mods - * needs to be user-modifiable. Can be < 0 to force a priority below user-modifable mods - * or INT_MAX to force priority above all user-modifiables. - */ - virtual int getFixedPriority() const = 0; + // check if this mod has a fixed priority (i.e. that cannot be modified by users) + // + bool isFixedPriority() const { return isBackup() || isOverwrite(); } /** * @return true if the mod is always enabled. diff --git a/src/modinfobackup.h b/src/modinfobackup.h index f25ee9cf..9529855b 100644 --- a/src/modinfobackup.h +++ b/src/modinfobackup.h @@ -19,7 +19,6 @@ public: virtual void setGameName(const QString& gameName) override {} virtual void setNexusID(int) override {} virtual void endorse(bool) override {} - virtual int getFixedPriority() const override { return -1; } virtual void ignoreUpdate(bool) override {} virtual bool canBeUpdated() const override { return false; } virtual QDateTime getExpires() const override { return QDateTime(); } diff --git a/src/modinfoforeign.h b/src/modinfoforeign.h index 31fd13aa..3acebeaf 100644 --- a/src/modinfoforeign.h +++ b/src/modinfoforeign.h @@ -63,7 +63,6 @@ public: virtual QDateTime getNexusLastModified() const override { return QDateTime(); } virtual void setNexusLastModified(QDateTime) override {} virtual QString getNexusDescription() const override { return QString(); } - virtual int getFixedPriority() const override { return std::numeric_limits::min(); } virtual QStringList archives(bool = false) override { return m_Archives; } virtual QStringList stealFiles() const override { return m_Archives + QStringList(m_ReferenceFile); } virtual bool alwaysEnabled() const override { return true; } diff --git a/src/modinfooverwrite.h b/src/modinfooverwrite.h index 065a3ba2..997e24ea 100644 --- a/src/modinfooverwrite.h +++ b/src/modinfooverwrite.h @@ -48,7 +48,6 @@ public: virtual QString installationFile() const override { return ""; } virtual bool converted() const override { return false; } virtual bool validated() const override { return false; } - virtual int getFixedPriority() const override { return std::numeric_limits::max(); } virtual QString gameName() const override { return ""; } virtual int nexusId() const override { return -1; } virtual bool isOverwrite() const override { return true; } diff --git a/src/modinforegular.h b/src/modinforegular.h index 08660993..24f5cf9c 100644 --- a/src/modinforegular.h +++ b/src/modinforegular.h @@ -250,12 +250,6 @@ public: **/ int nexusId() const override { return m_NexusID; } - /** - * @return the fixed priority of mods of this type or INT_MIN if the priority of mods - * needs to be user-modifiable - */ - virtual int getFixedPriority() const override { return std::numeric_limits::min(); } - /** * @return true if the mod can be updated */ diff --git a/src/modlist.cpp b/src/modlist.cpp index ffa841ed..4518f2e9 100644 --- a/src/modlist.cpp +++ b/src/modlist.cpp @@ -223,8 +223,7 @@ QVariant ModList::data(const QModelIndex &modelIndex, int role) const return version; } else if (column == COL_PRIORITY) { - int priority = modInfo->getFixedPriority(); - if (priority != INT_MIN) { + if (modInfo->isBackup() || modInfo->isOverwrite()) { return QVariant(); // hide priority for mods where it's fixed } else { @@ -337,9 +336,11 @@ QVariant ModList::data(const QModelIndex &modelIndex, int role) const } } else if (column == COL_PRIORITY) { - int priority = modInfo->getFixedPriority(); - if (priority != INT_MIN) { - return priority; + if (modInfo->isBackup()) { + return ModInfo::BACKUP_PRIORITY; + } + else if (modInfo->isOverwrite()) { + return ModInfo::OVERWRITE_PRIORITY; } else { return m_Profile->getModPriority(modIndex); @@ -365,9 +366,11 @@ QVariant ModList::data(const QModelIndex &modelIndex, int role) const return modInfo->gameName(); } else if (role == PriorityRole) { - int priority = modInfo->getFixedPriority(); - if (priority != std::numeric_limits::min()) { - return priority; + if (modInfo->isBackup()) { + return ModInfo::BACKUP_PRIORITY; + } + else if (modInfo->isOverwrite()) { + return ModInfo::OVERWRITE_PRIORITY; } else { return m_Profile->getModPriority(modIndex); @@ -687,7 +690,7 @@ Qt::ItemFlags ModList::flags(const QModelIndex &modelIndex) const } if (modelIndex.isValid()) { ModInfo::Ptr modInfo = ModInfo::getByIndex(modelIndex.row()); - if (modInfo->getFixedPriority() == INT_MIN) { + if (!modInfo->isFixedPriority()) { result |= Qt::ItemIsDragEnabled; result |= Qt::ItemIsUserCheckable; if ((modelIndex.column() == COL_PRIORITY) || @@ -743,8 +746,9 @@ void ModList::changeModPriority(std::vector sourceIndices, int newPriority) iter != sourceIndices.end(); ++iter) { int oldPriority = m_Profile->getModPriority(*iter); if (oldPriority > newPriority) { - m_Profile->setModPriority(*iter, newPriority); - m_ModMoved(ModInfo::getByIndex(*iter)->name(), oldPriority, newPriority); + if (m_Profile->setModPriority(*iter, newPriority)) { + m_ModMoved(ModInfo::getByIndex(*iter)->name(), oldPriority, newPriority); + } } } @@ -770,8 +774,9 @@ void ModList::changeModPriority(std::vector sourceIndices, int newPriority) iter != sourceIndices.end(); ++iter) { int oldPriority = m_Profile->getModPriority(*iter); if (oldPriority < newPriority) { - m_Profile->setModPriority(*iter, newPriority); - m_ModMoved(ModInfo::getByIndex(*iter)->name(), oldPriority, newPriority); + if (m_Profile->setModPriority(*iter, newPriority)) { + m_ModMoved(ModInfo::getByIndex(*iter)->name(), oldPriority, newPriority); + } } } @@ -901,11 +906,8 @@ QStringList ModList::allModsByProfilePriority(MOBase::IProfile* profile) const m_Organizer->currentProfile() : static_cast(profile); QStringList res; - for (int i = mo2Profile->getPriorityMinimum(); - i < mo2Profile->getPriorityMinimum() + (int)mo2Profile->numRegularMods(); - ++i) { - int modIndex = mo2Profile->modIndexByPriority(i); - auto modInfo = ModInfo::getByIndex(modIndex); + for (auto& [priority, index] : mo2Profile->getAllIndexesByPriority()) { + auto modInfo = ModInfo::getByIndex(index); if (!modInfo->isBackup() && !modInfo->isOverwrite()) { res.push_back(modInfo->internalName()); } @@ -1008,16 +1010,13 @@ int ModList::priority(const QString &name) const bool ModList::setPriority(const QString &name, int newPriority) { - if ((newPriority < 0) || (newPriority >= static_cast(m_Profile->numRegularMods()))) { - return false; - } - - unsigned int modIndex = ModInfo::getIndex(name); - if (modIndex == UINT_MAX) { + unsigned int index = ModInfo::getIndex(name); + if (index == UINT_MAX) { return false; } else { - m_Profile->setModPriority(modIndex, newPriority); - notifyChange(modIndex); + if (m_Profile->setModPriority(index, newPriority)) { + notifyChange(index); + } return true; } } @@ -1074,14 +1073,14 @@ int ModList::dropPriority(int row, const QModelIndex& parent) const int newPriority = 0; { - if ((row < 0) || (row > static_cast(m_Profile->numRegularMods()))) { - newPriority = m_Profile->numRegularMods() + 1; + if (row < 0 || row >= rowCount()) { + newPriority = std::numeric_limits::max(); } else { newPriority = m_Profile->getModPriority(row); } if (newPriority == -1) { - newPriority = m_Profile->numRegularMods() + 1; + newPriority = std::numeric_limits::max(); } } @@ -1408,8 +1407,7 @@ void ModList::shiftModsPriority(const QModelIndexList& indices, int offset) std::vector notify; for (auto index : allIndex) { int newPriority = m_Profile->getModPriority(index) + offset; - if ((newPriority >= 0) && (newPriority < static_cast(m_Profile->numRegularMods()))) { - m_Profile->setModPriority(index, newPriority); + if (m_Profile->setModPriority(index, newPriority)) { notify.push_back(index); } } diff --git a/src/modlistview.cpp b/src/modlistview.cpp index 9597b48e..aa920905 100644 --- a/src/modlistview.cpp +++ b/src/modlistview.cpp @@ -647,16 +647,15 @@ void ModListView::onExternalFolderDropped(const QUrl& url, int priority) bool ModListView::moveSelection(int key) { - auto [cindex, sourceRows] = selected(); + auto rows = selectionModel()->selectedRows(); + const QPersistentModelIndex current(key == Qt::Key_Up ? rows.first() : rows.last()); int offset = key == Qt::Key_Up ? -1 : 1; if (m_sortProxy->sortOrder() == Qt::DescendingOrder) { offset = -offset; } - m_core->modList()->shiftModsPriority(sourceRows, offset); - - auto current = indexModelToView(key == Qt::Key_Up ? sourceRows.first() : sourceRows.last()); + m_core->modList()->shiftModsPriority(indexViewToModel(rows), offset); selectionModel()->setCurrentIndex(current, QItemSelectionModel::NoUpdate); scrollTo(current); diff --git a/src/profile.cpp b/src/profile.cpp index bb3a11e2..098cff6e 100644 --- a/src/profile.cpp +++ b/src/profile.cpp @@ -230,14 +230,13 @@ void Profile::doWriteModlist() return; } - for (std::map::const_reverse_iterator iter = m_ModIndexByPriority.crbegin(); iter != m_ModIndexByPriority.crend(); iter++ ) { + for (auto iter = m_ModIndexByPriority.crbegin(); iter != m_ModIndexByPriority.crend(); iter++) { // the priority order was inverted on load so it has to be inverted again unsigned int index = iter->second; if (index != UINT_MAX) { ModInfo::Ptr modInfo = ModInfo::getByIndex(index); - std::vector flags = modInfo->getFlags(); - if ((modInfo->getFixedPriority() == INT_MIN)) { - if (std::find(flags.begin(), flags.end(), ModInfo::FLAG_FOREIGN) != flags.end()) { + if (!modInfo->isFixedPriority()) { + if (modInfo->isForeign()) { file->write("*"); } else if (m_ModStatus[index].m_Enabled) { file->write("+"); @@ -270,10 +269,9 @@ void Profile::createTweakedIniFile() return; } - for (int i = getPriorityMinimum(); i < getPriorityMinimum() + (int)numRegularMods(); ++i) { - unsigned int idx = modIndexByPriority(i); - if (m_ModStatus[idx].m_Enabled) { - ModInfo::Ptr modInfo = ModInfo::getByIndex(idx); + for (auto& [priority, index] : m_ModIndexByPriority) { + if (m_ModStatus[index].m_Enabled) { + ModInfo::Ptr modInfo = ModInfo::getByIndex(index); mergeTweaks(modInfo, tweakedIni); } } @@ -368,6 +366,38 @@ void Profile::renameModInList(QFile &modList, const QString &oldName, const QStr void Profile::refreshModStatus() { + // this function refreshes mod status (enabled/disabled) and priority + // using the profile mod list file and the mods in the mods folder using + // the following steps + // + // 1) the mod list file is read and mods status/priority are updated by + // considering the content of the file (for status) and the order (for + // priority), missing or invalid mods are discarded (with a warning) + // 2) the priority are reversed to match the plugin list (highest wins) + // since the mod list is written in reverse order + // 3) at the same time, new mods (not in the mod list file) are added + // - foreign mods are given low priority (below 0) + // - regular mods are given high priority (above mods from the mod list) + // 4) the priority are shifted to ensure that the minimum priority is 0 + // 5) the priority of backups are computed such that the first backup is + // above all regular mods + // + // in the context of the profile, "regular mods" means a mod whose priority + // can be set by the user (i.e. not a backup or overwrite) + // + // this method ensures that the mods priority is as follow + // + // 0 mod1 + // 1 mod2 + // ... + // K-1 modK (K = m_NumRegularMods) + // K backup1 + // K+1 backup2 + // ... + // N-2 backupX + // N-1 overwrite (N = number of mods) + // + writeModlistNow(true); // if there are pending changes write them first QFile file(getModlistFileName()); @@ -387,6 +417,8 @@ void Profile::refreshModStatus() int index = 0; while (!file.atEnd()) { QByteArray line = file.readLine().trimmed(); + + // find the mod name and the enabled status bool enabled = true; QString modName; if (line.length() == 0) { @@ -398,89 +430,106 @@ void Profile::refreshModStatus() } else if (line.at(0) == '-') { enabled = false; modName = QString::fromUtf8(line.mid(1).trimmed().constData()); - } else if ((line.at(0) == '+') - || (line.at(0) == '*')) { + } else if (line.at(0) == '+' || line.at(0) == '*') { modName = QString::fromUtf8(line.mid(1).trimmed().constData()); } else { modName = QString::fromUtf8(line.trimmed().constData()); } - if (modName.size() > 0) { - QString lookupName = modName; - if (modName.compare("overwrite", Qt::CaseInsensitive) == 0) { - warnAboutOverwrite = true; - } - if (namesRead.find(lookupName) != namesRead.end()) { - continue; - } else { - namesRead.insert(lookupName); - } - unsigned int modIndex = ModInfo::getIndex(lookupName); - if (modIndex != UINT_MAX) { - ModInfo::Ptr info = ModInfo::getByIndex(modIndex); - if ((modIndex < m_ModStatus.size()) - && (info->getFixedPriority() == INT_MIN)) { - m_ModStatus[modIndex].m_Enabled = enabled; - if (m_ModStatus[modIndex].m_Priority == -1) { - if (static_cast(index) >= m_ModStatus.size()) { - throw MyException(tr("invalid mod index: %1").arg(index)); - } - m_ModStatus[modIndex].m_Priority = index++; - } - } else { - log::warn( - "no mod state for \"{}\" (profile \"{}\")", - modName, m_Directory.path()); - // need to rewrite the modlist to fix this - modStatusModified = true; + + if (modName.isEmpty()) { + continue; + } + + if (modName.compare("overwrite", Qt::CaseInsensitive) == 0) { + warnAboutOverwrite = true; + } + + // check if the name was already read + if (namesRead.find(modName) != namesRead.end()) { + continue; + } + namesRead.insert(modName); + + unsigned int modIndex = ModInfo::getIndex(modName); + if (modIndex == UINT_MAX) { + log::debug( + "mod not found: \"{}\" (profile \"{}\")", + modName, m_Directory.path()); + // need to rewrite the modlist to fix this + modStatusModified = true; + continue; + } + + // find the mod and check that this is a regular mod (and not a backup) + ModInfo::Ptr info = ModInfo::getByIndex(modIndex); + if (modIndex < m_ModStatus.size() && !info->isFixedPriority()) { + m_ModStatus[modIndex].m_Enabled = enabled; + if (m_ModStatus[modIndex].m_Priority == -1) { + if (static_cast(index) >= m_ModStatus.size()) { + throw Exception(tr("invalid mod index: %1").arg(index)); } - } else { - log::debug( - "mod not found: \"{}\" (profile \"{}\")", - modName, m_Directory.path()); - // need to rewrite the modlist to fix this - modStatusModified = true; + m_ModStatus[modIndex].m_Priority = index++; } + } else { + log::warn( + "no mod state for \"{}\" (profile \"{}\")", + modName, m_Directory.path()); + // need to rewrite the modlist to fix this + modStatusModified = true; } - } - int numKnownMods = index; + } // while (!file.atEnd()) + file.close(); + + const int numKnownMods = index; int topInsert = 0; - // invert priority order to match that of the pluginlist. Also - // give priorities to mods not referenced in the profile + // invert priority order to match that of the pluginlist, also + // give priorities to mods not referenced in the profile and + // count the number of regular mods + m_NumRegularMods = 0; for (size_t i = 0; i < m_ModStatus.size(); ++i) { ModInfo::Ptr modInfo = ModInfo::getByIndex(static_cast(i)); if (modInfo->alwaysEnabled()) { m_ModStatus[i].m_Enabled = true; } - if (modInfo->getFixedPriority() == INT_MAX) { + if (modInfo->isOverwrite()) { + m_ModStatus[i].m_Priority = m_ModStatus.size() - 1; continue; } if (m_ModStatus[i].m_Priority != -1) { m_ModStatus[i].m_Priority = numKnownMods - m_ModStatus[i].m_Priority - 1; + ++m_NumRegularMods; } else { if (static_cast(index) >= m_ModStatus.size()) { - throw MyException(tr("invalid mod index: %1").arg(index)); + throw Exception(tr("invalid mod index: %1").arg(index)); } - if (modInfo->hasFlag(ModInfo::FLAG_FOREIGN)) { + + // skip backups on purpose to avoid inserting backups in-between + // regular mods + if (modInfo->isForeign()) { m_ModStatus[i].m_Priority = --topInsert; - } else { + ++m_NumRegularMods; + } else if (!modInfo->isBackup()) { m_ModStatus[i].m_Priority = index++; + ++m_NumRegularMods; } + // also, mark the mod-list as changed modStatusModified = true; } } - // to support insertion of new mods at the top we may now have mods with negative priority. shift them all up - // to align priority with 0 + + // to support insertion of new mods at the top we may now have mods with negative priority, + // so shift them all up to align priority with 0 if (topInsert < 0) { int offset = topInsert * -1; for (size_t i = 0; i < m_ModStatus.size(); ++i) { ModInfo::Ptr modInfo = ModInfo::getByIndex(static_cast(i)); - if (modInfo->getFixedPriority() == INT_MAX) { + if (modInfo->isFixedPriority()) { continue; } @@ -488,7 +537,15 @@ void Profile::refreshModStatus() } } - file.close(); + // set the backups priority + int backupPriority = m_NumRegularMods; + for (size_t i = 0; i < m_ModStatus.size(); ++i) { + ModInfo::Ptr modInfo = ModInfo::getByIndex(static_cast(i)); + if (modInfo->isBackup()) { + m_ModStatus[i].m_Priority = backupPriority++; + } + } + updateIndices(); // User has a mod named some variation of "overwrite". Tell them about it. @@ -519,17 +576,10 @@ void Profile::dumpModStatus() const void Profile::updateIndices() { - m_NumRegularMods = 0; m_ModIndexByPriority.clear(); for (unsigned int i = 0; i < m_ModStatus.size(); ++i) { int priority = m_ModStatus[i].m_Priority; - if (priority == INT_MIN) { - // don't assign this to mapping at all, it's probably the overwrite mod - continue; - } else { - ++m_NumRegularMods; - m_ModIndexByPriority[priority] = i; - } + m_ModIndexByPriority[priority] = i; } } @@ -631,27 +681,21 @@ int Profile::getModPriority(unsigned int index) const } -void Profile::setModPriority(unsigned int index, int &newPriority) +bool Profile::setModPriority(unsigned int index, int &newPriority) { - if (m_ModStatus.at(index).m_Overwrite) { - // can't change priority of the overwrite - return; + if (ModInfo::getByIndex(index)->isFixedPriority()) { + // can't change priority of overwrite/backups + return false; } + newPriority = std::clamp(newPriority, 0, static_cast(m_NumRegularMods) - 1); + int oldPriority = m_ModStatus.at(index).m_Priority; int lastPriority = INT_MIN; if (newPriority == oldPriority) { // nothing to do - return; - } - - // we need to put the mod before backups - auto it = std::find_if(m_ModIndexByPriority.begin(), m_ModIndexByPriority.end(), [](auto&& p) { - return ModInfo::getByIndex(p.second)->isBackup(); - }); - if (it != m_ModIndexByPriority.end() && it->first <= newPriority) { - newPriority = it->first - 1; + return false; } for (auto& [priority, index] : m_ModIndexByPriority) { @@ -669,6 +713,8 @@ void Profile::setModPriority(unsigned int index, int &newPriority) updateIndices(); m_ModListWriter.write(); + + return true; } Profile *Profile::createPtrFrom(const QString &name, const Profile &reference, MOBase::IPluginGame const *gamePlugin) diff --git a/src/profile.h b/src/profile.h index 04452ff6..ebb69c0e 100644 --- a/src/profile.h +++ b/src/profile.h @@ -261,11 +261,6 @@ public: **/ size_t numMods() const { return m_ModStatus.size(); } - /** - * @return the number of mods that can be enabled and where the priority can be modified - */ - unsigned int numRegularMods() const { return m_NumRegularMods; } - /** * @brief retrieve the mod index based on the priority * @@ -293,17 +288,17 @@ public: **/ void setModsEnabled(const QList &modsToEnable, const QList &modsToDisable); - /** - * change the priority of a mod. Of course this also changes the priority of other mods. - * The priority of the mods in the range ]old, new priority] are shifted so that no gaps - * are possible. - * - * @param index index of the mod to change - * @param newPriority the new priority value - * - * @todo what happens if the new priority is outside the range? - **/ - void setModPriority(unsigned int index, int &newPriority); + // set the priority of a mod, and the priority of other mods in the range + // [old priority, new priority] such that no gaps are possible + // + // the priority is clamped in the range of valid priority (>= 0, and lower than + // the number of "regular" mods) + // + // the function returns true if the priority was changed, or false if the mod + // was already at the given priority (or if the priority of the mod cannot be + // set) + // + bool setModPriority(unsigned int index, int& newPriority); /** * @brief determine if a mod is enabled @@ -364,7 +359,7 @@ signals: **/ void modStatusChanged(QList index); -public slots: +protected slots: // should only be called by DelayedFileWriter, use writeModlist() and writeModlistNow() instead void doWriteModlist(); @@ -374,9 +369,8 @@ private: class ModStatus { friend class Profile; public: - ModStatus() : m_Overwrite(false), m_Enabled(false), m_Priority(-1) {} + ModStatus() : m_Enabled(false), m_Priority(-1) {} private: - bool m_Overwrite; bool m_Enabled; int m_Priority; }; -- cgit v1.3.1 From 946d7fc192d47b542e048d9ec72e65ad982eb09c Mon Sep 17 00:00:00 2001 From: Mikaël Capelle Date: Wed, 20 Jan 2021 18:33:54 +0100 Subject: Add comment for m_NumRegularMods and remove unused methods. --- src/profile.h | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/profile.h b/src/profile.h index ebb69c0e..903a8553 100644 --- a/src/profile.h +++ b/src/profile.h @@ -343,6 +343,9 @@ public: void debugDump() const; + + Profile& operator=(const Profile& reference) = delete; + signals: /** @@ -376,9 +379,6 @@ private: }; private: - Profile& operator=(const Profile &reference); // not implemented - - void initTimer(); void updateIndices(); @@ -388,7 +388,6 @@ private: void mergeTweak(const QString &tweakName, const QString &tweakedIni) const; void mergeTweaks(ModInfo::Ptr modInfo, const QString &tweakedIni) const; void touchFile(QString fileName); - void finishChangeStatus() const; static void renameModInList(QFile &modList, const QString &oldName, const QString &newName); @@ -400,11 +399,14 @@ private: const MOBase::IPluginGame *m_GamePlugin; - mutable QByteArray m_LastModlistHash; std::vector m_ModStatus; std::map m_ModIndexByPriority; - unsigned int m_NumRegularMods; + // "regular" here means mods with modifiable priority (i.e. not backups + // or overwrite) + std::size_t m_NumRegularMods; + + mutable QByteArray m_LastModlistHash; MOBase::DelayedFileWriter m_ModListWriter; }; -- cgit v1.3.1 From 0e7fed0e32cf7cd6ff342493621287e0040e51ad Mon Sep 17 00:00:00 2001 From: Mikaël Capelle Date: Wed, 20 Jan 2021 21:01:49 +0100 Subject: Move backup and overwrite priority to ModList. --- src/modinfo.h | 6 ------ src/modlist.cpp | 8 ++++---- src/modlist.h | 9 +++++++-- 3 files changed, 11 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/modinfo.h b/src/modinfo.h index 621a0443..0fbcd1c0 100644 --- a/src/modinfo.h +++ b/src/modinfo.h @@ -103,12 +103,6 @@ public: // Type definitions: MOD_CC }; - // the priority of backups and overwrite from a mod list point of - // view, these do not correspond to the actual priority in the profile - // - static constexpr int BACKUP_PRIORITY = -1; - static constexpr int OVERWRITE_PRIORITY = std::numeric_limits::max(); - public: // Static functions: diff --git a/src/modlist.cpp b/src/modlist.cpp index 4518f2e9..073dbfd3 100644 --- a/src/modlist.cpp +++ b/src/modlist.cpp @@ -337,10 +337,10 @@ QVariant ModList::data(const QModelIndex &modelIndex, int role) const } else if (column == COL_PRIORITY) { if (modInfo->isBackup()) { - return ModInfo::BACKUP_PRIORITY; + return BACKUP_PRIORITY; } else if (modInfo->isOverwrite()) { - return ModInfo::OVERWRITE_PRIORITY; + return OVERWRITE_PRIORITY; } else { return m_Profile->getModPriority(modIndex); @@ -367,10 +367,10 @@ QVariant ModList::data(const QModelIndex &modelIndex, int role) const } else if (role == PriorityRole) { if (modInfo->isBackup()) { - return ModInfo::BACKUP_PRIORITY; + return BACKUP_PRIORITY; } else if (modInfo->isOverwrite()) { - return ModInfo::OVERWRITE_PRIORITY; + return OVERWRITE_PRIORITY; } else { return m_Profile->getModPriority(modIndex); diff --git a/src/modlist.h b/src/modlist.h index 5c7f28ee..8d0a2384 100644 --- a/src/modlist.h +++ b/src/modlist.h @@ -366,10 +366,15 @@ private: // int dropPriority(int row, const QModelIndex& parent) const; -private slots: - private: + // the priority of backups and overwrite for sorting (and display, although + // those are not displayed), these do not correspond to the actual priority + // in the mod list + // + static constexpr int BACKUP_PRIORITY = -1; + static constexpr int OVERWRITE_PRIORITY = std::numeric_limits::max(); + struct TModInfo { TModInfo(unsigned int index, ModInfo::Ptr modInfo) : modInfo(modInfo), nameOrder(index), priorityOrder(0), modIDOrder(0), categoryOrder(0) {} -- cgit v1.3.1 From 7c9d3777c28f79b1ae7cdbda107493493ca1ba2a Mon Sep 17 00:00:00 2001 From: Mikaël Capelle Date: Wed, 20 Jan 2021 21:04:49 +0100 Subject: Remove unused/undefined ModList functions. --- src/modlist.cpp | 26 -------------------------- src/modlist.h | 7 ------- 2 files changed, 33 deletions(-) (limited to 'src') diff --git a/src/modlist.cpp b/src/modlist.cpp index 073dbfd3..a9a4781e 100644 --- a/src/modlist.cpp +++ b/src/modlist.cpp @@ -128,32 +128,6 @@ QString ModList::makeInternalName(ModInfo::Ptr info, QString name) const return name; } -QVariant ModList::getOverwriteData(int column, int role) const -{ - switch (role) { - case Qt::DisplayRole: { - if (column == 0) { - return "Overwrite"; - } else { - return QVariant(); - } - } break; - case Qt::CheckStateRole: { - if (column == 0) { - return Qt::Checked; - } else { - return QVariant(); - } - } break; - case Qt::TextAlignmentRole: return QVariant(Qt::AlignCenter | Qt::AlignVCenter); - case GroupingRole: return -1; - case Qt::ForegroundRole: return QBrush(Qt::red); - case Qt::ToolTipRole: return tr("This entry contains files that have been created inside the virtual data tree (i.e. by the construction kit)"); - default: return QVariant(); - } -} - - QString ModList::getFlagText(ModInfo::EFlag flag, ModInfo::Ptr modInfo) const { switch (flag) { diff --git a/src/modlist.h b/src/modlist.h index 8d0a2384..242d185f 100644 --- a/src/modlist.h +++ b/src/modlist.h @@ -341,19 +341,12 @@ private: QString getDisplayName(ModInfo::Ptr info) const; QString makeInternalName(ModInfo::Ptr info, QString name) const; - QVariant getOverwriteData(int column, int role) const; - QString getFlagText(ModInfo::EFlag flag, ModInfo::Ptr modInfo) const; QString getConflictFlagText(ModInfo::EConflictFlag flag, ModInfo::Ptr modInfo) const; QString getColumnToolTip(int column) const; - ModList::EColumn getEnabledColumn(int index) const; - - QVariant categoryData(int categoryID, int column, int role) const; - QVariant modData(int modID, int modelColumn, int role) const; - bool renameMod(int index, const QString &newName); MOBase::IModList::ModStates state(unsigned int modIndex) const; -- cgit v1.3.1 From 0803920486ff62cccd79374b9b68084b880f010c Mon Sep 17 00:00:00 2001 From: Mikaël Capelle Date: Thu, 21 Jan 2021 19:20:24 +0100 Subject: Add method to retrieve priority of mods in ModList. --- src/modlist.cpp | 34 ++++++++++++++++------------------ src/modlist.h | 22 +++++++++++++++------- 2 files changed, 31 insertions(+), 25 deletions(-) (limited to 'src') diff --git a/src/modlist.cpp b/src/modlist.cpp index a9a4781e..c82aa802 100644 --- a/src/modlist.cpp +++ b/src/modlist.cpp @@ -168,6 +168,20 @@ QString ModList::getConflictFlagText(ModInfo::EConflictFlag flag, ModInfo::Ptr m } } +int ModList::modPriority(unsigned int index) const +{ + auto info = ModInfo::getByIndex(index); + if (info->isBackup()) { + return BACKUP_PRIORITY; + } + else if (info->isOverwrite()) { + return OVERWRITE_PRIORITY; + } + else { + return m_Profile->getModPriority(index); + } +} + QVariant ModList::data(const QModelIndex &modelIndex, int role) const { if (m_Profile == nullptr) return QVariant(); @@ -310,15 +324,7 @@ QVariant ModList::data(const QModelIndex &modelIndex, int role) const } } else if (column == COL_PRIORITY) { - if (modInfo->isBackup()) { - return BACKUP_PRIORITY; - } - else if (modInfo->isOverwrite()) { - return OVERWRITE_PRIORITY; - } - else { - return m_Profile->getModPriority(modIndex); - } + return modPriority(modIndex); } else { return modInfo->nexusId(); @@ -340,15 +346,7 @@ QVariant ModList::data(const QModelIndex &modelIndex, int role) const return modInfo->gameName(); } else if (role == PriorityRole) { - if (modInfo->isBackup()) { - return BACKUP_PRIORITY; - } - else if (modInfo->isOverwrite()) { - return OVERWRITE_PRIORITY; - } - else { - return m_Profile->getModPriority(modIndex); - } + return modPriority(modIndex); } else if (role == Qt::FontRole) { QFont result; diff --git a/src/modlist.h b/src/modlist.h index 242d185f..68316613 100644 --- a/src/modlist.h +++ b/src/modlist.h @@ -335,6 +335,21 @@ signals: private: + // the priority of backups and overwrite for sorting (and display, although + // those are not displayed), these do not correspond to the actual priority + // in the mod list + // + static constexpr int BACKUP_PRIORITY = -1; + static constexpr int OVERWRITE_PRIORITY = std::numeric_limits::max(); + + // retrieve the priority of a mod for the purpose of display (i.e. sorting + // or grouping) + // + // this can be different from the priority in the profile (e.g. for backups + // or overwrite) + // + int modPriority(unsigned int index) const; + // retrieve the display name of a mod or convert from a user-provided // name to internal name // @@ -361,13 +376,6 @@ private: private: - // the priority of backups and overwrite for sorting (and display, although - // those are not displayed), these do not correspond to the actual priority - // in the mod list - // - static constexpr int BACKUP_PRIORITY = -1; - static constexpr int OVERWRITE_PRIORITY = std::numeric_limits::max(); - struct TModInfo { TModInfo(unsigned int index, ModInfo::Ptr modInfo) : modInfo(modInfo), nameOrder(index), priorityOrder(0), modIDOrder(0), categoryOrder(0) {} -- cgit v1.3.1 From ffb820c701617721b82515be330a3f604b26dd7b Mon Sep 17 00:00:00 2001 From: Mikaël Capelle Date: Thu, 21 Jan 2021 19:21:07 +0100 Subject: Use isFixedPriority() when appropriate. --- src/modlist.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/modlist.cpp b/src/modlist.cpp index c82aa802..f83acc9c 100644 --- a/src/modlist.cpp +++ b/src/modlist.cpp @@ -211,7 +211,7 @@ QVariant ModList::data(const QModelIndex &modelIndex, int role) const return version; } else if (column == COL_PRIORITY) { - if (modInfo->isBackup() || modInfo->isOverwrite()) { + if (modInfo->isFixedPriority()) { return QVariant(); // hide priority for mods where it's fixed } else { -- cgit v1.3.1 From 36489c7d8fd6f1b79f29edc5d1f6c2d8b231adf9 Mon Sep 17 00:00:00 2001 From: Mikaël Capelle Date: Thu, 21 Jan 2021 19:21:27 +0100 Subject: Add const-qualifier to for loop variable. --- src/profile.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/profile.cpp b/src/profile.cpp index 098cff6e..c45ecd30 100644 --- a/src/profile.cpp +++ b/src/profile.cpp @@ -269,7 +269,7 @@ void Profile::createTweakedIniFile() return; } - for (auto& [priority, index] : m_ModIndexByPriority) { + for (const auto& [priority, index] : m_ModIndexByPriority) { if (m_ModStatus[index].m_Enabled) { ModInfo::Ptr modInfo = ModInfo::getByIndex(index); mergeTweaks(modInfo, tweakedIni); -- cgit v1.3.1 From 62a9d13948e6e299d41eb6876c0f1fbaf0160d79 Mon Sep 17 00:00:00 2001 From: Mikaël Capelle Date: Thu, 21 Jan 2021 19:31:05 +0100 Subject: Remove unused priority-related functions from Profile. --- src/profile.cpp | 18 +----------------- src/profile.h | 11 ----------- 2 files changed, 1 insertion(+), 28 deletions(-) (limited to 'src') diff --git a/src/profile.cpp b/src/profile.cpp index c45ecd30..caea776c 100644 --- a/src/profile.cpp +++ b/src/profile.cpp @@ -600,17 +600,6 @@ std::vector > Profile::getActiveMods() return result; } - -unsigned int Profile::modIndexByPriority(int priority) const -{ - try { - return m_ModIndexByPriority.at(priority); - } catch (std::out_of_range) { - throw MyException(tr("invalid priority %1").arg(priority)); - } -} - - void Profile::setModEnabled(unsigned int index, bool enabled) { if (index >= m_ModStatus.size()) { @@ -698,7 +687,7 @@ bool Profile::setModPriority(unsigned int index, int &newPriority) return false; } - for (auto& [priority, index] : m_ModIndexByPriority) { + for (const auto& [priority, index] : m_ModIndexByPriority) { if (newPriority < oldPriority && priority >= newPriority && priority < oldPriority) { m_ModStatus.at(index).m_Priority += 1; } @@ -1085,11 +1074,6 @@ void Profile::storeSettingsByArray(const QString &prefix, const QListendArray(); } -int Profile::getPriorityMinimum() const -{ - return m_ModIndexByPriority.begin()->first; -} - bool Profile::forcedLibrariesEnabled(const QString &executable) const { return setting("forced_libraries", executable + "/enabled", false).toBool(); diff --git a/src/profile.h b/src/profile.h index 903a8553..d354dd48 100644 --- a/src/profile.h +++ b/src/profile.h @@ -261,15 +261,6 @@ public: **/ size_t numMods() const { return m_ModStatus.size(); } - /** - * @brief retrieve the mod index based on the priority - * - * @param priority priority to look up - * @return the index of the mod - * @throw std::exception an exception is thrown if there is no mod with the specified priority - **/ - unsigned int modIndexByPriority(int priority) const; - /** * @brief enable or disable a mod * @@ -333,8 +324,6 @@ public: QList settingsByArray(const QString &prefix) const; void storeSettingsByArray(const QString &prefix, const QList &values); - int getPriorityMinimum() const; - bool forcedLibrariesEnabled(const QString &executable) const; void setForcedLibrariesEnabled(const QString &executable, bool enabled); QList determineForcedLibraries(const QString &executable) const; -- cgit v1.3.1 From f8943ee477e1cb5821e6208ee2d177c26c4b4ad3 Mon Sep 17 00:00:00 2001 From: Mikaël Capelle Date: Thu, 21 Jan 2021 19:38:53 +0100 Subject: Use range-loop instead of old-style iterators. --- src/modlist.cpp | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/modlist.cpp b/src/modlist.cpp index f83acc9c..5cbc6c9f 100644 --- a/src/modlist.cpp +++ b/src/modlist.cpp @@ -714,12 +714,11 @@ void ModList::changeModPriority(std::vector sourceIndices, int newPriority) }); // move mods that are decreasing in priority - for (std::vector::const_iterator iter = sourceIndices.begin(); - iter != sourceIndices.end(); ++iter) { - int oldPriority = m_Profile->getModPriority(*iter); + for (const auto& index : sourceIndices) { + int oldPriority = m_Profile->getModPriority(index); if (oldPriority > newPriority) { - if (m_Profile->setModPriority(*iter, newPriority)) { - m_ModMoved(ModInfo::getByIndex(*iter)->name(), oldPriority, newPriority); + if (m_Profile->setModPriority(index, newPriority)) { + m_ModMoved(ModInfo::getByIndex(index)->name(), oldPriority, newPriority); } } } @@ -732,9 +731,8 @@ void ModList::changeModPriority(std::vector sourceIndices, int newPriority) // if at least one mod is increasing in priority, the target index is // that of the row BELOW the dropped location, otherwise it's the one above - for (std::vector::const_iterator iter = sourceIndices.begin(); - iter != sourceIndices.end(); ++iter) { - int oldPriority = m_Profile->getModPriority(*iter); + for (const auto& index : sourceIndices) { + int oldPriority = m_Profile->getModPriority(index); if (oldPriority < newPriority) { --newPriority; break; @@ -742,12 +740,11 @@ void ModList::changeModPriority(std::vector sourceIndices, int newPriority) } // move mods that are increasing in priority - for (std::vector::const_iterator iter = sourceIndices.begin(); - iter != sourceIndices.end(); ++iter) { - int oldPriority = m_Profile->getModPriority(*iter); + for (const auto& index : sourceIndices) { + int oldPriority = m_Profile->getModPriority(index); if (oldPriority < newPriority) { - if (m_Profile->setModPriority(*iter, newPriority)) { - m_ModMoved(ModInfo::getByIndex(*iter)->name(), oldPriority, newPriority); + if (m_Profile->setModPriority(index, newPriority)) { + m_ModMoved(ModInfo::getByIndex(index)->name(), oldPriority, newPriority); } } } -- cgit v1.3.1 From 1747dcf5632a7887906b9b6d412e95e3af9c8249 Mon Sep 17 00:00:00 2001 From: Mikaël Capelle Date: Thu, 21 Jan 2021 19:42:41 +0100 Subject: INT_MAX -> std::numeric_limits, plus minor clean. --- src/modlistbypriorityproxy.cpp | 2 +- src/organizercore.cpp | 2 +- src/profile.cpp | 2 +- src/profile.h | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/modlistbypriorityproxy.cpp b/src/modlistbypriorityproxy.cpp index 7dae7a54..d1d045fc 100644 --- a/src/modlistbypriorityproxy.cpp +++ b/src/modlistbypriorityproxy.cpp @@ -234,7 +234,7 @@ bool ModListByPriorityProxy::canDropMimeData(const QMimeData* data, Qt::DropActi bool hasSeparator = false; unsigned int firstRowIndex = -1; - int firstRowPriority = INT_MAX; + int firstRowPriority = std::numeric_limits::max(); for (auto sourceRow : dropInfo.rows()) { hasSeparator = hasSeparator || ModInfo::getByIndex(sourceRow)->isSeparator(); if (m_sortOrder == Qt::AscendingOrder && m_profile->getModPriority(sourceRow) < firstRowPriority diff --git a/src/organizercore.cpp b/src/organizercore.cpp index d6c22d3c..cf641886 100644 --- a/src/organizercore.cpp +++ b/src/organizercore.cpp @@ -1943,7 +1943,7 @@ std::vector OrganizerCore::fileMapping(const QString &profileName, bool overwriteActive = false; - for (auto mod : profile.getActiveMods()) { + for (const auto& mod : profile.getActiveMods()) { if (std::get<0>(mod).compare("overwrite", Qt::CaseInsensitive) == 0) { continue; } diff --git a/src/profile.cpp b/src/profile.cpp index caea776c..acda465b 100644 --- a/src/profile.cpp +++ b/src/profile.cpp @@ -591,7 +591,7 @@ std::vector > Profile::getActiveMods() if ((iter->second != UINT_MAX) && m_ModStatus[iter->second].m_Enabled) { ModInfo::Ptr modInfo = ModInfo::getByIndex(iter->second); if (modInfo->hasFlag(ModInfo::FLAG_OVERWRITE)) - result.push_back(std::make_tuple(modInfo->internalName(), modInfo->absolutePath(), INT_MAX)); + result.push_back(std::make_tuple(modInfo->internalName(), modInfo->absolutePath(), std::numeric_limits::max())); else result.push_back(std::make_tuple(modInfo->internalName(), modInfo->absolutePath(), m_ModStatus[iter->second].m_Priority)); } diff --git a/src/profile.h b/src/profile.h index d354dd48..d1e3f104 100644 --- a/src/profile.h +++ b/src/profile.h @@ -243,7 +243,7 @@ public: * * @return list of active mods sorted by priority (ascending). "first" is the mod name, "second" is its path **/ - std::vector > getActiveMods(); + std::vector> getActiveMods(); /** * @brief retrieve a mod of the indexes ordered by priority -- cgit v1.3.1 From 49461f00864df6e00479704fad7d7e15bc104c1e Mon Sep 17 00:00:00 2001 From: Mikaël Capelle Date: Thu, 21 Jan 2021 20:01:27 +0100 Subject: Remove unused variables. --- src/modinfodialogconflicts.cpp | 3 --- 1 file changed, 3 deletions(-) (limited to 'src') diff --git a/src/modinfodialogconflicts.cpp b/src/modinfodialogconflicts.cpp index 1bfb3218..bb3346f7 100644 --- a/src/modinfodialogconflicts.cpp +++ b/src/modinfodialogconflicts.cpp @@ -992,9 +992,6 @@ std::optional AdvancedConflictsTab::createItem( if (!alternatives.empty()) { const bool showAllAlts = ui->conflictsAdvancedShowAll->isChecked(); - int beforePrio = 0; - int afterPrio = std::numeric_limits::max(); - if (currOrigin->getID() == fileOrigin) { // current origin is the active winner, all alternatives go in 'before' -- cgit v1.3.1 From 60085ae4b662cfd5a3f3d4da78994a275904af96 Mon Sep 17 00:00:00 2001 From: Mikaël Capelle Date: Thu, 21 Jan 2021 20:01:43 +0100 Subject: Use actual priority of overwrite instead of INT_MAX, and remove useless checks. --- src/profile.cpp | 35 +++++++++++++++-------------------- 1 file changed, 15 insertions(+), 20 deletions(-) (limited to 'src') diff --git a/src/profile.cpp b/src/profile.cpp index acda465b..6b8d0709 100644 --- a/src/profile.cpp +++ b/src/profile.cpp @@ -232,20 +232,18 @@ void Profile::doWriteModlist() for (auto iter = m_ModIndexByPriority.crbegin(); iter != m_ModIndexByPriority.crend(); iter++) { // the priority order was inverted on load so it has to be inverted again - unsigned int index = iter->second; - if (index != UINT_MAX) { - ModInfo::Ptr modInfo = ModInfo::getByIndex(index); - if (!modInfo->isFixedPriority()) { - if (modInfo->isForeign()) { - file->write("*"); - } else if (m_ModStatus[index].m_Enabled) { - file->write("+"); - } else { - file->write("-"); - } - file->write(modInfo->name().toUtf8()); - file->write("\r\n"); + const auto index = iter->second; + ModInfo::Ptr modInfo = ModInfo::getByIndex(index); + if (!modInfo->isFixedPriority()) { + if (modInfo->isForeign()) { + file->write("*"); + } else if (m_ModStatus[index].m_Enabled) { + file->write("+"); + } else { + file->write("-"); } + file->write(modInfo->name().toUtf8()); + file->write("\r\n"); } } @@ -587,13 +585,10 @@ void Profile::updateIndices() std::vector > Profile::getActiveMods() { std::vector > result; - for (std::map::const_iterator iter = m_ModIndexByPriority.begin(); iter != m_ModIndexByPriority.end(); iter++ ) { - if ((iter->second != UINT_MAX) && m_ModStatus[iter->second].m_Enabled) { - ModInfo::Ptr modInfo = ModInfo::getByIndex(iter->second); - if (modInfo->hasFlag(ModInfo::FLAG_OVERWRITE)) - result.push_back(std::make_tuple(modInfo->internalName(), modInfo->absolutePath(), std::numeric_limits::max())); - else - result.push_back(std::make_tuple(modInfo->internalName(), modInfo->absolutePath(), m_ModStatus[iter->second].m_Priority)); + for (const auto& [priority, index] : m_ModIndexByPriority) { + if (m_ModStatus[index].m_Enabled) { + ModInfo::Ptr modInfo = ModInfo::getByIndex(index); + result.push_back(std::make_tuple(modInfo->internalName(), modInfo->absolutePath(), m_ModStatus[index].m_Priority)); } } -- cgit v1.3.1 From 0a069709900fe37c265d8645554ae19e25bea06a Mon Sep 17 00:00:00 2001 From: Mikaël Capelle Date: Thu, 21 Jan 2021 20:21:57 +0100 Subject: Expose proper priority in ModList and sort in the sort proxy. --- src/modlist.cpp | 22 +--------------------- src/modlist.h | 15 --------------- src/modlistsortproxy.cpp | 7 ++++++- 3 files changed, 7 insertions(+), 37 deletions(-) (limited to 'src') diff --git a/src/modlist.cpp b/src/modlist.cpp index 5cbc6c9f..6637f48a 100644 --- a/src/modlist.cpp +++ b/src/modlist.cpp @@ -168,20 +168,6 @@ QString ModList::getConflictFlagText(ModInfo::EConflictFlag flag, ModInfo::Ptr m } } -int ModList::modPriority(unsigned int index) const -{ - auto info = ModInfo::getByIndex(index); - if (info->isBackup()) { - return BACKUP_PRIORITY; - } - else if (info->isOverwrite()) { - return OVERWRITE_PRIORITY; - } - else { - return m_Profile->getModPriority(index); - } -} - QVariant ModList::data(const QModelIndex &modelIndex, int role) const { if (m_Profile == nullptr) return QVariant(); @@ -323,9 +309,6 @@ QVariant ModList::data(const QModelIndex &modelIndex, int role) const return QVariant(); } } - else if (column == COL_PRIORITY) { - return modPriority(modIndex); - } else { return modInfo->nexusId(); } @@ -346,7 +329,7 @@ QVariant ModList::data(const QModelIndex &modelIndex, int role) const return modInfo->gameName(); } else if (role == PriorityRole) { - return modPriority(modIndex); + return m_Profile->getModPriority(modIndex); } else if (role == Qt::FontRole) { QFont result; @@ -580,9 +563,6 @@ bool ModList::setData(const QModelIndex &index, const QVariant &value, int role) case COL_PRIORITY: { bool ok = false; int newPriority = value.toInt(&ok); - if (ok && newPriority < 0) { - newPriority = 0; - } if (ok) { changeModPriority(modID, newPriority); result = true; diff --git a/src/modlist.h b/src/modlist.h index 68316613..e201de27 100644 --- a/src/modlist.h +++ b/src/modlist.h @@ -335,21 +335,6 @@ signals: private: - // the priority of backups and overwrite for sorting (and display, although - // those are not displayed), these do not correspond to the actual priority - // in the mod list - // - static constexpr int BACKUP_PRIORITY = -1; - static constexpr int OVERWRITE_PRIORITY = std::numeric_limits::max(); - - // retrieve the priority of a mod for the purpose of display (i.e. sorting - // or grouping) - // - // this can be different from the priority in the profile (e.g. for backups - // or overwrite) - // - int modPriority(unsigned int index) const; - // retrieve the display name of a mod or convert from a user-provided // name to internal name // diff --git a/src/modlistsortproxy.cpp b/src/modlistsortproxy.cpp index 18e91e6e..fc7f3270 100644 --- a/src/modlistsortproxy.cpp +++ b/src/modlistsortproxy.cpp @@ -215,7 +215,12 @@ bool ModListSortProxy::lessThan(const QModelIndex &left, } } break; case ModList::COL_PRIORITY: { - // nop, already compared by priority + if (leftMod->isBackup() != rightMod->isBackup()) { + lt = leftMod->isBackup(); + } + else if (leftMod->isOverwrite() != rightMod->isOverwrite()) { + lt = rightMod->isOverwrite(); + } } break; default: { log::warn("Sorting is not defined for column {}", left.column()); -- cgit v1.3.1 From 569ce219594e5bf3246a97237d26db150c60e8fa Mon Sep 17 00:00:00 2001 From: Mikaël Capelle Date: Thu, 21 Jan 2021 21:02:10 +0100 Subject: Remove unused mapping. --- src/shared/filesorigin.cpp | 2 -- src/shared/filesorigin.h | 4 ++-- src/shared/originconnection.cpp | 14 -------------- src/shared/originconnection.h | 1 - 4 files changed, 2 insertions(+), 19 deletions(-) (limited to 'src') diff --git a/src/shared/filesorigin.cpp b/src/shared/filesorigin.cpp index 7476b6c5..049e4258 100644 --- a/src/shared/filesorigin.cpp +++ b/src/shared/filesorigin.cpp @@ -33,8 +33,6 @@ FilesOrigin::FilesOrigin( void FilesOrigin::setPriority(int priority) { - m_OriginConnection.lock()->changePriorityLookup(m_Priority, priority); - m_Priority = priority; } diff --git a/src/shared/filesorigin.h b/src/shared/filesorigin.h index 222a834f..1aa4c645 100644 --- a/src/shared/filesorigin.h +++ b/src/shared/filesorigin.h @@ -22,8 +22,8 @@ public: FilesOrigin(const FilesOrigin&) = delete; FilesOrigin& operator=(const FilesOrigin&) = delete; - // sets priority for this origin, but it will overwrite the existing mapping - // for this priority, the previous origin will no longer be referenced + // sets priority for this origin (does not automatically refresh + // the structure) void setPriority(int priority); int getPriority() const diff --git a/src/shared/originconnection.cpp b/src/shared/originconnection.cpp index c1c096f0..2830e8e3 100644 --- a/src/shared/originconnection.cpp +++ b/src/shared/originconnection.cpp @@ -88,19 +88,6 @@ FilesOrigin& OriginConnection::getByName(const std::wstring &name) } } -void OriginConnection::changePriorityLookup(int oldPriority, int newPriority) -{ - std::scoped_lock lock(m_Mutex); - - auto iter = m_OriginsPriorityMap.find(oldPriority); - - if (iter != m_OriginsPriorityMap.end()) { - OriginID idx = iter->second; - m_OriginsPriorityMap.erase(iter); - m_OriginsPriorityMap[newPriority] = idx; - } -} - void OriginConnection::changeNameLookup(const std::wstring &oldName, const std::wstring &newName) { std::scoped_lock lock(m_Mutex); @@ -137,7 +124,6 @@ FilesOrigin& OriginConnection::createOriginNoLock( .first; m_OriginsNameMap.insert({originName, newID}); - m_OriginsPriorityMap.insert({priority, newID}); return itor->second; } diff --git a/src/shared/originconnection.h b/src/shared/originconnection.h index 5fecd63a..ef8692bb 100644 --- a/src/shared/originconnection.h +++ b/src/shared/originconnection.h @@ -40,7 +40,6 @@ private: std::atomic m_NextID; std::map m_Origins; std::map m_OriginsNameMap; - std::map m_OriginsPriorityMap; mutable std::mutex m_Mutex; OriginID createID(); -- cgit v1.3.1 From e1106ad42c003f58c06172cb6afef9f526d05d59 Mon Sep 17 00:00:00 2001 From: Mikaël Capelle Date: Thu, 21 Jan 2021 21:02:25 +0100 Subject: Use priority from profile (+1) in directory structure to be consistent. --- src/directoryrefresher.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/directoryrefresher.cpp b/src/directoryrefresher.cpp index 26e43d53..063cd328 100644 --- a/src/directoryrefresher.cpp +++ b/src/directoryrefresher.cpp @@ -415,7 +415,7 @@ void DirectoryRefresher::addMultipleModsFilesToStructure( for (std::size_t i=0; i(i + 1); + const int prio = e.priority + 1; if constexpr (DirectoryStats::EnableInstrumentation) { stats[i].mod = entries[i].modName.toStdString(); -- cgit v1.3.1 From 34c87a0efa18ad77cbf773bc99bd9f08082b27e9 Mon Sep 17 00:00:00 2001 From: Mikaël Capelle Date: Thu, 21 Jan 2021 21:12:46 +0100 Subject: Prevent backups from being enabled. --- src/modinfo.h | 6 +++--- src/modinfobackup.h | 1 + src/profile.cpp | 9 ++++++++- 3 files changed, 12 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/modinfo.h b/src/modinfo.h index 0fbcd1c0..ff6c4001 100644 --- a/src/modinfo.h +++ b/src/modinfo.h @@ -606,10 +606,10 @@ public: // Methods after this do not come from IModInterface: // bool isFixedPriority() const { return isBackup() || isOverwrite(); } - /** - * @return true if the mod is always enabled. - */ + // check if this mod should always be enabled or disabled + // virtual bool alwaysEnabled() const { return false; } + virtual bool alwaysDisabled() const { return false; } /** * @return true if the mod can be updated. diff --git a/src/modinfobackup.h b/src/modinfobackup.h index 9529855b..853a1211 100644 --- a/src/modinfobackup.h +++ b/src/modinfobackup.h @@ -20,6 +20,7 @@ public: virtual void setNexusID(int) override {} virtual void endorse(bool) override {} virtual void ignoreUpdate(bool) override {} + virtual bool alwaysDisabled() const override { return true; } virtual bool canBeUpdated() const override { return false; } virtual QDateTime getExpires() const override { return QDateTime(); } virtual bool canBeEnabled() const override { return false; } diff --git a/src/profile.cpp b/src/profile.cpp index 6b8d0709..66c23ea1 100644 --- a/src/profile.cpp +++ b/src/profile.cpp @@ -602,11 +602,15 @@ void Profile::setModEnabled(unsigned int index, bool enabled) } ModInfo::Ptr modInfo = ModInfo::getByIndex(index); + // we could quit in the following case, this shouldn't be a change anyway, // but at least this allows the situation to be fixed in case of an error if (modInfo->alwaysEnabled()) { enabled = true; } + if (modInfo->alwaysDisabled()) { + enabled = false; + } if (enabled != m_ModStatus[index].m_Enabled) { m_ModStatus[index].m_Enabled = enabled; @@ -614,7 +618,7 @@ void Profile::setModEnabled(unsigned int index, bool enabled) } } -void Profile::setModsEnabled(const QList &modsToEnable, const QList &modsToDisable) +void Profile::setModsEnabled(const QList& modsToEnable, const QList& modsToDisable) { QList dirtyMods; for (auto idx : modsToEnable) { @@ -622,6 +626,9 @@ void Profile::setModsEnabled(const QList &modsToEnable, const QLis log::error("invalid mod index: {}", idx); continue; } + if (ModInfo::getByIndex(idx)->alwaysDisabled()) { + continue; + } if (!m_ModStatus[idx].m_Enabled) { m_ModStatus[idx].m_Enabled = true; dirtyMods.append(idx); -- cgit v1.3.1 From d81fb09f33f8cd668db20b6120c481580c6c938e Mon Sep 17 00:00:00 2001 From: Mikaël Capelle Date: Thu, 21 Jan 2021 21:20:01 +0100 Subject: Replace isFixedPriority by hasAutomaticPriority. --- src/modinfo.h | 5 +++-- src/modlist.cpp | 4 ++-- src/profile.cpp | 8 ++++---- 3 files changed, 9 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/modinfo.h b/src/modinfo.h index ff6c4001..f93296d2 100644 --- a/src/modinfo.h +++ b/src/modinfo.h @@ -602,9 +602,10 @@ public: // Methods after this do not come from IModInterface: */ virtual void ignoreUpdate(bool ignore) = 0; - // check if this mod has a fixed priority (i.e. that cannot be modified by users) + // check if the priority of this mod is not user-modifiable (i.e. + // computed by MO2 automatically) // - bool isFixedPriority() const { return isBackup() || isOverwrite(); } + bool hasAutomaticPriority() const { return isBackup() || isOverwrite(); } // check if this mod should always be enabled or disabled // diff --git a/src/modlist.cpp b/src/modlist.cpp index 6637f48a..e2a443bd 100644 --- a/src/modlist.cpp +++ b/src/modlist.cpp @@ -197,7 +197,7 @@ QVariant ModList::data(const QModelIndex &modelIndex, int role) const return version; } else if (column == COL_PRIORITY) { - if (modInfo->isFixedPriority()) { + if (modInfo->hasAutomaticPriority()) { return QVariant(); // hide priority for mods where it's fixed } else { @@ -642,7 +642,7 @@ Qt::ItemFlags ModList::flags(const QModelIndex &modelIndex) const } if (modelIndex.isValid()) { ModInfo::Ptr modInfo = ModInfo::getByIndex(modelIndex.row()); - if (!modInfo->isFixedPriority()) { + if (!modInfo->hasAutomaticPriority()) { result |= Qt::ItemIsDragEnabled; result |= Qt::ItemIsUserCheckable; if ((modelIndex.column() == COL_PRIORITY) || diff --git a/src/profile.cpp b/src/profile.cpp index 66c23ea1..2546661b 100644 --- a/src/profile.cpp +++ b/src/profile.cpp @@ -234,7 +234,7 @@ void Profile::doWriteModlist() // the priority order was inverted on load so it has to be inverted again const auto index = iter->second; ModInfo::Ptr modInfo = ModInfo::getByIndex(index); - if (!modInfo->isFixedPriority()) { + if (!modInfo->hasAutomaticPriority()) { if (modInfo->isForeign()) { file->write("*"); } else if (m_ModStatus[index].m_Enabled) { @@ -460,7 +460,7 @@ void Profile::refreshModStatus() // find the mod and check that this is a regular mod (and not a backup) ModInfo::Ptr info = ModInfo::getByIndex(modIndex); - if (modIndex < m_ModStatus.size() && !info->isFixedPriority()) { + if (modIndex < m_ModStatus.size() && !info->hasAutomaticPriority()) { m_ModStatus[modIndex].m_Enabled = enabled; if (m_ModStatus[modIndex].m_Priority == -1) { if (static_cast(index) >= m_ModStatus.size()) { @@ -527,7 +527,7 @@ void Profile::refreshModStatus() int offset = topInsert * -1; for (size_t i = 0; i < m_ModStatus.size(); ++i) { ModInfo::Ptr modInfo = ModInfo::getByIndex(static_cast(i)); - if (modInfo->isFixedPriority()) { + if (modInfo->hasAutomaticPriority()) { continue; } @@ -674,7 +674,7 @@ int Profile::getModPriority(unsigned int index) const bool Profile::setModPriority(unsigned int index, int &newPriority) { - if (ModInfo::getByIndex(index)->isFixedPriority()) { + if (ModInfo::getByIndex(index)->hasAutomaticPriority()) { // can't change priority of overwrite/backups return false; } -- cgit v1.3.1 From b1795f83cd500b5b58928efa5e170de8338178d5 Mon Sep 17 00:00:00 2001 From: Mikaël Capelle Date: Thu, 21 Jan 2021 21:56:08 +0100 Subject: Refresh data tab when mods are enabled or moved. --- src/mainwindow.cpp | 6 ++++++ src/modlist.cpp | 2 ++ 2 files changed, 8 insertions(+) (limited to 'src') diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index a79aca2f..d6391677 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -313,6 +313,12 @@ MainWindow::MainWindow(Settings &settings setupModList(); ui->espList->setup(m_OrganizerCore, this, ui); + connect(m_OrganizerCore.modList(), &ModList::modPrioritiesChanged, [this]() { + m_DataTab->updateTree(); + }); + connect(m_OrganizerCore.modList(), &ModList::modStatesChanged, [this]() { + m_DataTab->updateTree(); + }); ui->bsaList->setLocalMoveOnly(true); ui->bsaList->setHeaderHidden(true); diff --git a/src/modlist.cpp b/src/modlist.cpp index e2a443bd..13b2298f 100644 --- a/src/modlist.cpp +++ b/src/modlist.cpp @@ -1433,4 +1433,6 @@ void ModList::setActive(const QModelIndexList& indices, bool active) else { m_Profile->setModsEnabled({}, mods); } + + emit modStatesChanged(indices); } -- cgit v1.3.1 From d94b7c444d02e070875026d8c037fbd9700d2ca8 Mon Sep 17 00:00:00 2001 From: Mikaël Capelle Date: Thu, 21 Jan 2021 21:56:26 +0100 Subject: Move update of directory structure after mod priority change to organizer core. --- src/modlistview.cpp | 36 ------------------------------------ src/organizercore.cpp | 45 +++++++++++++++++++++++++++++++++++++++++++-- src/organizercore.h | 1 + 3 files changed, 44 insertions(+), 38 deletions(-) (limited to 'src') diff --git a/src/modlistview.cpp b/src/modlistview.cpp index aa920905..a6bb4982 100644 --- a/src/modlistview.cpp +++ b/src/modlistview.cpp @@ -434,42 +434,6 @@ void ModListView::onModPrioritiesChanged(const QModelIndexList& indices) } } - for (unsigned int i = 0; i < m_core->currentProfile()->numMods(); ++i) { - int priority = m_core->currentProfile()->getModPriority(i); - if (m_core->currentProfile()->modEnabled(i)) { - ModInfo::Ptr modInfo = ModInfo::getByIndex(i); - // priorities in the directory structure are one higher because data is 0 - m_core->directoryStructure()->getOriginByName(MOBase::ToWString(modInfo->internalName())).setPriority(priority + 1); - } - } - m_core->refreshBSAList(); - m_core->currentProfile()->writeModlist(); - m_core->directoryStructure()->getFileRegister()->sortOrigins(); - - for (auto& idx : indices) { - ModInfo::Ptr modInfo = ModInfo::getByIndex(idx.data(ModList::IndexRole).toInt()); - // clear caches on all mods conflicting with the moved mod - for (int i : modInfo->getModOverwrite()) { - ModInfo::getByIndex(i)->clearCaches(); - } - for (int i : modInfo->getModOverwritten()) { - ModInfo::getByIndex(i)->clearCaches(); - } - for (int i : modInfo->getModArchiveOverwrite()) { - ModInfo::getByIndex(i)->clearCaches(); - } - for (int i : modInfo->getModArchiveOverwritten()) { - ModInfo::getByIndex(i)->clearCaches(); - } - for (int i : modInfo->getModArchiveLooseOverwrite()) { - ModInfo::getByIndex(i)->clearCaches(); - } - for (int i : modInfo->getModArchiveLooseOverwritten()) { - ModInfo::getByIndex(i)->clearCaches(); - } - // update conflict check on the moved mod - modInfo->doConflictCheck(); - } setOverwriteMarkers(selectionModel()->selectedRows()); } diff --git a/src/organizercore.cpp b/src/organizercore.cpp index cf641886..df4cfe5e 100644 --- a/src/organizercore.cpp +++ b/src/organizercore.cpp @@ -119,6 +119,7 @@ OrganizerCore::OrganizerCore(Settings &settings) connect(&m_ModList, SIGNAL(removeOrigin(QString)), this, SLOT(removeOrigin(QString))); connect(&m_ModList, &ModList::modStatesChanged, [=] { currentProfile()->writeModlist(); }); + connect(&m_ModList, &ModList::modPrioritiesChanged, [this](auto&& indexes) { modPrioritiesChanged(indexes); }); connect(NexusInterface::instance().getAccessManager(), SIGNAL(validateSuccessful(bool)), this, SLOT(loginSuccessful(bool))); @@ -581,8 +582,8 @@ void OrganizerCore::setCurrentProfile(const QString &profileName) m_Settings.game().setSelectedProfileName(m_CurrentProfile->name()); - connect(m_CurrentProfile.get(), SIGNAL(modStatusChanged(uint)), this, SLOT(modStatusChanged(uint))); - connect(m_CurrentProfile.get(), SIGNAL(modStatusChanged(QList)), this, SLOT(modStatusChanged(QList))); + connect(m_CurrentProfile.get(), qOverload(&Profile::modStatusChanged), [this](auto&& index) { modStatusChanged(index); }); + connect(m_CurrentProfile.get(), qOverload>(&Profile::modStatusChanged), [this](auto&& indexes) { modStatusChanged(indexes); }); refreshDirectoryStructure(); m_CurrentProfile->debugDump(); @@ -1565,6 +1566,46 @@ void OrganizerCore::profileRefresh() refresh(); } +void OrganizerCore::modPrioritiesChanged(const QModelIndexList& indices) +{ + for (unsigned int i = 0; i < currentProfile()->numMods(); ++i) { + int priority = currentProfile()->getModPriority(i); + if (currentProfile()->modEnabled(i)) { + ModInfo::Ptr modInfo = ModInfo::getByIndex(i); + // priorities in the directory structure are one higher because data is 0 + directoryStructure()->getOriginByName(MOBase::ToWString(modInfo->internalName())).setPriority(priority + 1); + } + } + refreshBSAList(); + currentProfile()->writeModlist(); + directoryStructure()->getFileRegister()->sortOrigins(); + + for (auto& idx : indices) { + ModInfo::Ptr modInfo = ModInfo::getByIndex(idx.data(ModList::IndexRole).toInt()); + // clear caches on all mods conflicting with the moved mod + for (int i : modInfo->getModOverwrite()) { + ModInfo::getByIndex(i)->clearCaches(); + } + for (int i : modInfo->getModOverwritten()) { + ModInfo::getByIndex(i)->clearCaches(); + } + for (int i : modInfo->getModArchiveOverwrite()) { + ModInfo::getByIndex(i)->clearCaches(); + } + for (int i : modInfo->getModArchiveOverwritten()) { + ModInfo::getByIndex(i)->clearCaches(); + } + for (int i : modInfo->getModArchiveLooseOverwrite()) { + ModInfo::getByIndex(i)->clearCaches(); + } + for (int i : modInfo->getModArchiveLooseOverwritten()) { + ModInfo::getByIndex(i)->clearCaches(); + } + // update conflict check on the moved mod + modInfo->doConflictCheck(); + } +} + void OrganizerCore::modStatusChanged(unsigned int index) { try { diff --git a/src/organizercore.h b/src/organizercore.h index 53686c8a..c00d0d42 100644 --- a/src/organizercore.h +++ b/src/organizercore.h @@ -362,6 +362,7 @@ public slots: ModInfo::Ptr installArchive(const QString& archivePath, int priority = -1, bool reinstallation = false, ModInfo::Ptr currentMod = nullptr, const QString& modName = QString()); + void modPrioritiesChanged(QModelIndexList const& indexes); void modStatusChanged(unsigned int index); void modStatusChanged(QList index); void requestDownload(const QUrl &url, QNetworkReply *reply); -- cgit v1.3.1 From 7864fc0950729621c0297389f5b47d27e4d41d8f Mon Sep 17 00:00:00 2001 From: Mikaël Capelle Date: Fri, 22 Jan 2021 21:18:54 +0100 Subject: Use constant for minimum/maximum priorities. --- src/modlist.cpp | 5 +---- src/modlistbypriorityproxy.cpp | 2 +- src/modlistviewactions.cpp | 6 +++--- src/profile.h | 12 ++++++++++-- 4 files changed, 15 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/modlist.cpp b/src/modlist.cpp index 13b2298f..81dc91bf 100644 --- a/src/modlist.cpp +++ b/src/modlist.cpp @@ -1023,14 +1023,11 @@ int ModList::dropPriority(int row, const QModelIndex& parent) const int newPriority = 0; { if (row < 0 || row >= rowCount()) { - newPriority = std::numeric_limits::max(); + newPriority = Profile::MaximumPriority; } else { newPriority = m_Profile->getModPriority(row); } - if (newPriority == -1) { - newPriority = std::numeric_limits::max(); - } } return newPriority; diff --git a/src/modlistbypriorityproxy.cpp b/src/modlistbypriorityproxy.cpp index d1d045fc..24e58ed0 100644 --- a/src/modlistbypriorityproxy.cpp +++ b/src/modlistbypriorityproxy.cpp @@ -234,7 +234,7 @@ bool ModListByPriorityProxy::canDropMimeData(const QMimeData* data, Qt::DropActi bool hasSeparator = false; unsigned int firstRowIndex = -1; - int firstRowPriority = std::numeric_limits::max(); + int firstRowPriority = Profile::MaximumPriority; for (auto sourceRow : dropInfo.rows()) { hasSeparator = hasSeparator || ModInfo::getByIndex(sourceRow)->isSeparator(); if (m_sortOrder == Qt::AscendingOrder && m_profile->getModPriority(sourceRow) < firstRowPriority diff --git a/src/modlistviewactions.cpp b/src/modlistviewactions.cpp index e7e74b16..647aac0b 100644 --- a/src/modlistviewactions.cpp +++ b/src/modlistviewactions.cpp @@ -539,12 +539,12 @@ void ModListViewActions::displayModInformation(ModInfo::Ptr modInfo, unsigned in void ModListViewActions::sendModsToTop(const QModelIndexList& indexes) const { - m_core.modList()->changeModsPriority(indexes, 0); + m_core.modList()->changeModsPriority(indexes, Profile::MinimumPriority); } void ModListViewActions::sendModsToBottom(const QModelIndexList& indexes) const { - m_core.modList()->changeModsPriority(indexes, std::numeric_limits::max()); + m_core.modList()->changeModsPriority(indexes, Profile::MaximumPriority); } void ModListViewActions::sendModsToPriority(const QModelIndexList& indexes) const @@ -580,7 +580,7 @@ void ModListViewActions::sendModsToSeparator(const QModelIndexList& indexes) con if (!result.isEmpty()) { result += "_separator"; - int newPriority = std::numeric_limits::max(); + int newPriority = Profile::MaximumPriority; bool foundSection = false; for (auto mod : m_core.modList()->allModsByProfilePriority()) { unsigned int modIndex = ModInfo::getIndex(mod); diff --git a/src/profile.h b/src/profile.h index d1e3f104..672a2c13 100644 --- a/src/profile.h +++ b/src/profile.h @@ -52,7 +52,14 @@ class Profile : public QObject, public MOBase::IProfile public: - typedef boost::shared_ptr Ptr; + using Ptr = boost::shared_ptr; + +public: + + // the minimum and maximum priority achievable by mods + // + static constexpr int MinimumPriority = 0; + static constexpr int MaximumPriority = std::numeric_limits::max(); public: @@ -283,7 +290,8 @@ public: // [old priority, new priority] such that no gaps are possible // // the priority is clamped in the range of valid priority (>= 0, and lower than - // the number of "regular" mods) + // the number of "regular" mods), you should use MinimumPriority or MaximumPriority + // to send a mod to the "top" or "bottom" of the priority list // // the function returns true if the priority was changed, or false if the mod // was already at the given priority (or if the priority of the mod cannot be -- cgit v1.3.1 From 54744c04b25454440c6d9a590a9ae2f36226bc03 Mon Sep 17 00:00:00 2001 From: Mikaël Capelle Date: Fri, 22 Jan 2021 21:19:35 +0100 Subject: Use proper naming convention for constants. --- src/downloadlist.cpp | 2 +- src/modlist.cpp | 2 +- src/modlistdropinfo.cpp | 4 ++-- src/modlistdropinfo.h | 4 ++-- src/settingsdialogplugins.cpp | 30 +++++++++++++++--------------- src/settingsdialogplugins.h | 8 +++++--- 6 files changed, 26 insertions(+), 24 deletions(-) (limited to 'src') diff --git a/src/downloadlist.cpp b/src/downloadlist.cpp index 93f8538c..9f29f475 100644 --- a/src/downloadlist.cpp +++ b/src/downloadlist.cpp @@ -99,7 +99,7 @@ Qt::ItemFlags DownloadList::flags(const QModelIndex& idx) const QMimeData* DownloadList::mimeData(const QModelIndexList& indexes) const { QMimeData* result = QAbstractItemModel::mimeData(indexes); - result->setData("text/plain", ModListDropInfo::DOWNLOAD_TEXT); + result->setData("text/plain", ModListDropInfo::DownloadText); return result; } diff --git a/src/modlist.cpp b/src/modlist.cpp index 81dc91bf..de24fbbd 100644 --- a/src/modlist.cpp +++ b/src/modlist.cpp @@ -677,7 +677,7 @@ QStringList ModList::mimeTypes() const QMimeData *ModList::mimeData(const QModelIndexList &indexes) const { QMimeData *result = QAbstractItemModel::mimeData(indexes); - result->setData("text/plain", ModListDropInfo::MOD_TEXT); + result->setData("text/plain", ModListDropInfo::ModText); return result; } diff --git a/src/modlistdropinfo.cpp b/src/modlistdropinfo.cpp index 62a103a4..a247194f 100644 --- a/src/modlistdropinfo.cpp +++ b/src/modlistdropinfo.cpp @@ -48,8 +48,8 @@ ModListDropInfo::ModListDropInfo(const QMimeData* mimeData, OrganizerCore& core) } } - if (mimeData->text() != ModListDropInfo::MOD_TEXT) { - if (mimeData->text() == ModListDropInfo::DOWNLOAD_TEXT && m_rows.size() == 1) { + if (mimeData->text() != ModListDropInfo::ModText) { + if (mimeData->text() == ModListDropInfo::DownloadText && m_rows.size() == 1) { m_download = m_rows[0]; } m_rows = {}; diff --git a/src/modlistdropinfo.h b/src/modlistdropinfo.h index 14a21691..5d2af92f 100644 --- a/src/modlistdropinfo.h +++ b/src/modlistdropinfo.h @@ -18,8 +18,8 @@ public: // text value for the mime-data for the various possible // origin (not for external drops) // - static constexpr const char* MOD_TEXT = "mod"; - static constexpr const char* DOWNLOAD_TEXT = "download"; + static constexpr const char* ModText = "mod"; + static constexpr const char* DownloadText = "download"; public: diff --git a/src/settingsdialogplugins.cpp b/src/settingsdialogplugins.cpp index 16f6fb0a..2f7f3985 100644 --- a/src/settingsdialogplugins.cpp +++ b/src/settingsdialogplugins.cpp @@ -40,18 +40,18 @@ PluginsSettingsTab::PluginsSettingsTab(Settings& s, PluginContainer* pluginConta QTreeWidgetItem* listItem = new QTreeWidgetItem( topItems.at(m_pluginContainer->topImplementedInterface(plugin))); listItem->setData(0, Qt::DisplayRole, plugin->localizedName()); - listItem->setData(0, ROLE_PLUGIN, QVariant::fromValue((void*)plugin)); - listItem->setData(0, ROLE_SETTINGS, settings().plugins().settings(plugin->name())); - listItem->setData(0, ROLE_DESCRIPTIONS, settings().plugins().descriptions(plugin->name())); + listItem->setData(0, PluginRole, QVariant::fromValue((void*)plugin)); + listItem->setData(0, SettingsRole, settings().plugins().settings(plugin->name())); + listItem->setData(0, DescriptionsRole, settings().plugins().descriptions(plugin->name())); // Handle child item: auto children = m_pluginContainer->requirements(plugin).children(); for (auto* child : children) { QTreeWidgetItem* childItem = new QTreeWidgetItem(listItem); childItem->setData(0, Qt::DisplayRole, child->localizedName()); - childItem->setData(0, ROLE_PLUGIN, QVariant::fromValue((void*)child)); - childItem->setData(0, ROLE_SETTINGS, settings().plugins().settings(child->name())); - childItem->setData(0, ROLE_DESCRIPTIONS, settings().plugins().descriptions(child->name())); + childItem->setData(0, PluginRole, QVariant::fromValue((void*)child)); + childItem->setData(0, SettingsRole, settings().plugins().settings(child->name())); + childItem->setData(0, DescriptionsRole, settings().plugins().descriptions(child->name())); handledNames.insert(child->name()); } @@ -174,7 +174,7 @@ void PluginsSettingsTab::filterPluginList() IPlugin* PluginsSettingsTab::plugin(QTreeWidgetItem* pluginItem) const { - return static_cast(qvariant_cast(pluginItem->data(0, ROLE_PLUGIN))); + return static_cast(qvariant_cast(pluginItem->data(0, PluginRole))); } void PluginsSettingsTab::update() @@ -185,7 +185,7 @@ void PluginsSettingsTab::update() for (int j = 0; j < topLevelItem->childCount(); ++j) { auto* item = topLevelItem->child(j); settings().plugins().setSettings( - plugin(item)->name(), item->data(0, ROLE_SETTINGS).toMap()); + plugin(item)->name(), item->data(0, SettingsRole).toMap()); } } @@ -209,7 +209,7 @@ void PluginsSettingsTab::on_checkboxEnabled_clicked(bool checked) { // Retrieve the plugin: auto *item = ui->pluginsList->currentItem(); - if (!item || !item->data(0, ROLE_PLUGIN).isValid()) { + if (!item || !item->data(0, PluginRole).isValid()) { return; } IPlugin* plugin = this->plugin(item); @@ -278,7 +278,7 @@ void PluginsSettingsTab::on_pluginsList_currentItemChanged(QTreeWidgetItem *curr { storeSettings(previous); - if (!current->data(0, ROLE_PLUGIN).isValid()) { + if (!current->data(0, PluginRole).isValid()) { return; } @@ -325,8 +325,8 @@ void PluginsSettingsTab::on_pluginsList_currentItemChanged(QTreeWidgetItem *curr } } - QVariantMap settings = current->data(0, ROLE_SETTINGS).toMap(); - QVariantMap descriptions = current->data(0, ROLE_DESCRIPTIONS).toMap(); + QVariantMap settings = current->data(0, SettingsRole).toMap(); + QVariantMap descriptions = current->data(0, DescriptionsRole).toMap(); ui->pluginSettingsList->setEnabled(settings.count() != 0); for (auto iter = settings.begin(); iter != settings.end(); ++iter) { QTreeWidgetItem *newItem = new QTreeWidgetItem(QStringList(iter.key())); @@ -359,14 +359,14 @@ void PluginsSettingsTab::deleteBlacklistItem() void PluginsSettingsTab::storeSettings(QTreeWidgetItem *pluginItem) { - if (pluginItem != nullptr && pluginItem->data(0, ROLE_PLUGIN).isValid()) { - QVariantMap settings = pluginItem->data(0, ROLE_SETTINGS).toMap(); + if (pluginItem != nullptr && pluginItem->data(0, PluginRole).isValid()) { + QVariantMap settings = pluginItem->data(0, SettingsRole).toMap(); for (int i = 0; i < ui->pluginSettingsList->topLevelItemCount(); ++i) { const QTreeWidgetItem *item = ui->pluginSettingsList->topLevelItem(i); settings[item->text(0)] = item->data(1, Qt::DisplayRole); } - pluginItem->setData(0, ROLE_SETTINGS, settings); + pluginItem->setData(0, SettingsRole, settings); } } diff --git a/src/settingsdialogplugins.h b/src/settingsdialogplugins.h index 3de0d7dc..c784b83e 100644 --- a/src/settingsdialogplugins.h +++ b/src/settingsdialogplugins.h @@ -39,9 +39,11 @@ private slots: */ MOBase::IPlugin* plugin(QTreeWidgetItem *pluginItem) const; - constexpr static int ROLE_PLUGIN = Qt::UserRole; - constexpr static int ROLE_SETTINGS = Qt::UserRole + 1; - constexpr static int ROLE_DESCRIPTIONS = Qt::UserRole + 2; + enum { + PluginRole = Qt::UserRole, + SettingsRole = Qt::UserRole + 1, + DescriptionsRole = Qt::UserRole + 2 + }; private: -- cgit v1.3.1 From ab820c1b0a5bb0f002ec5aba7954330acbdeb978 Mon Sep 17 00:00:00 2001 From: Mikaël Capelle Date: Sun, 24 Jan 2021 11:09:12 +0100 Subject: Fix enable/disable all message. --- src/modlistview.cpp | 105 ++++++++++++++++++----------------------- src/modlistview.h | 113 +++++++++++++++++++++++++++------------------ src/modlistviewactions.cpp | 8 +++- 3 files changed, 120 insertions(+), 106 deletions(-) (limited to 'src') diff --git a/src/modlistview.cpp b/src/modlistview.cpp index a6bb4982..d7f90c9f 100644 --- a/src/modlistview.cpp +++ b/src/modlistview.cpp @@ -471,67 +471,52 @@ void ModListView::onModFilterActive(bool filterActive) } } -void ModListView::updateModCount() +ModListView::ModCounters ModListView::counters() const { - int activeCount = 0; - int visActiveCount = 0; - int backupCount = 0; - int visBackupCount = 0; - int foreignCount = 0; - int visForeignCount = 0; - int separatorCount = 0; - int visSeparatorCount = 0; - int regularCount = 0; - int visRegularCount = 0; - - QStringList allMods = m_core->modList()->allMods(); + ModCounters c; auto hasFlag = [](std::vector flags, ModInfo::EFlag filter) { return std::find(flags.begin(), flags.end(), filter) != flags.end(); }; - bool isEnabled; - bool isVisible; - for (QString mod : allMods) { - int modIndex = ModInfo::getIndex(mod); - ModInfo::Ptr modInfo = ModInfo::getByIndex(modIndex); - std::vector modFlags = modInfo->getFlags(); - isEnabled = m_core->currentProfile()->modEnabled(modIndex); - isVisible = m_sortProxy->filterMatchesMod(modInfo, isEnabled); - - for (auto flag : modFlags) { - switch (flag) { - case ModInfo::FLAG_BACKUP: backupCount++; - if (isVisible) - visBackupCount++; - break; - case ModInfo::FLAG_FOREIGN: foreignCount++; - if (isVisible) - visForeignCount++; - break; - case ModInfo::FLAG_SEPARATOR: separatorCount++; - if (isVisible) - visSeparatorCount++; - break; - } - } - if (!hasFlag(modFlags, ModInfo::FLAG_BACKUP) && - !hasFlag(modFlags, ModInfo::FLAG_FOREIGN) && - !hasFlag(modFlags, ModInfo::FLAG_SEPARATOR) && - !hasFlag(modFlags, ModInfo::FLAG_OVERWRITE)) { - if (isEnabled) { - activeCount++; - if (isVisible) - visActiveCount++; + for (unsigned int index = 0; index < ModInfo::getNumMods(); ++index) { + auto info = ModInfo::getByIndex(index); + const auto flags = info->getFlags(); + + const bool enabled = m_core->currentProfile()->modEnabled(index); + const bool visible = m_sortProxy->filterMatchesMod(info, enabled); + + if (info->isBackup()) { + c.backup++; + if (visible) c.visible.backup++; + } + else if (info->isForeign()) { + c.foreign++; + if (visible) c.visible.foreign++; + } + else if (info->isSeparator()) { + c.separator++; + if (visible) c.visible.separator++; + } + else if (!info->isOverwrite()) { + c.regular++; + if (visible) c.visible.regular++; + if (enabled) { + c.active++; + if (visible) c.visible.active++; } - if (isVisible) - visRegularCount++; - regularCount++; } } - ui.counter->display(visActiveCount); + return c; +} + +void ModListView::updateModCount() +{ + const auto c = counters(); + + ui.counter->display(c.visible.active); ui.counter->setToolTip(tr("" "" "" @@ -539,16 +524,16 @@ void ModListView::updateModCount() "" "" "
TypeAllVisible
Enabled mods: %1 / %2%3 / %4
Mod backups: %7%8
Separators: %9%10
") - .arg(activeCount) - .arg(regularCount) - .arg(visActiveCount) - .arg(visRegularCount) - .arg(foreignCount) - .arg(visForeignCount) - .arg(backupCount) - .arg(visBackupCount) - .arg(separatorCount) - .arg(visSeparatorCount) + .arg(c.active) + .arg(c.regular) + .arg(c.visible.active) + .arg(c.visible.regular) + .arg(c.foreign) + .arg(c.visible.foreign) + .arg(c.backup) + .arg(c.visible.backup) + .arg(c.separator) + .arg(c.visible.separator) ); } diff --git a/src/modlistview.h b/src/modlistview.h index adffd737..408bc900 100644 --- a/src/modlistview.h +++ b/src/modlistview.h @@ -131,9 +131,6 @@ public slots: protected: - friend class ModListContextMenu; - friend class ModListViewActions; - // map from/to the view indexes to the model // QModelIndex indexModelToView(const QModelIndex& index) const; @@ -183,14 +180,74 @@ protected slots: void commitData(QWidget* editor) override; -private: +private: // friend classes friend class ModConflictIconDelegate; - friend class ModFlagIconDelegate; friend class ModContentIconDelegate; + friend class ModFlagIconDelegate; + friend class ModListContextMenu; friend class ModListStyledItemDelegate; + friend class ModListViewActions; friend class ModListViewMarkingScrollBar; +private: // private structures + + struct ModListViewUi { + // the group by combo box + QComboBox* groupBy; + + // the mod counter + QLCDNumber* counter; + + // filters related + QLineEdit* filter; + QLabel* currentCategory; + QPushButton* clearFilters; + QComboBox* filterSeparators; + + // the plugin list (for highligths) + PluginListView* pluginList; + }; + + struct MarkerInfos { + // conflicts + std::set overwrite; + std::set overwritten; + std::set archiveOverwrite; + std::set archiveOverwritten; + std::set archiveLooseOverwrite; + std::set archiveLooseOverwritten; + + // selected plugins + std::set highlight; + }; + + struct ModCounters { + int active = 0; + int backup = 0; + int foreign = 0; + int separator = 0; + int regular = 0; + + struct { + int active = 0; + int backup = 0; + int foreign = 0; + int separator = 0; + int regular = 0; + } visible; + }; + + // index in the groupby combo + // + enum GroupBy { + NONE = 0, + CATEGORY = 1, + NEXUS_ID = 2 + }; + +private: // private functions + void onModPrioritiesChanged(const QModelIndexList& indices); void onModInstalled(const QString& modName); void onModFilterActive(bool filterActive); @@ -229,6 +286,10 @@ private: QList contentsIcons(const QModelIndex& index, bool* forceCompact = nullptr) const; QString contentsTooltip(const QModelIndex& index) const; + // compute the counters for mods according to the current filter + // + ModCounters counters() const; + // get/set the selected items on the view, this method return/take indices // from the mod list model, not the view, so it's safe to restore // @@ -244,33 +305,7 @@ private: // void updateGroupByProxy(); - // index in the groupby combo - // - enum GroupBy { - NONE = 0, - CATEGORY = 1, - NEXUS_ID = 2 - }; - -private: - - struct ModListViewUi - { - // the group by combo box - QComboBox* groupBy; - - // the mod counter - QLCDNumber* counter; - - // filters related - QLineEdit* filter; - QLabel* currentCategory; - QPushButton* clearFilters; - QComboBox* filterSeparators; - - // the plugin list (for highligths) - PluginListView* pluginList; - }; +public: // member variables OrganizerCore* m_core; std::unique_ptr m_filters; @@ -291,19 +326,7 @@ private: // losing them on model reset std::map> m_collapsed; - struct MarkerInfos { - // conflicts - std::set overwrite; - std::set overwritten; - std::set archiveOverwrite; - std::set archiveOverwritten; - std::set archiveLooseOverwrite; - std::set archiveLooseOverwritten; - - // selected plugins - std::set highlight; - } m_markers; - + MarkerInfos m_markers; ViewMarkingScrollBar* m_scrollbar; bool m_inDragMoveEvent = false; diff --git a/src/modlistviewactions.cpp b/src/modlistviewactions.cpp index 647aac0b..9d4be554 100644 --- a/src/modlistviewactions.cpp +++ b/src/modlistviewactions.cpp @@ -207,10 +207,16 @@ void ModListViewActions::createSeparator(const QModelIndex& index) const void ModListViewActions::setAllMatchingModsEnabled(bool enabled) const { + // number of mods to enable / disable + const auto counters = m_view->counters(); + const auto count = enabled ? + counters.visible.regular - counters.visible.active : counters.visible.active; + + // retrieve visible mods from the model view const auto allIndex = m_view->indexViewToModel(flatIndex(m_view->model())); const QString message = enabled ? tr("Really enable %1 mod(s)?") : tr("Really disable %1 mod(s)?"); - if (QMessageBox::question(m_parent, tr("Confirm"), message.arg(allIndex.size()), + if (QMessageBox::question(m_parent, tr("Confirm"), message.arg(count), QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) { m_core.modList()->setActive(allIndex, enabled); } -- cgit v1.3.1 From 48fae18ac6baced388b1fa7cee6c18e6aa8dbab3 Mon Sep 17 00:00:00 2001 From: Mikaël Capelle Date: Fri, 29 Jan 2021 19:27:10 +0100 Subject: Fix refresh of data tab. --- src/datatab.cpp | 24 ++++++++++++++++++++---- src/datatab.h | 10 +++++++++- src/mainwindow.cpp | 16 ++++++++-------- src/mainwindow.h | 7 +++++-- 4 files changed, 42 insertions(+), 15 deletions(-) (limited to 'src') diff --git a/src/datatab.cpp b/src/datatab.cpp index 21c205e5..165ee26a 100644 --- a/src/datatab.cpp +++ b/src/datatab.cpp @@ -20,9 +20,9 @@ DataTab::DataTab( QWidget* parent, Ui::MainWindow* mwui) : m_core(core), m_pluginContainer(pc), m_parent(parent), ui{ - mwui->dataTabRefresh, mwui->dataTree, + mwui->tabWidget, mwui->dataTab, mwui->dataTabRefresh, mwui->dataTree, mwui->dataTabShowOnlyConflicts, mwui->dataTabShowFromArchives}, - m_firstActivation(true) + m_needUpdate(true) { m_filetree.reset(new FileTree(core, m_pluginContainer, ui.tree)); m_filter.setUseSourceSort(true); @@ -85,12 +85,16 @@ void DataTab::restoreState(const Settings& s) void DataTab::activated() { - if (m_firstActivation) { - m_firstActivation = false; + if (m_needUpdate) { updateTree(); } } +bool DataTab::isActive() const +{ + return ui.tabs->currentWidget() == ui.tab; +} + void DataTab::onRefresh() { if (QGuiApplication::keyboardModifiers() & Qt::ShiftModifier) { @@ -102,6 +106,16 @@ void DataTab::onRefresh() } void DataTab::updateTree() +{ + if (isActive()) { + doUpdateTree(); + } + else { + m_needUpdate = true; + } +} + +void DataTab::doUpdateTree() { m_filetree->model()->setEnabled(true); m_filetree->refresh(); @@ -113,6 +127,8 @@ void DataTab::updateTree() m->invalidate(); } } + + m_needUpdate = true; } void DataTab::ensureFullyLoaded() diff --git a/src/datatab.h b/src/datatab.h index 32d788f6..ad172ab0 100644 --- a/src/datatab.h +++ b/src/datatab.h @@ -29,6 +29,10 @@ public: void restoreState(const Settings& s); void activated(); + // if the data tab is currently visible, trigger an update of the + // tree, otherwise mark the tree has modified and will refresh when + // the tab is activated + // void updateTree(); signals: @@ -39,6 +43,8 @@ signals: private: struct DataTabUi { + QTabWidget* tabs; + QWidget* tab; QPushButton* refresh; QTreeView* tree; QCheckBox* conflicts; @@ -52,7 +58,7 @@ private: std::unique_ptr m_filetree; std::vector m_removeLater; MOBase::FilterWidget m_filter; - bool m_firstActivation; + bool m_needUpdate; void onRefresh(); void onItemExpanded(QTreeWidgetItem* item); @@ -60,6 +66,8 @@ private: void onArchives(); void updateOptions(); void ensureFullyLoaded(); + bool isActive() const; + void doUpdateTree(); }; #endif // MODORGANIZER_DATATAB_INCLUDED diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index d6391677..a3144edd 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -314,10 +314,13 @@ MainWindow::MainWindow(Settings &settings setupModList(); ui->espList->setup(m_OrganizerCore, this, ui); connect(m_OrganizerCore.modList(), &ModList::modPrioritiesChanged, [this]() { - m_DataTab->updateTree(); + onDirectoryStructureChanged(); }); connect(m_OrganizerCore.modList(), &ModList::modStatesChanged, [this]() { - m_DataTab->updateTree(); + onDirectoryStructureChanged(); + }); + connect(m_OrganizerCore.modList(), &QAbstractItemModel::rowsRemoved, [this]() { + onDirectoryStructureChanged(); }); ui->bsaList->setLocalMoveOnly(true); @@ -391,7 +394,7 @@ MainWindow::MainWindow(Settings &settings connect(&m_PluginContainer, SIGNAL(diagnosisUpdate()), this, SLOT(scheduleCheckForProblems())); - connect(m_OrganizerCore.directoryRefresher(), SIGNAL(refreshed()), this, SLOT(directory_refreshed())); + connect(m_OrganizerCore.directoryRefresher(), &DirectoryRefresher::refreshed, [this] { onDirectoryStructureChanged(); }); connect( m_OrganizerCore.directoryRefresher(), &DirectoryRefresher::progress, @@ -2184,15 +2187,12 @@ void MainWindow::refresherProgress(const DirectoryRefreshProgress* p) } } -void MainWindow::directory_refreshed() +void MainWindow::onDirectoryStructureChanged() { // some problem-reports may rely on the virtual directory tree so they need to be updated // now scheduleCheckForProblems(); - - if (ui->tabWidget->currentWidget() == ui->dataTab) { - m_DataTab->updateTree(); - } + m_DataTab->updateTree(); } void MainWindow::modInstalled(const QString &modName) diff --git a/src/mainwindow.h b/src/mainwindow.h index 1f521f38..f9cf541c 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -142,8 +142,6 @@ public: public slots: void refresherProgress(const DirectoryRefreshProgress* p); - void directory_refreshed(); - signals: /** @@ -169,6 +167,11 @@ private slots: private: + // update data tab and schedule a problem check after a directory + // structure update + // + void onDirectoryStructureChanged(); + void cleanup(); void setupToolbar(); -- cgit v1.3.1