#ifndef DECKLIST_H #define DECKLIST_H #include #include #include #include #include #include #include // Required on Mac. Forward declaration doesn't work. Don't ask why. #include #include #include class CardDatabase; class QIODevice; class QTextStream; class InnerDecklistNode; #define DECK_ZONE_MAIN "main" #define DECK_ZONE_SIDE "side" #define DECK_ZONE_TOKENS "tokens" class SideboardPlan { private: QString name; 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, Default }; class AbstractDecklistNode { protected: InnerDecklistNode *parent; DeckSortMethod sortMethod; 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: 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: 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) override; void writeElement(QXmlStreamWriter *xml) override; }; 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 { Q_OBJECT private: QString name, comments; QString deckHash; QMap sideboardPlans; InnerDecklistNode *root; void getCardListHelper(InnerDecklistNode *node, QSet &result) const; InnerDecklistNode *getZoneObjFromName(QString zoneName); protected: virtual QString getCardZoneFromName(const 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: 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; } 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); 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