[Card DB] Split out database loading and querying from main class (#6175)

* Simplify add card.

Took 25 minutes

Took 8 minutes

# Commit time for manual adjustment:
# Took 16 minutes

Took 7 seconds

* Refactor out db loading from card db.

Took 39 minutes

Took 9 minutes

Took 2 minutes


Took 17 seconds

* Refactor out db queries from card db.

Took 42 minutes

* Lint.

Took 3 minutes

* I guess.

Took 7 minutes

* Tests.

Took 15 minutes

* I don't understand this.

Took 9 minutes

* fix linker errors

* Rename to querier and promote to QObject

Took 39 minutes

* Lint.

Took 3 minutes

---------

Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
Co-authored-by: ebbit1q <ebbit1q@gmail.com>
This commit is contained in:
BruebachL 2025-09-27 00:27:15 +02:00 committed by GitHub
parent 754dd904d2
commit d31b044529
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
49 changed files with 719 additions and 572 deletions

View file

@ -22,7 +22,9 @@ set(cockatrice_SOURCES
src/client/tapped_out_interface.cpp src/client/tapped_out_interface.cpp
src/client/update_downloader.cpp src/client/update_downloader.cpp
src/database/card_database.cpp src/database/card_database.cpp
src/database/card_database_loader.cpp
src/database/card_database_manager.cpp src/database/card_database_manager.cpp
src/database/card_database_querier.cpp
src/database/model/card_database_model.cpp src/database/model/card_database_model.cpp
src/database/model/card_database_display_model.cpp src/database/model/card_database_display_model.cpp
src/database/model/card/card_completer_proxy_model.cpp src/database/model/card/card_completer_proxy_model.cpp

View file

@ -96,7 +96,7 @@ void TappedOutInterface::analyzeDeck(DeckList *deck)
void TappedOutInterface::copyDeckSplitMainAndSide(DeckList &source, DeckList &mainboard, DeckList &sideboard) void TappedOutInterface::copyDeckSplitMainAndSide(DeckList &source, DeckList &mainboard, DeckList &sideboard)
{ {
auto copyMainOrSide = [this, &mainboard, &sideboard](const auto node, const auto card) { auto copyMainOrSide = [this, &mainboard, &sideboard](const auto node, const auto card) {
CardInfoPtr dbCard = cardDatabase.getCardInfo(card->getName()); CardInfoPtr dbCard = cardDatabase.query()->getCardInfo(card->getName());
if (!dbCard || dbCard->getIsToken()) if (!dbCard || dbCard->getIsToken())
return; return;

View file

@ -2,7 +2,6 @@
#include "../picture_loader/picture_loader.h" #include "../picture_loader/picture_loader.h"
#include "../settings/cache_settings.h" #include "../settings/cache_settings.h"
#include "../utility/card_set_comparator.h"
#include "parser/cockatrice_xml_3.h" #include "parser/cockatrice_xml_3.h"
#include "parser/cockatrice_xml_4.h" #include "parser/cockatrice_xml_4.h"
@ -14,7 +13,6 @@
#include <QMessageBox> #include <QMessageBox>
#include <QRegularExpression> #include <QRegularExpression>
#include <algorithm> #include <algorithm>
#include <qrandom.h>
#include <utility> #include <utility>
CardDatabase::CardDatabase(QObject *parent) : QObject(parent), loadStatus(NotLoaded) CardDatabase::CardDatabase(QObject *parent) : QObject(parent), loadStatus(NotLoaded)
@ -22,23 +20,20 @@ CardDatabase::CardDatabase(QObject *parent) : QObject(parent), loadStatus(NotLoa
qRegisterMetaType<CardInfoPtr>("CardInfoPtr"); qRegisterMetaType<CardInfoPtr>("CardInfoPtr");
qRegisterMetaType<CardInfoPtr>("CardSetPtr"); qRegisterMetaType<CardInfoPtr>("CardSetPtr");
// add new parsers here // create loader and wire it up
availableParsers << new CockatriceXml4Parser; loader = new CardDatabaseLoader(this, this);
availableParsers << new CockatriceXml3Parser; // re-emit loader signals (so other code doesn't need to know about internals)
connect(loader, &CardDatabaseLoader::loadingFinished, this, &CardDatabase::cardDatabaseLoadingFinished);
connect(loader, &CardDatabaseLoader::loadingFailed, this, &CardDatabase::cardDatabaseLoadingFailed);
connect(loader, &CardDatabaseLoader::newSetsFound, this, &CardDatabase::cardDatabaseNewSetsFound);
connect(loader, &CardDatabaseLoader::allNewSetsEnabled, this, &CardDatabase::cardDatabaseAllNewSetsEnabled);
for (auto &parser : availableParsers) { querier = new CardDatabaseQuerier(this, this);
connect(parser, &ICardDatabaseParser::addCard, this, &CardDatabase::addCard, Qt::DirectConnection);
connect(parser, &ICardDatabaseParser::addSet, this, &CardDatabase::addSet, Qt::DirectConnection);
}
connect(&SettingsCache::instance(), &SettingsCache::cardDatabasePathChanged, this,
&CardDatabase::loadCardDatabases);
} }
CardDatabase::~CardDatabase() CardDatabase::~CardDatabase()
{ {
clear(); clear();
qDeleteAll(availableParsers);
} }
void CardDatabase::clear() void CardDatabase::clear()
@ -60,91 +55,14 @@ void CardDatabase::clear()
loadStatus = NotLoaded; loadStatus = NotLoaded;
} }
LoadStatus CardDatabase::loadFromFile(const QString &fileName) void CardDatabase::loadCardDatabases()
{ {
QFile file(fileName); loadStatus = loader->loadCardDatabases();
file.open(QIODevice::ReadOnly);
if (!file.isOpen()) {
return FileError;
}
for (auto parser : availableParsers) {
file.reset();
if (parser->getCanParseFile(fileName, file)) {
file.reset();
parser->parseFile(file);
return Ok;
}
}
return Invalid;
} }
LoadStatus CardDatabase::loadCardDatabase(const QString &path) bool CardDatabase::saveCustomTokensToFile()
{ {
auto startTime = QTime::currentTime(); return loader->saveCustomTokensToFile();
LoadStatus tempLoadStatus = NotLoaded;
if (!path.isEmpty()) {
QMutexLocker locker(loadFromFileMutex);
tempLoadStatus = loadFromFile(path);
}
int msecs = startTime.msecsTo(QTime::currentTime());
qCInfo(CardDatabaseLoadingLog) << "Loaded card database: Path =" << path << "Status =" << tempLoadStatus
<< "Cards =" << cards.size() << "Sets =" << sets.size()
<< QString("%1ms").arg(msecs);
return tempLoadStatus;
}
LoadStatus CardDatabase::loadCardDatabases()
{
QMutexLocker locker(reloadDatabaseMutex);
qCInfo(CardDatabaseLoadingLog) << "Card Database Loading Started";
clear(); // remove old db
loadStatus = loadCardDatabase(SettingsCache::instance().getCardDatabasePath()); // load main card database
loadCardDatabase(SettingsCache::instance().getTokenDatabasePath()); // load tokens database
loadCardDatabase(SettingsCache::instance().getSpoilerCardDatabasePath()); // load spoilers database
// find all custom card databases, recursively & following symlinks
// then load them alphabetically
auto customPaths = collectCustomDatabasePaths();
for (int i = 0, n = customPaths.size(); i < n; ++i) {
const auto &path = customPaths.at(i);
qCInfo(CardDatabaseLoadingLog) << "Loading Custom Set" << i << "(" << path << ")";
loadCardDatabase(path);
}
// AFTER all the cards have been loaded
// resolve the reverse-related tags
refreshCachedReverseRelatedCards();
if (loadStatus == Ok) {
checkUnknownSets(); // update deck editors, etc
qCInfo(CardDatabaseLoadingSuccessOrFailureLog) << "Card Database Loading Success";
emit cardDatabaseLoadingFinished();
} else {
qCInfo(CardDatabaseLoadingSuccessOrFailureLog) << "Card Database Loading Failed";
emit cardDatabaseLoadingFailed(); // bring up the settings dialog
}
return loadStatus;
}
QStringList CardDatabase::collectCustomDatabasePaths()
{
QDirIterator it(SettingsCache::instance().getCustomCardDatabasePath(), {"*.xml"}, QDir::Files,
QDirIterator::Subdirectories | QDirIterator::FollowSymlinks);
QStringList paths;
while (it.hasNext())
paths << it.next();
paths.sort();
return paths;
} }
void CardDatabase::refreshCachedReverseRelatedCards() void CardDatabase::refreshCachedReverseRelatedCards()
@ -210,135 +128,9 @@ void CardDatabase::removeCard(CardInfoPtr card)
emit cardRemoved(card); emit cardRemoved(card);
} }
/** void CardDatabase::addSet(CardSetPtr set)
* Looks up the cardInfo corresponding to the cardName.
*
* @param cardName The card name to look up
* @return A CardInfoPtr, or null if not corresponding CardInfo is found.
*/
CardInfoPtr CardDatabase::getCardInfo(const QString &cardName) const
{ {
return cards.value(cardName); sets.insert(set->getShortName(), set);
}
/**
* Looks up the cardInfos for a list of card names.
*
* @param cardNames The card names to look up
* @return A List of CardInfoPtr. Any failed lookups will be ignored and dropped from the resulting list
*/
QList<CardInfoPtr> CardDatabase::getCardInfos(const QStringList &cardNames) const
{
QList<CardInfoPtr> cardInfos;
for (const QString &cardName : cardNames) {
CardInfoPtr ptr = cards.value(cardName);
if (ptr)
cardInfos.append(ptr);
}
return cardInfos;
}
/**
* Looks up the cards corresponding to the CardRefs.
* If the providerId is empty, will default to the preferred printing.
* If providerId is given but not found, the PrintingInfo will be empty.
*
* @param cardRefs The cards to look up. If providerId is empty for an entry, will default to the preferred printing for
* that entry. If providerId is given but not found, the PrintingInfo will be empty for that entry.
* @return A list of cards. Any failed lookups will be ignored and dropped from the resulting list.
*/
QList<ExactCard> CardDatabase::getCards(const QList<CardRef> &cardRefs) const
{
QList<ExactCard> cards;
for (const auto &cardRef : cardRefs) {
ExactCard card = getCard(cardRef);
if (card)
cards.append(card);
}
return cards;
}
/**
* Looks up the card corresponding to the CardRef.
* If the providerId is empty, will default to the preferred printing.
* If providerId is given but not found, the PrintingInfo will be empty.
*
* @param cardRef The card to look up.
* @return A specific printing of a card, or empty if not found.
*/
ExactCard CardDatabase::getCard(const CardRef &cardRef) const
{
auto info = getCardInfo(cardRef.name);
if (info.isNull()) {
return {};
}
if (cardRef.providerId.isEmpty() || cardRef.providerId.isNull()) {
return ExactCard(info, getPreferredPrinting(info));
}
return ExactCard(info, findPrintingWithId(info, cardRef.providerId));
}
CardInfoPtr CardDatabase::getCardBySimpleName(const QString &cardName) const
{
return simpleNameCards.value(CardInfo::simplifyName(cardName));
}
CardInfoPtr CardDatabase::lookupCardByName(const QString &name) const
{
if (auto info = getCardInfo(name))
return info;
if (auto info = getCardBySimpleName(name))
return info;
return getCardBySimpleName(CardInfo::simplifyName(name));
}
/**
* Looks up the card by CardRef, simplifying the name if required.
* If the providerId is empty, will default to the preferred printing.
* If providerId is given but not found, the PrintingInfo will be empty.
*
* @param cardRef The card to look up.
* @return A specific printing of a card, or empty if not found.
*/
ExactCard CardDatabase::guessCard(const CardRef &cardRef) const
{
auto card = lookupCardByName(cardRef.name);
auto printing =
cardRef.providerId.isEmpty() ? getPreferredPrinting(card) : findPrintingWithId(card, cardRef.providerId);
return ExactCard(card, printing);
}
ExactCard CardDatabase::getRandomCard()
{
if (cards.isEmpty())
return {};
const auto keys = cards.keys();
int randomIndex = QRandomGenerator::global()->bounded(keys.size());
const QString &randomKey = keys.at(randomIndex);
CardInfoPtr randomCard = getCardInfo(randomKey);
return ExactCard{randomCard, getPreferredPrinting(randomCard)};
}
ExactCard CardDatabase::getCardFromSameSet(const QString &cardName, const PrintingInfo &otherPrinting) const
{
// The source card does not have a printing defined, which means we can't get a card from the same set.
if (otherPrinting == PrintingInfo()) {
return getCard({cardName});
}
// The source card does have a printing defined, which means we can attempt to get a card from the same set.
PrintingInfo relatedPrinting = getSpecificPrinting(cardName, otherPrinting.getSet()->getCorrectedShortName(), "");
ExactCard relatedCard(guessCard({cardName}).getCardPtr(), relatedPrinting);
// If we didn't find a card from the same set, just try to find any card with the same name.
return relatedCard ? relatedCard : getCard({cardName});
} }
CardSetPtr CardDatabase::getSet(const QString &setName) CardSetPtr CardDatabase::getSet(const QString &setName)
@ -352,11 +144,6 @@ CardSetPtr CardDatabase::getSet(const QString &setName)
} }
} }
void CardDatabase::addSet(CardSetPtr set)
{
sets.insert(set->getShortName(), set);
}
SetList CardDatabase::getSetList() const SetList CardDatabase::getSetList() const
{ {
SetList result; SetList result;
@ -366,187 +153,6 @@ SetList CardDatabase::getSetList() const
return result; return result;
} }
/**
* Finds the PrintingInfo in the cardInfo that has the given uuid field.
*
* @param cardInfo The CardInfo to search
* @param providerId The uuid to look for
* @return The PrintingInfo, or a default-constructed PrintingInfo if not found.
*/
PrintingInfo CardDatabase::findPrintingWithId(const CardInfoPtr &cardInfo, const QString &providerId)
{
for (const auto &printings : cardInfo->getSets()) {
for (const auto &printing : printings) {
if (printing.getUuid() == providerId) {
return printing;
}
}
}
return PrintingInfo();
}
PrintingInfo CardDatabase::getSpecificPrinting(const CardRef &cardRef) const
{
CardInfoPtr cardInfo = getCardInfo(cardRef.name);
if (!cardInfo) {
return PrintingInfo(nullptr);
}
return findPrintingWithId(cardInfo, cardRef.providerId);
}
PrintingInfo CardDatabase::getSpecificPrinting(const QString &cardName,
const QString &setShortName,
const QString &collectorNumber) const
{
CardInfoPtr cardInfo = getCardInfo(cardName);
if (!cardInfo) {
return PrintingInfo(nullptr);
}
SetToPrintingsMap setMap = cardInfo->getSets();
if (setMap.empty()) {
return PrintingInfo(nullptr);
}
for (const auto &printings : setMap) {
for (auto &cardInfoForSet : printings) {
if (!collectorNumber.isEmpty()) {
if (cardInfoForSet.getSet()->getShortName() == setShortName &&
cardInfoForSet.getProperty("num") == collectorNumber) {
return cardInfoForSet;
}
} else {
if (cardInfoForSet.getSet()->getShortName() == setShortName) {
return cardInfoForSet;
}
}
}
}
return PrintingInfo(nullptr);
}
/**
* Gets the card representing the preferred printing of the cardInfo
*
* @param cardInfo The cardInfo to find the preferred printing for
* @return A specific printing of a card
*/
ExactCard CardDatabase::getPreferredCard(const CardInfoPtr &cardInfo) const
{
return ExactCard(cardInfo, getPreferredPrinting(cardInfo));
}
bool CardDatabase::isPreferredPrinting(const CardRef &cardRef) const
{
if (cardRef.providerId.startsWith("card_")) {
return cardRef.providerId ==
QLatin1String("card_") + cardRef.name + QString("_") + getPreferredPrintingProviderId(cardRef.name);
}
return cardRef.providerId == getPreferredPrintingProviderId(cardRef.name);
}
PrintingInfo CardDatabase::getPreferredPrinting(const QString &cardName) const
{
CardInfoPtr cardInfo = getCardInfo(cardName);
return getPreferredPrinting(cardInfo);
}
PrintingInfo CardDatabase::getPreferredPrinting(const CardInfoPtr &cardInfo) const
{
if (!cardInfo) {
return PrintingInfo(nullptr);
}
SetToPrintingsMap setMap = cardInfo->getSets();
if (setMap.empty()) {
return PrintingInfo(nullptr);
}
CardSetPtr preferredSet = nullptr;
PrintingInfo preferredPrinting;
SetPriorityComparator comparator;
for (const auto &printings : setMap) {
for (auto &printing : printings) {
CardSetPtr currentSet = printing.getSet();
if (!preferredSet || comparator(currentSet, preferredSet)) {
preferredSet = currentSet;
preferredPrinting = printing;
}
}
}
if (preferredSet) {
return preferredPrinting;
}
return PrintingInfo(nullptr);
}
QString CardDatabase::getPreferredPrintingProviderId(const QString &cardName) const
{
PrintingInfo preferredPrinting = getPreferredPrinting(cardName);
QString uuid = preferredPrinting.getUuid();
if (!uuid.isEmpty()) {
return uuid;
}
CardInfoPtr defaultCardInfo = getCardInfo(cardName);
if (defaultCardInfo.isNull()) {
return cardName;
}
return defaultCardInfo->getName();
}
QStringList CardDatabase::getAllMainCardTypes() const
{
QSet<QString> types;
for (const auto &card : cards.values()) {
types.insert(card->getMainCardType());
}
return types.values();
}
QMap<QString, int> CardDatabase::getAllMainCardTypesWithCount() const
{
QMap<QString, int> typeCounts;
for (const auto &card : cards.values()) {
QString type = card->getMainCardType();
typeCounts[type]++;
}
return typeCounts;
}
QMap<QString, int> CardDatabase::getAllSubCardTypesWithCount() const
{
QMap<QString, int> typeCounts;
for (const auto &card : cards.values()) {
QString type = card->getCardType();
QStringList parts = type.split("");
if (parts.size() > 1) { // Ensure there are subtypes
#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
QStringList subtypes = parts[1].split(" ", Qt::SkipEmptyParts);
#else
QStringList subtypes = parts[1].split(" ", QString::SkipEmptyParts);
#endif
for (const QString &subtype : subtypes) {
typeCounts[subtype]++;
}
}
}
return typeCounts;
}
void CardDatabase::checkUnknownSets() void CardDatabase::checkUnknownSets()
{ {
auto _sets = getSetList(); auto _sets = getSetList();
@ -592,22 +198,3 @@ void CardDatabase::notifyEnabledSetsChanged()
// inform the carddatabasemodels that they need to re-check their list of cards // inform the carddatabasemodels that they need to re-check their list of cards
emit cardDatabaseEnabledSetsChanged(); emit cardDatabaseEnabledSetsChanged();
} }
bool CardDatabase::saveCustomTokensToFile()
{
QString fileName = SettingsCache::instance().getCustomCardDatabasePath() + "/" + CardSet::TOKENS_SETNAME + ".xml";
SetNameMap tmpSets;
CardSetPtr customTokensSet = getSet(CardSet::TOKENS_SETNAME);
tmpSets.insert(CardSet::TOKENS_SETNAME, customTokensSet);
CardNameMap tmpCards;
for (const CardInfoPtr &card : cards) {
if (card->getSets().contains(CardSet::TOKENS_SETNAME)) {
tmpCards.insert(card->getName(), card);
}
}
availableParsers.first()->saveToFile(tmpSets, tmpCards, fileName);
return true;
}

