mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-04-27 07:48:01 -07:00
* move message_log_widget to game * move files * update headers * fix cmakelists * oracle fixes * split implementation out to cpp * fix recursive import * fix main file * format
This commit is contained in:
parent
f484c98152
commit
17dcaf9afa
337 changed files with 728 additions and 721 deletions
|
|
@ -0,0 +1,257 @@
|
|||
#include "visual_database_display_color_filter_widget.h"
|
||||
|
||||
#include "../../../filters/filter_tree.h"
|
||||
#include "../cards/additional_info/mana_symbol_widget.h"
|
||||
|
||||
#include <QSet>
|
||||
#include <QTimer>
|
||||
|
||||
/**
|
||||
* This widget provides a graphical control element for the CardFilter::Attr::AttrColor filters applied to the filter
|
||||
* model.
|
||||
* @param parent The Qt Widget that this widget will parent to
|
||||
* @param _filterModel The filter model that this widget will manipulate
|
||||
*/
|
||||
VisualDatabaseDisplayColorFilterWidget::VisualDatabaseDisplayColorFilterWidget(QWidget *parent,
|
||||
FilterTreeModel *_filterModel)
|
||||
: QWidget(parent), filterModel(_filterModel), layout(new QHBoxLayout(this))
|
||||
{
|
||||
setLayout(layout);
|
||||
layout->setSpacing(5);
|
||||
layout->setContentsMargins(0, 0, 0, 0);
|
||||
|
||||
QString fullColorIdentity = "WUBRG";
|
||||
for (const QChar &color : fullColorIdentity) {
|
||||
auto *manaSymbol = new ManaSymbolWidget(this, color, false, true);
|
||||
manaSymbol->setFixedWidth(25);
|
||||
|
||||
layout->addWidget(manaSymbol);
|
||||
|
||||
// Connect the color toggled signal
|
||||
connect(manaSymbol, &ManaSymbolWidget::colorToggled, this,
|
||||
&VisualDatabaseDisplayColorFilterWidget::handleColorToggled);
|
||||
}
|
||||
|
||||
toggleButton = new QPushButton(this);
|
||||
toggleButton->setCheckable(true);
|
||||
layout->addWidget(toggleButton);
|
||||
|
||||
// Connect the button's toggled signal
|
||||
connect(toggleButton, &QPushButton::toggled, this, &VisualDatabaseDisplayColorFilterWidget::updateFilterMode);
|
||||
connect(filterModel, &FilterTreeModel::layoutChanged, this,
|
||||
[this]() { QTimer::singleShot(100, this, &VisualDatabaseDisplayColorFilterWidget::syncWithFilterModel); });
|
||||
|
||||
// Call retranslateUi to set the initial text
|
||||
retranslateUi();
|
||||
}
|
||||
|
||||
void VisualDatabaseDisplayColorFilterWidget::retranslateUi()
|
||||
{
|
||||
switch (currentMode) {
|
||||
case FilterMode::ExactMatch:
|
||||
toggleButton->setText(tr("Mode: Exact Match"));
|
||||
break;
|
||||
case FilterMode::Includes:
|
||||
toggleButton->setText(tr("Mode: Includes"));
|
||||
break;
|
||||
case FilterMode::IncludeExclude:
|
||||
toggleButton->setText(tr("Mode: Include/Exclude"));
|
||||
break;
|
||||
}
|
||||
|
||||
toggleButton->setToolTip(tr("Filter mode (AND/OR/NOT conjunctions of filters)"));
|
||||
}
|
||||
|
||||
void VisualDatabaseDisplayColorFilterWidget::handleColorToggled(QChar color, bool active)
|
||||
{
|
||||
if (active) {
|
||||
addFilter(color);
|
||||
} else {
|
||||
removeFilter(color);
|
||||
}
|
||||
}
|
||||
|
||||
void VisualDatabaseDisplayColorFilterWidget::addFilter(QChar color)
|
||||
{
|
||||
QString colorString = color;
|
||||
QString typeStr;
|
||||
|
||||
// Remove previous filters
|
||||
|
||||
QList<const CardFilter *> allColorFilters = filterModel->getFiltersOfType(CardFilter::Attr::AttrColor);
|
||||
QList<const CardFilter *> matchingFilters;
|
||||
|
||||
for (const CardFilter *filter : allColorFilters) {
|
||||
if (filter->term() == color) {
|
||||
matchingFilters.append(filter);
|
||||
}
|
||||
}
|
||||
|
||||
for (const CardFilter *filter : matchingFilters) {
|
||||
filterModel->removeFilter(filter);
|
||||
}
|
||||
|
||||
// Add actual filter
|
||||
|
||||
switch (currentMode) {
|
||||
case FilterMode::ExactMatch:
|
||||
filterModel->addFilter(new CardFilter(colorString, CardFilter::Type::TypeAnd, CardFilter::Attr::AttrColor));
|
||||
break;
|
||||
|
||||
case FilterMode::Includes:
|
||||
filterModel->addFilter(new CardFilter(colorString, CardFilter::Type::TypeOr, CardFilter::Attr::AttrColor));
|
||||
break;
|
||||
|
||||
case FilterMode::IncludeExclude:
|
||||
filterModel->addFilter(new CardFilter(colorString, CardFilter::Type::TypeOr, CardFilter::Attr::AttrColor));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void VisualDatabaseDisplayColorFilterWidget::removeFilter(QChar color)
|
||||
{
|
||||
QString colorString = color;
|
||||
|
||||
// Remove inclusion filters
|
||||
QList<const CardFilter *> allColorFilters = filterModel->getFiltersOfType(CardFilter::Attr::AttrColor);
|
||||
QList<const CardFilter *> matchingFilters;
|
||||
|
||||
for (const CardFilter *filter : allColorFilters) {
|
||||
if (filter->term() == color) {
|
||||
matchingFilters.append(filter);
|
||||
}
|
||||
}
|
||||
|
||||
for (const CardFilter *filter : matchingFilters) {
|
||||
filterModel->removeFilter(filter);
|
||||
}
|
||||
|
||||
// Add exclusion filters if the mode demands it
|
||||
switch (currentMode) {
|
||||
case FilterMode::ExactMatch:
|
||||
filterModel->addFilter(
|
||||
new CardFilter(colorString, CardFilter::Type::TypeAndNot, CardFilter::Attr::AttrColor));
|
||||
break;
|
||||
|
||||
case FilterMode::IncludeExclude:
|
||||
filterModel->addFilter(
|
||||
new CardFilter(colorString, CardFilter::Type::TypeAndNot, CardFilter::Attr::AttrColor));
|
||||
break;
|
||||
|
||||
case FilterMode::Includes:
|
||||
// No exclusion in Includes mode
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void VisualDatabaseDisplayColorFilterWidget::updateFilterMode()
|
||||
{
|
||||
switch (currentMode) {
|
||||
case FilterMode::ExactMatch:
|
||||
currentMode = FilterMode::Includes; // Switch to Includes
|
||||
break;
|
||||
case FilterMode::Includes:
|
||||
currentMode = FilterMode::IncludeExclude; // Switch to Include/Exclude
|
||||
break;
|
||||
case FilterMode::IncludeExclude:
|
||||
currentMode = FilterMode::ExactMatch; // Switch to Exact Match
|
||||
break;
|
||||
}
|
||||
|
||||
filterModel->blockSignals(true);
|
||||
filterModel->filterTree()->blockSignals(true);
|
||||
|
||||
filterModel->clearFiltersOfType(CardFilter::Attr::AttrColor);
|
||||
|
||||
QList<ManaSymbolWidget *> manaSymbolWidgets = findChildren<ManaSymbolWidget *>();
|
||||
|
||||
for (ManaSymbolWidget *manaSymbolWidget : manaSymbolWidgets) {
|
||||
handleColorToggled(manaSymbolWidget->getSymbolChar(), manaSymbolWidget->isColorActive());
|
||||
}
|
||||
|
||||
filterModel->blockSignals(false);
|
||||
filterModel->filterTree()->blockSignals(false);
|
||||
|
||||
emit filterModel->filterTree()->changed();
|
||||
emit filterModel->layoutChanged();
|
||||
|
||||
retranslateUi(); // Update button text based on the mode
|
||||
emit filterModeChanged(currentMode); // Signal mode change
|
||||
}
|
||||
|
||||
void VisualDatabaseDisplayColorFilterWidget::setManaSymbolActive(QChar color, bool active)
|
||||
{
|
||||
QList<ManaSymbolWidget *> manaSymbolWidgets = findChildren<ManaSymbolWidget *>();
|
||||
|
||||
for (ManaSymbolWidget *manaSymbolWidget : manaSymbolWidgets) {
|
||||
if (manaSymbolWidget->getSymbolChar() == color) {
|
||||
manaSymbolWidget->setColorActive(active);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QList<QChar> VisualDatabaseDisplayColorFilterWidget::getActiveColors()
|
||||
{
|
||||
QList<QChar> activeColors;
|
||||
QList<ManaSymbolWidget *> manaSymbolWidgets = findChildren<ManaSymbolWidget *>();
|
||||
|
||||
for (ManaSymbolWidget *manaSymbolWidget : manaSymbolWidgets) {
|
||||
if (manaSymbolWidget->isColorActive()) {
|
||||
activeColors.append(manaSymbolWidget->getSymbolChar());
|
||||
}
|
||||
}
|
||||
|
||||
return activeColors;
|
||||
}
|
||||
|
||||
void VisualDatabaseDisplayColorFilterWidget::syncWithFilterModel()
|
||||
{
|
||||
QList<const CardFilter *> allColorFilters = filterModel->getFiltersOfType(CardFilter::Attr::AttrColor);
|
||||
|
||||
QList<ManaSymbolWidget *> manaSymbolWidgets = findChildren<ManaSymbolWidget *>();
|
||||
|
||||
for (ManaSymbolWidget *manaSymbolWidget : manaSymbolWidgets) {
|
||||
bool found = false;
|
||||
for (const CardFilter *filter : allColorFilters) {
|
||||
if (manaSymbolWidget->getSymbolChar() == filter->term()) {
|
||||
switch (currentMode) {
|
||||
case FilterMode::ExactMatch:
|
||||
switch (filter->type()) {
|
||||
case CardFilter::Type::TypeAnd:
|
||||
setManaSymbolActive(filter->term().at(0), true);
|
||||
break;
|
||||
default:
|
||||
setManaSymbolActive(filter->term().at(0), false);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case FilterMode::Includes:
|
||||
switch (filter->type()) {
|
||||
case CardFilter::Type::TypeOr:
|
||||
setManaSymbolActive(filter->term().at(0), true);
|
||||
break;
|
||||
default:
|
||||
setManaSymbolActive(filter->term().at(0), false);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case FilterMode::IncludeExclude:
|
||||
switch (filter->type()) {
|
||||
case CardFilter::Type::TypeOr:
|
||||
setManaSymbolActive(filter->term().at(0), true);
|
||||
break;
|
||||
default:
|
||||
setManaSymbolActive(filter->term().at(0), false);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
setManaSymbolActive(manaSymbolWidget->getSymbolChar(), false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
#ifndef VISUAL_DATABASE_DISPLAY_COLOR_FILTER_WIDGET_H
|
||||
#define VISUAL_DATABASE_DISPLAY_COLOR_FILTER_WIDGET_H
|
||||
|
||||
#include "../../../filters/filter_tree_model.h"
|
||||
|
||||
#include <QHBoxLayout>
|
||||
#include <QPushButton>
|
||||
#include <QWidget>
|
||||
|
||||
class VisualDatabaseDisplayColorFilterCircleWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit VisualDatabaseDisplayColorFilterCircleWidget(QChar color, QWidget *parent = nullptr);
|
||||
void setColorActive(bool active);
|
||||
bool isColorActive() const;
|
||||
QChar getColorChar() const;
|
||||
|
||||
signals:
|
||||
void colorToggled(QChar color, bool active);
|
||||
|
||||
private:
|
||||
QChar colorChar;
|
||||
bool isActive;
|
||||
int circleDiameter;
|
||||
};
|
||||
|
||||
enum class FilterMode
|
||||
{
|
||||
ExactMatch, // Only selected colors are included, all others are excluded.
|
||||
Includes, // Include selected colors (OR condition).
|
||||
IncludeExclude // Include selected colors (OR) and exclude unselected colors (AND NOT).
|
||||
};
|
||||
|
||||
class VisualDatabaseDisplayColorFilterWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit VisualDatabaseDisplayColorFilterWidget(QWidget *parent, FilterTreeModel *filterModel);
|
||||
void retranslateUi();
|
||||
|
||||
signals:
|
||||
void filterModeChanged(FilterMode filterMode);
|
||||
|
||||
private slots:
|
||||
void handleColorToggled(QChar color, bool active);
|
||||
void addFilter(QChar color);
|
||||
void removeFilter(QChar color);
|
||||
void updateFilterMode();
|
||||
void setManaSymbolActive(QChar color, bool active);
|
||||
QList<QChar> getActiveColors();
|
||||
void syncWithFilterModel();
|
||||
|
||||
private:
|
||||
FilterTreeModel *filterModel;
|
||||
QHBoxLayout *layout;
|
||||
QPushButton *toggleButton;
|
||||
FilterMode currentMode = FilterMode::Includes; // Default mode
|
||||
};
|
||||
|
||||
#endif // VISUAL_DATABASE_DISPLAY_COLOR_FILTER_WIDGET_H
|
||||
|
|
@ -0,0 +1,154 @@
|
|||
#include "visual_database_display_filter_save_load_widget.h"
|
||||
|
||||
#include "../../../filters/filter_tree.h"
|
||||
#include "../../../settings/cache_settings.h"
|
||||
#include "visual_database_filter_display_widget.h"
|
||||
|
||||
#include <QHBoxLayout>
|
||||
#include <QJsonArray>
|
||||
#include <QJsonObject>
|
||||
#include <QMessageBox>
|
||||
|
||||
VisualDatabaseDisplayFilterSaveLoadWidget::VisualDatabaseDisplayFilterSaveLoadWidget(QWidget *parent,
|
||||
FilterTreeModel *_filterModel)
|
||||
: QWidget(parent), filterModel(_filterModel)
|
||||
{
|
||||
setMinimumWidth(300);
|
||||
setMaximumHeight(300);
|
||||
|
||||
layout = new QVBoxLayout(this);
|
||||
setLayout(layout);
|
||||
|
||||
// Input for filter filename
|
||||
filenameInput = new QLineEdit(this);
|
||||
layout->addWidget(filenameInput);
|
||||
|
||||
// Save button
|
||||
saveButton = new QPushButton(this);
|
||||
layout->addWidget(saveButton);
|
||||
connect(saveButton, &QPushButton::clicked, this, &VisualDatabaseDisplayFilterSaveLoadWidget::saveFilter);
|
||||
|
||||
// File list container
|
||||
fileListWidget = new FlowWidget(this, Qt::Horizontal, Qt::ScrollBarAlwaysOff, Qt::ScrollBarAsNeeded);
|
||||
layout->addWidget(fileListWidget);
|
||||
|
||||
refreshFilterList(); // Populate the file list on startup
|
||||
retranslateUi();
|
||||
}
|
||||
|
||||
void VisualDatabaseDisplayFilterSaveLoadWidget::retranslateUi()
|
||||
{
|
||||
saveButton->setText(tr("Save Filter"));
|
||||
saveButton->setToolTip(tr("Save all currently applied filters to a file"));
|
||||
filenameInput->setPlaceholderText(tr("Enter filename..."));
|
||||
}
|
||||
|
||||
void VisualDatabaseDisplayFilterSaveLoadWidget::saveFilter()
|
||||
{
|
||||
QString filename = filenameInput->text().trimmed();
|
||||
if (filename.isEmpty())
|
||||
return;
|
||||
|
||||
QString filePath = SettingsCache::instance().getFiltersPath() + QDir::separator() + filename + ".json";
|
||||
|
||||
// Serialize the filter model to JSON
|
||||
QJsonArray filtersArray;
|
||||
QList<const CardFilter *> cardFilters = filterModel->allFilters();
|
||||
|
||||
for (const CardFilter *filter : cardFilters) {
|
||||
filtersArray.append(filter->toJson());
|
||||
}
|
||||
|
||||
QJsonObject root;
|
||||
root["filters"] = filtersArray;
|
||||
|
||||
QFile file(filePath);
|
||||
if (file.open(QIODevice::WriteOnly)) {
|
||||
file.write(QJsonDocument(root).toJson(QJsonDocument::Indented));
|
||||
file.close();
|
||||
}
|
||||
|
||||
filenameInput->clear();
|
||||
refreshFilterList(); // Update the file list
|
||||
}
|
||||
|
||||
void VisualDatabaseDisplayFilterSaveLoadWidget::loadFilter(const QString &filename)
|
||||
{
|
||||
QString filePath = SettingsCache::instance().getFiltersPath() + QDir::separator() + filename;
|
||||
|
||||
QFile file(filePath);
|
||||
if (!file.open(QIODevice::ReadOnly))
|
||||
return;
|
||||
|
||||
QByteArray jsonData = file.readAll();
|
||||
file.close();
|
||||
|
||||
QJsonDocument doc = QJsonDocument::fromJson(jsonData);
|
||||
if (!doc.isObject())
|
||||
return;
|
||||
|
||||
QJsonObject root = doc.object();
|
||||
if (!root.contains("filters") || !root["filters"].isArray())
|
||||
return;
|
||||
|
||||
QJsonArray filtersArray = root["filters"].toArray();
|
||||
|
||||
filterModel->clear();
|
||||
|
||||
filterModel->blockSignals(true);
|
||||
filterModel->filterTree()->blockSignals(true);
|
||||
for (const QJsonValue &value : filtersArray) {
|
||||
if (value.isObject()) {
|
||||
QJsonObject filterObj = value.toObject();
|
||||
CardFilter *filter = CardFilter::fromJson(filterObj);
|
||||
if (filter) {
|
||||
filterModel->addFilter(filter);
|
||||
}
|
||||
}
|
||||
}
|
||||
filterModel->blockSignals(false);
|
||||
filterModel->filterTree()->blockSignals(false);
|
||||
|
||||
emit filterModel->filterTree()->changed();
|
||||
emit filterModel->layoutChanged();
|
||||
}
|
||||
|
||||
void VisualDatabaseDisplayFilterSaveLoadWidget::refreshFilterList()
|
||||
{
|
||||
fileListWidget->clearLayout();
|
||||
// Clear existing widgets
|
||||
for (auto buttonPair : fileButtons) {
|
||||
buttonPair.first->deleteLater();
|
||||
buttonPair.second->deleteLater();
|
||||
}
|
||||
fileButtons.clear(); // Clear the list of buttons
|
||||
|
||||
// Refresh the filter file list
|
||||
QDir dir(SettingsCache::instance().getFiltersPath());
|
||||
QStringList filterFiles = dir.entryList(QStringList() << "*.json", QDir::Files, QDir::Name);
|
||||
|
||||
// Loop through the filter files and create widgets for them
|
||||
for (const QString &filename : filterFiles) {
|
||||
bool alreadyAdded = false;
|
||||
|
||||
// Check if the widget for this filter file already exists to avoid duplicates
|
||||
for (const auto &pair : fileButtons) {
|
||||
if (pair.first->text() == filename) {
|
||||
alreadyAdded = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!alreadyAdded) {
|
||||
// Create a new custom widget for the filter
|
||||
FilterDisplayWidget *filterWidget = new FilterDisplayWidget(this, filename, filterModel);
|
||||
fileListWidget->addWidget(filterWidget);
|
||||
|
||||
// Connect signals to handle loading and deletion
|
||||
connect(filterWidget, &FilterDisplayWidget::filterLoadRequested, this,
|
||||
&VisualDatabaseDisplayFilterSaveLoadWidget::loadFilter);
|
||||
connect(filterWidget, &FilterDisplayWidget::filterDeleted, this,
|
||||
&VisualDatabaseDisplayFilterSaveLoadWidget::refreshFilterList);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
#ifndef VISUAL_DATABASE_DISPLAY_FILTER_SAVE_LOAD_WIDGET_H
|
||||
#define VISUAL_DATABASE_DISPLAY_FILTER_SAVE_LOAD_WIDGET_H
|
||||
|
||||
#include "../../../filters/filter_tree_model.h"
|
||||
#include "../general/layout_containers/flow_widget.h"
|
||||
|
||||
#include <QDir>
|
||||
#include <QFile>
|
||||
#include <QFileDialog>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QLineEdit>
|
||||
#include <QMap>
|
||||
#include <QPushButton>
|
||||
#include <QVBoxLayout>
|
||||
#include <QWidget>
|
||||
|
||||
class VisualDatabaseDisplayFilterSaveLoadWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit VisualDatabaseDisplayFilterSaveLoadWidget(QWidget *parent, FilterTreeModel *filterModel);
|
||||
|
||||
void saveFilter();
|
||||
void loadFilter(const QString &filename);
|
||||
void refreshFilterList();
|
||||
void deleteFilter(const QString &filename, QPushButton *deleteButton);
|
||||
|
||||
public slots:
|
||||
void retranslateUi();
|
||||
|
||||
private:
|
||||
FilterTreeModel *filterModel;
|
||||
|
||||
QVBoxLayout *layout;
|
||||
QLineEdit *filenameInput;
|
||||
QPushButton *saveButton;
|
||||
FlowWidget *fileListWidget;
|
||||
|
||||
QMap<QString, QPair<QPushButton *, QPushButton *>> fileButtons;
|
||||
};
|
||||
|
||||
#endif // VISUAL_DATABASE_DISPLAY_FILTER_SAVE_LOAD_WIDGET_H
|
||||
|
|
@ -0,0 +1,204 @@
|
|||
#include "visual_database_display_main_type_filter_widget.h"
|
||||
|
||||
#include "../../../database/card_database_manager.h"
|
||||
#include "../../../filters/filter_tree.h"
|
||||
#include "../../../filters/filter_tree_model.h"
|
||||
|
||||
#include <QPushButton>
|
||||
#include <QSpinBox>
|
||||
#include <QTimer>
|
||||
|
||||
VisualDatabaseDisplayMainTypeFilterWidget::VisualDatabaseDisplayMainTypeFilterWidget(QWidget *parent,
|
||||
FilterTreeModel *_filterModel)
|
||||
: QWidget(parent), filterModel(_filterModel)
|
||||
{
|
||||
allMainCardTypesWithCount = CardDatabaseManager::getInstance()->getAllMainCardTypesWithCount();
|
||||
// Get all main card types with their count
|
||||
|
||||
setMaximumHeight(75);
|
||||
setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Minimum);
|
||||
|
||||
layout = new QHBoxLayout(this);
|
||||
setLayout(layout);
|
||||
layout->setContentsMargins(0, 1, 0, 1);
|
||||
layout->setSpacing(1);
|
||||
layout->setAlignment(Qt::AlignTop);
|
||||
|
||||
flowWidget = new FlowWidget(this, Qt::Horizontal, Qt::ScrollBarAlwaysOff, Qt::ScrollBarAsNeeded);
|
||||
layout->addWidget(flowWidget);
|
||||
|
||||
// Create the spinbox
|
||||
spinBox = new QSpinBox(this);
|
||||
spinBox->setMinimum(1);
|
||||
spinBox->setMaximum(getMaxMainTypeCount()); // Set the max value dynamically
|
||||
spinBox->setValue(150);
|
||||
layout->addWidget(spinBox);
|
||||
connect(spinBox, QOverload<int>::of(&QSpinBox::valueChanged), this,
|
||||
&VisualDatabaseDisplayMainTypeFilterWidget::updateMainTypeButtonsVisibility);
|
||||
|
||||
// Create the toggle button for Exact Match/Includes mode
|
||||
toggleButton = new QPushButton(this);
|
||||
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
|
||||
|
||||
retranslateUi();
|
||||
}
|
||||
|
||||
void VisualDatabaseDisplayMainTypeFilterWidget::retranslateUi()
|
||||
{
|
||||
spinBox->setToolTip(tr("Do not display card main-types with less than this amount of cards in the database"));
|
||||
toggleButton->setToolTip(tr("Filter mode (AND/OR/NOT conjunctions of filters)"));
|
||||
}
|
||||
|
||||
void VisualDatabaseDisplayMainTypeFilterWidget::createMainTypeButtons()
|
||||
{
|
||||
// Iterate through main types and create buttons
|
||||
for (auto it = allMainCardTypesWithCount.begin(); it != allMainCardTypesWithCount.end(); ++it) {
|
||||
auto *button = new QPushButton(it.key(), flowWidget);
|
||||
button->setCheckable(true);
|
||||
button->setStyleSheet("QPushButton { background-color: lightgray; border: 1px solid gray; padding: 5px; }"
|
||||
"QPushButton:checked { background-color: green; color: white; }");
|
||||
|
||||
flowWidget->addWidget(button);
|
||||
typeButtons[it.key()] = button;
|
||||
|
||||
// Connect toggle signal
|
||||
connect(button, &QPushButton::toggled, this,
|
||||
[this, mainType = it.key()](bool checked) { handleMainTypeToggled(mainType, checked); });
|
||||
}
|
||||
updateMainTypeButtonsVisibility(); // Ensure visibility is updated initially
|
||||
}
|
||||
|
||||
void VisualDatabaseDisplayMainTypeFilterWidget::updateMainTypeButtonsVisibility()
|
||||
{
|
||||
int threshold = spinBox->value(); // Get the current spinbox value
|
||||
|
||||
// Iterate through buttons and hide/disable those below the threshold
|
||||
for (auto it = typeButtons.begin(); it != typeButtons.end(); ++it) {
|
||||
bool visible = allMainCardTypesWithCount[it.key()] >= threshold;
|
||||
it.value()->setVisible(visible);
|
||||
it.value()->setEnabled(visible);
|
||||
}
|
||||
}
|
||||
|
||||
int VisualDatabaseDisplayMainTypeFilterWidget::getMaxMainTypeCount() const
|
||||
{
|
||||
int maxCount = 1;
|
||||
for (auto it = allMainCardTypesWithCount.begin(); it != allMainCardTypesWithCount.end(); ++it) {
|
||||
maxCount = qMax(maxCount, it.value());
|
||||
}
|
||||
return maxCount;
|
||||
}
|
||||
|
||||
void VisualDatabaseDisplayMainTypeFilterWidget::handleMainTypeToggled(const QString &mainType, bool active)
|
||||
{
|
||||
activeMainTypes[mainType] = active;
|
||||
|
||||
if (typeButtons.contains(mainType)) {
|
||||
typeButtons[mainType]->setChecked(active);
|
||||
}
|
||||
|
||||
updateMainTypeFilter();
|
||||
}
|
||||
|
||||
void VisualDatabaseDisplayMainTypeFilterWidget::updateMainTypeFilter()
|
||||
{
|
||||
// Clear existing filters related to main type
|
||||
filterModel->blockSignals(true);
|
||||
filterModel->filterTree()->blockSignals(true);
|
||||
filterModel->clearFiltersOfType(CardFilter::Attr::AttrMainType);
|
||||
|
||||
if (exactMatchMode) {
|
||||
// Exact Match: Only selected main types are allowed
|
||||
QSet<QString> selectedTypes;
|
||||
for (const auto &type : activeMainTypes.keys()) {
|
||||
if (activeMainTypes[type]) {
|
||||
selectedTypes.insert(type);
|
||||
}
|
||||
}
|
||||
|
||||
if (!selectedTypes.isEmpty()) {
|
||||
// Require all selected types (TypeAnd)
|
||||
for (const auto &type : selectedTypes) {
|
||||
QString typeString = type;
|
||||
filterModel->addFilter(
|
||||
new CardFilter(typeString, CardFilter::Type::TypeAnd, CardFilter::Attr::AttrMainType));
|
||||
}
|
||||
|
||||
// Exclude any other types (TypeAndNot)
|
||||
for (const auto &type : typeButtons.keys()) {
|
||||
if (!selectedTypes.contains(type)) {
|
||||
QString typeString = type;
|
||||
filterModel->addFilter(
|
||||
new CardFilter(typeString, CardFilter::Type::TypeAndNot, CardFilter::Attr::AttrMainType));
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Default Includes Mode (TypeOr) - match any selected main types
|
||||
for (const auto &type : activeMainTypes.keys()) {
|
||||
if (activeMainTypes[type]) {
|
||||
QString typeString = type;
|
||||
filterModel->addFilter(
|
||||
new CardFilter(typeString, CardFilter::Type::TypeAnd, CardFilter::Attr::AttrMainType));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
filterModel->blockSignals(false);
|
||||
filterModel->filterTree()->blockSignals(false);
|
||||
|
||||
emit filterModel->filterTree()->changed();
|
||||
emit filterModel->layoutChanged();
|
||||
}
|
||||
|
||||
void VisualDatabaseDisplayMainTypeFilterWidget::updateFilterMode(bool checked)
|
||||
{
|
||||
exactMatchMode = 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<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();
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
#ifndef VISUAL_DATABASE_DISPLAY_MAIN_TYPE_FILTER_WIDGET_H
|
||||
#define VISUAL_DATABASE_DISPLAY_MAIN_TYPE_FILTER_WIDGET_H
|
||||
|
||||
#include "../../../filters/filter_tree_model.h"
|
||||
#include "../general/layout_containers/flow_widget.h"
|
||||
|
||||
#include <QMap>
|
||||
#include <QPushButton>
|
||||
#include <QSpinBox>
|
||||
#include <QToolButton>
|
||||
#include <QVBoxLayout>
|
||||
#include <QWidget>
|
||||
|
||||
class VisualDatabaseDisplayMainTypeFilterWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit VisualDatabaseDisplayMainTypeFilterWidget(QWidget *parent, FilterTreeModel *filterModel);
|
||||
void retranslateUi();
|
||||
void createMainTypeButtons();
|
||||
void updateMainTypeButtonsVisibility();
|
||||
int getMaxMainTypeCount() const;
|
||||
|
||||
void handleMainTypeToggled(const QString &mainType, bool active);
|
||||
void updateMainTypeFilter();
|
||||
void updateFilterMode(bool checked);
|
||||
void syncWithFilterModel();
|
||||
|
||||
private:
|
||||
FilterTreeModel *filterModel;
|
||||
QMap<QString, int> allMainCardTypesWithCount;
|
||||
QSpinBox *spinBox;
|
||||
QHBoxLayout *layout;
|
||||
FlowWidget *flowWidget;
|
||||
QPushButton *toggleButton; // Mode switch button
|
||||
|
||||
QMap<QString, bool> activeMainTypes; // Track active filters
|
||||
QMap<QString, QPushButton *> typeButtons; // Store toggle buttons
|
||||
|
||||
bool exactMatchMode = false; // Toggle between "Exact Match" and "Includes"
|
||||
};
|
||||
|
||||
#endif // VISUAL_DATABASE_DISPLAY_MAIN_TYPE_FILTER_WIDGET_H
|
||||
|
|
@ -0,0 +1,186 @@
|
|||
#include "visual_database_display_name_filter_widget.h"
|
||||
|
||||
#include "../../../dialogs/dlg_load_deck_from_clipboard.h"
|
||||
#include "../../../tabs/abstract_tab_deck_editor.h"
|
||||
|
||||
#include <QHBoxLayout>
|
||||
|
||||
VisualDatabaseDisplayNameFilterWidget::VisualDatabaseDisplayNameFilterWidget(QWidget *parent,
|
||||
AbstractTabDeckEditor *_deckEditor,
|
||||
FilterTreeModel *_filterModel)
|
||||
: QWidget(parent), deckEditor(_deckEditor), filterModel(_filterModel)
|
||||
{
|
||||
setMinimumWidth(300);
|
||||
setMaximumHeight(300);
|
||||
|
||||
layout = new QVBoxLayout(this);
|
||||
setLayout(layout);
|
||||
|
||||
searchBox = new QLineEdit(this);
|
||||
layout->addWidget(searchBox);
|
||||
|
||||
connect(searchBox, &QLineEdit::returnPressed, this, [this]() {
|
||||
QString text = searchBox->text().trimmed();
|
||||
if (!text.isEmpty() && !activeFilters.contains(text)) {
|
||||
createNameFilter(text);
|
||||
searchBox->clear();
|
||||
updateFilterModel();
|
||||
}
|
||||
});
|
||||
|
||||
// Create container for active filters
|
||||
flowWidget = new FlowWidget(this, Qt::Horizontal, Qt::ScrollBarAlwaysOff, Qt::ScrollBarAsNeeded);
|
||||
layout->addWidget(flowWidget);
|
||||
|
||||
loadFromDeckButton = new QPushButton(this);
|
||||
layout->addWidget(loadFromDeckButton);
|
||||
|
||||
connect(loadFromDeckButton, &QPushButton::clicked, this, &VisualDatabaseDisplayNameFilterWidget::actLoadFromDeck);
|
||||
|
||||
loadFromClipboardButton = new QPushButton(this);
|
||||
layout->addWidget(loadFromClipboardButton);
|
||||
|
||||
connect(loadFromClipboardButton, &QPushButton::clicked, this,
|
||||
&VisualDatabaseDisplayNameFilterWidget::actLoadFromClipboard);
|
||||
|
||||
connect(filterModel, &FilterTreeModel::layoutChanged, this,
|
||||
[this]() { QTimer::singleShot(100, this, &VisualDatabaseDisplayNameFilterWidget::syncWithFilterModel); });
|
||||
|
||||
retranslateUi();
|
||||
}
|
||||
|
||||
void VisualDatabaseDisplayNameFilterWidget::retranslateUi()
|
||||
{
|
||||
searchBox->setPlaceholderText(tr("Filter by name..."));
|
||||
loadFromDeckButton->setText(tr("Load from Deck"));
|
||||
loadFromDeckButton->setToolTip(tr("Apply all card names in currently loaded deck as exact match name filters"));
|
||||
loadFromClipboardButton->setText(tr("Load from Clipboard"));
|
||||
loadFromClipboardButton->setToolTip(tr("Apply all card names in clipboard as exact match name filters"));
|
||||
}
|
||||
|
||||
void VisualDatabaseDisplayNameFilterWidget::actLoadFromDeck()
|
||||
{
|
||||
DeckListModel *deckListModel = deckEditor->deckDockWidget->deckModel;
|
||||
|
||||
if (!deckListModel)
|
||||
return;
|
||||
DeckList *decklist = deckListModel->getDeckList();
|
||||
if (!decklist)
|
||||
return;
|
||||
InnerDecklistNode *listRoot = decklist->getRoot();
|
||||
if (!listRoot)
|
||||
return;
|
||||
|
||||
for (int i = 0; i < listRoot->size(); i++) {
|
||||
InnerDecklistNode *currentZone = dynamic_cast<InnerDecklistNode *>(listRoot->at(i));
|
||||
if (!currentZone)
|
||||
continue;
|
||||
for (int j = 0; j < currentZone->size(); j++) {
|
||||
DecklistCardNode *currentCard = dynamic_cast<DecklistCardNode *>(currentZone->at(j));
|
||||
if (!currentCard)
|
||||
continue;
|
||||
createNameFilter(currentCard->getName());
|
||||
}
|
||||
}
|
||||
updateFilterModel();
|
||||
}
|
||||
|
||||
void VisualDatabaseDisplayNameFilterWidget::actLoadFromClipboard()
|
||||
{
|
||||
DlgLoadDeckFromClipboard dlg(this);
|
||||
if (!dlg.exec())
|
||||
return;
|
||||
|
||||
QStringList cardsInClipboard = dlg.getDeckList()->getCardList();
|
||||
for (QString cardName : cardsInClipboard) {
|
||||
createNameFilter(cardName);
|
||||
}
|
||||
|
||||
updateFilterModel();
|
||||
}
|
||||
|
||||
void VisualDatabaseDisplayNameFilterWidget::createNameFilter(const QString &name)
|
||||
{
|
||||
if (activeFilters.contains(name))
|
||||
return;
|
||||
|
||||
// Create a button for the filter
|
||||
auto *button = new QPushButton(name, flowWidget);
|
||||
button->setStyleSheet("QPushButton { background-color: lightgray; border: 1px solid gray; padding: 5px; }"
|
||||
"QPushButton:hover { background-color: red; color: white; }");
|
||||
|
||||
connect(button, &QPushButton::clicked, this, [this, name]() {
|
||||
removeNameFilter(name);
|
||||
QTimer::singleShot(0, this,
|
||||
&VisualDatabaseDisplayNameFilterWidget::updateFilterModel); // Avoid concurrent modification
|
||||
});
|
||||
|
||||
flowWidget->addWidget(button);
|
||||
activeFilters[name] = button;
|
||||
}
|
||||
|
||||
void VisualDatabaseDisplayNameFilterWidget::removeNameFilter(const QString &name)
|
||||
{
|
||||
if (activeFilters.contains(name)) {
|
||||
activeFilters[name]->deleteLater(); // Safe deletion
|
||||
activeFilters.remove(name);
|
||||
}
|
||||
}
|
||||
|
||||
void VisualDatabaseDisplayNameFilterWidget::updateFilterModel()
|
||||
{
|
||||
// Clear existing name filters
|
||||
emit filterModel->layoutAboutToBeChanged();
|
||||
filterModel->clearFiltersOfType(CardFilter::Attr::AttrName);
|
||||
|
||||
filterModel->blockSignals(true);
|
||||
filterModel->filterTree()->blockSignals(true);
|
||||
|
||||
for (const auto &name : activeFilters.keys()) {
|
||||
QString nameString = name;
|
||||
filterModel->addFilter(new CardFilter(nameString, CardFilter::Type::TypeOr, CardFilter::Attr::AttrName));
|
||||
}
|
||||
|
||||
filterModel->blockSignals(false);
|
||||
filterModel->filterTree()->blockSignals(false);
|
||||
|
||||
filterModel->blockSignals(false);
|
||||
filterModel->filterTree()->blockSignals(false);
|
||||
|
||||
emit filterModel->filterTree()->changed();
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
#ifndef VISUAL_DATABASE_DISPLAY_NAME_FILTER_WIDGET_H
|
||||
#define VISUAL_DATABASE_DISPLAY_NAME_FILTER_WIDGET_H
|
||||
|
||||
#include "../../../filters/filter_tree_model.h"
|
||||
#include "../../../tabs/abstract_tab_deck_editor.h"
|
||||
#include "../general/layout_containers/flow_widget.h"
|
||||
|
||||
#include <QLineEdit>
|
||||
#include <QMap>
|
||||
#include <QPushButton>
|
||||
#include <QVBoxLayout>
|
||||
#include <QWidget>
|
||||
|
||||
class VisualDatabaseDisplayNameFilterWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit VisualDatabaseDisplayNameFilterWidget(QWidget *parent,
|
||||
AbstractTabDeckEditor *deckEditor,
|
||||
FilterTreeModel *filterModel);
|
||||
|
||||
void createNameFilter(const QString &name);
|
||||
void removeNameFilter(const QString &name);
|
||||
void updateFilterList();
|
||||
void updateFilterModel();
|
||||
void syncWithFilterModel();
|
||||
|
||||
public slots:
|
||||
void retranslateUi();
|
||||
|
||||
private:
|
||||
AbstractTabDeckEditor *deckEditor;
|
||||
FilterTreeModel *filterModel;
|
||||
QVBoxLayout *layout;
|
||||
QLineEdit *searchBox;
|
||||
FlowWidget *flowWidget;
|
||||
QPushButton *loadFromDeckButton;
|
||||
QPushButton *loadFromClipboardButton;
|
||||
|
||||
QMap<QString, QPushButton *> activeFilters; // Store active name filter buttons
|
||||
|
||||
private slots:
|
||||
void actLoadFromDeck();
|
||||
void actLoadFromClipboard();
|
||||
};
|
||||
|
||||
#endif // VISUAL_DATABASE_DISPLAY_NAME_FILTER_WIDGET_H
|
||||
|
|
@ -0,0 +1,272 @@
|
|||
#include "visual_database_display_set_filter_widget.h"
|
||||
|
||||
#include "../../../database/card_database_manager.h"
|
||||
#include "../../../filters/filter_tree.h"
|
||||
#include "../../../filters/filter_tree_model.h"
|
||||
#include "../../../settings/cache_settings.h"
|
||||
|
||||
#include <QLineEdit>
|
||||
#include <QPushButton>
|
||||
#include <QTimer>
|
||||
#include <algorithm>
|
||||
|
||||
VisualDatabaseDisplayRecentSetFilterSettingsWidget::VisualDatabaseDisplayRecentSetFilterSettingsWidget(QWidget *parent)
|
||||
: QWidget(parent)
|
||||
{
|
||||
layout = new QHBoxLayout(this);
|
||||
setLayout(layout);
|
||||
|
||||
filterToMostRecentSetsCheckBox = new QCheckBox(this);
|
||||
filterToMostRecentSetsCheckBox->setChecked(
|
||||
SettingsCache::instance().getVisualDatabaseDisplayFilterToMostRecentSetsEnabled());
|
||||
connect(filterToMostRecentSetsCheckBox, &QCheckBox::QT_STATE_CHANGED, &SettingsCache::instance(),
|
||||
&SettingsCache::setVisualDatabaseDisplayFilterToMostRecentSetsEnabled);
|
||||
|
||||
filterToMostRecentSetsAmount = new QSpinBox(this);
|
||||
filterToMostRecentSetsAmount->setMinimum(1);
|
||||
filterToMostRecentSetsAmount->setMaximum(100);
|
||||
filterToMostRecentSetsAmount->setValue(
|
||||
SettingsCache::instance().getVisualDatabaseDisplayFilterToMostRecentSetsAmount());
|
||||
connect(filterToMostRecentSetsAmount, QOverload<int>::of(&QSpinBox::valueChanged), &SettingsCache::instance(),
|
||||
&SettingsCache::setVisualDatabaseDisplayFilterToMostRecentSetsAmount);
|
||||
|
||||
layout->addWidget(filterToMostRecentSetsCheckBox);
|
||||
layout->addWidget(filterToMostRecentSetsAmount);
|
||||
|
||||
retranslateUi();
|
||||
}
|
||||
|
||||
void VisualDatabaseDisplayRecentSetFilterSettingsWidget::retranslateUi()
|
||||
{
|
||||
filterToMostRecentSetsCheckBox->setText(tr("Filter to most recent sets"));
|
||||
}
|
||||
|
||||
VisualDatabaseDisplaySetFilterWidget::VisualDatabaseDisplaySetFilterWidget(QWidget *parent,
|
||||
FilterTreeModel *_filterModel)
|
||||
: QWidget(parent), filterModel(_filterModel)
|
||||
{
|
||||
setMinimumWidth(300);
|
||||
setMaximumHeight(300);
|
||||
|
||||
layout = new QVBoxLayout(this);
|
||||
setLayout(layout);
|
||||
|
||||
recentSetsSettingsWidget = new VisualDatabaseDisplayRecentSetFilterSettingsWidget(this);
|
||||
layout->addWidget(recentSetsSettingsWidget);
|
||||
|
||||
connect(&SettingsCache::instance(), &SettingsCache::visualDatabaseDisplayFilterToMostRecentSetsEnabledChanged, this,
|
||||
&VisualDatabaseDisplaySetFilterWidget::filterToRecentSets);
|
||||
connect(&SettingsCache::instance(), &SettingsCache::visualDatabaseDisplayFilterToMostRecentSetsAmountChanged, this,
|
||||
&VisualDatabaseDisplaySetFilterWidget::filterToRecentSets);
|
||||
|
||||
searchBox = new QLineEdit(this);
|
||||
searchBox->setPlaceholderText(tr("Search sets..."));
|
||||
layout->addWidget(searchBox);
|
||||
connect(searchBox, &QLineEdit::textChanged, this,
|
||||
&VisualDatabaseDisplaySetFilterWidget::updateSetButtonsVisibility);
|
||||
|
||||
flowWidget = new FlowWidget(this, Qt::Horizontal, Qt::ScrollBarAlwaysOff, Qt::ScrollBarAsNeeded);
|
||||
layout->addWidget(flowWidget);
|
||||
|
||||
// Create the toggle button for Exact Match/Includes mode
|
||||
toggleButton = new QPushButton(this);
|
||||
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
|
||||
retranslateUi();
|
||||
}
|
||||
|
||||
void VisualDatabaseDisplaySetFilterWidget::retranslateUi()
|
||||
{
|
||||
toggleButton->setText(exactMatchMode ? tr("Mode: Exact Match") : tr("Mode: Includes"));
|
||||
}
|
||||
|
||||
void VisualDatabaseDisplaySetFilterWidget::createSetButtons()
|
||||
{
|
||||
SetList allSets = CardDatabaseManager::getInstance()->getSetList();
|
||||
|
||||
// Sort by release date
|
||||
std::sort(allSets.begin(), allSets.end(),
|
||||
[](const auto &a, const auto &b) { return a->getReleaseDate() > b->getReleaseDate(); });
|
||||
|
||||
for (const auto &set : allSets) {
|
||||
QString shortName = set->getShortName();
|
||||
QString longName = set->getLongName();
|
||||
|
||||
auto *button = new QPushButton(longName + " (" + shortName + ")", flowWidget);
|
||||
button->setCheckable(true);
|
||||
button->setStyleSheet("QPushButton { background-color: lightgray; border: 1px solid gray; padding: 5px; }"
|
||||
"QPushButton:checked { background-color: green; color: white; }");
|
||||
|
||||
flowWidget->addWidget(button);
|
||||
setButtons[shortName] = button;
|
||||
|
||||
// Connect toggle signal
|
||||
connect(button, &QPushButton::toggled, this,
|
||||
[this, shortName](bool checked) { handleSetToggled(shortName, checked); });
|
||||
}
|
||||
|
||||
filterToRecentSets();
|
||||
}
|
||||
|
||||
void VisualDatabaseDisplaySetFilterWidget::filterToRecentSets()
|
||||
{
|
||||
if (SettingsCache::instance().getVisualDatabaseDisplayFilterToMostRecentSetsEnabled()) {
|
||||
for (auto set : activeSets.keys()) {
|
||||
activeSets[set] = false;
|
||||
}
|
||||
|
||||
SetList allSets = CardDatabaseManager::getInstance()->getSetList();
|
||||
|
||||
// Sort by release date
|
||||
std::sort(allSets.begin(), allSets.end(),
|
||||
[](const auto &a, const auto &b) { return a->getReleaseDate() > b->getReleaseDate(); });
|
||||
|
||||
int setsToPreactivate = SettingsCache::instance().getVisualDatabaseDisplayFilterToMostRecentSetsAmount();
|
||||
int setsActivated = 0;
|
||||
|
||||
for (const auto &set : allSets) {
|
||||
QString shortName = set->getShortName();
|
||||
QString longName = set->getLongName();
|
||||
|
||||
auto button = setButtons[shortName];
|
||||
|
||||
if (setsActivated < setsToPreactivate) {
|
||||
setsActivated++;
|
||||
activeSets[shortName] = true;
|
||||
button->blockSignals(true);
|
||||
button->setChecked(true);
|
||||
button->blockSignals(false);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
updateSetFilter();
|
||||
updateSetButtonsVisibility();
|
||||
}
|
||||
}
|
||||
|
||||
void VisualDatabaseDisplaySetFilterWidget::updateSetButtonsVisibility()
|
||||
{
|
||||
QString filterText = searchBox->text().trimmed().toLower();
|
||||
|
||||
for (const QString &setName : setButtons.keys()) {
|
||||
QPushButton *buttonForSet = setButtons[setName];
|
||||
QString shortName = setName.toLower();
|
||||
QString longName = buttonForSet->text().toLower();
|
||||
bool alwaysVisible = activeSets.contains(setName) && activeSets[setName];
|
||||
bool visible =
|
||||
alwaysVisible || filterText.isEmpty() || shortName.contains(filterText) || longName.contains(filterText);
|
||||
buttonForSet->setVisible(visible);
|
||||
}
|
||||
}
|
||||
|
||||
void VisualDatabaseDisplaySetFilterWidget::handleSetToggled(const QString &setShortName, bool active)
|
||||
{
|
||||
activeSets[setShortName] = active;
|
||||
|
||||
if (setButtons.contains(setShortName)) {
|
||||
setButtons[setShortName]->setChecked(active);
|
||||
}
|
||||
|
||||
updateSetFilter();
|
||||
}
|
||||
|
||||
void VisualDatabaseDisplaySetFilterWidget::updateSetFilter()
|
||||
{
|
||||
// Clear existing filters related to sets
|
||||
filterModel->blockSignals(true);
|
||||
filterModel->filterTree()->blockSignals(true);
|
||||
filterModel->clearFiltersOfType(CardFilter::Attr::AttrSet);
|
||||
|
||||
if (exactMatchMode) {
|
||||
// Exact Match: Only selected sets are allowed
|
||||
QSet<QString> selectedSets;
|
||||
for (const auto &set : activeSets.keys()) {
|
||||
if (activeSets[set]) {
|
||||
selectedSets.insert(set);
|
||||
}
|
||||
}
|
||||
|
||||
if (!selectedSets.isEmpty()) {
|
||||
// Require all selected sets (TypeAnd)
|
||||
for (const auto &set : selectedSets) {
|
||||
QString setString = set;
|
||||
filterModel->addFilter(new CardFilter(setString, CardFilter::Type::TypeAnd, CardFilter::Attr::AttrSet));
|
||||
}
|
||||
|
||||
// Exclude any other sets (TypeAndNot)
|
||||
for (const auto &set : setButtons.keys()) {
|
||||
if (!selectedSets.contains(set)) {
|
||||
QString setString = set;
|
||||
filterModel->addFilter(
|
||||
new CardFilter(setString, CardFilter::Type::TypeAndNot, CardFilter::Attr::AttrSet));
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Default Includes Mode (TypeOr) - match any selected sets
|
||||
for (const auto &set : activeSets.keys()) {
|
||||
if (activeSets[set]) {
|
||||
QString setString = set;
|
||||
filterModel->addFilter(new CardFilter(setString, CardFilter::Type::TypeOr, CardFilter::Attr::AttrSet));
|
||||
}
|
||||
}
|
||||
}
|
||||
filterModel->blockSignals(false);
|
||||
filterModel->filterTree()->blockSignals(false);
|
||||
|
||||
emit filterModel->filterTree()->changed();
|
||||
emit filterModel->layoutChanged();
|
||||
}
|
||||
|
||||
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 (const auto &key : setButtons.keys()) {
|
||||
bool active = selectedSets.contains(key);
|
||||
activeSets[key] = active;
|
||||
setButtons[key]->blockSignals(true);
|
||||
setButtons[key]->setChecked(active);
|
||||
setButtons[key]->blockSignals(false);
|
||||
}
|
||||
}
|
||||
|
||||
void VisualDatabaseDisplaySetFilterWidget::updateFilterMode(bool checked)
|
||||
{
|
||||
exactMatchMode = checked;
|
||||
updateSetFilter();
|
||||
retranslateUi();
|
||||
}
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
#ifndef VISUAL_DATABASE_DISPLAY_SET_FILTER_WIDGET_H
|
||||
#define VISUAL_DATABASE_DISPLAY_SET_FILTER_WIDGET_H
|
||||
|
||||
#include "../../../filters/filter_tree_model.h"
|
||||
#include "../general/layout_containers/flow_widget.h"
|
||||
|
||||
#include <QCheckBox>
|
||||
#include <QLineEdit>
|
||||
#include <QMap>
|
||||
#include <QPushButton>
|
||||
#include <QSpinBox>
|
||||
#include <QToolButton>
|
||||
#include <QVBoxLayout>
|
||||
#include <QWidget>
|
||||
|
||||
class VisualDatabaseDisplayRecentSetFilterSettingsWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
VisualDatabaseDisplayRecentSetFilterSettingsWidget(QWidget *parent);
|
||||
void retranslateUi();
|
||||
|
||||
private:
|
||||
QHBoxLayout *layout;
|
||||
QCheckBox *filterToMostRecentSetsCheckBox;
|
||||
QSpinBox *filterToMostRecentSetsAmount;
|
||||
};
|
||||
|
||||
class VisualDatabaseDisplaySetFilterWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit VisualDatabaseDisplaySetFilterWidget(QWidget *parent, FilterTreeModel *filterModel);
|
||||
void retranslateUi();
|
||||
void createSetButtons();
|
||||
void filterToRecentSets();
|
||||
void updateSetButtonsVisibility();
|
||||
void handleSetToggled(const QString &setShortName, bool active);
|
||||
|
||||
void updateSetFilter();
|
||||
void syncWithFilterModel();
|
||||
void updateFilterMode(bool checked);
|
||||
|
||||
private:
|
||||
FilterTreeModel *filterModel;
|
||||
QMap<QString, int> allMainCardTypesWithCount;
|
||||
QVBoxLayout *layout;
|
||||
VisualDatabaseDisplayRecentSetFilterSettingsWidget *recentSetsSettingsWidget;
|
||||
QLineEdit *searchBox;
|
||||
FlowWidget *flowWidget;
|
||||
QPushButton *toggleButton; // Mode switch button
|
||||
|
||||
QMap<QString, bool> activeMainTypes; // Track active filters
|
||||
QMap<QString, QPushButton *> typeButtons; // Store toggle buttons
|
||||
QMap<QString, QPushButton *> setButtons; // Store set filter buttons
|
||||
QMap<QString, bool> activeSets; // Track active set filters
|
||||
|
||||
bool exactMatchMode = false; // Toggle between "Exact Match" and "Includes"
|
||||
};
|
||||
|
||||
#endif // VISUAL_DATABASE_DISPLAY_SET_FILTER_WIDGET_H
|
||||
|
|
@ -0,0 +1,211 @@
|
|||
#include "visual_database_display_sub_type_filter_widget.h"
|
||||
|
||||
#include "../../../database/card_database_manager.h"
|
||||
#include "../../../filters/filter_tree.h"
|
||||
#include "../../../filters/filter_tree_model.h"
|
||||
|
||||
#include <QLineEdit>
|
||||
#include <QPushButton>
|
||||
#include <QSpinBox>
|
||||
#include <QTimer>
|
||||
|
||||
VisualDatabaseDisplaySubTypeFilterWidget::VisualDatabaseDisplaySubTypeFilterWidget(QWidget *parent,
|
||||
FilterTreeModel *_filterModel)
|
||||
: QWidget(parent), filterModel(_filterModel)
|
||||
{
|
||||
allSubCardTypesWithCount = CardDatabaseManager::getInstance()->getAllSubCardTypesWithCount();
|
||||
|
||||
setMinimumWidth(300);
|
||||
|
||||
layout = new QVBoxLayout(this);
|
||||
setLayout(layout);
|
||||
|
||||
// Create and setup the spinbox
|
||||
spinBox = new QSpinBox(this);
|
||||
spinBox->setMinimum(1);
|
||||
spinBox->setMaximum(getMaxSubTypeCount());
|
||||
spinBox->setValue(150);
|
||||
layout->addWidget(spinBox);
|
||||
connect(spinBox, QOverload<int>::of(&QSpinBox::valueChanged), this,
|
||||
&VisualDatabaseDisplaySubTypeFilterWidget::updateSubTypeButtonsVisibility);
|
||||
|
||||
// Create search box
|
||||
searchBox = new QLineEdit(this);
|
||||
searchBox->setPlaceholderText(tr("Search subtypes..."));
|
||||
layout->addWidget(searchBox);
|
||||
connect(searchBox, &QLineEdit::textChanged, this,
|
||||
&VisualDatabaseDisplaySubTypeFilterWidget::updateSubTypeButtonsVisibility);
|
||||
|
||||
flowWidget = new FlowWidget(this, Qt::Horizontal, Qt::ScrollBarAlwaysOff, Qt::ScrollBarAsNeeded);
|
||||
flowWidget->setMaximumHeight(300);
|
||||
layout->addWidget(flowWidget);
|
||||
|
||||
// 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); // Initialize the toggle button text
|
||||
|
||||
retranslateUi();
|
||||
}
|
||||
|
||||
void VisualDatabaseDisplaySubTypeFilterWidget::retranslateUi()
|
||||
{
|
||||
spinBox->setToolTip(tr("Do not display card sub-types with less than this amount of cards in the database"));
|
||||
toggleButton->setToolTip(tr("Filter mode (AND/OR/NOT conjunctions of filters)"));
|
||||
}
|
||||
|
||||
void VisualDatabaseDisplaySubTypeFilterWidget::createSubTypeButtons()
|
||||
{
|
||||
// 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);
|
||||
button->setStyleSheet("QPushButton { background-color: lightgray; border: 1px solid gray; padding: 5px; }"
|
||||
"QPushButton:checked { background-color: green; color: white; }");
|
||||
|
||||
flowWidget->addWidget(button);
|
||||
typeButtons[it.key()] = button;
|
||||
|
||||
// Connect toggle signal for each button
|
||||
connect(button, &QPushButton::toggled, this,
|
||||
[this, subType = it.key()](bool checked) { handleSubTypeToggled(subType, checked); });
|
||||
}
|
||||
updateSubTypeButtonsVisibility(); // Ensure visibility is updated initially
|
||||
}
|
||||
|
||||
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);
|
||||
bool visible = isActive || (allSubCardTypesWithCount[it.key()] >= threshold &&
|
||||
(filterText.isEmpty() || subType.contains(filterText)));
|
||||
|
||||
it.value()->setVisible(visible);
|
||||
it.value()->setEnabled(visible);
|
||||
}
|
||||
}
|
||||
|
||||
int VisualDatabaseDisplaySubTypeFilterWidget::getMaxSubTypeCount() const
|
||||
{
|
||||
int maxCount = 1;
|
||||
for (auto it = allSubCardTypesWithCount.begin(); it != allSubCardTypesWithCount.end(); ++it) {
|
||||
maxCount = qMax(maxCount, it.value());
|
||||
}
|
||||
return maxCount;
|
||||
}
|
||||
|
||||
void VisualDatabaseDisplaySubTypeFilterWidget::handleSubTypeToggled(const QString &subType, bool active)
|
||||
{
|
||||
activeSubTypes[subType] = active;
|
||||
|
||||
if (typeButtons.contains(subType)) {
|
||||
typeButtons[subType]->setChecked(active);
|
||||
}
|
||||
|
||||
updateSubTypeFilter();
|
||||
}
|
||||
|
||||
void VisualDatabaseDisplaySubTypeFilterWidget::updateSubTypeFilter()
|
||||
{
|
||||
filterModel->blockSignals(true);
|
||||
// Clear existing filters related to sub types
|
||||
filterModel->clearFiltersOfType(CardFilter::Attr::AttrSubType);
|
||||
|
||||
if (exactMatchMode) {
|
||||
// Exact Match: Only selected sub types are allowed
|
||||
QSet<QString> selectedTypes;
|
||||
for (const auto &type : activeSubTypes.keys()) {
|
||||
if (activeSubTypes[type]) {
|
||||
selectedTypes.insert(type);
|
||||
}
|
||||
}
|
||||
|
||||
if (!selectedTypes.isEmpty()) {
|
||||
// Require all selected subtypes (TypeAnd)
|
||||
for (const auto &type : selectedTypes) {
|
||||
QString typeString = type;
|
||||
filterModel->addFilter(
|
||||
new CardFilter(typeString, CardFilter::Type::TypeAnd, CardFilter::Attr::AttrSubType));
|
||||
}
|
||||
|
||||
// Exclude any other types (TypeAndNot)
|
||||
for (const auto &type : typeButtons.keys()) {
|
||||
if (!selectedTypes.contains(type)) {
|
||||
QString typeString = type;
|
||||
filterModel->addFilter(
|
||||
new CardFilter(typeString, CardFilter::Type::TypeAndNot, CardFilter::Attr::AttrSubType));
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 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::AttrSubType));
|
||||
}
|
||||
}
|
||||
}
|
||||
filterModel->blockSignals(false);
|
||||
filterModel->filterTree()->blockSignals(false);
|
||||
|
||||
emit filterModel->filterTree()->changed();
|
||||
emit filterModel->layoutChanged();
|
||||
}
|
||||
|
||||
void VisualDatabaseDisplaySubTypeFilterWidget::updateFilterMode(bool checked)
|
||||
{
|
||||
exactMatchMode = 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<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();
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
#ifndef VISUAL_DATABASE_DISPLAY_SUB_TYPE_FILTER_WIDGET_H
|
||||
#define VISUAL_DATABASE_DISPLAY_SUB_TYPE_FILTER_WIDGET_H
|
||||
|
||||
#include "../../../filters/filter_tree_model.h"
|
||||
#include "../general/layout_containers/flow_widget.h"
|
||||
|
||||
#include <QMap>
|
||||
#include <QPushButton>
|
||||
#include <QSpinBox>
|
||||
#include <QToolButton>
|
||||
#include <QVBoxLayout>
|
||||
#include <QWidget>
|
||||
|
||||
class VisualDatabaseDisplaySubTypeFilterWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit VisualDatabaseDisplaySubTypeFilterWidget(QWidget *parent, FilterTreeModel *filterModel);
|
||||
void retranslateUi();
|
||||
void createSubTypeButtons();
|
||||
void updateSubTypeButtonsVisibility();
|
||||
int getMaxSubTypeCount() const;
|
||||
|
||||
void handleSubTypeToggled(const QString &mainType, bool active);
|
||||
void updateSubTypeFilter();
|
||||
void updateFilterMode(bool checked);
|
||||
void syncWithFilterModel();
|
||||
|
||||
private:
|
||||
FilterTreeModel *filterModel;
|
||||
QMap<QString, int> allSubCardTypesWithCount;
|
||||
QSpinBox *spinBox;
|
||||
QVBoxLayout *layout;
|
||||
QLineEdit *searchBox;
|
||||
FlowWidget *flowWidget;
|
||||
QPushButton *toggleButton; // Mode switch button
|
||||
|
||||
QMap<QString, bool> activeSubTypes; // Track active filters
|
||||
QMap<QString, QPushButton *> typeButtons; // Store toggle buttons
|
||||
|
||||
bool exactMatchMode = false; // Toggle between "Exact Match" and "Includes"
|
||||
};
|
||||
|
||||
#endif // VISUAL_DATABASE_DISPLAY_SUB_TYPE_FILTER_WIDGET_H
|
||||
|
|
@ -0,0 +1,378 @@
|
|||
#include "visual_database_display_widget.h"
|
||||
|
||||
#include "../../../database/card_database.h"
|
||||
#include "../../../database/card_database_manager.h"
|
||||
#include "../../../deck/custom_line_edit.h"
|
||||
#include "../../../filters/filter_tree_model.h"
|
||||
#include "../../../filters/syntax_help.h"
|
||||
#include "../../../settings/cache_settings.h"
|
||||
#include "../../../utility/card_info_comparator.h"
|
||||
#include "../../pixel_map_generator.h"
|
||||
#include "../cards/card_info_picture_with_text_overlay_widget.h"
|
||||
#include "../quick_settings/settings_button_widget.h"
|
||||
#include "visual_database_display_color_filter_widget.h"
|
||||
#include "visual_database_display_filter_save_load_widget.h"
|
||||
#include "visual_database_display_main_type_filter_widget.h"
|
||||
#include "visual_database_display_name_filter_widget.h"
|
||||
#include "visual_database_display_set_filter_widget.h"
|
||||
#include "visual_database_display_sub_type_filter_widget.h"
|
||||
|
||||
#include <QHeaderView>
|
||||
#include <QScrollBar>
|
||||
#include <qpropertyanimation.h>
|
||||
#include <utility>
|
||||
|
||||
VisualDatabaseDisplayWidget::VisualDatabaseDisplayWidget(QWidget *parent,
|
||||
AbstractTabDeckEditor *_deckEditor,
|
||||
CardDatabaseModel *database_model,
|
||||
CardDatabaseDisplayModel *database_display_model)
|
||||
: QWidget(parent), deckEditor(_deckEditor), databaseModel(database_model),
|
||||
databaseDisplayModel(database_display_model)
|
||||
{
|
||||
cards = new QList<ExactCard>;
|
||||
connect(databaseDisplayModel, &CardDatabaseDisplayModel::modelDirty, this,
|
||||
&VisualDatabaseDisplayWidget::modelDirty);
|
||||
|
||||
// Set up main layout and widgets
|
||||
setMinimumSize(0, 0);
|
||||
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||
mainLayout = new QVBoxLayout(this);
|
||||
setLayout(mainLayout);
|
||||
mainLayout->setSpacing(1);
|
||||
mainLayout->setContentsMargins(0, 0, 0, 0);
|
||||
|
||||
flowWidget = new FlowWidget(this, Qt::Horizontal, Qt::ScrollBarAlwaysOff, Qt::ScrollBarPolicy::ScrollBarAsNeeded);
|
||||
cardSizeWidget = new CardSizeWidget(this, flowWidget);
|
||||
|
||||
searchContainer = new QWidget(this);
|
||||
searchLayout = new QHBoxLayout(searchContainer);
|
||||
searchContainer->setLayout(searchLayout);
|
||||
|
||||
searchEdit = new SearchLineEdit();
|
||||
searchEdit->setObjectName("searchEdit");
|
||||
searchEdit->setPlaceholderText(tr("Search by card name (or search expressions)"));
|
||||
searchEdit->setClearButtonEnabled(true);
|
||||
searchEdit->addAction(loadColorAdjustedPixmap("theme:icons/search"), QLineEdit::LeadingPosition);
|
||||
auto help = searchEdit->addAction(QPixmap("theme:icons/info"), QLineEdit::TrailingPosition);
|
||||
connect(help, &QAction::triggered, this, [this] { createSearchSyntaxHelpWindow(searchEdit); });
|
||||
searchEdit->installEventFilter(&searchKeySignals);
|
||||
|
||||
setFocusProxy(searchEdit);
|
||||
setFocusPolicy(Qt::ClickFocus);
|
||||
|
||||
filterModel = new FilterTreeModel();
|
||||
filterModel->setObjectName("filterModel");
|
||||
|
||||
searchKeySignals.setObjectName("searchKeySignals");
|
||||
connect(searchEdit, &QLineEdit::textChanged, this, &VisualDatabaseDisplayWidget::updateSearch);
|
||||
/*connect(&searchKeySignals, SIGNAL(onEnter()), this, SLOT(actAddCard()));
|
||||
connect(&searchKeySignals, SIGNAL(onCtrlAltEqual()), this, SLOT(actAddCard()));
|
||||
connect(&searchKeySignals, SIGNAL(onCtrlAltRBracket()), this, SLOT(actAddCardToSideboard()));
|
||||
connect(&searchKeySignals, SIGNAL(onCtrlAltMinus()), this, SLOT(actDecrementCard()));
|
||||
connect(&searchKeySignals, SIGNAL(onCtrlAltLBracket()), this, SLOT(actDecrementCardFromSideboard()));
|
||||
connect(&searchKeySignals, SIGNAL(onCtrlAltEnter()), this, SLOT(actAddCardToSideboard()));
|
||||
connect(&searchKeySignals, SIGNAL(onCtrlEnter()), this, SLOT(actAddCardToSideboard()));
|
||||
connect(&searchKeySignals, SIGNAL(onCtrlC()), this, SLOT(copyDatabaseCellContents()));*/
|
||||
|
||||
databaseView = new QTreeView(this);
|
||||
databaseView->setObjectName("databaseView");
|
||||
databaseView->setFocusProxy(searchEdit);
|
||||
databaseView->setRootIsDecorated(false);
|
||||
databaseView->setItemDelegate(nullptr);
|
||||
databaseView->setSortingEnabled(true);
|
||||
databaseView->sortByColumn(0, Qt::AscendingOrder);
|
||||
databaseView->setModel(databaseDisplayModel);
|
||||
databaseView->setVisible(false);
|
||||
|
||||
searchEdit->setTreeView(databaseView);
|
||||
|
||||
colorFilterWidget = new VisualDatabaseDisplayColorFilterWidget(this, filterModel);
|
||||
|
||||
filterContainer = new QWidget(this);
|
||||
filterContainerLayout = new QHBoxLayout(filterContainer);
|
||||
filterContainer->setLayout(filterContainerLayout);
|
||||
|
||||
clearFilterWidget = new QToolButton();
|
||||
clearFilterWidget->setFixedSize(32, 32);
|
||||
clearFilterWidget->setIcon(QPixmap("theme:icons/delete"));
|
||||
connect(clearFilterWidget, &QToolButton::clicked, this, [this] {
|
||||
filterModel->blockSignals(true);
|
||||
filterModel->filterTree()->blockSignals(true);
|
||||
filterModel->clear();
|
||||
filterModel->blockSignals(false);
|
||||
filterModel->filterTree()->blockSignals(false);
|
||||
emit filterModel->filterTree()->changed();
|
||||
emit filterModel->layoutChanged();
|
||||
});
|
||||
|
||||
quickFilterSaveLoadWidget = new SettingsButtonWidget(this);
|
||||
quickFilterSaveLoadWidget->setButtonIcon(QPixmap("theme:icons/lock"));
|
||||
|
||||
quickFilterNameWidget = new SettingsButtonWidget(this);
|
||||
quickFilterNameWidget->setButtonIcon(QPixmap("theme:icons/rename"));
|
||||
|
||||
quickFilterSubTypeWidget = new SettingsButtonWidget(this);
|
||||
quickFilterSubTypeWidget->setButtonIcon(QPixmap("theme:icons/player"));
|
||||
|
||||
quickFilterSetWidget = new SettingsButtonWidget(this);
|
||||
quickFilterSetWidget->setButtonIcon(QPixmap("theme:icons/scales"));
|
||||
|
||||
filterContainer->setMaximumHeight(80);
|
||||
|
||||
databaseLoadIndicator = new QLabel(this);
|
||||
databaseLoadIndicator->setAlignment(Qt::AlignCenter);
|
||||
|
||||
mainLayout->addWidget(databaseLoadIndicator);
|
||||
|
||||
if (CardDatabaseManager::getInstance()->getLoadStatus() != LoadStatus::Ok) {
|
||||
connect(CardDatabaseManager::getInstance(), &CardDatabase::cardDatabaseLoadingFinished, this,
|
||||
&VisualDatabaseDisplayWidget::initialize);
|
||||
quickFilterSaveLoadWidget->setVisible(false);
|
||||
quickFilterNameWidget->setVisible(false);
|
||||
quickFilterSubTypeWidget->setVisible(false);
|
||||
quickFilterSetWidget->setVisible(false);
|
||||
} else {
|
||||
initialize();
|
||||
databaseLoadIndicator->setVisible(false);
|
||||
}
|
||||
|
||||
retranslateUi();
|
||||
}
|
||||
|
||||
void VisualDatabaseDisplayWidget::initialize()
|
||||
{
|
||||
databaseLoadIndicator->setVisible(false);
|
||||
|
||||
quickFilterSaveLoadWidget->setVisible(true);
|
||||
quickFilterNameWidget->setVisible(true);
|
||||
quickFilterSubTypeWidget->setVisible(true);
|
||||
quickFilterSetWidget->setVisible(true);
|
||||
|
||||
saveLoadWidget = new VisualDatabaseDisplayFilterSaveLoadWidget(this, filterModel);
|
||||
nameFilterWidget = new VisualDatabaseDisplayNameFilterWidget(this, deckEditor, filterModel);
|
||||
mainTypeFilterWidget = new VisualDatabaseDisplayMainTypeFilterWidget(this, filterModel);
|
||||
subTypeFilterWidget = new VisualDatabaseDisplaySubTypeFilterWidget(this, filterModel);
|
||||
setFilterWidget = new VisualDatabaseDisplaySetFilterWidget(this, filterModel);
|
||||
|
||||
quickFilterSaveLoadWidget->addSettingsWidget(saveLoadWidget);
|
||||
quickFilterNameWidget->addSettingsWidget(nameFilterWidget);
|
||||
quickFilterSubTypeWidget->addSettingsWidget(subTypeFilterWidget);
|
||||
quickFilterSetWidget->addSettingsWidget(setFilterWidget);
|
||||
|
||||
filterContainerLayout->addWidget(quickFilterSaveLoadWidget);
|
||||
filterContainerLayout->addWidget(quickFilterNameWidget);
|
||||
filterContainerLayout->addWidget(quickFilterSubTypeWidget);
|
||||
filterContainerLayout->addWidget(quickFilterSetWidget);
|
||||
filterContainerLayout->addWidget(mainTypeFilterWidget);
|
||||
|
||||
searchLayout->addWidget(colorFilterWidget);
|
||||
searchLayout->addWidget(clearFilterWidget);
|
||||
searchLayout->addWidget(searchEdit);
|
||||
|
||||
mainLayout->addWidget(searchContainer);
|
||||
|
||||
mainLayout->addWidget(filterContainer);
|
||||
|
||||
mainLayout->addWidget(flowWidget);
|
||||
|
||||
mainLayout->addWidget(cardSizeWidget);
|
||||
|
||||
debounceTimer = new QTimer(this);
|
||||
debounceTimer->setSingleShot(true); // Ensure it only fires once after the timeout
|
||||
|
||||
connect(debounceTimer, &QTimer::timeout, this, &VisualDatabaseDisplayWidget::searchModelChanged);
|
||||
|
||||
databaseDisplayModel->setFilterTree(filterModel->filterTree());
|
||||
|
||||
connect(filterModel, &FilterTreeModel::layoutChanged, this, &VisualDatabaseDisplayWidget::searchModelChanged);
|
||||
|
||||
loadCardsTimer = new QTimer(this);
|
||||
loadCardsTimer->setSingleShot(true); // Ensure it only fires once after the timeout
|
||||
|
||||
connect(loadCardsTimer, &QTimer::timeout, this, [this]() { loadCurrentPage(); });
|
||||
loadCardsTimer->start(5000);
|
||||
|
||||
retranslateUi();
|
||||
}
|
||||
|
||||
void VisualDatabaseDisplayWidget::retranslateUi()
|
||||
{
|
||||
databaseLoadIndicator->setText(tr("Loading database ..."));
|
||||
|
||||
clearFilterWidget->setToolTip(tr("Clear all filters"));
|
||||
|
||||
quickFilterSaveLoadWidget->setToolTip(tr("Save and load filters"));
|
||||
quickFilterNameWidget->setToolTip(tr("Filter by exact card name"));
|
||||
quickFilterSubTypeWidget->setToolTip(tr("Filter by card sub-type"));
|
||||
quickFilterSetWidget->setToolTip(tr("Filter by set"));
|
||||
}
|
||||
|
||||
void VisualDatabaseDisplayWidget::resizeEvent(QResizeEvent *event)
|
||||
{
|
||||
QWidget::resizeEvent(event);
|
||||
loadCurrentPage();
|
||||
}
|
||||
|
||||
void VisualDatabaseDisplayWidget::onClick(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *instance)
|
||||
{
|
||||
emit cardClickedDatabaseDisplay(event, instance);
|
||||
}
|
||||
|
||||
void VisualDatabaseDisplayWidget::onHover(const ExactCard &hoveredCard)
|
||||
{
|
||||
emit cardHoveredDatabaseDisplay(hoveredCard);
|
||||
}
|
||||
|
||||
void VisualDatabaseDisplayWidget::addCard(const ExactCard &cardToAdd)
|
||||
{
|
||||
cards->append(cardToAdd);
|
||||
auto *display = new CardInfoPictureWithTextOverlayWidget(flowWidget, false);
|
||||
display->setScaleFactor(cardSizeWidget->getSlider()->value());
|
||||
display->setCard(cardToAdd);
|
||||
flowWidget->addWidget(display);
|
||||
connect(display, &CardInfoPictureWithTextOverlayWidget::imageClicked, this, &VisualDatabaseDisplayWidget::onClick);
|
||||
connect(display, &CardInfoPictureWithTextOverlayWidget::hoveredOnCard, this, &VisualDatabaseDisplayWidget::onHover);
|
||||
connect(cardSizeWidget->getSlider(), &QSlider::valueChanged, display, &CardInfoPictureWidget::setScaleFactor);
|
||||
}
|
||||
|
||||
void VisualDatabaseDisplayWidget::updateSearch(const QString &search) const
|
||||
{
|
||||
databaseDisplayModel->setStringFilter(search);
|
||||
QModelIndexList sel = databaseView->selectionModel()->selectedRows();
|
||||
if (sel.isEmpty() && databaseDisplayModel->rowCount())
|
||||
databaseView->selectionModel()->setCurrentIndex(databaseDisplayModel->index(0, 0),
|
||||
QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows);
|
||||
}
|
||||
|
||||
void VisualDatabaseDisplayWidget::searchModelChanged()
|
||||
{
|
||||
// Clear the current page and prepare for new data
|
||||
flowWidget->clearLayout(); // Clear existing cards
|
||||
cards->clear(); // Clear the card list
|
||||
// Reset scrollbar position to the top after loading new cards
|
||||
if (QScrollBar *scrollBar = flowWidget->scrollArea->verticalScrollBar()) {
|
||||
scrollBar->setValue(0); // Reset scrollbar to top
|
||||
}
|
||||
|
||||
currentPage = 0;
|
||||
loadCurrentPage();
|
||||
qCDebug(VisualDatabaseDisplayLog) << "Search model changed";
|
||||
}
|
||||
|
||||
void VisualDatabaseDisplayWidget::loadCurrentPage()
|
||||
{
|
||||
// Ensure only the initial page is loaded
|
||||
if (currentPage == 0) {
|
||||
// Only load the first page initially
|
||||
qCDebug(VisualDatabaseDisplayLog) << "Loading the first page";
|
||||
populateCards();
|
||||
} else {
|
||||
// If not the first page, just load the next page and append to the flow widget
|
||||
loadNextPage();
|
||||
}
|
||||
}
|
||||
|
||||
void VisualDatabaseDisplayWidget::populateCards()
|
||||
{
|
||||
int rowCount = databaseDisplayModel->rowCount();
|
||||
cards->clear();
|
||||
|
||||
// Calculate the start and end indices for the current page
|
||||
int start = currentPage * cardsPerPage;
|
||||
int end = qMin(start + cardsPerPage, rowCount);
|
||||
|
||||
qCDebug(VisualDatabaseDisplayLog) << "Fetching from " << start << " to " << end << " cards";
|
||||
// Load more cards if we are at the end of the current list and can fetch more
|
||||
if (end >= rowCount && databaseDisplayModel->canFetchMore(QModelIndex())) {
|
||||
qCDebug(VisualDatabaseDisplayLog) << "We gotta load more";
|
||||
databaseDisplayModel->fetchMore(QModelIndex());
|
||||
}
|
||||
|
||||
loadPage(start, end);
|
||||
}
|
||||
|
||||
void VisualDatabaseDisplayWidget::loadNextPage()
|
||||
{
|
||||
// Calculate the start and end indices for the next page
|
||||
int rowCount = databaseDisplayModel->rowCount();
|
||||
int start = currentPage * cardsPerPage;
|
||||
int end = qMin(start + cardsPerPage, rowCount);
|
||||
|
||||
// Load more cards if we are at the end of the current list and can fetch more
|
||||
if (end >= rowCount && databaseDisplayModel->canFetchMore(QModelIndex())) {
|
||||
databaseDisplayModel->fetchMore(QModelIndex());
|
||||
}
|
||||
|
||||
// Load the next page of cards and add them to the flow widget
|
||||
loadPage(start, end);
|
||||
}
|
||||
|
||||
void VisualDatabaseDisplayWidget::loadPage(int start, int end)
|
||||
{
|
||||
QList<const CardFilter *> setFilters = filterModel->getFiltersOfType(CardFilter::AttrSet);
|
||||
for (int row = start; row < end; ++row) {
|
||||
qCDebug(VisualDatabaseDisplayLog) << "Adding " << row;
|
||||
QModelIndex index = databaseDisplayModel->index(row, CardDatabaseModel::NameColumn);
|
||||
QVariant name = databaseDisplayModel->data(index, Qt::DisplayRole);
|
||||
qCDebug(VisualDatabaseDisplayLog) << name.toString();
|
||||
|
||||
if (CardInfoPtr info = CardDatabaseManager::getInstance()->getCardInfo(name.toString())) {
|
||||
if (!setFilters.empty()) {
|
||||
SetToPrintingsMap setMap = info->getSets();
|
||||
for (const CardFilter *setFilter : setFilters) {
|
||||
if (setMap.contains(setFilter->term())) {
|
||||
for (PrintingInfo printing : setMap[setFilter->term()]) {
|
||||
addCard(ExactCard(info, printing));
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
addCard(CardDatabaseManager::getInstance()->getPreferredCard(info));
|
||||
}
|
||||
} else {
|
||||
qCDebug(VisualDatabaseDisplayLog) << "Card not found in database!";
|
||||
}
|
||||
}
|
||||
currentPage++;
|
||||
}
|
||||
|
||||
void VisualDatabaseDisplayWidget::modelDirty() const
|
||||
{
|
||||
debounceTimer->start(debounceTime);
|
||||
}
|
||||
|
||||
void VisualDatabaseDisplayWidget::sortCardList(const QStringList &properties,
|
||||
Qt::SortOrder order = Qt::AscendingOrder) const
|
||||
{
|
||||
CardInfoComparator comparator(properties, order);
|
||||
std::sort(cards->begin(), cards->end(), [comparator](const ExactCard &a, const ExactCard &b) {
|
||||
return comparator(a.getCardPtr(), b.getCardPtr());
|
||||
});
|
||||
}
|
||||
|
||||
void VisualDatabaseDisplayWidget::databaseDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight)
|
||||
{
|
||||
(void)topLeft;
|
||||
(void)bottomRight;
|
||||
qCDebug(VisualDatabaseDisplayLog) << "Database Data changed";
|
||||
}
|
||||
|
||||
void VisualDatabaseDisplayWidget::wheelEvent(QWheelEvent *event)
|
||||
{
|
||||
int totalRows = databaseDisplayModel->rowCount(); // Total number of cards
|
||||
int nextPageStartIndex = (currentPage + 1) * cardsPerPage;
|
||||
|
||||
// Handle scrolling down
|
||||
if (event->angleDelta().y() < 0) {
|
||||
// Check if the next page has any cards to load
|
||||
if (nextPageStartIndex < totalRows) {
|
||||
loadCurrentPage(); // Load the next page
|
||||
event->accept(); // Accept the event as valid
|
||||
return;
|
||||
}
|
||||
qCDebug(VisualDatabaseDisplayLog) << nextPageStartIndex << ":" << totalRows;
|
||||
}
|
||||
|
||||
// Prevent overscrolling when there's no more data to load
|
||||
event->ignore();
|
||||
}
|
||||
|
|
@ -0,0 +1,112 @@
|
|||
#ifndef VISUAL_DATABASE_DISPLAY_WIDGET_H
|
||||
#define VISUAL_DATABASE_DISPLAY_WIDGET_H
|
||||
|
||||
#include "../../../database/card_database.h"
|
||||
#include "../../../database/card_database_model.h"
|
||||
#include "../../../deck/custom_line_edit.h"
|
||||
#include "../../../deck/deck_list_model.h"
|
||||
#include "../../../filters/filter_tree_model.h"
|
||||
#include "../../../tabs/abstract_tab_deck_editor.h"
|
||||
#include "../../../utility/key_signals.h"
|
||||
#include "../../layouts/flow_layout.h"
|
||||
#include "../cards/card_info_picture_with_text_overlay_widget.h"
|
||||
#include "../cards/card_size_widget.h"
|
||||
#include "../general/layout_containers/flow_widget.h"
|
||||
#include "../general/layout_containers/overlap_control_widget.h"
|
||||
#include "visual_database_display_color_filter_widget.h"
|
||||
#include "visual_database_display_filter_save_load_widget.h"
|
||||
#include "visual_database_display_main_type_filter_widget.h"
|
||||
#include "visual_database_display_name_filter_widget.h"
|
||||
#include "visual_database_display_set_filter_widget.h"
|
||||
#include "visual_database_display_sub_type_filter_widget.h"
|
||||
|
||||
#include <QLoggingCategory>
|
||||
#include <QTreeView>
|
||||
#include <QVBoxLayout>
|
||||
#include <QWheelEvent>
|
||||
#include <QWidget>
|
||||
#include <qscrollarea.h>
|
||||
|
||||
inline Q_LOGGING_CATEGORY(VisualDatabaseDisplayLog, "visual_database_display");
|
||||
|
||||
class VisualDatabaseDisplayWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit VisualDatabaseDisplayWidget(QWidget *parent,
|
||||
AbstractTabDeckEditor *deckEditor,
|
||||
CardDatabaseModel *database_model,
|
||||
CardDatabaseDisplayModel *database_display_model);
|
||||
void retranslateUi();
|
||||
|
||||
void adjustCardsPerPage();
|
||||
void populateCards();
|
||||
void loadPage(int start, int end);
|
||||
void loadNextPage();
|
||||
void loadCurrentPage();
|
||||
void sortCardList(const QStringList &properties, Qt::SortOrder order) const;
|
||||
void setDeckList(const DeckList &new_deck_list_model);
|
||||
|
||||
QWidget *searchContainer;
|
||||
QHBoxLayout *searchLayout;
|
||||
SearchLineEdit *searchEdit;
|
||||
FilterTreeModel *filterModel;
|
||||
VisualDatabaseDisplayColorFilterWidget *colorFilterWidget;
|
||||
|
||||
public slots:
|
||||
void searchModelChanged();
|
||||
|
||||
signals:
|
||||
void cardClickedDatabaseDisplay(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *instance);
|
||||
void cardHoveredDatabaseDisplay(const ExactCard &hoveredCard);
|
||||
|
||||
protected slots:
|
||||
void initialize();
|
||||
void onClick(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *instance);
|
||||
void onHover(const ExactCard &hoveredCard);
|
||||
void addCard(const ExactCard &cardToAdd);
|
||||
void databaseDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight);
|
||||
void wheelEvent(QWheelEvent *event) override;
|
||||
void modelDirty() const;
|
||||
void updateSearch(const QString &search) const;
|
||||
|
||||
private:
|
||||
QLabel *databaseLoadIndicator;
|
||||
QToolButton *clearFilterWidget;
|
||||
QWidget *filterContainer;
|
||||
QHBoxLayout *filterContainerLayout;
|
||||
SettingsButtonWidget *quickFilterSaveLoadWidget;
|
||||
VisualDatabaseDisplayFilterSaveLoadWidget *saveLoadWidget;
|
||||
SettingsButtonWidget *quickFilterNameWidget;
|
||||
VisualDatabaseDisplayNameFilterWidget *nameFilterWidget;
|
||||
VisualDatabaseDisplayMainTypeFilterWidget *mainTypeFilterWidget;
|
||||
SettingsButtonWidget *quickFilterSubTypeWidget;
|
||||
VisualDatabaseDisplaySubTypeFilterWidget *subTypeFilterWidget;
|
||||
SettingsButtonWidget *quickFilterSetWidget;
|
||||
VisualDatabaseDisplaySetFilterWidget *setFilterWidget;
|
||||
KeySignals searchKeySignals;
|
||||
AbstractTabDeckEditor *deckEditor;
|
||||
CardDatabaseModel *databaseModel;
|
||||
CardDatabaseDisplayModel *databaseDisplayModel;
|
||||
QTreeView *databaseView;
|
||||
QList<ExactCard> *cards;
|
||||
QVBoxLayout *mainLayout;
|
||||
QScrollArea *scrollArea;
|
||||
FlowWidget *flowWidget;
|
||||
QWidget *overlapCategories;
|
||||
QVBoxLayout *overlapCategoriesLayout;
|
||||
OverlapControlWidget *overlapControlWidget;
|
||||
CardSizeWidget *cardSizeWidget;
|
||||
QTimer *debounceTimer;
|
||||
QTimer *loadCardsTimer;
|
||||
|
||||
int debounceTime = 300; // in Ms
|
||||
int currentPage = 0; // Current page index
|
||||
int cardsPerPage = 100; // Number of cards per page
|
||||
|
||||
protected:
|
||||
void resizeEvent(QResizeEvent *event) override;
|
||||
};
|
||||
|
||||
#endif // VISUAL_DATABASE_DISPLAY_WIDGET_H
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
#include "visual_database_filter_display_widget.h"
|
||||
|
||||
#include "../../../settings/cache_settings.h"
|
||||
|
||||
#include <QDir>
|
||||
#include <QFile>
|
||||
#include <QFontMetrics>
|
||||
#include <QHBoxLayout>
|
||||
#include <QMessageBox>
|
||||
#include <QPushButton>
|
||||
|
||||
FilterDisplayWidget::FilterDisplayWidget(QWidget *parent, const QString &filename, FilterTreeModel *_filterModel)
|
||||
: QWidget(parent), filterFilename(filename), filterModel(_filterModel)
|
||||
{
|
||||
setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
|
||||
// Create layout
|
||||
auto *layout = new QHBoxLayout(this);
|
||||
layout->setContentsMargins(5, 5, 5, 5);
|
||||
layout->setSpacing(5);
|
||||
|
||||
// Filter button (displays filename)
|
||||
filterButton = new QPushButton(filterFilename, this);
|
||||
layout->addWidget(filterButton);
|
||||
|
||||
// Create close button (inside the filter button)
|
||||
closeButton = new QPushButton("x", this);
|
||||
closeButton->setFixedSize(20, 20); // Small square close button
|
||||
closeButton->setFocusPolicy(Qt::NoFocus);
|
||||
layout->addWidget(closeButton);
|
||||
|
||||
// Connect the filter button for loading the filter
|
||||
connect(filterButton, &QPushButton::clicked, this, &FilterDisplayWidget::loadFilter);
|
||||
|
||||
// Connect the close button for deleting the filter
|
||||
connect(closeButton, &QPushButton::clicked, this, &FilterDisplayWidget::deleteFilter);
|
||||
}
|
||||
|
||||
QSize FilterDisplayWidget::sizeHint() const
|
||||
{
|
||||
// Calculate the size based on the filter name and the close button
|
||||
QFontMetrics fm(font());
|
||||
int textWidth = fm.horizontalAdvance(filterFilename);
|
||||
int width = textWidth + 30 + 16; // Space for the filename and close button
|
||||
int height = fm.height() + 10; // Height based on font size + padding
|
||||
|
||||
return QSize(width, height);
|
||||
}
|
||||
|
||||
void FilterDisplayWidget::mousePressEvent(QMouseEvent *event)
|
||||
{
|
||||
if (event->button() == Qt::LeftButton) {
|
||||
emit filterClicked();
|
||||
}
|
||||
QWidget::mousePressEvent(event);
|
||||
}
|
||||
|
||||
void FilterDisplayWidget::loadFilter()
|
||||
{
|
||||
// Trigger the loading of the filter
|
||||
emit filterLoadRequested(filterFilename);
|
||||
}
|
||||
|
||||
void FilterDisplayWidget::deleteFilter()
|
||||
{
|
||||
// Show confirmation dialog before deleting the filter
|
||||
QMessageBox::StandardButton reply = QMessageBox::question(
|
||||
this, tr("Confirm Delete"), tr("Are you sure you want to delete the filter '%1'?").arg(filterFilename),
|
||||
QMessageBox::Yes | QMessageBox::No);
|
||||
if (reply == QMessageBox::Yes) {
|
||||
// If confirmed, delete the filter
|
||||
QString filePath = SettingsCache::instance().getFiltersPath() + QDir::separator() + filterFilename;
|
||||
QFile file(filePath);
|
||||
if (file.remove()) {
|
||||
emit filterDeleted(filterFilename); // Emit signal for deletion
|
||||
delete this; // Delete this widget
|
||||
} else {
|
||||
QMessageBox::warning(this, tr("Delete Failed"), tr("Failed to delete filter '%1'.").arg(filterFilename));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
#ifndef VISUAL_DATABASE_FILTER_DISPLAY_WIDGET_H
|
||||
#define VISUAL_DATABASE_FILTER_DISPLAY_WIDGET_H
|
||||
|
||||
#include <QMouseEvent>
|
||||
#include <QPushButton>
|
||||
#include <QString>
|
||||
#include <QWidget>
|
||||
|
||||
class FilterTreeModel;
|
||||
|
||||
class FilterDisplayWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit FilterDisplayWidget(QWidget *parent, const QString &filename, FilterTreeModel *_filterModel);
|
||||
~FilterDisplayWidget() = default;
|
||||
|
||||
QSize sizeHint() const override;
|
||||
|
||||
protected:
|
||||
void mousePressEvent(QMouseEvent *event) override;
|
||||
|
||||
private slots:
|
||||
void loadFilter();
|
||||
void deleteFilter();
|
||||
|
||||
signals:
|
||||
void filterClicked();
|
||||
void filterLoadRequested(const QString &filename);
|
||||
void filterDeleted(const QString &filename);
|
||||
|
||||
private:
|
||||
QString filterFilename;
|
||||
FilterTreeModel *filterModel;
|
||||
QPushButton *filterButton; // Button for the filter text
|
||||
QPushButton *closeButton; // Close button to delete the filter
|
||||
};
|
||||
|
||||
#endif // VISUAL_DATABASE_FILTER_DISPLAY_WIDGET_H
|
||||
Loading…
Add table
Add a link
Reference in a new issue