[TabDeckEditor] Refactor card database view into own class (#6967)

* rename method

* [TabDeckEditor] Refactor card database view into own class

* fix include guard

* directly get key signals for eventFilter

* fix includes
This commit is contained in:
RickyRister 2026-06-05 10:20:46 -07:00 committed by GitHub
parent 0da2ac4087
commit c14a008080
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
15 changed files with 392 additions and 252 deletions

View file

@ -0,0 +1,167 @@
#include "card_database_view.h"
#include "../../../client/settings/cache_settings.h"
#include "card_database_display_model.h"
#include "card_database_model.h"
#include <QApplication>
#include <QClipboard>
#include <QHeaderView>
#include <QMenu>
#include <libcockatrice/card/database/card_database_manager.h>
#include <libcockatrice/card/relation/card_relation.h>
#include <libcockatrice/deck_list/tree/inner_deck_list_node.h>
static bool canBeCommander(const CardInfo &cardInfo)
{
return (cardInfo.getCardType().contains("Legendary", Qt::CaseInsensitive) &&
cardInfo.getCardType().contains("Creature", Qt::CaseInsensitive)) ||
cardInfo.getText().contains("can be your commander", Qt::CaseInsensitive);
}
CardDatabaseView::CardDatabaseView(QWidget *parent, CardDatabaseDisplayModel *model)
: QTreeView(parent), databaseDisplayModel(model)
{
// set up object
setUniformRowHeights(true);
setRootIsDecorated(false);
setAlternatingRowColors(true);
setSortingEnabled(true);
sortByColumn(0, Qt::AscendingOrder);
QTreeView::setModel(databaseDisplayModel);
setContextMenuPolicy(Qt::CustomContextMenu);
connect(databaseDisplayModel, &CardDatabaseDisplayModel::modelDirty, this,
&CardDatabaseView::resetSelectionIfEmpty);
connect(this, &QTreeView::customContextMenuRequested, this, &CardDatabaseView::openCustomMenu);
connect(selectionModel(), &QItemSelectionModel::currentRowChanged, this, &CardDatabaseView::updateCard);
connect(this, &QTreeView::doubleClicked, this, &CardDatabaseView::actDoubleClick);
// layout settings
QByteArray dbHeaderState = SettingsCache::instance().layouts().getDeckEditorDbHeaderState();
if (dbHeaderState.isNull()) {
// first run
setColumnWidth(0, 200);
} else {
header()->restoreState(dbHeaderState);
}
connect(header(), &QHeaderView::geometriesChanged, this, &CardDatabaseView::saveDbHeaderState);
// create key filters
searchKeySignals.setObjectName("searchKeySignals");
connect(&searchKeySignals, &KeySignals::onEnter, this, [this] { addCard(DECK_ZONE_MAIN); });
connect(&searchKeySignals, &KeySignals::onCtrlAltEqual, this, [this] { addCard(DECK_ZONE_MAIN); });
connect(&searchKeySignals, &KeySignals::onCtrlAltRBracket, this, [this] { addCard(DECK_ZONE_SIDE); });
connect(&searchKeySignals, &KeySignals::onCtrlAltMinus, this, [this] { decrementCard(DECK_ZONE_MAIN); });
connect(&searchKeySignals, &KeySignals::onCtrlAltLBracket, this, [this] { decrementCard(DECK_ZONE_SIDE); });
connect(&searchKeySignals, &KeySignals::onCtrlAltEnter, this, [this] { addCard(DECK_ZONE_SIDE); });
connect(&searchKeySignals, &KeySignals::onCtrlEnter, this, [this] { addCard(DECK_ZONE_SIDE); });
connect(&searchKeySignals, &KeySignals::onCtrlC, this, &CardDatabaseView::copyDatabaseCellContents);
}
QString CardDatabaseView::currentCardName() const
{
const QModelIndex currentIndex = selectionModel()->currentIndex();
if (!currentIndex.isValid()) {
return {};
}
return currentIndex.siblingAtColumn(CardDatabaseModel::NameColumn).data().toString();
}
void CardDatabaseView::actDoubleClick()
{
if (QApplication::keyboardModifiers() & Qt::ControlModifier) {
addCard(DECK_ZONE_SIDE);
} else {
addCard(DECK_ZONE_MAIN);
}
}
void CardDatabaseView::addCard(const QString &zoneName)
{
emit cardAdded(currentCardName(), zoneName);
}
void CardDatabaseView::decrementCard(const QString &zoneName)
{
emit cardDecremented(currentCardName(), zoneName);
}
void CardDatabaseView::updateCard(const QModelIndex &current, const QModelIndex & /*previous*/)
{
if (!current.isValid()) {
return;
}
const QString cardName = current.siblingAtColumn(CardDatabaseModel::NameColumn).data().toString();
if (!current.model()->hasChildren(current.siblingAtColumn(CardDatabaseModel::NameColumn))) {
emit cardChanged(cardName);
}
}
void CardDatabaseView::resetSelectionIfEmpty()
{
QModelIndexList sel = selectionModel()->selectedRows();
if (sel.isEmpty() && databaseDisplayModel->rowCount() > 0) {
selectionModel()->setCurrentIndex(databaseDisplayModel->index(0, 0),
QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows);
}
}
void CardDatabaseView::copyDatabaseCellContents() const
{
auto _data = selectionModel()->currentIndex().data();
QApplication::clipboard()->setText(_data.toString());
}
void CardDatabaseView::saveDbHeaderState()
{
SettingsCache::instance().layouts().setDeckEditorDbHeaderState(header()->saveState());
}
void CardDatabaseView::openCustomMenu(QPoint point)
{
CardInfoPtr card = CardDatabaseManager::query()->getCardInfo(currentCardName());
if (!card) {
return;
}
QMenu menu;
// add to deck and sideboard options
QAction *addToDeck = menu.addAction(tr("Add to Deck"));
QAction *addToSideboard = menu.addAction(tr("Add to Sideboard"));
QAction *selectPrinting = menu.addAction(tr("Select Printing"));
connect(addToDeck, &QAction::triggered, this, [this, card] { emit cardAdded(card->getName(), DECK_ZONE_MAIN); });
connect(addToSideboard, &QAction::triggered, this,
[this, card] { emit cardAdded(card->getName(), DECK_ZONE_SIDE); });
connect(selectPrinting, &QAction::triggered, this, &CardDatabaseView::selectPrintingClicked);
if (canBeCommander(*card)) {
QAction *edhRecCommander = menu.addAction(tr("Show on EDHRec (Commander)"));
connect(edhRecCommander, &QAction::triggered, this, [this, card] { emit edhrecClicked(card, true); });
}
QAction *edhRecCard = menu.addAction(tr("Show on EDHRec (Card)"));
connect(edhRecCard, &QAction::triggered, this, [this, card] { emit edhrecClicked(card, false); });
// filling out the related cards submenu
auto *relatedMenu = new QMenu(tr("Show Related cards"));
menu.addMenu(relatedMenu);
auto relatedCards = card->getAllRelatedCards();
if (relatedCards.isEmpty()) {
relatedMenu->setDisabled(true);
} else {
for (const CardRelation *rel : relatedCards) {
const QString &relatedCardName = rel->getName();
QAction *relatedCard = relatedMenu->addAction(relatedCardName);
connect(relatedCard, &QAction::triggered, this,
[this, relatedCardName] { emit relatedCardClicked(relatedCardName); });
}
}
menu.exec(mapToGlobal(point));
}

View file

@ -0,0 +1,59 @@
#ifndef COCKATRICE_CARD_DATABASE_VIEW_H
#define COCKATRICE_CARD_DATABASE_VIEW_H
#include "../../key_signals.h"
#include <QTreeView>
#include <libcockatrice/card/card_info.h>
class CardDatabaseModel;
class CardDatabaseDisplayModel;
/**
* @brief The card database table.
*/
class CardDatabaseView : public QTreeView
{
Q_OBJECT
KeySignals searchKeySignals;
CardDatabaseDisplayModel *databaseDisplayModel;
public:
explicit CardDatabaseView(QWidget *parent, CardDatabaseDisplayModel *model);
QString currentCardName() const;
/**
* @brief Get the KeySignals that are connected to this view.
* You can install the KeySignals as an eventFilter to capture keyboard shortcuts for adding and decrementing cards.
*/
KeySignals *getKeySignals()
{
return &searchKeySignals;
}
signals:
void cardChanged(const QString &cardName);
void cardAdded(const QString &cardName, const QString &zoneName);
void cardDecremented(const QString &cardName, const QString &zoneName);
void edhrecClicked(const CardInfoPtr &cardInfo, bool isCommander);
void selectPrintingClicked();
void relatedCardClicked(const QString &relatedCard);
private slots:
void actDoubleClick();
void addCard(const QString &zoneName);
void decrementCard(const QString &zoneName);
void updateCard(const QModelIndex &current, const QModelIndex &);
void resetSelectionIfEmpty();
void copyDatabaseCellContents() const;
void saveDbHeaderState();
void openCustomMenu(QPoint point);
};
#endif // COCKATRICE_CARD_DATABASE_VIEW_H

View file

@ -41,11 +41,6 @@ void DeckEditorCardDatabaseDockWidget::createDatabaseDisplayDock(AbstractTabDeck
&AbstractTabDeckEditor::updateCardInfo);
}
CardDatabase *DeckEditorCardDatabaseDockWidget::getDatabase() const
{
return databaseDisplayWidget->databaseModel->getDatabase();
}
void DeckEditorCardDatabaseDockWidget::retranslateUi()
{
setWindowTitle(tr("Card Database"));

View file

@ -17,7 +17,6 @@ public:
DeckEditorDatabaseDisplayWidget *databaseDisplayWidget;
CardDatabase *getDatabase() const;
void setFilterTree(FilterTree *filterTree);
public slots:

View file

@ -5,24 +5,17 @@
#include "../../../interface/widgets/tabs/abstract_tab_deck_editor.h"
#include "../../../interface/widgets/tabs/tab_supervisor.h"
#include "../../pixel_map_generator.h"
#include "card_database_view.h"
#include <QClipboard>
#include <QHeaderView>
#include <QMenu>
#include <QToolButton>
#include <QTreeView>
#include <libcockatrice/card/database/card_database_manager.h>
#include <libcockatrice/card/relation/card_relation.h>
static bool canBeCommander(const CardInfo &cardInfo)
{
return (cardInfo.getCardType().contains("Legendary", Qt::CaseInsensitive) &&
cardInfo.getCardType().contains("Creature", Qt::CaseInsensitive)) ||
cardInfo.getText().contains("can be your commander", Qt::CaseInsensitive);
}
DeckEditorDatabaseDisplayWidget::DeckEditorDatabaseDisplayWidget(QWidget *parent, CardDatabaseModel *databaseModel)
: QWidget(parent), databaseModel(databaseModel)
: QWidget(parent)
{
setObjectName("databaseDisplayWidget");
@ -36,26 +29,10 @@ DeckEditorDatabaseDisplayWidget::DeckEditorDatabaseDisplayWidget(QWidget *parent
searchEdit->setClearButtonEnabled(true);
searchEdit->addAction(loadColorAdjustedPixmap("theme:icons/search"), QLineEdit::LeadingPosition);
auto help = searchEdit->addAction(QPixmap("theme:icons/info"), QLineEdit::TrailingPosition);
searchEdit->installEventFilter(&searchKeySignals);
setFocusProxy(searchEdit);
setFocusPolicy(Qt::ClickFocus);
searchKeySignals.setObjectName("searchKeySignals");
connect(searchEdit, &SearchLineEdit::textChanged, this, &DeckEditorDatabaseDisplayWidget::updateSearch);
connect(&searchKeySignals, &KeySignals::onEnter, this, &DeckEditorDatabaseDisplayWidget::actAddCardToMainDeck);
connect(&searchKeySignals, &KeySignals::onCtrlAltEqual, this,
&DeckEditorDatabaseDisplayWidget::actAddCardToMainDeck);
connect(&searchKeySignals, &KeySignals::onCtrlAltRBracket, this,
&DeckEditorDatabaseDisplayWidget::actAddCardToSideboard);
connect(&searchKeySignals, &KeySignals::onCtrlAltMinus, this,
&DeckEditorDatabaseDisplayWidget::actDecrementCardFromMainDeck);
connect(&searchKeySignals, &KeySignals::onCtrlAltLBracket, this,
&DeckEditorDatabaseDisplayWidget::actDecrementCardFromSideboard);
connect(&searchKeySignals, &KeySignals::onCtrlAltEnter, this,
&DeckEditorDatabaseDisplayWidget::actAddCardToSideboard);
connect(&searchKeySignals, &KeySignals::onCtrlEnter, this, &DeckEditorDatabaseDisplayWidget::actAddCardToSideboard);
connect(&searchKeySignals, &KeySignals::onCtrlC, this, &DeckEditorDatabaseDisplayWidget::copyDatabaseCellContents);
connect(help, &QAction::triggered, this, [this] { createSearchSyntaxHelpWindow(searchEdit); });
databaseDisplayModel = new CardDatabaseDisplayModel(this);
@ -63,33 +40,23 @@ DeckEditorDatabaseDisplayWidget::DeckEditorDatabaseDisplayWidget(QWidget *parent
databaseDisplayModel->setSourceModel(databaseModel);
databaseDisplayModel->setFilterKeyColumn(0);
databaseView = new QTreeView(this);
databaseView = new CardDatabaseView(this, databaseDisplayModel);
databaseView->setObjectName("databaseView");
databaseView->setFocusProxy(searchEdit);
databaseView->setUniformRowHeights(true);
databaseView->setRootIsDecorated(false);
databaseView->setAlternatingRowColors(true);
databaseView->setSortingEnabled(true);
databaseView->sortByColumn(0, Qt::AscendingOrder);
databaseView->setModel(databaseDisplayModel);
databaseView->setContextMenuPolicy(Qt::CustomContextMenu);
connect(databaseView, &QTreeView::customContextMenuRequested, this,
&DeckEditorDatabaseDisplayWidget::databaseCustomMenu);
connect(databaseView->selectionModel(), &QItemSelectionModel::currentRowChanged, this,
&DeckEditorDatabaseDisplayWidget::updateCard);
connect(databaseView, &QTreeView::doubleClicked, this, &DeckEditorDatabaseDisplayWidget::actAddCard);
QByteArray dbHeaderState = SettingsCache::instance().layouts().getDeckEditorDbHeaderState();
if (dbHeaderState.isNull()) {
// first run
databaseView->setColumnWidth(0, 200);
} else {
databaseView->header()->restoreState(dbHeaderState);
}
connect(databaseView->header(), &QHeaderView::geometriesChanged, this,
&DeckEditorDatabaseDisplayWidget::saveDbHeaderState);
searchEdit->setTreeView(databaseView);
searchEdit->installEventFilter(databaseView->getKeySignals());
connect(searchEdit, &SearchLineEdit::textChanged, databaseDisplayModel, &CardDatabaseDisplayModel::setStringFilter);
connect(databaseView, &CardDatabaseView::cardAdded, this, &DeckEditorDatabaseDisplayWidget::addCard);
connect(databaseView, &CardDatabaseView::cardDecremented, this, &DeckEditorDatabaseDisplayWidget::decrementCard);
connect(databaseView, &CardDatabaseView::cardChanged, this, &DeckEditorDatabaseDisplayWidget::updateCard);
connect(databaseView, &CardDatabaseView::edhrecClicked, this, &DeckEditorDatabaseDisplayWidget::edhrecRequested);
connect(databaseView, &CardDatabaseView::selectPrintingClicked, this,
&DeckEditorDatabaseDisplayWidget::printingSelectorRequested);
connect(databaseView, &CardDatabaseView::relatedCardClicked, this,
&DeckEditorDatabaseDisplayWidget::onRelatedCardClicked);
aAddCard = new QAction(QString(), this);
aAddCard->setIcon(QPixmap("theme:icons/arrow_right_green"));
@ -115,131 +82,39 @@ DeckEditorDatabaseDisplayWidget::DeckEditorDatabaseDisplayWidget(QWidget *parent
retranslateUi();
}
void DeckEditorDatabaseDisplayWidget::updateSearch(const QString &search)
{
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 DeckEditorDatabaseDisplayWidget::clearAllDatabaseFilters()
{
databaseDisplayModel->clearFilterAll();
searchEdit->setText("");
}
void DeckEditorDatabaseDisplayWidget::updateCard(const QModelIndex &current, const QModelIndex & /*previous*/)
{
if (!current.isValid()) {
return;
}
const QString cardName = current.siblingAtColumn(CardDatabaseModel::NameColumn).data().toString();
if (!current.model()->hasChildren(current.siblingAtColumn(CardDatabaseModel::NameColumn))) {
emit cardChanged(CardDatabaseManager::query()->getPreferredCard(cardName));
}
}
void DeckEditorDatabaseDisplayWidget::actAddCard()
{
if (QApplication::keyboardModifiers() & Qt::ControlModifier) {
actAddCardToSideboard();
} else {
actAddCardToMainDeck();
}
}
void DeckEditorDatabaseDisplayWidget::actAddCardToMainDeck()
{
highlightAllSearchEdit();
emit cardAdded(currentCard(), DECK_ZONE_MAIN);
addCard(databaseView->currentCardName(), DECK_ZONE_MAIN);
}
void DeckEditorDatabaseDisplayWidget::actAddCardToSideboard()
{
addCard(databaseView->currentCardName(), DECK_ZONE_SIDE);
}
void DeckEditorDatabaseDisplayWidget::addCard(const QString &cardName, const QString &zoneName)
{
highlightAllSearchEdit();
emit cardAdded(currentCard(), DECK_ZONE_SIDE);
ExactCard exactCard = CardDatabaseManager::query()->getPreferredCard(cardName);
emit cardAdded(exactCard, zoneName);
}
void DeckEditorDatabaseDisplayWidget::actDecrementCardFromMainDeck()
void DeckEditorDatabaseDisplayWidget::decrementCard(const QString &cardName, const QString &zoneName)
{
emit cardDecremented(currentCard(), DECK_ZONE_MAIN);
ExactCard exactCard = CardDatabaseManager::query()->getPreferredCard(cardName);
emit cardDecremented(exactCard, zoneName);
}
void DeckEditorDatabaseDisplayWidget::actDecrementCardFromSideboard()
void DeckEditorDatabaseDisplayWidget::updateCard(const QString &cardName)
{
emit cardDecremented(currentCard(), DECK_ZONE_SIDE);
}
ExactCard DeckEditorDatabaseDisplayWidget::currentCard() const
{
const QModelIndex currentIndex = databaseView->selectionModel()->currentIndex();
if (!currentIndex.isValid()) {
return {};
}
const QString cardName = currentIndex.siblingAtColumn(CardDatabaseModel::NameColumn).data().toString();
return CardDatabaseManager::query()->getPreferredCard(cardName);
}
void DeckEditorDatabaseDisplayWidget::databaseCustomMenu(QPoint point)
{
QMenu menu;
ExactCard card = currentCard();
if (card) {
// add to deck and sideboard options
QAction *addToDeck, *addToSideboard, *selectPrinting, *edhRecCommander, *edhRecCard;
addToDeck = menu.addAction(tr("Add to Deck"));
addToSideboard = menu.addAction(tr("Add to Sideboard"));
selectPrinting = menu.addAction(tr("Select Printing"));
connect(selectPrinting, &QAction::triggered, this, &DeckEditorDatabaseDisplayWidget::printingSelectorRequested);
if (canBeCommander(card.getInfo())) {
edhRecCommander = menu.addAction(tr("Show on EDHRec (Commander)"));
connect(edhRecCommander, &QAction::triggered, this,
[this, card] { emit edhrecRequested(card.getCardPtr(), true); });
}
edhRecCard = menu.addAction(tr("Show on EDHRec (Card)"));
connect(addToDeck, &QAction::triggered, this, &DeckEditorDatabaseDisplayWidget::actAddCardToMainDeck);
connect(addToSideboard, &QAction::triggered, this, &DeckEditorDatabaseDisplayWidget::actAddCardToSideboard);
connect(edhRecCard, &QAction::triggered, this,
[this, card] { emit edhrecRequested(card.getCardPtr(), false); });
// filling out the related cards submenu
auto *relatedMenu = new QMenu(tr("Show Related cards"));
menu.addMenu(relatedMenu);
auto relatedCards = card.getInfo().getAllRelatedCards();
if (relatedCards.isEmpty()) {
relatedMenu->setDisabled(true);
} else {
for (const CardRelation *rel : relatedCards) {
const QString &relatedCardName = rel->getName();
QAction *relatedCard = relatedMenu->addAction(relatedCardName);
connect(relatedCard, &QAction::triggered, this, [this, relatedCardName] {
ExactCard card = CardDatabaseManager::query()->guessCard({relatedCardName});
emit cardInfoRequested(card);
});
}
}
menu.exec(databaseView->mapToGlobal(point));
}
}
void DeckEditorDatabaseDisplayWidget::copyDatabaseCellContents()
{
auto _data = databaseView->selectionModel()->currentIndex().data();
QApplication::clipboard()->setText(_data.toString());
}
void DeckEditorDatabaseDisplayWidget::saveDbHeaderState()
{
SettingsCache::instance().layouts().setDeckEditorDbHeaderState(databaseView->header()->saveState());
ExactCard exactCard = CardDatabaseManager::query()->getPreferredCard(cardName);
emit cardChanged(exactCard);
}
void DeckEditorDatabaseDisplayWidget::setFilterTree(FilterTree *filterTree)
@ -256,4 +131,10 @@ void DeckEditorDatabaseDisplayWidget::retranslateUi()
void DeckEditorDatabaseDisplayWidget::highlightAllSearchEdit()
{
searchEdit->setSelection(0, searchEdit->text().length());
}
void DeckEditorDatabaseDisplayWidget::onRelatedCardClicked(const QString &relatedCard)
{
ExactCard exactCard = CardDatabaseManager::query()->guessCard({relatedCard});
emit cardInfoRequested(exactCard);
}

View file

@ -9,7 +9,6 @@
#define DECK_EDITOR_DATABASE_DISPLAY_WIDGET_H
#include "../../../interface/widgets/tabs/abstract_tab_deck_editor.h"
#include "../../key_signals.h"
#include "../utility/custom_line_edit.h"
#include <QHBoxLayout>
@ -17,34 +16,31 @@
#include <libcockatrice/models/database/card_database_display_model.h>
#include <libcockatrice/models/database/card_database_model.h>
class CardDatabaseView;
class AbstractTabDeckEditor;
class DeckEditorDatabaseDisplayWidget : public QWidget
{
Q_OBJECT
public:
explicit DeckEditorDatabaseDisplayWidget(QWidget *parent, CardDatabaseModel *databaseModel);
CardDatabaseModel *databaseModel;
CardDatabaseDisplayModel *databaseDisplayModel;
QTreeView *getDatabaseView()
CardDatabaseView *getDatabaseView() const
{
return databaseView;
}
public slots:
ExactCard currentCard() const;
void setFilterTree(FilterTree *filterTree);
void clearAllDatabaseFilters();
void updateSearch(const QString &search);
void updateCard(const QModelIndex &current, const QModelIndex &);
void actAddCard();
void actAddCardToMainDeck();
void actAddCardToSideboard();
void actDecrementCardFromMainDeck();
void actDecrementCardFromSideboard();
void databaseCustomMenu(QPoint point);
void copyDatabaseCellContents();
void addCard(const QString &cardName, const QString &zoneName);
void decrementCard(const QString &cardName, const QString &zoneName);
void updateCard(const QString &cardName);
signals:
void cardAdded(const ExactCard &card, const QString &zoneName);
@ -56,8 +52,8 @@ signals:
void cardInfoRequested(const ExactCard &card);
private:
KeySignals searchKeySignals;
QTreeView *databaseView;
CardDatabaseDisplayModel *databaseDisplayModel;
CardDatabaseView *databaseView;
QHBoxLayout *searchLayout;
SearchLineEdit *searchEdit;
QAction *aAddCard, *aAddCardToSideboard;
@ -68,7 +64,8 @@ private:
private slots:
void retranslateUi();
void saveDbHeaderState();
void onRelatedCardClicked(const QString &relatedCard);
};
#endif // DECK_EDITOR_DATABASE_DISPLAY_WIDGET_H