[DeckList] Make DeckList not a QObject (#6383)

This commit is contained in:
RickyRister
2025-12-02 21:18:46 -08:00
committed by GitHub
parent d29e72ce72
commit 658ae83157
6 changed files with 28 additions and 67 deletions

View File

@@ -424,7 +424,6 @@ void DeckEditorDeckDockWidget::setDeck(DeckLoader *_deck)
deckLoader->setParent(this); deckLoader->setParent(this);
deckModel->setDeckList(deckLoader->getDeckList()); deckModel->setDeckList(deckLoader->getDeckList());
connect(deckLoader, &DeckLoader::deckLoaded, deckModel, &DeckListModel::rebuildTree); connect(deckLoader, &DeckLoader::deckLoaded, deckModel, &DeckListModel::rebuildTree);
connect(deckLoader->getDeckList(), &DeckList::deckHashChanged, deckModel, &DeckListModel::deckHashChanged);
emit requestDeckHistoryClear(); emit requestDeckHistoryClear();
historyManagerWidget->setDeckListModel(deckModel); historyManagerWidget->setDeckListModel(deckModel);
@@ -452,7 +451,7 @@ void DeckEditorDeckDockWidget::syncDisplayWidgetsToModel()
sortDeckModelToDeckView(); sortDeckModelToDeckView();
expandAll(); expandAll();
deckTagsDisplayWidget->connectDeckList(deckModel->getDeckList()); deckTagsDisplayWidget->setDeckList(deckModel->getDeckList());
} }
void DeckEditorDeckDockWidget::sortDeckModelToDeckView() void DeckEditorDeckDockWidget::sortDeckModelToDeckView()
@@ -485,7 +484,7 @@ void DeckEditorDeckDockWidget::cleanDeck()
emit deckModified(); emit deckModified();
emit deckChanged(); emit deckChanged();
updateBannerCardComboBox(); updateBannerCardComboBox();
deckTagsDisplayWidget->connectDeckList(deckModel->getDeckList()); deckTagsDisplayWidget->setDeckList(deckModel->getDeckList());
} }
void DeckEditorDeckDockWidget::recursiveExpand(const QModelIndex &index) void DeckEditorDeckDockWidget::recursiveExpand(const QModelIndex &index)

View File

@@ -28,21 +28,15 @@ DeckPreviewDeckTagsDisplayWidget::DeckPreviewDeckTagsDisplayWidget(QWidget *_par
flowWidget = new FlowWidget(this, Qt::Horizontal, Qt::ScrollBarAlwaysOff, Qt::ScrollBarAsNeeded); flowWidget = new FlowWidget(this, Qt::Horizontal, Qt::ScrollBarAlwaysOff, Qt::ScrollBarAsNeeded);
if (_deckList) { if (_deckList) {
connectDeckList(_deckList); setDeckList(_deckList);
} }
layout->addWidget(flowWidget); layout->addWidget(flowWidget);
} }
void DeckPreviewDeckTagsDisplayWidget::connectDeckList(DeckList *_deckList) void DeckPreviewDeckTagsDisplayWidget::setDeckList(DeckList *_deckList)
{ {
if (deckList) {
disconnect(deckList, &DeckList::deckTagsChanged, this, &DeckPreviewDeckTagsDisplayWidget::refreshTags);
}
deckList = _deckList; deckList = _deckList;
connect(deckList, &DeckList::deckTagsChanged, this, &DeckPreviewDeckTagsDisplayWidget::refreshTags);
refreshTags(); refreshTags();
} }
@@ -150,6 +144,7 @@ void DeckPreviewDeckTagsDisplayWidget::openTagEditDlg()
QStringList updatedTags = dialog.getActiveTags(); QStringList updatedTags = dialog.getActiveTags();
deckList->setTags(updatedTags); deckList->setTags(updatedTags);
deckPreviewWidget->deckLoader->saveToFile(deckPreviewWidget->filePath, DeckLoader::CockatriceFormat); deckPreviewWidget->deckLoader->saveToFile(deckPreviewWidget->filePath, DeckLoader::CockatriceFormat);
refreshTags();
} }
} }
} else if (parentWidget()) { } else if (parentWidget()) {
@@ -181,6 +176,7 @@ void DeckPreviewDeckTagsDisplayWidget::openTagEditDlg()
QStringList updatedTags = dialog.getActiveTags(); QStringList updatedTags = dialog.getActiveTags();
deckList->setTags(updatedTags); deckList->setTags(updatedTags);
deckEditor->setModified(true); deckEditor->setModified(true);
refreshTags();
} }
} }
} }