View file

@ -3,6 +3,8 @@
#include "../card/exact_card.h" #include "../card/exact_card.h"
#include "../common/card_ref.h" #include "../common/card_ref.h"
#include "card_database_loader.h"
#include "card_database_querier.h"
#include <QBasicMutex> #include <QBasicMutex>
#include <QDate> #include <QDate>
@ -14,20 +16,6 @@
#include <utility> #include <utility>
inline Q_LOGGING_CATEGORY(CardDatabaseLog, "card_database"); inline Q_LOGGING_CATEGORY(CardDatabaseLog, "card_database");
inline Q_LOGGING_CATEGORY(CardDatabaseLoadingLog, "card_database.loading");
inline Q_LOGGING_CATEGORY(CardDatabaseLoadingSuccessOrFailureLog, "card_database.loading.success_or_failure");
class ICardDatabaseParser;
enum LoadStatus
{
Ok,
VersionTooOld,
Invalid,
NotLoaded,
FileError,
NoCards
};
class CardDatabase : public QObject class CardDatabase : public QObject
{ {
@ -48,79 +36,50 @@ protected:
*/ */
SetNameMap sets; SetNameMap sets;
// loader responsible for file discovery & parsing
CardDatabaseLoader *loader;
LoadStatus loadStatus; LoadStatus loadStatus;
QVector<ICardDatabaseParser *> availableParsers; CardDatabaseQuerier *querier;
private: private:
void checkUnknownSets(); void checkUnknownSets();
void refreshCachedReverseRelatedCards(); void refreshCachedReverseRelatedCards();
QBasicMutex *reloadDatabaseMutex = new QBasicMutex(), *clearDatabaseMutex = new QBasicMutex(), QBasicMutex *clearDatabaseMutex = new QBasicMutex(), *addCardMutex = new QBasicMutex(),
*loadFromFileMutex = new QBasicMutex(), *addCardMutex = new QBasicMutex(),
*removeCardMutex = new QBasicMutex(); *removeCardMutex = new QBasicMutex();
public: public:
explicit CardDatabase(QObject *parent = nullptr); explicit CardDatabase(QObject *parent = nullptr);
~CardDatabase() override; ~CardDatabase() override;
void clear();
void removeCard(CardInfoPtr card); void removeCard(CardInfoPtr card);
void clear();
[[nodiscard]] CardInfoPtr getCardInfo(const QString &cardName) const;
[[nodiscard]] QList<CardInfoPtr> getCardInfos(const QStringList &cardNames) const;
QList<ExactCard> getCards(const QList<CardRef> &cardRefs) const;
[[nodiscard]] ExactCard getCard(const CardRef &cardRef) const;
[[nodiscard]] ExactCard getPreferredCard(const CardInfoPtr &cardInfo) const;
static PrintingInfo findPrintingWithId(const CardInfoPtr &cardInfo, const QString &providerId);
[[nodiscard]] PrintingInfo getPreferredPrinting(const QString &cardName) const;
[[nodiscard]] PrintingInfo getPreferredPrinting(const CardInfoPtr &cardInfo) const;
[[nodiscard]] PrintingInfo getSpecificPrinting(const CardRef &cardRef) const;
PrintingInfo
getSpecificPrinting(const QString &cardName, const QString &setShortName, const QString &collectorNumber) const;
QString getPreferredPrintingProviderId(const QString &cardName) const;
bool isPreferredPrinting(const CardRef &cardRef) const;
ExactCard getCardFromSameSet(const QString &cardName, const PrintingInfo &otherPrinting) const;
[[nodiscard]] ExactCard guessCard(const CardRef &cardRef) const;
[[nodiscard]] ExactCard getRandomCard();
/*
* Get a card by its simple name. The name will be simplified in this
* function, so you don't need to simplify it beforehand.
*/
[[nodiscard]] CardInfoPtr getCardBySimpleName(const QString &cardName) const;
CardInfoPtr lookupCardByName(const QString &name) const;
CardSetPtr getSet(const QString &setName);
const CardNameMap &getCardList() const const CardNameMap &getCardList() const
{ {
return cards; return cards;
} }
CardSetPtr getSet(const QString &setName);
SetList getSetList() const; SetList getSetList() const;
CardInfoPtr getCardFromMap(const CardNameMap &cardMap, const QString &cardName) const;
LoadStatus loadFromFile(const QString &fileName);
bool saveCustomTokensToFile();
QStringList getAllMainCardTypes() const;
QMap<QString, int> getAllMainCardTypesWithCount() const;
QMap<QString, int> getAllSubCardTypesWithCount() const;
LoadStatus getLoadStatus() const LoadStatus getLoadStatus() const
{ {
return loadStatus; return loadStatus;
} }
CardDatabaseQuerier *query() const
{
return querier;
}
void enableAllUnknownSets(); void enableAllUnknownSets();
void markAllSetsAsKnown(); void markAllSetsAsKnown();
void notifyEnabledSetsChanged(); void notifyEnabledSetsChanged();
static QStringList collectCustomDatabasePaths();
public slots: public slots:
LoadStatus loadCardDatabases();
void addCard(CardInfoPtr card); void addCard(CardInfoPtr card);
void addSet(CardSetPtr set); void addSet(CardSetPtr set);
protected slots: void loadCardDatabases();
LoadStatus loadCardDatabase(const QString &path); bool saveCustomTokensToFile();
signals: signals:
void cardDatabaseLoadingFinished(); void cardDatabaseLoadingFinished();
void cardDatabaseLoadingFailed(); void cardDatabaseLoadingFailed();
@ -129,6 +88,9 @@ signals:
void cardDatabaseEnabledSetsChanged(); void cardDatabaseEnabledSetsChanged();
void cardAdded(CardInfoPtr card); void cardAdded(CardInfoPtr card);
void cardRemoved(CardInfoPtr card); void cardRemoved(CardInfoPtr card);
friend class CardDatabaseLoader;
friend class CardDatabaseQuerier;
}; };
#endif #endif

