From 34bec90193f3a1d28a340bcc92a580e0c83c323c Mon Sep 17 00:00:00 2001 From: Zach H Date: Thu, 18 Jan 2018 19:23:13 -0500 Subject: [PATCH] Fix deck loader with spaces (#3007) --- cockatrice/src/decklistmodel.cpp | 278 +++++++++++------ cockatrice/src/decklistmodel.h | 10 +- .../src/dlg_load_deck_from_clipboard.cpp | 26 +- cockatrice/src/dlg_load_deck_from_clipboard.h | 28 +- common/decklist.cpp | 256 ++++++++++----- common/decklist.h | 293 +++++++++--------- 6 files changed, 561 insertions(+), 330 deletions(-) diff --git a/cockatrice/src/decklistmodel.cpp b/cockatrice/src/decklistmodel.cpp index 456889ca..ef8b89cb 100644 --- a/cockatrice/src/decklistmodel.cpp +++ b/cockatrice/src/decklistmodel.cpp @@ -31,23 +31,34 @@ DeckListModel::~DeckListModel() void DeckListModel::rebuildTree() { beginResetModel(); - root->clearTree(); + InnerDecklistNode *listRoot = deckList->getRoot(); - for (int i = 0; i < listRoot->size(); i++) { - InnerDecklistNode *currentZone = dynamic_cast(listRoot->at(i)); - InnerDecklistNode *node = new InnerDecklistNode(currentZone->getName(), root); - for (int j = 0; j < currentZone->size(); j++) { - DecklistCardNode *currentCard = dynamic_cast(currentZone->at(j)); - // XXX better sanity checking - if (!currentCard) + + for (int i = 0; i < listRoot->size(); i++) + { + auto *currentZone = dynamic_cast(listRoot->at(i)); + auto *node = new InnerDecklistNode(currentZone->getName(), root); + + for (int j = 0; j < currentZone->size(); j++) + { + auto *currentCard = dynamic_cast(currentZone->at(j)); + + // TODO: better sanity checking + if (currentCard == nullptr) + { continue; + } CardInfo *info = db->getCard(currentCard->getName()); QString cardType = info ? info->getMainCardType() : "unknown"; - InnerDecklistNode *cardTypeNode = dynamic_cast(node->findChild(cardType)); + + auto *cardTypeNode = dynamic_cast(node->findChild(cardType)); + if (!cardTypeNode) + { cardTypeNode = new InnerDecklistNode(cardType, node); + } new DecklistModelCardNode(currentCard, cardTypeNode); } @@ -58,71 +69,99 @@ void DeckListModel::rebuildTree() int DeckListModel::rowCount(const QModelIndex &parent) const { -// debugIndexInfo("rowCount", parent); - InnerDecklistNode *node = getNode(parent); + //debugIndexInfo("rowCount", parent); + auto *node = getNode(parent); if (node) + { return node->size(); + } else + { return 0; + } } int DeckListModel::columnCount(const QModelIndex &/*parent*/) const { - return 2; + return 2; } QVariant DeckListModel::data(const QModelIndex &index, int role) const { -// debugIndexInfo("data", index); + //debugIndexInfo("data", index); if (!index.isValid()) + { return QVariant(); - if (index.column() >= columnCount()) - return QVariant(); + } - AbstractDecklistNode *temp = static_cast(index.internalPointer()); - DecklistModelCardNode *card = dynamic_cast(temp); - if (!card) { - InnerDecklistNode *node = dynamic_cast(temp); - switch (role) { - case Qt::FontRole: { + if (index.column() >= columnCount()) + { + return QVariant(); + } + + auto *temp = static_cast(index.internalPointer()); + auto *card = dynamic_cast(temp); + if (card == nullptr) + { + auto *node = dynamic_cast(temp); + switch (role) + { + case Qt::FontRole: + { QFont f; f.setBold(true); return f; } case Qt::DisplayRole: case Qt::EditRole: - switch (index.column()) { - case 0: return node->recursiveCount(true); - case 1: return node->getVisibleName(); - default: return QVariant(); + { + switch (index.column()) + { + case 0: + return node->recursiveCount(true); + case 1: + return node->getVisibleName(); + default: + return QVariant(); } - case Qt::BackgroundRole: { + } + case Qt::BackgroundRole: + { int color = 90 + 60 * node->depth(); return QBrush(QColor(color, 255, color)); } - case Qt::ForegroundRole: { + case Qt::ForegroundRole: + { return QBrush(QColor(0 ,0 ,0)); } default: return QVariant(); } - } else { - switch (role) { + } + else + { + switch (role) + { case Qt::DisplayRole: - case Qt::EditRole: { - switch (index.column()) { - case 0: return card->getNumber(); - case 1: return card->getName(); + case Qt::EditRole: + { + switch (index.column()) + { + case 0: return card->getNumber(); + case 1: return card->getName(); default: return QVariant(); } } - case Qt::BackgroundRole: { + case Qt::BackgroundRole: + { int color = 255 - (index.row() % 2) * 30; return QBrush(QColor(color, color, color)); } - case Qt::ForegroundRole: { + case Qt::ForegroundRole: + { return QBrush(QColor(0 ,0 ,0)); } - default: return QVariant(); + default: + return QVariant(); } } } @@ -130,33 +169,42 @@ QVariant DeckListModel::data(const QModelIndex &index, int role) const QVariant DeckListModel::headerData(int section, Qt::Orientation orientation, int role) const { if ((role != Qt::DisplayRole) || (orientation != Qt::Horizontal)) + { return QVariant(); + } + if (section >= columnCount()) + { return QVariant(); - switch (section) { - case 0: return tr("Number"); - case 1: return tr("Card"); + } + + switch (section) + { + case 0: return tr("Number"); + case 1: return tr("Card"); default: return QVariant(); } } QModelIndex DeckListModel::index(int row, int column, const QModelIndex &parent) const { -// debugIndexInfo("index", parent); + //debugIndexInfo("index", parent); if (!hasIndex(row, column, parent)) - return QModelIndex(); + { + return {}; + } - InnerDecklistNode *parentNode = getNode(parent); - if (row >= parentNode->size()) - return QModelIndex(); + auto *parentNode = getNode(parent); + return row >= parentNode->size() ? QModelIndex() : createIndex(row, column, parentNode->at(row)); - return createIndex(row, column, parentNode->at(row)); } QModelIndex DeckListModel::parent(const QModelIndex &ind) const { if (!ind.isValid()) - return QModelIndex(); + { + return {}; + } return nodeToIndex(static_cast(ind.internalPointer())->getParent()); } @@ -164,7 +212,9 @@ QModelIndex DeckListModel::parent(const QModelIndex &ind) const Qt::ItemFlags DeckListModel::flags(const QModelIndex &index) const { if (!index.isValid()) - return 0; + { + return nullptr; + } Qt::ItemFlags result = Qt::ItemIsEnabled; result |= Qt::ItemIsSelectable; @@ -175,22 +225,29 @@ Qt::ItemFlags DeckListModel::flags(const QModelIndex &index) const void DeckListModel::emitRecursiveUpdates(const QModelIndex &index) { if (!index.isValid()) + { return; + } + emit dataChanged(index, index); emitRecursiveUpdates(index.parent()); } bool DeckListModel::setData(const QModelIndex &index, const QVariant &value, int role) { - DecklistModelCardNode *node = getNode(index); + auto *node = getNode(index); if (!node || (role != Qt::EditRole)) + { return false; + } - switch (index.column()) { - case 0: node->setNumber(value.toInt()); break; - case 1: node->setName(value.toString()); break; + switch (index.column()) + { + case 0: node->setNumber(value.toInt()); break; + case 1: node->setName(value.toString()); break; default: return false; } + emitRecursiveUpdates(index); deckList->updateDeckHash(); return true; @@ -198,33 +255,46 @@ bool DeckListModel::setData(const QModelIndex &index, const QVariant &value, int bool DeckListModel::removeRows(int row, int count, const QModelIndex &parent) { - InnerDecklistNode *node = getNode(parent); + auto *node = getNode(parent); if (!node) + { return false; + } + if (row + count > node->size()) + { return false; + } beginRemoveRows(parent, row, row + count - 1); - for (int i = 0; i < count; i++) { + for (int i = 0; i < count; i++) + { AbstractDecklistNode *toDelete = node->takeAt(row); - if (DecklistModelCardNode *temp = dynamic_cast(toDelete)) + if (auto *temp = dynamic_cast(toDelete)) + { deckList->deleteNode(temp->getDataNode()); + } delete toDelete; } endRemoveRows(); - if (!node->size() && (node != root)) + if (node->empty() && (node != root)) + { removeRows(parent.row(), 1, parent.parent()); + } else + { emitRecursiveUpdates(parent); + } return true; } InnerDecklistNode *DeckListModel::createNodeIfNeeded(const QString &name, InnerDecklistNode *parent) { - InnerDecklistNode *newNode = dynamic_cast(parent->findChild(name)); - if (!newNode) { + auto *newNode = dynamic_cast(parent->findChild(name)); + if (!newNode) + { beginInsertRows(nodeToIndex(parent), parent->size(), parent->size()); newNode = new InnerDecklistNode(name, parent); endInsertRows(); @@ -239,17 +309,23 @@ DecklistModelCardNode *DeckListModel::findCardNode(const QString &cardName, cons QString cardType; zoneNode = dynamic_cast(root->findChild(zoneName)); - if(!zoneNode) - return NULL; + if (!zoneNode) + { + return nullptr; + } info = db->getCard(cardName); - if(!info) - return NULL; + if (!info) + { + return nullptr; + } cardType = info->getMainCardType(); typeNode = dynamic_cast(zoneNode->findChild(cardType)); - if(!typeNode) - return NULL; + if (!typeNode) + { + return nullptr; + } return dynamic_cast(typeNode->findChild(cardName)); } @@ -259,8 +335,11 @@ QModelIndex DeckListModel::findCard(const QString &cardName, const QString &zone DecklistModelCardNode *cardNode; cardNode = findCardNode(cardName, zoneName); - if(!cardNode) - return QModelIndex(); + if (!cardNode) + { + return {}; + } + return nodeToIndex(cardNode); } @@ -299,7 +378,7 @@ QModelIndex DeckListModel::addCard(const QString &cardName, const QString &zoneN } else { - return QModelIndex(); + return {}; } } @@ -309,13 +388,16 @@ QModelIndex DeckListModel::addCard(const QString &cardName, const QString &zoneN InnerDecklistNode *cardTypeNode = createNodeIfNeeded(cardType, zoneNode); QModelIndex parentIndex = nodeToIndex(cardTypeNode); - DecklistModelCardNode *cardNode = dynamic_cast(cardTypeNode->findChild(cardName)); - if (!cardNode) { + auto *cardNode = dynamic_cast(cardTypeNode->findChild(cardName)); + if (!cardNode) + { DecklistCardNode *decklistCard = deckList->addCard(cardName, zoneName); beginInsertRows(parentIndex, cardTypeNode->size(), cardTypeNode->size()); cardNode = new DecklistModelCardNode(decklistCard, cardTypeNode); endInsertRows(); - } else { + } + else + { cardNode->setNumber(cardNode->getNumber() + 1); deckList->updateDeckHash(); } @@ -327,7 +409,9 @@ QModelIndex DeckListModel::addCard(const QString &cardName, const QString &zoneN QModelIndex DeckListModel::nodeToIndex(AbstractDecklistNode *node) const { if (node == nullptr || node == root) - return QModelIndex(); + { + return {}; + } return createIndex(node->getParent()->indexOf(node), 0, node); } @@ -340,11 +424,13 @@ void DeckListModel::sortHelper(InnerDecklistNode *node, Qt::SortOrder order) QModelIndexList from, to; int columns = columnCount(); - for (int i = sortResult.size() - 1; i >= 0; --i) { + for (int i = sortResult.size() - 1; i >= 0; --i) + { const int fromRow = sortResult[i].first; const int toRow = sortResult[i].second; AbstractDecklistNode *temp = node->at(toRow); - for (int j = 0; j < columns; ++j) { + for (int j = 0; j < columns; ++j) + { from << createIndex(fromRow, j, temp); to << createIndex(toRow, j, temp); } @@ -352,10 +438,13 @@ void DeckListModel::sortHelper(InnerDecklistNode *node, Qt::SortOrder order) changePersistentIndexList(from, to); // Recursion - for (int i = node->size() - 1; i >= 0; --i) { - InnerDecklistNode *subNode = dynamic_cast(node->at(i)); + for (int i = node->size() - 1; i >= 0; --i) + { + auto *subNode = dynamic_cast(node->at(i)); if (subNode) + { sortHelper(subNode, order); + } } } @@ -366,16 +455,18 @@ void DeckListModel::sort(int column, Qt::SortOrder order) emit layoutAboutToBeChanged(); DeckSortMethod sortMethod; - switch(column) { - case 0: - sortMethod = ByNumber; - break; - case 1: - sortMethod = ByName; - break; - default: - sortMethod = ByName; + switch(column) + { + case 0: + sortMethod = ByNumber; + break; + case 1: + sortMethod = ByName; + break; + default: + sortMethod = ByName; } + root->setSortMethod(sortMethod); sortHelper(root, order); emit layoutChanged(); @@ -399,7 +490,8 @@ void DeckListModel::printDeckListNode(QTextCursor *cursor, InnerDecklistNode *no { const int totalColumns = 2; - if (node->height() == 1) { + if (node->height() == 1) + { QTextBlockFormat blockFormat; QTextCharFormat charFormat; charFormat.setFontPointSize(11); @@ -411,8 +503,9 @@ void DeckListModel::printDeckListNode(QTextCursor *cursor, InnerDecklistNode *no tableFormat.setCellSpacing(0); tableFormat.setBorder(0); QTextTable *table = cursor->insertTable(node->size() + 1, totalColumns, tableFormat); - for (int i = 0; i < node->size(); i++) { - AbstractDecklistCardNode *card = dynamic_cast(node->at(i)); + for (int i = 0; i < node->size(); i++) + { + auto *card = dynamic_cast(node->at(i)); QTextCharFormat cellCharFormat; cellCharFormat.setFontPointSize(9); @@ -428,7 +521,9 @@ void DeckListModel::printDeckListNode(QTextCursor *cursor, InnerDecklistNode *no cellCursor.insertText(card->getName()); } - } else if (node->height() == 2) { + } + else if (node->height() == 2) + { QTextBlockFormat blockFormat; QTextCharFormat charFormat; charFormat.setFontPointSize(14); @@ -442,15 +537,19 @@ void DeckListModel::printDeckListNode(QTextCursor *cursor, InnerDecklistNode *no tableFormat.setBorder(0); QVector constraints; for (int i = 0; i < totalColumns; i++) + { constraints << QTextLength(QTextLength::PercentageLength, 100.0 / totalColumns); + } tableFormat.setColumnWidthConstraints(constraints); QTextTable *table = cursor->insertTable(1, totalColumns, tableFormat); - for (int i = 0; i < node->size(); i++) { + for (int i = 0; i < node->size(); i++) + { QTextCursor cellCursor = table->cellAt(0, (i * totalColumns) / node->size()).lastCursorPosition(); printDeckListNode(&cellCursor, dynamic_cast(node->at(i))); } } + cursor->movePosition(QTextCursor::End); } @@ -477,7 +576,8 @@ void DeckListModel::printDeckList(QPrinter *printer) cursor.insertText(deckList->getComments()); cursor.insertBlock(headerBlockFormat, headerCharFormat); - for (int i = 0; i < root->size(); i++) { + for (int i = 0; i < root->size(); i++) + { cursor.insertHtml("
"); //cursor.insertHtml("
"); cursor.insertBlock(headerBlockFormat, headerCharFormat); diff --git a/cockatrice/src/decklistmodel.h b/cockatrice/src/decklistmodel.h index f23d945a..898b4a51 100644 --- a/cockatrice/src/decklistmodel.h +++ b/cockatrice/src/decklistmodel.h @@ -34,18 +34,18 @@ signals: public: DeckListModel(QObject *parent = 0); ~DeckListModel(); - int rowCount(const QModelIndex &parent = QModelIndex()) const; + int rowCount(const QModelIndex &parent) const; int columnCount(const QModelIndex &/*parent*/ = QModelIndex()) const; QVariant data(const QModelIndex &index, int role) const; - QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; - QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const; + QVariant headerData(int section, Qt::Orientation orientation, int role) const; + QModelIndex index(int row, int column, const QModelIndex &parent) const; QModelIndex parent(const QModelIndex &index) const; Qt::ItemFlags flags(const QModelIndex &index) const; bool setData(const QModelIndex &index, const QVariant &value, int role); - bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex()); + bool removeRows(int row, int count, const QModelIndex &parent); QModelIndex findCard(const QString &cardName, const QString &zoneName) const; QModelIndex addCard(const QString &cardName, const QString &zoneName, bool abAddAnyway = false); - void sort(int column, Qt::SortOrder order = Qt::AscendingOrder); + void sort(int column, Qt::SortOrder order); void cleanList(); DeckLoader *getDeckList() const { return deckList; } void setDeckList(DeckLoader *_deck); diff --git a/cockatrice/src/dlg_load_deck_from_clipboard.cpp b/cockatrice/src/dlg_load_deck_from_clipboard.cpp index 1c41cc1a..12b15931 100644 --- a/cockatrice/src/dlg_load_deck_from_clipboard.cpp +++ b/cockatrice/src/dlg_load_deck_from_clipboard.cpp @@ -2,8 +2,6 @@ #include #include #include -#include -#include #include #include #include @@ -12,8 +10,7 @@ #include "deck_loader.h" #include "settingscache.h" -DlgLoadDeckFromClipboard::DlgLoadDeckFromClipboard(QWidget *parent) - : QDialog(parent), deckList(0) +DlgLoadDeckFromClipboard::DlgLoadDeckFromClipboard(QWidget *parent) : QDialog(parent), deckList(nullptr) { contentsEdit = new QPlainTextEdit; @@ -25,7 +22,7 @@ DlgLoadDeckFromClipboard::DlgLoadDeckFromClipboard(QWidget *parent) connect(buttonBox, SIGNAL(accepted()), this, SLOT(actOK())); connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); - QVBoxLayout *mainLayout = new QVBoxLayout; + auto *mainLayout = new QVBoxLayout; mainLayout->addWidget(contentsEdit); mainLayout->addWidget(buttonBox); @@ -54,25 +51,28 @@ void DlgLoadDeckFromClipboard::actOK() QString buffer = contentsEdit->toPlainText(); QTextStream stream(&buffer); - DeckLoader *l = new DeckLoader; + auto *deckLoader = new DeckLoader; if (buffer.contains("")) { - if (l->loadFromString_Native(buffer)) + if (deckLoader->loadFromString_Native(buffer)) { - deckList = l; + deckList = deckLoader; accept(); } else { QMessageBox::critical(this, tr("Error"), tr("Invalid deck list.")); - delete l; + delete deckLoader; } } - else if (l->loadFromStream_Plain(stream)) { - deckList = l; + else if (deckLoader->loadFromStream_Plain(stream)) + { + deckList = deckLoader; accept(); - } else { + } + else + { QMessageBox::critical(this, tr("Error"), tr("Invalid deck list.")); - delete l; + delete deckLoader; } } diff --git a/cockatrice/src/dlg_load_deck_from_clipboard.h b/cockatrice/src/dlg_load_deck_from_clipboard.h index ec133a1b..63fb68d1 100644 --- a/cockatrice/src/dlg_load_deck_from_clipboard.h +++ b/cockatrice/src/dlg_load_deck_from_clipboard.h @@ -7,20 +7,22 @@ class DeckLoader; class QPlainTextEdit; class QPushButton; -class DlgLoadDeckFromClipboard : public QDialog { +class DlgLoadDeckFromClipboard : public QDialog +{ Q_OBJECT -private slots: - void actOK(); - void actRefresh(); - void refreshShortcuts(); -private: - DeckLoader *deckList; -public: - DlgLoadDeckFromClipboard(QWidget *parent = 0); - DeckLoader *getDeckList() const { return deckList; } -private: - QPlainTextEdit *contentsEdit; - QPushButton *refreshButton; + private slots: + void actOK(); + void actRefresh(); + void refreshShortcuts(); + + private: + DeckLoader *deckList; + QPlainTextEdit *contentsEdit; + QPushButton *refreshButton; + + public: + explicit DlgLoadDeckFromClipboard(QWidget *parent = nullptr); + DeckLoader *getDeckList() const { return deckList; } }; #endif diff --git a/common/decklist.cpp b/common/decklist.cpp index 7d3c39fa..71ea5094 100644 --- a/common/decklist.cpp +++ b/common/decklist.cpp @@ -1,6 +1,5 @@ #include #include -#include #include #include #include "decklist.h" @@ -51,40 +50,50 @@ void SideboardPlan::write(QXmlStreamWriter *xml) { xml->writeStartElement("sideboard_plan"); xml->writeTextElement("name", name); - for (int i = 0; i < moveList.size(); ++i) { + for (auto &i : moveList) + { xml->writeStartElement("move_card_to_zone"); - xml->writeTextElement("card_name", QString::fromStdString(moveList[i].card_name())); - xml->writeTextElement("start_zone", QString::fromStdString(moveList[i].start_zone())); - xml->writeTextElement("target_zone", QString::fromStdString(moveList[i].target_zone())); + xml->writeTextElement("card_name", QString::fromStdString(i.card_name())); + xml->writeTextElement("start_zone", QString::fromStdString(i.start_zone())); + xml->writeTextElement("target_zone", QString::fromStdString(i.target_zone())); xml->writeEndElement(); } xml->writeEndElement(); } -AbstractDecklistNode::AbstractDecklistNode(InnerDecklistNode *_parent) - : parent(_parent) +AbstractDecklistNode::AbstractDecklistNode(InnerDecklistNode *_parent) : parent(_parent), sortMethod(Default) { if (parent) + { parent->append(this); + } } int AbstractDecklistNode::depth() const { if (parent) + { return parent->depth() + 1; + } else + { return 0; + } } -InnerDecklistNode::InnerDecklistNode(InnerDecklistNode *other, InnerDecklistNode *_parent) - : AbstractDecklistNode(_parent), name(other->getName()) +InnerDecklistNode::InnerDecklistNode(InnerDecklistNode *other, InnerDecklistNode *_parent) : AbstractDecklistNode(_parent), name(other->getName()) { - for (int i = 0; i < other->size(); ++i) { - InnerDecklistNode *inner = dynamic_cast(other->at(i)); + for (int i = 0; i < other->size(); ++i) + { + auto *inner = dynamic_cast(other->at(i)); if (inner) + { new InnerDecklistNode(inner, this); + } else + { new DecklistCardNode(dynamic_cast(other->at(i)), this); + } } } @@ -96,20 +105,30 @@ InnerDecklistNode::~InnerDecklistNode() QString InnerDecklistNode::visibleNameFromName(const QString &_name) { if (_name == DECK_ZONE_MAIN) + { return QObject::tr("Maindeck"); + } else if (_name == DECK_ZONE_SIDE) + { return QObject::tr("Sideboard"); + } else if (_name == DECK_ZONE_TOKENS) + { return QObject::tr("Tokens"); + } else + { return _name; + } } void InnerDecklistNode::setSortMethod(DeckSortMethod method) { sortMethod = method; for (int i = 0; i < size(); i++) + { at(i)->setSortMethod(method); + } } QString InnerDecklistNode::getVisibleName() const @@ -124,17 +143,21 @@ void InnerDecklistNode::clearTree() clear(); } -DecklistCardNode::DecklistCardNode(DecklistCardNode *other, InnerDecklistNode *_parent) - : AbstractDecklistCardNode(_parent), name(other->getName()), number(other->getNumber()) +DecklistCardNode::DecklistCardNode(DecklistCardNode *other, InnerDecklistNode *_parent) : AbstractDecklistCardNode(_parent), name(other->getName()), number(other->getNumber()) { + } AbstractDecklistNode *InnerDecklistNode::findChild(const QString &name) { for (int i = 0; i < size(); i++) + { if (at(i)->getName() == name) + { return at(i); - return 0; + } + } + return nullptr; } int InnerDecklistNode::height() const @@ -145,32 +168,42 @@ int InnerDecklistNode::height() const int InnerDecklistNode::recursiveCount(bool countTotalCards) const { int result = 0; - for (int i = 0; i < size(); i++) { - InnerDecklistNode *node = dynamic_cast(at(i)); + for (int i = 0; i < size(); i++) + { + auto *node = dynamic_cast(at(i)); + if (node) + { result += node->recursiveCount(countTotalCards); + } else if (countTotalCards) + { result += dynamic_cast(at(i))->getNumber(); + } else - result += 1; + { + result++; + } } return result; } bool InnerDecklistNode::compare(AbstractDecklistNode *other) const { - switch (sortMethod) { + switch (sortMethod) + { case ByNumber: return compareNumber(other); case ByName: return compareName(other); + default: + return false; } - return 0; } bool InnerDecklistNode::compareNumber(AbstractDecklistNode *other) const { - InnerDecklistNode *other2 = dynamic_cast(other); + auto *other2 = dynamic_cast(other); if (other2) { int n1 = recursiveCount(true); int n2 = other2->recursiveCount(true); @@ -182,43 +215,54 @@ bool InnerDecklistNode::compareNumber(AbstractDecklistNode *other) const bool InnerDecklistNode::compareName(AbstractDecklistNode *other) const { - InnerDecklistNode *other2 = dynamic_cast(other); - if (other2) { + auto *other2 = dynamic_cast(other); + if (other2) + { return (getName() > other2->getName()); - } else { + } + else + { return false; } } bool AbstractDecklistCardNode::compare(AbstractDecklistNode *other) const { - switch (sortMethod) { + switch (sortMethod) + { case ByNumber: return compareNumber(other); case ByName: return compareName(other); + default: + return false; } - return 0; } bool AbstractDecklistCardNode::compareNumber(AbstractDecklistNode *other) const { - AbstractDecklistCardNode *other2 = dynamic_cast(other); - if (other2) { + auto *other2 = dynamic_cast(other); + if (other2) + { int n1 = getNumber(); int n2 = other2->getNumber(); return (n1 != n2) ? (n1 > n2) : compareName(other); - } else { + } + else + { return true; } } bool AbstractDecklistCardNode::compareName(AbstractDecklistNode *other) const { - AbstractDecklistCardNode *other2 = dynamic_cast(other); - if (other2) { + auto *other2 = dynamic_cast(other); + if (other2) + { return (getName() > other2->getName()); - } else { + } + else + { return true; } } @@ -227,7 +271,7 @@ class InnerDecklistNode::compareFunctor { private: Qt::SortOrder order; public: - compareFunctor(Qt::SortOrder _order) : order(_order) { } + explicit compareFunctor(Qt::SortOrder _order) : order(_order) { } inline bool operator()(QPair a, QPair b) const { return (order == Qt::AscendingOrder) ^ (a.second->compare(b.second)); @@ -311,16 +355,13 @@ DeckList::DeckList() } // TODO: http://qt-project.org/doc/qt-4.8/qobject.html#no-copy-constructor-or-assignment-operator -DeckList::DeckList(const DeckList &other) - : QObject(), - name(other.name), - comments(other.comments), - deckHash(other.deckHash) +DeckList::DeckList(const DeckList &other) : QObject(), name(other.name), comments(other.comments), deckHash(other.deckHash) { root = new InnerDecklistNode(other.getRoot()); QMapIterator spIterator(other.getSideboardPlans()); - while (spIterator.hasNext()) { + while (spIterator.hasNext()) + { spIterator.next(); sideboardPlans.insert(spIterator.key(), new SideboardPlan(spIterator.key(), spIterator.value()->getMoveList())); } @@ -481,13 +522,18 @@ bool DeckList::loadFromStream_Plain(QTextStream &in) * This will also concise multiple blank lines in a row to just one blank * Ex: ("Card1", "Card2", "", "", "", "Card3") => ("Card1", "Card2", "", "Card3") */ - if (line.isEmpty()) { + if (line.isEmpty()) + { if (priorEntryIsBlank || isAtBeginning) + { continue; + } priorEntryIsBlank = true; blankLines++; - } else { + } + else + { isAtBeginning = false; priorEntryIsBlank = false; } @@ -501,7 +547,7 @@ bool DeckList::loadFromStream_Plain(QTextStream &in) * NOTE: Any duplicates were taken care of above, so there can be * at most one blank line at the very end */ - if (inputs.size() && inputs.last().isEmpty()) + if (!inputs.empty() && inputs.last().isEmpty()) { blankLines--; inputs.erase(inputs.end() - 1); @@ -509,20 +555,28 @@ bool DeckList::loadFromStream_Plain(QTextStream &in) // If "Sideboard" line appears in inputs, then blank lines mean nothing if (inputs.contains("sideboard")) + { blankLines = 2; + } bool inSideboard = false, titleFound = false, isSideboard; int okRows = 0; - foreach(QString line, inputs) { + + foreach(QString line, inputs) + { // This is a comment line, ignore it if (line.startsWith("//")) { - if (!titleFound) { // Set the title to the first comment + if (!titleFound) // Set the title to the first comment + { name = line.mid(2).trimmed(); titleFound = true; - } else if (okRows == 0) { // We haven't processed any cards yet + } + else if (okRows == 0) // We haven't processed any cards yet + { comments += line.mid(2).trimmed() + "\n"; } + continue; } @@ -530,20 +584,24 @@ bool DeckList::loadFromStream_Plain(QTextStream &in) // Then we assume it means to start the sideboard section of the paste. // If we have the word "Sideboard" appear on any line, then that will // also indicate the start of the sideboard. - if ((line.isEmpty() && blankLines == 1) || line.startsWith("sideboard")) { + if ((line.isEmpty() && blankLines == 1) || line.startsWith("sideboard")) + { inSideboard = true; continue; // The line isn't actually a card } isSideboard = inSideboard; - if (line.startsWith("sb:")) { + if (line.startsWith("sb:")) + { line = line.mid(3).trimmed(); isSideboard = true; } if (line.trimmed().isEmpty()) + { continue; // The line was " " instead of "\n" + } // Filter out MWS edition symbols and basic land extras QRegExp rx("\\[.*\\]"); @@ -555,21 +613,37 @@ bool DeckList::loadFromStream_Plain(QTextStream &in) rx.setPattern("\\|.*$"); line.remove(rx); + // If the user inputs "Quicksilver Elemental" then it will cut it off + // 1x Squishy Treaker int i = line.indexOf(' '); int cardNameStart = i + 1; - // If the count ends with an 'x', ignore it. For example, - // "4x Storm Crow" will count 4 correctly. - if (i > 0 && line[i - 1] == 'x') - i--; + if (i > 0) + { + // If the count ends with an 'x', ignore it. For example, + // "4x Storm Crow" will count 4 correctly. + if (line.at(i-1) == 'x') + { + i--; + } + else if (! line.at(i-1).isDigit()) + { + // If the user inputs "Quicksilver Elemental" then it will work as 1x of that card + cardNameStart = 0; + } + } bool ok; int number = line.left(i).toInt(&ok); + if (!ok) + { number = 1; // If input is "cardName" assume it's "1x cardName" + } QString cardName = line.mid(cardNameStart); + // Common differences between Cockatrice's card names // and what's commonly used in decklists rx.setPattern("’"); @@ -585,7 +659,9 @@ bool DeckList::loadFromStream_Plain(QTextStream &in) // Qt regexes don't support lookbehind so we capture and replace instead. rx.setPattern("([^A-Z])\\s*&\\s*"); if (rx.indexIn(cardName) != -1) + { cardName.replace(rx, QString("%1 // ").arg(rx.cap(1))); + } // We need to get the name of the card from the database, // but we can't do that until we get the "real" name @@ -608,10 +684,13 @@ bool DeckList::loadFromStream_Plain(QTextStream &in) InnerDecklistNode * DeckList::getZoneObjFromName(const QString zoneName) { - for (int i = 0; i < root->size(); i++) { - InnerDecklistNode *node = dynamic_cast(root->at(i)); - if(node->getName() == zoneName) + for (int i = 0; i < root->size(); i++) + { + auto *node = dynamic_cast(root->at(i)); + if (node->getName() == zoneName) + { return node; + } } return new InnerDecklistNode(zoneName, root); @@ -685,12 +764,18 @@ void DeckList::cleanList() void DeckList::getCardListHelper(InnerDecklistNode *item, QSet &result) const { - for (int i = 0; i < item->size(); ++i) { - DecklistCardNode *node = dynamic_cast(item->at(i)); + for (int i = 0; i < item->size(); ++i) + { + auto *node = dynamic_cast(item->at(i)); + if (node) + { result.insert(node->getName()); + } else + { getCardListHelper(dynamic_cast(item->at(i)), result); + } } } @@ -704,12 +789,17 @@ QStringList DeckList::getCardList() const int DeckList::getSideboardSize() const { int size = 0; - for (int i = 0; i < root->size(); ++i) { - InnerDecklistNode *node = dynamic_cast(root->at(i)); + for (int i = 0; i < root->size(); ++i) + { + auto *node = dynamic_cast(root->at(i)); if (node->getName() != DECK_ZONE_SIDE) + { continue; - for (int j = 0; j < node->size(); j++) { - DecklistCardNode *card = dynamic_cast(node->at(j)); + } + + for (int j = 0; j < node->size(); j++) + { + auto *card = dynamic_cast(node->at(j)); size += card->getNumber(); } } @@ -718,43 +808,67 @@ int DeckList::getSideboardSize() const DecklistCardNode *DeckList::addCard(const QString &cardName, const QString &zoneName) { - InnerDecklistNode *zoneNode = dynamic_cast(root->findChild(zoneName)); - if (!zoneNode) + auto *zoneNode = dynamic_cast(root->findChild(zoneName)); + if (zoneNode == nullptr) + { zoneNode = new InnerDecklistNode(zoneName, root); + } - DecklistCardNode *node = new DecklistCardNode(cardName, 1, zoneNode); + auto *node = new DecklistCardNode(cardName, 1, zoneNode); updateDeckHash(); + return node; } bool DeckList::deleteNode(AbstractDecklistNode *node, InnerDecklistNode *rootNode) { if (node == root) + { return true; + } + bool updateHash = false; - if (!rootNode) { + if (rootNode == nullptr) + { rootNode = root; updateHash = true; } int index = rootNode->indexOf(node); - if (index != -1) { + if (index != -1) + { delete rootNode->takeAt(index); - if (!rootNode->size()) + + if (rootNode->empty()) + { deleteNode(rootNode, rootNode->getParent()); + } + if (updateHash) + { updateDeckHash(); + } + return true; } - for (int i = 0; i < rootNode->size(); i++) { - InnerDecklistNode *inner = dynamic_cast(rootNode->at(i)); + + for (int i = 0; i < rootNode->size(); i++) + { + auto *inner = dynamic_cast(rootNode->at(i)); if (inner) - if (deleteNode(node, inner)) { + { + if (deleteNode(node, inner)) + { if (updateHash) + { updateDeckHash(); + } + return true; } + } } + return false; } @@ -769,14 +883,16 @@ void DeckList::updateDeckHash() for (int i = 0; i < root->size(); i++) { - InnerDecklistNode *node = dynamic_cast(root->at(i)); + auto *node = dynamic_cast(root->at(i)); for (int j = 0; j < node->size(); j++) { if (hashZones.contains(node->getName())) // Mainboard or Sideboard { - DecklistCardNode *card = dynamic_cast(node->at(j)); + auto *card = dynamic_cast(node->at(j)); for (int k = 0; k < card->getNumber(); ++k) + { cardList.append((node->getName() == DECK_ZONE_SIDE ? "SB:" : "") + card->getName().toLower()); + } } else if (!optionalZones.contains(node->getName())) // Not a valid zone -> cheater? { diff --git a/common/decklist.h b/common/decklist.h index 3ff24cf0..20845bc5 100644 --- a/common/decklist.h +++ b/common/decklist.h @@ -25,170 +25,183 @@ class InnerDecklistNode; #define DECK_ZONE_SIDE "side" #define DECK_ZONE_TOKENS "tokens" -class SideboardPlan { -private: - QString name; - QList moveList; -public: - SideboardPlan(const QString &_name = QString(), const QList &_moveList = QList()); - bool readElement(QXmlStreamReader *xml); - void write(QXmlStreamWriter *xml); +class SideboardPlan +{ + private: + QString name; + QList moveList; - QString getName() const { return name; } - const QList &getMoveList() const { return moveList; } - void setMoveList(const QList &_moveList); + public: + explicit SideboardPlan(const QString &_name = QString(), const QList &_moveList = QList()); + bool readElement(QXmlStreamReader *xml); + void write(QXmlStreamWriter *xml); + + QString getName() const { return name; } + const QList &getMoveList() const { return moveList; } + void setMoveList(const QList &_moveList); }; -enum DeckSortMethod { ByNumber, ByName }; +enum DeckSortMethod { ByNumber, ByName, Default }; -class AbstractDecklistNode { -protected: - InnerDecklistNode *parent; - DeckSortMethod sortMethod; -public: - AbstractDecklistNode(InnerDecklistNode *_parent = 0); - virtual ~AbstractDecklistNode() { } - virtual void setSortMethod(DeckSortMethod method) { sortMethod = method; } - virtual QString getName() const = 0; - InnerDecklistNode *getParent() const { return parent; } - int depth() const; - virtual int height() const = 0; - virtual bool compare(AbstractDecklistNode *other) const = 0; +class AbstractDecklistNode +{ + protected: + InnerDecklistNode *parent; + DeckSortMethod sortMethod; - virtual bool readElement(QXmlStreamReader *xml) = 0; - virtual void writeElement(QXmlStreamWriter *xml) = 0; + public: + explicit AbstractDecklistNode(InnerDecklistNode *_parent = nullptr); + virtual ~AbstractDecklistNode() = default; + virtual void setSortMethod(DeckSortMethod method) { sortMethod = method; } + virtual QString getName() const = 0; + InnerDecklistNode *getParent() const { return parent; } + int depth() const; + virtual int height() const = 0; + virtual bool compare(AbstractDecklistNode *other) const = 0; + + virtual bool readElement(QXmlStreamReader *xml) = 0; + virtual void writeElement(QXmlStreamWriter *xml) = 0; }; -class InnerDecklistNode : public AbstractDecklistNode, public QList { -private: - QString name; - class compareFunctor; -public: - InnerDecklistNode(const QString &_name = QString(), InnerDecklistNode *_parent = 0) : AbstractDecklistNode(_parent), name(_name) { } - InnerDecklistNode(InnerDecklistNode *other, InnerDecklistNode *_parent = 0); - virtual ~InnerDecklistNode(); - void setSortMethod(DeckSortMethod method); - QString getName() const { return name; } - void setName(const QString &_name) { name = _name; } - static QString visibleNameFromName(const QString &_name); - virtual QString getVisibleName() const; - void clearTree(); - AbstractDecklistNode *findChild(const QString &name); - int height() const; - int recursiveCount(bool countTotalCards = false) const; - bool compare(AbstractDecklistNode *other) const; - bool compareNumber(AbstractDecklistNode *other) const; - bool compareName(AbstractDecklistNode *other) const; - QVector > sort(Qt::SortOrder order = Qt::AscendingOrder); +class InnerDecklistNode : public AbstractDecklistNode, public QList +{ + private: + QString name; + class compareFunctor; - bool readElement(QXmlStreamReader *xml); - void writeElement(QXmlStreamWriter *xml); + public: + explicit InnerDecklistNode(QString _name = QString(), InnerDecklistNode *_parent = nullptr) : AbstractDecklistNode(_parent), name(std::move(_name)) { } + explicit InnerDecklistNode(InnerDecklistNode *other, InnerDecklistNode *_parent = nullptr); + ~InnerDecklistNode() override; + void setSortMethod(DeckSortMethod method) override; + QString getName() const override { return name; } + void setName(const QString &_name) { name = _name; } + static QString visibleNameFromName(const QString &_name); + virtual QString getVisibleName() const; + void clearTree(); + AbstractDecklistNode *findChild(const QString &name); + int height() const override; + int recursiveCount(bool countTotalCards = false) const; + bool compare(AbstractDecklistNode *other) const override; + bool compareNumber(AbstractDecklistNode *other) const; + bool compareName(AbstractDecklistNode *other) const; + QVector > sort(Qt::SortOrder order = Qt::AscendingOrder); + + bool readElement(QXmlStreamReader *xml) override; + void writeElement(QXmlStreamWriter *xml) override; }; -class AbstractDecklistCardNode : public AbstractDecklistNode { -public: - AbstractDecklistCardNode(InnerDecklistNode *_parent = 0) : AbstractDecklistNode(_parent) { } - virtual int getNumber() const = 0; - virtual void setNumber(int _number) = 0; - virtual QString getName() const = 0; - virtual void setName(const QString &_name) = 0; - int height() const { return 0; } - bool compare(AbstractDecklistNode *other) const; - bool compareNumber(AbstractDecklistNode *other) const; - bool compareName(AbstractDecklistNode *other) const; +class AbstractDecklistCardNode : public AbstractDecklistNode +{ + public: + explicit AbstractDecklistCardNode(InnerDecklistNode *_parent = nullptr) : AbstractDecklistNode(_parent) { } + virtual int getNumber() const = 0; + virtual void setNumber(int _number) = 0; + QString getName() const override = 0; + virtual void setName(const QString &_name) = 0; + int height() const override { return 0; } + bool compare(AbstractDecklistNode *other) const override; + bool compareNumber(AbstractDecklistNode *other) const; + bool compareName(AbstractDecklistNode *other) const; - bool readElement(QXmlStreamReader *xml); - void writeElement(QXmlStreamWriter *xml); + bool readElement(QXmlStreamReader *xml) override; + void writeElement(QXmlStreamWriter *xml) override; }; -class DecklistCardNode : public AbstractDecklistCardNode { -private: - QString name; - int number; -public: - DecklistCardNode(const QString &_name = QString(), int _number = 1, InnerDecklistNode *_parent = 0) : AbstractDecklistCardNode(_parent), name(_name), number(_number) { } - DecklistCardNode(DecklistCardNode *other, InnerDecklistNode *_parent); - int getNumber() const { return number; } - void setNumber(int _number) { number = _number; } - QString getName() const { return name; } - void setName(const QString &_name) { name = _name; } +class DecklistCardNode : public AbstractDecklistCardNode +{ + private: + QString name; + int number; + public: + explicit DecklistCardNode(QString _name = QString(), int _number = 1, InnerDecklistNode *_parent = nullptr) : AbstractDecklistCardNode(_parent), name(std::move(_name)), number(_number) { } + explicit DecklistCardNode(DecklistCardNode *other, InnerDecklistNode *_parent); + int getNumber() const override { return number; } + void setNumber(int _number) override { number = _number; } + QString getName() const override { return name; } + void setName(const QString &_name) override { name = _name; } }; -class DeckList : public QObject { +class DeckList : public QObject +{ Q_OBJECT -private: - QString name, comments; - QString deckHash; - QMap sideboardPlans; - InnerDecklistNode *root; - void getCardListHelper(InnerDecklistNode *node, QSet &result) const; - InnerDecklistNode *getZoneObjFromName(const QString zoneName); -protected: - virtual QString getCardZoneFromName(QString /* cardName */, QString currentZoneName) { return currentZoneName; }; - virtual QString getCompleteCardName(const QString cardName) const { return cardName; }; -signals: - void deckHashChanged(); -public slots: - void setName(const QString &_name = QString()) { name = _name; } - void setComments(const QString &_comments = QString()) { comments = _comments; } -public: - DeckList(); - DeckList(const DeckList &other); - DeckList(const QString &nativeString); - ~DeckList(); - QString getName() const { return name; } - QString getComments() const { return comments; } - QList getCurrentSideboardPlan(); - void setCurrentSideboardPlan(const QList &plan); - const QMap &getSideboardPlans() const { return sideboardPlans; } + private: + QString name, comments; + QString deckHash; + QMap sideboardPlans; + InnerDecklistNode *root; + void getCardListHelper(InnerDecklistNode *node, QSet &result) const; + InnerDecklistNode *getZoneObjFromName(QString zoneName); - bool readElement(QXmlStreamReader *xml); - void write(QXmlStreamWriter *xml); - bool loadFromXml(QXmlStreamReader *xml); - bool loadFromString_Native(const QString &nativeString); - QString writeToString_Native(); - bool loadFromFile_Native(QIODevice *device); - bool saveToFile_Native(QIODevice *device); - bool loadFromStream_Plain(QTextStream &stream); - bool loadFromFile_Plain(QIODevice *device); - bool saveToStream_Plain(QTextStream &stream, bool prefixSideboardCards, bool slashTappedOutSplitCards); - bool saveToFile_Plain(QIODevice *device, bool prefixSideboardCards=true, bool slashTappedOutSplitCards=false); - QString writeToString_Plain(bool prefixSideboardCards=true, bool slashTappedOutSplitCards=false); + protected: + virtual QString getCardZoneFromName(const QString /*cardName*/, QString currentZoneName) { return currentZoneName; }; + virtual QString getCompleteCardName(const QString cardName) const { return cardName; }; - void cleanList(); - bool isEmpty() const { return root->isEmpty() && name.isEmpty() && comments.isEmpty() && sideboardPlans.isEmpty(); } - QStringList getCardList() const; + signals: + void deckHashChanged(); - int getSideboardSize() const; + public slots: + void setName(const QString &_name = QString()) { name = _name; } + void setComments(const QString &_comments = QString()) { comments = _comments; } - QString getDeckHash() const { return deckHash; } - void updateDeckHash(); + public: + explicit DeckList(); + DeckList(const DeckList &other); + explicit DeckList(const QString &nativeString); + ~DeckList() override; + QString getName() const { return name; } + QString getComments() const { return comments; } + QList getCurrentSideboardPlan(); + void setCurrentSideboardPlan(const QList &plan); + const QMap &getSideboardPlans() const { return sideboardPlans; } - InnerDecklistNode *getRoot() const { return root; } - DecklistCardNode *addCard(const QString &cardName, const QString &zoneName); - bool deleteNode(AbstractDecklistNode *node, InnerDecklistNode *rootNode = 0); + bool readElement(QXmlStreamReader *xml); + void write(QXmlStreamWriter *xml); + bool loadFromXml(QXmlStreamReader *xml); + bool loadFromString_Native(const QString &nativeString); + QString writeToString_Native(); + bool loadFromFile_Native(QIODevice *device); + bool saveToFile_Native(QIODevice *device); + bool loadFromStream_Plain(QTextStream &stream); + bool loadFromFile_Plain(QIODevice *device); + bool saveToStream_Plain(QTextStream &stream, bool prefixSideboardCards, bool slashTappedOutSplitCards); + bool saveToFile_Plain(QIODevice *device, bool prefixSideboardCards=true, bool slashTappedOutSplitCards=false); + QString writeToString_Plain(bool prefixSideboardCards=true, bool slashTappedOutSplitCards=false); - /** - * Calls a given function object for each card in the deck. It must - * take a InnerDecklistNode* as its first argument and a - * DecklistCardNode* as its second. - */ - template - void forEachCard(Callback &callback) const { - // Support for this is only possible if the internal structure - // doesn't get more complicated. - for (int i = 0; i < root->size(); i++) { - const InnerDecklistNode *node = - dynamic_cast(root->at(i)); - for (int j = 0; j < node->size(); j++) { - const DecklistCardNode *card = - dynamic_cast( - node->at(j) - ); - callback(node, card); + void cleanList(); + bool isEmpty() const { return root->isEmpty() && name.isEmpty() && comments.isEmpty() && sideboardPlans.isEmpty(); } + QStringList getCardList() const; + + int getSideboardSize() const; + + QString getDeckHash() const { return deckHash; } + void updateDeckHash(); + + InnerDecklistNode *getRoot() const { return root; } + DecklistCardNode *addCard(const QString &cardName, const QString &zoneName); + bool deleteNode(AbstractDecklistNode *node, InnerDecklistNode *rootNode = nullptr); + + /** + * Calls a given function object for each card in the deck. It must + * take a InnerDecklistNode* as its first argument and a + * DecklistCardNode* as its second. + */ + template + void forEachCard(Callback &callback) const { + // Support for this is only possible if the internal structure + // doesn't get more complicated. + for (int i = 0; i < root->size(); i++) { + const InnerDecklistNode *node = + dynamic_cast(root->at(i)); + for (int j = 0; j < node->size(); j++) { + const DecklistCardNode *card = + dynamic_cast( + node->at(j) + ); + callback(node, card); + } } } - } }; #endif