From aeb24fa58ecbde97993fe2406a27d08bde4a96ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20Br=C3=BCbach?= Date: Thu, 13 Mar 2025 14:35:21 +0100 Subject: [PATCH] Restore filters on load correctly. --- ...tabase_display_filter_save_load_widget.cpp | 5 +- ...tabase_display_main_type_filter_widget.cpp | 49 ++++++++++- ...database_display_main_type_filter_widget.h | 1 + ...al_database_display_name_filter_widget.cpp | 42 +++++++++- ...sual_database_display_name_filter_widget.h | 1 + ...ual_database_display_set_filter_widget.cpp | 40 +++++++++ ...isual_database_display_set_filter_widget.h | 1 + ...atabase_display_sub_type_filter_widget.cpp | 82 ++++++++++++++----- ..._database_display_sub_type_filter_widget.h | 1 + cockatrice/src/game/filters/filter_card.h | 2 +- 10 files changed, 196 insertions(+), 28 deletions(-) diff --git a/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_filter_save_load_widget.cpp b/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_filter_save_load_widget.cpp index 995158f44..b9627a863 100644 --- a/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_filter_save_load_widget.cpp +++ b/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_filter_save_load_widget.cpp @@ -89,11 +89,14 @@ void VisualDatabaseDisplayFilterSaveLoadWidget::loadFilter(const QString &filena filterModel->blockSignals(true); filterModel->filterTree()->blockSignals(true); for (const QJsonValue &value : filtersArray) { + qDebug() << value; if (value.isObject()) { QJsonObject filterObj = value.toObject(); CardFilter *filter = CardFilter::fromJson(filterObj); - if (filter) + if (filter) { + qDebug() << "Adding filter " << filter->type() << filter->attr() << filter->term(); filterModel->addFilter(filter); + } } } filterModel->blockSignals(false); diff --git a/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_main_type_filter_widget.cpp b/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_main_type_filter_widget.cpp index 6caa68ab3..e350506aa 100644 --- a/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_main_type_filter_widget.cpp +++ b/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_main_type_filter_widget.cpp @@ -5,6 +5,7 @@ #include #include +#include VisualDatabaseDisplayMainTypeFilterWidget::VisualDatabaseDisplayMainTypeFilterWidget(QWidget *parent, FilterTreeModel *_filterModel) @@ -35,6 +36,9 @@ VisualDatabaseDisplayMainTypeFilterWidget::VisualDatabaseDisplayMainTypeFilterWi toggleButton->setCheckable(true); layout->addWidget(toggleButton); connect(toggleButton, &QPushButton::toggled, this, &VisualDatabaseDisplayMainTypeFilterWidget::updateFilterMode); + connect(filterModel, &FilterTreeModel::layoutChanged, this, [this]() { + QTimer::singleShot(100, this, &VisualDatabaseDisplayMainTypeFilterWidget::syncWithFilterModel); + }); createMainTypeButtons(); // Populate buttons initially updateFilterMode(false); // Initialize toggle button text @@ -94,7 +98,7 @@ void VisualDatabaseDisplayMainTypeFilterWidget::handleMainTypeToggled(const QStr void VisualDatabaseDisplayMainTypeFilterWidget::updateMainTypeFilter() { // Clear existing filters related to main type - filterModel->clearFiltersOfType(CardFilter::Attr::AttrType); + filterModel->clearFiltersOfType(CardFilter::Attr::AttrMainType); if (exactMatchMode) { // Exact Match: Only selected main types are allowed @@ -110,7 +114,7 @@ void VisualDatabaseDisplayMainTypeFilterWidget::updateMainTypeFilter() for (const auto &type : selectedTypes) { QString typeString = type; filterModel->addFilter( - new CardFilter(typeString, CardFilter::Type::TypeAnd, CardFilter::Attr::AttrType)); + new CardFilter(typeString, CardFilter::Type::TypeAnd, CardFilter::Attr::AttrMainType)); } // Exclude any other types (TypeAndNot) @@ -118,7 +122,7 @@ void VisualDatabaseDisplayMainTypeFilterWidget::updateMainTypeFilter() if (!selectedTypes.contains(type)) { QString typeString = type; filterModel->addFilter( - new CardFilter(typeString, CardFilter::Type::TypeAndNot, CardFilter::Attr::AttrType)); + new CardFilter(typeString, CardFilter::Type::TypeAndNot, CardFilter::Attr::AttrMainType)); } } } @@ -128,7 +132,7 @@ void VisualDatabaseDisplayMainTypeFilterWidget::updateMainTypeFilter() if (activeMainTypes[type]) { QString typeString = type; filterModel->addFilter( - new CardFilter(typeString, CardFilter::Type::TypeAnd, CardFilter::Attr::AttrType)); + new CardFilter(typeString, CardFilter::Type::TypeAnd, CardFilter::Attr::AttrMainType)); } } } @@ -140,3 +144,40 @@ void VisualDatabaseDisplayMainTypeFilterWidget::updateFilterMode(bool checked) toggleButton->setText(exactMatchMode ? tr("Mode: Exact Match") : tr("Mode: Includes")); updateMainTypeFilter(); } + +void VisualDatabaseDisplayMainTypeFilterWidget::syncWithFilterModel() +{ + // Temporarily block signals for each button to prevent toggling while updating button states + for (auto it = typeButtons.begin(); it != typeButtons.end(); ++it) { + it.value()->blockSignals(true); + } + + // Uncheck all buttons + for (auto it = typeButtons.begin(); it != typeButtons.end(); ++it) { + it.value()->setChecked(false); + } + + // Get active filters for main types + QSet activeTypes; + for (const auto &filter : filterModel->getFiltersOfType(CardFilter::AttrMainType)) { + if (filter->type() == CardFilter::Type::TypeAnd) { + activeTypes.insert(filter->term()); + } + } + + // Check the buttons for active types + for (const auto &type : activeTypes) { + activeMainTypes[type] = true; + if (typeButtons.contains(type)) { + typeButtons[type]->setChecked(true); + } + } + + // Re-enable signal emissions for each button + for (auto it = typeButtons.begin(); it != typeButtons.end(); ++it) { + it.value()->blockSignals(false); + } + + // Update the visibility of buttons + updateMainTypeButtonsVisibility(); +} diff --git a/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_main_type_filter_widget.h b/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_main_type_filter_widget.h index 370ddde9b..74eb8b237 100644 --- a/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_main_type_filter_widget.h +++ b/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_main_type_filter_widget.h @@ -23,6 +23,7 @@ public: void handleMainTypeToggled(const QString &mainType, bool active); void updateMainTypeFilter(); void updateFilterMode(bool checked); + void syncWithFilterModel(); private: FilterTreeModel *filterModel; diff --git a/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_name_filter_widget.cpp b/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_name_filter_widget.cpp index 2ffb9a8a0..14b482808 100644 --- a/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_name_filter_widget.cpp +++ b/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_name_filter_widget.cpp @@ -38,6 +38,8 @@ VisualDatabaseDisplayNameFilterWidget::VisualDatabaseDisplayNameFilterWidget(QWi layout->addWidget(loadFromDeckButton); connect(loadFromDeckButton, &QPushButton::clicked, this, &VisualDatabaseDisplayNameFilterWidget::actLoadFromDeck); + connect(filterModel, &FilterTreeModel::layoutChanged, this, + [this]() { QTimer::singleShot(100, this, &VisualDatabaseDisplayNameFilterWidget::syncWithFilterModel); }); } void VisualDatabaseDisplayNameFilterWidget::actLoadFromDeck() @@ -86,9 +88,11 @@ void VisualDatabaseDisplayNameFilterWidget::createNameFilter(const QString &name void VisualDatabaseDisplayNameFilterWidget::removeNameFilter(const QString &name) { if (activeFilters.contains(name)) { - delete activeFilters[name]; // Remove button + activeFilters[name]->deleteLater(); // Safe deletion activeFilters.remove(name); - updateFilterModel(); + + QTimer::singleShot(0, this, + &VisualDatabaseDisplayNameFilterWidget::updateFilterModel); // Avoid concurrent modification } } @@ -112,3 +116,37 @@ void VisualDatabaseDisplayNameFilterWidget::updateFilterModel() filterModel->filterTree()->nodeAt(0)->nodeChanged(); emit filterModel->layoutChanged(); } + +void VisualDatabaseDisplayNameFilterWidget::syncWithFilterModel() +{ + QStringList currentFilters; + for (const auto &filter : filterModel->getFiltersOfType(CardFilter::Attr::AttrName)) { + if (filter->type() == CardFilter::Type::TypeOr) { + currentFilters.append(filter->term()); + } + } + + QStringList activeFilterList = activeFilters.keys(); + + // Sort lists for efficient comparison + std::sort(currentFilters.begin(), currentFilters.end()); + std::sort(activeFilterList.begin(), activeFilterList.end()); + + if (currentFilters == activeFilterList) { + return; + } + + // Remove filters that are in the UI but not in the model + for (const auto &name : activeFilterList) { + if (!currentFilters.contains(name)) { + removeNameFilter(name); + } + } + + // Add filters that are in the model but not in the UI + for (const auto &name : currentFilters) { + if (!activeFilters.contains(name)) { + createNameFilter(name); + } + } +} diff --git a/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_name_filter_widget.h b/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_name_filter_widget.h index 9505da3da..26802b455 100644 --- a/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_name_filter_widget.h +++ b/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_name_filter_widget.h @@ -23,6 +23,7 @@ public: void removeNameFilter(const QString &name); void updateFilterList(); void updateFilterModel(); + void syncWithFilterModel(); private: AbstractTabDeckEditor *deckEditor; diff --git a/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_set_filter_widget.cpp b/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_set_filter_widget.cpp index fb602bec9..4e7e0a2c7 100644 --- a/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_set_filter_widget.cpp +++ b/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_set_filter_widget.cpp @@ -5,6 +5,7 @@ #include #include +#include #include VisualDatabaseDisplaySetFilterWidget::VisualDatabaseDisplaySetFilterWidget(QWidget *parent, @@ -32,6 +33,8 @@ VisualDatabaseDisplaySetFilterWidget::VisualDatabaseDisplaySetFilterWidget(QWidg toggleButton->setCheckable(true); layout->addWidget(toggleButton); connect(toggleButton, &QPushButton::toggled, this, &VisualDatabaseDisplaySetFilterWidget::updateFilterMode); + connect(filterModel, &FilterTreeModel::layoutChanged, this, + [this]() { QTimer::singleShot(100, this, &VisualDatabaseDisplaySetFilterWidget::syncWithFilterModel); }); createSetButtons(); // Populate buttons initially updateFilterMode(false); // Initialize toggle button text @@ -130,6 +133,43 @@ void VisualDatabaseDisplaySetFilterWidget::updateSetFilter() } } +void VisualDatabaseDisplaySetFilterWidget::syncWithFilterModel() +{ + // Clear activeSets + activeSets.clear(); + + // Read the current filters in filterModel + auto currentFilters = filterModel->getFiltersOfType(CardFilter::Attr::AttrSet); + + // Determine if we're in Exact Match mode or Includes mode + QSet selectedSets; + QSet excludedSets; + for (const auto &filter : currentFilters) { + if (filter->type() == CardFilter::Type::TypeAnd) { + selectedSets.insert(filter->term()); + } else if (filter->type() == CardFilter::Type::TypeAndNot) { + excludedSets.insert(filter->term()); + } else if (filter->type() == CardFilter::Type::TypeOr) { + selectedSets.insert(filter->term()); + } + } + + // Determine exact match mode based on filter structure + bool newExactMatchMode = !excludedSets.isEmpty(); + + if (newExactMatchMode != exactMatchMode) { + exactMatchMode = newExactMatchMode; + toggleButton->setText(exactMatchMode ? tr("Mode: Exact Match") : tr("Mode: Includes")); + } + + // Sync button states with selected sets + for (auto it = setButtons.begin(); it != setButtons.end(); ++it) { + bool active = selectedSets.contains(it.key()); + activeSets[it.key()] = active; + it.value()->setChecked(active); + } +} + void VisualDatabaseDisplaySetFilterWidget::updateFilterMode(bool checked) { exactMatchMode = checked; diff --git a/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_set_filter_widget.h b/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_set_filter_widget.h index 3d8b5d033..41da57ef8 100644 --- a/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_set_filter_widget.h +++ b/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_set_filter_widget.h @@ -21,6 +21,7 @@ public: void handleSetToggled(const QString &setShortName, bool active); void updateSetFilter(); + void syncWithFilterModel(); void updateFilterMode(bool checked); private: diff --git a/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_sub_type_filter_widget.cpp b/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_sub_type_filter_widget.cpp index 1adec9a99..5b7f56330 100644 --- a/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_sub_type_filter_widget.cpp +++ b/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_sub_type_filter_widget.cpp @@ -6,6 +6,7 @@ #include #include #include +#include VisualDatabaseDisplaySubTypeFilterWidget::VisualDatabaseDisplaySubTypeFilterWidget(QWidget *parent, FilterTreeModel *_filterModel) @@ -18,7 +19,7 @@ VisualDatabaseDisplaySubTypeFilterWidget::VisualDatabaseDisplaySubTypeFilterWidg layout = new QVBoxLayout(this); setLayout(layout); - // Create the spinbox + // Create and setup the spinbox spinBox = new QSpinBox(this); spinBox->setMinimum(1); spinBox->setMaximum(getMaxSubTypeCount()); @@ -27,7 +28,7 @@ VisualDatabaseDisplaySubTypeFilterWidget::VisualDatabaseDisplaySubTypeFilterWidg connect(spinBox, QOverload::of(&QSpinBox::valueChanged), this, &VisualDatabaseDisplaySubTypeFilterWidget::updateSubTypeButtonsVisibility); - // Create the search box + // Create search box searchBox = new QLineEdit(this); searchBox->setPlaceholderText(tr("Search subtypes...")); layout->addWidget(searchBox); @@ -38,19 +39,22 @@ VisualDatabaseDisplaySubTypeFilterWidget::VisualDatabaseDisplaySubTypeFilterWidg flowWidget->setMaximumHeight(300); layout->addWidget(flowWidget); - // Create the toggle button for Exact Match/Includes mode + // Toggle button setup (Exact Match / Includes mode) toggleButton = new QPushButton(this); toggleButton->setCheckable(true); layout->addWidget(toggleButton); connect(toggleButton, &QPushButton::toggled, this, &VisualDatabaseDisplaySubTypeFilterWidget::updateFilterMode); + connect(filterModel, &FilterTreeModel::layoutChanged, this, [this]() { + QTimer::singleShot(100, this, &VisualDatabaseDisplaySubTypeFilterWidget::syncWithFilterModel); + }); - createSubTypeButtons(); // Populate buttons initially - updateFilterMode(false); + createSubTypeButtons(); // Populate buttons initially + updateFilterMode(false); // Initialize the toggle button text } void VisualDatabaseDisplaySubTypeFilterWidget::createSubTypeButtons() { - // Iterate through main types and create buttons + // Iterate through sub types and create buttons for (auto it = allSubCardTypesWithCount.begin(); it != allSubCardTypesWithCount.end(); ++it) { auto *button = new QPushButton(it.key(), flowWidget); button->setCheckable(true); @@ -60,9 +64,9 @@ void VisualDatabaseDisplaySubTypeFilterWidget::createSubTypeButtons() flowWidget->addWidget(button); typeButtons[it.key()] = button; - // Connect toggle signal + // Connect toggle signal for each button connect(button, &QPushButton::toggled, this, - [this, mainType = it.key()](bool checked) { handleSubTypeToggled(mainType, checked); }); + [this, subType = it.key()](bool checked) { handleSubTypeToggled(subType, checked); }); } updateSubTypeButtonsVisibility(); // Ensure visibility is updated initially } @@ -72,6 +76,7 @@ void VisualDatabaseDisplaySubTypeFilterWidget::updateSubTypeButtonsVisibility() int threshold = spinBox->value(); QString filterText = searchBox->text().trimmed().toLower(); + // Iterate through buttons and hide/disable those below the threshold for (auto it = typeButtons.begin(); it != typeButtons.end(); ++it) { QString subType = it.key().toLower(); bool isActive = activeSubTypes.value(it.key(), false); @@ -92,12 +97,12 @@ int VisualDatabaseDisplaySubTypeFilterWidget::getMaxSubTypeCount() const return maxCount; } -void VisualDatabaseDisplaySubTypeFilterWidget::handleSubTypeToggled(const QString &mainType, bool active) +void VisualDatabaseDisplaySubTypeFilterWidget::handleSubTypeToggled(const QString &subType, bool active) { - activeSubTypes[mainType] = active; + activeSubTypes[subType] = active; - if (typeButtons.contains(mainType)) { - typeButtons[mainType]->setChecked(active); + if (typeButtons.contains(subType)) { + typeButtons[subType]->setChecked(active); } updateSubTypeFilter(); @@ -105,11 +110,11 @@ void VisualDatabaseDisplaySubTypeFilterWidget::handleSubTypeToggled(const QStrin void VisualDatabaseDisplaySubTypeFilterWidget::updateSubTypeFilter() { - // Clear existing filters related to main type - filterModel->clearFiltersOfType(CardFilter::Attr::AttrType); + // Clear existing filters related to sub types + filterModel->clearFiltersOfType(CardFilter::Attr::AttrSubType); if (exactMatchMode) { - // Exact Match: Only selected main types are allowed + // Exact Match: Only selected sub types are allowed QSet selectedTypes; for (const auto &type : activeSubTypes.keys()) { if (activeSubTypes[type]) { @@ -118,11 +123,11 @@ void VisualDatabaseDisplaySubTypeFilterWidget::updateSubTypeFilter() } if (!selectedTypes.isEmpty()) { - // Require all selected types (TypeAnd) + // Require all selected subtypes (TypeAnd) for (const auto &type : selectedTypes) { QString typeString = type; filterModel->addFilter( - new CardFilter(typeString, CardFilter::Type::TypeAnd, CardFilter::Attr::AttrType)); + new CardFilter(typeString, CardFilter::Type::TypeAnd, CardFilter::Attr::AttrSubType)); } // Exclude any other types (TypeAndNot) @@ -130,17 +135,17 @@ void VisualDatabaseDisplaySubTypeFilterWidget::updateSubTypeFilter() if (!selectedTypes.contains(type)) { QString typeString = type; filterModel->addFilter( - new CardFilter(typeString, CardFilter::Type::TypeAndNot, CardFilter::Attr::AttrType)); + new CardFilter(typeString, CardFilter::Type::TypeAndNot, CardFilter::Attr::AttrSubType)); } } } } else { - // Default Includes Mode (TypeOr) - match any selected main types + // Default Includes Mode (TypeOr) - match any selected subtypes for (const auto &type : activeSubTypes.keys()) { if (activeSubTypes[type]) { QString typeString = type; filterModel->addFilter( - new CardFilter(typeString, CardFilter::Type::TypeAnd, CardFilter::Attr::AttrType)); + new CardFilter(typeString, CardFilter::Type::TypeAnd, CardFilter::Attr::AttrSubType)); } } } @@ -152,3 +157,40 @@ void VisualDatabaseDisplaySubTypeFilterWidget::updateFilterMode(bool checked) toggleButton->setText(exactMatchMode ? tr("Mode: Exact Match") : tr("Mode: Includes")); updateSubTypeFilter(); } + +void VisualDatabaseDisplaySubTypeFilterWidget::syncWithFilterModel() +{ + // Temporarily block signals for each button to prevent toggling while updating button states + for (auto it = typeButtons.begin(); it != typeButtons.end(); ++it) { + it.value()->blockSignals(true); + } + + // Uncheck all buttons + for (auto it = typeButtons.begin(); it != typeButtons.end(); ++it) { + it.value()->setChecked(false); + } + + // Get active filters for sub types + QSet activeTypes; + for (const auto &filter : filterModel->getFiltersOfType(CardFilter::AttrSubType)) { + if (filter->type() == CardFilter::Type::TypeAnd) { + activeTypes.insert(filter->term()); + } + } + + // Check the buttons for active types + for (const auto &type : activeTypes) { + activeSubTypes[type] = true; + if (typeButtons.contains(type)) { + typeButtons[type]->setChecked(true); + } + } + + // Re-enable signal emissions for each button + for (auto it = typeButtons.begin(); it != typeButtons.end(); ++it) { + it.value()->blockSignals(false); + } + + // Update the visibility of buttons + updateSubTypeButtonsVisibility(); +} diff --git a/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_sub_type_filter_widget.h b/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_sub_type_filter_widget.h index 9a6148625..72a0a25bb 100644 --- a/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_sub_type_filter_widget.h +++ b/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_sub_type_filter_widget.h @@ -23,6 +23,7 @@ public: void handleSubTypeToggled(const QString &mainType, bool active); void updateSubTypeFilter(); void updateFilterMode(bool checked); + void syncWithFilterModel(); private: FilterTreeModel *filterModel; diff --git a/cockatrice/src/game/filters/filter_card.h b/cockatrice/src/game/filters/filter_card.h index 210d5c062..66e4e674e 100644 --- a/cockatrice/src/game/filters/filter_card.h +++ b/cockatrice/src/game/filters/filter_card.h @@ -46,7 +46,7 @@ private: enum Attr a; public: - CardFilter(QString &term, Type type, Attr attr) : trm(term), t(type), a(attr){}; + CardFilter(QString &term, Type type, Attr attr) : trm(term), t(type), a(attr) {}; Type type() const {