diff --git a/cockatrice/src/client/network/sets_model.cpp b/cockatrice/src/client/network/sets_model.cpp index de3521772..a86b710b5 100644 --- a/cockatrice/src/client/network/sets_model.cpp +++ b/cockatrice/src/client/network/sets_model.cpp @@ -195,6 +195,13 @@ void SetsModel::swapRows(int oldRow, int newRow) emit dataChanged(index(0, 0), index(rowCount() - 1, columnCount() - 1)); } +void SetsModel::restoreOriginalOrder() +{ + int numRows = rowCount(); + sets.defaultSort(); + emit dataChanged(index(0, 0), index(numRows - 1, columnCount() - 1)); +} + void SetsModel::sort(int column, Qt::SortOrder order) { QMultiMap setMap; diff --git a/cockatrice/src/client/network/sets_model.h b/cockatrice/src/client/network/sets_model.h index 20b5adbcb..cba1c735d 100644 --- a/cockatrice/src/client/network/sets_model.h +++ b/cockatrice/src/client/network/sets_model.h @@ -49,7 +49,8 @@ public: LongNameCol, ShortNameCol, SetTypeCol, - ReleaseDateCol + ReleaseDateCol, + PriorityCol }; enum Role { @@ -80,6 +81,7 @@ public: void sort(int column, Qt::SortOrder order = Qt::AscendingOrder); void save(CardDatabase *db); void restore(CardDatabase *db); + void restoreOriginalOrder(); }; class SetsDisplayModel : public QSortFilterProxyModel diff --git a/cockatrice/src/dialogs/dlg_manage_sets.cpp b/cockatrice/src/dialogs/dlg_manage_sets.cpp index b547a6ed0..ed1a0bd93 100644 --- a/cockatrice/src/dialogs/dlg_manage_sets.cpp +++ b/cockatrice/src/dialogs/dlg_manage_sets.cpp @@ -102,6 +102,7 @@ WndSets::WndSets(QWidget *parent) : QMainWindow(parent) view->sortByColumn(SetsModel::SortKeyCol, Qt::AscendingOrder); view->setColumnHidden(SetsModel::SortKeyCol, true); view->setColumnHidden(SetsModel::IsKnownCol, true); + view->setColumnHidden(SetsModel::PriorityCol, true); view->setRootIsDecorated(false); connect(view->header(), SIGNAL(sectionClicked(int)), this, SLOT(actSort(int))); @@ -254,7 +255,7 @@ void WndSets::actRestore() void WndSets::actRestoreOriginalOrder() { view->header()->setSortIndicator(SORT_RESET, Qt::DescendingOrder); - model->sort(model->ReleaseDateCol, Qt::DescendingOrder); + model->restoreOriginalOrder(); sortWarning->setVisible(false); } diff --git a/cockatrice/src/game/cards/card_database.cpp b/cockatrice/src/game/cards/card_database.cpp index cd101d37f..5372bc1ff 100644 --- a/cockatrice/src/game/cards/card_database.cpp +++ b/cockatrice/src/game/cards/card_database.cpp @@ -23,8 +23,9 @@ const char *CardDatabase::TOKENS_SETNAME = "TK"; CardSet::CardSet(const QString &_shortName, const QString &_longName, const QString &_setType, - const QDate &_releaseDate) - : shortName(_shortName), longName(_longName), releaseDate(_releaseDate), setType(_setType) + const QDate &_releaseDate, + const CardSet::Priority _priority) + : shortName(_shortName), longName(_longName), releaseDate(_releaseDate), setType(_setType), priority(_priority) { loadSetOptions(); } @@ -32,9 +33,10 @@ CardSet::CardSet(const QString &_shortName, CardSetPtr CardSet::newInstance(const QString &_shortName, const QString &_longName, const QString &_setType, - const QDate &_releaseDate) + const QDate &_releaseDate, + const Priority _priority) { - CardSetPtr ptr(new CardSet(_shortName, _longName, _setType, _releaseDate)); + CardSetPtr ptr(new CardSet(_shortName, _longName, _setType, _releaseDate, _priority)); // ptr->setSmartPointer(ptr); return ptr; } @@ -195,25 +197,31 @@ void SetList::markAllAsKnown() void SetList::guessSortKeys() { - // sort by release date DESC; invalid dates to the bottom. - QDate distantFuture(2050, 1, 1); - int aHundredYears = 36500; + defaultSort(); for (int i = 0; i < size(); ++i) { CardSetPtr set = at(i); if (set.isNull()) { qDebug() << "guessSortKeys set is null"; continue; } - - QDate date = set->getReleaseDate(); - if (date.isNull()) { - set->setSortKey(static_cast(aHundredYears)); - } else { - set->setSortKey(static_cast(date.daysTo(distantFuture))); - } + set->setSortKey(i); } } +void SetList::defaultSort() +{ + std::sort(begin(), end(), [](const CardSetPtr &a, const CardSetPtr &b) { + // Sort by priority, then by release date, then by short name + if (a->getPriority() != b->getPriority()) { + return a->getPriority() < b->getPriority(); // lowest first + } else if (a->getReleaseDate() != b->getReleaseDate()) { + return a->getReleaseDate() > b->getReleaseDate(); // most recent first + } else { + return a->getShortName() < b->getShortName(); // alphabetically + } + }); +} + CardInfoPerSet::CardInfoPerSet(const CardSetPtr &_set) : set(_set) { } diff --git a/cockatrice/src/game/cards/card_database.h b/cockatrice/src/game/cards/card_database.h index 3322a5bb6..6f73f16a4 100644 --- a/cockatrice/src/game/cards/card_database.h +++ b/cockatrice/src/game/cards/card_database.h @@ -29,22 +29,36 @@ Q_DECLARE_METATYPE(CardInfoPtr) class CardSet : public QList { +public: + enum Priority + { + PriorityFallback = 0, + PriorityPrimary = 10, + PrioritySecondary = 20, + PriorityReprint = 30, + PriorityOther = 40, + PriorityLowest = 100, + }; + private: QString shortName, longName; unsigned int sortKey; QDate releaseDate; QString setType; + Priority priority; bool enabled, isknown; public: explicit CardSet(const QString &_shortName = QString(), const QString &_longName = QString(), const QString &_setType = QString(), - const QDate &_releaseDate = QDate()); + const QDate &_releaseDate = QDate(), + const Priority _priority = PriorityFallback); static CardSetPtr newInstance(const QString &_shortName = QString(), const QString &_longName = QString(), const QString &_setType = QString(), - const QDate &_releaseDate = QDate()); + const QDate &_releaseDate = QDate(), + const Priority _priority = PriorityFallback); QString getCorrectedShortName() const; QString getShortName() const { @@ -62,6 +76,10 @@ public: { return releaseDate; } + Priority getPriority() const + { + return priority; + } void setLongName(const QString &_longName) { longName = _longName; @@ -74,6 +92,10 @@ public: { releaseDate = _releaseDate; } + void setPriority(const Priority _priority) + { + priority = _priority; + } void loadSetOptions(); int getSortKey() const @@ -113,6 +135,7 @@ public: int getEnabledSetsNum(); int getUnknownSetsNum(); QStringList getUnknownSetsNames(); + void defaultSort(); }; class CardInfoPerSet diff --git a/cockatrice/src/game/cards/card_database_parser/card_database_parser.cpp b/cockatrice/src/game/cards/card_database_parser/card_database_parser.cpp index 67dcce748..ac1372f7f 100644 --- a/cockatrice/src/game/cards/card_database_parser/card_database_parser.cpp +++ b/cockatrice/src/game/cards/card_database_parser/card_database_parser.cpp @@ -10,7 +10,8 @@ void ICardDatabaseParser::clearSetlist() CardSetPtr ICardDatabaseParser::internalAddSet(const QString &setName, const QString &longName, const QString &setType, - const QDate &releaseDate) + const QDate &releaseDate, + const CardSet::Priority priority) { if (sets.contains(setName)) { return sets.value(setName); @@ -20,8 +21,9 @@ CardSetPtr ICardDatabaseParser::internalAddSet(const QString &setName, newSet->setLongName(longName); newSet->setSetType(setType); newSet->setReleaseDate(releaseDate); + newSet->setPriority(priority); sets.insert(setName, newSet); emit addSet(newSet); return newSet; -} \ No newline at end of file +} diff --git a/cockatrice/src/game/cards/card_database_parser/card_database_parser.h b/cockatrice/src/game/cards/card_database_parser/card_database_parser.h index 0bc2b9d98..87e8eec5e 100644 --- a/cockatrice/src/game/cards/card_database_parser/card_database_parser.h +++ b/cockatrice/src/game/cards/card_database_parser/card_database_parser.h @@ -32,7 +32,8 @@ protected: CardSetPtr internalAddSet(const QString &setName, const QString &longName = "", const QString &setType = "", - const QDate &releaseDate = QDate()); + const QDate &releaseDate = QDate(), + const CardSet::Priority priority = CardSet::PriorityFallback); signals: virtual void addCard(CardInfoPtr card) = 0; virtual void addSet(CardSetPtr set) = 0; @@ -40,4 +41,4 @@ signals: Q_DECLARE_INTERFACE(ICardDatabaseParser, "ICardDatabaseParser") -#endif \ No newline at end of file +#endif diff --git a/cockatrice/src/game/cards/card_database_parser/cockatrice_xml_4.cpp b/cockatrice/src/game/cards/card_database_parser/cockatrice_xml_4.cpp index 7b6fb75e7..f2c50d8d4 100644 --- a/cockatrice/src/game/cards/card_database_parser/cockatrice_xml_4.cpp +++ b/cockatrice/src/game/cards/card_database_parser/cockatrice_xml_4.cpp @@ -77,6 +77,7 @@ void CockatriceXml4Parser::loadSetsFromXml(QXmlStreamReader &xml) if (xmlName == "set") { QString shortName, longName, setType; QDate releaseDate; + short priority; while (!xml.atEnd()) { if (xml.readNext() == QXmlStreamReader::EndElement) { break; @@ -92,6 +93,8 @@ void CockatriceXml4Parser::loadSetsFromXml(QXmlStreamReader &xml) } else if (xmlName == "releasedate") { releaseDate = QDate::fromString(xml.readElementText(QXmlStreamReader::IncludeChildElements), Qt::ISODate); + } else if (xmlName == "priority") { + priority = xml.readElementText(QXmlStreamReader::IncludeChildElements).toShort(); } else if (!xmlName.isEmpty()) { qDebug() << "[CockatriceXml4Parser] Unknown set property" << xmlName << ", trying to continue anyway"; @@ -99,7 +102,7 @@ void CockatriceXml4Parser::loadSetsFromXml(QXmlStreamReader &xml) } } - internalAddSet(shortName, longName, setType, releaseDate); + internalAddSet(shortName, longName, setType, releaseDate, static_cast(priority)); } } } @@ -249,6 +252,7 @@ static QXmlStreamWriter &operator<<(QXmlStreamWriter &xml, const CardSetPtr &set xml.writeTextElement("longname", set->getLongName()); xml.writeTextElement("settype", set->getSetType()); xml.writeTextElement("releasedate", set->getReleaseDate().toString(Qt::ISODate)); + xml.writeTextElement("priority", QString::number(set->getPriority())); xml.writeEndElement(); return xml; diff --git a/doc/carddatabase_v4/cards.xsd b/doc/carddatabase_v4/cards.xsd index d8c4c299e..00ed72555 100644 --- a/doc/carddatabase_v4/cards.xsd +++ b/doc/carddatabase_v4/cards.xsd @@ -15,6 +15,7 @@ + diff --git a/oracle/src/oracleimporter.cpp b/oracle/src/oracleimporter.cpp index c21ce72be..bfa68e64e 100644 --- a/oracle/src/oracleimporter.cpp +++ b/oracle/src/oracleimporter.cpp @@ -19,6 +19,18 @@ OracleImporter::OracleImporter(const QString &_dataDir, QObject *parent) : CardD { } +CardSet::Priority OracleImporter::getSetPriority(QString &setType, QString &shortName) +{ + if (!setTypePriorities.contains(setType.toLower())) { + qDebug() << "warning: Set type" << setType << "unrecognized for prioritization"; + } + CardSet::Priority priority = setTypePriorities.value(setType.toLower(), CardSet::PriorityOther); + if (nonEnglishSets.contains(shortName)) { + priority = CardSet::PriorityLowest; + } + return priority; +} + bool OracleImporter::readSetsFromByteArray(const QByteArray &data) { QList newSetList; @@ -38,6 +50,7 @@ bool OracleImporter::readSetsFromByteArray(const QByteArray &data) QList setCards; QString setType; QDate releaseDate; + CardSet::Priority priority; while (it.hasNext()) { map = it.next().toMap(); @@ -45,6 +58,8 @@ bool OracleImporter::readSetsFromByteArray(const QByteArray &data) longName = map.value("name").toString(); setCards = map.value("cards").toList(); setType = map.value("type").toString(); + releaseDate = map.value("releaseDate").toDate(); + priority = getSetPriority(setType, shortName); // capitalize set type if (setType.length() > 0) { // basic grammar for words that aren't capitalized, like in "From the Vault" @@ -62,12 +77,7 @@ bool OracleImporter::readSetsFromByteArray(const QByteArray &data) } setType = setType.trimmed(); } - if (!nonEnglishSets.contains(shortName)) { - releaseDate = map.value("releaseDate").toDate(); - } else { - releaseDate = QDate(); - } - newSetList.append(SetToDownload(shortName, longName, setCards, setType, releaseDate)); + newSetList.append(SetToDownload(shortName, longName, setCards, priority, setType, releaseDate)); } std::sort(newSetList.begin(), newSetList.end()); @@ -493,8 +503,9 @@ int OracleImporter::startImport() sets.insert(TOKENS_SETNAME, tokenSet); for (const SetToDownload &curSetToParse : allSets) { - CardSetPtr newSet = CardSet::newInstance(curSetToParse.getShortName(), curSetToParse.getLongName(), - curSetToParse.getSetType(), curSetToParse.getReleaseDate()); + CardSetPtr newSet = + CardSet::newInstance(curSetToParse.getShortName(), curSetToParse.getLongName(), curSetToParse.getSetType(), + curSetToParse.getReleaseDate(), curSetToParse.getPriority()); if (!sets.contains(newSet->getShortName())) sets.insert(newSet->getShortName(), newSet); diff --git a/oracle/src/oracleimporter.h b/oracle/src/oracleimporter.h index 7c1c21bf8..48b609e2f 100644 --- a/oracle/src/oracleimporter.h +++ b/oracle/src/oracleimporter.h @@ -7,11 +7,36 @@ #include // many users prefer not to see these sets with non english arts -// as a solution we remove the date property on these sets -// that way they will be sorted last by default -// this will cause their art to not get priority over english cards -// users will still be able to find these sets and prioritize them manually +// they will given priority PriorityLowest const QStringList nonEnglishSets = {"4BB", "FBB", "PS11", "PSAL", "REN", "RIN"}; +const QMap setTypePriorities{ + {"core", CardSet::PriorityPrimary}, + {"expansion", CardSet::PriorityPrimary}, + + {"commander", CardSet::PrioritySecondary}, + {"starter", CardSet::PrioritySecondary}, + {"draft_innovation", CardSet::PrioritySecondary}, + {"duel_deck", CardSet::PrioritySecondary}, + + {"archenemy", CardSet::PriorityReprint}, + {"arsenal", CardSet::PriorityReprint}, + {"box", CardSet::PriorityReprint}, + {"from_the_vault", CardSet::PriorityReprint}, + {"masterpiece", CardSet::PriorityReprint}, + {"masters", CardSet::PriorityReprint}, + {"memorabilia", CardSet::PriorityReprint}, + {"planechase", CardSet::PriorityReprint}, + {"premium_deck", CardSet::PriorityReprint}, + {"promo", CardSet::PriorityReprint}, + {"spellbook", CardSet::PriorityReprint}, + {"token", CardSet::PriorityReprint}, + {"treasure_chest", CardSet::PriorityReprint}, + + {"alchemy", CardSet::PriorityOther}, + {"funny", CardSet::PriorityOther}, + {"minigame", CardSet::PriorityOther}, + {"vanguard", CardSet::PriorityOther}, +}; class SetToDownload { @@ -20,6 +45,7 @@ private: QList cards; QDate releaseDate; QString setType; + CardSet::Priority priority; public: const QString &getShortName() const @@ -42,13 +68,18 @@ public: { return releaseDate; } + CardSet::Priority getPriority() const + { + return priority; + } SetToDownload(QString _shortName, QString _longName, QList _cards, + CardSet::Priority _priority, QString _setType = QString(), const QDate &_releaseDate = QDate()) : shortName(std::move(_shortName)), longName(std::move(_longName)), cards(std::move(_cards)), - releaseDate(_releaseDate), setType(std::move(_setType)) + releaseDate(_releaseDate), setType(std::move(_setType)), priority(_priority) { } bool operator<(const SetToDownload &set) const @@ -108,6 +139,7 @@ signals: public: explicit OracleImporter(const QString &_dataDir, QObject *parent = nullptr); + CardSet::Priority getSetPriority(QString &setType, QString &shortName); bool readSetsFromByteArray(const QByteArray &data); int startImport(); bool saveToFile(const QString &fileName, const QString &sourceUrl, const QString &sourceVersion);