Restore filters on load correctly.

This commit is contained in:
Lukas Brübach 2025-03-13 14:35:21 +01:00
parent b823ad2d9d
commit aeb24fa58e
10 changed files with 196 additions and 28 deletions

View file

@ -89,11 +89,14 @@ void VisualDatabaseDisplayFilterSaveLoadWidget::loadFilter(const QString &filena
filterModel->blockSignals(true); filterModel->blockSignals(true);
filterModel->filterTree()->blockSignals(true); filterModel->filterTree()->blockSignals(true);
for (const QJsonValue &value : filtersArray) { for (const QJsonValue &value : filtersArray) {
qDebug() << value;
if (value.isObject()) { if (value.isObject()) {
QJsonObject filterObj = value.toObject(); QJsonObject filterObj = value.toObject();
CardFilter *filter = CardFilter::fromJson(filterObj); CardFilter *filter = CardFilter::fromJson(filterObj);
if (filter) if (filter) {
qDebug() << "Adding filter " << filter->type() << filter->attr() << filter->term();
filterModel->addFilter(filter); filterModel->addFilter(filter);
}
} }
} }
filterModel->blockSignals(false); filterModel->blockSignals(false);

View file

@ -5,6 +5,7 @@
#include <QPushButton> #include <QPushButton>
#include <QSpinBox> #include <QSpinBox>
#include <QTimer>
VisualDatabaseDisplayMainTypeFilterWidget::VisualDatabaseDisplayMainTypeFilterWidget(QWidget *parent, VisualDatabaseDisplayMainTypeFilterWidget::VisualDatabaseDisplayMainTypeFilterWidget(QWidget *parent,
FilterTreeModel *_filterModel) FilterTreeModel *_filterModel)
@ -35,6 +36,9 @@ VisualDatabaseDisplayMainTypeFilterWidget::VisualDatabaseDisplayMainTypeFilterWi
toggleButton->setCheckable(true); toggleButton->setCheckable(true);
layout->addWidget(toggleButton); layout->addWidget(toggleButton);
connect(toggleButton, &QPushButton::toggled, this, &VisualDatabaseDisplayMainTypeFilterWidget::updateFilterMode); connect(toggleButton, &QPushButton::toggled, this, &VisualDatabaseDisplayMainTypeFilterWidget::updateFilterMode);
connect(filterModel, &FilterTreeModel::layoutChanged, this, [this]() {
QTimer::singleShot(100, this, &VisualDatabaseDisplayMainTypeFilterWidget::syncWithFilterModel);
});
createMainTypeButtons(); // Populate buttons initially createMainTypeButtons(); // Populate buttons initially
updateFilterMode(false); // Initialize toggle button text updateFilterMode(false); // Initialize toggle button text
@ -94,7 +98,7 @@ void VisualDatabaseDisplayMainTypeFilterWidget::handleMainTypeToggled(const QStr
void VisualDatabaseDisplayMainTypeFilterWidget::updateMainTypeFilter() void VisualDatabaseDisplayMainTypeFilterWidget::updateMainTypeFilter()
{ {
// Clear existing filters related to main type // Clear existing filters related to main type
filterModel->clearFiltersOfType(CardFilter::Attr::AttrType); filterModel->clearFiltersOfType(CardFilter::Attr::AttrMainType);
if (exactMatchMode) { if (exactMatchMode) {
// Exact Match: Only selected main types are allowed // Exact Match: Only selected main types are allowed
@ -110,7 +114,7 @@ void VisualDatabaseDisplayMainTypeFilterWidget::updateMainTypeFilter()
for (const auto &type : selectedTypes) { for (const auto &type : selectedTypes) {
QString typeString = type; QString typeString = type;
filterModel->addFilter( 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) // Exclude any other types (TypeAndNot)
@ -118,7 +122,7 @@ void VisualDatabaseDisplayMainTypeFilterWidget::updateMainTypeFilter()
if (!selectedTypes.contains(type)) { if (!selectedTypes.contains(type)) {
QString typeString = type; QString typeString = type;
filterModel->addFilter( 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]) { if (activeMainTypes[type]) {
QString typeString = type; QString typeString = type;
filterModel->addFilter( 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")); toggleButton->setText(exactMatchMode ? tr("Mode: Exact Match") : tr("Mode: Includes"));
updateMainTypeFilter(); 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<QString> 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();
}

View file

@ -23,6 +23,7 @@ public:
void handleMainTypeToggled(const QString &mainType, bool active); void handleMainTypeToggled(const QString &mainType, bool active);
void updateMainTypeFilter(); void updateMainTypeFilter();
void updateFilterMode(bool checked); void updateFilterMode(bool checked);
void syncWithFilterModel();
private: private:
FilterTreeModel *filterModel; FilterTreeModel *filterModel;

View file

@ -38,6 +38,8 @@ VisualDatabaseDisplayNameFilterWidget::VisualDatabaseDisplayNameFilterWidget(QWi
layout->addWidget(loadFromDeckButton); layout->addWidget(loadFromDeckButton);
connect(loadFromDeckButton, &QPushButton::clicked, this, &VisualDatabaseDisplayNameFilterWidget::actLoadFromDeck); connect(loadFromDeckButton, &QPushButton::clicked, this, &VisualDatabaseDisplayNameFilterWidget::actLoadFromDeck);
connect(filterModel, &FilterTreeModel::layoutChanged, this,
[this]() { QTimer::singleShot(100, this, &VisualDatabaseDisplayNameFilterWidget::syncWithFilterModel); });
} }
void VisualDatabaseDisplayNameFilterWidget::actLoadFromDeck() void VisualDatabaseDisplayNameFilterWidget::actLoadFromDeck()
@ -86,9 +88,11 @@ void VisualDatabaseDisplayNameFilterWidget::createNameFilter(const QString &name
void VisualDatabaseDisplayNameFilterWidget::removeNameFilter(const QString &name) void VisualDatabaseDisplayNameFilterWidget::removeNameFilter(const QString &name)
{ {
if (activeFilters.contains(name)) { if (activeFilters.contains(name)) {
delete activeFilters[name]; // Remove button activeFilters[name]->deleteLater(); // Safe deletion
activeFilters.remove(name); 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(); filterModel->filterTree()->nodeAt(0)->nodeChanged();
emit filterModel->layoutChanged(); 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);
}
}
}

View file

@ -23,6 +23,7 @@ public:
void removeNameFilter(const QString &name); void removeNameFilter(const QString &name);
void updateFilterList(); void updateFilterList();
void updateFilterModel(); void updateFilterModel();
void syncWithFilterModel();
private: private:
AbstractTabDeckEditor *deckEditor; AbstractTabDeckEditor *deckEditor;

View file

@ -5,6 +5,7 @@
#include <QLineEdit> #include <QLineEdit>
#include <QPushButton> #include <QPushButton>
#include <QTimer>
#include <algorithm> #include <algorithm>
VisualDatabaseDisplaySetFilterWidget::VisualDatabaseDisplaySetFilterWidget(QWidget *parent, VisualDatabaseDisplaySetFilterWidget::VisualDatabaseDisplaySetFilterWidget(QWidget *parent,
@ -32,6 +33,8 @@ VisualDatabaseDisplaySetFilterWidget::VisualDatabaseDisplaySetFilterWidget(QWidg
toggleButton->setCheckable(true); toggleButton->setCheckable(true);
layout->addWidget(toggleButton); layout->addWidget(toggleButton);
connect(toggleButton, &QPushButton::toggled, this, &VisualDatabaseDisplaySetFilterWidget::updateFilterMode); connect(toggleButton, &QPushButton::toggled, this, &VisualDatabaseDisplaySetFilterWidget::updateFilterMode);
connect(filterModel, &FilterTreeModel::layoutChanged, this,
[this]() { QTimer::singleShot(100, this, &VisualDatabaseDisplaySetFilterWidget::syncWithFilterModel); });
createSetButtons(); // Populate buttons initially createSetButtons(); // Populate buttons initially
updateFilterMode(false); // Initialize toggle button text 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<QString> selectedSets;
QSet<QString> 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) void VisualDatabaseDisplaySetFilterWidget::updateFilterMode(bool checked)
{ {
exactMatchMode = checked; exactMatchMode = checked;

View file

@ -21,6 +21,7 @@ public:
void handleSetToggled(const QString &setShortName, bool active); void handleSetToggled(const QString &setShortName, bool active);
void updateSetFilter(); void updateSetFilter();
void syncWithFilterModel();
void updateFilterMode(bool checked); void updateFilterMode(bool checked);
private: private:

View file

@ -6,6 +6,7 @@
#include <QLineEdit> #include <QLineEdit>
#include <QPushButton> #include <QPushButton>
#include <QSpinBox> #include <QSpinBox>
#include <QTimer>
VisualDatabaseDisplaySubTypeFilterWidget::VisualDatabaseDisplaySubTypeFilterWidget(QWidget *parent, VisualDatabaseDisplaySubTypeFilterWidget::VisualDatabaseDisplaySubTypeFilterWidget(QWidget *parent,
FilterTreeModel *_filterModel) FilterTreeModel *_filterModel)
@ -18,7 +19,7 @@ VisualDatabaseDisplaySubTypeFilterWidget::VisualDatabaseDisplaySubTypeFilterWidg
layout = new QVBoxLayout(this); layout = new QVBoxLayout(this);
setLayout(layout); setLayout(layout);
// Create the spinbox // Create and setup the spinbox
spinBox = new QSpinBox(this); spinBox = new QSpinBox(this);
spinBox->setMinimum(1); spinBox->setMinimum(1);
spinBox->setMaximum(getMaxSubTypeCount()); spinBox->setMaximum(getMaxSubTypeCount());
@ -27,7 +28,7 @@ VisualDatabaseDisplaySubTypeFilterWidget::VisualDatabaseDisplaySubTypeFilterWidg
connect(spinBox, QOverload<int>::of(&QSpinBox::valueChanged), this, connect(spinBox, QOverload<int>::of(&QSpinBox::valueChanged), this,
&VisualDatabaseDisplaySubTypeFilterWidget::updateSubTypeButtonsVisibility); &VisualDatabaseDisplaySubTypeFilterWidget::updateSubTypeButtonsVisibility);
// Create the search box // Create search box
searchBox = new QLineEdit(this); searchBox = new QLineEdit(this);
searchBox->setPlaceholderText(tr("Search subtypes...")); searchBox->setPlaceholderText(tr("Search subtypes..."));
layout->addWidget(searchBox); layout->addWidget(searchBox);
@ -38,19 +39,22 @@ VisualDatabaseDisplaySubTypeFilterWidget::VisualDatabaseDisplaySubTypeFilterWidg
flowWidget->setMaximumHeight(300); flowWidget->setMaximumHeight(300);
layout->addWidget(flowWidget); layout->addWidget(flowWidget);
// Create the toggle button for Exact Match/Includes mode // Toggle button setup (Exact Match / Includes mode)
toggleButton = new QPushButton(this); toggleButton = new QPushButton(this);
toggleButton->setCheckable(true); toggleButton->setCheckable(true);
layout->addWidget(toggleButton); layout->addWidget(toggleButton);
connect(toggleButton, &QPushButton::toggled, this, &VisualDatabaseDisplaySubTypeFilterWidget::updateFilterMode); connect(toggleButton, &QPushButton::toggled, this, &VisualDatabaseDisplaySubTypeFilterWidget::updateFilterMode);
connect(filterModel, &FilterTreeModel::layoutChanged, this, [this]() {
QTimer::singleShot(100, this, &VisualDatabaseDisplaySubTypeFilterWidget::syncWithFilterModel);
});
createSubTypeButtons(); // Populate buttons initially createSubTypeButtons(); // Populate buttons initially
updateFilterMode(false); updateFilterMode(false); // Initialize the toggle button text
} }
void VisualDatabaseDisplaySubTypeFilterWidget::createSubTypeButtons() 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) { for (auto it = allSubCardTypesWithCount.begin(); it != allSubCardTypesWithCount.end(); ++it) {
auto *button = new QPushButton(it.key(), flowWidget); auto *button = new QPushButton(it.key(), flowWidget);
button->setCheckable(true); button->setCheckable(true);
@ -60,9 +64,9 @@ void VisualDatabaseDisplaySubTypeFilterWidget::createSubTypeButtons()
flowWidget->addWidget(button); flowWidget->addWidget(button);
typeButtons[it.key()] = button; typeButtons[it.key()] = button;
// Connect toggle signal // Connect toggle signal for each button
connect(button, &QPushButton::toggled, this, 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 updateSubTypeButtonsVisibility(); // Ensure visibility is updated initially
} }
@ -72,6 +76,7 @@ void VisualDatabaseDisplaySubTypeFilterWidget::updateSubTypeButtonsVisibility()
int threshold = spinBox->value(); int threshold = spinBox->value();
QString filterText = searchBox->text().trimmed().toLower(); 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) { for (auto it = typeButtons.begin(); it != typeButtons.end(); ++it) {
QString subType = it.key().toLower(); QString subType = it.key().toLower();
bool isActive = activeSubTypes.value(it.key(), false); bool isActive = activeSubTypes.value(it.key(), false);
@ -92,12 +97,12 @@ int VisualDatabaseDisplaySubTypeFilterWidget::getMaxSubTypeCount() const
return maxCount; 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)) { if (typeButtons.contains(subType)) {
typeButtons[mainType]->setChecked(active); typeButtons[subType]->setChecked(active);
} }
updateSubTypeFilter(); updateSubTypeFilter();
@ -105,11 +110,11 @@ void VisualDatabaseDisplaySubTypeFilterWidget::handleSubTypeToggled(const QStrin
void VisualDatabaseDisplaySubTypeFilterWidget::updateSubTypeFilter() void VisualDatabaseDisplaySubTypeFilterWidget::updateSubTypeFilter()
{ {
// Clear existing filters related to main type // Clear existing filters related to sub types
filterModel->clearFiltersOfType(CardFilter::Attr::AttrType); filterModel->clearFiltersOfType(CardFilter::Attr::AttrSubType);
if (exactMatchMode) { if (exactMatchMode) {
// Exact Match: Only selected main types are allowed // Exact Match: Only selected sub types are allowed
QSet<QString> selectedTypes; QSet<QString> selectedTypes;
for (const auto &type : activeSubTypes.keys()) { for (const auto &type : activeSubTypes.keys()) {
if (activeSubTypes[type]) { if (activeSubTypes[type]) {
@ -118,11 +123,11 @@ void VisualDatabaseDisplaySubTypeFilterWidget::updateSubTypeFilter()
} }
if (!selectedTypes.isEmpty()) { if (!selectedTypes.isEmpty()) {
// Require all selected types (TypeAnd) // Require all selected subtypes (TypeAnd)
for (const auto &type : selectedTypes) { for (const auto &type : selectedTypes) {
QString typeString = type; QString typeString = type;
filterModel->addFilter( 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) // Exclude any other types (TypeAndNot)
@ -130,17 +135,17 @@ void VisualDatabaseDisplaySubTypeFilterWidget::updateSubTypeFilter()
if (!selectedTypes.contains(type)) { if (!selectedTypes.contains(type)) {
QString typeString = type; QString typeString = type;
filterModel->addFilter( filterModel->addFilter(
new CardFilter(typeString, CardFilter::Type::TypeAndNot, CardFilter::Attr::AttrType)); new CardFilter(typeString, CardFilter::Type::TypeAndNot, CardFilter::Attr::AttrSubType));
} }
} }
} }
} else { } else {
// Default Includes Mode (TypeOr) - match any selected main types // Default Includes Mode (TypeOr) - match any selected subtypes
for (const auto &type : activeSubTypes.keys()) { for (const auto &type : activeSubTypes.keys()) {
if (activeSubTypes[type]) { if (activeSubTypes[type]) {
QString typeString = type; QString typeString = type;
filterModel->addFilter( 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")); toggleButton->setText(exactMatchMode ? tr("Mode: Exact Match") : tr("Mode: Includes"));
updateSubTypeFilter(); 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<QString> 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();
}

View file

@ -23,6 +23,7 @@ public:
void handleSubTypeToggled(const QString &mainType, bool active); void handleSubTypeToggled(const QString &mainType, bool active);
void updateSubTypeFilter(); void updateSubTypeFilter();
void updateFilterMode(bool checked); void updateFilterMode(bool checked);
void syncWithFilterModel();
private: private:
FilterTreeModel *filterModel; FilterTreeModel *filterModel;

View file

@ -46,7 +46,7 @@ private:
enum Attr a; enum Attr a;
public: 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 Type type() const
{ {