From 1da5c63726e81597a2196a5f8cd4768eac9d4399 Mon Sep 17 00:00:00 2001 From: Max-Wilhelm Bruker Date: Wed, 3 Jun 2009 00:15:06 +0200 Subject: [PATCH] deck editor --- cockatrice/src/carddatabasemodel.cpp | 6 +- cockatrice/src/decklist.cpp | 207 +++++++++++++++++------ cockatrice/src/decklist.h | 30 +++- cockatrice/src/decklistmodel.cpp | 240 +++++++++++---------------- cockatrice/src/decklistmodel.h | 31 ++-- cockatrice/src/dlg_startgame.cpp | 34 ++-- cockatrice/src/dlg_startgame.h | 6 +- cockatrice/src/window_deckeditor.cpp | 48 +++--- cockatrice/src/window_deckeditor.h | 3 +- 9 files changed, 349 insertions(+), 256 deletions(-) diff --git a/cockatrice/src/carddatabasemodel.cpp b/cockatrice/src/carddatabasemodel.cpp index fc3cacc7..4de61f56 100644 --- a/cockatrice/src/carddatabasemodel.cpp +++ b/cockatrice/src/carddatabasemodel.cpp @@ -11,15 +11,13 @@ CardDatabaseModel::~CardDatabaseModel() } -int CardDatabaseModel::rowCount(const QModelIndex &parent) const +int CardDatabaseModel::rowCount(const QModelIndex &/*parent*/) const { - Q_UNUSED(parent); return cardList.size(); } -int CardDatabaseModel::columnCount(const QModelIndex &parent) const +int CardDatabaseModel::columnCount(const QModelIndex &/*parent*/) const { - Q_UNUSED(parent); return 5; } diff --git a/cockatrice/src/decklist.cpp b/cockatrice/src/decklist.cpp index e50d04d0..258ad3c2 100644 --- a/cockatrice/src/decklist.cpp +++ b/cockatrice/src/decklist.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include "decklist.h" #include "carddatabase.h" @@ -14,6 +15,14 @@ AbstractDecklistNode::AbstractDecklistNode(InnerDecklistNode *_parent) parent->append(this); } +int AbstractDecklistNode::depth() const +{ + if (parent) + return parent->depth() + 1; + else + return 0; +} + InnerDecklistNode::~InnerDecklistNode() { clearTree(); @@ -26,33 +35,83 @@ QString InnerDecklistNode::getVisibleName() const else if (name == "side") return QObject::tr("Sideboard"); else - return QString(); + return getName(); } void InnerDecklistNode::clearTree() { for (int i = 0; i < size(); i++) delete at(i); + clear(); } -int InnerDecklistNode::recursiveCount() const +AbstractDecklistNode *InnerDecklistNode::findChild(const QString &name) +{ + for (int i = 0; i < size(); i++) + if (at(i)->getName() == name) + return at(i); + return 0; +} + +int InnerDecklistNode::recursiveCount(bool countTotalCards) const { int result = 0; for (int i = 0; i < size(); i++) { InnerDecklistNode *node = dynamic_cast(at(i)); if (node) - result += node->recursiveCount(); + result += node->recursiveCount(countTotalCards); + else if (countTotalCards) + result += dynamic_cast(at(i))->getNumber(); else result += 1; } return result; } +bool InnerDecklistNode::compare(AbstractDecklistNode *other) const +{ + InnerDecklistNode *other2 = dynamic_cast(other); + if (other2) + return (getName() > other->getName()); + else + return false; +} + +bool AbstractDecklistCardNode::compare(AbstractDecklistNode *other) const +{ + AbstractDecklistCardNode *other2 = dynamic_cast(other); + if (other2) + return (getName() > other->getName()); + else + return true; +} + +class InnerDecklistNode::compareFunctor { +private: + Qt::SortOrder order; +public: + compareFunctor(Qt::SortOrder _order) : order(_order) { } + inline bool operator()(AbstractDecklistNode *a, AbstractDecklistNode *b) const + { + return (order == Qt::AscendingOrder) ^ (a->compare(b)); + } +}; + +void InnerDecklistNode::sort(Qt::SortOrder order) +{ + compareFunctor cmp(order); + qSort(begin(), end(), cmp); + for (int i = 0; i < size(); i++) { + InnerDecklistNode *node = dynamic_cast(at(i)); + if (node) + node->sort(order); + } +} + DeckList::DeckList(CardDatabase *_db, QObject *parent) : QObject(parent), db(_db) { root = new InnerDecklistNode; - initZones(); } DeckList::~DeckList() @@ -60,6 +119,25 @@ DeckList::~DeckList() delete root; } +QXmlStreamReader &operator>>(QXmlStreamReader &xml, InnerDecklistNode *node) +{ + while (!xml.atEnd()) { + if (xml.readNext() == QXmlStreamReader::EndElement) + break; + if (xml.name() == "zone") + xml >> new InnerDecklistNode(xml.attributes().value("name").toString(), node); + else if (xml.name() == "card") { + const int number = xml.attributes().value("number").toString().toInt(); + const QString card = xml.attributes().value("name").toString(); + new DecklistCardNode(card, number, node); + while (!xml.atEnd()) + if (xml.readNext() == QXmlStreamReader::EndElement) + break; + } + } + return xml; +} + bool DeckList::loadFromFile_Native(QIODevice *device) { QXmlStreamReader xml(device); @@ -74,30 +152,35 @@ bool DeckList::loadFromFile_Native(QIODevice *device) name = xml.readElementText(); else if (xml.name() == "comments") comments = xml.readElementText(); - else if (xml.name() == "zone") { - InnerDecklistNode *node = new InnerDecklistNode(xml.attributes().value("name").toString(), root); - while (!xml.atEnd()) { - if (xml.readNext() == QXmlStreamReader::EndElement) - break; - if (xml.name() == "card") { - const int number = xml.attributes().value("number").toString().toInt(); - const QString card = xml.attributes().value("name").toString(); - new DecklistCardNode(card, number, node); - while (!xml.atEnd()) - if (xml.readNext() == QXmlStreamReader::EndElement) - break; - } - } - } + else if (xml.name() == "zone") + xml >> new InnerDecklistNode(xml.attributes().value("name").toString(), root); } } } return true; } +QXmlStreamWriter &operator<<(QXmlStreamWriter &xml, const AbstractDecklistNode *node) +{ + const InnerDecklistNode *inner = dynamic_cast(node); + if (inner) { + xml.writeStartElement("zone"); + xml.writeAttribute("name", inner->getName()); + for (int i = 0; i < inner->size(); i++) + xml << inner->at(i); + xml.writeEndElement(); // zone + } else { + const AbstractDecklistCardNode *card = dynamic_cast(node); + xml.writeEmptyElement("card"); + xml.writeAttribute("number", QString::number(card->getNumber())); + xml.writeAttribute("name", card->getName()); + } + return xml; +} + bool DeckList::saveToFile_Native(QIODevice *device) { -/* QXmlStreamWriter xml(device); + QXmlStreamWriter xml(device); xml.setAutoFormatting(true); xml.writeStartDocument(); @@ -106,27 +189,18 @@ bool DeckList::saveToFile_Native(QIODevice *device) xml.writeTextElement("deckname", name); xml.writeTextElement("comments", comments); - for (int i = 0; i < zones.size(); i++) { - xml.writeStartElement("zone"); - xml.writeAttribute("name", zones[i]->getName()); - for (int j = 0; j < zones[i]->size(); j++) { - DecklistRow *r = zones[i]->at(j); - xml.writeEmptyElement("card"); - xml.writeAttribute("number", QString::number(r->getNumber())); - xml.writeAttribute("name", r->getCard()); - } - xml.writeEndElement(); // zone - } + for (int i = 0; i < root->size(); i++) + xml << root->at(i); xml.writeEndElement(); // cockatrice_deck xml.writeEndDocument(); return true; -*/} +} bool DeckList::loadFromFile_Plain(QIODevice *device) { -/* initZones(); + InnerDecklistNode *main = 0, *side = 0; QTextStream in(device); while (!in.atEnd()) { @@ -134,12 +208,17 @@ bool DeckList::loadFromFile_Plain(QIODevice *device) if (line.startsWith("//")) continue; - DecklistZone *zone; + InnerDecklistNode *zone; if (line.startsWith("SB:", Qt::CaseInsensitive)) { line = line.mid(3).trimmed(); - zone = zones[1]; - } else - zone = zones[0]; + if (!side) + side = new InnerDecklistNode("side", root); + zone = side; + } else { + if (!main) + main = new InnerDecklistNode("main", root); + zone = main; + } // Filter out MWS edition symbols and basic land extras QRegExp rx("\\[.*\\]"); @@ -153,21 +232,24 @@ bool DeckList::loadFromFile_Plain(QIODevice *device) int number = line.left(i).toInt(&ok); if (!ok) continue; - zone->append(new DecklistRow(number, line.mid(i + 1))); + new DecklistCardNode(line.mid(i + 1), number, zone); } return true; -*/} +} bool DeckList::saveToFile_Plain(QIODevice *device) { -/* QTextStream out(device); - for (int i = 0; i < zones.size(); i++) - for (int j = 0; j < zones[i]->size(); j++) { - DecklistRow *r = zones[i]->at(j); - out << QString("%1%2 %3\n").arg(zones[i]->getName() == "side" ? "SB: " : "").arg(r->getNumber()).arg(r->getCard()); + // Support for this is only possible if the internal structure doesn't get more complicated. + QTextStream out(device); + for (int i = 0; i < root->size(); i++) { + InnerDecklistNode *node = dynamic_cast(root->at(i)); + for (int j = 0; j < node->size(); j++) { + DecklistCardNode *card = dynamic_cast(node->at(j)); + out << QString("%1%2 %3\n").arg(node->getName() == "side" ? "SB: " : "").arg(card->getNumber()).arg(card->getName()); } + } return true; -*/} +} bool DeckList::loadFromFile(const QString &fileName, FileFormat fmt, QWidget *parent) { @@ -286,9 +368,34 @@ void DeckList::cleanList() setComments(); } -void DeckList::initZones() +DecklistCardNode *DeckList::addCard(const QString &cardName, const QString &zoneName) { -/* // possibly Magic specific - zones.append(new DecklistZone("main")); - zones.append(new DecklistZone("side")); -*/} + InnerDecklistNode *zoneNode = dynamic_cast(root->findChild(zoneName)); + if (!zoneNode) + zoneNode = new InnerDecklistNode(zoneName, root); + + return new DecklistCardNode(cardName, 1, zoneNode); +} + +bool DeckList::deleteNode(AbstractDecklistNode *node, InnerDecklistNode *rootNode) +{ + if (node == root) + return true; + if (!rootNode) + rootNode = root; + + int index = rootNode->indexOf(node); + if (index != -1) { + delete rootNode->takeAt(index); + if (!rootNode->size()) + deleteNode(rootNode, rootNode->getParent()); + return true; + } + for (int i = 0; i < rootNode->size(); i++) { + InnerDecklistNode *inner = dynamic_cast(rootNode->at(i)); + if (inner) + if (deleteNode(node, inner)) + return true; + } + return false; +} diff --git a/cockatrice/src/decklist.h b/cockatrice/src/decklist.h index 73a07c39..a7db6d5d 100644 --- a/cockatrice/src/decklist.h +++ b/cockatrice/src/decklist.h @@ -15,32 +15,45 @@ protected: InnerDecklistNode *parent; public: AbstractDecklistNode(InnerDecklistNode *_parent = 0); - virtual bool hasChildren() const = 0; virtual QString getName() const = 0; - const InnerDecklistNode *getParent() const { return parent; } + InnerDecklistNode *getParent() const { return parent; } + int depth() const; + virtual bool compare(AbstractDecklistNode *other) const = 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(); - bool hasChildren() const { return true; } QString getName() const { return name; } void setName(const QString &_name) { name = _name; } virtual QString getVisibleName() const; void clearTree(); - int recursiveCount() const; + AbstractDecklistNode *findChild(const QString &name); + int recursiveCount(bool countTotalCards = false) const; + bool compare(AbstractDecklistNode *other) const; + void sort(Qt::SortOrder order = Qt::AscendingOrder); }; -class DecklistCardNode : public AbstractDecklistNode { +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; + bool compare(AbstractDecklistNode *other) const; +}; + +class DecklistCardNode : public AbstractDecklistCardNode { private: QString name; int number; public: - DecklistCardNode(const QString &_name = QString(), int _number = 1, InnerDecklistNode *_parent = 0) : AbstractDecklistNode(_parent), name(_name), number(_number) { } - bool hasChildren() const { return false; } + DecklistCardNode(const QString &_name = QString(), int _number = 1, InnerDecklistNode *_parent = 0) : AbstractDecklistCardNode(_parent), name(_name), number(_number) { } int getNumber() const { return number; } void setNumber(int _number) { number = _number; } QString getName() const { return name; } @@ -83,9 +96,10 @@ public: bool saveDialog(QWidget *parent = 0); void cleanList(); - void initZones(); InnerDecklistNode *getRoot() const { return root; } + DecklistCardNode *addCard(const QString &cardName, const QString &zoneName); + bool deleteNode(AbstractDecklistNode *node, InnerDecklistNode *rootNode = 0); }; #endif diff --git a/cockatrice/src/decklistmodel.cpp b/cockatrice/src/decklistmodel.cpp index b69915da..663b2c32 100644 --- a/cockatrice/src/decklistmodel.cpp +++ b/cockatrice/src/decklistmodel.cpp @@ -17,18 +17,15 @@ DeckListModel::~DeckListModel() { } + void DeckListModel::debugIndexInfo(const QString &func, const QModelIndex &index) const { - quint32 id = index.internalId(); // 32 bit int, from MSB to LSB: - int zone = id >> 30; // 2 bits - zone - int cardtype = (id >> 25) & 0x1f; // 5 bits - card type - int card = (id >> 3) & 0x3fffff; // 22 bits - card - int column = id & 0x7; // 3 bits - column - - if (index.isValid()) - qDebug(QString("index: function = %1, zone = %2, cardtype = %3, card = %4, column = %5").arg(func).arg(zone).arg(cardtype).arg(card).arg(column).toLatin1()); - else - qDebug(QString("index: function = %1, invalid").arg(func).toLatin1()); + if (!index.isValid()) + qDebug(QString("debugIndexInfo: %1: index invalid").arg(func).toLatin1()); + else if (InnerDecklistNode *node = getNode(index)) + qDebug(QString("debugIndexInfo: %1: INNER index '%2', row=%3, col=%4").arg(func).arg(node->getName()).arg(index.row()).arg(index.column()).toLatin1()); + else if (DecklistModelCardNode *node = getNode(index)) + qDebug(QString("debugIndexInfo: %1: CARD index '%2', row=%3, col=%4").arg(func).arg(node->getName()).arg(index.row()).arg(index.column()).toLatin1()); } void DeckListModel::debugShowTree(InnerDecklistNode *node, int depth) const @@ -44,6 +41,7 @@ void DeckListModel::debugShowTree(InnerDecklistNode *node, int depth) const } } + void DeckListModel::rebuildTree() { root->clearTree(); @@ -55,75 +53,25 @@ void DeckListModel::rebuildTree() DecklistCardNode *currentCard = dynamic_cast(currentZone->at(j)); QString cardType = db->getCard(currentCard->getName())->getMainCardType(); - InnerDecklistNode *cardTypeNode = dynamic_cast(findNode(cardType, node)); + InnerDecklistNode *cardTypeNode = dynamic_cast(node->findChild(cardType)); if (!cardTypeNode) cardTypeNode = new InnerDecklistNode(cardType, node); - DecklistModelCardNode *newCard = new DecklistModelCardNode(currentCard, cardTypeNode); + new DecklistModelCardNode(currentCard, cardTypeNode); } } - debugShowTree(root, 0); reset(); } -AbstractDecklistNode *DeckListModel::findNode(const QString &name, InnerDecklistNode *root) const -{ - for (int i = 0; i < root->size(); i++) - if (root->at(i)->getName() == name) - return root->at(i); - return 0; -} - -AbstractDecklistNode *DeckListModel::findNode(const QModelIndex &index) const -{ -// debugIndexInfo("findNode", index); - if (index.isValid()) { - InnerDecklistNode *parentNode = dynamic_cast(findNode(index.parent())); - return parentNode->at(index.row()); - } else - return root; -} - int DeckListModel::rowCount(const QModelIndex &parent) const { // debugIndexInfo("rowCount", parent); - InnerDecklistNode *node = dynamic_cast(findNode(parent)); - if (node) { -// qDebug(QString(" rowCount: return %1").arg(node->size()).toLatin1()); + InnerDecklistNode *node = getNode(parent); + if (node) return node->size(); - } else { -// qDebug(" rowCount: return const 0"); + else return 0; - } -} - -bool DeckListModel::hasChildren(const QModelIndex &parent) const -{ -// debugIndexInfo("hasChildren", parent); - if (!parent.isValid() && root->size()) - return true; - if (parent.column() != 0) - return false; -/* - InnerDecklistNode *node = dynamic_cast(findNode(parent)); - if (!node) - qDebug("line 109: return false"); - return false; - } - qDebug(QString("line 112: return %1").arg(node->size()).toLatin1()); - return node->size(); - - if (!parent.isValid()) - return true; - qDebug(QString(" hasChildren: return %1").arg((!parent.column() && (((parent.internalId() >> 3) & 0x3fffff) == 0x3fffff))).toLatin1()); -*/ // An item (possibly) has children if its column is zero and its card is -1. - return (!parent.column() && (((parent.internalId() >> 3) & 0x3fffff) == 0x3fffff)); -} - -int DeckListModel::columnCount(const QModelIndex &/*parent*/) const -{ - return 2; } QVariant DeckListModel::data(const QModelIndex &index, int role) const @@ -134,11 +82,10 @@ QVariant DeckListModel::data(const QModelIndex &index, int role) const if (index.column() >= 2) return QVariant(); - AbstractDecklistNode *tempNode = findNode(index); - if (tempNode == root) - return QVariant(); - - if (tempNode->hasChildren()) { + AbstractDecklistNode *temp = static_cast(index.internalPointer()); + DecklistModelCardNode *card = dynamic_cast(temp); + if (!card) { + InnerDecklistNode *node = dynamic_cast(temp); switch (role) { case Qt::FontRole: { QFont f; @@ -146,27 +93,25 @@ QVariant DeckListModel::data(const QModelIndex &index, int role) const return f; } case Qt::DisplayRole: - case Qt::EditRole: { + case Qt::EditRole: switch (index.column()) { - case 0: { - InnerDecklistNode *node = dynamic_cast(tempNode); - return node->getVisibleName(); - } + case 0: return node->recursiveCount(true); + case 1: return node->getVisibleName(); default: return QVariant(); } + case Qt::BackgroundRole: { + int color = 90 + 60 * node->depth(); + return QBrush(QColor(color, 255, color)); } - case Qt::BackgroundRole: - return QBrush(QColor(200, 255, 200)); default: return QVariant(); } } else { switch (role) { case Qt::DisplayRole: case Qt::EditRole: { - DecklistModelCardNode *node = dynamic_cast(tempNode); switch (index.column()) { - case 0: return node->getNumber(); - case 1: return node->getName(); + case 0: return card->getNumber(); + case 1: return card->getName(); default: return QVariant(); } } @@ -181,9 +126,7 @@ QVariant DeckListModel::data(const QModelIndex &index, int role) const QVariant DeckListModel::headerData(int section, Qt::Orientation orientation, int role) const { - if (role != Qt::DisplayRole) - return QVariant(); - if (orientation != Qt::Horizontal) + if ((role != Qt::DisplayRole) || (orientation != Qt::Horizontal)) return QVariant(); switch (section) { case 0: return QString(tr("Number")); @@ -195,52 +138,31 @@ QVariant DeckListModel::headerData(int section, Qt::Orientation orientation, int QModelIndex DeckListModel::index(int row, int column, const QModelIndex &parent) const { // debugIndexInfo("index", parent); - // for explanation of the bit shifting, look at parent() - int indexZone, indexCardType, indexCard; - if (!parent.isValid()) { - indexZone = row; - indexCardType = 0x1f; - indexCard = 0x3fffff; - } else { - quint32 pid = parent.internalId(); - indexZone = pid >> 30; - int pcardtype = (pid >> 25) & 0x1f; + if (!hasIndex(row, column, parent)) + return QModelIndex(); + + InnerDecklistNode *parentNode = getNode(parent); + if (row >= parentNode->size()) + return QModelIndex(); - if (pcardtype == 0x1f) { - indexCardType = row; - indexCard = 0x3fffff; - } else { - indexCardType = pcardtype; - indexCard = row; - } - } - -// qDebug(QString("index(): zone = %1, cardtype = %2, card = %3, column = %4").arg(indexZone).arg(indexCardType).arg(indexCard).arg(column).toLatin1()); - return createIndex(row, column, (indexZone << 30) + (indexCardType << 25) + (indexCard << 3) + column); + return createIndex(row, column, parentNode->at(row)); } QModelIndex DeckListModel::parent(const QModelIndex &ind) const { -// debugIndexInfo("parent", ind); - - quint32 id = ind.internalId(); // 32 bit int, from MSB to LSB: - int zone = id >> 30; // 2 bits - zone - int cardtype = (id >> 25) & 0x1f; // 5 bits - card type - int card = (id >> 3) & 0x3fffff; // 22 bits - card -// int column = id & 0x7; // 3 bits - column - - if (cardtype == 0x1f) + if (!ind.isValid()) return QModelIndex(); - else if (card == 0x3fffff) - return index(zone, 0); - else - return index(cardtype, 0, index(zone, 0)); + + return nodeToIndex(static_cast(ind.internalPointer())->getParent()); } Qt::ItemFlags DeckListModel::flags(const QModelIndex &index) const { + if (!index.isValid()) + return 0; + Qt::ItemFlags result = Qt::ItemIsEnabled; - if (((index.internalId() >> 3) & 0x3fffff) != 0x3fffff) { + if (getNode(index)) { result |= Qt::ItemIsSelectable; if (index.column() == 0) result |= Qt::ItemIsEditable; @@ -250,7 +172,7 @@ Qt::ItemFlags DeckListModel::flags(const QModelIndex &index) const bool DeckListModel::setData(const QModelIndex &index, const QVariant &value, int role) { - DecklistModelCardNode *node = dynamic_cast(findNode(index)); + DecklistModelCardNode *node = getNode(index); if (!node || (role != Qt::EditRole)) return false; @@ -265,46 +187,80 @@ bool DeckListModel::setData(const QModelIndex &index, const QVariant &value, int bool DeckListModel::removeRows(int row, int count, const QModelIndex &parent) { -/* DecklistNode *node = findNode(parent); + debugIndexInfo("removeRows", parent); + InnerDecklistNode *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++) - delete node->takeAt(row); - + for (int i = 0; i < count; i++) { + AbstractDecklistNode *toDelete = node->takeAt(row); + if (DecklistModelCardNode *temp = dynamic_cast(toDelete)) + deckList->deleteNode(temp->getDataNode()); + delete toDelete; + } endRemoveRows(); + + if (!node->size() && (node != root)) + removeRows(parent.row(), 1, parent.parent()); + return true; -*/} -/* -void DeckListModel::insertCard(...) -{ } -void DeckListModel::removeCard(...) +InnerDecklistNode *DeckListModel::createNodeIfNeeded(const QString &name, InnerDecklistNode *parent) { + InnerDecklistNode *newNode = dynamic_cast(parent->findChild(name)); + if (!newNode) { + beginInsertRows(nodeToIndex(parent), parent->size(), parent->size()); + newNode = new InnerDecklistNode(name, parent); + endInsertRows(); + } + return newNode; } -*/ -bool DeckListModel::insertRows(int row, int count, const QModelIndex &parent) + +QModelIndex DeckListModel::addCard(const QString &cardName, const QString &zoneName) { -/* - // Inserting zones is not supported. - if (!parent.isValid()) - return false; + InnerDecklistNode *zoneNode = createNodeIfNeeded(zoneName, root); + + CardInfo *info = db->getCard(cardName); + QString cardType = info->getMainCardType(); + InnerDecklistNode *cardTypeNode = createNodeIfNeeded(cardType, zoneNode); + + DecklistModelCardNode *cardNode = dynamic_cast(cardTypeNode->findChild(cardName)); + if (!cardNode) { + DecklistCardNode *decklistCard = deckList->addCard(cardName, zoneName); + beginInsertRows(nodeToIndex(cardTypeNode), cardTypeNode->size(), cardTypeNode->size()); + cardNode = new DecklistModelCardNode(decklistCard, cardTypeNode); + endInsertRows(); + sort(1); + return nodeToIndex(cardNode); + } else { + cardNode->setNumber(cardNode->getNumber() + 1); + QModelIndex ind = nodeToIndex(cardNode); + emit dataChanged(ind, ind); + return ind; + } +} - beginInsertRows(parent, row, row + count - 1); +QModelIndex DeckListModel::nodeToIndex(AbstractDecklistNode *node) const +{ + if (node == root) + return QModelIndex(); + return createIndex(node->getParent()->indexOf(node), 0, node); +} - for (int i = 0; i < count; i++) - deckList->getZoneByIndex(parent.row())->insert(row, new DecklistRow); - endInsertRows(); - return true; -*/} +void DeckListModel::sort(int /*column*/, Qt::SortOrder order) +{ + emit layoutAboutToBeChanged(); + root->sort(order); + emit layoutChanged(); +} void DeckListModel::cleanList() { deckList->cleanList(); - deckList->initZones(); reset(); } diff --git a/cockatrice/src/decklistmodel.h b/cockatrice/src/decklistmodel.h index 323e36a4..8fd194eb 100644 --- a/cockatrice/src/decklistmodel.h +++ b/cockatrice/src/decklistmodel.h @@ -7,16 +7,16 @@ class CardDatabase; -class DecklistModelCardNode : public AbstractDecklistNode { +class DecklistModelCardNode : public AbstractDecklistCardNode { private: DecklistCardNode *dataNode; public: - DecklistModelCardNode(DecklistCardNode *_dataNode, InnerDecklistNode *_parent) : AbstractDecklistNode(_parent), dataNode(_dataNode) { } - bool hasChildren() const { return false; } - inline int getNumber() const { return dataNode->getNumber(); } - inline void setNumber(int _number) { dataNode->setNumber(_number); } - inline QString getName() const { return dataNode->getName(); } - inline void setName(const QString &_name) { dataNode->setName(_name); } + DecklistModelCardNode(DecklistCardNode *_dataNode, InnerDecklistNode *_parent) : AbstractDecklistCardNode(_parent), dataNode(_dataNode) { } + int getNumber() const { return dataNode->getNumber(); } + void setNumber(int _number) { dataNode->setNumber(_number); } + QString getName() const { return dataNode->getName(); } + void setName(const QString &_name) { dataNode->setName(_name); } + DecklistCardNode *getDataNode() const { return dataNode; } }; class DeckListModel : public QAbstractItemModel { @@ -27,8 +27,7 @@ public: DeckListModel(CardDatabase *_db, QObject *parent = 0); ~DeckListModel(); int rowCount(const QModelIndex &parent = QModelIndex()) const; - bool hasChildren(const QModelIndex &parent = QModelIndex()) const; - int columnCount(const QModelIndex &parent = QModelIndex()) const; + int columnCount(const QModelIndex &/*parent*/) const { return 2; } 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; @@ -36,17 +35,25 @@ public: 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 insertRows(int row, int count, const QModelIndex &parent = QModelIndex()); + QModelIndex addCard(const QString &cardName, const QString &zoneName); + void sort(int column, Qt::SortOrder order = Qt::AscendingOrder); void cleanList(); DeckList *getDeckList() const { return deckList; } private: CardDatabase *db; DeckList *deckList; InnerDecklistNode *root; - AbstractDecklistNode *findNode(const QString &name, InnerDecklistNode *root) const; - AbstractDecklistNode *findNode(const QModelIndex &index) const; + InnerDecklistNode *createNodeIfNeeded(const QString &name, InnerDecklistNode *parent); + QModelIndex nodeToIndex(AbstractDecklistNode *node) const; void debugIndexInfo(const QString &func, const QModelIndex &index) const; void debugShowTree(InnerDecklistNode *node, int depth) const; + + template T getNode(const QModelIndex &index) const + { + if (!index.isValid()) + return dynamic_cast(root); + return dynamic_cast(static_cast(index.internalPointer())); + } }; #endif diff --git a/cockatrice/src/dlg_startgame.cpp b/cockatrice/src/dlg_startgame.cpp index 290db923..02b96ed8 100644 --- a/cockatrice/src/dlg_startgame.cpp +++ b/cockatrice/src/dlg_startgame.cpp @@ -7,9 +7,10 @@ DlgStartGame::DlgStartGame(CardDatabase *_db, QWidget *parent) : QDialog(parent), db(_db) { - tableView = new QTreeView; - tableModel = new DeckListModel(db, this); - tableView->setModel(tableModel); + deckView = new QTreeView; + deckModel = new DeckListModel(db, this); + deckView->setModel(deckModel); + deckView->setUniformRowHeights(true); loadButton = new QPushButton(tr("&Load...")); okButton = new QPushButton(tr("&OK")); @@ -21,13 +22,14 @@ DlgStartGame::DlgStartGame(CardDatabase *_db, QWidget *parent) buttonLayout->addWidget(okButton); QVBoxLayout *mainLayout = new QVBoxLayout; - mainLayout->addWidget(tableView); + mainLayout->addWidget(deckView); mainLayout->addLayout(buttonLayout); setLayout(mainLayout); setWindowTitle(tr("Start game")); setMinimumWidth(sizeHint().width()); + resize(300, 500); connect(loadButton, SIGNAL(clicked()), this, SLOT(actLoad())); connect(okButton, SIGNAL(clicked()), this, SLOT(accept())); @@ -35,24 +37,28 @@ DlgStartGame::DlgStartGame(CardDatabase *_db, QWidget *parent) void DlgStartGame::actLoad() { - if (!tableModel->getDeckList()->loadDialog(this)) + if (!deckModel->getDeckList()->loadDialog(this)) return; - tableView->reset(); + deckView->reset(); + deckModel->sort(1); + deckView->expandAll(); + deckView->resizeColumnToContents(0); + emit newDeckLoaded(getDeckList()); } QStringList DlgStartGame::getDeckList() const { QStringList result; -/* DeckList *deckList = tableModel->getDeckList(); - for (int i = 0; i < deckList->zoneCount(); i++) { - DecklistZone *zone = deckList->getZoneByIndex(i); - for (int j = 0; j < zone->size(); j++) { - DecklistRow *r = zone->at(j); - for (int k = 0; k < r->getNumber(); k++) - result << QString("%1%2").arg(zone->getName() == "side" ? "SB:" : "").arg(r->getCard()); + DeckList *deckList = deckModel->getDeckList(); + for (int i = 0; i < deckList->getRoot()->size(); i++) { + InnerDecklistNode *node = dynamic_cast(deckList->getRoot()->at(i)); + for (int j = 0; j < node->size(); j++) { + DecklistCardNode *card = dynamic_cast(node->at(j)); + for (int k = 0; k < card->getNumber(); k++) + result << QString("%1%2").arg(node->getName() == "side" ? "SB: " : "").arg(card->getName()); } } -*/ return result; + return result; } diff --git a/cockatrice/src/dlg_startgame.h b/cockatrice/src/dlg_startgame.h index 8a3d5bb7..efd24950 100644 --- a/cockatrice/src/dlg_startgame.h +++ b/cockatrice/src/dlg_startgame.h @@ -2,11 +2,11 @@ #define DLG_STARTGAME_H #include -#include "decklistmodel.h" class QTreeView; class QPushButton; class CardDatabase; +class DeckListModel; class DlgStartGame: public QDialog { Q_OBJECT @@ -19,8 +19,8 @@ private slots: void actLoad(); private: CardDatabase *db; - QTreeView *tableView; - DeckListModel *tableModel; + QTreeView *deckView; + DeckListModel *deckModel; QPushButton *loadButton, *okButton; }; diff --git a/cockatrice/src/window_deckeditor.cpp b/cockatrice/src/window_deckeditor.cpp index 599234d7..0a957ecc 100644 --- a/cockatrice/src/window_deckeditor.cpp +++ b/cockatrice/src/window_deckeditor.cpp @@ -23,6 +23,7 @@ WndDeckEditor::WndDeckEditor(CardDatabase *_db, QWidget *parent) databaseView->setModel(databaseModel); databaseView->setUniformRowHeights(true); databaseView->setSortingEnabled(true); + databaseView->resizeColumnToContents(0); connect(databaseView->selectionModel(), SIGNAL(currentRowChanged(const QModelIndex &, const QModelIndex &)), this, SLOT(updateCardInfoLeft(const QModelIndex &, const QModelIndex &))); connect(databaseView, SIGNAL(doubleClicked(const QModelIndex &)), this, SLOT(actAddCard())); @@ -49,7 +50,6 @@ WndDeckEditor::WndDeckEditor(CardDatabase *_db, QWidget *parent) deckView = new QTreeView(); deckView->setModel(deckModel); deckView->setUniformRowHeights(true); - deckView->setRootIsDecorated(false); connect(deckView->selectionModel(), SIGNAL(currentRowChanged(const QModelIndex &, const QModelIndex &)), this, SLOT(updateCardInfoRight(const QModelIndex &, const QModelIndex &))); QLabel *nameLabel = new QLabel(tr("Deck &name:")); @@ -113,7 +113,7 @@ WndDeckEditor::WndDeckEditor(CardDatabase *_db, QWidget *parent) aAddCardToSideboard->setShortcut(tr("Ctrl+N")); aRemoveCard = new QAction(tr("&Remove row"), this); connect(aRemoveCard, SIGNAL(triggered()), this, SLOT(actRemoveCard())); - aRemoveCard->setShortcut(tr("Ctrl+R")); + aRemoveCard->setShortcut(tr("Del")); aIncrement = new QAction(tr("&Increment number"), this); connect(aIncrement, SIGNAL(triggered()), this, SLOT(actIncrement())); aIncrement->setShortcut(tr("+")); @@ -140,7 +140,10 @@ void WndDeckEditor::updateCardInfoLeft(const QModelIndex ¤t, const QModelI void WndDeckEditor::updateCardInfoRight(const QModelIndex ¤t, const QModelIndex &/*previous*/) { - cardInfo->setCard(current.sibling(current.row(), 1).data().toString()); + if (!current.isValid()) + return; + if (!current.model()->hasChildren(current.sibling(current.row(), 0))) + cardInfo->setCard(current.sibling(current.row(), 1).data().toString()); } void WndDeckEditor::updateSearch(const QString &search) @@ -195,7 +198,9 @@ void WndDeckEditor::actLoadDeck() lastFileFormat = l->getLastFileFormat(); nameEdit->setText(l->getName()); commentsEdit->setText(l->getComments()); + deckModel->sort(1); deckView->expandAll(); + deckView->resizeColumnToContents(0); } } @@ -222,41 +227,40 @@ bool WndDeckEditor::actSaveDeckAs() return false; } -void WndDeckEditor::addCardHelper(int baseRow) +void WndDeckEditor::recursiveExpand(const QModelIndex &index) +{ + if (index.parent().isValid()) + recursiveExpand(index.parent()); + deckView->expand(index); +} + +void WndDeckEditor::addCardHelper(const QString &zoneName) { const QModelIndex currentIndex = databaseView->selectionModel()->currentIndex(); if (!currentIndex.isValid()) return; const QString cardName = databaseModel->index(currentIndex.row(), 0).data().toString(); - QModelIndex zoneRoot = deckModel->index(baseRow, 0); - deckView->expand(zoneRoot); - QModelIndexList matches = deckModel->match(deckModel->index(0, 1, zoneRoot), Qt::EditRole, cardName); - if (matches.isEmpty()) { - int row = deckModel->rowCount(zoneRoot); - deckModel->insertRow(row, zoneRoot); - deckModel->setData(deckModel->index(row, 1, zoneRoot), cardName, Qt::EditRole); - } else { - const QModelIndex numberIndex = deckModel->index(matches[0].row(), 0, zoneRoot); - const int count = deckModel->data(numberIndex, Qt::EditRole).toInt(); - deckModel->setData(numberIndex, count + 1, Qt::EditRole); - } + + QModelIndex newCardIndex = deckModel->addCard(cardName, zoneName); + recursiveExpand(newCardIndex); + setWindowModified(true); } void WndDeckEditor::actAddCard() { - addCardHelper(0); + addCardHelper("main"); } void WndDeckEditor::actAddCardToSideboard() { - addCardHelper(1); + addCardHelper("side"); } void WndDeckEditor::actRemoveCard() { - const QModelIndex currentIndex = deckView->selectionModel()->currentIndex(); - if (!currentIndex.isValid()) + const QModelIndex ¤tIndex = deckView->selectionModel()->currentIndex(); + if (!currentIndex.isValid() || deckModel->hasChildren(currentIndex)) return; deckModel->removeRow(currentIndex.row(), currentIndex.parent()); setWindowModified(true); @@ -264,7 +268,7 @@ void WndDeckEditor::actRemoveCard() void WndDeckEditor::actIncrement() { - const QModelIndex currentIndex = deckView->selectionModel()->currentIndex(); + const QModelIndex ¤tIndex = deckView->selectionModel()->currentIndex(); if (!currentIndex.isValid()) return; const QModelIndex numberIndex = currentIndex.sibling(currentIndex.row(), 0); @@ -275,7 +279,7 @@ void WndDeckEditor::actIncrement() void WndDeckEditor::actDecrement() { - const QModelIndex currentIndex = deckView->selectionModel()->currentIndex(); + const QModelIndex ¤tIndex = deckView->selectionModel()->currentIndex(); if (!currentIndex.isValid()) return; const QModelIndex numberIndex = currentIndex.sibling(currentIndex.row(), 0); diff --git a/cockatrice/src/window_deckeditor.h b/cockatrice/src/window_deckeditor.h index ff0775d3..9f15f567 100644 --- a/cockatrice/src/window_deckeditor.h +++ b/cockatrice/src/window_deckeditor.h @@ -31,7 +31,8 @@ private slots: void actIncrement(); void actDecrement(); private: - void addCardHelper(int baseRow); + void addCardHelper(const QString &zoneName); + void recursiveExpand(const QModelIndex &index); bool confirmClose(); QString lastFileName;