Compare commits

..

4 Commits

Author SHA1 Message Date
dependabot[bot]
e557ae0f2a Bump actions/upload-artifact from 5 to 6 (#6445) 2025-12-22 18:09:50 +01:00
RickyRister
e80f13b78e [DeckDockWidget] Refactor to move down some methods in AbstractTabDeckEditor (#6444)
* move actSwapCard down

* rename method

* move actAddCard down
2025-12-22 05:48:55 -08:00
RickyRister
c12f4e9d2a [DeckListModel] remove more access to underlying decklist for iteration (#6436)
* [DeckListModel] remove more access to underlying decklist for iteration

* remove one last direct iteration of decklist
2025-12-21 16:19:57 -08:00
RickyRister
a0f977e80c [DeckList] refactor: pass DeckList by const ref (#6437)
* [DeckList] refactor: pass DeckList by const ref

* Change getDeckList to return a const ref
2025-12-21 16:19:33 -08:00
21 changed files with 168 additions and 148 deletions

View File

@@ -213,7 +213,7 @@ jobs:
- name: Upload artifact - name: Upload artifact
id: upload_artifact id: upload_artifact
if: matrix.package != 'skip' if: matrix.package != 'skip'
uses: actions/upload-artifact@v5 uses: actions/upload-artifact@v6
with: with:
name: ${{matrix.distro}}${{matrix.version}}-package name: ${{matrix.distro}}${{matrix.version}}-package
path: ${{steps.build.outputs.path}} path: ${{steps.build.outputs.path}}
@@ -450,7 +450,7 @@ jobs:
- name: Upload artifact - name: Upload artifact
id: upload_artifact id: upload_artifact
if: matrix.make_package if: matrix.make_package
uses: actions/upload-artifact@v5 uses: actions/upload-artifact@v6
with: with:
name: ${{matrix.artifact_name}} name: ${{matrix.artifact_name}}
path: ${{steps.build.outputs.path}} path: ${{steps.build.outputs.path}}
@@ -458,7 +458,7 @@ jobs:
- name: Upload pdb database - name: Upload pdb database
if: matrix.os == 'Windows' if: matrix.os == 'Windows'
uses: actions/upload-artifact@v5 uses: actions/upload-artifact@v6
with: with:
name: Windows${{matrix.target}}-debug-pdbs name: Windows${{matrix.target}}-debug-pdbs
path: | path: |

View File

@@ -1,13 +1,11 @@
@page deck_search_syntax_help Deck Search Syntax Help @page deck_search_syntax_help Deck Search Syntax Help
## Deck Search Syntax Help ## Deck Search Syntax Help
-----
The search bar recognizes a set of special commands.<br> The search bar recognizes a set of special commands.<br>
In this list of examples below, each entry has an explanation and can be clicked to test the query. Note that all In this list of examples below, each entry has an explanation and can be clicked to test the query. Note that all
searches are case insensitive. searches are case insensitive.
<dl> <dl>
<dt>Display Name (The deck name, or the filename if the deck name isn't set):</dt> <dt>Display Name (The deck name, or the filename if the deck name isn't set):</dt>
<dd>[red deck wins](#red deck wins) <small>(Any deck with a display name containing the words red, deck, and wins)</small></dd> <dd>[red deck wins](#red deck wins) <small>(Any deck with a display name containing the words red, deck, and wins)</small></dd>
<dd>["red deck wins"](#%22red deck wins%22) <small>(Any deck with a display name containing the exact phrase "red deck wins")</small></dd> <dd>["red deck wins"](#%22red deck wins%22) <small>(Any deck with a display name containing the exact phrase "red deck wins")</small></dd>

View File

@@ -1,12 +1,10 @@
@page search_syntax_help Search Syntax Help @page search_syntax_help Search Syntax Help
## Search Syntax Help ## Search Syntax Help
-----
The search bar recognizes a set of special commands similar to some other card databases.<br> The search bar recognizes a set of special commands similar to some other card databases.<br>
In this list of examples below, each entry has an explanation and can be clicked to test the query. Note that all searches are case insensitive. In this list of examples below, each entry has an explanation and can be clicked to test the query. Note that all searches are case insensitive.
<dl> <dl>
<dt>Name:</dt> <dt>Name:</dt>
<dd>[birds of paradise](#birds of paradise) <small>(Any card name containing the words birds, of, and paradise)</small></dd> <dd>[birds of paradise](#birds of paradise) <small>(Any card name containing the words birds, of, and paradise)</small></dd>
<dd>["birds of paradise"](#%22birds of paradise%22) <small>(Any card name containing the exact phrase "birds of paradise")</small></dd> <dd>["birds of paradise"](#%22birds of paradise%22) <small>(Any card name containing the exact phrase "birds of paradise")</small></dd>

View File

@@ -43,23 +43,23 @@ void DeckStatsInterface::queryFinished(QNetworkReply *reply)
deleteLater(); deleteLater();
} }
void DeckStatsInterface::getAnalyzeRequestData(DeckList *deck, QByteArray *data) void DeckStatsInterface::getAnalyzeRequestData(const DeckList &deck, QByteArray &data)
{ {
DeckList deckWithoutTokens; DeckList deckWithoutTokens;
copyDeckWithoutTokens(*deck, deckWithoutTokens); copyDeckWithoutTokens(deck, deckWithoutTokens);
QUrl params; QUrl params;
QUrlQuery urlQuery; QUrlQuery urlQuery;
urlQuery.addQueryItem("deck", deckWithoutTokens.writeToString_Plain()); urlQuery.addQueryItem("deck", deckWithoutTokens.writeToString_Plain());
urlQuery.addQueryItem("decktitle", deck->getName()); urlQuery.addQueryItem("decktitle", deck.getName());
params.setQuery(urlQuery); params.setQuery(urlQuery);
data->append(params.query(QUrl::EncodeReserved).toUtf8()); data.append(params.query(QUrl::EncodeReserved).toUtf8());
} }
void DeckStatsInterface::analyzeDeck(DeckList *deck) void DeckStatsInterface::analyzeDeck(const DeckList &deck)
{ {
QByteArray data; QByteArray data;
getAnalyzeRequestData(deck, &data); getAnalyzeRequestData(deck, data);
QNetworkRequest request(QUrl("https://deckstats.net/index.php")); QNetworkRequest request(QUrl("https://deckstats.net/index.php"));
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded"); request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
@@ -68,7 +68,7 @@ void DeckStatsInterface::analyzeDeck(DeckList *deck)
manager->post(request, data); manager->post(request, data);
} }
void DeckStatsInterface::copyDeckWithoutTokens(DeckList &source, DeckList &destination) void DeckStatsInterface::copyDeckWithoutTokens(const DeckList &source, DeckList &destination)
{ {
auto copyIfNotAToken = [this, &destination](const auto node, const auto card) { auto copyIfNotAToken = [this, &destination](const auto node, const auto card) {
CardInfoPtr dbCard = cardDatabase.query()->getCardInfo(card->getName()); CardInfoPtr dbCard = cardDatabase.query()->getCardInfo(card->getName());

View File

@@ -28,15 +28,15 @@ private:
* closest non-token card instead. So we construct a new deck which has no * closest non-token card instead. So we construct a new deck which has no
* tokens. * tokens.
*/ */
void copyDeckWithoutTokens(DeckList &source, DeckList &destination); void copyDeckWithoutTokens(const DeckList &source, DeckList &destination);
private slots: private slots:
void queryFinished(QNetworkReply *reply); void queryFinished(QNetworkReply *reply);
void getAnalyzeRequestData(DeckList *deck, QByteArray *data); void getAnalyzeRequestData(const DeckList &deck, QByteArray &data);
public: public:
explicit DeckStatsInterface(CardDatabase &_cardDatabase, QObject *parent = nullptr); explicit DeckStatsInterface(CardDatabase &_cardDatabase, QObject *parent = nullptr);
void analyzeDeck(DeckList *deck); void analyzeDeck(const DeckList &deck);
}; };
#endif #endif

View File

@@ -67,24 +67,24 @@ void TappedOutInterface::queryFinished(QNetworkReply *reply)
deleteLater(); deleteLater();
} }
void TappedOutInterface::getAnalyzeRequestData(DeckList *deck, QByteArray *data) void TappedOutInterface::getAnalyzeRequestData(const DeckList &deck, QByteArray &data)
{ {
DeckList mainboard, sideboard; DeckList mainboard, sideboard;
copyDeckSplitMainAndSide(*deck, mainboard, sideboard); copyDeckSplitMainAndSide(deck, mainboard, sideboard);
QUrl params; QUrl params;
QUrlQuery urlQuery; QUrlQuery urlQuery;
urlQuery.addQueryItem("name", deck->getName()); urlQuery.addQueryItem("name", deck.getName());
urlQuery.addQueryItem("mainboard", mainboard.writeToString_Plain(false, true)); urlQuery.addQueryItem("mainboard", mainboard.writeToString_Plain(false, true));
urlQuery.addQueryItem("sideboard", sideboard.writeToString_Plain(false, true)); urlQuery.addQueryItem("sideboard", sideboard.writeToString_Plain(false, true));
params.setQuery(urlQuery); params.setQuery(urlQuery);
data->append(params.query(QUrl::EncodeReserved).toUtf8()); data.append(params.query(QUrl::EncodeReserved).toUtf8());
} }
void TappedOutInterface::analyzeDeck(DeckList *deck) void TappedOutInterface::analyzeDeck(const DeckList &deck)
{ {
QByteArray data; QByteArray data;
getAnalyzeRequestData(deck, &data); getAnalyzeRequestData(deck, data);
QNetworkRequest request(QUrl("https://tappedout.net/mtg-decks/paste/")); QNetworkRequest request(QUrl("https://tappedout.net/mtg-decks/paste/"));
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded"); request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
@@ -93,7 +93,7 @@ void TappedOutInterface::analyzeDeck(DeckList *deck)
manager->post(request, data); manager->post(request, data);
} }
void TappedOutInterface::copyDeckSplitMainAndSide(DeckList &source, DeckList &mainboard, DeckList &sideboard) void TappedOutInterface::copyDeckSplitMainAndSide(const DeckList &source, DeckList &mainboard, DeckList &sideboard)
{ {
auto copyMainOrSide = [this, &mainboard, &sideboard](const auto node, const auto card) { auto copyMainOrSide = [this, &mainboard, &sideboard](const auto node, const auto card) {
CardInfoPtr dbCard = cardDatabase.query()->getCardInfo(card->getName()); CardInfoPtr dbCard = cardDatabase.query()->getCardInfo(card->getName());

View File

@@ -30,14 +30,14 @@ private:
QNetworkAccessManager *manager; QNetworkAccessManager *manager;
CardDatabase &cardDatabase; CardDatabase &cardDatabase;
void copyDeckSplitMainAndSide(DeckList &source, DeckList &mainboard, DeckList &sideboard); void copyDeckSplitMainAndSide(const DeckList &source, DeckList &mainboard, DeckList &sideboard);
private slots: private slots:
void queryFinished(QNetworkReply *reply); void queryFinished(QNetworkReply *reply);
void getAnalyzeRequestData(DeckList *deck, QByteArray *data); void getAnalyzeRequestData(const DeckList &deck, QByteArray &data);
public: public:
explicit TappedOutInterface(CardDatabase &_cardDatabase, QObject *parent = nullptr); explicit TappedOutInterface(CardDatabase &_cardDatabase, QObject *parent = nullptr);
void analyzeDeck(DeckList *deck); void analyzeDeck(const DeckList &deck);
}; };
#endif #endif

View File

@@ -287,14 +287,14 @@ static QString toDecklistExportString(const QList<const DecklistCardNode *> &car
* @param deckList The decklist to export * @param deckList The decklist to export
* @param website The website we're sending the deck to * @param website The website we're sending the deck to
*/ */
QString DeckLoader::exportDeckToDecklist(const DeckList *deckList, DecklistWebsite website) QString DeckLoader::exportDeckToDecklist(const DeckList &deckList, DecklistWebsite website)
{ {
// Add the base url // Add the base url
QString deckString = "https://" + getDomainForWebsite(website) + "/?"; QString deckString = "https://" + getDomainForWebsite(website) + "/?";
// export all cards in zone // export all cards in zone
QString mainBoardCards = toDecklistExportString(deckList->getCardNodes({DECK_ZONE_MAIN})); QString mainBoardCards = toDecklistExportString(deckList.getCardNodes({DECK_ZONE_MAIN}));
QString sideBoardCards = toDecklistExportString(deckList->getCardNodes({DECK_ZONE_SIDE})); QString sideBoardCards = toDecklistExportString(deckList.getCardNodes({DECK_ZONE_SIDE}));
// Remove the extra return at the end of the last cards // Remove the extra return at the end of the last cards
mainBoardCards.chop(3); mainBoardCards.chop(3);
@@ -310,7 +310,7 @@ QString DeckLoader::exportDeckToDecklist(const DeckList *deckList, DecklistWebsi
return deckString; return deckString;
} }
void DeckLoader::saveToClipboard(const DeckList *deckList, bool addComments, bool addSetNameAndNumber) void DeckLoader::saveToClipboard(const DeckList &deckList, bool addComments, bool addSetNameAndNumber)
{ {
QString buffer; QString buffer;
QTextStream stream(&buffer); QTextStream stream(&buffer);
@@ -320,7 +320,7 @@ void DeckLoader::saveToClipboard(const DeckList *deckList, bool addComments, boo
} }
bool DeckLoader::saveToStream_Plain(QTextStream &out, bool DeckLoader::saveToStream_Plain(QTextStream &out,
const DeckList *deckList, const DeckList &deckList,
bool addComments, bool addComments,
bool addSetNameAndNumber) bool addSetNameAndNumber)
{ {
@@ -329,7 +329,7 @@ bool DeckLoader::saveToStream_Plain(QTextStream &out,
} }
// loop zones // loop zones
for (auto zoneNode : deckList->getZoneNodes()) { for (auto zoneNode : deckList.getZoneNodes()) {
saveToStream_DeckZone(out, zoneNode, addComments, addSetNameAndNumber); saveToStream_DeckZone(out, zoneNode, addComments, addSetNameAndNumber);
// end of zone // end of zone
@@ -339,14 +339,14 @@ bool DeckLoader::saveToStream_Plain(QTextStream &out,
return true; return true;
} }
void DeckLoader::saveToStream_DeckHeader(QTextStream &out, const DeckList *deckList) void DeckLoader::saveToStream_DeckHeader(QTextStream &out, const DeckList &deckList)
{ {
if (!deckList->getName().isEmpty()) { if (!deckList.getName().isEmpty()) {
out << "// " << deckList->getName() << "\n\n"; out << "// " << deckList.getName() << "\n\n";
} }
if (!deckList->getComments().isEmpty()) { if (!deckList.getComments().isEmpty()) {
QStringList commentRows = deckList->getComments().split(QRegularExpression("\n|\r\n|\r")); QStringList commentRows = deckList.getComments().split(QRegularExpression("\n|\r\n|\r"));
for (const QString &row : commentRows) { for (const QString &row : commentRows) {
out << "// " << row << "\n"; out << "// " << row << "\n";
} }
@@ -434,7 +434,7 @@ void DeckLoader::saveToStream_DeckZoneCards(QTextStream &out,
} }
} }
bool DeckLoader::convertToCockatriceFormat(QString fileName) bool DeckLoader::convertToCockatriceFormat(const QString &fileName)
{ {
// Change the file extension to .cod // Change the file extension to .cod
QFileInfo fileInfo(fileName); QFileInfo fileInfo(fileName);
@@ -543,7 +543,7 @@ void DeckLoader::printDeckListNode(QTextCursor *cursor, const InnerDecklistNode
cursor->movePosition(QTextCursor::End); cursor->movePosition(QTextCursor::End);
} }
void DeckLoader::printDeckList(QPrinter *printer, const DeckList *deckList) void DeckLoader::printDeckList(QPrinter *printer, const DeckList &deckList)
{ {
QTextDocument doc; QTextDocument doc;
@@ -559,14 +559,14 @@ void DeckLoader::printDeckList(QPrinter *printer, const DeckList *deckList)
headerCharFormat.setFontWeight(QFont::Bold); headerCharFormat.setFontWeight(QFont::Bold);
cursor.insertBlock(headerBlockFormat, headerCharFormat); cursor.insertBlock(headerBlockFormat, headerCharFormat);
cursor.insertText(deckList->getName()); cursor.insertText(deckList.getName());
headerCharFormat.setFontPointSize(12); headerCharFormat.setFontPointSize(12);
cursor.insertBlock(headerBlockFormat, headerCharFormat); cursor.insertBlock(headerBlockFormat, headerCharFormat);
cursor.insertText(deckList->getComments()); cursor.insertText(deckList.getComments());
cursor.insertBlock(headerBlockFormat, headerCharFormat); cursor.insertBlock(headerBlockFormat, headerCharFormat);
for (auto zoneNode : deckList->getZoneNodes()) { for (auto zoneNode : deckList.getZoneNodes()) {
cursor.insertHtml("<br><img src=theme:hr.jpg>"); cursor.insertHtml("<br><img src=theme:hr.jpg>");
cursor.insertBlock(headerBlockFormat, headerCharFormat); cursor.insertBlock(headerBlockFormat, headerCharFormat);

View File

@@ -59,11 +59,11 @@ public:
bool saveToFile(const QString &fileName, DeckFileFormat::Format fmt); bool saveToFile(const QString &fileName, DeckFileFormat::Format fmt);
bool updateLastLoadedTimestamp(const QString &fileName, DeckFileFormat::Format fmt); bool updateLastLoadedTimestamp(const QString &fileName, DeckFileFormat::Format fmt);
static QString exportDeckToDecklist(const DeckList *deckList, DecklistWebsite website); static QString exportDeckToDecklist(const DeckList &deckList, DecklistWebsite website);
static void saveToClipboard(const DeckList *deckList, bool addComments = true, bool addSetNameAndNumber = true); static void saveToClipboard(const DeckList &deckList, bool addComments = true, bool addSetNameAndNumber = true);
static bool saveToStream_Plain(QTextStream &out, static bool saveToStream_Plain(QTextStream &out,
const DeckList *deckList, const DeckList &deckList,
bool addComments = true, bool addComments = true,
bool addSetNameAndNumber = true); bool addSetNameAndNumber = true);
@@ -72,9 +72,9 @@ public:
* @param printer The printer to render the decklist to. * @param printer The printer to render the decklist to.
* @param deckList * @param deckList
*/ */
static void printDeckList(QPrinter *printer, const DeckList *deckList); static void printDeckList(QPrinter *printer, const DeckList &deckList);
bool convertToCockatriceFormat(QString fileName); bool convertToCockatriceFormat(const QString &fileName);
LoadedDeck &getDeck() LoadedDeck &getDeck()
{ {
@@ -91,7 +91,7 @@ public:
private: private:
static void printDeckListNode(QTextCursor *cursor, const InnerDecklistNode *node); static void printDeckListNode(QTextCursor *cursor, const InnerDecklistNode *node);
static void saveToStream_DeckHeader(QTextStream &out, const DeckList *deckList); static void saveToStream_DeckHeader(QTextStream &out, const DeckList &deckList);
static void saveToStream_DeckZone(QTextStream &out, static void saveToStream_DeckZone(QTextStream &out,
const InnerDecklistNode *zoneNode, const InnerDecklistNode *zoneNode,

View File

@@ -76,14 +76,14 @@ void DeckEditorDeckDockWidget::createDeckDock()
deckView->setSelectionMode(QAbstractItemView::ExtendedSelection); deckView->setSelectionMode(QAbstractItemView::ExtendedSelection);
connect(deckView->selectionModel(), &QItemSelectionModel::currentRowChanged, this, connect(deckView->selectionModel(), &QItemSelectionModel::currentRowChanged, this,
&DeckEditorDeckDockWidget::updateCard); &DeckEditorDeckDockWidget::updateCard);
connect(deckView, &QTreeView::doubleClicked, this, &DeckEditorDeckDockWidget::actSwapCard); connect(deckView, &QTreeView::doubleClicked, this, &DeckEditorDeckDockWidget::actSwapSelection);
deckView->setContextMenuPolicy(Qt::CustomContextMenu); deckView->setContextMenuPolicy(Qt::CustomContextMenu);
connect(deckView, &QTreeView::customContextMenuRequested, this, &DeckEditorDeckDockWidget::decklistCustomMenu); connect(deckView, &QTreeView::customContextMenuRequested, this, &DeckEditorDeckDockWidget::decklistCustomMenu);
connect(&deckViewKeySignals, &KeySignals::onShiftS, this, &DeckEditorDeckDockWidget::actSwapCard); connect(&deckViewKeySignals, &KeySignals::onShiftS, this, &DeckEditorDeckDockWidget::actSwapSelection);
connect(&deckViewKeySignals, &KeySignals::onEnter, this, &DeckEditorDeckDockWidget::actIncrement); connect(&deckViewKeySignals, &KeySignals::onEnter, this, &DeckEditorDeckDockWidget::actIncrementSelection);
connect(&deckViewKeySignals, &KeySignals::onCtrlAltEqual, this, &DeckEditorDeckDockWidget::actIncrement); connect(&deckViewKeySignals, &KeySignals::onCtrlAltEqual, this, &DeckEditorDeckDockWidget::actIncrementSelection);
connect(&deckViewKeySignals, &KeySignals::onCtrlAltMinus, this, &DeckEditorDeckDockWidget::actDecrementSelection); connect(&deckViewKeySignals, &KeySignals::onCtrlAltMinus, this, &DeckEditorDeckDockWidget::actDecrementSelection);
connect(&deckViewKeySignals, &KeySignals::onShiftRight, this, &DeckEditorDeckDockWidget::actIncrement); connect(&deckViewKeySignals, &KeySignals::onShiftRight, this, &DeckEditorDeckDockWidget::actIncrementSelection);
connect(&deckViewKeySignals, &KeySignals::onShiftLeft, this, &DeckEditorDeckDockWidget::actDecrementSelection); connect(&deckViewKeySignals, &KeySignals::onShiftLeft, this, &DeckEditorDeckDockWidget::actDecrementSelection);
connect(&deckViewKeySignals, &KeySignals::onDelete, this, &DeckEditorDeckDockWidget::actRemoveCard); connect(&deckViewKeySignals, &KeySignals::onDelete, this, &DeckEditorDeckDockWidget::actRemoveCard);
@@ -181,7 +181,7 @@ void DeckEditorDeckDockWidget::createDeckDock()
aIncrement = new QAction(QString(), this); aIncrement = new QAction(QString(), this);
aIncrement->setIcon(QPixmap("theme:icons/increment")); aIncrement->setIcon(QPixmap("theme:icons/increment"));
connect(aIncrement, &QAction::triggered, this, &DeckEditorDeckDockWidget::actIncrement); connect(aIncrement, &QAction::triggered, this, &DeckEditorDeckDockWidget::actIncrementSelection);
auto *tbIncrement = new QToolButton(this); auto *tbIncrement = new QToolButton(this);
tbIncrement->setDefaultAction(aIncrement); tbIncrement->setDefaultAction(aIncrement);
@@ -199,7 +199,7 @@ void DeckEditorDeckDockWidget::createDeckDock()
aSwapCard = new QAction(QString(), this); aSwapCard = new QAction(QString(), this);
aSwapCard->setIcon(QPixmap("theme:icons/swap")); aSwapCard->setIcon(QPixmap("theme:icons/swap"));
connect(aSwapCard, &QAction::triggered, this, &DeckEditorDeckDockWidget::actSwapCard); connect(aSwapCard, &QAction::triggered, this, &DeckEditorDeckDockWidget::actSwapSelection);
auto *tbSwapCard = new QToolButton(this); auto *tbSwapCard = new QToolButton(this);
tbSwapCard->setDefaultAction(aSwapCard); tbSwapCard->setDefaultAction(aSwapCard);
@@ -386,15 +386,15 @@ void DeckEditorDeckDockWidget::updateBannerCardComboBox()
// Collect unique (name, providerId) pairs // Collect unique (name, providerId) pairs
QSet<QPair<QString, QString>> bannerCardSet; QSet<QPair<QString, QString>> bannerCardSet;
QList<const DecklistCardNode *> cardsInDeck = deckModel->getDeckList()->getCardNodes(); QList<CardRef> cardsInDeck = deckModel->getCardRefs();
for (auto currentCard : cardsInDeck) { for (auto cardRef : cardsInDeck) {
if (!CardDatabaseManager::query()->getCard(currentCard->toCardRef())) { if (!CardDatabaseManager::query()->getCard(cardRef)) {
continue; continue;
} }
// Insert one entry per distinct card, ignore copies // Insert one entry per distinct card, ignore copies
bannerCardSet.insert({currentCard->getName(), currentCard->getCardProviderId()}); bannerCardSet.insert({cardRef.name, cardRef.providerId});
} }
// Convert to sorted list // Convert to sorted list
@@ -527,9 +527,9 @@ DeckLoader *DeckEditorDeckDockWidget::getDeckLoader()
return deckLoader; return deckLoader;
} }
DeckList *DeckEditorDeckDockWidget::getDeckList() const DeckList &DeckEditorDeckDockWidget::getDeckList() const
{ {
return deckModel->getDeckList(); return *deckModel->getDeckList();
} }
/** /**
@@ -582,7 +582,32 @@ QModelIndexList DeckEditorDeckDockWidget::getSelectedCardNodes() const
return selectedRows; return selectedRows;
} }
void DeckEditorDeckDockWidget::actIncrement() void DeckEditorDeckDockWidget::actAddCard(const ExactCard &card, const QString &_zoneName)
{
if (!card) {
return;
}
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;
}
expandAll();
deckView->clearSelection();
deckView->setCurrentIndex(newCardIndex);
emit deckModified();
}
void DeckEditorDeckDockWidget::actIncrementSelection()
{ {
auto selectedRows = getSelectedCardNodes(); auto selectedRows = getSelectedCardNodes();
@@ -591,7 +616,20 @@ void DeckEditorDeckDockWidget::actIncrement()
} }
} }
void DeckEditorDeckDockWidget::actSwapCard() void DeckEditorDeckDockWidget::actSwapCard(const ExactCard &card, const QString &zoneName)
{
QString providerId = card.getPrinting().getUuid();
QString collectorNumber = card.getPrinting().getProperty("num");
QModelIndex foundCard = deckModel->findCard(card.getName(), zoneName, providerId, collectorNumber);
if (!foundCard.isValid()) {
foundCard = deckModel->findCard(card.getName(), zoneName);
}
swapCard(foundCard);
}
void DeckEditorDeckDockWidget::actSwapSelection()
{ {
auto selectedRows = getSelectedCardNodes(); auto selectedRows = getSelectedCardNodes();

View File

@@ -61,14 +61,14 @@ public slots:
void syncDisplayWidgetsToModel(); void syncDisplayWidgetsToModel();
void sortDeckModelToDeckView(); void sortDeckModelToDeckView();
DeckLoader *getDeckLoader(); DeckLoader *getDeckLoader();
DeckList *getDeckList(); const DeckList &getDeckList() const;
void actIncrement(); void actAddCard(const ExactCard &card, const QString &zoneName);
bool swapCard(const QModelIndex &idx); void actIncrementSelection();
void actDecrementCard(const ExactCard &card, QString zoneName); void actDecrementCard(const ExactCard &card, QString zoneName);
void actDecrementSelection(); void actDecrementSelection();
void actSwapCard(); void actSwapCard(const ExactCard &card, const QString &zoneName);
void actSwapSelection();
void actRemoveCard(); void actRemoveCard();
void offsetCountAtIndex(const QModelIndex &idx, int offset);
void initializeFormats(); void initializeFormats();
void expandAll(); void expandAll();
@@ -108,9 +108,11 @@ private:
void recursiveExpand(const QModelIndex &index); void recursiveExpand(const QModelIndex &index);
[[nodiscard]] QModelIndexList getSelectedCardNodes() const; [[nodiscard]] QModelIndexList getSelectedCardNodes() const;
void offsetCountAtIndex(const QModelIndex &idx, int offset);
private slots: private slots:
void decklistCustomMenu(QPoint point); void decklistCustomMenu(QPoint point);
bool swapCard(const QModelIndex &currentIndex);
void updateCard(QModelIndex, const QModelIndex &current); void updateCard(QModelIndex, const QModelIndex &current);
void updateName(const QString &name); void updateName(const QString &name);
void updateComments(); void updateComments();

View File

@@ -150,7 +150,7 @@ DlgEditDeckInClipboard::DlgEditDeckInClipboard(const DeckList &_deckList, bool _
* @param addComments Whether to add annotations * @param addComments Whether to add annotations
* @return A QString * @return A QString
*/ */
static QString deckListToString(const DeckList *deckList, bool addComments) static QString deckListToString(const DeckList &deckList, bool addComments)
{ {
QString buffer; QString buffer;
QTextStream stream(&buffer); QTextStream stream(&buffer);
@@ -160,7 +160,7 @@ static QString deckListToString(const DeckList *deckList, bool addComments)
void DlgEditDeckInClipboard::actRefresh() void DlgEditDeckInClipboard::actRefresh()
{ {
setText(deckListToString(&deckList, annotated)); setText(deckListToString(deckList, annotated));
} }
void DlgEditDeckInClipboard::actOK() void DlgEditDeckInClipboard::actOK()

View File

@@ -178,7 +178,7 @@ void DlgSelectSetForCards::actOK()
void DlgSelectSetForCards::actClear() void DlgSelectSetForCards::actClear()
{ {
emit deckAboutToBeModified(tr("Cleared all printing information.")); emit deckAboutToBeModified(tr("Cleared all printing information."));
model->getDeckList()->forEachCard(CardNodeFunction::ClearPrintingData()); model->forEachCard(CardNodeFunction::ClearPrintingData());
emit deckModified(); emit deckModified();
accept(); accept();
} }
@@ -186,8 +186,8 @@ void DlgSelectSetForCards::actClear()
void DlgSelectSetForCards::actSetAllToPreferred() void DlgSelectSetForCards::actSetAllToPreferred()
{ {
emit deckAboutToBeModified(tr("Set all printings to preferred.")); emit deckAboutToBeModified(tr("Set all printings to preferred."));
model->getDeckList()->forEachCard(CardNodeFunction::ClearPrintingData()); model->forEachCard(CardNodeFunction::ClearPrintingData());
model->getDeckList()->forEachCard(CardNodeFunction::SetProviderIdToPreferred()); model->forEachCard(CardNodeFunction::SetProviderIdToPreferred());
emit deckModified(); emit deckModified();
accept(); accept();
} }

View File

@@ -124,7 +124,7 @@ void AbstractTabDeckEditor::onDeckModified()
*/ */
void AbstractTabDeckEditor::onDeckHistorySaveRequested(const QString &modificationReason) void AbstractTabDeckEditor::onDeckHistorySaveRequested(const QString &modificationReason)
{ {
historyManager->save(deckDockWidget->getDeckList()->createMemento(modificationReason)); historyManager->save(deckDockWidget->getDeckList().createMemento(modificationReason));
} }
/** /**
@@ -140,23 +140,9 @@ void AbstractTabDeckEditor::onDeckHistoryClearRequested()
* @param card Card to add. * @param card Card to add.
* @param zoneName Zone to add the card to. * @param zoneName Zone to add the card to.
*/ */
void AbstractTabDeckEditor::addCardHelper(const ExactCard &card, QString zoneName) void AbstractTabDeckEditor::addCardHelper(const ExactCard &card, const QString &zoneName)
{ {
if (!card) deckDockWidget->actAddCard(card, zoneName);
return;
if (card.getInfo().getIsToken())
zoneName = DECK_ZONE_TOKENS;
onDeckHistorySaveRequested(QString(tr("Added (%1): %2 (%3) %4"))
.arg(zoneName, card.getName(), card.getPrinting().getSet()->getCorrectedShortName(),
card.getPrinting().getProperty("num")));
QModelIndex newCardIndex = deckDockWidget->deckModel->addCard(card, zoneName);
deckDockWidget->expandAll();
deckDockWidget->deckView->clearSelection();
deckDockWidget->deckView->setCurrentIndex(newCardIndex);
setModified(true);
databaseDisplayDockWidget->searchEdit->setSelection(0, databaseDisplayDockWidget->searchEdit->text().length()); databaseDisplayDockWidget->searchEdit->setSelection(0, databaseDisplayDockWidget->searchEdit->text().length());
} }
@@ -193,24 +179,6 @@ void AbstractTabDeckEditor::actDecrementCardFromSideboard(const ExactCard &card)
emit decrementCard(card, DECK_ZONE_SIDE); emit decrementCard(card, DECK_ZONE_SIDE);
} }
/**
* @brief Swaps a card in a deck zone.
* @param card Card to swap.
* @param zoneName Zone to swap in.
*/
void AbstractTabDeckEditor::actSwapCard(const ExactCard &card, const QString &zoneName)
{
QString providerId = card.getPrinting().getUuid();
QString collectorNumber = card.getPrinting().getProperty("num");
QModelIndex foundCard = deckDockWidget->deckModel->findCard(card.getName(), zoneName, providerId, collectorNumber);
if (!foundCard.isValid()) {
foundCard = deckDockWidget->deckModel->findCard(card.getName(), zoneName);
}
deckDockWidget->swapCard(foundCard);
}
/** /**
* @brief Opens a deck in this tab. * @brief Opens a deck in this tab.
* @param deck The deck * @param deck The deck
@@ -231,7 +199,7 @@ void AbstractTabDeckEditor::openDeck(const LoadedDeck &deck)
void AbstractTabDeckEditor::setDeck(const LoadedDeck &_deck) void AbstractTabDeckEditor::setDeck(const LoadedDeck &_deck)
{ {
deckDockWidget->setDeck(_deck); deckDockWidget->setDeck(_deck);
CardPictureLoader::cacheCardPixmaps(CardDatabaseManager::query()->getCards(getDeckList()->getCardRefList())); CardPictureLoader::cacheCardPixmaps(CardDatabaseManager::query()->getCards(getDeckList().getCardRefList()));
setModified(false); setModified(false);
aDeckDockVisible->setChecked(true); aDeckDockVisible->setChecked(true);
@@ -245,7 +213,7 @@ DeckLoader *AbstractTabDeckEditor::getDeckLoader() const
} }
/** @brief Returns the currently loaded deck list. */ /** @brief Returns the currently loaded deck list. */
DeckList *AbstractTabDeckEditor::getDeckList() const const DeckList &AbstractTabDeckEditor::getDeckList() const
{ {
return deckDockWidget->getDeckList(); return deckDockWidget->getDeckList();
} }
@@ -446,7 +414,7 @@ bool AbstractTabDeckEditor::actSaveDeckAs()
dialog.setAcceptMode(QFileDialog::AcceptSave); dialog.setAcceptMode(QFileDialog::AcceptSave);
dialog.setDefaultSuffix("cod"); dialog.setDefaultSuffix("cod");
dialog.setNameFilters(DeckLoader::FILE_NAME_FILTERS); dialog.setNameFilters(DeckLoader::FILE_NAME_FILTERS);
dialog.selectFile(getDeckList()->getName().trimmed()); dialog.selectFile(getDeckList().getName().trimmed());
if (!dialog.exec()) if (!dialog.exec())
return false; return false;
@@ -591,26 +559,21 @@ void AbstractTabDeckEditor::actLoadDeckFromWebsite()
*/ */
void AbstractTabDeckEditor::exportToDecklistWebsite(DeckLoader::DecklistWebsite website) void AbstractTabDeckEditor::exportToDecklistWebsite(DeckLoader::DecklistWebsite website)
{ {
if (DeckList *deckList = getDeckList()) { QString decklistUrlString = DeckLoader::exportDeckToDecklist(getDeckList(), website);
QString decklistUrlString = DeckLoader::exportDeckToDecklist(deckList, website); // Check to make sure the string isn't empty.
// Check to make sure the string isn't empty. if (decklistUrlString.isEmpty()) {
if (decklistUrlString.isEmpty()) { // Show an error if the deck is empty, and return.
// Show an error if the deck is empty, and return. QMessageBox::critical(this, tr("Error"), tr("There are no cards in your deck to be exported"));
QMessageBox::critical(this, tr("Error"), tr("There are no cards in your deck to be exported")); return;
return;
}
// Encode the string recieved from the model to make sure all characters are encoded.
// first we put it into a qurl object
QUrl decklistUrl = QUrl(decklistUrlString);
// we get the correctly encoded url.
decklistUrlString = decklistUrl.toEncoded();
// We open the url in the user's default browser
QDesktopServices::openUrl(decklistUrlString);
} else {
// if there's no deck loader object, return an error
QMessageBox::critical(this, tr("Error"), tr("No deck was selected to be exported."));
} }
// Encode the string recieved from the model to make sure all characters are encoded.
// first we put it into a qurl object
QUrl decklistUrl = QUrl(decklistUrlString);
// we get the correctly encoded url.
decklistUrlString = decklistUrl.toEncoded();
// We open the url in the user's default browser
QDesktopServices::openUrl(decklistUrlString);
} }
/** @brief Exports deck to www.decklist.org. */ /** @brief Exports deck to www.decklist.org. */

View File

@@ -77,7 +77,6 @@ class QAction;
* *
* - actAddCard(const ExactCard &card) — Adds a card to the deck. * - actAddCard(const ExactCard &card) — Adds a card to the deck.
* - actDecrementCard(const ExactCard &card) — Removes a single instance of a card from the deck. * - actDecrementCard(const ExactCard &card) — Removes a single instance of a card from the deck.
* - actSwapCard(const ExactCard &card, const QString &zone) — Swaps a card between zones.
* - actRemoveCard() — Removes the currently selected card from the deck. * - actRemoveCard() — Removes the currently selected card from the deck.
* - actSaveDeckAs() — Performs a "Save As" action for the deck. * - actSaveDeckAs() — Performs a "Save As" action for the deck.
* - updateCard(const ExactCard &card) — Updates the currently displayed card info in the dock. * - updateCard(const ExactCard &card) — Updates the currently displayed card info in the dock.
@@ -122,7 +121,7 @@ public:
DeckLoader *getDeckLoader() const; DeckLoader *getDeckLoader() const;
/** @brief Returns the currently active deck list. */ /** @brief Returns the currently active deck list. */
DeckList *getDeckList() const; const DeckList &getDeckList() const;
/** @brief Sets the modified state of the tab. /** @brief Sets the modified state of the tab.
* @param _windowModified Whether the tab is modified. * @param _windowModified Whether the tab is modified.
@@ -320,10 +319,7 @@ protected:
bool isBlankNewDeck() const; bool isBlankNewDeck() const;
/** @brief Helper function to add a card to a specific deck zone. */ /** @brief Helper function to add a card to a specific deck zone. */
void addCardHelper(const ExactCard &card, QString zoneName); void addCardHelper(const ExactCard &card, const QString &zoneName);
/** @brief Swaps a card in the deck view. */
void actSwapCard(const ExactCard &card, const QString &zoneName);
/** @brief Opens a deck from a file. */ /** @brief Opens a deck from a file. */
virtual void openDeckFromFile(const QString &fileName, DeckOpenLocation deckOpenLocation); virtual void openDeckFromFile(const QString &fileName, DeckOpenLocation deckOpenLocation);

View File

@@ -70,9 +70,7 @@ ArchidektApiResponseDeckDisplayWidget::ArchidektApiResponseDeckDisplayWidget(QWi
connect(model, &DeckListModel::modelReset, this, &ArchidektApiResponseDeckDisplayWidget::decklistModelReset); connect(model, &DeckListModel::modelReset, this, &ArchidektApiResponseDeckDisplayWidget::decklistModelReset);
model->getDeckList()->loadFromStream_Plain(deckStream, false); model->getDeckList()->loadFromStream_Plain(deckStream, false);
model->getDeckList()->forEachCard(CardNodeFunction::ResolveProviderId()); model->forEachCard(CardNodeFunction::ResolveProviderId());
model->rebuildTree();
retranslateUi(); retranslateUi();
} }

View File

@@ -191,7 +191,7 @@ void TabDeckEditorVisual::processMainboardCardClick(QMouseEvent *event,
// Double click = swap // Double click = swap
if (event->type() == QEvent::MouseButtonDblClick && event->button() == Qt::LeftButton) { if (event->type() == QEvent::MouseButtonDblClick && event->button() == Qt::LeftButton) {
actSwapCard(card, zoneName); deckDockWidget->actSwapCard(card, zoneName);
idx = deckDockWidget->deckModel->findCard(card.getName(), zoneName); idx = deckDockWidget->deckModel->findCard(card.getName(), zoneName);
sel->setCurrentIndex(idx, QItemSelectionModel::ClearAndSelect); sel->setCurrentIndex(idx, QItemSelectionModel::ClearAndSelect);
return; return;

View File

@@ -334,13 +334,13 @@ QMenu *DeckPreviewWidget::createRightClickMenu()
auto saveToClipboardMenu = menu->addMenu(tr("Save Deck to Clipboard")); auto saveToClipboardMenu = menu->addMenu(tr("Save Deck to Clipboard"));
connect(saveToClipboardMenu->addAction(tr("Annotated")), &QAction::triggered, this, connect(saveToClipboardMenu->addAction(tr("Annotated")), &QAction::triggered, this,
[this] { DeckLoader::saveToClipboard(&deckLoader->getDeck().deckList, true, true); }); [this] { DeckLoader::saveToClipboard(deckLoader->getDeck().deckList, true, true); });
connect(saveToClipboardMenu->addAction(tr("Annotated (No set info)")), &QAction::triggered, this, connect(saveToClipboardMenu->addAction(tr("Annotated (No set info)")), &QAction::triggered, this,
[this] { DeckLoader::saveToClipboard(&deckLoader->getDeck().deckList, true, false); }); [this] { DeckLoader::saveToClipboard(deckLoader->getDeck().deckList, true, false); });
connect(saveToClipboardMenu->addAction(tr("Not Annotated")), &QAction::triggered, this, connect(saveToClipboardMenu->addAction(tr("Not Annotated")), &QAction::triggered, this,
[this] { DeckLoader::saveToClipboard(&deckLoader->getDeck().deckList, false, true); }); [this] { DeckLoader::saveToClipboard(deckLoader->getDeck().deckList, false, true); });
connect(saveToClipboardMenu->addAction(tr("Not Annotated (No set info)")), &QAction::triggered, this, connect(saveToClipboardMenu->addAction(tr("Not Annotated (No set info)")), &QAction::triggered, this,
[this] { DeckLoader::saveToClipboard(&deckLoader->getDeck().deckList, false, false); }); [this] { DeckLoader::saveToClipboard(deckLoader->getDeck().deckList, false, false); });
menu->addSeparator(); menu->addSeparator();

View File

@@ -7,4 +7,4 @@ This is the **main landing page** of the Cockatrice documentation.
- Go to the @subpage user_reference page - Go to the @subpage user_reference page
- Review the @subpage developer_reference - Review the @subpage developer_reference
Or check out the <a href="https://cockatrice.github.io/" target="_blank" rel="noopener noreferrer">Cockatrice Webpage</a>. Or check out the [Cockatrice Webpage](https://cockatrice.github.io/).

View File

@@ -561,6 +561,11 @@ void DeckListModel::setDeckList(DeckList *_deck)
rebuildTree(); rebuildTree();
} }
void DeckListModel::forEachCard(const std::function<void(InnerDecklistNode *, DecklistCardNode *)> &func)
{
deckList->forEachCard(func);
}
static QList<ExactCard> cardNodesToExactCards(QList<const DecklistCardNode *> nodes) static QList<ExactCard> cardNodesToExactCards(QList<const DecklistCardNode *> nodes)
{ {
QList<ExactCard> cards; QList<ExactCard> cards;
@@ -600,6 +605,17 @@ QList<QString> DeckListModel::getCardNames() const
return names; return names;
} }
QList<CardRef> DeckListModel::getCardRefs() const
{
auto nodes = deckList->getCardNodes();
QList<CardRef> cardRefs;
std::transform(nodes.cbegin(), nodes.cend(), std::back_inserter(cardRefs),
[](auto node) { return node->toCardRef(); });
return cardRefs;
}
QList<QString> DeckListModel::getZones() const QList<QString> DeckListModel::getZones() const
{ {
auto zoneNodes = deckList->getZoneNodes(); auto zoneNodes = deckList->getZoneNodes();

View File

@@ -309,6 +309,13 @@ public:
} }
void setDeckList(DeckList *_deck); void setDeckList(DeckList *_deck);
/**
* @brief Apply a function to every card in the deck tree.
*
* @param func Function taking (zone node, card node).
*/
void forEachCard(const std::function<void(InnerDecklistNode *, DecklistCardNode *)> &func);
/** /**
* @brief Creates a list consisting of the entries of the model mapped into ExactCards (with each entry looked up * @brief Creates a list consisting of the entries of the model mapped into ExactCards (with each entry looked up
* in the card database). * in the card database).
@@ -323,6 +330,10 @@ public:
* @brief Gets a deduplicated list of all card names that appear in the model * @brief Gets a deduplicated list of all card names that appear in the model
*/ */
[[nodiscard]] QList<QString> getCardNames() const; [[nodiscard]] QList<QString> getCardNames() const;
/**
* @brief Gets a deduplicated list of all CardRefs that appear in the model
*/
[[nodiscard]] QList<CardRef> getCardRefs() const;
/** /**
* @brief Gets a list of all zone names that appear in the model * @brief Gets a list of all zone names that appear in the model
*/ */