Rework of the card database, xml format and oracle parser (#3511)

* CardDB: merge all card properties in a new structure

* Pre Json parser changes

 * Cockatrice: use qt's builtin json support
 * Move qt-json src dir from cockatrice to oracle
 * Add dummy cockatricexml4 parser (yet to be implemented)

* Implement a new parser and xml format

 * cockatricexml4: new xml parser following the "generic properties hash" pattern;
 * oracleimporter: refactor the parsing code to better adapt to cockatricexml4; rewrote split cards parsing
 * carddb: change "colors" from a stringlist to a string
 * carddb: move the getMainCardType() method to the cockatricexml3 parser
 *

* CardInfo: show all properties (stil missing: nice name + translation)

* Rework the "add related card" feature so that it doesn't change the card name in the carddb

Also, fix token count display

* Picture loader: Added support for transform cards

* Fix side information for flip cards

Mtgjson uses side a/b for flip cards, while scryfall doesn't

* Pictureloader: dynamic tag resolution from card properties

Examples old => new
* !cardid! => !set:muid!
* !uuid!   => !set:uuid!
* !collectornumber! => !set:num!
New examples:
 * !prop:type!
 * !prop:manacost!

* Start moving mtg-related property names to a specific file

* Clangify

* Fix tests

* Make gcc an happy puppy

* Revert "Make gcc an happy puppy"

This reverts commit 446ec5f27516c4d3b32dbfc79557f4827c5c5bdf.

* Some gcc fixes

* Share set list between different db parsers, so they won't overwrite one each other

* All glory to the hypnoclangifier!

* Fix test compilation

* Cleanup edited files in the prior PR. (#3519)

* Cleanup edited files in the prior PR.

Signed-off-by: Zach Halpern <ZaHalpern+github@gmail.com>

* Fix includes

Signed-off-by: Zach Halpern <ZaHalpern+github@gmail.com>

* Update carddatabase.h
This commit is contained in:
ctrlaltca 2019-01-24 00:17:10 +01:00 committed by Zach H
parent 19180243aa
commit ed70099e36
44 changed files with 1814 additions and 1360 deletions

View file

@ -12,11 +12,11 @@ include=("common" \
"cockatrice/src" \
"oracle/src" \
"servatrice/src")
exclude=("cockatrice/src/qt-json" \
"servatrice/src/smtp" \
exclude=("servatrice/src/smtp" \
"common/sfmt" \
"oracle/src/zip" \
"oracle/src/lzma")
"oracle/src/lzma" \
"oracle/src/qt-json")
exts=("cpp" "h")
cf_cmd="clang-format"
branch="origin/master"

View file

@ -100,7 +100,6 @@ SET(cockatrice_SOURCES
src/localserver.cpp
src/localserverinterface.cpp
src/localclient.cpp
src/qt-json/json.cpp
src/soundengine.cpp
src/pending_command.cpp
src/pictureloader.cpp
@ -121,7 +120,9 @@ SET(cockatrice_SOURCES
src/userconnection_information.cpp
src/spoilerbackgroundupdater.cpp
src/handle_public_servers.cpp
src/carddbparser/carddatabaseparser.cpp
src/carddbparser/cockatricexml3.cpp
src/carddbparser/cockatricexml4.cpp
${VERSION_STRING_CPP}
)

View file

@ -1,5 +1,7 @@
#include "carddatabase.h"
#include "carddbparser/cockatricexml3.h"
#include "carddbparser/cockatricexml4.h"
#include "game_specific_terms.h"
#include "pictureloader.h"
#include "settingscache.h"
#include "spoilerbackgroundupdater.h"
@ -207,31 +209,23 @@ void SetList::guessSortKeys()
}
}
CardInfoPerSet::CardInfoPerSet(const CardSetPtr &_set) : set(_set)
{
}
CardInfo::CardInfo(const QString &_name,
bool _isToken,
const QString &_manacost,
const QString &_cmc,
const QString &_cardtype,
const QString &_powtough,
const QString &_text,
const QStringList &_colors,
bool _isToken,
QVariantHash _properties,
const QList<CardRelation *> &_relatedCards,
const QList<CardRelation *> &_reverseRelatedCards,
bool _upsideDownArt,
const QString &_loyalty,
CardInfoPerSetMap _sets,
bool _cipt,
int _tableRow,
const SetList &_sets,
const QStringMap &_customPicURLs,
MuidMap _muIds,
QStringMap _uuIds,
QStringMap _collectorNumbers,
QStringMap _rarities)
: name(_name), isToken(_isToken), sets(_sets), manacost(_manacost), cmc(_cmc), cardtype(_cardtype),
powtough(_powtough), text(_text), colors(_colors), relatedCards(_relatedCards),
reverseRelatedCards(_reverseRelatedCards), setsNames(), upsideDownArt(_upsideDownArt), loyalty(_loyalty),
customPicURLs(_customPicURLs), muIds(std::move(_muIds)), uuIds(std::move(_uuIds)),
collectorNumbers(std::move(_collectorNumbers)), rarities(std::move(_rarities)), cipt(_cipt), tableRow(_tableRow)
bool _upsideDownArt)
: name(_name), text(_text), isToken(_isToken), properties(std::move(_properties)), relatedCards(_relatedCards),
reverseRelatedCards(_reverseRelatedCards), sets(std::move(_sets)), cipt(_cipt), tableRow(_tableRow),
upsideDownArt(_upsideDownArt)
{
pixmapCacheKey = QLatin1String("card_") + name;
simpleName = CardInfo::simplifyName(name);
@ -245,77 +239,27 @@ CardInfo::~CardInfo()
}
CardInfoPtr CardInfo::newInstance(const QString &_name,
bool _isToken,
const QString &_manacost,
const QString &_cmc,
const QString &_cardtype,
const QString &_powtough,
const QString &_text,
const QStringList &_colors,
bool _isToken,
QVariantHash _properties,
const QList<CardRelation *> &_relatedCards,
const QList<CardRelation *> &_reverseRelatedCards,
bool _upsideDownArt,
const QString &_loyalty,
CardInfoPerSetMap _sets,
bool _cipt,
int _tableRow,
const SetList &_sets,
const QStringMap &_customPicURLs,
MuidMap _muIds,
QStringMap _uuIds,
QStringMap _collectorNumbers,
QStringMap _rarities)
bool _upsideDownArt)
{
CardInfoPtr ptr(new CardInfo(_name, _isToken, _manacost, _cmc, _cardtype, _powtough, _text, _colors, _relatedCards,
_reverseRelatedCards, _upsideDownArt, _loyalty, _cipt, _tableRow, _sets,
_customPicURLs, std::move(_muIds), std::move(_uuIds), std::move(_collectorNumbers),
std::move(_rarities)));
CardInfoPtr ptr(new CardInfo(_name, _text, _isToken, std::move(_properties), _relatedCards, _reverseRelatedCards,
_sets, _cipt, _tableRow, _upsideDownArt));
ptr->setSmartPointer(ptr);
for (int i = 0; i < _sets.size(); i++) {
_sets[i]->append(ptr);
for (const CardInfoPerSet &set : _sets) {
set.getPtr()->append(ptr);
}
return ptr;
}
QString CardInfo::getMainCardType() const
{
QString result = getCardType();
/*
Legendary Artifact Creature - Golem
Instant // Instant
*/
int pos;
if ((pos = result.indexOf('-')) != -1) {
result.remove(pos, result.length());
}
if ((pos = result.indexOf("")) != -1) {
result.remove(pos, result.length());
}
if ((pos = result.indexOf("//")) != -1) {
result.remove(pos, result.length());
}
result = result.simplified();
/*
Legendary Artifact Creature
Instant
*/
if ((pos = result.lastIndexOf(' ')) != -1) {
result = result.mid(pos + 1);
}
/*
Creature
Instant
*/
return result;
}
QString CardInfo::getCorrectedName() const
{
QString result = name;
@ -323,26 +267,21 @@ QString CardInfo::getCorrectedName() const
return result.remove(" // ").remove(':').remove('"').remove('?').replace('/', ' ');
}
void CardInfo::addToSet(CardSetPtr set)
void CardInfo::addToSet(const CardSetPtr &_set, const CardInfoPerSet _info)
{
if (set.isNull()) {
qDebug() << "addToSet(nullptr)";
return;
}
set->append(smartThis);
sets << set;
_set->append(smartThis);
sets.insert(_set->getShortName(), _info);
refreshCachedSetNames();
}
void CardInfo::refreshCachedSetNames()
{
// update the cached list of set names
QStringList setList;
for (int i = 0; i < sets.size(); i++) {
if (sets[i]->getEnabled()) {
setList << sets[i]->getShortName();
// update the cached list of set names
for (const auto &set : sets) {
if (set.getPtr()->getEnabled()) {
setList << set.getPtr()->getShortName();
}
}
setsNames = setList.join(", ");
@ -371,11 +310,12 @@ QString CardInfo::simplifyName(const QString &name)
const QChar CardInfo::getColorChar() const
{
QString colors = getColors();
switch (colors.size()) {
case 0:
return QChar();
case 1:
return colors.first().isEmpty() ? QChar() : colors.first().at(0);
return colors.at(0);
default:
return QChar('m');
}
@ -388,6 +328,7 @@ CardDatabase::CardDatabase(QObject *parent) : QObject(parent), loadStatus(NotLoa
// add new parsers here
availableParsers << new CockatriceXml3Parser;
availableParsers << new CockatriceXml4Parser;
for (auto &parser : availableParsers) {
connect(parser, SIGNAL(addCard(CardInfoPtr)), this, SLOT(addCard(CardInfoPtr)), Qt::DirectConnection);
@ -419,9 +360,7 @@ void CardDatabase::clear()
simpleNameCards.clear();
sets.clear();
for (auto parser : availableParsers) {
parser->clearSetlist();
}
ICardDatabaseParser::clearSetlist();
loadStatus = NotLoaded;
@ -438,13 +377,8 @@ void CardDatabase::addCard(CardInfoPtr card)
// if card already exists just add the new set property
if (cards.contains(card->getName())) {
CardInfoPtr sameCard = cards[card->getName()];
for (auto set : card->getSets()) {
QString setName = set->getCorrectedShortName();
sameCard->setSet(set);
sameCard->setMuId(setName, card->getMuId(setName));
sameCard->setUuId(setName, card->getUuId(setName));
sameCard->setRarity(setName, card->getRarity(setName));
sameCard->setSetNumber(setName, card->getCollectorNumber(setName));
for (const CardInfoPerSet &set : card->getSets()) {
sameCard->addToSet(set.getPtr(), set);
}
return;
}
@ -585,7 +519,7 @@ LoadStatus CardDatabase::loadCardDatabases()
// load custom card databases
QDir dir(settingsCache->getCustomCardDatabasePath());
for (QString fileName :
for (const QString &fileName :
dir.entryList(QStringList("*.xml"), QDir::Files | QDir::Readable, QDir::Name | QDir::IgnoreCase)) {
loadCardDatabase(dir.absoluteFilePath(fileName));
}
@ -617,20 +551,13 @@ void CardDatabase::refreshCachedReverseRelatedCards()
continue;
}
QString relatedCardName;
if (card->getPowTough().size() > 0) {
relatedCardName = card->getPowTough() + " " + card->getName(); // "n/n name"
} else {
relatedCardName = card->getName(); // "name"
}
foreach (CardRelation *cardRelation, card->getReverseRelatedCards()) {
const QString &targetCard = cardRelation->getName();
if (!cards.contains(targetCard)) {
continue;
}
auto *newCardRelation = new CardRelation(relatedCardName, cardRelation->getDoesAttach(),
auto *newCardRelation = new CardRelation(card->getName(), cardRelation->getDoesAttach(),
cardRelation->getIsCreateAllExclusion(),
cardRelation->getIsVariable(), cardRelation->getDefaultCount());
cards.value(targetCard)->addReverseRelatedCards2Me(newCardRelation);
@ -638,23 +565,6 @@ void CardDatabase::refreshCachedReverseRelatedCards()
}
}
QStringList CardDatabase::getAllColors() const
{
QSet<QString> colors;
QHashIterator<QString, CardInfoPtr> cardIterator(cards);
while (cardIterator.hasNext()) {
const QStringList &cardColors = cardIterator.next().value()->getColors();
if (cardColors.isEmpty()) {
colors.insert("X");
} else {
for (int i = 0; i < cardColors.size(); ++i) {
colors.insert(cardColors[i]);
}
}
}
return colors.toList();
}
QStringList CardDatabase::getAllMainCardTypes() const
{
QSet<QString> types;
@ -720,8 +630,8 @@ bool CardDatabase::saveCustomTokensToFile()
tmpSets.insert(CardDatabase::TOKENS_SETNAME, customTokensSet);
CardNameMap tmpCards;
for (CardInfoPtr card : cards) {
if (card->getSets().contains(customTokensSet)) {
for (const CardInfoPtr &card : cards) {
if (card->getSets().contains(CardDatabase::TOKENS_SETNAME)) {
tmpCards.insert(card->getName(), card);
}
}
@ -747,3 +657,45 @@ void CardInfo::resetReverseRelatedCards2Me()
}
reverseRelatedCardsToMe = QList<CardRelation *>();
}
// Back-compatibility methods. Remove ASAP
const QString CardInfo::getCardType() const
{
return getProperty(Mtg::CardType);
}
void CardInfo::setCardType(const QString &value)
{
setProperty(Mtg::CardType, value);
}
const QString CardInfo::getCmc() const
{
return getProperty(Mtg::ConvertedManaCost);
}
const QString CardInfo::getColors() const
{
return getProperty(Mtg::Colors);
}
void CardInfo::setColors(const QString &value)
{
setProperty(Mtg::Colors, value);
}
const QString CardInfo::getLoyalty() const
{
return getProperty(Mtg::Loyalty);
}
const QString CardInfo::getMainCardType() const
{
return getProperty(Mtg::MainCardType);
}
const QString CardInfo::getManaCost() const
{
return getProperty(Mtg::ManaCost);
}
const QString CardInfo::getPowTough() const
{
return getProperty(Mtg::PowTough);
}
void CardInfo::setPowTough(const QString &value)
{
setProperty(Mtg::PowTough, value);
}

View file

@ -9,10 +9,13 @@
#include <QMetaType>
#include <QSharedPointer>
#include <QStringList>
#include <QVariant>
#include <QVector>
#include <utility>
class CardDatabase;
class CardInfo;
class CardInfoPerSet;
class CardSet;
class CardRelation;
class ICardDatabaseParser;
@ -21,6 +24,7 @@ typedef QMap<QString, QString> QStringMap;
typedef QMap<QString, int> MuidMap;
typedef QSharedPointer<CardInfo> CardInfoPtr;
typedef QSharedPointer<CardSet> CardSetPtr;
typedef QMap<QString, CardInfoPerSet> CardInfoPerSetMap;
Q_DECLARE_METATYPE(CardInfoPtr)
@ -112,178 +116,162 @@ public:
QStringList getUnknownSetsNames();
};
class CardInfoPerSet
{
public:
explicit CardInfoPerSet(const CardSetPtr &_set = QSharedPointer<CardSet>(nullptr));
~CardInfoPerSet() = default;
private:
CardSetPtr set;
// per-set card properties;
QVariantHash properties;
public:
const CardSetPtr getPtr() const
{
return set;
}
const QStringList getProperties() const
{
return properties.keys();
}
const QString getProperty(const QString &propertyName) const
{
return properties.value(propertyName).toString();
}
void setProperty(const QString &_name, const QString &_value)
{
properties.insert(_name, _value);
}
};
class CardInfo : public QObject
{
Q_OBJECT
private:
CardInfoPtr smartThis;
// The card name
QString name;
/*
* The name without punctuation or capitalization, for better card tag name
* recognition.
*/
// The name without punctuation or capitalization, for better card name recognition.
QString simpleName;
bool isToken;
SetList sets;
QString manacost;
QString cmc;
QString cardtype;
QString powtough;
// The key used to identify this card in the cache
QString pixmapCacheKey;
// card text
QString text;
QStringList colors;
// whether this is not a "real" card but a token
bool isToken;
// basic card properties; common for all the sets
QVariantHash properties;
// the cards i'm related to
QList<CardRelation *> relatedCards;
// the card i'm reverse-related to
QList<CardRelation *> reverseRelatedCards;
// the cards thare are reverse-related to me
QList<CardRelation *> reverseRelatedCardsToMe;
// card sets
CardInfoPerSetMap sets;
// cached set names
QString setsNames;
bool upsideDownArt;
QString loyalty;
QStringMap customPicURLs;
MuidMap muIds;
QStringMap uuIds;
QStringMap collectorNumbers;
QStringMap rarities;
// positioning properties; used by UI
bool cipt;
int tableRow;
QString pixmapCacheKey;
bool upsideDownArt;
public:
explicit CardInfo(const QString &_name = QString(),
bool _isToken = false,
const QString &_manacost = QString(),
const QString &_cmc = QString(),
const QString &_cardtype = QString(),
const QString &_powtough = QString(),
const QString &_text = QString(),
const QStringList &_colors = QStringList(),
bool _isToken = false,
QVariantHash _properties = QVariantHash(),
const QList<CardRelation *> &_relatedCards = QList<CardRelation *>(),
const QList<CardRelation *> &_reverseRelatedCards = QList<CardRelation *>(),
bool _upsideDownArt = false,
const QString &_loyalty = QString(),
CardInfoPerSetMap _sets = CardInfoPerSetMap(),
bool _cipt = false,
int _tableRow = 0,
const SetList &_sets = SetList(),
const QStringMap &_customPicURLs = QStringMap(),
MuidMap _muids = MuidMap(),
QStringMap _uuIds = QStringMap(),
QStringMap _collectorNumbers = QStringMap(),
QStringMap _rarities = QStringMap());
bool _upsideDownArt = false);
~CardInfo() override;
static CardInfoPtr newInstance(const QString &_name = QString(),
bool _isToken = false,
const QString &_manacost = QString(),
const QString &_cmc = QString(),
const QString &_cardtype = QString(),
const QString &_powtough = QString(),
const QString &_text = QString(),
const QStringList &_colors = QStringList(),
bool _isToken = false,
QVariantHash _properties = QVariantHash(),
const QList<CardRelation *> &_relatedCards = QList<CardRelation *>(),
const QList<CardRelation *> &_reverseRelatedCards = QList<CardRelation *>(),
bool _upsideDownArt = false,
const QString &_loyalty = QString(),
CardInfoPerSetMap _sets = CardInfoPerSetMap(),
bool _cipt = false,
int _tableRow = 0,
const SetList &_sets = SetList(),
const QStringMap &_customPicURLs = QStringMap(),
MuidMap _muids = MuidMap(),
QStringMap _uuIds = QStringMap(),
QStringMap _collectorNumbers = QStringMap(),
QStringMap _rarities = QStringMap());
bool _upsideDownArt = false);
void setSmartPointer(CardInfoPtr _ptr)
{
smartThis = _ptr;
smartThis = std::move(_ptr);
}
// basic properties
inline const QString &getName() const
{
return name;
}
inline const QString &getSetsNames() const
{
return setsNames;
}
const QString &getSimpleName() const
{
return simpleName;
}
bool getIsToken() const
{
return isToken;
}
const SetList &getSets() const
{
return sets;
}
inline const QString &getManaCost() const
{
return manacost;
}
inline const QString &getCmc() const
{
return cmc;
}
inline const QString &getCardType() const
{
return cardtype;
}
inline const QString &getPowTough() const
{
return powtough;
}
const QString &getText() const
{
return text;
}
const QString &getPixmapCacheKey() const
{
return pixmapCacheKey;
}
const QString &getLoyalty() const
const QString &getText() const
{
return loyalty;
}
bool getCipt() const
{
return cipt;
}
// void setManaCost(const QString &_manaCost) { manacost = _manaCost; emit cardInfoChanged(smartThis); }
// void setCmc(const QString &_cmc) { cmc = _cmc; emit cardInfoChanged(smartThis); }
void setCardType(const QString &_cardType)
{
cardtype = _cardType;
emit cardInfoChanged(smartThis);
}
void setPowTough(const QString &_powTough)
{
powtough = _powTough;
emit cardInfoChanged(smartThis);
return text;
}
void setText(const QString &_text)
{
text = _text;
emit cardInfoChanged(smartThis);
}
void setColors(const QStringList &_colors)
bool getIsToken() const
{
colors = _colors;
return isToken;
}
const QStringList getProperties() const
{
return properties.keys();
}
const QString getProperty(const QString &propertyName) const
{
return properties.value(propertyName).toString();
}
void setProperty(const QString &_name, const QString &_value)
{
properties.insert(_name, _value);
emit cardInfoChanged(smartThis);
}
const QChar getColorChar() const;
const QStringList &getColors() const
const CardInfoPerSetMap &getSets() const
{
return colors;
return sets;
}
const QString &getSetsNames() const
{
return setsNames;
}
const QString getSetProperty(const QString &setName, const QString &propertyName) const
{
if (!sets.contains(setName))
return "";
return sets[setName].getProperty(propertyName);
}
void setSetProperty(const QString &setName, const QString &_name, const QString &_value)
{
if (!sets.contains(setName))
return;
sets[setName].setProperty(_name, _value);
emit cardInfoChanged(smartThis);
}
// related cards
const QList<CardRelation *> &getRelatedCards() const
{
return relatedCards;
@ -301,36 +289,12 @@ public:
{
reverseRelatedCardsToMe.append(cardRelation);
}
bool getUpsideDownArt() const
// positioning
bool getCipt() const
{
return upsideDownArt;
return cipt;
}
QString getCustomPicURL(const QString &set) const
{
return customPicURLs.value(set);
}
int getMuId(const QString &set) const
{
return muIds.value(set);
}
QString getUuId(const QString &set) const
{
return uuIds.value(set);
}
QString getCollectorNumber(const QString &set) const
{
return collectorNumbers.value(set);
}
QString getRarity(const QString &set) const
{
return rarities.value(set);
}
QStringMap getRarities() const
{
return rarities;
}
QString getMainCardType() const;
QString getCorrectedName() const;
int getTableRow() const
{
return tableRow;
@ -339,31 +303,31 @@ public:
{
tableRow = _tableRow;
}
// void setLoyalty(int _loyalty) { loyalty = _loyalty; emit cardInfoChanged(smartThis); }
// void setCustomPicURL(const QString &_set, const QString &_customPicURL) { customPicURLs.insert(_set,
// _customPicURL); }
void setSet(const CardSetPtr &_set)
bool getUpsideDownArt() const
{
sets.append(_set);
refreshCachedSetNames();
return upsideDownArt;
}
void setMuId(const QString &_set, const int &_muId)
const QChar getColorChar() const;
// Back-compatibility methods. Remove ASAP
const QString getCardType() const;
void setCardType(const QString &value);
const QString getCmc() const;
const QString getColors() const;
void setColors(const QString &value);
const QString getLoyalty() const;
const QString getMainCardType() const;
const QString getManaCost() const;
const QString getPowTough() const;
void setPowTough(const QString &value);
// methods using per-set properties
QString getCustomPicURL(const QString &set) const
{
muIds.insert(_set, _muId);
return getSetProperty(set, "picurl");
}
void setUuId(const QString &_set, const QString &_uuId)
{
uuIds.insert(_set, _uuId);
}
void setSetNumber(const QString &_set, const QString &_setNumber)
{
collectorNumbers.insert(_set, _setNumber);
}
void setRarity(const QString &_set, const QString &_setNumber)
{
rarities.insert(_set, _setNumber);
}
void addToSet(CardSetPtr set);
QString getCorrectedName() const;
void addToSet(const CardSetPtr &_set, CardInfoPerSet _info = CardInfoPerSet());
void emitPixmapUpdated()
{
emit pixmapUpdated();
@ -450,7 +414,6 @@ public:
SetList getSetList() const;
LoadStatus loadFromFile(const QString &fileName);
bool saveCustomTokensToFile();
QStringList getAllColors() const;
QStringList getAllMainCardTypes() const;
LoadStatus getLoadStatus() const
{

View file

@ -14,9 +14,7 @@ CardDatabaseModel::CardDatabaseModel(CardDatabase *_db, bool _showOnlyCardsFromE
cardDatabaseEnabledSetsChanged();
}
CardDatabaseModel::~CardDatabaseModel()
{
}
CardDatabaseModel::~CardDatabaseModel() = default;
QMap<wchar_t, wchar_t> CardDatabaseDisplayModel::characterTranslation = {{L'', L'\"'},
{L'', L'\"'},
@ -53,7 +51,7 @@ QVariant CardDatabaseModel::data(const QModelIndex &index, int role) const
case PTColumn:
return card->getPowTough();
case ColorColumn:
return card->getColors().join("");
return card->getColors();
default:
return QVariant();
}
@ -97,8 +95,8 @@ bool CardDatabaseModel::checkCardHasAtLeastOneEnabledSet(CardInfoPtr card)
if (!showOnlyCardsFromEnabledSets)
return true;
for (CardSetPtr set : card->getSets()) {
if (set->getEnabled())
for (const auto &set : card->getSets()) {
if (set.getPtr()->getEnabled())
return true;
}

View file

@ -26,12 +26,12 @@ public:
{
SortRole = Qt::UserRole
};
CardDatabaseModel(CardDatabase *_db, bool _showOnlyCardsFromEnabledSets, QObject *parent = 0);
~CardDatabaseModel();
int rowCount(const QModelIndex &parent = QModelIndex()) const;
int columnCount(const QModelIndex &parent = QModelIndex()) const;
QVariant data(const QModelIndex &index, int role) const;
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
CardDatabaseModel(CardDatabase *_db, bool _showOnlyCardsFromEnabledSets, QObject *parent = nullptr);
~CardDatabaseModel() override;
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role) const override;
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
CardDatabase *getDatabase() const
{
return db;
@ -77,7 +77,7 @@ private:
static QMap<wchar_t, wchar_t> characterTranslation;
public:
CardDatabaseDisplayModel(QObject *parent = 0);
explicit CardDatabaseDisplayModel(QObject *parent = nullptr);
void setFilterTree(FilterTree *filterTree);
void setIsToken(FilterBool _isToken)
{
@ -119,15 +119,15 @@ public:
invalidate();
}
void clearFilterAll();
int rowCount(const QModelIndex &parent = QModelIndex()) const;
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
protected:
bool lessThan(const QModelIndex &left, const QModelIndex &right) const;
bool lessThan(const QModelIndex &left, const QModelIndex &right) const override;
static int lessThanNumerically(const QString &left, const QString &right);
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const;
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override;
bool rowMatchesCardName(CardInfoPtr info) const;
bool canFetchMore(const QModelIndex &parent) const;
void fetchMore(const QModelIndex &parent);
bool canFetchMore(const QModelIndex &parent) const override;
void fetchMore(const QModelIndex &parent) override;
private slots:
void filterTreeChanged();
/** Will translate all undesirable characters in DIRTYNAME according to the TABLE. */
@ -138,11 +138,11 @@ class TokenDisplayModel : public CardDatabaseDisplayModel
{
Q_OBJECT
public:
TokenDisplayModel(QObject *parent = 0);
int rowCount(const QModelIndex &parent = QModelIndex()) const;
explicit TokenDisplayModel(QObject *parent = nullptr);
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
protected:
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const;
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override;
};
#endif

View file

@ -0,0 +1,27 @@
#include "carddatabaseparser.h"
SetNameMap ICardDatabaseParser::sets;
void ICardDatabaseParser::clearSetlist()
{
sets.clear();
}
CardSetPtr ICardDatabaseParser::internalAddSet(const QString &setName,
const QString &longName,
const QString &setType,
const QDate &releaseDate)
{
if (sets.contains(setName)) {
return sets.value(setName);
}
CardSetPtr newSet = CardSet::newInstance(setName);
newSet->setLongName(longName);
newSet->setSetType(setType);
newSet->setReleaseDate(releaseDate);
sets.insert(setName, newSet);
emit addSet(newSet);
return newSet;
}

View file

@ -9,15 +9,27 @@
class ICardDatabaseParser : public QObject
{
public:
virtual ~ICardDatabaseParser()
{
}
~ICardDatabaseParser() override = default;
virtual bool getCanParseFile(const QString &name, QIODevice &device) = 0;
virtual void parseFile(QIODevice &device) = 0;
virtual bool saveToFile(SetNameMap sets, CardNameMap cards, const QString &fileName) = 0;
virtual void clearSetlist() = 0;
static void clearSetlist();
protected:
/*
* A cached list of the available sets, needed to cross-reference sets from cards.
* Shared between all parsers
*/
static SetNameMap sets;
CardSetPtr internalAddSet(const QString &setName,
const QString &longName = "",
const QString &setType = "",
const QDate &releaseDate = QDate());
signals:
virtual void addCard(CardInfoPtr card) = 0;
virtual void addSet(CardSetPtr set) = 0;
};
Q_DECLARE_INTERFACE(ICardDatabaseParser, "ICardDatabaseParser")

View file

@ -61,30 +61,6 @@ void CockatriceXml3Parser::parseFile(QIODevice &device)
}
}
CardSetPtr CockatriceXml3Parser::internalAddSet(const QString &setName,
const QString &longName,
const QString &setType,
const QDate &releaseDate)
{
if (sets.contains(setName)) {
return sets.value(setName);
}
CardSetPtr newSet = CardSet::newInstance(setName);
newSet->setLongName(longName);
newSet->setSetType(setType);
newSet->setReleaseDate(releaseDate);
sets.insert(setName, newSet);
emit addSet(newSet);
return newSet;
}
void CockatriceXml3Parser::clearSetlist()
{
sets.clear();
}
void CockatriceXml3Parser::loadSetsFromXml(QXmlStreamReader &xml)
{
while (!xml.atEnd()) {
@ -120,6 +96,44 @@ void CockatriceXml3Parser::loadSetsFromXml(QXmlStreamReader &xml)
}
}
QString CockatriceXml3Parser::getMainCardType(QString &type)
{
QString result = type;
/*
Legendary Artifact Creature - Golem
Instant // Instant
*/
int pos;
if ((pos = result.indexOf('-')) != -1) {
result.remove(pos, result.length());
}
if ((pos = result.indexOf("")) != -1) {
result.remove(pos, result.length());
}
if ((pos = result.indexOf("//")) != -1) {
result.remove(pos, result.length());
}
result = result.simplified();
/*
Legendary Artifact Creature
Instant
*/
if ((pos = result.lastIndexOf(' ')) != -1) {
result = result.mid(pos + 1);
}
/*
Creature
Instant
*/
return result;
}
void CockatriceXml3Parser::loadCardsFromXml(QXmlStreamReader &xml)
{
while (!xml.atEnd()) {
@ -128,59 +142,77 @@ void CockatriceXml3Parser::loadCardsFromXml(QXmlStreamReader &xml)
}
if (xml.name() == "card") {
QString name, manacost, cmc, type, pt, text, loyalty;
QStringList colors;
QString name = QString("");
QString text = QString("");
QVariantHash properties = QVariantHash();
QString colors = QString("");
QList<CardRelation *> relatedCards, reverseRelatedCards;
QStringMap customPicURLs;
MuidMap muids;
QStringMap uuids, collectorNumbers, rarities;
SetList sets;
CardInfoPerSetMap sets = CardInfoPerSetMap();
int tableRow = 0;
bool cipt = false;
bool isToken = false;
bool upsideDown = false;
while (!xml.atEnd()) {
if (xml.readNext() == QXmlStreamReader::EndElement) {
break;
}
// variable - assigned properties
if (xml.name() == "name") {
name = xml.readElementText();
} else if (xml.name() == "manacost") {
manacost = xml.readElementText();
} else if (xml.name() == "cmc") {
cmc = xml.readElementText();
} else if (xml.name() == "type") {
type = xml.readElementText();
} else if (xml.name() == "pt") {
pt = xml.readElementText();
} else if (xml.name() == "text") {
text = xml.readElementText();
} else if (xml.name() == "color") {
colors.append(xml.readElementText());
} else if (xml.name() == "token") {
isToken = static_cast<bool>(xml.readElementText().toInt());
// generic properties
} else if (xml.name() == "manacost") {
properties.insert("manacost", xml.readElementText());
} else if (xml.name() == "cmc") {
properties.insert("cmc", xml.readElementText());
} else if (xml.name() == "type") {
QString type = xml.readElementText();
properties.insert("type", type);
properties.insert("maintype", getMainCardType(type));
} else if (xml.name() == "pt") {
properties.insert("pt", xml.readElementText());
} else if (xml.name() == "loyalty") {
properties.insert("loyalty", xml.readElementText());
// positioning info
} else if (xml.name() == "tablerow") {
tableRow = xml.readElementText().toInt();
} else if (xml.name() == "cipt") {
cipt = (xml.readElementText() == "1");
} else if (xml.name() == "upsidedown") {
upsideDown = (xml.readElementText() == "1");
// sets
} else if (xml.name() == "set") {
// NOTE: attributes must be read before readElementText()
QXmlStreamAttributes attrs = xml.attributes();
QString setName = xml.readElementText();
sets.append(internalAddSet(setName));
CardInfoPerSet setInfo(internalAddSet(setName));
if (attrs.hasAttribute("muId")) {
muids[setName] = attrs.value("muId").toString().toInt();
setInfo.setProperty("muid", attrs.value("muId").toString());
}
if (attrs.hasAttribute("muId")) {
uuids[setName] = attrs.value("uuId").toString();
setInfo.setProperty("uuid", attrs.value("uuId").toString());
}
if (attrs.hasAttribute("picURL")) {
customPicURLs[setName] = attrs.value("picURL").toString();
setInfo.setProperty("picurl", attrs.value("picURL").toString());
}
if (attrs.hasAttribute("num")) {
collectorNumbers[setName] = attrs.value("num").toString();
setInfo.setProperty("num", attrs.value("num").toString());
}
if (attrs.hasAttribute("rarity")) {
rarities[setName] = attrs.value("rarity").toString();
setInfo.setProperty("rarity", attrs.value("rarity").toString());
}
} else if (xml.name() == "color") {
colors << xml.readElementText();
sets.insert(setName, setInfo);
// relatd cards
} else if (xml.name() == "related" || xml.name() == "reverse-related") {
bool attach = false;
bool exclude = false;
@ -217,16 +249,6 @@ void CockatriceXml3Parser::loadCardsFromXml(QXmlStreamReader &xml)
} else {
relatedCards << relation;
}
} else if (xml.name() == "tablerow") {
tableRow = xml.readElementText().toInt();
} else if (xml.name() == "cipt") {
cipt = (xml.readElementText() == "1");
} else if (xml.name() == "upsidedown") {
upsideDown = (xml.readElementText() == "1");
} else if (xml.name() == "loyalty") {
loyalty = xml.readElementText();
} else if (xml.name() == "token") {
isToken = static_cast<bool>(xml.readElementText().toInt());
} else if (xml.name() != "") {
qDebug() << "[CockatriceXml3Parser] Unknown card property" << xml.name()
<< ", trying to continue anyway";
@ -234,9 +256,9 @@ void CockatriceXml3Parser::loadCardsFromXml(QXmlStreamReader &xml)
}
}
CardInfoPtr newCard = CardInfo::newInstance(
name, isToken, manacost, cmc, type, pt, text, colors, relatedCards, reverseRelatedCards, upsideDown,
loyalty, cipt, tableRow, sets, customPicURLs, muids, uuids, collectorNumbers, rarities);
properties.insert("colors", colors);
CardInfoPtr newCard = CardInfo::newInstance(name, text, isToken, properties, relatedCards,
reverseRelatedCards, sets, cipt, tableRow, upsideDown);
emit addCard(newCard);
}
}
@ -266,38 +288,60 @@ static QXmlStreamWriter &operator<<(QXmlStreamWriter &xml, const CardInfoPtr &in
return xml;
}
xml.writeStartElement("card");
xml.writeTextElement("name", info->getName());
const SetList &sets = info->getSets();
QString tmpString;
QString tmpSet;
for (int i = 0; i < sets.size(); i++) {
xml.writeStartElement("set");
tmpSet = sets[i]->getShortName();
xml.writeAttribute("rarity", info->getRarity(tmpSet));
xml.writeAttribute("muId", QString::number(info->getMuId(tmpSet)));
xml.writeAttribute("uuId", info->getUuId(tmpSet));
xml.writeStartElement("card");
tmpString = info->getCollectorNumber(tmpSet);
if (!tmpString.isEmpty()) {
xml.writeAttribute("num", info->getCollectorNumber(tmpSet));
// variable - assigned properties
xml.writeTextElement("name", info->getName());
xml.writeTextElement("text", info->getText());
if (info->getIsToken()) {
xml.writeTextElement("token", "1");
}
tmpString = info->getCustomPicURL(tmpSet);
// generic properties
xml.writeTextElement("manacost", info->getProperty("manacost"));
xml.writeTextElement("cmc", info->getProperty("cmc"));
xml.writeTextElement("type", info->getProperty("type"));
int colorSize = info->getColors().size();
for (int i = 0; i < colorSize; ++i) {
xml.writeTextElement("color", info->getColors().at(i));
}
tmpString = info->getProperty("pt");
if (!tmpString.isEmpty()) {
xml.writeTextElement("pt", tmpString);
}
tmpString = info->getProperty("loyalty");
if (!tmpString.isEmpty()) {
xml.writeTextElement("loyalty", tmpString);
}
// sets
const CardInfoPerSetMap sets = info->getSets();
for (CardInfoPerSet set : sets) {
xml.writeStartElement("set");
xml.writeAttribute("rarity", set.getProperty("rarity"));
xml.writeAttribute("muId", set.getProperty("muid"));
xml.writeAttribute("uuId", set.getProperty("uuid"));
tmpString = set.getProperty("num");
if (!tmpString.isEmpty()) {
xml.writeAttribute("num", tmpString);
}
tmpString = set.getProperty("picurl");
if (!tmpString.isEmpty()) {
xml.writeAttribute("picURL", tmpString);
}
xml.writeCharacters(tmpSet);
xml.writeCharacters(set.getPtr()->getShortName());
xml.writeEndElement();
}
const QStringList &colors = info->getColors();
for (int i = 0; i < colors.size(); i++) {
xml.writeTextElement("color", colors[i]);
}
// related cards
const QList<CardRelation *> related = info->getRelatedCards();
for (auto i : related) {
xml.writeStartElement("related");
@ -343,23 +387,12 @@ static QXmlStreamWriter &operator<<(QXmlStreamWriter &xml, const CardInfoPtr &in
xml.writeCharacters(i->getName());
xml.writeEndElement();
}
xml.writeTextElement("manacost", info->getManaCost());
xml.writeTextElement("cmc", info->getCmc());
xml.writeTextElement("type", info->getCardType());
if (!info->getPowTough().isEmpty()) {
xml.writeTextElement("pt", info->getPowTough());
}
// positioning
xml.writeTextElement("tablerow", QString::number(info->getTableRow()));
xml.writeTextElement("text", info->getText());
if (info->getMainCardType() == "Planeswalker") {
xml.writeTextElement("loyalty", info->getLoyalty());
}
if (info->getCipt()) {
xml.writeTextElement("cipt", "1");
}
if (info->getIsToken()) {
xml.writeTextElement("token", "1");
}
if (info->getUpsideDownArt()) {
xml.writeTextElement("upsidedown", "1");
}

View file

@ -11,27 +11,18 @@ class CockatriceXml3Parser : public ICardDatabaseParser
Q_INTERFACES(ICardDatabaseParser)
public:
CockatriceXml3Parser() = default;
~CockatriceXml3Parser() = default;
bool getCanParseFile(const QString &name, QIODevice &device);
void parseFile(QIODevice &device);
bool saveToFile(SetNameMap sets, CardNameMap cards, const QString &fileName);
void clearSetlist();
~CockatriceXml3Parser() override = default;
bool getCanParseFile(const QString &name, QIODevice &device) override;
void parseFile(QIODevice &device) override;
bool saveToFile(SetNameMap sets, CardNameMap cards, const QString &fileName) override;
private:
/*
* A cached list of the available sets, needed to cross-reference sets from cards.
*/
SetNameMap sets;
CardSetPtr internalAddSet(const QString &setName,
const QString &longName = "",
const QString &setType = "",
const QDate &releaseDate = QDate());
void loadCardsFromXml(QXmlStreamReader &xml);
void loadSetsFromXml(QXmlStreamReader &xml);
QString getMainCardType(QString &type);
signals:
void addCard(CardInfoPtr card);
void addSet(CardSetPtr set);
void addCard(CardInfoPtr card) override;
void addSet(CardSetPtr set) override;
};
#endif

View file

@ -0,0 +1,362 @@
#include "cockatricexml4.h"
#include <QDebug>
#include <QFile>
#include <QXmlStreamReader>
#define COCKATRICE_XML4_TAGNAME "cockatrice_carddatabase"
#define COCKATRICE_XML4_TAGVER 4
bool CockatriceXml4Parser::getCanParseFile(const QString &fileName, QIODevice &device)
{
qDebug() << "[CockatriceXml4Parser] Trying to parse: " << fileName;
if (!fileName.endsWith(".xml", Qt::CaseInsensitive)) {
qDebug() << "[CockatriceXml4Parser] Parsing failed: wrong extension";
return false;
}
QXmlStreamReader xml(&device);
while (!xml.atEnd()) {
if (xml.readNext() == QXmlStreamReader::StartElement) {
if (xml.name() == COCKATRICE_XML4_TAGNAME) {
int version = xml.attributes().value("version").toString().toInt();
if (version == COCKATRICE_XML4_TAGVER) {
return true;
} else {
qDebug() << "[CockatriceXml4Parser] Parsing failed: wrong version" << version;
return false;
}
} else {
qDebug() << "[CockatriceXml4Parser] Parsing failed: wrong element tag" << xml.name();
return false;
}
}
}
return true;
}
void CockatriceXml4Parser::parseFile(QIODevice &device)
{
QXmlStreamReader xml(&device);
while (!xml.atEnd()) {
if (xml.readNext() == QXmlStreamReader::StartElement) {
while (!xml.atEnd()) {
if (xml.readNext() == QXmlStreamReader::EndElement) {
break;
}
if (xml.name() == "sets") {
loadSetsFromXml(xml);
} else if (xml.name() == "cards") {
loadCardsFromXml(xml);
} else if (xml.name() != "") {
qDebug() << "[CockatriceXml4Parser] Unknown item" << xml.name() << ", trying to continue anyway";
xml.skipCurrentElement();
}
}
}
}
}
void CockatriceXml4Parser::loadSetsFromXml(QXmlStreamReader &xml)
{
while (!xml.atEnd()) {
if (xml.readNext() == QXmlStreamReader::EndElement) {
break;
}
if (xml.name() == "set") {
QString shortName, longName, setType;
QDate releaseDate;
while (!xml.atEnd()) {
if (xml.readNext() == QXmlStreamReader::EndElement) {
break;
}
if (xml.name() == "name") {
shortName = xml.readElementText();
} else if (xml.name() == "longname") {
longName = xml.readElementText();
} else if (xml.name() == "settype") {
setType = xml.readElementText();
} else if (xml.name() == "releasedate") {
releaseDate = QDate::fromString(xml.readElementText(), Qt::ISODate);
} else if (xml.name() != "") {
qDebug() << "[CockatriceXml4Parser] Unknown set property" << xml.name()
<< ", trying to continue anyway";
xml.skipCurrentElement();
}
}
internalAddSet(shortName, longName, setType, releaseDate);
}
}
}
QVariantHash CockatriceXml4Parser::loadCardPropertiesFromXml(QXmlStreamReader &xml)
{
QVariantHash properties = QVariantHash();
while (!xml.atEnd()) {
if (xml.readNext() == QXmlStreamReader::EndElement) {
break;
}
if (xml.name() != "") {
properties.insert(xml.name().toString(), xml.readElementText());
}
}
return properties;
}
void CockatriceXml4Parser::loadCardsFromXml(QXmlStreamReader &xml)
{
while (!xml.atEnd()) {
if (xml.readNext() == QXmlStreamReader::EndElement) {
break;
}
if (xml.name() == "card") {
QString name = QString("");
QString text = QString("");
QVariantHash properties = QVariantHash();
QList<CardRelation *> relatedCards, reverseRelatedCards;
CardInfoPerSetMap sets = CardInfoPerSetMap();
int tableRow = 0;
bool cipt = false;
bool isToken = false;
bool upsideDown = false;
while (!xml.atEnd()) {
if (xml.readNext() == QXmlStreamReader::EndElement) {
break;
}
// variable - assigned properties
if (xml.name() == "name") {
name = xml.readElementText();
} else if (xml.name() == "text") {
text = xml.readElementText();
} else if (xml.name() == "token") {
isToken = static_cast<bool>(xml.readElementText().toInt());
// generic properties
} else if (xml.name() == "prop") {
properties = loadCardPropertiesFromXml(xml);
// positioning info
} else if (xml.name() == "tablerow") {
tableRow = xml.readElementText().toInt();
} else if (xml.name() == "cipt") {
cipt = (xml.readElementText() == "1");
} else if (xml.name() == "upsidedown") {
upsideDown = (xml.readElementText() == "1");
// sets
} else if (xml.name() == "set") {
// NOTE: attributes but be read before readElementText()
QXmlStreamAttributes attrs = xml.attributes();
QString setName = xml.readElementText();
CardInfoPerSet setInfo(internalAddSet(setName));
for (QXmlStreamAttribute attr : attrs) {
setInfo.setProperty(attr.name().toString(), attr.value().toString());
}
sets.insert(setName, setInfo);
// relatd cards
} else if (xml.name() == "related" || xml.name() == "reverse-related") {
bool attach = false;
bool exclude = false;
bool variable = false;
int count = 1;
QXmlStreamAttributes attrs = xml.attributes();
QString cardName = xml.readElementText();
if (attrs.hasAttribute("count")) {
if (attrs.value("count").toString().indexOf("x=") == 0) {
variable = true;
count = attrs.value("count").toString().remove(0, 2).toInt();
} else if (attrs.value("count").toString().indexOf("x") == 0) {
variable = true;
} else {
count = attrs.value("count").toString().toInt();
}
if (count < 1) {
count = 1;
}
}
if (attrs.hasAttribute("attach")) {
attach = true;
}
if (attrs.hasAttribute("exclude")) {
exclude = true;
}
auto *relation = new CardRelation(cardName, attach, exclude, variable, count);
if (xml.name() == "reverse-related") {
reverseRelatedCards << relation;
} else {
relatedCards << relation;
}
} else if (xml.name() != "") {
qDebug() << "[CockatriceXml4Parser] Unknown card property" << xml.name()
<< ", trying to continue anyway";
xml.skipCurrentElement();
}
}
CardInfoPtr newCard = CardInfo::newInstance(name, text, isToken, properties, relatedCards,
reverseRelatedCards, sets, cipt, tableRow, upsideDown);
emit addCard(newCard);
}
}
}
static QXmlStreamWriter &operator<<(QXmlStreamWriter &xml, const CardSetPtr &set)
{
if (set.isNull()) {
qDebug() << "&operator<< set is nullptr";
return xml;
}
xml.writeStartElement("set");
xml.writeTextElement("name", set->getShortName());
xml.writeTextElement("longname", set->getLongName());
xml.writeTextElement("settype", set->getSetType());
xml.writeTextElement("releasedate", set->getReleaseDate().toString(Qt::ISODate));
xml.writeEndElement();
return xml;
}
static QXmlStreamWriter &operator<<(QXmlStreamWriter &xml, const CardInfoPtr &info)
{
if (info.isNull()) {
qDebug() << "operator<< info is nullptr";
return xml;
}
QString tmpString;
xml.writeStartElement("card");
// variable - assigned properties
xml.writeTextElement("name", info->getName());
xml.writeTextElement("text", info->getText());
if (info->getIsToken()) {
xml.writeTextElement("token", "1");
}
// generic properties
xml.writeStartElement("prop");
for (QString propName : info->getProperties()) {
xml.writeTextElement(propName, info->getProperty(propName));
}
xml.writeEndElement();
// sets
for (CardInfoPerSet set : info->getSets()) {
xml.writeStartElement("set");
for (QString propName : set.getProperties()) {
xml.writeAttribute(propName, set.getProperty(propName));
}
xml.writeCharacters(set.getPtr()->getShortName());
xml.writeEndElement();
}
// related cards
const QList<CardRelation *> related = info->getRelatedCards();
for (auto i : related) {
xml.writeStartElement("related");
if (i->getDoesAttach()) {
xml.writeAttribute("attach", "attach");
}
if (i->getIsCreateAllExclusion()) {
xml.writeAttribute("exclude", "exclude");
}
if (i->getIsVariable()) {
if (1 == i->getDefaultCount()) {
xml.writeAttribute("count", "x");
} else {
xml.writeAttribute("count", "x=" + QString::number(i->getDefaultCount()));
}
} else if (1 != i->getDefaultCount()) {
xml.writeAttribute("count", QString::number(i->getDefaultCount()));
}
xml.writeCharacters(i->getName());
xml.writeEndElement();
}
const QList<CardRelation *> reverseRelated = info->getReverseRelatedCards();
for (auto i : reverseRelated) {
xml.writeStartElement("reverse-related");
if (i->getDoesAttach()) {
xml.writeAttribute("attach", "attach");
}
if (i->getIsCreateAllExclusion()) {
xml.writeAttribute("exclude", "exclude");
}
if (i->getIsVariable()) {
if (1 == i->getDefaultCount()) {
xml.writeAttribute("count", "x");
} else {
xml.writeAttribute("count", "x=" + QString::number(i->getDefaultCount()));
}
} else if (1 != i->getDefaultCount()) {
xml.writeAttribute("count", QString::number(i->getDefaultCount()));
}
xml.writeCharacters(i->getName());
xml.writeEndElement();
}
// positioning
xml.writeTextElement("tablerow", QString::number(info->getTableRow()));
if (info->getCipt()) {
xml.writeTextElement("cipt", "1");
}
if (info->getUpsideDownArt()) {
xml.writeTextElement("upsidedown", "1");
}
xml.writeEndElement(); // card
return xml;
}
bool CockatriceXml4Parser::saveToFile(SetNameMap sets, CardNameMap cards, const QString &fileName)
{
QFile file(fileName);
if (!file.open(QIODevice::WriteOnly)) {
return false;
}
QXmlStreamWriter xml(&file);
xml.setAutoFormatting(true);
xml.writeStartDocument();
xml.writeStartElement(COCKATRICE_XML4_TAGNAME);
xml.writeAttribute("version", QString::number(COCKATRICE_XML4_TAGVER));
if (sets.count() > 0) {
xml.writeStartElement("sets");
for (CardSetPtr set : sets) {
xml << set;
}
xml.writeEndElement();
}
if (cards.count() > 0) {
xml.writeStartElement("cards");
for (CardInfoPtr card : cards) {
xml << card;
}
xml.writeEndElement();
}
xml.writeEndElement(); // cockatrice_carddatabase
xml.writeEndDocument();
return true;
}

View file

@ -0,0 +1,28 @@
#ifndef COCKATRICE_XML4_H
#define COCKATRICE_XML4_H
#include <QXmlStreamReader>
#include "carddatabaseparser.h"
class CockatriceXml4Parser : public ICardDatabaseParser
{
Q_OBJECT
Q_INTERFACES(ICardDatabaseParser)
public:
CockatriceXml4Parser() = default;
~CockatriceXml4Parser() override = default;
bool getCanParseFile(const QString &name, QIODevice &device) override;
void parseFile(QIODevice &device) override;
bool saveToFile(SetNameMap sets, CardNameMap cards, const QString &fileName) override;
private:
QVariantHash loadCardPropertiesFromXml(QXmlStreamReader &xml);
void loadCardsFromXml(QXmlStreamReader &xml);
void loadSetsFromXml(QXmlStreamReader &xml);
signals:
void addCard(CardInfoPtr card) override;
void addSet(CardSetPtr set) override;
};
#endif

View file

@ -1,3 +1,5 @@
#include <utility>
#include "cardframe.h"
#include "cardinfopicture.h"
@ -16,6 +18,7 @@ CardFrame::CardFrame(const QString &cardName, QWidget *parent) : QTabWidget(pare
pic->setObjectName("pic");
text = new CardInfoText();
text->setObjectName("text");
connect(text, SIGNAL(linkActivated(const QString &)), this, SLOT(setCard(const QString &)));
tab1 = new QWidget(this);
tab2 = new QWidget(this);
@ -93,10 +96,10 @@ void CardFrame::setCard(CardInfoPtr card)
disconnect(info.data(), nullptr, this, nullptr);
}
info = card;
info = std::move(card);
if (info) {
connect(info.data(), SIGNAL(destroyed()), this, SLOT(clear()));
connect(info.data(), SIGNAL(destroyed()), this, SLOT(clearCard()));
}
text->setCard(info);
@ -115,7 +118,7 @@ void CardFrame::setCard(AbstractCardItem *card)
}
}
void CardFrame::clear()
void CardFrame::clearCard()
{
setCard((CardInfoPtr) nullptr);
}

View file

@ -37,7 +37,7 @@ public slots:
void setCard(CardInfoPtr card);
void setCard(const QString &cardName);
void setCard(AbstractCardItem *card);
void clear();
void clearCard();
void setViewMode(int mode);
};

View file

@ -1,137 +1,83 @@
#include "cardinfotext.h"
#include "carditem.h"
#include "game_specific_terms.h"
#include "main.h"
#include <QGridLayout>
#include <QLabel>
#include <QTextEdit>
CardInfoText::CardInfoText(QWidget *parent) : QFrame(parent), info(nullptr)
{
nameLabel1 = new QLabel;
nameLabel2 = new QLabel;
nameLabel2->setWordWrap(true);
nameLabel2->setTextInteractionFlags(Qt::TextBrowserInteraction);
manacostLabel1 = new QLabel;
manacostLabel2 = new QLabel;
manacostLabel2->setWordWrap(true);
manacostLabel2->setTextInteractionFlags(Qt::TextBrowserInteraction);
colorLabel1 = new QLabel;
colorLabel2 = new QLabel;
colorLabel2->setWordWrap(true);
colorLabel2->setTextInteractionFlags(Qt::TextBrowserInteraction);
cardtypeLabel1 = new QLabel;
cardtypeLabel2 = new QLabel;
cardtypeLabel2->setWordWrap(true);
cardtypeLabel2->setTextInteractionFlags(Qt::TextBrowserInteraction);
powtoughLabel1 = new QLabel;
powtoughLabel2 = new QLabel;
powtoughLabel2->setTextInteractionFlags(Qt::TextBrowserInteraction);
loyaltyLabel1 = new QLabel;
loyaltyLabel2 = new QLabel;
loyaltyLabel1->setTextInteractionFlags(Qt::TextBrowserInteraction);
nameLabel = new QLabel;
nameLabel->setOpenExternalLinks(false);
connect(nameLabel, SIGNAL(linkActivated(const QString &)), this, SIGNAL(linkActivated(const QString &)));
textLabel = new QTextEdit();
textLabel->setReadOnly(true);
QGridLayout *grid = new QGridLayout(this);
int row = 0;
grid->addWidget(nameLabel1, row, 0);
grid->addWidget(nameLabel2, row++, 1);
grid->addWidget(manacostLabel1, row, 0);
grid->addWidget(manacostLabel2, row++, 1);
grid->addWidget(colorLabel1, row, 0);
grid->addWidget(colorLabel2, row++, 1);
grid->addWidget(cardtypeLabel1, row, 0);
grid->addWidget(cardtypeLabel2, row++, 1);
grid->addWidget(powtoughLabel1, row, 0);
grid->addWidget(powtoughLabel2, row++, 1);
grid->addWidget(loyaltyLabel1, row, 0);
grid->addWidget(loyaltyLabel2, row++, 1);
grid->addWidget(textLabel, row, 0, -1, 2);
grid->setRowStretch(row, 1);
grid->addWidget(nameLabel, 0, 0);
grid->addWidget(textLabel, 1, 0, -1, 2);
grid->setRowStretch(1, 1);
grid->setColumnStretch(1, 1);
retranslateUi();
}
// Reset every label which is optionally hidden
void CardInfoText::resetLabels()
{
nameLabel1->show();
nameLabel2->show();
manacostLabel1->show();
manacostLabel2->show();
colorLabel1->show();
colorLabel2->show();
cardtypeLabel1->show();
cardtypeLabel2->show();
powtoughLabel1->show();
powtoughLabel2->show();
loyaltyLabel1->show();
loyaltyLabel2->show();
textLabel->show();
}
void CardInfoText::setCard(CardInfoPtr card)
{
if (card) {
resetLabels();
nameLabel2->setText(card->getName());
if (!card->getManaCost().isEmpty()) {
manacostLabel2->setText(card->getManaCost());
} else {
manacostLabel1->hide();
manacostLabel2->hide();
if (card == nullptr) {
nameLabel->setText("");
textLabel->setText("");
return;
}
if (!card->getColors().isEmpty()) {
colorLabel2->setText(card->getColors().join(""));
} else {
colorLabel2->setText("Colorless");
QString text = "<table width=\"100%\" border=0 cellspacing=0 cellpadding=0>";
text += QString("<tr><td>%1</td><td width=\"5\"></td><td>%2</td></tr>")
.arg(tr("Name:"), card->getName().toHtmlEscaped());
QStringList cardProps = card->getProperties();
foreach (QString key, cardProps) {
QString keyText = Mtg::getNicePropertyName(key).toHtmlEscaped() + ":";
text +=
QString("<tr><td>%1</td><td></td><td>%2</td></tr>").arg(keyText, card->getProperty(key).toHtmlEscaped());
}
cardtypeLabel2->setText(card->getCardType());
if (!card->getPowTough().isEmpty()) {
powtoughLabel2->setText(card->getPowTough());
} else {
powtoughLabel1->hide();
powtoughLabel2->hide();
auto relatedCards = card->getRelatedCards();
auto reverserelatedCards2Me = card->getReverseRelatedCards2Me();
if (relatedCards.size() || reverserelatedCards2Me.size()) {
text += QString("<tr><td>%1</td><td width=\"5\"></td><td>").arg(tr("Related cards:"));
for (int i = 0; i < relatedCards.size(); ++i) {
QString tmp = relatedCards.at(i)->getName().toHtmlEscaped();
text += "<a href=\"" + tmp + "\">" + tmp + "</a><br>";
}
if (!card->getLoyalty().isEmpty()) {
loyaltyLabel2->setText(card->getLoyalty());
} else {
loyaltyLabel1->hide();
loyaltyLabel2->hide();
for (int i = 0; i < reverserelatedCards2Me.size(); ++i) {
QString tmp = reverserelatedCards2Me.at(i)->getName().toHtmlEscaped();
text += "<a href=\"" + tmp + "\">" + tmp + "</a><br>";
}
text += "</td></tr>";
}
text += "</table>";
nameLabel->setText(text);
textLabel->setText(card->getText());
} else {
nameLabel1->hide();
nameLabel2->hide();
manacostLabel1->hide();
manacostLabel2->hide();
colorLabel1->hide();
colorLabel2->hide();
cardtypeLabel1->hide();
cardtypeLabel2->hide();
powtoughLabel1->hide();
powtoughLabel2->hide();
loyaltyLabel1->hide();
loyaltyLabel2->hide();
textLabel->hide();
}
}
void CardInfoText::setInvalidCardName(const QString &cardName)
{
nameLabel1->setText(tr("Unknown card:"));
nameLabel1->show();
nameLabel2->setText(cardName);
nameLabel2->show();
nameLabel->setText(tr("Unknown card:") + " " + cardName);
textLabel->setText("");
}
void CardInfoText::retranslateUi()
{
nameLabel1->setText(tr("Name:"));
manacostLabel1->setText(tr("Mana cost:"));
colorLabel1->setText(tr("Color(s):"));
cardtypeLabel1->setText(tr("Card type:"));
powtoughLabel1->setText(tr("P / T:"));
loyaltyLabel1->setText(tr("Loyalty:"));
/*
* There's no way we can really translate the text currently being rendered.
* The best we can do is invalidate the current text.
*/
setInvalidCardName("");
}

View file

@ -12,23 +12,17 @@ class CardInfoText : public QFrame
Q_OBJECT
private:
QLabel *nameLabel1, *nameLabel2;
QLabel *manacostLabel1, *manacostLabel2;
QLabel *colorLabel1, *colorLabel2;
QLabel *cardtypeLabel1, *cardtypeLabel2;
QLabel *powtoughLabel1, *powtoughLabel2;
QLabel *loyaltyLabel1, *loyaltyLabel2;
QLabel *nameLabel;
QTextEdit *textLabel;
CardInfoPtr info;
void resetLabels();
public:
CardInfoText(QWidget *parent = 0);
void retranslateUi();
void setInvalidCardName(const QString &cardName);
signals:
void linkActivated(const QString &link);
public slots:
void setCard(CardInfoPtr card);
};

View file

@ -1,6 +1,8 @@
#include "cardinfowidget.h"
#include <utility>
#include "cardinfopicture.h"
#include "cardinfotext.h"
#include "cardinfowidget.h"
#include "carditem.h"
#include "main.h"
#include <QDesktopWidget>
@ -14,8 +16,9 @@ CardInfoWidget::CardInfoWidget(const QString &cardName, QWidget *parent, Qt::Win
pic->setObjectName("pic");
text = new CardInfoText();
text->setObjectName("text");
connect(text, SIGNAL(linkActivated(const QString &)), this, SLOT(setCard(const QString &)));
QVBoxLayout *layout = new QVBoxLayout();
auto *layout = new QVBoxLayout();
layout->setObjectName("layout");
layout->setContentsMargins(0, 0, 0, 0);
layout->setSpacing(0);
@ -26,7 +29,7 @@ CardInfoWidget::CardInfoWidget(const QString &cardName, QWidget *parent, Qt::Win
setFrameStyle(QFrame::Panel | QFrame::Raised);
QDesktopWidget desktopWidget;
int pixmapHeight = desktopWidget.screenGeometry().height() / 3;
int pixmapWidth = pixmapHeight / aspectRatio;
int pixmapWidth = static_cast<int>(pixmapHeight / aspectRatio);
pic->setFixedWidth(pixmapWidth);
pic->setFixedHeight(pixmapHeight);
setFixedWidth(pixmapWidth + 150);
@ -41,7 +44,7 @@ void CardInfoWidget::setCard(CardInfoPtr card)
{
if (info)
disconnect(info.data(), nullptr, this, nullptr);
info = card;
info = std::move(card);
if (info)
connect(info.data(), SIGNAL(destroyed()), this, SLOT(clear()));

View file

@ -22,7 +22,7 @@ private:
CardInfoText *text;
public:
CardInfoWidget(const QString &cardName, QWidget *parent = 0, Qt::WindowFlags f = 0);
explicit CardInfoWidget(const QString &cardName, QWidget *parent = nullptr, Qt::WindowFlags f = nullptr);
public slots:
void setCard(CardInfoPtr card);

View file

@ -322,9 +322,7 @@ QModelIndex DeckListModel::addCard(const QString &cardName, const QString &zoneN
// This is usually called from tab_deck_editor
// So we'll create a new CardInfo with the name
// and default values for all fields
info = CardInfo::newInstance(cardName, false, nullptr, nullptr, "unknown", nullptr, nullptr, QStringList(),
QList<CardRelation *>(), QList<CardRelation *>(), false, 0, false, 0,
SetList(), QStringMap(), MuidMap(), QStringMap(), QStringMap(), QStringMap());
info = CardInfo::newInstance(cardName);
} else {
return {};
}

View file

@ -7,7 +7,6 @@
class DeckLoader;
class CardDatabase;
class QProgressDialog;
class QPrinter;
class QTextCursor;
@ -21,19 +20,19 @@ public:
: AbstractDecklistCardNode(_parent), dataNode(_dataNode)
{
}
int getNumber() const
int getNumber() const override
{
return dataNode->getNumber();
}
void setNumber(int _number)
void setNumber(int _number) override
{
dataNode->setNumber(_number);
}
QString getName() const
QString getName() const override
{
return dataNode->getName();
}
void setName(const QString &_name)
void setName(const QString &_name) override
{
dataNode->setName(_name);
}
@ -54,20 +53,20 @@ signals:
void deckHashChanged();
public:
DeckListModel(QObject *parent = 0);
~DeckListModel();
int rowCount(const QModelIndex &parent) const;
int columnCount(const QModelIndex & /*parent*/ = QModelIndex()) const;
QVariant data(const QModelIndex &index, int role) const;
QVariant headerData(int section, Qt::Orientation orientation, int role) const;
QModelIndex index(int row, int column, const QModelIndex &parent) const;
QModelIndex parent(const QModelIndex &index) const;
Qt::ItemFlags flags(const QModelIndex &index) const;
bool setData(const QModelIndex &index, const QVariant &value, int role);
bool removeRows(int row, int count, const QModelIndex &parent);
explicit DeckListModel(QObject *parent = nullptr);
~DeckListModel() override;
int rowCount(const QModelIndex &parent) const override;
int columnCount(const QModelIndex & /*parent*/ = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role) const override;
QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
QModelIndex index(int row, int column, const QModelIndex &parent) const override;
QModelIndex parent(const QModelIndex &index) const override;
Qt::ItemFlags flags(const QModelIndex &index) const override;
bool setData(const QModelIndex &index, const QVariant &value, int role) override;
bool removeRows(int row, int count, const QModelIndex &parent) override;
QModelIndex findCard(const QString &cardName, const QString &zoneName) const;
QModelIndex addCard(const QString &cardName, const QString &zoneName, bool abAddAnyway = false);
void sort(int column, Qt::SortOrder order);
void sort(int column, Qt::SortOrder order) override;
void cleanList();
DeckLoader *getDeckList() const
{

View file

@ -17,7 +17,7 @@
#include <QTreeView>
#include <QVBoxLayout>
DlgEditTokens::DlgEditTokens(QWidget *parent) : QDialog(parent), currentCard(0)
DlgEditTokens::DlgEditTokens(QWidget *parent) : QDialog(parent), currentCard(nullptr)
{
nameLabel = new QLabel(tr("&Name:"));
nameEdit = new QLineEdit;
@ -46,7 +46,7 @@ DlgEditTokens::DlgEditTokens(QWidget *parent) : QDialog(parent), currentCard(0)
annotationLabel->setBuddy(annotationEdit);
connect(annotationEdit, SIGNAL(textChanged(QString)), this, SLOT(annotationChanged(QString)));
QGridLayout *grid = new QGridLayout;
auto *grid = new QGridLayout;
grid->addWidget(nameLabel, 0, 0);
grid->addWidget(nameEdit, 0, 1);
grid->addWidget(colorLabel, 1, 0);
@ -89,15 +89,15 @@ DlgEditTokens::DlgEditTokens(QWidget *parent) : QDialog(parent), currentCard(0)
aRemoveToken->setIcon(QPixmap("theme:icons/decrement"));
connect(aRemoveToken, SIGNAL(triggered()), this, SLOT(actRemoveToken()));
QToolBar *databaseToolBar = new QToolBar;
auto *databaseToolBar = new QToolBar;
databaseToolBar->addAction(aAddToken);
databaseToolBar->addAction(aRemoveToken);
QVBoxLayout *leftVBox = new QVBoxLayout;
auto *leftVBox = new QVBoxLayout;
leftVBox->addWidget(chooseTokenView);
leftVBox->addWidget(databaseToolBar);
QHBoxLayout *hbox = new QHBoxLayout;
auto *hbox = new QHBoxLayout;
hbox->addLayout(leftVBox);
hbox->addWidget(tokenDataGroupBox);
@ -105,7 +105,7 @@ DlgEditTokens::DlgEditTokens(QWidget *parent) : QDialog(parent), currentCard(0)
connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
QVBoxLayout *mainLayout = new QVBoxLayout;
auto *mainLayout = new QVBoxLayout;
mainLayout->addLayout(hbox);
mainLayout->addWidget(buttonBox);
@ -154,9 +154,10 @@ void DlgEditTokens::actAddToken()
}
} while (askAgain);
CardInfoPtr card = CardInfo::newInstance(name, true);
card->addToSet(databaseModel->getDatabase()->getSet(CardDatabase::TOKENS_SETNAME));
CardInfoPtr card = CardInfo::newInstance(name, "", true);
card->setCardType("Token");
card->addToSet(databaseModel->getDatabase()->getSet(CardDatabase::TOKENS_SETNAME));
databaseModel->getDatabase()->addCard(card);
}
@ -172,7 +173,7 @@ void DlgEditTokens::actRemoveToken()
void DlgEditTokens::colorChanged(int colorIndex)
{
if (currentCard)
currentCard->setColors(QStringList() << QString(colorEdit->itemData(colorIndex).toChar()));
currentCard->setColors(QString(colorEdit->itemData(colorIndex).toChar()));
}
void DlgEditTokens::ptChanged(const QString &_pt)

View file

@ -35,7 +35,7 @@ private:
QTreeView *chooseTokenView;
public:
DlgEditTokens(QWidget *parent = nullptr);
explicit DlgEditTokens(QWidget *parent = nullptr);
};
#endif

View file

@ -187,12 +187,9 @@ bool FilterItem::acceptColor(const CardInfoPtr info) const
*/
int match_count = 0;
for (auto &it : converted_term) {
for (auto i = info->getColors().constBegin(); i != info->getColors().constEnd(); i++) {
if ((*i).contains(it, Qt::CaseInsensitive)) {
if (info->getColors().contains(it, Qt::CaseInsensitive))
match_count++;
}
}
}
return match_count == converted_term.length();
}
@ -205,9 +202,9 @@ bool FilterItem::acceptText(const CardInfoPtr info) const
bool FilterItem::acceptSet(const CardInfoPtr info) const
{
bool status = false;
for (auto i = info->getSets().constBegin(); i != info->getSets().constEnd(); i++) {
if ((*i)->getShortName().compare(term, Qt::CaseInsensitive) == 0 ||
(*i)->getLongName().compare(term, Qt::CaseInsensitive) == 0) {
for (const auto &set : info->getSets()) {
if (set.getPtr()->getShortName().compare(term, Qt::CaseInsensitive) == 0 ||
set.getPtr()->getLongName().compare(term, Qt::CaseInsensitive) == 0) {
status = true;
break;
}
@ -299,7 +296,7 @@ bool FilterItem::acceptRarity(const CardInfoPtr info) const
/*
* The purpose of this loop is to only apply one of the replacement
* policies and then escape. If we attempt to layer them ontop of
* policies and then escape. If we attempt to layer them on top of
* each other, we will get awkward results (i.e. comythic rare mythic rareon)
* Conditional statement will exit once a case is successful in
* replacement OR we go through all possible cases.
@ -334,8 +331,8 @@ bool FilterItem::acceptRarity(const CardInfoPtr info) const
}
}
for (const QString &rareLevel : info->getRarities()) {
if (rareLevel.compare(converted_term, Qt::CaseInsensitive) == 0) {
for (const auto &set : info->getSets()) {
if (set.getProperty("rarity").compare(converted_term, Qt::CaseInsensitive) == 0) {
return true;
}
}

View file

@ -1,12 +1,14 @@
#ifndef FILTERTREE_H
#define FILTERTREE_H
#include "carddatabase.h"
#include "cardfilter.h"
#include <QList>
#include <QMap>
#include <QObject>
#include "carddatabase.h"
#include "cardfilter.h"
#include <utility>
class FilterTreeNode
{
@ -33,11 +35,11 @@ public:
}
virtual FilterTreeNode *parent() const
{
return NULL;
return nullptr;
}
virtual FilterTreeNode *nodeAt(int /* i */) const
{
return NULL;
return nullptr;
}
virtual void deleteAt(int /* i */)
{
@ -52,7 +54,7 @@ public:
}
virtual int index() const
{
return (parent() != NULL) ? parent()->childIndex(this) : -1;
return (parent() != nullptr) ? parent()->childIndex(this) : -1;
}
virtual const QString text() const
{
@ -64,27 +66,27 @@ public:
}
virtual void nodeChanged() const
{
if (parent() != NULL)
if (parent() != nullptr)
parent()->nodeChanged();
}
virtual void preInsertChild(const FilterTreeNode *p, int i) const
{
if (parent() != NULL)
if (parent() != nullptr)
parent()->preInsertChild(p, i);
}
virtual void postInsertChild(const FilterTreeNode *p, int i) const
{
if (parent() != NULL)
if (parent() != nullptr)
parent()->postInsertChild(p, i);
}
virtual void preRemoveChild(const FilterTreeNode *p, int i) const
{
if (parent() != NULL)
if (parent() != nullptr)
parent()->preRemoveChild(p, i);
}
virtual void postRemoveChild(const FilterTreeNode *p, int i) const
{
if (parent() != NULL)
if (parent() != nullptr)
parent()->postRemoveChild(p, i);
}
};
@ -96,13 +98,13 @@ protected:
public:
virtual ~FilterTreeBranch();
FilterTreeNode *nodeAt(int i) const;
void deleteAt(int i);
int childCount() const
FilterTreeNode *nodeAt(int i) const override;
void deleteAt(int i) override;
int childCount() const override
{
return childNodes.size();
}
int childIndex(const FilterTreeNode *node) const;
int childIndex(const FilterTreeNode *node) const override;
};
class FilterItemList;
@ -121,8 +123,8 @@ public:
}
const FilterItemList *findTypeList(CardFilter::Type type) const;
FilterItemList *typeList(CardFilter::Type type);
FilterTreeNode *parent() const;
const QString text() const
FilterTreeNode *parent() const override;
const QString text() const override
{
return CardFilter::attrName(attr);
}
@ -144,21 +146,21 @@ public:
{
return p->attr;
}
FilterTreeNode *parent() const
FilterTreeNode *parent() const override
{
return p;
}
int termIndex(const QString &term) const;
FilterTreeNode *termNode(const QString &term);
const QString text() const
const QString text() const override
{
return CardFilter::typeName(type);
}
bool testTypeAnd(const CardInfoPtr info, CardFilter::Attr attr) const;
bool testTypeAndNot(const CardInfoPtr info, CardFilter::Attr attr) const;
bool testTypeOr(const CardInfoPtr info, CardFilter::Attr attr) const;
bool testTypeOrNot(const CardInfoPtr info, CardFilter::Attr attr) const;
bool testTypeAnd(CardInfoPtr info, CardFilter::Attr attr) const;
bool testTypeAndNot(CardInfoPtr info, CardFilter::Attr attr) const;
bool testTypeOr(CardInfoPtr info, CardFilter::Attr attr) const;
bool testTypeOrNot(CardInfoPtr info, CardFilter::Attr attr) const;
};
class FilterItem : public FilterTreeNode
@ -169,10 +171,10 @@ private:
public:
const QString term;
FilterItem(QString trm, FilterItemList *parent) : p(parent), term(trm)
FilterItem(QString trm, FilterItemList *parent) : p(parent), term(std::move(trm))
{
}
virtual ~FilterItem(){};
virtual ~FilterItem() = default;
CardFilter::Attr attr() const
{
@ -182,30 +184,30 @@ public:
{
return p->type;
}
FilterTreeNode *parent() const
FilterTreeNode *parent() const override
{
return p;
}
const QString text() const
const QString text() const override
{
return term;
}
bool isLeaf() const
bool isLeaf() const override
{
return true;
}
bool acceptName(const CardInfoPtr info) const;
bool acceptType(const CardInfoPtr info) const;
bool acceptColor(const CardInfoPtr info) const;
bool acceptText(const CardInfoPtr info) const;
bool acceptSet(const CardInfoPtr info) const;
bool acceptManaCost(const CardInfoPtr info) const;
bool acceptCmc(const CardInfoPtr info) const;
bool acceptPowerToughness(const CardInfoPtr info, CardFilter::Attr attr) const;
bool acceptLoyalty(const CardInfoPtr info) const;
bool acceptRarity(const CardInfoPtr info) const;
bool acceptCardAttr(const CardInfoPtr info, CardFilter::Attr attr) const;
bool acceptName(CardInfoPtr info) const;
bool acceptType(CardInfoPtr info) const;
bool acceptColor(CardInfoPtr info) const;
bool acceptText(CardInfoPtr info) const;
bool acceptSet(CardInfoPtr info) const;
bool acceptManaCost(CardInfoPtr info) const;
bool acceptCmc(CardInfoPtr info) const;
bool acceptPowerToughness(CardInfoPtr info, CardFilter::Attr attr) const;
bool acceptLoyalty(CardInfoPtr info) const;
bool acceptRarity(CardInfoPtr info) const;
bool acceptCardAttr(CardInfoPtr info, CardFilter::Attr attr) const;
bool relationCheck(int cardInfo) const;
};
@ -224,47 +226,47 @@ private:
LogicMap *attrLogicMap(CardFilter::Attr attr);
FilterItemList *attrTypeList(CardFilter::Attr attr, CardFilter::Type type);
bool testAttr(const CardInfoPtr info, const LogicMap *lm) const;
bool testAttr(CardInfoPtr info, const LogicMap *lm) const;
void nodeChanged() const
void nodeChanged() const override
{
emit changed();
}
void preInsertChild(const FilterTreeNode *p, int i) const
void preInsertChild(const FilterTreeNode *p, int i) const override
{
emit preInsertRow(p, i);
}
void postInsertChild(const FilterTreeNode *p, int i) const
void postInsertChild(const FilterTreeNode *p, int i) const override
{
emit postInsertRow(p, i);
}
void preRemoveChild(const FilterTreeNode *p, int i) const
void preRemoveChild(const FilterTreeNode *p, int i) const override
{
emit preRemoveRow(p, i);
}
void postRemoveChild(const FilterTreeNode *p, int i) const
void postRemoveChild(const FilterTreeNode *p, int i) const override
{
emit postRemoveRow(p, i);
}
public:
FilterTree();
~FilterTree();
~FilterTree() override;
int findTermIndex(CardFilter::Attr attr, CardFilter::Type type, const QString &term);
int findTermIndex(const CardFilter *f);
FilterTreeNode *termNode(CardFilter::Attr attr, CardFilter::Type type, const QString &term);
FilterTreeNode *termNode(const CardFilter *f);
FilterTreeNode *attrTypeNode(CardFilter::Attr attr, CardFilter::Type type);
const QString text() const
const QString text() const override
{
return QString("root");
}
int index() const
int index() const override
{
return 0;
}
bool acceptsCard(const CardInfoPtr info) const;
bool acceptsCard(CardInfoPtr info) const;
void clear();
};

View file

@ -0,0 +1,49 @@
#ifndef GAME_SPECIFIC_TERMS_H
#define GAME_SPECIFIC_TERMS_H
#include <QCoreApplication>
#include <QString>
/*
* Collection of traslatable property names used in games,
* so we can use Game::Property instead of hardcoding strings.
* Note: Mtg = "Maybe that game"
*/
namespace Mtg
{
QString const CardType("type");
QString const ConvertedManaCost("cmc");
QString const Colors("colors");
QString const Loyalty("loyalty");
QString const MainCardType("maintype");
QString const ManaCost("manacost");
QString const PowTough("pt");
QString const Side("side");
QString const Layout("layout");
inline static const QString getNicePropertyName(QString key)
{
if (key == CardType)
return QCoreApplication::translate("Mtg", "Card type");
if (key == ConvertedManaCost)
return QCoreApplication::translate("Mtg", "Converted mana cost");
if (key == Colors)
return QCoreApplication::translate("Mtg", "Color(s)");
if (key == Loyalty)
return QCoreApplication::translate("Mtg", "Loyalty");
if (key == MainCardType)
return QCoreApplication::translate("Mtg", "Main card type");
if (key == ManaCost)
return QCoreApplication::translate("Mtg", "Mana cost");
if (key == PowTough)
return QCoreApplication::translate("Mtg", "P / T");
if (key == Side)
return QCoreApplication::translate("Mtg", "Side");
if (key == Layout)
return QCoreApplication::translate("Mtg", "Layout");
return key;
}
}; // namespace Mtg
#endif

View file

@ -1,6 +1,6 @@
#include "handle_public_servers.h"
#include "qt-json/json.h"
#include "settingscache.h"
#include <QJsonDocument>
#include <QMessageBox>
#include <QNetworkAccessManager>
#include <QNetworkReply>
@ -31,19 +31,16 @@ void HandlePublicServers::actFinishParsingDownloadedData()
savedHostList = uci.getServerInfo();
// Downloaded data from GitHub
bool jsonSuccessful;
QString jsonData = QString(reply->readAll());
auto jsonMap = QtJson::Json::parse(jsonData, jsonSuccessful).toMap();
if (jsonSuccessful) {
QJsonParseError parseError{};
QJsonDocument jsonResponse = QJsonDocument::fromJson(reply->readAll(), &parseError);
if (parseError.error == QJsonParseError::NoError) {
QVariantMap jsonMap = jsonResponse.toVariant().toMap();
updateServerINISettings(jsonMap);
} else {
qDebug() << "[PUBLIC SERVER HANDLER]"
<< "JSON Parsing Error";
<< "JSON Parsing Error:" << parseError.errorString();
emit sigPublicServersDownloadedUnsuccessfully(errorCode);
}
} else {
qDebug() << "[PUBLIC SERVER HANDLER]"
<< "Error Downloading Public Servers" << errorCode;

View file

@ -30,7 +30,9 @@ PictureToLoad::PictureToLoad(CardInfoPtr _card) : card(std::move(_card))
urlTemplates = settingsCache->downloads().getAllURLs();
if (card) {
sortedSets = card->getSets();
for (const auto &set : card->getSets()) {
sortedSets << set.getPtr();
}
qSort(sortedSets.begin(), sortedSets.end(), SetDownloadPriorityComparator());
// The first time called, nextSet will also populate the Urls for the first set.
nextSet();
@ -240,28 +242,50 @@ QString PictureToLoad::transformUrl(const QString &urlTemplate) const
CardSetPtr set = getCurrentSet();
QMap<QString, QString> transformMap = QMap<QString, QString>();
// name
transformMap["!name!"] = card->getName();
transformMap["!name_lower!"] = card->getName().toLower();
transformMap["!corrected_name!"] = card->getCorrectedName();
transformMap["!corrected_name_lower!"] = card->getCorrectedName().toLower();
// card properties
QRegExp rxCardProp("!prop:([^!]+)!");
int pos = 0;
while ((pos = rxCardProp.indexIn(transformedUrl, pos)) != -1) {
QString propertyName = rxCardProp.cap(1);
pos += rxCardProp.matchedLength();
QString propertyValue = card->getProperty(propertyName);
if (propertyValue.isEmpty()) {
qDebug() << "PictureLoader: [card: " << card->getName() << " set: " << getSetName()
<< "]: Requested property (" << propertyName << ") for Url template (" << urlTemplate
<< ") is not available";
return QString();
} else {
transformMap["!prop:" + propertyName + "!"] = propertyValue;
}
}
if (set) {
transformMap["!cardid!"] = QString::number(card->getMuId(set->getShortName()));
transformMap["!uuid!"] = card->getUuId(set->getShortName());
transformMap["!collectornumber!"] = card->getCollectorNumber(set->getShortName());
transformMap["!setcode!"] = set->getShortName();
transformMap["!setcode_lower!"] = set->getShortName().toLower();
transformMap["!setname!"] = set->getLongName();
transformMap["!setname_lower!"] = set->getLongName().toLower();
QRegExp rxSetProp("!set:([^!]+)!");
pos = 0; // Defined above
while ((pos = rxSetProp.indexIn(transformedUrl, pos)) != -1) {
QString propertyName = rxSetProp.cap(1);
pos += rxSetProp.matchedLength();
QString propertyValue = card->getSetProperty(set->getShortName(), propertyName);
if (propertyValue.isEmpty()) {
qDebug() << "PictureLoader: [card: " << card->getName() << " set: " << getSetName()
<< "]: Requested set property (" << propertyName << ") for Url template (" << urlTemplate
<< ") is not available";
return QString();
} else {
transformMap["!cardid!"] = QString();
transformMap["!uuid!"] = QString();
transformMap["!collectornumber!"] = QString();
transformMap["!setcode!"] = QString();
transformMap["!setcode_lower!"] = QString();
transformMap["!setname!"] = QString();
transformMap["!setname_lower!"] = QString();
transformMap["!set:" + propertyName + "!"] = propertyValue;
}
}
}
for (const QString &prop : transformMap.keys()) {
@ -483,7 +507,7 @@ void PictureLoader::getPixmap(QPixmap &pixmap, CardInfoPtr card, QSize size)
return;
}
// search for an exact size copy of the picure in cache
// search for an exact size copy of the picture in cache
QString key = card->getPixmapCacheKey();
QString sizeKey = key + QLatin1Char('_') + QString::number(size.width()) + QString::number(size.height());
if (QPixmapCache::find(sizeKey, &pixmap))

View file

@ -94,7 +94,7 @@ void PlayerArea::setSize(qreal width, qreal height)
Player::Player(const ServerInfo_User &info, int _id, bool _local, TabGame *_parent)
: QObject(_parent), game(_parent), shortcutsActive(false), defaultNumberTopCards(1),
defaultNumberTopCardsToPlaceBelow(1), lastTokenDestroy(true), lastTokenTableRow(0), id(_id), active(false),
local(_local), mirrored(false), handVisible(false), conceded(false), dialogSemaphore(false), deck(0)
local(_local), mirrored(false), handVisible(false), conceded(false), dialogSemaphore(false), deck(nullptr)
{
userInfo = new ServerInfo_User;
userInfo->CopyFrom(info);
@ -115,7 +115,7 @@ Player::Player(const ServerInfo_User &info, int _id, bool _local, TabGame *_pare
qreal h = deck->boundingRect().width() + 5;
HandCounter *handCounter = new HandCounter(playerArea);
auto *handCounter = new HandCounter(playerArea);
handCounter->setPos(base + QPointF(0, h + 10));
qreal h2 = handCounter->boundingRect().height();
@ -279,8 +279,8 @@ Player::Player(const ServerInfo_User &info, int _id, bool _local, TabGame *_pare
libraryMenu->addAction(aOpenDeckInDeckEditor);
deck->setMenu(libraryMenu, aDrawCard);
} else {
handMenu = 0;
libraryMenu = 0;
handMenu = nullptr;
libraryMenu = nullptr;
}
graveMenu = playerMenu->addMenu(QString());
@ -356,19 +356,19 @@ Player::Player(const ServerInfo_User &info, int _id, bool _local, TabGame *_pare
playerMenu->addSeparator();
playerMenu->addAction(aCardMenu);
for (int i = 0; i < playerLists.size(); ++i) {
QAction *newAction = playerLists[i]->addAction(QString());
for (auto &playerList : playerLists) {
QAction *newAction = playerList->addAction(QString());
newAction->setData(-1);
connect(newAction, SIGNAL(triggered()), this, SLOT(playerListActionTriggered()));
allPlayersActions.append(newAction);
playerLists[i]->addSeparator();
playerList->addSeparator();
}
} else {
countersMenu = 0;
sbMenu = 0;
aCreateAnotherToken = 0;
createPredefinedTokenMenu = 0;
aCardMenu = 0;
countersMenu = nullptr;
sbMenu = nullptr;
aCreateAnotherToken = nullptr;
createPredefinedTokenMenu = nullptr;
aCardMenu = nullptr;
}
aTap = new QAction(this);
@ -436,11 +436,11 @@ Player::Player(const ServerInfo_User &info, int _id, bool _local, TabGame *_pare
connect(aPlayFacedown, SIGNAL(triggered()), this, SLOT(actPlayFacedown()));
for (int i = 0; i < 3; ++i) {
QAction *tempAddCounter = new QAction(this);
auto *tempAddCounter = new QAction(this);
tempAddCounter->setData(9 + i * 1000);
QAction *tempRemoveCounter = new QAction(this);
auto *tempRemoveCounter = new QAction(this);
tempRemoveCounter->setData(10 + i * 1000);
QAction *tempSetCounter = new QAction(this);
auto *tempSetCounter = new QAction(this);
tempSetCounter->setData(11 + i * 1000);
aAddCounter.append(tempAddCounter);
aRemoveCounter.append(tempRemoveCounter);
@ -451,8 +451,8 @@ Player::Player(const ServerInfo_User &info, int _id, bool _local, TabGame *_pare
}
const QList<Player *> &players = game->getPlayers().values();
for (int i = 0; i < players.size(); ++i)
addPlayer(players[i]);
for (auto player : players)
addPlayer(player);
rearrangeZones();
retranslateUi();
@ -494,8 +494,8 @@ void Player::addPlayer(Player *player)
return;
}
for (int i = 0; i < playerLists.size(); ++i) {
QAction *newAction = playerLists[i]->addAction(player->getName());
for (auto &playerList : playerLists) {
QAction *newAction = playerList->addAction(player->getName());
newAction->setData(player->getId());
connect(newAction, SIGNAL(triggered()), this, SLOT(playerListActionTriggered()));
}
@ -507,20 +507,20 @@ void Player::removePlayer(Player *player)
return;
}
for (int i = 0; i < playerLists.size(); ++i) {
QList<QAction *> actionList = playerLists[i]->actions();
for (int j = 0; j < actionList.size(); ++j)
if (actionList[j]->data().toInt() == player->getId()) {
playerLists[i]->removeAction(actionList[j]);
actionList[j]->deleteLater();
for (auto &playerList : playerLists) {
QList<QAction *> actionList = playerList->actions();
for (auto &j : actionList)
if (j->data().toInt() == player->getId()) {
playerList->removeAction(j);
j->deleteLater();
}
}
}
void Player::playerListActionTriggered()
{
QAction *action = static_cast<QAction *>(sender());
QMenu *menu = static_cast<QMenu *>(action->parentWidget());
auto *action = static_cast<QAction *>(sender());
auto *menu = static_cast<QMenu *>(action->parentWidget());
Command_RevealCards cmd;
const int otherPlayerId = action->data().toInt();
@ -533,9 +533,9 @@ void Player::playerListActionTriggered()
} else if (menu == mRevealTopCard) {
int decksize = zones.value("deck")->getCards().size();
bool ok;
int number =
QInputDialog::getInt(0, tr("Reveal top cards of library"), tr("Number of cards: (max. %1)").arg(decksize),
defaultNumberTopCards, 1, decksize, 1, &ok);
int number = QInputDialog::getInt(nullptr, tr("Reveal top cards of library"),
tr("Number of cards: (max. %1)").arg(decksize), defaultNumberTopCards, 1,
decksize, 1, &ok);
if (ok) {
cmd.set_zone_name("deck");
cmd.set_top_cards(number);
@ -692,8 +692,8 @@ void Player::retranslateUi()
aCardMenu->setText(tr("C&ard"));
for (int i = 0; i < allPlayersActions.size(); ++i)
allPlayersActions[i]->setText(tr("&All players"));
for (auto &allPlayersAction : allPlayersActions)
allPlayersAction->setText(tr("&All players"));
}
aPlay->setText(tr("&Play"));
@ -904,8 +904,8 @@ void Player::actViewLibrary()
void Player::actViewTopCards()
{
bool ok;
int number = QInputDialog::getInt(0, tr("View top cards of library"), tr("Number of cards:"), defaultNumberTopCards,
1, 2000000000, 1, &ok);
int number = QInputDialog::getInt(nullptr, tr("View top cards of library"), tr("Number of cards:"),
defaultNumberTopCards, 1, 2000000000, 1, &ok);
if (ok) {
defaultNumberTopCards = number;
static_cast<GameScene *>(scene())->toggleZoneView(this, "deck", number);
@ -934,7 +934,7 @@ void Player::actViewGraveyard()
void Player::actRevealRandomGraveyardCard()
{
Command_RevealCards cmd;
QAction *action = dynamic_cast<QAction *>(sender());
auto *action = dynamic_cast<QAction *>(sender());
const int otherPlayerId = action->data().toInt();
if (otherPlayerId != -1) {
cmd.set_player_id(otherPlayerId);
@ -973,10 +973,10 @@ void Player::actMulligan()
void Player::actDrawCards()
{
int number = QInputDialog::getInt(0, tr("Draw cards"), tr("Number:"));
int number = QInputDialog::getInt(nullptr, tr("Draw cards"), tr("Number:"));
if (number) {
Command_DrawCards cmd;
cmd.set_number(number);
cmd.set_number(static_cast<google::protobuf::uint32>(number));
sendGameCommand(cmd);
}
}
@ -988,7 +988,7 @@ void Player::actUndoDraw()
void Player::actMoveTopCardToGrave()
{
if (zones.value("deck")->getCards().size() == 0) {
if (zones.value("deck")->getCards().empty()) {
return;
}
@ -1005,7 +1005,7 @@ void Player::actMoveTopCardToGrave()
void Player::actMoveTopCardToExile()
{
if (zones.value("deck")->getCards().size() == 0) {
if (zones.value("deck")->getCards().empty()) {
return;
}
@ -1022,7 +1022,7 @@ void Player::actMoveTopCardToExile()
void Player::actMoveTopCardsToGrave()
{
int number = QInputDialog::getInt(0, tr("Move top cards to grave"), tr("Number:"));
int number = QInputDialog::getInt(nullptr, tr("Move top cards to grave"), tr("Number:"));
if (!number) {
return;
}
@ -1048,7 +1048,7 @@ void Player::actMoveTopCardsToGrave()
void Player::actMoveTopCardsToExile()
{
int number = QInputDialog::getInt(0, tr("Move top cards to exile"), tr("Number:"));
int number = QInputDialog::getInt(nullptr, tr("Move top cards to exile"), tr("Number:"));
if (!number) {
return;
}
@ -1131,7 +1131,7 @@ void Player::actRollDie()
1000, 1, &ok);
if (ok) {
Command_RollDie cmd;
cmd.set_sides(sides);
cmd.set_sides(static_cast<google::protobuf::uint32>(sides));
sendGameCommand(cmd);
}
}
@ -1148,7 +1148,7 @@ void Player::actCreateToken()
CardInfoPtr correctedCard = db->getCardBySimpleName(lastTokenName);
if (correctedCard) {
lastTokenName = correctedCard->getName();
lastTokenTableRow = table->clampValidTableRow(2 - correctedCard->getTableRow());
lastTokenTableRow = TableZone::clampValidTableRow(2 - correctedCard->getTableRow());
if (lastTokenPT.isEmpty()) {
lastTokenPT = correctedCard->getPowTough();
}
@ -1182,7 +1182,7 @@ void Player::actCreateAnotherToken()
void Player::actCreatePredefinedToken()
{
QAction *action = static_cast<QAction *>(sender());
auto *action = static_cast<QAction *>(sender());
CardInfoPtr cardInfo = db->getCard(action->text());
if (!cardInfo) {
return;
@ -1199,7 +1199,7 @@ void Player::actCreateRelatedCard()
if (!sourceCard) {
return;
}
QAction *action = static_cast<QAction *>(sender());
auto *action = static_cast<QAction *>(sender());
// If there is a better way of passing a CardRelation through a QAction, please add it here.
QList<CardRelation *> relatedCards = QList<CardRelation *>();
relatedCards.append(sourceCard->getInfo()->getRelatedCards());
@ -1211,7 +1211,7 @@ void Player::actCreateRelatedCard()
* then let's allow it to be created via "create another token"
*/
if (createRelatedFromRelation(sourceCard, cardRelation) && cardRelation->getCanCreateAnother()) {
CardInfoPtr cardInfo = db->getCard(dbNameFromTokenDisplayName(cardRelation->getName()));
CardInfoPtr cardInfo = db->getCard(cardRelation->getName());
setLastToken(cardInfo);
}
}
@ -1257,7 +1257,7 @@ void Player::actCreateAllRelatedCards()
case 0: // else if nonExcludedRelatedCards == 0
for (CardRelation *cardRelationAll : relatedCards) {
if (!cardRelationAll->getDoesAttach() && !cardRelationAll->getIsVariable()) {
dbName = dbNameFromTokenDisplayName(cardRelationAll->getName());
dbName = cardRelationAll->getName();
for (int i = 0; i < cardRelationAll->getDefaultCount(); ++i) {
createCard(sourceCard, dbName);
}
@ -1271,7 +1271,7 @@ void Player::actCreateAllRelatedCards()
default: // else
for (CardRelation *cardRelationNotExcluded : nonExcludedRelatedCards) {
if (!cardRelationNotExcluded->getDoesAttach() && !cardRelationNotExcluded->getIsVariable()) {
dbName = dbNameFromTokenDisplayName(cardRelationNotExcluded->getName());
dbName = cardRelationNotExcluded->getName();
for (int i = 0; i < cardRelationNotExcluded->getDefaultCount(); ++i) {
createCard(sourceCard, dbName);
}
@ -1290,7 +1290,7 @@ void Player::actCreateAllRelatedCards()
* then assign the first to the "Create another" shortcut.
*/
if (cardRelation != nullptr && cardRelation->getCanCreateAnother()) {
CardInfoPtr cardInfo = db->getCard(dbNameFromTokenDisplayName(cardRelation->getName()));
CardInfoPtr cardInfo = db->getCard(cardRelation->getName());
setLastToken(cardInfo);
}
}
@ -1300,12 +1300,12 @@ bool Player::createRelatedFromRelation(const CardItem *sourceCard, const CardRel
if (sourceCard == nullptr || cardRelation == nullptr) {
return false;
}
QString dbName = dbNameFromTokenDisplayName(cardRelation->getName());
QString dbName = cardRelation->getName();
if (cardRelation->getIsVariable()) {
bool ok;
dialogSemaphore = true;
int count = QInputDialog::getInt(0, tr("Create tokens"), tr("Number:"), cardRelation->getDefaultCount(), 1,
MAX_TOKENS_PER_DIALOG, 1, &ok);
int count = QInputDialog::getInt(nullptr, tr("Create tokens"), tr("Number:"), cardRelation->getDefaultCount(),
1, MAX_TOKENS_PER_DIALOG, 1, &ok);
dialogSemaphore = false;
if (!ok) {
return false;
@ -1337,19 +1337,22 @@ void Player::createCard(const CardItem *sourceCard, const QString &dbCardName, b
// get the target token's location
// TODO: Define this QPoint into its own function along with the one below
QPoint gridPoint = QPoint(-1, table->clampValidTableRow(2 - cardInfo->getTableRow()));
QPoint gridPoint = QPoint(-1, TableZone::clampValidTableRow(2 - cardInfo->getTableRow()));
// create the token for the related card
Command_CreateToken cmd;
cmd.set_zone("table");
cmd.set_card_name(cardInfo->getName().toStdString());
if (cardInfo->getColors().length() > 1) // Multicoloured
{
cmd.set_color("m");
} else if (cardInfo->getColors().isEmpty()) {
switch (cardInfo->getColors().size()) {
case 0:
cmd.set_color("");
} else {
cmd.set_color(cardInfo->getColors().first().toLower().toStdString());
break;
case 1:
cmd.set_color("m");
break;
default:
cmd.set_color(cardInfo->getColors().left(1).toLower().toStdString());
break;
}
cmd.set_pt(cardInfo->getPowTough().toStdString());
@ -1377,7 +1380,7 @@ void Player::createAttachedCard(const CardItem *sourceCard, const QString &dbCar
void Player::actSayMessage()
{
QAction *a = qobject_cast<QAction *>(sender());
auto *a = qobject_cast<QAction *>(sender());
Command_GameSay cmd;
cmd.set_message(a->text().toStdString());
sendGameCommand(cmd);
@ -1436,22 +1439,6 @@ void Player::setCardAttrHelper(const GameEventContext &context,
}
}
// token names take the form of "<Descriptors> <Power>/<Toughness> <Card Name> " or "<Card Name> ".
// dbName for tokens should take the form of "<Card Name> ".
// trailing whitespace is significant; it is hacked on at the end as an additional identifier in our single key database
QString Player::dbNameFromTokenDisplayName(const QString &tokenName)
{
QRegularExpression tokenNamePattern(".*/\\S+\\s+(.*)");
QRegularExpressionMatch match = tokenNamePattern.match(tokenName);
if (match.hasMatch()) {
return match.captured(1);
} else if (tokenName.indexOf(tr("Token: ")) != -1) {
return tokenName.mid(tr("Token: ").length());
} else {
return tokenName;
}
}
void Player::eventGameSay(const Event_GameSay &event)
{
emit logSay(this, QString::fromStdString(event.message()));
@ -1481,8 +1468,8 @@ void Player::eventCreateArrow(const Event_CreateArrow &event)
return;
}
CardItem *startCard = static_cast<CardItem *>(arrow->getStartItem());
CardItem *targetCard = qgraphicsitem_cast<CardItem *>(arrow->getTargetItem());
auto *startCard = static_cast<CardItem *>(arrow->getStartItem());
auto *targetCard = qgraphicsitem_cast<CardItem *>(arrow->getTargetItem());
if (targetCard) {
emit logCreateArrow(this, startCard->getOwner(), startCard->getName(), targetCard->getOwner(),
targetCard->getName(), false);
@ -1536,7 +1523,7 @@ void Player::eventSetCardAttr(const Event_SetCardAttr &event, const GameEventCon
true);
}
if (event.attribute() == AttrTapped) {
emit logSetTapped(this, 0, event.attr_value() == "1");
emit logSetTapped(this, nullptr, event.attr_value() == "1");
}
} else {
CardItem *card = zone->getCard(event.card_id(), QString());
@ -1654,7 +1641,7 @@ void Player::eventMoveCard(const Event_MoveCard &event, const GameEventContext &
if (card->getAttachedTo() && (startZone != targetZone)) {
CardItem *parentCard = card->getAttachedTo();
card->setAttachedTo(0);
card->setAttachedTo(nullptr);
parentCard->getZone()->reorganizeCards();
}
@ -1667,8 +1654,8 @@ void Player::eventMoveCard(const Event_MoveCard &event, const GameEventContext &
card->setHovered(false);
const QList<CardItem *> &attachedCards = card->getAttachedCards();
for (int i = 0; i < attachedCards.size(); ++i) {
attachedCards[i]->setParentItem(targetZone);
for (auto attachedCard : attachedCards) {
attachedCard->setParentItem(targetZone);
}
if (startZone->getPlayer() != targetZone->getPlayer()) {
@ -1704,8 +1691,8 @@ void Player::eventMoveCard(const Event_MoveCard &event, const GameEventContext &
}
}
}
for (int i = 0; i < arrowsToDelete.size(); ++i) {
arrowsToDelete[i]->delArrow();
for (auto &i : arrowsToDelete) {
i->delArrow();
}
}
}
@ -1738,8 +1725,8 @@ void Player::eventDestroyCard(const Event_DestroyCard &event)
QList<CardItem *> attachedCards = card->getAttachedCards();
// This list is always empty except for buggy server implementations.
for (int i = 0; i < attachedCards.size(); ++i) {
attachedCards[i]->setAttachedTo(0);
for (auto &attachedCard : attachedCards) {
attachedCard->setAttachedTo(0);
}
emit logDestroyCard(this, card->getName());
@ -1750,9 +1737,9 @@ void Player::eventDestroyCard(const Event_DestroyCard &event)
void Player::eventAttachCard(const Event_AttachCard &event)
{
const QMap<int, Player *> &playerList = game->getPlayers();
Player *targetPlayer = 0;
CardZone *targetZone = 0;
CardItem *targetCard = 0;
Player *targetPlayer = nullptr;
CardZone *targetZone = nullptr;
CardItem *targetCard = nullptr;
if (event.has_target_player_id()) {
targetPlayer = playerList.value(event.target_player_id(), 0);
if (targetPlayer) {
@ -1823,7 +1810,7 @@ void Player::eventRevealCards(const Event_RevealCards &event)
if (!zone) {
return;
}
Player *otherPlayer = 0;
Player *otherPlayer = nullptr;
if (event.has_other_player_id()) {
otherPlayer = game->getPlayers().value(event.other_player_id());
if (!otherPlayer) {
@ -1843,14 +1830,14 @@ void Player::eventRevealCards(const Event_RevealCards &event)
}
if (peeking) {
for (int i = 0; i < cardList.size(); ++i) {
QString cardName = QString::fromStdString(cardList.at(i)->name());
CardItem *card = zone->getCard(cardList.at(i)->id(), QString());
for (auto i : cardList) {
QString cardName = QString::fromStdString(i->name());
CardItem *card = zone->getCard(i->id(), QString());
if (!card) {
continue;
}
card->setName(cardName);
emit logRevealCards(this, zone, cardList.at(i)->id(), cardName, this, true);
emit logRevealCards(this, zone, i->id(), cardName, this, true);
}
} else {
bool showZoneView = true;
@ -1953,7 +1940,7 @@ void Player::processGameEvent(GameEvent::GameEventType type, const GameEvent &ev
}
}
void Player::setActive(bool _active)
void Player::setActivePlayer(bool _active)
{
active = _active;
table->setActive(active);
@ -2073,7 +2060,7 @@ void Player::playCard(CardItem *card, bool faceDown, bool tapped)
cmd.set_y(0);
} else {
int tableRow = faceDown ? 2 : info->getTableRow();
QPoint gridPoint = QPoint(-1, table->clampValidTableRow(2 - tableRow));
QPoint gridPoint = QPoint(-1, TableZone::clampValidTableRow(2 - tableRow));
cardToMove->set_face_down(faceDown);
cardToMove->set_pt(info->getPowTough().toStdString());
cardToMove->set_tapped(faceDown ? false : tapped);
@ -2116,7 +2103,7 @@ AbstractCounter *Player::addCounter(int counterId, const QString &name, QColor c
{
qDebug() << "addCounter:" << getName() << counterId << name;
if (counters.contains(counterId)) {
return 0;
return nullptr;
}
AbstractCounter *ctr;
@ -2163,25 +2150,25 @@ ArrowItem *Player::addArrow(const ServerInfo_Arrow &arrow)
Player *startPlayer = playerList.value(arrow.start_player_id(), 0);
Player *targetPlayer = playerList.value(arrow.target_player_id(), 0);
if (!startPlayer || !targetPlayer) {
return 0;
return nullptr;
}
CardZone *startZone = startPlayer->getZones().value(QString::fromStdString(arrow.start_zone()), 0);
CardZone *targetZone = 0;
CardZone *targetZone = nullptr;
if (arrow.has_target_zone()) {
targetZone = targetPlayer->getZones().value(QString::fromStdString(arrow.target_zone()), 0);
}
if (!startZone || (!targetZone && arrow.has_target_zone())) {
return 0;
return nullptr;
}
CardItem *startCard = startZone->getCard(arrow.start_card_id(), QString());
CardItem *targetCard = 0;
CardItem *targetCard = nullptr;
if (targetZone) {
targetCard = targetZone->getCard(arrow.target_card_id(), QString());
}
if (!startCard || (!targetCard && arrow.has_target_card_id())) {
return 0;
return nullptr;
}
if (targetCard) {
@ -2194,7 +2181,7 @@ ArrowItem *Player::addArrow(const ServerInfo_Arrow &arrow)
ArrowItem *Player::addArrow(int arrowId, CardItem *startCard, ArrowTarget *targetItem, const QColor &color)
{
ArrowItem *arrow = new ArrowItem(this, arrowId, startCard, targetItem, color);
auto *arrow = new ArrowItem(this, arrowId, startCard, targetItem, color);
arrows.insert(arrowId, arrow);
scene()->addItem(arrow);
return arrow;
@ -2295,7 +2282,7 @@ bool Player::clearCardsToDelete()
void Player::actMoveCardXCardsFromTop()
{
bool ok;
int number = QInputDialog::getInt(0, tr("Place card X cards from top of library"),
int number = QInputDialog::getInt(nullptr, tr("Place card X cards from top of library"),
tr("How many cards from the top of the deck should this card be placed:"),
defaultNumberTopCardsToPlaceBelow, 1, 2000000000, 1, &ok);
number--;
@ -2325,7 +2312,7 @@ void Player::actMoveCardXCardsFromTop()
int startPlayerId = cardList[0]->getZone()->getPlayer()->getId();
QString startZone = cardList[0]->getZone()->getName();
Command_MoveCard *cmd = new Command_MoveCard;
auto *cmd = new Command_MoveCard;
cmd->set_start_player_id(startPlayerId);
cmd->set_start_zone(startZone.toStdString());
cmd->mutable_cards_to_move()->CopyFrom(idList);
@ -2344,7 +2331,7 @@ void Player::actMoveCardXCardsFromTop()
void Player::cardMenuAction()
{
QAction *a = dynamic_cast<QAction *>(sender());
auto *a = dynamic_cast<QAction *>(sender());
QList<QGraphicsItem *> sel = scene()->selectedItems();
QList<CardItem *> cardList;
while (!sel.isEmpty()) {
@ -2353,14 +2340,13 @@ void Player::cardMenuAction()
QList<const ::google::protobuf::Message *> commandList;
if (a->data().toInt() <= (int)cmClone) {
for (int i = 0; i < cardList.size(); ++i) {
CardItem *card = cardList[i];
for (auto card : cardList) {
switch (static_cast<CardMenuActionType>(a->data().toInt())) {
// Leaving both for compatibility with server
case cmUntap:
// fallthrough
case cmTap: {
Command_SetCardAttr *cmd = new Command_SetCardAttr;
auto *cmd = new Command_SetCardAttr;
cmd->set_zone(card->getZone()->getName().toStdString());
cmd->set_card_id(card->getId());
cmd->set_attribute(AttrTapped);
@ -2369,7 +2355,7 @@ void Player::cardMenuAction()
break;
}
case cmDoesntUntap: {
Command_SetCardAttr *cmd = new Command_SetCardAttr;
auto *cmd = new Command_SetCardAttr;
cmd->set_zone(card->getZone()->getName().toStdString());
cmd->set_card_id(card->getId());
cmd->set_attribute(AttrDoesntUntap);
@ -2378,7 +2364,7 @@ void Player::cardMenuAction()
break;
}
case cmFlip: {
Command_FlipCard *cmd = new Command_FlipCard;
auto *cmd = new Command_FlipCard;
cmd->set_zone(card->getZone()->getName().toStdString());
cmd->set_card_id(card->getId());
cmd->set_face_down(!card->getFaceDown());
@ -2392,7 +2378,7 @@ void Player::cardMenuAction()
break;
}
case cmPeek: {
Command_RevealCards *cmd = new Command_RevealCards;
auto *cmd = new Command_RevealCards;
cmd->set_zone_name(card->getZone()->getName().toStdString());
cmd->set_card_id(card->getId());
cmd->set_player_id(id);
@ -2400,7 +2386,7 @@ void Player::cardMenuAction()
break;
}
case cmClone: {
Command_CreateToken *cmd = new Command_CreateToken;
auto *cmd = new Command_CreateToken;
cmd->set_zone("table");
cmd->set_card_name(card->getName().toStdString());
cmd->set_color(card->getColor().toStdString());
@ -2418,15 +2404,15 @@ void Player::cardMenuAction()
}
} else {
ListOfCardsToMove idList;
for (int i = 0; i < cardList.size(); ++i) {
idList.add_card()->set_card_id(cardList[i]->getId());
for (auto &i : cardList) {
idList.add_card()->set_card_id(i->getId());
}
int startPlayerId = cardList[0]->getZone()->getPlayer()->getId();
QString startZone = cardList[0]->getZone()->getName();
switch (static_cast<CardMenuActionType>(a->data().toInt())) {
case cmMoveToTopLibrary: {
Command_MoveCard *cmd = new Command_MoveCard;
auto *cmd = new Command_MoveCard;
cmd->set_start_player_id(startPlayerId);
cmd->set_start_zone(startZone.toStdString());
cmd->mutable_cards_to_move()->CopyFrom(idList);
@ -2438,7 +2424,7 @@ void Player::cardMenuAction()
break;
}
case cmMoveToBottomLibrary: {
Command_MoveCard *cmd = new Command_MoveCard;
auto *cmd = new Command_MoveCard;
cmd->set_start_player_id(startPlayerId);
cmd->set_start_zone(startZone.toStdString());
cmd->mutable_cards_to_move()->CopyFrom(idList);
@ -2450,7 +2436,7 @@ void Player::cardMenuAction()
break;
}
case cmMoveToHand: {
Command_MoveCard *cmd = new Command_MoveCard;
auto *cmd = new Command_MoveCard;
cmd->set_start_player_id(startPlayerId);
cmd->set_start_zone(startZone.toStdString());
cmd->mutable_cards_to_move()->CopyFrom(idList);
@ -2462,7 +2448,7 @@ void Player::cardMenuAction()
break;
}
case cmMoveToGraveyard: {
Command_MoveCard *cmd = new Command_MoveCard;
auto *cmd = new Command_MoveCard;
cmd->set_start_player_id(startPlayerId);
cmd->set_start_zone(startZone.toStdString());
cmd->mutable_cards_to_move()->CopyFrom(idList);
@ -2474,7 +2460,7 @@ void Player::cardMenuAction()
break;
}
case cmMoveToExile: {
Command_MoveCard *cmd = new Command_MoveCard;
auto *cmd = new Command_MoveCard;
cmd->set_start_player_id(startPlayerId);
cmd->set_start_zone(startZone.toStdString());
cmd->mutable_cards_to_move()->CopyFrom(idList);
@ -2505,8 +2491,8 @@ void Player::actIncPT(int deltaP, int deltaT)
QList<const ::google::protobuf::Message *> commandList;
QListIterator<QGraphicsItem *> j(scene()->selectedItems());
while (j.hasNext()) {
CardItem *card = static_cast<CardItem *>(j.next());
Command_SetCardAttr *cmd = new Command_SetCardAttr;
auto *card = static_cast<CardItem *>(j.next());
auto *cmd = new Command_SetCardAttr;
cmd->set_zone(card->getZone()->getName().toStdString());
cmd->set_card_id(card->getId());
cmd->set_attribute(AttrPT);
@ -2527,12 +2513,12 @@ void Player::actResetPT()
QList<const ::google::protobuf::Message *> commandList;
QListIterator<QGraphicsItem *> selected(scene()->selectedItems());
while (selected.hasNext()) {
CardItem *card = static_cast<CardItem *>(selected.next());
auto *card = static_cast<CardItem *>(selected.next());
CardInfoPtr info = card->getInfo();
if (!info) {
continue;
}
Command_SetCardAttr *cmd = new Command_SetCardAttr;
auto *cmd = new Command_SetCardAttr;
QString zoneName = card->getZone()->getName();
cmd->set_zone(zoneName.toStdString());
cmd->set_card_id(card->getId());
@ -2556,15 +2542,15 @@ void Player::actSetPT()
QListIterator<QGraphicsItem *> i(scene()->selectedItems());
while (i.hasNext()) {
CardItem *card = static_cast<CardItem *>(i.next());
auto *card = static_cast<CardItem *>(i.next());
if (!card->getPT().isEmpty()) {
oldPT = card->getPT();
}
}
bool ok;
dialogSemaphore = true;
QString pt = QInputDialog::getText(0, tr("Set power/toughness"), tr("Please enter the new PT:"), QLineEdit::Normal,
oldPT, &ok);
QString pt = QInputDialog::getText(nullptr, tr("Set power/toughness"), tr("Please enter the new PT:"),
QLineEdit::Normal, oldPT, &ok);
dialogSemaphore = false;
if (clearCardsToDelete()) {
return;
@ -2576,8 +2562,8 @@ void Player::actSetPT()
QList<const ::google::protobuf::Message *> commandList;
QListIterator<QGraphicsItem *> j(scene()->selectedItems());
while (j.hasNext()) {
CardItem *card = static_cast<CardItem *>(j.next());
Command_SetCardAttr *cmd = new Command_SetCardAttr;
auto *card = static_cast<CardItem *>(j.next());
auto *cmd = new Command_SetCardAttr;
cmd->set_zone(card->getZone()->getName().toStdString());
cmd->set_card_id(card->getId());
cmd->set_attribute(AttrPT);
@ -2636,7 +2622,7 @@ void Player::actSetAnnotation()
QString oldAnnotation;
QListIterator<QGraphicsItem *> i(scene()->selectedItems());
while (i.hasNext()) {
CardItem *card = static_cast<CardItem *>(i.next());
auto *card = static_cast<CardItem *>(i.next());
if (!card->getAnnotation().isEmpty()) {
oldAnnotation = card->getAnnotation();
}
@ -2644,7 +2630,7 @@ void Player::actSetAnnotation()
bool ok;
dialogSemaphore = true;
QString annotation = QInputDialog::getText(0, tr("Set annotation"), tr("Please enter the new annotation:"),
QString annotation = QInputDialog::getText(nullptr, tr("Set annotation"), tr("Please enter the new annotation:"),
QLineEdit::Normal, oldAnnotation, &ok);
dialogSemaphore = false;
if (clearCardsToDelete()) {
@ -2657,8 +2643,8 @@ void Player::actSetAnnotation()
QList<const ::google::protobuf::Message *> commandList;
i.toFront();
while (i.hasNext()) {
CardItem *card = static_cast<CardItem *>(i.next());
Command_SetCardAttr *cmd = new Command_SetCardAttr;
auto *card = static_cast<CardItem *>(i.next());
auto *cmd = new Command_SetCardAttr;
cmd->set_zone(card->getZone()->getName().toStdString());
cmd->set_card_id(card->getId());
cmd->set_attribute(AttrAnnotation);
@ -2674,7 +2660,7 @@ void Player::actAttach()
return;
}
ArrowAttachItem *arrow = new ArrowAttachItem(game->getActiveCard());
auto *arrow = new ArrowAttachItem(game->getActiveCard());
scene()->addItem(arrow);
arrow->grabMouse();
}
@ -2693,16 +2679,16 @@ void Player::actUnattach()
void Player::actCardCounterTrigger()
{
QAction *action = static_cast<QAction *>(sender());
auto *action = static_cast<QAction *>(sender());
int counterId = action->data().toInt() / 1000;
QList<const ::google::protobuf::Message *> commandList;
switch (action->data().toInt() % 1000) { // TODO: define case numbers
case 9: {
QListIterator<QGraphicsItem *> i(scene()->selectedItems());
while (i.hasNext()) {
CardItem *card = static_cast<CardItem *>(i.next());
auto *card = static_cast<CardItem *>(i.next());
if (card->getCounters().value(counterId, 0) < MAX_COUNTERS_ON_CARD) {
Command_SetCardCounter *cmd = new Command_SetCardCounter;
auto *cmd = new Command_SetCardCounter;
cmd->set_zone(card->getZone()->getName().toStdString());
cmd->set_card_id(card->getId());
cmd->set_counter_id(counterId);
@ -2715,9 +2701,9 @@ void Player::actCardCounterTrigger()
case 10: {
QListIterator<QGraphicsItem *> i(scene()->selectedItems());
while (i.hasNext()) {
CardItem *card = static_cast<CardItem *>(i.next());
auto *card = static_cast<CardItem *>(i.next());
if (card->getCounters().value(counterId, 0)) {
Command_SetCardCounter *cmd = new Command_SetCardCounter;
auto *cmd = new Command_SetCardCounter;
cmd->set_zone(card->getZone()->getName().toStdString());
cmd->set_card_id(card->getId());
cmd->set_counter_id(counterId);
@ -2730,7 +2716,8 @@ void Player::actCardCounterTrigger()
case 11: {
bool ok;
dialogSemaphore = true;
int number = QInputDialog::getInt(0, tr("Set counters"), tr("Number:"), 0, 0, MAX_COUNTERS_ON_CARD, 1, &ok);
int number =
QInputDialog::getInt(nullptr, tr("Set counters"), tr("Number:"), 0, 0, MAX_COUNTERS_ON_CARD, 1, &ok);
dialogSemaphore = false;
if (clearCardsToDelete() || !ok) {
return;
@ -2738,8 +2725,8 @@ void Player::actCardCounterTrigger()
QListIterator<QGraphicsItem *> i(scene()->selectedItems());
while (i.hasNext()) {
CardItem *card = static_cast<CardItem *>(i.next());
Command_SetCardCounter *cmd = new Command_SetCardCounter;
auto *card = static_cast<CardItem *>(i.next());
auto *cmd = new Command_SetCardCounter;
cmd->set_zone(card->getZone()->getName().toStdString());
cmd->set_card_id(card->getId());
cmd->set_counter_id(counterId);
@ -2964,16 +2951,25 @@ void Player::addRelatedCardActions(const CardItem *card, QMenu *cardMenu)
int index = 0;
QAction *createRelatedCards = nullptr;
for (const CardRelation *cardRelation : relatedCards) {
QString cardName = cardRelation->getName();
CardInfoPtr relatedCard = db->getCard(cardRelation->getName());
if (relatedCard == nullptr)
continue;
QString relatedCardName;
if (relatedCard->getPowTough().size() > 0) {
relatedCardName = relatedCard->getPowTough() + " " + relatedCard->getName(); // "n/n name"
} else {
relatedCardName = relatedCard->getName(); // "name"
}
QString text = tr("Token: ");
if (cardRelation->getDoesAttach()) {
text += tr("Attach to ") + "\"" + cardName + "\"";
text += tr("Attach to ") + "\"" + relatedCardName + "\"";
} else if (cardRelation->getIsVariable()) {
text += "X " + cardName;
text += "X " + relatedCardName;
} else if (cardRelation->getDefaultCount() != 1) {
text += QString(cardRelation->getDefaultCount()) + "x " + cardName;
text += QString::number(cardRelation->getDefaultCount()) + "x " + relatedCardName;
} else {
text += cardName;
text += relatedCardName;
}
if (createRelatedCards == nullptr) {
@ -2985,7 +2981,7 @@ void Player::addRelatedCardActions(const CardItem *card, QMenu *cardMenu)
}
}
QAction *createRelated = new QAction(text, this);
auto *createRelated = new QAction(text, this);
createRelated->setData(QVariant(index++));
connect(createRelated, SIGNAL(triggered()), this, SLOT(actCreateRelatedCard()));
cardMenu->addAction(createRelated);
@ -3010,7 +3006,7 @@ QMenu *Player::getCardMenu() const
if (aCardMenu) {
return aCardMenu->menu();
}
return 0;
return nullptr;
}
QString Player::getName() const
@ -3055,7 +3051,7 @@ void Player::setMirrored(bool _mirrored)
void Player::processSceneSizeChange(int newPlayerWidth)
{
// Extend table (and hand, if horizontal) to accomodate the new player width.
// Extend table (and hand, if horizontal) to accommodate the new player width.
qreal tableWidth = newPlayerWidth - CARD_HEIGHT - 15 - counterAreaWidth - stack->boundingRect().width();
if (!settingsCache->getHorizontalHand()) {
tableWidth -= hand->boundingRect().width();
@ -3072,10 +3068,10 @@ void Player::setLastToken(CardInfoPtr cardInfo)
}
lastTokenName = cardInfo->getName();
lastTokenColor = cardInfo->getColors().isEmpty() ? QString() : cardInfo->getColors().first().toLower();
lastTokenColor = cardInfo->getColors().isEmpty() ? QString() : cardInfo->getColors().left(1).toLower();
lastTokenPT = cardInfo->getPowTough();
lastTokenAnnotation = settingsCache->getAnnotateTokens() ? cardInfo->getText() : "";
lastTokenTableRow = table->clampValidTableRow(2 - cardInfo->getTableRow());
lastTokenTableRow = TableZone::clampValidTableRow(2 - cardInfo->getTableRow());
lastTokenDestroy = true;
aCreateAnotherToken->setText(tr("C&reate another %1 token").arg(lastTokenName));
aCreateAnotherToken->setEnabled(true);

View file

@ -79,17 +79,17 @@ public:
{
Type = typeOther
};
int type() const
int type() const override
{
return Type;
}
PlayerArea(QGraphicsItem *parent = 0);
QRectF boundingRect() const
explicit PlayerArea(QGraphicsItem *parent = nullptr);
QRectF boundingRect() const override
{
return bRect;
}
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;
void setSize(qreal width, qreal height);
};
@ -251,7 +251,6 @@ private:
void createCard(const CardItem *sourceCard, const QString &dbCardName, bool attach = false);
void createAttachedCard(const CardItem *sourceCard, const QString &dbCardName);
bool createRelatedFromRelation(const CardItem *sourceCard, const CardRelation *cardRelation);
QString dbNameFromTokenDisplayName(const QString &tokenName);
QRectF bRect;
@ -308,12 +307,12 @@ public:
{
Type = typeOther
};
int type() const
int type() const override
{
return Type;
}
QRectF boundingRect() const;
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
QRectF boundingRect() const override;
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;
void playCard(CardItem *c, bool faceDown, bool tapped);
void addCard(CardItem *c);
@ -336,7 +335,7 @@ public:
}
Player(const ServerInfo_User &info, int _id, bool _local, TabGame *_parent);
~Player();
~Player() override;
void retranslateUi();
void clear();
TabGame *getGame() const
@ -380,7 +379,7 @@ public:
{
return active;
}
void setActive(bool _active);
void setActivePlayer(bool _active);
void setShortcutsActive();
void setShortcutsInactive();
void updateZones();

View file

@ -1,5 +1,4 @@
#include "releasechannel.h"
#include "qt-json/json.h"
#include "version_string.h"
#include <QJsonArray>
@ -93,21 +92,20 @@ QString StableReleaseChannel::getReleaseChannelUrl() const
void StableReleaseChannel::releaseListFinished()
{
QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
bool ok;
QString tmp = QString(reply->readAll());
auto *reply = static_cast<QNetworkReply *>(sender());
QJsonParseError parseError{};
QJsonDocument jsonResponse = QJsonDocument::fromJson(reply->readAll(), &parseError);
reply->deleteLater();
QVariantMap resultMap = QtJson::Json::parse(tmp, ok).toMap();
if (!ok) {
qWarning() << "No reply received from the release update server:" << tmp;
if (parseError.error != QJsonParseError::NoError) {
qWarning() << "No reply received from the release update server.";
emit error(tr("No reply received from the release update server."));
return;
}
QVariantMap resultMap = jsonResponse.toVariant().toMap();
if (!(resultMap.contains("name") && resultMap.contains("html_url") && resultMap.contains("tag_name") &&
resultMap.contains("published_at"))) {
qWarning() << "Invalid received from the release update server:" << tmp;
qWarning() << "Invalid received from the release update server.";
emit error(tr("Invalid reply received from the release update server."));
return;
}
@ -145,7 +143,7 @@ void StableReleaseChannel::releaseListFinished()
QString myHash = QString(VERSION_COMMIT);
qDebug() << "Current hash=" << myHash << "update hash=" << shortHash;
qDebug() << "Got reply from release server, size=" << tmp.size() << "name=" << lastRelease->getName()
qDebug() << "Got reply from release server, name=" << lastRelease->getName()
<< "desc=" << lastRelease->getDescriptionUrl() << "date=" << lastRelease->getPublishDate()
<< "url=" << lastRelease->getDownloadUrl();
@ -158,26 +156,25 @@ void StableReleaseChannel::releaseListFinished()
void StableReleaseChannel::tagListFinished()
{
QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
bool ok;
QString tmp = QString(reply->readAll());
auto *reply = static_cast<QNetworkReply *>(sender());
QJsonParseError parseError{};
QJsonDocument jsonResponse = QJsonDocument::fromJson(reply->readAll(), &parseError);
reply->deleteLater();
QVariantMap resultMap = QtJson::Json::parse(tmp, ok).toMap();
if (!ok) {
qWarning() << "No reply received from the tag update server:" << tmp;
if (parseError.error != QJsonParseError::NoError) {
qWarning() << "No reply received from the tag update server.";
emit error(tr("No reply received from the tag update server."));
return;
}
QVariantMap resultMap = jsonResponse.toVariant().toMap();
if (!(resultMap.contains("object") && resultMap["object"].toMap().contains("sha"))) {
qWarning() << "Invalid received from the tag update server:" << tmp;
qWarning() << "Invalid received from the tag update server.";
emit error(tr("Invalid reply received from the tag update server."));
return;
}
lastRelease->setCommitHash(resultMap["object"].toMap()["sha"].toString());
qDebug() << "Got reply from tag server, size=" << tmp.size() << "commit=" << lastRelease->getCommitHash();
qDebug() << "Got reply from tag server, commit=" << lastRelease->getCommitHash();
QString shortHash = lastRelease->getCommitHash().left(GIT_SHORT_HASH_LEN);
QString myHash = QString(VERSION_COMMIT);
@ -190,7 +187,6 @@ void StableReleaseChannel::tagListFinished()
void StableReleaseChannel::fileListFinished()
{
// Only implemented to satisfy interface
return;
}
QString BetaReleaseChannel::getManualDownloadUrl() const
@ -210,7 +206,7 @@ QString BetaReleaseChannel::getReleaseChannelUrl() const
void BetaReleaseChannel::releaseListFinished()
{
QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
auto *reply = static_cast<QNetworkReply *>(sender());
QByteArray jsonData = reply->readAll();
reply->deleteLater();
@ -224,7 +220,7 @@ void BetaReleaseChannel::releaseListFinished()
*/
QVariantMap resultMap = array.at(0).toObject().toVariantMap();
if (array.size() == 0 || resultMap.size() == 0) {
if (array.empty() || resultMap.empty()) {
qWarning() << "No reply received from the release update server:" << QString(jsonData);
emit error(tr("No reply received from the release update server."));
return;
@ -262,18 +258,17 @@ void BetaReleaseChannel::releaseListFinished()
void BetaReleaseChannel::fileListFinished()
{
QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
QByteArray jsonData = reply->readAll();
auto *reply = static_cast<QNetworkReply *>(sender());
QJsonParseError parseError{};
QJsonDocument jsonResponse = QJsonDocument::fromJson(reply->readAll(), &parseError);
reply->deleteLater();
bool ok;
QVariantList resultList = QtJson::Json::parse(jsonData, ok).toList();
if (!ok) {
qWarning() << "No reply received from the file update server:" << QString(jsonData);
if (parseError.error != QJsonParseError::NoError) {
qWarning() << "No reply received from the file update server.";
emit error(tr("No reply received from the file update server."));
return;
}
QVariantList resultList = jsonResponse.toVariant().toList();
QString shortHash = lastRelease->getCommitHash().left(GIT_SHORT_HASH_LEN);
QString myHash = QString(VERSION_COMMIT);
qDebug() << "Current hash=" << myHash << "update hash=" << shortHash;

View file

@ -5,6 +5,7 @@
#include <QObject>
#include <QString>
#include <QVariantMap>
#include <utility>
class QNetworkReply;
class QNetworkAccessManager;
@ -15,8 +16,8 @@ class Release
friend class BetaReleaseChannel;
public:
Release(){};
~Release(){};
Release() = default;
~Release() = default;
private:
QString name, descriptionUrl, downloadUrl, commitHash;
@ -26,20 +27,20 @@ private:
protected:
void setName(QString _name)
{
name = _name;
name = std::move(_name);
}
void setDescriptionUrl(QString _descriptionUrl)
{
descriptionUrl = _descriptionUrl;
descriptionUrl = std::move(_descriptionUrl);
}
void setDownloadUrl(QString _downloadUrl)
{
downloadUrl = _downloadUrl;
downloadUrl = std::move(_downloadUrl);
compatibleVersionFound = true;
}
void setCommitHash(QString _commitHash)
{
commitHash = _commitHash;
commitHash = std::move(_commitHash);
}
void setPublishDate(QDate _publishDate)
{
@ -78,7 +79,7 @@ class ReleaseChannel : public QObject
Q_OBJECT
public:
ReleaseChannel();
~ReleaseChannel();
~ReleaseChannel() override;
protected:
// shared by all instances
@ -116,33 +117,41 @@ class StableReleaseChannel : public ReleaseChannel
{
Q_OBJECT
public:
StableReleaseChannel(){};
~StableReleaseChannel(){};
virtual QString getManualDownloadUrl() const;
virtual QString getName() const;
StableReleaseChannel() = default;
~StableReleaseChannel() override = default;
QString getManualDownloadUrl() const override;
QString getName() const override;
protected:
virtual QString getReleaseChannelUrl() const;
QString getReleaseChannelUrl() const override;
protected slots:
virtual void releaseListFinished();
void releaseListFinished() override;
void tagListFinished();
virtual void fileListFinished();
void fileListFinished() override;
};
class BetaReleaseChannel : public ReleaseChannel
{
Q_OBJECT
public:
BetaReleaseChannel(){};
~BetaReleaseChannel(){};
virtual QString getManualDownloadUrl() const;
virtual QString getName() const;
BetaReleaseChannel() = default;
~BetaReleaseChannel() override = default;
QString getManualDownloadUrl() const override;
QString getName() const override;
protected:
virtual QString getReleaseChannelUrl() const;
QString getReleaseChannelUrl() const override;
protected slots:
virtual void releaseListFinished();
virtual void fileListFinished();
void releaseListFinished() override;
void fileListFinished() override;
};
#endif

View file

@ -29,9 +29,9 @@ QStringList DownloadSettings::getAllURLs()
void DownloadSettings::populateDefaultURLs()
{
downloadURLs.clear();
downloadURLs.append("https://api.scryfall.com/cards/!uuid!?format=image");
downloadURLs.append("https://api.scryfall.com/cards/multiverse/!cardid!?format=image");
downloadURLs.append("http://gatherer.wizards.com/Handlers/Image.ashx?multiverseid=!cardid!&type=card");
downloadURLs.append("https://api.scryfall.com/cards/!set:uuid!?format=image&face=!prop:side!");
downloadURLs.append("https://api.scryfall.com/cards/multiverse/!set:muid!?format=image");
downloadURLs.append("http://gatherer.wizards.com/Handlers/Image.ashx?multiverseid=!set:muid!&type=card");
downloadURLs.append("http://gatherer.wizards.com/Handlers/Image.ashx?name=!name!&type=card");
setValue(QVariant::fromValue(downloadURLs), "urls", "downloads");
}

View file

@ -22,62 +22,62 @@
<context>
<name>AppearanceSettingsPage</name>
<message>
<location filename="../src/dlg_settings.cpp" line="418"/>
<location filename="../src/dlg_settings.cpp" line="338"/>
<source>Theme settings</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="419"/>
<location filename="../src/dlg_settings.cpp" line="339"/>
<source>Current theme:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="421"/>
<location filename="../src/dlg_settings.cpp" line="341"/>
<source>Card rendering</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="422"/>
<location filename="../src/dlg_settings.cpp" line="342"/>
<source>Display card names on cards having a picture</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="423"/>
<location filename="../src/dlg_settings.cpp" line="343"/>
<source>Scale cards on mouse over</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="425"/>
<location filename="../src/dlg_settings.cpp" line="345"/>
<source>Hand layout</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="426"/>
<location filename="../src/dlg_settings.cpp" line="346"/>
<source>Display hand horizontally (wastes space)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="427"/>
<location filename="../src/dlg_settings.cpp" line="347"/>
<source>Enable left justification</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="429"/>
<location filename="../src/dlg_settings.cpp" line="349"/>
<source>Table grid layout</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="430"/>
<location filename="../src/dlg_settings.cpp" line="350"/>
<source>Invert vertical coordinate</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="431"/>
<location filename="../src/dlg_settings.cpp" line="351"/>
<source>Minimum player count for multi-column layout:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="432"/>
<location filename="../src/dlg_settings.cpp" line="352"/>
<source>Maximum font size for information displayed on cards:</source>
<translation type="unfinished"></translation>
</message>
@ -192,22 +192,22 @@ This is only saved for moderators and cannot be seen by the banned person.</sour
<context>
<name>BetaReleaseChannel</name>
<message>
<location filename="../src/releasechannel.cpp" line="203"/>
<location filename="../src/releasechannel.cpp" line="200"/>
<source>Beta Releases</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/releasechannel.cpp" line="229"/>
<location filename="../src/releasechannel.cpp" line="226"/>
<source>No reply received from the release update server.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/releasechannel.cpp" line="238"/>
<location filename="../src/releasechannel.cpp" line="235"/>
<source>Invalid reply received from the release update server.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/releasechannel.cpp" line="273"/>
<location filename="../src/releasechannel.cpp" line="268"/>
<source>No reply received from the file update server.</source>
<translation type="unfinished"></translation>
</message>
@ -330,17 +330,17 @@ This is only saved for moderators and cannot be seen by the banned person.</sour
<context>
<name>CardFrame</name>
<message>
<location filename="../src/cardframe.cpp" line="63"/>
<location filename="../src/cardframe.cpp" line="64"/>
<source>Image</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/cardframe.cpp" line="64"/>
<location filename="../src/cardframe.cpp" line="65"/>
<source>Description</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/cardframe.cpp" line="65"/>
<location filename="../src/cardframe.cpp" line="66"/>
<source>Both</source>
<translation type="unfinished"></translation>
</message>
@ -348,40 +348,20 @@ This is only saved for moderators and cannot be seen by the banned person.</sour
<context>
<name>CardInfoText</name>
<message>
<location filename="../src/cardinfotext.cpp" line="123"/>
<location filename="../src/cardinfotext.cpp" line="53"/>
<source>Related cards:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/cardinfotext.cpp" line="77"/>
<source>Unknown card:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/cardinfotext.cpp" line="131"/>
<location filename="../src/cardinfotext.cpp" line="37"/>
<source>Name:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/cardinfotext.cpp" line="132"/>
<source>Mana cost:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/cardinfotext.cpp" line="133"/>
<source>Color(s):</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/cardinfotext.cpp" line="134"/>
<source>Card type:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/cardinfotext.cpp" line="135"/>
<source>P / T:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/cardinfotext.cpp" line="136"/>
<source>Loyalty:</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>CardItem</name>
@ -522,58 +502,120 @@ This is only saved for moderators and cannot be seen by the banned person.</sour
<context>
<name>DeckEditorSettingsPage</name>
<message>
<location filename="../src/dlg_settings.cpp" line="511"/>
<location filename="../src/dlg_settings.cpp" line="561"/>
<location filename="../src/dlg_settings.cpp" line="440"/>
<location filename="../src/dlg_settings.cpp" line="615"/>
<source>Update Spoilers</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="517"/>
<location filename="../src/dlg_settings.cpp" line="548"/>
<source>Success</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="517"/>
<source>Download URLs have been reset.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="548"/>
<source>Downloaded card pictures have been reset.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="550"/>
<source>Error</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="550"/>
<source>One or more downloaded card pictures could not be cleared.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="557"/>
<source>Add URL</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="557"/>
<location filename="../src/dlg_settings.cpp" line="577"/>
<source>URL:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="577"/>
<source>Edit URL</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="604"/>
<source>Updating...</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="580"/>
<location filename="../src/dlg_settings.cpp" line="634"/>
<source>Choose path</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="606"/>
<location filename="../src/dlg_settings.cpp" line="660"/>
<source>URL Download Priority</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="661"/>
<source>Spoilers</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="607"/>
<location filename="../src/dlg_settings.cpp" line="662"/>
<source>Download Spoilers Automatically</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="608"/>
<location filename="../src/dlg_settings.cpp" line="663"/>
<source>Spoiler Location:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="609"/>
<source>Hey, something&apos;s here finally!</source>
<location filename="../src/dlg_settings.cpp" line="668"/>
<source>Download card pictures on the fly</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="610"/>
<location filename="../src/dlg_settings.cpp" line="669"/>
<source>How to add a custom URL</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="670"/>
<source>Delete Downloaded Images</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="671"/>
<source>Reset Download URLs</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="664"/>
<source>Last Updated</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="611"/>
<location filename="../src/dlg_settings.cpp" line="665"/>
<source>Spoilers download automatically on launch</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="612"/>
<location filename="../src/dlg_settings.cpp" line="666"/>
<source>Press the button to manually update without relaunching</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="613"/>
<location filename="../src/dlg_settings.cpp" line="667"/>
<source>Do not close settings until manual update complete</source>
<translation type="unfinished"></translation>
</message>
@ -1498,12 +1540,12 @@ Make sure to enable the &apos;Token&apos; set in the &quot;Manage sets&quot; dia
<context>
<name>DlgSettings</name>
<message>
<location filename="../src/dlg_settings.cpp" line="1017"/>
<location filename="../src/dlg_settings.cpp" line="1079"/>
<source>Unknown Error loading card database</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="1025"/>
<location filename="../src/dlg_settings.cpp" line="1087"/>
<source>Your card database is invalid.
Cockatrice may not function correctly with an invalid database
@ -1514,7 +1556,7 @@ Would you like to change your database location setting?</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="1031"/>
<location filename="../src/dlg_settings.cpp" line="1093"/>
<source>Your card database version is too old.
This can cause problems loading card information or images
@ -1525,7 +1567,7 @@ Would you like to change your database location setting?</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="1037"/>
<location filename="../src/dlg_settings.cpp" line="1099"/>
<source>Your card database did not finish loading
Please file a ticket at http://github.com/Cockatrice/Cockatrice/issues with your cards.xml attached
@ -1534,21 +1576,21 @@ Would you like to change your database location setting?</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="1043"/>
<location filename="../src/dlg_settings.cpp" line="1105"/>
<source>File Error loading your card database.
Would you like to change your database location setting?</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="1047"/>
<location filename="../src/dlg_settings.cpp" line="1109"/>
<source>Your card database was loaded but contains no cards.
Would you like to change your database location setting?</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="1051"/>
<location filename="../src/dlg_settings.cpp" line="1113"/>
<source>Unknown card database load status
Please file a ticket at http://github.com/Cockatrice/Cockatrice/issues
@ -1557,59 +1599,59 @@ Would you like to change your database location setting?</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="1059"/>
<location filename="../src/dlg_settings.cpp" line="1069"/>
<location filename="../src/dlg_settings.cpp" line="1079"/>
<location filename="../src/dlg_settings.cpp" line="1121"/>
<location filename="../src/dlg_settings.cpp" line="1131"/>
<location filename="../src/dlg_settings.cpp" line="1141"/>
<source>Error</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="1070"/>
<location filename="../src/dlg_settings.cpp" line="1132"/>
<source>The path to your deck directory is invalid. Would you like to go back and set the correct path?</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="1080"/>
<location filename="../src/dlg_settings.cpp" line="1142"/>
<source>The path to your card pictures directory is invalid. Would you like to go back and set the correct path?</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="1092"/>
<location filename="../src/dlg_settings.cpp" line="1154"/>
<source>Settings</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="1094"/>
<location filename="../src/dlg_settings.cpp" line="1156"/>
<source>General</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="1095"/>
<location filename="../src/dlg_settings.cpp" line="1157"/>
<source>Appearance</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="1096"/>
<location filename="../src/dlg_settings.cpp" line="1158"/>
<source>User Interface</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="1097"/>
<source>Deck Editor</source>
<location filename="../src/dlg_settings.cpp" line="1159"/>
<source>Card Sources</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="1098"/>
<location filename="../src/dlg_settings.cpp" line="1160"/>
<source>Chat</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="1099"/>
<location filename="../src/dlg_settings.cpp" line="1161"/>
<source>Sound</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="1100"/>
<location filename="../src/dlg_settings.cpp" line="1162"/>
<source>Shortcuts</source>
<translation type="unfinished"></translation>
</message>
@ -2001,127 +2043,76 @@ You may have to build from source yourself.</source>
<context>
<name>GeneralSettingsPage</name>
<message>
<location filename="../src/dlg_settings.cpp" line="173"/>
<location filename="../src/dlg_settings.cpp" line="183"/>
<location filename="../src/dlg_settings.cpp" line="193"/>
<location filename="../src/dlg_settings.cpp" line="203"/>
<location filename="../src/dlg_settings.cpp" line="213"/>
<location filename="../src/dlg_settings.cpp" line="223"/>
<location filename="../src/dlg_settings.cpp" line="233"/>
<location filename="../src/dlg_settings.cpp" line="267"/>
<location filename="../src/dlg_settings.cpp" line="277"/>
<source>Choose path</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="260"/>
<source>Success</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="260"/>
<source>Downloaded card pictures have been reset.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="262"/>
<source>Error</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="262"/>
<source>One or more downloaded card pictures could not be cleared.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="292"/>
<location filename="../src/dlg_settings.cpp" line="228"/>
<source>Personal settings</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="293"/>
<location filename="../src/dlg_settings.cpp" line="229"/>
<source>Language:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="294"/>
<source>Download card pictures on the fly</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="297"/>
<location filename="../src/dlg_settings.cpp" line="232"/>
<source>Paths (editing disabled in portable mode)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="299"/>
<location filename="../src/dlg_settings.cpp" line="234"/>
<source>Paths</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="302"/>
<location filename="../src/dlg_settings.cpp" line="237"/>
<source>Decks directory:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="303"/>
<location filename="../src/dlg_settings.cpp" line="238"/>
<source>Replays directory:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="304"/>
<location filename="../src/dlg_settings.cpp" line="239"/>
<source>Pictures directory:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="305"/>
<location filename="../src/dlg_settings.cpp" line="240"/>
<source>Card database:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="306"/>
<location filename="../src/dlg_settings.cpp" line="241"/>
<source>Token database:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="307"/>
<location filename="../src/dlg_settings.cpp" line="242"/>
<source>Picture cache size:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="308"/>
<source>Primary download URL:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="309"/>
<source>Fallback download URL:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="311"/>
<source>How to set a custom picture url</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="312"/>
<source>Reset/clear downloaded pictures</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="313"/>
<location filename="../src/dlg_settings.cpp" line="243"/>
<source>Update channel</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="314"/>
<location filename="../src/dlg_settings.cpp" line="244"/>
<source>Notify if a feature supported by the server is missing in my client</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="315"/>
<location filename="../src/dlg_settings.cpp" line="316"/>
<source>Reset</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="317"/>
<location filename="../src/dlg_settings.cpp" line="245"/>
<source>Show tips on startup</source>
<translation type="unfinished"></translation>
</message>
@ -3443,94 +3434,157 @@ Cockatrice will now reload the card database.</source>
<context>
<name>MessagesSettingsPage</name>
<message>
<location filename="../src/dlg_settings.cpp" line="652"/>
<location filename="../src/dlg_settings.cpp" line="710"/>
<source>Word1 Word2 Word3</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="779"/>
<location filename="../src/dlg_settings.cpp" line="750"/>
<source>Add New URL</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="755"/>
<source>Edit URL</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="759"/>
<source>Remove URL</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="841"/>
<source>Add message</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="779"/>
<location filename="../src/dlg_settings.cpp" line="791"/>
<location filename="../src/dlg_settings.cpp" line="841"/>
<location filename="../src/dlg_settings.cpp" line="853"/>
<source>Message:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="791"/>
<location filename="../src/dlg_settings.cpp" line="853"/>
<source>Edit message</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="809"/>
<location filename="../src/dlg_settings.cpp" line="871"/>
<source>Chat settings</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="810"/>
<location filename="../src/dlg_settings.cpp" line="872"/>
<source>Custom alert words</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="811"/>
<location filename="../src/dlg_settings.cpp" line="873"/>
<source>Enable chat mentions</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="812"/>
<location filename="../src/dlg_settings.cpp" line="874"/>
<source>Enable mention completer</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="813"/>
<location filename="../src/dlg_settings.cpp" line="875"/>
<source>In-game message macros</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="814"/>
<location filename="../src/dlg_settings.cpp" line="876"/>
<source>Ignore chat room messages sent by unregistered users</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="815"/>
<location filename="../src/dlg_settings.cpp" line="877"/>
<source>Ignore private messages sent by unregistered users</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="816"/>
<location filename="../src/dlg_settings.cpp" line="817"/>
<location filename="../src/dlg_settings.cpp" line="878"/>
<location filename="../src/dlg_settings.cpp" line="879"/>
<source>Invert text color</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="818"/>
<location filename="../src/dlg_settings.cpp" line="880"/>
<source>Enable desktop notifications for private messages</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="819"/>
<location filename="../src/dlg_settings.cpp" line="881"/>
<source>Enable desktop notification for mentions</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="820"/>
<location filename="../src/dlg_settings.cpp" line="882"/>
<source>Enable room message history on join</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="821"/>
<location filename="../src/dlg_settings.cpp" line="822"/>
<location filename="../src/dlg_settings.cpp" line="883"/>
<location filename="../src/dlg_settings.cpp" line="884"/>
<source>(Color is hexadecimal)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="823"/>
<location filename="../src/dlg_settings.cpp" line="885"/>
<source>Separate words with a space, alphanumeric characters only</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>Mtg</name>
<message>
<location filename="../src/game_specific_terms.h" line="28"/>
<source>Card type</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/game_specific_terms.h" line="30"/>
<source>Converted mana cost</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/game_specific_terms.h" line="32"/>
<source>Color(s)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/game_specific_terms.h" line="34"/>
<source>Loyalty</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/game_specific_terms.h" line="36"/>
<source>Main card type</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/game_specific_terms.h" line="38"/>
<source>Mana cost</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/game_specific_terms.h" line="40"/>
<source>P / T</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/game_specific_terms.h" line="42"/>
<source>Side</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/game_specific_terms.h" line="44"/>
<source>Layout</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>PhasesToolbar</name>
<message>
@ -3948,7 +4002,7 @@ Cockatrice will now reload the card database.</source>
</message>
<message>
<location filename="../src/player.cpp" line="1160"/>
<location filename="../src/player.cpp" line="3080"/>
<location filename="../src/player.cpp" line="3077"/>
<source>C&amp;reate another %1 token</source>
<translation type="unfinished"></translation>
</message>
@ -3958,34 +4012,32 @@ Cockatrice will now reload the card database.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/player.cpp" line="1448"/>
<location filename="../src/player.cpp" line="1449"/>
<location filename="../src/player.cpp" line="2968"/>
<location filename="../src/player.cpp" line="2965"/>
<source>Token: </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/player.cpp" line="2298"/>
<location filename="../src/player.cpp" line="2286"/>
<source>Place card X cards from top of library</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/player.cpp" line="2299"/>
<location filename="../src/player.cpp" line="2287"/>
<source>How many cards from the top of the deck should this card be placed:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/player.cpp" line="2940"/>
<location filename="../src/player.cpp" line="2928"/>
<source>View related cards</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/player.cpp" line="2970"/>
<location filename="../src/player.cpp" line="2967"/>
<source>Attach to </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/player.cpp" line="2984"/>
<location filename="../src/player.cpp" line="2981"/>
<source>All tokens</source>
<translation type="unfinished"></translation>
</message>
@ -4036,7 +4088,7 @@ Cockatrice will now reload the card database.</source>
<location filename="../src/player.cpp" line="1025"/>
<location filename="../src/player.cpp" line="1051"/>
<location filename="../src/player.cpp" line="1307"/>
<location filename="../src/player.cpp" line="2733"/>
<location filename="../src/player.cpp" line="2721"/>
<source>Number:</source>
<translation type="unfinished"></translation>
</message>
@ -4061,27 +4113,27 @@ Cockatrice will now reload the card database.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/player.cpp" line="2566"/>
<location filename="../src/player.cpp" line="2554"/>
<source>Set power/toughness</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/player.cpp" line="2566"/>
<location filename="../src/player.cpp" line="2554"/>
<source>Please enter the new PT:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/player.cpp" line="2647"/>
<location filename="../src/player.cpp" line="2635"/>
<source>Set annotation</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/player.cpp" line="2647"/>
<location filename="../src/player.cpp" line="2635"/>
<source>Please enter the new annotation:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/player.cpp" line="2733"/>
<location filename="../src/player.cpp" line="2721"/>
<source>Set counters</source>
<translation type="unfinished"></translation>
</message>
@ -4352,27 +4404,27 @@ Please check your shortcut settings!</source>
<context>
<name>SoundSettingsPage</name>
<message>
<location filename="../src/dlg_settings.cpp" line="891"/>
<location filename="../src/dlg_settings.cpp" line="953"/>
<source>Enable &amp;sounds</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="892"/>
<location filename="../src/dlg_settings.cpp" line="954"/>
<source>Current sounds theme:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="893"/>
<location filename="../src/dlg_settings.cpp" line="955"/>
<source>Test system sound engine</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="894"/>
<location filename="../src/dlg_settings.cpp" line="956"/>
<source>Sound settings</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="895"/>
<location filename="../src/dlg_settings.cpp" line="957"/>
<source>Master volume</source>
<translation type="unfinished"></translation>
</message>
@ -4429,27 +4481,27 @@ Please check your shortcut settings!</source>
<context>
<name>StableReleaseChannel</name>
<message>
<location filename="../src/releasechannel.cpp" line="86"/>
<location filename="../src/releasechannel.cpp" line="85"/>
<source>Stable Releases</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/releasechannel.cpp" line="104"/>
<location filename="../src/releasechannel.cpp" line="101"/>
<source>No reply received from the release update server.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/releasechannel.cpp" line="111"/>
<location filename="../src/releasechannel.cpp" line="109"/>
<source>Invalid reply received from the release update server.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/releasechannel.cpp" line="169"/>
<location filename="../src/releasechannel.cpp" line="165"/>
<source>No reply received from the tag update server.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/releasechannel.cpp" line="175"/>
<location filename="../src/releasechannel.cpp" line="172"/>
<source>Invalid reply received from the tag update server.</source>
<translation type="unfinished"></translation>
</message>
@ -5788,42 +5840,42 @@ Please refrain from engaging in this activity or further actions may be taken ag
<context>
<name>UserInterfaceSettingsPage</name>
<message>
<location filename="../src/dlg_settings.cpp" line="489"/>
<location filename="../src/dlg_settings.cpp" line="409"/>
<source>General interface settings</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="490"/>
<location filename="../src/dlg_settings.cpp" line="410"/>
<source>Enable notifications in taskbar</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="491"/>
<location filename="../src/dlg_settings.cpp" line="411"/>
<source>Notify in the taskbar for game events while you are spectating</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="492"/>
<location filename="../src/dlg_settings.cpp" line="412"/>
<source>&amp;Double-click cards to play them (instead of single-click)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="493"/>
<location filename="../src/dlg_settings.cpp" line="413"/>
<source>&amp;Play all nonlands onto the stack (not the battlefield) by default</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="494"/>
<location filename="../src/dlg_settings.cpp" line="414"/>
<source>Annotate card text on tokens</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="495"/>
<location filename="../src/dlg_settings.cpp" line="415"/>
<source>Animation settings</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../src/dlg_settings.cpp" line="496"/>
<location filename="../src/dlg_settings.cpp" line="416"/>
<source>&amp;Tap/untap animation</source>
<translation type="unfinished"></translation>
</message>

View file

@ -11,9 +11,12 @@ SET(oracle_SOURCES
src/main.cpp
src/oraclewizard.cpp
src/oracleimporter.cpp
src/qt-json/json.cpp
../cockatrice/src/carddatabase.cpp
../cockatrice/src/pictureloader.cpp
../cockatrice/src/carddbparser/carddatabaseparser.cpp
../cockatrice/src/carddbparser/cockatricexml3.cpp
../cockatrice/src/carddbparser/cockatricexml4.cpp
../cockatrice/src/settingscache.cpp
../cockatrice/src/shortcutssettings.cpp
../cockatrice/src/settings/carddatabasesettings.cpp
@ -24,7 +27,6 @@ SET(oracle_SOURCES
../cockatrice/src/settings/layoutssettings.cpp
../cockatrice/src/settings/downloadsettings.cpp
../cockatrice/src/thememanager.cpp
../cockatrice/src/qt-json/json.cpp
../cockatrice/src/releasechannel.cpp
${VERSION_STRING_CPP}
)

View file

@ -1,5 +1,5 @@
#include "oracleimporter.h"
#include "carddbparser/cockatricexml3.h"
#include "carddbparser/cockatricexml4.h"
#include <QDebug>
#include <QtWidgets>
@ -7,6 +7,14 @@
#include "qt-json/json.h"
SplitCardPart::SplitCardPart(const int _index,
const QString &_text,
const QVariantHash &_properties,
const CardInfoPerSet _setInfo)
: index(_index), text(_text), properties(_properties), setInfo(_setInfo)
{
}
OracleImporter::OracleImporter(const QString &_dataDir, QObject *parent) : CardDatabase(parent), dataDir(_dataDir)
{
}
@ -25,24 +33,23 @@ bool OracleImporter::readSetsFromByteArray(const QByteArray &data)
QListIterator<QVariant> it(setsMap.values());
QVariantMap map;
QString edition;
QString editionLong;
QVariant editionCards;
QString shortName;
QString longName;
QList<QVariant> setCards;
QString setType;
QDate releaseDate;
while (it.hasNext()) {
map = it.next().toMap();
edition = map.value("code").toString().toUpper();
editionLong = map.value("name").toString();
editionCards = map.value("cards");
shortName = map.value("code").toString().toUpper();
longName = map.value("name").toString();
setCards = map.value("cards").toList();
setType = map.value("type").toString();
// capitalize set type
if (setType.length() > 0)
setType[0] = setType[0].toUpper();
releaseDate = map.value("releaseDate").toDate();
newSetList.append(SetToDownload(edition, editionLong, editionCards, setType, releaseDate));
newSetList.append(SetToDownload(shortName, longName, setCards, setType, releaseDate));
}
qSort(newSetList);
@ -53,37 +60,27 @@ bool OracleImporter::readSetsFromByteArray(const QByteArray &data)
return true;
}
CardInfoPtr OracleImporter::addCard(const QString &setName,
QString cardName,
CardInfoPtr OracleImporter::addCard(QString name,
QString text,
bool isToken,
int cardId,
QString &cardUuId,
QString &setNumber,
QString &cardCost,
QString &cmc,
const QString &cardType,
const QString &cardPT,
const QString &cardLoyalty,
const QString &cardText,
const QStringList &colors,
const QList<CardRelation *> &relatedCards,
const QList<CardRelation *> &reverseRelatedCards,
bool upsideDown,
QString &rarity)
QVariantHash properties,
QList<CardRelation *> &relatedCards,
CardInfoPerSet setInfo)
{
QStringList cardTextRows = cardText.split("\n");
// Workaround for card name weirdness
cardName = cardName.replace("Æ", "AE");
cardName = cardName.replace("", "'");
name = name.replace("Æ", "AE");
name = name.replace("", "'");
if (cards.contains(name)) {
CardInfoPtr card = cards.value(name);
card->addToSet(setInfo.getPtr(), setInfo);
return card;
}
CardInfoPtr card;
if (cards.contains(cardName)) {
card = cards.value(cardName);
} else {
// Remove {} around mana costs, except if it's split cost
QStringList symbols = cardCost.split("}");
QString formattedCardCost = QString();
QString manacost = properties.value("manacost").toString();
if (!manacost.isEmpty()) {
QStringList symbols = manacost.split("}");
QString formattedCardCost;
for (QString symbol : symbols) {
if (symbol.contains(QRegExp("[0-9WUBGRP]/[0-9WUBGRP]"))) {
symbol.append("}");
@ -92,9 +89,26 @@ CardInfoPtr OracleImporter::addCard(const QString &setName,
}
formattedCardCost.append(symbol);
}
properties.insert("manacost", formattedCardCost);
}
// fix colors
QString allColors = properties.value("colors").toString();
if (allColors.size() > 1) {
sortAndReduceColors(allColors);
properties.insert("colors", allColors);
}
// DETECT CARD POSITIONING INFO
// cards that enter the field tapped
bool cipt = text.contains("Hideaway") || (text.contains(name + " enters the battlefield tapped") &&
!text.contains(name + " enters the battlefield tapped unless"));
// detect mana generator artifacts
QStringList cardTextRows = text.split("\n");
bool mArtifact = false;
QString cardType = properties.value("type").toString();
if (cardType.endsWith("Artifact")) {
for (int i = 0; i < cardTextRows.size(); ++i) {
cardTextRows[i].remove(QRegularExpression(R"(\".*?\")"));
@ -104,228 +118,222 @@ CardInfoPtr OracleImporter::addCard(const QString &setName,
}
}
// detect cards that enter the field tapped
bool cipt =
cardText.contains("Hideaway") || (cardText.contains(cardName + " enters the battlefield tapped") &&
!cardText.contains(cardName + " enters the battlefield tapped unless"));
// insert the card and its properties
card = CardInfo::newInstance(cardName, isToken, formattedCardCost, cmc, cardType, cardPT, cardText, colors,
relatedCards, reverseRelatedCards, upsideDown, cardLoyalty, cipt);
// table row
int tableRow = 1;
QString mainCardType = card->getMainCardType();
QString mainCardType = properties.value("maintype").toString();
if ((mainCardType == "Land") || mArtifact)
tableRow = 0;
else if ((mainCardType == "Sorcery") || (mainCardType == "Instant"))
tableRow = 3;
else if (mainCardType == "Creature")
tableRow = 2;
card->setTableRow(tableRow);
cards.insert(cardName, card);
// card side
QString side = properties.value("side").toString() == "b" ? "back" : "front";
properties.insert("side", side);
// upsideDown (flip cards)
bool upsideDown = false;
QStringList additionalNames = properties.value("names").toStringList();
QString layout = properties.value("layout").toString();
if (layout == "flip") {
if (properties.value("side").toString() != "front") {
upsideDown = true;
}
// reset the side property, since the card has no back image
properties.insert("side", "front");
}
card->setMuId(setName, cardId);
card->setUuId(setName, cardUuId);
card->setSetNumber(setName, setNumber);
card->setRarity(setName, rarity);
// insert the card and its properties
QList<CardRelation *> reverseRelatedCards;
CardInfoPerSetMap setsInfo;
setsInfo.insert(setInfo.getPtr()->getShortName(), setInfo);
CardInfoPtr newCard = CardInfo::newInstance(name, text, isToken, properties, relatedCards, reverseRelatedCards,
setsInfo, cipt, tableRow, upsideDown);
return card;
cards.insert(name, newCard);
return newCard;
}
int OracleImporter::importTextSpoiler(CardSetPtr set, const QVariant &data)
QString OracleImporter::getStringPropertyFromMap(QVariantMap card, QString propertyName)
{
int cards = 0;
return card.contains(propertyName) ? card.value(propertyName).toString() : QString("");
}
QListIterator<QVariant> it(data.toList());
QVariantMap map;
QString cardName;
QString cardCost;
QString cmc;
QString cardType;
QString cardPT;
QString cardText;
QStringList colors;
int OracleImporter::importCardsFromSet(CardSetPtr currentSet, const QList<QVariant> &cardsList)
{
static const QMap<QString, QString> cardProperties{
// mtgjson name => xml name
{"manaCost", "manacost"}, {"convertedManaCost", "cmc"}, {"type", "type"},
{"loyalty", "loyalty"}, {"layout", "layout"}, {"side", "side"},
};
static const QMap<QString, QString> setInfoProperties{// mtgjson name => xml name
{"multiverseId", "muid"},
{"scryfallId", "uuid"},
{"number", "num"},
{"rarity", "rarity"}};
int numCards = 0;
QMap<QString, SplitCardPart> splitCards;
QString ptSeparator("/");
QVariantMap card;
QString layout, name, text, colors, maintype, power, toughness;
bool isToken;
QStringList additionalNames;
QVariantHash properties;
CardInfoPerSet setInfo;
QList<CardRelation *> relatedCards;
QList<CardRelation *> reverseRelatedCards; // dummy
int cardId;
QString cardUuId;
QString setNumber;
QString rarity;
QString cardLoyalty;
bool upsideDown;
QMap<int, QVariantMap> splitCards;
while (it.hasNext()) {
map = it.next().toMap();
for (const QVariant &cardVar : cardsList) {
card = cardVar.toMap();
/* Currently used layouts are:
* augment, double_faced_token, flip, host, leveler, meld, normal, planar,
* saga, scheme, split, token, transform, vanguard
*/
QString layout = map.value("layout").toString();
layout = getStringPropertyFromMap(card, "layout");
// don't import tokens from the json file
isToken = false;
if (layout == "token")
continue;
// Aftermath card layout seems to have been integrated in "split"
if (layout == "split") {
// Enqueue split card for later handling
cardId = map.contains("multiverseId") ? map.value("multiverseId").toInt() : 0;
if (cardId)
splitCards.insertMulti(cardId, map);
continue;
}
// normal cards handling
cardName = map.contains("name") ? map.value("name").toString() : QString("");
cardCost = map.contains("manaCost") ? map.value("manaCost").toString() : QString("");
cmc = map.contains("convertedManaCost") ? map.value("convertedManaCost").toString() : QString("0");
cardType = map.contains("type") ? map.value("type").toString() : QString("");
cardPT = map.contains("power") || map.contains("toughness")
? map.value("power").toString() + QString('/') + map.value("toughness").toString()
: QString("");
cardText = map.contains("text") ? map.value("text").toString() : QString("");
cardId = map.contains("multiverseId") ? map.value("multiverseId").toInt() : 0;
cardUuId = map.contains("scryfallId") ? map.value("scryfallId").toString() : QString("");
setNumber = map.contains("number") ? map.value("number").toString() : QString("");
rarity = map.contains("rarity") ? map.value("rarity").toString() : QString("");
cardLoyalty = map.contains("loyalty") ? map.value("loyalty").toString() : QString("");
colors = map.contains("colors") ? map.value("colors").toStringList() : QStringList();
relatedCards = QList<CardRelation *>();
if (map.contains("names"))
for (const QString &name : map.value("names").toStringList()) {
if (name != cardName)
relatedCards.append(new CardRelation(name, true));
name = getStringPropertyFromMap(card, "name");
text = getStringPropertyFromMap(card, "text");
// card properties
properties.clear();
QMapIterator<QString, QString> it(cardProperties);
while (it.hasNext()) {
it.next();
QString mtgjsonProperty = it.key();
QString xmlPropertyName = it.value();
QString propertyValue = getStringPropertyFromMap(card, mtgjsonProperty);
if (!propertyValue.isEmpty())
properties.insert(xmlPropertyName, propertyValue);
}
if (0 == QString::compare(map.value("layout").toString(), QString("flip"), Qt::CaseInsensitive)) {
QStringList cardNames = map.contains("names") ? map.value("names").toStringList() : QStringList();
upsideDown = (cardNames.indexOf(cardName) > 0);
// per-set properties
setInfo = CardInfoPerSet(currentSet);
QMapIterator<QString, QString> it2(setInfoProperties);
while (it2.hasNext()) {
it2.next();
QString mtgjsonProperty = it2.key();
QString xmlPropertyName = it2.value();
QString propertyValue = getStringPropertyFromMap(card, mtgjsonProperty);
if (!propertyValue.isEmpty())
setInfo.setProperty(xmlPropertyName, propertyValue);
}
// special handling properties
colors = card.value("colors").toStringList().join("");
if (!colors.isEmpty())
properties.insert("colors", colors);
maintype = card.value("types").toStringList().first();
if (!maintype.isEmpty())
properties.insert("maintype", maintype);
power = getStringPropertyFromMap(card, "power");
toughness = getStringPropertyFromMap(card, "toughness");
if (!(power.isEmpty() && toughness.isEmpty()))
properties.insert("pt", power + ptSeparator + toughness);
additionalNames = card.value("names").toStringList();
// split cards are considered a single card, enqueue for later merging
if (layout == "split") {
// get the position of this card part
int index = additionalNames.indexOf(name);
// construct full card name
name = additionalNames.join(QString(" // "));
SplitCardPart split(index, text, properties, setInfo);
splitCards.insertMulti(name, split);
} else {
upsideDown = false;
}
CardInfoPtr card =
addCard(set->getShortName(), cardName, false, cardId, cardUuId, setNumber, cardCost, cmc, cardType, cardPT,
cardLoyalty, cardText, colors, relatedCards, reverseRelatedCards, upsideDown, rarity);
if (!set->contains(card)) {
card->addToSet(set);
cards++;
// relations
relatedCards.clear();
if (additionalNames.size() > 1) {
for (const QString &additionalName : additionalNames) {
if (additionalName != name)
relatedCards.append(new CardRelation(additionalName, true));
}
}
// split cards handling - get all unique card muids
QList<int> muids = splitCards.uniqueKeys();
for (int muid : muids) {
// get all cards for this specific muid
QList<QVariantMap> maps = splitCards.values(muid);
QStringList names;
// now, reorder the cards using the ordered list of names
QMap<int, QVariantMap> orderedMaps;
for (const QVariantMap &inner_map : maps) {
if (names.isEmpty())
names = inner_map.contains("names") ? inner_map.value("names").toStringList() : QStringList();
QString name = inner_map.value("name").toString();
int index = names.indexOf(name);
orderedMaps.insertMulti(index, inner_map);
}
// clean variables
cardName = "";
cardCost = "";
cmc = "";
cardType = "";
cardPT = "";
cardText = "";
cardUuId = "";
setNumber = "";
rarity = "";
cardLoyalty = "";
colors.clear();
// loop cards and merge their contents
QString prefix = QString(" // ");
QString prefix2 = QString("\n\n---\n\n");
for (const QVariantMap &inner_map : orderedMaps.values()) {
if (inner_map.contains("name")) {
if (!cardName.isEmpty())
cardName += (orderedMaps.count() > 2) ? QString("/") : prefix;
cardName += inner_map.value("name").toString();
}
if (inner_map.contains("manaCost")) {
if (!cardCost.isEmpty())
cardCost += prefix;
cardCost += inner_map.value("manaCost").toString();
}
if (inner_map.contains("convertedManaCost")) {
if (!cmc.isEmpty())
cmc += prefix;
cmc += inner_map.value("convertedManaCost").toString();
}
if (inner_map.contains("type")) {
if (!cardType.isEmpty())
cardType += prefix;
cardType += inner_map.value("type").toString();
}
if (inner_map.contains("power") || inner_map.contains("toughness")) {
if (!cardPT.isEmpty())
cardPT += prefix;
cardPT += inner_map.value("power").toString() + QString('/') + inner_map.value("toughness").toString();
}
if (inner_map.contains("text")) {
if (!cardText.isEmpty())
cardText += prefix2;
cardText += inner_map.value("text").toString();
}
if (inner_map.contains("uuid")) {
if (cardUuId.isEmpty())
cardUuId = inner_map.value("uuid").toString();
}
if (inner_map.contains("number")) {
if (setNumber.isEmpty())
setNumber = inner_map.value("number").toString();
}
if (inner_map.contains("rarity")) {
if (rarity.isEmpty())
rarity = inner_map.value("rarity").toString();
}
colors << inner_map.value("colors").toStringList();
}
colors.removeDuplicates();
if (colors.length() > 1) {
sortColors(colors);
}
// Fortunately, there are no split cards that flip, transform or meld.
relatedCards = QList<CardRelation *>();
reverseRelatedCards = QList<CardRelation *>();
upsideDown = false;
// add the card
CardInfoPtr card =
addCard(set->getShortName(), cardName, false, muid, cardUuId, setNumber, cardCost, cmc, cardType, cardPT,
cardLoyalty, cardText, colors, relatedCards, reverseRelatedCards, upsideDown, rarity);
if (!set->contains(card)) {
card->addToSet(set);
cards++;
CardInfoPtr newCard = addCard(name, text, isToken, properties, relatedCards, setInfo);
numCards++;
}
}
return cards;
// split cards handling
QString splitCardPropSeparator = QString(" // ");
QString splitCardTextSeparator = QString("\n\n---\n\n");
for (const QString &nameSplit : splitCards.uniqueKeys()) {
// get all parts for this specific card
QList<SplitCardPart> splitCardParts = splitCards.values(nameSplit);
// sort them by index (aka position)
qSort(splitCardParts.begin(), splitCardParts.end(),
[](const SplitCardPart &a, const SplitCardPart &b) -> bool { return a.getIndex() < b.getIndex(); });
text = QString("");
isToken = false;
properties.clear();
relatedCards.clear();
int lastIndex = -1;
for (const SplitCardPart &tmp : splitCardParts) {
// some sets have 2 different variations of the same split card,
// eg. Fire // Ice in WC02. Avoid adding duplicates.
if (lastIndex == tmp.getIndex())
continue;
lastIndex = tmp.getIndex();
if (!text.isEmpty())
text.append(splitCardTextSeparator);
text.append(tmp.getText());
if (properties.isEmpty()) {
properties = tmp.getProperties();
setInfo = tmp.getSetInfo();
} else {
const QVariantHash &props = tmp.getProperties();
for (const QString &prop : props.keys()) {
QString originalPropertyValue = properties.value(prop).toString();
QString thisCardPropertyValue = props.value(prop).toString();
if (originalPropertyValue != thisCardPropertyValue) {
if (prop == "colors") {
properties.insert(prop, originalPropertyValue + thisCardPropertyValue);
} else {
properties.insert(prop,
originalPropertyValue + splitCardPropSeparator + thisCardPropertyValue);
}
}
}
}
}
CardInfoPtr newCard = addCard(name, text, isToken, properties, relatedCards, setInfo);
numCards++;
}
return numCards;
}
void OracleImporter::sortColors(QStringList &colors)
void OracleImporter::sortAndReduceColors(QString &colors)
{
const QHash<QString, unsigned int> colorOrder{{"W", 0}, {"U", 1}, {"B", 2}, {"R", 3}, {"G", 4}};
std::sort(colors.begin(), colors.end(), [&colorOrder](const QString a, const QString b) {
// sort
const QHash<QChar, unsigned int> colorOrder{{'W', 0}, {'U', 1}, {'B', 2}, {'R', 3}, {'G', 4}};
std::sort(colors.begin(), colors.end(), [&colorOrder](const QChar a, const QChar b) {
return colorOrder.value(a, INT_MAX) < colorOrder.value(b, INT_MAX);
});
// reduce
QChar lastChar = '\0';
for (int i = 0; i < colors.size(); ++i) {
if (colors.at(i) == lastChar)
colors.remove(i, 1);
else
lastChar = colors.at(i);
}
}
int OracleImporter::startImport()
@ -333,25 +341,21 @@ int OracleImporter::startImport()
clear();
int setCards = 0, setIndex = 0;
QListIterator<SetToDownload> it(allSets);
const SetToDownload *curSet;
// add an empty set for tokens
CardSetPtr tokenSet = CardSet::newInstance(TOKENS_SETNAME, tr("Dummy set containing tokens"), "Tokens");
sets.insert(TOKENS_SETNAME, tokenSet);
while (it.hasNext()) {
curSet = &it.next();
CardSetPtr set = CardSet::newInstance(curSet->getShortName(), curSet->getLongName(), curSet->getSetType(),
curSet->getReleaseDate());
if (!sets.contains(set->getShortName()))
sets.insert(set->getShortName(), set);
for (const SetToDownload &curSetToParse : allSets) {
CardSetPtr newSet = CardSet::newInstance(curSetToParse.getShortName(), curSetToParse.getLongName(),
curSetToParse.getSetType(), curSetToParse.getReleaseDate());
if (!sets.contains(newSet->getShortName()))
sets.insert(newSet->getShortName(), newSet);
int setCardsHere = importTextSpoiler(set, curSet->getCards());
int numCardsInSet = importCardsFromSet(newSet, curSetToParse.getCards());
++setIndex;
emit setIndexChanged(setCardsHere, setIndex, curSet->getLongName());
emit setIndexChanged(numCardsInSet, setIndex, curSetToParse.getLongName());
}
emit setIndexChanged(setCards, setIndex, QString());
@ -362,6 +366,6 @@ int OracleImporter::startImport()
bool OracleImporter::saveToFile(const QString &fileName)
{
CockatriceXml3Parser parser;
CockatriceXml4Parser parser;
return parser.saveToFile(sets, cards, fileName);
}

View file

@ -3,14 +3,14 @@
#include <QMap>
#include <QVariant>
#include <carddatabase.h>
#include <utility>
class SetToDownload
{
private:
QString shortName, longName;
QVariant cards;
QList<QVariant> cards;
QDate releaseDate;
QString setType;
@ -23,7 +23,7 @@ public:
{
return longName;
}
const QVariant &getCards() const
const QList<QVariant> &getCards() const
{
return cards;
}
@ -35,12 +35,13 @@ public:
{
return releaseDate;
}
SetToDownload(const QString &_shortName,
const QString &_longName,
const QVariant &_cards,
const QString &_setType = QString(),
SetToDownload(QString _shortName,
QString _longName,
QList<QVariant> _cards,
QString _setType = QString(),
const QDate &_releaseDate = QDate())
: shortName(_shortName), longName(_longName), cards(_cards), releaseDate(_releaseDate), setType(_setType)
: shortName(std::move(_shortName)), longName(std::move(_longName)), cards(std::move(_cards)),
releaseDate(_releaseDate), setType(std::move(_setType))
{
}
bool operator<(const SetToDownload &set) const
@ -49,6 +50,34 @@ public:
}
};
class SplitCardPart
{
public:
SplitCardPart(int _index, const QString &_text, const QVariantHash &_properties, CardInfoPerSet setInfo);
inline const int &getIndex() const
{
return index;
}
inline const QString &getText() const
{
return text;
}
inline const QVariantHash &getProperties() const
{
return properties;
}
inline const CardInfoPerSet &getSetInfo() const
{
return setInfo;
}
private:
int index;
QString text;
QVariantHash properties;
CardInfoPerSet setInfo;
};
class OracleImporter : public CardDatabase
{
Q_OBJECT
@ -57,33 +86,22 @@ private:
QVariantMap setsMap;
QString dataDir;
CardInfoPtr addCard(const QString &setName,
QString cardName,
CardInfoPtr addCard(QString name,
QString text,
bool isToken,
int cardId,
QString &cardUuId,
QString &setNumber,
QString &cardCost,
QString &cmc,
const QString &cardType,
const QString &cardPT,
const QString &cardLoyalty,
const QString &cardText,
const QStringList &colors,
const QList<CardRelation *> &relatedCards,
const QList<CardRelation *> &reverseRelatedCards,
bool upsideDown,
QString &rarity);
QVariantHash properties,
QList<CardRelation *> &relatedCards,
CardInfoPerSet setInfo);
signals:
void setIndexChanged(int cardsImported, int setIndex, const QString &setName);
void dataReadProgress(int bytesRead, int totalBytes);
public:
OracleImporter(const QString &_dataDir, QObject *parent = 0);
explicit OracleImporter(const QString &_dataDir, QObject *parent = nullptr);
bool readSetsFromByteArray(const QByteArray &data);
int startImport();
bool saveToFile(const QString &fileName);
int importTextSpoiler(CardSetPtr set, const QVariant &data);
int importCardsFromSet(CardSetPtr currentSet, const QList<QVariant> &cards);
QList<SetToDownload> &getSets()
{
return allSets;
@ -94,7 +112,8 @@ public:
}
protected:
void sortColors(QStringList &colors);
inline QString getStringPropertyFromMap(QVariantMap card, QString propertyName);
void sortAndReduceColors(QString &colors);
};
#endif

View file

@ -253,7 +253,7 @@
<context>
<name>OracleImporter</name>
<message>
<location filename="../src/oracleimporter.cpp" line="339"/>
<location filename="../src/oracleimporter.cpp" line="359"/>
<source>Dummy set containing tokens</source>
<translation type="unfinished"></translation>
</message>

View file

@ -2,8 +2,9 @@ ADD_DEFINITIONS("-DCARDDB_DATADIR=\"${CMAKE_CURRENT_SOURCE_DIR}/data/\"")
add_executable(carddatabase_test
carddatabase_test.cpp
../../cockatrice/src/carddatabase.cpp
../../cockatrice/src/carddbparser/carddatabaseparser.cpp
../../cockatrice/src/carddbparser/cockatricexml3.cpp
../../cockatrice/src/carddbparser/cockatricexml4.cpp
)
if(NOT GTEST_FOUND)
add_dependencies(carddatabase_test gtest)

View file

@ -64,7 +64,6 @@ TEST(CardDatabaseTest, LoadXml)
// ensure the card database is 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->getAllColors().size()) << "Colors not empty at start";
ASSERT_EQ(0, db->getAllMainCardTypes().size()) << "Types not empty at start";
ASSERT_EQ(NotLoaded, db->getLoadStatus()) << "Incorrect status at start";
@ -72,7 +71,6 @@ TEST(CardDatabaseTest, LoadXml)
db->loadCardDatabases();
ASSERT_EQ(6, db->getCardList().size()) << "Wrong card count after load";
ASSERT_EQ(3, db->getSetList().size()) << "Wrong sets count after load";
ASSERT_EQ(4, db->getAllColors().size()) << "Wrong colors count after load";
ASSERT_EQ(2, db->getAllMainCardTypes().size()) << "Wrong types count after load";
ASSERT_EQ(Ok, db->getLoadStatus()) << "Wrong status after load";
@ -80,7 +78,6 @@ TEST(CardDatabaseTest, LoadXml)
db->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->getAllColors().size()) << "Colors not empty after clear";
ASSERT_EQ(0, db->getAllMainCardTypes().size()) << "Types not empty after clear";
ASSERT_EQ(NotLoaded, db->getLoadStatus()) << "Incorrect status after clear";
}