diff --git a/cockatrice/src/decklist.cpp b/cockatrice/src/decklist.cpp index 7f1d6e4c..6a59f708 100644 --- a/cockatrice/src/decklist.cpp +++ b/cockatrice/src/decklist.cpp @@ -7,9 +7,20 @@ #include "decklist.h" #include "carddatabase.h" +QString DecklistZone::getVisibleName() const +{ + if (name == "main") + return QObject::tr("Maindeck"); + else if (name == "side") + return QObject::tr("Sideboard"); + else + return QString(); +} + DeckList::DeckList(CardDatabase *_db, QObject *parent) : QObject(parent), db(_db) { + initZones(); } DeckList::~DeckList() @@ -31,15 +42,16 @@ bool DeckList::loadFromFile_Native(QIODevice *device) name = xml.readElementText(); else if (xml.name() == "comments") comments = xml.readElementText(); - else if (xml.name() == "decklist") { + else if (xml.name() == "zone") { + DecklistZone *zone = new DecklistZone(xml.attributes().value("name").toString()); + zones.append(zone); 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(); - const bool sb = xml.attributes().value("zone") == "side"; - append(new DecklistRow(number, card, sb)); + zone->append(new DecklistRow(number, card)); while (!xml.atEnd()) if (xml.readNext() == QXmlStreamReader::EndElement) break; @@ -63,18 +75,17 @@ bool DeckList::saveToFile_Native(QIODevice *device) xml.writeTextElement("deckname", name); xml.writeTextElement("comments", comments); - xml.writeStartElement("decklist"); - for (int i = 0; i < size(); i++) { - DecklistRow *r = at(i); - xml.writeEmptyElement("card"); - if (r->isSideboard()) - xml.writeAttribute("zone", "side"); - else - xml.writeAttribute("zone", "main"); - xml.writeAttribute("number", QString::number(r->getNumber())); - xml.writeAttribute("name", r->getCard()); + 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 } - xml.writeEndElement(); // decklist xml.writeEndElement(); // cockatrice_deck @@ -84,17 +95,20 @@ bool DeckList::saveToFile_Native(QIODevice *device) bool DeckList::loadFromFile_Plain(QIODevice *device) { + initZones(); + QTextStream in(device); while (!in.atEnd()) { QString line = in.readLine().simplified(); if (line.startsWith("//")) continue; - bool isSideboard = false; + DecklistZone *zone; if (line.startsWith("SB:", Qt::CaseInsensitive)) { line = line.mid(3).trimmed(); - isSideboard = true; - } + zone = zones[1]; + } else + zone = zones[0]; // Filter out MWS edition symbols and basic land extras QRegExp rx("\\[.*\\]"); @@ -108,7 +122,7 @@ bool DeckList::loadFromFile_Plain(QIODevice *device) int number = line.left(i).toInt(&ok); if (!ok) continue; - append(new DecklistRow(number, line.mid(i + 1), isSideboard)); + zone->append(new DecklistRow(number, line.mid(i + 1))); } return true; } @@ -116,10 +130,11 @@ bool DeckList::loadFromFile_Plain(QIODevice *device) bool DeckList::saveToFile_Plain(QIODevice *device) { QTextStream out(device); - for (int i = 0; i < size(); i++) { - DecklistRow *r = at(i); - out << QString("%1%2 %3\n").arg(r->isSideboard() ? "SB: " : "").arg(r->getNumber()).arg(r->getCard()); - } + 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; } @@ -212,18 +227,37 @@ bool DeckList::saveDialog(QWidget *parent) void DeckList::cacheCardPictures(QWidget *parent) { - QProgressDialog progress(tr("Caching card pictures..."), QString(), 0, size(), parent); + int totalCards = 0; + for (int i = 0; i < zones.size(); i++) + totalCards += zones[i]->size(); + + QProgressDialog progress(tr("Caching card pictures..."), QString(), 0, totalCards, parent); + progress.setMinimumDuration(1000); progress.setWindowModality(Qt::WindowModal); - for (int i = 0; i < size(); i++) { - db->getCard(at(i)->getCard())->getPixmap(); - progress.setValue(i + 1); - } + 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); + } } void DeckList::cleanList() { - for (int i = 0; i < size(); i++) - delete at(i); - clear(); + 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(); + setName(); + setComments(); +} + +void DeckList::initZones() +{ + // 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 d2efb1ec..99482e96 100644 --- a/cockatrice/src/decklist.h +++ b/cockatrice/src/decklist.h @@ -11,17 +11,24 @@ class DecklistRow { private: int number; QString card; - bool sideboard; public: - DecklistRow(int _number = 1, const QString &_card = QString(), bool _sideboard = false) : number(_number), card(_card), sideboard(_sideboard) { } + 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; } - bool isSideboard() const { return sideboard; } }; -class DeckList : public QObject, public QList { +class DecklistZone : public QList { +private: + QString name; +public: + DecklistZone(const QString &_name) : name(_name) { } + QString getName() const { return name; } + QString getVisibleName() const; +}; + +class DeckList : public QObject { Q_OBJECT public: enum FileFormat { PlainTextFormat, CockatriceFormat }; @@ -32,11 +39,12 @@ private: QString name, comments; QString lastFileName; FileFormat lastFileFormat; + QList zones; signals: void deckLoaded(); public slots: - void setName(const QString &_name) { name = _name; } - void setComments(const QString &_comments) { comments = _comments; } + void setName(const QString &_name = QString()) { name = _name; } + void setComments(const QString &_comments = QString()) { comments = _comments; } public: DeckList(CardDatabase *_db, QObject *parent = 0); ~DeckList(); @@ -55,6 +63,10 @@ public: bool saveDialog(QWidget *parent = 0); void cleanList(); + void initZones(); + + int zoneCount() const { return zones.size(); } + DecklistZone *getZoneByIndex(int index) const { return zones[index]; } }; #endif diff --git a/cockatrice/src/decklistmodel.cpp b/cockatrice/src/decklistmodel.cpp index f9299577..ea9b4ad4 100644 --- a/cockatrice/src/decklistmodel.cpp +++ b/cockatrice/src/decklistmodel.cpp @@ -1,10 +1,12 @@ #include #include +#include +#include #include "decklistmodel.h" #include "carddatabase.h" DeckListModel::DeckListModel(CardDatabase *_db, QObject *parent) - : QAbstractListModel(parent), db(_db) + : QAbstractItemModel(parent), db(_db) { deckList = new DeckList(db, this); connect(deckList, SIGNAL(deckLoaded()), this, SLOT(resetModel())); @@ -19,10 +21,19 @@ void DeckListModel::resetModel() reset(); } -int DeckListModel::rowCount(const QModelIndex &/*parent*/) const +int DeckListModel::rowCount(const QModelIndex &parent) const { -// qDebug(QString("rowCount = %1").arg(deckList->size()).toLatin1()); - return deckList->size(); + 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 + return 0; +} + +bool DeckListModel::hasChildren(const QModelIndex &parent) const +{ + return !parent.parent().isValid(); } int DeckListModel::columnCount(const QModelIndex &/*parent*/) const @@ -32,26 +43,58 @@ int DeckListModel::columnCount(const QModelIndex &/*parent*/) const QVariant DeckListModel::data(const QModelIndex &index, int role) const { -// qDebug(QString("data() called: index.row = %1, column = %2, role = %3").arg(index.row()).arg(index.column()).arg(role).toLatin1()); if (!index.isValid()) return QVariant(); - if ((index.row() >= deckList->size()) || (index.column() >= 2)) + if (index.column() >= 2) return QVariant(); - if ((role != Qt::DisplayRole) && (role != Qt::EditRole)) - return QVariant(); - - DecklistRow *r = deckList->at(index.row()); - switch (index.column()) { - case 0: return r->getNumber(); - case 1: return r->getCard(); - default: return QVariant(); + if (!index.parent().isValid()) { + if (index.row() >= deckList->zoneCount()) + return QVariant(); + switch (role) { + case Qt::FontRole: { + QFont f; + f.setBold(true); + return f; + } + case Qt::DisplayRole: + case Qt::EditRole: { + DecklistZone *zone = deckList->getZoneByIndex(index.row()); + switch (index.column()) { + case 0: return zone->getVisibleName(); + case 1: return QVariant(); + default: return QVariant(); + } + } + case Qt::BackgroundRole: + return QBrush(QColor(200, 255, 200)); + 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()); + switch (index.column()) { + case 0: return r->getNumber(); + case 1: return r->getCard(); + default: return QVariant(); + } + } + case Qt::BackgroundRole: { + int color = 255 - (index.row() % 2) * 30; + return QBrush(QColor(color, color, color)); + } + default: return QVariant(); + } } } QVariant DeckListModel::headerData(int section, Qt::Orientation orientation, int role) const { -// qDebug(QString("headerData() called: section = %1, orientation = %2, role = %3").arg(section).arg(orientation).arg(role).toLatin1()); if (role != Qt::DisplayRole) return QVariant(); if (orientation != Qt::Horizontal) @@ -63,22 +106,43 @@ 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); +} + +QModelIndex DeckListModel::parent(const QModelIndex &ind) const +{ + if ((int) ind.internalId() < 0) + return QModelIndex(); + else + return index(ind.internalId() / 1000000, 0); +} + Qt::ItemFlags DeckListModel::flags(const QModelIndex &index) const { - if (index.column() == 0) - return QAbstractItemModel::flags(index) | Qt::ItemIsEditable; - else - return QAbstractItemModel::flags(index); + Qt::ItemFlags result = Qt::ItemIsEnabled; + if (index.parent().isValid()) { + result |= Qt::ItemIsSelectable; + if (index.column() == 0) + result |= Qt::ItemIsEditable; + } + return result; } bool DeckListModel::setData(const QModelIndex &index, const QVariant &value, int role) { - if (!index.isValid() || role != Qt::EditRole) + if (!index.isValid() || !index.parent().isValid() || role != Qt::EditRole) return false; switch (index.column()) { - case 0: deckList->at(index.row())->setNumber(value.toInt()); break; - case 1: deckList->at(index.row())->setCard(value.toString()); break; + 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; default: return false; } emit dataChanged(index, index); @@ -87,10 +151,14 @@ 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()) + return false; + beginRemoveRows(parent, row, row + count - 1); for (int i = 0; i < count; i++) - deckList->removeAt(row); + deckList->getZoneByIndex(parent.row())->removeAt(row); endRemoveRows(); return true; @@ -98,10 +166,14 @@ bool DeckListModel::removeRows(int row, int count, const QModelIndex &parent) bool DeckListModel::insertRows(int row, int count, const QModelIndex &parent) { + // Inserting zones is not supported. + if (!parent.isValid()) + return false; + beginInsertRows(parent, row, row + count - 1); for (int i = 0; i < count; i++) - deckList->insert(row, new DecklistRow); + deckList->getZoneByIndex(parent.row())->insert(row, new DecklistRow); endInsertRows(); return true; diff --git a/cockatrice/src/decklistmodel.h b/cockatrice/src/decklistmodel.h index 9539ea5c..915af024 100644 --- a/cockatrice/src/decklistmodel.h +++ b/cockatrice/src/decklistmodel.h @@ -1,13 +1,13 @@ #ifndef DECKLISTMODEL_H #define DECKLISTMODEL_H -#include +#include #include #include "decklist.h" class CardDatabase; -class DeckListModel : public QAbstractListModel { +class DeckListModel : public QAbstractItemModel { Q_OBJECT private slots: void resetModel(); @@ -15,9 +15,12 @@ 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; 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; + 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()); diff --git a/cockatrice/src/dlg_startgame.cpp b/cockatrice/src/dlg_startgame.cpp index 1948229b..7e0e4c4b 100644 --- a/cockatrice/src/dlg_startgame.cpp +++ b/cockatrice/src/dlg_startgame.cpp @@ -46,10 +46,13 @@ QStringList DlgStartGame::getDeckList() const { QStringList result; DeckList *deckList = tableModel->getDeckList(); - for (int i = 0; i < deckList->size(); i++) { - DecklistRow *temp = deckList->at(i); - for (int j = 0; j < temp->getNumber(); j++) - result << QString("%1%2").arg(temp->isSideboard() ? "SB:" : "").arg(temp->getCard()); + 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()); + } } return result; } diff --git a/cockatrice/src/window_deckeditor.cpp b/cockatrice/src/window_deckeditor.cpp index 94f76c94..5f463ffa 100644 --- a/cockatrice/src/window_deckeditor.cpp +++ b/cockatrice/src/window_deckeditor.cpp @@ -11,6 +11,7 @@ WndDeckEditor::WndDeckEditor(CardDatabase *_db, QWidget *parent) databaseModel = new CardDatabaseModel(db); databaseView = new QTreeView(); databaseView->setModel(databaseModel); + databaseView->setUniformRowHeights(true); databaseView->setSortingEnabled(true); connect(databaseView->selectionModel(), SIGNAL(currentRowChanged(const QModelIndex &, const QModelIndex &)), this, SLOT(updateCardInfoLeft(const QModelIndex &, const QModelIndex &))); @@ -35,6 +36,8 @@ WndDeckEditor::WndDeckEditor(CardDatabase *_db, QWidget *parent) deckModel = new DeckListModel(db, this); 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:")); @@ -83,9 +86,11 @@ WndDeckEditor::WndDeckEditor(CardDatabase *_db, QWidget *parent) deckMenu->addAction(aSaveDeck); deckMenu->addAction(aSaveDeckAs); - aAddCard = new QAction(tr("&Add card"), this); + aAddCard = new QAction(tr("&Add card to maindeck"), this); connect(aAddCard, SIGNAL(triggered()), this, SLOT(actAddCard())); - aRemoveCard = new QAction(tr("&Remove card"), this); + aAddCardToSideboard = new QAction(tr("&Add card to sideboard"), this); + connect(aAddCardToSideboard, SIGNAL(triggered()), this, SLOT(actAddCardToSideboard())); + aRemoveCard = new QAction(tr("&Remove row"), this); connect(aRemoveCard, SIGNAL(triggered()), this, SLOT(actRemoveCard())); aIncrement = new QAction(tr("&Increment number"), this); connect(aIncrement, SIGNAL(triggered()), this, SLOT(actIncrement())); @@ -93,6 +98,7 @@ WndDeckEditor::WndDeckEditor(CardDatabase *_db, QWidget *parent) connect(aDecrement, SIGNAL(triggered()), this, SLOT(actDecrement())); verticalToolBar->addAction(aAddCard); + verticalToolBar->addAction(aAddCardToSideboard); verticalToolBar->addAction(aRemoveCard); verticalToolBar->addAction(aIncrement); verticalToolBar->addAction(aDecrement); @@ -125,9 +131,9 @@ void WndDeckEditor::actLoadDeck() if (l->loadDialog(this)) { lastFileName = l->getLastFileName(); lastFileFormat = l->getLastFileFormat(); -// deckView->reset(); nameEdit->setText(l->getName()); commentsEdit->setText(l->getComments()); + deckView->expandAll(); } } @@ -149,30 +155,42 @@ void WndDeckEditor::actSaveDeckAs() } } -void WndDeckEditor::actAddCard() +void WndDeckEditor::addCardHelper(int baseRow) { const QModelIndex currentIndex = databaseView->selectionModel()->currentIndex(); if (!currentIndex.isValid()) return; const QString cardName = databaseModel->index(currentIndex.row(), 0).data().toString(); - QModelIndexList matches = deckModel->match(deckModel->index(0, 1), Qt::EditRole, cardName); + 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(); - deckModel->insertRow(row); - deckModel->setData(deckModel->index(row, 1), cardName, Qt::EditRole); + 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); + 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); } } +void WndDeckEditor::actAddCard() +{ + addCardHelper(0); +} + +void WndDeckEditor::actAddCardToSideboard() +{ + addCardHelper(1); +} + void WndDeckEditor::actRemoveCard() { const QModelIndex currentIndex = deckView->selectionModel()->currentIndex(); if (!currentIndex.isValid()) return; - deckModel->removeRow(currentIndex.row()); + deckModel->removeRow(currentIndex.row(), currentIndex.parent()); } void WndDeckEditor::actIncrement() @@ -180,7 +198,7 @@ void WndDeckEditor::actIncrement() const QModelIndex currentIndex = deckView->selectionModel()->currentIndex(); if (!currentIndex.isValid()) return; - const QModelIndex numberIndex = deckModel->index(currentIndex.row(), 0); + const QModelIndex numberIndex = currentIndex.sibling(currentIndex.row(), 0); const int count = deckModel->data(numberIndex, Qt::EditRole).toInt(); deckModel->setData(numberIndex, count + 1, Qt::EditRole); } @@ -190,10 +208,10 @@ void WndDeckEditor::actDecrement() const QModelIndex currentIndex = deckView->selectionModel()->currentIndex(); if (!currentIndex.isValid()) return; - const QModelIndex numberIndex = deckModel->index(currentIndex.row(), 0); + const QModelIndex numberIndex = currentIndex.sibling(currentIndex.row(), 0); const int count = deckModel->data(numberIndex, Qt::EditRole).toInt(); if (count == 1) - deckModel->removeRow(currentIndex.row()); + deckModel->removeRow(currentIndex.row(), currentIndex.parent()); else deckModel->setData(numberIndex, count - 1, Qt::EditRole); } diff --git a/cockatrice/src/window_deckeditor.h b/cockatrice/src/window_deckeditor.h index a0fb0369..162c8806 100644 --- a/cockatrice/src/window_deckeditor.h +++ b/cockatrice/src/window_deckeditor.h @@ -25,10 +25,13 @@ private slots: void actSaveDeckAs(); void actAddCard(); + void actAddCardToSideboard(); void actRemoveCard(); void actIncrement(); void actDecrement(); private: + void addCardHelper(int baseRow); + QString lastFileName; DeckList::FileFormat lastFileFormat; CardDatabase *db; @@ -42,7 +45,7 @@ private: QMenu *deckMenu; QAction *aNewDeck, *aLoadDeck, *aSaveDeck, *aSaveDeckAs; - QAction *aAddCard, *aRemoveCard, *aIncrement, *aDecrement; + QAction *aAddCard, *aAddCardToSideboard, *aRemoveCard, *aIncrement, *aDecrement; public: WndDeckEditor(CardDatabase *_db, QWidget *parent = 0); ~WndDeckEditor();