From e99dfe153c62f914ada0605430305fca81a332a9 Mon Sep 17 00:00:00 2001 From: isanae <14251494+isanae@users.noreply.github.com> Date: Sat, 30 Nov 2019 01:53:09 -0500 Subject: renamed filters to criteria merged categories and content, they can be distinguished using the type added a not flag for criteria, not used yet --- src/filterlist.cpp | 116 +++++++++++++++++++++++++-------------------- src/filterlist.h | 14 +++--- src/mainwindow.cpp | 50 +++++++++----------- src/mainwindow.h | 4 +- src/mainwindow.ui | 38 +++++++-------- src/modlistsortproxy.cpp | 120 +++++++++++++++++------------------------------ src/modlistsortproxy.h | 42 +++++++++++------ 7 files changed, 182 insertions(+), 202 deletions(-) (limited to 'src') diff --git a/src/filterlist.cpp b/src/filterlist.cpp index 5562736d..9e5437b3 100644 --- a/src/filterlist.cpp +++ b/src/filterlist.cpp @@ -6,6 +6,9 @@ using namespace MOBase; +const int CategoryIDRole = Qt::UserRole; +const int CategoryTypeRole = Qt::UserRole + 1; + FilterList::FilterList(Ui::MainWindow* ui, CategoryFactory& factory) : ui(ui), m_factory(factory) { @@ -29,61 +32,76 @@ FilterList::FilterList(Ui::MainWindow* ui, CategoryFactory& factory) ui->filtersOr, &QCheckBox::toggled, [&]{ onCriteriaChanged(); }); - connect( - ui->filtersNot, &QCheckBox::toggled, - [&]{ onCriteriaChanged(); }); - connect( ui->filtersSeparators, &QCheckBox::toggled, [&]{ onCriteriaChanged(); }); + + ui->filters->header()->setSectionResizeMode(0, QHeaderView::Stretch); + ui->filters->header()->resizeSection(1, 50); } -QTreeWidgetItem* FilterList::addFilterItem( +QTreeWidgetItem* FilterList::addCriteriaItem( QTreeWidgetItem *root, const QString &name, int categoryID, - ModListSortProxy::FilterType type) + ModListSortProxy::CriteriaType type) { QTreeWidgetItem *item = new QTreeWidgetItem(QStringList(name)); + item->setData(0, Qt::ToolTipRole, name); - item->setData(0, Qt::UserRole, categoryID); - item->setData(0, Qt::UserRole + 1, type); + item->setData(0, CategoryIDRole, categoryID); + item->setData(0, CategoryTypeRole, type); + if (root != nullptr) { root->addChild(item); } else { ui->filters->addTopLevelItem(item); } + + auto* w = new QWidget; + w->setStyleSheet("background-color: rgba(0,0,0,0)"); + + auto* ly = new QVBoxLayout(w); + ly->setAlignment(Qt::AlignCenter); + ly->setContentsMargins(0, 0, 0, 0); + + auto* cb = new QCheckBox; + connect(cb, &QCheckBox::toggled, [&]{ onSelection(); }); + ly->addWidget(cb); + + ui->filters->setItemWidget(item, 1, w); + return item; } -void FilterList::addContentFilters() +void FilterList::addContentCriteria() { for (unsigned i = 0; i < ModInfo::NUM_CONTENT_TYPES; ++i) { - addFilterItem( + addCriteriaItem( nullptr, tr("").arg(ModInfo::getContentTypeName(i)), i, ModListSortProxy::TYPE_CONTENT); } } -void FilterList::addCategoryFilters(QTreeWidgetItem *root, const std::set &categoriesUsed, int targetID) +void FilterList::addCategoryCriteria(QTreeWidgetItem *root, const std::set &categoriesUsed, int targetID) { - for (unsigned int i = 1; - i < static_cast(m_factory.numCategories()); ++i) { - if ((m_factory.getParentID(i) == targetID)) { + const auto count = static_cast(m_factory.numCategories()); + for (unsigned int i = 1; i < count; ++i) { + if (m_factory.getParentID(i) == targetID) { int categoryID = m_factory.getCategoryID(i); if (categoriesUsed.find(categoryID) != categoriesUsed.end()) { QTreeWidgetItem *item = - addFilterItem(root, m_factory.getCategoryName(i), + addCriteriaItem(root, m_factory.getCategoryName(i), categoryID, ModListSortProxy::TYPE_CATEGORY); if (m_factory.hasChildren(i)) { - addCategoryFilters(item, categoriesUsed, categoryID); + addCategoryCriteria(item, categoriesUsed, categoryID); } } } } } -void FilterList::addSpecialFilterItem(int type) +void FilterList::addSpecialCriteria(int type) { - addFilterItem( + addCriteriaItem( nullptr, m_factory.getSpecialCategoryName(type), type, ModListSortProxy::TYPE_SPECIAL); } @@ -98,19 +116,19 @@ void FilterList::refresh() ui->filters->clear(); using F = CategoryFactory; - addSpecialFilterItem(F::CATEGORY_SPECIAL_CHECKED); - addSpecialFilterItem(F::CATEGORY_SPECIAL_UNCHECKED); - addSpecialFilterItem(F::CATEGORY_SPECIAL_UPDATEAVAILABLE); - addSpecialFilterItem(F::CATEGORY_SPECIAL_BACKUP); - addSpecialFilterItem(F::CATEGORY_SPECIAL_MANAGED); - addSpecialFilterItem(F::CATEGORY_SPECIAL_UNMANAGED); - addSpecialFilterItem(F::CATEGORY_SPECIAL_NOCATEGORY); - addSpecialFilterItem(F::CATEGORY_SPECIAL_CONFLICT); - addSpecialFilterItem(F::CATEGORY_SPECIAL_NOTENDORSED); - addSpecialFilterItem(F::CATEGORY_SPECIAL_NONEXUSID); - addSpecialFilterItem(F::CATEGORY_SPECIAL_NOGAMEDATA); - - addContentFilters(); + addSpecialCriteria(F::CATEGORY_SPECIAL_CHECKED); + addSpecialCriteria(F::CATEGORY_SPECIAL_UNCHECKED); + addSpecialCriteria(F::CATEGORY_SPECIAL_UPDATEAVAILABLE); + addSpecialCriteria(F::CATEGORY_SPECIAL_BACKUP); + addSpecialCriteria(F::CATEGORY_SPECIAL_MANAGED); + addSpecialCriteria(F::CATEGORY_SPECIAL_UNMANAGED); + addSpecialCriteria(F::CATEGORY_SPECIAL_NOCATEGORY); + addSpecialCriteria(F::CATEGORY_SPECIAL_CONFLICT); + addSpecialCriteria(F::CATEGORY_SPECIAL_NOTENDORSED); + addSpecialCriteria(F::CATEGORY_SPECIAL_NONEXUSID); + addSpecialCriteria(F::CATEGORY_SPECIAL_NOGAMEDATA); + + addContentCriteria(); std::set categoriesUsed; for (unsigned int modIdx = 0; modIdx < ModInfo::getNumMods(); ++modIdx) { @@ -130,7 +148,7 @@ void FilterList::refresh() } } - addCategoryFilters(nullptr, categoriesUsed, 0); + addCategoryCriteria(nullptr, categoriesUsed, 0); for (const QString &item : selectedItems) { QList matches = ui->filters->findItems( @@ -145,7 +163,7 @@ void FilterList::refresh() void FilterList::setSelection(std::vector categories) { for (int i = 0; i < ui->filters->topLevelItemCount(); ++i) { - if (ui->filters->topLevelItem(i)->data(0, Qt::UserRole) == CategoryFactory::CATEGORY_SPECIAL_UPDATEAVAILABLE) { + if (ui->filters->topLevelItem(i)->data(0, CategoryIDRole) == CategoryFactory::CATEGORY_SPECIAL_UPDATEAVAILABLE) { ui->filters->setCurrentItem(ui->filters->topLevelItem(i)); break; } @@ -159,27 +177,24 @@ void FilterList::clearSelection() void FilterList::onSelection() { - QModelIndexList indices = ui->filters->selectionModel()->selectedRows(); - std::vector categories; - std::vector content; + const QModelIndexList indices = ui->filters->selectionModel()->selectedRows(); + std::vector criteria; - for (const QModelIndex &index : indices) { - const int filterType = index.data(Qt::UserRole + 1).toInt(); + for (auto* item: ui->filters->selectedItems()) { + const auto type = static_cast( + item->data(0, CategoryTypeRole).toInt()); - if ((filterType == ModListSortProxy::TYPE_CATEGORY) || (filterType == ModListSortProxy::TYPE_SPECIAL)) { - const int categoryId = index.data(Qt::UserRole).toInt(); - if (categoryId != CategoryFactory::CATEGORY_NONE) { - categories.push_back(categoryId); - } - } else if (filterType == ModListSortProxy::TYPE_CONTENT) { - const int contentId = index.data(Qt::UserRole).toInt(); - content.push_back(contentId); - } + const int id = item->data(0, CategoryIDRole).toInt(); + + auto* cb = static_cast(ui->filters->itemWidget(item, 1)); + const bool inverse = cb->isChecked(); + + criteria.push_back({type, id, inverse}); } - ui->filtersClear->setEnabled(categories.size() > 0 || content.size() >0); + ui->filtersClear->setEnabled(!criteria.empty()); - emit filtersChanged(categories, content); + emit criteriaChanged(criteria); } void FilterList::onContextMenu(const QPoint &pos) @@ -205,8 +220,7 @@ void FilterList::onCriteriaChanged() const auto mode = ui->filtersAnd->isChecked() ? ModListSortProxy::FILTER_AND : ModListSortProxy::FILTER_OR; - const bool inverse = ui->filtersNot->isChecked(); const bool separators = ui->filtersSeparators->isChecked(); - emit criteriaChanged(mode, inverse, separators); + emit optionsChanged(mode, separators); } diff --git a/src/filterlist.h b/src/filterlist.h index 85982392..418989e7 100644 --- a/src/filterlist.h +++ b/src/filterlist.h @@ -19,8 +19,8 @@ public: void refresh(); signals: - void filtersChanged(std::vector categories, std::vector content); - void criteriaChanged(ModListSortProxy::FilterMode mode, bool inverse, bool separators); + void criteriaChanged(std::vector criteria); + void optionsChanged(ModListSortProxy::FilterMode mode, bool separators); private: Ui::MainWindow* ui; @@ -32,14 +32,14 @@ private: void editCategories(); - QTreeWidgetItem* addFilterItem( + QTreeWidgetItem* addCriteriaItem( QTreeWidgetItem *root, const QString &name, int categoryID, - ModListSortProxy::FilterType type); + ModListSortProxy::CriteriaType type); - void addContentFilters(); - void addCategoryFilters( + void addContentCriteria(); + void addCategoryCriteria( QTreeWidgetItem *root, const std::set &categoriesUsed, int targetID); - void addSpecialFilterItem(int type); + void addSpecialCriteria(int type); }; diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 1319d906..03d61bc6 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -264,12 +264,12 @@ MainWindow::MainWindow(Settings &settings m_Filters.reset(new FilterList(ui, m_CategoryFactory)); connect( - m_Filters.get(), &FilterList::filtersChanged, - [&](auto&& cats, auto&& content) { onFilters(cats, content); }); + m_Filters.get(), &FilterList::criteriaChanged, + [&](auto&& v) { onFiltersCriteria(v); }); connect( - m_Filters.get(), &FilterList::criteriaChanged, - [&](auto mode, bool inv, bool sep) { onFiltersCriteria(mode, inv, sep); }); + m_Filters.get(), &FilterList::optionsChanged, + [&](auto mode, bool sep) { onFiltersOptions(mode, sep); }); ui->logList->setCore(m_OrganizerCore); @@ -4124,7 +4124,12 @@ void MainWindow::checkModsForUpdates() } if (updatesAvailable || checkingModsForUpdate) { - m_ModListSortProxy->setCategoryFilter(boost::assign::list_of(CategoryFactory::CATEGORY_SPECIAL_UPDATEAVAILABLE)); + m_ModListSortProxy->setCriteria({{ + ModListSortProxy::TYPE_SPECIAL, + CategoryFactory::CATEGORY_SPECIAL_UPDATEAVAILABLE, + false} + }); + m_Filters->setSelection({CategoryFactory::CATEGORY_SPECIAL_UPDATEAVAILABLE}); } } @@ -6111,44 +6116,31 @@ void MainWindow::refreshFilters() } } -void MainWindow::onFilters( - const std::vector& categories, const std::vector& content) +void MainWindow::onFiltersCriteria(const std::vector& criteria) { - m_ModListSortProxy->setCategoryFilter(categories); - m_ModListSortProxy->setContentFilter(content); + m_ModListSortProxy->setCriteria(criteria); QString label = "?"; - if ((categories.size() + content.size()) > 1) { - label = tr(""); - } else if (!categories.empty()) { - const int c = categories[0]; - label = m_CategoryFactory.getCategoryNameByID(c); + if (criteria.empty()) { + label = ""; + } else if (criteria.size() == 1) { + const auto& c = criteria[0]; + label = m_CategoryFactory.getCategoryNameByID(c.id); if (label.isEmpty()) { - log::error("category '{}' not found", c); - } - } else if (!content.empty()) { - const int c = content[0]; - try { - label = ModInfo::getContentTypeName(c); - } - catch(std::exception&) { - log::error("content filter '{}' not found", c); + log::error("category '{}' not found", c.id); } } else { - label = ""; + label = tr(""); } ui->currentCategoryLabel->setText(label); ui->modList->reset(); } -void MainWindow::onFiltersCriteria( - ModListSortProxy::FilterMode mode, bool inverse, bool separators) +void MainWindow::onFiltersOptions(ModListSortProxy::FilterMode mode, bool separators) { - m_ModListSortProxy->setFilterMode(mode); - m_ModListSortProxy->setFilterNot(inverse); - m_ModListSortProxy->setFilterSeparators(separators); + m_ModListSortProxy->setOptions(mode, separators); } void MainWindow::updateESPLock(bool locked) diff --git a/src/mainwindow.h b/src/mainwindow.h index 9837378b..0b559300 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -514,8 +514,8 @@ private slots: void deselectFilters(); void refreshFilters(); - void onFilters(const std::vector& categories, const std::vector& content); - void onFiltersCriteria(ModListSortProxy::FilterMode mode, bool inverse, bool separators); + void onFiltersCriteria(const std::vector& filters); + void onFiltersOptions(ModListSortProxy::FilterMode mode, bool separators); void displayModInformation(const QString &modName, ModInfoTabIDs tabID); diff --git a/src/mainwindow.ui b/src/mainwindow.ui index ed35f783..7cc7dca4 100644 --- a/src/mainwindow.ui +++ b/src/mainwindow.ui @@ -85,12 +85,26 @@ true + + false + + true + + + true + + false - 1 + Category + + + + + Invert @@ -152,16 +166,6 @@ - - - - Invert each selected category - - - Not - - - @@ -351,9 +355,6 @@ p, li { white-space: pre-wrap; } Qt::CustomContextMenu - - List of available mods. - This is a list of installed mods. Use the checkboxes to activate/deactivate mods and drag & drop mods to change their "installation" orders. @@ -448,14 +449,7 @@ p, li { white-space: pre-wrap; } - - - - 8 - true - - - + diff --git a/src/modlistsortproxy.cpp b/src/modlistsortproxy.cpp index d2a5e258..646401b9 100644 --- a/src/modlistsortproxy.cpp +++ b/src/modlistsortproxy.cpp @@ -38,7 +38,6 @@ ModListSortProxy::ModListSortProxy(Profile* profile, QObject *parent) , m_Profile(profile) , m_FilterActive(false) , m_FilterMode(FILTER_AND) - , m_FilterNot(false) , m_FilterSeparators(false) { setDynamicSortFilter(true); // this seems to work without dynamicsortfilter @@ -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 &categories) +void ModListSortProxy::setCriteria(const std::vector& 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(); - } -} - -void ModListSortProxy::setContentFilter(const std::vector &content) -{ - if (content != m_ContentFilter) { - m_ContentFilter = content; + // 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::CATEGORY_SPECIAL_UPDATEAVAILABLE); + + 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(); } @@ -282,14 +273,8 @@ bool ModListSortProxy::filterMatchesModAnd(ModInfo::Ptr info, bool enabled) cons return false; } - for (auto iter = m_CategoryFilter.begin(); iter != m_CategoryFilter.end(); ++iter) { - if (!categoryMatchesMod(info, enabled, *iter)) { - return false; - } - } - - foreach (int content, m_ContentFilter) { - if (!contentMatchesMod(info, enabled, content)) { + for (auto&& c : m_Criteria) { + if (!criteriaMatchesMod(info, enabled, c)) { return false; } } @@ -303,29 +288,35 @@ bool ModListSortProxy::filterMatchesModOr(ModInfo::Ptr info, bool enabled) const return false; } - for (auto iter = m_CategoryFilter.begin(); iter != m_CategoryFilter.end(); ++iter) { - if (categoryMatchesMod(info, enabled, *iter)) { + for (auto&& c : m_Criteria) { + if (criteriaMatchesMod(info, enabled, c)) { return true; } } - if (!m_CategoryFilter.empty()) { + if (!m_Criteria.empty()) { // nothing matched return false; } - foreach (int content, m_ContentFilter) { - if (contentMatchesMod(info, enabled, content)) { - return true; - } - } + return true; +} - if (!m_ContentFilter.empty()) { - // nothing matched - return false; - } +bool ModListSortProxy::criteriaMatchesMod( + ModInfo::Ptr info, bool enabled, const Criteria& c) const +{ + switch (c.type) + { + case TYPE_SPECIAL: // fall-through + case TYPE_CATEGORY: + return categoryMatchesMod(info, enabled, c.id); - return true; + case TYPE_CONTENT: + return contentMatchesMod(info, enabled, c.id); + + default: + return false; + } } bool ModListSortProxy::categoryMatchesMod( @@ -414,29 +405,19 @@ bool ModListSortProxy::categoryMatchesMod( } } - if (m_FilterNot) { - b = !b; - } - return b; } bool ModListSortProxy::contentMatchesMod(ModInfo::Ptr info, bool enabled, int content) const { - bool b = info->hasContent(static_cast(content)); - - if (m_FilterNot) { - b = !b; - } - - return b; + return info->hasContent(static_cast(content)); } bool ModListSortProxy::filterMatchesMod(ModInfo::Ptr info, bool enabled) const { - if (!m_CurrentFilter.isEmpty()) { + 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); @@ -527,26 +508,11 @@ void ModListSortProxy::setColumnVisible(int column, bool visible) m_EnabledColumns[column] = visible; } -void ModListSortProxy::setFilterMode(ModListSortProxy::FilterMode mode) +void ModListSortProxy::setOptions(ModListSortProxy::FilterMode mode, bool separators) { - if (m_FilterMode != mode) { + if (m_FilterMode != mode || separators != m_FilterSeparators) { m_FilterMode = mode; - this->invalidate(); - } -} - -void ModListSortProxy::setFilterNot(bool b) -{ - if (b != m_FilterNot) { - m_FilterNot = b; - this->invalidate(); - } -} - -void ModListSortProxy::setFilterSeparators(bool b) -{ - if (b != m_FilterSeparators) { - m_FilterSeparators = b; + m_FilterSeparators = separators; this->invalidate(); } } @@ -623,8 +589,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()); + m_PreChangeCriteria = m_Criteria; + setCriteria({}); } void ModListSortProxy::postDataChanged() @@ -633,8 +599,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(); }); } diff --git a/src/modlistsortproxy.h b/src/modlistsortproxy.h index 2ebfbcf0..5aeaccce 100644 --- a/src/modlistsortproxy.h +++ b/src/modlistsortproxy.h @@ -37,22 +37,38 @@ public: FILTER_OR }; - enum FilterType { + enum CriteriaType { TYPE_SPECIAL, TYPE_CATEGORY, TYPE_CONTENT }; + struct Criteria + { + CriteriaType type; + int id; + bool inverse; + + bool operator==(const Criteria& other) const + { + return + (type == other.type) && + (id == other.id) && + (inverse == other.inverse); + } + + bool operator!=(const Criteria& other) const + { + return !(*this == other); + } + }; + public: explicit ModListSortProxy(Profile *profile, QObject *parent = 0); void setProfile(Profile *profile); - void setCategoryFilter(const std::vector &categories); - std::vector categoryFilter() const { return m_CategoryFilter; } - - void setContentFilter(const std::vector &content); virtual Qt::ItemFlags flags(const QModelIndex &modelIndex) const; virtual bool dropMimeData(const QMimeData *data, Qt::DropAction action, @@ -84,9 +100,8 @@ public: */ bool isFilterActive() const { return m_FilterActive; } - void setFilterMode(FilterMode mode); - void setFilterNot(bool b); - void setFilterSeparators(bool b); + void setCriteria(const std::vector& criteria); + void setOptions(FilterMode mode, bool separators); /** * @brief tests if the specified index has child nodes @@ -131,19 +146,18 @@ private slots: void postDataChanged(); private: - Profile *m_Profile; - std::vector m_CategoryFilter; - std::vector m_ContentFilter; + Profile* m_Profile; + std::vector m_Criteria; + QString m_Filter; std::bitset m_EnabledColumns; - QString m_CurrentFilter; bool m_FilterActive; FilterMode m_FilterMode; - bool m_FilterNot; bool m_FilterSeparators; - std::vector m_PreChangeFilters; + std::vector m_PreChangeCriteria; + bool criteriaMatchesMod(ModInfo::Ptr info, bool enabled, const Criteria& c) const; bool categoryMatchesMod(ModInfo::Ptr info, bool enabled, int category) const; bool contentMatchesMod(ModInfo::Ptr info, bool enabled, int content) const; }; -- cgit v1.3.1