From cf1bbdd13e0db8856df672c367d3ec1610f6c556 Mon Sep 17 00:00:00 2001 From: Mikaël Capelle Date: Mon, 25 May 2020 19:53:21 +0200 Subject: Switch to using the ModDataContent feature from the game plugin. --- src/modlistsortproxy.cpp | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) (limited to 'src/modlistsortproxy.cpp') diff --git a/src/modlistsortproxy.cpp b/src/modlistsortproxy.cpp index 018b9760..99dba913 100644 --- a/src/modlistsortproxy.cpp +++ b/src/modlistsortproxy.cpp @@ -177,22 +177,7 @@ bool ModListSortProxy::lessThan(const QModelIndex &left, } } break; case ModList::COL_CONTENT: { - std::vector lContent = leftMod->getContents(); - std::vector rContent = rightMod->getContents(); - if (lContent.size() != rContent.size()) { - lt = lContent.size() < rContent.size(); - } - - int lValue = 0; - int rValue = 0; - for (ModInfo::EContent content : lContent) { - lValue += 2 << (unsigned int)content; - } - for (ModInfo::EContent content : rContent) { - rValue += 2 << (unsigned int)content; - } - - lt = lValue < rValue; + lt = leftMod->getContents() < rightMod->getContents(); } break; case ModList::COL_NAME: { int comp = QString::compare(leftMod->name(), rightMod->name(), Qt::CaseInsensitive); @@ -449,7 +434,7 @@ bool ModListSortProxy::categoryMatchesMod( bool ModListSortProxy::contentMatchesMod(ModInfo::Ptr info, bool enabled, int content) const { - return info->hasContent(static_cast(content)); + return info->hasContent(content); } bool ModListSortProxy::filterMatchesMod(ModInfo::Ptr info, bool enabled) const -- cgit v1.3.1 From 9c3ddb53c9042ead731fcbfcf9daf9fec60dbbf7 Mon Sep 17 00:00:00 2001 From: Mikaël Capelle Date: Wed, 27 May 2020 21:29:17 +0200 Subject: Fix sorting for the Content column. --- src/modlistsortproxy.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'src/modlistsortproxy.cpp') diff --git a/src/modlistsortproxy.cpp b/src/modlistsortproxy.cpp index 99dba913..87db4fed 100644 --- a/src/modlistsortproxy.cpp +++ b/src/modlistsortproxy.cpp @@ -177,7 +177,15 @@ bool ModListSortProxy::lessThan(const QModelIndex &left, } } break; case ModList::COL_CONTENT: { - lt = leftMod->getContents() < rightMod->getContents(); + unsigned int lValue = 0; + unsigned int rValue = 0; + for (int content : leftMod->getContents()) { + lValue += 2U << static_cast(content); + } + for (int content : rightMod->getContents()) { + rValue += 2U << static_cast(content); + } + lt = lValue < rValue; } break; case ModList::COL_NAME: { int comp = QString::compare(leftMod->name(), rightMod->name(), Qt::CaseInsensitive); -- cgit v1.3.1 From 4791569790e9695512248a9acdfbcd1c96f13967 Mon Sep 17 00:00:00 2001 From: Mikaël Capelle Date: Wed, 27 May 2020 22:46:03 +0200 Subject: Ignore filter-only content when sorting. --- src/modlistsortproxy.cpp | 23 ++++++++++++++++------- src/modlistsortproxy.h | 5 ++++- 2 files changed, 20 insertions(+), 8 deletions(-) (limited to 'src/modlistsortproxy.cpp') diff --git a/src/modlistsortproxy.cpp b/src/modlistsortproxy.cpp index 87db4fed..321722f5 100644 --- a/src/modlistsortproxy.cpp +++ b/src/modlistsortproxy.cpp @@ -22,6 +22,8 @@ along with Mod Organizer. If not, see . #include "profile.h" #include "messagedialog.h" #include "qtgroupingproxy.h" +#include "organizercore.h" + #include #include #include @@ -33,8 +35,9 @@ along with Mod Organizer. If not, see . using namespace MOBase; -ModListSortProxy::ModListSortProxy(Profile* profile, QObject *parent) - : QSortFilterProxyModel(parent) +ModListSortProxy::ModListSortProxy(Profile* profile, OrganizerCore * organizer) + : QSortFilterProxyModel(organizer) + , m_Organizer(organizer) , m_Profile(profile) , m_FilterActive(false) , m_FilterMode(FilterAnd) @@ -177,13 +180,19 @@ bool ModListSortProxy::lessThan(const QModelIndex &left, } } break; case ModList::COL_CONTENT: { + auto& lContents = leftMod->getContents(); + auto& rContents = rightMod->getContents(); unsigned int lValue = 0; unsigned int rValue = 0; - for (int content : leftMod->getContents()) { - lValue += 2U << static_cast(content); - } - for (int content : rightMod->getContents()) { - rValue += 2U << static_cast(content); + for (auto& content : m_Organizer->modDataContents()) { + if (!content.isOnlyForFilter()) { + if (std::find(std::begin(lContents), std::end(lContents), content.id()) != std::end(lContents)) { + lValue += 2U << static_cast(content.id()); + } + if (std::find(std::begin(rContents), std::end(rContents), content.id()) != std::end(rContents)) { + rValue += 2U << static_cast(content.id()); + } + } } lt = lValue < rValue; } break; diff --git a/src/modlistsortproxy.h b/src/modlistsortproxy.h index 3a29b7f7..bf5c077a 100644 --- a/src/modlistsortproxy.h +++ b/src/modlistsortproxy.h @@ -25,6 +25,7 @@ along with Mod Organizer. If not, see . #include "modlist.h" class Profile; +class OrganizerCore; class ModListSortProxy : public QSortFilterProxyModel { @@ -72,7 +73,7 @@ public: public: - explicit ModListSortProxy(Profile *profile, QObject *parent = 0); + explicit ModListSortProxy(Profile *profile, OrganizerCore * organizer); void setProfile(Profile *profile); @@ -154,6 +155,8 @@ private slots: void postDataChanged(); private: + OrganizerCore* m_Organizer; + Profile* m_Profile; std::vector m_Criteria; QString m_Filter; -- cgit v1.3.1 From d2b7a1a321d5cf496860f717eccdfb9487621169 Mon Sep 17 00:00:00 2001 From: Mikaël Capelle Date: Thu, 28 May 2020 19:48:21 +0200 Subject: Expose ModDataContentHolder from OrganizerCore instead of vector of Content. --- src/filterlist.cpp | 4 +- src/mainwindow.cpp | 5 +-- src/modlist.cpp | 38 ++++++----------- src/modlistsortproxy.cpp | 16 +++---- src/organizercore.cpp | 4 +- src/organizercore.h | 108 ++++++++++++++++++++++++++++++++++++++++++++++- 6 files changed, 132 insertions(+), 43 deletions(-) (limited to 'src/modlistsortproxy.cpp') diff --git a/src/filterlist.cpp b/src/filterlist.cpp index 142751f0..2b72c152 100644 --- a/src/filterlist.cpp +++ b/src/filterlist.cpp @@ -234,11 +234,11 @@ QTreeWidgetItem* FilterList::addCriteriaItem( void FilterList::addContentCriteria() { - for (auto &content: m_Organizer->modDataContents()) { + m_Organizer->modDataContents().forEachContent([this](auto const& content) { addCriteriaItem( nullptr, QString("<%1>").arg(tr("Contains %1").arg(content.name())), content.id(), ModListSortProxy::TypeContent); - } + }, true); } void FilterList::addCategoryCriteria(QTreeWidgetItem *root, const std::set &categoriesUsed, int targetID) diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index a720b621..35e31e61 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -5950,9 +5950,8 @@ void MainWindow::onFiltersCriteria(const std::vector const auto& c = criteria[0]; if (c.type == ModListSortProxy::TypeContent) { - auto& contents = m_OrganizerCore.modDataContents(); - auto it = std::find_if(std::begin(contents), std::end(contents), [&c](auto const& content) { return content.id() == c.id; }); - label = it != std::end(contents) ? it->name() : QString(); + const auto *content = m_OrganizerCore.modDataContents().findById(c.id); + label = content ? content->name() : QString(); } else { label = m_CategoryFactory.getCategoryNameByID(c.id); } diff --git a/src/modlist.cpp b/src/modlist.cpp index 614588db..06e5e9bf 100644 --- a/src/modlist.cpp +++ b/src/modlist.cpp @@ -181,29 +181,21 @@ QString ModList::getConflictFlagText(ModInfo::EConflictFlag flag, ModInfo::Ptr m QVariantList ModList::contentsToIcons(const std::set &contents) const { QVariantList result; - for (auto &content: m_Organizer->modDataContents()) { - if (!content.isOnlyForFilter()) { - if (contents.find(content.id()) != contents.end()) { - result.append(content.icon()); - } - else { - result.append(QString()); - } - } - } + m_Organizer->modDataContents().forEachContentInOrOut( + contents, + [&result](auto const& content) { result.append(content.icon()); }, + [&result](auto const&) { result.append(QString()); }); return result; } QString ModList::contentsToToolTip(const std::set &contents) const { QString result(""); - for (auto& content : m_Organizer->modDataContents()) { - if (!content.isOnlyForFilter() && contents.find(content.id()) != contents.end()) { - result.append(QString("" - "") - .arg(content.icon()).arg(content.name())); - } - } + m_Organizer->modDataContents().forEachContentIn(contents, [&result](auto const& content) { + result.append(QString("" + "") + .arg(content.icon()).arg(content.name())); + }); result.append("
%2
%2
"); return result; } @@ -1320,16 +1312,14 @@ QString ModList::getColumnToolTip(int column) const case COL_FLAGS: return tr("Emblems to highlight things that might require attention."); case COL_CONTENT: { auto& contents = m_Organizer->modDataContents(); - if (contents.empty()) { + if (m_Organizer->modDataContents().empty()) { return QString(); } QString result = tr("Depicts the content of the mod:") + "
" + ""; - for (auto& content : contents) { - if (!content.isOnlyForFilter()) { - result += QString("") - .arg(content.icon()).arg(content.name()); - } - } + m_Organizer->modDataContents().forEachContent([&result](auto const& content) { + result += QString("") + .arg(content.icon()).arg(content.name()); + }); return result + "
%2
%2
"; }; case COL_INSTALLTIME: return tr("Time this mod was installed"); diff --git a/src/modlistsortproxy.cpp b/src/modlistsortproxy.cpp index 321722f5..b56dff78 100644 --- a/src/modlistsortproxy.cpp +++ b/src/modlistsortproxy.cpp @@ -184,16 +184,12 @@ bool ModListSortProxy::lessThan(const QModelIndex &left, auto& rContents = rightMod->getContents(); unsigned int lValue = 0; unsigned int rValue = 0; - for (auto& content : m_Organizer->modDataContents()) { - if (!content.isOnlyForFilter()) { - if (std::find(std::begin(lContents), std::end(lContents), content.id()) != std::end(lContents)) { - lValue += 2U << static_cast(content.id()); - } - if (std::find(std::begin(rContents), std::end(rContents), content.id()) != std::end(rContents)) { - rValue += 2U << static_cast(content.id()); - } - } - } + m_Organizer->modDataContents().forEachContentIn(lContents, [&lValue](auto const& content) { + lValue += 2U << static_cast(content.id()); + }); + m_Organizer->modDataContents().forEachContentIn(rContents, [&rValue](auto const& content) { + rValue += 2U << static_cast(content.id()); + }); lt = lValue < rValue; } break; case ModList::COL_NAME: { diff --git a/src/organizercore.cpp b/src/organizercore.cpp index 45fe5220..14f85ac0 100644 --- a/src/organizercore.cpp +++ b/src/organizercore.cpp @@ -138,10 +138,10 @@ OrganizerCore::OrganizerCore(Settings &settings) connect(this, &OrganizerCore::managedGameChanged, [this](IPluginGame const* gamePlugin) { ModDataContent* contentFeature = gamePlugin->feature(); if (contentFeature) { - m_Contents = contentFeature->getAllContents(); + m_Contents = ModDataContentHolder(contentFeature->getAllContents()); } else { - m_Contents = {}; + m_Contents = ModDataContentHolder(); } }); diff --git a/src/organizercore.h b/src/organizercore.h index af741964..c08a1495 100644 --- a/src/organizercore.h +++ b/src/organizercore.h @@ -83,6 +83,110 @@ private: typedef boost::signals2::signal SignalModInstalled; public: + + /** + * Small holder for the game content returned by the ModDataContent feature (the + * list of all possible contents, not the per-mod content). + */ + struct ModDataContentHolder { + + using Content = ModDataContent::Content; + + /** + * @return true if the hold list of contents is empty, false otherwise. + */ + bool empty() const { return m_Contents.empty(); } + + /** + * @param id ID of the content to retrieve. + * + * @return the content with the given ID, or a null pointer if it is not found. + */ + const Content* findById(int id) const { + auto it = std::find_if(std::begin(m_Contents), std::end(m_Contents), [&id](auto const& content) { return content.id() == id; }); + return it == std::end(m_Contents) ? nullptr : &(*it); + } + + /** + * Apply the given function to each content whose ID is in the given set. + * + * @param ids The set of content IDs. + * @param fn The function to apply. + * @param includeFilter true to also apply the function to filter-only contents, false otherwise. + */ + template + void forEachContentIn(std::set const& ids, Fn const& fn, bool includeFilter = false) const { + for (const auto& content : m_Contents) { + if ((includeFilter || !content.isOnlyForFilter()) + && ids.find(content.id()) != ids.end()) { + fn(content); + } + } + } + + /** + * Apply fnIn to each content whose ID is in the given set, and fnOut to each content not in the + * given set, excluding filter-only content (from both cases) unless includeFilter is true.. + * + * @param ids The set of content IDs. + * @param fnIn Function to apply to content whose IDs are in ids. + * @param fnOut Function to apply to content whose IDs are not in ids. + * @param includeFilter true to also apply the function to filter-only contents, false otherwise. + */ + template + void forEachContentInOrOut(std::set const& ids, FnIn const& fnIn, FnOut const& fnOut, bool includeFilter = false) const { + for (const auto& content : m_Contents) { + if ((includeFilter || !content.isOnlyForFilter())) { + if (ids.find(content.id()) != ids.end()) { + fnIn(content); + } + else { + fnOut(content); + } + } + } + } + + /** + * Apply the given function to each content. + * + * @param fn The function to apply. + * @param includeFilter true to also apply the function to filter-only contents, false otherwise. + */ + template + void forEachContent(Fn const& fn, bool includeFilter = false) const { + for (const auto& content : m_Contents) { + if (includeFilter || !content.isOnlyForFilter()) { + fn(content); + } + } + } + + + ModDataContentHolder& operator=(ModDataContentHolder const&) = delete; + ModDataContentHolder& operator=(ModDataContentHolder&&) = default; + + private: + + std::vector m_Contents; + + /** + * @brief Construct a ModDataContentHolder without any contents (e.g., if the feature is + * missing). + */ + ModDataContentHolder() { } + + /** + * @brief Construct a ModDataContentHold holding the given list of contents. + */ + ModDataContentHolder(std::vector contents) : + m_Contents(std::move(contents)) { } + + friend class OrganizerCore; + }; + +public: + static bool isNxmLink(const QString &link) { return link.startsWith("nxm://", Qt::CaseInsensitive); } OrganizerCore(Settings &settings); @@ -127,7 +231,7 @@ public: * @return the list of contents for the currently managed game, or an empty vector * if the game plugin does not implement the ModDataContent feature. */ - const std::vector& modDataContents() const { return m_Contents; } + const ModDataContentHolder& modDataContents() const { return m_Contents; } bool isArchivesInit() const { return m_ArchivesInit; } @@ -312,7 +416,7 @@ private: PluginContainer *m_PluginContainer; QString m_GameName; MOBase::IPluginGame *m_GamePlugin; - std::vector m_Contents; + ModDataContentHolder m_Contents; Profile *m_CurrentProfile; -- cgit v1.3.1 From 7f42698f4c733269a1b2b74d993186b362a9208a Mon Sep 17 00:00:00 2001 From: Mikaël Capelle Date: Thu, 28 May 2020 19:50:39 +0200 Subject: Change auto& to const auto&. --- src/modlistsortproxy.cpp | 4 ++-- src/organizercore.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'src/modlistsortproxy.cpp') diff --git a/src/modlistsortproxy.cpp b/src/modlistsortproxy.cpp index b56dff78..ab6dd852 100644 --- a/src/modlistsortproxy.cpp +++ b/src/modlistsortproxy.cpp @@ -180,8 +180,8 @@ bool ModListSortProxy::lessThan(const QModelIndex &left, } } break; case ModList::COL_CONTENT: { - auto& lContents = leftMod->getContents(); - auto& rContents = rightMod->getContents(); + const auto& lContents = leftMod->getContents(); + const auto& rContents = rightMod->getContents(); unsigned int lValue = 0; unsigned int rValue = 0; m_Organizer->modDataContents().forEachContentIn(lContents, [&lValue](auto const& content) { diff --git a/src/organizercore.h b/src/organizercore.h index c08a1495..00765694 100644 --- a/src/organizercore.h +++ b/src/organizercore.h @@ -125,8 +125,8 @@ public: } /** - * Apply fnIn to each content whose ID is in the given set, and fnOut to each content not in the - * given set, excluding filter-only content (from both cases) unless includeFilter is true.. + * @brief Apply fnIn to each content whose ID is in the given set, and fnOut to each content not in the + * given set, excluding filter-only content (from both cases) unless includeFilter is true. * * @param ids The set of content IDs. * @param fnIn Function to apply to content whose IDs are in ids. -- cgit v1.3.1