summaryrefslogtreecommitdiff
path: root/src/modlistsortproxy.cpp
diff options
context:
space:
mode:
authorisanae <14251494+isanae@users.noreply.github.com>2019-12-02 10:43:52 -0500
committerGitHub <noreply@github.com>2019-12-02 10:43:52 -0500
commiteabca00c35d7af3b6822bb7857ef1e073807ca0a (patch)
treea2a48759382677373bb1d23c5473e85c6ec0dd0e /src/modlistsortproxy.cpp
parentfb3c15094fded829b120274189b0b331a68b2afa (diff)
parent3c25117fe163f7fab7afa22ba171ea2d41112f23 (diff)
Merge pull request #913 from isanae/negative-filters
Negative filters
Diffstat (limited to 'src/modlistsortproxy.cpp')
-rw-r--r--src/modlistsortproxy.cpp311
1 files changed, 190 insertions, 121 deletions
diff --git a/src/modlistsortproxy.cpp b/src/modlistsortproxy.cpp
index a9ff6463..7ac98f66 100644
--- a/src/modlistsortproxy.cpp
+++ b/src/modlistsortproxy.cpp
@@ -36,10 +36,9 @@ using namespace MOBase;
ModListSortProxy::ModListSortProxy(Profile* profile, QObject *parent)
: QSortFilterProxyModel(parent)
, m_Profile(profile)
- , m_CategoryFilter()
- , m_CurrentFilter()
, m_FilterActive(false)
- , m_FilterMode(FILTER_AND)
+ , m_FilterMode(FilterAnd)
+ , m_FilterSeparators(SeparatorFilter)
{
setDynamicSortFilter(true); // this seems to work without dynamicsortfilter
// but I don't know why. This should be necessary
@@ -52,26 +51,20 @@ void ModListSortProxy::setProfile(Profile *profile)
void ModListSortProxy::updateFilterActive()
{
- m_FilterActive = ((m_CategoryFilter.size() > 0)
- || (m_ContentFilter.size() > 0)
- || !m_CurrentFilter.isEmpty());
+ m_FilterActive = (!m_Criteria.empty() || !m_Filter.isEmpty());
emit filterActive(m_FilterActive);
}
-void ModListSortProxy::setCategoryFilter(const std::vector<int> &categories)
+void ModListSortProxy::setCriteria(const std::vector<Criteria>& criteria)
{
- //avoid refreshing the filter unless we are checking all mods for update.
- if (categories != m_CategoryFilter || (!categories.empty() && categories.at(0) == CategoryFactory::CATEGORY_SPECIAL_UPDATEAVAILABLE)) {
- m_CategoryFilter = categories;
- updateFilterActive();
- invalidate();
- }
-}
+ // avoid refreshing the filter unless we are checking all mods for update.
+ const bool changed = (criteria != m_Criteria);
+ const bool isForUpdates = (
+ !criteria.empty() &&
+ criteria[0].id == CategoryFactory::UpdateAvailable);
-void ModListSortProxy::setContentFilter(const std::vector<int> &content)
-{
- if (content != m_ContentFilter) {
- m_ContentFilter = content;
+ if (changed || isForUpdates) {
+ m_Criteria = criteria;
updateFilterActive();
invalidate();
}
@@ -248,12 +241,10 @@ bool ModListSortProxy::lessThan(const QModelIndex &left,
return lt;
}
-void ModListSortProxy::updateFilter(const QString &filter)
+void ModListSortProxy::updateFilter(const QString& filter)
{
- m_CurrentFilter = filter;
+ m_Filter = filter;
updateFilterActive();
- // using invalidateFilter here should be enough but that crashes the application? WTF?
- // invalidateFilter();
invalidate();
}
@@ -278,117 +269,192 @@ bool ModListSortProxy::hasConflictFlag(const std::vector<ModInfo::EFlag> &flags)
bool ModListSortProxy::filterMatchesModAnd(ModInfo::Ptr info, bool enabled) const
{
- for (auto iter = m_CategoryFilter.begin(); iter != m_CategoryFilter.end(); ++iter) {
- switch (*iter) {
- case CategoryFactory::CATEGORY_SPECIAL_CHECKED: {
- if (!enabled && !info->alwaysEnabled() && !info->hasFlag(ModInfo::FLAG_SEPARATOR)) return false;
- } break;
- case CategoryFactory::CATEGORY_SPECIAL_UNCHECKED: {
- if (enabled || info->alwaysEnabled()) return false;
- } break;
- case CategoryFactory::CATEGORY_SPECIAL_UPDATEAVAILABLE: {
- if (!info->updateAvailable() && !info->downgradeAvailable()) return false;
- } break;
- case CategoryFactory::CATEGORY_SPECIAL_NOCATEGORY: {
- if (info->getCategories().size() > 0) return false;
- } break;
- case CategoryFactory::CATEGORY_SPECIAL_CONFLICT: {
- if (!hasConflictFlag(info->getFlags())) return false;
- } break;
- case CategoryFactory::CATEGORY_SPECIAL_NOTENDORSED: {
- ModInfo::EEndorsedState state = info->endorsedState();
- if (state != ModInfo::ENDORSED_FALSE) return false;
- } break;
- case CategoryFactory::CATEGORY_SPECIAL_BACKUP: {
- if (!info->hasFlag(ModInfo::FLAG_BACKUP)) return false;
- } break;
- case CategoryFactory::CATEGORY_SPECIAL_MANAGED: {
- if (info->hasFlag(ModInfo::FLAG_FOREIGN)) return false;
- } break;
- case CategoryFactory::CATEGORY_SPECIAL_UNMANAGED: {
- if (!info->hasFlag(ModInfo::FLAG_FOREIGN)) return false;
- } break;
- case CategoryFactory::CATEGORY_SPECIAL_NOGAMEDATA: {
- if (!info->hasFlag(ModInfo::FLAG_INVALID)) return false;
- } break;
- case CategoryFactory::CATEGORY_SPECIAL_NONEXUSID: {
- if (!(info->getNexusID() == -1 && !info->hasFlag(ModInfo::FLAG_FOREIGN) &&
- !info->hasFlag(ModInfo::FLAG_BACKUP) &&
- !info->hasFlag(ModInfo::FLAG_SEPARATOR) &&
- !info->hasFlag(ModInfo::FLAG_OVERWRITE))) return false;
- } break;
- default: {
- if (!info->categorySet(*iter)) return false;
- } break;
+ for (auto&& c : m_Criteria) {
+ if (!criteriaMatchMod(info, enabled, c)) {
+ return false;
}
}
- foreach (int content, m_ContentFilter) {
- if (!info->hasContent(static_cast<ModInfo::EContent>(content))) return false;
+ return true;
+}
+
+bool ModListSortProxy::filterMatchesModOr(ModInfo::Ptr info, bool enabled) const
+{
+ for (auto&& c : m_Criteria) {
+ if (criteriaMatchMod(info, enabled, c)) {
+ return true;
+ }
+ }
+
+ if (!m_Criteria.empty()) {
+ // nothing matched
+ return false;
}
return true;
}
-bool ModListSortProxy::filterMatchesModOr(ModInfo::Ptr info, bool enabled) const
+bool ModListSortProxy::optionsMatchMod(ModInfo::Ptr info, bool) const
+{
+
+ return true;
+}
+
+bool ModListSortProxy::criteriaMatchMod(
+ ModInfo::Ptr info, bool enabled, const Criteria& c) const
{
- for (auto iter = m_CategoryFilter.begin(); iter != m_CategoryFilter.end(); ++iter) {
- switch (*iter) {
- case CategoryFactory::CATEGORY_SPECIAL_CHECKED: {
- if (enabled || info->alwaysEnabled()) return true;
- } break;
- case CategoryFactory::CATEGORY_SPECIAL_UNCHECKED: {
- if (!enabled && !info->alwaysEnabled()) return true;
- } break;
- case CategoryFactory::CATEGORY_SPECIAL_UPDATEAVAILABLE: {
- if (info->updateAvailable() || info->downgradeAvailable()) return true;
- } break;
- case CategoryFactory::CATEGORY_SPECIAL_NOCATEGORY: {
- if (info->getCategories().size() == 0) return true;
- } break;
- case CategoryFactory::CATEGORY_SPECIAL_CONFLICT: {
- if (hasConflictFlag(info->getFlags())) return true;
- } break;
- case CategoryFactory::CATEGORY_SPECIAL_NOTENDORSED: {
- ModInfo::EEndorsedState state = info->endorsedState();
- if ((state == ModInfo::ENDORSED_FALSE) || (state == ModInfo::ENDORSED_NEVER)) return true;
- } break;
- case CategoryFactory::CATEGORY_SPECIAL_BACKUP: {
- if (info->hasFlag(ModInfo::FLAG_BACKUP)) return true;
- } break;
- case CategoryFactory::CATEGORY_SPECIAL_MANAGED: {
- if (!info->hasFlag(ModInfo::FLAG_FOREIGN)) return true;
- } break;
- case CategoryFactory::CATEGORY_SPECIAL_UNMANAGED: {
- if (info->hasFlag(ModInfo::FLAG_FOREIGN)) return true;
- } break;
- case CategoryFactory::CATEGORY_SPECIAL_NOGAMEDATA: {
- if (info->hasFlag(ModInfo::FLAG_INVALID)) return true;
- } break;
- case CategoryFactory::CATEGORY_SPECIAL_NONEXUSID: {
- if ((info->getNexusID() == -1 && !info->hasFlag(ModInfo::FLAG_FOREIGN) &&
- !info->hasFlag(ModInfo::FLAG_BACKUP) &&
- !info->hasFlag(ModInfo::FLAG_SEPARATOR) &&
- !info->hasFlag(ModInfo::FLAG_OVERWRITE))) return true;
- } break;
- default: {
- if (info->categorySet(*iter)) return true;
- } break;
+ bool b = false;
+
+ switch (c.type)
+ {
+ case TypeSpecial: // fall-through
+ case TypeCategory:
+ {
+ b = categoryMatchesMod(info, enabled, c.id);
+ break;
+ }
+
+ case TypeContent:
+ {
+ b = contentMatchesMod(info, enabled, c.id);
+ break;
+ }
+
+ default:
+ {
+ log::error("bad criteria type {}", c.type);
+ break;
}
}
- foreach (int content, m_ContentFilter) {
- if (info->hasContent(static_cast<ModInfo::EContent>(content))) return true;
+ if (c.inverse) {
+ b = !b;
}
- return false;
+ return b;
+}
+
+bool ModListSortProxy::categoryMatchesMod(
+ ModInfo::Ptr info, bool enabled, int category) const
+{
+ bool b = false;
+
+ switch (category)
+ {
+ case CategoryFactory::Checked:
+ {
+ b = (enabled || info->alwaysEnabled());
+ break;
+ }
+
+ case CategoryFactory::UpdateAvailable:
+ {
+ b = (info->updateAvailable() || info->downgradeAvailable());
+ break;
+ }
+
+ case CategoryFactory::HasCategory:
+ {
+ b = !info->getCategories().empty();
+ break;
+ }
+
+ case CategoryFactory::Conflict:
+ {
+ b = (hasConflictFlag(info->getFlags()));
+ break;
+ }
+
+ case CategoryFactory::Endorsed:
+ {
+ b = (info->endorsedState() == ModInfo::ENDORSED_TRUE);
+ break;
+ }
+
+ case CategoryFactory::Backup:
+ {
+ b = (info->hasFlag(ModInfo::FLAG_BACKUP));
+ break;
+ }
+
+ case CategoryFactory::Managed:
+ {
+ b = (!info->hasFlag(ModInfo::FLAG_FOREIGN));
+ break;
+ }
+
+ case CategoryFactory::HasGameData:
+ {
+ b = !info->hasFlag(ModInfo::FLAG_INVALID);
+ break;
+ }
+
+ case CategoryFactory::HasNexusID:
+ {
+ // never show these
+ if (
+ info->hasFlag(ModInfo::FLAG_FOREIGN) ||
+ info->hasFlag(ModInfo::FLAG_BACKUP) ||
+ info->hasFlag(ModInfo::FLAG_OVERWRITE))
+ {
+ return false;
+ }
+
+ b = (info->getNexusID() > 0);
+ break;
+ }
+
+ default:
+ {
+ b = (info->categorySet(category));
+ break;
+ }
+ }
+
+ return b;
+}
+
+bool ModListSortProxy::contentMatchesMod(ModInfo::Ptr info, bool enabled, int content) const
+{
+ return info->hasContent(static_cast<ModInfo::EContent>(content));
}
bool ModListSortProxy::filterMatchesMod(ModInfo::Ptr info, bool enabled) const
{
- if (!m_CurrentFilter.isEmpty()) {
+ // don't check if there are no filters selected
+ if (!m_FilterActive) {
+ return true;
+ }
+
+
+ // special case for separators
+ if (info->hasFlag(ModInfo::FLAG_SEPARATOR)) {
+ switch (m_FilterSeparators)
+ {
+ case SeparatorFilter:
+ {
+ // filter normally
+ break;
+ }
+
+ case SeparatorShow:
+ {
+ // force visible
+ return true;
+ }
+
+ case SeparatorHide:
+ {
+ // force hide
+ return false;
+ }
+ }
+ }
+
+
+ if (!m_Filter.isEmpty()) {
bool display = false;
- QString filterCopy = QString(m_CurrentFilter);
+ QString filterCopy = QString(m_Filter);
filterCopy.replace("||", ";").replace("OR", ";").replace("|", ";");
QStringList ORList = filterCopy.split(";", QString::SkipEmptyParts);
@@ -466,7 +532,8 @@ bool ModListSortProxy::filterMatchesMod(ModInfo::Ptr info, bool enabled) const
}
}//if (!m_CurrentFilter.isEmpty())
- if (m_FilterMode == FILTER_AND) {
+
+ if (m_FilterMode == FilterAnd) {
return filterMatchesModAnd(info, enabled);
}
else {
@@ -479,10 +546,12 @@ void ModListSortProxy::setColumnVisible(int column, bool visible)
m_EnabledColumns[column] = visible;
}
-void ModListSortProxy::setFilterMode(ModListSortProxy::FilterMode mode)
+void ModListSortProxy::setOptions(
+ ModListSortProxy::FilterMode mode, SeparatorsMode separators)
{
- if (m_FilterMode != mode) {
+ if (m_FilterMode != mode || separators != m_FilterSeparators) {
m_FilterMode = mode;
+ m_FilterSeparators = separators;
this->invalidate();
}
}
@@ -559,8 +628,8 @@ void ModListSortProxy::aboutToChangeData()
// (at least with some Qt versions)
// this may be related to the fact that the item being edited may disappear from the view as a
// result of the edit
- m_PreChangeFilters = categoryFilter();
- setCategoryFilter(std::vector<int>());
+ m_PreChangeCriteria = m_Criteria;
+ setCriteria({});
}
void ModListSortProxy::postDataChanged()
@@ -569,8 +638,8 @@ void ModListSortProxy::postDataChanged()
// or at least the view continues to think it's being edited. As a result no new editor can be
// opened
QTimer::singleShot(10, [this] () {
- setCategoryFilter(m_PreChangeFilters);
- m_PreChangeFilters.clear();
+ setCriteria(m_PreChangeCriteria);
+ m_PreChangeCriteria.clear();
});
}