diff --git a/cockatrice/src/carddatabase.cpp b/cockatrice/src/carddatabase.cpp index 647e1693..6dfd50bf 100644 --- a/cockatrice/src/carddatabase.cpp +++ b/cockatrice/src/carddatabase.cpp @@ -28,6 +28,35 @@ CardInfo::~CardInfo() delete pixmap; } +QString CardInfo::getMainCardType() const +{ + QString result = getCardType(); + /* + Legendary Artifact Creature - Golem + Instant // Instant + */ + + int pos; + if ((pos = result.indexOf('-')) != -1) + result.remove(pos, result.length()); + if ((pos = result.indexOf("//")) != -1) + result.remove(pos, result.length()); + result = result.simplified(); + /* + Legendary Artifact Creature + Instant + */ + + if ((pos = result.lastIndexOf(' ')) != -1) + result = result.mid(pos + 1); + /* + Creature + Instant + */ + + return result; +} + void CardInfo::addEdition(const QString &edition) { if (!editions.contains(edition)) diff --git a/cockatrice/src/carddatabase.h b/cockatrice/src/carddatabase.h index d078cdb5..bfa25524 100644 --- a/cockatrice/src/carddatabase.h +++ b/cockatrice/src/carddatabase.h @@ -28,6 +28,7 @@ public: QString getCardType() const { return cardtype; } QString getPowTough() const { return powtough; } QStringList getText() const { return text; } + QString getMainCardType() const; void addEdition(const QString &edition); QPixmap *getPixmap(); void saveToStream(QDataStream &stream); diff --git a/cockatrice/src/decklist.cpp b/cockatrice/src/decklist.cpp index 6a59f708..e50d04d0 100644 --- a/cockatrice/src/decklist.cpp +++ b/cockatrice/src/decklist.cpp @@ -7,7 +7,19 @@ #include "decklist.h" #include "carddatabase.h" -QString DecklistZone::getVisibleName() const +AbstractDecklistNode::AbstractDecklistNode(InnerDecklistNode *_parent) + : parent(_parent) +{ + if (parent) + parent->append(this); +} + +InnerDecklistNode::~InnerDecklistNode() +{ + clearTree(); +} + +QString InnerDecklistNode::getVisibleName() const { if (name == "main") return QObject::tr("Maindeck"); @@ -17,15 +29,35 @@ QString DecklistZone::getVisibleName() const return QString(); } +void InnerDecklistNode::clearTree() +{ + for (int i = 0; i < size(); i++) + delete at(i); +} + +int InnerDecklistNode::recursiveCount() const +{ + int result = 0; + for (int i = 0; i < size(); i++) { + InnerDecklistNode *node = dynamic_cast(at(i)); + if (node) + result += node->recursiveCount(); + else + result += 1; + } + return result; +} + DeckList::DeckList(CardDatabase *_db, QObject *parent) : QObject(parent), db(_db) { + root = new InnerDecklistNode; initZones(); } DeckList::~DeckList() { - cleanList(); + delete root; } bool DeckList::loadFromFile_Native(QIODevice *device) @@ -43,15 +75,14 @@ bool DeckList::loadFromFile_Native(QIODevice *device) else if (xml.name() == "comments") comments = xml.readElementText(); else if (xml.name() == "zone") { - DecklistZone *zone = new DecklistZone(xml.attributes().value("name").toString()); - zones.append(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(); - zone->append(new DecklistRow(number, card)); + new DecklistCardNode(card, number, node); while (!xml.atEnd()) if (xml.readNext() == QXmlStreamReader::EndElement) break; @@ -66,7 +97,7 @@ bool DeckList::loadFromFile_Native(QIODevice *device) bool DeckList::saveToFile_Native(QIODevice *device) { - QXmlStreamWriter xml(device); +/* QXmlStreamWriter xml(device); xml.setAutoFormatting(true); xml.writeStartDocument(); @@ -91,11 +122,11 @@ bool DeckList::saveToFile_Native(QIODevice *device) xml.writeEndDocument(); return true; -} +*/} bool DeckList::loadFromFile_Plain(QIODevice *device) { - initZones(); +/* initZones(); QTextStream in(device); while (!in.atEnd()) { @@ -125,18 +156,18 @@ bool DeckList::loadFromFile_Plain(QIODevice *device) zone->append(new DecklistRow(number, line.mid(i + 1))); } return true; -} +*/} bool DeckList::saveToFile_Plain(QIODevice *device) { - QTextStream out(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()); } return true; -} +*/} bool DeckList::loadFromFile(const QString &fileName, FileFormat fmt, QWidget *parent) { @@ -151,8 +182,8 @@ bool DeckList::loadFromFile(const QString &fileName, FileFormat fmt, QWidget *pa case CockatriceFormat: result = loadFromFile_Native(&file); break; } if (result) { - cacheCardPictures(parent); emit deckLoaded(); + cacheCardPictures(parent); } return result; } @@ -225,39 +256,39 @@ bool DeckList::saveDialog(QWidget *parent) return false; } +void DeckList::cacheCardPicturesHelper(InnerDecklistNode *item, QProgressDialog *progress) +{ + for (int i = 0; i < item->size(); i++) { + DecklistCardNode *node = dynamic_cast(item->at(i)); + if (node) { + db->getCard(node->getName())->getPixmap(); + progress->setValue(progress->value() + 1); + } else + cacheCardPicturesHelper(dynamic_cast(item->at(i)), progress); + } +} + void DeckList::cacheCardPictures(QWidget *parent) { - int totalCards = 0; - for (int i = 0; i < zones.size(); i++) - totalCards += zones[i]->size(); + int totalCards = root->recursiveCount(); QProgressDialog progress(tr("Caching card pictures..."), QString(), 0, totalCards, parent); progress.setMinimumDuration(1000); progress.setWindowModality(Qt::WindowModal); - for (int i = 0; i < zones.size(); i++) - for (int j = 0; j < zones[i]->size(); j++) { - db->getCard(zones[i]->at(j)->getCard())->getPixmap(); - progress.setValue(progress.value() + 1); - } + cacheCardPicturesHelper(root, &progress); } void DeckList::cleanList() { - for (int i = 0; i < zones.size(); i++) { - for (int j = 0; j < zones[i]->size(); j++) - delete zones[i]->at(j); - zones[i]->clear(); - delete zones[i]; - } - zones.clear(); + root->clearTree(); setName(); setComments(); } void DeckList::initZones() { - // possibly Magic specific +/* // possibly Magic specific zones.append(new DecklistZone("main")); zones.append(new DecklistZone("side")); -} +*/} diff --git a/cockatrice/src/decklist.h b/cockatrice/src/decklist.h index 99482e96..73a07c39 100644 --- a/cockatrice/src/decklist.h +++ b/cockatrice/src/decklist.h @@ -6,26 +6,45 @@ class CardDatabase; class QIODevice; +class QProgressDialog; -class DecklistRow { -private: - int number; - QString card; +class InnerDecklistNode; + +class AbstractDecklistNode { +protected: + InnerDecklistNode *parent; public: - DecklistRow(int _number = 1, const QString &_card = QString()) : number(_number), card(_card) { } - int getNumber() const { return number; } - void setNumber(int _number) { number = _number; } - QString getCard() const { return card; } - void setCard(const QString &_card) { card = _card; } + AbstractDecklistNode(InnerDecklistNode *_parent = 0); + virtual bool hasChildren() const = 0; + virtual QString getName() const = 0; + const InnerDecklistNode *getParent() const { return parent; } }; -class DecklistZone : public QList { +class InnerDecklistNode : public AbstractDecklistNode, public QList { private: QString name; public: - DecklistZone(const QString &_name) : name(_name) { } + InnerDecklistNode(const QString &_name = QString(), InnerDecklistNode *_parent = 0) : AbstractDecklistNode(_parent), name(_name) { } + ~InnerDecklistNode(); + bool hasChildren() const { return true; } QString getName() const { return name; } - QString getVisibleName() const; + void setName(const QString &_name) { name = _name; } + virtual QString getVisibleName() const; + void clearTree(); + int recursiveCount() const; +}; + +class DecklistCardNode : public AbstractDecklistNode { +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; } + int getNumber() const { return number; } + void setNumber(int _number) { number = _number; } + QString getName() const { return name; } + void setName(const QString &_name) { name = _name; } }; class DeckList : public QObject { @@ -39,7 +58,8 @@ private: QString name, comments; QString lastFileName; FileFormat lastFileFormat; - QList zones; + InnerDecklistNode *root; + void cacheCardPicturesHelper(InnerDecklistNode *item, QProgressDialog *progress); signals: void deckLoaded(); public slots: @@ -65,8 +85,7 @@ public: void cleanList(); void initZones(); - int zoneCount() const { return zones.size(); } - DecklistZone *getZoneByIndex(int index) const { return zones[index]; } + InnerDecklistNode *getRoot() const { return root; } }; #endif diff --git a/cockatrice/src/decklistmodel.cpp b/cockatrice/src/decklistmodel.cpp index 164868da..b69915da 100644 --- a/cockatrice/src/decklistmodel.cpp +++ b/cockatrice/src/decklistmodel.cpp @@ -9,31 +9,116 @@ DeckListModel::DeckListModel(CardDatabase *_db, QObject *parent) : QAbstractItemModel(parent), db(_db) { deckList = new DeckList(db, this); - connect(deckList, SIGNAL(deckLoaded()), this, SLOT(resetModel())); + connect(deckList, SIGNAL(deckLoaded()), this, SLOT(rebuildTree())); + root = new InnerDecklistNode; } DeckListModel::~DeckListModel() { } -void DeckListModel::resetModel() +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()); +} + +void DeckListModel::debugShowTree(InnerDecklistNode *node, int depth) const +{ + for (int i = 0; i < node->size(); i++) { + DecklistModelCardNode *foo = dynamic_cast(node->at(i)); + if (!foo) { + InnerDecklistNode *bar = dynamic_cast(node->at(i)); + qDebug(QString("%1%2").arg(QString(depth * 4, ' ')).arg(bar->getName()).toLatin1()); + debugShowTree(bar, depth + 1); + } else + qDebug(QString("%1%2 %3").arg(QString(depth * 4, ' ')).arg(foo->getNumber()).arg(foo->getName()).toLatin1()); + } +} + +void DeckListModel::rebuildTree() +{ + 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)); + + QString cardType = db->getCard(currentCard->getName())->getMainCardType(); + InnerDecklistNode *cardTypeNode = dynamic_cast(findNode(cardType, node)); + if (!cardTypeNode) + cardTypeNode = new InnerDecklistNode(cardType, node); + + DecklistModelCardNode *newCard = 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 { - if (!parent.isValid()) // parent = root - return deckList->zoneCount(); - else if (!parent.parent().isValid()) // parent = zone root - return deckList->getZoneByIndex(parent.row())->size(); - else // parent = card +// debugIndexInfo("rowCount", parent); + InnerDecklistNode *node = dynamic_cast(findNode(parent)); + if (node) { +// qDebug(QString(" rowCount: return %1").arg(node->size()).toLatin1()); + return node->size(); + } else { +// qDebug(" rowCount: return const 0"); return 0; + } } bool DeckListModel::hasChildren(const QModelIndex &parent) const { - return !parent.parent().isValid(); +// 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 @@ -43,14 +128,17 @@ int DeckListModel::columnCount(const QModelIndex &/*parent*/) const QVariant DeckListModel::data(const QModelIndex &index, int role) const { +// debugIndexInfo("data", index); if (!index.isValid()) return QVariant(); if (index.column() >= 2) return QVariant(); - if (!index.parent().isValid()) { - if (index.row() >= deckList->zoneCount()) - return QVariant(); + AbstractDecklistNode *tempNode = findNode(index); + if (tempNode == root) + return QVariant(); + + if (tempNode->hasChildren()) { switch (role) { case Qt::FontRole: { QFont f; @@ -59,10 +147,11 @@ QVariant DeckListModel::data(const QModelIndex &index, int role) const } case Qt::DisplayRole: case Qt::EditRole: { - DecklistZone *zone = deckList->getZoneByIndex(index.row()); switch (index.column()) { - case 0: return zone->getVisibleName(); - case 1: return QVariant(); + case 0: { + InnerDecklistNode *node = dynamic_cast(tempNode); + return node->getVisibleName(); + } default: return QVariant(); } } @@ -71,16 +160,13 @@ QVariant DeckListModel::data(const QModelIndex &index, int role) const default: return QVariant(); } } else { - DecklistZone *zone = deckList->getZoneByIndex(index.parent().row()); - if (index.row() >= zone->size()) - return QVariant(); switch (role) { case Qt::DisplayRole: case Qt::EditRole: { - DecklistRow *r = zone->at(index.row()); + DecklistModelCardNode *node = dynamic_cast(tempNode); switch (index.column()) { - case 0: return r->getNumber(); - case 1: return r->getCard(); + case 0: return node->getNumber(); + case 1: return node->getName(); default: return QVariant(); } } @@ -108,26 +194,53 @@ QVariant DeckListModel::headerData(int section, Qt::Orientation orientation, int QModelIndex DeckListModel::index(int row, int column, const QModelIndex &parent) const { - int id; - if (!parent.isValid()) - id = -((row + 1) * 1000 + column); - else - id = parent.row() * 1000000 + row * 1000 + column; - return createIndex(row, column, id); +// 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 (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); } QModelIndex DeckListModel::parent(const QModelIndex &ind) const { - if ((int) ind.internalId() < 0) +// 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) return QModelIndex(); + else if (card == 0x3fffff) + return index(zone, 0); else - return index(ind.internalId() / 1000000, 0); + return index(cardtype, 0, index(zone, 0)); } Qt::ItemFlags DeckListModel::flags(const QModelIndex &index) const { Qt::ItemFlags result = Qt::ItemIsEnabled; - if (index.parent().isValid()) { + if (((index.internalId() >> 3) & 0x3fffff) != 0x3fffff) { result |= Qt::ItemIsSelectable; if (index.column() == 0) result |= Qt::ItemIsEditable; @@ -137,12 +250,13 @@ Qt::ItemFlags DeckListModel::flags(const QModelIndex &index) const bool DeckListModel::setData(const QModelIndex &index, const QVariant &value, int role) { - if (!index.isValid() || !index.parent().isValid() || role != Qt::EditRole) + DecklistModelCardNode *node = dynamic_cast(findNode(index)); + if (!node || (role != Qt::EditRole)) return false; switch (index.column()) { - case 0: deckList->getZoneByIndex(index.parent().row())->at(index.row())->setNumber(value.toInt()); break; - case 1: deckList->getZoneByIndex(index.parent().row())->at(index.row())->setCard(value.toString()); break; + case 0: node->setNumber(value.toInt()); break; + case 1: node->setName(value.toString()); break; default: return false; } emit dataChanged(index, index); @@ -151,21 +265,30 @@ bool DeckListModel::setData(const QModelIndex &index, const QVariant &value, int bool DeckListModel::removeRows(int row, int count, const QModelIndex &parent) { - // Inserting zones is not supported. - if (!parent.isValid()) +/* DecklistNode *node = findNode(parent); + if (row + count > node->size()) return false; beginRemoveRows(parent, row, row + count - 1); for (int i = 0; i < count; i++) - deckList->getZoneByIndex(parent.row())->removeAt(row); + delete node->takeAt(row); endRemoveRows(); return true; +*/} +/* +void DeckListModel::insertCard(...) +{ } +void DeckListModel::removeCard(...) +{ +} +*/ bool DeckListModel::insertRows(int row, int count, const QModelIndex &parent) { +/* // Inserting zones is not supported. if (!parent.isValid()) return false; @@ -177,7 +300,7 @@ bool DeckListModel::insertRows(int row, int count, const QModelIndex &parent) endInsertRows(); return true; -} +*/} void DeckListModel::cleanList() { diff --git a/cockatrice/src/decklistmodel.h b/cockatrice/src/decklistmodel.h index 915af024..323e36a4 100644 --- a/cockatrice/src/decklistmodel.h +++ b/cockatrice/src/decklistmodel.h @@ -7,10 +7,22 @@ class CardDatabase; +class DecklistModelCardNode : public AbstractDecklistNode { +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); } +}; + class DeckListModel : public QAbstractItemModel { Q_OBJECT private slots: - void resetModel(); + void rebuildTree(); public: DeckListModel(CardDatabase *_db, QObject *parent = 0); ~DeckListModel(); @@ -27,11 +39,14 @@ public: bool insertRows(int row, int count, const QModelIndex &parent = QModelIndex()); void cleanList(); DeckList *getDeckList() const { return deckList; } - bool loadFromFile(const QString &fileName, DeckList::FileFormat fmt); - bool saveToFile(const QString &fileName, DeckList::FileFormat fmt); private: CardDatabase *db; DeckList *deckList; + InnerDecklistNode *root; + AbstractDecklistNode *findNode(const QString &name, InnerDecklistNode *root) const; + AbstractDecklistNode *findNode(const QModelIndex &index) const; + void debugIndexInfo(const QString &func, const QModelIndex &index) const; + void debugShowTree(InnerDecklistNode *node, int depth) const; }; #endif diff --git a/cockatrice/src/dlg_startgame.cpp b/cockatrice/src/dlg_startgame.cpp index 7e0e4c4b..290db923 100644 --- a/cockatrice/src/dlg_startgame.cpp +++ b/cockatrice/src/dlg_startgame.cpp @@ -45,7 +45,7 @@ void DlgStartGame::actLoad() QStringList DlgStartGame::getDeckList() const { QStringList result; - DeckList *deckList = tableModel->getDeckList(); +/* 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++) { @@ -54,5 +54,5 @@ QStringList DlgStartGame::getDeckList() const result << QString("%1%2").arg(zone->getName() == "side" ? "SB:" : "").arg(r->getCard()); } } - return result; +*/ return result; } diff --git a/cockatrice/src/window_deckeditor.cpp b/cockatrice/src/window_deckeditor.cpp index 15c2ff1e..599234d7 100644 --- a/cockatrice/src/window_deckeditor.cpp +++ b/cockatrice/src/window_deckeditor.cpp @@ -91,7 +91,7 @@ WndDeckEditor::WndDeckEditor(CardDatabase *_db, QWidget *parent) aSaveDeck->setShortcuts(QKeySequence::Save); connect(aSaveDeck, SIGNAL(triggered()), this, SLOT(actSaveDeck())); aSaveDeckAs = new QAction(tr("&Save deck as..."), this); - aSaveDeckAs->setShortcuts(QKeySequence::SaveAs); +// aSaveDeckAs->setShortcuts(QKeySequence::SaveAs); connect(aSaveDeckAs, SIGNAL(triggered()), this, SLOT(actSaveDeckAs())); aClose = new QAction(tr("&Close"), this); aClose->setShortcut(tr("Ctrl+Q"));