View File

@@ -21,7 +21,7 @@ class DeckPreviewDeckTagsDisplayWidget : public QWidget
public: public:
explicit DeckPreviewDeckTagsDisplayWidget(QWidget *_parent, DeckList *_deckList); explicit DeckPreviewDeckTagsDisplayWidget(QWidget *_parent, DeckList *_deckList);
void connectDeckList(DeckList *_deckList); void setDeckList(DeckList *_deckList);
void refreshTags(); void refreshTags();
DeckList *deckList; DeckList *deckList;
FlowWidget *flowWidget; FlowWidget *flowWidget;

View File

@@ -87,6 +87,12 @@ DeckList::DeckList()
root = new InnerDecklistNode; root = new InnerDecklistNode;
} }
DeckList::DeckList(const DeckList &other)
: metadata(other.metadata), sideboardPlans(other.sideboardPlans), root(new InnerDecklistNode(other.getRoot())),
cachedDeckHash(other.cachedDeckHash)
{
}
DeckList::DeckList(const QString &nativeString) DeckList::DeckList(const QString &nativeString)
{ {
root = new InnerDecklistNode; root = new InnerDecklistNode;
@@ -443,11 +449,8 @@ bool DeckList::loadFromStream_Plain(QTextStream &in, bool preserveMetadata)
cardName.replace(diff.key(), diff.value()); cardName.replace(diff.key(), diff.value());
} }
// Resolve complete card name, this function does nothing if the name is not found
cardName = getCompleteCardName(cardName);
// Determine the zone (mainboard/sideboard) // Determine the zone (mainboard/sideboard)
QString zoneName = getCardZoneFromName(cardName, sideboard ? DECK_ZONE_SIDE : DECK_ZONE_MAIN); QString zoneName = sideboard ? DECK_ZONE_SIDE : DECK_ZONE_MAIN;
// make new entry in decklist // make new entry in decklist
new DecklistCardNode(cardName, amount, getZoneObjFromName(zoneName), -1, setCode, collectorNumber); new DecklistCardNode(cardName, amount, getZoneObjFromName(zoneName), -1, setCode, collectorNumber);
@@ -708,12 +711,11 @@ QString DeckList::getDeckHash() const
} }
/** /**
* Invalidates the cached deckHash and emits the deckHashChanged signal. * Invalidates the cached deckHash.
*/ */
void DeckList::refreshDeckHash() void DeckList::refreshDeckHash()
{ {
cachedDeckHash = QString(); cachedDeckHash = QString();
emit deckHashChanged();
} }
/** /**

View File

@@ -1,5 +1,5 @@
/** /**
* @file decklist.h * @file deck_list.h
* @brief Defines the DeckList class and supporting types for managing a full * @brief Defines the DeckList class and supporting types for managing a full
* deck structure including cards, zones, sideboard plans, and * deck structure including cards, zones, sideboard plans, and
* serialization to/from multiple formats. This is a logic class which * serialization to/from multiple formats. This is a logic class which
@@ -93,7 +93,7 @@ public:
* @brief Represents a complete deck, including metadata, zones, cards, * @brief Represents a complete deck, including metadata, zones, cards,
* and sideboard plans. * and sideboard plans.
* *
* A DeckList is a QObject wrapper around an `InnerDecklistNode` tree, * A DeckList is a wrapper around an `InnerDecklistNode` tree,
* enriched with metadata like deck name, comments, tags, banner card, * enriched with metadata like deck name, comments, tags, banner card,
* and multiple sideboard plans. * and multiple sideboard plans.
* *
@@ -110,10 +110,6 @@ public:
* - Owns the root `InnerDecklistNode` tree. * - Owns the root `InnerDecklistNode` tree.
* - Owns `SideboardPlan` instances stored in `sideboardPlans`. * - Owns `SideboardPlan` instances stored in `sideboardPlans`.
* *
* ### Signals:
* - @c deckHashChanged() — emitted when the deck contents change.
* - @c deckTagsChanged() — emitted when tags are added/removed.
*
* ### Example workflow: * ### Example workflow:
* ``` * ```
* DeckList deck; * DeckList deck;
@@ -123,10 +119,8 @@ public:
* deck.saveToFile_Native(device); * deck.saveToFile_Native(device);
* ``` * ```
*/ */
class DeckList : public QObject class DeckList
{ {
Q_OBJECT
public: public:
struct Metadata struct Metadata
{ {
@@ -158,37 +152,7 @@ private:
static void getCardRefListHelper(InnerDecklistNode *item, QList<CardRef> &result); static void getCardRefListHelper(InnerDecklistNode *item, QList<CardRef> &result);
InnerDecklistNode *getZoneObjFromName(const QString &zoneName); InnerDecklistNode *getZoneObjFromName(const QString &zoneName);
protected: public:
/**
* @brief Map a card name to its zone.
* Override in subclasses for format-specific logic.
* @param cardName Card being placed.
* @param currentZoneName Zone candidate.
* @return Zone name to use.
*/
virtual QString getCardZoneFromName(const QString /*cardName*/, QString currentZoneName)
{
return currentZoneName;
}
/**
* @brief Produce the complete display name of a card.
* Override in subclasses to add set suffixes or annotations.
* @param cardName Base name.
* @return Full display name.
*/
virtual QString getCompleteCardName(const QString &cardName) const
{
return cardName;
}
signals:
/// Emitted when the deck hash changes.
void deckHashChanged();
/// Emitted when the deck tags are modified.
void deckTagsChanged();
public slots:
/// @name Metadata setters /// @name Metadata setters
///@{ ///@{
void setName(const QString &_name = QString()) void setName(const QString &_name = QString())
@@ -202,17 +166,14 @@ public slots:
void setTags(const QStringList &_tags = QStringList()) void setTags(const QStringList &_tags = QStringList())
{ {
metadata.tags = _tags; metadata.tags = _tags;
emit deckTagsChanged();
} }
void addTag(const QString &_tag) void addTag(const QString &_tag)
{ {
metadata.tags.append(_tag); metadata.tags.append(_tag);
emit deckTagsChanged();
} }
void clearTags() void clearTags()
{ {
metadata.tags.clear(); metadata.tags.clear();
emit deckTagsChanged();
} }
void setBannerCard(const CardRef &_bannerCard = {}) void setBannerCard(const CardRef &_bannerCard = {})
{ {
@@ -224,15 +185,13 @@ public slots:
} }
///@} ///@}
public:
/// @brief Construct an empty deck. /// @brief Construct an empty deck.
explicit DeckList(); explicit DeckList();
/// @brief Delete copy constructor. /// @brief Copy constructor (deep copies the node tree)
DeckList(const DeckList &) = delete; DeckList(const DeckList &other);
DeckList &operator=(const DeckList &) = delete;
/// @brief Construct from a serialized native-format string. /// @brief Construct from a serialized native-format string.
explicit DeckList(const QString &nativeString); explicit DeckList(const QString &nativeString);
~DeckList() override; virtual ~DeckList();
/// @name Metadata getters /// @name Metadata getters
/// The individual metadata getters still exist for backwards compatibility. /// The individual metadata getters still exist for backwards compatibility.

View File

@@ -5,8 +5,11 @@
DeckListModel::DeckListModel(QObject *parent) DeckListModel::DeckListModel(QObject *parent)
: QAbstractItemModel(parent), lastKnownColumn(1), lastKnownOrder(Qt::AscendingOrder) : 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 = new DeckList;
deckList->setParent(this);
root = new InnerDecklistNode; root = new InnerDecklistNode;
} }
@@ -284,6 +287,7 @@ bool DeckListModel::setData(const QModelIndex &index, const QVariant &value, con
emitRecursiveUpdates(index); emitRecursiveUpdates(index);
deckList->refreshDeckHash(); deckList->refreshDeckHash();
emit deckHashChanged();
emit dataChanged(index, index); emit dataChanged(index, index);
return true; return true;
@@ -422,6 +426,7 @@ QModelIndex DeckListModel::addCard(const ExactCard &card, const QString &zoneNam
cardNode->setCardCollectorNumber(printingInfo.getProperty("num")); cardNode->setCardCollectorNumber(printingInfo.getProperty("num"));
cardNode->setCardProviderId(printingInfo.getProperty("uuid")); cardNode->setCardProviderId(printingInfo.getProperty("uuid"));
deckList->refreshDeckHash(); deckList->refreshDeckHash();
emit deckHashChanged();
} }
sort(lastKnownColumn, lastKnownOrder); sort(lastKnownColumn, lastKnownOrder);
emitRecursiveUpdates(parentIndex); emitRecursiveUpdates(parentIndex);