View file

@ -0,0 +1,153 @@
#include "card_database_loader.h"
#include "../settings/cache_settings.h"
#include "card_database.h"
#include "parser/cockatrice_xml_3.h"
#include "parser/cockatrice_xml_4.h"
#include <QDebug>
#include <QDirIterator>
#include <QFile>
#include <QTime>
CardDatabaseLoader::CardDatabaseLoader(QObject *parent, CardDatabase *db) : QObject(parent), database(db)
{
// instantiate available parsers here and connect them to the database
availableParsers << new CockatriceXml4Parser;
availableParsers << new CockatriceXml3Parser;
for (auto *p : availableParsers) {
// connect parser outputs to the database adders
connect(p, &ICardDatabaseParser::addCard, database, &CardDatabase::addCard, Qt::DirectConnection);
connect(p, &ICardDatabaseParser::addSet, database, &CardDatabase::addSet, Qt::DirectConnection);
}
// when SettingsCache's path changes, trigger reloads
connect(&SettingsCache::instance(), &SettingsCache::cardDatabasePathChanged, this,
&CardDatabaseLoader::loadCardDatabases);
}
CardDatabaseLoader::~CardDatabaseLoader()
{
qDeleteAll(availableParsers);
availableParsers.clear();
}
LoadStatus CardDatabaseLoader::loadFromFile(const QString &fileName)
{
QFile file(fileName);
file.open(QIODevice::ReadOnly);
if (!file.isOpen()) {
return FileError;
}
for (auto parser : availableParsers) {
file.reset();
if (parser->getCanParseFile(fileName, file)) {
file.reset();
parser->parseFile(file);
return Ok;
}
}
return Invalid;
}
LoadStatus CardDatabaseLoader::loadCardDatabase(const QString &path)
{
auto startTime = QTime::currentTime();
LoadStatus tempLoadStatus = NotLoaded;
if (!path.isEmpty()) {
QMutexLocker locker(loadFromFileMutex);
tempLoadStatus = loadFromFile(path);
}
int msecs = startTime.msecsTo(QTime::currentTime());
qCInfo(CardDatabaseLoadingLog) << "Loaded card database: Path =" << path << "Status =" << tempLoadStatus
<< "Cards =" << (database ? database->cards.size() : 0)
<< "Sets =" << (database ? database->sets.size() : 0) << QString("%1ms").arg(msecs);
return tempLoadStatus;
}
LoadStatus CardDatabaseLoader::loadCardDatabases()
{
QMutexLocker locker(reloadDatabaseMutex);
if (!database) {
qCWarning(CardDatabaseLoadingLog) << "Loader has no database pointer";
emit loadingFailed();
return FileError;
}
emit loadingStarted();
qCInfo(CardDatabaseLoadingLog) << "Card Database Loading Started";
database->clear(); // remove old db
LoadStatus loadStatus =
loadCardDatabase(SettingsCache::instance().getCardDatabasePath()); // load main card database
loadCardDatabase(SettingsCache::instance().getTokenDatabasePath()); // load tokens database
loadCardDatabase(SettingsCache::instance().getSpoilerCardDatabasePath()); // load spoilers database
// find all custom card databases, recursively & following symlinks
// then load them alphabetically
const QStringList customPaths = collectCustomDatabasePaths();
for (int i = 0; i < customPaths.size(); ++i) {
const auto &p = customPaths.at(i);
qCInfo(CardDatabaseLoadingLog) << "Loading Custom Set" << i << "(" << p << ")";
loadCardDatabase(p);
}
// AFTER all the cards have been loaded
// resolve the reverse-related tags
database->refreshCachedReverseRelatedCards();
if (loadStatus == Ok) {
database->checkUnknownSets(); // update deck editors, etc
qCInfo(CardDatabaseLoadingSuccessOrFailureLog) << "Card Database Loading Success";
emit loadingFinished();
} else {
qCInfo(CardDatabaseLoadingSuccessOrFailureLog) << "Card Database Loading Failed";
emit loadingFailed(); // bring up the settings dialog
}
return loadStatus;
}
QStringList CardDatabaseLoader::collectCustomDatabasePaths() const
{
QDirIterator it(SettingsCache::instance().getCustomCardDatabasePath(), {"*.xml"}, QDir::Files,
QDirIterator::Subdirectories | QDirIterator::FollowSymlinks);
QStringList paths;
while (it.hasNext())
paths << it.next();
paths.sort();
return paths;
}
bool CardDatabaseLoader::saveCustomTokensToFile()
{
if (!database) {
qCWarning(CardDatabaseLog) << "saveCustomTokensToFile: database pointer missing";
return false;
}
QString fileName = SettingsCache::instance().getCustomCardDatabasePath() + "/" + CardSet::TOKENS_SETNAME + ".xml";
SetNameMap tmpSets;
CardSetPtr customTokensSet = database->getSet(CardSet::TOKENS_SETNAME);
tmpSets.insert(CardSet::TOKENS_SETNAME, customTokensSet);
CardNameMap tmpCards;
for (const CardInfoPtr &card : database->cards) {
if (card->getSets().contains(CardSet::TOKENS_SETNAME)) {
tmpCards.insert(card->getName(), card);
}
}
availableParsers.first()->saveToFile(tmpSets, tmpCards, fileName);
return true;
}

View file

@ -0,0 +1,57 @@
#ifndef COCKATRICE_CARD_DATABASE_LOADER_H
#define COCKATRICE_CARD_DATABASE_LOADER_H
#include <QBasicMutex>
#include <QList>
#include <QLoggingCategory>
#include <QObject>
inline Q_LOGGING_CATEGORY(CardDatabaseLoadingLog, "card_database.loading");
inline Q_LOGGING_CATEGORY(CardDatabaseLoadingSuccessOrFailureLog, "card_database.loading.success_or_failure");
class CardDatabase;
class ICardDatabaseParser;
enum LoadStatus
{
Ok,
VersionTooOld,
Invalid,
NotLoaded,
FileError,
NoCards
};
class CardDatabaseLoader : public QObject
{
Q_OBJECT
public:
explicit CardDatabaseLoader(QObject *parent, CardDatabase *db);
~CardDatabaseLoader() override;
public slots:
LoadStatus loadCardDatabases(); // discover & load the configured databases
LoadStatus loadCardDatabase(const QString &path); // load a single file
bool saveCustomTokensToFile(); // write tokens to custom DB path
signals:
void loadingStarted();
void loadingFinished();
void loadingFailed();
void newSetsFound(int numSets, const QStringList &setNames);
void allNewSetsEnabled();
private:
LoadStatus loadFromFile(const QString &fileName); // internal helper
QStringList collectCustomDatabasePaths() const;
CardDatabase *database; // non-owning pointer to the container
// parsers
QList<ICardDatabaseParser *> availableParsers;
QBasicMutex *loadFromFileMutex = new QBasicMutex();
QBasicMutex *reloadDatabaseMutex = new QBasicMutex();
};
#endif // COCKATRICE_CARD_DATABASE_LOADER_H

View file

@ -4,4 +4,9 @@ CardDatabase *CardDatabaseManager::getInstance()
{ {
static CardDatabase instance; // Created only once, on first access static CardDatabase instance; // Created only once, on first access
return &instance; return &instance;
}
CardDatabaseQuerier *CardDatabaseManager::query()
{
return getInstance()->query();
} }

View file

@ -1,4 +1,3 @@
#ifndef CARD_DATABASE_ACCESSOR_H #ifndef CARD_DATABASE_ACCESSOR_H
#define CARD_DATABASE_ACCESSOR_H #define CARD_DATABASE_ACCESSOR_H
@ -14,6 +13,7 @@ public:
// Static method to access the singleton instance // Static method to access the singleton instance
static CardDatabase *getInstance(); static CardDatabase *getInstance();
static CardDatabaseQuerier *query();
private: private:
CardDatabaseManager() = default; // Private constructor CardDatabaseManager() = default; // Private constructor

View file

