diff --git a/cockatrice/src/carddatabase.cpp b/cockatrice/src/carddatabase.cpp index eff101f9..c55148aa 100644 --- a/cockatrice/src/carddatabase.cpp +++ b/cockatrice/src/carddatabase.cpp @@ -434,6 +434,13 @@ int CardInfo::getPreferredMuId() return muIds[getPreferredSet()->getShortName()]; } +QString CardInfo::simplifyName(const QString &name) { + QString simpleName(name); + simpleName.remove(QRegExp("[^a-zA-Z0-9 ]")); + simpleName = simpleName.toLower(); + return simpleName; +} + static QXmlStreamWriter &operator<<(QXmlStreamWriter &xml, const CardInfo *info) { xml.writeStartElement("card"); @@ -507,55 +514,57 @@ CardDatabase::~CardDatabase() void CardDatabase::clear() { - QHashIterator setIt(setHash); + QHashIterator setIt(sets); while (setIt.hasNext()) { setIt.next(); delete setIt.value(); } - setHash.clear(); + sets.clear(); - QHashIterator i(cardHash); + QHashIterator i(cards); while (i.hasNext()) { i.next(); delete i.value(); } - cardHash.clear(); + cards.clear(); + + // The pointers themselves were already deleted, so we don't delete them + // again. + simpleNameCards.clear(); } void CardDatabase::addCard(CardInfo *card) { - cardHash.insert(card->getName(), card); + cards.insert(card->getName(), card); + simpleNameCards.insert(CardInfo::simplifyName(card->getName()), card); emit cardAdded(card); } void CardDatabase::removeCard(CardInfo *card) { - cardHash.remove(card->getName()); + cards.remove(card->getName()); + simpleNameCards.remove(CardInfo::simplifyName(card->getName())); emit cardRemoved(card); } -CardInfo *CardDatabase::getCard(const QString &cardName, bool createIfNotFound) -{ - if (cardName.isEmpty()) - return noCard; - else if (cardHash.contains(cardName)) - return cardHash.value(cardName); - else if (createIfNotFound) { - CardInfo *newCard = new CardInfo(this, cardName, true); - newCard->addToSet(getSet("TK")); - cardHash.insert(cardName, newCard); - return newCard; - } else - return 0; +CardInfo *CardDatabase::getCard(const QString &cardName, bool createIfNotFound) { + return getCardFromMap(cards, cardName, createIfNotFound); +} + +CardInfo *CardDatabase::getCardBySimpleName(const QString &cardName, bool createIfNotFound) { + QString simpleName = CardInfo::simplifyName(cardName); + qDebug() << "Getting card by name " << simpleName << "\n"; + qDebug() << "Cards available: " << simpleNameCards.size() << "\n"; + return getCardFromMap(simpleNameCards, simpleName, createIfNotFound); } CardSet *CardDatabase::getSet(const QString &setName) { - if (setHash.contains(setName)) - return setHash.value(setName); + if (sets.contains(setName)) + return sets.value(setName); else { CardSet *newSet = new CardSet(setName); - setHash.insert(setName, newSet); + sets.insert(setName, newSet); return newSet; } } @@ -563,7 +572,7 @@ CardSet *CardDatabase::getSet(const QString &setName) SetList CardDatabase::getSetList() const { SetList result; - QHashIterator i(setHash); + QHashIterator i(sets); while (i.hasNext()) { i.next(); result << i.value(); @@ -573,7 +582,9 @@ SetList CardDatabase::getSetList() const void CardDatabase::clearPixmapCache() { - QHashIterator i(cardHash); + // This also clears the cards in simpleNameCards since they point to the + // same object. + QHashIterator i(cards); while (i.hasNext()) { i.next(); i.value()->clearPixmapCache(); @@ -597,7 +608,7 @@ void CardDatabase::loadSetsFromXml(QXmlStreamReader &xml) else if (xml.name() == "longname") longName = xml.readElementText(); } - setHash.insert(shortName, new CardSet(shortName, longName)); + sets.insert(shortName, new CardSet(shortName, longName)); } } } @@ -647,11 +658,25 @@ void CardDatabase::loadCardsFromXml(QXmlStreamReader &xml) else if (xml.name() == "token") isToken = xml.readElementText().toInt(); } - cardHash.insert(name, new CardInfo(this, name, isToken, manacost, type, pt, text, colors, loyalty, cipt, tableRow, sets, muids)); + addCard(new CardInfo(this, name, isToken, manacost, type, pt, text, colors, loyalty, cipt, tableRow, sets, muids)); } } } +CardInfo *CardDatabase::getCardFromMap(CardNameMap &cardMap, const QString &cardName, bool createIfNotFound) { + if (cardName.isEmpty()) + return noCard; + else if (cardMap.contains(cardName)) + return cardMap.value(cardName); + else if (createIfNotFound) { + CardInfo *newCard = new CardInfo(this, cardName, true); + newCard->addToSet(getSet("TK")); + cardMap.insert(cardName, newCard); + return newCard; + } else + return 0; +} + LoadStatus CardDatabase::loadFromFile(const QString &fileName, bool tokens) { QFile file(fileName); @@ -660,31 +685,32 @@ LoadStatus CardDatabase::loadFromFile(const QString &fileName, bool tokens) return FileError; if (tokens) { - QMutableHashIterator i(cardHash); + QMutableHashIterator i(cards); while (i.hasNext()) { i.next(); if (i.value()->getIsToken()) { + removeCard(i.value()); delete i.value(); - i.remove(); } } } else { - QHashIterator setIt(setHash); + QHashIterator setIt(sets); while (setIt.hasNext()) { setIt.next(); delete setIt.value(); } - setHash.clear(); + sets.clear(); - QMutableHashIterator i(cardHash); + QMutableHashIterator i(cards); while (i.hasNext()) { i.next(); if (!i.value()->getIsToken()) { + removeCard(i.value()); delete i.value(); - i.remove(); } } - cardHash.clear(); + cards.clear(); + simpleNameCards.clear(); } QXmlStreamReader xml(&file); @@ -707,9 +733,9 @@ LoadStatus CardDatabase::loadFromFile(const QString &fileName, bool tokens) } } } - qDebug() << cardHash.size() << "cards in" << setHash.size() << "sets loaded"; + qDebug() << cards.size() << "cards in" << sets.size() << "sets loaded"; - if (cardHash.isEmpty()) return NoCards; + if (cards.isEmpty()) return NoCards; return Ok; } @@ -728,14 +754,14 @@ bool CardDatabase::saveToFile(const QString &fileName, bool tokens) if (!tokens) { xml.writeStartElement("sets"); - QHashIterator setIterator(setHash); + QHashIterator setIterator(sets); while (setIterator.hasNext()) xml << setIterator.next().value(); xml.writeEndElement(); // sets } xml.writeStartElement("cards"); - QHashIterator cardIterator(cardHash); + QHashIterator cardIterator(cards); while (cardIterator.hasNext()) { CardInfo *card = cardIterator.next().value(); if (card->getIsToken() == tokens) @@ -753,7 +779,7 @@ void CardDatabase::picDownloadChanged() { pictureLoader->setPicDownload(settingsCache->getPicDownload()); if (settingsCache->getPicDownload()) { - QHashIterator cardIterator(cardHash); + QHashIterator cardIterator(cards); while (cardIterator.hasNext()) cardIterator.next().value()->clearPixmapCacheMiss(); } @@ -763,7 +789,7 @@ void CardDatabase::picDownloadHqChanged() { pictureLoader->setPicDownloadHq(settingsCache->getPicDownloadHq()); if (settingsCache->getPicDownloadHq()) { - QHashIterator cardIterator(cardHash); + QHashIterator cardIterator(cards); while (cardIterator.hasNext()) cardIterator.next().value()->clearPixmapCacheMiss(); } @@ -777,7 +803,7 @@ LoadStatus CardDatabase::loadCardDatabase(const QString &path, bool tokens) if (tempLoadStatus == Ok) { SetList allSets; - QHashIterator setsIterator(setHash); + QHashIterator setsIterator(sets); while (setsIterator.hasNext()) allSets.append(setsIterator.next().value()); allSets.sortByKey(); @@ -809,7 +835,7 @@ void CardDatabase::loadTokenDatabase() QStringList CardDatabase::getAllColors() const { QSet colors; - QHashIterator cardIterator(cardHash); + QHashIterator cardIterator(cards); while (cardIterator.hasNext()) { const QStringList &cardColors = cardIterator.next().value()->getColors(); if (cardColors.isEmpty()) @@ -824,7 +850,7 @@ QStringList CardDatabase::getAllColors() const QStringList CardDatabase::getAllMainCardTypes() const { QSet types; - QHashIterator cardIterator(cardHash); + QHashIterator cardIterator(cards); while (cardIterator.hasNext()) types.insert(cardIterator.next().value()->getMainCardType()); return types.toList(); diff --git a/cockatrice/src/carddatabase.h b/cockatrice/src/carddatabase.h index 09edeff4..50a4d1b7 100644 --- a/cockatrice/src/carddatabase.h +++ b/cockatrice/src/carddatabase.h @@ -95,6 +95,13 @@ private: CardDatabase *db; QString name; + + /* + * The name without punctuation or capitalization, for better card tag name + * recognition. + */ + QString simpleName; + bool isToken; SetList sets; QString manacost; @@ -153,6 +160,12 @@ public: void imageLoaded(const QImage &image); CardSet *getPreferredSet(); int getPreferredMuId(); + + /** + * Simplify a name to have no punctuation and lowercase all letters, for + * less strict name-matching. + */ + static QString simplifyName(const QString &name); public slots: void updatePixmapCache(); signals: @@ -162,11 +175,27 @@ signals: enum LoadStatus { Ok, VersionTooOld, Invalid, NotLoaded, FileError, NoCards }; +typedef QHash CardNameMap; +typedef QHash SetNameMap; + class CardDatabase : public QObject { Q_OBJECT protected: - QHash cardHash; - QHash setHash; + /* + * The cards, indexed by name. + */ + CardNameMap cards; + + /** + * The cards, indexed by their simple name. + */ + CardNameMap simpleNameCards; + + /* + * The sets, indexed by short name. + */ + SetNameMap sets; + CardInfo *noCard; QThread *pictureLoaderThread; @@ -176,6 +205,8 @@ private: static const int versionNeeded; void loadCardsFromXml(QXmlStreamReader &xml); void loadSetsFromXml(QXmlStreamReader &xml); + + CardInfo *getCardFromMap(CardNameMap &cardMap, const QString &cardName, bool createIfNotFound); public: CardDatabase(QObject *parent = 0); ~CardDatabase(); @@ -183,8 +214,15 @@ public: void addCard(CardInfo *card); void removeCard(CardInfo *card); CardInfo *getCard(const QString &cardName = QString(), bool createIfNotFound = true); + + /* + * Get a card by its simple name. The name will be simplified in this + * function, so you don't need to simplify it beforehand. + */ + CardInfo *getCardBySimpleName(const QString &cardName = QString(), bool createIfNotFound = true); + CardSet *getSet(const QString &setName); - QList getCardList() const { return cardHash.values(); } + QList getCardList() const { return cards.values(); } SetList getSetList() const; LoadStatus loadFromFile(const QString &fileName, bool tokens = false); bool saveToFile(const QString &fileName, bool tokens = false); diff --git a/cockatrice/src/cardinfowidget.cpp b/cockatrice/src/cardinfowidget.cpp index 6b5e995a..21b00a13 100644 --- a/cockatrice/src/cardinfowidget.cpp +++ b/cockatrice/src/cardinfowidget.cpp @@ -81,7 +81,7 @@ CardInfoWidget::CardInfoWidget(ResizeMode _mode, const QString &cardName, QWidge } else setFixedWidth(250); - setCard(db->getCard(cardName)); + setCard(getCard(cardName)); setMinimized(settingsCache->getCardInfoMinimized()); } @@ -166,7 +166,7 @@ void CardInfoWidget::setCard(CardInfo *card) void CardInfoWidget::setCard(const QString &cardName) { - setCard(db->getCard(cardName)); + setCard(getCard(cardName)); } void CardInfoWidget::setCard(AbstractCardItem *card) @@ -176,7 +176,11 @@ void CardInfoWidget::setCard(AbstractCardItem *card) void CardInfoWidget::clear() { - setCard(db->getCard()); + setCard(getCard()); +} + +CardInfo *CardInfoWidget::getCard(const QString &cardName) { + return db->getCardBySimpleName(cardName); } void CardInfoWidget::updatePixmap() @@ -188,7 +192,7 @@ void CardInfoWidget::updatePixmap() if (resizedPixmap) cardPicture->setPixmap(*resizedPixmap); else - cardPicture->setPixmap(*(db->getCard()->getPixmap(QSize(pixmapWidth, pixmapWidth * aspectRatio)))); + cardPicture->setPixmap(*(getCard()->getPixmap(QSize(pixmapWidth, pixmapWidth * aspectRatio)))); } void CardInfoWidget::retranslateUi() diff --git a/cockatrice/src/cardinfowidget.h b/cockatrice/src/cardinfowidget.h index ecfd6eca..b9988a7a 100644 --- a/cockatrice/src/cardinfowidget.h +++ b/cockatrice/src/cardinfowidget.h @@ -42,6 +42,11 @@ private: CardInfo *info; void setMinimized(int _minimized); + /* + * Wrapper around db->getCardBySimpleName. + */ + CardInfo *getCard(const QString &cardName = QString()); + public: CardInfoWidget(ResizeMode _mode, const QString &cardName = QString(), QWidget *parent = 0, Qt::WindowFlags f = 0); void retranslateUi(); diff --git a/oracle/src/oracleimporter.cpp b/oracle/src/oracleimporter.cpp index 70972d92..cdc51095 100644 --- a/oracle/src/oracleimporter.cpp +++ b/oracle/src/oracleimporter.cpp @@ -76,8 +76,8 @@ CardInfo *OracleImporter::addCard(const QString &setName, cardCost.remove(QChar('}')); CardInfo *card; - if (cardHash.contains(cardName)) { - card = cardHash.value(cardName); + if (cards.contains(cardName)) { + card = cards.value(cardName); if (splitCard && !card->getText().contains(fullCardText)) card->setText(card->getText() + "\n---\n" + fullCardText); } else { @@ -117,7 +117,7 @@ CardInfo *OracleImporter::addCard(const QString &setName, tableRow = 2; card->setTableRow(tableRow); - cardHash.insert(cardName, card); + cards.insert(cardName, card); } card->setMuId(setName, cardId); @@ -225,8 +225,8 @@ int OracleImporter::startImport() continue; CardSet *set = new CardSet(curSet->getShortName(), curSet->getLongName()); - if (!setHash.contains(set->getShortName())) - setHash.insert(set->getShortName(), set); + if (!sets.contains(set->getShortName())) + sets.insert(set->getShortName(), set); int setCards = importTextSpoiler(set, curSet->getCards());