diff --git a/Doxyfile b/Doxyfile index 5b125ef13..a1861f64f 100644 --- a/Doxyfile +++ b/Doxyfile @@ -991,7 +991,7 @@ WARN_LOGFILE = # spaces. See also FILE_PATTERNS and EXTENSION_MAPPING # Note: If this tag is empty the current directory is searched. -INPUT = cockatrice doc/doxygen-groups libcockatrice_card libcockatrice_deck_list libcockatrice_filters libcockatrice_interfaces libcockatrice_models libcockatrice_network libcockatrice_protocol libcockatrice_rng libcockatrice_settings libcockatrice_utility +INPUT = cockatrice doc/doxygen-extra-pages doc/doxygen-groups libcockatrice_card libcockatrice_deck_list libcockatrice_filters libcockatrice_interfaces libcockatrice_models libcockatrice_network libcockatrice_protocol libcockatrice_rng libcockatrice_settings libcockatrice_utility # This tag can be used to specify the character encoding of the source files # that Doxygen parses. Internally Doxygen uses the UTF-8 encoding. Doxygen uses @@ -1145,7 +1145,7 @@ EXAMPLE_RECURSIVE = NO # that contain images that are to be included in the documentation (see the # \image command). -IMAGE_PATH = +IMAGE_PATH = doc/doxygen-images # The INPUT_FILTER tag can be used to specify a program that Doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program diff --git a/cockatrice/src/client/network/update/client/release_channel.h b/cockatrice/src/client/network/update/client/release_channel.h index 74568c146..93e6b985d 100644 --- a/cockatrice/src/client/network/update/client/release_channel.h +++ b/cockatrice/src/client/network/update/client/release_channel.h @@ -57,27 +57,27 @@ protected: } public: - QString getName() const + [[nodiscard]] QString getName() const { return name; } - QString getDescriptionUrl() const + [[nodiscard]] QString getDescriptionUrl() const { return descriptionUrl; } - QString getDownloadUrl() const + [[nodiscard]] QString getDownloadUrl() const { return downloadUrl; } - QString getCommitHash() const + [[nodiscard]] QString getCommitHash() const { return commitHash; } - QDate getPublishDate() const + [[nodiscard]] QDate getPublishDate() const { return publishDate; } - bool isCompatibleVersionFound() const + [[nodiscard]] bool isCompatibleVersionFound() const { return compatibleVersionFound; } @@ -97,15 +97,15 @@ protected: protected: static bool downloadMatchesCurrentOS(const QString &fileName); - virtual QString getReleaseChannelUrl() const = 0; + [[nodiscard]] virtual QString getReleaseChannelUrl() const = 0; public: Release *getLastRelease() { return lastRelease; } - virtual QString getManualDownloadUrl() const = 0; - virtual QString getName() const = 0; + [[nodiscard]] virtual QString getManualDownloadUrl() const = 0; + [[nodiscard]] virtual QString getName() const = 0; void checkForUpdates(); signals: void finishedCheck(bool needToUpdate, bool isCompatible, Release *release); @@ -122,12 +122,12 @@ public: explicit StableReleaseChannel() = default; ~StableReleaseChannel() override = default; - QString getManualDownloadUrl() const override; + [[nodiscard]] QString getManualDownloadUrl() const override; - QString getName() const override; + [[nodiscard]] QString getName() const override; protected: - QString getReleaseChannelUrl() const override; + [[nodiscard]] QString getReleaseChannelUrl() const override; protected slots: void releaseListFinished() override; @@ -143,12 +143,12 @@ public: BetaReleaseChannel() = default; ~BetaReleaseChannel() override = default; - QString getManualDownloadUrl() const override; + [[nodiscard]] QString getManualDownloadUrl() const override; - QString getName() const override; + [[nodiscard]] QString getName() const override; protected: - QString getReleaseChannelUrl() const override; + [[nodiscard]] QString getReleaseChannelUrl() const override; protected slots: void releaseListFinished() override; diff --git a/cockatrice/src/client/settings/card_counter_settings.cpp b/cockatrice/src/client/settings/card_counter_settings.cpp index d22eb239f..71ce4cfc6 100644 --- a/cockatrice/src/client/settings/card_counter_settings.cpp +++ b/cockatrice/src/client/settings/card_counter_settings.cpp @@ -5,7 +5,7 @@ #include CardCounterSettings::CardCounterSettings(const QString &settingsPath, QObject *parent) - : SettingsManager(settingsPath + "global.ini", parent) + : SettingsManager(settingsPath + "global.ini", "cards", "counters", parent) { } diff --git a/cockatrice/src/game/board/abstract_card_drag_item.h b/cockatrice/src/game/board/abstract_card_drag_item.h index 64e329474..1d741eded 100644 --- a/cockatrice/src/game/board/abstract_card_drag_item.h +++ b/cockatrice/src/game/board/abstract_card_drag_item.h @@ -27,22 +27,22 @@ public: { Type = typeCardDrag }; - int type() const override + [[nodiscard]] int type() const override { return Type; } AbstractCardDragItem(AbstractCardItem *_item, const QPointF &_hotSpot, AbstractCardDragItem *parentDrag = 0); - QRectF boundingRect() const override + [[nodiscard]] QRectF boundingRect() const override { return QRectF(0, 0, CARD_WIDTH, CARD_HEIGHT); } - QPainterPath shape() const override; + [[nodiscard]] QPainterPath shape() const override; void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override; - AbstractCardItem *getItem() const + [[nodiscard]] AbstractCardItem *getItem() const { return item; } - QPointF getHotSpot() const + [[nodiscard]] QPointF getHotSpot() const { return hotSpot; } diff --git a/cockatrice/src/game/board/abstract_counter.cpp b/cockatrice/src/game/board/abstract_counter.cpp index 8ca593ace..985c78ad2 100644 --- a/cockatrice/src/game/board/abstract_counter.cpp +++ b/cockatrice/src/game/board/abstract_counter.cpp @@ -85,9 +85,13 @@ void AbstractCounter::retranslateUi() void AbstractCounter::setShortcutsActive() { + if (!menu) { + return; + } if (!player->getPlayerInfo()->getLocal()) { return; } + ShortcutsSettings &shortcuts = SettingsCache::instance().shortcuts(); if (name == "life") { shortcutActive = true; @@ -104,6 +108,10 @@ void AbstractCounter::setShortcutsActive() void AbstractCounter::setShortcutsInactive() { + if (!menu) { + return; + } + shortcutActive = false; if (name == "life" || useNameForShortcut) { aSet->setShortcut(QKeySequence()); diff --git a/cockatrice/src/game/board/arrow_item.h b/cockatrice/src/game/board/arrow_item.h index 6015123e1..8405083fe 100644 --- a/cockatrice/src/game/board/arrow_item.h +++ b/cockatrice/src/game/board/arrow_item.h @@ -36,22 +36,22 @@ public: ArrowItem(Player *_player, int _id, ArrowTarget *_startItem, ArrowTarget *_targetItem, const QColor &color); ~ArrowItem() override; void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override; - QRectF boundingRect() const override + [[nodiscard]] QRectF boundingRect() const override { return path.boundingRect(); } - QPainterPath shape() const override + [[nodiscard]] QPainterPath shape() const override { return path; } void updatePath(); void updatePath(const QPointF &endPoint); - int getId() const + [[nodiscard]] int getId() const { return id; } - Player *getPlayer() const + [[nodiscard]] Player *getPlayer() const { return player; } @@ -63,11 +63,11 @@ public: { targetItem = _item; } - ArrowTarget *getStartItem() const + [[nodiscard]] ArrowTarget *getStartItem() const { return startItem; } - ArrowTarget *getTargetItem() const + [[nodiscard]] ArrowTarget *getTargetItem() const { return targetItem; } diff --git a/cockatrice/src/game/board/arrow_target.h b/cockatrice/src/game/board/arrow_target.h index d2f0a6a32..8cc5d55dc 100644 --- a/cockatrice/src/game/board/arrow_target.h +++ b/cockatrice/src/game/board/arrow_target.h @@ -28,18 +28,18 @@ public: explicit ArrowTarget(Player *_owner, QGraphicsItem *parent = nullptr); ~ArrowTarget() override; - Player *getOwner() const + [[nodiscard]] Player *getOwner() const { return owner; } void setBeingPointedAt(bool _beingPointedAt); - bool getBeingPointedAt() const + [[nodiscard]] bool getBeingPointedAt() const { return beingPointedAt; } - const QList &getArrowsFrom() const + [[nodiscard]] const QList &getArrowsFrom() const { return arrowsFrom; } @@ -51,7 +51,7 @@ public: { arrowsFrom.removeOne(arrow); } - const QList &getArrowsTo() const + [[nodiscard]] const QList &getArrowsTo() const { return arrowsTo; } diff --git a/cockatrice/src/game/board/card_item.h b/cockatrice/src/game/board/card_item.h index dcaf33520..86c4fe594 100644 --- a/cockatrice/src/game/board/card_item.h +++ b/cockatrice/src/game/board/card_item.h @@ -51,7 +51,7 @@ public: { Type = typeCard }; - int type() const override + [[nodiscard]] int type() const override { return Type; } @@ -62,13 +62,13 @@ public: CardZoneLogic *_zone = nullptr); void retranslateUi(); - CardZoneLogic *getZone() const + [[nodiscard]] CardZoneLogic *getZone() const { return zone; } void setZone(CardZoneLogic *_zone); void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override; - QPoint getGridPoint() const + [[nodiscard]] QPoint getGridPoint() const { return gridPoint; } @@ -76,11 +76,11 @@ public: { gridPoint = _gridPoint; } - QPoint getGridPos() const + [[nodiscard]] QPoint getGridPos() const { return gridPoint; } - Player *getOwner() const + [[nodiscard]] Player *getOwner() const { return owner; } @@ -88,32 +88,32 @@ public: { owner = _owner; } - bool getAttacking() const + [[nodiscard]] bool getAttacking() const { return attacking; } void setAttacking(bool _attacking); - const QMap &getCounters() const + [[nodiscard]] const QMap &getCounters() const { return counters; } void setCounter(int _id, int _value); - QString getAnnotation() const + [[nodiscard]] QString getAnnotation() const { return annotation; } void setAnnotation(const QString &_annotation); - bool getDoesntUntap() const + [[nodiscard]] bool getDoesntUntap() const { return doesntUntap; } void setDoesntUntap(bool _doesntUntap); - QString getPT() const + [[nodiscard]] QString getPT() const { return pt; } void setPT(const QString &_pt); - bool getDestroyOnZoneChange() const + [[nodiscard]] bool getDestroyOnZoneChange() const { return destroyOnZoneChange; } @@ -121,7 +121,7 @@ public: { destroyOnZoneChange = _destroy; } - CardItem *getAttachedTo() const + [[nodiscard]] CardItem *getAttachedTo() const { return attachedTo; } @@ -134,7 +134,7 @@ public: { attachedCards.removeOne(card); } - const QList &getAttachedCards() const + [[nodiscard]] const QList &getAttachedCards() const { return attachedCards; } diff --git a/cockatrice/src/game/deckview/deck_view.cpp b/cockatrice/src/game/deckview/deck_view.cpp index 6c5e51fc4..48c906100 100644 --- a/cockatrice/src/game/deckview/deck_view.cpp +++ b/cockatrice/src/game/deckview/deck_view.cpp @@ -41,8 +41,8 @@ void DeckViewCardDragItem::updatePosition(const QPointF &cursorScenePos) void DeckViewCardDragItem::handleDrop(DeckViewCardContainer *target) { - DeckViewCard *card = static_cast(item); - DeckViewCardContainer *start = static_cast(item->parentItem()); + auto *card = static_cast(item); + auto *start = static_cast(item->parentItem()); start->removeCard(card); target->addCard(card); card->setParentItem(target); @@ -51,13 +51,13 @@ void DeckViewCardDragItem::handleDrop(DeckViewCardContainer *target) void DeckViewCardDragItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) { setCursor(Qt::OpenHandCursor); - DeckViewScene *sc = static_cast(scene()); + auto *sc = static_cast(scene()); sc->removeItem(this); if (currentZone) { handleDrop(currentZone); for (int i = 0; i < childDrags.size(); i++) { - DeckViewCardDragItem *c = static_cast(childDrags[i]); + auto *c = static_cast(childDrags[i]); c->handleDrop(currentZone); sc->removeItem(c); } @@ -118,12 +118,12 @@ void DeckViewCard::mouseMoveEvent(QGraphicsSceneMouseEvent *event) QList sel = scene()->selectedItems(); int j = 0; for (int i = 0; i < sel.size(); i++) { - DeckViewCard *c = static_cast(sel.at(i)); + auto *c = static_cast(sel.at(i)); if (c == this) continue; ++j; - QPointF childPos = QPointF(j * CARD_WIDTH / 2, 0); - DeckViewCardDragItem *drag = new DeckViewCardDragItem(c, childPos, dragItem); + auto childPos = QPointF(j * CARD_WIDTH / 2, 0); + auto *drag = new DeckViewCardDragItem(c, childPos, dragItem); drag->setPos(dragItem->pos() + childPos); scene()->addItem(drag); } @@ -140,8 +140,8 @@ void DeckView::mouseDoubleClickEvent(QMouseEvent *event) QList sel = scene()->selectedItems(); for (int i = 0; i < sel.size(); i++) { - DeckViewCard *c = static_cast(sel.at(i)); - DeckViewCardContainer *zone = static_cast(c->parentItem()); + auto *c = static_cast(sel.at(i)); + auto *zone = static_cast(c->parentItem()); MoveCard_ToZone m; m.set_card_name(c->getName().toStdString()); m.set_start_zone(zone->getName().toStdString()); @@ -345,7 +345,7 @@ void DeckViewScene::rebuildTree() InnerDecklistNode *listRoot = deck->getRoot(); for (int i = 0; i < listRoot->size(); i++) { - InnerDecklistNode *currentZone = dynamic_cast(listRoot->at(i)); + auto *currentZone = dynamic_cast(listRoot->at(i)); DeckViewCardContainer *container = cardContainers.value(currentZone->getName(), 0); if (!container) { @@ -355,12 +355,12 @@ void DeckViewScene::rebuildTree() } for (int j = 0; j < currentZone->size(); j++) { - DecklistCardNode *currentCard = dynamic_cast(currentZone->at(j)); + auto *currentCard = dynamic_cast(currentZone->at(j)); if (!currentCard) continue; for (int k = 0; k < currentCard->getNumber(); ++k) { - DeckViewCard *newCard = new DeckViewCard(container, currentCard->toCardRef(), currentZone->getName()); + auto *newCard = new DeckViewCard(container, currentCard->toCardRef(), currentZone->getName()); container->addCard(newCard); emit newCardAdded(newCard); } diff --git a/cockatrice/src/game/deckview/deck_view.h b/cockatrice/src/game/deckview/deck_view.h index 7d01d5670..027d0fafd 100644 --- a/cockatrice/src/game/deckview/deck_view.h +++ b/cockatrice/src/game/deckview/deck_view.h @@ -35,7 +35,7 @@ public: const QString &_originZone = QString()); ~DeckViewCard() override; void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override; - const QString &getOriginZone() const + [[nodiscard]] const QString &getOriginZone() const { return originZone; } @@ -71,34 +71,34 @@ private: QMultiMap cardsByType; QList> currentRowsAndCols; qreal width, height; - int getCardTypeTextWidth() const; + [[nodiscard]] int getCardTypeTextWidth() const; public: enum { Type = typeDeckViewCardContainer }; - int type() const override + [[nodiscard]] int type() const override { return Type; } explicit DeckViewCardContainer(const QString &_name); - QRectF boundingRect() const override; + [[nodiscard]] QRectF boundingRect() const override; void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override; void addCard(DeckViewCard *card); void removeCard(DeckViewCard *card); - const QList &getCards() const + [[nodiscard]] const QList &getCards() const { return cards; } - const QString &getName() const + [[nodiscard]] const QString &getName() const { return name; } void setWidth(qreal _width); - QList> getRowsAndCols() const; - QSizeF calculateBoundingRect(const QList> &rowsAndCols) const; + [[nodiscard]] QList> getRowsAndCols() const; + [[nodiscard]] QSizeF calculateBoundingRect(const QList> &rowsAndCols) const; void rearrangeItems(const QList> &rowsAndCols); }; @@ -123,7 +123,7 @@ public: { locked = _locked; } - bool getLocked() const + [[nodiscard]] bool getLocked() const { return locked; } @@ -135,7 +135,7 @@ public: } void rearrangeItems(); void updateContents(); - QList getSideboardPlan() const; + [[nodiscard]] QList getSideboardPlan() const; void resetSideboardPlan(); void applySideboardPlan(const QList &plan); }; @@ -162,7 +162,7 @@ public: { deckViewScene->setLocked(_locked); } - QList getSideboardPlan() const + [[nodiscard]] QList getSideboardPlan() const { return deckViewScene->getSideboardPlan(); } diff --git a/cockatrice/src/game/deckview/deck_view_container.h b/cockatrice/src/game/deckview/deck_view_container.h index b764a6db3..620929789 100644 --- a/cockatrice/src/game/deckview/deck_view_container.h +++ b/cockatrice/src/game/deckview/deck_view_container.h @@ -32,7 +32,7 @@ signals: public: explicit ToggleButton(QWidget *parent = nullptr); - bool getState() const + [[nodiscard]] bool getState() const { return state; } diff --git a/cockatrice/src/game/dialogs/dlg_create_token.cpp b/cockatrice/src/game/dialogs/dlg_create_token.cpp index 7cafc3219..6594e339d 100644 --- a/cockatrice/src/game/dialogs/dlg_create_token.cpp +++ b/cockatrice/src/game/dialogs/dlg_create_token.cpp @@ -67,7 +67,7 @@ DlgCreateToken::DlgCreateToken(const QStringList &_predefinedTokens, QWidget *pa faceDownCheckBox = new QCheckBox(tr("Create face-down (Only hides name)")); connect(faceDownCheckBox, &QCheckBox::toggled, this, &DlgCreateToken::faceDownCheckBoxToggled); - QGridLayout *grid = new QGridLayout; + auto *grid = new QGridLayout; grid->addWidget(nameLabel, 0, 0); grid->addWidget(nameEdit, 0, 1); grid->addWidget(colorLabel, 1, 0); @@ -79,7 +79,7 @@ DlgCreateToken::DlgCreateToken(const QStringList &_predefinedTokens, QWidget *pa grid->addWidget(destroyCheckBox, 4, 0, 1, 2); grid->addWidget(faceDownCheckBox, 5, 0, 1, 2); - QGroupBox *tokenDataGroupBox = new QGroupBox(tr("Token data")); + auto *tokenDataGroupBox = new QGroupBox(tr("Token data")); tokenDataGroupBox->setLayout(grid); cardDatabaseModel = new CardDatabaseModel(CardDatabaseManager::getInstance(), false, this); @@ -125,25 +125,25 @@ DlgCreateToken::DlgCreateToken(const QStringList &_predefinedTokens, QWidget *pa #endif } - QVBoxLayout *tokenChooseLayout = new QVBoxLayout; + auto *tokenChooseLayout = new QVBoxLayout; tokenChooseLayout->addWidget(chooseTokenFromAllRadioButton); tokenChooseLayout->addWidget(chooseTokenFromDeckRadioButton); tokenChooseLayout->addWidget(chooseTokenView); - QGroupBox *tokenChooseGroupBox = new QGroupBox(tr("Choose token from list")); + auto *tokenChooseGroupBox = new QGroupBox(tr("Choose token from list")); tokenChooseGroupBox->setLayout(tokenChooseLayout); - QGridLayout *hbox = new QGridLayout; + auto *hbox = new QGridLayout; hbox->addWidget(pic, 0, 0, 1, 1); hbox->addWidget(tokenDataGroupBox, 1, 0, 1, 1); hbox->addWidget(tokenChooseGroupBox, 0, 1, 2, 1); hbox->setColumnStretch(1, 1); - QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); + auto *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); connect(buttonBox, &QDialogButtonBox::accepted, this, &DlgCreateToken::actOk); connect(buttonBox, &QDialogButtonBox::rejected, this, &DlgCreateToken::actReject); - QVBoxLayout *mainLayout = new QVBoxLayout; + auto *mainLayout = new QVBoxLayout; mainLayout->addLayout(hbox); mainLayout->addWidget(buttonBox); setLayout(mainLayout); diff --git a/cockatrice/src/game/dialogs/dlg_create_token.h b/cockatrice/src/game/dialogs/dlg_create_token.h index a777f6b97..8235aa4cc 100644 --- a/cockatrice/src/game/dialogs/dlg_create_token.h +++ b/cockatrice/src/game/dialogs/dlg_create_token.h @@ -39,7 +39,7 @@ class DlgCreateToken : public QDialog Q_OBJECT public: explicit DlgCreateToken(const QStringList &_predefinedTokens, QWidget *parent = nullptr); - TokenInfo getTokenInfo() const; + [[nodiscard]] TokenInfo getTokenInfo() const; protected: void closeEvent(QCloseEvent *event) override; diff --git a/cockatrice/src/game/dialogs/dlg_move_top_cards_until.h b/cockatrice/src/game/dialogs/dlg_move_top_cards_until.h index 00d437bcc..9a9dc91e7 100644 --- a/cockatrice/src/game/dialogs/dlg_move_top_cards_until.h +++ b/cockatrice/src/game/dialogs/dlg_move_top_cards_until.h @@ -34,10 +34,10 @@ public: QStringList exprs = QStringList(), uint numberOfHits = 1, bool autoPlay = false); - QString getExpr() const; - QStringList getExprs() const; - uint getNumberOfHits() const; - bool isAutoPlay() const; + [[nodiscard]] QString getExpr() const; + [[nodiscard]] QStringList getExprs() const; + [[nodiscard]] uint getNumberOfHits() const; + [[nodiscard]] bool isAutoPlay() const; }; #endif // DLG_MOVE_TOP_CARDS_UNTIL_H diff --git a/cockatrice/src/game/phases_toolbar.h b/cockatrice/src/game/phases_toolbar.h index 83290205d..57ab6de66 100644 --- a/cockatrice/src/game/phases_toolbar.h +++ b/cockatrice/src/game/phases_toolbar.h @@ -45,10 +45,10 @@ public: QGraphicsItem *parent = nullptr, QAction *_doubleClickAction = nullptr, bool _highlightable = true); - QRectF boundingRect() const override; + [[nodiscard]] QRectF boundingRect() const override; void setWidth(double _width); void setActive(bool _active); - bool getActive() const + [[nodiscard]] bool getActive() const { return active; } @@ -77,18 +77,18 @@ private: public: explicit PhasesToolbar(QGraphicsItem *parent = nullptr); - QRectF boundingRect() const override; + [[nodiscard]] QRectF boundingRect() const override; void retranslateUi(); void setHeight(double _height); - double getWidth() const + [[nodiscard]] double getWidth() const { return width; } - int phaseCount() const + [[nodiscard]] int phaseCount() const { return buttonList.size(); } - QString getLongPhaseName(int phase) const; + [[nodiscard]] QString getLongPhaseName(int phase) const; public slots: void setActivePhase(int phase); void triggerPhaseAction(int phase); diff --git a/cockatrice/src/game/player/menu/library_menu.h b/cockatrice/src/game/player/menu/library_menu.h index b82a78b12..96d4b82b1 100644 --- a/cockatrice/src/game/player/menu/library_menu.h +++ b/cockatrice/src/game/player/menu/library_menu.h @@ -49,15 +49,15 @@ public: } // expose useful actions/menus if PlayerMenu needs them - QMenu *revealLibrary() const + [[nodiscard]] QMenu *revealLibrary() const { return mRevealLibrary; } - QMenu *lendLibraryMenu() const + [[nodiscard]] QMenu *lendLibraryMenu() const { return mLendLibrary; } - QMenu *revealTopCardMenu() const + [[nodiscard]] QMenu *revealTopCardMenu() const { return mRevealTopCard; } diff --git a/cockatrice/src/game/player/menu/player_menu.h b/cockatrice/src/game/player/menu/player_menu.h index 2019e4397..882bfedc5 100644 --- a/cockatrice/src/game/player/menu/player_menu.h +++ b/cockatrice/src/game/player/menu/player_menu.h @@ -61,7 +61,7 @@ public: return utilityMenu; } - bool getShortcutsActive() const + [[nodiscard]] bool getShortcutsActive() const { return shortcutsActive; } diff --git a/cockatrice/src/game/player/player.cpp b/cockatrice/src/game/player/player.cpp index a18e464d6..300300de3 100644 --- a/cockatrice/src/game/player/player.cpp +++ b/cockatrice/src/game/player/player.cpp @@ -194,7 +194,7 @@ void Player::processPlayerInfo(const ServerInfo_Player &info) } else { for (int j = 0; j < cardListSize; ++j) { const ServerInfo_Card &cardInfo = zoneInfo.card_list(j); - CardItem *card = new CardItem(this); + auto *card = new CardItem(this); card->processCardInfo(cardInfo); zone->addCard(card, false, cardInfo.x(), cardInfo.y()); } diff --git a/cockatrice/src/game/player/player_actions.h b/cockatrice/src/game/player/player_actions.h index 2317d0b92..9c775691c 100644 --- a/cockatrice/src/game/player/player_actions.h +++ b/cockatrice/src/game/player/player_actions.h @@ -63,7 +63,7 @@ public: void moveOneCardUntil(CardItem *card); void stopMoveTopCardsUntil(); - bool isMovingCardsUntil() const + [[nodiscard]] bool isMovingCardsUntil() const { return movingCardsUntil; } diff --git a/cockatrice/src/game/player/player_area.h b/cockatrice/src/game/player/player_area.h index ea8dc98e1..ec065fb4b 100644 --- a/cockatrice/src/game/player/player_area.h +++ b/cockatrice/src/game/player/player_area.h @@ -28,13 +28,13 @@ public: { Type = typeOther }; - int type() const override + [[nodiscard]] int type() const override { return Type; } explicit PlayerArea(QGraphicsItem *parent = nullptr); - QRectF boundingRect() const override + [[nodiscard]] QRectF boundingRect() const override { return bRect; } @@ -43,7 +43,7 @@ public: void setSize(qreal width, qreal height); void setPlayerZoneId(int _playerZoneId); - int getPlayerZoneId() const + [[nodiscard]] int getPlayerZoneId() const { return playerZoneId; } diff --git a/cockatrice/src/game/player/player_graphics_item.cpp b/cockatrice/src/game/player/player_graphics_item.cpp index e609591b3..27fbc82c8 100644 --- a/cockatrice/src/game/player/player_graphics_item.cpp +++ b/cockatrice/src/game/player/player_graphics_item.cpp @@ -50,8 +50,8 @@ void PlayerGraphicsItem::onPlayerActiveChanged(bool _active) void PlayerGraphicsItem::initializeZones() { deckZoneGraphicsItem = new PileZone(player->getDeckZone(), this); - QPointF base = QPointF(counterAreaWidth + (CARD_HEIGHT - CARD_WIDTH + 15) / 2.0, - 10 + playerTarget->boundingRect().height() + 5 - (CARD_HEIGHT - CARD_WIDTH) / 2.0); + auto base = QPointF(counterAreaWidth + (CARD_HEIGHT - CARD_WIDTH + 15) / 2.0, + 10 + playerTarget->boundingRect().height() + 5 - (CARD_HEIGHT - CARD_WIDTH) / 2.0); deckZoneGraphicsItem->setPos(base); qreal h = deckZoneGraphicsItem->boundingRect().width() + 5; @@ -147,7 +147,7 @@ void PlayerGraphicsItem::rearrangeCounters() void PlayerGraphicsItem::rearrangeZones() { - QPointF base = QPointF(CARD_HEIGHT + counterAreaWidth + 15, 0); + auto base = QPointF(CARD_HEIGHT + counterAreaWidth + 15, 0); if (SettingsCache::instance().getHorizontalHand()) { if (mirrored) { if (player->getHandZone()->contentsKnown()) { diff --git a/cockatrice/src/game/player/player_list_widget.cpp b/cockatrice/src/game/player/player_list_widget.cpp index 3281d8541..7cf7c34a6 100644 --- a/cockatrice/src/game/player/player_list_widget.cpp +++ b/cockatrice/src/game/player/player_list_widget.cpp @@ -27,7 +27,7 @@ bool PlayerListItemDelegate::editorEvent(QEvent *event, const QModelIndex &index) { if ((event->type() == QEvent::MouseButtonPress) && index.isValid()) { - QMouseEvent *const mouseEvent = static_cast(event); + auto *const mouseEvent = static_cast(event); if (mouseEvent->button() == Qt::RightButton) { #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) static_cast(parent())->showContextMenu(mouseEvent->globalPosition().toPoint(), index); diff --git a/cockatrice/src/game/player/player_manager.h b/cockatrice/src/game/player/player_manager.h index 20542d466..0f813b3e4 100644 --- a/cockatrice/src/game/player/player_manager.h +++ b/cockatrice/src/game/player/player_manager.h @@ -27,39 +27,39 @@ public: bool localPlayerIsSpectator; QMap spectators; - bool isSpectator() const + [[nodiscard]] bool isSpectator() const { return localPlayerIsSpectator; } - bool isJudge() const + [[nodiscard]] bool isJudge() const { return localPlayerIsJudge; } - int getLocalPlayerId() const + [[nodiscard]] int getLocalPlayerId() const { return localPlayerId; } - const QMap &getPlayers() const + [[nodiscard]] const QMap &getPlayers() const { return players; } - int getPlayerCount() const + [[nodiscard]] int getPlayerCount() const { return players.size(); } - Player *getActiveLocalPlayer(int activePlayer) const; + [[nodiscard]] Player *getActiveLocalPlayer(int activePlayer) const; bool isLocalPlayer(int playerId); Player *addPlayer(int playerId, const ServerInfo_User &info); void removePlayer(int playerId); - Player *getPlayer(int playerId) const; + [[nodiscard]] Player *getPlayer(int playerId) const; void onPlayerConceded(int playerId, bool conceded); @@ -70,17 +70,17 @@ public: return playerId == getLocalPlayerId(); } - const QMap &getSpectators() const + [[nodiscard]] const QMap &getSpectators() const { return spectators; } - ServerInfo_User getSpectator(int playerId) const + [[nodiscard]] ServerInfo_User getSpectator(int playerId) const { return spectators.value(playerId); } - QString getSpectatorName(int spectatorId) const + [[nodiscard]] QString getSpectatorName(int spectatorId) const { return QString::fromStdString(spectators.value(spectatorId).name()); } @@ -100,7 +100,7 @@ public: emit spectatorRemoved(spectatorId, spectatorInfo); } - AbstractGame *getGame() const + [[nodiscard]] AbstractGame *getGame() const { return game; } diff --git a/cockatrice/src/game/zones/logic/card_zone_logic.h b/cockatrice/src/game/zones/logic/card_zone_logic.h index 9be654d22..4d02b7dd1 100644 --- a/cockatrice/src/game/zones/logic/card_zone_logic.h +++ b/cockatrice/src/game/zones/logic/card_zone_logic.h @@ -63,16 +63,16 @@ public: { cards.sortBy(options); } - QString getName() const + [[nodiscard]] QString getName() const { return name; } - QString getTranslatedName(bool theirOwn, GrammaticalCase gc) const; - Player *getPlayer() const + [[nodiscard]] QString getTranslatedName(bool theirOwn, GrammaticalCase gc) const; + [[nodiscard]] Player *getPlayer() const { return player; } - bool contentsKnown() const + [[nodiscard]] bool contentsKnown() const { return cards.getContentsKnown(); } @@ -84,15 +84,15 @@ public: { alwaysRevealTopCard = _alwaysRevealTopCard; } - bool getAlwaysRevealTopCard() const + [[nodiscard]] bool getAlwaysRevealTopCard() const { return alwaysRevealTopCard; } - bool getHasCardAttr() const + [[nodiscard]] bool getHasCardAttr() const { return hasCardAttr; } - bool getIsShufflable() const + [[nodiscard]] bool getIsShufflable() const { return isShufflable; } diff --git a/cockatrice/src/game/zones/table_zone.h b/cockatrice/src/game/zones/table_zone.h index e196fe943..3b353e76c 100644 --- a/cockatrice/src/game/zones/table_zone.h +++ b/cockatrice/src/game/zones/table_zone.h @@ -84,7 +84,7 @@ private: */ bool active = false; - bool isInverted() const; + [[nodiscard]] bool isInverted() const; private slots: /** @@ -110,7 +110,7 @@ public: /** @return a QRectF of the TableZone bounding box. */ - QRectF boundingRect() const override; + [[nodiscard]] QRectF boundingRect() const override; /** Render the TableZone @@ -140,12 +140,12 @@ public: /** @return CardItem from grid location */ - CardItem *getCardFromGrid(const QPoint &gridPoint) const; + [[nodiscard]] CardItem *getCardFromGrid(const QPoint &gridPoint) const; /** @return CardItem from coordinate location */ - CardItem *getCardFromCoords(const QPointF &point) const; + [[nodiscard]] CardItem *getCardFromCoords(const QPointF &point) const; QPointF closestGridPoint(const QPointF &point) override; @@ -157,7 +157,7 @@ public: */ void resizeToContents(); - int getMinimumWidth() const + [[nodiscard]] int getMinimumWidth() const { return currentMinimumWidth; } @@ -166,7 +166,7 @@ public: prepareGeometryChange(); width = _width; } - qreal getWidth() const + [[nodiscard]] qreal getWidth() const { return width; } @@ -188,13 +188,13 @@ private: /* Mapping functions for points to/from gridpoints. */ - QPointF mapFromGrid(QPoint gridPoint) const; - QPoint mapToGrid(const QPointF &mapPoint) const; + [[nodiscard]] QPointF mapFromGrid(QPoint gridPoint) const; + [[nodiscard]] QPoint mapToGrid(const QPointF &mapPoint) const; /* Helper function to create a single key from a card stack location. */ - int getCardStackMapKey(int x, int y) const + [[nodiscard]] int getCardStackMapKey(int x, int y) const { return x + (y * 1000); } diff --git a/cockatrice/src/game/zones/view_zone.h b/cockatrice/src/game/zones/view_zone.h index 2ebb65cf0..81279c72e 100644 --- a/cockatrice/src/game/zones/view_zone.h +++ b/cockatrice/src/game/zones/view_zone.h @@ -58,12 +58,12 @@ private: public: ZoneViewZone(ZoneViewZoneLogic *_logic, QGraphicsItem *parent); - QRectF boundingRect() const override; + [[nodiscard]] QRectF boundingRect() const override; void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override; void reorganizeCards() override; void initializeCards(const QList &cardList = QList()); void setGeometry(const QRectF &rect) override; - QRectF getOptimumRect() const + [[nodiscard]] QRectF getOptimumRect() const { return optimumRect; } @@ -83,7 +83,7 @@ signals: void wheelEventReceived(QGraphicsSceneWheelEvent *event); protected: - QSizeF sizeHint(Qt::SizeHint which, const QSizeF &constraint = QSizeF()) const override; + [[nodiscard]] QSizeF sizeHint(Qt::SizeHint which, const QSizeF &constraint = QSizeF()) const override; void wheelEvent(QGraphicsSceneWheelEvent *event) override; }; diff --git a/cockatrice/src/interface/card_picture_loader/card_picture_loader.h b/cockatrice/src/interface/card_picture_loader/card_picture_loader.h index 213231cd9..29bdf26c8 100644 --- a/cockatrice/src/interface/card_picture_loader/card_picture_loader.h +++ b/cockatrice/src/interface/card_picture_loader/card_picture_loader.h @@ -1,9 +1,3 @@ -/** - * @file card_picture_loader.h - * @ingroup PictureLoader - * @brief TODO: Document this. - */ - #ifndef CARD_PICTURE_LOADER_H #define CARD_PICTURE_LOADER_H @@ -16,10 +10,37 @@ inline Q_LOGGING_CATEGORY(CardPictureLoaderLog, "card_picture_loader"); inline Q_LOGGING_CATEGORY(CardPictureLoaderCardBackCacheFailLog, "card_picture_loader.card_back_cache_fail"); +/** + * @class CardPictureLoader + * @ingroup PictureLoader + * @brief Singleton class to manage card image loading and caching. Provides functionality to asynchronously load, + * cache, and manage card images for the client. + * + * This class is a singleton and handles: + * - Loading card images from disk or network. + * - Caching images in QPixmapCache for fast reuse. + * - Providing themed card backs, including fallback and in-progress/failed states. + * - Emitting updates when pixmaps are loaded. + * + * It interacts with CardPictureLoaderWorker for background loading and + * CardPictureLoaderStatusBar to display loading progress in the main window. + * + * Provides static accessors for: + * - Card images by ExactCard. + * - Card back images (normal, in-progress, failed). + * - Cache management (clearPixmapCache(), clearNetworkCache(), cacheCardPixmaps(const QList &cards)). + * + * Uses a worker thread for asynchronous image loading and a status bar widget + * to track load progress. + */ class CardPictureLoader : public QObject { Q_OBJECT public: + /** + * @brief Access the singleton instance of CardPictureLoader. + * @return Reference to the singleton. + */ static CardPictureLoader &getInstance() { static CardPictureLoader instance; @@ -29,30 +50,87 @@ public: private: explicit CardPictureLoader(); ~CardPictureLoader() override; - // Singleton - Don't implement copy constructor and assign operator - CardPictureLoader(CardPictureLoader const &); - void operator=(CardPictureLoader const &); - CardPictureLoaderWorker *worker; - CardPictureLoaderStatusBar *statusBar; + // Disable copy and assignment for singleton + CardPictureLoader(CardPictureLoader const &) = delete; + void operator=(CardPictureLoader const &) = delete; + + CardPictureLoaderWorker *worker; ///< Worker thread for async image loading + CardPictureLoaderStatusBar *statusBar; ///< Status bar widget showing load progress public: + /** + * @brief Retrieve a card pixmap, either from cache or enqueued for loading. + * @param pixmap Reference to QPixmap where result will be stored. + * @param card ExactCard to load. + * @param size Desired size of pixmap. + */ static void getPixmap(QPixmap &pixmap, const ExactCard &card, QSize size); + + /** + * @brief Retrieve a generic card back pixmap. + * @param pixmap Reference to QPixmap where result will be stored. + * @param size Desired size of pixmap. + */ static void getCardBackPixmap(QPixmap &pixmap, QSize size); + + /** + * @brief Retrieve a card back pixmap for the loading-in-progress state. + * @param pixmap Reference to QPixmap where result will be stored. + * @param size Desired size of pixmap. + */ static void getCardBackLoadingInProgressPixmap(QPixmap &pixmap, QSize size); + + /** + * @brief Retrieve a card back pixmap for the loading-failed state. + * @param pixmap Reference to QPixmap where result will be stored. + * @param size Desired size of pixmap. + */ static void getCardBackLoadingFailedPixmap(QPixmap &pixmap, QSize size); - static void clearPixmapCache(); + + /** + * @brief Preload a list of cards into the pixmap cache (limited to CACHED_CARD_PER_DECK_MAX). + * @param cards List of ExactCard objects to preload. + */ static void cacheCardPixmaps(const QList &cards); + + /** + * @brief Check if the user has custom card art in the picsPath directory. + * @return True if any custom art exists. + */ static bool hasCustomArt(); + /** + * @brief Clears the in-memory QPixmap cache for all cards. + */ + static void clearPixmapCache(); + public slots: + /** + * @brief Clears the network disk cache of the worker. + */ static void clearNetworkCache(); -private slots: - void picDownloadChanged(); - void picsPathChanged(); - -public slots: + /** + * @brief Slot called by the worker when an image is loaded. + * Inserts the pixmap into the cache and emits pixmap updated signals. + * @param card ExactCard that was loaded. + * @param image Loaded QImage. + */ void imageLoaded(const ExactCard &card, const QImage &image); + +private slots: + /** + * @brief Triggered when the user changes the picture download settings. + * Clears the QPixmap cache to reload images. + */ + void picDownloadChanged(); + + /** + * @brief Triggered when the pictures path changes. + * Clears the QPixmap cache to reload images. + */ + void picsPathChanged(); }; + #endif diff --git a/cockatrice/src/interface/card_picture_loader/card_picture_loader_local.cpp b/cockatrice/src/interface/card_picture_loader/card_picture_loader_local.cpp index 33a78ddaf..dd00e6e1d 100644 --- a/cockatrice/src/interface/card_picture_loader/card_picture_loader_local.cpp +++ b/cockatrice/src/interface/card_picture_loader/card_picture_loader_local.cpp @@ -47,12 +47,6 @@ void CardPictureLoaderLocal::refreshIndex() << customFolderIndex.size() << "entries."; } -/** - * Tries to load the card image from the local images. - * - * @param toLoad The card to load - * @return The loaded image, or an empty QImage if loading failed. - */ QImage CardPictureLoaderLocal::tryLoad(const ExactCard &toLoad) const { PrintingInfo setInstance = toLoad.getPrinting(); diff --git a/cockatrice/src/interface/card_picture_loader/card_picture_loader_local.h b/cockatrice/src/interface/card_picture_loader/card_picture_loader_local.h index 1d4325412..84f16cc38 100644 --- a/cockatrice/src/interface/card_picture_loader/card_picture_loader_local.h +++ b/cockatrice/src/interface/card_picture_loader/card_picture_loader_local.h @@ -1,9 +1,3 @@ -/** - * @file card_picture_loader_local.h - * @ingroup PictureLoader - * @brief TODO: Document this. - */ - #ifndef PICTURE_LOADER_LOCAL_H #define PICTURE_LOADER_LOCAL_H @@ -15,32 +9,80 @@ inline Q_LOGGING_CATEGORY(CardPictureLoaderLocalLog, "card_picture_loader.local"); /** - * Handles searching for and loading card images from the local pics and custom image folders. - * This class maintains an index of the CUSTOM folder, to avoid repeatedly searching the entire directory. + * @class CardPictureLoaderLocal + * @ingroup PictureLoader + * @brief Handles searching for and loading card images from local and custom image folders. + * + * This class maintains an index of the CUSTOM folder to avoid repeatedly scanning + * directories, and supports periodic refreshes to update the index. + * + * Responsibilities: + * - Load images for ExactCard objects from local disk or custom folders. + * - Maintain an index for fast lookup of images in the CUSTOM folder. + * - Refresh the index periodically to account for changes in local image directories. */ class CardPictureLoaderLocal : public QObject { Q_OBJECT public: + /** + * @brief Constructs a CardPictureLoaderLocal object. + * @param parent Optional parent QObject. + * + * Initializes paths from SettingsCache, connects to settings change signals, + * builds the initial folder index, and starts a periodic refresh timer. + */ explicit CardPictureLoaderLocal(QObject *parent); + /** + * @brief Attempts to load a card image from local disk or custom folders. + * @param toLoad ExactCard object representing the card to load. + * @return Loaded QImage if found; otherwise, an empty QImage. + * + * Uses a set of name variants and folder paths to attempt to locate the correct image. + */ QImage tryLoad(const ExactCard &toLoad) const; private: - QString picsPath, customPicsPath; + QString picsPath; ///< Path to standard card image folder + QString customPicsPath; ///< Path to custom card image folder - QMultiHash customFolderIndex; // multimap of cardName to picPaths - QTimer *refreshTimer; + QMultiHash customFolderIndex; ///< Multimap from cardName to file paths in CUSTOM folder + QTimer *refreshTimer; ///< Timer for periodic folder index refresh + /** + * @brief Rebuilds the index of the custom image folder. + * + * Iterates through all subdirectories of the CUSTOM folder and populates + * `customFolderIndex` with all discovered image files keyed by base name + * and complete base name. + */ void refreshIndex(); + /** + * @brief Attempts to load a card image from disk given its set and name info. + * @param setName Corrected short name of the card's set. + * @param correctedCardName Corrected card name (e.g., normalized name). + * @param collectorNumber Collector number of the card. + * @param providerId Optional provider UUID of the card. + * @return Loaded QImage if found; otherwise, an empty QImage. + * + * Searches in both the custom folder index and standard pictures paths. + * Uses several filename patterns to match card images, in order from + * most-specific to least-specific. + */ QImage tryLoadCardImageFromDisk(const QString &setName, const QString &correctedCardName, const QString &collectorNumber, const QString &providerId) const; private slots: + /** + * @brief Updates internal paths when the user changes picture settings. + * + * Triggered by `SettingsCache::picsPathChanged`. + */ void picsPathChanged(); }; diff --git a/cockatrice/src/interface/card_picture_loader/card_picture_loader_request_status_display_widget.h b/cockatrice/src/interface/card_picture_loader/card_picture_loader_request_status_display_widget.h index be032ae64..2e3233c2d 100644 --- a/cockatrice/src/interface/card_picture_loader/card_picture_loader_request_status_display_widget.h +++ b/cockatrice/src/interface/card_picture_loader/card_picture_loader_request_status_display_widget.h @@ -1,26 +1,43 @@ -/** - * @file card_picture_loader_request_status_display_widget.h - * @ingroup PictureLoader - * @brief TODO: Document this. - */ - #ifndef PICTURE_LOADER_REQUEST_STATUS_DISPLAY_WIDGET_H #define PICTURE_LOADER_REQUEST_STATUS_DISPLAY_WIDGET_H + #include "card_picture_loader_worker_work.h" #include #include #include +/** + * @class CardPictureLoaderRequestStatusDisplayWidget + * @ingroup PictureLoader + * @brief A small widget to display the status of a single card image request. + * + * Displays: + * - Card name + * - Set short name + * - Provider ID + * - Start time of request + * - Elapsed time since start + * - Finished status + * - URL of the requested image + */ class CardPictureLoaderRequestStatusDisplayWidget : public QWidget { Q_OBJECT public: + /** + * @brief Constructs a new status widget for a specific card image request. + * @param parent Parent widget + * @param url URL of the image being requested + * @param card The ExactCard being downloaded + * @param setName Set name for the card + */ CardPictureLoaderRequestStatusDisplayWidget(QWidget *parent, const QUrl &url, const ExactCard &card, const QString &setName); + /** Marks the request as finished */ void setFinished() { finished->setText("True"); @@ -28,19 +45,25 @@ public: repaint(); } - bool getFinished() const + /** Returns whether the request has finished */ + [[nodiscard]] bool getFinished() const { return finished->text() == "True"; } + /** Updates the elapsed time display */ void setElapsedTime(const QString &_elapsedTime) const { elapsedTime->setText(_elapsedTime); } + /** + * @brief Queries the elapsed time in seconds since the request started + * @return Elapsed time in seconds + */ int queryElapsedSeconds() { - if (!finished) { + if (!getFinished()) { int elapsedSeconds = QDateTime::fromString(startTime->text()).secsTo(QDateTime::currentDateTime()); elapsedTime->setText(QString::number(elapsedSeconds)); update(); @@ -50,25 +73,27 @@ public: return elapsedTime->text().toInt(); } - QString getStartTime() const + /** Returns the start time as a string */ + [[nodiscard]] QString getStartTime() const { return startTime->text(); } - QString getUrl() const + /** Returns the URL of the request */ + [[nodiscard]] QString getUrl() const { return url->text(); } private: - QHBoxLayout *layout; - QLabel *name; - QLabel *setShortname; - QLabel *providerId; - QLabel *startTime; - QLabel *elapsedTime; - QLabel *finished; - QLabel *url; + QHBoxLayout *layout; ///< Horizontal layout for arranging labels + QLabel *name; ///< Card name + QLabel *setShortname; ///< Set short name + QLabel *providerId; ///< Provider ID for the card + QLabel *startTime; ///< Start time of the request + QLabel *elapsedTime; ///< Elapsed time since start + QLabel *finished; ///< Whether the request has finished + QLabel *url; ///< URL of the requested image }; #endif // PICTURE_LOADER_REQUEST_STATUS_DISPLAY_WIDGET_H diff --git a/cockatrice/src/interface/card_picture_loader/card_picture_loader_status_bar.h b/cockatrice/src/interface/card_picture_loader/card_picture_loader_status_bar.h index b44d2cc20..cb469269c 100644 --- a/cockatrice/src/interface/card_picture_loader/card_picture_loader_status_bar.h +++ b/cockatrice/src/interface/card_picture_loader/card_picture_loader_status_bar.h @@ -1,9 +1,3 @@ -/** - * @file card_picture_loader_status_bar.h - * @ingroup PictureLoader - * @brief TODO: Document this. - */ - #ifndef PICTURE_LOADER_STATUS_BAR_H #define PICTURE_LOADER_STATUS_BAR_H @@ -12,24 +6,56 @@ #include #include +#include #include +/** + * @class CardPictureLoaderStatusBar + * @ingroup PictureLoader + * @brief Displays the status of card image downloads in a horizontal progress bar with a log popup. + * + * Responsibilities: + * - Shows overall progress of image downloads. + * - Maintains a log of individual requests via a popup (SettingsButtonWidget). + * - Cleans up finished request entries automatically after a delay. + */ class CardPictureLoaderStatusBar : public QWidget { Q_OBJECT public: + /** + * @brief Constructs a status bar with progress bar and log button. + * @param parent Parent widget + */ explicit CardPictureLoaderStatusBar(QWidget *parent); public slots: + /** + * @brief Adds a queued image download to the log and increments the progress bar maximum. + * @param url URL of the image + * @param card The card being loaded + * @param setName The set name of the card + */ void addQueuedImageLoad(const QUrl &url, const ExactCard &card, const QString &setName); + + /** + * @brief Marks an image as successfully loaded. + * Updates the progress bar and marks the corresponding log entry as finished. + * @param url URL of the successfully loaded image + */ void addSuccessfulImageLoad(const QUrl &url); + + /** + * @brief Cleans up old entries from the log that have finished more than 10 seconds ago. + * Adjusts the progress bar accordingly. + */ void cleanOldEntries(); private: - QHBoxLayout *layout; - QProgressBar *progressBar; - SettingsButtonWidget *loadLog; - QTimer *cleaner; + QHBoxLayout *layout; ///< Horizontal layout containing progress bar and log button + QProgressBar *progressBar; ///< Progress bar showing overall download progress + SettingsButtonWidget *loadLog; ///< Popup log showing individual request statuses + QTimer *cleaner; ///< Timer for periodically cleaning old log entries }; #endif // PICTURE_LOADER_STATUS_BAR_H diff --git a/cockatrice/src/interface/card_picture_loader/card_picture_loader_worker.cpp b/cockatrice/src/interface/card_picture_loader/card_picture_loader_worker.cpp index 4a831c24a..a2da3c953 100644 --- a/cockatrice/src/interface/card_picture_loader/card_picture_loader_worker.cpp +++ b/cockatrice/src/interface/card_picture_loader/card_picture_loader_worker.cpp @@ -105,9 +105,6 @@ void CardPictureLoaderWorker::resetRequestQuota() processQueuedRequests(); } -/** - * Keeps processing requests from the queue until it is empty or until the quota runs out. - */ void CardPictureLoaderWorker::processQueuedRequests() { while (requestQuota > 0 && processSingleRequest()) { @@ -115,10 +112,6 @@ void CardPictureLoaderWorker::processQueuedRequests() } } -/** - * Immediately processes a single queued request. No-ops if the load queue is empty - * @return If a request was processed - */ bool CardPictureLoaderWorker::processSingleRequest() { if (!requestLoadQueue.isEmpty()) { diff --git a/cockatrice/src/interface/card_picture_loader/card_picture_loader_worker.h b/cockatrice/src/interface/card_picture_loader/card_picture_loader_worker.h index cdee37db3..f927abde6 100644 --- a/cockatrice/src/interface/card_picture_loader/card_picture_loader_worker.h +++ b/cockatrice/src/interface/card_picture_loader/card_picture_loader_worker.h @@ -1,9 +1,3 @@ -/** - * @file card_picture_loader_worker.h - * @ingroup PictureLoader - * @brief TODO: Document this. - */ - #ifndef PICTURE_LOADER_WORKER_H #define PICTURE_LOADER_WORKER_H @@ -27,57 +21,131 @@ #define REDIRECT_TIMESTAMP "timestamp" #define REDIRECT_CACHE_FILENAME "cache.ini" -inline Q_LOGGING_CATEGORY(CardPictureLoaderWorkerLog, "card_picture_loader.worker"); +inline Q_LOGGING_CATEGORY(CardPictureLoaderWorkerLog, "card_picture_loader.worker") -class CardPictureLoaderWorkerWork; + class CardPictureLoaderWorkerWork; + +/** + * @class CardPictureLoaderWorker + * @ingroup PictureLoader + * @brief Handles asynchronous loading of card images, both locally and via network. + * + * Responsibilities: + * - Maintain a queue of network image requests with rate-limiting. + * - Load images from local cache first via CardPictureLoaderLocal. + * - Handle network redirects and persistent caching of redirects. + * - Deduplicate simultaneous requests for the same card. + * - Emit signals for status updates and loaded images. + */ class CardPictureLoaderWorker : public QObject { Q_OBJECT + public: + /** + * @brief Constructs a CardPictureLoaderWorker. + * + * Initializes network manager, cache, redirect cache, local loader, and request quota timer. + */ explicit CardPictureLoaderWorker(); + ~CardPictureLoaderWorker() override; - void enqueueImageLoad(const ExactCard &card); // Starts a thread for the image to be loaded - void queueRequest(const QUrl &url, CardPictureLoaderWorkerWork *worker); // Queues network requests for load threads + /** + * @brief Enqueues an ExactCard for loading. + * @param card ExactCard to load + * + * This will first try to load the image locally; if that fails, it will enqueue a network request. + */ + void enqueueImageLoad(const ExactCard &card); + + /** + * @brief Queues a network request for a given URL and worker thread. + * @param url URL to load + * @param worker Worker handling this request + */ + void queueRequest(const QUrl &url, CardPictureLoaderWorkerWork *worker); + + /** @brief Clears the network cache and redirect cache. */ void clearNetworkCache(); public slots: + /** + * @brief Makes a network request for the given URL using the specified worker. + * @param url URL to load + * @param workThread Worker handling the request + * @return The QNetworkReply object representing the request + */ QNetworkReply *makeRequest(const QUrl &url, CardPictureLoaderWorkerWork *workThread); + + /** @brief Processes all queued requests respecting the request quota. */ void processQueuedRequests(); + + /** + * @brief Processes a single queued request. + * @return true if a request was processed, false if queue is empty. + */ bool processSingleRequest(); + + /** + * @brief Handles an image that has finished loading. + * @param card The ExactCard that was loaded + * @param image The loaded QImage; empty if loading failed + */ void handleImageLoaded(const ExactCard &card, const QImage &image); + + /** @brief Caches a redirect mapping between original and redirected URL. */ void cacheRedirect(const QUrl &originalUrl, const QUrl &redirectUrl); + + /** @brief Removes a URL from the network cache. */ void removedCachedUrl(const QUrl &url); private: - QThread *pictureLoaderThread; - QNetworkAccessManager *networkManager; - QNetworkDiskCache *cache; - QHash> redirectCache; // Stores redirect and timestamp - QString cacheFilePath; // Path to persistent storage - static constexpr int CacheTTLInDays = 30; // TODO: Make user configurable - bool picDownload; - QQueue> requestLoadQueue; + QThread *pictureLoaderThread; ///< Thread for executing worker tasks + QNetworkAccessManager *networkManager; ///< Network manager for HTTP requests + QNetworkDiskCache *cache; ///< Disk cache for downloaded images + QHash> redirectCache; ///< Maps original URLs to redirects with timestamp + QString cacheFilePath; ///< Path to persistent redirect cache file + static constexpr int CacheTTLInDays = 30; ///< Time-to-live for redirect cache entries (days) + bool picDownload; ///< Whether downloading images from network is enabled + QQueue> requestLoadQueue; ///< Queue of pending network requests - int requestQuota; - QTimer requestTimer; // Timer for refreshing request quota + int requestQuota; ///< Remaining requests allowed per second + QTimer requestTimer; ///< Timer to reset the request quota - CardPictureLoaderLocal *localLoader; - QSet currentlyLoading; // for deduplication purposes. Contains pixmapCacheKey + CardPictureLoaderLocal *localLoader; ///< Loader for local images + QSet currentlyLoading; ///< Deduplication: contains pixmapCacheKey currently being loaded - QUrl getCachedRedirect(const QUrl &originalUrl) const; + /** @brief Returns cached redirect URL for the given original URL, if available. */ + [[nodiscard]] QUrl getCachedRedirect(const QUrl &originalUrl) const; + + /** @brief Loads redirect cache from disk. */ void loadRedirectCache(); + + /** @brief Saves redirect cache to disk. */ void saveRedirectCache() const; + + /** @brief Removes stale redirect entries older than TTL. */ void cleanStaleEntries(); private slots: + /** @brief Resets the request quota for rate-limiting. */ void resetRequestQuota(); + + /** @brief Handles image load requests enqueued on this worker. */ void handleImageLoadEnqueued(const ExactCard &card); signals: + /** @brief Emitted when an image load is enqueued. */ void imageLoadEnqueued(const ExactCard &card); + + /** @brief Emitted when an image has finished loading. */ void imageLoaded(const ExactCard &card, const QImage &image); + + /** @brief Emitted when a request is added to the network queue. */ void imageRequestQueued(const QUrl &url, const ExactCard &card, const QString &setName); + + /** @brief Emitted when a network request successfully completes. */ void imageRequestSucceeded(const QUrl &url); }; diff --git a/cockatrice/src/interface/card_picture_loader/card_picture_loader_worker_work.cpp b/cockatrice/src/interface/card_picture_loader/card_picture_loader_worker_work.cpp index 07478ee70..e74103419 100644 --- a/cockatrice/src/interface/card_picture_loader/card_picture_loader_worker_work.cpp +++ b/cockatrice/src/interface/card_picture_loader/card_picture_loader_worker_work.cpp @@ -51,10 +51,6 @@ void CardPictureLoaderWorkerWork::startNextPicDownload() } } -/** - * Starts another pic download using the next possible url combination for the card. - * If all possibilities are exhausted, then concludes the image loading with an empty QImage. - */ void CardPictureLoaderWorkerWork::picDownloadFailed() { /* Take advantage of short-circuiting here to call the nextUrl until one @@ -73,10 +69,6 @@ void CardPictureLoaderWorkerWork::picDownloadFailed() } } -/** - * - * @param reply The reply. Takes ownership of the object - */ void CardPictureLoaderWorkerWork::handleNetworkReply(QNetworkReply *reply) { QVariant redirectTarget = reply->attribute(QNetworkRequest::RedirectionTargetAttribute); @@ -180,10 +172,6 @@ void CardPictureLoaderWorkerWork::handleSuccessfulReply(QNetworkReply *reply) } } -/** - * @param reply The reply to load the image from - * @return The loaded image, or an empty QImage if loading failed - */ QImage CardPictureLoaderWorkerWork::tryLoadImageFromReply(QNetworkReply *reply) { static constexpr int riffHeaderSize = 12; // RIFF_HEADER_SIZE from webp/format_constants.h @@ -207,10 +195,6 @@ QImage CardPictureLoaderWorkerWork::tryLoadImageFromReply(QNetworkReply *reply) return imgReader.read(); } -/** - * Call this method when the image has finished being loaded. - * @param image The image that was loaded. Empty QImage indicates failure. - */ void CardPictureLoaderWorkerWork::concludeImageLoad(const QImage &image) { emit imageLoaded(cardToDownload.getCard(), image); diff --git a/cockatrice/src/interface/card_picture_loader/card_picture_loader_worker_work.h b/cockatrice/src/interface/card_picture_loader/card_picture_loader_worker_work.h index c7ccf7566..cdffc1dff 100644 --- a/cockatrice/src/interface/card_picture_loader/card_picture_loader_worker_work.h +++ b/cockatrice/src/interface/card_picture_loader/card_picture_loader_worker_work.h @@ -1,9 +1,3 @@ -/** - * @file picture_loader_worker_work.h - * @ingroup PictureLoader - * @brief TODO: Document this. - */ - #ifndef PICTURE_LOADER_WORKER_WORK_H #define PICTURE_LOADER_WORKER_WORK_H @@ -17,55 +11,96 @@ #include #include -#define REDIRECT_HEADER_NAME "redirects" -#define REDIRECT_ORIGINAL_URL "original" -#define REDIRECT_URL "redirect" -#define REDIRECT_TIMESTAMP "timestamp" -#define REDIRECT_CACHE_FILENAME "cache.ini" - inline Q_LOGGING_CATEGORY(CardPictureLoaderWorkerWorkLog, "card_picture_loader.worker"); class CardPictureLoaderWorker; +/** + * @class CardPictureLoaderWorkerWork + * @ingroup PictureLoader + * @brief Handles downloading a single card image from network or local sources. + * + * Responsibilities: + * - Try to load images from all possible URLs and sets for a given ExactCard. + * - Handle network redirects and cache invalidation. + * - Check for blacklisted images and discard them. + * - Emit signals when image is successfully loaded or all attempts fail. + * - Delete itself after loading completes. + */ class CardPictureLoaderWorkerWork : public QObject { Q_OBJECT public: + /** + * @brief Constructs a worker for downloading a specific card image. + * @param worker The orchestrating CardPictureLoaderWorker + * @param toLoad The ExactCard to download + */ explicit CardPictureLoaderWorkerWork(const CardPictureLoaderWorker *worker, const ExactCard &toLoad); - CardPictureToLoad cardToDownload; + CardPictureToLoad cardToDownload; ///< The card and associated URLs to try downloading public slots: + /** + * @brief Handles a finished network reply for the card image. + * @param reply The QNetworkReply object to process. Ownership is transferred. + */ void handleNetworkReply(QNetworkReply *reply); private: - bool picDownload; + bool picDownload; ///< Whether network downloading is enabled + /** @brief Starts downloading the next URL for this card. */ void startNextPicDownload(); + + /** @brief Called when all URLs have been exhausted or download failed. */ void picDownloadFailed(); + + /** @brief Processes a failed network reply. */ void handleFailedReply(const QNetworkReply *reply); + + /** @brief Processes a successful network reply. */ void handleSuccessfulReply(QNetworkReply *reply); + + /** + * @brief Attempts to read an image from a network reply. + * @param reply The network reply + * @return The loaded QImage or an empty image if reading failed + */ QImage tryLoadImageFromReply(QNetworkReply *reply); + + /** + * @brief Finalizes the image loading process. + * @param image The loaded image (empty if failed) + * + * Emits imageLoaded() and deletes this object. + */ void concludeImageLoad(const QImage &image); private slots: + /** @brief Updates the picDownload setting when it changes. */ void picDownloadChanged(); signals: /** - * Emitted when this worker has successfully loaded the image or has exhausted all attempts at loading the image. - * Failures are represented by an empty QImage. - * Note that this object will delete itself as this signal is emitted. + * @brief Emitted when the image has been loaded or all attempts failed. + * @param card The card corresponding to the image + * @param image The loaded image (empty if failed) + * + * The worker deletes itself after emitting this signal. */ void imageLoaded(const ExactCard &card, const QImage &image); - /** - * Emitted when a request did not return a 400 or 500 response - */ + /** @brief Emitted when a network request completes successfully. */ void requestSucceeded(const QUrl &url); + + /** @brief Request that a URL be downloaded. */ void requestImageDownload(const QUrl &url, CardPictureLoaderWorkerWork *instance); + /** @brief Emitted when a URL has been redirected. */ void urlRedirected(const QUrl &originalUrl, const QUrl &redirectUrl); + + /** @brief Emitted when a cached URL is invalid and must be removed. */ void cachedUrlInvalidated(const QUrl &url); }; diff --git a/cockatrice/src/interface/card_picture_loader/card_picture_to_load.cpp b/cockatrice/src/interface/card_picture_loader/card_picture_to_load.cpp index 3727988ad..d72226aab 100644 --- a/cockatrice/src/interface/card_picture_loader/card_picture_to_load.cpp +++ b/cockatrice/src/interface/card_picture_loader/card_picture_to_load.cpp @@ -20,12 +20,6 @@ CardPictureToLoad::CardPictureToLoad(const ExactCard &_card) } } -/** - * Extracts a list of all the sets from the card, sorted in priority order. - * If the card does not contain any sets, then a dummy set will be inserted into the list. - * - * @return A list of sets. Will not be empty. - */ QList CardPictureToLoad::extractSetsSorted(const ExactCard &card) { QList sortedSets; @@ -109,11 +103,6 @@ void CardPictureToLoad::populateSetUrls() (void)nextUrl(); } -/** - * Advances the currentSet to the next set in the list. Then repopulates the url list with the urls from that set. - * If we are already at the end of the list, then currentSet is set to empty. - * @return If we are already at the end of the list - */ bool CardPictureToLoad::nextSet() { if (!sortedSets.isEmpty()) { @@ -125,11 +114,6 @@ bool CardPictureToLoad::nextSet() return false; } -/** - * Advances the currentUrl to the next url in the list. - * If we are already at the end of the list, then currentUrl is set to empty. - * @return If we are already at the end of the list - */ bool CardPictureToLoad::nextUrl() { if (!currentSetUrls.isEmpty()) { diff --git a/cockatrice/src/interface/card_picture_loader/card_picture_to_load.h b/cockatrice/src/interface/card_picture_loader/card_picture_to_load.h index b7c0e6a53..b0a555c86 100644 --- a/cockatrice/src/interface/card_picture_loader/card_picture_to_load.h +++ b/cockatrice/src/interface/card_picture_loader/card_picture_to_load.h @@ -1,9 +1,3 @@ -/** - * @file card_picture_to_load.h - * @ingroup PictureLoader - * @brief TODO: Document this. - */ - #ifndef PICTURE_TO_LOAD_H #define PICTURE_TO_LOAD_H @@ -12,37 +6,97 @@ inline Q_LOGGING_CATEGORY(CardPictureToLoadLog, "card_picture_loader.picture_to_load"); +/** + * @class CardPictureToLoad + * @ingroup PictureLoader + * @brief Manages all URLs and sets for downloading a specific card image. + * + * Responsibilities: + * - Maintains a sorted list of sets for a card. + * - Generates URLs to download images from, including custom URLs and URL templates. + * - Tracks which URL and set is currently being attempted. + * - Provides helper methods to advance to next URL or set. + */ class CardPictureToLoad { private: - ExactCard card; - QList sortedSets; - QList urlTemplates; - QList currentSetUrls; - QString currentUrl; - CardSetPtr currentSet; + ExactCard card; ///< The ExactCard being downloaded + QList sortedSets; ///< All sets for this card, sorted by priority + QList urlTemplates; ///< URL templates from settings + QList currentSetUrls; ///< URLs for the current set being attempted + QString currentUrl; ///< Currently active URL to download + CardSetPtr currentSet; ///< Currently active set public: + /** + * @brief Constructs a CardPictureToLoad for a given ExactCard. + * @param _card The card to download + * + * Initializes URL templates and pre-populates the first set URLs. + */ explicit CardPictureToLoad(const ExactCard &_card); - const ExactCard &getCard() const + /** @return The card being loaded. */ + [[nodiscard]] const ExactCard &getCard() const { return card; } - QString getCurrentUrl() const + + /** @return The current URL being attempted. */ + [[nodiscard]] QString getCurrentUrl() const { return currentUrl; } - CardSetPtr getCurrentSet() const + + /** @return The current set being attempted. */ + [[nodiscard]] CardSetPtr getCurrentSet() const { return currentSet; } - QString getSetName() const; + + /** @return The short name of the current set, or empty string if no set. */ + [[nodiscard]] QString getSetName() const; + + /** + * @brief Transforms a URL template into a concrete URL for this card/set. + * @param urlTemplate The URL template to transform + * @return The transformed URL or empty string if the template cannot be fulfilled + */ QString transformUrl(const QString &urlTemplate) const; + + /** + * @brief Advance to the next set in the list. + * @return True if a next set exists and was selected, false if at the end. + * + * Updates currentSet and repopulates currentSetUrls. + * If we are already at the end of the list, then currentSet is set to empty. + */ bool nextSet(); + + /** + * @brief Advance to the next URL in the current set's list. + * @return True if a next URL exists, false if at the end. + * + * Updates currentUrl. + * If we are already at the end of the list, then currentUrl is set to empty. + */ bool nextUrl(); + + /** + * @brief Populates the currentSetUrls list with URLs for the current set. + * + * Includes custom URLs first, followed by template-based URLs. + */ void populateSetUrls(); + /** + * @brief Extract all sets from the card and sort them by priority. + * @param card The card to extract sets from + * @return A non-empty list of CardSetPtr, sorted by priority + * + * If the card has no sets, a dummy set is inserted. Also ensures + * the printing corresponding to the ExactCard is first in the list. + */ static QList extractSetsSorted(const ExactCard &card); }; diff --git a/cockatrice/src/interface/deck_loader/deck_loader.cpp b/cockatrice/src/interface/deck_loader/deck_loader.cpp index 9e309c55d..b33aa5881 100644 --- a/cockatrice/src/interface/deck_loader/deck_loader.cpp +++ b/cockatrice/src/interface/deck_loader/deck_loader.cpp @@ -33,6 +33,7 @@ DeckLoader::DeckLoader(QObject *parent) DeckLoader::DeckLoader(QObject *parent, DeckList *_deckList) : QObject(parent), deckList(_deckList), lastFileFormat(CockatriceFormat), lastRemoteDeckId(-1) { + deckList->setParent(this); } DeckLoader::DeckLoader(const DeckLoader &other) @@ -44,6 +45,7 @@ DeckLoader::DeckLoader(const DeckLoader &other) void DeckLoader::setDeckList(DeckList *_deckList) { deckList = _deckList; + deckList->setParent(this); } bool DeckLoader::loadFromFile(const QString &fileName, FileFormat fmt, bool userRequest) diff --git a/cockatrice/src/interface/layouts/overlap_layout.h b/cockatrice/src/interface/layouts/overlap_layout.h index 47209a2ec..5844fca41 100644 --- a/cockatrice/src/interface/layouts/overlap_layout.h +++ b/cockatrice/src/interface/layouts/overlap_layout.h @@ -27,18 +27,18 @@ public: void insertWidgetAtIndex(QWidget *toInsert, int index); void addItem(QLayoutItem *item) override; - int count() const override; - QLayoutItem *itemAt(int index) const override; + [[nodiscard]] int count() const override; + [[nodiscard]] QLayoutItem *itemAt(int index) const override; QLayoutItem *takeAt(int index) override; void setGeometry(const QRect &rect) override; - QSize minimumSize() const override; - QSize sizeHint() const override; + [[nodiscard]] QSize minimumSize() const override; + [[nodiscard]] QSize sizeHint() const override; void setMaxColumns(int _maxColumns); void setMaxRows(int _maxRows); - int calculateMaxColumns() const; - int calculateRowsForColumns(int columns) const; - int calculateMaxRows() const; - int calculateColumnsForRows(int rows) const; + [[nodiscard]] int calculateMaxColumns() const; + [[nodiscard]] int calculateRowsForColumns(int columns) const; + [[nodiscard]] int calculateMaxRows() const; + [[nodiscard]] int calculateColumnsForRows(int rows) const; void setDirection(Qt::Orientation _direction); private: @@ -50,7 +50,7 @@ private: Qt::Orientation flowDirection; // Calculate the preferred size of the layout - QSize calculatePreferredSize() const; + [[nodiscard]] QSize calculatePreferredSize() const; }; #endif // OVERLAP_LAYOUT_H diff --git a/cockatrice/src/interface/widgets/cards/additional_info/mana_symbol_widget.h b/cockatrice/src/interface/widgets/cards/additional_info/mana_symbol_widget.h index 4c5ad8a0b..2ae76e9c0 100644 --- a/cockatrice/src/interface/widgets/cards/additional_info/mana_symbol_widget.h +++ b/cockatrice/src/interface/widgets/cards/additional_info/mana_symbol_widget.h @@ -20,15 +20,15 @@ public: void toggleSymbol(); void setColorActive(bool active); void updateOpacity(); - bool isColorActive() const + [[nodiscard]] bool isColorActive() const { return isActive; }; - QString getSymbol() const + [[nodiscard]] QString getSymbol() const { return symbol; }; - QChar getSymbolChar() const + [[nodiscard]] QChar getSymbolChar() const { return symbol[0]; }; diff --git a/cockatrice/src/interface/widgets/deck_analytics/mana_base_widget.cpp b/cockatrice/src/interface/widgets/deck_analytics/mana_base_widget.cpp index 27079dd52..568583af5 100644 --- a/cockatrice/src/interface/widgets/deck_analytics/mana_base_widget.cpp +++ b/cockatrice/src/interface/widgets/deck_analytics/mana_base_widget.cpp @@ -78,20 +78,14 @@ void ManaBaseWidget::updateDisplay() QHash ManaBaseWidget::analyzeManaBase() { manaBaseMap.clear(); - InnerDecklistNode *listRoot = deckListModel->getDeckList()->getRoot(); - for (int i = 0; i < listRoot->size(); i++) { - InnerDecklistNode *currentZone = dynamic_cast(listRoot->at(i)); - for (int j = 0; j < currentZone->size(); j++) { - DecklistCardNode *currentCard = dynamic_cast(currentZone->at(j)); - if (!currentCard) - continue; + QList cardsInDeck = deckListModel->getDeckList()->getCardNodes(); - for (int k = 0; k < currentCard->getNumber(); ++k) { - CardInfoPtr info = CardDatabaseManager::query()->getCardInfo(currentCard->getName()); - if (info) { - auto devotion = determineManaProduction(info->getText()); - mergeManaCounts(manaBaseMap, devotion); - } + for (auto currentCard : cardsInDeck) { + for (int k = 0; k < currentCard->getNumber(); ++k) { + CardInfoPtr info = CardDatabaseManager::query()->getCardInfo(currentCard->getName()); + if (info) { + auto devotion = determineManaProduction(info->getText()); + mergeManaCounts(manaBaseMap, devotion); } } } diff --git a/cockatrice/src/interface/widgets/deck_analytics/mana_curve_widget.cpp b/cockatrice/src/interface/widgets/deck_analytics/mana_curve_widget.cpp index 668b3afd5..4515b723b 100644 --- a/cockatrice/src/interface/widgets/deck_analytics/mana_curve_widget.cpp +++ b/cockatrice/src/interface/widgets/deck_analytics/mana_curve_widget.cpp @@ -44,20 +44,15 @@ void ManaCurveWidget::setDeckModel(DeckListModel *deckModel) std::unordered_map ManaCurveWidget::analyzeManaCurve() { manaCurveMap.clear(); - InnerDecklistNode *listRoot = deckListModel->getDeckList()->getRoot(); - for (int i = 0; i < listRoot->size(); i++) { - InnerDecklistNode *currentZone = dynamic_cast(listRoot->at(i)); - for (int j = 0; j < currentZone->size(); j++) { - DecklistCardNode *currentCard = dynamic_cast(currentZone->at(j)); - if (!currentCard) - continue; - for (int k = 0; k < currentCard->getNumber(); ++k) { - CardInfoPtr info = CardDatabaseManager::query()->getCardInfo(currentCard->getName()); - if (info) { - int cmc = info->getCmc().toInt(); - manaCurveMap[cmc]++; - } + QList cardsInDeck = deckListModel->getDeckList()->getCardNodes(); + + for (auto currentCard : cardsInDeck) { + for (int k = 0; k < currentCard->getNumber(); ++k) { + CardInfoPtr info = CardDatabaseManager::query()->getCardInfo(currentCard->getName()); + if (info) { + int cmc = info->getCmc().toInt(); + manaCurveMap[cmc]++; } } } diff --git a/cockatrice/src/interface/widgets/deck_analytics/mana_devotion_widget.cpp b/cockatrice/src/interface/widgets/deck_analytics/mana_devotion_widget.cpp index 4454caef1..3cafdaeab 100644 --- a/cockatrice/src/interface/widgets/deck_analytics/mana_devotion_widget.cpp +++ b/cockatrice/src/interface/widgets/deck_analytics/mana_devotion_widget.cpp @@ -46,20 +46,15 @@ void ManaDevotionWidget::setDeckModel(DeckListModel *deckModel) std::unordered_map ManaDevotionWidget::analyzeManaDevotion() { manaDevotionMap.clear(); - InnerDecklistNode *listRoot = deckListModel->getDeckList()->getRoot(); - for (int i = 0; i < listRoot->size(); i++) { - InnerDecklistNode *currentZone = dynamic_cast(listRoot->at(i)); - for (int j = 0; j < currentZone->size(); j++) { - DecklistCardNode *currentCard = dynamic_cast(currentZone->at(j)); - if (!currentCard) - continue; - for (int k = 0; k < currentCard->getNumber(); ++k) { - CardInfoPtr info = CardDatabaseManager::query()->getCardInfo(currentCard->getName()); - if (info) { - auto devotion = countManaSymbols(info->getManaCost()); - mergeManaCounts(manaDevotionMap, devotion); - } + QList cardsInDeck = deckListModel->getDeckList()->getCardNodes(); + + for (auto currentCard : cardsInDeck) { + for (int k = 0; k < currentCard->getNumber(); ++k) { + CardInfoPtr info = CardDatabaseManager::query()->getCardInfo(currentCard->getName()); + if (info) { + auto devotion = countManaSymbols(info->getManaCost()); + mergeManaCounts(manaDevotionMap, devotion); } } } diff --git a/cockatrice/src/interface/widgets/deck_editor/deck_editor_deck_dock_widget.cpp b/cockatrice/src/interface/widgets/deck_editor/deck_editor_deck_dock_widget.cpp index c83171c78..7a4820dd5 100644 --- a/cockatrice/src/interface/widgets/deck_editor/deck_editor_deck_dock_widget.cpp +++ b/cockatrice/src/interface/widgets/deck_editor/deck_editor_deck_dock_widget.cpp @@ -34,7 +34,7 @@ void DeckEditorDeckDockWidget::createDeckDock() deckLoader = new DeckLoader(this, deckModel->getDeckList()); - DeckListStyleProxy *proxy = new DeckListStyleProxy(this); + proxy = new DeckListStyleProxy(this); proxy->setSourceModel(deckModel); deckView = new QTreeView(); @@ -233,9 +233,7 @@ ExactCard DeckEditorDeckDockWidget::getCurrentCard() const QString zoneName = gparent.sibling(gparent.row(), 1).data(Qt::EditRole).toString(); if (!current.model()->hasChildren(current.sibling(current.row(), 0))) { - QString cardName = current.sibling(current.row(), 1).data().toString(); - QString providerId = current.sibling(current.row(), 4).data().toString(); - if (ExactCard selectedCard = CardDatabaseManager::query()->getCard({cardName, providerId})) { + if (ExactCard selectedCard = CardDatabaseManager::query()->getCard({cardName, cardProviderID})) { return selectedCard; } } @@ -285,18 +283,12 @@ void DeckEditorDeckDockWidget::updateBannerCardComboBox() // Prepare the new items with deduplication QSet> bannerCardSet; - InnerDecklistNode *listRoot = deckModel->getDeckList()->getRoot(); - for (int i = 0; i < listRoot->size(); i++) { - InnerDecklistNode *currentZone = dynamic_cast(listRoot->at(i)); - for (int j = 0; j < currentZone->size(); j++) { - DecklistCardNode *currentCard = dynamic_cast(currentZone->at(j)); - if (!currentCard) - continue; + QList cardsInDeck = deckModel->getDeckList()->getCardNodes(); - for (int k = 0; k < currentCard->getNumber(); ++k) { - if (CardDatabaseManager::query()->getCard(currentCard->toCardRef())) { - bannerCardSet.insert({currentCard->getName(), currentCard->getCardProviderId()}); - } + for (auto currentCard : cardsInDeck) { + for (int k = 0; k < currentCard->getNumber(); ++k) { + if (CardDatabaseManager::query()->getCard(currentCard->toCardRef())) { + bannerCardSet.insert({currentCard->getName(), currentCard->getCardProviderId()}); } } } @@ -375,6 +367,7 @@ void DeckEditorDeckDockWidget::syncBannerCardComboBoxSelectionWithDeck() void DeckEditorDeckDockWidget::setDeck(DeckLoader *_deck) { deckLoader = _deck; + deckLoader->setParent(this); deckModel->setDeckList(deckLoader->getDeckList()); connect(deckLoader, &DeckLoader::deckLoaded, deckModel, &DeckListModel::rebuildTree); connect(deckLoader->getDeckList(), &DeckList::deckHashChanged, deckModel, &DeckListModel::deckHashChanged); @@ -439,7 +432,9 @@ QModelIndexList DeckEditorDeckDockWidget::getSelectedCardNodes() const { auto selectedRows = deckView->selectionModel()->selectedRows(); - const auto notLeafNode = [this](const auto &index) { return deckModel->hasChildren(index); }; + const auto notLeafNode = [this](const QModelIndex &index) { + return deckModel->hasChildren(proxy->mapToSource(index)); + }; selectedRows.erase(std::remove_if(selectedRows.begin(), selectedRows.end(), notLeafNode), selectedRows.end()); std::reverse(selectedRows.begin(), selectedRows.end()); @@ -506,7 +501,7 @@ bool DeckEditorDeckDockWidget::swapCard(const QModelIndex ¤tIndex) QModelIndex newCardIndex = card ? deckModel->addCard(card, otherZoneName) // Third argument (true) says create the card no matter what, even if not in DB : deckModel->addPreferredPrintingCard(cardName, otherZoneName, true); - recursiveExpand(newCardIndex); + recursiveExpand(proxy->mapToSource(newCardIndex)); return true; } @@ -527,7 +522,7 @@ void DeckEditorDeckDockWidget::actDecrementCard(const ExactCard &card, QString z } deckView->clearSelection(); - deckView->setCurrentIndex(idx); + deckView->setCurrentIndex(proxy->mapToSource(idx)); offsetCountAtIndex(idx, -1); } @@ -563,7 +558,8 @@ void DeckEditorDeckDockWidget::actRemoveCard() if (!index.isValid() || deckModel->hasChildren(index)) { continue; } - deckModel->removeRow(index.row(), index.parent()); + QModelIndex sourceIndex = proxy->mapToSource(index); + deckModel->removeRow(sourceIndex.row(), sourceIndex.parent()); isModified = true; } @@ -580,13 +576,17 @@ void DeckEditorDeckDockWidget::offsetCountAtIndex(const QModelIndex &idx, int of return; } - const QModelIndex numberIndex = idx.sibling(idx.row(), 0); + QModelIndex sourceIndex = proxy->mapToSource(idx); + + const QModelIndex numberIndex = sourceIndex.sibling(sourceIndex.row(), 0); const int count = deckModel->data(numberIndex, Qt::EditRole).toInt(); const int new_count = count + offset; - if (new_count <= 0) - deckModel->removeRow(idx.row(), idx.parent()); - else + + if (new_count <= 0) { + deckModel->removeRow(sourceIndex.row(), sourceIndex.parent()); + } else { deckModel->setData(numberIndex, new_count, Qt::EditRole); + } emit deckModified(); } diff --git a/cockatrice/src/interface/widgets/deck_editor/deck_editor_deck_dock_widget.h b/cockatrice/src/interface/widgets/deck_editor/deck_editor_deck_dock_widget.h index 90b6f9797..d4703a5dc 100644 --- a/cockatrice/src/interface/widgets/deck_editor/deck_editor_deck_dock_widget.h +++ b/cockatrice/src/interface/widgets/deck_editor/deck_editor_deck_dock_widget.h @@ -12,6 +12,7 @@ #include "../../key_signals.h" #include "../utility/custom_line_edit.h" #include "../visual_deck_storage/deck_preview/deck_preview_deck_tags_display_widget.h" +#include "deck_list_style_proxy.h" #include #include @@ -28,6 +29,7 @@ class DeckEditorDeckDockWidget : public QDockWidget public: explicit DeckEditorDeckDockWidget(AbstractTabDeckEditor *parent); DeckLoader *deckLoader; + DeckListStyleProxy *proxy; DeckListModel *deckModel; QTreeView *deckView; QComboBox *bannerCardComboBox; diff --git a/cockatrice/src/interface/widgets/deck_editor/deck_list_style_proxy.h b/cockatrice/src/interface/widgets/deck_editor/deck_list_style_proxy.h index a7e58eb02..52b7eea10 100644 --- a/cockatrice/src/interface/widgets/deck_editor/deck_list_style_proxy.h +++ b/cockatrice/src/interface/widgets/deck_editor/deck_list_style_proxy.h @@ -9,7 +9,7 @@ class DeckListStyleProxy : public QIdentityProxyModel public: using QIdentityProxyModel::QIdentityProxyModel; - QVariant data(const QModelIndex &index, int role) const override; + [[nodiscard]] QVariant data(const QModelIndex &index, int role) const override; }; #endif // COCKATRICE_DECK_LIST_STYLE_PROXY_H diff --git a/cockatrice/src/interface/widgets/dialogs/dlg_connect.h b/cockatrice/src/interface/widgets/dialogs/dlg_connect.h index e89f0b4d6..41993e068 100644 --- a/cockatrice/src/interface/widgets/dialogs/dlg_connect.h +++ b/cockatrice/src/interface/widgets/dialogs/dlg_connect.h @@ -34,16 +34,16 @@ signals: public: explicit DlgConnect(QWidget *parent = nullptr); ~DlgConnect() override; - QString getHost() const; - int getPort() const + [[nodiscard]] QString getHost() const; + [[nodiscard]] int getPort() const { return portEdit->text().toInt(); } - QString getPlayerName() const + [[nodiscard]] QString getPlayerName() const { return playernameEdit->text(); } - QString getPassword() const + [[nodiscard]] QString getPassword() const { return passwordEdit->text(); } diff --git a/cockatrice/src/interface/widgets/dialogs/dlg_create_game.cpp b/cockatrice/src/interface/widgets/dialogs/dlg_create_game.cpp index d69c7a08a..2b1b63065 100644 --- a/cockatrice/src/interface/widgets/dialogs/dlg_create_game.cpp +++ b/cockatrice/src/interface/widgets/dialogs/dlg_create_game.cpp @@ -35,7 +35,7 @@ void DlgCreateGame::sharedCtor() maxPlayersEdit->setValue(2); maxPlayersLabel->setBuddy(maxPlayersEdit); - QGridLayout *generalGrid = new QGridLayout; + auto *generalGrid = new QGridLayout; generalGrid->addWidget(descriptionLabel, 0, 0); generalGrid->addWidget(descriptionEdit, 0, 1); generalGrid->addWidget(maxPlayersLabel, 1, 0); @@ -43,17 +43,17 @@ void DlgCreateGame::sharedCtor() generalGroupBox = new QGroupBox(tr("General")); generalGroupBox->setLayout(generalGrid); - QVBoxLayout *gameTypeLayout = new QVBoxLayout; + auto *gameTypeLayout = new QVBoxLayout; QMapIterator gameTypeIterator(gameTypes); while (gameTypeIterator.hasNext()) { gameTypeIterator.next(); - QRadioButton *gameTypeRadioButton = new QRadioButton(gameTypeIterator.value(), this); + auto *gameTypeRadioButton = new QRadioButton(gameTypeIterator.value(), this); gameTypeLayout->addWidget(gameTypeRadioButton); gameTypeCheckBoxes.insert(gameTypeIterator.key(), gameTypeRadioButton); bool isChecked = SettingsCache::instance().getGameTypes().contains(gameTypeIterator.value() + ", "); gameTypeCheckBoxes[gameTypeIterator.key()]->setChecked(isChecked); } - QGroupBox *gameTypeGroupBox = new QGroupBox(tr("Game type")); + auto *gameTypeGroupBox = new QGroupBox(tr("Game type")); gameTypeGroupBox->setLayout(gameTypeLayout); passwordLabel = new QLabel(tr("&Password:")); @@ -70,13 +70,13 @@ void DlgCreateGame::sharedCtor() onlyRegisteredCheckBox->setEnabled(false); } - QGridLayout *joinRestrictionsLayout = new QGridLayout; + auto *joinRestrictionsLayout = new QGridLayout; joinRestrictionsLayout->addWidget(passwordLabel, 0, 0); joinRestrictionsLayout->addWidget(passwordEdit, 0, 1); joinRestrictionsLayout->addWidget(onlyBuddiesCheckBox, 1, 0, 1, 2); joinRestrictionsLayout->addWidget(onlyRegisteredCheckBox, 2, 0, 1, 2); - QGroupBox *joinRestrictionsGroupBox = new QGroupBox(tr("Joining restrictions")); + auto *joinRestrictionsGroupBox = new QGroupBox(tr("Joining restrictions")); joinRestrictionsGroupBox->setLayout(joinRestrictionsLayout); spectatorsAllowedCheckBox = new QCheckBox(tr("&Spectators can watch")); @@ -86,7 +86,7 @@ void DlgCreateGame::sharedCtor() spectatorsCanTalkCheckBox = new QCheckBox(tr("Spectators can &chat")); spectatorsSeeEverythingCheckBox = new QCheckBox(tr("Spectators can see &hands")); createGameAsSpectatorCheckBox = new QCheckBox(tr("Create game as spectator")); - QVBoxLayout *spectatorsLayout = new QVBoxLayout; + auto *spectatorsLayout = new QVBoxLayout; spectatorsLayout->addWidget(spectatorsAllowedCheckBox); spectatorsLayout->addWidget(spectatorsNeedPasswordCheckBox); spectatorsLayout->addWidget(spectatorsCanTalkCheckBox); @@ -106,7 +106,7 @@ void DlgCreateGame::sharedCtor() shareDecklistsOnLoadCheckBox = new QCheckBox(); shareDecklistsOnLoadLabel->setBuddy(shareDecklistsOnLoadCheckBox); - QGridLayout *gameSetupOptionsLayout = new QGridLayout; + auto *gameSetupOptionsLayout = new QGridLayout; gameSetupOptionsLayout->addWidget(startingLifeTotalLabel, 0, 0); gameSetupOptionsLayout->addWidget(startingLifeTotalEdit, 0, 1); gameSetupOptionsLayout->addWidget(shareDecklistsOnLoadLabel, 1, 0); @@ -136,7 +136,7 @@ void DlgCreateGame::sharedCtor() buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok); connect(buttonBox, &QDialogButtonBox::rejected, this, &DlgCreateGame::reject); - QVBoxLayout *mainLayout = new QVBoxLayout; + auto *mainLayout = new QVBoxLayout; mainLayout->addLayout(grid); mainLayout->addWidget(buttonBox); @@ -275,7 +275,7 @@ void DlgCreateGame::actOK() cmd.set_starting_life_total(startingLifeTotalEdit->value()); cmd.set_share_decklists_on_load(shareDecklistsOnLoadCheckBox->isChecked()); - QString _gameTypes = QString(); + auto _gameTypes = QString(); QMapIterator gameTypeCheckBoxIterator(gameTypeCheckBoxes); while (gameTypeCheckBoxIterator.hasNext()) { gameTypeCheckBoxIterator.next(); diff --git a/cockatrice/src/interface/widgets/dialogs/dlg_edit_avatar.cpp b/cockatrice/src/interface/widgets/dialogs/dlg_edit_avatar.cpp index 28be359a3..7330c749b 100644 --- a/cockatrice/src/interface/widgets/dialogs/dlg_edit_avatar.cpp +++ b/cockatrice/src/interface/widgets/dialogs/dlg_edit_avatar.cpp @@ -23,16 +23,16 @@ DlgEditAvatar::DlgEditAvatar(QWidget *parent) : QDialog(parent), image() browseButton = new QPushButton(tr("Browse...")); connect(browseButton, &QPushButton::clicked, this, &DlgEditAvatar::actBrowse); - QGridLayout *grid = new QGridLayout; + auto *grid = new QGridLayout; grid->addWidget(imageLabel, 0, 0, 1, 2); grid->addWidget(textLabel, 1, 0); grid->addWidget(browseButton, 1, 1); - QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); + auto *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); connect(buttonBox, &QDialogButtonBox::accepted, this, &DlgEditAvatar::actOk); connect(buttonBox, &QDialogButtonBox::rejected, this, &DlgEditAvatar::reject); - QVBoxLayout *mainLayout = new QVBoxLayout; + auto *mainLayout = new QVBoxLayout; mainLayout->addLayout(grid); mainLayout->addWidget(buttonBox); setLayout(mainLayout); diff --git a/cockatrice/src/interface/widgets/dialogs/dlg_edit_user.h b/cockatrice/src/interface/widgets/dialogs/dlg_edit_user.h index 1a01d563a..b89a3be04 100644 --- a/cockatrice/src/interface/widgets/dialogs/dlg_edit_user.h +++ b/cockatrice/src/interface/widgets/dialogs/dlg_edit_user.h @@ -23,15 +23,15 @@ public: QString email = QString(), QString country = QString(), QString realName = QString()); - QString getEmail() const + [[nodiscard]] QString getEmail() const { return emailEdit->text(); } - QString getCountry() const + [[nodiscard]] QString getCountry() const { return countryEdit->currentIndex() == 0 ? "" : countryEdit->currentText(); } - QString getRealName() const + [[nodiscard]] QString getRealName() const { return realnameEdit->text(); } diff --git a/cockatrice/src/interface/widgets/dialogs/dlg_forgot_password_challenge.cpp b/cockatrice/src/interface/widgets/dialogs/dlg_forgot_password_challenge.cpp index c8c86d1f1..7ad957e6c 100644 --- a/cockatrice/src/interface/widgets/dialogs/dlg_forgot_password_challenge.cpp +++ b/cockatrice/src/interface/widgets/dialogs/dlg_forgot_password_challenge.cpp @@ -66,7 +66,7 @@ DlgForgotPasswordChallenge::DlgForgotPasswordChallenge(QWidget *parent) : QDialo playernameEdit->hide(); } - QGridLayout *grid = new QGridLayout; + auto *grid = new QGridLayout; grid->addWidget(infoLabel, 0, 0, 1, 2); grid->addWidget(hostLabel, 1, 0); grid->addWidget(hostEdit, 1, 1); @@ -77,11 +77,11 @@ DlgForgotPasswordChallenge::DlgForgotPasswordChallenge(QWidget *parent) : QDialo grid->addWidget(emailLabel, 4, 0); grid->addWidget(emailEdit, 4, 1); - QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); + auto *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); connect(buttonBox, &QDialogButtonBox::accepted, this, &DlgForgotPasswordChallenge::actOk); connect(buttonBox, &QDialogButtonBox::rejected, this, &DlgForgotPasswordChallenge::reject); - QVBoxLayout *mainLayout = new QVBoxLayout; + auto *mainLayout = new QVBoxLayout; mainLayout->addLayout(grid); mainLayout->addWidget(buttonBox); setLayout(mainLayout); diff --git a/cockatrice/src/interface/widgets/dialogs/dlg_forgot_password_challenge.h b/cockatrice/src/interface/widgets/dialogs/dlg_forgot_password_challenge.h index 88427a7c9..e8925b1d3 100644 --- a/cockatrice/src/interface/widgets/dialogs/dlg_forgot_password_challenge.h +++ b/cockatrice/src/interface/widgets/dialogs/dlg_forgot_password_challenge.h @@ -20,19 +20,19 @@ class DlgForgotPasswordChallenge : public QDialog Q_OBJECT public: explicit DlgForgotPasswordChallenge(QWidget *parent = nullptr); - QString getHost() const + [[nodiscard]] QString getHost() const { return hostEdit->text(); } - int getPort() const + [[nodiscard]] int getPort() const { return portEdit->text().toInt(); } - QString getPlayerName() const + [[nodiscard]] QString getPlayerName() const { return playernameEdit->text(); } - QString getEmail() const + [[nodiscard]] QString getEmail() const { return emailEdit->text(); } diff --git a/cockatrice/src/interface/widgets/dialogs/dlg_forgot_password_request.cpp b/cockatrice/src/interface/widgets/dialogs/dlg_forgot_password_request.cpp index 4921630f3..8f79b543f 100644 --- a/cockatrice/src/interface/widgets/dialogs/dlg_forgot_password_request.cpp +++ b/cockatrice/src/interface/widgets/dialogs/dlg_forgot_password_request.cpp @@ -45,7 +45,7 @@ DlgForgotPasswordRequest::DlgForgotPasswordRequest(QWidget *parent) : QDialog(pa playernameEdit->setMaxLength(MAX_NAME_LENGTH); playernameLabel->setBuddy(playernameEdit); - QGridLayout *grid = new QGridLayout; + auto *grid = new QGridLayout; grid->addWidget(infoLabel, 0, 0, 1, 2); grid->addWidget(hostLabel, 1, 0); grid->addWidget(hostEdit, 1, 1); @@ -54,11 +54,11 @@ DlgForgotPasswordRequest::DlgForgotPasswordRequest(QWidget *parent) : QDialog(pa grid->addWidget(playernameLabel, 3, 0); grid->addWidget(playernameEdit, 3, 1); - QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); + auto *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); connect(buttonBox, &QDialogButtonBox::accepted, this, &DlgForgotPasswordRequest::actOk); connect(buttonBox, &QDialogButtonBox::rejected, this, &DlgForgotPasswordRequest::reject); - QVBoxLayout *mainLayout = new QVBoxLayout; + auto *mainLayout = new QVBoxLayout; mainLayout->addLayout(grid); mainLayout->addWidget(buttonBox); setLayout(mainLayout); diff --git a/cockatrice/src/interface/widgets/dialogs/dlg_load_deck_from_clipboard.cpp b/cockatrice/src/interface/widgets/dialogs/dlg_load_deck_from_clipboard.cpp index 59170c0fc..b1f4d066f 100644 --- a/cockatrice/src/interface/widgets/dialogs/dlg_load_deck_from_clipboard.cpp +++ b/cockatrice/src/interface/widgets/dialogs/dlg_load_deck_from_clipboard.cpp @@ -24,7 +24,7 @@ AbstractDlgDeckTextEdit::AbstractDlgDeckTextEdit(QWidget *parent) : QDialog(pare refreshButton = new QPushButton(tr("&Refresh")); connect(refreshButton, &QPushButton::clicked, this, &AbstractDlgDeckTextEdit::actRefresh); - QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); + auto *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); buttonBox->addButton(refreshButton, QDialogButtonBox::ActionRole); connect(buttonBox, &QDialogButtonBox::accepted, this, &AbstractDlgDeckTextEdit::actOK); connect(buttonBox, &QDialogButtonBox::rejected, this, &AbstractDlgDeckTextEdit::reject); diff --git a/cockatrice/src/interface/widgets/dialogs/dlg_load_deck_from_clipboard.h b/cockatrice/src/interface/widgets/dialogs/dlg_load_deck_from_clipboard.h index 7873d4bf3..d93a020cc 100644 --- a/cockatrice/src/interface/widgets/dialogs/dlg_load_deck_from_clipboard.h +++ b/cockatrice/src/interface/widgets/dialogs/dlg_load_deck_from_clipboard.h @@ -39,7 +39,7 @@ public: * to use it, since otherwise it will get destroyed once this dlg is destroyed * @return The DeckLoader */ - virtual DeckLoader *getDeckList() const = 0; + [[nodiscard]] virtual DeckLoader *getDeckList() const = 0; protected: void setText(const QString &text); @@ -67,7 +67,7 @@ private: public: explicit DlgLoadDeckFromClipboard(QWidget *parent = nullptr); - DeckLoader *getDeckList() const override + [[nodiscard]] DeckLoader *getDeckList() const override { return deckList; } @@ -90,7 +90,7 @@ private: public: explicit DlgEditDeckInClipboard(const DeckLoader &deckList, bool _annotated, QWidget *parent = nullptr); - DeckLoader *getDeckList() const override + [[nodiscard]] DeckLoader *getDeckList() const override { return deckLoader; } diff --git a/cockatrice/src/interface/widgets/dialogs/dlg_load_remote_deck.cpp b/cockatrice/src/interface/widgets/dialogs/dlg_load_remote_deck.cpp index 9abe1949a..214ccc588 100644 --- a/cockatrice/src/interface/widgets/dialogs/dlg_load_remote_deck.cpp +++ b/cockatrice/src/interface/widgets/dialogs/dlg_load_remote_deck.cpp @@ -18,7 +18,7 @@ DlgLoadRemoteDeck::DlgLoadRemoteDeck(AbstractClient *_client, QWidget *parent) : connect(buttonBox, &QDialogButtonBox::accepted, this, &DlgLoadRemoteDeck::accept); connect(buttonBox, &QDialogButtonBox::rejected, this, &DlgLoadRemoteDeck::reject); - QVBoxLayout *mainLayout = new QVBoxLayout; + auto *mainLayout = new QVBoxLayout; mainLayout->addWidget(dirView); mainLayout->addWidget(buttonBox); diff --git a/cockatrice/src/interface/widgets/dialogs/dlg_load_remote_deck.h b/cockatrice/src/interface/widgets/dialogs/dlg_load_remote_deck.h index 372db5ba8..b7e0d7aa3 100644 --- a/cockatrice/src/interface/widgets/dialogs/dlg_load_remote_deck.h +++ b/cockatrice/src/interface/widgets/dialogs/dlg_load_remote_deck.h @@ -28,7 +28,7 @@ private slots: public: explicit DlgLoadRemoteDeck(AbstractClient *_client, QWidget *parent = nullptr); - int getDeckId() const; + [[nodiscard]] int getDeckId() const; }; #endif diff --git a/cockatrice/src/interface/widgets/dialogs/dlg_register.cpp b/cockatrice/src/interface/widgets/dialogs/dlg_register.cpp index dff99e4d8..3493c1047 100644 --- a/cockatrice/src/interface/widgets/dialogs/dlg_register.cpp +++ b/cockatrice/src/interface/widgets/dialogs/dlg_register.cpp @@ -321,7 +321,7 @@ DlgRegister::DlgRegister(QWidget *parent) : QDialog(parent) realnameEdit->setMaxLength(MAX_NAME_LENGTH); realnameLabel->setBuddy(realnameEdit); - QGridLayout *grid = new QGridLayout; + auto *grid = new QGridLayout; grid->addWidget(infoLabel, 0, 0, 1, 2); grid->addWidget(hostLabel, 1, 0); grid->addWidget(hostEdit, 1, 1); @@ -342,11 +342,11 @@ DlgRegister::DlgRegister(QWidget *parent) : QDialog(parent) grid->addWidget(realnameLabel, 10, 0); grid->addWidget(realnameEdit, 10, 1); - QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); + auto *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); connect(buttonBox, &QDialogButtonBox::accepted, this, &DlgRegister::actOk); connect(buttonBox, &QDialogButtonBox::rejected, this, &DlgRegister::reject); - QVBoxLayout *mainLayout = new QVBoxLayout; + auto *mainLayout = new QVBoxLayout; mainLayout->addLayout(grid); mainLayout->addWidget(buttonBox); setLayout(mainLayout); diff --git a/cockatrice/src/interface/widgets/dialogs/dlg_select_set_for_cards.cpp b/cockatrice/src/interface/widgets/dialogs/dlg_select_set_for_cards.cpp index 31e2f8d14..3bb81844c 100644 --- a/cockatrice/src/interface/widgets/dialogs/dlg_select_set_for_cards.cpp +++ b/cockatrice/src/interface/widgets/dialogs/dlg_select_set_for_cards.cpp @@ -209,30 +209,19 @@ QMap DlgSelectSetForCards::getSetsForCards() if (!decklist) return setCounts; - InnerDecklistNode *listRoot = decklist->getRoot(); - if (!listRoot) - return setCounts; + QList cardsInDeck = decklist->getCardNodes(); - for (auto *i : *listRoot) { - auto *countCurrentZone = dynamic_cast(i); - if (!countCurrentZone) + for (auto currentCard : cardsInDeck) { + CardInfoPtr infoPtr = CardDatabaseManager::query()->getCardInfo(currentCard->getName()); + if (!infoPtr) continue; - for (auto *cardNode : *countCurrentZone) { - auto *currentCard = dynamic_cast(cardNode); - if (!currentCard) - continue; - - CardInfoPtr infoPtr = CardDatabaseManager::query()->getCardInfo(currentCard->getName()); - if (!infoPtr) - continue; - - SetToPrintingsMap setMap = infoPtr->getSets(); - for (auto &setName : setMap.keys()) { - setCounts[setName]++; - } + SetToPrintingsMap setMap = infoPtr->getSets(); + for (auto &setName : setMap.keys()) { + setCounts[setName]++; } } + return setCounts; } @@ -263,48 +252,36 @@ void DlgSelectSetForCards::updateCardLists() if (!decklist) return; - InnerDecklistNode *listRoot = decklist->getRoot(); - if (!listRoot) - return; + QList cardsInDeck = decklist->getCardNodes(); - for (auto *i : *listRoot) { - auto *countCurrentZone = dynamic_cast(i); - if (!countCurrentZone) - continue; + for (auto currentCard : cardsInDeck) { + bool found = false; + QString foundSetName; - for (auto *cardNode : *countCurrentZone) { - auto *currentCard = dynamic_cast(cardNode); - if (!currentCard) - continue; - - bool found = false; - QString foundSetName; - - // Check across all sets if the card is present - for (auto it = selectedCardsBySet.begin(); it != selectedCardsBySet.end(); ++it) { - if (it.value().contains(currentCard->getName())) { - found = true; - foundSetName = it.key(); // Store the set name where it was found - break; // Stop at the first match - } + // Check across all sets if the card is present + for (auto it = selectedCardsBySet.begin(); it != selectedCardsBySet.end(); ++it) { + if (it.value().contains(currentCard->getName())) { + found = true; + foundSetName = it.key(); // Store the set name where it was found + break; // Stop at the first match } + } - if (!found) { - // The card was not in any selected set - ExactCard card = CardDatabaseManager::query()->getCard({currentCard->getName()}); - CardInfoPictureWidget *picture_widget = new CardInfoPictureWidget(uneditedCardsFlowWidget); - picture_widget->setCard(card); - uneditedCardsFlowWidget->addWidget(picture_widget); - } else { - ExactCard card = CardDatabaseManager::query()->getCard( - {currentCard->getName(), CardDatabaseManager::getInstance() - ->query() - ->getSpecificPrinting(currentCard->getName(), foundSetName, "") - .getUuid()}); - CardInfoPictureWidget *picture_widget = new CardInfoPictureWidget(modifiedCardsFlowWidget); - picture_widget->setCard(card); - modifiedCardsFlowWidget->addWidget(picture_widget); - } + if (!found) { + // The card was not in any selected set + ExactCard card = CardDatabaseManager::query()->getCard({currentCard->getName()}); + CardInfoPictureWidget *picture_widget = new CardInfoPictureWidget(uneditedCardsFlowWidget); + picture_widget->setCard(card); + uneditedCardsFlowWidget->addWidget(picture_widget); + } else { + ExactCard card = CardDatabaseManager::query()->getCard( + {currentCard->getName(), CardDatabaseManager::getInstance() + ->query() + ->getSpecificPrinting(currentCard->getName(), foundSetName, "") + .getUuid()}); + CardInfoPictureWidget *picture_widget = new CardInfoPictureWidget(modifiedCardsFlowWidget); + picture_widget->setCard(card); + modifiedCardsFlowWidget->addWidget(picture_widget); } } } @@ -364,30 +341,19 @@ QMap DlgSelectSetForCards::getCardsForSets() if (!decklist) return setCards; - InnerDecklistNode *listRoot = decklist->getRoot(); - if (!listRoot) - return setCards; + QList cardsInDeck = decklist->getCardNodes(); - for (auto *i : *listRoot) { - auto *countCurrentZone = dynamic_cast(i); - if (!countCurrentZone) + for (auto currentCard : cardsInDeck) { + CardInfoPtr infoPtr = CardDatabaseManager::query()->getCardInfo(currentCard->getName()); + if (!infoPtr) continue; - for (auto *cardNode : *countCurrentZone) { - auto *currentCard = dynamic_cast(cardNode); - if (!currentCard) - continue; - - CardInfoPtr infoPtr = CardDatabaseManager::query()->getCardInfo(currentCard->getName()); - if (!infoPtr) - continue; - - SetToPrintingsMap setMap = infoPtr->getSets(); - for (auto it = setMap.begin(); it != setMap.end(); ++it) { - setCards[it.key()].append(currentCard->getName()); - } + SetToPrintingsMap setMap = infoPtr->getSets(); + for (auto it = setMap.begin(); it != setMap.end(); ++it) { + setCards[it.key()].append(currentCard->getName()); } } + return setCards; } diff --git a/cockatrice/src/interface/widgets/dialogs/dlg_select_set_for_cards.h b/cockatrice/src/interface/widgets/dialogs/dlg_select_set_for_cards.h index 93eb592c6..335b86d2c 100644 --- a/cockatrice/src/interface/widgets/dialogs/dlg_select_set_for_cards.h +++ b/cockatrice/src/interface/widgets/dialogs/dlg_select_set_for_cards.h @@ -78,7 +78,7 @@ public: QStringList getAllCardsForSet(); void populateCardList(); void updateCardDisplayWidgets(); - bool isChecked() const; + [[nodiscard]] bool isChecked() const; DlgSelectSetForCards *parent; QString setName; bool expanded; diff --git a/cockatrice/src/interface/widgets/dialogs/dlg_settings.cpp b/cockatrice/src/interface/widgets/dialogs/dlg_settings.cpp index d825a2125..73508d843 100644 --- a/cockatrice/src/interface/widgets/dialogs/dlg_settings.cpp +++ b/cockatrice/src/interface/widgets/dialogs/dlg_settings.cpp @@ -141,38 +141,38 @@ GeneralSettingsPage::GeneralSettingsPage() deckPathEdit = new QLineEdit(settings.getDeckPath()); deckPathEdit->setReadOnly(true); - QPushButton *deckPathButton = new QPushButton("..."); + auto *deckPathButton = new QPushButton("..."); connect(deckPathButton, &QPushButton::clicked, this, &GeneralSettingsPage::deckPathButtonClicked); filtersPathEdit = new QLineEdit(settings.getFiltersPath()); filtersPathEdit->setReadOnly(true); - QPushButton *filtersPathButton = new QPushButton("..."); + auto *filtersPathButton = new QPushButton("..."); connect(filtersPathButton, &QPushButton::clicked, this, &GeneralSettingsPage::filtersPathButtonClicked); replaysPathEdit = new QLineEdit(settings.getReplaysPath()); replaysPathEdit->setReadOnly(true); - QPushButton *replaysPathButton = new QPushButton("..."); + auto *replaysPathButton = new QPushButton("..."); connect(replaysPathButton, &QPushButton::clicked, this, &GeneralSettingsPage::replaysPathButtonClicked); picsPathEdit = new QLineEdit(settings.getPicsPath()); picsPathEdit->setReadOnly(true); - QPushButton *picsPathButton = new QPushButton("..."); + auto *picsPathButton = new QPushButton("..."); connect(picsPathButton, &QPushButton::clicked, this, &GeneralSettingsPage::picsPathButtonClicked); cardDatabasePathEdit = new QLineEdit(settings.getCardDatabasePath()); cardDatabasePathEdit->setReadOnly(true); - QPushButton *cardDatabasePathButton = new QPushButton("..."); + auto *cardDatabasePathButton = new QPushButton("..."); connect(cardDatabasePathButton, &QPushButton::clicked, this, &GeneralSettingsPage::cardDatabasePathButtonClicked); customCardDatabasePathEdit = new QLineEdit(settings.getCustomCardDatabasePath()); customCardDatabasePathEdit->setReadOnly(true); - QPushButton *customCardDatabasePathButton = new QPushButton("..."); + auto *customCardDatabasePathButton = new QPushButton("..."); connect(customCardDatabasePathButton, &QPushButton::clicked, this, &GeneralSettingsPage::customCardDatabaseButtonClicked); tokenDatabasePathEdit = new QLineEdit(settings.getTokenDatabasePath()); tokenDatabasePathEdit->setReadOnly(true); - QPushButton *tokenDatabasePathButton = new QPushButton("..."); + auto *tokenDatabasePathButton = new QPushButton("..."); connect(tokenDatabasePathButton, &QPushButton::clicked, this, &GeneralSettingsPage::tokenDatabasePathButtonClicked); // Required init here to avoid crashing on Portable builds diff --git a/cockatrice/src/interface/widgets/general/display/banner_widget.h b/cockatrice/src/interface/widgets/general/display/banner_widget.h index d43693903..8a81dcfce 100644 --- a/cockatrice/src/interface/widgets/general/display/banner_widget.h +++ b/cockatrice/src/interface/widgets/general/display/banner_widget.h @@ -26,7 +26,7 @@ public: void setText(const QString &text) const; void setClickable(bool _clickable); void setBuddy(QWidget *_buddy); - QString getText() const + [[nodiscard]] QString getText() const { return bannerLabel->text(); } diff --git a/cockatrice/src/interface/widgets/printing_selector/card_amount_widget.cpp b/cockatrice/src/interface/widgets/printing_selector/card_amount_widget.cpp index 168a21ee7..416de18dc 100644 --- a/cockatrice/src/interface/widgets/printing_selector/card_amount_widget.cpp +++ b/cockatrice/src/interface/widgets/printing_selector/card_amount_widget.cpp @@ -266,35 +266,16 @@ int CardAmountWidget::countCardsInZone(const QString &deckZone) return -1; } - InnerDecklistNode *listRoot = decklist->getRoot(); - if (!listRoot) { - return -1; - } + QList cardsInDeck = decklist->getCardNodes({deckZone}); int count = 0; - - for (auto *i : *listRoot) { - auto *countCurrentZone = dynamic_cast(i); - if (!countCurrentZone) { - continue; - } - - if (countCurrentZone->getName() != deckZone) { - continue; - } - - for (auto *cardNode : *countCurrentZone) { - auto *currentCard = dynamic_cast(cardNode); - if (!currentCard) { - continue; - } - - for (int k = 0; k < currentCard->getNumber(); ++k) { - if (currentCard->getCardProviderId() == rootCard.getPrinting().getProperty("uuid")) { - count++; - } + for (auto currentCard : cardsInDeck) { + for (int k = 0; k < currentCard->getNumber(); ++k) { + if (currentCard->getCardProviderId() == rootCard.getPrinting().getProperty("uuid")) { + count++; } } } + return count; } \ No newline at end of file diff --git a/cockatrice/src/interface/widgets/printing_selector/printing_selector.cpp b/cockatrice/src/interface/widgets/printing_selector/printing_selector.cpp index 1a47c56a6..a551ac290 100644 --- a/cockatrice/src/interface/widgets/printing_selector/printing_selector.cpp +++ b/cockatrice/src/interface/widgets/printing_selector/printing_selector.cpp @@ -218,7 +218,7 @@ void PrintingSelector::getAllSetsForCurrentCard() connect(widgetLoadingBufferTimer, &QTimer::timeout, this, [=, this]() mutable { for (int i = 0; i < BATCH_SIZE && currentIndex < printingsToUse.size(); ++i, ++currentIndex) { - ExactCard card = ExactCard(selectedCard, printingsToUse[currentIndex]); + auto card = ExactCard(selectedCard, printingsToUse[currentIndex]); auto *cardDisplayWidget = new PrintingSelectorCardDisplayWidget( this, deckEditor, deckModel, deckView, cardSizeWidget->getSlider(), card, currentZone); flowWidget->addWidget(cardDisplayWidget); diff --git a/cockatrice/src/interface/widgets/printing_selector/printing_selector.h b/cockatrice/src/interface/widgets/printing_selector/printing_selector.h index 7da861d24..b83768327 100644 --- a/cockatrice/src/interface/widgets/printing_selector/printing_selector.h +++ b/cockatrice/src/interface/widgets/printing_selector/printing_selector.h @@ -36,7 +36,7 @@ public: void setCard(const CardInfoPtr &newCard, const QString &_currentZone); void getAllSetsForCurrentCard(); - DeckListModel *getDeckModel() const + [[nodiscard]] DeckListModel *getDeckModel() const { return deckModel; }; diff --git a/cockatrice/src/interface/widgets/printing_selector/printing_selector_card_selection_widget.cpp b/cockatrice/src/interface/widgets/printing_selector/printing_selector_card_selection_widget.cpp index 9c046a51b..57d5fd895 100644 --- a/cockatrice/src/interface/widgets/printing_selector/printing_selector_card_selection_widget.cpp +++ b/cockatrice/src/interface/widgets/printing_selector/printing_selector_card_selection_widget.cpp @@ -47,7 +47,7 @@ void PrintingSelectorCardSelectionWidget::connectSignals() void PrintingSelectorCardSelectionWidget::selectSetForCards() { - DlgSelectSetForCards *setSelectionDialog = new DlgSelectSetForCards(nullptr, parent->getDeckModel()); + auto *setSelectionDialog = new DlgSelectSetForCards(nullptr, parent->getDeckModel()); if (!setSelectionDialog->exec()) { return; } diff --git a/cockatrice/src/interface/widgets/server/chat_view/chat_view.h b/cockatrice/src/interface/widgets/server/chat_view/chat_view.h index 9b2287726..00fcc4f5e 100644 --- a/cockatrice/src/interface/widgets/server/chat_view/chat_view.h +++ b/cockatrice/src/interface/widgets/server/chat_view/chat_view.h @@ -68,7 +68,7 @@ private: QAction *messageClicked; QMap> userMessagePositions; - QTextFragment getFragmentUnderMouse(const QPoint &pos) const; + [[nodiscard]] QTextFragment getFragmentUnderMouse(const QPoint &pos) const; QTextCursor prepareBlock(bool same = false); void appendCardTag(QTextCursor &cursor, const QString &cardName); void appendUrlTag(QTextCursor &cursor, QString url); diff --git a/cockatrice/src/interface/widgets/server/games_model.cpp b/cockatrice/src/interface/widgets/server/games_model.cpp index 1da92cdad..4c68390c9 100644 --- a/cockatrice/src/interface/widgets/server/games_model.cpp +++ b/cockatrice/src/interface/widgets/server/games_model.cpp @@ -28,7 +28,7 @@ enum GameListColumn const int DEFAULT_MAX_PLAYERS_MIN = 1; const int DEFAULT_MAX_PLAYERS_MAX = 99; -constexpr QTime DEFAULT_MAX_GAME_AGE = QTime(); +constexpr auto DEFAULT_MAX_GAME_AGE = QTime(); const QString GamesModel::getGameCreatedString(const int secs) { @@ -333,7 +333,7 @@ void GamesProxyModel::setGameFilters(bool _hideBuddiesOnlyGames, int GamesProxyModel::getNumFilteredGames() const { - GamesModel *model = qobject_cast(sourceModel()); + auto *model = qobject_cast(sourceModel()); if (!model) return 0; diff --git a/cockatrice/src/interface/widgets/server/remote/remote_replay_list_tree_widget.cpp b/cockatrice/src/interface/widgets/server/remote/remote_replay_list_tree_widget.cpp index a5e8e46df..5152880d9 100644 --- a/cockatrice/src/interface/widgets/server/remote/remote_replay_list_tree_widget.cpp +++ b/cockatrice/src/interface/widgets/server/remote/remote_replay_list_tree_widget.cpp @@ -48,7 +48,7 @@ int RemoteReplayList_TreeModel::rowCount(const QModelIndex &parent) const if (!parent.isValid()) return replayMatches.size(); - MatchNode *matchNode = dynamic_cast(static_cast(parent.internalPointer())); + auto *matchNode = dynamic_cast(static_cast(parent.internalPointer())); if (matchNode) return matchNode->size(); else @@ -62,7 +62,7 @@ QVariant RemoteReplayList_TreeModel::data(const QModelIndex &index, int role) co if (index.column() >= numberOfColumns) return QVariant(); - ReplayNode *replayNode = dynamic_cast(static_cast(index.internalPointer())); + auto *replayNode = dynamic_cast(static_cast(index.internalPointer())); if (replayNode) { const ServerInfo_Replay &replayInfo = replayNode->getReplayInfo(); switch (role) { @@ -84,7 +84,7 @@ QVariant RemoteReplayList_TreeModel::data(const QModelIndex &index, int role) co return index.column() == 0 ? fileIcon : QVariant(); } } else { - MatchNode *matchNode = dynamic_cast(static_cast(index.internalPointer())); + auto *matchNode = dynamic_cast(static_cast(index.internalPointer())); const ServerInfo_ReplayMatch &matchInfo = matchNode->getMatchInfo(); switch (role) { case Qt::TextAlignmentRole: @@ -170,7 +170,7 @@ QModelIndex RemoteReplayList_TreeModel::index(int row, int column, const QModelI if (!hasIndex(row, column, parent)) return QModelIndex(); - MatchNode *matchNode = dynamic_cast(static_cast(parent.internalPointer())); + auto *matchNode = dynamic_cast(static_cast(parent.internalPointer())); if (matchNode) { if (row >= matchNode->size()) return QModelIndex(); @@ -188,7 +188,7 @@ QModelIndex RemoteReplayList_TreeModel::parent(const QModelIndex &ind) const if (matchNode) return QModelIndex(); else { - ReplayNode *replayNode = dynamic_cast(static_cast(ind.internalPointer())); + auto *replayNode = dynamic_cast(static_cast(ind.internalPointer())); return createIndex(replayNode->getParent()->indexOf(replayNode), 0, replayNode->getParent()); } } @@ -206,7 +206,7 @@ ServerInfo_Replay const *RemoteReplayList_TreeModel::getReplay(const QModelIndex if (!index.isValid()) return 0; - ReplayNode *node = dynamic_cast(static_cast(index.internalPointer())); + auto *node = dynamic_cast(static_cast(index.internalPointer())); if (!node) return 0; return &node->getReplayInfo(); diff --git a/cockatrice/src/interface/widgets/server/user/user_context_menu.cpp b/cockatrice/src/interface/widgets/server/user/user_context_menu.cpp index a255a38d5..cb7d2eca9 100644 --- a/cockatrice/src/interface/widgets/server/user/user_context_menu.cpp +++ b/cockatrice/src/interface/widgets/server/user/user_context_menu.cpp @@ -110,7 +110,7 @@ void UserContextMenu::gamesOfUserReceived(const Response &resp, const CommandCon gameTypeMap.insert(roomInfo.room_id(), tempMap); } - GameSelector *selector = new GameSelector(client, tabSupervisor, nullptr, roomMap, gameTypeMap, false, false); + auto *selector = new GameSelector(client, tabSupervisor, nullptr, roomMap, gameTypeMap, false, false); selector->setParent(static_cast(parent()), Qt::Window); const int gameListSize = response.game_list_size(); for (int i = 0; i < gameListSize; ++i) { @@ -128,7 +128,7 @@ void UserContextMenu::banUser_processUserInfoResponse(const Response &r) const Response_GetUserInfo &response = r.GetExtension(Response_GetUserInfo::ext); // The dialog needs to be non-modal in order to not block the event queue of the client. - BanDialog *dlg = new BanDialog(response.user_info(), static_cast(parent())); + auto *dlg = new BanDialog(response.user_info(), static_cast(parent())); connect(dlg, &QDialog::accepted, this, &UserContextMenu::banUser_dialogFinished); dlg->show(); } @@ -141,7 +141,7 @@ void UserContextMenu::warnUser_processGetWarningsListResponse(const Response &r) QString clientid = QString::fromStdString(response.user_clientid()).simplified(); // The dialog needs to be non-modal in order to not block the event queue of the client. - WarningDialog *dlg = new WarningDialog(user, clientid, static_cast(parent())); + auto *dlg = new WarningDialog(user, clientid, static_cast(parent())); connect(dlg, &QDialog::accepted, this, &UserContextMenu::warnUser_dialogFinished); if (response.warning_size() > 0) { @@ -171,7 +171,7 @@ void UserContextMenu::banUserHistory_processResponse(const Response &resp) if (resp.response_code() == Response::RespOk) { if (response.ban_list_size() > 0) { - QTableWidget *table = new QTableWidget(); + auto *table = new QTableWidget(); table->setWindowTitle(tr("Ban History")); table->setRowCount(response.ban_list_size()); table->setColumnCount(5); @@ -209,7 +209,7 @@ void UserContextMenu::warnUserHistory_processResponse(const Response &resp) if (resp.response_code() == Response::RespOk) { if (response.warn_list_size() > 0) { - QTableWidget *table = new QTableWidget(); + auto *table = new QTableWidget(); table->setWindowTitle(tr("Warning History")); table->setRowCount(response.warn_list_size()); table->setColumnCount(4); @@ -278,7 +278,7 @@ void UserContextMenu::adjustMod_processUserResponse(const Response &resp, const void UserContextMenu::banUser_dialogFinished() { - BanDialog *dlg = static_cast(sender()); + auto *dlg = static_cast(sender()); Command_BanFromServer cmd; cmd.set_user_name(dlg->getBanName().toStdString()); @@ -297,7 +297,7 @@ void UserContextMenu::banUser_dialogFinished() void UserContextMenu::warnUser_dialogFinished() { - WarningDialog *dlg = static_cast(sender()); + auto *dlg = static_cast(sender()); if (dlg->getName().isEmpty() || userListProxy->getOwnUsername().simplified().isEmpty()) return; @@ -433,7 +433,7 @@ void UserContextMenu::showContextMenu(const QPoint &pos, QAction *actionClicked = menu->exec(pos); if (actionClicked == nullptr) { } else if (actionClicked == aDetails) { - UserInfoBox *infoWidget = + auto *infoWidget = new UserInfoBox(client, false, static_cast(parent()), Qt::Dialog | Qt::WindowTitleHint | Qt::CustomizeWindowHint | Qt::WindowCloseButtonHint); infoWidget->setAttribute(Qt::WA_DeleteOnClose); diff --git a/cockatrice/src/interface/widgets/server/user/user_list_proxy.h b/cockatrice/src/interface/widgets/server/user/user_list_proxy.h index b1c20645c..bff76077f 100644 --- a/cockatrice/src/interface/widgets/server/user/user_list_proxy.h +++ b/cockatrice/src/interface/widgets/server/user/user_list_proxy.h @@ -18,11 +18,11 @@ class ServerInfo_User; class UserListProxy { public: - virtual bool isOwnUserRegistered() const = 0; - virtual QString getOwnUsername() const = 0; - virtual bool isUserBuddy(const QString &userName) const = 0; - virtual bool isUserIgnored(const QString &userName) const = 0; - virtual const ServerInfo_User *getOnlineUser(const QString &userName) const = 0; // Can return nullptr + [[nodiscard]] virtual bool isOwnUserRegistered() const = 0; + [[nodiscard]] virtual QString getOwnUsername() const = 0; + [[nodiscard]] virtual bool isUserBuddy(const QString &userName) const = 0; + [[nodiscard]] virtual bool isUserIgnored(const QString &userName) const = 0; + [[nodiscard]] virtual const ServerInfo_User *getOnlineUser(const QString &userName) const = 0; // Can return nullptr }; #endif // COCKATRICE_USERLISTPROXY_H diff --git a/cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/card_prices/edhrec_api_response_card_prices.h b/cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/card_prices/edhrec_api_response_card_prices.h index 7011d3aaf..66a407acd 100644 --- a/cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/card_prices/edhrec_api_response_card_prices.h +++ b/cockatrice/src/interface/widgets/tabs/api/edhrec/api_response/card_prices/edhrec_api_response_card_prices.h @@ -20,39 +20,39 @@ public: void debugPrint() const; // Getter methods for card prices - const QJsonObject &getCardhoarder() const + [[nodiscard]] const QJsonObject &getCardhoarder() const { return cardhoarder; } - const QJsonObject &getCardkingdom() const + [[nodiscard]] const QJsonObject &getCardkingdom() const { return cardkingdom; } - const QJsonObject &getCardmarket() const + [[nodiscard]] const QJsonObject &getCardmarket() const { return cardmarket; } - const QJsonObject &getFace2face() const + [[nodiscard]] const QJsonObject &getFace2face() const { return face2face; } - const QJsonObject &getManapool() const + [[nodiscard]] const QJsonObject &getManapool() const { return manapool; } - const QJsonObject &getMtgstocks() const + [[nodiscard]] const QJsonObject &getMtgstocks() const { return mtgstocks; } - const QJsonObject &getScg() const + [[nodiscard]] const QJsonObject &getScg() const { return scg; } - const QJsonObject &getTcgl() const + [[nodiscard]] const QJsonObject &getTcgl() const { return tcgl; } - const QJsonObject &getTcgplayer() const + [[nodiscard]] const QJsonObject &getTcgplayer() const { return tcgplayer; } diff --git a/cockatrice/src/interface/widgets/tabs/api/edhrec/tab_edhrec.h b/cockatrice/src/interface/widgets/tabs/api/edhrec/tab_edhrec.h index b6030578c..b5ee8d2ca 100644 --- a/cockatrice/src/interface/widgets/tabs/api/edhrec/tab_edhrec.h +++ b/cockatrice/src/interface/widgets/tabs/api/edhrec/tab_edhrec.h @@ -20,7 +20,7 @@ public: explicit TabEdhRec(TabSupervisor *_tabSupervisor); void retranslateUi() override; - QString getTabText() const override + [[nodiscard]] QString getTabText() const override { auto cardName = cardToQuery.isNull() ? QString() : cardToQuery->getName(); return tr("EDHREC: ") + cardName; diff --git a/cockatrice/src/interface/widgets/tabs/api/edhrec/tab_edhrec_main.cpp b/cockatrice/src/interface/widgets/tabs/api/edhrec/tab_edhrec_main.cpp index 95754e8ad..208a5f717 100644 --- a/cockatrice/src/interface/widgets/tabs/api/edhrec/tab_edhrec_main.cpp +++ b/cockatrice/src/interface/widgets/tabs/api/edhrec/tab_edhrec_main.cpp @@ -64,14 +64,14 @@ TabEdhRecMain::TabEdhRecMain(TabSupervisor *_tabSupervisor) : Tab(_tabSupervisor auto cardDatabaseModel = new CardDatabaseModel(CardDatabaseManager::getInstance(), false, this); auto displayModel = new CardDatabaseDisplayModel(this); displayModel->setSourceModel(cardDatabaseModel); - CardSearchModel *searchModel = new CardSearchModel(displayModel, this); + auto *searchModel = new CardSearchModel(displayModel, this); - CardCompleterProxyModel *proxyModel = new CardCompleterProxyModel(this); + auto *proxyModel = new CardCompleterProxyModel(this); proxyModel->setSourceModel(searchModel); proxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive); proxyModel->setFilterRole(Qt::DisplayRole); - QCompleter *completer = new QCompleter(proxyModel, this); + auto *completer = new QCompleter(proxyModel, this); completer->setCompletionRole(Qt::DisplayRole); completer->setCompletionMode(QCompleter::PopupCompletion); completer->setCaseSensitivity(Qt::CaseInsensitive); diff --git a/cockatrice/src/interface/widgets/tabs/tab_admin.cpp b/cockatrice/src/interface/widgets/tabs/tab_admin.cpp index 3ddb53579..533e1cc83 100644 --- a/cockatrice/src/interface/widgets/tabs/tab_admin.cpp +++ b/cockatrice/src/interface/widgets/tabs/tab_admin.cpp @@ -17,22 +17,22 @@ ShutdownDialog::ShutdownDialog(QWidget *parent) : QDialog(parent) { - QLabel *reasonLabel = new QLabel(tr("&Reason for shutdown:")); + auto *reasonLabel = new QLabel(tr("&Reason for shutdown:")); reasonEdit = new QLineEdit; reasonEdit->setMaxLength(MAX_TEXT_LENGTH); reasonLabel->setBuddy(reasonEdit); - QLabel *minutesLabel = new QLabel(tr("&Time until shutdown (minutes):")); + auto *minutesLabel = new QLabel(tr("&Time until shutdown (minutes):")); minutesEdit = new QSpinBox; minutesLabel->setBuddy(minutesEdit); minutesEdit->setMinimum(0); minutesEdit->setValue(5); minutesEdit->setMaximum(999); - QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); + auto *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); connect(buttonBox, &QDialogButtonBox::accepted, this, &ShutdownDialog::accept); connect(buttonBox, &QDialogButtonBox::rejected, this, &ShutdownDialog::reject); - QGridLayout *mainLayout = new QGridLayout; + auto *mainLayout = new QGridLayout; mainLayout->addWidget(reasonLabel, 0, 0); mainLayout->addWidget(reasonEdit, 0, 1); mainLayout->addWidget(minutesLabel, 1, 0); @@ -109,7 +109,7 @@ TabAdmin::TabAdmin(TabSupervisor *_tabSupervisor, AbstractClient *_client, bool lockButton->setEnabled(false); connect(lockButton, &QPushButton::clicked, this, &TabAdmin::actLock); - QVBoxLayout *mainLayout = new QVBoxLayout; + auto *mainLayout = new QVBoxLayout; mainLayout->addWidget(adminGroupBox); mainLayout->addWidget(moderatorGroupBox); mainLayout->addStretch(); @@ -118,7 +118,7 @@ TabAdmin::TabAdmin(TabSupervisor *_tabSupervisor, AbstractClient *_client, bool retranslateUi(); - QWidget *mainWidget = new QWidget(this); + auto *mainWidget = new QWidget(this); mainWidget->setLayout(mainLayout); setCentralWidget(mainWidget); diff --git a/cockatrice/src/interface/widgets/tabs/tab_admin.h b/cockatrice/src/interface/widgets/tabs/tab_admin.h index 5b44a6569..e1935e351 100644 --- a/cockatrice/src/interface/widgets/tabs/tab_admin.h +++ b/cockatrice/src/interface/widgets/tabs/tab_admin.h @@ -29,8 +29,8 @@ private: public: explicit ShutdownDialog(QWidget *parent = nullptr); - QString getReason() const; - int getMinutes() const; + [[nodiscard]] QString getReason() const; + [[nodiscard]] int getMinutes() const; }; class TabAdmin : public Tab @@ -62,11 +62,11 @@ private slots: public: TabAdmin(TabSupervisor *_tabSupervisor, AbstractClient *_client, bool _fullAdmin); void retranslateUi() override; - QString getTabText() const override + [[nodiscard]] QString getTabText() const override { return tr("Administration"); } - bool getLocked() const + [[nodiscard]] bool getLocked() const { return locked; } diff --git a/cockatrice/src/interface/widgets/tabs/tab_deck_editor.h b/cockatrice/src/interface/widgets/tabs/tab_deck_editor.h index 8f6e1f90d..9e00099a0 100644 --- a/cockatrice/src/interface/widgets/tabs/tab_deck_editor.h +++ b/cockatrice/src/interface/widgets/tabs/tab_deck_editor.h @@ -86,7 +86,7 @@ public: void retranslateUi() override; /** @brief Returns the tab text, including modified mark if applicable. */ - QString getTabText() const override; + [[nodiscard]] QString getTabText() const override; /** @brief Creates menus for deck editing and view options. */ void createMenus() override; diff --git a/cockatrice/src/interface/widgets/tabs/tab_game.cpp b/cockatrice/src/interface/widgets/tabs/tab_game.cpp index 02d176cef..8f187575c 100644 --- a/cockatrice/src/interface/widgets/tabs/tab_game.cpp +++ b/cockatrice/src/interface/widgets/tabs/tab_game.cpp @@ -982,7 +982,7 @@ void TabGame::createMenuItems() phasesMenu = new TearOffMenu(this); for (int i = 0; i < phasesToolbar->phaseCount(); ++i) { - QAction *temp = new QAction(QString(), this); + auto *temp = new QAction(QString(), this); connect(temp, &QAction::triggered, this, &TabGame::actPhaseAction); phasesMenu->addAction(temp); phaseActions.append(temp); diff --git a/cockatrice/src/interface/widgets/tabs/tab_game.h b/cockatrice/src/interface/widgets/tabs/tab_game.h index 7c42ce5d2..e500fefbd 100644 --- a/cockatrice/src/interface/widgets/tabs/tab_game.h +++ b/cockatrice/src/interface/widgets/tabs/tab_game.h @@ -183,9 +183,9 @@ public: void updatePlayerListDockTitle(); bool closeRequest() override; - QString getTabText() const override; + [[nodiscard]] QString getTabText() const override; - AbstractGame *getGame() const + [[nodiscard]] AbstractGame *getGame() const { return game; } diff --git a/cockatrice/src/interface/widgets/tabs/tab_logs.h b/cockatrice/src/interface/widgets/tabs/tab_logs.h index f87739051..7cbf6aedc 100644 --- a/cockatrice/src/interface/widgets/tabs/tab_logs.h +++ b/cockatrice/src/interface/widgets/tabs/tab_logs.h @@ -62,7 +62,7 @@ public: TabLog(TabSupervisor *_tabSupervisor, AbstractClient *_client); ~TabLog() override; void retranslateUi() override; - QString getTabText() const override + [[nodiscard]] QString getTabText() const override { return tr("Logs"); } diff --git a/cockatrice/src/interface/widgets/tabs/tab_message.cpp b/cockatrice/src/interface/widgets/tabs/tab_message.cpp index f1a942f16..bd0457990 100644 --- a/cockatrice/src/interface/widgets/tabs/tab_message.cpp +++ b/cockatrice/src/interface/widgets/tabs/tab_message.cpp @@ -34,7 +34,7 @@ TabMessage::TabMessage(TabSupervisor *_tabSupervisor, sayEdit->setMaxLength(MAX_TEXT_LENGTH); connect(sayEdit, &LineEditUnfocusable::returnPressed, this, &TabMessage::sendMessage); - QVBoxLayout *vbox = new QVBoxLayout; + auto *vbox = new QVBoxLayout; vbox->addWidget(chatView); vbox->addWidget(sayEdit); @@ -47,7 +47,7 @@ TabMessage::TabMessage(TabSupervisor *_tabSupervisor, retranslateUi(); - QWidget *mainWidget = new QWidget(this); + auto *mainWidget = new QWidget(this); mainWidget->setLayout(vbox); setCentralWidget(mainWidget); } diff --git a/cockatrice/src/interface/widgets/tabs/tab_replays.h b/cockatrice/src/interface/widgets/tabs/tab_replays.h index bf21ada82..fa1131cd5 100644 --- a/cockatrice/src/interface/widgets/tabs/tab_replays.h +++ b/cockatrice/src/interface/widgets/tabs/tab_replays.h @@ -84,7 +84,7 @@ signals: public: TabReplays(TabSupervisor *_tabSupervisor, AbstractClient *_client, const ServerInfo_User *currentUserInfo); void retranslateUi() override; - QString getTabText() const override + [[nodiscard]] QString getTabText() const override { return tr("Game Replays"); } diff --git a/cockatrice/src/interface/widgets/tabs/tab_room.cpp b/cockatrice/src/interface/widgets/tabs/tab_room.cpp index e1fcca216..92e38662b 100644 --- a/cockatrice/src/interface/widgets/tabs/tab_room.cpp +++ b/cockatrice/src/interface/widgets/tabs/tab_room.cpp @@ -67,7 +67,7 @@ TabRoom::TabRoom(TabSupervisor *_tabSupervisor, sayLabel->setBuddy(sayEdit); connect(sayEdit, &LineEditCompleter::returnPressed, this, &TabRoom::sendMessage); - QMenu *chatSettingsMenu = new QMenu(this); + auto *chatSettingsMenu = new QMenu(this); aClearChat = chatSettingsMenu->addAction(QString()); connect(aClearChat, &QAction::triggered, this, &TabRoom::actClearChat); @@ -77,28 +77,28 @@ TabRoom::TabRoom(TabSupervisor *_tabSupervisor, aOpenChatSettings = chatSettingsMenu->addAction(QString()); connect(aOpenChatSettings, &QAction::triggered, this, &TabRoom::actOpenChatSettings); - QToolButton *chatSettingsButton = new QToolButton; + auto *chatSettingsButton = new QToolButton; chatSettingsButton->setIcon(QPixmap("theme:icons/settings")); chatSettingsButton->setMenu(chatSettingsMenu); chatSettingsButton->setPopupMode(QToolButton::InstantPopup); - QHBoxLayout *sayHbox = new QHBoxLayout; + auto *sayHbox = new QHBoxLayout; sayHbox->addWidget(sayLabel); sayHbox->addWidget(sayEdit); sayHbox->addWidget(chatSettingsButton); - QVBoxLayout *chatVbox = new QVBoxLayout; + auto *chatVbox = new QVBoxLayout; chatVbox->addWidget(chatView); chatVbox->addLayout(sayHbox); chatGroupBox = new QGroupBox; chatGroupBox->setLayout(chatVbox); - QSplitter *splitter = new QSplitter(Qt::Vertical); + auto *splitter = new QSplitter(Qt::Vertical); splitter->addWidget(gameSelector); splitter->addWidget(chatGroupBox); - QHBoxLayout *hbox = new QHBoxLayout; + auto *hbox = new QHBoxLayout; hbox->addWidget(splitter, 3); hbox->addWidget(userList, 1); @@ -133,7 +133,7 @@ TabRoom::TabRoom(TabSupervisor *_tabSupervisor, retranslateUi(); - QWidget *mainWidget = new QWidget(this); + auto *mainWidget = new QWidget(this); mainWidget->setLayout(hbox); setCentralWidget(mainWidget); } diff --git a/cockatrice/src/interface/widgets/tabs/tab_room.h b/cockatrice/src/interface/widgets/tabs/tab_room.h index 8aadab499..c5d0a950a 100644 --- a/cockatrice/src/interface/widgets/tabs/tab_room.h +++ b/cockatrice/src/interface/widgets/tabs/tab_room.h @@ -68,7 +68,7 @@ private: QAction *aLeaveRoom; QAction *aOpenChatSettings; QAction *aClearChat; - QString sanitizeHtml(QString dirty) const; + [[nodiscard]] QString sanitizeHtml(QString dirty) const; QStringList autocompleteUserList; QCompleter *completer; @@ -106,23 +106,23 @@ public: void retranslateUi() override; void tabActivated() override; void processRoomEvent(const RoomEvent &event); - int getRoomId() const + [[nodiscard]] int getRoomId() const { return roomId; } - const QMap &getGameTypes() const + [[nodiscard]] const QMap &getGameTypes() const { return gameTypes; } - QString getChannelName() const + [[nodiscard]] QString getChannelName() const { return roomName; } - QString getTabText() const override + [[nodiscard]] QString getTabText() const override { return roomName; } - const ServerInfo_User *getUserInfo() const + [[nodiscard]] const ServerInfo_User *getUserInfo() const { return ownUser; } diff --git a/cockatrice/src/interface/widgets/tabs/tab_server.h b/cockatrice/src/interface/widgets/tabs/tab_server.h index 39e55fd26..f2dd8f0a2 100644 --- a/cockatrice/src/interface/widgets/tabs/tab_server.h +++ b/cockatrice/src/interface/widgets/tabs/tab_server.h @@ -63,7 +63,7 @@ private: public: TabServer(TabSupervisor *_tabSupervisor, AbstractClient *_client); void retranslateUi() override; - QString getTabText() const override + [[nodiscard]] QString getTabText() const override { return tr("Server"); } diff --git a/cockatrice/src/interface/widgets/tabs/tab_supervisor.cpp b/cockatrice/src/interface/widgets/tabs/tab_supervisor.cpp index 6d6f2d4ec..6d550be01 100644 --- a/cockatrice/src/interface/widgets/tabs/tab_supervisor.cpp +++ b/cockatrice/src/interface/widgets/tabs/tab_supervisor.cpp @@ -931,7 +931,7 @@ void TabSupervisor::deckEditorClosed(AbstractTabDeckEditor *tab) void TabSupervisor::tabUserEvent(bool globalEvent) { - Tab *tab = static_cast(sender()); + auto *tab = static_cast(sender()); if (tab != currentWidget()) { tab->setContentsChanged(true); setTabIcon(indexOf(tab), QPixmap("theme:icons/tab_changed")); @@ -1032,7 +1032,7 @@ void TabSupervisor::processUserJoined(const ServerInfo_User &userInfoJoined) void TabSupervisor::updateCurrent(int index) { if (index != -1) { - Tab *tab = static_cast(widget(index)); + auto *tab = static_cast(widget(index)); if (tab->getContentsChanged()) { setTabIcon(index, QIcon()); tab->setContentsChanged(false); diff --git a/cockatrice/src/interface/widgets/tabs/tab_supervisor.h b/cockatrice/src/interface/widgets/tabs/tab_supervisor.h index e20ba5fb4..7a3b9cbb9 100644 --- a/cockatrice/src/interface/widgets/tabs/tab_supervisor.h +++ b/cockatrice/src/interface/widgets/tabs/tab_supervisor.h @@ -64,8 +64,8 @@ class CloseButton : public QAbstractButton Q_OBJECT public: explicit CloseButton(QWidget *parent = nullptr); - QSize sizeHint() const override; - inline QSize minimumSizeHint() const override + [[nodiscard]] QSize sizeHint() const override; + [[nodiscard]] QSize minimumSizeHint() const override { return sizeHint(); } @@ -129,36 +129,36 @@ public: void start(const ServerInfo_User &userInfo); void startLocal(const QList &_clients); void stop(); - bool getIsLocalGame() const + [[nodiscard]] bool getIsLocalGame() const { return isLocalGame; } - int getGameCount() const + [[nodiscard]] int getGameCount() const { return gameTabs.size(); } - TabAccount *getTabAccount() const + [[nodiscard]] TabAccount *getTabAccount() const { return tabAccount; } - ServerInfo_User *getUserInfo() const + [[nodiscard]] ServerInfo_User *getUserInfo() const { return userInfo; } - AbstractClient *getClient() const; - const UserListManager *getUserListManager() const + [[nodiscard]] AbstractClient *getClient() const; + [[nodiscard]] const UserListManager *getUserListManager() const { return userListManager; } - const QMap &getRoomTabs() const + [[nodiscard]] const QMap &getRoomTabs() const { return roomTabs; } - QList getDeckEditorTabs() const + [[nodiscard]] QList getDeckEditorTabs() const { return deckEditorTabs; } - bool getAdminLocked() const; + [[nodiscard]] bool getAdminLocked() const; void closeEvent(QCloseEvent *event) override; bool switchToGameTabIfAlreadyExists(const int gameId); static void actShowPopup(const QString &message); diff --git a/cockatrice/src/interface/widgets/tabs/tab_visual_database_display.h b/cockatrice/src/interface/widgets/tabs/tab_visual_database_display.h index b9e1a9387..dd6128885 100644 --- a/cockatrice/src/interface/widgets/tabs/tab_visual_database_display.h +++ b/cockatrice/src/interface/widgets/tabs/tab_visual_database_display.h @@ -23,7 +23,7 @@ private: public: TabVisualDatabaseDisplay(TabSupervisor *_tabSupervisor); void retranslateUi() override; - QString getTabText() const override + [[nodiscard]] QString getTabText() const override { return tr("Visual Database Display"); } diff --git a/cockatrice/src/interface/widgets/tabs/visual_deck_editor/tab_deck_editor_visual.h b/cockatrice/src/interface/widgets/tabs/visual_deck_editor/tab_deck_editor_visual.h index 0d34ac91f..87f6c5df8 100644 --- a/cockatrice/src/interface/widgets/tabs/visual_deck_editor/tab_deck_editor_visual.h +++ b/cockatrice/src/interface/widgets/tabs/visual_deck_editor/tab_deck_editor_visual.h @@ -125,7 +125,7 @@ public: * @brief Get the display text for the tab. * @return Tab text with optional modification indicator. */ - QString getTabText() const override; + [[nodiscard]] QString getTabText() const override; /** * @brief Update the currently selected card in the deck and UI. diff --git a/cockatrice/src/interface/widgets/tabs/visual_deck_editor/tab_deck_editor_visual_tab_widget.h b/cockatrice/src/interface/widgets/tabs/visual_deck_editor/tab_deck_editor_visual_tab_widget.h index b84e9bf33..59c577024 100644 --- a/cockatrice/src/interface/widgets/tabs/visual_deck_editor/tab_deck_editor_visual_tab_widget.h +++ b/cockatrice/src/interface/widgets/tabs/visual_deck_editor/tab_deck_editor_visual_tab_widget.h @@ -73,10 +73,10 @@ public: void setTabTitle(int index, const QString &title); /// Get the currently active tab widget. - QWidget *getCurrentTab() const; + [[nodiscard]] QWidget *getCurrentTab() const; /// Get the total number of tabs. - int getTabCount() const; + [[nodiscard]] int getTabCount() const; VisualDeckEditorWidget *visualDeckView; ///< Visual deck editor widget. DeckAnalyticsWidget *deckAnalytics; ///< Deck analytics widget. diff --git a/cockatrice/src/interface/widgets/visual_database_display/visual_database_display_name_filter_widget.cpp b/cockatrice/src/interface/widgets/visual_database_display/visual_database_display_name_filter_widget.cpp index cdb9a8d0c..64eed8b16 100644 --- a/cockatrice/src/interface/widgets/visual_database_display/visual_database_display_name_filter_widget.cpp +++ b/cockatrice/src/interface/widgets/visual_database_display/visual_database_display_name_filter_widget.cpp @@ -67,21 +67,13 @@ void VisualDatabaseDisplayNameFilterWidget::actLoadFromDeck() DeckList *decklist = deckListModel->getDeckList(); if (!decklist) return; - InnerDecklistNode *listRoot = decklist->getRoot(); - if (!listRoot) - return; - for (int i = 0; i < listRoot->size(); i++) { - InnerDecklistNode *currentZone = dynamic_cast(listRoot->at(i)); - if (!currentZone) - continue; - for (int j = 0; j < currentZone->size(); j++) { - DecklistCardNode *currentCard = dynamic_cast(currentZone->at(j)); - if (!currentCard) - continue; - createNameFilter(currentCard->getName()); - } + QList cardsInDeck = decklist->getCardNodes(); + + for (auto currentCard : cardsInDeck) { + createNameFilter(currentCard->getName()); } + updateFilterModel(); } diff --git a/cockatrice/src/interface/widgets/visual_database_display/visual_database_display_sub_type_filter_widget.h b/cockatrice/src/interface/widgets/visual_database_display/visual_database_display_sub_type_filter_widget.h index b77a1ba44..fdddbed41 100644 --- a/cockatrice/src/interface/widgets/visual_database_display/visual_database_display_sub_type_filter_widget.h +++ b/cockatrice/src/interface/widgets/visual_database_display/visual_database_display_sub_type_filter_widget.h @@ -25,7 +25,7 @@ public: void retranslateUi(); void createSubTypeButtons(); void updateSubTypeButtonsVisibility(); - int getMaxSubTypeCount() const; + [[nodiscard]] int getMaxSubTypeCount() const; void handleSubTypeToggled(const QString &mainType, bool active); void updateSubTypeFilter(); diff --git a/cockatrice/src/interface/widgets/visual_deck_editor/visual_deck_editor_sample_hand_widget.cpp b/cockatrice/src/interface/widgets/visual_deck_editor/visual_deck_editor_sample_hand_widget.cpp index ae9cb10ef..b1db1cf37 100644 --- a/cockatrice/src/interface/widgets/visual_deck_editor/visual_deck_editor_sample_hand_widget.cpp +++ b/cockatrice/src/interface/widgets/visual_deck_editor/visual_deck_editor_sample_hand_widget.cpp @@ -83,28 +83,15 @@ QList VisualDeckEditorSampleHandWidget::getRandomCards(int amountToGe DeckList *decklist = deckListModel->getDeckList(); if (!decklist) return randomCards; - InnerDecklistNode *listRoot = decklist->getRoot(); - if (!listRoot) - return randomCards; + + QList cardsInDeck = decklist->getCardNodes({DECK_ZONE_MAIN}); // Collect all cards in the main deck, allowing duplicates based on their count - for (int i = 0; i < listRoot->size(); i++) { - InnerDecklistNode *currentZone = dynamic_cast(listRoot->at(i)); - if (!currentZone) - continue; - if (currentZone->getName() != DECK_ZONE_MAIN) - continue; // Only process the main deck - - for (int j = 0; j < currentZone->size(); j++) { - DecklistCardNode *currentCard = dynamic_cast(currentZone->at(j)); - if (!currentCard) - continue; - - for (int k = 0; k < currentCard->getNumber(); ++k) { - ExactCard card = CardDatabaseManager::query()->getCard(currentCard->toCardRef()); - if (card) { - mainDeckCards.append(card); - } + for (auto currentCard : cardsInDeck) { + for (int k = 0; k < currentCard->getNumber(); ++k) { + ExactCard card = CardDatabaseManager::query()->getCard(currentCard->toCardRef()); + if (card) { + mainDeckCards.append(card); } } } diff --git a/cockatrice/src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_tag_dialog.h b/cockatrice/src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_tag_dialog.h index e3e35fc15..f23040a81 100644 --- a/cockatrice/src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_tag_dialog.h +++ b/cockatrice/src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_tag_dialog.h @@ -25,7 +25,7 @@ public: explicit DeckPreviewTagDialog(const QStringList &knownTags, const QStringList &activeTags, QWidget *parent = nullptr); - QStringList getActiveTags() const; + [[nodiscard]] QStringList getActiveTags() const; void filterTags(const QString &text); private slots: diff --git a/cockatrice/src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_tag_item_widget.h b/cockatrice/src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_tag_item_widget.h index 10670d8a0..5caae90a1 100644 --- a/cockatrice/src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_tag_item_widget.h +++ b/cockatrice/src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_tag_item_widget.h @@ -19,7 +19,7 @@ public: DeckPreviewTagItemWidget(const QString &tagName, bool isChecked, QWidget *parent = nullptr); // Accessor for the checkbox widget - QCheckBox *checkBox() const; + [[nodiscard]] QCheckBox *checkBox() const; private: QCheckBox *checkBox_; // Checkbox to represent the tag's state diff --git a/cockatrice/src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_widget.cpp b/cockatrice/src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_widget.cpp index ca380bc22..df401e247 100644 --- a/cockatrice/src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_widget.cpp +++ b/cockatrice/src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_widget.cpp @@ -232,17 +232,12 @@ void DeckPreviewWidget::updateBannerCardComboBox() // Prepare the new items with deduplication QSet> bannerCardSet; - InnerDecklistNode *listRoot = deckLoader->getDeckList()->getRoot(); - for (auto i : *listRoot) { - auto *currentZone = dynamic_cast(i); - for (auto j : *currentZone) { - auto *currentCard = dynamic_cast(j); - if (!currentCard) - continue; - for (int k = 0; k < currentCard->getNumber(); ++k) { - bannerCardSet.insert(QPair(currentCard->getName(), currentCard->getCardProviderId())); - } + QList cardsInDeck = deckLoader->getDeckList()->getCardNodes(); + + for (auto currentCard : cardsInDeck) { + for (int k = 0; k < currentCard->getNumber(); ++k) { + bannerCardSet.insert(QPair(currentCard->getName(), currentCard->getCardProviderId())); } } diff --git a/cockatrice/src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_widget.h b/cockatrice/src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_widget.h index 25a29b9bd..76db9e569 100644 --- a/cockatrice/src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_widget.h +++ b/cockatrice/src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_widget.h @@ -33,7 +33,7 @@ public: const QString &_filePath); void retranslateUi(); QString getColorIdentity(); - QString getDisplayName() const; + [[nodiscard]] QString getDisplayName() const; VisualDeckStorageWidget *visualDeckStorageWidget; QVBoxLayout *layout; @@ -47,7 +47,7 @@ public: bool filteredBySearch = false; bool filteredByColor = false; bool filteredByTags = false; - bool checkVisibility() const; + [[nodiscard]] bool checkVisibility() const; signals: void deckLoadRequested(const QString &filePath); diff --git a/cockatrice/src/interface/widgets/visual_deck_storage/visual_deck_storage_folder_display_widget.h b/cockatrice/src/interface/widgets/visual_deck_storage/visual_deck_storage_folder_display_widget.h index 3390e016e..fe1693c7e 100644 --- a/cockatrice/src/interface/widgets/visual_deck_storage/visual_deck_storage_folder_display_widget.h +++ b/cockatrice/src/interface/widgets/visual_deck_storage/visual_deck_storage_folder_display_widget.h @@ -27,8 +27,8 @@ public: void createWidgetsForFiles(); void createWidgetsForFolders(); void flattenFolderStructure(); - QStringList gatherAllTagsFromFlowWidget() const; - FlowWidget *getFlowWidget() const + [[nodiscard]] QStringList gatherAllTagsFromFlowWidget() const; + [[nodiscard]] FlowWidget *getFlowWidget() const { return flowWidget; }; diff --git a/cockatrice/src/interface/widgets/visual_deck_storage/visual_deck_storage_quick_settings_widget.h b/cockatrice/src/interface/widgets/visual_deck_storage/visual_deck_storage_quick_settings_widget.h index 9f3225aed..5bb7e4110 100644 --- a/cockatrice/src/interface/widgets/visual_deck_storage/visual_deck_storage_quick_settings_widget.h +++ b/cockatrice/src/interface/widgets/visual_deck_storage/visual_deck_storage_quick_settings_widget.h @@ -47,14 +47,14 @@ public: void retranslateUi(); - bool getShowFolders() const; - bool getDrawUnusedColorIdentities() const; - bool getShowBannerCardComboBox() const; - bool getShowTagFilter() const; - bool getShowTagsOnDeckPreviews() const; - int getUnusedColorIdentitiesOpacity() const; - TooltipType getDeckPreviewTooltip() const; - int getCardSize() const; + [[nodiscard]] bool getShowFolders() const; + [[nodiscard]] bool getDrawUnusedColorIdentities() const; + [[nodiscard]] bool getShowBannerCardComboBox() const; + [[nodiscard]] bool getShowTagFilter() const; + [[nodiscard]] bool getShowTagsOnDeckPreviews() const; + [[nodiscard]] int getUnusedColorIdentitiesOpacity() const; + [[nodiscard]] TooltipType getDeckPreviewTooltip() const; + [[nodiscard]] int getCardSize() const; signals: void showFoldersChanged(bool enabled); diff --git a/cockatrice/src/interface/widgets/visual_deck_storage/visual_deck_storage_tag_filter_widget.h b/cockatrice/src/interface/widgets/visual_deck_storage/visual_deck_storage_tag_filter_widget.h index 50ef855f0..f5f160b55 100644 --- a/cockatrice/src/interface/widgets/visual_deck_storage/visual_deck_storage_tag_filter_widget.h +++ b/cockatrice/src/interface/widgets/visual_deck_storage/visual_deck_storage_tag_filter_widget.h @@ -18,7 +18,7 @@ class VisualDeckStorageTagFilterWidget : public QWidget VisualDeckStorageWidget *parent; - QSet gatherAllTags() const; + [[nodiscard]] QSet gatherAllTags() const; void removeTagsNotInList(const QSet &tags); void addTagsIfNotPresent(const QSet &tags); void addTagIfNotPresent(const QString &tag); @@ -26,7 +26,7 @@ class VisualDeckStorageTagFilterWidget : public QWidget public: explicit VisualDeckStorageTagFilterWidget(VisualDeckStorageWidget *_parent); - QStringList getAllKnownTags() const; + [[nodiscard]] QStringList getAllKnownTags() const; void filterDecksBySelectedTags(const QList &deckPreviews) const; public slots: diff --git a/cockatrice/src/interface/widgets/visual_deck_storage/visual_deck_storage_widget.h b/cockatrice/src/interface/widgets/visual_deck_storage/visual_deck_storage_widget.h index 5ff56bb33..69e70f969 100644 --- a/cockatrice/src/interface/widgets/visual_deck_storage/visual_deck_storage_widget.h +++ b/cockatrice/src/interface/widgets/visual_deck_storage/visual_deck_storage_widget.h @@ -40,7 +40,7 @@ public: VisualDeckStorageTagFilterWidget *tagFilterWidget; bool deckPreviewSelectionAnimationEnabled; - const VisualDeckStorageQuickSettingsWidget *settings() const; + [[nodiscard]] const VisualDeckStorageQuickSettingsWidget *settings() const; public slots: void createRootFolderWidget(); // Refresh the display of cards based on the current sorting option diff --git a/dbconverter/src/mocks.cpp b/dbconverter/src/mocks.cpp index c54d2b9c2..75195fc96 100644 --- a/dbconverter/src/mocks.cpp +++ b/dbconverter/src/mocks.cpp @@ -2,7 +2,7 @@ #include "mocks.h" CardDatabaseSettings::CardDatabaseSettings(const QString &settingPath, QObject *parent) - : SettingsManager(settingPath + "cardDatabase.ini", parent) + : SettingsManager(settingPath + "cardDatabase.ini", QString(), QString(), parent) { } void CardDatabaseSettings::setSortKey(QString /* shortName */, unsigned int /* sortKey */) diff --git a/doc/doxygen-extra-pages/developer_documentation/card_database_schema_and_parsing.md b/doc/doxygen-extra-pages/developer_documentation/card_database_schema_and_parsing.md new file mode 100644 index 000000000..6c5e3512b --- /dev/null +++ b/doc/doxygen-extra-pages/developer_documentation/card_database_schema_and_parsing.md @@ -0,0 +1 @@ +@page card_database_schema_and_parsing Card Database Schema and Parsing \ No newline at end of file diff --git a/doc/doxygen-extra-pages/developer_documentation/displaying_cards.md b/doc/doxygen-extra-pages/developer_documentation/displaying_cards.md new file mode 100644 index 000000000..6a43097c5 --- /dev/null +++ b/doc/doxygen-extra-pages/developer_documentation/displaying_cards.md @@ -0,0 +1,83 @@ +@page displaying_cards Displaying Cards + +Cockatrice offers a number of widgets for displaying cards. To pick the right one for your purpose, it is first +important +to determine the context in which you will be displaying the card. + +# In-client + +In the client (like in your custom widgets), you can use the existing card display widgets. + +## Simple Display + +The most general purpose of these is @ref CardInfoPictureWidget, which simply displays a picture of a card. + +The textual equivalent to this is @ref CardInfoTextWidget, which displays all the properties of a card in text form. + +## Detailed Display + +The convenience class @ref CardInfoDisplayWidget displays both of these widgets in a tabbed container, which allows +choosing between either visual, textual, or both representations at the same time. It is the class that is most +familiar to our users when a single card is highlighted or inspected, since it is used in the deck editor and in-game +for these purposes. + +If you would like the user to be able to inspect a single card in your custom widget, you should +expose a @ref CardInfoDisplayWidget to them and incorporate it as a dock widget inside your custom widget. + +@ref CardInfoDisplayWidget is great for ensuring that the user has all the relevant details of a card available. +It is crucial anywhere the user might encounter a card for the first time or needs to make an informed decision. + +## Visual Display + +However, there is a reason why it is possible to have a visual-only representation of the card in the +@ref CardInfoDisplayWidget. + +Cards are, by design, meant to be represented as images and cards which we can reasonably +expect the user to know (for example, cards contained in a user made deck or explicitly chosen by the user) can be +represented with just their image as a sort of "visual shorthand". + +The simplest way to do this is of course, the above-mentioned @ref CardInfoPictureWidget which simply displays the +picture without modifications. + +However, there exist a couple of other convenience classes which subclass @ref CardInfoPictureWidget to accomplish some +things which you might find useful as well. + +- @ref CardInfoPictureWithTextOverlayWidget displays text overlaid on top of the card picture and scales this text to + fit automatically. +- @ref DeckPreviewCardPictureWidget is a @ref CardInfoPictureWithTextOverlayWidget which also features a + raise-on-mouse-enter animation, controlled by the global setting (TODO: specify which). +- @ref CardInfoPictureArtCropWidget attempts to display an 'art crop' of the card by cropping the upper region of the + card and only displaying that. + +## Groups of Cards + +Sometimes it is useful to display images of cards in groups, for example to represent the deck in the @ref +VisualDeckEditorWidget or during confirmation in the pre-game lobby. + +To this end, Cockatrice offers three convenience classes to display cards for an index in a @ref DeckListModel in a +group and one to display all cards in a particular zone of a @ref DeckListModel. + +The generic way to do this is @ref CardGroupDisplayWidget, which displays cards in @ref QVBoxLayout. This class is very +generic and it is probably a better choice to either subclass it or use one of the two existing implementations. + +@ref FlatCardGroupDisplayWidget displays cards using a horizontal @ref FlowWidget. This means it will fill available +screen space, left to right with no margins, with card pictures, skipping to a new line if it overflows available screen +space horizontally. + +@ref OverlappedCardGroupDisplayWidget displays cards using an @ref OverlapWidget, which displays widgets on top of each +other in vertical columns until it exceeds available screen space in which case it will start a new column. The amount +of overlap as well as the overlap direction is configurable. + +@ref DeckCardZoneDisplayWidget can be used to visualize all cards in a zone with either a @ref +FlatCardGroupDisplayWidget or a @ref OverlappedCardGroupDisplayWidget and headed by a @ref BannerWidget. It also allows +grouping and sorting. + +# In-game + +The in-game view is a @ref QGraphicsScene, which means any widget we want to display inside of it should be a @ref +QGraphicsObject. + +- @ref CardItem + + + diff --git a/doc/doxygen-extra-pages/developer_documentation/index.md b/doc/doxygen-extra-pages/developer_documentation/index.md index 121ee7c6f..b26faf836 100644 --- a/doc/doxygen-extra-pages/developer_documentation/index.md +++ b/doc/doxygen-extra-pages/developer_documentation/index.md @@ -1,3 +1,9 @@ @page developer_reference Developer Reference -- [Contributing](@subpage contributing) +- @subpage primer_cards + +- @subpage card_database_schema_and_parsing +- @subpage querying_the_card_database + +- @subpage loading_card_pictures +- @subpage displaying_cards \ No newline at end of file diff --git a/doc/doxygen-extra-pages/developer_documentation/loading_card_pictures.md b/doc/doxygen-extra-pages/developer_documentation/loading_card_pictures.md new file mode 100644 index 000000000..b606f9e4b --- /dev/null +++ b/doc/doxygen-extra-pages/developer_documentation/loading_card_pictures.md @@ -0,0 +1,52 @@ +@page loading_card_pictures Loading Card Pictures + +Pictures associated with CardInfo%s are retrieved either from on-disk or the network through the CardPictureLoader. + +In most cases, you don't need to concern yourself with the internals of CardPictureLoader. + +Simply using one of the ways described in @ref displaying_cards is enough to automatically queue a request to the +CardPictureLoader when the chosen widget is shown, emitting signals to refresh the widget when the request is finished. + +# How requests are triggered + +CardPictureLoader::getPixmap() is called exactly two times in the code base, in CardInfoPictureWidget::loadPixmap(), the +base class +for all widget based card picture display, and AbstractCardItem::paintPicture(), the base class for all QGraphicsItem +based card picture +display. See @ref displaying_cards for more information on the difference between these two display methods. + +Because both of these calls are made in the paintEvent() methods of their respective classes, this means that requests +are issued as soon as but not before the widget is shown on screen. + +It is also possible to "warm up" the cache by issuing card picture load requests to the CardPictureLoader without using +a display widget and waiting for it to be shown by calling CardPictureLoader::cacheCardPixmaps() with a list of +ExactCard%s. + +# The QPixmapCache and QNetworkDiskCache + +Cockatrice uses the QPixmapCache from the Qt GUI module to store card pictures in-memory and the QNetworkDiskCache from +the Qt Network module to cache network requests for card pictures on-disk. + +What this means is that the CardPictureLoader will first attempt to look up a card in the QPixmapCache according to the +ExactCard::getPixmapCacheKey() method of an ExactCard object. If it does not find it in the in-memory cache, it will +issue a load request, which will first look for local images on-disk and then consult the QNetworkDiskCache and if +found, use the stored binary data from the network cache to populate the in-memory pixmap cache under the card's cache +key. If it is not found, it will then proceed with issuing a network request. + +The size of both of these caches can be configured by the user in the "Card Sources" settings page. + +# PixmapCacheKeys and ProviderIDs + +TODO + +# The Redirect Cache + +TODO + +# Local Image Loading + +TODO + +# URL Generation and Resolution + +TODO \ No newline at end of file diff --git a/doc/doxygen-extra-pages/developer_documentation/primer_cards.md b/doc/doxygen-extra-pages/developer_documentation/primer_cards.md new file mode 100644 index 000000000..8f79adbc9 --- /dev/null +++ b/doc/doxygen-extra-pages/developer_documentation/primer_cards.md @@ -0,0 +1,71 @@ +@page primer_cards A Primer on Cards + +# The Cockatrice Card Library + +All non-gui code related to cards used by Cockatrice is contained within libcockatrice_card. + +# A Basic Card Object: CardInfo + +A CardInfo object is the translational unit used by the CardDatabase to represent an on-disk XML entry as an in-memory +Qt object. + +For a complete overview of the fields that define a CardInfo object, see the class documentation and more specifically +@ref PrivateCardProperties. + +These fields correspond to either entries or a combination of entries in the XML card entry to which the +CardDatabaseParser applies special logic to map, populate or determine their respective values in the CardInfo object. + +Any property to which special parsing is not applied is stored in CardInfo::properties and may be retrieved or set with +CardInfo::getProperty() or CardInfo::setProperty() as well as CardInfo::getProperties() to get a collection of the +property keys a CardInfo contains. + +For more information on how special fields contained within @ref PrivateCardProperties are parsed, see +CockatriceXml4Parser::loadCardsFromXml(). + +Apart from access to the basic and extended properties of a card, CardInfo also provides two important mechanisms to us. +The first is the CardInfo::pixmapUpdated() signal, which allows the CardPictureLoader to signal when it is done +manipulating (in most cases: loading) the QPixmap of an ExactCard::getPixmapCacheKey(), where the ExactCard::card +corresponds to this CardInfo object. + +Put simply: Whenever the CardPictureLoader loads a new PrintingInfo which is not already in the cache, it emits this +signal so that any widget using a CardInfo object can update the display of it to possibly use this new QPixmap. + +\attention It should be noted that it is not possible to use CardPictureLoader::getPixmap() with anything but an +ExactCard, which is a CardInfo object associated with a PrintingInfo, i.e. a definitive printing of a specific card + +The other signal, CardInfo::cardInfoChanged() conceptually works much the same way, except it is concerned with the +properties of the CardInfo object. + +# Getting specific: PrintingInfo and ExactCard + +## Printing Info + +A CardInfo object describes the basic properties of a card in much the same way that we say "Two cards with the same +name are and should be equal if their properties are equal". However, there are certain (mostly visual) properties which +might differ between printings of a card but still conceptually classify two instances of a card as "the same card". +The most obvious example to this are cards which fundamentally share all properties except the artwork depicted on the +card. + +We refer to such differences as Printings and track them in the PrintingInfo class. A PrintingInfo is always related to +the CardSet that introduced the variation. Multiple variations can exist in the same CardSet and the respective +PrintingInfo::getProperty() can be used to determine the differences, such as the collector numbers on the printings, if +there are any. + +## Exact Card + +A CardInfo object is used to hold the functional properties of a card and a PrintingInfo object can be used to hold the +visual properties of a card. To represent a 'physical' card, as in, a concrete immutable instance of a card, we can use +ExactCard, which combines a CardInfo and a PrintingInfo object into one class. The class is used as a container around +CardInfo objects whenever the user (and thus the program) expects to be presented with a defined card printing. + +# Using Cards + +For more information on the XML database schema which the CardDatabaseParser parses to generate CardInfo objects, see +@ref card_database_schema_and_parsing. + +For more information on querying the CardDatabase for CardInfo objects, see @ref querying_the_card_database. + +For more information on displaying CardInfo and ExactCard objects using Qt Widgets, see @ref displaying_cards. + +For more information on how card pictures are loaded from disk or the network, see @ref loading_card_pictures as well as +the CardPictureLoader documentation. \ No newline at end of file diff --git a/doc/doxygen-extra-pages/developer_documentation/querying_the_card_database.md b/doc/doxygen-extra-pages/developer_documentation/querying_the_card_database.md new file mode 100644 index 000000000..b2812b0ad --- /dev/null +++ b/doc/doxygen-extra-pages/developer_documentation/querying_the_card_database.md @@ -0,0 +1,39 @@ +@page querying_the_card_database Querying the Card Database + +# The CardDatabaseQuerier Class + +The CardDatabaseQuerier is the only class used for querying the database. The CardDatabase is an in-memory map and thus +provides no structured query language. CardDatabaseQuerier offers methods to retrieve cards by name, by providerID or in +bulk, as CardSet%s. + +## Obtaining a handle to the CardDatabaseQuerier for usage + +To obtain the CardDatabaseQuerier related to the global CardDatabase singleton, use CardDatabaseManager::query(). + +## Querying for known cards + +There are, essentially, two ways to ensure card equality, with the second being optional but necessitating the first. +These two ways are CardInfo name equality and PrintingInfo provider ID equality. + +Because of this, most queries require, at the very least, a card name to match against and optionally a providerID to +narrow the results. + +### Generic Card Infos + +To check if a card with the exact provided name exists as a CardInfo in the CardDatabase use, +CardDatabaseQuerier::getCardInfo() or CardDatabaseQuerier::getCardInfos() for multiple cards. + +### Guessing Cards + +If the exact name might not be present in the CardDatabase, you can use CardDatabaseQuerier::getCardBySimpleName(), +which automatically simplifies the card name and matches it against simplified card names in the CardDatabase. + +Alternatively, you can use CardDatabaseQuerier::lookupCardByName(), which first attempts an exact match search and then +uses CardDatabaseQuerier::getCardBySimpleName() as a fallback. + +### ExactCard%s + +To obtain an ExactCard from the CardDatabaseQuerier, you must use a CardRef as a parameter to +CardDatabaseQuerier::getCard(), CardDatabaseQuerier::getCards(), or CardDatabaseQuerier::guessCard(). + +CardRef is a simple struct consisting of a card name and a card provider ID as QString%s. \ No newline at end of file diff --git a/doc/doxygen-extra-pages/user_documentation/deck_management/creating_decks.md b/doc/doxygen-extra-pages/user_documentation/deck_management/creating_decks.md new file mode 100644 index 000000000..bfe578afd --- /dev/null +++ b/doc/doxygen-extra-pages/user_documentation/deck_management/creating_decks.md @@ -0,0 +1,17 @@ +@page creating_decks Creating Decks + +Creating a new deck is done using either the \ref editing_decks_classic or \ref editing_decks_visual. + +They can be accessed either by clicking the "Create Deck" button in the TabHome screen, which will open the default deck +editor configured in the "User Interface" -> "Deck editor/storage settings" -> "Default deck editor type" setting, or +by selecting "Deck Editor" or "Visual Deck Editor" under the "Tabs" application menu located at the top. + +# Further References + +See @ref editing_decks for information on how to modify the attributes and contents of a deck in the Deck Editor +widgets. + +See @ref exporting_decks for information on how to store and persist your deck either in-client or to external +services. + +See @ref importing_decks for information on how to import existing decks either in-client or from external services \ No newline at end of file diff --git a/doc/doxygen-extra-pages/user_documentation/deck_management/editing_decks.md b/doc/doxygen-extra-pages/user_documentation/deck_management/editing_decks.md new file mode 100644 index 000000000..d8b96dac3 --- /dev/null +++ b/doc/doxygen-extra-pages/user_documentation/deck_management/editing_decks.md @@ -0,0 +1,5 @@ +@page editing_decks Editing Decks + +@subpage editing_decks_classic + +@subpage editing_decks_visual \ No newline at end of file diff --git a/doc/doxygen-extra-pages/user_documentation/deck_management/editing_decks_classic.md b/doc/doxygen-extra-pages/user_documentation/deck_management/editing_decks_classic.md new file mode 100644 index 000000000..f9f2239bc --- /dev/null +++ b/doc/doxygen-extra-pages/user_documentation/deck_management/editing_decks_classic.md @@ -0,0 +1,54 @@ +@page editing_decks_classic Classic Deck Editor + +\image html classic_deck_editor.png width=900px + +# Editing Basic Deck Information + +Editing basic deck information is done through the deck dock widget (DeckEditorDeckDockWidget). + +\image html deckeditordeckdockwidget.png + +This widget allows editing: + +- The name +- The comments +- The banner card, which is used to represent the deck in the visual deck storage +- The tags, which are used for filtering in the visual deck storage + +# Adding Cards + +Adding cards is done using the list of cards in the database presented in the list view on the left. + +\image html classic_database_display.png + +Cards can be added by either double-clicking an entry, pressing return with an entry selected to add it to the mainboard +or pressing ctrl/cmd + return to add it to the sideboard. + +There are also buttons for these two functions on the right of the search bar above the list view. + +\image html classic_database_display_add_buttons.png + +# Modifying the Deck List + +To modify or remove cards in the deck list, the tree list view in the deck dock widget can be used. + +\image html deck_dock_deck_list.png + +Just above the list, at the top right, there are four buttons to manipulate the currently selected card(s): + +- Increment Card +- Decrement Card +- Remove Card +- Switch Card between Mainboard and Sideboard + +\image html deck_dock_deck_list_buttons.png + +Additionally, there is a combo box above the list, which may be used to change how cards are grouped in the list +display. This is only for visual display and does not affect how the list is saved. + +\image html deck_dock_deck_list_group_by.png + +# Modifying printings + +For more information on modifying the printings in a deck see @ref editing_decks_printings + diff --git a/doc/doxygen-extra-pages/user_documentation/deck_management/editing_decks_printings.md b/doc/doxygen-extra-pages/user_documentation/deck_management/editing_decks_printings.md new file mode 100644 index 000000000..27ade3f63 --- /dev/null +++ b/doc/doxygen-extra-pages/user_documentation/deck_management/editing_decks_printings.md @@ -0,0 +1 @@ +@page editing_decks_printings Printing Selector \ No newline at end of file diff --git a/doc/doxygen-extra-pages/user_documentation/deck_management/editing_decks_visual.md b/doc/doxygen-extra-pages/user_documentation/deck_management/editing_decks_visual.md new file mode 100644 index 000000000..e7d503735 --- /dev/null +++ b/doc/doxygen-extra-pages/user_documentation/deck_management/editing_decks_visual.md @@ -0,0 +1,93 @@ +@page editing_decks_visual Visual Deck Editor + +\image html vde_overlap_layout_type_grouped.png width=1200px + +# Editing Basic Deck Information + +Editing basic deck information is done through the deck dock widget (DeckEditorDeckDockWidget). + +\image html deckeditordeckdockwidget.png + +This widget allows editing: + +- The name +- The comments +- The banner card, which is used to represent the deck in the visual deck storage +- The tags, which are used for filtering in the visual deck storage + +# Adding Cards + +Adding cards is done by either using the "Quick search and add card" search bar at the top of the "Visual Deck View" tab +or by clicking on a picture of a card in the "Visual Database Display" tab. + +See @ref visual_database_display for more information on how to utilize the visual database display. + +# Modifying the Deck List + +To modify or remove cards in the deck list, the tree list view in the deck dock widget can be used. + +\image html deck_dock_deck_list.png + +Just above the list, at the top right, there are four buttons to manipulate the currently selected card(s): + +- Increment Card +- Decrement Card +- Remove Card +- Switch Card between Mainboard and Sideboard + +\image html deck_dock_deck_list_buttons.png + +Additionally, there is a combo box above the list, which may be used to change how cards are grouped in the list +display. This is only for visual display and does not affect how the list is saved. + +\image html deck_dock_deck_list_group_by.png + +# Modifying the visual deck layout + +The visual deck editor displays cards visually, as opposed to simply in list form in the Deck Dock Widget. Each entry in +the deck list is represented by a picture. These entries are grouped together under their respective sub-groups. +Sub-groups may be collapsed (i.e. the pictures contained within them are hidden) by clicking on the name of the group in +the banner. + +Cards may be displayed in a "Flat" layout, which displays each picture next to each other and ensures full +visibility for each card. + +\image html vde_flat_layout_type_grouped.png width=1200px + +or in an "Overlap" layout, which overlaps cards on top of each other (leaving the top 20% of +the card uncovered so names remain readable) and arranges them in stacks to save space and allow for an easy overview. + +\image html vde_overlap_layout_type_grouped.png width=1200px + +Additionally, it is possible to change how the cards in the deck list are grouped by selecting a different grouping +method from the combo box, either in the top left of the "Visual Deck View" tab or above the list view in the deck dock +widget. + +Example - Cards grouped by suit/color: + +\image html vde_flat_layout_color_grouped.png width=1200px + +Furthermore, it is possible to change how the cards are sorted within the sub-group. This is done by clicking on the +button with the cogwheel icon next to the combo box that adjusts grouping in the top left of the "Visual Deck View" tab. +This presents a list of available sort criteria, which may be rearranged to change their priorities. + +# Modifying printings + +For more information on modifying the printings in a deck see @ref editing_decks_printings + +# Deck Analytics + +The visual deck editor offers a "Deck Analytics" tab, which displays information about: + +- The mana curve +- The mana devotion +- The mana base + +\image html vde_deck_analytics.png width=1200px + +# Sample Hand + +The visual deck editor offers a "Sample Hand" tab, which allows simulating drawing a configurable amount of cards from +the deck, which reduces the need to launch a single player game for testing purposes. + +\image html vde_sample_hand.png width=1200px \ No newline at end of file diff --git a/doc/doxygen-extra-pages/user_documentation/deck_management/exporting_decks.md b/doc/doxygen-extra-pages/user_documentation/deck_management/exporting_decks.md new file mode 100644 index 000000000..607ba3360 --- /dev/null +++ b/doc/doxygen-extra-pages/user_documentation/deck_management/exporting_decks.md @@ -0,0 +1,151 @@ +@page exporting_decks Exporting Decks + +# Where to export? + +There are two screens in the client which can be used to import decks, depending on the context. + +- The deck editor tab +- The deck storage tab (not to be confused with the visual deck storage tab) + +# The Deck Editor Tab + +The deck editor tabs (Classic and Visual) offer three ways of export a deck: + +- To a file on your local storage +- To your clipboard +- To an online service + +## Local File Storage + +To save a deck to a file on your local storage, select the "Save Deck" action in the "Deck Editor" or "Visual Deck +Editor" menu in the application menu bar at the top of the screen. Alternatively, you can use the shortcut Ctrl/Cmd + S +to access this action. + +Selecting this action will open a file picker dialog provided by your operating system. Simply enter a file name and +select a format (.cod is recommended) and confirm. + +Just below the "Save Deck" action described above is the "Save Deck as..." option, which allows saving an existing file +under a different filename, which is useful for saving a different version or copy of a deck. + +## From Clipboard + +To save a deck to your clipboard, select the "Save deck to clipboard..." action in the "Deck Editor" or "Visual Deck +Editor" menu in the application menu bar at the top of the screen. Alternatively, you can use the shortcut Ctrl/Cmd + +Shift + C or Ctrl/Cmd + Shift + R to access this action. + +Selecting this action will save the currently open deck list to your clipboard. + +Saving the decklist without annotations will export the decklist, with each card being described in the following format + +``` +CARD_AMOUNT CARD_NAME (SET_SHORT_NAME) CARD_COLLECTOR_NUMBER +``` + +There is also the (no set info) option, which will simply export each card as + +``` +CARD_AMOUNT CARD_NAME +``` + +Mainboard and sideboard are delimited by a newline like so: + +``` +1 MainboardCard +1 OtherMainboardCard + +1 SideboardCard +``` + +Saving the decklist as annotated will insert comments (marked with // in front of them). +It will first insert the name and any comments associated with the deck before separating each deck section into its own +newline delimited and annotated group. + +Example: TODO: Adjust this to be non mtg based. + +``` +// Full Deck + +// An example comment. + +// 63 Maindeck +// 4 Ace +1 Ace of Clubs (PKR) 49 +1 Ace of Diamonds (PKR) 50 +1 Ace of Hearts (PKR) 51 +1 Ace of Spades (PKR) 52 + +// 13 Face +1 Jack of Clubs (PKR) 53 +1 Jack of Diamonds (PKR) 54 +1 Jack of Hearts (PKR) 55 +1 Jack of Spades (PKR) 56 +1 King of Clubs (PKR) 57 +1 King of Diamonds (PKR) 58 +1 King of Spades (PKR) 60 +1 Queen of Clubs (PKR) 61 +1 Queen of Diamonds (PKR) 62 +1 Queen of Hearts (PKR) 63 +1 Queen of Spades (PKR) 64 +2 King of Hearts (PKR) 59 + +// 44 Number +1 0 of Clubs (PKR) 1 +1 0 of Diamonds (PKR) 2 +1 0 of Hearts (PKR) 3 +1 1 of Clubs (PKR) 11 +1 1 of Diamonds (PKR) 12 +1 1 of Hearts (PKR) 13 +1 1 of Spades (PKR) 14 +1 10 of Clubs (PKR) 5 +1 10 of Diamonds (PKR) 6 +1 10 of Hearts (PKR) 7 +1 2 of Clubs (PKR) 17 +1 2 of Diamonds (PKR) 18 +1 2 of Hearts (PKR) 19 +1 2 of Spades (PKR) 20 +1 3 of Clubs (PKR) 21 +1 3 of Diamonds (PKR) 22 +1 3 of Hearts (PKR) 23 +1 3 of Spades (PKR) 24 +1 4 of Clubs (PKR) 25 +1 4 of Diamonds (PKR) 26 +1 4 of Hearts (PKR) 27 +1 4 of Spades (PKR) 28 +1 5 of Clubs (PKR) 29 +1 5 of Diamonds (PKR) 30 +1 5 of Hearts (PKR) 31 +1 5 of Spades (PKR) 32 +1 6 of Clubs (PKR) 33 +1 6 of Diamonds (PKR) 34 +1 6 of Hearts (PKR) 35 +1 6 of Spades (PKR) 36 +1 7 of Clubs (PKR) 37 +1 7 of Diamonds (PKR) 38 +1 7 of Hearts (PKR) 39 +1 7 of Spades (PKR) 40 +1 8 of Clubs (PKR) 41 +1 8 of Diamonds (PKR) 42 +1 8 of Hearts (PKR) 43 +1 8 of Spades (PKR) 44 +1 9 of Clubs (PKR) 45 +1 9 of Diamonds (PKR) 46 +1 9 of Hearts (PKR) 47 +1 9 of Spades (PKR) 48 +1 10 of Spades (PKR) 8 +1 0 of Spades (PKR) 4 + + +// 2 Joker +1 1 Joker (PKR) 10 +1 2 Joker (PKR) 16 +``` + +## From an online service + +To export a deck to an online service, select the "Send deck to online service..." action in the "Deck Editor" or " +Visual Deck Editor" menu in the application menu bar at the top of the screen. + +Selecting this action will open your browser with the selected service open and the deck list information from the +client supplied to it. + +Currently supported services are DeckList and TappedOut. \ No newline at end of file diff --git a/doc/doxygen-extra-pages/user_documentation/deck_management/importing_decks.md b/doc/doxygen-extra-pages/user_documentation/deck_management/importing_decks.md new file mode 100644 index 000000000..e9626d57f --- /dev/null +++ b/doc/doxygen-extra-pages/user_documentation/deck_management/importing_decks.md @@ -0,0 +1,62 @@ +@page importing_decks Importing Decks + +# Where to import? + +There are three screens in the client which can be used to import decks, depending on the context. + +- The deck editor tab +- The pre-game lobby tab +- The deck storage tab (not to be confused with the visual deck storage tab) + +# The Deck Editor Tab + +The deck editor tabs (Classic and Visual) offer three ways of importing a deck: + +- From a file on your local storage +- From your clipboard +- From an online service + +## Local File Storage + +To load a deck from a file on your local storage, select the "Load Deck" action in the "Deck Editor" or "Visual Deck +Editor" menu in the application menu bar at the top of the screen. Alternatively, you can use the shortcut Ctrl/Cmd + O +to access this action. + +Selecting this action will open a file picker dialog provided by your operating system. Simply select a supported file +here and it will be loaded. + +Just below the "Load Deck" action described above is the "Load recent deck" option, which keeps a record of the last 10 +loaded decks for quick access. + +## From Clipboard + +To load a deck from your clipboard, select the "Load deck from clipboard..." action in the "Deck Editor" or "Visual Deck +Editor" menu in the application menu bar at the top of the screen. Alternatively, you can use the shortcut Ctrl/Cmd + +Shift + V to access this action. + +Selecting this action will open a new text editor dialog with the contents of your clipboard pasted inside it. + +The import dialog expects each line to be a card with the following format: + +TODO + +Each card should be on a separate line and there should be no empty lines between cards. The first empty line between +two blocks of cards will be considered as the divider between mainboard and sideboard. + +Selecting "Parse Set Name and Number (if available)" will automatically parse these options and attempt to resolve them +to valid provider IDs found in the card database. If this option is unselected, Cockatrice will import all cards as +versions without provider IDs, which means they will display to everyone according to their own user defined set +preferences, rather than being the same defined printing for everyone. + +## From an online service + +To load a deck from an online service, select the "Load deck from online service..." action in the "Deck Editor" or " +Visual Deck Editor" menu in the application menu bar at the top of the screen. + +Selecting this action will open a dialog containing the contents of your clipboard pasted into it. If your clipboard +currently contains a supported URL, the dialog will accept it and close on its own, otherwise you may adjust the URL and +confirm. + +The action will automatically import the deck from the online service without any other required user action. + +Currently supported services are Archidekt, Deckstats, Moxfield, and TappedOut. \ No newline at end of file diff --git a/doc/doxygen-extra-pages/user_documentation/index.md b/doc/doxygen-extra-pages/user_documentation/index.md index 97c6f375c..8a5c88c37 100644 --- a/doc/doxygen-extra-pages/user_documentation/index.md +++ b/doc/doxygen-extra-pages/user_documentation/index.md @@ -1,4 +1,13 @@ @page user_reference User Reference @subpage search_syntax_help -@subpage deck_search_syntax_help \ No newline at end of file + +@subpage deck_search_syntax_help + +@subpage creating_decks + +@subpage importing_decks + +@subpage editing_decks + +@subpage exporting_decks \ No newline at end of file diff --git a/doc/doxygen-images/classic_database_display.png b/doc/doxygen-images/classic_database_display.png new file mode 100644 index 000000000..fb762d9a3 Binary files /dev/null and b/doc/doxygen-images/classic_database_display.png differ diff --git a/doc/doxygen-images/classic_database_display_add_buttons.png b/doc/doxygen-images/classic_database_display_add_buttons.png new file mode 100644 index 000000000..b9cb7cd32 Binary files /dev/null and b/doc/doxygen-images/classic_database_display_add_buttons.png differ diff --git a/doc/doxygen-images/classic_deck_editor.png b/doc/doxygen-images/classic_deck_editor.png new file mode 100644 index 000000000..9371651e9 Binary files /dev/null and b/doc/doxygen-images/classic_deck_editor.png differ diff --git a/doc/doxygen-images/deck_dock_deck_list.png b/doc/doxygen-images/deck_dock_deck_list.png new file mode 100644 index 000000000..bf12d97c2 Binary files /dev/null and b/doc/doxygen-images/deck_dock_deck_list.png differ diff --git a/doc/doxygen-images/deck_dock_deck_list_buttons.png b/doc/doxygen-images/deck_dock_deck_list_buttons.png new file mode 100644 index 000000000..cb66b41da Binary files /dev/null and b/doc/doxygen-images/deck_dock_deck_list_buttons.png differ diff --git a/doc/doxygen-images/deck_dock_deck_list_group_by.png b/doc/doxygen-images/deck_dock_deck_list_group_by.png new file mode 100644 index 000000000..ba23b1fb5 Binary files /dev/null and b/doc/doxygen-images/deck_dock_deck_list_group_by.png differ diff --git a/doc/doxygen-images/deckeditordeckdockwidget.png b/doc/doxygen-images/deckeditordeckdockwidget.png new file mode 100644 index 000000000..33b9588d0 Binary files /dev/null and b/doc/doxygen-images/deckeditordeckdockwidget.png differ diff --git a/doc/doxygen-images/vde_deck_analytics.png b/doc/doxygen-images/vde_deck_analytics.png new file mode 100644 index 000000000..0b4b11e19 Binary files /dev/null and b/doc/doxygen-images/vde_deck_analytics.png differ diff --git a/doc/doxygen-images/vde_flat_layout_color_grouped.png b/doc/doxygen-images/vde_flat_layout_color_grouped.png new file mode 100644 index 000000000..51f176668 Binary files /dev/null and b/doc/doxygen-images/vde_flat_layout_color_grouped.png differ diff --git a/doc/doxygen-images/vde_flat_layout_type_grouped.png b/doc/doxygen-images/vde_flat_layout_type_grouped.png new file mode 100644 index 000000000..4a33e0017 Binary files /dev/null and b/doc/doxygen-images/vde_flat_layout_type_grouped.png differ diff --git a/doc/doxygen-images/vde_overlap_layout_type_grouped.png b/doc/doxygen-images/vde_overlap_layout_type_grouped.png new file mode 100644 index 000000000..606144586 Binary files /dev/null and b/doc/doxygen-images/vde_overlap_layout_type_grouped.png differ diff --git a/doc/doxygen-images/vde_sample_hand.png b/doc/doxygen-images/vde_sample_hand.png new file mode 100644 index 000000000..95924a5d4 Binary files /dev/null and b/doc/doxygen-images/vde_sample_hand.png differ diff --git a/libcockatrice_card/libcockatrice/card/card_info.h b/libcockatrice_card/libcockatrice/card/card_info.h index c2a8453d9..b72d1fbbe 100644 --- a/libcockatrice_card/libcockatrice/card/card_info.h +++ b/libcockatrice_card/libcockatrice/card/card_info.h @@ -1,9 +1,3 @@ -/** - * @file card_info.h - * @ingroup Cards - * @brief TODO: Document this. - */ - #ifndef CARD_INFO_H #define CARD_INFO_H @@ -54,6 +48,10 @@ class CardInfo : public QObject Q_OBJECT private: + /** @name Private Card Properties + * @anchor PrivateCardProperties + */ + ///@{ CardInfoPtr smartThis; ///< Smart pointer to self for safe cross-references. QString name; ///< Full name of the card. QString simpleName; ///< Simplified name for fuzzy matching. @@ -69,6 +67,7 @@ private: bool landscapeOrientation; ///< Orientation flag for rendering. int tableRow; ///< Row index in a table or visual representation. bool upsideDownArt; ///< Whether artwork is flipped for visual purposes. + ///@} public: /** @@ -161,7 +160,7 @@ public: */ CardInfoPtr clone() const { - CardInfoPtr newCardInfo = CardInfoPtr(new CardInfo(*this)); + auto newCardInfo = CardInfoPtr(new CardInfo(*this)); newCardInfo->setSmartPointer(newCardInfo); // Set the smart pointer for the new instance return newCardInfo; } diff --git a/libcockatrice_card/libcockatrice/card/database/card_database.h b/libcockatrice_card/libcockatrice/card/database/card_database.h index 4b2769fcb..cb46d6d00 100644 --- a/libcockatrice_card/libcockatrice/card/database/card_database.h +++ b/libcockatrice_card/libcockatrice/card/database/card_database.h @@ -1,10 +1,3 @@ -/** - * @file card_database.h - * @ingroup CardDatabase - * @brief The CardDatabase is responsible for holding the card and set maps, managing card additions/removals, - * and providing access to sets and card querying via CardDatabaseQuerier. - */ - #ifndef CARDDATABASE_H #define CARDDATABASE_H @@ -101,7 +94,7 @@ public: void clear(); /** @brief Returns the map of cards by name. */ - const CardNameMap &getCardList() const + [[nodiscard]] const CardNameMap &getCardList() const { return cards; } @@ -114,16 +107,16 @@ public: CardSetPtr getSet(const QString &setName); /** @brief Returns a list of all sets in the database. */ - CardSetList getSetList() const; + [[nodiscard]] CardSetList getSetList() const; /** @brief Returns the current load status. */ - LoadStatus getLoadStatus() const + [[nodiscard]] LoadStatus getLoadStatus() const { return loadStatus; } /** @brief Returns the querier for performing card lookups. */ - CardDatabaseQuerier *query() const + [[nodiscard]] CardDatabaseQuerier *query() const { return querier; } diff --git a/libcockatrice_card/libcockatrice/card/database/card_database_loader.h b/libcockatrice_card/libcockatrice/card/database/card_database_loader.h index 7bf02cc9a..db1376ac7 100644 --- a/libcockatrice_card/libcockatrice/card/database/card_database_loader.h +++ b/libcockatrice_card/libcockatrice/card/database/card_database_loader.h @@ -1,12 +1,3 @@ -/** - * @file card_database_loader.h - * @ingroup CardDatabase - * @brief The CardDatabaseLoader is responsible for discovering, loading, and saving card databases from files on disk. - * - * This class interacts with available parsers to populate a CardDatabase instance. It also handles - * loading main, token, spoiler, and custom card databases. - */ - #ifndef COCKATRICE_CARD_DATABASE_LOADER_H #define COCKATRICE_CARD_DATABASE_LOADER_H diff --git a/libcockatrice_card/libcockatrice/card/database/card_database_querier.h b/libcockatrice_card/libcockatrice/card/database/card_database_querier.h index fcef3fea1..d9a980f06 100644 --- a/libcockatrice_card/libcockatrice/card/database/card_database_querier.h +++ b/libcockatrice_card/libcockatrice/card/database/card_database_querier.h @@ -124,7 +124,7 @@ public: * @param cardName Name of the card. * @return The preferred ExactCard. */ - ExactCard getPreferredCard(const QString &cardName) const; + [[nodiscard]] ExactCard getPreferredCard(const QString &cardName) const; /** * @brief Returns the preferred printing of a card based on user preferences and set priority. diff --git a/libcockatrice_card/libcockatrice/card/printing/exact_card.h b/libcockatrice_card/libcockatrice/card/printing/exact_card.h index b36233bd5..01c61a3a1 100644 --- a/libcockatrice_card/libcockatrice/card/printing/exact_card.h +++ b/libcockatrice_card/libcockatrice/card/printing/exact_card.h @@ -5,7 +5,7 @@ /** * @class ExactCard - * @ingroup Cards + * @ingroup CardPrintings * * @brief Represents a specific card instance, defined by its CardInfo * and a particular printing. diff --git a/libcockatrice_card/libcockatrice/card/printing/printing_info.h b/libcockatrice_card/libcockatrice/card/printing/printing_info.h index cacb98068..37d7a15e2 100644 --- a/libcockatrice_card/libcockatrice/card/printing/printing_info.h +++ b/libcockatrice_card/libcockatrice/card/printing/printing_info.h @@ -14,7 +14,7 @@ using SetToPrintingsMap = QMap>; /** * @class PrintingInfo - * @ingroup Cards + * @ingroup CardPrintings * * @brief Represents metadata for a specific variation of a card within a set. * diff --git a/libcockatrice_card/libcockatrice/card/set/card_set.h b/libcockatrice_card/libcockatrice/card/set/card_set.h index b3e35f2db..5fc769bb6 100644 --- a/libcockatrice_card/libcockatrice/card/set/card_set.h +++ b/libcockatrice_card/libcockatrice/card/set/card_set.h @@ -15,7 +15,7 @@ using CardSetPtr = QSharedPointer; /** * @class CardSet - * @ingroup Cards + * @ingroup CardSets * * @brief A collection of cards grouped under a common identifier. * diff --git a/libcockatrice_card/libcockatrice/card/set/card_set_comparator.h b/libcockatrice_card/libcockatrice/card/set/card_set_comparator.h index 53e2cb97d..96f1052a9 100644 --- a/libcockatrice_card/libcockatrice/card/set/card_set_comparator.h +++ b/libcockatrice_card/libcockatrice/card/set/card_set_comparator.h @@ -1,6 +1,6 @@ /** * @file card_set_comparator.h - * @ingroup Cards + * @ingroup CardSets * @brief TODO: Document this. */ diff --git a/libcockatrice_card/libcockatrice/card/set/card_set_list.h b/libcockatrice_card/libcockatrice/card/set/card_set_list.h index 2e644a277..21b4a55d4 100644 --- a/libcockatrice_card/libcockatrice/card/set/card_set_list.h +++ b/libcockatrice_card/libcockatrice/card/set/card_set_list.h @@ -8,7 +8,7 @@ /** * @class CardSetList - * @ingroup Cards + * @ingroup CardSets * * @brief A list-like container for CardSet objects with extended management methods. * diff --git a/libcockatrice_deck_list/libcockatrice/deck_list/abstract_deck_list_card_node.h b/libcockatrice_deck_list/libcockatrice/deck_list/abstract_deck_list_card_node.h index 19bebf5f9..1d201a4c1 100644 --- a/libcockatrice_deck_list/libcockatrice/deck_list/abstract_deck_list_card_node.h +++ b/libcockatrice_deck_list/libcockatrice/deck_list/abstract_deck_list_card_node.h @@ -59,31 +59,31 @@ public: } /// @return The number of copies of this card in the deck. - virtual int getNumber() const = 0; + [[nodiscard]] virtual int getNumber() const = 0; /// @param _number Set the number of copies of this card. virtual void setNumber(int _number) = 0; /// @return The display name of this card. - QString getName() const override = 0; + [[nodiscard]] QString getName() const override = 0; /// @param _name Set the display name of this card. virtual void setName(const QString &_name) = 0; /// @return The provider identifier for this card (e.g., UUID). - virtual QString getCardProviderId() const override = 0; + [[nodiscard]] virtual QString getCardProviderId() const override = 0; /// @param _cardProviderId Set the provider identifier for this card. virtual void setCardProviderId(const QString &_cardProviderId) = 0; /// @return The abbreviated set code (e.g., "NEO"). - virtual QString getCardSetShortName() const override = 0; + [[nodiscard]] virtual QString getCardSetShortName() const override = 0; /// @param _cardSetShortName Set the abbreviated set code. virtual void setCardSetShortName(const QString &_cardSetShortName) = 0; /// @return The collector number of the card within its set. - virtual QString getCardCollectorNumber() const override = 0; + [[nodiscard]] virtual QString getCardCollectorNumber() const override = 0; /// @param _cardSetNumber Set the collector number. virtual void setCardCollectorNumber(const QString &_cardSetNumber) = 0; @@ -96,7 +96,7 @@ public: * * @return 0 */ - int height() const override + [[nodiscard]] int height() const override { return 0; } diff --git a/libcockatrice_deck_list/libcockatrice/deck_list/abstract_deck_list_node.h b/libcockatrice_deck_list/libcockatrice/deck_list/abstract_deck_list_node.h index 3a82cfab9..31e7b165e 100644 --- a/libcockatrice_deck_list/libcockatrice/deck_list/abstract_deck_list_node.h +++ b/libcockatrice_deck_list/libcockatrice/deck_list/abstract_deck_list_node.h @@ -123,10 +123,10 @@ public: * identifying information about a node, regardless of type. * @{ */ - virtual QString getName() const = 0; - virtual QString getCardProviderId() const = 0; - virtual QString getCardSetShortName() const = 0; - virtual QString getCardCollectorNumber() const = 0; + [[nodiscard]] virtual QString getName() const = 0; + [[nodiscard]] virtual QString getCardProviderId() const = 0; + [[nodiscard]] virtual QString getCardSetShortName() const = 0; + [[nodiscard]] virtual QString getCardCollectorNumber() const = 0; /// @} /** @@ -138,7 +138,7 @@ public: [[nodiscard]] virtual bool isDeckHeader() const = 0; /// @return The parent node, or nullptr if this is the root. - InnerDecklistNode *getParent() const + [[nodiscard]] InnerDecklistNode *getParent() const { return parent; } @@ -147,7 +147,7 @@ public: * @brief Compute the depth of this node in the tree. * @return Distance from the root (root = 0, children = 1, etc.). */ - int depth() const; + [[nodiscard]] int depth() const; /** * @brief Compute the "height" of this node. @@ -159,7 +159,7 @@ public: * - A card node has height 1. * - A group node containing cards has height 2. */ - virtual int height() const = 0; + [[nodiscard]] virtual int height() const = 0; /** * @brief Compare this node against another for sorting. diff --git a/libcockatrice_deck_list/libcockatrice/deck_list/deck_list.cpp b/libcockatrice_deck_list/libcockatrice/deck_list/deck_list.cpp index b2fbdb028..43a474ca8 100644 --- a/libcockatrice_deck_list/libcockatrice/deck_list/deck_list.cpp +++ b/libcockatrice_deck_list/libcockatrice/deck_list/deck_list.cpp @@ -563,6 +563,29 @@ QList DeckList::getCardRefList() const return result; } +QList DeckList::getCardNodes(const QStringList &restrictToZones) const +{ + QList result; + + for (auto *node : *root) { + auto *zoneNode = dynamic_cast(node); + if (zoneNode == nullptr) { + continue; + } + if (!restrictToZones.isEmpty() && !restrictToZones.contains(node->getName())) { + continue; + } + for (auto *cardNode : *zoneNode) { + auto *cardCardNode = dynamic_cast(cardNode); + if (cardCardNode != nullptr) { + result.append(cardCardNode); + } + } + } + + return result; +} + int DeckList::getSideboardSize() const { int size = 0; diff --git a/libcockatrice_deck_list/libcockatrice/deck_list/deck_list.h b/libcockatrice_deck_list/libcockatrice/deck_list/deck_list.h index fc0c07405..2a03c4374 100644 --- a/libcockatrice_deck_list/libcockatrice/deck_list/deck_list.h +++ b/libcockatrice_deck_list/libcockatrice/deck_list/deck_list.h @@ -72,13 +72,13 @@ public: void write(QXmlStreamWriter *xml); /// @return The plan name. - QString getName() const + [[nodiscard]] QString getName() const { return name; } /// @return Const reference to the move list. - const QList &getMoveList() const + [[nodiscard]] const QList &getMoveList() const { return moveList; } @@ -289,6 +289,7 @@ public: } QStringList getCardList() const; QList getCardRefList() const; + QList getCardNodes(const QStringList &restrictToZones = QStringList()) const; int getSideboardSize() const; InnerDecklistNode *getRoot() const { diff --git a/libcockatrice_deck_list/libcockatrice/deck_list/inner_deck_list_node.cpp b/libcockatrice_deck_list/libcockatrice/deck_list/inner_deck_list_node.cpp index c91b3ea14..eca58963a 100644 --- a/libcockatrice_deck_list/libcockatrice/deck_list/inner_deck_list_node.cpp +++ b/libcockatrice_deck_list/libcockatrice/deck_list/inner_deck_list_node.cpp @@ -145,10 +145,10 @@ bool InnerDecklistNode::readElement(QXmlStreamReader *xml) const QString childName = xml->name().toString(); if (xml->isStartElement()) { if (childName == "zone") { - InnerDecklistNode *newZone = new InnerDecklistNode(xml->attributes().value("name").toString(), this); + auto *newZone = new InnerDecklistNode(xml->attributes().value("name").toString(), this); newZone->readElement(xml); } else if (childName == "card") { - DecklistCardNode *newCard = new DecklistCardNode( + auto *newCard = new DecklistCardNode( xml->attributes().value("name").toString(), xml->attributes().value("number").toString().toInt(), this, -1, xml->attributes().value("setShortName").toString(), xml->attributes().value("collectorNumber").toString(), xml->attributes().value("uuid").toString()); diff --git a/libcockatrice_deck_list/libcockatrice/deck_list/inner_deck_list_node.h b/libcockatrice_deck_list/libcockatrice/deck_list/inner_deck_list_node.h index 07bb4203f..f4c48afce 100644 --- a/libcockatrice_deck_list/libcockatrice/deck_list/inner_deck_list_node.h +++ b/libcockatrice_deck_list/libcockatrice/deck_list/inner_deck_list_node.h @@ -176,7 +176,7 @@ public: * @brief Compute the height of this node. * @return Maximum depth of descendants + 1. */ - int height() const override; + [[nodiscard]] int height() const override; /** * @brief Count cards recursively under this node. @@ -184,7 +184,7 @@ public: * If false, counts unique card nodes. * @return Total count. */ - int recursiveCount(bool countTotalCards = false) const; + [[nodiscard]] int recursiveCount(bool countTotalCards = false) const; /** * @brief Compare this node against another for sorting. diff --git a/libcockatrice_network/libcockatrice/network/server/remote/game/server_abstract_player.cpp b/libcockatrice_network/libcockatrice/network/server/remote/game/server_abstract_player.cpp index 5ac0a26ad..1c81b6823 100644 --- a/libcockatrice_network/libcockatrice/network/server/remote/game/server_abstract_player.cpp +++ b/libcockatrice_network/libcockatrice/network/server/remote/game/server_abstract_player.cpp @@ -1095,12 +1095,11 @@ Server_AbstractPlayer::cmdCreateToken(const Command_CreateToken &cmd, ResponseCo arrowInfo->set_start_player_id(player->getPlayerId()); arrowInfo->set_start_zone(startCard->getZone()->getName().toStdString()); arrowInfo->set_start_card_id(startCard->getId()); - const Server_AbstractPlayer *arrowTargetPlayer = - qobject_cast(targetItem); + const auto *arrowTargetPlayer = qobject_cast(targetItem); if (arrowTargetPlayer != nullptr) { arrowInfo->set_target_player_id(arrowTargetPlayer->getPlayerId()); } else { - const Server_Card *arrowTargetCard = qobject_cast(targetItem); + const auto *arrowTargetCard = qobject_cast(targetItem); arrowInfo->set_target_player_id(arrowTargetCard->getZone()->getPlayer()->getPlayerId()); arrowInfo->set_target_zone(arrowTargetCard->getZone()->getName().toStdString()); arrowInfo->set_target_card_id(arrowTargetCard->getId()); diff --git a/libcockatrice_network/libcockatrice/network/server/remote/game/server_arrow.cpp b/libcockatrice_network/libcockatrice/network/server/remote/game/server_arrow.cpp index e077416bc..9433d8d3f 100644 --- a/libcockatrice_network/libcockatrice/network/server/remote/game/server_arrow.cpp +++ b/libcockatrice_network/libcockatrice/network/server/remote/game/server_arrow.cpp @@ -19,7 +19,7 @@ void Server_Arrow::getInfo(ServerInfo_Arrow *info) info->set_start_card_id(startCard->getId()); info->mutable_arrow_color()->CopyFrom(arrowColor); - Server_Card *targetCard = qobject_cast(targetItem); + auto *targetCard = qobject_cast(targetItem); if (targetCard) { info->set_target_player_id(targetCard->getZone()->getPlayer()->getPlayerId()); info->set_target_zone(targetCard->getZone()->getName().toStdString()); diff --git a/libcockatrice_network/libcockatrice/network/server/remote/game/server_cardzone.h b/libcockatrice_network/libcockatrice/network/server/remote/game/server_cardzone.h index 2a30de53d..0dc368a80 100644 --- a/libcockatrice_network/libcockatrice/network/server/remote/game/server_cardzone.h +++ b/libcockatrice_network/libcockatrice/network/server/remote/game/server_cardzone.h @@ -57,7 +57,7 @@ public: ServerInfo_Zone::ZoneType _type); ~Server_CardZone(); - const QList &getCards() const + [[nodiscard]] const QList &getCards() const { return cards; } @@ -65,7 +65,7 @@ public: int removeCard(Server_Card *card, bool &wasLookedAt); Server_Card *getCard(int id, int *position = nullptr, bool remove = false); - int getCardsBeingLookedAt() const + [[nodiscard]] int getCardsBeingLookedAt() const { return cardsBeingLookedAt; } @@ -73,28 +73,28 @@ public: { cardsBeingLookedAt = qMax(0, _cardsBeingLookedAt); } - bool isCardAtPosLookedAt(int pos) const; - bool hasCoords() const + [[nodiscard]] bool isCardAtPosLookedAt(int pos) const; + [[nodiscard]] bool hasCoords() const { return has_coords; } - ServerInfo_Zone::ZoneType getType() const + [[nodiscard]] ServerInfo_Zone::ZoneType getType() const { return type; } - QString getName() const + [[nodiscard]] QString getName() const { return name; } - Server_AbstractPlayer *getPlayer() const + [[nodiscard]] Server_AbstractPlayer *getPlayer() const { return player; } void getInfo(ServerInfo_Zone *info, Server_AbstractParticipant *recipient, bool omniscient); - int getFreeGridColumn(int x, int y, const QString &cardName, bool dontStackSameName) const; - bool isColumnEmpty(int x, int y) const; - bool isColumnStacked(int x, int y) const; + [[nodiscard]] int getFreeGridColumn(int x, int y, const QString &cardName, bool dontStackSameName) const; + [[nodiscard]] bool isColumnEmpty(int x, int y) const; + [[nodiscard]] bool isColumnStacked(int x, int y) const; void fixFreeSpaces(GameEventStorage &ges); void moveCardInRow(GameEventStorage &ges, Server_Card *card, int x, int y); void insertCard(Server_Card *card, int x, int y); @@ -102,11 +102,11 @@ public: void shuffle(int start = 0, int end = -1); void clear(); void addWritePermission(int playerId); - const QSet &getPlayersWithWritePermission() const + [[nodiscard]] const QSet &getPlayersWithWritePermission() const { return playersWithWritePermission; } - bool getAlwaysRevealTopCard() const + [[nodiscard]] bool getAlwaysRevealTopCard() const { return alwaysRevealTopCard; } @@ -114,7 +114,7 @@ public: { alwaysRevealTopCard = _alwaysRevealTopCard; } - bool getAlwaysLookAtTopCard() const + [[nodiscard]] bool getAlwaysLookAtTopCard() const { return alwaysLookAtTopCard; } diff --git a/libcockatrice_network/libcockatrice/network/server/remote/game/server_game.cpp b/libcockatrice_network/libcockatrice/network/server/remote/game/server_game.cpp index 647d1d078..82b24ccde 100644 --- a/libcockatrice_network/libcockatrice/network/server/remote/game/server_game.cpp +++ b/libcockatrice_network/libcockatrice/network/server/remote/game/server_game.cpp @@ -589,7 +589,7 @@ void Server_Game::removeArrowsRelatedToPlayer(GameEventStorage &ges, Server_Abst for (Server_AbstractPlayer *anyPlayer : getPlayers().values()) { QList toDelete; for (auto *arrow : anyPlayer->getArrows().values()) { - Server_Card *targetCard = qobject_cast(arrow->getTargetItem()); + auto *targetCard = qobject_cast(arrow->getTargetItem()); if (targetCard) { if (targetCard->getZone() != nullptr && targetCard->getZone()->getPlayer() == player) toDelete.append(arrow); @@ -781,7 +781,7 @@ void Server_Game::sendGameEventContainer(GameEventContainer *cont, GameEventContainer * Server_Game::prepareGameEvent(const ::google::protobuf::Message &gameEvent, int playerId, GameEventContext *context) { - GameEventContainer *cont = new GameEventContainer; + auto *cont = new GameEventContainer; cont->set_game_id(gameId); if (context) cont->mutable_context()->CopyFrom(*context); diff --git a/libcockatrice_network/libcockatrice/network/server/remote/server_abstractuserinterface.cpp b/libcockatrice_network/libcockatrice/network/server/remote/server_abstractuserinterface.cpp index 96626a4bf..e228f0128 100644 --- a/libcockatrice_network/libcockatrice/network/server/remote/server_abstractuserinterface.cpp +++ b/libcockatrice_network/libcockatrice/network/server/remote/server_abstractuserinterface.cpp @@ -35,7 +35,7 @@ void Server_AbstractUserInterface::sendProtocolItemByType(ServerMessage::Message SessionEvent *Server_AbstractUserInterface::prepareSessionEvent(const ::google::protobuf::Message &sessionEvent) { - SessionEvent *event = new SessionEvent; + auto *event = new SessionEvent; event->GetReflection() ->MutableMessage(event, sessionEvent.GetDescriptor()->FindExtensionByName("ext")) ->CopyFrom(sessionEvent); diff --git a/libcockatrice_network/libcockatrice/network/server/remote/server_protocolhandler.cpp b/libcockatrice_network/libcockatrice/network/server/remote/server_protocolhandler.cpp index 92dcf4230..bfd8d113c 100644 --- a/libcockatrice_network/libcockatrice/network/server/remote/server_protocolhandler.cpp +++ b/libcockatrice_network/libcockatrice/network/server/remote/server_protocolhandler.cpp @@ -473,7 +473,7 @@ Response::ResponseCode Server_ProtocolHandler::cmdLogin(const Command_Login &cmd if (!missingClientFeatures.isEmpty()) { if (features.isRequiredFeaturesMissing(missingClientFeatures, server->getServerRequiredFeatureList())) { - Response_Login *re = new Response_Login; + auto *re = new Response_Login; re->set_denied_reason_str("Client upgrade required"); QMap::iterator i; for (i = missingClientFeatures.begin(); i != missingClientFeatures.end(); ++i) { @@ -491,7 +491,7 @@ Response::ResponseCode Server_ProtocolHandler::cmdLogin(const Command_Login &cmd clientId, clientVersion, connectionType); switch (res) { case UserIsBanned: { - Response_Login *re = new Response_Login; + auto *re = new Response_Login; re->set_denied_reason_str(reasonStr.toStdString()); if (banSecondsLeft != 0) re->set_denied_end_time(QDateTime::currentDateTime().addSecs(banSecondsLeft).toSecsSinceEpoch()); @@ -503,7 +503,7 @@ Response::ResponseCode Server_ProtocolHandler::cmdLogin(const Command_Login &cmd case WouldOverwriteOldSession: return Response::RespWouldOverwriteOldSession; case UsernameInvalid: { - Response_Login *re = new Response_Login; + auto *re = new Response_Login; re->set_denied_reason_str(reasonStr.toStdString()); rc.setResponseExtension(re); return Response::RespUsernameInvalid; @@ -534,7 +534,7 @@ Response::ResponseCode Server_ProtocolHandler::cmdLogin(const Command_Login &cmd event.set_message(server->getLoginMessage().toStdString()); rc.enqueuePostResponseItem(ServerMessage::SESSION_EVENT, prepareSessionEvent(event)); - Response_Login *re = new Response_Login; + auto *re = new Response_Login; re->mutable_user_info()->CopyFrom(copyUserInfo(true)); if (authState == PasswordRight) { @@ -616,7 +616,7 @@ Response::ResponseCode Server_ProtocolHandler::cmdGetGamesOfUser(const Command_G // We don't need to check whether the user is logged in; persistent games should also work. // The client needs to deal with an empty result list. - Response_GetGamesOfUser *re = new Response_GetGamesOfUser; + auto *re = new Response_GetGamesOfUser; server->roomsLock.lockForRead(); QMapIterator roomIterator(server->getRooms()); while (roomIterator.hasNext()) { @@ -640,7 +640,7 @@ Response::ResponseCode Server_ProtocolHandler::cmdGetUserInfo(const Command_GetU return Response::RespLoginNeeded; QString userName = nameFromStdString(cmd.user_name()); - Response_GetUserInfo *re = new Response_GetUserInfo; + auto *re = new Response_GetUserInfo; if (userName.isEmpty()) re->mutable_user_info()->CopyFrom(*userInfo); else { @@ -713,7 +713,7 @@ Response::ResponseCode Server_ProtocolHandler::cmdJoinRoom(const Command_JoinRoo joinMessageEvent.set_message_type(Event_RoomSay::Welcome); rc.enqueuePostResponseItem(ServerMessage::ROOM_EVENT, room->prepareRoomEvent(joinMessageEvent)); - Response_JoinRoom *re = new Response_JoinRoom; + auto *re = new Response_JoinRoom; room->getInfo(*re->mutable_room_info(), true); rc.setResponseExtension(re); @@ -725,7 +725,7 @@ Response::ResponseCode Server_ProtocolHandler::cmdListUsers(const Command_ListUs if (authState == NotLoggedIn) return Response::RespLoginNeeded; - Response_ListUsers *re = new Response_ListUsers; + auto *re = new Response_ListUsers; server->clientsLock.lockForRead(); QMapIterator userIterator = server->getUsers(); while (userIterator.hasNext()) @@ -838,10 +838,10 @@ Server_ProtocolHandler::cmdCreateGame(const Command_CreateGame &cmd, Server_Room // When server doesn't permit registered users to exist, do not honor only-reg setting bool onlyRegisteredUsers = cmd.only_registered() && (server->permitUnregisteredUsers()); - Server_Game *game = new Server_Game( - copyUserInfo(false), gameId, description, QString::fromStdString(cmd.password()), cmd.max_players(), gameTypes, - cmd.only_buddies(), onlyRegisteredUsers, cmd.spectators_allowed(), cmd.spectators_need_password(), - cmd.spectators_can_talk(), cmd.spectators_see_everything(), startingLifeTotal, shareDecklistsOnLoad, room); + auto *game = new Server_Game(copyUserInfo(false), gameId, description, QString::fromStdString(cmd.password()), + cmd.max_players(), gameTypes, cmd.only_buddies(), onlyRegisteredUsers, + cmd.spectators_allowed(), cmd.spectators_need_password(), cmd.spectators_can_talk(), + cmd.spectators_see_everything(), startingLifeTotal, shareDecklistsOnLoad, room); game->addPlayer(this, rc, asSpectator, asJudge, false); room->addGame(game); diff --git a/libcockatrice_network/libcockatrice/network/server/remote/server_response_containers.h b/libcockatrice_network/libcockatrice/network/server/remote/server_response_containers.h index e533d6692..118b32d38 100644 --- a/libcockatrice_network/libcockatrice/network/server/remote/server_response_containers.h +++ b/libcockatrice_network/libcockatrice/network/server/remote/server_response_containers.h @@ -31,11 +31,11 @@ public: GameEventStorageItem(const ::google::protobuf::Message &_event, int _playerId, EventRecipients _recipients); ~GameEventStorageItem(); - const GameEvent &getGameEvent() const + [[nodiscard]] const GameEvent &getGameEvent() const { return *event; } - EventRecipients getRecipients() const + [[nodiscard]] EventRecipients getRecipients() const { return recipients; } @@ -56,15 +56,15 @@ public: ~GameEventStorage(); void setGameEventContext(const ::google::protobuf::Message &_gameEventContext); - ::google::protobuf::Message *getGameEventContext() const + [[nodiscard]] ::google::protobuf::Message *getGameEventContext() const { return gameEventContext; } - const QList &getGameEventList() const + [[nodiscard]] const QList &getGameEventList() const { return gameEventList; } - int getPrivatePlayerId() const + [[nodiscard]] int getPrivatePlayerId() const { return privatePlayerId; } @@ -96,7 +96,7 @@ public: ResponseContainer(int _cmdId); ~ResponseContainer(); - int getCmdId() const + [[nodiscard]] int getCmdId() const { return cmdId; } @@ -104,7 +104,7 @@ public: { responseExtension = _responseExtension; } - ::google::protobuf::Message *getResponseExtension() const + [[nodiscard]] ::google::protobuf::Message *getResponseExtension() const { return responseExtension; } @@ -116,11 +116,13 @@ public: { postResponseQueue.append(qMakePair(type, item)); } - const QList> &getPreResponseQueue() const + [[nodiscard]] const QList> & + getPreResponseQueue() const { return preResponseQueue; } - const QList> &getPostResponseQueue() const + [[nodiscard]] const QList> & + getPostResponseQueue() const { return postResponseQueue; } diff --git a/libcockatrice_network/libcockatrice/network/server/remote/server_room.cpp b/libcockatrice_network/libcockatrice/network/server/remote/server_room.cpp index e94b255bd..bfa8912b1 100644 --- a/libcockatrice_network/libcockatrice/network/server/remote/server_room.cpp +++ b/libcockatrice_network/libcockatrice/network/server/remote/server_room.cpp @@ -128,7 +128,7 @@ Server_Room::getInfo(ServerInfo_Room &result, bool complete, bool showGameTypes, RoomEvent *Server_Room::prepareRoomEvent(const ::google::protobuf::Message &roomEvent) { - RoomEvent *event = new RoomEvent; + auto *event = new RoomEvent; event->set_room_id(id); event->GetReflection() ->MutableMessage(event, roomEvent.GetDescriptor()->FindExtensionByName("ext")) diff --git a/libcockatrice_network/libcockatrice/network/server/remote/serverinfo_user_container.h b/libcockatrice_network/libcockatrice/network/server/remote/serverinfo_user_container.h index 4a29bce2d..a959f4535 100644 --- a/libcockatrice_network/libcockatrice/network/server/remote/serverinfo_user_container.h +++ b/libcockatrice_network/libcockatrice/network/server/remote/serverinfo_user_container.h @@ -14,14 +14,15 @@ public: ServerInfo_User_Container(const ServerInfo_User_Container &other); ServerInfo_User_Container &operator=(const ServerInfo_User_Container &other) = default; virtual ~ServerInfo_User_Container(); - ServerInfo_User *getUserInfo() const + [[nodiscard]] ServerInfo_User *getUserInfo() const { return userInfo; } void setUserInfo(const ServerInfo_User &_userInfo); ServerInfo_User & copyUserInfo(ServerInfo_User &result, bool complete, bool internalInfo = false, bool sessionInfo = false) const; - ServerInfo_User copyUserInfo(bool complete, bool internalInfo = false, bool sessionInfo = false) const; + [[nodiscard]] ServerInfo_User + copyUserInfo(bool complete, bool internalInfo = false, bool sessionInfo = false) const; }; #endif diff --git a/libcockatrice_settings/libcockatrice/settings/card_database_settings.cpp b/libcockatrice_settings/libcockatrice/settings/card_database_settings.cpp index f0b8d58b1..79738f1cd 100644 --- a/libcockatrice_settings/libcockatrice/settings/card_database_settings.cpp +++ b/libcockatrice_settings/libcockatrice/settings/card_database_settings.cpp @@ -1,7 +1,7 @@ #include "card_database_settings.h" CardDatabaseSettings::CardDatabaseSettings(const QString &settingPath, QObject *parent) - : SettingsManager(settingPath + "cardDatabase.ini", parent) + : SettingsManager(settingPath + "cardDatabase.ini", QString(), QString(), parent) { } diff --git a/libcockatrice_settings/libcockatrice/settings/card_override_settings.cpp b/libcockatrice_settings/libcockatrice/settings/card_override_settings.cpp index 2e2c7607d..894358be6 100644 --- a/libcockatrice_settings/libcockatrice/settings/card_override_settings.cpp +++ b/libcockatrice_settings/libcockatrice/settings/card_override_settings.cpp @@ -1,21 +1,21 @@ #include "card_override_settings.h" CardOverrideSettings::CardOverrideSettings(const QString &settingPath, QObject *parent) - : SettingsManager(settingPath + "cardPreferenceOverrides.ini", parent) + : SettingsManager(settingPath + "cardPreferenceOverrides.ini", "cards", QString(), parent) { } void CardOverrideSettings::setCardPreferenceOverride(const CardRef &cardRef) { - setValue(cardRef.providerId, cardRef.name, "cards"); + setValue(cardRef.providerId, cardRef.name); } void CardOverrideSettings::deleteCardPreferenceOverride(const QString &cardName) { - deleteValue(cardName, "cards"); + deleteValue(cardName); } QString CardOverrideSettings::getCardPreferenceOverride(const QString &cardName) { - return getValue(cardName, "cards").toString(); + return getValue(cardName).toString(); } \ No newline at end of file diff --git a/libcockatrice_settings/libcockatrice/settings/debug_settings.cpp b/libcockatrice_settings/libcockatrice/settings/debug_settings.cpp index f6f12f60e..084696dc1 100644 --- a/libcockatrice_settings/libcockatrice/settings/debug_settings.cpp +++ b/libcockatrice_settings/libcockatrice/settings/debug_settings.cpp @@ -3,7 +3,7 @@ #include DebugSettings::DebugSettings(const QString &settingPath, QObject *parent) - : SettingsManager(settingPath + "debug.ini", parent) + : SettingsManager(settingPath + "debug.ini", "debug", QString(), parent) { // Create the default debug.ini if it doesn't exist yet if (!QFile(settingPath + "debug.ini").exists()) { @@ -13,7 +13,7 @@ DebugSettings::DebugSettings(const QString &settingPath, QObject *parent) bool DebugSettings::getShowCardId() { - return getValue("showCardId", "debug").toBool(); + return getValue("showCardId").toBool(); } bool DebugSettings::getLocalGameOnStartup() diff --git a/libcockatrice_settings/libcockatrice/settings/download_settings.cpp b/libcockatrice_settings/libcockatrice/settings/download_settings.cpp index adbe26363..ad4b81ec5 100644 --- a/libcockatrice_settings/libcockatrice/settings/download_settings.cpp +++ b/libcockatrice_settings/libcockatrice/settings/download_settings.cpp @@ -9,21 +9,21 @@ const QStringList DownloadSettings::DEFAULT_DOWNLOAD_URLS = { "https://gatherer.wizards.com/Handlers/Image.ashx?name=!name!&type=card"}; DownloadSettings::DownloadSettings(const QString &settingPath, QObject *parent = nullptr) - : SettingsManager(settingPath + "downloads.ini", parent) + : SettingsManager(settingPath + "downloads.ini", "downloads", QString(), parent) { } void DownloadSettings::setDownloadUrls(const QStringList &downloadURLs) { - setValue(QVariant::fromValue(downloadURLs), "urls", "downloads"); + setValue(QVariant::fromValue(downloadURLs), "urls"); } QStringList DownloadSettings::getAllURLs() { - return getValue("urls", "downloads").toStringList(); + return getValue("urls").toStringList(); } void DownloadSettings::resetToDefaultURLs() { - setValue(QVariant::fromValue(DEFAULT_DOWNLOAD_URLS), "urls", "downloads"); + setValue(QVariant::fromValue(DEFAULT_DOWNLOAD_URLS), "urls"); } diff --git a/libcockatrice_settings/libcockatrice/settings/game_filters_settings.cpp b/libcockatrice_settings/libcockatrice/settings/game_filters_settings.cpp index e82b18a47..2da9b9bc3 100644 --- a/libcockatrice_settings/libcockatrice/settings/game_filters_settings.cpp +++ b/libcockatrice_settings/libcockatrice/settings/game_filters_settings.cpp @@ -4,7 +4,7 @@ #include GameFiltersSettings::GameFiltersSettings(const QString &settingPath, QObject *parent) - : SettingsManager(settingPath + "gamefilters.ini", parent) + : SettingsManager(settingPath + "gamefilters.ini", "filter_games", QString(), parent) { } @@ -19,190 +19,190 @@ QString GameFiltersSettings::hashGameType(const QString &gameType) const void GameFiltersSettings::setHideBuddiesOnlyGames(bool hide) { - setValue(hide, "hide_buddies_only_games", "filter_games"); + setValue(hide, "hide_buddies_only_games"); } bool GameFiltersSettings::isHideBuddiesOnlyGames() { - QVariant previous = getValue("hide_buddies_only_games", "filter_games"); + QVariant previous = getValue("hide_buddies_only_games"); return previous == QVariant() || previous.toBool(); } void GameFiltersSettings::setHideFullGames(bool hide) { - setValue(hide, "hide_full_games", "filter_games"); + setValue(hide, "hide_full_games"); } bool GameFiltersSettings::isHideFullGames() { - QVariant previous = getValue("hide_full_games", "filter_games"); + QVariant previous = getValue("hide_full_games"); return !(previous == QVariant()) && previous.toBool(); } void GameFiltersSettings::setHideGamesThatStarted(bool hide) { - setValue(hide, "hide_games_that_started", "filter_games"); + setValue(hide, "hide_games_that_started"); } bool GameFiltersSettings::isHideGamesThatStarted() { - QVariant previous = getValue("hide_games_that_started", "filter_games"); + QVariant previous = getValue("hide_games_that_started"); return !(previous == QVariant()) && previous.toBool(); } void GameFiltersSettings::setHidePasswordProtectedGames(bool hide) { - setValue(hide, "hide_password_protected_games", "filter_games"); + setValue(hide, "hide_password_protected_games"); } bool GameFiltersSettings::isHidePasswordProtectedGames() { - QVariant previous = getValue("hide_password_protected_games", "filter_games"); + QVariant previous = getValue("hide_password_protected_games"); return previous == QVariant() || previous.toBool(); } void GameFiltersSettings::setHideIgnoredUserGames(bool hide) { - setValue(hide, "hide_ignored_user_games", "filter_games"); + setValue(hide, "hide_ignored_user_games"); } bool GameFiltersSettings::isHideIgnoredUserGames() { - QVariant previous = getValue("hide_ignored_user_games", "filter_games"); + QVariant previous = getValue("hide_ignored_user_games"); return !(previous == QVariant()) && previous.toBool(); } void GameFiltersSettings::setHideNotBuddyCreatedGames(bool hide) { - setValue(hide, "hide_not_buddy_created_games", "filter_games"); + setValue(hide, "hide_not_buddy_created_games"); } bool GameFiltersSettings::isHideNotBuddyCreatedGames() { - QVariant previous = getValue("hide_not_buddy_created_games", "filter_games"); + QVariant previous = getValue("hide_not_buddy_created_games"); return !(previous == QVariant()) && previous.toBool(); } void GameFiltersSettings::setHideOpenDecklistGames(bool hide) { - setValue(hide, "hide_open_decklist_games", "filter_games"); + setValue(hide, "hide_open_decklist_games"); } bool GameFiltersSettings::isHideOpenDecklistGames() { - QVariant previous = getValue("hide_open_decklist_games", "filter_games"); + QVariant previous = getValue("hide_open_decklist_games"); return !(previous == QVariant()) && previous.toBool(); } void GameFiltersSettings::setGameNameFilter(QString gameName) { - setValue(gameName, "game_name_filter", "filter_games"); + setValue(gameName, "game_name_filter"); } QString GameFiltersSettings::getGameNameFilter() { - return getValue("game_name_filter", "filter_games").toString(); + return getValue("game_name_filter").toString(); } void GameFiltersSettings::setCreatorNameFilter(QString creatorName) { - setValue(creatorName, "creator_name_filter", "filter_games"); + setValue(creatorName, "creator_name_filter"); } QString GameFiltersSettings::getCreatorNameFilter() { - return getValue("creator_name_filter", "filter_games").toString(); + return getValue("creator_name_filter").toString(); } void GameFiltersSettings::setMinPlayers(int min) { - setValue(min, "min_players", "filter_games"); + setValue(min, "min_players"); } int GameFiltersSettings::getMinPlayers() { - QVariant previous = getValue("min_players", "filter_games"); + QVariant previous = getValue("min_players"); return previous == QVariant() ? 1 : previous.toInt(); } void GameFiltersSettings::setMaxPlayers(int max) { - setValue(max, "max_players", "filter_games"); + setValue(max, "max_players"); } int GameFiltersSettings::getMaxPlayers() { - QVariant previous = getValue("max_players", "filter_games"); + QVariant previous = getValue("max_players"); return previous == QVariant() ? 99 : previous.toInt(); } void GameFiltersSettings::setMaxGameAge(const QTime &maxGameAge) { - setValue(maxGameAge, "max_game_age_time", "filter_games"); + setValue(maxGameAge, "max_game_age_time"); } QTime GameFiltersSettings::getMaxGameAge() { - QVariant previous = getValue("max_game_age_time", "filter_games"); + QVariant previous = getValue("max_game_age_time"); return previous.toTime(); } void GameFiltersSettings::setGameTypeEnabled(QString gametype, bool enabled) { - setValue(enabled, "game_type/" + hashGameType(gametype), "filter_games"); + setValue(enabled, "game_type/" + hashGameType(gametype)); } void GameFiltersSettings::setGameHashedTypeEnabled(QString gametypeHASHED, bool enabled) { - setValue(enabled, gametypeHASHED, "filter_games"); + setValue(enabled, gametypeHASHED); } bool GameFiltersSettings::isGameTypeEnabled(QString gametype) { - QVariant previous = getValue("game_type/" + hashGameType(gametype), "filter_games"); + QVariant previous = getValue("game_type/" + hashGameType(gametype)); return previous == QVariant() ? false : previous.toBool(); } void GameFiltersSettings::setShowOnlyIfSpectatorsCanWatch(bool show) { - setValue(show, "show_only_if_spectators_can_watch", "filter_games"); + setValue(show, "show_only_if_spectators_can_watch"); } bool GameFiltersSettings::isShowOnlyIfSpectatorsCanWatch() { - QVariant previous = getValue("show_only_if_spectators_can_watch", "filter_games"); + QVariant previous = getValue("show_only_if_spectators_can_watch"); return previous == QVariant() ? false : previous.toBool(); } void GameFiltersSettings::setShowSpectatorPasswordProtected(bool show) { - setValue(show, "show_spectator_password_protected", "filter_games"); + setValue(show, "show_spectator_password_protected"); } bool GameFiltersSettings::isShowSpectatorPasswordProtected() { - QVariant previous = getValue("show_spectator_password_protected", "filter_games"); + QVariant previous = getValue("show_spectator_password_protected"); return previous == QVariant() ? true : previous.toBool(); } void GameFiltersSettings::setShowOnlyIfSpectatorsCanChat(bool show) { - setValue(show, "show_only_if_spectators_can_chat", "filter_games"); + setValue(show, "show_only_if_spectators_can_chat"); } bool GameFiltersSettings::isShowOnlyIfSpectatorsCanChat() { - QVariant previous = getValue("show_only_if_spectators_can_chat", "filter_games"); + QVariant previous = getValue("show_only_if_spectators_can_chat"); return previous == QVariant() ? true : previous.toBool(); } void GameFiltersSettings::setShowOnlyIfSpectatorsCanSeeHands(bool show) { - setValue(show, "show_only_if_spectators_can_see_hands", "filter_games"); + setValue(show, "show_only_if_spectators_can_see_hands"); } bool GameFiltersSettings::isShowOnlyIfSpectatorsCanSeeHands() { - QVariant previous = getValue("show_only_if_spectators_can_see_hands", "filter_games"); + QVariant previous = getValue("show_only_if_spectators_can_see_hands"); return previous == QVariant() ? true : previous.toBool(); } \ No newline at end of file diff --git a/libcockatrice_settings/libcockatrice/settings/layouts_settings.cpp b/libcockatrice_settings/libcockatrice/settings/layouts_settings.cpp index 5791cbfe9..4b1400e0c 100644 --- a/libcockatrice_settings/libcockatrice/settings/layouts_settings.cpp +++ b/libcockatrice_settings/libcockatrice/settings/layouts_settings.cpp @@ -1,7 +1,7 @@ #include "layouts_settings.h" LayoutsSettings::LayoutsSettings(const QString &settingPath, QObject *parent) - : SettingsManager(settingPath + "layouts.ini", parent) + : SettingsManager(settingPath + "layouts.ini", "layouts", QString(), parent) { } diff --git a/libcockatrice_settings/libcockatrice/settings/message_settings.cpp b/libcockatrice_settings/libcockatrice/settings/message_settings.cpp index 786ea9cd1..761c94484 100644 --- a/libcockatrice_settings/libcockatrice/settings/message_settings.cpp +++ b/libcockatrice_settings/libcockatrice/settings/message_settings.cpp @@ -1,26 +1,26 @@ #include "message_settings.h" MessageSettings::MessageSettings(const QString &settingPath, QObject *parent) - : SettingsManager(settingPath + "messages.ini", parent) + : SettingsManager(settingPath + "messages.ini", "messages", QString(), parent) { } QString MessageSettings::getMessageAt(int index) { - return getValue(QString("msg%1").arg(index), "messages").toString(); + return getValue(QString("msg%1").arg(index)).toString(); } int MessageSettings::getCount() { - return getValue("count", "messages").toInt(); + return getValue("count").toInt(); } void MessageSettings::setCount(int count) { - setValue(count, "count", "messages"); + setValue(count, "count"); } void MessageSettings::setMessageAt(int index, QString message) { - setValue(message, QString("msg%1").arg(index), "messages"); + setValue(message, QString("msg%1").arg(index)); } diff --git a/libcockatrice_settings/libcockatrice/settings/recents_settings.cpp b/libcockatrice_settings/libcockatrice/settings/recents_settings.cpp index 5bbec3c8c..e64dd7494 100644 --- a/libcockatrice_settings/libcockatrice/settings/recents_settings.cpp +++ b/libcockatrice_settings/libcockatrice/settings/recents_settings.cpp @@ -3,22 +3,22 @@ #define MAX_RECENT_DECK_COUNT 10 RecentsSettings::RecentsSettings(const QString &settingPath, QObject *parent) - : SettingsManager(settingPath + "recents.ini", parent) + : SettingsManager(settingPath + "recents.ini", "deckbuilder", QString(), parent) { } QStringList RecentsSettings::getRecentlyOpenedDeckPaths() { - return getValue("deckpaths", "deckbuilder").toStringList(); + return getValue("deckpaths").toStringList(); } void RecentsSettings::clearRecentlyOpenedDeckPaths() { - deleteValue("deckpaths", "deckbuilder"); + deleteValue("deckpaths"); emit recentlyOpenedDeckPathsChanged(); } void RecentsSettings::updateRecentlyOpenedDeckPaths(const QString &deckPath) { - auto deckPaths = getValue("deckpaths", "deckbuilder").toStringList(); + auto deckPaths = getValue("deckpaths").toStringList(); deckPaths.removeAll(deckPath); deckPaths.prepend(deckPath); @@ -27,7 +27,7 @@ void RecentsSettings::updateRecentlyOpenedDeckPaths(const QString &deckPath) deckPaths.removeLast(); } - setValue(deckPaths, "deckpaths", "deckbuilder"); + setValue(deckPaths, "deckpaths"); emit recentlyOpenedDeckPathsChanged(); } diff --git a/libcockatrice_settings/libcockatrice/settings/servers_settings.cpp b/libcockatrice_settings/libcockatrice/settings/servers_settings.cpp index 01a6c795b..5f69f47c9 100644 --- a/libcockatrice_settings/libcockatrice/settings/servers_settings.cpp +++ b/libcockatrice_settings/libcockatrice/settings/servers_settings.cpp @@ -4,34 +4,34 @@ #include ServersSettings::ServersSettings(const QString &settingPath, QObject *parent) - : SettingsManager(settingPath + "servers.ini", parent) + : SettingsManager(settingPath + "servers.ini", "server", QString(), parent) { } void ServersSettings::setPreviousHostLogin(int previous) { - setValue(previous, "previoushostlogin", "server"); + setValue(previous, "previoushostlogin"); } int ServersSettings::getPreviousHostLogin() { - QVariant previous = getValue("previoushostlogin", "server"); + QVariant previous = getValue("previoushostlogin"); return previous == QVariant() ? 1 : previous.toInt(); } void ServersSettings::setPreviousHostList(QStringList list) { - setValue(list, "previoushosts", "server"); + setValue(list, "previoushosts"); } QStringList ServersSettings::getPreviousHostList() { - return getValue("previoushosts", "server").toStringList(); + return getValue("previoushosts").toStringList(); } void ServersSettings::setPrevioushostName(const QString &name) { - setValue(name, "previoushostName", "server"); + setValue(name, "previoushostName"); } QString ServersSettings::getSaveName(QString defaultname) @@ -50,7 +50,7 @@ QString ServersSettings::getSite(QString defaultSite) QString ServersSettings::getPrevioushostName() { - QVariant value = getValue("previoushostName", "server"); + QVariant value = getValue("previoushostName"); return value == QVariant() ? "Rooster Ranges" : value.toString(); } @@ -107,56 +107,56 @@ bool ServersSettings::getSavePassword() void ServersSettings::setAutoConnect(int autoconnect) { - setValue(autoconnect, "auto_connect", "server"); + setValue(autoconnect, "auto_connect"); } int ServersSettings::getAutoConnect() { - QVariant autoconnect = getValue("auto_connect", "server"); + QVariant autoconnect = getValue("auto_connect"); return autoconnect == QVariant() ? 0 : autoconnect.toInt(); } void ServersSettings::setFPHostName(QString hostname) { - setValue(hostname, "fphostname", "server"); + setValue(hostname, "fphostname"); } QString ServersSettings::getFPHostname(QString defaultHost) { - QVariant hostname = getValue("fphostname", "server"); + QVariant hostname = getValue("fphostname"); return hostname == QVariant() ? std::move(defaultHost) : hostname.toString(); } void ServersSettings::setFPPort(QString port) { - setValue(port, "fpport", "server"); + setValue(port, "fpport"); } QString ServersSettings::getFPPort(QString defaultPort) { - QVariant port = getValue("fpport", "server"); + QVariant port = getValue("fpport"); return port == QVariant() ? std::move(defaultPort) : port.toString(); } void ServersSettings::setFPPlayerName(QString playerName) { - setValue(playerName, "fpplayername", "server"); + setValue(playerName, "fpplayername"); } QString ServersSettings::getFPPlayerName(QString defaultName) { - QVariant name = getValue("fpplayername", "server"); + QVariant name = getValue("fpplayername"); return name == QVariant() ? std::move(defaultName) : name.toString(); } void ServersSettings::setClearDebugLogStatus(bool abIsChecked) { - setValue(abIsChecked, "save_debug_log", "server"); + setValue(abIsChecked, "save_debug_log"); } bool ServersSettings::getClearDebugLogStatus(bool abDefaultValue) { - QVariant cbFlushLog = getValue("save_debug_log", "server"); + QVariant cbFlushLog = getValue("save_debug_log"); return cbFlushLog == QVariant() ? abDefaultValue : cbFlushLog.toBool(); } diff --git a/libcockatrice_settings/libcockatrice/settings/settings_manager.cpp b/libcockatrice_settings/libcockatrice/settings/settings_manager.cpp index dc2da741e..ede5a2027 100644 --- a/libcockatrice_settings/libcockatrice/settings/settings_manager.cpp +++ b/libcockatrice_settings/libcockatrice/settings/settings_manager.cpp @@ -1,10 +1,35 @@ #include "settings_manager.h" -SettingsManager::SettingsManager(const QString &settingPath, QObject *parent) - : QObject(parent), settings(settingPath, QSettings::IniFormat) +SettingsManager::SettingsManager(const QString &settingPath, + const QString &_defaultGroup, + const QString &_defaultSubGroup, + QObject *parent) + : QObject(parent), settings(settingPath, QSettings::IniFormat), defaultGroup(_defaultGroup), + defaultSubGroup(_defaultSubGroup) { } +void SettingsManager::setValue(const QVariant &value, const QString &name) +{ + if (!defaultGroup.isEmpty()) { + settings.beginGroup(defaultGroup); + } + + if (!defaultSubGroup.isEmpty()) { + settings.beginGroup(defaultSubGroup); + } + + settings.setValue(name, value); + + if (!defaultSubGroup.isEmpty()) { + settings.endGroup(); + } + + if (!defaultGroup.isEmpty()) { + settings.endGroup(); + } +} + void SettingsManager::setValue(const QVariant &value, const QString &name, const QString &group, @@ -29,6 +54,27 @@ void SettingsManager::setValue(const QVariant &value, } } +void SettingsManager::deleteValue(const QString &name) +{ + if (!defaultGroup.isEmpty()) { + settings.beginGroup(defaultGroup); + } + + if (!defaultSubGroup.isEmpty()) { + settings.beginGroup(defaultSubGroup); + } + + settings.remove(name); + + if (!defaultSubGroup.isEmpty()) { + settings.endGroup(); + } + + if (!defaultGroup.isEmpty()) { + settings.endGroup(); + } +} + void SettingsManager::deleteValue(const QString &name, const QString &group, const QString &subGroup) { if (!group.isEmpty()) { @@ -50,6 +96,29 @@ void SettingsManager::deleteValue(const QString &name, const QString &group, con } } +QVariant SettingsManager::getValue(const QString &name) +{ + if (!defaultGroup.isEmpty()) { + settings.beginGroup(defaultGroup); + } + + if (!defaultSubGroup.isEmpty()) { + settings.beginGroup(defaultSubGroup); + } + + QVariant value = settings.value(name); + + if (!defaultSubGroup.isEmpty()) { + settings.endGroup(); + } + + if (!defaultGroup.isEmpty()) { + settings.endGroup(); + } + + return value; +} + QVariant SettingsManager::getValue(const QString &name, const QString &group, const QString &subGroup) { if (!group.isEmpty()) { diff --git a/libcockatrice_settings/libcockatrice/settings/settings_manager.h b/libcockatrice_settings/libcockatrice/settings/settings_manager.h index 1a24ecb28..a72094b4e 100644 --- a/libcockatrice_settings/libcockatrice/settings/settings_manager.h +++ b/libcockatrice_settings/libcockatrice/settings/settings_manager.h @@ -16,14 +16,23 @@ class SettingsManager : public QObject { Q_OBJECT public: - explicit SettingsManager(const QString &settingPath, QObject *parent = nullptr); - QVariant getValue(const QString &name, const QString &group = "", const QString &subGroup = ""); + explicit SettingsManager(const QString &settingPath, + const QString &defaultGroup = QString(), + const QString &defaultSubGroup = QString(), + QObject *parent = nullptr); + QVariant getValue(const QString &name); + QVariant getValue(const QString &name, const QString &group, const QString &subGroup = QString()); void sync(); protected: QSettings settings; - void setValue(const QVariant &value, const QString &name, const QString &group = "", const QString &subGroup = ""); - void deleteValue(const QString &name, const QString &group = "", const QString &subGroup = ""); + QString defaultGroup; + QString defaultSubGroup; + void setValue(const QVariant &value, const QString &name); + void + setValue(const QVariant &value, const QString &name, const QString &group, const QString &subGroup = QString()); + void deleteValue(const QString &name); + void deleteValue(const QString &name, const QString &group, const QString &subGroup = QString()); }; #endif // SETTINGSMANAGER_H diff --git a/oracle/CMakeLists.txt b/oracle/CMakeLists.txt index 36001a566..3bb4de5df 100644 --- a/oracle/CMakeLists.txt +++ b/oracle/CMakeLists.txt @@ -20,6 +20,7 @@ set(oracle_SOURCES src/main.cpp src/oraclewizard.cpp src/oracleimporter.cpp + src/pages.cpp src/pagetemplates.cpp src/parsehelpers.cpp src/qt-json/json.cpp diff --git a/oracle/src/oracleimporter.cpp b/oracle/src/oracleimporter.cpp index 98149e0b0..049dbaede 100644 --- a/oracle/src/oracleimporter.cpp +++ b/oracle/src/oracleimporter.cpp @@ -1,6 +1,8 @@ #include "oracleimporter.h" #include "client/settings/cache_settings.h" +#include "libcockatrice/interfaces/noop_card_preference_provider.h" +#include "libcockatrice/interfaces/noop_card_set_priority_controller.h" #include "parsehelpers.h" #include "qt-json/json.h" @@ -8,7 +10,6 @@ #include #include #include -#include #include #include @@ -457,14 +458,17 @@ int OracleImporter::importCardsFromSet(const CardSetPtr ¤tSet, const QList int OracleImporter::startImport() { - int setIndex = 0; + static ICardSetPriorityController *noOpController = new NoopCardSetPriorityController(); + // add an empty set for tokens - CardSetPtr tokenSet = CardSet::newInstance(SettingsCache::instance().cardDatabase(), CardSet::TOKENS_SETNAME, - tr("Dummy set containing tokens"), "Tokens"); + CardSetPtr tokenSet = + CardSet::newInstance(noOpController, CardSet::TOKENS_SETNAME, tr("Dummy set containing tokens"), "Tokens"); sets.insert(CardSet::TOKENS_SETNAME, tokenSet); + int setIndex = 0; + for (const SetToDownload &curSetToParse : allSets) { - CardSetPtr newSet = CardSet::newInstance(SettingsCache::instance().cardDatabase(), curSetToParse.getShortName(), + CardSetPtr newSet = CardSet::newInstance(noOpController, curSetToParse.getShortName(), curSetToParse.getLongName(), curSetToParse.getSetType(), curSetToParse.getReleaseDate(), curSetToParse.getPriority()); if (!sets.contains(newSet->getShortName())) @@ -485,7 +489,7 @@ int OracleImporter::startImport() bool OracleImporter::saveToFile(const QString &fileName, const QString &sourceUrl, const QString &sourceVersion) { - CockatriceXml4Parser parser(new SettingsCardPreferenceProvider()); + CockatriceXml4Parser parser(new NoopCardPreferenceProvider()); return parser.saveToFile(sets, cards, fileName, sourceUrl, sourceVersion); } diff --git a/oracle/src/oraclewizard.cpp b/oracle/src/oraclewizard.cpp index 6b463d5de..46e4722c6 100644 --- a/oracle/src/oraclewizard.cpp +++ b/oracle/src/oraclewizard.cpp @@ -3,55 +3,19 @@ #include "client/settings/cache_settings.h" #include "main.h" #include "oracleimporter.h" -#include "version_string.h" +#include "pages.h" +#include "pagetemplates.h" -#include -#include #include -#include -#include #include #include -#include #include -#include -#include #include -#include #include -#include #include -#include -#include #include #include -#ifdef HAS_LZMA -#include "lzma/decompress.h" -#endif - -#ifdef HAS_ZLIB -#include "zip/unzip.h" -#endif - -#define ZIP_SIGNATURE "PK" -// Xz stream header: 0xFD + "7zXZ" -#define XZ_SIGNATURE "\xFD\x37\x7A\x58\x5A" -#define MTGJSON_V4_URL_COMPONENT "mtgjson.com/files/" -#define ALLSETS_URL_FALLBACK "https://www.mtgjson.com/api/v5/AllPrintings.json" -#define MTGJSON_VERSION_URL "https://www.mtgjson.com/api/v5/Meta.json" - -#ifdef HAS_LZMA -#define ALLSETS_URL "https://www.mtgjson.com/api/v5/AllPrintings.json.xz" -#elif defined(HAS_ZLIB) -#define ALLSETS_URL "https://www.mtgjson.com/api/v5/AllPrintings.json.zip" -#else -#define ALLSETS_URL "https://www.mtgjson.com/api/v5/AllPrintings.json" -#endif - -#define TOKENS_URL "https://raw.githubusercontent.com/Cockatrice/Magic-Token/master/tokens.xml" -#define SPOILERS_URL "https://raw.githubusercontent.com/Cockatrice/Magic-Spoiler/files/spoiler.xml" - OracleWizard::OracleWizard(QWidget *parent) : QWizard(parent) { // define a dummy context that will be used where needed @@ -142,669 +106,3 @@ bool OracleWizard::saveTokensToFile(const QString &fileName) file.close(); return true; } - -IntroPage::IntroPage(QWidget *parent) : OracleWizardPage(parent) -{ - label = new QLabel(this); - label->setWordWrap(true); - - languageLabel = new QLabel(this); - versionLabel = new QLabel(this); - languageBox = new QComboBox(this); - - QStringList languageCodes = findQmFiles(); - for (const QString &code : languageCodes) { - QString langName = languageName(code); - languageBox->addItem(langName, code); - } - - QString setLanguage = QCoreApplication::translate("i18n", DEFAULT_LANG_NAME); - int index = languageBox->findText(setLanguage, Qt::MatchExactly); - if (index == -1) { - qWarning() << "could not find language" << setLanguage; - } else { - languageBox->setCurrentIndex(index); - } - - connect(languageBox, qOverload(&QComboBox::currentIndexChanged), this, &IntroPage::languageBoxChanged); - - auto *layout = new QGridLayout(this); - layout->addWidget(label, 0, 0, 1, 2); - layout->addWidget(languageLabel, 1, 0); - layout->addWidget(languageBox, 1, 1); - layout->addWidget(versionLabel, 2, 0, 1, 2); - - setLayout(layout); -} - -void IntroPage::initializePage() -{ - if (wizard()->backgroundMode) { - emit readyToContinue(); - } -} - -QStringList IntroPage::findQmFiles() -{ - QDir dir(translationPath); - QStringList fileNames = dir.entryList(QStringList(translationPrefix + "_*.qm"), QDir::Files, QDir::Name); - fileNames.replaceInStrings(QRegularExpression(translationPrefix + "_(.*)\\.qm"), "\\1"); - return fileNames; -} - -QString IntroPage::languageName(const QString &lang) -{ - QTranslator qTranslator; - - QString appNameHint = translationPrefix + "_" + lang; - bool appTranslationLoaded = qTranslator.load(appNameHint, translationPath); - if (!appTranslationLoaded) { - qDebug() << "Unable to load" << translationPrefix << "translation" << appNameHint << "at" << translationPath; - } - - return qTranslator.translate("i18n", DEFAULT_LANG_NAME); -} - -void IntroPage::languageBoxChanged(int index) -{ - SettingsCache::instance().setLang(languageBox->itemData(index).toString()); -} - -void IntroPage::retranslateUi() -{ - setTitle(tr("Introduction")); - label->setText(tr("This wizard will import the list of sets, cards, and tokens " - "that will be used by Cockatrice.")); - languageLabel->setText(tr("Interface language:")); - versionLabel->setText(tr("Version:") + QString(" %1").arg(VERSION_STRING)); -} - -void OutroPage::retranslateUi() -{ - setTitle(tr("Finished")); - setSubTitle(tr("The wizard has finished.") + "
" + - tr("You can now start using Cockatrice with the newly updated cards.") + "

