Merge branch 'master' into fix-compiler-warnings
4
Doxyfile
|
|
@ -991,7 +991,7 @@ WARN_LOGFILE =
|
||||||
# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
|
# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
|
||||||
# Note: If this tag is empty the current directory is searched.
|
# 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
|
# 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
|
# 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
|
# that contain images that are to be included in the documentation (see the
|
||||||
# \image command).
|
# \image command).
|
||||||
|
|
||||||
IMAGE_PATH =
|
IMAGE_PATH = doc/doxygen-images
|
||||||
|
|
||||||
# The INPUT_FILTER tag can be used to specify a program that Doxygen should
|
# 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
|
# invoke to filter for each input file. Doxygen will invoke the filter program
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
#include <QtMath>
|
#include <QtMath>
|
||||||
|
|
||||||
CardCounterSettings::CardCounterSettings(const QString &settingsPath, QObject *parent)
|
CardCounterSettings::CardCounterSettings(const QString &settingsPath, QObject *parent)
|
||||||
: SettingsManager(settingsPath + "global.ini", parent)
|
: SettingsManager(settingsPath + "global.ini", "cards", "counters", parent)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -41,8 +41,8 @@ void DeckViewCardDragItem::updatePosition(const QPointF &cursorScenePos)
|
||||||
|
|
||||||
void DeckViewCardDragItem::handleDrop(DeckViewCardContainer *target)
|
void DeckViewCardDragItem::handleDrop(DeckViewCardContainer *target)
|
||||||
{
|
{
|
||||||
DeckViewCard *card = static_cast<DeckViewCard *>(item);
|
auto *card = static_cast<DeckViewCard *>(item);
|
||||||
DeckViewCardContainer *start = static_cast<DeckViewCardContainer *>(item->parentItem());
|
auto *start = static_cast<DeckViewCardContainer *>(item->parentItem());
|
||||||
start->removeCard(card);
|
start->removeCard(card);
|
||||||
target->addCard(card);
|
target->addCard(card);
|
||||||
card->setParentItem(target);
|
card->setParentItem(target);
|
||||||
|
|
@ -51,13 +51,13 @@ void DeckViewCardDragItem::handleDrop(DeckViewCardContainer *target)
|
||||||
void DeckViewCardDragItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
|
void DeckViewCardDragItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
|
||||||
{
|
{
|
||||||
setCursor(Qt::OpenHandCursor);
|
setCursor(Qt::OpenHandCursor);
|
||||||
DeckViewScene *sc = static_cast<DeckViewScene *>(scene());
|
auto *sc = static_cast<DeckViewScene *>(scene());
|
||||||
sc->removeItem(this);
|
sc->removeItem(this);
|
||||||
|
|
||||||
if (currentZone) {
|
if (currentZone) {
|
||||||
handleDrop(currentZone);
|
handleDrop(currentZone);
|
||||||
for (int i = 0; i < childDrags.size(); i++) {
|
for (int i = 0; i < childDrags.size(); i++) {
|
||||||
DeckViewCardDragItem *c = static_cast<DeckViewCardDragItem *>(childDrags[i]);
|
auto *c = static_cast<DeckViewCardDragItem *>(childDrags[i]);
|
||||||
c->handleDrop(currentZone);
|
c->handleDrop(currentZone);
|
||||||
sc->removeItem(c);
|
sc->removeItem(c);
|
||||||
}
|
}
|
||||||
|
|
@ -118,12 +118,12 @@ void DeckViewCard::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
|
||||||
QList<QGraphicsItem *> sel = scene()->selectedItems();
|
QList<QGraphicsItem *> sel = scene()->selectedItems();
|
||||||
int j = 0;
|
int j = 0;
|
||||||
for (int i = 0; i < sel.size(); i++) {
|
for (int i = 0; i < sel.size(); i++) {
|
||||||
DeckViewCard *c = static_cast<DeckViewCard *>(sel.at(i));
|
auto *c = static_cast<DeckViewCard *>(sel.at(i));
|
||||||
if (c == this)
|
if (c == this)
|
||||||
continue;
|
continue;
|
||||||
++j;
|
++j;
|
||||||
QPointF childPos = QPointF(j * CARD_WIDTH / 2, 0);
|
auto childPos = QPointF(j * CARD_WIDTH / 2, 0);
|
||||||
DeckViewCardDragItem *drag = new DeckViewCardDragItem(c, childPos, dragItem);
|
auto *drag = new DeckViewCardDragItem(c, childPos, dragItem);
|
||||||
drag->setPos(dragItem->pos() + childPos);
|
drag->setPos(dragItem->pos() + childPos);
|
||||||
scene()->addItem(drag);
|
scene()->addItem(drag);
|
||||||
}
|
}
|
||||||
|
|
@ -140,8 +140,8 @@ void DeckView::mouseDoubleClickEvent(QMouseEvent *event)
|
||||||
QList<QGraphicsItem *> sel = scene()->selectedItems();
|
QList<QGraphicsItem *> sel = scene()->selectedItems();
|
||||||
|
|
||||||
for (int i = 0; i < sel.size(); i++) {
|
for (int i = 0; i < sel.size(); i++) {
|
||||||
DeckViewCard *c = static_cast<DeckViewCard *>(sel.at(i));
|
auto *c = static_cast<DeckViewCard *>(sel.at(i));
|
||||||
DeckViewCardContainer *zone = static_cast<DeckViewCardContainer *>(c->parentItem());
|
auto *zone = static_cast<DeckViewCardContainer *>(c->parentItem());
|
||||||
MoveCard_ToZone m;
|
MoveCard_ToZone m;
|
||||||
m.set_card_name(c->getName().toStdString());
|
m.set_card_name(c->getName().toStdString());
|
||||||
m.set_start_zone(zone->getName().toStdString());
|
m.set_start_zone(zone->getName().toStdString());
|
||||||
|
|
@ -345,7 +345,7 @@ void DeckViewScene::rebuildTree()
|
||||||
|
|
||||||
InnerDecklistNode *listRoot = deck->getRoot();
|
InnerDecklistNode *listRoot = deck->getRoot();
|
||||||
for (int i = 0; i < listRoot->size(); i++) {
|
for (int i = 0; i < listRoot->size(); i++) {
|
||||||
InnerDecklistNode *currentZone = dynamic_cast<InnerDecklistNode *>(listRoot->at(i));
|
auto *currentZone = dynamic_cast<InnerDecklistNode *>(listRoot->at(i));
|
||||||
|
|
||||||
DeckViewCardContainer *container = cardContainers.value(currentZone->getName(), 0);
|
DeckViewCardContainer *container = cardContainers.value(currentZone->getName(), 0);
|
||||||
if (!container) {
|
if (!container) {
|
||||||
|
|
@ -355,12 +355,12 @@ void DeckViewScene::rebuildTree()
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int j = 0; j < currentZone->size(); j++) {
|
for (int j = 0; j < currentZone->size(); j++) {
|
||||||
DecklistCardNode *currentCard = dynamic_cast<DecklistCardNode *>(currentZone->at(j));
|
auto *currentCard = dynamic_cast<DecklistCardNode *>(currentZone->at(j));
|
||||||
if (!currentCard)
|
if (!currentCard)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
for (int k = 0; k < currentCard->getNumber(); ++k) {
|
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);
|
container->addCard(newCard);
|
||||||
emit newCardAdded(newCard);
|
emit newCardAdded(newCard);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -67,7 +67,7 @@ DlgCreateToken::DlgCreateToken(const QStringList &_predefinedTokens, QWidget *pa
|
||||||
faceDownCheckBox = new QCheckBox(tr("Create face-down (Only hides name)"));
|
faceDownCheckBox = new QCheckBox(tr("Create face-down (Only hides name)"));
|
||||||
connect(faceDownCheckBox, &QCheckBox::toggled, this, &DlgCreateToken::faceDownCheckBoxToggled);
|
connect(faceDownCheckBox, &QCheckBox::toggled, this, &DlgCreateToken::faceDownCheckBoxToggled);
|
||||||
|
|
||||||
QGridLayout *grid = new QGridLayout;
|
auto *grid = new QGridLayout;
|
||||||
grid->addWidget(nameLabel, 0, 0);
|
grid->addWidget(nameLabel, 0, 0);
|
||||||
grid->addWidget(nameEdit, 0, 1);
|
grid->addWidget(nameEdit, 0, 1);
|
||||||
grid->addWidget(colorLabel, 1, 0);
|
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(destroyCheckBox, 4, 0, 1, 2);
|
||||||
grid->addWidget(faceDownCheckBox, 5, 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);
|
tokenDataGroupBox->setLayout(grid);
|
||||||
|
|
||||||
cardDatabaseModel = new CardDatabaseModel(CardDatabaseManager::getInstance(), false, this);
|
cardDatabaseModel = new CardDatabaseModel(CardDatabaseManager::getInstance(), false, this);
|
||||||
|
|
@ -125,25 +125,25 @@ DlgCreateToken::DlgCreateToken(const QStringList &_predefinedTokens, QWidget *pa
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
QVBoxLayout *tokenChooseLayout = new QVBoxLayout;
|
auto *tokenChooseLayout = new QVBoxLayout;
|
||||||
tokenChooseLayout->addWidget(chooseTokenFromAllRadioButton);
|
tokenChooseLayout->addWidget(chooseTokenFromAllRadioButton);
|
||||||
tokenChooseLayout->addWidget(chooseTokenFromDeckRadioButton);
|
tokenChooseLayout->addWidget(chooseTokenFromDeckRadioButton);
|
||||||
tokenChooseLayout->addWidget(chooseTokenView);
|
tokenChooseLayout->addWidget(chooseTokenView);
|
||||||
|
|
||||||
QGroupBox *tokenChooseGroupBox = new QGroupBox(tr("Choose token from list"));
|
auto *tokenChooseGroupBox = new QGroupBox(tr("Choose token from list"));
|
||||||
tokenChooseGroupBox->setLayout(tokenChooseLayout);
|
tokenChooseGroupBox->setLayout(tokenChooseLayout);
|
||||||
|
|
||||||
QGridLayout *hbox = new QGridLayout;
|
auto *hbox = new QGridLayout;
|
||||||
hbox->addWidget(pic, 0, 0, 1, 1);
|
hbox->addWidget(pic, 0, 0, 1, 1);
|
||||||
hbox->addWidget(tokenDataGroupBox, 1, 0, 1, 1);
|
hbox->addWidget(tokenDataGroupBox, 1, 0, 1, 1);
|
||||||
hbox->addWidget(tokenChooseGroupBox, 0, 1, 2, 1);
|
hbox->addWidget(tokenChooseGroupBox, 0, 1, 2, 1);
|
||||||
hbox->setColumnStretch(1, 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::accepted, this, &DlgCreateToken::actOk);
|
||||||
connect(buttonBox, &QDialogButtonBox::rejected, this, &DlgCreateToken::actReject);
|
connect(buttonBox, &QDialogButtonBox::rejected, this, &DlgCreateToken::actReject);
|
||||||
|
|
||||||
QVBoxLayout *mainLayout = new QVBoxLayout;
|
auto *mainLayout = new QVBoxLayout;
|
||||||
mainLayout->addLayout(hbox);
|
mainLayout->addLayout(hbox);
|
||||||
mainLayout->addWidget(buttonBox);
|
mainLayout->addWidget(buttonBox);
|
||||||
setLayout(mainLayout);
|
setLayout(mainLayout);
|
||||||
|
|
|
||||||
|
|
@ -194,7 +194,7 @@ void Player::processPlayerInfo(const ServerInfo_Player &info)
|
||||||
} else {
|
} else {
|
||||||
for (int j = 0; j < cardListSize; ++j) {
|
for (int j = 0; j < cardListSize; ++j) {
|
||||||
const ServerInfo_Card &cardInfo = zoneInfo.card_list(j);
|
const ServerInfo_Card &cardInfo = zoneInfo.card_list(j);
|
||||||
CardItem *card = new CardItem(this);
|
auto *card = new CardItem(this);
|
||||||
card->processCardInfo(cardInfo);
|
card->processCardInfo(cardInfo);
|
||||||
zone->addCard(card, false, cardInfo.x(), cardInfo.y());
|
zone->addCard(card, false, cardInfo.x(), cardInfo.y());
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,7 @@ void PlayerGraphicsItem::onPlayerActiveChanged(bool _active)
|
||||||
void PlayerGraphicsItem::initializeZones()
|
void PlayerGraphicsItem::initializeZones()
|
||||||
{
|
{
|
||||||
deckZoneGraphicsItem = new PileZone(player->getDeckZone(), this);
|
deckZoneGraphicsItem = new PileZone(player->getDeckZone(), this);
|
||||||
QPointF base = QPointF(counterAreaWidth + (CARD_HEIGHT - CARD_WIDTH + 15) / 2.0,
|
auto base = QPointF(counterAreaWidth + (CARD_HEIGHT - CARD_WIDTH + 15) / 2.0,
|
||||||
10 + playerTarget->boundingRect().height() + 5 - (CARD_HEIGHT - CARD_WIDTH) / 2.0);
|
10 + playerTarget->boundingRect().height() + 5 - (CARD_HEIGHT - CARD_WIDTH) / 2.0);
|
||||||
deckZoneGraphicsItem->setPos(base);
|
deckZoneGraphicsItem->setPos(base);
|
||||||
|
|
||||||
|
|
@ -147,7 +147,7 @@ void PlayerGraphicsItem::rearrangeCounters()
|
||||||
|
|
||||||
void PlayerGraphicsItem::rearrangeZones()
|
void PlayerGraphicsItem::rearrangeZones()
|
||||||
{
|
{
|
||||||
QPointF base = QPointF(CARD_HEIGHT + counterAreaWidth + 15, 0);
|
auto base = QPointF(CARD_HEIGHT + counterAreaWidth + 15, 0);
|
||||||
if (SettingsCache::instance().getHorizontalHand()) {
|
if (SettingsCache::instance().getHorizontalHand()) {
|
||||||
if (mirrored) {
|
if (mirrored) {
|
||||||
if (player->getHandZone()->contentsKnown()) {
|
if (player->getHandZone()->contentsKnown()) {
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ bool PlayerListItemDelegate::editorEvent(QEvent *event,
|
||||||
const QModelIndex &index)
|
const QModelIndex &index)
|
||||||
{
|
{
|
||||||
if ((event->type() == QEvent::MouseButtonPress) && index.isValid()) {
|
if ((event->type() == QEvent::MouseButtonPress) && index.isValid()) {
|
||||||
QMouseEvent *const mouseEvent = static_cast<QMouseEvent *>(event);
|
auto *const mouseEvent = static_cast<QMouseEvent *>(event);
|
||||||
if (mouseEvent->button() == Qt::RightButton) {
|
if (mouseEvent->button() == Qt::RightButton) {
|
||||||
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
|
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
|
||||||
static_cast<PlayerListWidget *>(parent())->showContextMenu(mouseEvent->globalPosition().toPoint(), index);
|
static_cast<PlayerListWidget *>(parent())->showContextMenu(mouseEvent->globalPosition().toPoint(), index);
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,3 @@
|
||||||
/**
|
|
||||||
* @file card_picture_loader.h
|
|
||||||
* @ingroup PictureLoader
|
|
||||||
* @brief TODO: Document this.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef CARD_PICTURE_LOADER_H
|
#ifndef CARD_PICTURE_LOADER_H
|
||||||
#define 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(CardPictureLoaderLog, "card_picture_loader");
|
||||||
inline Q_LOGGING_CATEGORY(CardPictureLoaderCardBackCacheFailLog, "card_picture_loader.card_back_cache_fail");
|
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<ExactCard> &cards)).
|
||||||
|
*
|
||||||
|
* Uses a worker thread for asynchronous image loading and a status bar widget
|
||||||
|
* to track load progress.
|
||||||
|
*/
|
||||||
class CardPictureLoader : public QObject
|
class CardPictureLoader : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Access the singleton instance of CardPictureLoader.
|
||||||
|
* @return Reference to the singleton.
|
||||||
|
*/
|
||||||
static CardPictureLoader &getInstance()
|
static CardPictureLoader &getInstance()
|
||||||
{
|
{
|
||||||
static CardPictureLoader instance;
|
static CardPictureLoader instance;
|
||||||
|
|
@ -29,30 +50,87 @@ public:
|
||||||
private:
|
private:
|
||||||
explicit CardPictureLoader();
|
explicit CardPictureLoader();
|
||||||
~CardPictureLoader() override;
|
~CardPictureLoader() override;
|
||||||
// Singleton - Don't implement copy constructor and assign operator
|
|
||||||
CardPictureLoader(CardPictureLoader const &);
|
|
||||||
void operator=(CardPictureLoader const &);
|
|
||||||
|
|
||||||
CardPictureLoaderWorker *worker;
|
// Disable copy and assignment for singleton
|
||||||
CardPictureLoaderStatusBar *statusBar;
|
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:
|
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);
|
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);
|
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);
|
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 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<ExactCard> &cards);
|
static void cacheCardPixmaps(const QList<ExactCard> &cards);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Check if the user has custom card art in the picsPath directory.
|
||||||
|
* @return True if any custom art exists.
|
||||||
|
*/
|
||||||
static bool hasCustomArt();
|
static bool hasCustomArt();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Clears the in-memory QPixmap cache for all cards.
|
||||||
|
*/
|
||||||
|
static void clearPixmapCache();
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
|
/**
|
||||||
|
* @brief Clears the network disk cache of the worker.
|
||||||
|
*/
|
||||||
static void clearNetworkCache();
|
static void clearNetworkCache();
|
||||||
|
|
||||||
private slots:
|
/**
|
||||||
void picDownloadChanged();
|
* @brief Slot called by the worker when an image is loaded.
|
||||||
void picsPathChanged();
|
* Inserts the pixmap into the cache and emits pixmap updated signals.
|
||||||
|
* @param card ExactCard that was loaded.
|
||||||
public slots:
|
* @param image Loaded QImage.
|
||||||
|
*/
|
||||||
void imageLoaded(const ExactCard &card, const QImage &image);
|
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
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -47,12 +47,6 @@ void CardPictureLoaderLocal::refreshIndex()
|
||||||
<< customFolderIndex.size() << "entries.";
|
<< 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
|
QImage CardPictureLoaderLocal::tryLoad(const ExactCard &toLoad) const
|
||||||
{
|
{
|
||||||
PrintingInfo setInstance = toLoad.getPrinting();
|
PrintingInfo setInstance = toLoad.getPrinting();
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,3 @@
|
||||||
/**
|
|
||||||
* @file card_picture_loader_local.h
|
|
||||||
* @ingroup PictureLoader
|
|
||||||
* @brief TODO: Document this.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef PICTURE_LOADER_LOCAL_H
|
#ifndef PICTURE_LOADER_LOCAL_H
|
||||||
#define PICTURE_LOADER_LOCAL_H
|
#define PICTURE_LOADER_LOCAL_H
|
||||||
|
|
||||||
|
|
@ -15,32 +9,80 @@
|
||||||
inline Q_LOGGING_CATEGORY(CardPictureLoaderLocalLog, "card_picture_loader.local");
|
inline Q_LOGGING_CATEGORY(CardPictureLoaderLocalLog, "card_picture_loader.local");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles searching for and loading card images from the local pics and custom image folders.
|
* @class CardPictureLoaderLocal
|
||||||
* This class maintains an index of the CUSTOM folder, to avoid repeatedly searching the entire directory.
|
* @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
|
class CardPictureLoaderLocal : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
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);
|
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;
|
QImage tryLoad(const ExactCard &toLoad) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QString picsPath, customPicsPath;
|
QString picsPath; ///< Path to standard card image folder
|
||||||
|
QString customPicsPath; ///< Path to custom card image folder
|
||||||
|
|
||||||
QMultiHash<QString, QString> customFolderIndex; // multimap of cardName to picPaths
|
QMultiHash<QString, QString> customFolderIndex; ///< Multimap from cardName to file paths in CUSTOM folder
|
||||||
QTimer *refreshTimer;
|
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();
|
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,
|
QImage tryLoadCardImageFromDisk(const QString &setName,
|
||||||
const QString &correctedCardName,
|
const QString &correctedCardName,
|
||||||
const QString &collectorNumber,
|
const QString &collectorNumber,
|
||||||
const QString &providerId) const;
|
const QString &providerId) const;
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
|
/**
|
||||||
|
* @brief Updates internal paths when the user changes picture settings.
|
||||||
|
*
|
||||||
|
* Triggered by `SettingsCache::picsPathChanged`.
|
||||||
|
*/
|
||||||
void picsPathChanged();
|
void picsPathChanged();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
#ifndef PICTURE_LOADER_REQUEST_STATUS_DISPLAY_WIDGET_H
|
||||||
#define PICTURE_LOADER_REQUEST_STATUS_DISPLAY_WIDGET_H
|
#define PICTURE_LOADER_REQUEST_STATUS_DISPLAY_WIDGET_H
|
||||||
|
|
||||||
#include "card_picture_loader_worker_work.h"
|
#include "card_picture_loader_worker_work.h"
|
||||||
|
|
||||||
#include <QHBoxLayout>
|
#include <QHBoxLayout>
|
||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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
|
class CardPictureLoaderRequestStatusDisplayWidget : public QWidget
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
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,
|
CardPictureLoaderRequestStatusDisplayWidget(QWidget *parent,
|
||||||
const QUrl &url,
|
const QUrl &url,
|
||||||
const ExactCard &card,
|
const ExactCard &card,
|
||||||
const QString &setName);
|
const QString &setName);
|
||||||
|
|
||||||
|
/** Marks the request as finished */
|
||||||
void setFinished()
|
void setFinished()
|
||||||
{
|
{
|
||||||
finished->setText("True");
|
finished->setText("True");
|
||||||
|
|
@ -28,19 +45,25 @@ public:
|
||||||
repaint();
|
repaint();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Returns whether the request has finished */
|
||||||
[[nodiscard]] bool getFinished() const
|
[[nodiscard]] bool getFinished() const
|
||||||
{
|
{
|
||||||
return finished->text() == "True";
|
return finished->text() == "True";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Updates the elapsed time display */
|
||||||
void setElapsedTime(const QString &_elapsedTime) const
|
void setElapsedTime(const QString &_elapsedTime) const
|
||||||
{
|
{
|
||||||
elapsedTime->setText(_elapsedTime);
|
elapsedTime->setText(_elapsedTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Queries the elapsed time in seconds since the request started
|
||||||
|
* @return Elapsed time in seconds
|
||||||
|
*/
|
||||||
int queryElapsedSeconds()
|
int queryElapsedSeconds()
|
||||||
{
|
{
|
||||||
if (!finished) {
|
if (!getFinished()) {
|
||||||
int elapsedSeconds = QDateTime::fromString(startTime->text()).secsTo(QDateTime::currentDateTime());
|
int elapsedSeconds = QDateTime::fromString(startTime->text()).secsTo(QDateTime::currentDateTime());
|
||||||
elapsedTime->setText(QString::number(elapsedSeconds));
|
elapsedTime->setText(QString::number(elapsedSeconds));
|
||||||
update();
|
update();
|
||||||
|
|
@ -50,25 +73,27 @@ public:
|
||||||
return elapsedTime->text().toInt();
|
return elapsedTime->text().toInt();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Returns the start time as a string */
|
||||||
[[nodiscard]] QString getStartTime() const
|
[[nodiscard]] QString getStartTime() const
|
||||||
{
|
{
|
||||||
return startTime->text();
|
return startTime->text();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Returns the URL of the request */
|
||||||
[[nodiscard]] QString getUrl() const
|
[[nodiscard]] QString getUrl() const
|
||||||
{
|
{
|
||||||
return url->text();
|
return url->text();
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QHBoxLayout *layout;
|
QHBoxLayout *layout; ///< Horizontal layout for arranging labels
|
||||||
QLabel *name;
|
QLabel *name; ///< Card name
|
||||||
QLabel *setShortname;
|
QLabel *setShortname; ///< Set short name
|
||||||
QLabel *providerId;
|
QLabel *providerId; ///< Provider ID for the card
|
||||||
QLabel *startTime;
|
QLabel *startTime; ///< Start time of the request
|
||||||
QLabel *elapsedTime;
|
QLabel *elapsedTime; ///< Elapsed time since start
|
||||||
QLabel *finished;
|
QLabel *finished; ///< Whether the request has finished
|
||||||
QLabel *url;
|
QLabel *url; ///< URL of the requested image
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // PICTURE_LOADER_REQUEST_STATUS_DISPLAY_WIDGET_H
|
#endif // PICTURE_LOADER_REQUEST_STATUS_DISPLAY_WIDGET_H
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,3 @@
|
||||||
/**
|
|
||||||
* @file card_picture_loader_status_bar.h
|
|
||||||
* @ingroup PictureLoader
|
|
||||||
* @brief TODO: Document this.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef PICTURE_LOADER_STATUS_BAR_H
|
#ifndef PICTURE_LOADER_STATUS_BAR_H
|
||||||
#define PICTURE_LOADER_STATUS_BAR_H
|
#define PICTURE_LOADER_STATUS_BAR_H
|
||||||
|
|
||||||
|
|
@ -12,24 +6,56 @@
|
||||||
|
|
||||||
#include <QHBoxLayout>
|
#include <QHBoxLayout>
|
||||||
#include <QProgressBar>
|
#include <QProgressBar>
|
||||||
|
#include <QTimer>
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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
|
class CardPictureLoaderStatusBar : public QWidget
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Constructs a status bar with progress bar and log button.
|
||||||
|
* @param parent Parent widget
|
||||||
|
*/
|
||||||
explicit CardPictureLoaderStatusBar(QWidget *parent);
|
explicit CardPictureLoaderStatusBar(QWidget *parent);
|
||||||
|
|
||||||
public slots:
|
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);
|
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);
|
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();
|
void cleanOldEntries();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QHBoxLayout *layout;
|
QHBoxLayout *layout; ///< Horizontal layout containing progress bar and log button
|
||||||
QProgressBar *progressBar;
|
QProgressBar *progressBar; ///< Progress bar showing overall download progress
|
||||||
SettingsButtonWidget *loadLog;
|
SettingsButtonWidget *loadLog; ///< Popup log showing individual request statuses
|
||||||
QTimer *cleaner;
|
QTimer *cleaner; ///< Timer for periodically cleaning old log entries
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // PICTURE_LOADER_STATUS_BAR_H
|
#endif // PICTURE_LOADER_STATUS_BAR_H
|
||||||
|
|
|
||||||
|
|
@ -105,9 +105,6 @@ void CardPictureLoaderWorker::resetRequestQuota()
|
||||||
processQueuedRequests();
|
processQueuedRequests();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Keeps processing requests from the queue until it is empty or until the quota runs out.
|
|
||||||
*/
|
|
||||||
void CardPictureLoaderWorker::processQueuedRequests()
|
void CardPictureLoaderWorker::processQueuedRequests()
|
||||||
{
|
{
|
||||||
while (requestQuota > 0 && processSingleRequest()) {
|
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()
|
bool CardPictureLoaderWorker::processSingleRequest()
|
||||||
{
|
{
|
||||||
if (!requestLoadQueue.isEmpty()) {
|
if (!requestLoadQueue.isEmpty()) {
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,3 @@
|
||||||
/**
|
|
||||||
* @file card_picture_loader_worker.h
|
|
||||||
* @ingroup PictureLoader
|
|
||||||
* @brief TODO: Document this.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef PICTURE_LOADER_WORKER_H
|
#ifndef PICTURE_LOADER_WORKER_H
|
||||||
#define PICTURE_LOADER_WORKER_H
|
#define PICTURE_LOADER_WORKER_H
|
||||||
|
|
||||||
|
|
@ -27,57 +21,131 @@
|
||||||
#define REDIRECT_TIMESTAMP "timestamp"
|
#define REDIRECT_TIMESTAMP "timestamp"
|
||||||
#define REDIRECT_CACHE_FILENAME "cache.ini"
|
#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
|
class CardPictureLoaderWorker : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Constructs a CardPictureLoaderWorker.
|
||||||
|
*
|
||||||
|
* Initializes network manager, cache, redirect cache, local loader, and request quota timer.
|
||||||
|
*/
|
||||||
explicit CardPictureLoaderWorker();
|
explicit CardPictureLoaderWorker();
|
||||||
|
|
||||||
~CardPictureLoaderWorker() override;
|
~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();
|
void clearNetworkCache();
|
||||||
|
|
||||||
public slots:
|
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);
|
QNetworkReply *makeRequest(const QUrl &url, CardPictureLoaderWorkerWork *workThread);
|
||||||
|
|
||||||
|
/** @brief Processes all queued requests respecting the request quota. */
|
||||||
void processQueuedRequests();
|
void processQueuedRequests();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Processes a single queued request.
|
||||||
|
* @return true if a request was processed, false if queue is empty.
|
||||||
|
*/
|
||||||
bool processSingleRequest();
|
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);
|
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);
|
void cacheRedirect(const QUrl &originalUrl, const QUrl &redirectUrl);
|
||||||
|
|
||||||
|
/** @brief Removes a URL from the network cache. */
|
||||||
void removedCachedUrl(const QUrl &url);
|
void removedCachedUrl(const QUrl &url);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QThread *pictureLoaderThread;
|
QThread *pictureLoaderThread; ///< Thread for executing worker tasks
|
||||||
QNetworkAccessManager *networkManager;
|
QNetworkAccessManager *networkManager; ///< Network manager for HTTP requests
|
||||||
QNetworkDiskCache *cache;
|
QNetworkDiskCache *cache; ///< Disk cache for downloaded images
|
||||||
QHash<QUrl, QPair<QUrl, QDateTime>> redirectCache; // Stores redirect and timestamp
|
QHash<QUrl, QPair<QUrl, QDateTime>> redirectCache; ///< Maps original URLs to redirects with timestamp
|
||||||
QString cacheFilePath; // Path to persistent storage
|
QString cacheFilePath; ///< Path to persistent redirect cache file
|
||||||
static constexpr int CacheTTLInDays = 30; // TODO: Make user configurable
|
static constexpr int CacheTTLInDays = 30; ///< Time-to-live for redirect cache entries (days)
|
||||||
bool picDownload;
|
bool picDownload; ///< Whether downloading images from network is enabled
|
||||||
QQueue<QPair<QUrl, CardPictureLoaderWorkerWork *>> requestLoadQueue;
|
QQueue<QPair<QUrl, CardPictureLoaderWorkerWork *>> requestLoadQueue; ///< Queue of pending network requests
|
||||||
|
|
||||||
int requestQuota;
|
int requestQuota; ///< Remaining requests allowed per second
|
||||||
QTimer requestTimer; // Timer for refreshing request quota
|
QTimer requestTimer; ///< Timer to reset the request quota
|
||||||
|
|
||||||
CardPictureLoaderLocal *localLoader;
|
CardPictureLoaderLocal *localLoader; ///< Loader for local images
|
||||||
QSet<QString> currentlyLoading; // for deduplication purposes. Contains pixmapCacheKey
|
QSet<QString> currentlyLoading; ///< Deduplication: contains pixmapCacheKey currently being loaded
|
||||||
|
|
||||||
|
/** @brief Returns cached redirect URL for the given original URL, if available. */
|
||||||
[[nodiscard]] QUrl getCachedRedirect(const QUrl &originalUrl) const;
|
[[nodiscard]] QUrl getCachedRedirect(const QUrl &originalUrl) const;
|
||||||
|
|
||||||
|
/** @brief Loads redirect cache from disk. */
|
||||||
void loadRedirectCache();
|
void loadRedirectCache();
|
||||||
|
|
||||||
|
/** @brief Saves redirect cache to disk. */
|
||||||
void saveRedirectCache() const;
|
void saveRedirectCache() const;
|
||||||
|
|
||||||
|
/** @brief Removes stale redirect entries older than TTL. */
|
||||||
void cleanStaleEntries();
|
void cleanStaleEntries();
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
|
/** @brief Resets the request quota for rate-limiting. */
|
||||||
void resetRequestQuota();
|
void resetRequestQuota();
|
||||||
|
|
||||||
|
/** @brief Handles image load requests enqueued on this worker. */
|
||||||
void handleImageLoadEnqueued(const ExactCard &card);
|
void handleImageLoadEnqueued(const ExactCard &card);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
/** @brief Emitted when an image load is enqueued. */
|
||||||
void imageLoadEnqueued(const ExactCard &card);
|
void imageLoadEnqueued(const ExactCard &card);
|
||||||
|
|
||||||
|
/** @brief Emitted when an image has finished loading. */
|
||||||
void imageLoaded(const ExactCard &card, const QImage &image);
|
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);
|
void imageRequestQueued(const QUrl &url, const ExactCard &card, const QString &setName);
|
||||||
|
|
||||||
|
/** @brief Emitted when a network request successfully completes. */
|
||||||
void imageRequestSucceeded(const QUrl &url);
|
void imageRequestSucceeded(const QUrl &url);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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()
|
void CardPictureLoaderWorkerWork::picDownloadFailed()
|
||||||
{
|
{
|
||||||
/* Take advantage of short-circuiting here to call the nextUrl until one
|
/* 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)
|
void CardPictureLoaderWorkerWork::handleNetworkReply(QNetworkReply *reply)
|
||||||
{
|
{
|
||||||
QVariant redirectTarget = reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
|
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)
|
QImage CardPictureLoaderWorkerWork::tryLoadImageFromReply(QNetworkReply *reply)
|
||||||
{
|
{
|
||||||
static constexpr int riffHeaderSize = 12; // RIFF_HEADER_SIZE from webp/format_constants.h
|
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();
|
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)
|
void CardPictureLoaderWorkerWork::concludeImageLoad(const QImage &image)
|
||||||
{
|
{
|
||||||
emit imageLoaded(cardToDownload.getCard(), image);
|
emit imageLoaded(cardToDownload.getCard(), image);
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,3 @@
|
||||||
/**
|
|
||||||
* @file picture_loader_worker_work.h
|
|
||||||
* @ingroup PictureLoader
|
|
||||||
* @brief TODO: Document this.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef PICTURE_LOADER_WORKER_WORK_H
|
#ifndef PICTURE_LOADER_WORKER_WORK_H
|
||||||
#define PICTURE_LOADER_WORKER_WORK_H
|
#define PICTURE_LOADER_WORKER_WORK_H
|
||||||
|
|
||||||
|
|
@ -17,55 +11,96 @@
|
||||||
#include <QThread>
|
#include <QThread>
|
||||||
#include <libcockatrice/card/database/card_database.h>
|
#include <libcockatrice/card/database/card_database.h>
|
||||||
|
|
||||||
#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");
|
inline Q_LOGGING_CATEGORY(CardPictureLoaderWorkerWorkLog, "card_picture_loader.worker");
|
||||||
|
|
||||||
class CardPictureLoaderWorker;
|
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
|
class CardPictureLoaderWorkerWork : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
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);
|
explicit CardPictureLoaderWorkerWork(const CardPictureLoaderWorker *worker, const ExactCard &toLoad);
|
||||||
|
|
||||||
CardPictureToLoad cardToDownload;
|
CardPictureToLoad cardToDownload; ///< The card and associated URLs to try downloading
|
||||||
|
|
||||||
public slots:
|
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);
|
void handleNetworkReply(QNetworkReply *reply);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool picDownload;
|
bool picDownload; ///< Whether network downloading is enabled
|
||||||
|
|
||||||
|
/** @brief Starts downloading the next URL for this card. */
|
||||||
void startNextPicDownload();
|
void startNextPicDownload();
|
||||||
|
|
||||||
|
/** @brief Called when all URLs have been exhausted or download failed. */
|
||||||
void picDownloadFailed();
|
void picDownloadFailed();
|
||||||
|
|
||||||
|
/** @brief Processes a failed network reply. */
|
||||||
void handleFailedReply(const QNetworkReply *reply);
|
void handleFailedReply(const QNetworkReply *reply);
|
||||||
|
|
||||||
|
/** @brief Processes a successful network reply. */
|
||||||
void handleSuccessfulReply(QNetworkReply *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);
|
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);
|
void concludeImageLoad(const QImage &image);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
|
/** @brief Updates the picDownload setting when it changes. */
|
||||||
void picDownloadChanged();
|
void picDownloadChanged();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
/**
|
/**
|
||||||
* Emitted when this worker has successfully loaded the image or has exhausted all attempts at loading the image.
|
* @brief Emitted when the image has been loaded or all attempts failed.
|
||||||
* Failures are represented by an empty QImage.
|
* @param card The card corresponding to the image
|
||||||
* Note that this object will delete itself as this signal is emitted.
|
* @param image The loaded image (empty if failed)
|
||||||
|
*
|
||||||
|
* The worker deletes itself after emitting this signal.
|
||||||
*/
|
*/
|
||||||
void imageLoaded(const ExactCard &card, const QImage &image);
|
void imageLoaded(const ExactCard &card, const QImage &image);
|
||||||
|
|
||||||
/**
|
/** @brief Emitted when a network request completes successfully. */
|
||||||
* Emitted when a request did not return a 400 or 500 response
|
|
||||||
*/
|
|
||||||
void requestSucceeded(const QUrl &url);
|
void requestSucceeded(const QUrl &url);
|
||||||
|
|
||||||
|
/** @brief Request that a URL be downloaded. */
|
||||||
void requestImageDownload(const QUrl &url, CardPictureLoaderWorkerWork *instance);
|
void requestImageDownload(const QUrl &url, CardPictureLoaderWorkerWork *instance);
|
||||||
|
|
||||||
|
/** @brief Emitted when a URL has been redirected. */
|
||||||
void urlRedirected(const QUrl &originalUrl, const QUrl &redirectUrl);
|
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);
|
void cachedUrlInvalidated(const QUrl &url);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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<CardSetPtr> CardPictureToLoad::extractSetsSorted(const ExactCard &card)
|
QList<CardSetPtr> CardPictureToLoad::extractSetsSorted(const ExactCard &card)
|
||||||
{
|
{
|
||||||
QList<CardSetPtr> sortedSets;
|
QList<CardSetPtr> sortedSets;
|
||||||
|
|
@ -109,11 +103,6 @@ void CardPictureToLoad::populateSetUrls()
|
||||||
(void)nextUrl();
|
(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()
|
bool CardPictureToLoad::nextSet()
|
||||||
{
|
{
|
||||||
if (!sortedSets.isEmpty()) {
|
if (!sortedSets.isEmpty()) {
|
||||||
|
|
@ -125,11 +114,6 @@ bool CardPictureToLoad::nextSet()
|
||||||
return false;
|
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()
|
bool CardPictureToLoad::nextUrl()
|
||||||
{
|
{
|
||||||
if (!currentSetUrls.isEmpty()) {
|
if (!currentSetUrls.isEmpty()) {
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,3 @@
|
||||||
/**
|
|
||||||
* @file card_picture_to_load.h
|
|
||||||
* @ingroup PictureLoader
|
|
||||||
* @brief TODO: Document this.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef PICTURE_TO_LOAD_H
|
#ifndef PICTURE_TO_LOAD_H
|
||||||
#define PICTURE_TO_LOAD_H
|
#define PICTURE_TO_LOAD_H
|
||||||
|
|
||||||
|
|
@ -12,37 +6,97 @@
|
||||||
|
|
||||||
inline Q_LOGGING_CATEGORY(CardPictureToLoadLog, "card_picture_loader.picture_to_load");
|
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
|
class CardPictureToLoad
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
ExactCard card;
|
ExactCard card; ///< The ExactCard being downloaded
|
||||||
QList<CardSetPtr> sortedSets;
|
QList<CardSetPtr> sortedSets; ///< All sets for this card, sorted by priority
|
||||||
QList<QString> urlTemplates;
|
QList<QString> urlTemplates; ///< URL templates from settings
|
||||||
QList<QString> currentSetUrls;
|
QList<QString> currentSetUrls; ///< URLs for the current set being attempted
|
||||||
QString currentUrl;
|
QString currentUrl; ///< Currently active URL to download
|
||||||
CardSetPtr currentSet;
|
CardSetPtr currentSet; ///< Currently active set
|
||||||
|
|
||||||
public:
|
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);
|
explicit CardPictureToLoad(const ExactCard &_card);
|
||||||
|
|
||||||
|
/** @return The card being loaded. */
|
||||||
[[nodiscard]] const ExactCard &getCard() const
|
[[nodiscard]] const ExactCard &getCard() const
|
||||||
{
|
{
|
||||||
return card;
|
return card;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @return The current URL being attempted. */
|
||||||
[[nodiscard]] QString getCurrentUrl() const
|
[[nodiscard]] QString getCurrentUrl() const
|
||||||
{
|
{
|
||||||
return currentUrl;
|
return currentUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @return The current set being attempted. */
|
||||||
[[nodiscard]] CardSetPtr getCurrentSet() const
|
[[nodiscard]] CardSetPtr getCurrentSet() const
|
||||||
{
|
{
|
||||||
return currentSet;
|
return currentSet;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @return The short name of the current set, or empty string if no set. */
|
||||||
[[nodiscard]] QString getSetName() const;
|
[[nodiscard]] QString getSetName() const;
|
||||||
[[nodiscard]] QString transformUrl(const QString &urlTemplate) 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();
|
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();
|
bool nextUrl();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Populates the currentSetUrls list with URLs for the current set.
|
||||||
|
*
|
||||||
|
* Includes custom URLs first, followed by template-based URLs.
|
||||||
|
*/
|
||||||
void populateSetUrls();
|
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<CardSetPtr> extractSetsSorted(const ExactCard &card);
|
static QList<CardSetPtr> extractSetsSorted(const ExactCard &card);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -78,14 +78,9 @@ void ManaBaseWidget::updateDisplay()
|
||||||
QHash<QString, int> ManaBaseWidget::analyzeManaBase()
|
QHash<QString, int> ManaBaseWidget::analyzeManaBase()
|
||||||
{
|
{
|
||||||
manaBaseMap.clear();
|
manaBaseMap.clear();
|
||||||
InnerDecklistNode *listRoot = deckListModel->getDeckList()->getRoot();
|
QList<DecklistCardNode *> cardsInDeck = deckListModel->getDeckList()->getCardNodes();
|
||||||
for (int i = 0; i < listRoot->size(); i++) {
|
|
||||||
InnerDecklistNode *currentZone = dynamic_cast<InnerDecklistNode *>(listRoot->at(i));
|
|
||||||
for (int j = 0; j < currentZone->size(); j++) {
|
|
||||||
DecklistCardNode *currentCard = dynamic_cast<DecklistCardNode *>(currentZone->at(j));
|
|
||||||
if (!currentCard)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
|
for (auto currentCard : cardsInDeck) {
|
||||||
for (int k = 0; k < currentCard->getNumber(); ++k) {
|
for (int k = 0; k < currentCard->getNumber(); ++k) {
|
||||||
CardInfoPtr info = CardDatabaseManager::query()->getCardInfo(currentCard->getName());
|
CardInfoPtr info = CardDatabaseManager::query()->getCardInfo(currentCard->getName());
|
||||||
if (info) {
|
if (info) {
|
||||||
|
|
@ -94,7 +89,6 @@ QHash<QString, int> ManaBaseWidget::analyzeManaBase()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
updateDisplay();
|
updateDisplay();
|
||||||
return manaBaseMap;
|
return manaBaseMap;
|
||||||
|
|
|
||||||
|
|
@ -44,14 +44,10 @@ void ManaCurveWidget::setDeckModel(DeckListModel *deckModel)
|
||||||
std::unordered_map<int, int> ManaCurveWidget::analyzeManaCurve()
|
std::unordered_map<int, int> ManaCurveWidget::analyzeManaCurve()
|
||||||
{
|
{
|
||||||
manaCurveMap.clear();
|
manaCurveMap.clear();
|
||||||
InnerDecklistNode *listRoot = deckListModel->getDeckList()->getRoot();
|
|
||||||
for (int i = 0; i < listRoot->size(); i++) {
|
|
||||||
InnerDecklistNode *currentZone = dynamic_cast<InnerDecklistNode *>(listRoot->at(i));
|
|
||||||
for (int j = 0; j < currentZone->size(); j++) {
|
|
||||||
DecklistCardNode *currentCard = dynamic_cast<DecklistCardNode *>(currentZone->at(j));
|
|
||||||
if (!currentCard)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
|
QList<DecklistCardNode *> cardsInDeck = deckListModel->getDeckList()->getCardNodes();
|
||||||
|
|
||||||
|
for (auto currentCard : cardsInDeck) {
|
||||||
for (int k = 0; k < currentCard->getNumber(); ++k) {
|
for (int k = 0; k < currentCard->getNumber(); ++k) {
|
||||||
CardInfoPtr info = CardDatabaseManager::query()->getCardInfo(currentCard->getName());
|
CardInfoPtr info = CardDatabaseManager::query()->getCardInfo(currentCard->getName());
|
||||||
if (info) {
|
if (info) {
|
||||||
|
|
@ -60,7 +56,6 @@ std::unordered_map<int, int> ManaCurveWidget::analyzeManaCurve()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
updateDisplay();
|
updateDisplay();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -46,14 +46,10 @@ void ManaDevotionWidget::setDeckModel(DeckListModel *deckModel)
|
||||||
std::unordered_map<char, int> ManaDevotionWidget::analyzeManaDevotion()
|
std::unordered_map<char, int> ManaDevotionWidget::analyzeManaDevotion()
|
||||||
{
|
{
|
||||||
manaDevotionMap.clear();
|
manaDevotionMap.clear();
|
||||||
InnerDecklistNode *listRoot = deckListModel->getDeckList()->getRoot();
|
|
||||||
for (int i = 0; i < listRoot->size(); i++) {
|
|
||||||
InnerDecklistNode *currentZone = dynamic_cast<InnerDecklistNode *>(listRoot->at(i));
|
|
||||||
for (int j = 0; j < currentZone->size(); j++) {
|
|
||||||
DecklistCardNode *currentCard = dynamic_cast<DecklistCardNode *>(currentZone->at(j));
|
|
||||||
if (!currentCard)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
|
QList<DecklistCardNode *> cardsInDeck = deckListModel->getDeckList()->getCardNodes();
|
||||||
|
|
||||||
|
for (auto currentCard : cardsInDeck) {
|
||||||
for (int k = 0; k < currentCard->getNumber(); ++k) {
|
for (int k = 0; k < currentCard->getNumber(); ++k) {
|
||||||
CardInfoPtr info = CardDatabaseManager::query()->getCardInfo(currentCard->getName());
|
CardInfoPtr info = CardDatabaseManager::query()->getCardInfo(currentCard->getName());
|
||||||
if (info) {
|
if (info) {
|
||||||
|
|
@ -62,7 +58,6 @@ std::unordered_map<char, int> ManaDevotionWidget::analyzeManaDevotion()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
updateDisplay();
|
updateDisplay();
|
||||||
return manaDevotionMap;
|
return manaDevotionMap;
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@ void DeckEditorDeckDockWidget::createDeckDock()
|
||||||
|
|
||||||
deckLoader = new DeckLoader(this, deckModel->getDeckList());
|
deckLoader = new DeckLoader(this, deckModel->getDeckList());
|
||||||
|
|
||||||
DeckListStyleProxy *proxy = new DeckListStyleProxy(this);
|
proxy = new DeckListStyleProxy(this);
|
||||||
proxy->setSourceModel(deckModel);
|
proxy->setSourceModel(deckModel);
|
||||||
|
|
||||||
deckView = new QTreeView();
|
deckView = new QTreeView();
|
||||||
|
|
@ -283,21 +283,15 @@ void DeckEditorDeckDockWidget::updateBannerCardComboBox()
|
||||||
|
|
||||||
// Prepare the new items with deduplication
|
// Prepare the new items with deduplication
|
||||||
QSet<QPair<QString, QString>> bannerCardSet;
|
QSet<QPair<QString, QString>> bannerCardSet;
|
||||||
InnerDecklistNode *listRoot = deckModel->getDeckList()->getRoot();
|
QList<DecklistCardNode *> cardsInDeck = deckModel->getDeckList()->getCardNodes();
|
||||||
for (int i = 0; i < listRoot->size(); i++) {
|
|
||||||
InnerDecklistNode *currentZone = dynamic_cast<InnerDecklistNode *>(listRoot->at(i));
|
|
||||||
for (int j = 0; j < currentZone->size(); j++) {
|
|
||||||
DecklistCardNode *currentCard = dynamic_cast<DecklistCardNode *>(currentZone->at(j));
|
|
||||||
if (!currentCard)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
|
for (auto currentCard : cardsInDeck) {
|
||||||
for (int k = 0; k < currentCard->getNumber(); ++k) {
|
for (int k = 0; k < currentCard->getNumber(); ++k) {
|
||||||
if (CardDatabaseManager::query()->getCard(currentCard->toCardRef())) {
|
if (CardDatabaseManager::query()->getCard(currentCard->toCardRef())) {
|
||||||
bannerCardSet.insert({currentCard->getName(), currentCard->getCardProviderId()});
|
bannerCardSet.insert({currentCard->getName(), currentCard->getCardProviderId()});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
QList<QPair<QString, QString>> pairList = bannerCardSet.values();
|
QList<QPair<QString, QString>> pairList = bannerCardSet.values();
|
||||||
|
|
||||||
|
|
@ -438,7 +432,9 @@ QModelIndexList DeckEditorDeckDockWidget::getSelectedCardNodes() const
|
||||||
{
|
{
|
||||||
auto selectedRows = deckView->selectionModel()->selectedRows();
|
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());
|
selectedRows.erase(std::remove_if(selectedRows.begin(), selectedRows.end(), notLeafNode), selectedRows.end());
|
||||||
|
|
||||||
std::reverse(selectedRows.begin(), selectedRows.end());
|
std::reverse(selectedRows.begin(), selectedRows.end());
|
||||||
|
|
@ -505,7 +501,7 @@ bool DeckEditorDeckDockWidget::swapCard(const QModelIndex ¤tIndex)
|
||||||
QModelIndex newCardIndex = card ? deckModel->addCard(card, otherZoneName)
|
QModelIndex newCardIndex = card ? deckModel->addCard(card, otherZoneName)
|
||||||
// Third argument (true) says create the card no matter what, even if not in DB
|
// Third argument (true) says create the card no matter what, even if not in DB
|
||||||
: deckModel->addPreferredPrintingCard(cardName, otherZoneName, true);
|
: deckModel->addPreferredPrintingCard(cardName, otherZoneName, true);
|
||||||
recursiveExpand(newCardIndex);
|
recursiveExpand(proxy->mapToSource(newCardIndex));
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -526,7 +522,7 @@ void DeckEditorDeckDockWidget::actDecrementCard(const ExactCard &card, QString z
|
||||||
}
|
}
|
||||||
|
|
||||||
deckView->clearSelection();
|
deckView->clearSelection();
|
||||||
deckView->setCurrentIndex(idx);
|
deckView->setCurrentIndex(proxy->mapToSource(idx));
|
||||||
offsetCountAtIndex(idx, -1);
|
offsetCountAtIndex(idx, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -562,7 +558,8 @@ void DeckEditorDeckDockWidget::actRemoveCard()
|
||||||
if (!index.isValid() || deckModel->hasChildren(index)) {
|
if (!index.isValid() || deckModel->hasChildren(index)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
deckModel->removeRow(index.row(), index.parent());
|
QModelIndex sourceIndex = proxy->mapToSource(index);
|
||||||
|
deckModel->removeRow(sourceIndex.row(), sourceIndex.parent());
|
||||||
isModified = true;
|
isModified = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -579,13 +576,17 @@ void DeckEditorDeckDockWidget::offsetCountAtIndex(const QModelIndex &idx, int of
|
||||||
return;
|
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 count = deckModel->data(numberIndex, Qt::EditRole).toInt();
|
||||||
const int new_count = count + offset;
|
const int new_count = count + offset;
|
||||||
if (new_count <= 0)
|
|
||||||
deckModel->removeRow(idx.row(), idx.parent());
|
if (new_count <= 0) {
|
||||||
else
|
deckModel->removeRow(sourceIndex.row(), sourceIndex.parent());
|
||||||
|
} else {
|
||||||
deckModel->setData(numberIndex, new_count, Qt::EditRole);
|
deckModel->setData(numberIndex, new_count, Qt::EditRole);
|
||||||
|
}
|
||||||
|
|
||||||
emit deckModified();
|
emit deckModified();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@
|
||||||
#include "../../key_signals.h"
|
#include "../../key_signals.h"
|
||||||
#include "../utility/custom_line_edit.h"
|
#include "../utility/custom_line_edit.h"
|
||||||
#include "../visual_deck_storage/deck_preview/deck_preview_deck_tags_display_widget.h"
|
#include "../visual_deck_storage/deck_preview/deck_preview_deck_tags_display_widget.h"
|
||||||
|
#include "deck_list_style_proxy.h"
|
||||||
|
|
||||||
#include <QComboBox>
|
#include <QComboBox>
|
||||||
#include <QDockWidget>
|
#include <QDockWidget>
|
||||||
|
|
@ -28,6 +29,7 @@ class DeckEditorDeckDockWidget : public QDockWidget
|
||||||
public:
|
public:
|
||||||
explicit DeckEditorDeckDockWidget(AbstractTabDeckEditor *parent);
|
explicit DeckEditorDeckDockWidget(AbstractTabDeckEditor *parent);
|
||||||
DeckLoader *deckLoader;
|
DeckLoader *deckLoader;
|
||||||
|
DeckListStyleProxy *proxy;
|
||||||
DeckListModel *deckModel;
|
DeckListModel *deckModel;
|
||||||
QTreeView *deckView;
|
QTreeView *deckView;
|
||||||
QComboBox *bannerCardComboBox;
|
QComboBox *bannerCardComboBox;
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@ void DlgCreateGame::sharedCtor()
|
||||||
maxPlayersEdit->setValue(2);
|
maxPlayersEdit->setValue(2);
|
||||||
maxPlayersLabel->setBuddy(maxPlayersEdit);
|
maxPlayersLabel->setBuddy(maxPlayersEdit);
|
||||||
|
|
||||||
QGridLayout *generalGrid = new QGridLayout;
|
auto *generalGrid = new QGridLayout;
|
||||||
generalGrid->addWidget(descriptionLabel, 0, 0);
|
generalGrid->addWidget(descriptionLabel, 0, 0);
|
||||||
generalGrid->addWidget(descriptionEdit, 0, 1);
|
generalGrid->addWidget(descriptionEdit, 0, 1);
|
||||||
generalGrid->addWidget(maxPlayersLabel, 1, 0);
|
generalGrid->addWidget(maxPlayersLabel, 1, 0);
|
||||||
|
|
@ -43,17 +43,17 @@ void DlgCreateGame::sharedCtor()
|
||||||
generalGroupBox = new QGroupBox(tr("General"));
|
generalGroupBox = new QGroupBox(tr("General"));
|
||||||
generalGroupBox->setLayout(generalGrid);
|
generalGroupBox->setLayout(generalGrid);
|
||||||
|
|
||||||
QVBoxLayout *gameTypeLayout = new QVBoxLayout;
|
auto *gameTypeLayout = new QVBoxLayout;
|
||||||
QMapIterator<int, QString> gameTypeIterator(gameTypes);
|
QMapIterator<int, QString> gameTypeIterator(gameTypes);
|
||||||
while (gameTypeIterator.hasNext()) {
|
while (gameTypeIterator.hasNext()) {
|
||||||
gameTypeIterator.next();
|
gameTypeIterator.next();
|
||||||
QRadioButton *gameTypeRadioButton = new QRadioButton(gameTypeIterator.value(), this);
|
auto *gameTypeRadioButton = new QRadioButton(gameTypeIterator.value(), this);
|
||||||
gameTypeLayout->addWidget(gameTypeRadioButton);
|
gameTypeLayout->addWidget(gameTypeRadioButton);
|
||||||
gameTypeCheckBoxes.insert(gameTypeIterator.key(), gameTypeRadioButton);
|
gameTypeCheckBoxes.insert(gameTypeIterator.key(), gameTypeRadioButton);
|
||||||
bool isChecked = SettingsCache::instance().getGameTypes().contains(gameTypeIterator.value() + ", ");
|
bool isChecked = SettingsCache::instance().getGameTypes().contains(gameTypeIterator.value() + ", ");
|
||||||
gameTypeCheckBoxes[gameTypeIterator.key()]->setChecked(isChecked);
|
gameTypeCheckBoxes[gameTypeIterator.key()]->setChecked(isChecked);
|
||||||
}
|
}
|
||||||
QGroupBox *gameTypeGroupBox = new QGroupBox(tr("Game type"));
|
auto *gameTypeGroupBox = new QGroupBox(tr("Game type"));
|
||||||
gameTypeGroupBox->setLayout(gameTypeLayout);
|
gameTypeGroupBox->setLayout(gameTypeLayout);
|
||||||
|
|
||||||
passwordLabel = new QLabel(tr("&Password:"));
|
passwordLabel = new QLabel(tr("&Password:"));
|
||||||
|
|
@ -70,13 +70,13 @@ void DlgCreateGame::sharedCtor()
|
||||||
onlyRegisteredCheckBox->setEnabled(false);
|
onlyRegisteredCheckBox->setEnabled(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
QGridLayout *joinRestrictionsLayout = new QGridLayout;
|
auto *joinRestrictionsLayout = new QGridLayout;
|
||||||
joinRestrictionsLayout->addWidget(passwordLabel, 0, 0);
|
joinRestrictionsLayout->addWidget(passwordLabel, 0, 0);
|
||||||
joinRestrictionsLayout->addWidget(passwordEdit, 0, 1);
|
joinRestrictionsLayout->addWidget(passwordEdit, 0, 1);
|
||||||
joinRestrictionsLayout->addWidget(onlyBuddiesCheckBox, 1, 0, 1, 2);
|
joinRestrictionsLayout->addWidget(onlyBuddiesCheckBox, 1, 0, 1, 2);
|
||||||
joinRestrictionsLayout->addWidget(onlyRegisteredCheckBox, 2, 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);
|
joinRestrictionsGroupBox->setLayout(joinRestrictionsLayout);
|
||||||
|
|
||||||
spectatorsAllowedCheckBox = new QCheckBox(tr("&Spectators can watch"));
|
spectatorsAllowedCheckBox = new QCheckBox(tr("&Spectators can watch"));
|
||||||
|
|
@ -86,7 +86,7 @@ void DlgCreateGame::sharedCtor()
|
||||||
spectatorsCanTalkCheckBox = new QCheckBox(tr("Spectators can &chat"));
|
spectatorsCanTalkCheckBox = new QCheckBox(tr("Spectators can &chat"));
|
||||||
spectatorsSeeEverythingCheckBox = new QCheckBox(tr("Spectators can see &hands"));
|
spectatorsSeeEverythingCheckBox = new QCheckBox(tr("Spectators can see &hands"));
|
||||||
createGameAsSpectatorCheckBox = new QCheckBox(tr("Create game as spectator"));
|
createGameAsSpectatorCheckBox = new QCheckBox(tr("Create game as spectator"));
|
||||||
QVBoxLayout *spectatorsLayout = new QVBoxLayout;
|
auto *spectatorsLayout = new QVBoxLayout;
|
||||||
spectatorsLayout->addWidget(spectatorsAllowedCheckBox);
|
spectatorsLayout->addWidget(spectatorsAllowedCheckBox);
|
||||||
spectatorsLayout->addWidget(spectatorsNeedPasswordCheckBox);
|
spectatorsLayout->addWidget(spectatorsNeedPasswordCheckBox);
|
||||||
spectatorsLayout->addWidget(spectatorsCanTalkCheckBox);
|
spectatorsLayout->addWidget(spectatorsCanTalkCheckBox);
|
||||||
|
|
@ -106,7 +106,7 @@ void DlgCreateGame::sharedCtor()
|
||||||
shareDecklistsOnLoadCheckBox = new QCheckBox();
|
shareDecklistsOnLoadCheckBox = new QCheckBox();
|
||||||
shareDecklistsOnLoadLabel->setBuddy(shareDecklistsOnLoadCheckBox);
|
shareDecklistsOnLoadLabel->setBuddy(shareDecklistsOnLoadCheckBox);
|
||||||
|
|
||||||
QGridLayout *gameSetupOptionsLayout = new QGridLayout;
|
auto *gameSetupOptionsLayout = new QGridLayout;
|
||||||
gameSetupOptionsLayout->addWidget(startingLifeTotalLabel, 0, 0);
|
gameSetupOptionsLayout->addWidget(startingLifeTotalLabel, 0, 0);
|
||||||
gameSetupOptionsLayout->addWidget(startingLifeTotalEdit, 0, 1);
|
gameSetupOptionsLayout->addWidget(startingLifeTotalEdit, 0, 1);
|
||||||
gameSetupOptionsLayout->addWidget(shareDecklistsOnLoadLabel, 1, 0);
|
gameSetupOptionsLayout->addWidget(shareDecklistsOnLoadLabel, 1, 0);
|
||||||
|
|
@ -136,7 +136,7 @@ void DlgCreateGame::sharedCtor()
|
||||||
buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok);
|
buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok);
|
||||||
connect(buttonBox, &QDialogButtonBox::rejected, this, &DlgCreateGame::reject);
|
connect(buttonBox, &QDialogButtonBox::rejected, this, &DlgCreateGame::reject);
|
||||||
|
|
||||||
QVBoxLayout *mainLayout = new QVBoxLayout;
|
auto *mainLayout = new QVBoxLayout;
|
||||||
mainLayout->addLayout(grid);
|
mainLayout->addLayout(grid);
|
||||||
mainLayout->addWidget(buttonBox);
|
mainLayout->addWidget(buttonBox);
|
||||||
|
|
||||||
|
|
@ -275,7 +275,7 @@ void DlgCreateGame::actOK()
|
||||||
cmd.set_starting_life_total(startingLifeTotalEdit->value());
|
cmd.set_starting_life_total(startingLifeTotalEdit->value());
|
||||||
cmd.set_share_decklists_on_load(shareDecklistsOnLoadCheckBox->isChecked());
|
cmd.set_share_decklists_on_load(shareDecklistsOnLoadCheckBox->isChecked());
|
||||||
|
|
||||||
QString _gameTypes = QString();
|
auto _gameTypes = QString();
|
||||||
QMapIterator<int, QRadioButton *> gameTypeCheckBoxIterator(gameTypeCheckBoxes);
|
QMapIterator<int, QRadioButton *> gameTypeCheckBoxIterator(gameTypeCheckBoxes);
|
||||||
while (gameTypeCheckBoxIterator.hasNext()) {
|
while (gameTypeCheckBoxIterator.hasNext()) {
|
||||||
gameTypeCheckBoxIterator.next();
|
gameTypeCheckBoxIterator.next();
|
||||||
|
|
|
||||||
|
|
@ -23,16 +23,16 @@ DlgEditAvatar::DlgEditAvatar(QWidget *parent) : QDialog(parent), image()
|
||||||
browseButton = new QPushButton(tr("Browse..."));
|
browseButton = new QPushButton(tr("Browse..."));
|
||||||
connect(browseButton, &QPushButton::clicked, this, &DlgEditAvatar::actBrowse);
|
connect(browseButton, &QPushButton::clicked, this, &DlgEditAvatar::actBrowse);
|
||||||
|
|
||||||
QGridLayout *grid = new QGridLayout;
|
auto *grid = new QGridLayout;
|
||||||
grid->addWidget(imageLabel, 0, 0, 1, 2);
|
grid->addWidget(imageLabel, 0, 0, 1, 2);
|
||||||
grid->addWidget(textLabel, 1, 0);
|
grid->addWidget(textLabel, 1, 0);
|
||||||
grid->addWidget(browseButton, 1, 1);
|
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::accepted, this, &DlgEditAvatar::actOk);
|
||||||
connect(buttonBox, &QDialogButtonBox::rejected, this, &DlgEditAvatar::reject);
|
connect(buttonBox, &QDialogButtonBox::rejected, this, &DlgEditAvatar::reject);
|
||||||
|
|
||||||
QVBoxLayout *mainLayout = new QVBoxLayout;
|
auto *mainLayout = new QVBoxLayout;
|
||||||
mainLayout->addLayout(grid);
|
mainLayout->addLayout(grid);
|
||||||
mainLayout->addWidget(buttonBox);
|
mainLayout->addWidget(buttonBox);
|
||||||
setLayout(mainLayout);
|
setLayout(mainLayout);
|
||||||
|
|
|
||||||
|
|
@ -66,7 +66,7 @@ DlgForgotPasswordChallenge::DlgForgotPasswordChallenge(QWidget *parent) : QDialo
|
||||||
playernameEdit->hide();
|
playernameEdit->hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
QGridLayout *grid = new QGridLayout;
|
auto *grid = new QGridLayout;
|
||||||
grid->addWidget(infoLabel, 0, 0, 1, 2);
|
grid->addWidget(infoLabel, 0, 0, 1, 2);
|
||||||
grid->addWidget(hostLabel, 1, 0);
|
grid->addWidget(hostLabel, 1, 0);
|
||||||
grid->addWidget(hostEdit, 1, 1);
|
grid->addWidget(hostEdit, 1, 1);
|
||||||
|
|
@ -77,11 +77,11 @@ DlgForgotPasswordChallenge::DlgForgotPasswordChallenge(QWidget *parent) : QDialo
|
||||||
grid->addWidget(emailLabel, 4, 0);
|
grid->addWidget(emailLabel, 4, 0);
|
||||||
grid->addWidget(emailEdit, 4, 1);
|
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::accepted, this, &DlgForgotPasswordChallenge::actOk);
|
||||||
connect(buttonBox, &QDialogButtonBox::rejected, this, &DlgForgotPasswordChallenge::reject);
|
connect(buttonBox, &QDialogButtonBox::rejected, this, &DlgForgotPasswordChallenge::reject);
|
||||||
|
|
||||||
QVBoxLayout *mainLayout = new QVBoxLayout;
|
auto *mainLayout = new QVBoxLayout;
|
||||||
mainLayout->addLayout(grid);
|
mainLayout->addLayout(grid);
|
||||||
mainLayout->addWidget(buttonBox);
|
mainLayout->addWidget(buttonBox);
|
||||||
setLayout(mainLayout);
|
setLayout(mainLayout);
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,7 @@ DlgForgotPasswordRequest::DlgForgotPasswordRequest(QWidget *parent) : QDialog(pa
|
||||||
playernameEdit->setMaxLength(MAX_NAME_LENGTH);
|
playernameEdit->setMaxLength(MAX_NAME_LENGTH);
|
||||||
playernameLabel->setBuddy(playernameEdit);
|
playernameLabel->setBuddy(playernameEdit);
|
||||||
|
|
||||||
QGridLayout *grid = new QGridLayout;
|
auto *grid = new QGridLayout;
|
||||||
grid->addWidget(infoLabel, 0, 0, 1, 2);
|
grid->addWidget(infoLabel, 0, 0, 1, 2);
|
||||||
grid->addWidget(hostLabel, 1, 0);
|
grid->addWidget(hostLabel, 1, 0);
|
||||||
grid->addWidget(hostEdit, 1, 1);
|
grid->addWidget(hostEdit, 1, 1);
|
||||||
|
|
@ -54,11 +54,11 @@ DlgForgotPasswordRequest::DlgForgotPasswordRequest(QWidget *parent) : QDialog(pa
|
||||||
grid->addWidget(playernameLabel, 3, 0);
|
grid->addWidget(playernameLabel, 3, 0);
|
||||||
grid->addWidget(playernameEdit, 3, 1);
|
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::accepted, this, &DlgForgotPasswordRequest::actOk);
|
||||||
connect(buttonBox, &QDialogButtonBox::rejected, this, &DlgForgotPasswordRequest::reject);
|
connect(buttonBox, &QDialogButtonBox::rejected, this, &DlgForgotPasswordRequest::reject);
|
||||||
|
|
||||||
QVBoxLayout *mainLayout = new QVBoxLayout;
|
auto *mainLayout = new QVBoxLayout;
|
||||||
mainLayout->addLayout(grid);
|
mainLayout->addLayout(grid);
|
||||||
mainLayout->addWidget(buttonBox);
|
mainLayout->addWidget(buttonBox);
|
||||||
setLayout(mainLayout);
|
setLayout(mainLayout);
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ AbstractDlgDeckTextEdit::AbstractDlgDeckTextEdit(QWidget *parent) : QDialog(pare
|
||||||
refreshButton = new QPushButton(tr("&Refresh"));
|
refreshButton = new QPushButton(tr("&Refresh"));
|
||||||
connect(refreshButton, &QPushButton::clicked, this, &AbstractDlgDeckTextEdit::actRefresh);
|
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);
|
buttonBox->addButton(refreshButton, QDialogButtonBox::ActionRole);
|
||||||
connect(buttonBox, &QDialogButtonBox::accepted, this, &AbstractDlgDeckTextEdit::actOK);
|
connect(buttonBox, &QDialogButtonBox::accepted, this, &AbstractDlgDeckTextEdit::actOK);
|
||||||
connect(buttonBox, &QDialogButtonBox::rejected, this, &AbstractDlgDeckTextEdit::reject);
|
connect(buttonBox, &QDialogButtonBox::rejected, this, &AbstractDlgDeckTextEdit::reject);
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ DlgLoadRemoteDeck::DlgLoadRemoteDeck(AbstractClient *_client, QWidget *parent) :
|
||||||
connect(buttonBox, &QDialogButtonBox::accepted, this, &DlgLoadRemoteDeck::accept);
|
connect(buttonBox, &QDialogButtonBox::accepted, this, &DlgLoadRemoteDeck::accept);
|
||||||
connect(buttonBox, &QDialogButtonBox::rejected, this, &DlgLoadRemoteDeck::reject);
|
connect(buttonBox, &QDialogButtonBox::rejected, this, &DlgLoadRemoteDeck::reject);
|
||||||
|
|
||||||
QVBoxLayout *mainLayout = new QVBoxLayout;
|
auto *mainLayout = new QVBoxLayout;
|
||||||
mainLayout->addWidget(dirView);
|
mainLayout->addWidget(dirView);
|
||||||
mainLayout->addWidget(buttonBox);
|
mainLayout->addWidget(buttonBox);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -321,7 +321,7 @@ DlgRegister::DlgRegister(QWidget *parent) : QDialog(parent)
|
||||||
realnameEdit->setMaxLength(MAX_NAME_LENGTH);
|
realnameEdit->setMaxLength(MAX_NAME_LENGTH);
|
||||||
realnameLabel->setBuddy(realnameEdit);
|
realnameLabel->setBuddy(realnameEdit);
|
||||||
|
|
||||||
QGridLayout *grid = new QGridLayout;
|
auto *grid = new QGridLayout;
|
||||||
grid->addWidget(infoLabel, 0, 0, 1, 2);
|
grid->addWidget(infoLabel, 0, 0, 1, 2);
|
||||||
grid->addWidget(hostLabel, 1, 0);
|
grid->addWidget(hostLabel, 1, 0);
|
||||||
grid->addWidget(hostEdit, 1, 1);
|
grid->addWidget(hostEdit, 1, 1);
|
||||||
|
|
@ -342,11 +342,11 @@ DlgRegister::DlgRegister(QWidget *parent) : QDialog(parent)
|
||||||
grid->addWidget(realnameLabel, 10, 0);
|
grid->addWidget(realnameLabel, 10, 0);
|
||||||
grid->addWidget(realnameEdit, 10, 1);
|
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::accepted, this, &DlgRegister::actOk);
|
||||||
connect(buttonBox, &QDialogButtonBox::rejected, this, &DlgRegister::reject);
|
connect(buttonBox, &QDialogButtonBox::rejected, this, &DlgRegister::reject);
|
||||||
|
|
||||||
QVBoxLayout *mainLayout = new QVBoxLayout;
|
auto *mainLayout = new QVBoxLayout;
|
||||||
mainLayout->addLayout(grid);
|
mainLayout->addLayout(grid);
|
||||||
mainLayout->addWidget(buttonBox);
|
mainLayout->addWidget(buttonBox);
|
||||||
setLayout(mainLayout);
|
setLayout(mainLayout);
|
||||||
|
|
|
||||||
|
|
@ -209,20 +209,9 @@ QMap<QString, int> DlgSelectSetForCards::getSetsForCards()
|
||||||
if (!decklist)
|
if (!decklist)
|
||||||
return setCounts;
|
return setCounts;
|
||||||
|
|
||||||
InnerDecklistNode *listRoot = decklist->getRoot();
|
QList<DecklistCardNode *> cardsInDeck = decklist->getCardNodes();
|
||||||
if (!listRoot)
|
|
||||||
return setCounts;
|
|
||||||
|
|
||||||
for (auto *i : *listRoot) {
|
|
||||||
auto *countCurrentZone = dynamic_cast<InnerDecklistNode *>(i);
|
|
||||||
if (!countCurrentZone)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
for (auto *cardNode : *countCurrentZone) {
|
|
||||||
auto *currentCard = dynamic_cast<DecklistCardNode *>(cardNode);
|
|
||||||
if (!currentCard)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
|
for (auto currentCard : cardsInDeck) {
|
||||||
CardInfoPtr infoPtr = CardDatabaseManager::query()->getCardInfo(currentCard->getName());
|
CardInfoPtr infoPtr = CardDatabaseManager::query()->getCardInfo(currentCard->getName());
|
||||||
if (!infoPtr)
|
if (!infoPtr)
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -232,7 +221,7 @@ QMap<QString, int> DlgSelectSetForCards::getSetsForCards()
|
||||||
setCounts[setName]++;
|
setCounts[setName]++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return setCounts;
|
return setCounts;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -263,20 +252,9 @@ void DlgSelectSetForCards::updateCardLists()
|
||||||
if (!decklist)
|
if (!decklist)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
InnerDecklistNode *listRoot = decklist->getRoot();
|
QList<DecklistCardNode *> cardsInDeck = decklist->getCardNodes();
|
||||||
if (!listRoot)
|
|
||||||
return;
|
|
||||||
|
|
||||||
for (auto *i : *listRoot) {
|
|
||||||
auto *countCurrentZone = dynamic_cast<InnerDecklistNode *>(i);
|
|
||||||
if (!countCurrentZone)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
for (auto *cardNode : *countCurrentZone) {
|
|
||||||
auto *currentCard = dynamic_cast<DecklistCardNode *>(cardNode);
|
|
||||||
if (!currentCard)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
|
for (auto currentCard : cardsInDeck) {
|
||||||
bool found = false;
|
bool found = false;
|
||||||
QString foundSetName;
|
QString foundSetName;
|
||||||
|
|
||||||
|
|
@ -307,7 +285,6 @@ void DlgSelectSetForCards::updateCardLists()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void DlgSelectSetForCards::dragEnterEvent(QDragEnterEvent *event)
|
void DlgSelectSetForCards::dragEnterEvent(QDragEnterEvent *event)
|
||||||
{
|
{
|
||||||
|
|
@ -364,20 +341,9 @@ QMap<QString, QStringList> DlgSelectSetForCards::getCardsForSets()
|
||||||
if (!decklist)
|
if (!decklist)
|
||||||
return setCards;
|
return setCards;
|
||||||
|
|
||||||
InnerDecklistNode *listRoot = decklist->getRoot();
|
QList<DecklistCardNode *> cardsInDeck = decklist->getCardNodes();
|
||||||
if (!listRoot)
|
|
||||||
return setCards;
|
|
||||||
|
|
||||||
for (auto *i : *listRoot) {
|
|
||||||
auto *countCurrentZone = dynamic_cast<InnerDecklistNode *>(i);
|
|
||||||
if (!countCurrentZone)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
for (auto *cardNode : *countCurrentZone) {
|
|
||||||
auto *currentCard = dynamic_cast<DecklistCardNode *>(cardNode);
|
|
||||||
if (!currentCard)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
|
for (auto currentCard : cardsInDeck) {
|
||||||
CardInfoPtr infoPtr = CardDatabaseManager::query()->getCardInfo(currentCard->getName());
|
CardInfoPtr infoPtr = CardDatabaseManager::query()->getCardInfo(currentCard->getName());
|
||||||
if (!infoPtr)
|
if (!infoPtr)
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -387,7 +353,7 @@ QMap<QString, QStringList> DlgSelectSetForCards::getCardsForSets()
|
||||||
setCards[it.key()].append(currentCard->getName());
|
setCards[it.key()].append(currentCard->getName());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return setCards;
|
return setCards;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -141,38 +141,38 @@ GeneralSettingsPage::GeneralSettingsPage()
|
||||||
|
|
||||||
deckPathEdit = new QLineEdit(settings.getDeckPath());
|
deckPathEdit = new QLineEdit(settings.getDeckPath());
|
||||||
deckPathEdit->setReadOnly(true);
|
deckPathEdit->setReadOnly(true);
|
||||||
QPushButton *deckPathButton = new QPushButton("...");
|
auto *deckPathButton = new QPushButton("...");
|
||||||
connect(deckPathButton, &QPushButton::clicked, this, &GeneralSettingsPage::deckPathButtonClicked);
|
connect(deckPathButton, &QPushButton::clicked, this, &GeneralSettingsPage::deckPathButtonClicked);
|
||||||
|
|
||||||
filtersPathEdit = new QLineEdit(settings.getFiltersPath());
|
filtersPathEdit = new QLineEdit(settings.getFiltersPath());
|
||||||
filtersPathEdit->setReadOnly(true);
|
filtersPathEdit->setReadOnly(true);
|
||||||
QPushButton *filtersPathButton = new QPushButton("...");
|
auto *filtersPathButton = new QPushButton("...");
|
||||||
connect(filtersPathButton, &QPushButton::clicked, this, &GeneralSettingsPage::filtersPathButtonClicked);
|
connect(filtersPathButton, &QPushButton::clicked, this, &GeneralSettingsPage::filtersPathButtonClicked);
|
||||||
|
|
||||||
replaysPathEdit = new QLineEdit(settings.getReplaysPath());
|
replaysPathEdit = new QLineEdit(settings.getReplaysPath());
|
||||||
replaysPathEdit->setReadOnly(true);
|
replaysPathEdit->setReadOnly(true);
|
||||||
QPushButton *replaysPathButton = new QPushButton("...");
|
auto *replaysPathButton = new QPushButton("...");
|
||||||
connect(replaysPathButton, &QPushButton::clicked, this, &GeneralSettingsPage::replaysPathButtonClicked);
|
connect(replaysPathButton, &QPushButton::clicked, this, &GeneralSettingsPage::replaysPathButtonClicked);
|
||||||
|
|
||||||
picsPathEdit = new QLineEdit(settings.getPicsPath());
|
picsPathEdit = new QLineEdit(settings.getPicsPath());
|
||||||
picsPathEdit->setReadOnly(true);
|
picsPathEdit->setReadOnly(true);
|
||||||
QPushButton *picsPathButton = new QPushButton("...");
|
auto *picsPathButton = new QPushButton("...");
|
||||||
connect(picsPathButton, &QPushButton::clicked, this, &GeneralSettingsPage::picsPathButtonClicked);
|
connect(picsPathButton, &QPushButton::clicked, this, &GeneralSettingsPage::picsPathButtonClicked);
|
||||||
|
|
||||||
cardDatabasePathEdit = new QLineEdit(settings.getCardDatabasePath());
|
cardDatabasePathEdit = new QLineEdit(settings.getCardDatabasePath());
|
||||||
cardDatabasePathEdit->setReadOnly(true);
|
cardDatabasePathEdit->setReadOnly(true);
|
||||||
QPushButton *cardDatabasePathButton = new QPushButton("...");
|
auto *cardDatabasePathButton = new QPushButton("...");
|
||||||
connect(cardDatabasePathButton, &QPushButton::clicked, this, &GeneralSettingsPage::cardDatabasePathButtonClicked);
|
connect(cardDatabasePathButton, &QPushButton::clicked, this, &GeneralSettingsPage::cardDatabasePathButtonClicked);
|
||||||
|
|
||||||
customCardDatabasePathEdit = new QLineEdit(settings.getCustomCardDatabasePath());
|
customCardDatabasePathEdit = new QLineEdit(settings.getCustomCardDatabasePath());
|
||||||
customCardDatabasePathEdit->setReadOnly(true);
|
customCardDatabasePathEdit->setReadOnly(true);
|
||||||
QPushButton *customCardDatabasePathButton = new QPushButton("...");
|
auto *customCardDatabasePathButton = new QPushButton("...");
|
||||||
connect(customCardDatabasePathButton, &QPushButton::clicked, this,
|
connect(customCardDatabasePathButton, &QPushButton::clicked, this,
|
||||||
&GeneralSettingsPage::customCardDatabaseButtonClicked);
|
&GeneralSettingsPage::customCardDatabaseButtonClicked);
|
||||||
|
|
||||||
tokenDatabasePathEdit = new QLineEdit(settings.getTokenDatabasePath());
|
tokenDatabasePathEdit = new QLineEdit(settings.getTokenDatabasePath());
|
||||||
tokenDatabasePathEdit->setReadOnly(true);
|
tokenDatabasePathEdit->setReadOnly(true);
|
||||||
QPushButton *tokenDatabasePathButton = new QPushButton("...");
|
auto *tokenDatabasePathButton = new QPushButton("...");
|
||||||
connect(tokenDatabasePathButton, &QPushButton::clicked, this, &GeneralSettingsPage::tokenDatabasePathButtonClicked);
|
connect(tokenDatabasePathButton, &QPushButton::clicked, this, &GeneralSettingsPage::tokenDatabasePathButtonClicked);
|
||||||
|
|
||||||
// Required init here to avoid crashing on Portable builds
|
// Required init here to avoid crashing on Portable builds
|
||||||
|
|
|
||||||
|
|
@ -266,35 +266,16 @@ int CardAmountWidget::countCardsInZone(const QString &deckZone)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
InnerDecklistNode *listRoot = decklist->getRoot();
|
QList<DecklistCardNode *> cardsInDeck = decklist->getCardNodes({deckZone});
|
||||||
if (!listRoot) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int count = 0;
|
int count = 0;
|
||||||
|
for (auto currentCard : cardsInDeck) {
|
||||||
for (auto *i : *listRoot) {
|
|
||||||
auto *countCurrentZone = dynamic_cast<InnerDecklistNode *>(i);
|
|
||||||
if (!countCurrentZone) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (countCurrentZone->getName() != deckZone) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto *cardNode : *countCurrentZone) {
|
|
||||||
auto *currentCard = dynamic_cast<DecklistCardNode *>(cardNode);
|
|
||||||
if (!currentCard) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int k = 0; k < currentCard->getNumber(); ++k) {
|
for (int k = 0; k < currentCard->getNumber(); ++k) {
|
||||||
if (currentCard->getCardProviderId() == rootCard.getPrinting().getProperty("uuid")) {
|
if (currentCard->getCardProviderId() == rootCard.getPrinting().getProperty("uuid")) {
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
@ -218,7 +218,7 @@ void PrintingSelector::getAllSetsForCurrentCard()
|
||||||
|
|
||||||
connect(widgetLoadingBufferTimer, &QTimer::timeout, this, [=, this]() mutable {
|
connect(widgetLoadingBufferTimer, &QTimer::timeout, this, [=, this]() mutable {
|
||||||
for (int i = 0; i < BATCH_SIZE && currentIndex < printingsToUse.size(); ++i, ++currentIndex) {
|
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(
|
auto *cardDisplayWidget = new PrintingSelectorCardDisplayWidget(
|
||||||
this, deckEditor, deckModel, deckView, cardSizeWidget->getSlider(), card, currentZone);
|
this, deckEditor, deckModel, deckView, cardSizeWidget->getSlider(), card, currentZone);
|
||||||
flowWidget->addWidget(cardDisplayWidget);
|
flowWidget->addWidget(cardDisplayWidget);
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,7 @@ void PrintingSelectorCardSelectionWidget::connectSignals()
|
||||||
|
|
||||||
void PrintingSelectorCardSelectionWidget::selectSetForCards()
|
void PrintingSelectorCardSelectionWidget::selectSetForCards()
|
||||||
{
|
{
|
||||||
DlgSelectSetForCards *setSelectionDialog = new DlgSelectSetForCards(nullptr, parent->getDeckModel());
|
auto *setSelectionDialog = new DlgSelectSetForCards(nullptr, parent->getDeckModel());
|
||||||
if (!setSelectionDialog->exec()) {
|
if (!setSelectionDialog->exec()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ enum GameListColumn
|
||||||
|
|
||||||
const int DEFAULT_MAX_PLAYERS_MIN = 1;
|
const int DEFAULT_MAX_PLAYERS_MIN = 1;
|
||||||
const int DEFAULT_MAX_PLAYERS_MAX = 99;
|
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)
|
const QString GamesModel::getGameCreatedString(const int secs)
|
||||||
{
|
{
|
||||||
|
|
@ -333,7 +333,7 @@ void GamesProxyModel::setGameFilters(bool _hideBuddiesOnlyGames,
|
||||||
|
|
||||||
int GamesProxyModel::getNumFilteredGames() const
|
int GamesProxyModel::getNumFilteredGames() const
|
||||||
{
|
{
|
||||||
GamesModel *model = qobject_cast<GamesModel *>(sourceModel());
|
auto *model = qobject_cast<GamesModel *>(sourceModel());
|
||||||
if (!model)
|
if (!model)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,7 @@ int RemoteReplayList_TreeModel::rowCount(const QModelIndex &parent) const
|
||||||
if (!parent.isValid())
|
if (!parent.isValid())
|
||||||
return replayMatches.size();
|
return replayMatches.size();
|
||||||
|
|
||||||
MatchNode *matchNode = dynamic_cast<MatchNode *>(static_cast<Node *>(parent.internalPointer()));
|
auto *matchNode = dynamic_cast<MatchNode *>(static_cast<Node *>(parent.internalPointer()));
|
||||||
if (matchNode)
|
if (matchNode)
|
||||||
return matchNode->size();
|
return matchNode->size();
|
||||||
else
|
else
|
||||||
|
|
@ -62,7 +62,7 @@ QVariant RemoteReplayList_TreeModel::data(const QModelIndex &index, int role) co
|
||||||
if (index.column() >= numberOfColumns)
|
if (index.column() >= numberOfColumns)
|
||||||
return QVariant();
|
return QVariant();
|
||||||
|
|
||||||
ReplayNode *replayNode = dynamic_cast<ReplayNode *>(static_cast<Node *>(index.internalPointer()));
|
auto *replayNode = dynamic_cast<ReplayNode *>(static_cast<Node *>(index.internalPointer()));
|
||||||
if (replayNode) {
|
if (replayNode) {
|
||||||
const ServerInfo_Replay &replayInfo = replayNode->getReplayInfo();
|
const ServerInfo_Replay &replayInfo = replayNode->getReplayInfo();
|
||||||
switch (role) {
|
switch (role) {
|
||||||
|
|
@ -84,7 +84,7 @@ QVariant RemoteReplayList_TreeModel::data(const QModelIndex &index, int role) co
|
||||||
return index.column() == 0 ? fileIcon : QVariant();
|
return index.column() == 0 ? fileIcon : QVariant();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
MatchNode *matchNode = dynamic_cast<MatchNode *>(static_cast<Node *>(index.internalPointer()));
|
auto *matchNode = dynamic_cast<MatchNode *>(static_cast<Node *>(index.internalPointer()));
|
||||||
const ServerInfo_ReplayMatch &matchInfo = matchNode->getMatchInfo();
|
const ServerInfo_ReplayMatch &matchInfo = matchNode->getMatchInfo();
|
||||||
switch (role) {
|
switch (role) {
|
||||||
case Qt::TextAlignmentRole:
|
case Qt::TextAlignmentRole:
|
||||||
|
|
@ -170,7 +170,7 @@ QModelIndex RemoteReplayList_TreeModel::index(int row, int column, const QModelI
|
||||||
if (!hasIndex(row, column, parent))
|
if (!hasIndex(row, column, parent))
|
||||||
return QModelIndex();
|
return QModelIndex();
|
||||||
|
|
||||||
MatchNode *matchNode = dynamic_cast<MatchNode *>(static_cast<Node *>(parent.internalPointer()));
|
auto *matchNode = dynamic_cast<MatchNode *>(static_cast<Node *>(parent.internalPointer()));
|
||||||
if (matchNode) {
|
if (matchNode) {
|
||||||
if (row >= matchNode->size())
|
if (row >= matchNode->size())
|
||||||
return QModelIndex();
|
return QModelIndex();
|
||||||
|
|
@ -188,7 +188,7 @@ QModelIndex RemoteReplayList_TreeModel::parent(const QModelIndex &ind) const
|
||||||
if (matchNode)
|
if (matchNode)
|
||||||
return QModelIndex();
|
return QModelIndex();
|
||||||
else {
|
else {
|
||||||
ReplayNode *replayNode = dynamic_cast<ReplayNode *>(static_cast<Node *>(ind.internalPointer()));
|
auto *replayNode = dynamic_cast<ReplayNode *>(static_cast<Node *>(ind.internalPointer()));
|
||||||
return createIndex(replayNode->getParent()->indexOf(replayNode), 0, replayNode->getParent());
|
return createIndex(replayNode->getParent()->indexOf(replayNode), 0, replayNode->getParent());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -206,7 +206,7 @@ ServerInfo_Replay const *RemoteReplayList_TreeModel::getReplay(const QModelIndex
|
||||||
if (!index.isValid())
|
if (!index.isValid())
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
ReplayNode *node = dynamic_cast<ReplayNode *>(static_cast<Node *>(index.internalPointer()));
|
auto *node = dynamic_cast<ReplayNode *>(static_cast<Node *>(index.internalPointer()));
|
||||||
if (!node)
|
if (!node)
|
||||||
return 0;
|
return 0;
|
||||||
return &node->getReplayInfo();
|
return &node->getReplayInfo();
|
||||||
|
|
|
||||||
|
|
@ -110,7 +110,7 @@ void UserContextMenu::gamesOfUserReceived(const Response &resp, const CommandCon
|
||||||
gameTypeMap.insert(roomInfo.room_id(), tempMap);
|
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<QWidget *>(parent()), Qt::Window);
|
selector->setParent(static_cast<QWidget *>(parent()), Qt::Window);
|
||||||
const int gameListSize = response.game_list_size();
|
const int gameListSize = response.game_list_size();
|
||||||
for (int i = 0; i < gameListSize; ++i) {
|
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);
|
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.
|
// 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<QWidget *>(parent()));
|
auto *dlg = new BanDialog(response.user_info(), static_cast<QWidget *>(parent()));
|
||||||
connect(dlg, &QDialog::accepted, this, &UserContextMenu::banUser_dialogFinished);
|
connect(dlg, &QDialog::accepted, this, &UserContextMenu::banUser_dialogFinished);
|
||||||
dlg->show();
|
dlg->show();
|
||||||
}
|
}
|
||||||
|
|
@ -141,7 +141,7 @@ void UserContextMenu::warnUser_processGetWarningsListResponse(const Response &r)
|
||||||
QString clientid = QString::fromStdString(response.user_clientid()).simplified();
|
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.
|
// 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<QWidget *>(parent()));
|
auto *dlg = new WarningDialog(user, clientid, static_cast<QWidget *>(parent()));
|
||||||
connect(dlg, &QDialog::accepted, this, &UserContextMenu::warnUser_dialogFinished);
|
connect(dlg, &QDialog::accepted, this, &UserContextMenu::warnUser_dialogFinished);
|
||||||
|
|
||||||
if (response.warning_size() > 0) {
|
if (response.warning_size() > 0) {
|
||||||
|
|
@ -171,7 +171,7 @@ void UserContextMenu::banUserHistory_processResponse(const Response &resp)
|
||||||
if (resp.response_code() == Response::RespOk) {
|
if (resp.response_code() == Response::RespOk) {
|
||||||
|
|
||||||
if (response.ban_list_size() > 0) {
|
if (response.ban_list_size() > 0) {
|
||||||
QTableWidget *table = new QTableWidget();
|
auto *table = new QTableWidget();
|
||||||
table->setWindowTitle(tr("Ban History"));
|
table->setWindowTitle(tr("Ban History"));
|
||||||
table->setRowCount(response.ban_list_size());
|
table->setRowCount(response.ban_list_size());
|
||||||
table->setColumnCount(5);
|
table->setColumnCount(5);
|
||||||
|
|
@ -209,7 +209,7 @@ void UserContextMenu::warnUserHistory_processResponse(const Response &resp)
|
||||||
if (resp.response_code() == Response::RespOk) {
|
if (resp.response_code() == Response::RespOk) {
|
||||||
|
|
||||||
if (response.warn_list_size() > 0) {
|
if (response.warn_list_size() > 0) {
|
||||||
QTableWidget *table = new QTableWidget();
|
auto *table = new QTableWidget();
|
||||||
table->setWindowTitle(tr("Warning History"));
|
table->setWindowTitle(tr("Warning History"));
|
||||||
table->setRowCount(response.warn_list_size());
|
table->setRowCount(response.warn_list_size());
|
||||||
table->setColumnCount(4);
|
table->setColumnCount(4);
|
||||||
|
|
@ -278,7 +278,7 @@ void UserContextMenu::adjustMod_processUserResponse(const Response &resp, const
|
||||||
|
|
||||||
void UserContextMenu::banUser_dialogFinished()
|
void UserContextMenu::banUser_dialogFinished()
|
||||||
{
|
{
|
||||||
BanDialog *dlg = static_cast<BanDialog *>(sender());
|
auto *dlg = static_cast<BanDialog *>(sender());
|
||||||
|
|
||||||
Command_BanFromServer cmd;
|
Command_BanFromServer cmd;
|
||||||
cmd.set_user_name(dlg->getBanName().toStdString());
|
cmd.set_user_name(dlg->getBanName().toStdString());
|
||||||
|
|
@ -297,7 +297,7 @@ void UserContextMenu::banUser_dialogFinished()
|
||||||
|
|
||||||
void UserContextMenu::warnUser_dialogFinished()
|
void UserContextMenu::warnUser_dialogFinished()
|
||||||
{
|
{
|
||||||
WarningDialog *dlg = static_cast<WarningDialog *>(sender());
|
auto *dlg = static_cast<WarningDialog *>(sender());
|
||||||
|
|
||||||
if (dlg->getName().isEmpty() || userListProxy->getOwnUsername().simplified().isEmpty())
|
if (dlg->getName().isEmpty() || userListProxy->getOwnUsername().simplified().isEmpty())
|
||||||
return;
|
return;
|
||||||
|
|
@ -433,7 +433,7 @@ void UserContextMenu::showContextMenu(const QPoint &pos,
|
||||||
QAction *actionClicked = menu->exec(pos);
|
QAction *actionClicked = menu->exec(pos);
|
||||||
if (actionClicked == nullptr) {
|
if (actionClicked == nullptr) {
|
||||||
} else if (actionClicked == aDetails) {
|
} else if (actionClicked == aDetails) {
|
||||||
UserInfoBox *infoWidget =
|
auto *infoWidget =
|
||||||
new UserInfoBox(client, false, static_cast<QWidget *>(parent()),
|
new UserInfoBox(client, false, static_cast<QWidget *>(parent()),
|
||||||
Qt::Dialog | Qt::WindowTitleHint | Qt::CustomizeWindowHint | Qt::WindowCloseButtonHint);
|
Qt::Dialog | Qt::WindowTitleHint | Qt::CustomizeWindowHint | Qt::WindowCloseButtonHint);
|
||||||
infoWidget->setAttribute(Qt::WA_DeleteOnClose);
|
infoWidget->setAttribute(Qt::WA_DeleteOnClose);
|
||||||
|
|
|
||||||
|
|
@ -64,14 +64,14 @@ TabEdhRecMain::TabEdhRecMain(TabSupervisor *_tabSupervisor) : Tab(_tabSupervisor
|
||||||
auto cardDatabaseModel = new CardDatabaseModel(CardDatabaseManager::getInstance(), false, this);
|
auto cardDatabaseModel = new CardDatabaseModel(CardDatabaseManager::getInstance(), false, this);
|
||||||
auto displayModel = new CardDatabaseDisplayModel(this);
|
auto displayModel = new CardDatabaseDisplayModel(this);
|
||||||
displayModel->setSourceModel(cardDatabaseModel);
|
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->setSourceModel(searchModel);
|
||||||
proxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
|
proxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
|
||||||
proxyModel->setFilterRole(Qt::DisplayRole);
|
proxyModel->setFilterRole(Qt::DisplayRole);
|
||||||
|
|
||||||
QCompleter *completer = new QCompleter(proxyModel, this);
|
auto *completer = new QCompleter(proxyModel, this);
|
||||||
completer->setCompletionRole(Qt::DisplayRole);
|
completer->setCompletionRole(Qt::DisplayRole);
|
||||||
completer->setCompletionMode(QCompleter::PopupCompletion);
|
completer->setCompletionMode(QCompleter::PopupCompletion);
|
||||||
completer->setCaseSensitivity(Qt::CaseInsensitive);
|
completer->setCaseSensitivity(Qt::CaseInsensitive);
|
||||||
|
|
|
||||||
|
|
@ -17,22 +17,22 @@
|
||||||
|
|
||||||
ShutdownDialog::ShutdownDialog(QWidget *parent) : QDialog(parent)
|
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 = new QLineEdit;
|
||||||
reasonEdit->setMaxLength(MAX_TEXT_LENGTH);
|
reasonEdit->setMaxLength(MAX_TEXT_LENGTH);
|
||||||
reasonLabel->setBuddy(reasonEdit);
|
reasonLabel->setBuddy(reasonEdit);
|
||||||
QLabel *minutesLabel = new QLabel(tr("&Time until shutdown (minutes):"));
|
auto *minutesLabel = new QLabel(tr("&Time until shutdown (minutes):"));
|
||||||
minutesEdit = new QSpinBox;
|
minutesEdit = new QSpinBox;
|
||||||
minutesLabel->setBuddy(minutesEdit);
|
minutesLabel->setBuddy(minutesEdit);
|
||||||
minutesEdit->setMinimum(0);
|
minutesEdit->setMinimum(0);
|
||||||
minutesEdit->setValue(5);
|
minutesEdit->setValue(5);
|
||||||
minutesEdit->setMaximum(999);
|
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::accepted, this, &ShutdownDialog::accept);
|
||||||
connect(buttonBox, &QDialogButtonBox::rejected, this, &ShutdownDialog::reject);
|
connect(buttonBox, &QDialogButtonBox::rejected, this, &ShutdownDialog::reject);
|
||||||
|
|
||||||
QGridLayout *mainLayout = new QGridLayout;
|
auto *mainLayout = new QGridLayout;
|
||||||
mainLayout->addWidget(reasonLabel, 0, 0);
|
mainLayout->addWidget(reasonLabel, 0, 0);
|
||||||
mainLayout->addWidget(reasonEdit, 0, 1);
|
mainLayout->addWidget(reasonEdit, 0, 1);
|
||||||
mainLayout->addWidget(minutesLabel, 1, 0);
|
mainLayout->addWidget(minutesLabel, 1, 0);
|
||||||
|
|
@ -109,7 +109,7 @@ TabAdmin::TabAdmin(TabSupervisor *_tabSupervisor, AbstractClient *_client, bool
|
||||||
lockButton->setEnabled(false);
|
lockButton->setEnabled(false);
|
||||||
connect(lockButton, &QPushButton::clicked, this, &TabAdmin::actLock);
|
connect(lockButton, &QPushButton::clicked, this, &TabAdmin::actLock);
|
||||||
|
|
||||||
QVBoxLayout *mainLayout = new QVBoxLayout;
|
auto *mainLayout = new QVBoxLayout;
|
||||||
mainLayout->addWidget(adminGroupBox);
|
mainLayout->addWidget(adminGroupBox);
|
||||||
mainLayout->addWidget(moderatorGroupBox);
|
mainLayout->addWidget(moderatorGroupBox);
|
||||||
mainLayout->addStretch();
|
mainLayout->addStretch();
|
||||||
|
|
@ -118,7 +118,7 @@ TabAdmin::TabAdmin(TabSupervisor *_tabSupervisor, AbstractClient *_client, bool
|
||||||
|
|
||||||
retranslateUi();
|
retranslateUi();
|
||||||
|
|
||||||
QWidget *mainWidget = new QWidget(this);
|
auto *mainWidget = new QWidget(this);
|
||||||
mainWidget->setLayout(mainLayout);
|
mainWidget->setLayout(mainLayout);
|
||||||
setCentralWidget(mainWidget);
|
setCentralWidget(mainWidget);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -982,7 +982,7 @@ void TabGame::createMenuItems()
|
||||||
phasesMenu = new TearOffMenu(this);
|
phasesMenu = new TearOffMenu(this);
|
||||||
|
|
||||||
for (int i = 0; i < phasesToolbar->phaseCount(); ++i) {
|
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);
|
connect(temp, &QAction::triggered, this, &TabGame::actPhaseAction);
|
||||||
phasesMenu->addAction(temp);
|
phasesMenu->addAction(temp);
|
||||||
phaseActions.append(temp);
|
phaseActions.append(temp);
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@ TabMessage::TabMessage(TabSupervisor *_tabSupervisor,
|
||||||
sayEdit->setMaxLength(MAX_TEXT_LENGTH);
|
sayEdit->setMaxLength(MAX_TEXT_LENGTH);
|
||||||
connect(sayEdit, &LineEditUnfocusable::returnPressed, this, &TabMessage::sendMessage);
|
connect(sayEdit, &LineEditUnfocusable::returnPressed, this, &TabMessage::sendMessage);
|
||||||
|
|
||||||
QVBoxLayout *vbox = new QVBoxLayout;
|
auto *vbox = new QVBoxLayout;
|
||||||
vbox->addWidget(chatView);
|
vbox->addWidget(chatView);
|
||||||
vbox->addWidget(sayEdit);
|
vbox->addWidget(sayEdit);
|
||||||
|
|
||||||
|
|
@ -47,7 +47,7 @@ TabMessage::TabMessage(TabSupervisor *_tabSupervisor,
|
||||||
|
|
||||||
retranslateUi();
|
retranslateUi();
|
||||||
|
|
||||||
QWidget *mainWidget = new QWidget(this);
|
auto *mainWidget = new QWidget(this);
|
||||||
mainWidget->setLayout(vbox);
|
mainWidget->setLayout(vbox);
|
||||||
setCentralWidget(mainWidget);
|
setCentralWidget(mainWidget);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -67,7 +67,7 @@ TabRoom::TabRoom(TabSupervisor *_tabSupervisor,
|
||||||
sayLabel->setBuddy(sayEdit);
|
sayLabel->setBuddy(sayEdit);
|
||||||
connect(sayEdit, &LineEditCompleter::returnPressed, this, &TabRoom::sendMessage);
|
connect(sayEdit, &LineEditCompleter::returnPressed, this, &TabRoom::sendMessage);
|
||||||
|
|
||||||
QMenu *chatSettingsMenu = new QMenu(this);
|
auto *chatSettingsMenu = new QMenu(this);
|
||||||
|
|
||||||
aClearChat = chatSettingsMenu->addAction(QString());
|
aClearChat = chatSettingsMenu->addAction(QString());
|
||||||
connect(aClearChat, &QAction::triggered, this, &TabRoom::actClearChat);
|
connect(aClearChat, &QAction::triggered, this, &TabRoom::actClearChat);
|
||||||
|
|
@ -77,28 +77,28 @@ TabRoom::TabRoom(TabSupervisor *_tabSupervisor,
|
||||||
aOpenChatSettings = chatSettingsMenu->addAction(QString());
|
aOpenChatSettings = chatSettingsMenu->addAction(QString());
|
||||||
connect(aOpenChatSettings, &QAction::triggered, this, &TabRoom::actOpenChatSettings);
|
connect(aOpenChatSettings, &QAction::triggered, this, &TabRoom::actOpenChatSettings);
|
||||||
|
|
||||||
QToolButton *chatSettingsButton = new QToolButton;
|
auto *chatSettingsButton = new QToolButton;
|
||||||
chatSettingsButton->setIcon(QPixmap("theme:icons/settings"));
|
chatSettingsButton->setIcon(QPixmap("theme:icons/settings"));
|
||||||
chatSettingsButton->setMenu(chatSettingsMenu);
|
chatSettingsButton->setMenu(chatSettingsMenu);
|
||||||
chatSettingsButton->setPopupMode(QToolButton::InstantPopup);
|
chatSettingsButton->setPopupMode(QToolButton::InstantPopup);
|
||||||
|
|
||||||
QHBoxLayout *sayHbox = new QHBoxLayout;
|
auto *sayHbox = new QHBoxLayout;
|
||||||
sayHbox->addWidget(sayLabel);
|
sayHbox->addWidget(sayLabel);
|
||||||
sayHbox->addWidget(sayEdit);
|
sayHbox->addWidget(sayEdit);
|
||||||
sayHbox->addWidget(chatSettingsButton);
|
sayHbox->addWidget(chatSettingsButton);
|
||||||
|
|
||||||
QVBoxLayout *chatVbox = new QVBoxLayout;
|
auto *chatVbox = new QVBoxLayout;
|
||||||
chatVbox->addWidget(chatView);
|
chatVbox->addWidget(chatView);
|
||||||
chatVbox->addLayout(sayHbox);
|
chatVbox->addLayout(sayHbox);
|
||||||
|
|
||||||
chatGroupBox = new QGroupBox;
|
chatGroupBox = new QGroupBox;
|
||||||
chatGroupBox->setLayout(chatVbox);
|
chatGroupBox->setLayout(chatVbox);
|
||||||
|
|
||||||
QSplitter *splitter = new QSplitter(Qt::Vertical);
|
auto *splitter = new QSplitter(Qt::Vertical);
|
||||||
splitter->addWidget(gameSelector);
|
splitter->addWidget(gameSelector);
|
||||||
splitter->addWidget(chatGroupBox);
|
splitter->addWidget(chatGroupBox);
|
||||||
|
|
||||||
QHBoxLayout *hbox = new QHBoxLayout;
|
auto *hbox = new QHBoxLayout;
|
||||||
hbox->addWidget(splitter, 3);
|
hbox->addWidget(splitter, 3);
|
||||||
hbox->addWidget(userList, 1);
|
hbox->addWidget(userList, 1);
|
||||||
|
|
||||||
|
|
@ -133,7 +133,7 @@ TabRoom::TabRoom(TabSupervisor *_tabSupervisor,
|
||||||
|
|
||||||
retranslateUi();
|
retranslateUi();
|
||||||
|
|
||||||
QWidget *mainWidget = new QWidget(this);
|
auto *mainWidget = new QWidget(this);
|
||||||
mainWidget->setLayout(hbox);
|
mainWidget->setLayout(hbox);
|
||||||
setCentralWidget(mainWidget);
|
setCentralWidget(mainWidget);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -931,7 +931,7 @@ void TabSupervisor::deckEditorClosed(AbstractTabDeckEditor *tab)
|
||||||
|
|
||||||
void TabSupervisor::tabUserEvent(bool globalEvent)
|
void TabSupervisor::tabUserEvent(bool globalEvent)
|
||||||
{
|
{
|
||||||
Tab *tab = static_cast<Tab *>(sender());
|
auto *tab = static_cast<Tab *>(sender());
|
||||||
if (tab != currentWidget()) {
|
if (tab != currentWidget()) {
|
||||||
tab->setContentsChanged(true);
|
tab->setContentsChanged(true);
|
||||||
setTabIcon(indexOf(tab), QPixmap("theme:icons/tab_changed"));
|
setTabIcon(indexOf(tab), QPixmap("theme:icons/tab_changed"));
|
||||||
|
|
@ -1032,7 +1032,7 @@ void TabSupervisor::processUserJoined(const ServerInfo_User &userInfoJoined)
|
||||||
void TabSupervisor::updateCurrent(int index)
|
void TabSupervisor::updateCurrent(int index)
|
||||||
{
|
{
|
||||||
if (index != -1) {
|
if (index != -1) {
|
||||||
Tab *tab = static_cast<Tab *>(widget(index));
|
auto *tab = static_cast<Tab *>(widget(index));
|
||||||
if (tab->getContentsChanged()) {
|
if (tab->getContentsChanged()) {
|
||||||
setTabIcon(index, QIcon());
|
setTabIcon(index, QIcon());
|
||||||
tab->setContentsChanged(false);
|
tab->setContentsChanged(false);
|
||||||
|
|
|
||||||
|
|
@ -67,21 +67,13 @@ void VisualDatabaseDisplayNameFilterWidget::actLoadFromDeck()
|
||||||
DeckList *decklist = deckListModel->getDeckList();
|
DeckList *decklist = deckListModel->getDeckList();
|
||||||
if (!decklist)
|
if (!decklist)
|
||||||
return;
|
return;
|
||||||
InnerDecklistNode *listRoot = decklist->getRoot();
|
|
||||||
if (!listRoot)
|
|
||||||
return;
|
|
||||||
|
|
||||||
for (int i = 0; i < listRoot->size(); i++) {
|
QList<DecklistCardNode *> cardsInDeck = decklist->getCardNodes();
|
||||||
InnerDecklistNode *currentZone = dynamic_cast<InnerDecklistNode *>(listRoot->at(i));
|
|
||||||
if (!currentZone)
|
for (auto currentCard : cardsInDeck) {
|
||||||
continue;
|
|
||||||
for (int j = 0; j < currentZone->size(); j++) {
|
|
||||||
DecklistCardNode *currentCard = dynamic_cast<DecklistCardNode *>(currentZone->at(j));
|
|
||||||
if (!currentCard)
|
|
||||||
continue;
|
|
||||||
createNameFilter(currentCard->getName());
|
createNameFilter(currentCard->getName());
|
||||||
}
|
}
|
||||||
}
|
|
||||||
updateFilterModel();
|
updateFilterModel();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -83,23 +83,11 @@ QList<ExactCard> VisualDeckEditorSampleHandWidget::getRandomCards(int amountToGe
|
||||||
DeckList *decklist = deckListModel->getDeckList();
|
DeckList *decklist = deckListModel->getDeckList();
|
||||||
if (!decklist)
|
if (!decklist)
|
||||||
return randomCards;
|
return randomCards;
|
||||||
InnerDecklistNode *listRoot = decklist->getRoot();
|
|
||||||
if (!listRoot)
|
QList<DecklistCardNode *> cardsInDeck = decklist->getCardNodes({DECK_ZONE_MAIN});
|
||||||
return randomCards;
|
|
||||||
|
|
||||||
// Collect all cards in the main deck, allowing duplicates based on their count
|
// Collect all cards in the main deck, allowing duplicates based on their count
|
||||||
for (int i = 0; i < listRoot->size(); i++) {
|
for (auto currentCard : cardsInDeck) {
|
||||||
InnerDecklistNode *currentZone = dynamic_cast<InnerDecklistNode *>(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<DecklistCardNode *>(currentZone->at(j));
|
|
||||||
if (!currentCard)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
for (int k = 0; k < currentCard->getNumber(); ++k) {
|
for (int k = 0; k < currentCard->getNumber(); ++k) {
|
||||||
ExactCard card = CardDatabaseManager::query()->getCard(currentCard->toCardRef());
|
ExactCard card = CardDatabaseManager::query()->getCard(currentCard->toCardRef());
|
||||||
if (card) {
|
if (card) {
|
||||||
|
|
@ -107,7 +95,6 @@ QList<ExactCard> VisualDeckEditorSampleHandWidget::getRandomCards(int amountToGe
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (mainDeckCards.isEmpty())
|
if (mainDeckCards.isEmpty())
|
||||||
return randomCards;
|
return randomCards;
|
||||||
|
|
|
||||||
|
|
@ -232,19 +232,14 @@ void DeckPreviewWidget::updateBannerCardComboBox()
|
||||||
|
|
||||||
// Prepare the new items with deduplication
|
// Prepare the new items with deduplication
|
||||||
QSet<QPair<QString, QString>> bannerCardSet;
|
QSet<QPair<QString, QString>> bannerCardSet;
|
||||||
InnerDecklistNode *listRoot = deckLoader->getDeckList()->getRoot();
|
|
||||||
for (auto i : *listRoot) {
|
|
||||||
auto *currentZone = dynamic_cast<InnerDecklistNode *>(i);
|
|
||||||
for (auto j : *currentZone) {
|
|
||||||
auto *currentCard = dynamic_cast<DecklistCardNode *>(j);
|
|
||||||
if (!currentCard)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
|
QList<DecklistCardNode *> cardsInDeck = deckLoader->getDeckList()->getCardNodes();
|
||||||
|
|
||||||
|
for (auto currentCard : cardsInDeck) {
|
||||||
for (int k = 0; k < currentCard->getNumber(); ++k) {
|
for (int k = 0; k < currentCard->getNumber(); ++k) {
|
||||||
bannerCardSet.insert(QPair<QString, QString>(currentCard->getName(), currentCard->getCardProviderId()));
|
bannerCardSet.insert(QPair<QString, QString>(currentCard->getName(), currentCard->getCardProviderId()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
QList<QPair<QString, QString>> pairList = bannerCardSet.values();
|
QList<QPair<QString, QString>> pairList = bannerCardSet.values();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
#include "mocks.h"
|
#include "mocks.h"
|
||||||
|
|
||||||
CardDatabaseSettings::CardDatabaseSettings(const QString &settingPath, QObject *parent)
|
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 */)
|
void CardDatabaseSettings::setSortKey(QString /* shortName */, unsigned int /* sortKey */)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
@page card_database_schema_and_parsing Card Database Schema and Parsing
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,3 +1,9 @@
|
||||||
@page developer_reference Developer Reference
|
@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
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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.
|
||||||
|
|
@ -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.
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
@page creating_decks Creating Decks
|
||||||
|
|
||||||
|
Creating a new deck is done using either the TabDeckEditor or TabDeckEditorVisual.
|
||||||
|
|
||||||
|
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
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
@page editing_decks Editing Decks
|
||||||
|
|
||||||
|
@subpage editing_decks_classic
|
||||||
|
|
||||||
|
@subpage editing_decks_visual
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
@page editing_decks_printings Printing Selector
|
||||||
|
|
@ -0,0 +1,71 @@
|
||||||
|
@page editing_decks_visual Visual Deck Editor
|
||||||
|
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
# 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 either be displayed in a "Flat" layout, which displays each picture next to each other and ensures full
|
||||||
|
visibility for each card, 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.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
# 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.
|
||||||
|
|
@ -0,0 +1,95 @@
|
||||||
|
@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.
|
||||||
|
|
||||||
|
```
|
||||||
|
// Deck Name
|
||||||
|
|
||||||
|
// Deck Comment
|
||||||
|
|
||||||
|
// 10 Maindeck
|
||||||
|
// 6 Artifact
|
||||||
|
2 The Darkness Crystal (FIN) 335
|
||||||
|
2 The Fire Crystal (FIN) 337
|
||||||
|
2 Black Mage's Rod (FIN) 90
|
||||||
|
|
||||||
|
// 6 Sorcery
|
||||||
|
2 Nibelheim Aflame (FIN) 339
|
||||||
|
4 Cornered by Black Mages (FIN) 93
|
||||||
|
|
||||||
|
// 6 Sideboard
|
||||||
|
// 6 Creature
|
||||||
|
SB: 4 Blazing Bomb (FIN) 130
|
||||||
|
SB: 1 Garland, Knight of Cornelia (FIN) 221
|
||||||
|
SB: 1 Undercity Dire Rat (FIN) 123
|
||||||
|
```
|
||||||
|
|
||||||
|
## 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.
|
||||||
|
|
@ -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.
|
||||||
|
|
@ -1,4 +1,13 @@
|
||||||
@page user_reference User Reference
|
@page user_reference User Reference
|
||||||
|
|
||||||
@subpage search_syntax_help
|
@subpage search_syntax_help
|
||||||
|
|
||||||
@subpage deck_search_syntax_help
|
@subpage deck_search_syntax_help
|
||||||
|
|
||||||
|
@subpage creating_decks
|
||||||
|
|
||||||
|
@subpage importing_decks
|
||||||
|
|
||||||
|
@subpage editing_decks
|
||||||
|
|
||||||
|
@subpage exporting_decks
|
||||||
BIN
doc/doxygen-images/classic_database_display.png
Normal file
|
After Width: | Height: | Size: 107 KiB |
BIN
doc/doxygen-images/classic_database_display_add_buttons.png
Normal file
|
After Width: | Height: | Size: 5.3 KiB |
BIN
doc/doxygen-images/classic_deck_editor.png
Normal file
|
After Width: | Height: | Size: 458 KiB |
BIN
doc/doxygen-images/deck_dock_deck_list.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
doc/doxygen-images/deck_dock_deck_list_buttons.png
Normal file
|
After Width: | Height: | Size: 885 B |
BIN
doc/doxygen-images/deck_dock_deck_list_group_by.png
Normal file
|
After Width: | Height: | Size: 2.6 KiB |
BIN
doc/doxygen-images/deckeditordeckdockwidget.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
|
|
@ -1,9 +1,3 @@
|
||||||
/**
|
|
||||||
* @file card_info.h
|
|
||||||
* @ingroup Cards
|
|
||||||
* @brief TODO: Document this.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef CARD_INFO_H
|
#ifndef CARD_INFO_H
|
||||||
#define CARD_INFO_H
|
#define CARD_INFO_H
|
||||||
|
|
||||||
|
|
@ -54,6 +48,10 @@ class CardInfo : public QObject
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
/** @name Private Card Properties
|
||||||
|
* @anchor PrivateCardProperties
|
||||||
|
*/
|
||||||
|
///@{
|
||||||
CardInfoPtr smartThis; ///< Smart pointer to self for safe cross-references.
|
CardInfoPtr smartThis; ///< Smart pointer to self for safe cross-references.
|
||||||
QString name; ///< Full name of the card.
|
QString name; ///< Full name of the card.
|
||||||
QString simpleName; ///< Simplified name for fuzzy matching.
|
QString simpleName; ///< Simplified name for fuzzy matching.
|
||||||
|
|
@ -69,6 +67,7 @@ private:
|
||||||
bool landscapeOrientation; ///< Orientation flag for rendering.
|
bool landscapeOrientation; ///< Orientation flag for rendering.
|
||||||
int tableRow; ///< Row index in a table or visual representation.
|
int tableRow; ///< Row index in a table or visual representation.
|
||||||
bool upsideDownArt; ///< Whether artwork is flipped for visual purposes.
|
bool upsideDownArt; ///< Whether artwork is flipped for visual purposes.
|
||||||
|
///@}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
|
|
@ -161,7 +160,7 @@ public:
|
||||||
*/
|
*/
|
||||||
CardInfoPtr clone() const
|
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
|
newCardInfo->setSmartPointer(newCardInfo); // Set the smart pointer for the new instance
|
||||||
return newCardInfo;
|
return newCardInfo;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
#ifndef CARDDATABASE_H
|
||||||
#define CARDDATABASE_H
|
#define CARDDATABASE_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
|
#ifndef COCKATRICE_CARD_DATABASE_LOADER_H
|
||||||
#define COCKATRICE_CARD_DATABASE_LOADER_H
|
#define COCKATRICE_CARD_DATABASE_LOADER_H
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @class ExactCard
|
* @class ExactCard
|
||||||
* @ingroup Cards
|
* @ingroup CardPrintings
|
||||||
*
|
*
|
||||||
* @brief Represents a specific card instance, defined by its CardInfo
|
* @brief Represents a specific card instance, defined by its CardInfo
|
||||||
* and a particular printing.
|
* and a particular printing.
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ using SetToPrintingsMap = QMap<QString, QList<PrintingInfo>>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @class PrintingInfo
|
* @class PrintingInfo
|
||||||
* @ingroup Cards
|
* @ingroup CardPrintings
|
||||||
*
|
*
|
||||||
* @brief Represents metadata for a specific variation of a card within a set.
|
* @brief Represents metadata for a specific variation of a card within a set.
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ using CardSetPtr = QSharedPointer<CardSet>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @class CardSet
|
* @class CardSet
|
||||||
* @ingroup Cards
|
* @ingroup CardSets
|
||||||
*
|
*
|
||||||
* @brief A collection of cards grouped under a common identifier.
|
* @brief A collection of cards grouped under a common identifier.
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/**
|
/**
|
||||||
* @file card_set_comparator.h
|
* @file card_set_comparator.h
|
||||||
* @ingroup Cards
|
* @ingroup CardSets
|
||||||
* @brief TODO: Document this.
|
* @brief TODO: Document this.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @class CardSetList
|
* @class CardSetList
|
||||||
* @ingroup Cards
|
* @ingroup CardSets
|
||||||
*
|
*
|
||||||
* @brief A list-like container for CardSet objects with extended management methods.
|
* @brief A list-like container for CardSet objects with extended management methods.
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -563,6 +563,29 @@ QList<CardRef> DeckList::getCardRefList() const
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QList<DecklistCardNode *> DeckList::getCardNodes(const QStringList &restrictToZones) const
|
||||||
|
{
|
||||||
|
QList<DecklistCardNode *> result;
|
||||||
|
|
||||||
|
for (auto *node : *root) {
|
||||||
|
auto *zoneNode = dynamic_cast<InnerDecklistNode *>(node);
|
||||||
|
if (zoneNode == nullptr) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!restrictToZones.isEmpty() && !restrictToZones.contains(node->getName())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for (auto *cardNode : *zoneNode) {
|
||||||
|
auto *cardCardNode = dynamic_cast<DecklistCardNode *>(cardNode);
|
||||||
|
if (cardCardNode != nullptr) {
|
||||||
|
result.append(cardCardNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
int DeckList::getSideboardSize() const
|
int DeckList::getSideboardSize() const
|
||||||
{
|
{
|
||||||
int size = 0;
|
int size = 0;
|
||||||
|
|
|
||||||
|
|
@ -289,6 +289,7 @@ public:
|
||||||
}
|
}
|
||||||
QStringList getCardList() const;
|
QStringList getCardList() const;
|
||||||
QList<CardRef> getCardRefList() const;
|
QList<CardRef> getCardRefList() const;
|
||||||
|
QList<DecklistCardNode *> getCardNodes(const QStringList &restrictToZones = QStringList()) const;
|
||||||
int getSideboardSize() const;
|
int getSideboardSize() const;
|
||||||
InnerDecklistNode *getRoot() const
|
InnerDecklistNode *getRoot() const
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -145,10 +145,10 @@ bool InnerDecklistNode::readElement(QXmlStreamReader *xml)
|
||||||
const QString childName = xml->name().toString();
|
const QString childName = xml->name().toString();
|
||||||
if (xml->isStartElement()) {
|
if (xml->isStartElement()) {
|
||||||
if (childName == "zone") {
|
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);
|
newZone->readElement(xml);
|
||||||
} else if (childName == "card") {
|
} else if (childName == "card") {
|
||||||
DecklistCardNode *newCard = new DecklistCardNode(
|
auto *newCard = new DecklistCardNode(
|
||||||
xml->attributes().value("name").toString(), xml->attributes().value("number").toString().toInt(),
|
xml->attributes().value("name").toString(), xml->attributes().value("number").toString().toInt(),
|
||||||
this, -1, xml->attributes().value("setShortName").toString(),
|
this, -1, xml->attributes().value("setShortName").toString(),
|
||||||
xml->attributes().value("collectorNumber").toString(), xml->attributes().value("uuid").toString());
|
xml->attributes().value("collectorNumber").toString(), xml->attributes().value("uuid").toString());
|
||||||
|
|
|
||||||
|
|
@ -1095,12 +1095,11 @@ Server_AbstractPlayer::cmdCreateToken(const Command_CreateToken &cmd, ResponseCo
|
||||||
arrowInfo->set_start_player_id(player->getPlayerId());
|
arrowInfo->set_start_player_id(player->getPlayerId());
|
||||||
arrowInfo->set_start_zone(startCard->getZone()->getName().toStdString());
|
arrowInfo->set_start_zone(startCard->getZone()->getName().toStdString());
|
||||||
arrowInfo->set_start_card_id(startCard->getId());
|
arrowInfo->set_start_card_id(startCard->getId());
|
||||||
const Server_AbstractPlayer *arrowTargetPlayer =
|
const auto *arrowTargetPlayer = qobject_cast<const Server_AbstractPlayer *>(targetItem);
|
||||||
qobject_cast<const Server_AbstractPlayer *>(targetItem);
|
|
||||||
if (arrowTargetPlayer != nullptr) {
|
if (arrowTargetPlayer != nullptr) {
|
||||||
arrowInfo->set_target_player_id(arrowTargetPlayer->getPlayerId());
|
arrowInfo->set_target_player_id(arrowTargetPlayer->getPlayerId());
|
||||||
} else {
|
} else {
|
||||||
const Server_Card *arrowTargetCard = qobject_cast<const Server_Card *>(targetItem);
|
const auto *arrowTargetCard = qobject_cast<const Server_Card *>(targetItem);
|
||||||
arrowInfo->set_target_player_id(arrowTargetCard->getZone()->getPlayer()->getPlayerId());
|
arrowInfo->set_target_player_id(arrowTargetCard->getZone()->getPlayer()->getPlayerId());
|
||||||
arrowInfo->set_target_zone(arrowTargetCard->getZone()->getName().toStdString());
|
arrowInfo->set_target_zone(arrowTargetCard->getZone()->getName().toStdString());
|
||||||
arrowInfo->set_target_card_id(arrowTargetCard->getId());
|
arrowInfo->set_target_card_id(arrowTargetCard->getId());
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ void Server_Arrow::getInfo(ServerInfo_Arrow *info)
|
||||||
info->set_start_card_id(startCard->getId());
|
info->set_start_card_id(startCard->getId());
|
||||||
info->mutable_arrow_color()->CopyFrom(arrowColor);
|
info->mutable_arrow_color()->CopyFrom(arrowColor);
|
||||||
|
|
||||||
Server_Card *targetCard = qobject_cast<Server_Card *>(targetItem);
|
auto *targetCard = qobject_cast<Server_Card *>(targetItem);
|
||||||
if (targetCard) {
|
if (targetCard) {
|
||||||
info->set_target_player_id(targetCard->getZone()->getPlayer()->getPlayerId());
|
info->set_target_player_id(targetCard->getZone()->getPlayer()->getPlayerId());
|
||||||
info->set_target_zone(targetCard->getZone()->getName().toStdString());
|
info->set_target_zone(targetCard->getZone()->getName().toStdString());
|
||||||
|
|
|
||||||
|
|
@ -589,7 +589,7 @@ void Server_Game::removeArrowsRelatedToPlayer(GameEventStorage &ges, Server_Abst
|
||||||
for (Server_AbstractPlayer *anyPlayer : getPlayers().values()) {
|
for (Server_AbstractPlayer *anyPlayer : getPlayers().values()) {
|
||||||
QList<Server_Arrow *> toDelete;
|
QList<Server_Arrow *> toDelete;
|
||||||
for (auto *arrow : anyPlayer->getArrows().values()) {
|
for (auto *arrow : anyPlayer->getArrows().values()) {
|
||||||
Server_Card *targetCard = qobject_cast<Server_Card *>(arrow->getTargetItem());
|
auto *targetCard = qobject_cast<Server_Card *>(arrow->getTargetItem());
|
||||||
if (targetCard) {
|
if (targetCard) {
|
||||||
if (targetCard->getZone() != nullptr && targetCard->getZone()->getPlayer() == player)
|
if (targetCard->getZone() != nullptr && targetCard->getZone()->getPlayer() == player)
|
||||||
toDelete.append(arrow);
|
toDelete.append(arrow);
|
||||||
|
|
@ -781,7 +781,7 @@ void Server_Game::sendGameEventContainer(GameEventContainer *cont,
|
||||||
GameEventContainer *
|
GameEventContainer *
|
||||||
Server_Game::prepareGameEvent(const ::google::protobuf::Message &gameEvent, int playerId, GameEventContext *context)
|
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);
|
cont->set_game_id(gameId);
|
||||||
if (context)
|
if (context)
|
||||||
cont->mutable_context()->CopyFrom(*context);
|
cont->mutable_context()->CopyFrom(*context);
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@ void Server_AbstractUserInterface::sendProtocolItemByType(ServerMessage::Message
|
||||||
|
|
||||||
SessionEvent *Server_AbstractUserInterface::prepareSessionEvent(const ::google::protobuf::Message &sessionEvent)
|
SessionEvent *Server_AbstractUserInterface::prepareSessionEvent(const ::google::protobuf::Message &sessionEvent)
|
||||||
{
|
{
|
||||||
SessionEvent *event = new SessionEvent;
|
auto *event = new SessionEvent;
|
||||||
event->GetReflection()
|
event->GetReflection()
|
||||||
->MutableMessage(event, sessionEvent.GetDescriptor()->FindExtensionByName("ext"))
|
->MutableMessage(event, sessionEvent.GetDescriptor()->FindExtensionByName("ext"))
|
||||||
->CopyFrom(sessionEvent);
|
->CopyFrom(sessionEvent);
|
||||||
|
|
|
||||||
|
|
@ -473,7 +473,7 @@ Response::ResponseCode Server_ProtocolHandler::cmdLogin(const Command_Login &cmd
|
||||||
|
|
||||||
if (!missingClientFeatures.isEmpty()) {
|
if (!missingClientFeatures.isEmpty()) {
|
||||||
if (features.isRequiredFeaturesMissing(missingClientFeatures, server->getServerRequiredFeatureList())) {
|
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");
|
re->set_denied_reason_str("Client upgrade required");
|
||||||
QMap<QString, bool>::iterator i;
|
QMap<QString, bool>::iterator i;
|
||||||
for (i = missingClientFeatures.begin(); i != missingClientFeatures.end(); ++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);
|
clientId, clientVersion, connectionType);
|
||||||
switch (res) {
|
switch (res) {
|
||||||
case UserIsBanned: {
|
case UserIsBanned: {
|
||||||
Response_Login *re = new Response_Login;
|
auto *re = new Response_Login;
|
||||||
re->set_denied_reason_str(reasonStr.toStdString());
|
re->set_denied_reason_str(reasonStr.toStdString());
|
||||||
if (banSecondsLeft != 0)
|
if (banSecondsLeft != 0)
|
||||||
re->set_denied_end_time(QDateTime::currentDateTime().addSecs(banSecondsLeft).toSecsSinceEpoch());
|
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:
|
case WouldOverwriteOldSession:
|
||||||
return Response::RespWouldOverwriteOldSession;
|
return Response::RespWouldOverwriteOldSession;
|
||||||
case UsernameInvalid: {
|
case UsernameInvalid: {
|
||||||
Response_Login *re = new Response_Login;
|
auto *re = new Response_Login;
|
||||||
re->set_denied_reason_str(reasonStr.toStdString());
|
re->set_denied_reason_str(reasonStr.toStdString());
|
||||||
rc.setResponseExtension(re);
|
rc.setResponseExtension(re);
|
||||||
return Response::RespUsernameInvalid;
|
return Response::RespUsernameInvalid;
|
||||||
|
|
@ -534,7 +534,7 @@ Response::ResponseCode Server_ProtocolHandler::cmdLogin(const Command_Login &cmd
|
||||||
event.set_message(server->getLoginMessage().toStdString());
|
event.set_message(server->getLoginMessage().toStdString());
|
||||||
rc.enqueuePostResponseItem(ServerMessage::SESSION_EVENT, prepareSessionEvent(event));
|
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));
|
re->mutable_user_info()->CopyFrom(copyUserInfo(true));
|
||||||
|
|
||||||
if (authState == PasswordRight) {
|
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.
|
// 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.
|
// The client needs to deal with an empty result list.
|
||||||
|
|
||||||
Response_GetGamesOfUser *re = new Response_GetGamesOfUser;
|
auto *re = new Response_GetGamesOfUser;
|
||||||
server->roomsLock.lockForRead();
|
server->roomsLock.lockForRead();
|
||||||
QMapIterator<int, Server_Room *> roomIterator(server->getRooms());
|
QMapIterator<int, Server_Room *> roomIterator(server->getRooms());
|
||||||
while (roomIterator.hasNext()) {
|
while (roomIterator.hasNext()) {
|
||||||
|
|
@ -640,7 +640,7 @@ Response::ResponseCode Server_ProtocolHandler::cmdGetUserInfo(const Command_GetU
|
||||||
return Response::RespLoginNeeded;
|
return Response::RespLoginNeeded;
|
||||||
|
|
||||||
QString userName = nameFromStdString(cmd.user_name());
|
QString userName = nameFromStdString(cmd.user_name());
|
||||||
Response_GetUserInfo *re = new Response_GetUserInfo;
|
auto *re = new Response_GetUserInfo;
|
||||||
if (userName.isEmpty())
|
if (userName.isEmpty())
|
||||||
re->mutable_user_info()->CopyFrom(*userInfo);
|
re->mutable_user_info()->CopyFrom(*userInfo);
|
||||||
else {
|
else {
|
||||||
|
|
@ -713,7 +713,7 @@ Response::ResponseCode Server_ProtocolHandler::cmdJoinRoom(const Command_JoinRoo
|
||||||
joinMessageEvent.set_message_type(Event_RoomSay::Welcome);
|
joinMessageEvent.set_message_type(Event_RoomSay::Welcome);
|
||||||
rc.enqueuePostResponseItem(ServerMessage::ROOM_EVENT, room->prepareRoomEvent(joinMessageEvent));
|
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);
|
room->getInfo(*re->mutable_room_info(), true);
|
||||||
|
|
||||||
rc.setResponseExtension(re);
|
rc.setResponseExtension(re);
|
||||||
|
|
@ -725,7 +725,7 @@ Response::ResponseCode Server_ProtocolHandler::cmdListUsers(const Command_ListUs
|
||||||
if (authState == NotLoggedIn)
|
if (authState == NotLoggedIn)
|
||||||
return Response::RespLoginNeeded;
|
return Response::RespLoginNeeded;
|
||||||
|
|
||||||
Response_ListUsers *re = new Response_ListUsers;
|
auto *re = new Response_ListUsers;
|
||||||
server->clientsLock.lockForRead();
|
server->clientsLock.lockForRead();
|
||||||
QMapIterator<QString, Server_ProtocolHandler *> userIterator = server->getUsers();
|
QMapIterator<QString, Server_ProtocolHandler *> userIterator = server->getUsers();
|
||||||
while (userIterator.hasNext())
|
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
|
// When server doesn't permit registered users to exist, do not honor only-reg setting
|
||||||
bool onlyRegisteredUsers = cmd.only_registered() && (server->permitUnregisteredUsers());
|
bool onlyRegisteredUsers = cmd.only_registered() && (server->permitUnregisteredUsers());
|
||||||
Server_Game *game = new Server_Game(
|
auto *game = new Server_Game(copyUserInfo(false), gameId, description, QString::fromStdString(cmd.password()),
|
||||||
copyUserInfo(false), gameId, description, QString::fromStdString(cmd.password()), cmd.max_players(), gameTypes,
|
cmd.max_players(), gameTypes, cmd.only_buddies(), onlyRegisteredUsers,
|
||||||
cmd.only_buddies(), onlyRegisteredUsers, cmd.spectators_allowed(), cmd.spectators_need_password(),
|
cmd.spectators_allowed(), cmd.spectators_need_password(), cmd.spectators_can_talk(),
|
||||||
cmd.spectators_can_talk(), cmd.spectators_see_everything(), startingLifeTotal, shareDecklistsOnLoad, room);
|
cmd.spectators_see_everything(), startingLifeTotal, shareDecklistsOnLoad, room);
|
||||||
|
|
||||||
game->addPlayer(this, rc, asSpectator, asJudge, false);
|
game->addPlayer(this, rc, asSpectator, asJudge, false);
|
||||||
room->addGame(game);
|
room->addGame(game);
|
||||||
|
|
|
||||||
|
|
@ -128,7 +128,7 @@ Server_Room::getInfo(ServerInfo_Room &result, bool complete, bool showGameTypes,
|
||||||
|
|
||||||
RoomEvent *Server_Room::prepareRoomEvent(const ::google::protobuf::Message &roomEvent)
|
RoomEvent *Server_Room::prepareRoomEvent(const ::google::protobuf::Message &roomEvent)
|
||||||
{
|
{
|
||||||
RoomEvent *event = new RoomEvent;
|
auto *event = new RoomEvent;
|
||||||
event->set_room_id(id);
|
event->set_room_id(id);
|
||||||
event->GetReflection()
|
event->GetReflection()
|
||||||
->MutableMessage(event, roomEvent.GetDescriptor()->FindExtensionByName("ext"))
|
->MutableMessage(event, roomEvent.GetDescriptor()->FindExtensionByName("ext"))
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
#include "card_database_settings.h"
|
#include "card_database_settings.h"
|
||||||
|
|
||||||
CardDatabaseSettings::CardDatabaseSettings(const QString &settingPath, QObject *parent)
|
CardDatabaseSettings::CardDatabaseSettings(const QString &settingPath, QObject *parent)
|
||||||
: SettingsManager(settingPath + "cardDatabase.ini", parent)
|
: SettingsManager(settingPath + "cardDatabase.ini", QString(), QString(), parent)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,21 +1,21 @@
|
||||||
#include "card_override_settings.h"
|
#include "card_override_settings.h"
|
||||||
|
|
||||||
CardOverrideSettings::CardOverrideSettings(const QString &settingPath, QObject *parent)
|
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)
|
void CardOverrideSettings::setCardPreferenceOverride(const CardRef &cardRef)
|
||||||
{
|
{
|
||||||
setValue(cardRef.providerId, cardRef.name, "cards");
|
setValue(cardRef.providerId, cardRef.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CardOverrideSettings::deleteCardPreferenceOverride(const QString &cardName)
|
void CardOverrideSettings::deleteCardPreferenceOverride(const QString &cardName)
|
||||||
{
|
{
|
||||||
deleteValue(cardName, "cards");
|
deleteValue(cardName);
|
||||||
}
|
}
|
||||||
|
|
||||||
QString CardOverrideSettings::getCardPreferenceOverride(const QString &cardName)
|
QString CardOverrideSettings::getCardPreferenceOverride(const QString &cardName)
|
||||||
{
|
{
|
||||||
return getValue(cardName, "cards").toString();
|
return getValue(cardName).toString();
|
||||||
}
|
}
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
#include <QtCore/QFile>
|
#include <QtCore/QFile>
|
||||||
|
|
||||||
DebugSettings::DebugSettings(const QString &settingPath, QObject *parent)
|
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
|
// Create the default debug.ini if it doesn't exist yet
|
||||||
if (!QFile(settingPath + "debug.ini").exists()) {
|
if (!QFile(settingPath + "debug.ini").exists()) {
|
||||||
|
|
@ -13,7 +13,7 @@ DebugSettings::DebugSettings(const QString &settingPath, QObject *parent)
|
||||||
|
|
||||||
bool DebugSettings::getShowCardId()
|
bool DebugSettings::getShowCardId()
|
||||||
{
|
{
|
||||||
return getValue("showCardId", "debug").toBool();
|
return getValue("showCardId").toBool();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DebugSettings::getLocalGameOnStartup()
|
bool DebugSettings::getLocalGameOnStartup()
|
||||||
|
|
|
||||||
|
|
@ -9,21 +9,21 @@ const QStringList DownloadSettings::DEFAULT_DOWNLOAD_URLS = {
|
||||||
"https://gatherer.wizards.com/Handlers/Image.ashx?name=!name!&type=card"};
|
"https://gatherer.wizards.com/Handlers/Image.ashx?name=!name!&type=card"};
|
||||||
|
|
||||||
DownloadSettings::DownloadSettings(const QString &settingPath, QObject *parent = nullptr)
|
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)
|
void DownloadSettings::setDownloadUrls(const QStringList &downloadURLs)
|
||||||
{
|
{
|
||||||
setValue(QVariant::fromValue(downloadURLs), "urls", "downloads");
|
setValue(QVariant::fromValue(downloadURLs), "urls");
|
||||||
}
|
}
|
||||||
|
|
||||||
QStringList DownloadSettings::getAllURLs()
|
QStringList DownloadSettings::getAllURLs()
|
||||||
{
|
{
|
||||||
return getValue("urls", "downloads").toStringList();
|
return getValue("urls").toStringList();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DownloadSettings::resetToDefaultURLs()
|
void DownloadSettings::resetToDefaultURLs()
|
||||||
{
|
{
|
||||||
setValue(QVariant::fromValue(DEFAULT_DOWNLOAD_URLS), "urls", "downloads");
|
setValue(QVariant::fromValue(DEFAULT_DOWNLOAD_URLS), "urls");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
#include <QTime>
|
#include <QTime>
|
||||||
|
|
||||||
GameFiltersSettings::GameFiltersSettings(const QString &settingPath, QObject *parent)
|
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)
|
void GameFiltersSettings::setHideBuddiesOnlyGames(bool hide)
|
||||||
{
|
{
|
||||||
setValue(hide, "hide_buddies_only_games", "filter_games");
|
setValue(hide, "hide_buddies_only_games");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GameFiltersSettings::isHideBuddiesOnlyGames()
|
bool GameFiltersSettings::isHideBuddiesOnlyGames()
|
||||||
{
|
{
|
||||||
QVariant previous = getValue("hide_buddies_only_games", "filter_games");
|
QVariant previous = getValue("hide_buddies_only_games");
|
||||||
return previous == QVariant() || previous.toBool();
|
return previous == QVariant() || previous.toBool();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameFiltersSettings::setHideFullGames(bool hide)
|
void GameFiltersSettings::setHideFullGames(bool hide)
|
||||||
{
|
{
|
||||||
setValue(hide, "hide_full_games", "filter_games");
|
setValue(hide, "hide_full_games");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GameFiltersSettings::isHideFullGames()
|
bool GameFiltersSettings::isHideFullGames()
|
||||||
{
|
{
|
||||||
QVariant previous = getValue("hide_full_games", "filter_games");
|
QVariant previous = getValue("hide_full_games");
|
||||||
return !(previous == QVariant()) && previous.toBool();
|
return !(previous == QVariant()) && previous.toBool();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameFiltersSettings::setHideGamesThatStarted(bool hide)
|
void GameFiltersSettings::setHideGamesThatStarted(bool hide)
|
||||||
{
|
{
|
||||||
setValue(hide, "hide_games_that_started", "filter_games");
|
setValue(hide, "hide_games_that_started");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GameFiltersSettings::isHideGamesThatStarted()
|
bool GameFiltersSettings::isHideGamesThatStarted()
|
||||||
{
|
{
|
||||||
QVariant previous = getValue("hide_games_that_started", "filter_games");
|
QVariant previous = getValue("hide_games_that_started");
|
||||||
return !(previous == QVariant()) && previous.toBool();
|
return !(previous == QVariant()) && previous.toBool();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameFiltersSettings::setHidePasswordProtectedGames(bool hide)
|
void GameFiltersSettings::setHidePasswordProtectedGames(bool hide)
|
||||||
{
|
{
|
||||||
setValue(hide, "hide_password_protected_games", "filter_games");
|
setValue(hide, "hide_password_protected_games");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GameFiltersSettings::isHidePasswordProtectedGames()
|
bool GameFiltersSettings::isHidePasswordProtectedGames()
|
||||||
{
|
{
|
||||||
QVariant previous = getValue("hide_password_protected_games", "filter_games");
|
QVariant previous = getValue("hide_password_protected_games");
|
||||||
return previous == QVariant() || previous.toBool();
|
return previous == QVariant() || previous.toBool();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameFiltersSettings::setHideIgnoredUserGames(bool hide)
|
void GameFiltersSettings::setHideIgnoredUserGames(bool hide)
|
||||||
{
|
{
|
||||||
setValue(hide, "hide_ignored_user_games", "filter_games");
|
setValue(hide, "hide_ignored_user_games");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GameFiltersSettings::isHideIgnoredUserGames()
|
bool GameFiltersSettings::isHideIgnoredUserGames()
|
||||||
{
|
{
|
||||||
QVariant previous = getValue("hide_ignored_user_games", "filter_games");
|
QVariant previous = getValue("hide_ignored_user_games");
|
||||||
return !(previous == QVariant()) && previous.toBool();
|
return !(previous == QVariant()) && previous.toBool();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameFiltersSettings::setHideNotBuddyCreatedGames(bool hide)
|
void GameFiltersSettings::setHideNotBuddyCreatedGames(bool hide)
|
||||||
{
|
{
|
||||||
setValue(hide, "hide_not_buddy_created_games", "filter_games");
|
setValue(hide, "hide_not_buddy_created_games");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GameFiltersSettings::isHideNotBuddyCreatedGames()
|
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();
|
return !(previous == QVariant()) && previous.toBool();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameFiltersSettings::setHideOpenDecklistGames(bool hide)
|
void GameFiltersSettings::setHideOpenDecklistGames(bool hide)
|
||||||
{
|
{
|
||||||
setValue(hide, "hide_open_decklist_games", "filter_games");
|
setValue(hide, "hide_open_decklist_games");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GameFiltersSettings::isHideOpenDecklistGames()
|
bool GameFiltersSettings::isHideOpenDecklistGames()
|
||||||
{
|
{
|
||||||
QVariant previous = getValue("hide_open_decklist_games", "filter_games");
|
QVariant previous = getValue("hide_open_decklist_games");
|
||||||
return !(previous == QVariant()) && previous.toBool();
|
return !(previous == QVariant()) && previous.toBool();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameFiltersSettings::setGameNameFilter(QString gameName)
|
void GameFiltersSettings::setGameNameFilter(QString gameName)
|
||||||
{
|
{
|
||||||
setValue(gameName, "game_name_filter", "filter_games");
|
setValue(gameName, "game_name_filter");
|
||||||
}
|
}
|
||||||
|
|
||||||
QString GameFiltersSettings::getGameNameFilter()
|
QString GameFiltersSettings::getGameNameFilter()
|
||||||
{
|
{
|
||||||
return getValue("game_name_filter", "filter_games").toString();
|
return getValue("game_name_filter").toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameFiltersSettings::setCreatorNameFilter(QString creatorName)
|
void GameFiltersSettings::setCreatorNameFilter(QString creatorName)
|
||||||
{
|
{
|
||||||
setValue(creatorName, "creator_name_filter", "filter_games");
|
setValue(creatorName, "creator_name_filter");
|
||||||
}
|
}
|
||||||
|
|
||||||
QString GameFiltersSettings::getCreatorNameFilter()
|
QString GameFiltersSettings::getCreatorNameFilter()
|
||||||
{
|
{
|
||||||
return getValue("creator_name_filter", "filter_games").toString();
|
return getValue("creator_name_filter").toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameFiltersSettings::setMinPlayers(int min)
|
void GameFiltersSettings::setMinPlayers(int min)
|
||||||
{
|
{
|
||||||
setValue(min, "min_players", "filter_games");
|
setValue(min, "min_players");
|
||||||
}
|
}
|
||||||
|
|
||||||
int GameFiltersSettings::getMinPlayers()
|
int GameFiltersSettings::getMinPlayers()
|
||||||
{
|
{
|
||||||
QVariant previous = getValue("min_players", "filter_games");
|
QVariant previous = getValue("min_players");
|
||||||
return previous == QVariant() ? 1 : previous.toInt();
|
return previous == QVariant() ? 1 : previous.toInt();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameFiltersSettings::setMaxPlayers(int max)
|
void GameFiltersSettings::setMaxPlayers(int max)
|
||||||
{
|
{
|
||||||
setValue(max, "max_players", "filter_games");
|
setValue(max, "max_players");
|
||||||
}
|
}
|
||||||
|
|
||||||
int GameFiltersSettings::getMaxPlayers()
|
int GameFiltersSettings::getMaxPlayers()
|
||||||
{
|
{
|
||||||
QVariant previous = getValue("max_players", "filter_games");
|
QVariant previous = getValue("max_players");
|
||||||
return previous == QVariant() ? 99 : previous.toInt();
|
return previous == QVariant() ? 99 : previous.toInt();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameFiltersSettings::setMaxGameAge(const QTime &maxGameAge)
|
void GameFiltersSettings::setMaxGameAge(const QTime &maxGameAge)
|
||||||
{
|
{
|
||||||
setValue(maxGameAge, "max_game_age_time", "filter_games");
|
setValue(maxGameAge, "max_game_age_time");
|
||||||
}
|
}
|
||||||
|
|
||||||
QTime GameFiltersSettings::getMaxGameAge()
|
QTime GameFiltersSettings::getMaxGameAge()
|
||||||
{
|
{
|
||||||
QVariant previous = getValue("max_game_age_time", "filter_games");
|
QVariant previous = getValue("max_game_age_time");
|
||||||
return previous.toTime();
|
return previous.toTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameFiltersSettings::setGameTypeEnabled(QString gametype, bool enabled)
|
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)
|
void GameFiltersSettings::setGameHashedTypeEnabled(QString gametypeHASHED, bool enabled)
|
||||||
{
|
{
|
||||||
setValue(enabled, gametypeHASHED, "filter_games");
|
setValue(enabled, gametypeHASHED);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GameFiltersSettings::isGameTypeEnabled(QString gametype)
|
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();
|
return previous == QVariant() ? false : previous.toBool();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameFiltersSettings::setShowOnlyIfSpectatorsCanWatch(bool show)
|
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()
|
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();
|
return previous == QVariant() ? false : previous.toBool();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameFiltersSettings::setShowSpectatorPasswordProtected(bool show)
|
void GameFiltersSettings::setShowSpectatorPasswordProtected(bool show)
|
||||||
{
|
{
|
||||||
setValue(show, "show_spectator_password_protected", "filter_games");
|
setValue(show, "show_spectator_password_protected");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GameFiltersSettings::isShowSpectatorPasswordProtected()
|
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();
|
return previous == QVariant() ? true : previous.toBool();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameFiltersSettings::setShowOnlyIfSpectatorsCanChat(bool show)
|
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()
|
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();
|
return previous == QVariant() ? true : previous.toBool();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameFiltersSettings::setShowOnlyIfSpectatorsCanSeeHands(bool show)
|
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()
|
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();
|
return previous == QVariant() ? true : previous.toBool();
|
||||||
}
|
}
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
#include "layouts_settings.h"
|
#include "layouts_settings.h"
|
||||||
|
|
||||||
LayoutsSettings::LayoutsSettings(const QString &settingPath, QObject *parent)
|
LayoutsSettings::LayoutsSettings(const QString &settingPath, QObject *parent)
|
||||||
: SettingsManager(settingPath + "layouts.ini", parent)
|
: SettingsManager(settingPath + "layouts.ini", "layouts", QString(), parent)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,26 +1,26 @@
|
||||||
#include "message_settings.h"
|
#include "message_settings.h"
|
||||||
|
|
||||||
MessageSettings::MessageSettings(const QString &settingPath, QObject *parent)
|
MessageSettings::MessageSettings(const QString &settingPath, QObject *parent)
|
||||||
: SettingsManager(settingPath + "messages.ini", parent)
|
: SettingsManager(settingPath + "messages.ini", "messages", QString(), parent)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
QString MessageSettings::getMessageAt(int index)
|
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()
|
int MessageSettings::getCount()
|
||||||
{
|
{
|
||||||
return getValue("count", "messages").toInt();
|
return getValue("count").toInt();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MessageSettings::setCount(int count)
|
void MessageSettings::setCount(int count)
|
||||||
{
|
{
|
||||||
setValue(count, "count", "messages");
|
setValue(count, "count");
|
||||||
}
|
}
|
||||||
|
|
||||||
void MessageSettings::setMessageAt(int index, QString message)
|
void MessageSettings::setMessageAt(int index, QString message)
|
||||||
{
|
{
|
||||||
setValue(message, QString("msg%1").arg(index), "messages");
|
setValue(message, QString("msg%1").arg(index));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,22 +3,22 @@
|
||||||
#define MAX_RECENT_DECK_COUNT 10
|
#define MAX_RECENT_DECK_COUNT 10
|
||||||
|
|
||||||
RecentsSettings::RecentsSettings(const QString &settingPath, QObject *parent)
|
RecentsSettings::RecentsSettings(const QString &settingPath, QObject *parent)
|
||||||
: SettingsManager(settingPath + "recents.ini", parent)
|
: SettingsManager(settingPath + "recents.ini", "deckbuilder", QString(), parent)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
QStringList RecentsSettings::getRecentlyOpenedDeckPaths()
|
QStringList RecentsSettings::getRecentlyOpenedDeckPaths()
|
||||||
{
|
{
|
||||||
return getValue("deckpaths", "deckbuilder").toStringList();
|
return getValue("deckpaths").toStringList();
|
||||||
}
|
}
|
||||||
void RecentsSettings::clearRecentlyOpenedDeckPaths()
|
void RecentsSettings::clearRecentlyOpenedDeckPaths()
|
||||||
{
|
{
|
||||||
deleteValue("deckpaths", "deckbuilder");
|
deleteValue("deckpaths");
|
||||||
emit recentlyOpenedDeckPathsChanged();
|
emit recentlyOpenedDeckPathsChanged();
|
||||||
}
|
}
|
||||||
void RecentsSettings::updateRecentlyOpenedDeckPaths(const QString &deckPath)
|
void RecentsSettings::updateRecentlyOpenedDeckPaths(const QString &deckPath)
|
||||||
{
|
{
|
||||||
auto deckPaths = getValue("deckpaths", "deckbuilder").toStringList();
|
auto deckPaths = getValue("deckpaths").toStringList();
|
||||||
deckPaths.removeAll(deckPath);
|
deckPaths.removeAll(deckPath);
|
||||||
|
|
||||||
deckPaths.prepend(deckPath);
|
deckPaths.prepend(deckPath);
|
||||||
|
|
@ -27,7 +27,7 @@ void RecentsSettings::updateRecentlyOpenedDeckPaths(const QString &deckPath)
|
||||||
deckPaths.removeLast();
|
deckPaths.removeLast();
|
||||||
}
|
}
|
||||||
|
|
||||||
setValue(deckPaths, "deckpaths", "deckbuilder");
|
setValue(deckPaths, "deckpaths");
|
||||||
emit recentlyOpenedDeckPathsChanged();
|
emit recentlyOpenedDeckPathsChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,34 +4,34 @@
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
ServersSettings::ServersSettings(const QString &settingPath, QObject *parent)
|
ServersSettings::ServersSettings(const QString &settingPath, QObject *parent)
|
||||||
: SettingsManager(settingPath + "servers.ini", parent)
|
: SettingsManager(settingPath + "servers.ini", "server", QString(), parent)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void ServersSettings::setPreviousHostLogin(int previous)
|
void ServersSettings::setPreviousHostLogin(int previous)
|
||||||
{
|
{
|
||||||
setValue(previous, "previoushostlogin", "server");
|
setValue(previous, "previoushostlogin");
|
||||||
}
|
}
|
||||||
|
|
||||||
int ServersSettings::getPreviousHostLogin()
|
int ServersSettings::getPreviousHostLogin()
|
||||||
{
|
{
|
||||||
QVariant previous = getValue("previoushostlogin", "server");
|
QVariant previous = getValue("previoushostlogin");
|
||||||
return previous == QVariant() ? 1 : previous.toInt();
|
return previous == QVariant() ? 1 : previous.toInt();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ServersSettings::setPreviousHostList(QStringList list)
|
void ServersSettings::setPreviousHostList(QStringList list)
|
||||||
{
|
{
|
||||||
setValue(list, "previoushosts", "server");
|
setValue(list, "previoushosts");
|
||||||
}
|
}
|
||||||
|
|
||||||
QStringList ServersSettings::getPreviousHostList()
|
QStringList ServersSettings::getPreviousHostList()
|
||||||
{
|
{
|
||||||
return getValue("previoushosts", "server").toStringList();
|
return getValue("previoushosts").toStringList();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ServersSettings::setPrevioushostName(const QString &name)
|
void ServersSettings::setPrevioushostName(const QString &name)
|
||||||
{
|
{
|
||||||
setValue(name, "previoushostName", "server");
|
setValue(name, "previoushostName");
|
||||||
}
|
}
|
||||||
|
|
||||||
QString ServersSettings::getSaveName(QString defaultname)
|
QString ServersSettings::getSaveName(QString defaultname)
|
||||||
|
|
@ -50,7 +50,7 @@ QString ServersSettings::getSite(QString defaultSite)
|
||||||
|
|
||||||
QString ServersSettings::getPrevioushostName()
|
QString ServersSettings::getPrevioushostName()
|
||||||
{
|
{
|
||||||
QVariant value = getValue("previoushostName", "server");
|
QVariant value = getValue("previoushostName");
|
||||||
return value == QVariant() ? "Rooster Ranges" : value.toString();
|
return value == QVariant() ? "Rooster Ranges" : value.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -107,56 +107,56 @@ bool ServersSettings::getSavePassword()
|
||||||
|
|
||||||
void ServersSettings::setAutoConnect(int autoconnect)
|
void ServersSettings::setAutoConnect(int autoconnect)
|
||||||
{
|
{
|
||||||
setValue(autoconnect, "auto_connect", "server");
|
setValue(autoconnect, "auto_connect");
|
||||||
}
|
}
|
||||||
|
|
||||||
int ServersSettings::getAutoConnect()
|
int ServersSettings::getAutoConnect()
|
||||||
{
|
{
|
||||||
QVariant autoconnect = getValue("auto_connect", "server");
|
QVariant autoconnect = getValue("auto_connect");
|
||||||
return autoconnect == QVariant() ? 0 : autoconnect.toInt();
|
return autoconnect == QVariant() ? 0 : autoconnect.toInt();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ServersSettings::setFPHostName(QString hostname)
|
void ServersSettings::setFPHostName(QString hostname)
|
||||||
{
|
{
|
||||||
setValue(hostname, "fphostname", "server");
|
setValue(hostname, "fphostname");
|
||||||
}
|
}
|
||||||
|
|
||||||
QString ServersSettings::getFPHostname(QString defaultHost)
|
QString ServersSettings::getFPHostname(QString defaultHost)
|
||||||
{
|
{
|
||||||
QVariant hostname = getValue("fphostname", "server");
|
QVariant hostname = getValue("fphostname");
|
||||||
return hostname == QVariant() ? std::move(defaultHost) : hostname.toString();
|
return hostname == QVariant() ? std::move(defaultHost) : hostname.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ServersSettings::setFPPort(QString port)
|
void ServersSettings::setFPPort(QString port)
|
||||||
{
|
{
|
||||||
setValue(port, "fpport", "server");
|
setValue(port, "fpport");
|
||||||
}
|
}
|
||||||
|
|
||||||
QString ServersSettings::getFPPort(QString defaultPort)
|
QString ServersSettings::getFPPort(QString defaultPort)
|
||||||
{
|
{
|
||||||
QVariant port = getValue("fpport", "server");
|
QVariant port = getValue("fpport");
|
||||||
return port == QVariant() ? std::move(defaultPort) : port.toString();
|
return port == QVariant() ? std::move(defaultPort) : port.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ServersSettings::setFPPlayerName(QString playerName)
|
void ServersSettings::setFPPlayerName(QString playerName)
|
||||||
{
|
{
|
||||||
setValue(playerName, "fpplayername", "server");
|
setValue(playerName, "fpplayername");
|
||||||
}
|
}
|
||||||
|
|
||||||
QString ServersSettings::getFPPlayerName(QString defaultName)
|
QString ServersSettings::getFPPlayerName(QString defaultName)
|
||||||
{
|
{
|
||||||
QVariant name = getValue("fpplayername", "server");
|
QVariant name = getValue("fpplayername");
|
||||||
return name == QVariant() ? std::move(defaultName) : name.toString();
|
return name == QVariant() ? std::move(defaultName) : name.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ServersSettings::setClearDebugLogStatus(bool abIsChecked)
|
void ServersSettings::setClearDebugLogStatus(bool abIsChecked)
|
||||||
{
|
{
|
||||||
setValue(abIsChecked, "save_debug_log", "server");
|
setValue(abIsChecked, "save_debug_log");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ServersSettings::getClearDebugLogStatus(bool abDefaultValue)
|
bool ServersSettings::getClearDebugLogStatus(bool abDefaultValue)
|
||||||
{
|
{
|
||||||
QVariant cbFlushLog = getValue("save_debug_log", "server");
|
QVariant cbFlushLog = getValue("save_debug_log");
|
||||||
return cbFlushLog == QVariant() ? abDefaultValue : cbFlushLog.toBool();
|
return cbFlushLog == QVariant() ? abDefaultValue : cbFlushLog.toBool();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,35 @@
|
||||||
#include "settings_manager.h"
|
#include "settings_manager.h"
|
||||||
|
|
||||||
SettingsManager::SettingsManager(const QString &settingPath, QObject *parent)
|
SettingsManager::SettingsManager(const QString &settingPath,
|
||||||
: QObject(parent), settings(settingPath, QSettings::IniFormat)
|
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,
|
void SettingsManager::setValue(const QVariant &value,
|
||||||
const QString &name,
|
const QString &name,
|
||||||
const QString &group,
|
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)
|
void SettingsManager::deleteValue(const QString &name, const QString &group, const QString &subGroup)
|
||||||
{
|
{
|
||||||
if (!group.isEmpty()) {
|
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)
|
QVariant SettingsManager::getValue(const QString &name, const QString &group, const QString &subGroup)
|
||||||
{
|
{
|
||||||
if (!group.isEmpty()) {
|
if (!group.isEmpty()) {
|
||||||
|
|
|
||||||
|
|
@ -16,14 +16,23 @@ class SettingsManager : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit SettingsManager(const QString &settingPath, QObject *parent = nullptr);
|
explicit SettingsManager(const QString &settingPath,
|
||||||
QVariant getValue(const QString &name, const QString &group = "", const QString &subGroup = "");
|
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();
|
void sync();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
QSettings settings;
|
QSettings settings;
|
||||||
void setValue(const QVariant &value, const QString &name, const QString &group = "", const QString &subGroup = "");
|
QString defaultGroup;
|
||||||
void deleteValue(const QString &name, const QString &group = "", const QString &subGroup = "");
|
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
|
#endif // SETTINGSMANAGER_H
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ set(oracle_SOURCES
|
||||||
src/main.cpp
|
src/main.cpp
|
||||||
src/oraclewizard.cpp
|
src/oraclewizard.cpp
|
||||||
src/oracleimporter.cpp
|
src/oracleimporter.cpp
|
||||||
|
src/pages.cpp
|
||||||
src/pagetemplates.cpp
|
src/pagetemplates.cpp
|
||||||
src/parsehelpers.cpp
|
src/parsehelpers.cpp
|
||||||
src/qt-json/json.cpp
|
src/qt-json/json.cpp
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
#include "oracleimporter.h"
|
#include "oracleimporter.h"
|
||||||
|
|
||||||
#include "client/settings/cache_settings.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 "parsehelpers.h"
|
||||||
#include "qt-json/json.h"
|
#include "qt-json/json.h"
|
||||||
|
|
||||||
|
|
@ -8,7 +10,6 @@
|
||||||
#include <QRegularExpression>
|
#include <QRegularExpression>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <climits>
|
#include <climits>
|
||||||
#include <database/interface/settings_card_preference_provider.h>
|
|
||||||
#include <libcockatrice/card/database/parser/cockatrice_xml_4.h>
|
#include <libcockatrice/card/database/parser/cockatrice_xml_4.h>
|
||||||
#include <libcockatrice/card/relation/card_relation.h>
|
#include <libcockatrice/card/relation/card_relation.h>
|
||||||
|
|
||||||
|
|
@ -457,14 +458,17 @@ int OracleImporter::importCardsFromSet(const CardSetPtr ¤tSet, const QList
|
||||||
|
|
||||||
int OracleImporter::startImport()
|
int OracleImporter::startImport()
|
||||||
{
|
{
|
||||||
int setIndex = 0;
|
static ICardSetPriorityController *noOpController = new NoopCardSetPriorityController();
|
||||||
|
|
||||||
// add an empty set for tokens
|
// add an empty set for tokens
|
||||||
CardSetPtr tokenSet = CardSet::newInstance(SettingsCache::instance().cardDatabase(), CardSet::TOKENS_SETNAME,
|
CardSetPtr tokenSet =
|
||||||
tr("Dummy set containing tokens"), "Tokens");
|
CardSet::newInstance(noOpController, CardSet::TOKENS_SETNAME, tr("Dummy set containing tokens"), "Tokens");
|
||||||
sets.insert(CardSet::TOKENS_SETNAME, tokenSet);
|
sets.insert(CardSet::TOKENS_SETNAME, tokenSet);
|
||||||
|
|
||||||
|
int setIndex = 0;
|
||||||
|
|
||||||
for (const SetToDownload &curSetToParse : allSets) {
|
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.getLongName(), curSetToParse.getSetType(),
|
||||||
curSetToParse.getReleaseDate(), curSetToParse.getPriority());
|
curSetToParse.getReleaseDate(), curSetToParse.getPriority());
|
||||||
if (!sets.contains(newSet->getShortName()))
|
if (!sets.contains(newSet->getShortName()))
|
||||||
|
|
@ -485,7 +489,7 @@ int OracleImporter::startImport()
|
||||||
|
|
||||||
bool OracleImporter::saveToFile(const QString &fileName, const QString &sourceUrl, const QString &sourceVersion)
|
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);
|
return parser.saveToFile(sets, cards, fileName, sourceUrl, sourceVersion);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,55 +3,19 @@
|
||||||
#include "client/settings/cache_settings.h"
|
#include "client/settings/cache_settings.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "oracleimporter.h"
|
#include "oracleimporter.h"
|
||||||
#include "version_string.h"
|
#include "pages.h"
|
||||||
|
#include "pagetemplates.h"
|
||||||
|
|
||||||
#include <QAbstractButton>
|
|
||||||
#include <QBuffer>
|
|
||||||
#include <QCheckBox>
|
#include <QCheckBox>
|
||||||
#include <QComboBox>
|
|
||||||
#include <QDir>
|
|
||||||
#include <QFileDialog>
|
#include <QFileDialog>
|
||||||
#include <QGridLayout>
|
#include <QGridLayout>
|
||||||
#include <QLabel>
|
|
||||||
#include <QLineEdit>
|
#include <QLineEdit>
|
||||||
#include <QMessageBox>
|
|
||||||
#include <QNetworkAccessManager>
|
|
||||||
#include <QNetworkReply>
|
#include <QNetworkReply>
|
||||||
#include <QProgressBar>
|
|
||||||
#include <QPushButton>
|
#include <QPushButton>
|
||||||
#include <QRadioButton>
|
|
||||||
#include <QScrollBar>
|
#include <QScrollBar>
|
||||||
#include <QStandardPaths>
|
|
||||||
#include <QTextEdit>
|
|
||||||
#include <QtConcurrent>
|
#include <QtConcurrent>
|
||||||
#include <QtGui>
|
#include <QtGui>
|
||||||
|
|
||||||
#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)
|
OracleWizard::OracleWizard(QWidget *parent) : QWizard(parent)
|
||||||
{
|
{
|
||||||
// define a dummy context that will be used where needed
|
// define a dummy context that will be used where needed
|
||||||
|
|
@ -142,669 +106,3 @@ bool OracleWizard::saveTokensToFile(const QString &fileName)
|
||||||
file.close();
|
file.close();
|
||||||
return true;
|
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<int>(&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.") + "<br>" +
|
|
||||||
tr("You can now start using Cockatrice with the newly updated cards.") + "<br><br>" +
|
|
||||||
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<bool>::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<int>(total));
|
|
||||||
progressBar->setValue(static_cast<int>(received));
|
|
||||||
}
|
|
||||||
progressLabel->setText(tr("Downloading (%1MB)").arg((int)received / (1024 * 1024)));
|
|
||||||
}
|
|
||||||
|
|
||||||
void LoadSetsPage::actDownloadFinishedSetsFile()
|
|
||||||
{
|
|
||||||
// check for a reply
|
|
||||||
auto *reply = dynamic_cast<QNetworkReply *>(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::StandardButton>(QMessageBox::question(
|
|
||||||
this, tr("Error"), message + "<br>" + 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:") + "<br>" +
|
|
||||||
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("<b>" + tr("Import finished: %1 cards.").arg(wizard()->importer->getCardList().size()) +
|
|
||||||
"</b>");
|
|
||||||
} 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:") + "<br>" +
|
|
||||||
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:") + "<br>" +
|
|
||||||
SettingsCache::instance().getSpoilerCardDatabasePath());
|
|
||||||
defaultPathCheckBox->setText(tr("Save to a custom path (not recommended)"));
|
|
||||||
}
|
|
||||||
|
|
|
||||||