[TabDeckEditor] Create class to centralize deck state (#6459)

* create new file

* use QSharedPointer in DeckListModel

* [TabDeckEditor] Create class to centralize deck state

* delete method

* update docs
This commit is contained in:
RickyRister 2025-12-31 08:54:47 -08:00 committed by GitHub
parent 0085015ebe
commit b2dd8eed3f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
31 changed files with 933 additions and 577 deletions

View file

@ -156,6 +156,7 @@ set(cockatrice_SOURCES
src/interface/widgets/deck_editor/deck_editor_filter_dock_widget.cpp
src/interface/widgets/deck_editor/deck_editor_printing_selector_dock_widget.cpp
src/interface/widgets/deck_editor/deck_list_style_proxy.cpp
src/interface/widgets/deck_editor/deck_state_manager.cpp
src/interface/widgets/general/background_sources.cpp
src/interface/widgets/general/display/background_plate_widget.cpp
src/interface/widgets/general/display/banner_widget.cpp

View file

@ -1,8 +1,8 @@
#include "deck_editor_deck_dock_widget.h"
#include "../../../client/settings/cache_settings.h"
#include "../../deck_loader/deck_loader.h"
#include "deck_list_style_proxy.h"
#include "deck_state_manager.h"
#include <QComboBox>
#include <QDockWidget>
@ -38,7 +38,7 @@ static int findRestoreIndex(const CardRef &wanted, const QComboBox *combo)
}
DeckEditorDeckDockWidget::DeckEditorDeckDockWidget(AbstractTabDeckEditor *parent)
: QDockWidget(parent), deckEditor(parent)
: QDockWidget(parent), deckEditor(parent), deckStateManager(parent->deckStateManager)
{
setObjectName("deckDock");
@ -52,19 +52,19 @@ DeckEditorDeckDockWidget::DeckEditorDeckDockWidget(AbstractTabDeckEditor *parent
void DeckEditorDeckDockWidget::createDeckDock()
{
deckModel = new DeckListModel(this);
deckModel->setObjectName("deckModel");
connect(deckModel, &DeckListModel::deckHashChanged, this, &DeckEditorDeckDockWidget::updateHash);
deckLoader = new DeckLoader(this);
connect(getModel(), &DeckListModel::deckHashChanged, this, &DeckEditorDeckDockWidget::updateHash);
proxy = new DeckListStyleProxy(this);
proxy->setSourceModel(deckModel);
proxy->setSourceModel(getModel());
historyManagerWidget = new DeckListHistoryManagerWidget(deckModel, proxy, deckEditor->getHistoryManager(), this);
historyManagerWidget = new DeckListHistoryManagerWidget(deckStateManager, proxy, this);
connect(historyManagerWidget, &DeckListHistoryManagerWidget::requestDisplayWidgetSync, this,
&DeckEditorDeckDockWidget::syncDisplayWidgetsToModel);
connect(deckStateManager, &DeckStateManager::focusIndexChanged, this, &DeckEditorDeckDockWidget::setSelectedIndex);
connect(deckStateManager, &DeckStateManager::deckReplaced, this,
&DeckEditorDeckDockWidget::syncDisplayWidgetsToModel);
deckView = new QTreeView();
deckView->setObjectName("deckView");
deckView->setModel(proxy);
@ -97,7 +97,7 @@ void DeckEditorDeckDockWidget::createDeckDock()
nameDebounceTimer = new QTimer(this);
nameDebounceTimer->setSingleShot(true);
nameDebounceTimer->setInterval(300); // debounce duration in ms
connect(nameDebounceTimer, &QTimer::timeout, this, [this]() { updateName(nameEdit->text()); });
connect(nameDebounceTimer, &QTimer::timeout, this, &DeckEditorDeckDockWidget::writeName);
connect(nameEdit, &LineEditUnfocusable::textChanged, this, [this]() {
nameDebounceTimer->start(); // restart debounce timer
@ -141,7 +141,7 @@ void DeckEditorDeckDockWidget::createDeckDock()
commentsDebounceTimer = new QTimer(this);
commentsDebounceTimer->setSingleShot(true);
commentsDebounceTimer->setInterval(400); // longer debounce for multi-line
connect(commentsDebounceTimer, &QTimer::timeout, this, [this]() { updateComments(); });
connect(commentsDebounceTimer, &QTimer::timeout, this, &DeckEditorDeckDockWidget::writeComments);
connect(commentsEdit, &QTextEdit::textChanged, this, [this]() {
commentsDebounceTimer->start(); // restart debounce timer
@ -152,21 +152,21 @@ void DeckEditorDeckDockWidget::createDeckDock()
bannerCardLabel->setText(tr("Banner Card"));
bannerCardLabel->setHidden(!SettingsCache::instance().getDeckEditorBannerCardComboBoxVisible());
bannerCardComboBox = new QComboBox(this);
connect(deckModel, &DeckListModel::dataChanged, this, [this]() {
connect(getModel(), &DeckListModel::dataChanged, this, [this]() {
// Delay the update to avoid race conditions
QTimer::singleShot(100, this, &DeckEditorDeckDockWidget::updateBannerCardComboBox);
});
connect(deckModel, &DeckListModel::cardAddedAt, this, &DeckEditorDeckDockWidget::recursiveExpand);
connect(deckModel, &DeckListModel::modelReset, this, &DeckEditorDeckDockWidget::expandAll);
connect(getModel(), &DeckListModel::cardAddedAt, this, &DeckEditorDeckDockWidget::recursiveExpand);
connect(getModel(), &DeckListModel::modelReset, this, &DeckEditorDeckDockWidget::expandAll);
connect(bannerCardComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
&DeckEditorDeckDockWidget::setBannerCard);
&DeckEditorDeckDockWidget::writeBannerCard);
bannerCardComboBox->setHidden(!SettingsCache::instance().getDeckEditorBannerCardComboBoxVisible());
deckTagsDisplayWidget = new DeckPreviewDeckTagsDisplayWidget(this, deckModel->getDeckList()->getTags());
deckTagsDisplayWidget = new DeckPreviewDeckTagsDisplayWidget(this, {});
deckTagsDisplayWidget->setHidden(!SettingsCache::instance().getDeckEditorTagsWidgetVisible());
connect(deckTagsDisplayWidget, &DeckPreviewDeckTagsDisplayWidget::tagsChanged, this,
&DeckEditorDeckDockWidget::setTags);
connect(deckTagsDisplayWidget, &DeckPreviewDeckTagsDisplayWidget::tagsChanged, deckStateManager,
&DeckStateManager::setTags);
activeGroupCriteriaLabel = new QLabel(this);
@ -175,9 +175,9 @@ void DeckEditorDeckDockWidget::createDeckDock()
activeGroupCriteriaComboBox->addItem(tr("Mana Cost"), DeckListModelGroupCriteria::MANA_COST);
activeGroupCriteriaComboBox->addItem(tr("Colors"), DeckListModelGroupCriteria::COLOR);
connect(activeGroupCriteriaComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged), [this]() {
deckModel->setActiveGroupCriteria(static_cast<DeckListModelGroupCriteria::Type>(
getModel()->setActiveGroupCriteria(static_cast<DeckListModelGroupCriteria::Type>(
activeGroupCriteriaComboBox->currentData(Qt::UserRole).toInt()));
deckModel->sort(deckView->header()->sortIndicatorSection(), deckView->header()->sortIndicatorOrder());
getModel()->sort(deckView->header()->sortIndicatorSection(), deckView->header()->sortIndicatorOrder());
});
aIncrement = new QAction(QString(), this);
@ -295,9 +295,10 @@ void DeckEditorDeckDockWidget::initializeFormats()
formatComboBox->addItem(formatName, formatName); // store the raw key in itemData
}
if (!deckModel->getDeckList()->getGameFormat().isEmpty()) {
deckModel->setActiveFormat(deckModel->getDeckList()->getGameFormat());
formatComboBox->setCurrentIndex(formatComboBox->findData(deckModel->getDeckList()->getGameFormat()));
QString format = deckStateManager->getMetadata().gameFormat;
if (!format.isEmpty()) {
getModel()->setActiveFormat(format);
formatComboBox->setCurrentIndex(formatComboBox->findData(format));
} else {
// Ensure no selection is visible initially
formatComboBox->setCurrentIndex(-1);
@ -306,11 +307,10 @@ void DeckEditorDeckDockWidget::initializeFormats()
connect(formatComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged), this, [this](int index) {
if (index >= 0) {
QString formatKey = formatComboBox->itemData(index).toString();
deckModel->setActiveFormat(formatKey);
deckStateManager->setFormat(formatKey);
} else {
deckModel->setActiveFormat(QString()); // clear format if deselected
deckStateManager->setFormat(""); // clear format if deselected
}
emit deckModified();
});
}
@ -340,43 +340,37 @@ ExactCard DeckEditorDeckDockWidget::getCurrentCard()
void DeckEditorDeckDockWidget::updateCard(const QModelIndex /*&current*/, const QModelIndex & /*previous*/)
{
if (ExactCard card = getCurrentCard()) {
emit cardChanged(card);
emit selectedCardChanged(card);
}
}
void DeckEditorDeckDockWidget::updateName(const QString &name)
/**
* @brief Writes the contents of the name textBox to the DeckStateManager
*/
void DeckEditorDeckDockWidget::writeName()
{
emit requestDeckHistorySave(
QString(tr("Rename deck to \"%1\" from \"%2\"")).arg(name).arg(deckLoader->getDeck().deckList.getName()));
deckModel->getDeckList()->setName(name);
deckEditor->setModified(name.isEmpty());
emit nameChanged();
emit deckModified();
QString name = nameEdit->text();
deckStateManager->setName(name);
}
void DeckEditorDeckDockWidget::updateComments()
/**
* @brief Writes the contents of the comments textBox to the DeckStateManager
*/
void DeckEditorDeckDockWidget::writeComments()
{
emit requestDeckHistorySave(tr("Updated comments (was %1 chars, now %2 chars)")
.arg(deckLoader->getDeck().deckList.getComments().size())
.arg(commentsEdit->toPlainText().size()));
deckModel->getDeckList()->setComments(commentsEdit->toPlainText());
deckEditor->setModified(commentsEdit->toPlainText().isEmpty());
emit commentsChanged();
emit deckModified();
QString comments = commentsEdit->toPlainText();
deckStateManager->setComments(comments);
}
void DeckEditorDeckDockWidget::updateHash()
{
hashLabel->setText(deckModel->getDeckList()->getDeckHash());
emit hashChanged();
emit deckModified();
hashLabel->setText(deckStateManager->getDeckHash());
}
void DeckEditorDeckDockWidget::updateBannerCardComboBox()
{
// Store current banner card identity
CardRef wanted = deckModel->getDeckList()->getBannerCard();
CardRef wanted = deckStateManager->getMetadata().bannerCard;
// Block signals temporarily
bool wasBlocked = bannerCardComboBox->blockSignals(true);
@ -386,7 +380,7 @@ void DeckEditorDeckDockWidget::updateBannerCardComboBox()
// Collect unique (name, providerId) pairs
QSet<QPair<QString, QString>> bannerCardSet;
QList<CardRef> cardsInDeck = deckModel->getCardRefs();
QList<CardRef> cardsInDeck = getModel()->getCardRefs();
for (auto cardRef : cardsInDeck) {
if (!CardDatabaseManager::query()->getCard(cardRef)) {
@ -415,7 +409,6 @@ void DeckEditorDeckDockWidget::updateBannerCardComboBox()
// Handle results
if (restoreIndex != -1) {
bannerCardComboBox->setCurrentIndex(restoreIndex);
syncDeckListBannerCardWithComboBox();
} else {
// Add a placeholder "-" and set it as the current selection
bannerCardComboBox->insertItem(0, "-");
@ -426,25 +419,14 @@ void DeckEditorDeckDockWidget::updateBannerCardComboBox()
bannerCardComboBox->blockSignals(wasBlocked);
}
void DeckEditorDeckDockWidget::setBannerCard(int /* changedIndex */)
/**
* @brief Writes the selected bannerCard to the DeckStateManager
*/
void DeckEditorDeckDockWidget::writeBannerCard(int index)
{
emit requestDeckHistorySave(tr("Banner card changed"));
syncDeckListBannerCardWithComboBox();
deckEditor->setModified(true);
emit deckModified();
}
void DeckEditorDeckDockWidget::setTags(const QStringList &tags)
{
deckModel->getDeckList()->setTags(tags);
deckEditor->setModified(true);
emit deckModified();
}
void DeckEditorDeckDockWidget::syncDeckListBannerCardWithComboBox()
{
auto [name, id] = bannerCardComboBox->currentData().value<QPair<QString, QString>>();
deckModel->getDeckList()->setBannerCard({name, id});
auto [name, id] = bannerCardComboBox->itemData(index).value<QPair<QString, QString>>();
CardRef bannerCard = {name, id};
deckStateManager->setBannerCard(bannerCard);
}
void DeckEditorDeckDockWidget::updateShowBannerCardComboBox(const bool visible)
@ -460,7 +442,7 @@ void DeckEditorDeckDockWidget::updateShowTagsWidget(const bool visible)
void DeckEditorDeckDockWidget::syncBannerCardComboBoxSelectionWithDeck()
{
if (deckModel->getDeckList()->getBannerCard().name == "") {
if (deckStateManager->getMetadata().bannerCard.name == "") {
if (bannerCardComboBox->findText("-") != -1) {
bannerCardComboBox->setCurrentIndex(bannerCardComboBox->findText("-"));
} else {
@ -468,36 +450,26 @@ void DeckEditorDeckDockWidget::syncBannerCardComboBoxSelectionWithDeck()
bannerCardComboBox->setCurrentIndex(0);
}
} else {
bannerCardComboBox->setCurrentText(deckModel->getDeckList()->getBannerCard().name);
bannerCardComboBox->setCurrentText(deckStateManager->getMetadata().bannerCard.name);
}
}
/**
* Sets the currently active deck for this tab
* @param _deck The deck.
*/
void DeckEditorDeckDockWidget::setDeck(const LoadedDeck &_deck)
void DeckEditorDeckDockWidget::setSelectedIndex(const QModelIndex &newCardIndex)
{
deckLoader->setDeck(_deck);
deckModel->setDeckList(&deckLoader->getDeck().deckList);
connect(deckLoader, &DeckLoader::deckLoaded, deckModel, &DeckListModel::rebuildTree);
emit requestDeckHistoryClear();
historyManagerWidget->setDeckListModel(deckModel);
syncDisplayWidgetsToModel();
emit deckChanged();
deckView->clearSelection();
deckView->setCurrentIndex(newCardIndex);
recursiveExpand(newCardIndex);
deckView->setFocus(Qt::FocusReason::MouseFocusReason);
}
void DeckEditorDeckDockWidget::syncDisplayWidgetsToModel()
{
nameEdit->blockSignals(true);
nameEdit->setText(deckModel->getDeckList()->getName());
nameEdit->setText(deckStateManager->getMetadata().name);
nameEdit->blockSignals(false);
commentsEdit->blockSignals(true);
commentsEdit->setText(deckModel->getDeckList()->getComments());
commentsEdit->setText(deckStateManager->getMetadata().comments);
commentsEdit->blockSignals(false);
bannerCardComboBox->blockSignals(true);
@ -507,44 +479,22 @@ void DeckEditorDeckDockWidget::syncDisplayWidgetsToModel()
updateHash();
sortDeckModelToDeckView();
deckTagsDisplayWidget->setTags(deckModel->getDeckList()->getTags());
deckTagsDisplayWidget->setTags(deckStateManager->getMetadata().tags);
}
void DeckEditorDeckDockWidget::sortDeckModelToDeckView()
{
deckModel->sort(deckView->header()->sortIndicatorSection(), deckView->header()->sortIndicatorOrder());
deckModel->setActiveFormat(deckModel->getDeckList()->getGameFormat());
formatComboBox->setCurrentIndex(formatComboBox->findData(deckModel->getDeckList()->getGameFormat()));
emit deckChanged();
}
DeckLoader *DeckEditorDeckDockWidget::getDeckLoader()
{
return deckLoader;
}
const DeckList &DeckEditorDeckDockWidget::getDeckList() const
{
return *deckModel->getDeckList();
getModel()->sort(deckView->header()->sortIndicatorSection(), deckView->header()->sortIndicatorOrder());
getModel()->setActiveFormat(deckStateManager->getMetadata().gameFormat);
formatComboBox->setCurrentIndex(formatComboBox->findData(deckStateManager->getMetadata().gameFormat));
}
/**
* Resets the tab to the state for a blank new tab.
* @brief Convenience method to get the underlying model instance from the DeckStateManager
*/
void DeckEditorDeckDockWidget::cleanDeck()
DeckListModel *DeckEditorDeckDockWidget::getModel() const
{
deckModel->cleanList();
nameEdit->setText(QString());
emit nameChanged();
commentsEdit->setText(QString());
emit commentsChanged();
hashLabel->setText(QString());
emit hashChanged();
emit deckModified();
emit deckChanged();
updateBannerCardComboBox();
deckTagsDisplayWidget->setTags(deckModel->getDeckList()->getTags());
return deckStateManager->getModel();
}
void DeckEditorDeckDockWidget::selectPrevCard()
@ -635,7 +585,7 @@ QModelIndexList DeckEditorDeckDockWidget::getSelectedCardNodes() const
auto selectedRows = deckView->selectionModel()->selectedRows();
const auto notLeafNode = [this](const QModelIndex &index) {
return deckModel->hasChildren(proxy->mapToSource(index));
return getModel()->hasChildren(proxy->mapToSource(index));
};
selectedRows.erase(std::remove_if(selectedRows.begin(), selectedRows.end(), notLeafNode), selectedRows.end());
@ -650,21 +600,7 @@ void DeckEditorDeckDockWidget::actAddCard(const ExactCard &card, const QString &
}
QString zoneName = card.getInfo().getIsToken() ? DECK_ZONE_TOKENS : _zoneName;
emit requestDeckHistorySave(tr("Added (%1): %2 (%3) %4")
.arg(zoneName, card.getName(), card.getPrinting().getSet()->getCorrectedShortName(),
card.getPrinting().getProperty("num")));
QModelIndex newCardIndex = deckModel->addCard(card, zoneName);
if (!newCardIndex.isValid()) {
return;
}
deckView->clearSelection();
deckView->setCurrentIndex(newCardIndex);
emit deckModified();
deckStateManager->addCard(card, zoneName);
}
void DeckEditorDeckDockWidget::actIncrementSelection()
@ -681,12 +617,12 @@ void DeckEditorDeckDockWidget::actSwapCard(const ExactCard &card, const QString
QString providerId = card.getPrinting().getUuid();
QString collectorNumber = card.getPrinting().getProperty("num");
QModelIndex foundCard = deckModel->findCard(card.getName(), zoneName, providerId, collectorNumber);
QModelIndex foundCard = getModel()->findCard(card.getName(), zoneName, providerId, collectorNumber);
if (!foundCard.isValid()) {
foundCard = deckModel->findCard(card.getName(), zoneName);
foundCard = getModel()->findCard(card.getName(), zoneName);
}
swapCard(foundCard);
deckStateManager->swapCardAtIndex(foundCard);
}
void DeckEditorDeckDockWidget::actSwapSelection()
@ -699,54 +635,15 @@ void DeckEditorDeckDockWidget::actSwapSelection()
deckView->setSelectionMode(QAbstractItemView::SingleSelection);
}
bool isModified = false;
for (const auto &currentIndex : selectedRows) {
if (swapCard(currentIndex)) {
isModified = true;
}
deckStateManager->swapCardAtIndex(currentIndex);
}
deckView->setSelectionMode(QAbstractItemView::ExtendedSelection);
if (isModified) {
emit deckModified();
}
update();
}
/**
* Swaps the card at the index between the maindeck and sideboard
*
* @param currentIndex The index to swap.
* @return True if the swap was successful
*/
bool DeckEditorDeckDockWidget::swapCard(const QModelIndex &currentIndex)
{
if (!currentIndex.isValid())
return false;
const QString cardName = currentIndex.siblingAtColumn(DeckListModelColumns::CARD_NAME).data().toString();
const QString cardProviderID =
currentIndex.siblingAtColumn(DeckListModelColumns::CARD_PROVIDER_ID).data().toString();
const QModelIndex gparent = currentIndex.parent().parent();
if (!gparent.isValid())
return false;
const QString zoneName = gparent.siblingAtColumn(DeckListModelColumns::CARD_NAME).data(Qt::EditRole).toString();
offsetCountAtIndex(currentIndex, false);
const QString otherZoneName = zoneName == DECK_ZONE_MAIN ? DECK_ZONE_SIDE : DECK_ZONE_MAIN;
if (ExactCard card = CardDatabaseManager::query()->getCard({cardName, cardProviderID})) {
deckModel->addCard(card, otherZoneName);
} else {
// Third argument (true) says create the card no matter what, even if not in DB
deckModel->addPreferredPrintingCard(cardName, otherZoneName, true);
}
return true;
}
void DeckEditorDeckDockWidget::actDecrementCard(const ExactCard &card, QString zoneName)
{
if (!card)
@ -754,17 +651,7 @@ void DeckEditorDeckDockWidget::actDecrementCard(const ExactCard &card, QString z
if (card.getInfo().getIsToken())
zoneName = DECK_ZONE_TOKENS;
QString providerId = card.getPrinting().getUuid();
QString collectorNumber = card.getPrinting().getProperty("num");
QModelIndex idx = deckModel->findCard(card.getName(), zoneName, providerId, collectorNumber);
if (!idx.isValid()) {
return;
}
deckView->clearSelection();
deckView->setCurrentIndex(proxy->mapToSource(idx));
offsetCountAtIndex(idx, false);
deckStateManager->decrementCard(card, zoneName);
}
void DeckEditorDeckDockWidget::actDecrementSelection()
@ -794,25 +681,11 @@ void DeckEditorDeckDockWidget::actRemoveCard()
deckView->setSelectionMode(QAbstractItemView::SingleSelection);
}
bool isModified = false;
for (const auto &index : selectedRows) {
if (!index.isValid() || deckModel->hasChildren(index)) {
continue;
}
QModelIndex sourceIndex = proxy->mapToSource(index);
QString cardName = sourceIndex.siblingAtColumn(DeckListModelColumns::CARD_NAME).data().toString();
emit requestDeckHistorySave(QString(tr("Removed \"%1\" (all copies)")).arg(cardName));
deckModel->removeRow(sourceIndex.row(), sourceIndex.parent());
isModified = true;
for (const auto &row : selectedRows) {
deckStateManager->removeCardAtIndex(row);
}
deckView->setSelectionMode(QAbstractItemView::ExtendedSelection);
if (isModified) {
emit deckModified();
}
}
/**
@ -822,28 +695,17 @@ void DeckEditorDeckDockWidget::actRemoveCard()
*/
void DeckEditorDeckDockWidget::offsetCountAtIndex(const QModelIndex &idx, bool isIncrement)
{
if (!idx.isValid() || deckModel->hasChildren(idx)) {
if (!idx.isValid() || getModel()->hasChildren(idx)) {
return;
}
QModelIndex sourceIndex = proxy->mapToSource(idx);
QString cardName = sourceIndex.siblingAtColumn(DeckListModelColumns::CARD_NAME).data(Qt::EditRole).toString();
QString providerId =
sourceIndex.siblingAtColumn(DeckListModelColumns::CARD_PROVIDER_ID).data(Qt::DisplayRole).toString();
const auto reason = QString(tr("%1 %2 × \"%3\" (%4)"))
.arg(isIncrement ? tr("Added") : tr("Removed"))
.arg(1)
.arg(cardName)
.arg(providerId);
emit requestDeckHistorySave(reason);
int offset = isIncrement ? 1 : -1;
deckModel->offsetCountAtIndex(sourceIndex, offset);
emit deckModified();
if (isIncrement) {
deckStateManager->incrementCountAtIndex(sourceIndex);
} else {
deckStateManager->decrementCountAtIndex(sourceIndex);
}
}
void DeckEditorDeckDockWidget::decklistCustomMenu(QPoint point)

View file

@ -28,22 +28,14 @@ class DeckEditorDeckDockWidget : public QDockWidget
Q_OBJECT
public:
explicit DeckEditorDeckDockWidget(AbstractTabDeckEditor *parent);
DeckLoader *deckLoader;
DeckListStyleProxy *proxy;
DeckListModel *deckModel;
QTreeView *deckView;
QComboBox *bannerCardComboBox;
void createDeckDock();
ExactCard getCurrentCard();
void retranslateUi();
QString getDeckName()
{
return nameEdit->text();
}
QString getSimpleDeckName()
{
return nameEdit->text().simplified();
}
QComboBox *getGroupByComboBox()
{
return activeGroupCriteriaComboBox;
@ -55,15 +47,11 @@ public:
}
public slots:
void cleanDeck();
void selectPrevCard();
void selectNextCard();
void updateBannerCardComboBox();
void setDeck(const LoadedDeck &_deck);
void syncDisplayWidgetsToModel();
void sortDeckModelToDeckView();
DeckLoader *getDeckLoader();
const DeckList &getDeckList() const;
void actAddCard(const ExactCard &card, const QString &zoneName);
void actIncrementSelection();
void actDecrementCard(const ExactCard &card, QString zoneName);
@ -74,17 +62,12 @@ public slots:
void initializeFormats();
signals:
void nameChanged();
void commentsChanged();
void hashChanged();
void deckChanged();
void deckModified();
void requestDeckHistorySave(const QString &modificationReason);
void requestDeckHistoryClear();
void cardChanged(const ExactCard &_card);
void selectedCardChanged(const ExactCard &card);
private:
AbstractTabDeckEditor *deckEditor;
DeckStateManager *deckStateManager;
DeckListHistoryManagerWidget *historyManagerWidget;
KeySignals deckViewKeySignals;
QLabel *nameLabel;
@ -107,18 +90,17 @@ private:
QAction *aRemoveCard, *aIncrement, *aDecrement, *aSwapCard;
DeckListModel *getModel() const;
[[nodiscard]] QModelIndexList getSelectedCardNodes() const;
void offsetCountAtIndex(const QModelIndex &idx, bool isIncrement);
private slots:
void decklistCustomMenu(QPoint point);
bool swapCard(const QModelIndex &currentIndex);
void updateCard(QModelIndex, const QModelIndex &current);
void updateName(const QString &name);
void updateComments();
void setBannerCard(int);
void setTags(const QStringList &tags);
void syncDeckListBannerCardWithComboBox();
void writeName();
void writeComments();
void writeBannerCard(int);
void setSelectedIndex(const QModelIndex &newCardIndex);
void updateHash();
void refreshShortcuts();
void updateShowBannerCardComboBox(bool visible);

View file

@ -1,10 +1,11 @@
#include "deck_list_history_manager_widget.h"
DeckListHistoryManagerWidget::DeckListHistoryManagerWidget(DeckListModel *_deckListModel,
#include "deck_state_manager.h"
DeckListHistoryManagerWidget::DeckListHistoryManagerWidget(DeckStateManager *_deckStateManager,
DeckListStyleProxy *_styleProxy,
DeckListHistoryManager *manager,
QWidget *parent)
: QWidget(parent), deckListModel(_deckListModel), styleProxy(_styleProxy), historyManager(manager)
: QWidget(parent), deckStateManager(_deckStateManager), styleProxy(_styleProxy)
{
layout = new QHBoxLayout(this);
@ -43,8 +44,7 @@ DeckListHistoryManagerWidget::DeckListHistoryManagerWidget(DeckListModel *_deckL
connect(historyList, &QListWidget::itemClicked, this, &DeckListHistoryManagerWidget::onListClicked);
connect(historyManager, &DeckListHistoryManager::undoRedoStateChanged, this,
&DeckListHistoryManagerWidget::refreshList);
connect(deckStateManager, &DeckStateManager::historyChanged, this, &DeckListHistoryManagerWidget::refreshList);
refreshList();
retranslateUi();
@ -58,15 +58,12 @@ void DeckListHistoryManagerWidget::retranslateUi()
historyLabel->setText(tr("Click on an entry to revert to that point in the history."));
}
void DeckListHistoryManagerWidget::setDeckListModel(DeckListModel *_deckListModel)
{
deckListModel = _deckListModel;
}
void DeckListHistoryManagerWidget::refreshList()
{
historyList->clear();
DeckListHistoryManager *historyManager = deckStateManager->getHistoryManager();
// Fill redo section first (oldest redo at top, newest redo closest to divider)
const auto redoStack = historyManager->getRedoStack();
for (int i = 0; i < redoStack.size(); ++i) { // iterate forward
@ -98,36 +95,7 @@ void DeckListHistoryManagerWidget::refreshList()
redoButton->setEnabled(historyManager->canRedo());
}
void DeckListHistoryManagerWidget::doUndo()
{
if (!historyManager->canUndo()) {
return;
}
historyManager->undo(deckListModel->getDeckList());
deckListModel->rebuildTree();
emit deckListModel->layoutChanged();
emit requestDisplayWidgetSync();
refreshList();
}
void DeckListHistoryManagerWidget::doRedo()
{
if (!historyManager->canRedo()) {
return;
}
historyManager->redo(deckListModel->getDeckList());
deckListModel->rebuildTree();
emit deckListModel->layoutChanged();
emit requestDisplayWidgetSync();
refreshList();
}
void DeckListHistoryManagerWidget::onListClicked(QListWidgetItem *item)
void DeckListHistoryManagerWidget::onListClicked(const QListWidgetItem *item)
{
// Ignore non-selectable items (like divider)
if (!(item->flags() & Qt::ItemIsSelectable)) {
@ -138,23 +106,24 @@ void DeckListHistoryManagerWidget::onListClicked(QListWidgetItem *item)
int index = item->data(Qt::UserRole + 1).toInt();
if (mode == "redo") {
const auto redoStack = historyManager->getRedoStack();
const auto redoStack = deckStateManager->getHistoryManager()->getRedoStack();
int steps = redoStack.size() - index;
for (int i = 0; i < steps; ++i) {
historyManager->redo(deckListModel->getDeckList());
}
deckStateManager->redo(steps);
} else if (mode == "undo") {
const auto undoStack = historyManager->getUndoStack();
int steps = undoStack.size() - 1 - index;
for (int i = 0; i < steps + 1; ++i) {
historyManager->undo(deckListModel->getDeckList());
}
const auto undoStack = deckStateManager->getHistoryManager()->getUndoStack();
int steps = undoStack.size() - index;
deckStateManager->undo(steps);
}
deckListModel->rebuildTree();
emit deckListModel->layoutChanged();
emit requestDisplayWidgetSync();
refreshList();
}
void DeckListHistoryManagerWidget::doUndo()
{
deckStateManager->undo();
}
void DeckListHistoryManagerWidget::doRedo()
{
deckStateManager->redo();
}

View file

@ -14,6 +14,8 @@
#include <libcockatrice/deck_list/deck_list_history_manager.h>
#include <libcockatrice/models/deck_list/deck_list_model.h>
class DeckStateManager;
class DeckListHistoryManagerWidget : public QWidget
{
Q_OBJECT
@ -25,22 +27,19 @@ public slots:
void retranslateUi();
public:
explicit DeckListHistoryManagerWidget(DeckListModel *deckListModel,
explicit DeckListHistoryManagerWidget(DeckStateManager *deckStateManager,
DeckListStyleProxy *styleProxy,
DeckListHistoryManager *manager,
QWidget *parent = nullptr);
void setDeckListModel(DeckListModel *_deckListModel);
private slots:
void refreshList();
void onListClicked(QListWidgetItem *item);
void onListClicked(const QListWidgetItem *item);
void doUndo();
void doRedo();
private:
DeckListModel *deckListModel;
DeckStateManager *deckStateManager;
DeckListStyleProxy *styleProxy;
DeckListHistoryManager *historyManager;
QHBoxLayout *layout;
QAction *aUndo;

View file

@ -0,0 +1,361 @@
#include "deck_state_manager.h"
#include <libcockatrice/card/database/card_database_manager.h>
#include <libcockatrice/deck_list/deck_list_history_manager.h>
DeckStateManager::DeckStateManager(QObject *parent)
: QObject(parent), deckList(QSharedPointer<DeckList>(new DeckList)),
deckListModel(new DeckListModel(this, deckList)), historyManager(new DeckListHistoryManager(this))
{
connect(historyManager, &DeckListHistoryManager::undoRedoStateChanged, this, [this] {
setModified(true);
emit historyChanged();
});
connect(deckListModel, &DeckListModel::rowsInserted, this, &DeckStateManager::uniqueCardsChanged);
connect(deckListModel, &DeckListModel::rowsRemoved, this, &DeckStateManager::uniqueCardsChanged);
}
const DeckList &DeckStateManager::getDeckList() const
{
return *deckList.get();
}
LoadedDeck DeckStateManager::toLoadedDeck() const
{
return {getDeckList(), lastLoadInfo};
}
DeckList::Metadata const &DeckStateManager::getMetadata() const
{
return deckList->getMetadata();
}
QString DeckStateManager::getSimpleDeckName() const
{
return deckList->getMetadata().name.simplified();
}
QString DeckStateManager::getDeckHash() const
{
return deckList->getDeckHash();
}
bool DeckStateManager::isModified() const
{
return modified;
}
void DeckStateManager::setModified(bool state)
{
if (state == modified) {
return;
}
modified = state;
emit isModifiedChanged(modified);
}
bool DeckStateManager::isBlankNewDeck() const
{
return !isModified() && deckList->isBlankDeck();
}
void DeckStateManager::replaceDeck(const LoadedDeck &deck)
{
lastLoadInfo = deck.lastLoadInfo;
deckList = QSharedPointer<DeckList>(new DeckList(deck.deckList));
deckListModel->setDeckList(deckList);
historyManager->clear();
setModified(false);
emit deckReplaced();
}
void DeckStateManager::clearDeck()
{
replaceDeck(LoadedDeck());
}
bool DeckStateManager::modifyDeck(const QString &reason, const std::function<bool(DeckListModel *)> &operation)
{
DeckListMemento memento = deckList->createMemento(reason);
bool success = operation(deckListModel);
if (success) {
historyManager->save(memento);
doCardModified();
}
return success;
}
QModelIndex DeckStateManager::modifyDeck(const QString &reason,
const std::function<QModelIndex(DeckListModel *)> &operation)
{
DeckListMemento memento = deckList->createMemento(reason);
QModelIndex idx = operation(deckListModel);
if (idx.isValid()) {
historyManager->save(memento);
doCardModified();
}
return idx;
}
void DeckStateManager::setName(const QString &name)
{
QString previous = deckList->getName();
if (previous == name) {
return;
}
requestHistorySave(tr("Rename deck to \"%1\" from \"%2\"").arg(name).arg(previous));
deckList->setName(name);
doMetadataModified();
}
void DeckStateManager::setComments(const QString &comments)
{
QString previous = deckList->getComments();
if (previous == comments) {
return;
}
requestHistorySave(tr("Updated comments (was %1 chars, now %2 chars)").arg(previous.size()).arg(comments.size()));
deckList->setComments(comments);
doMetadataModified();
}
void DeckStateManager::setBannerCard(const CardRef &bannerCard)
{
CardRef previous = deckList->getBannerCard();
if (previous == bannerCard) {
return;
}
requestHistorySave(tr("Set banner card to %1 (%2)").arg(bannerCard.name).arg(bannerCard.providerId));
deckList->setBannerCard(bannerCard);
doMetadataModified();
}
void DeckStateManager::setTags(const QStringList &tags)
{
QStringList previous = deckList->getTags();
if (previous == tags) {
return;
}
requestHistorySave(tr("Tags changed"));
deckList->setTags(tags);
doMetadataModified();
}
void DeckStateManager::setFormat(const QString &format)
{
if (deckList->getMetadata().gameFormat == format) {
return;
}
requestHistorySave(tr("Set format to %1").arg(format));
deckListModel->setActiveFormat(format);
doMetadataModified();
}
QModelIndex DeckStateManager::addCard(const ExactCard &card, const QString &zoneName)
{
if (!card) {
return {};
}
QString reason = tr("Added (%1): %2 (%3) %4")
.arg(zoneName, card.getName(), card.getPrinting().getSet()->getCorrectedShortName(),
card.getPrinting().getProperty("num"));
QModelIndex idx = modifyDeck(reason, [&card, &zoneName](auto model) { return model->addCard(card, zoneName); });
if (idx.isValid()) {
emit focusIndexChanged(idx);
}
return idx;
}
QModelIndex DeckStateManager::decrementCard(const ExactCard &card, const QString &zoneName)
{
if (!card)
return {};
QString providerId = card.getPrinting().getUuid();
QString collectorNumber = card.getPrinting().getProperty("num");
QModelIndex idx = deckListModel->findCard(card.getName(), zoneName, providerId, collectorNumber);
if (!idx.isValid()) {
return {};
}
bool success = offsetCountAtIndex(idx, false);
if (!success) {
return {};
}
if (idx.isValid()) {
emit focusIndexChanged(idx);
}
return idx;
}
static bool doSwapCard(DeckListModel *model,
const QModelIndex &idx,
const QString &cardName,
const QString &providerId,
const QString &otherZone)
{
bool success = model->offsetCountAtIndex(idx, -1);
if (!success) {
return false;
}
if (ExactCard card = CardDatabaseManager::query()->getCard({cardName, providerId})) {
model->addCard(card, otherZone);
} else {
// Third argument (true) says create the card no matter what, even if not in DB
model->addPreferredPrintingCard(cardName, otherZone, true);
}
return true;
}
bool DeckStateManager::swapCardAtIndex(const QModelIndex &idx)
{
if (!idx.isValid())
return false;
QString cardName = idx.siblingAtColumn(DeckListModelColumns::CARD_NAME).data().toString();
QString providerId = idx.siblingAtColumn(DeckListModelColumns::CARD_PROVIDER_ID).data().toString();
QModelIndex gparent = idx.parent().parent();
if (!gparent.isValid())
return false;
QString zoneName = gparent.siblingAtColumn(DeckListModelColumns::CARD_NAME).data(Qt::EditRole).toString();
QString otherZoneName = zoneName == DECK_ZONE_MAIN ? DECK_ZONE_SIDE : DECK_ZONE_MAIN;
QString reason = tr("Moved to %1 1 × \"%2\" (%3)") //
.arg(otherZoneName)
.arg(cardName)
.arg(providerId);
return modifyDeck(reason, [&idx, &cardName, &providerId, &otherZoneName](auto model) {
return doSwapCard(model, idx, cardName, providerId, otherZoneName);
});
}
bool DeckStateManager::removeCardAtIndex(const QModelIndex &idx)
{
if (!idx.isValid() || deckListModel->hasChildren(idx)) {
return false;
}
QString cardName = idx.siblingAtColumn(DeckListModelColumns::CARD_NAME).data().toString();
QString reason = tr("Removed \"%1\" (all copies)").arg(cardName);
return modifyDeck(reason, [&idx](auto model) { return model->removeRow(idx.row(), idx.parent()); });
}
bool DeckStateManager::incrementCountAtIndex(const QModelIndex &idx)
{
return offsetCountAtIndex(idx, 1);
}
bool DeckStateManager::decrementCountAtIndex(const QModelIndex &idx)
{
return offsetCountAtIndex(idx, -1);
}
bool DeckStateManager::offsetCountAtIndex(const QModelIndex &idx, int offset)
{
if (!idx.isValid()) {
return false;
}
QString cardName = idx.siblingAtColumn(DeckListModelColumns::CARD_NAME).data(Qt::EditRole).toString();
QString providerId = idx.siblingAtColumn(DeckListModelColumns::CARD_PROVIDER_ID).data(Qt::DisplayRole).toString();
QString reason = tr("%1 1 × \"%2\" (%3)") //
.arg(offset > 0 ? tr("Added") : tr("Removed"))
.arg(cardName)
.arg(providerId);
return modifyDeck(reason, [&idx, &offset](auto model) { return model->offsetCountAtIndex(idx, offset); });
}
void DeckStateManager::undo(int steps)
{
if (!historyManager->canUndo()) {
return;
}
for (int i = 0; i < steps; i++) {
if (!historyManager->canUndo()) {
continue;
}
historyManager->undo(deckList.get());
}
deckListModel->rebuildTree();
emit deckListModel->layoutChanged();
}
void DeckStateManager::redo(int steps)
{
if (!historyManager->canRedo()) {
return;
}
for (int i = 0; i < steps; i++) {
if (!historyManager->canRedo()) {
continue;
}
historyManager->redo(deckList.get());
}
deckListModel->rebuildTree();
emit deckListModel->layoutChanged();
}
void DeckStateManager::requestHistorySave(const QString &reason)
{
historyManager->save(deckList->createMemento(reason));
}
/**
* @brief Handles updating state and emitting signals whenever the cards are modified
*/
void DeckStateManager::doCardModified()
{
setModified(true);
emit cardModified();
emit deckModified();
}
/**
* @brief Handles updating state and emitting signals whenever the metadata is modified
*/
void DeckStateManager::doMetadataModified()
{
setModified(true);
emit metadataModified();
emit deckModified();
}

View file

@ -0,0 +1,297 @@
#ifndef COCKATRICE_DECK_STATE_MANAGER_H
#define COCKATRICE_DECK_STATE_MANAGER_H
#include "../../deck_loader/loaded_deck.h"
#include "deck_list_model.h"
#include <QSharedPointer>
#include <libcockatrice/deck_list/deck_list.h>
class DeckListHistoryManager;
/**
* @brief This class centralizes the management of the state of the deck in the deck editor tab.
* It is responsible for owning and managing the DeckListModel, underlying DeckList, load info, and edit history.
*
* Although this class provides getters for the underlying DeckListModel, you should generally refrain from directly
* modifying the returned model. Outside modifications to the deck state should be done through @link
* DeckStateManager::modifyDeck and the metadata setters.
* Those methods ensure that the history is recorded and correct signals are emitted.
*/
class DeckStateManager : public QObject
{
Q_OBJECT
LoadedDeck::LoadInfo lastLoadInfo;
QSharedPointer<DeckList> deckList;
DeckListModel *deckListModel;
DeckListHistoryManager *historyManager;
bool modified = false;
public:
explicit DeckStateManager(QObject *parent = nullptr);
/**
* Gets the underlying HistoryManager.
* @return The DeckListHistoryManager instance
*/
DeckListHistoryManager *getHistoryManager() const
{
return historyManager;
}
/**
* @brief Gets the underlying DeckListModel.
* You should generally refrain modifying the returned model directly.
* However, it's fine (and intended) to perform queries on the returned model.
* @return The DeckListModel instance
*/
DeckListModel *getModel() const
{
return deckListModel;
}
/**
* @brief Gets a view of the current deck.
*/
const DeckList &getDeckList() const;
/**
* @brief Creates a LoadedDeck containing the contents of the current deck and the current LoadInfo.
*
* @return A new LoadedDeck instance.
*/
LoadedDeck toLoadedDeck() const;
/**
* @brief Gets a view of the metadata in the DeckList
*/
DeckList::Metadata const &getMetadata() const;
/**
* @brief Gets the deck's simplified name.
*/
QString getSimpleDeckName() const;
/**
* @brief Gets the deck hash.
*/
QString getDeckHash() const;
/**
* @brief Checks if the deck has been modified since it was last saved
*/
bool isModified() const;
/**
* @brief Sets the new isModified state, emitting a signal if the state changed.
* This class will automatically update its isModified state, but you may need to set it manually to handle, for
* example, saving.
* @param state The state
*/
void setModified(bool state);
/**
* @brief Checks if the deck state is as if it was a new deck
*/
bool isBlankNewDeck() const;
/**
* @brief Overwrites the current deck with a new deck, resetting all history
* @param deck The new deck.
*/
void replaceDeck(const LoadedDeck &deck);
/**
* @brief Resets the deck to a blank new deck, resetting all history.
*/
void clearDeck();
/**
* @brief Sets the lastLoadInfo.
* @param loadInfo The lastLoadInfo
*/
void setLastLoadInfo(const LoadedDeck::LoadInfo &loadInfo)
{
lastLoadInfo = loadInfo;
}
/**
* @brief Modifies the cards in the deck, in a wrapped operation that is saved to the history.
*
* The operation is a function that accepts a DeckListModel that it operates upon, and returns a bool.
*
* This method will pass the underlying DeckListModel into the operation function. The function can call methods on
* the model to modify the deck.
* The function should return a bool to indicate success/failure.
*
* If the operation returns true, the state of the deck before the operation is ran is saved to the history, and the
* isModified state is updated.
* If the operation returns false, the history and isModified state is not updated.
*
* Note that even if the operation fails, any modifications to the model will already have been made.
* It's recommended for the operation to always return true if any modification has already been made to the model,
* as not doing that may cause the state to become desynced.
*
* @param reason The reason to display in the history
* @param operation The modification operation.
* @return The bool returned from the operation
*/
bool modifyDeck(const QString &reason, const std::function<bool(DeckListModel *)> &operation);
/**
* @brief Modifies the cards in the deck, in a wrapped operation that is saved to the history.
*
* The operation is a function that accepts a DeckListModel that it operates upon, and returns a QModelIndex.
* If the index is invalid, then the operation is considered to be a failure.
*
* See the other @link DeckStateManager::modifyDeck for more info about the behavior of this method.
*
* @param reason The reason to display in the history
* @param operation The modification operation.
* @return The QModelIndex returned from the operation
*/
QModelIndex modifyDeck(const QString &reason, const std::function<QModelIndex(DeckListModel *)> &operation);
/// @name Metadata setters
/// @brief These methods set the metadata. Will no-op if the new value is the same as the current value.
/// Saves the operation to history if successful.
///@{
void setName(const QString &name);
void setComments(const QString &comments);
void setBannerCard(const CardRef &bannerCard);
void setTags(const QStringList &tags);
void setFormat(const QString &format);
///@}
/**
* @brief Adds the given card to the given zone.
* Saves the operation to history if successful.
*
* @param card The card to add
* @param zoneName The zone to add the card to
* @return The index of the added card
*/
QModelIndex addCard(const ExactCard &card, const QString &zoneName);
/**
* @brief Removes 1 copy of the given card from the given zone.
* Saves the operation to history if successful.
*
* @param card The card to remove
* @param zoneName The zone to remove the card from
* @return The index of the removed card. Will be invalid if the last copy was removed.
*/
QModelIndex decrementCard(const ExactCard &card, const QString &zoneName);
/**
* @brief Swaps one copy of the card at the given index between the maindeck and sideboard.
* No-ops if index is invalid or not a card node.
* Saves the operation to history if successful.
*
* @param idx The model index
* @return Whether the operation was successfully performed
*/
bool swapCardAtIndex(const QModelIndex &idx);
/**
* @brief Removes all copies of the card at the given index.
* No-ops if index is invalid or not a card node.
* Saves the operation to history if successful.
*
* @param idx The model index
* @return Whether the operation was successfully performed
*/
bool removeCardAtIndex(const QModelIndex &idx);
/**
* @brief Increments the number of copies of the card at the given index by 1.
* No-ops if index is invalid or not a card node.
* Saves the operation to history if successful.
*
* @param idx The model index
* @return Whether the operation was successfully performed
*/
bool incrementCountAtIndex(const QModelIndex &idx);
/**
* @brief Decrements the number of copies of the card at the given index by 1.
* No-ops if index is invalid or not a card node.
* Saves the operation to history if successful.
*
* @param idx The model index
* @return Whether the operation was successfully performed
*/
bool decrementCountAtIndex(const QModelIndex &idx);
/**
* Undoes n steps of the history, setting the decklist state and updating the current step in the historyManager.
* @param steps Number of steps to undo.
*/
void undo(int steps = 1);
/**
* Redoes n steps of the history, setting the decklist state and updating the current step in the historyManager.
* @param steps Number of steps to redo.
*/
void redo(int steps = 1);
public slots:
/**
* Saves the current decklist state to history.
* @param reason The reason that is shown in the history.
*/
void requestHistorySave(const QString &reason);
private:
bool offsetCountAtIndex(const QModelIndex &idx, int offset);
void doCardModified();
void doMetadataModified();
signals:
/**
* A modification has been made to the cards in the deck
*/
void cardModified();
/**
* A card that wasn't previously in the deck was added to the deck, or the last copy of a card was removed from the
* deck.
*/
void uniqueCardsChanged();
/**
* A modification has been made to the metadata in the deck
*/
void metadataModified();
/**
* A modification has been made to the cards or metadata in the deck
*/
void deckModified();
/**
* The history has been greatly changed and needs to be reloaded.
*/
void historyChanged();
/**
* The deck has been completely changed.
*/
void deckReplaced();
/**
* The isModified state of the deck has changed
* @param isModified the new state
*/
void isModifiedChanged(bool isModified);
/**
* The selected card on any views connected to this deck should be changed to this index.
* @param index The model index
*/
void focusIndexChanged(QModelIndex index);
};
#endif // COCKATRICE_DECK_STATE_MANAGER_H

View file

@ -2,6 +2,7 @@
#include "../../deck_loader/card_node_function.h"
#include "../../deck_loader/deck_loader.h"
#include "../deck_editor/deck_state_manager.h"
#include "../interface/widgets/cards/card_info_picture_widget.h"
#include "../interface/widgets/general/layout_containers/flow_widget.h"
@ -21,7 +22,8 @@
#include <qdrag.h>
#include <qevent.h>
DlgSelectSetForCards::DlgSelectSetForCards(QWidget *parent, DeckListModel *_model) : QDialog(parent), model(_model)
DlgSelectSetForCards::DlgSelectSetForCards(QWidget *parent, DeckStateManager *deckStateManger)
: QDialog(parent), deckStateManager(deckStateManger)
{
setMinimumSize(500, 500);
setAcceptDrops(true);
@ -165,36 +167,39 @@ void DlgSelectSetForCards::actOK()
if (modifiedSetsAndCardsMap.isEmpty()) {
accept(); // Nothing to do
} else {
emit deckAboutToBeModified(tr("Bulk modified printings."));
return;
}
for (QString modifiedSet : modifiedSetsAndCardsMap.keys()) {
for (QString card : modifiedSetsAndCardsMap.value(modifiedSet)) {
swapPrinting(model, modifiedSet, card);
auto bulkModify = [&modifiedSetsAndCardsMap](DeckListModel *model) {
for (QString modifiedSet : modifiedSetsAndCardsMap.keys()) {
for (QString card : modifiedSetsAndCardsMap.value(modifiedSet)) {
swapPrinting(model, modifiedSet, card);
}
}
}
return true;
};
deckStateManager->modifyDeck(tr("Bulk modified printings."), bulkModify);
if (!modifiedSetsAndCardsMap.isEmpty()) {
emit deckModified();
}
accept();
}
void DlgSelectSetForCards::actClear()
{
emit deckAboutToBeModified(tr("Cleared all printing information."));
model->forEachCard(CardNodeFunction::ClearPrintingData());
emit deckModified();
deckStateManager->modifyDeck(tr("Cleared all printing information."), [](auto model) {
model->forEachCard(CardNodeFunction::ClearPrintingData());
return true;
});
accept();
}
void DlgSelectSetForCards::actSetAllToPreferred()
{
emit deckAboutToBeModified(tr("Set all printings to preferred."));
model->forEachCard(CardNodeFunction::ClearPrintingData());
model->forEachCard(CardNodeFunction::SetProviderIdToPreferred());
emit deckModified();
deckStateManager->modifyDeck(tr("Set all printings to preferred."), [](auto model) {
model->forEachCard(CardNodeFunction::ClearPrintingData());
model->forEachCard(CardNodeFunction::SetProviderIdToPreferred());
return true;
});
accept();
}
@ -227,10 +232,8 @@ void DlgSelectSetForCards::sortSetsByCount()
QMap<QString, int> DlgSelectSetForCards::getSetsForCards()
{
QMap<QString, int> setCounts;
if (!model)
return setCounts;
QList<QString> cardNames = model->getCardNames();
QList<QString> cardNames = deckStateManager->getModel()->getCardNames();
for (auto cardName : cardNames) {
CardInfoPtr infoPtr = CardDatabaseManager::query()->getCardInfo(cardName);
@ -269,7 +272,7 @@ void DlgSelectSetForCards::updateCardLists()
}
}
QList<QString> cardNames = model->getCardNames();
QList<QString> cardNames = deckStateManager->getModel()->getCardNames();
for (auto cardName : cardNames) {
bool found = false;
@ -351,10 +354,8 @@ void DlgSelectSetForCards::dropEvent(QDropEvent *event)
QMap<QString, QStringList> DlgSelectSetForCards::getCardsForSets()
{
QMap<QString, QStringList> setCards;
if (!model)
return setCards;
QList<QString> cardNames = model->getCardNames();
QList<QString> cardNames = deckStateManager->getModel()->getCardNames();
for (auto cardName : cardNames) {
CardInfoPtr infoPtr = CardDatabaseManager::query()->getCardInfo(cardName);

View file

@ -18,6 +18,7 @@
#include <QVBoxLayout>
#include <libcockatrice/models/deck_list/deck_list_model.h>
class DeckStateManager;
class SetEntryWidget; // Forward declaration
class DlgSelectSetForCards : public QDialog
@ -25,7 +26,7 @@ class DlgSelectSetForCards : public QDialog
Q_OBJECT
public:
explicit DlgSelectSetForCards(QWidget *parent, DeckListModel *_model);
explicit DlgSelectSetForCards(QWidget *parent, DeckStateManager *deckStateManager);
void retranslateUi();
void sortSetsByCount();
QMap<QString, QStringList> getCardsForSets();
@ -37,7 +38,6 @@ public:
signals:
void widgetOrderChanged();
void orderChanged();
void deckAboutToBeModified(const QString &reason);
void deckModified();
public slots:
@ -61,7 +61,7 @@ private:
QLabel *modifiedCardsLabel;
QWidget *listContainer;
QListWidget *listWidget;
DeckListModel *model;
DeckStateManager *deckStateManager;
QMap<QString, SetEntryWidget *> setEntries;
QPushButton *clearButton;
QPushButton *setAllToPreferredButton;

View file

@ -11,16 +11,12 @@
* UI elements for managing card counts in both the mainboard and sideboard zones.
*
* @param parent The parent widget.
* @param deckEditor Pointer to the TabDeckEditor.
* @param deckModel Pointer to the DeckListModel.
* @param deckView Pointer to the QTreeView for the deck display.
* @param deckStateManager Pointer to the DeckStateManager
* @param cardSizeSlider Pointer to the QSlider used for dynamic font resizing.
* @param rootCard The root card for the widget.
*/
AllZonesCardAmountWidget::AllZonesCardAmountWidget(QWidget *parent,
AbstractTabDeckEditor *deckEditor,
DeckListModel *deckModel,
QTreeView *deckView,
DeckStateManager *deckStateManager,
QSlider *cardSizeSlider,
const ExactCard &rootCard)
: QWidget(parent), cardSizeSlider(cardSizeSlider)
@ -32,11 +28,9 @@ AllZonesCardAmountWidget::AllZonesCardAmountWidget(QWidget *parent,
setContentsMargins(5, 5, 5, 5); // Padding around the text
zoneLabelMainboard = new ShadowBackgroundLabel(this, tr("Mainboard"));
buttonBoxMainboard =
new CardAmountWidget(this, deckEditor, deckModel, deckView, cardSizeSlider, rootCard, DECK_ZONE_MAIN);
buttonBoxMainboard = new CardAmountWidget(this, deckStateManager, cardSizeSlider, rootCard, DECK_ZONE_MAIN);
zoneLabelSideboard = new ShadowBackgroundLabel(this, tr("Sideboard"));
buttonBoxSideboard =
new CardAmountWidget(this, deckEditor, deckModel, deckView, cardSizeSlider, rootCard, DECK_ZONE_SIDE);
buttonBoxSideboard = new CardAmountWidget(this, deckStateManager, cardSizeSlider, rootCard, DECK_ZONE_SIDE);
layout->addWidget(zoneLabelMainboard, 0, Qt::AlignHCenter | Qt::AlignBottom);
layout->addWidget(buttonBoxMainboard, 0, Qt::AlignHCenter | Qt::AlignTop);

View file

@ -18,9 +18,7 @@ class AllZonesCardAmountWidget : public QWidget
Q_OBJECT
public:
explicit AllZonesCardAmountWidget(QWidget *parent,
AbstractTabDeckEditor *deckEditor,
DeckListModel *deckModel,
QTreeView *deckView,
DeckStateManager *deckStateManager,
QSlider *cardSizeSlider,
const ExactCard &rootCard);
int getMainboardAmount();

View file

@ -1,5 +1,7 @@
#include "card_amount_widget.h"
#include "../deck_editor/deck_state_manager.h"
#include <QPainter>
#include <QTimer>
@ -7,22 +9,17 @@
* @brief Constructs a widget for displaying and controlling the card count in a specific zone.
*
* @param parent The parent widget.
* @param deckEditor Pointer to the TabDeckEditor instance.
* @param deckModel Pointer to the DeckListModel instance.
* @param deckView Pointer to the QTreeView displaying the deck.
* @param cardSizeSlider Pointer to the QSlider for adjusting font size.
* @param rootCard The root card to manage within the widget.
* @param zoneName The zone name (e.g., DECK_ZONE_MAIN or DECK_ZONE_SIDE).
*/
CardAmountWidget::CardAmountWidget(QWidget *parent,
AbstractTabDeckEditor *deckEditor,
DeckListModel *deckModel,
QTreeView *deckView,
DeckStateManager *deckStateManager,
QSlider *cardSizeSlider,
const ExactCard &rootCard,
const QString &zoneName)
: QWidget(parent), deckEditor(deckEditor), deckModel(deckModel), deckView(deckView), cardSizeSlider(cardSizeSlider),
rootCard(rootCard), zoneName(zoneName), hovered(false)
: QWidget(parent), deckStateManager(deckStateManager), cardSizeSlider(cardSizeSlider), rootCard(rootCard),
zoneName(zoneName), hovered(false)
{
layout = new QHBoxLayout(this);
layout->setContentsMargins(0, 0, 0, 0);
@ -56,15 +53,10 @@ CardAmountWidget::CardAmountWidget(QWidget *parent,
layout->addWidget(incrementButton);
// React to model changes
connect(deckModel, &DeckListModel::dataChanged, this, &CardAmountWidget::updateCardCount);
connect(deckModel, &QAbstractItemModel::rowsRemoved, this, &CardAmountWidget::updateCardCount);
connect(deckStateManager, &DeckStateManager::cardModified, this, &CardAmountWidget::updateCardCount);
// Connect slider for dynamic font size adjustment
connect(cardSizeSlider, &QSlider::valueChanged, this, &CardAmountWidget::adjustFontSize);
if (deckEditor) {
connect(this, &CardAmountWidget::deckModified, deckEditor, &AbstractTabDeckEditor::onDeckHistorySaveRequested);
}
}
/**
@ -168,7 +160,7 @@ static QModelIndex addAndReplacePrintings(DeckListModel *model,
void CardAmountWidget::addPrinting(const QString &zone)
{
// Check if we will need to add extra copies due to replacing copies without providerIds
QModelIndex existing = deckModel->findCard(rootCard.getName(), zone);
QModelIndex existing = deckStateManager->getModel()->findCard(rootCard.getName(), zone);
int extraCopies = 0;
bool replacingProviderless = false;
@ -192,15 +184,13 @@ void CardAmountWidget::addPrinting(const QString &zone)
.arg(rootCard.getPrinting().getUuid())
.arg(replacingProviderless ? " (replaced providerless printings)" : "");
emit deckModified(reason);
// Add the card and expand the list UI
auto newCardIndex = addAndReplacePrintings(deckModel, existing, rootCard, zone, extraCopies, replacingProviderless);
QModelIndex newCardIndex = deckStateManager->modifyDeck(reason, [&](auto model) {
return addAndReplacePrintings(model, existing, rootCard, zone, extraCopies, replacingProviderless);
});
if (newCardIndex.isValid()) {
deckView->setCurrentIndex(newCardIndex);
deckView->setFocus(Qt::FocusReason::MouseFocusReason);
deckEditor->setModified(true);
emit deckStateManager->focusIndexChanged(newCardIndex);
}
}
@ -250,13 +240,11 @@ void CardAmountWidget::decrementCardHelper(const QString &zone)
.arg(zone == DECK_ZONE_MAIN ? "mainboard" : "sideboard")
.arg(rootCard.getPrinting().getUuid());
emit deckModified(reason);
QModelIndex idx = deckModel->findCard(rootCard.getName(), zone, rootCard.getPrinting().getUuid(),
deckStateManager->modifyDeck(reason, [this, &zone](auto model) {
QModelIndex idx = model->findCard(rootCard.getName(), zone, rootCard.getPrinting().getUuid(),
rootCard.getPrinting().getProperty("num"));
deckModel->offsetCountAtIndex(idx, -1);
deckEditor->setModified(true);
return model->offsetCountAtIndex(idx, -1);
});
}
/**
@ -273,7 +261,7 @@ int CardAmountWidget::countCardsInZone(const QString &deckZone)
return 0; // Cards without uuids/providerIds CANNOT match another card, they are undefined for us.
}
QList<ExactCard> cards = deckModel->getCardsForZone(deckZone);
QList<ExactCard> cards = deckStateManager->getModel()->getCardsForZone(deckZone);
return std::count_if(cards.cbegin(), cards.cend(),
[&uuid](const ExactCard &card) { return card.getPrinting().getUuid() == uuid; });

View file

@ -27,9 +27,7 @@ signals:
public:
explicit CardAmountWidget(QWidget *parent,
AbstractTabDeckEditor *deckEditor,
DeckListModel *deckModel,
QTreeView *deckView,
DeckStateManager *deckStateManager,
QSlider *cardSizeSlider,
const ExactCard &rootCard,
const QString &zoneName);
@ -44,9 +42,7 @@ protected:
void showEvent(QShowEvent *event) override;
private:
AbstractTabDeckEditor *deckEditor;
DeckListModel *deckModel;
QTreeView *deckView;
DeckStateManager *deckStateManager;
QSlider *cardSizeSlider;
ExactCard rootCard;
QString zoneName;

View file

@ -3,6 +3,7 @@
#include "../../../client/settings/cache_settings.h"
#include "../../../interface/card_picture_loader/card_picture_loader.h"
#include "../../../interface/widgets/dialogs/dlg_select_set_for_cards.h"
#include "../deck_editor/deck_state_manager.h"
#include "printing_selector_card_display_widget.h"
#include "printing_selector_card_search_widget.h"
#include "printing_selector_card_selection_widget.h"
@ -21,12 +22,9 @@
*
* @param parent The parent widget for the PrintingSelector.
* @param deckEditor The TabDeckEditor instance used for managing the deck.
* @param deckModel The DeckListModel instance that provides data for the deck's contents.
* @param deckView The QTreeView instance used to display the deck and its contents.
*/
PrintingSelector::PrintingSelector(QWidget *parent, AbstractTabDeckEditor *_deckEditor)
: QWidget(parent), deckEditor(_deckEditor), deckModel(deckEditor->deckDockWidget->deckModel),
deckView(deckEditor->deckDockWidget->deckView)
: QWidget(parent), deckEditor(_deckEditor), deckStateManager(_deckEditor->deckStateManager)
{
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
layout = new QVBoxLayout(this);
@ -74,13 +72,12 @@ PrintingSelector::PrintingSelector(QWidget *parent, AbstractTabDeckEditor *_deck
layout->addWidget(flowWidget);
cardSelectionBar = new PrintingSelectorCardSelectionWidget(this);
cardSelectionBar = new PrintingSelectorCardSelectionWidget(this, deckStateManager);
cardSelectionBar->setVisible(SettingsCache::instance().getPrintingSelectorNavigationButtonsVisible());
layout->addWidget(cardSelectionBar);
// Connect deck model data change signal to update display
connect(deckModel, &DeckListModel::rowsInserted, this, &PrintingSelector::printingsInDeckChanged);
connect(deckModel, &DeckListModel::rowsRemoved, this, &PrintingSelector::printingsInDeckChanged);
connect(deckStateManager, &DeckStateManager::uniqueCardsChanged, this, &PrintingSelector::printingsInDeckChanged);
retranslateUi();
}
@ -152,7 +149,8 @@ void PrintingSelector::getAllSetsForCurrentCard()
QList<PrintingInfo> printingsToUse;
if (SettingsCache::instance().getBumpSetsWithCardsInDeckToTop()) {
printingsToUse = sortToolBar->prependPrintingsInDeck(filteredPrintings, selectedCard, deckModel);
printingsToUse =
sortToolBar->prependPrintingsInDeck(filteredPrintings, selectedCard, deckStateManager->getModel());
} else {
printingsToUse = filteredPrintings;
}
@ -164,7 +162,7 @@ void PrintingSelector::getAllSetsForCurrentCard()
connect(widgetLoadingBufferTimer, &QTimer::timeout, this, [=, this]() mutable {
for (int i = 0; i < BATCH_SIZE && currentIndex < printingsToUse.size(); ++i, ++currentIndex) {
auto card = ExactCard(selectedCard, printingsToUse[currentIndex]);
auto *cardDisplayWidget = new PrintingSelectorCardDisplayWidget(this, deckEditor, deckModel, deckView,
auto *cardDisplayWidget = new PrintingSelectorCardDisplayWidget(this, deckEditor, deckStateManager,
cardSizeWidget->getSlider(), card);
flowWidget->addWidget(cardDisplayWidget);
cardDisplayWidget->clampSetNameToPicture();

View file

@ -21,6 +21,7 @@
#define BATCH_SIZE 10
class DeckStateManager;
class PrintingSelectorCardSearchWidget;
class PrintingSelectorCardSelectionWidget;
class PrintingSelectorCardSortingWidget;
@ -35,15 +36,6 @@ public:
void setCard(const CardInfoPtr &newCard);
void getAllSetsForCurrentCard();
[[nodiscard]] DeckListModel *getDeckModel() const
{
return deckModel;
}
[[nodiscard]] AbstractTabDeckEditor *getDeckEditor() const
{
return deckEditor;
}
public slots:
void retranslateUi();
@ -75,8 +67,7 @@ private:
CardSizeWidget *cardSizeWidget;
PrintingSelectorCardSelectionWidget *cardSelectionBar;
AbstractTabDeckEditor *deckEditor;
DeckListModel *deckModel;
QTreeView *deckView;
DeckStateManager *deckStateManager;
CardInfoPtr selectedCard;
QTimer *widgetLoadingBufferTimer;
int currentIndex = 0;

View file

@ -18,15 +18,13 @@
*
* @param parent The parent widget for this display.
* @param deckEditor The TabDeckEditor instance for deck management.
* @param deckModel The DeckListModel instance providing deck data.
* @param deckView The QTreeView instance displaying the deck.
* @param deckStateManager The DeckStateManager instance providing deck data.
* @param cardSizeSlider The slider controlling the size of the displayed card.
* @param rootCard The root card object, representing the card to be displayed.
*/
PrintingSelectorCardDisplayWidget::PrintingSelectorCardDisplayWidget(QWidget *parent,
AbstractTabDeckEditor *deckEditor,
DeckListModel *deckModel,
QTreeView *deckView,
DeckStateManager *deckStateManager,
QSlider *cardSizeSlider,
const ExactCard &rootCard)
: QWidget(parent)
@ -36,8 +34,7 @@ PrintingSelectorCardDisplayWidget::PrintingSelectorCardDisplayWidget(QWidget *pa
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
// Create the overlay widget for the card display
overlayWidget =
new PrintingSelectorCardOverlayWidget(this, deckEditor, deckModel, deckView, cardSizeSlider, rootCard);
overlayWidget = new PrintingSelectorCardOverlayWidget(this, deckEditor, deckStateManager, cardSizeSlider, rootCard);
connect(overlayWidget, &PrintingSelectorCardOverlayWidget::cardPreferenceChanged, this,
[this]() { emit cardPreferenceChanged(); });

View file

@ -21,8 +21,7 @@ class PrintingSelectorCardDisplayWidget : public QWidget
public:
PrintingSelectorCardDisplayWidget(QWidget *parent,
AbstractTabDeckEditor *deckEditor,
DeckListModel *deckModel,
QTreeView *deckView,
DeckStateManager *deckStateManager,
QSlider *cardSizeSlider,
const ExactCard &rootCard);

View file

@ -22,15 +22,13 @@
*
* @param parent The parent widget for this overlay.
* @param _deckEditor The TabDeckEditor instance for deck management.
* @param deckModel The DeckListModel instance providing deck data.
* @param deckView The QTreeView instance displaying the deck.
* @param deckStateManager The DeckStateManager instance providing deck data.
* @param cardSizeSlider The slider controlling the size of the card.
* @param _rootCard The root card object that contains information about the card.
*/
PrintingSelectorCardOverlayWidget::PrintingSelectorCardOverlayWidget(QWidget *parent,
AbstractTabDeckEditor *_deckEditor,
DeckListModel *deckModel,
QTreeView *deckView,
DeckStateManager *deckStateManager,
QSlider *cardSizeSlider,
const ExactCard &_rootCard)
: QWidget(parent), deckEditor(_deckEditor), rootCard(_rootCard)
@ -58,8 +56,7 @@ PrintingSelectorCardOverlayWidget::PrintingSelectorCardOverlayWidget(QWidget *pa
updatePinBadgeVisibility();
// Add AllZonesCardAmountWidget
allZonesCardAmountWidget =
new AllZonesCardAmountWidget(this, deckEditor, deckModel, deckView, cardSizeSlider, _rootCard);
allZonesCardAmountWidget = new AllZonesCardAmountWidget(this, deckStateManager, cardSizeSlider, _rootCard);
allZonesCardAmountWidget->raise(); // Ensure it's on top of the picture
// Set initial visibility based on amounts

View file

@ -20,8 +20,7 @@ class PrintingSelectorCardOverlayWidget : public QWidget
public:
explicit PrintingSelectorCardOverlayWidget(QWidget *parent,
AbstractTabDeckEditor *_deckEditor,
DeckListModel *_deckModel,
QTreeView *_deckView,
DeckStateManager *_deckStateManager,
QSlider *_cardSizeSlider,
const ExactCard &_rootCard);

View file

@ -11,7 +11,9 @@
*
* @param parent The parent PrintingSelector widget responsible for managing card selection.
*/
PrintingSelectorCardSelectionWidget::PrintingSelectorCardSelectionWidget(PrintingSelector *parent) : parent(parent)
PrintingSelectorCardSelectionWidget::PrintingSelectorCardSelectionWidget(PrintingSelector *parent,
DeckStateManager *deckStateManager)
: parent(parent), deckStateManager(deckStateManager)
{
cardSelectionBarLayout = new QHBoxLayout(this);
cardSelectionBarLayout->setContentsMargins(9, 0, 9, 0);
@ -48,12 +50,6 @@ void PrintingSelectorCardSelectionWidget::connectSignals()
void PrintingSelectorCardSelectionWidget::selectSetForCards()
{
auto *setSelectionDialog = new DlgSelectSetForCards(nullptr, parent->getDeckModel());
connect(setSelectionDialog, &DlgSelectSetForCards::deckAboutToBeModified, parent->getDeckEditor(),
&AbstractTabDeckEditor::onDeckHistorySaveRequested);
connect(setSelectionDialog, &DlgSelectSetForCards::deckModified, parent->getDeckEditor(),
&AbstractTabDeckEditor::onDeckModified);
if (!setSelectionDialog->exec()) {
return;
}
auto *setSelectionDialog = new DlgSelectSetForCards(nullptr, deckStateManager);
setSelectionDialog->exec();
}

View file

@ -18,7 +18,7 @@ class PrintingSelectorCardSelectionWidget : public QWidget
Q_OBJECT
public:
explicit PrintingSelectorCardSelectionWidget(PrintingSelector *parent);
explicit PrintingSelectorCardSelectionWidget(PrintingSelector *parent, DeckStateManager *deckStateManager);
void connectSignals();
@ -27,6 +27,7 @@ public slots:
private:
PrintingSelector *parent;
DeckStateManager *deckStateManager;
QHBoxLayout *cardSelectionBarLayout;
QPushButton *previousCardButton;
QPushButton *selectSetForCardsButton;

View file

@ -183,7 +183,7 @@ QList<PrintingInfo> PrintingSelectorCardSortingWidget::prependPinnedPrintings(co
*/
QList<PrintingInfo> PrintingSelectorCardSortingWidget::prependPrintingsInDeck(const QList<PrintingInfo> &printings,
const CardInfoPtr &selectedCard,
DeckListModel *deckModel)
const DeckListModel *deckModel)
{
if (!selectedCard) {
return {};

View file

@ -23,7 +23,7 @@ public:
QList<PrintingInfo> prependPinnedPrintings(const QList<PrintingInfo> &printings, const QString &cardName);
QList<PrintingInfo> prependPrintingsInDeck(const QList<PrintingInfo> &printings,
const CardInfoPtr &selectedCard,
DeckListModel *deckModel);
const DeckListModel *deckModel);
public slots:
void updateSortOrder();

View file

@ -12,6 +12,7 @@
#include "../../../client/settings/cache_settings.h"
#include "../client/network/interfaces/deck_stats_interface.h"
#include "../client/network/interfaces/tapped_out_interface.h"
#include "../deck_editor/deck_state_manager.h"
#include "../interface/card_picture_loader/card_picture_loader.h"
#include "../interface/pixel_map_generator.h"
#include "../interface/widgets/dialogs/dlg_load_deck.h"
@ -52,7 +53,7 @@ AbstractTabDeckEditor::AbstractTabDeckEditor(TabSupervisor *_tabSupervisor) : Ta
{
setDockOptions(QMainWindow::AnimatedDocks | QMainWindow::AllowNestedDocks | QMainWindow::AllowTabbedDocks);
historyManager = new DeckListHistoryManager(this);
deckStateManager = new DeckStateManager(this);
databaseDisplayDockWidget = new DeckEditorDatabaseDisplayWidget(this);
deckDockWidget = new DeckEditorDeckDockWidget(this);
@ -64,14 +65,8 @@ AbstractTabDeckEditor::AbstractTabDeckEditor(TabSupervisor *_tabSupervisor) : Ta
});
// Connect deck signals to this tab
connect(deckDockWidget, &DeckEditorDeckDockWidget::deckChanged, this, &AbstractTabDeckEditor::onDeckChanged);
connect(deckDockWidget, &DeckEditorDeckDockWidget::deckModified, this, &AbstractTabDeckEditor::onDeckModified);
connect(deckDockWidget, &DeckEditorDeckDockWidget::requestDeckHistorySave, this,
&AbstractTabDeckEditor::onDeckHistorySaveRequested);
connect(deckDockWidget, &DeckEditorDeckDockWidget::requestDeckHistoryClear, this,
&AbstractTabDeckEditor::onDeckHistoryClearRequested);
connect(deckDockWidget, &DeckEditorDeckDockWidget::cardChanged, this, &AbstractTabDeckEditor::updateCard);
connect(this, &AbstractTabDeckEditor::decrementCard, deckDockWidget, &DeckEditorDeckDockWidget::actDecrementCard);
connect(deckStateManager, &DeckStateManager::isModifiedChanged, this, &AbstractTabDeckEditor::onDeckModified);
connect(deckDockWidget, &DeckEditorDeckDockWidget::selectedCardChanged, this, &AbstractTabDeckEditor::updateCard);
// Connect database display signals to this tab
connect(databaseDisplayDockWidget, &DeckEditorDatabaseDisplayWidget::cardChanged, this,
@ -107,7 +102,6 @@ void AbstractTabDeckEditor::updateCard(const ExactCard &card)
/** @brief Placeholder: called when the deck changes. */
void AbstractTabDeckEditor::onDeckChanged()
{
historyManager->clear();
}
/**
@ -115,24 +109,8 @@ void AbstractTabDeckEditor::onDeckChanged()
*/
void AbstractTabDeckEditor::onDeckModified()
{
setModified(!isBlankNewDeck());
deckMenu->setSaveStatus(!isBlankNewDeck());
}
/**
* @brief Marks the tab as modified and updates the save menu status.
*/
void AbstractTabDeckEditor::onDeckHistorySaveRequested(const QString &modificationReason)
{
historyManager->save(deckDockWidget->getDeckList().createMemento(modificationReason));
}
/**
* @brief Marks the tab as modified and updates the save menu status.
*/
void AbstractTabDeckEditor::onDeckHistoryClearRequested()
{
historyManager->clear();
deckMenu->setSaveStatus(!deckStateManager->isBlankNewDeck());
emit tabTextChanged(this, getTabText());
}
/**
@ -142,7 +120,7 @@ void AbstractTabDeckEditor::onDeckHistoryClearRequested()
*/
void AbstractTabDeckEditor::addCardHelper(const ExactCard &card, const QString &zoneName)
{
deckDockWidget->actAddCard(card, zoneName);
deckStateManager->addCard(card, zoneName);
databaseDisplayDockWidget->searchEdit->setSelection(0, databaseDisplayDockWidget->searchEdit->text().length());
}
@ -170,13 +148,13 @@ void AbstractTabDeckEditor::actAddCardToSideboard(const ExactCard &card)
/** @brief Decrements a card from the main deck. */
void AbstractTabDeckEditor::actDecrementCard(const ExactCard &card)
{
emit decrementCard(card, DECK_ZONE_MAIN);
deckStateManager->decrementCard(card, DECK_ZONE_MAIN);
}
/** @brief Decrements a card from the sideboard. */
void AbstractTabDeckEditor::actDecrementCardFromSideboard(const ExactCard &card)
{
emit decrementCard(card, DECK_ZONE_SIDE);
deckStateManager->decrementCard(card, DECK_ZONE_SIDE);
}
/**
@ -198,45 +176,13 @@ void AbstractTabDeckEditor::openDeck(const LoadedDeck &deck)
*/
void AbstractTabDeckEditor::setDeck(const LoadedDeck &_deck)
{
deckDockWidget->setDeck(_deck);
CardPictureLoader::cacheCardPixmaps(CardDatabaseManager::query()->getCards(getDeckList().getCardRefList()));
setModified(false);
deckStateManager->replaceDeck(_deck);
CardPictureLoader::cacheCardPixmaps(CardDatabaseManager::query()->getCards(_deck.deckList.getCardRefList()));
aDeckDockVisible->setChecked(true);
deckDockWidget->setVisible(aDeckDockVisible->isChecked());
}
/** @brief Returns the currently loaded deck. */
DeckLoader *AbstractTabDeckEditor::getDeckLoader() const
{
return deckDockWidget->getDeckLoader();
}
/** @brief Returns the currently loaded deck list. */
const DeckList &AbstractTabDeckEditor::getDeckList() const
{
return deckDockWidget->getDeckList();
}
/**
* @brief Sets the modified state of the tab.
* @param _modified True if tab is modified, false otherwise.
*/
void AbstractTabDeckEditor::setModified(bool _modified)
{
modified = _modified;
emit tabTextChanged(this, getTabText());
}
/**
* @brief Returns true if the tab is a blank newly created deck.
*/
bool AbstractTabDeckEditor::isBlankNewDeck() const
{
const LoadedDeck &loadedDeck = deckDockWidget->getDeckLoader()->getDeck();
return !modified && loadedDeck.isEmpty();
}
/** @brief Creates a new deck. Handles opening in new tab if needed. */
void AbstractTabDeckEditor::actNewDeck()
{
@ -255,9 +201,8 @@ void AbstractTabDeckEditor::actNewDeck()
/** @brief Clears the current deck and resets modified flag. */
void AbstractTabDeckEditor::cleanDeckAndResetModified()
{
deckStateManager->clearDeck();
deckMenu->setSaveStatus(false);
deckDockWidget->cleanDeck();
setModified(false);
}
/**
@ -268,13 +213,13 @@ void AbstractTabDeckEditor::cleanDeckAndResetModified()
AbstractTabDeckEditor::DeckOpenLocation AbstractTabDeckEditor::confirmOpen(const bool openInSameTabIfBlank)
{
if (SettingsCache::instance().getOpenDeckInNewTab()) {
if (openInSameTabIfBlank && isBlankNewDeck())
if (openInSameTabIfBlank && deckStateManager->isBlankNewDeck())
return SAME_TAB;
else
return NEW_TAB;
}
if (!modified)
if (!deckStateManager->isModified())
return SAME_TAB;
tabSupervisor->setCurrentWidget(this);
@ -325,7 +270,6 @@ void AbstractTabDeckEditor::actLoadDeck()
QString fileName = dialog.selectedFiles().at(0);
openDeckFromFile(fileName, deckOpenLocation);
deckDockWidget->updateBannerCardComboBox();
}
/**
@ -371,7 +315,7 @@ void AbstractTabDeckEditor::openDeckFromFile(const QString &fileName, DeckOpenLo
*/
bool AbstractTabDeckEditor::actSaveDeck()
{
const LoadedDeck &loadedDeck = getDeckLoader()->getDeck();
const auto loadedDeck = deckStateManager->toLoadedDeck();
if (loadedDeck.lastLoadInfo.remoteDeckId != LoadedDeck::LoadInfo::NON_REMOTE_ID) {
QString deckString = loadedDeck.deckList.writeToString_Native();
if (deckString.length() > MAX_FILE_LENGTH) {
@ -392,8 +336,10 @@ bool AbstractTabDeckEditor::actSaveDeck()
if (loadedDeck.lastLoadInfo.fileName.isEmpty())
return actSaveDeckAs();
if (getDeckLoader()->saveToFile(loadedDeck.lastLoadInfo.fileName, loadedDeck.lastLoadInfo.fileFormat)) {
setModified(false);
auto deckLoader = DeckLoader(this);
deckLoader.setDeck(loadedDeck);
if (deckLoader.saveToFile(loadedDeck.lastLoadInfo.fileName, loadedDeck.lastLoadInfo.fileFormat)) {
deckStateManager->setModified(false);
return true;
}
@ -409,12 +355,14 @@ bool AbstractTabDeckEditor::actSaveDeck()
*/
bool AbstractTabDeckEditor::actSaveDeckAs()
{
LoadedDeck loadedDeck = deckStateManager->toLoadedDeck();
QFileDialog dialog(this, tr("Save deck"));
dialog.setDirectory(SettingsCache::instance().getDeckPath());
dialog.setAcceptMode(QFileDialog::AcceptSave);
dialog.setDefaultSuffix("cod");
dialog.setNameFilters(DeckLoader::FILE_NAME_FILTERS);
dialog.selectFile(getDeckList().getName().trimmed());
dialog.selectFile(loadedDeck.deckList.getName().trimmed());
if (!dialog.exec())
return false;
@ -422,14 +370,18 @@ bool AbstractTabDeckEditor::actSaveDeckAs()
QString fileName = dialog.selectedFiles().at(0);
DeckFileFormat::Format fmt = DeckFileFormat::getFormatFromName(fileName);
if (!getDeckLoader()->saveToFile(fileName, fmt)) {
DeckLoader deckLoader = DeckLoader(this);
deckLoader.setDeck(loadedDeck);
if (!deckLoader.saveToFile(fileName, fmt)) {
QMessageBox::critical(
this, tr("Error"),
tr("The deck could not be saved.\nPlease check that the directory is writable and try again."));
return false;
}
setModified(false);
deckStateManager->setLastLoadInfo({.fileName = fileName, .fileFormat = fmt});
deckStateManager->setModified(false);
SettingsCache::instance().recents().updateRecentlyOpenedDeckPaths(fileName);
return true;
}
@ -443,7 +395,7 @@ void AbstractTabDeckEditor::saveDeckRemoteFinished(const Response &response)
if (response.response_code() != Response::RespOk)
QMessageBox::critical(this, tr("Error"), tr("The deck could not be saved."));
else
setModified(false);
deckStateManager->setModified(false);
}
/**
@ -464,7 +416,7 @@ void AbstractTabDeckEditor::actLoadDeckFromClipboard()
emit openDeckEditor({.deckList = dlg.getDeckList()});
} else {
setDeck({.deckList = dlg.getDeckList()});
setModified(true);
deckStateManager->setModified(true);
}
deckMenu->setSaveStatus(true);
@ -476,12 +428,13 @@ void AbstractTabDeckEditor::actLoadDeckFromClipboard()
*/
void AbstractTabDeckEditor::editDeckInClipboard(bool annotated)
{
DlgEditDeckInClipboard dlg(getDeckLoader()->getDeck().deckList, annotated, this);
LoadedDeck loadedDeck = deckStateManager->toLoadedDeck();
DlgEditDeckInClipboard dlg(loadedDeck.deckList, annotated, this);
if (!dlg.exec())
return;
setDeck({dlg.getDeckList(), getDeckLoader()->getDeck().lastLoadInfo});
setModified(true);
setDeck({dlg.getDeckList(), loadedDeck.lastLoadInfo});
deckStateManager->setModified(true);
deckMenu->setSaveStatus(true);
}
@ -500,25 +453,25 @@ void AbstractTabDeckEditor::actEditDeckInClipboardRaw()
/** @brief Saves deck to clipboard with set info and annotation. */
void AbstractTabDeckEditor::actSaveDeckToClipboard()
{
DeckLoader::saveToClipboard(getDeckList(), true, true);
DeckLoader::saveToClipboard(deckStateManager->getDeckList(), true, true);
}
/** @brief Saves deck to clipboard with annotation, without set info. */
void AbstractTabDeckEditor::actSaveDeckToClipboardNoSetInfo()
{
DeckLoader::saveToClipboard(getDeckList(), true, false);
DeckLoader::saveToClipboard(deckStateManager->getDeckList(), true, false);
}
/** @brief Saves deck to clipboard without annotations, with set info. */
void AbstractTabDeckEditor::actSaveDeckToClipboardRaw()
{
DeckLoader::saveToClipboard(getDeckList(), false, true);
DeckLoader::saveToClipboard(deckStateManager->getDeckList(), false, true);
}
/** @brief Saves deck to clipboard without annotations or set info. */
void AbstractTabDeckEditor::actSaveDeckToClipboardRawNoSetInfo()
{
DeckLoader::saveToClipboard(getDeckList(), false, false);
DeckLoader::saveToClipboard(deckStateManager->getDeckList(), false, false);
}
/** @brief Prints the deck using a QPrintPreviewDialog. */
@ -526,7 +479,7 @@ void AbstractTabDeckEditor::actPrintDeck()
{
auto *dlg = new QPrintPreviewDialog(this);
connect(dlg, &QPrintPreviewDialog::paintRequested, this,
[this](QPrinter *printer) { DeckLoader::printDeckList(printer, getDeckList()); });
[this](QPrinter *printer) { DeckLoader::printDeckList(printer, deckStateManager->getDeckList()); });
dlg->exec();
}
@ -547,7 +500,7 @@ void AbstractTabDeckEditor::actLoadDeckFromWebsite()
emit openDeckEditor({.deckList = dlg.getDeck()});
} else {
setDeck({.deckList = dlg.getDeck()});
setModified(true);
deckStateManager->setModified(true);
}
deckMenu->setSaveStatus(true);
@ -559,7 +512,7 @@ void AbstractTabDeckEditor::actLoadDeckFromWebsite()
*/
void AbstractTabDeckEditor::exportToDecklistWebsite(DeckLoader::DecklistWebsite website)
{
QString decklistUrlString = DeckLoader::exportDeckToDecklist(getDeckList(), website);
QString decklistUrlString = DeckLoader::exportDeckToDecklist(deckStateManager->getDeckList(), website);
// Check to make sure the string isn't empty.
if (decklistUrlString.isEmpty()) {
// Show an error if the deck is empty, and return.
@ -592,14 +545,14 @@ void AbstractTabDeckEditor::actExportDeckDecklistXyz()
void AbstractTabDeckEditor::actAnalyzeDeckDeckstats()
{
auto *interface = new DeckStatsInterface(*databaseDisplayDockWidget->databaseModel->getDatabase(), this);
interface->analyzeDeck(getDeckList());
interface->analyzeDeck(deckStateManager->getDeckList());
}
/** @brief Analyzes the deck using TappedOut. */
void AbstractTabDeckEditor::actAnalyzeDeckTappedout()
{
auto *interface = new TappedOutInterface(*databaseDisplayDockWidget->databaseModel->getDatabase(), this);
interface->analyzeDeck(getDeckList());
interface->analyzeDeck(deckStateManager->getDeckList());
}
/** @brief Applies a new filter tree to the database display. */
@ -658,7 +611,7 @@ bool AbstractTabDeckEditor::eventFilter(QObject *o, QEvent *e)
/** @brief Shows a confirmation dialog before closing. */
bool AbstractTabDeckEditor::confirmClose()
{
if (modified) {
if (deckStateManager->isModified()) {
tabSupervisor->setCurrentWidget(this);
int ret = createSaveConfirmationWindow()->exec();
if (ret == QMessageBox::Save)

View file

@ -19,6 +19,7 @@
#include <libcockatrice/deck_list/deck_list_history_manager.h>
class DeckStateManager;
class CardDatabaseModel;
class CardDatabaseDisplayModel;
@ -117,30 +118,13 @@ public:
*/
void openDeck(const LoadedDeck &deck);
/** @brief Returns the currently active deck loader. */
DeckLoader *getDeckLoader() const;
/** @brief Returns the currently active deck list. */
const DeckList &getDeckList() const;
/** @brief Sets the modified state of the tab.
* @param _windowModified Whether the tab is modified.
*/
void setModified(bool _windowModified);
DeckEditorDeckDockWidget *getDeckDockWidget() const
{
return deckDockWidget;
}
DeckListHistoryManager *getHistoryManager() const
{
return historyManager;
}
DeckListHistoryManager *historyManager;
// UI Elements
DeckStateManager *deckStateManager;
DeckEditorMenu *deckMenu; ///< Menu for deck operations
DeckEditorDatabaseDisplayWidget *databaseDisplayDockWidget; ///< Database dock
DeckEditorCardInfoDockWidget *cardInfoDockWidget; ///< Card info dock
@ -155,14 +139,6 @@ public slots:
/** @brief Called when the deck is modified. */
virtual void onDeckModified();
/** @brief Called when a widget is about to modify the state of the DeckList.
* @param modificationReason The reason for the state modification
*/
virtual void onDeckHistorySaveRequested(const QString &modificationReason);
/** @brief Called when a widget would like to clear the history. */
virtual void onDeckHistoryClearRequested();
/** @brief Updates the card info panel.
* @param card The card to display.
*/
@ -202,9 +178,6 @@ signals:
/** @brief Emitted before the tab is closed. */
void deckEditorClosing(AbstractTabDeckEditor *tab);
/** @brief Emitted when a card should be decremented. */
void decrementCard(const ExactCard &card, QString zoneName);
protected slots:
/** @brief Starts a new deck in this tab. */
virtual void actNewDeck();
@ -315,9 +288,6 @@ protected:
*/
QMessageBox *createSaveConfirmationWindow();
/** @brief Returns true if the tab is a blank newly created deck. */
bool isBlankNewDeck() const;
/** @brief Helper function to add a card to a specific deck zone. */
void addCardHelper(const ExactCard &card, const QString &zoneName);
@ -330,8 +300,6 @@ protected:
QAction *aResetLayout;
QAction *aCardInfoDockVisible, *aCardInfoDockFloating, *aDeckDockVisible, *aDeckDockFloating;
QAction *aFilterDockVisible, *aFilterDockFloating, *aPrintingSelectorDockVisible, *aPrintingSelectorDockFloating;
bool modified = false; ///< Whether the deck/tab has unsaved changes
};
#endif // TAB_GENERIC_DECK_EDITOR_H

View file

@ -68,7 +68,10 @@ ArchidektApiResponseDeckDisplayWidget::ArchidektApiResponseDeckDisplayWidget(QWi
model = new DeckListModel(this);
connect(model, &DeckListModel::modelReset, this, &ArchidektApiResponseDeckDisplayWidget::decklistModelReset);
model->getDeckList()->loadFromStream_Plain(deckStream, false);
auto decklist = QSharedPointer<DeckList>(new DeckList);
decklist->loadFromStream_Plain(deckStream, false);
model->setDeckList(decklist);
model->forEachCard(CardNodeFunction::ResolveProviderId());

View file

@ -1,6 +1,7 @@
#include "tab_deck_editor.h"
#include "../../../client/settings/cache_settings.h"
#include "../deck_editor/deck_state_manager.h"
#include "../filters/filter_builder.h"
#include "../interface/pixel_map_generator.h"
#include "../interface/widgets/cards/card_info_frame_widget.h"
@ -114,8 +115,8 @@ void TabDeckEditor::createMenus()
*/
QString TabDeckEditor::getTabText() const
{
QString result = tr("Deck: %1").arg(deckDockWidget->getSimpleDeckName());
if (modified)
QString result = tr("Deck: %1").arg(deckStateManager->getSimpleDeckName());
if (deckStateManager->isModified())
result.prepend("* ");
return result;
}

View file

@ -1,6 +1,7 @@
#include "tab_deck_editor_visual.h"
#include "../../../../client/settings/cache_settings.h"
#include "../../deck_editor/deck_state_manager.h"
#include "../../filters/filter_builder.h"
#include "../../interface/pixel_map_generator.h"
#include "../../interface/widgets/cards/card_info_frame_widget.h"
@ -61,7 +62,7 @@ void TabDeckEditorVisual::createCentralFrame()
centralFrame = new QVBoxLayout;
centralWidget->setLayout(centralFrame);
tabContainer = new TabDeckEditorVisualTabWidget(centralWidget, this, deckDockWidget->deckModel,
tabContainer = new TabDeckEditorVisualTabWidget(centralWidget, this, deckStateManager->getModel(),
databaseDisplayDockWidget->databaseModel,
databaseDisplayDockWidget->databaseDisplayModel);
@ -85,7 +86,7 @@ void TabDeckEditorVisual::onDeckChanged()
AbstractTabDeckEditor::onDeckModified();
tabContainer->visualDeckView->constructZoneWidgetsFromDeckListModel();
tabContainer->deckAnalytics->refreshDisplays();
tabContainer->sampleHandWidget->setDeckModel(deckDockWidget->deckModel);
tabContainer->sampleHandWidget->setDeckModel(deckStateManager->getModel());
}
/** @brief Creates menus for deck editing and view options, including dock actions. */
@ -149,8 +150,8 @@ void TabDeckEditorVisual::createMenus()
/** @brief Returns the tab text, prepending a mark if the deck has unsaved changes. */
QString TabDeckEditorVisual::getTabText() const
{
QString result = tr("Visual Deck: %1").arg(deckDockWidget->getSimpleDeckName());
if (modified)
QString result = tr("Visual Deck: %1").arg(deckStateManager->getSimpleDeckName());
if (deckStateManager->isModified())
result.prepend("* ");
return result;
}
@ -166,9 +167,9 @@ void TabDeckEditorVisual::changeModelIndexAndCardInfo(const ExactCard &activeCar
void TabDeckEditorVisual::changeModelIndexToCard(const ExactCard &activeCard)
{
QString cardName = activeCard.getName();
QModelIndex index = deckDockWidget->deckModel->findCard(cardName, DECK_ZONE_MAIN);
QModelIndex index = deckStateManager->getModel()->findCard(cardName, DECK_ZONE_MAIN);
if (!index.isValid()) {
index = deckDockWidget->deckModel->findCard(cardName, DECK_ZONE_SIDE);
index = deckStateManager->getModel()->findCard(cardName, DECK_ZONE_SIDE);
}
if (!deckDockWidget->getSelectionModel()->hasSelection()) {
deckDockWidget->getSelectionModel()->setCurrentIndex(index, QItemSelectionModel::NoUpdate);
@ -182,7 +183,7 @@ void TabDeckEditorVisual::processMainboardCardClick(QMouseEvent *event,
auto card = instance->getCard();
// Get the model index for the card
QModelIndex idx = deckDockWidget->deckModel->findCard(card.getName(), zoneName);
QModelIndex idx = deckStateManager->getModel()->findCard(card.getName(), zoneName);
if (!idx.isValid()) {
return;
}
@ -191,8 +192,8 @@ void TabDeckEditorVisual::processMainboardCardClick(QMouseEvent *event,
// Double click = swap
if (event->type() == QEvent::MouseButtonDblClick && event->button() == Qt::LeftButton) {
deckDockWidget->actSwapCard(card, zoneName);
idx = deckDockWidget->deckModel->findCard(card.getName(), zoneName);
deckStateManager->swapCardAtIndex(idx);
idx = deckStateManager->getModel()->findCard(card.getName(), zoneName);
sel->setCurrentIndex(idx, QItemSelectionModel::ClearAndSelect);
return;
}

View file

@ -2,6 +2,7 @@
#include "../../../interface/widgets/dialogs/dlg_load_deck_from_clipboard.h"
#include "../../../interface/widgets/tabs/abstract_tab_deck_editor.h"
#include "../deck_editor/deck_state_manager.h"
#include <QHBoxLayout>
@ -60,7 +61,7 @@ void VisualDatabaseDisplayNameFilterWidget::retranslateUi()
void VisualDatabaseDisplayNameFilterWidget::actLoadFromDeck()
{
DeckListModel *deckListModel = deckEditor->deckDockWidget->deckModel;
DeckListModel *deckListModel = deckEditor->deckStateManager->getModel();
if (!deckListModel)
return;

View file

@ -5,14 +5,15 @@
DeckListModel::DeckListModel(QObject *parent)
: QAbstractItemModel(parent), lastKnownColumn(1), lastKnownOrder(Qt::AscendingOrder)
{
// This class will leak the decklist object. We cannot safely delete it in the dtor because the deckList field is a
// non-owning pointer and another deckList might have been assigned to it.
// `DeckListModel::cleanList` also leaks for the same reason.
// TODO: fix the leak
deckList = new DeckList;
deckList = QSharedPointer<DeckList>(new DeckList());
root = new InnerDecklistNode;
}
DeckListModel::DeckListModel(QObject *parent, const QSharedPointer<DeckList> &deckList) : DeckListModel(parent)
{
setDeckList(deckList);
}
DeckListModel::~DeckListModel()
{
delete root;
@ -586,13 +587,13 @@ void DeckListModel::setActiveFormat(const QString &_format)
void DeckListModel::cleanList()
{
setDeckList(new DeckList);
setDeckList(QSharedPointer<DeckList>(new DeckList()));
}
/**
* @param _deck The deck.
*/
void DeckListModel::setDeckList(DeckList *_deck)
void DeckListModel::setDeckList(const QSharedPointer<DeckList> &_deck)
{
if (deckList != _deck) {
deckList = _deck;

View file

@ -245,6 +245,7 @@ signals:
public:
explicit DeckListModel(QObject *parent = nullptr);
explicit DeckListModel(QObject *parent, const QSharedPointer<DeckList> &deckList);
~DeckListModel() override;
/**
@ -314,11 +315,12 @@ public:
* @brief Removes all cards and resets the model.
*/
void cleanList();
[[nodiscard]] DeckList *getDeckList() const
[[nodiscard]] QSharedPointer<DeckList> getDeckList() const
{
return deckList;
}
void setDeckList(DeckList *_deck);
void setDeckList(const QSharedPointer<DeckList> &_deck);
/**
* @brief Apply a function to every card in the deck tree.
@ -351,8 +353,8 @@ public:
[[nodiscard]] QList<QString> getZones() const;
private:
DeckList *deckList; /**< Pointer to the deck loader providing the underlying data. */
InnerDecklistNode *root; /**< Root node of the model tree. */
QSharedPointer<DeckList> deckList; /**< Pointer to the decklist providing the underlying data. */
InnerDecklistNode *root; /**< Root node of the model tree. */
DeckListModelGroupCriteria::Type activeGroupCriteria = DeckListModelGroupCriteria::MAIN_TYPE;
int lastKnownColumn; /**< Last column used for sorting. */
Qt::SortOrder lastKnownOrder; /**< Last known sort order. */