" + - tr("If the card databases don't reload automatically, restart the Cockatrice client.")); -} - -void OutroPage::initializePage() -{ - if (wizard()->backgroundMode) { - wizard()->accept(); - exit(0); - } -} - -LoadSetsPage::LoadSetsPage(QWidget *parent) : OracleWizardPage(parent) -{ - urlRadioButton = new QRadioButton(this); - fileRadioButton = new QRadioButton(this); - - urlLineEdit = new QLineEdit(this); - fileLineEdit = new QLineEdit(this); - - progressLabel = new QLabel(this); - progressBar = new QProgressBar(this); - - urlRadioButton->setChecked(true); - - urlButton = new QPushButton(this); - connect(urlButton, &QPushButton::clicked, this, &LoadSetsPage::actRestoreDefaultUrl); - - fileButton = new QPushButton(this); - connect(fileButton, &QPushButton::clicked, this, &LoadSetsPage::actLoadSetsFile); - - auto *layout = new QGridLayout(this); - layout->addWidget(urlRadioButton, 0, 0); - layout->addWidget(urlLineEdit, 0, 1); - layout->addWidget(urlButton, 1, 1, Qt::AlignRight); - layout->addWidget(fileRadioButton, 2, 0); - layout->addWidget(fileLineEdit, 2, 1); - layout->addWidget(fileButton, 3, 1, Qt::AlignRight); - layout->addWidget(progressLabel, 4, 0); - layout->addWidget(progressBar, 4, 1); - - connect(&watcher, &QFutureWatcher::finished, this, &LoadSetsPage::importFinished); - - setLayout(layout); -} - -void LoadSetsPage::initializePage() -{ - urlLineEdit->setText(wizard()->settings->value("allsetsurl", ALLSETS_URL).toString()); - - progressLabel->hide(); - progressBar->hide(); - - if (wizard()->backgroundMode) { - if (isEnabled()) { - validatePage(); - } - } -} - -void LoadSetsPage::retranslateUi() -{ - setTitle(tr("Source selection")); - setSubTitle(tr("Please specify a compatible source for the list of sets and cards. " - "You can specify a URL address that will be downloaded or " - "use an existing file from your computer.")); - - urlRadioButton->setText(tr("Download URL:")); - fileRadioButton->setText(tr("Local file:")); - urlButton->setText(tr("Restore default URL")); - fileButton->setText(tr("Choose file...")); -} - -void LoadSetsPage::actRestoreDefaultUrl() -{ - urlLineEdit->setText(ALLSETS_URL); -} - -void LoadSetsPage::actLoadSetsFile() -{ - QFileDialog dialog(this, tr("Load sets file")); - dialog.setFileMode(QFileDialog::ExistingFile); - - QString extensions = "*.json *.xml"; -#ifdef HAS_ZLIB - extensions += " *.zip"; -#endif -#ifdef HAS_LZMA - extensions += " *.xz"; -#endif - dialog.setNameFilter(tr("Sets file (%1)").arg(extensions)); - - if (!fileLineEdit->text().isEmpty() && QFile::exists(fileLineEdit->text())) { - dialog.selectFile(fileLineEdit->text()); - } - - if (!dialog.exec()) { - return; - } - - fileLineEdit->setText(dialog.selectedFiles().at(0)); -} - -bool LoadSetsPage::validatePage() -{ - // once the import is finished, we call next(); skip validation - if (wizard()->downloadedPlainXml || wizard()->importer->getSets().count() > 0) { - return true; - } - - // else, try to import sets - if (urlRadioButton->isChecked()) { - // If a user attempts to download from V4, redirect them to V5 - if (urlLineEdit->text().contains(MTGJSON_V4_URL_COMPONENT)) { - actRestoreDefaultUrl(); - } - - const auto url = QUrl::fromUserInput(urlLineEdit->text()); - - if (!url.isValid()) { - QMessageBox::critical(this, tr("Error"), tr("The provided URL is not valid.")); - return false; - } - - progressLabel->setText(tr("Downloading (0MB)")); - // show an infinite progressbar - progressBar->setMaximum(0); - progressBar->setMinimum(0); - progressBar->setValue(0); - progressLabel->show(); - progressBar->show(); - - wizard()->disableButtons(); - setEnabled(false); - - downloadSetsFile(url); - } else if (fileRadioButton->isChecked()) { - QFile setsFile(fileLineEdit->text()); - if (!setsFile.exists()) { - QMessageBox::critical(this, tr("Error"), tr("Please choose a file.")); - return false; - } - - if (!setsFile.open(QIODevice::ReadOnly)) { - QMessageBox::critical(nullptr, tr("Error"), tr("Cannot open file '%1'.").arg(fileLineEdit->text())); - return false; - } - - wizard()->disableButtons(); - setEnabled(false); - - wizard()->setCardSourceUrl(setsFile.fileName()); - wizard()->setCardSourceVersion("unknown"); - - readSetsFromByteArray(setsFile.readAll()); - } - - return false; -} - -void LoadSetsPage::downloadSetsFile(const QUrl &url) -{ - wizard()->setCardSourceVersion("unknown"); - - const auto urlString = url.toString(); - if (urlString == ALLSETS_URL || urlString == ALLSETS_URL_FALLBACK) { - const auto versionUrl = QUrl::fromUserInput(MTGJSON_VERSION_URL); - auto *versionReply = wizard()->nam->get(QNetworkRequest(versionUrl)); - connect(versionReply, &QNetworkReply::finished, [this, versionReply]() { - if (versionReply->error() == QNetworkReply::NoError) { - auto jsonData = versionReply->readAll(); - QJsonParseError jsonError{}; - auto jsonResponse = QJsonDocument::fromJson(jsonData, &jsonError); - - if (jsonError.error == QJsonParseError::NoError) { - const auto jsonMap = jsonResponse.toVariant().toMap(); - - auto versionString = jsonMap.value("meta").toMap().value("version").toString(); - if (versionString.isEmpty()) { - versionString = "unknown"; - } - wizard()->setCardSourceVersion(versionString); - } - } - - versionReply->deleteLater(); - }); - } - - wizard()->setCardSourceUrl(url.toString()); - - auto *reply = wizard()->nam->get(QNetworkRequest(url)); - - connect(reply, &QNetworkReply::finished, this, &LoadSetsPage::actDownloadFinishedSetsFile); - connect(reply, &QNetworkReply::downloadProgress, this, &LoadSetsPage::actDownloadProgressSetsFile); -} - -void LoadSetsPage::actDownloadProgressSetsFile(qint64 received, qint64 total) -{ - if (total > 0) { - progressBar->setMaximum(static_cast(total)); - progressBar->setValue(static_cast(received)); - } - progressLabel->setText(tr("Downloading (%1MB)").arg((int)received / (1024 * 1024))); -} - -void LoadSetsPage::actDownloadFinishedSetsFile() -{ - // check for a reply - auto *reply = dynamic_cast(sender()); - auto errorCode = reply->error(); - if (errorCode != QNetworkReply::NoError) { - QMessageBox::critical(this, tr("Error"), tr("Network error: %1.").arg(reply->errorString())); - - wizard()->enableButtons(); - setEnabled(true); - - reply->deleteLater(); - return; - } - - auto statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); - if (statusCode == 301 || statusCode == 302) { - const auto redirectUrl = reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl(); - qDebug() << "following redirect url:" << redirectUrl.toString(); - downloadSetsFile(redirectUrl); - reply->deleteLater(); - return; - } - - progressLabel->hide(); - progressBar->hide(); - - // save AllPrintings.json url, but only if the user customized it and download was successful - if (urlLineEdit->text() != QString(ALLSETS_URL)) { - wizard()->settings->setValue("allsetsurl", urlLineEdit->text()); - } else { - wizard()->settings->remove("allsetsurl"); - } - - readSetsFromByteArray(reply->readAll()); - reply->deleteLater(); -} - -void LoadSetsPage::readSetsFromByteArray(QByteArray _data) -{ - // show an infinite progressbar - progressBar->setMaximum(0); - progressBar->setMinimum(0); - progressBar->setValue(0); - progressLabel->setText(tr("Parsing file")); - progressLabel->show(); - progressBar->show(); - - wizard()->downloadedPlainXml = false; - wizard()->xmlData.clear(); - readSetsFromByteArrayRef(_data); -} - -void LoadSetsPage::readSetsFromByteArrayRef(QByteArray &_data) -{ - // unzip the file if needed - if (_data.startsWith(XZ_SIGNATURE)) { -#ifdef HAS_LZMA - // zipped file - auto *inBuffer = new QBuffer(&_data); - auto newData = QByteArray(); - auto *outBuffer = new QBuffer(&newData); - inBuffer->open(QBuffer::ReadOnly); - outBuffer->open(QBuffer::WriteOnly); - XzDecompressor xz; - if (!xz.decompress(inBuffer, outBuffer)) { - zipDownloadFailed(tr("Xz extraction failed.")); - return; - } - _data.clear(); - readSetsFromByteArrayRef(newData); - return; -#else - zipDownloadFailed(tr("Sorry, this version of Oracle does not support xz compressed files.")); - - wizard()->enableButtons(); - setEnabled(true); - progressLabel->hide(); - progressBar->hide(); - return; -#endif - } else if (_data.startsWith(ZIP_SIGNATURE)) { -#ifdef HAS_ZLIB - // zipped file - auto *inBuffer = new QBuffer(&_data); - auto newData = QByteArray(); - auto *outBuffer = new QBuffer(&newData); - QString fileName; - UnZip::ErrorCode ec; - UnZip uz; - - ec = uz.openArchive(inBuffer); - if (ec != UnZip::Ok) { - zipDownloadFailed(tr("Failed to open Zip archive: %1.").arg(uz.formatError(ec))); - return; - } - - if (uz.fileList().size() != 1) { - zipDownloadFailed(tr("Zip extraction failed: the Zip archive doesn't contain exactly one file.")); - return; - } - fileName = uz.fileList().at(0); - - outBuffer->open(QBuffer::ReadWrite); - ec = uz.extractFile(fileName, outBuffer); - if (ec != UnZip::Ok) { - zipDownloadFailed(tr("Zip extraction failed: %1.").arg(uz.formatError(ec))); - uz.closeArchive(); - return; - } - _data.clear(); - readSetsFromByteArrayRef(newData); - return; -#else - zipDownloadFailed(tr("Sorry, this version of Oracle does not support zipped files.")); - - wizard()->enableButtons(); - setEnabled(true); - progressLabel->hide(); - progressBar->hide(); - return; -#endif - } else if (_data.startsWith("{")) { - // Start the computation. - jsonData = std::move(_data); - future = QtConcurrent::run([this] { return wizard()->importer->readSetsFromByteArray(std::move(jsonData)); }); - watcher.setFuture(future); - } else if (_data.startsWith("<")) { - // save xml file and don't do any processing - wizard()->downloadedPlainXml = true; - wizard()->xmlData = std::move(_data); - importFinished(); - } else { - wizard()->enableButtons(); - setEnabled(true); - progressLabel->hide(); - progressBar->hide(); - QMessageBox::critical(this, tr("Error"), tr("Failed to interpret downloaded data.")); - } -} - -void LoadSetsPage::zipDownloadFailed(const QString &message) -{ - wizard()->enableButtons(); - setEnabled(true); - progressLabel->hide(); - progressBar->hide(); - - QMessageBox::StandardButton reply; - reply = static_cast(QMessageBox::question( - this, tr("Error"), message + "
" + tr("Do you want to download the uncompressed file instead?"), - QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes)); - - if (reply == QMessageBox::Yes) { - urlRadioButton->setChecked(true); - urlLineEdit->setText(ALLSETS_URL_FALLBACK); - - wizard()->next(); - } -} - -void LoadSetsPage::importFinished() -{ - wizard()->enableButtons(); - setEnabled(true); - progressLabel->hide(); - progressBar->hide(); - - if (wizard()->downloadedPlainXml || watcher.future().result()) { - wizard()->next(); - } else { - QMessageBox::critical(this, tr("Error"), - tr("The file was retrieved successfully, but it does not contain any sets data.")); - } -} - -SaveSetsPage::SaveSetsPage(QWidget *parent) : OracleWizardPage(parent) -{ - pathLabel = new QLabel(this); - saveLabel = new QLabel(this); - - defaultPathCheckBox = new QCheckBox(this); - - messageLog = new QTextEdit(this); - messageLog->setReadOnly(true); - - auto *layout = new QGridLayout(this); - layout->addWidget(messageLog, 0, 0); - layout->addWidget(saveLabel, 1, 0); - layout->addWidget(pathLabel, 2, 0); - layout->addWidget(defaultPathCheckBox, 3, 0); - - setLayout(layout); -} - -void SaveSetsPage::cleanupPage() -{ - wizard()->importer->clear(); - disconnect(wizard()->importer, &OracleImporter::setIndexChanged, nullptr, nullptr); -} - -void SaveSetsPage::initializePage() -{ - messageLog->clear(); - - retranslateUi(); - if (wizard()->downloadedPlainXml) { - messageLog->hide(); - } else { - messageLog->show(); - connect(wizard()->importer, &OracleImporter::setIndexChanged, this, &SaveSetsPage::updateTotalProgress); - - int setsImported = wizard()->importer->startImport(); - - if (setsImported == 0) { - QMessageBox::critical(this, tr("Error"), tr("No set has been imported.")); - } - } - - if (wizard()->backgroundMode) { - emit readyToContinue(); - } -} - -void SaveSetsPage::retranslateUi() -{ - setTitle(tr("Sets imported")); - if (wizard()->downloadedPlainXml) { - setSubTitle(tr("A cockatrice database file of %1 MB has been downloaded.") - .arg(qRound(wizard()->xmlData.size() / 1000000.0))); - } else { - setSubTitle(tr("The following sets have been found:")); - } - - saveLabel->setText(tr("Press \"Save\" to store the imported cards in the Cockatrice database.")); - pathLabel->setText(tr("The card database will be saved at the following location:") + "
" + - SettingsCache::instance().getCardDatabasePath()); - defaultPathCheckBox->setText(tr("Save to a custom path (not recommended)")); - - setButtonText(QWizard::NextButton, tr("&Save")); -} - -void SaveSetsPage::updateTotalProgress(int cardsImported, int /* setIndex */, const QString &setName) -{ - if (setName.isEmpty()) { - messageLog->append("" + tr("Import finished: %1 cards.").arg(wizard()->importer->getCardList().size()) + - ""); - } else { - messageLog->append(tr("%1: %2 cards imported").arg(setName).arg(cardsImported)); - } - - messageLog->verticalScrollBar()->setValue(messageLog->verticalScrollBar()->maximum()); -} - -bool SaveSetsPage::validatePage() -{ - QString defaultPath = SettingsCache::instance().getCardDatabasePath(); - QString windowName = tr("Save card database"); - QString fileType = tr("XML; card database (*.xml)"); - - QString fileName; - if (defaultPathCheckBox->isChecked()) { - fileName = QFileDialog::getSaveFileName(this, windowName, defaultPath, fileType); - } else { - fileName = defaultPath; - } - - if (fileName.isEmpty()) { - return false; - } - - QFileInfo fi(fileName); - QDir fileDir(fi.path()); - if (!fileDir.exists() && !fileDir.mkpath(fileDir.absolutePath())) { - return false; - } - - if (wizard()->downloadedPlainXml) { - QFile file(fileName); - if (!file.open(QIODevice::WriteOnly)) { - qDebug() << "File write (w) failed for" << fileName; - return false; - } - if (file.write(wizard()->xmlData) < 1) { - qDebug() << "File write (w) failed for" << fileName; - return false; - } - wizard()->xmlData.clear(); - } else if (!wizard()->importer->saveToFile(fileName, wizard()->getCardSourceUrl(), - wizard()->getCardSourceVersion())) { - QMessageBox::critical(this, tr("Error"), tr("The file could not be saved to %1").arg(fileName)); - return false; - } - - return true; -} - -void LoadTokensPage::initializePage() -{ - SimpleDownloadFilePage::initializePage(); - - if (wizard()->backgroundMode) { - emit readyToContinue(); - } -} - -QString LoadTokensPage::getDefaultUrl() -{ - return TOKENS_URL; -} - -QString LoadTokensPage::getCustomUrlSettingsKey() -{ - return "tokensurl"; -} - -QString LoadTokensPage::getDefaultSavePath() -{ - return SettingsCache::instance().getTokenDatabasePath(); -} - -QString LoadTokensPage::getWindowTitle() -{ - return tr("Save token database"); -} - -QString LoadTokensPage::getFileType() -{ - return tr("XML; token database (*.xml)"); -} - -void LoadTokensPage::retranslateUi() -{ - setTitle(tr("Tokens import")); - setSubTitle(tr("Please specify a compatible source for token data.")); - - urlLabel->setText(tr("Download URL:")); - urlButton->setText(tr("Restore default URL")); - pathLabel->setText(tr("The token database will be saved at the following location:") + "
" + - SettingsCache::instance().getTokenDatabasePath()); - defaultPathCheckBox->setText(tr("Save to a custom path (not recommended)")); -} - -QString LoadSpoilersPage::getDefaultUrl() -{ - return SPOILERS_URL; -} - -QString LoadSpoilersPage::getCustomUrlSettingsKey() -{ - return "spoilersurl"; -} - -QString LoadSpoilersPage::getDefaultSavePath() -{ - return SettingsCache::instance().getTokenDatabasePath(); -} - -QString LoadSpoilersPage::getWindowTitle() -{ - return tr("Save spoiler database"); -} - -QString LoadSpoilersPage::getFileType() -{ - return tr("XML; spoiler database (*.xml)"); -} - -void LoadSpoilersPage::retranslateUi() -{ - setTitle(tr("Spoilers import")); - setSubTitle(tr("Please specify a compatible source for spoiler data.")); - - urlLabel->setText(tr("Download URL:")); - urlButton->setText(tr("Restore default URL")); - pathLabel->setText(tr("The spoiler database will be saved at the following location:") + "
" + - SettingsCache::instance().getSpoilerCardDatabasePath()); - defaultPathCheckBox->setText(tr("Save to a custom path (not recommended)")); -} diff --git a/oracle/src/oraclewizard.h b/oracle/src/oraclewizard.h index fe0bf1a21..c913094e3 100644 --- a/oracle/src/oraclewizard.h +++ b/oracle/src/oraclewizard.h @@ -1,9 +1,6 @@ #ifndef ORACLEWIZARD_H #define ORACLEWIZARD_H -#include -#include -#include #include #include @@ -20,8 +17,6 @@ class QVBoxLayout; class OracleImporter; class QSettings; -#include "pagetemplates.h" - class OracleWizard : public QWizard { Q_OBJECT @@ -84,133 +79,4 @@ protected: void changeEvent(QEvent *event) override; }; -class IntroPage : public OracleWizardPage -{ - Q_OBJECT -public: - explicit IntroPage(QWidget *parent = nullptr); - void retranslateUi() override; - -private: - QStringList findQmFiles(); - QString languageName(const QString &lang); - -private: - QLabel *label, *languageLabel, *versionLabel; - QComboBox *languageBox; - -private slots: - void languageBoxChanged(int index); - -protected slots: - void initializePage() override; -}; - -class OutroPage : public OracleWizardPage -{ - Q_OBJECT -public: - explicit OutroPage(QWidget * = nullptr) - { - } - void retranslateUi() override; - -protected: - void initializePage() override; -}; - -class LoadSetsPage : public OracleWizardPage -{ - Q_OBJECT -public: - explicit LoadSetsPage(QWidget *parent = nullptr); - void retranslateUi() override; - -protected: - void initializePage() override; - bool validatePage() override; - void readSetsFromByteArray(QByteArray _data); - void readSetsFromByteArrayRef(QByteArray &_data); - void downloadSetsFile(const QUrl &url); - -private: - QRadioButton *urlRadioButton; - QRadioButton *fileRadioButton; - QLineEdit *urlLineEdit; - QLineEdit *fileLineEdit; - QPushButton *urlButton; - QPushButton *fileButton; - QLabel *progressLabel; - QProgressBar *progressBar; - - QFutureWatcher watcher; - QFuture future; - QByteArray jsonData; - -private slots: - void actLoadSetsFile(); - void actRestoreDefaultUrl(); - void actDownloadProgressSetsFile(qint64 received, qint64 total); - void actDownloadFinishedSetsFile(); - void importFinished(); - void zipDownloadFailed(const QString &message); -}; - -class SaveSetsPage : public OracleWizardPage -{ - Q_OBJECT -public: - explicit SaveSetsPage(QWidget *parent = nullptr); - void retranslateUi() override; - -private: - QTextEdit *messageLog; - QCheckBox *defaultPathCheckBox; - QLabel *pathLabel; - QLabel *saveLabel; - -protected: - void initializePage() override; - void cleanupPage() override; - bool validatePage() override; - -private slots: - void updateTotalProgress(int cardsImported, int setIndex, const QString &setName); -}; - -class LoadSpoilersPage : public SimpleDownloadFilePage -{ - Q_OBJECT -public: - explicit LoadSpoilersPage(QWidget * = nullptr) - { - } - void retranslateUi() override; - -protected: - QString getDefaultUrl() override; - QString getCustomUrlSettingsKey() override; - QString getDefaultSavePath() override; - QString getWindowTitle() override; - QString getFileType() override; -}; - -class LoadTokensPage : public SimpleDownloadFilePage -{ - Q_OBJECT -public: - explicit LoadTokensPage(QWidget * = nullptr) - { - } - void retranslateUi() override; - -protected: - QString getDefaultUrl() override; - QString getCustomUrlSettingsKey() override; - QString getDefaultSavePath() override; - QString getWindowTitle() override; - QString getFileType() override; - void initializePage() override; -}; - #endif diff --git a/oracle/src/pages.cpp b/oracle/src/pages.cpp new file mode 100644 index 000000000..9b2f5ce7c --- /dev/null +++ b/oracle/src/pages.cpp @@ -0,0 +1,722 @@ +#include "pages.h" + +#include "client/settings/cache_settings.h" +#include "main.h" +#include "oracleimporter.h" +#include "oraclewizard.h" +#include "pages.h" +#include "pagetemplates.h" +#include "version_string.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAS_LZMA +#include "lzma/decompress.h" +#endif + +#ifdef HAS_ZLIB +#include "zip/unzip.h" +#endif + +#define ZIP_SIGNATURE "PK" +// Xz stream header: 0xFD + "7zXZ" +#define XZ_SIGNATURE "\xFD\x37\x7A\x58\x5A" +#define MTGJSON_V4_URL_COMPONENT "mtgjson.com/files/" +#define ALLSETS_URL_FALLBACK "https://www.mtgjson.com/api/v5/AllPrintings.json" +#define MTGJSON_VERSION_URL "https://www.mtgjson.com/api/v5/Meta.json" + +#ifdef HAS_LZMA +#define ALLSETS_URL "https://www.mtgjson.com/api/v5/AllPrintings.json.xz" +#elif defined(HAS_ZLIB) +#define ALLSETS_URL "https://www.mtgjson.com/api/v5/AllPrintings.json.zip" +#else +#define ALLSETS_URL "https://www.mtgjson.com/api/v5/AllPrintings.json" +#endif + +#define TOKENS_URL "https://raw.githubusercontent.com/Cockatrice/Magic-Token/master/tokens.xml" +#define SPOILERS_URL "https://raw.githubusercontent.com/Cockatrice/Magic-Spoiler/files/spoiler.xml" + +IntroPage::IntroPage(QWidget *parent) : OracleWizardPage(parent) +{ + label = new QLabel(this); + label->setWordWrap(true); + + languageLabel = new QLabel(this); + versionLabel = new QLabel(this); + languageBox = new QComboBox(this); + + QStringList languageCodes = findQmFiles(); + for (const QString &code : languageCodes) { + QString langName = languageName(code); + languageBox->addItem(langName, code); + } + + QString setLanguage = QCoreApplication::translate("i18n", DEFAULT_LANG_NAME); + int index = languageBox->findText(setLanguage, Qt::MatchExactly); + if (index == -1) { + qWarning() << "could not find language" << setLanguage; + } else { + languageBox->setCurrentIndex(index); + } + + connect(languageBox, qOverload(&QComboBox::currentIndexChanged), this, &IntroPage::languageBoxChanged); + + auto *layout = new QGridLayout(this); + layout->addWidget(label, 0, 0, 1, 2); + layout->addWidget(languageLabel, 1, 0); + layout->addWidget(languageBox, 1, 1); + layout->addWidget(versionLabel, 2, 0, 1, 2); + + setLayout(layout); +} + +void IntroPage::initializePage() +{ + if (wizard()->backgroundMode) { + emit readyToContinue(); + } +} + +QStringList IntroPage::findQmFiles() +{ + QDir dir(translationPath); + QStringList fileNames = dir.entryList(QStringList(translationPrefix + "_*.qm"), QDir::Files, QDir::Name); + fileNames.replaceInStrings(QRegularExpression(translationPrefix + "_(.*)\\.qm"), "\\1"); + return fileNames; +} + +QString IntroPage::languageName(const QString &lang) +{ + QTranslator qTranslator; + + QString appNameHint = translationPrefix + "_" + lang; + bool appTranslationLoaded = qTranslator.load(appNameHint, translationPath); + if (!appTranslationLoaded) { + qDebug() << "Unable to load" << translationPrefix << "translation" << appNameHint << "at" << translationPath; + } + + return qTranslator.translate("i18n", DEFAULT_LANG_NAME); +} + +void IntroPage::languageBoxChanged(int index) +{ + SettingsCache::instance().setLang(languageBox->itemData(index).toString()); +} + +void IntroPage::retranslateUi() +{ + setTitle(tr("Introduction")); + label->setText(tr("This wizard will import the list of sets, cards, and tokens " + "that will be used by Cockatrice.")); + languageLabel->setText(tr("Interface language:")); + versionLabel->setText(tr("Version:") + QString(" %1").arg(VERSION_STRING)); +} + +void OutroPage::retranslateUi() +{ + setTitle(tr("Finished")); + setSubTitle(tr("The wizard has finished.") + "
" + + tr("You can now start using Cockatrice with the newly updated cards.") + "

" + + tr("If the card databases don't reload automatically, restart the Cockatrice client.")); +} + +void OutroPage::initializePage() +{ + if (wizard()->backgroundMode) { + wizard()->accept(); + exit(0); + } +} + +LoadSetsPage::LoadSetsPage(QWidget *parent) : OracleWizardPage(parent) +{ + urlRadioButton = new QRadioButton(this); + fileRadioButton = new QRadioButton(this); + + urlLineEdit = new QLineEdit(this); + fileLineEdit = new QLineEdit(this); + + progressLabel = new QLabel(this); + progressBar = new QProgressBar(this); + + urlRadioButton->setChecked(true); + + urlButton = new QPushButton(this); + connect(urlButton, &QPushButton::clicked, this, &LoadSetsPage::actRestoreDefaultUrl); + + fileButton = new QPushButton(this); + connect(fileButton, &QPushButton::clicked, this, &LoadSetsPage::actLoadSetsFile); + + auto *layout = new QGridLayout(this); + layout->addWidget(urlRadioButton, 0, 0); + layout->addWidget(urlLineEdit, 0, 1); + layout->addWidget(urlButton, 1, 1, Qt::AlignRight); + layout->addWidget(fileRadioButton, 2, 0); + layout->addWidget(fileLineEdit, 2, 1); + layout->addWidget(fileButton, 3, 1, Qt::AlignRight); + layout->addWidget(progressLabel, 4, 0); + layout->addWidget(progressBar, 4, 1); + + connect(&watcher, &QFutureWatcher::finished, this, &LoadSetsPage::importFinished); + + setLayout(layout); +} + +void LoadSetsPage::initializePage() +{ + urlLineEdit->setText(wizard()->settings->value("allsetsurl", ALLSETS_URL).toString()); + + progressLabel->hide(); + progressBar->hide(); + + if (wizard()->backgroundMode) { + if (isEnabled()) { + validatePage(); + } + } +} + +void LoadSetsPage::retranslateUi() +{ + setTitle(tr("Source selection")); + setSubTitle(tr("Please specify a compatible source for the list of sets and cards. " + "You can specify a URL address that will be downloaded or " + "use an existing file from your computer.")); + + urlRadioButton->setText(tr("Download URL:")); + fileRadioButton->setText(tr("Local file:")); + urlButton->setText(tr("Restore default URL")); + fileButton->setText(tr("Choose file...")); +} + +void LoadSetsPage::actRestoreDefaultUrl() +{ + urlLineEdit->setText(ALLSETS_URL); +} + +void LoadSetsPage::actLoadSetsFile() +{ + QFileDialog dialog(this, tr("Load sets file")); + dialog.setFileMode(QFileDialog::ExistingFile); + + QString extensions = "*.json *.xml"; +#ifdef HAS_ZLIB + extensions += " *.zip"; +#endif +#ifdef HAS_LZMA + extensions += " *.xz"; +#endif + dialog.setNameFilter(tr("Sets file (%1)").arg(extensions)); + + if (!fileLineEdit->text().isEmpty() && QFile::exists(fileLineEdit->text())) { + dialog.selectFile(fileLineEdit->text()); + } + + if (!dialog.exec()) { + return; + } + + fileLineEdit->setText(dialog.selectedFiles().at(0)); +} + +bool LoadSetsPage::validatePage() +{ + // once the import is finished, we call next(); skip validation + if (wizard()->downloadedPlainXml || wizard()->importer->getSets().count() > 0) { + return true; + } + + // else, try to import sets + if (urlRadioButton->isChecked()) { + // If a user attempts to download from V4, redirect them to V5 + if (urlLineEdit->text().contains(MTGJSON_V4_URL_COMPONENT)) { + actRestoreDefaultUrl(); + } + + const auto url = QUrl::fromUserInput(urlLineEdit->text()); + + if (!url.isValid()) { + QMessageBox::critical(this, tr("Error"), tr("The provided URL is not valid.")); + return false; + } + + progressLabel->setText(tr("Downloading (0MB)")); + // show an infinite progressbar + progressBar->setMaximum(0); + progressBar->setMinimum(0); + progressBar->setValue(0); + progressLabel->show(); + progressBar->show(); + + wizard()->disableButtons(); + setEnabled(false); + + downloadSetsFile(url); + } else if (fileRadioButton->isChecked()) { + QFile setsFile(fileLineEdit->text()); + if (!setsFile.exists()) { + QMessageBox::critical(this, tr("Error"), tr("Please choose a file.")); + return false; + } + + if (!setsFile.open(QIODevice::ReadOnly)) { + QMessageBox::critical(nullptr, tr("Error"), tr("Cannot open file '%1'.").arg(fileLineEdit->text())); + return false; + } + + wizard()->disableButtons(); + setEnabled(false); + + wizard()->setCardSourceUrl(setsFile.fileName()); + wizard()->setCardSourceVersion("unknown"); + + readSetsFromByteArray(setsFile.readAll()); + } + + return false; +} + +void LoadSetsPage::downloadSetsFile(const QUrl &url) +{ + wizard()->setCardSourceVersion("unknown"); + + const auto urlString = url.toString(); + if (urlString == ALLSETS_URL || urlString == ALLSETS_URL_FALLBACK) { + const auto versionUrl = QUrl::fromUserInput(MTGJSON_VERSION_URL); + auto *versionReply = wizard()->nam->get(QNetworkRequest(versionUrl)); + connect(versionReply, &QNetworkReply::finished, [this, versionReply]() { + if (versionReply->error() == QNetworkReply::NoError) { + auto data = versionReply->readAll(); + QJsonParseError jsonError{}; + auto jsonResponse = QJsonDocument::fromJson(data, &jsonError); + + if (jsonError.error == QJsonParseError::NoError) { + const auto jsonMap = jsonResponse.toVariant().toMap(); + + auto versionString = jsonMap.value("meta").toMap().value("version").toString(); + if (versionString.isEmpty()) { + versionString = "unknown"; + } + wizard()->setCardSourceVersion(versionString); + } + } + + versionReply->deleteLater(); + }); + } + + wizard()->setCardSourceUrl(url.toString()); + + auto *reply = wizard()->nam->get(QNetworkRequest(url)); + + connect(reply, &QNetworkReply::finished, this, &LoadSetsPage::actDownloadFinishedSetsFile); + connect(reply, &QNetworkReply::downloadProgress, this, &LoadSetsPage::actDownloadProgressSetsFile); +} + +void LoadSetsPage::actDownloadProgressSetsFile(qint64 received, qint64 total) +{ + if (total > 0) { + progressBar->setMaximum(static_cast(total)); + progressBar->setValue(static_cast(received)); + } + progressLabel->setText(tr("Downloading (%1MB)").arg((int)received / (1024 * 1024))); +} + +void LoadSetsPage::actDownloadFinishedSetsFile() +{ + // check for a reply + auto *reply = dynamic_cast(sender()); + auto errorCode = reply->error(); + if (errorCode != QNetworkReply::NoError) { + QMessageBox::critical(this, tr("Error"), tr("Network error: %1.").arg(reply->errorString())); + + wizard()->enableButtons(); + setEnabled(true); + + reply->deleteLater(); + return; + } + + auto statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); + if (statusCode == 301 || statusCode == 302) { + const auto redirectUrl = reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl(); + qDebug() << "following redirect url:" << redirectUrl.toString(); + downloadSetsFile(redirectUrl); + reply->deleteLater(); + return; + } + + progressLabel->hide(); + progressBar->hide(); + + // save AllPrintings.json url, but only if the user customized it and download was successful + if (urlLineEdit->text() != QString(ALLSETS_URL)) { + wizard()->settings->setValue("allsetsurl", urlLineEdit->text()); + } else { + wizard()->settings->remove("allsetsurl"); + } + + readSetsFromByteArray(reply->readAll()); + reply->deleteLater(); +} + +void LoadSetsPage::readSetsFromByteArray(QByteArray _data) +{ + // show an infinite progressbar + progressBar->setMaximum(0); + progressBar->setMinimum(0); + progressBar->setValue(0); + progressLabel->setText(tr("Parsing file")); + progressLabel->show(); + progressBar->show(); + + wizard()->downloadedPlainXml = false; + wizard()->xmlData.clear(); + readSetsFromByteArrayRef(_data); +} + +void LoadSetsPage::readSetsFromByteArrayRef(QByteArray &_data) +{ + // unzip the file if needed + if (_data.startsWith(XZ_SIGNATURE)) { +#ifdef HAS_LZMA + // zipped file + auto *inBuffer = new QBuffer(&_data); + auto newData = QByteArray(); + auto *outBuffer = new QBuffer(&newData); + inBuffer->open(QBuffer::ReadOnly); + outBuffer->open(QBuffer::WriteOnly); + XzDecompressor xz; + if (!xz.decompress(inBuffer, outBuffer)) { + zipDownloadFailed(tr("Xz extraction failed.")); + return; + } + _data.clear(); + readSetsFromByteArrayRef(newData); + return; +#else + zipDownloadFailed(tr("Sorry, this version of Oracle does not support xz compressed files.")); + + wizard()->enableButtons(); + setEnabled(true); + progressLabel->hide(); + progressBar->hide(); + return; +#endif + } else if (_data.startsWith(ZIP_SIGNATURE)) { +#ifdef HAS_ZLIB + // zipped file + auto *inBuffer = new QBuffer(&_data); + auto newData = QByteArray(); + auto *outBuffer = new QBuffer(&newData); + QString fileName; + UnZip::ErrorCode ec; + UnZip uz; + + ec = uz.openArchive(inBuffer); + if (ec != UnZip::Ok) { + zipDownloadFailed(tr("Failed to open Zip archive: %1.").arg(uz.formatError(ec))); + return; + } + + if (uz.fileList().size() != 1) { + zipDownloadFailed(tr("Zip extraction failed: the Zip archive doesn't contain exactly one file.")); + return; + } + fileName = uz.fileList().at(0); + + outBuffer->open(QBuffer::ReadWrite); + ec = uz.extractFile(fileName, outBuffer); + if (ec != UnZip::Ok) { + zipDownloadFailed(tr("Zip extraction failed: %1.").arg(uz.formatError(ec))); + uz.closeArchive(); + return; + } + _data.clear(); + readSetsFromByteArrayRef(newData); + return; +#else + zipDownloadFailed(tr("Sorry, this version of Oracle does not support zipped files.")); + + wizard()->enableButtons(); + setEnabled(true); + progressLabel->hide(); + progressBar->hide(); + return; +#endif + } else if (_data.startsWith("{")) { + // Start the computation. + jsonData = std::move(_data); + future = QtConcurrent::run([this] { return wizard()->importer->readSetsFromByteArray(std::move(jsonData)); }); + watcher.setFuture(future); + } else if (_data.startsWith("<")) { + // save xml file and don't do any processing + wizard()->downloadedPlainXml = true; + wizard()->xmlData = std::move(_data); + importFinished(); + } else { + wizard()->enableButtons(); + setEnabled(true); + progressLabel->hide(); + progressBar->hide(); + QMessageBox::critical(this, tr("Error"), tr("Failed to interpret downloaded data.")); + } +} + +void LoadSetsPage::zipDownloadFailed(const QString &message) +{ + wizard()->enableButtons(); + setEnabled(true); + progressLabel->hide(); + progressBar->hide(); + + QMessageBox::StandardButton reply; + reply = static_cast(QMessageBox::question( + this, tr("Error"), message + "
" + tr("Do you want to download the uncompressed file instead?"), + QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes)); + + if (reply == QMessageBox::Yes) { + urlRadioButton->setChecked(true); + urlLineEdit->setText(ALLSETS_URL_FALLBACK); + + wizard()->next(); + } +} + +void LoadSetsPage::importFinished() +{ + wizard()->enableButtons(); + setEnabled(true); + progressLabel->hide(); + progressBar->hide(); + + if (wizard()->downloadedPlainXml || watcher.future().result()) { + wizard()->next(); + } else { + QMessageBox::critical(this, tr("Error"), + tr("The file was retrieved successfully, but it does not contain any sets data.")); + } +} + +SaveSetsPage::SaveSetsPage(QWidget *parent) : OracleWizardPage(parent) +{ + pathLabel = new QLabel(this); + saveLabel = new QLabel(this); + + defaultPathCheckBox = new QCheckBox(this); + + messageLog = new QTextEdit(this); + messageLog->setReadOnly(true); + + auto *layout = new QGridLayout(this); + layout->addWidget(messageLog, 0, 0); + layout->addWidget(saveLabel, 1, 0); + layout->addWidget(pathLabel, 2, 0); + layout->addWidget(defaultPathCheckBox, 3, 0); + + setLayout(layout); +} + +void SaveSetsPage::cleanupPage() +{ + wizard()->importer->clear(); + disconnect(wizard()->importer, &OracleImporter::setIndexChanged, nullptr, nullptr); +} + +void SaveSetsPage::initializePage() +{ + messageLog->clear(); + + retranslateUi(); + if (wizard()->downloadedPlainXml) { + messageLog->hide(); + } else { + messageLog->show(); + connect(wizard()->importer, &OracleImporter::setIndexChanged, this, &SaveSetsPage::updateTotalProgress); + + int setsImported = wizard()->importer->startImport(); + + if (setsImported == 0) { + QMessageBox::critical(this, tr("Error"), tr("No set has been imported.")); + } + } + + if (wizard()->backgroundMode) { + emit readyToContinue(); + } +} + +void SaveSetsPage::retranslateUi() +{ + setTitle(tr("Sets imported")); + if (wizard()->downloadedPlainXml) { + setSubTitle(tr("A cockatrice database file of %1 MB has been downloaded.") + .arg(qRound(wizard()->xmlData.size() / 1000000.0))); + } else { + setSubTitle(tr("The following sets have been found:")); + } + + saveLabel->setText(tr("Press \"Save\" to store the imported cards in the Cockatrice database.")); + pathLabel->setText(tr("The card database will be saved at the following location:") + "
" + + SettingsCache::instance().getCardDatabasePath()); + defaultPathCheckBox->setText(tr("Save to a custom path (not recommended)")); + + setButtonText(QWizard::NextButton, tr("&Save")); +} + +void SaveSetsPage::updateTotalProgress(int cardsImported, int /* setIndex */, const QString &setName) +{ + if (setName.isEmpty()) { + messageLog->append("" + tr("Import finished: %1 cards.").arg(wizard()->importer->getCardList().size()) + + ""); + } else { + messageLog->append(tr("%1: %2 cards imported").arg(setName).arg(cardsImported)); + } + + messageLog->verticalScrollBar()->setValue(messageLog->verticalScrollBar()->maximum()); +} + +bool SaveSetsPage::validatePage() +{ + QString defaultPath = SettingsCache::instance().getCardDatabasePath(); + QString windowName = tr("Save card database"); + QString fileType = tr("XML; card database (*.xml)"); + + QString fileName; + if (defaultPathCheckBox->isChecked()) { + fileName = QFileDialog::getSaveFileName(this, windowName, defaultPath, fileType); + } else { + fileName = defaultPath; + } + + if (fileName.isEmpty()) { + return false; + } + + QFileInfo fi(fileName); + QDir fileDir(fi.path()); + if (!fileDir.exists() && !fileDir.mkpath(fileDir.absolutePath())) { + return false; + } + + if (wizard()->downloadedPlainXml) { + QFile file(fileName); + if (!file.open(QIODevice::WriteOnly)) { + qDebug() << "File write (w) failed for" << fileName; + return false; + } + if (file.write(wizard()->xmlData) < 1) { + qDebug() << "File write (w) failed for" << fileName; + return false; + } + wizard()->xmlData.clear(); + } else if (!wizard()->importer->saveToFile(fileName, wizard()->getCardSourceUrl(), + wizard()->getCardSourceVersion())) { + QMessageBox::critical(this, tr("Error"), tr("The file could not be saved to %1").arg(fileName)); + return false; + } + + return true; +} + +void LoadTokensPage::initializePage() +{ + SimpleDownloadFilePage::initializePage(); + + if (wizard()->backgroundMode) { + emit readyToContinue(); + } +} + +QString LoadTokensPage::getDefaultUrl() +{ + return TOKENS_URL; +} + +QString LoadTokensPage::getCustomUrlSettingsKey() +{ + return "tokensurl"; +} + +QString LoadTokensPage::getDefaultSavePath() +{ + return SettingsCache::instance().getTokenDatabasePath(); +} + +QString LoadTokensPage::getWindowTitle() +{ + return tr("Save token database"); +} + +QString LoadTokensPage::getFileType() +{ + return tr("XML; token database (*.xml)"); +} + +void LoadTokensPage::retranslateUi() +{ + setTitle(tr("Tokens import")); + setSubTitle(tr("Please specify a compatible source for token data.")); + + urlLabel->setText(tr("Download URL:")); + urlButton->setText(tr("Restore default URL")); + pathLabel->setText(tr("The token database will be saved at the following location:") + "
" + + SettingsCache::instance().getTokenDatabasePath()); + defaultPathCheckBox->setText(tr("Save to a custom path (not recommended)")); +} + +QString LoadSpoilersPage::getDefaultUrl() +{ + return SPOILERS_URL; +} + +QString LoadSpoilersPage::getCustomUrlSettingsKey() +{ + return "spoilersurl"; +} + +QString LoadSpoilersPage::getDefaultSavePath() +{ + return SettingsCache::instance().getTokenDatabasePath(); +} + +QString LoadSpoilersPage::getWindowTitle() +{ + return tr("Save spoiler database"); +} + +QString LoadSpoilersPage::getFileType() +{ + return tr("XML; spoiler database (*.xml)"); +} + +void LoadSpoilersPage::retranslateUi() +{ + setTitle(tr("Spoilers import")); + setSubTitle(tr("Please specify a compatible source for spoiler data.")); + + urlLabel->setText(tr("Download URL:")); + urlButton->setText(tr("Restore default URL")); + pathLabel->setText(tr("The spoiler database will be saved at the following location:") + "
" + + SettingsCache::instance().getSpoilerCardDatabasePath()); + defaultPathCheckBox->setText(tr("Save to a custom path (not recommended)")); +} \ No newline at end of file diff --git a/oracle/src/pages.h b/oracle/src/pages.h new file mode 100644 index 000000000..6a88b6099 --- /dev/null +++ b/oracle/src/pages.h @@ -0,0 +1,154 @@ +#ifndef COCKATRICE_PAGES_H +#define COCKATRICE_PAGES_H + +#include "pagetemplates.h" + +#include +#include +#include +#include +#include + +class QCheckBox; +class QGroupBox; +class QComboBox; +class QLabel; +class QLineEdit; +class QRadioButton; +class QProgressBar; +class QNetworkAccessManager; +class QTextEdit; +class QVBoxLayout; +class OracleImporter; +class QSettings; + +class IntroPage : public OracleWizardPage +{ + Q_OBJECT +public: + explicit IntroPage(QWidget *parent = nullptr); + void retranslateUi() override; + +private: + QStringList findQmFiles(); + QString languageName(const QString &lang); + +private: + QLabel *label, *languageLabel, *versionLabel; + QComboBox *languageBox; + +private slots: + void languageBoxChanged(int index); + +protected slots: + void initializePage() override; +}; + +class OutroPage : public OracleWizardPage +{ + Q_OBJECT +public: + explicit OutroPage(QWidget * = nullptr) + { + } + void retranslateUi() override; + +protected: + void initializePage() override; +}; + +class LoadSetsPage : public OracleWizardPage +{ + Q_OBJECT +public: + explicit LoadSetsPage(QWidget *parent = nullptr); + void retranslateUi() override; + +protected: + void initializePage() override; + bool validatePage() override; + void readSetsFromByteArray(QByteArray _data); + void readSetsFromByteArrayRef(QByteArray &_data); + void downloadSetsFile(const QUrl &url); + +private: + QRadioButton *urlRadioButton; + QRadioButton *fileRadioButton; + QLineEdit *urlLineEdit; + QLineEdit *fileLineEdit; + QPushButton *urlButton; + QPushButton *fileButton; + QLabel *progressLabel; + QProgressBar *progressBar; + + QFutureWatcher watcher; + QFuture future; + QByteArray jsonData; + +private slots: + void actLoadSetsFile(); + void actRestoreDefaultUrl(); + void actDownloadProgressSetsFile(qint64 received, qint64 total); + void actDownloadFinishedSetsFile(); + void importFinished(); + void zipDownloadFailed(const QString &message); +}; + +class SaveSetsPage : public OracleWizardPage +{ + Q_OBJECT +public: + explicit SaveSetsPage(QWidget *parent = nullptr); + void retranslateUi() override; + +private: + QTextEdit *messageLog; + QCheckBox *defaultPathCheckBox; + QLabel *pathLabel; + QLabel *saveLabel; + +protected: + void initializePage() override; + void cleanupPage() override; + bool validatePage() override; + +private slots: + void updateTotalProgress(int cardsImported, int setIndex, const QString &setName); +}; + +class LoadSpoilersPage : public SimpleDownloadFilePage +{ + Q_OBJECT +public: + explicit LoadSpoilersPage(QWidget * = nullptr) + { + } + void retranslateUi() override; + +protected: + QString getDefaultUrl() override; + QString getCustomUrlSettingsKey() override; + QString getDefaultSavePath() override; + QString getWindowTitle() override; + QString getFileType() override; +}; + +class LoadTokensPage : public SimpleDownloadFilePage +{ + Q_OBJECT +public: + explicit LoadTokensPage(QWidget * = nullptr) + { + } + void retranslateUi() override; + +protected: + QString getDefaultUrl() override; + QString getCustomUrlSettingsKey() override; + QString getDefaultSavePath() override; + QString getWindowTitle() override; + QString getFileType() override; + void initializePage() override; +}; + +#endif // COCKATRICE_PAGES_H