@ -0,0 +1,322 @@
#include "card_database_querier.h"
#include "../utility/card_set_comparator.h"
#include "card_database.h"
#include <qrandom.h>
CardDatabaseQuerier::CardDatabaseQuerier(QObject *_parent, const CardDatabase *_db) : QObject(_parent), db(_db)
{
}
/**
* Looks up the cardInfo corresponding to the cardName.
*
* @param cardName The card name to look up
* @return A CardInfoPtr, or null if not corresponding CardInfo is found.
*/
CardInfoPtr CardDatabaseQuerier::getCardInfo(const QString &cardName) const
{
return db->cards.value(cardName);
}
/**
* Looks up the cardInfos for a list of card names.
*
* @param cardNames The card names to look up
* @return A List of CardInfoPtr. Any failed lookups will be ignored and dropped from the resulting list
*/
QList<CardInfoPtr> CardDatabaseQuerier::getCardInfos(const QStringList &cardNames) const
{
QList<CardInfoPtr> cardInfos;
for (const QString &cardName : cardNames) {
CardInfoPtr ptr = db->cards.value(cardName);
if (ptr)
cardInfos.append(ptr);
}
return cardInfos;
}
CardInfoPtr CardDatabaseQuerier::getCardBySimpleName(const QString &cardName) const
{
return db->simpleNameCards.value(CardInfo::simplifyName(cardName));
}
CardInfoPtr CardDatabaseQuerier::lookupCardByName(const QString &name) const
{
if (auto info = getCardInfo(name))
return info;
if (auto info = getCardBySimpleName(name))
return info;
return getCardBySimpleName(CardInfo::simplifyName(name));
}
/**
* Looks up the cards corresponding to the CardRefs.
* If the providerId is empty, will default to the preferred printing.
* If providerId is given but not found, the PrintingInfo will be empty.
*
* @param cardRefs The cards to look up. If providerId is empty for an entry, will default to the preferred printing for
* that entry. If providerId is given but not found, the PrintingInfo will be empty for that entry.
* @return A list of cards. Any failed lookups will be ignored and dropped from the resulting list.
*/
QList<ExactCard> CardDatabaseQuerier::getCards(const QList<CardRef> &cardRefs) const
{
QList<ExactCard> cards;
for (const auto &cardRef : cardRefs) {
ExactCard card = getCard(cardRef);
if (card)
cards.append(card);
}
return cards;
}
/**
* Looks up the card corresponding to the CardRef.
* If the providerId is empty, will default to the preferred printing.
* If providerId is given but not found, the PrintingInfo will be empty.
*
* @param cardRef The card to look up.
* @return A specific printing of a card, or empty if not found.
*/
ExactCard CardDatabaseQuerier::getCard(const CardRef &cardRef) const
{
auto info = getCardInfo(cardRef.name);
if (info.isNull()) {
return {};
}
if (cardRef.providerId.isEmpty() || cardRef.providerId.isNull()) {
return ExactCard(info, getPreferredPrinting(info));
}
return ExactCard(info, findPrintingWithId(info, cardRef.providerId));
}
/**
* Looks up the card by CardRef, simplifying the name if required.
* If the providerId is empty, will default to the preferred printing.
* If providerId is given but not found, the PrintingInfo will be empty.
*
* @param cardRef The card to look up.
* @return A specific printing of a card, or empty if not found.
*/
ExactCard CardDatabaseQuerier::guessCard(const CardRef &cardRef) const
{
auto card = lookupCardByName(cardRef.name);
auto printing =
cardRef.providerId.isEmpty() ? getPreferredPrinting(card) : findPrintingWithId(card, cardRef.providerId);
return ExactCard(card, printing);
}
ExactCard CardDatabaseQuerier::getRandomCard() const
{
if (db->cards.isEmpty())
return {};
const auto keys = db->cards.keys();
int randomIndex = QRandomGenerator::global()->bounded(keys.size());
const QString &randomKey = keys.at(randomIndex);
CardInfoPtr randomCard = getCardInfo(randomKey);
return ExactCard{randomCard, getPreferredPrinting(randomCard)};
}
ExactCard CardDatabaseQuerier::getCardFromSameSet(const QString &cardName, const PrintingInfo &otherPrinting) const
{
// The source card does not have a printing defined, which means we can't get a card from the same set.
if (otherPrinting == PrintingInfo()) {
return getCard({cardName});
}
// The source card does have a printing defined, which means we can attempt to get a card from the same set.
PrintingInfo relatedPrinting = getSpecificPrinting(cardName, otherPrinting.getSet()->getCorrectedShortName(), "");
ExactCard relatedCard(guessCard({cardName}).getCardPtr(), relatedPrinting);
// If we didn't find a card from the same set, just try to find any card with the same name.
return relatedCard ? relatedCard : getCard({cardName});
}
/**
* Finds the PrintingInfo in the cardInfo that has the given uuid field.
*
* @param cardInfo The CardInfo to search
* @param providerId The uuid to look for
* @return The PrintingInfo, or a default-constructed PrintingInfo if not found.
*/
PrintingInfo CardDatabaseQuerier::findPrintingWithId(const CardInfoPtr &cardInfo, const QString &providerId) const
{
for (const auto &printings : cardInfo->getSets()) {
for (const auto &printing : printings) {
if (printing.getUuid() == providerId) {
return printing;
}
}
}
return PrintingInfo();
}
PrintingInfo CardDatabaseQuerier::getSpecificPrinting(const CardRef &cardRef) const
{
CardInfoPtr cardInfo = getCardInfo(cardRef.name);
if (!cardInfo) {
return PrintingInfo(nullptr);
}
return findPrintingWithId(cardInfo, cardRef.providerId);
}
PrintingInfo CardDatabaseQuerier::getSpecificPrinting(const QString &cardName,
const QString &setShortName,
const QString &collectorNumber) const
{
CardInfoPtr cardInfo = getCardInfo(cardName);
if (!cardInfo) {
return PrintingInfo(nullptr);
}
SetToPrintingsMap setMap = cardInfo->getSets();
if (setMap.empty()) {
return PrintingInfo(nullptr);
}
for (const auto &printings : setMap) {
for (auto &cardInfoForSet : printings) {
if (!collectorNumber.isEmpty()) {
if (cardInfoForSet.getSet()->getShortName() == setShortName &&
cardInfoForSet.getProperty("num") == collectorNumber) {
return cardInfoForSet;
}
} else {
if (cardInfoForSet.getSet()->getShortName() == setShortName) {
return cardInfoForSet;
}
}
}
}
return PrintingInfo(nullptr);
}
/**
* Gets the card representing the preferred printing of the cardInfo
*
* @param cardInfo The cardInfo to find the preferred printing for
* @return A specific printing of a card
*/
ExactCard CardDatabaseQuerier::getPreferredCard(const CardInfoPtr &cardInfo) const
{
return ExactCard(cardInfo, getPreferredPrinting(cardInfo));
}
bool CardDatabaseQuerier::isPreferredPrinting(const CardRef &cardRef) const
{
if (cardRef.providerId.startsWith("card_")) {
return cardRef.providerId ==
QLatin1String("card_") + cardRef.name + QString("_") + getPreferredPrintingProviderId(cardRef.name);
}
return cardRef.providerId == getPreferredPrintingProviderId(cardRef.name);
}
PrintingInfo CardDatabaseQuerier::getPreferredPrinting(const QString &cardName) const
{
CardInfoPtr cardInfo = getCardInfo(cardName);
return getPreferredPrinting(cardInfo);
}
PrintingInfo CardDatabaseQuerier::getPreferredPrinting(const CardInfoPtr &cardInfo) const
{
if (!cardInfo) {
return PrintingInfo(nullptr);
}
SetToPrintingsMap setMap = cardInfo->getSets();
if (setMap.empty()) {
return PrintingInfo(nullptr);
}
CardSetPtr preferredSet = nullptr;
PrintingInfo preferredPrinting;
SetPriorityComparator comparator;
for (const auto &printings : setMap) {
for (auto &printing : printings) {
CardSetPtr currentSet = printing.getSet();
if (!preferredSet || comparator(currentSet, preferredSet)) {
preferredSet = currentSet;
preferredPrinting = printing;
}
}
}
if (preferredSet) {
return preferredPrinting;
}
return PrintingInfo(nullptr);
}
QString CardDatabaseQuerier::getPreferredPrintingProviderId(const QString &cardName) const
{
PrintingInfo preferredPrinting = getPreferredPrinting(cardName);
QString uuid = preferredPrinting.getUuid();
if (!uuid.isEmpty()) {
return uuid;
}
CardInfoPtr defaultCardInfo = getCardInfo(cardName);
if (defaultCardInfo.isNull()) {
return cardName;
}
return defaultCardInfo->getName();
}
QStringList CardDatabaseQuerier::getAllMainCardTypes() const
{
QSet<QString> types;
for (const auto &card : db->cards.values()) {
types.insert(card->getMainCardType());
}
return types.values();
}
QMap<QString, int> CardDatabaseQuerier::getAllMainCardTypesWithCount() const
{
QMap<QString, int> typeCounts;
for (const auto &card : db->cards.values()) {
QString type = card->getMainCardType();
typeCounts[type]++;
}
return typeCounts;
}
QMap<QString, int> CardDatabaseQuerier::getAllSubCardTypesWithCount() const
{
QMap<QString, int> typeCounts;
for (const auto &card : db->cards.values()) {
QString type = card->getCardType();
QStringList parts = type.split("");
if (parts.size() > 1) { // Ensure there are subtypes
#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
QStringList subtypes = parts[1].split(" ", Qt::SkipEmptyParts);
#else
QStringList subtypes = parts[1].split(" ", QString::SkipEmptyParts);
#endif
for (const QString &subtype : subtypes) {
typeCounts[subtype]++;
}
}
}
return typeCounts;
}

View file

@ -0,0 +1,54 @@
#ifndef COCKATRICE_CARD_DATABASE_QUERIER_H
#define COCKATRICE_CARD_DATABASE_QUERIER_H
#include "../card/exact_card.h"
#include "../common/card_ref.h"
#include <QObject>
class CardDatabase;
class CardDatabaseQuerier : public QObject
{
Q_OBJECT
public:
explicit CardDatabaseQuerier(QObject *parent, const CardDatabase *db);
[[nodiscard]] CardInfoPtr getCardInfo(const QString &cardName) const;
[[nodiscard]] QList<CardInfoPtr> getCardInfos(const QStringList &cardNames) const;
/*
* Get a card by its simple name. The name will be simplified in this
* function, so you don't need to simplify it beforehand.
*/
[[nodiscard]] CardInfoPtr getCardBySimpleName(const QString &cardName) const;
[[nodiscard]] ExactCard guessCard(const CardRef &cardRef) const;
[[nodiscard]] ExactCard getCard(const CardRef &cardRef) const;
[[nodiscard]] QList<ExactCard> getCards(const QList<CardRef> &cardRefs) const;
[[nodiscard]] ExactCard getRandomCard() const;
[[nodiscard]] ExactCard getCardFromSameSet(const QString &cardName, const PrintingInfo &otherPrinting) const;
[[nodiscard]] ExactCard getPreferredCard(const CardInfoPtr &card) const;
[[nodiscard]] bool isPreferredPrinting(const CardRef &cardRef) const;
[[nodiscard]] PrintingInfo getPreferredPrinting(const CardInfoPtr &card) const;
[[nodiscard]] PrintingInfo getPreferredPrinting(const QString &cardName) const;
[[nodiscard]] QString getPreferredPrintingProviderId(const QString &cardName) const;
[[nodiscard]] PrintingInfo getSpecificPrinting(const CardRef &cardRef) const;
[[nodiscard]] PrintingInfo
getSpecificPrinting(const QString &cardName, const QString &setCode, const QString &collectorNumber) const;
[[nodiscard]] PrintingInfo findPrintingWithId(const CardInfoPtr &card, const QString &providerId) const;
[[nodiscard]] QStringList getAllMainCardTypes() const;
[[nodiscard]] QMap<QString, int> getAllMainCardTypesWithCount() const;
[[nodiscard]] QMap<QString, int> getAllSubCardTypesWithCount() const;
private:
const CardDatabase *db;
CardInfoPtr lookupCardByName(const QString &name) const;
};
#endif // COCKATRICE_CARD_DATABASE_QUERIER_H

View file

@ -66,7 +66,7 @@ void DeckListModel::rebuildTree()
continue; continue;
} }
CardInfoPtr info = CardDatabaseManager::getInstance()->getCardInfo(currentCard->getName()); CardInfoPtr info = CardDatabaseManager::query()->getCardInfo(currentCard->getName());
QString groupCriteria = getGroupCriteriaForCard(info); QString groupCriteria = getGroupCriteriaForCard(info);
auto *groupNode = dynamic_cast<InnerDecklistNode *>(node->findChild(groupCriteria)); auto *groupNode = dynamic_cast<InnerDecklistNode *>(node->findChild(groupCriteria));
@ -341,7 +341,7 @@ DecklistModelCardNode *DeckListModel::findCardNode(const QString &cardName,
return nullptr; return nullptr;
} }
CardInfoPtr info = CardDatabaseManager::getInstance()->getCardInfo(cardName); CardInfoPtr info = CardDatabaseManager::query()->getCardInfo(cardName);
if (!info) { if (!info) {
return nullptr; return nullptr;
} }
@ -371,7 +371,7 @@ QModelIndex DeckListModel::findCard(const QString &cardName,
QModelIndex DeckListModel::addPreferredPrintingCard(const QString &cardName, const QString &zoneName, bool abAddAnyway) QModelIndex DeckListModel::addPreferredPrintingCard(const QString &cardName, const QString &zoneName, bool abAddAnyway)
{ {
ExactCard card = CardDatabaseManager::getInstance()->getCard({cardName}); ExactCard card = CardDatabaseManager::query()->getCard({cardName});
if (!card) { if (!card) {
if (abAddAnyway) { if (abAddAnyway) {
@ -566,7 +566,7 @@ QList<ExactCard> DeckListModel::getCards() const
if (!currentCard) if (!currentCard)
continue; continue;
for (int k = 0; k < currentCard->getNumber(); ++k) { for (int k = 0; k < currentCard->getNumber(); ++k) {
ExactCard card = CardDatabaseManager::getInstance()->getCard(currentCard->toCardRef()); ExactCard card = CardDatabaseManager::query()->getCard(currentCard->toCardRef());
if (card) { if (card) {
cards.append(card); cards.append(card);
} else { } else {
@ -599,7 +599,7 @@ QList<ExactCard> DeckListModel::getCardsForZone(const QString &zoneName) const
if (!currentCard) if (!currentCard)
continue; continue;
for (int k = 0; k < currentCard->getNumber(); ++k) { for (int k = 0; k < currentCard->getNumber(); ++k) {
ExactCard card = CardDatabaseManager::getInstance()->getCard(currentCard->toCardRef()); ExactCard card = CardDatabaseManager::query()->getCard(currentCard->toCardRef());
if (card) { if (card) {
cards.append(card); cards.append(card);
} else { } else {

View file

@ -282,7 +282,7 @@ QString DeckLoader::exportDeckToDecklist(DecklistWebsite website)
// Set up the function to call // Set up the function to call
auto formatDeckListForExport = [&mainBoardCards, &sideBoardCards](const auto *node, const auto *card) { auto formatDeckListForExport = [&mainBoardCards, &sideBoardCards](const auto *node, const auto *card) {
// Get the card name // Get the card name
CardInfoPtr dbCard = CardDatabaseManager::getInstance()->getCardInfo(card->getName()); CardInfoPtr dbCard = CardDatabaseManager::query()->getCardInfo(card->getName());
if (!dbCard || dbCard->getIsToken()) { if (!dbCard || dbCard->getIsToken()) {
// If it's a token, we don't care about the card. // If it's a token, we don't care about the card.
return; return;
@ -325,7 +325,7 @@ struct SetProviderIdToPreferred
void operator()(const InnerDecklistNode *node, DecklistCardNode *card) const void operator()(const InnerDecklistNode *node, DecklistCardNode *card) const
{ {
Q_UNUSED(node); Q_UNUSED(node);
PrintingInfo preferredPrinting = CardDatabaseManager::getInstance()->getPreferredPrinting(card->getName()); PrintingInfo preferredPrinting = CardDatabaseManager::query()->getPreferredPrinting(card->getName());
QString providerId = preferredPrinting.getUuid(); QString providerId = preferredPrinting.getUuid();
QString setShortName = preferredPrinting.getSet()->getShortName(); QString setShortName = preferredPrinting.getSet()->getShortName();
QString collectorNumber = preferredPrinting.getProperty("num"); QString collectorNumber = preferredPrinting.getProperty("num");
@ -359,6 +359,7 @@ void DeckLoader::resolveSetNameAndNumberToProviderID()
// Retrieve the providerId based on setName and collectorNumber // Retrieve the providerId based on setName and collectorNumber
QString providerId = QString providerId =
CardDatabaseManager::getInstance() CardDatabaseManager::getInstance()
->query()
->getSpecificPrinting(card->getName(), card->getCardSetShortName(), card->getCardCollectorNumber()) ->getSpecificPrinting(card->getName(), card->getCardSetShortName(), card->getCardCollectorNumber())
.getUuid(); .getUuid();
@ -468,7 +469,7 @@ void DeckLoader::saveToStream_DeckZone(QTextStream &out,
for (int j = 0; j < zoneNode->size(); j++) { for (int j = 0; j < zoneNode->size(); j++) {
auto *card = dynamic_cast<DecklistCardNode *>(zoneNode->at(j)); auto *card = dynamic_cast<DecklistCardNode *>(zoneNode->at(j));
CardInfoPtr info = CardDatabaseManager::getInstance()->getCardInfo(card->getName()); CardInfoPtr info = CardDatabaseManager::query()->getCardInfo(card->getName());
QString cardType = info ? info->getMainCardType() : "unknown"; QString cardType = info ? info->getMainCardType() : "unknown";
cardsByType.insert(cardType, card); cardsByType.insert(cardType, card);
@ -584,7 +585,7 @@ bool DeckLoader::convertToCockatriceFormat(QString fileName)
QString DeckLoader::getCardZoneFromName(QString cardName, QString currentZoneName) QString DeckLoader::getCardZoneFromName(QString cardName, QString currentZoneName)
{ {
CardInfoPtr card = CardDatabaseManager::getInstance()->getCardInfo(cardName); CardInfoPtr card = CardDatabaseManager::query()->getCardInfo(cardName);
if (card && card->getIsToken()) { if (card && card->getIsToken()) {
return DECK_ZONE_TOKENS; return DECK_ZONE_TOKENS;
@ -596,7 +597,7 @@ QString DeckLoader::getCardZoneFromName(QString cardName, QString currentZoneNam
QString DeckLoader::getCompleteCardName(const QString &cardName) const QString DeckLoader::getCompleteCardName(const QString &cardName) const
{ {
if (CardDatabaseManager::getInstance()) { if (CardDatabaseManager::getInstance()) {
ExactCard temp = CardDatabaseManager::getInstance()->guessCard({cardName}); ExactCard temp = CardDatabaseManager::query()->guessCard({cardName});
if (temp) { if (temp) {
return temp.getName(); return temp.getName();
} }

View file

@ -71,7 +71,7 @@ void DeckStatsInterface::analyzeDeck(DeckList *deck)
void DeckStatsInterface::copyDeckWithoutTokens(DeckList &source, DeckList &destination) void DeckStatsInterface::copyDeckWithoutTokens(DeckList &source, DeckList &destination)
{ {
auto copyIfNotAToken = [this, &destination](const auto node, const auto card) { auto copyIfNotAToken = [this, &destination](const auto node, const auto card) {
CardInfoPtr dbCard = cardDatabase.getCardInfo(card->getName()); CardInfoPtr dbCard = cardDatabase.query()->getCardInfo(card->getName());
if (dbCard && !dbCard->getIsToken()) { if (dbCard && !dbCard->getIsToken()) {
DecklistCardNode *addedCard = destination.addCard(card->getName(), node->getName(), -1); DecklistCardNode *addedCard = destination.addCard(card->getName(), node->getName(), -1);
addedCard->setNumber(card->getNumber()); addedCard->setNumber(card->getNumber());

View file

@ -153,7 +153,7 @@ void DlgEditTokens::actAddToken()
name = getTextWithMax(this, tr("Add token"), tr("Please enter the name of the token:")); name = getTextWithMax(this, tr("Add token"), tr("Please enter the name of the token:"));
if (name.isEmpty()) if (name.isEmpty())
return; return;
if (databaseModel->getDatabase()->getCardInfo(name)) { if (databaseModel->getDatabase()->query()->getCardInfo(name)) {
QMessageBox::critical(this, tr("Error"), QMessageBox::critical(this, tr("Error"),
tr("The chosen name conflicts with an existing card or token.\nMake sure to enable " tr("The chosen name conflicts with an existing card or token.\nMake sure to enable "
"the 'Token' set in the \"Manage sets\" dialog to display them correctly.")); "the 'Token' set in the \"Manage sets\" dialog to display them correctly."));

View file

@ -152,8 +152,8 @@ void DlgSelectSetForCards::actOK()
continue; continue;
} }
model->removeRow(find_card.row(), find_card.parent()); model->removeRow(find_card.row(), find_card.parent());
CardInfoPtr cardInfo = CardDatabaseManager::getInstance()->getCardInfo(card); CardInfoPtr cardInfo = CardDatabaseManager::query()->getCardInfo(card);
PrintingInfo printing = CardDatabaseManager::getInstance()->getSpecificPrinting(card, modifiedSet, ""); PrintingInfo printing = CardDatabaseManager::query()->getSpecificPrinting(card, modifiedSet, "");
model->addCard(ExactCard(cardInfo, printing), DECK_ZONE_MAIN); model->addCard(ExactCard(cardInfo, printing), DECK_ZONE_MAIN);
} }
} }
@ -223,7 +223,7 @@ QMap<QString, int> DlgSelectSetForCards::getSetsForCards()
if (!currentCard) if (!currentCard)
continue; continue;
CardInfoPtr infoPtr = CardDatabaseManager::getInstance()->getCardInfo(currentCard->getName()); CardInfoPtr infoPtr = CardDatabaseManager::query()->getCardInfo(currentCard->getName());
if (!infoPtr) if (!infoPtr)
continue; continue;
@ -291,13 +291,14 @@ void DlgSelectSetForCards::updateCardLists()
if (!found) { if (!found) {
// The card was not in any selected set // The card was not in any selected set
ExactCard card = CardDatabaseManager::getInstance()->getCard({currentCard->getName()}); ExactCard card = CardDatabaseManager::query()->getCard({currentCard->getName()});
CardInfoPictureWidget *picture_widget = new CardInfoPictureWidget(uneditedCardsFlowWidget); CardInfoPictureWidget *picture_widget = new CardInfoPictureWidget(uneditedCardsFlowWidget);
picture_widget->setCard(card); picture_widget->setCard(card);
uneditedCardsFlowWidget->addWidget(picture_widget); uneditedCardsFlowWidget->addWidget(picture_widget);
} else { } else {
ExactCard card = CardDatabaseManager::getInstance()->getCard( ExactCard card = CardDatabaseManager::query()->getCard(
{currentCard->getName(), CardDatabaseManager::getInstance() {currentCard->getName(), CardDatabaseManager::getInstance()
->query()
->getSpecificPrinting(currentCard->getName(), foundSetName, "") ->getSpecificPrinting(currentCard->getName(), foundSetName, "")
.getUuid()}); .getUuid()});
CardInfoPictureWidget *picture_widget = new CardInfoPictureWidget(modifiedCardsFlowWidget); CardInfoPictureWidget *picture_widget = new CardInfoPictureWidget(modifiedCardsFlowWidget);
@ -377,7 +378,7 @@ QMap<QString, QStringList> DlgSelectSetForCards::getCardsForSets()
if (!currentCard) if (!currentCard)
continue; continue;
CardInfoPtr infoPtr = CardDatabaseManager::getInstance()->getCardInfo(currentCard->getName()); CardInfoPtr infoPtr = CardDatabaseManager::query()->getCardInfo(currentCard->getName());
if (!infoPtr) if (!infoPtr)
continue; continue;
@ -627,17 +628,15 @@ void SetEntryWidget::updateCardDisplayWidgets()
for (const QString &cardName : possibleCards) { for (const QString &cardName : possibleCards) {
CardInfoPictureWidget *picture_widget = new CardInfoPictureWidget(cardListContainer); CardInfoPictureWidget *picture_widget = new CardInfoPictureWidget(cardListContainer);
QString providerId = QString providerId = CardDatabaseManager::query()->getSpecificPrinting(cardName, setName, nullptr).getUuid();
CardDatabaseManager::getInstance()->getSpecificPrinting(cardName, setName, nullptr).getUuid(); picture_widget->setCard(CardDatabaseManager::query()->getCard({cardName, providerId}));
picture_widget->setCard(CardDatabaseManager::getInstance()->getCard({cardName, providerId}));
cardListContainer->addWidget(picture_widget); cardListContainer->addWidget(picture_widget);
} }
for (const QString &cardName : unusedCards) { for (const QString &cardName : unusedCards) {
CardInfoPictureWidget *picture_widget = new CardInfoPictureWidget(alreadySelectedCardListContainer); CardInfoPictureWidget *picture_widget = new CardInfoPictureWidget(alreadySelectedCardListContainer);
QString providerId = QString providerId = CardDatabaseManager::query()->getSpecificPrinting(cardName, setName, nullptr).getUuid();
CardDatabaseManager::getInstance()->getSpecificPrinting(cardName, setName, nullptr).getUuid(); picture_widget->setCard(CardDatabaseManager::query()->getCard({cardName, providerId}));
picture_widget->setCard(CardDatabaseManager::getInstance()->getCard({cardName, providerId}));
alreadySelectedCardListContainer->addWidget(picture_widget); alreadySelectedCardListContainer->addWidget(picture_widget);
} }
} }

View file

@ -118,7 +118,7 @@ static void setupParserRules()
return [=](const DeckPreviewWidget *deck, const ExtraDeckSearchInfo &) -> bool { return [=](const DeckPreviewWidget *deck, const ExtraDeckSearchInfo &) -> bool {
int count = 0; int count = 0;
deck->deckLoader->forEachCard([&](InnerDecklistNode *, const DecklistCardNode *node) { deck->deckLoader->forEachCard([&](InnerDecklistNode *, const DecklistCardNode *node) {
auto cardInfoPtr = CardDatabaseManager::getInstance()->getCardInfo(node->getName()); auto cardInfoPtr = CardDatabaseManager::query()->getCardInfo(node->getName());
if (!cardInfoPtr.isNull() && cardFilter.check(cardInfoPtr)) { if (!cardInfoPtr.isNull() && cardFilter.check(cardInfoPtr)) {
count += node->getNumber(); count += node->getNumber();
} }

View file

@ -57,7 +57,7 @@ void AbstractCardItem::pixmapUpdated()
void AbstractCardItem::refreshCardInfo() void AbstractCardItem::refreshCardInfo()
{ {
exactCard = CardDatabaseManager::getInstance()->getCard(cardRef); exactCard = CardDatabaseManager::query()->getCard(cardRef);
if (!exactCard && !cardRef.name.isEmpty()) { if (!exactCard && !cardRef.name.isEmpty()) {
auto info = CardInfo::newInstance(cardRef.name, "", true, {}, {}, {}, {}, false, false, -1, false); auto info = CardInfo::newInstance(cardRef.name, "", true, {}, {}, {}, {}, false, false, -1, false);

View file

@ -332,7 +332,7 @@ void DeckViewContainer::deckSelectFinished(const Response &r)
{ {
const Response_DeckDownload &resp = r.GetExtension(Response_DeckDownload::ext); const Response_DeckDownload &resp = r.GetExtension(Response_DeckDownload::ext);
DeckLoader newDeck(QString::fromStdString(resp.deck())); DeckLoader newDeck(QString::fromStdString(resp.deck()));
PictureLoader::cacheCardPixmaps(CardDatabaseManager::getInstance()->getCards(newDeck.getCardRefList())); PictureLoader::cacheCardPixmaps(CardDatabaseManager::query()->getCards(newDeck.getCardRefList()));
setDeck(newDeck); setDeck(newDeck);
switchToDeckLoadedView(); switchToDeckLoadedView();
} }

View file

@ -205,9 +205,9 @@ void DlgCreateToken::tokenSelectionChanged(const QModelIndex &current, const QMo
CardRef ref; CardRef ref;
ref.name = cardInfo->getName(); ref.name = cardInfo->getName();
ref.providerId = cardProviderId; ref.providerId = cardProviderId;
pic->setCard(CardDatabaseManager::getInstance()->getCard(ref)); pic->setCard(CardDatabaseManager::query()->getCard(ref));
} else { } else {
pic->setCard(CardDatabaseManager::getInstance()->getPreferredCard(cardInfo)); pic->setCard(CardDatabaseManager::query()->getPreferredCard(cardInfo));
} }
} }

View file

@ -322,7 +322,7 @@ void CardMenu::addRelatedCardView()
bool atLeastOneGoodRelationFound = false; bool atLeastOneGoodRelationFound = false;
QList<CardRelation *> relatedCards = exactCard.getInfo().getAllRelatedCards(); QList<CardRelation *> relatedCards = exactCard.getInfo().getAllRelatedCards();
for (const CardRelation *cardRelation : relatedCards) { for (const CardRelation *cardRelation : relatedCards) {
CardInfoPtr relatedCard = CardDatabaseManager::getInstance()->getCardInfo(cardRelation->getName()); CardInfoPtr relatedCard = CardDatabaseManager::query()->getCardInfo(cardRelation->getName());
if (relatedCard != nullptr) { if (relatedCard != nullptr) {
atLeastOneGoodRelationFound = true; atLeastOneGoodRelationFound = true;
break; break;
@ -366,10 +366,10 @@ void CardMenu::addRelatedCardActions()
int index = 0; int index = 0;
QAction *createRelatedCards = nullptr; QAction *createRelatedCards = nullptr;
for (const CardRelation *cardRelation : relatedCards) { for (const CardRelation *cardRelation : relatedCards) {
ExactCard relatedCard = CardDatabaseManager::getInstance()->getCardFromSameSet(cardRelation->getName(), ExactCard relatedCard =
card->getCard().getPrinting()); CardDatabaseManager::query()->getCardFromSameSet(cardRelation->getName(), card->getCard().getPrinting());
if (!relatedCard) { if (!relatedCard) {
relatedCard = CardDatabaseManager::getInstance()->getCard({cardRelation->getName()}); relatedCard = CardDatabaseManager::query()->getCard({cardRelation->getName()});
} }
if (!relatedCard) { if (!relatedCard) {
continue; continue;

View file

@ -840,8 +840,7 @@ void PlayerActions::actCreateToken()
lastTokenInfo = dlg.getTokenInfo(); lastTokenInfo = dlg.getTokenInfo();
ExactCard correctedCard = ExactCard correctedCard = CardDatabaseManager::query()->guessCard({lastTokenInfo.name, lastTokenInfo.providerId});
CardDatabaseManager::getInstance()->guessCard({lastTokenInfo.name, lastTokenInfo.providerId});
if (correctedCard) { if (correctedCard) {
lastTokenInfo.name = correctedCard.getName(); lastTokenInfo.name = correctedCard.getName();
lastTokenTableRow = TableZone::clampValidTableRow(2 - correctedCard.getInfo().getTableRow()); lastTokenTableRow = TableZone::clampValidTableRow(2 - correctedCard.getInfo().getTableRow());
@ -903,7 +902,7 @@ void PlayerActions::setLastToken(CardInfoPtr cardInfo)
void PlayerActions::actCreatePredefinedToken() void PlayerActions::actCreatePredefinedToken()
{ {
auto *action = static_cast<QAction *>(sender()); auto *action = static_cast<QAction *>(sender());
CardInfoPtr cardInfo = CardDatabaseManager::getInstance()->getCardInfo(action->text()); CardInfoPtr cardInfo = CardDatabaseManager::query()->getCardInfo(action->text());
if (!cardInfo) { if (!cardInfo) {
return; return;
} }
@ -929,8 +928,8 @@ void PlayerActions::actCreateRelatedCard()
* then let's allow it to be created via "create another token" * then let's allow it to be created via "create another token"
*/ */
if (createRelatedFromRelation(sourceCard, cardRelation) && cardRelation->getCanCreateAnother()) { if (createRelatedFromRelation(sourceCard, cardRelation) && cardRelation->getCanCreateAnother()) {
ExactCard relatedCard = CardDatabaseManager::getInstance()->getCardFromSameSet( ExactCard relatedCard = CardDatabaseManager::query()->getCardFromSameSet(cardRelation->getName(),
cardRelation->getName(), sourceCard->getCard().getPrinting()); sourceCard->getCard().getPrinting());
setLastToken(relatedCard.getCardPtr()); setLastToken(relatedCard.getCardPtr());
} }
} }
@ -1010,7 +1009,7 @@ void PlayerActions::actCreateAllRelatedCards()
* then assign the first to the "Create another" shortcut. * then assign the first to the "Create another" shortcut.
*/ */
if (cardRelation != nullptr && cardRelation->getCanCreateAnother()) { if (cardRelation != nullptr && cardRelation->getCanCreateAnother()) {
CardInfoPtr cardInfo = CardDatabaseManager::getInstance()->getCardInfo(cardRelation->getName()); CardInfoPtr cardInfo = CardDatabaseManager::query()->getCardInfo(cardRelation->getName());
setLastToken(cardInfo); setLastToken(cardInfo);
} }
} }
@ -1057,7 +1056,7 @@ void PlayerActions::createCard(const CardItem *sourceCard,
CardRelation::AttachType attachType, CardRelation::AttachType attachType,
bool persistent) bool persistent)
{ {
CardInfoPtr cardInfo = CardDatabaseManager::getInstance()->getCardInfo(dbCardName); CardInfoPtr cardInfo = CardDatabaseManager::query()->getCardInfo(dbCardName);
if (cardInfo == nullptr || sourceCard == nullptr) { if (cardInfo == nullptr || sourceCard == nullptr) {
return; return;
@ -1093,8 +1092,8 @@ void PlayerActions::createCard(const CardItem *sourceCard,
cmd.set_x(gridPoint.x()); cmd.set_x(gridPoint.x());
cmd.set_y(gridPoint.y()); cmd.set_y(gridPoint.y());
ExactCard relatedCard = CardDatabaseManager::getInstance()->getCardFromSameSet(cardInfo->getName(), ExactCard relatedCard =
sourceCard->getCard().getPrinting()); CardDatabaseManager::query()->getCardFromSameSet(cardInfo->getName(), sourceCard->getCard().getPrinting());
switch (attachType) { switch (attachType) {
case CardRelation::DoesNotAttach: case CardRelation::DoesNotAttach:

View file

@ -55,7 +55,7 @@ QWidget *CardGroupDisplayWidget::constructWidgetForIndex(QPersistentModelIndex i
auto widget = new CardInfoPictureWithTextOverlayWidget(getLayoutParent(), true); auto widget = new CardInfoPictureWithTextOverlayWidget(getLayoutParent(), true);
widget->setScaleFactor(cardSizeWidget->getSlider()->value()); widget->setScaleFactor(cardSizeWidget->getSlider()->value());
widget->setCard(CardDatabaseManager::getInstance()->getCard({cardName, cardProviderId})); widget->setCard(CardDatabaseManager::query()->getCard({cardName, cardProviderId}));
connect(widget, &CardInfoPictureWithTextOverlayWidget::imageClicked, this, &CardGroupDisplayWidget::onClick); connect(widget, &CardInfoPictureWithTextOverlayWidget::imageClicked, this, &CardGroupDisplayWidget::onClick);
connect(widget, &CardInfoPictureWithTextOverlayWidget::hoveredOnCard, this, &CardGroupDisplayWidget::onHover); connect(widget, &CardInfoPictureWithTextOverlayWidget::hoveredOnCard, this, &CardGroupDisplayWidget::onHover);

View file

@ -57,7 +57,7 @@ void CardInfoDisplayWidget::setCard(const ExactCard &card)
void CardInfoDisplayWidget::setCard(const CardRef &cardRef) void CardInfoDisplayWidget::setCard(const CardRef &cardRef)
{ {
setCard(CardDatabaseManager::getInstance()->guessCard(cardRef)); setCard(CardDatabaseManager::query()->guessCard(cardRef));
if (exactCard.isEmpty()) { if (exactCard.isEmpty()) {
text->setInvalidCardName(cardRef.name); text->setInvalidCardName(cardRef.name);
} }

View file

@ -160,12 +160,12 @@ void CardInfoFrameWidget::setCard(const ExactCard &card)
void CardInfoFrameWidget::setCard(const QString &cardName) void CardInfoFrameWidget::setCard(const QString &cardName)
{ {
setCard(CardDatabaseManager::getInstance()->guessCard({cardName})); setCard(CardDatabaseManager::query()->guessCard({cardName}));
} }
void CardInfoFrameWidget::setCard(const CardRef &cardRef) void CardInfoFrameWidget::setCard(const CardRef &cardRef)
{ {
setCard(CardDatabaseManager::getInstance()->getCard(cardRef)); setCard(CardDatabaseManager::query()->getCard(cardRef));
} }
void CardInfoFrameWidget::setCard(AbstractCardItem *card) void CardInfoFrameWidget::setCard(AbstractCardItem *card)

View file

@ -368,7 +368,7 @@ QMenu *CardInfoPictureWidget::createViewRelatedCardsMenu()
QList<CardRelation *> relatedCards = exactCard.getInfo().getAllRelatedCards(); QList<CardRelation *> relatedCards = exactCard.getInfo().getAllRelatedCards();
auto relatedCardExists = [](const CardRelation *cardRelation) { auto relatedCardExists = [](const CardRelation *cardRelation) {
return CardDatabaseManager::getInstance()->getCardInfo(cardRelation->getName()) != nullptr; return CardDatabaseManager::query()->getCardInfo(cardRelation->getName()) != nullptr;
}; };
bool atLeastOneGoodRelationFound = std::any_of(relatedCards.begin(), relatedCards.end(), relatedCardExists); bool atLeastOneGoodRelationFound = std::any_of(relatedCards.begin(), relatedCards.end(), relatedCardExists);
@ -383,7 +383,7 @@ QMenu *CardInfoPictureWidget::createViewRelatedCardsMenu()
QAction *viewCard = viewRelatedCards->addAction(relatedCardName); QAction *viewCard = viewRelatedCards->addAction(relatedCardName);
connect(viewCard, &QAction::triggered, this, [this, &relatedCardName] { connect(viewCard, &QAction::triggered, this, [this, &relatedCardName] {
emit cardChanged( emit cardChanged(
CardDatabaseManager::getInstance()->getCard({relatedCardName, exactCard.getPrinting().getUuid()})); CardDatabaseManager::query()->getCard({relatedCardName, exactCard.getPrinting().getUuid()}));
}); });
viewRelatedCards->addAction(viewCard); viewRelatedCards->addAction(viewCard);
} }

View file

@ -87,7 +87,7 @@ QHash<QString, int> ManaBaseWidget::analyzeManaBase()
continue; continue;
for (int k = 0; k < currentCard->getNumber(); ++k) { for (int k = 0; k < currentCard->getNumber(); ++k) {
CardInfoPtr info = CardDatabaseManager::getInstance()->getCardInfo(currentCard->getName()); CardInfoPtr info = CardDatabaseManager::query()->getCardInfo(currentCard->getName());
if (info) { if (info) {
auto devotion = determineManaProduction(info->getText()); auto devotion = determineManaProduction(info->getText());
mergeManaCounts(manaBaseMap, devotion); mergeManaCounts(manaBaseMap, devotion);

View file

@ -53,7 +53,7 @@ std::unordered_map<int, int> ManaCurveWidget::analyzeManaCurve()
continue; continue;
for (int k = 0; k < currentCard->getNumber(); ++k) { for (int k = 0; k < currentCard->getNumber(); ++k) {
CardInfoPtr info = CardDatabaseManager::getInstance()->getCardInfo(currentCard->getName()); CardInfoPtr info = CardDatabaseManager::query()->getCardInfo(currentCard->getName());
if (info) { if (info) {
int cmc = info->getCmc().toInt(); int cmc = info->getCmc().toInt();
manaCurveMap[cmc]++; manaCurveMap[cmc]++;

View file

@ -55,7 +55,7 @@ std::unordered_map<char, int> ManaDevotionWidget::analyzeManaDevotion()
continue; continue;
for (int k = 0; k < currentCard->getNumber(); ++k) { for (int k = 0; k < currentCard->getNumber(); ++k) {
CardInfoPtr info = CardDatabaseManager::getInstance()->getCardInfo(currentCard->getName()); CardInfoPtr info = CardDatabaseManager::query()->getCardInfo(currentCard->getName());
if (info) { if (info) {
auto devotion = countManaSymbols(info->getManaCost()); auto devotion = countManaSymbols(info->getManaCost());
mergeManaCounts(manaDevotionMap, devotion); mergeManaCounts(manaDevotionMap, devotion);

View file

@ -182,11 +182,11 @@ ExactCard DeckEditorDatabaseDisplayWidget::getCardOrPinnedPrinting(QString cardN
{ {
const auto &cardProviderId = SettingsCache::instance().cardOverrides().getCardPreferenceOverride(cardName); const auto &cardProviderId = SettingsCache::instance().cardOverrides().getCardPreferenceOverride(cardName);
ExactCard card = CardDatabaseManager::getInstance()->getCard({cardName}); ExactCard card = CardDatabaseManager::query()->getCard({cardName});
if (cardProviderId != "") { if (cardProviderId != "") {
return ExactCard(card.getCardPtr(), return ExactCard(card.getCardPtr(),
CardDatabaseManager::getInstance()->getSpecificPrinting({cardName, cardProviderId})); CardDatabaseManager::query()->getSpecificPrinting({cardName, cardProviderId}));
} }
return card; return card;

View file

@ -227,7 +227,7 @@ ExactCard DeckEditorDeckDockWidget::getCurrentCard()
if (!current.model()->hasChildren(current.sibling(current.row(), 0))) { if (!current.model()->hasChildren(current.sibling(current.row(), 0))) {
QString cardName = current.sibling(current.row(), 1).data().toString(); QString cardName = current.sibling(current.row(), 1).data().toString();
QString providerId = current.sibling(current.row(), 4).data().toString(); QString providerId = current.sibling(current.row(), 4).data().toString();
if (ExactCard selectedCard = CardDatabaseManager::getInstance()->getCard({cardName, providerId})) { if (ExactCard selectedCard = CardDatabaseManager::query()->getCard({cardName, providerId})) {
return selectedCard; return selectedCard;
} }
} }
@ -286,7 +286,7 @@ void DeckEditorDeckDockWidget::updateBannerCardComboBox()
continue; continue;
for (int k = 0; k < currentCard->getNumber(); ++k) { for (int k = 0; k < currentCard->getNumber(); ++k) {
if (CardDatabaseManager::getInstance()->getCard(currentCard->toCardRef())) { if (CardDatabaseManager::query()->getCard(currentCard->toCardRef())) {
bannerCardSet.insert({currentCard->getName(), currentCard->getCardProviderId()}); bannerCardSet.insert({currentCard->getName(), currentCard->getCardProviderId()});
} }
} }
@ -486,7 +486,7 @@ bool DeckEditorDeckDockWidget::swapCard(const QModelIndex &currentIndex)
offsetCountAtIndex(currentIndex, -1); offsetCountAtIndex(currentIndex, -1);
const QString otherZoneName = zoneName == DECK_ZONE_MAIN ? DECK_ZONE_SIDE : DECK_ZONE_MAIN; const QString otherZoneName = zoneName == DECK_ZONE_MAIN ? DECK_ZONE_SIDE : DECK_ZONE_MAIN;
ExactCard card = CardDatabaseManager::getInstance()->getCard({cardName, cardProviderID}); ExactCard card = CardDatabaseManager::query()->getCard({cardName, cardProviderID});
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);

View file

@ -89,7 +89,7 @@ void HomeWidget::updateRandomCard()
break; break;
case BackgroundSources::RandomCardArt: case BackgroundSources::RandomCardArt:
do { do {
newCard = CardDatabaseManager::getInstance()->getRandomCard(); newCard = CardDatabaseManager::query()->getRandomCard();
} while (newCard == backgroundSourceCard->getCard() && } while (newCard == backgroundSourceCard->getCard() &&
newCard.getCardPtr()->getProperty("layout") != "normal"); newCard.getCardPtr()->getProperty("layout") != "normal");
break; break;
@ -99,17 +99,17 @@ void HomeWidget::updateRandomCard()
if (!cardRefs.empty()) { if (!cardRefs.empty()) {
if (cardRefs.size() == 1) { if (cardRefs.size() == 1) {
newCard = CardDatabaseManager::getInstance()->getCard(cardRefs.first()); newCard = CardDatabaseManager::query()->getCard(cardRefs.first());
} else { } else {
// Keep picking until different // Keep picking until different
do { do {
int idx = QRandomGenerator::global()->bounded(cardRefs.size()); int idx = QRandomGenerator::global()->bounded(cardRefs.size());
newCard = CardDatabaseManager::getInstance()->getCard(cardRefs.at(idx)); newCard = CardDatabaseManager::query()->getCard(cardRefs.at(idx));
} while (newCard == oldCard); } while (newCard == oldCard);
} }
} else { } else {
do { do {
newCard = CardDatabaseManager::getInstance()->getRandomCard(); newCard = CardDatabaseManager::query()->getRandomCard();
} while (newCard == oldCard); } while (newCard == oldCard);
} }
break; break;

View file

@ -196,7 +196,7 @@ void PrintingSelectorCardOverlayWidget::customMenu(QPoint point)
const QString &relatedCardName = rel->getName(); const QString &relatedCardName = rel->getName();
QAction *relatedCard = relatedMenu->addAction(relatedCardName); QAction *relatedCard = relatedMenu->addAction(relatedCardName);
connect(relatedCard, &QAction::triggered, deckEditor, [this, relatedCardName] { connect(relatedCard, &QAction::triggered, deckEditor, [this, relatedCardName] {
deckEditor->updateCard(CardDatabaseManager::getInstance()->getCard({relatedCardName})); deckEditor->updateCard(CardDatabaseManager::query()->getCard({relatedCardName}));
deckEditor->showPrintingSelector(); deckEditor->showPrintingSelector();
}); });
} }

View file

@ -12,7 +12,7 @@ VisualDatabaseDisplayMainTypeFilterWidget::VisualDatabaseDisplayMainTypeFilterWi
FilterTreeModel *_filterModel) FilterTreeModel *_filterModel)
: QWidget(parent), filterModel(_filterModel) : QWidget(parent), filterModel(_filterModel)
{ {
allMainCardTypesWithCount = CardDatabaseManager::getInstance()->getAllMainCardTypesWithCount(); allMainCardTypesWithCount = CardDatabaseManager::query()->getAllMainCardTypesWithCount();
// Get all main card types with their count // Get all main card types with their count
setMaximumHeight(75); setMaximumHeight(75);

View file

@ -13,7 +13,7 @@ VisualDatabaseDisplaySubTypeFilterWidget::VisualDatabaseDisplaySubTypeFilterWidg
FilterTreeModel *_filterModel) FilterTreeModel *_filterModel)
: QWidget(parent), filterModel(_filterModel) : QWidget(parent), filterModel(_filterModel)
{ {
allSubCardTypesWithCount = CardDatabaseManager::getInstance()->getAllSubCardTypesWithCount(); allSubCardTypesWithCount = CardDatabaseManager::query()->getAllSubCardTypesWithCount();
setMinimumWidth(300); setMinimumWidth(300);

View file

@ -303,7 +303,7 @@ void VisualDatabaseDisplayWidget::loadPage(int start, int end)
QVariant name = databaseDisplayModel->data(index, Qt::DisplayRole); QVariant name = databaseDisplayModel->data(index, Qt::DisplayRole);
qCDebug(VisualDatabaseDisplayLog) << name.toString(); qCDebug(VisualDatabaseDisplayLog) << name.toString();
if (CardInfoPtr info = CardDatabaseManager::getInstance()->getCardInfo(name.toString())) { if (CardInfoPtr info = CardDatabaseManager::query()->getCardInfo(name.toString())) {
if (!setFilters.empty()) { if (!setFilters.empty()) {
SetToPrintingsMap setMap = info->getSets(); SetToPrintingsMap setMap = info->getSets();
for (const CardFilter *setFilter : setFilters) { for (const CardFilter *setFilter : setFilters) {
@ -314,7 +314,7 @@ void VisualDatabaseDisplayWidget::loadPage(int start, int end)
} }
} }
} else { } else {
addCard(CardDatabaseManager::getInstance()->getPreferredCard(info)); addCard(CardDatabaseManager::query()->getPreferredCard(info));
} }
} else { } else {
qCDebug(VisualDatabaseDisplayLog) << "Card not found in database!"; qCDebug(VisualDatabaseDisplayLog) << "Card not found in database!";

View file

@ -101,7 +101,7 @@ QList<ExactCard> VisualDeckEditorSampleHandWidget::getRandomCards(int amountToGe
continue; continue;
for (int k = 0; k < currentCard->getNumber(); ++k) { for (int k = 0; k < currentCard->getNumber(); ++k) {
ExactCard card = CardDatabaseManager::getInstance()->getCard(currentCard->toCardRef()); ExactCard card = CardDatabaseManager::query()->getCard(currentCard->toCardRef());
if (card) { if (card) {
mainDeckCards.append(card); mainDeckCards.append(card);
} }

View file

@ -42,7 +42,7 @@ VisualDeckEditorWidget::VisualDeckEditorWidget(QWidget *parent, DeckListModel *_
if (!searchBar->hasFocus()) if (!searchBar->hasFocus())
return; return;
ExactCard card = CardDatabaseManager::getInstance()->getCard({searchBar->text()}); ExactCard card = CardDatabaseManager::query()->getCard({searchBar->text()});
if (card) { if (card) {
emit cardAdditionRequested(card); emit cardAdditionRequested(card);
} }
@ -103,7 +103,7 @@ VisualDeckEditorWidget::VisualDeckEditorWidget(QWidget *parent, DeckListModel *_
// Search button functionality // Search button functionality
searchPushButton = new QPushButton(this); searchPushButton = new QPushButton(this);
connect(searchPushButton, &QPushButton::clicked, this, [=, this]() { connect(searchPushButton, &QPushButton::clicked, this, [=, this]() {
ExactCard card = CardDatabaseManager::getInstance()->getCard({searchBar->text()}); ExactCard card = CardDatabaseManager::query()->getCard({searchBar->text()});
if (card) { if (card) {
emit cardAdditionRequested(card); emit cardAdditionRequested(card);
} }

View file

@ -76,7 +76,7 @@ void DeckPreviewWidget::initializeUi(const bool deckLoadSuccess)
} }
auto bannerCard = deckLoader->getBannerCard().name.isEmpty() auto bannerCard = deckLoader->getBannerCard().name.isEmpty()
? ExactCard() ? ExactCard()
: CardDatabaseManager::getInstance()->getCard(deckLoader->getBannerCard()); : CardDatabaseManager::query()->getCard(deckLoader->getBannerCard());
bannerCardDisplayWidget->setCard(bannerCard); bannerCardDisplayWidget->setCard(bannerCard);
bannerCardDisplayWidget->setFontSize(24); bannerCardDisplayWidget->setFontSize(24);
@ -160,7 +160,7 @@ QString DeckPreviewWidget::getColorIdentity()
QSet<QChar> colorSet; // A set to collect unique color symbols (e.g., W, U, B, R, G) QSet<QChar> colorSet; // A set to collect unique color symbols (e.g., W, U, B, R, G)
for (const QString &cardName : cardList) { for (const QString &cardName : cardList) {
CardInfoPtr currentCard = CardDatabaseManager::getInstance()->getCardInfo(cardName); CardInfoPtr currentCard = CardDatabaseManager::query()->getCardInfo(cardName);
if (currentCard) { if (currentCard) {
QString colors = currentCard->getColors(); // Assuming this returns something like "WUB" QString colors = currentCard->getColors(); // Assuming this returns something like "WUB"
for (const QChar &color : colors) { for (const QChar &color : colors) {
@ -293,7 +293,7 @@ void DeckPreviewWidget::setBannerCard(int /* changedIndex */)
CardRef cardRef = {name, id}; CardRef cardRef = {name, id};
deckLoader->setBannerCard(cardRef); deckLoader->setBannerCard(cardRef);
deckLoader->saveToFile(filePath, DeckLoader::getFormatFromName(filePath)); deckLoader->saveToFile(filePath, DeckLoader::getFormatFromName(filePath));
bannerCardDisplayWidget->setCard(CardDatabaseManager::getInstance()->getCard(cardRef)); bannerCardDisplayWidget->setCard(CardDatabaseManager::query()->getCard(cardRef));
} }
void DeckPreviewWidget::imageClickedEvent(QMouseEvent *event, DeckPreviewCardPictureWidget *instance) void DeckPreviewWidget::imageClickedEvent(QMouseEvent *event, DeckPreviewCardPictureWidget *instance)

View file

@ -161,7 +161,7 @@ void AbstractTabDeckEditor::openDeck(DeckLoader *deck)
void AbstractTabDeckEditor::setDeck(DeckLoader *_deck) void AbstractTabDeckEditor::setDeck(DeckLoader *_deck)
{ {
deckDockWidget->setDeck(_deck); deckDockWidget->setDeck(_deck);
PictureLoader::cacheCardPixmaps(CardDatabaseManager::getInstance()->getCards(getDeckList()->getCardRefList())); PictureLoader::cacheCardPixmaps(CardDatabaseManager::query()->getCards(getDeckList()->getCardRefList()));
setModified(false); setModified(false);
// If they load a deck, make the deck list appear // If they load a deck, make the deck list appear

View file

@ -12,7 +12,7 @@ EdhrecApiResponseCardDetailsDisplayWidget::EdhrecApiResponseCardDetailsDisplayWi
setLayout(layout); setLayout(layout);
cardPictureWidget = new CardInfoPictureWidget(this); cardPictureWidget = new CardInfoPictureWidget(this);
cardPictureWidget->setCard(CardDatabaseManager::getInstance()->guessCard({toDisplay.sanitized})); cardPictureWidget->setCard(CardDatabaseManager::query()->guessCard({toDisplay.sanitized}));
nameLabel = new QLabel(this); nameLabel = new QLabel(this);
nameLabel->setText(toDisplay.name); nameLabel->setText(toDisplay.name);

View file

@ -15,7 +15,7 @@ EdhrecCommanderResponseCommanderDetailsDisplayWidget::EdhrecCommanderResponseCom
setLayout(layout); setLayout(layout);
commanderPicture = new CardInfoPictureWidget(this); commanderPicture = new CardInfoPictureWidget(this);
commanderPicture->setCard(CardDatabaseManager::getInstance()->getCard({commanderDetails.getName()})); commanderPicture->setCard(CardDatabaseManager::query()->getCard({commanderDetails.getName()}));
QWidget *currentParent = parentWidget(); QWidget *currentParent = parentWidget();
TabEdhRecMain *parentTab = nullptr; TabEdhRecMain *parentTab = nullptr;

View file

@ -136,7 +136,7 @@ void TabEdhRecMain::retranslateUi()
void TabEdhRecMain::doSearch() void TabEdhRecMain::doSearch()
{ {
CardInfoPtr searchedCard = CardDatabaseManager::getInstance()->getCardInfo(searchBar->text()); CardInfoPtr searchedCard = CardDatabaseManager::query()->getCardInfo(searchBar->text());
if (!searchedCard) { if (!searchedCard) {
return; return;
} }

View file

@ -740,7 +740,7 @@ void TabGame::loadDeckForLocalPlayer(Player *localPlayer, int playerId, ServerIn
TabbedDeckViewContainer *deckViewContainer = deckViewContainers.value(playerId); TabbedDeckViewContainer *deckViewContainer = deckViewContainers.value(playerId);
if (playerInfo.has_deck_list()) { if (playerInfo.has_deck_list()) {
DeckLoader newDeck(QString::fromStdString(playerInfo.deck_list())); DeckLoader newDeck(QString::fromStdString(playerInfo.deck_list()));
PictureLoader::cacheCardPixmaps(CardDatabaseManager::getInstance()->getCards(newDeck.getCardRefList())); PictureLoader::cacheCardPixmaps(CardDatabaseManager::query()->getCards(newDeck.getCardRefList()));
deckViewContainer->playerDeckView->setDeck(newDeck); deckViewContainer->playerDeckView->setDeck(newDeck);
localPlayer->setDeck(newDeck); localPlayer->setDeck(newDeck);
} }

View file

@ -20,8 +20,8 @@ bool DeckListSortFilterProxyModel::lessThan(const QModelIndex &left, const QMode
auto *lNode = static_cast<DecklistModelCardNode *>(left.internalPointer()); auto *lNode = static_cast<DecklistModelCardNode *>(left.internalPointer());
auto *rNode = static_cast<DecklistModelCardNode *>(right.internalPointer()); auto *rNode = static_cast<DecklistModelCardNode *>(right.internalPointer());
CardInfoPtr lInfo = CardDatabaseManager::getInstance()->guessCard({lNode->getName()}).getCardPtr(); CardInfoPtr lInfo = CardDatabaseManager::query()->guessCard({lNode->getName()}).getCardPtr();
CardInfoPtr rInfo = CardDatabaseManager::getInstance()->guessCard({rNode->getName()}).getCardPtr(); CardInfoPtr rInfo = CardDatabaseManager::query()->guessCard({rNode->getName()}).getCardPtr();
// Example: multiple tie-break criteria (colors > cmc > name) // Example: multiple tie-break criteria (colors > cmc > name)
for (const QString &crit : sortCriteria) { for (const QString &crit : sortCriteria) {

View file

@ -8,6 +8,8 @@ set(dbconverter_SOURCES
../cockatrice/src/card/card_info.cpp ../cockatrice/src/card/card_info.cpp
../cockatrice/src/card/exact_card.cpp ../cockatrice/src/card/exact_card.cpp
../cockatrice/src/database/card_database.cpp ../cockatrice/src/database/card_database.cpp
../cockatrice/src/database/card_database_loader.cpp
../cockatrice/src/database/card_database_querier.cpp
../cockatrice/src/database/parser/card_database_parser.cpp ../cockatrice/src/database/parser/card_database_parser.cpp
../cockatrice/src/database/parser/cockatrice_xml_3.cpp ../cockatrice/src/database/parser/cockatrice_xml_3.cpp
../cockatrice/src/database/parser/cockatrice_xml_4.cpp ../cockatrice/src/database/parser/cockatrice_xml_4.cpp

View file

@ -9,7 +9,7 @@ class CardDatabaseConverter : public CardDatabase
public: public:
LoadStatus loadCardDatabase(const QString &path) LoadStatus loadCardDatabase(const QString &path)
{ {
return CardDatabase::loadCardDatabase(path); return loader->loadCardDatabase(path);
} }
bool saveCardDatabase(const QString &fileName) bool saveCardDatabase(const QString &fileName)

View file

@ -21,6 +21,8 @@ add_executable(
../../cockatrice/src/card/card_info.cpp ../../cockatrice/src/card/card_info.cpp
../../cockatrice/src/card/exact_card.cpp ../../cockatrice/src/card/exact_card.cpp
../../cockatrice/src/database/card_database.cpp ../../cockatrice/src/database/card_database.cpp
../../cockatrice/src/database/card_database_loader.cpp
../../cockatrice/src/database/card_database_querier.cpp
../../cockatrice/src/database/parser/card_database_parser.cpp ../../cockatrice/src/database/parser/card_database_parser.cpp
../../cockatrice/src/database/parser/cockatrice_xml_3.cpp ../../cockatrice/src/database/parser/cockatrice_xml_3.cpp
../../cockatrice/src/database/parser/cockatrice_xml_4.cpp ../../cockatrice/src/database/parser/cockatrice_xml_4.cpp
@ -35,6 +37,8 @@ add_executable(
../../cockatrice/src/card/card_info.cpp ../../cockatrice/src/card/card_info.cpp
../../cockatrice/src/card/exact_card.cpp ../../cockatrice/src/card/exact_card.cpp
../../cockatrice/src/database/card_database.cpp ../../cockatrice/src/database/card_database.cpp
../../cockatrice/src/database/card_database_loader.cpp
../../cockatrice/src/database/card_database_querier.cpp
../../cockatrice/src/database/card_database_manager.cpp ../../cockatrice/src/database/card_database_manager.cpp
../../cockatrice/src/database/parser/card_database_parser.cpp ../../cockatrice/src/database/parser/card_database_parser.cpp
../../cockatrice/src/database/parser/cockatrice_xml_3.cpp ../../cockatrice/src/database/parser/cockatrice_xml_3.cpp

View file

@ -13,21 +13,21 @@ TEST(CardDatabaseTest, LoadXml)
// ensure the card database is empty at start // ensure the card database is empty at start
ASSERT_EQ(0, db->getCardList().size()) << "Cards not empty at start"; ASSERT_EQ(0, db->getCardList().size()) << "Cards not empty at start";
ASSERT_EQ(0, db->getSetList().size()) << "Sets not empty at start"; ASSERT_EQ(0, db->getSetList().size()) << "Sets not empty at start";
ASSERT_EQ(0, db->getAllMainCardTypes().size()) << "Types not empty at start"; ASSERT_EQ(0, db->query()->getAllMainCardTypes().size()) << "Types not empty at start";
ASSERT_EQ(NotLoaded, db->getLoadStatus()) << "Incorrect status at start"; ASSERT_EQ(NotLoaded, db->getLoadStatus()) << "Incorrect status at start";
// load dummy cards and test result // load dummy cards and test result
db->loadCardDatabases(); db->loadCardDatabases();
ASSERT_EQ(9, db->getCardList().size()) << "Wrong card count after load"; ASSERT_EQ(9, db->getCardList().size()) << "Wrong card count after load";
ASSERT_EQ(5, db->getSetList().size()) << "Wrong sets count after load"; ASSERT_EQ(5, db->getSetList().size()) << "Wrong sets count after load";
ASSERT_EQ(3, db->getAllMainCardTypes().size()) << "Wrong types count after load"; ASSERT_EQ(3, db->query()->getAllMainCardTypes().size()) << "Wrong types count after load";
ASSERT_EQ(Ok, db->getLoadStatus()) << "Wrong status after load"; ASSERT_EQ(Ok, db->getLoadStatus()) << "Wrong status after load";
// ensure the card database is empty after clear() // ensure the card database is empty after clear()
db->clear(); db->clear();
ASSERT_EQ(0, db->getCardList().size()) << "Cards not empty after clear"; ASSERT_EQ(0, db->getCardList().size()) << "Cards not empty after clear";
ASSERT_EQ(0, db->getSetList().size()) << "Sets not empty after clear"; ASSERT_EQ(0, db->getSetList().size()) << "Sets not empty after clear";
ASSERT_EQ(0, db->getAllMainCardTypes().size()) << "Types not empty after clear"; ASSERT_EQ(0, db->query()->getAllMainCardTypes().size()) << "Types not empty after clear";
ASSERT_EQ(NotLoaded, db->getLoadStatus()) << "Incorrect status after clear"; ASSERT_EQ(NotLoaded, db->getLoadStatus()) << "Incorrect status after clear";
} }
} // namespace } // namespace

View file

@ -18,10 +18,10 @@ class CardQuery : public ::testing::Test
protected: protected:
void SetUp() override void SetUp() override
{ {
cat = CardDatabaseManager::getInstance()->getCardBySimpleName("Cat"); cat = CardDatabaseManager::query()->getCardBySimpleName("Cat");
notDeadAfterAll = CardDatabaseManager::getInstance()->getCardBySimpleName("Not Dead"); notDeadAfterAll = CardDatabaseManager::query()->getCardBySimpleName("Not Dead");
truth = CardDatabaseManager::getInstance()->getCardBySimpleName("Truth"); truth = CardDatabaseManager::query()->getCardBySimpleName("Truth");
doctor = CardDatabaseManager::getInstance()->getCardBySimpleName("Doctor"); doctor = CardDatabaseManager::query()->getCardBySimpleName("Doctor");
} }
// void TearDown() override {} // void TearDown() override {}