1 #include "carddatabase.h"
2
3 #include "carddbparser/cockatricexml3.h"
4 #include "carddbparser/cockatricexml4.h"
5 #include "game_specific_terms.h"
6 #include "pictureloader.h"
7 #include "settingscache.h"
8 #include "spoilerbackgroundupdater.h"
9
10 #include <QCryptographicHash>
11 #include <QDebug>
12 #include <QDir>
13 #include <QDirIterator>
14 #include <QFile>
15 #include <QMessageBox>
16 #include <QRegularExpression>
17 #include <algorithm>
18 #include <utility>
19
20 const char *CardDatabase::TOKENS_SETNAME = "TK";
21
CardSet(const QString & _shortName,const QString & _longName,const QString & _setType,const QDate & _releaseDate)22 CardSet::CardSet(const QString &_shortName,
23 const QString &_longName,
24 const QString &_setType,
25 const QDate &_releaseDate)
26 : shortName(_shortName), longName(_longName), releaseDate(_releaseDate), setType(_setType)
27 {
28 loadSetOptions();
29 }
30
newInstance(const QString & _shortName,const QString & _longName,const QString & _setType,const QDate & _releaseDate)31 CardSetPtr CardSet::newInstance(const QString &_shortName,
32 const QString &_longName,
33 const QString &_setType,
34 const QDate &_releaseDate)
35 {
36 CardSetPtr ptr(new CardSet(_shortName, _longName, _setType, _releaseDate));
37 // ptr->setSmartPointer(ptr);
38 return ptr;
39 }
40
getCorrectedShortName() const41 QString CardSet::getCorrectedShortName() const
42 {
43 // For Windows machines.
44 QSet<QString> invalidFileNames;
45 invalidFileNames << "CON"
46 << "PRN"
47 << "AUX"
48 << "NUL"
49 << "COM1"
50 << "COM2"
51 << "COM3"
52 << "COM4"
53 << "COM5"
54 << "COM6"
55 << "COM7"
56 << "COM8"
57 << "COM9"
58 << "LPT1"
59 << "LPT2"
60 << "LPT3"
61 << "LPT4"
62 << "LPT5"
63 << "LPT6"
64 << "LPT7"
65 << "LPT8"
66 << "LPT9";
67
68 return invalidFileNames.contains(shortName) ? shortName + "_" : shortName;
69 }
70
loadSetOptions()71 void CardSet::loadSetOptions()
72 {
73 sortKey = SettingsCache::instance().cardDatabase().getSortKey(shortName);
74 enabled = SettingsCache::instance().cardDatabase().isEnabled(shortName);
75 isknown = SettingsCache::instance().cardDatabase().isKnown(shortName);
76 }
77
setSortKey(unsigned int _sortKey)78 void CardSet::setSortKey(unsigned int _sortKey)
79 {
80 sortKey = _sortKey;
81 SettingsCache::instance().cardDatabase().setSortKey(shortName, _sortKey);
82 }
83
setEnabled(bool _enabled)84 void CardSet::setEnabled(bool _enabled)
85 {
86 enabled = _enabled;
87 SettingsCache::instance().cardDatabase().setEnabled(shortName, _enabled);
88 }
89
setIsKnown(bool _isknown)90 void CardSet::setIsKnown(bool _isknown)
91 {
92 isknown = _isknown;
93 SettingsCache::instance().cardDatabase().setIsKnown(shortName, _isknown);
94 }
95
96 class SetList::KeyCompareFunctor
97 {
98 public:
operator ()(const CardSetPtr & a,const CardSetPtr & b) const99 inline bool operator()(const CardSetPtr &a, const CardSetPtr &b) const
100 {
101 if (a.isNull() || b.isNull()) {
102 qDebug() << "SetList::KeyCompareFunctor a or b is null";
103 return false;
104 }
105
106 return a->getSortKey() < b->getSortKey();
107 }
108 };
109
sortByKey()110 void SetList::sortByKey()
111 {
112 std::sort(begin(), end(), KeyCompareFunctor());
113 }
114
getEnabledSetsNum()115 int SetList::getEnabledSetsNum()
116 {
117 int num = 0;
118 for (int i = 0; i < size(); ++i) {
119 CardSetPtr set = at(i);
120 if (set && set->getEnabled()) {
121 ++num;
122 }
123 }
124 return num;
125 }
126
getUnknownSetsNum()127 int SetList::getUnknownSetsNum()
128 {
129 int num = 0;
130 for (int i = 0; i < size(); ++i) {
131 CardSetPtr set = at(i);
132 if (set && !set->getIsKnown() && !set->getIsKnownIgnored()) {
133 ++num;
134 }
135 }
136 return num;
137 }
138
getUnknownSetsNames()139 QStringList SetList::getUnknownSetsNames()
140 {
141 QStringList sets = QStringList();
142 for (int i = 0; i < size(); ++i) {
143 CardSetPtr set = at(i);
144 if (set && !set->getIsKnown() && !set->getIsKnownIgnored()) {
145 sets << set->getShortName();
146 }
147 }
148 return sets;
149 }
150
enableAllUnknown()151 void SetList::enableAllUnknown()
152 {
153 for (int i = 0; i < size(); ++i) {
154 CardSetPtr set = at(i);
155 if (set && !set->getIsKnown() && !set->getIsKnownIgnored()) {
156 set->setIsKnown(true);
157 set->setEnabled(true);
158 } else if (set && set->getIsKnownIgnored() && !set->getEnabled()) {
159 set->setEnabled(true);
160 }
161 }
162 }
163
enableAll()164 void SetList::enableAll()
165 {
166 for (int i = 0; i < size(); ++i) {
167 CardSetPtr set = at(i);
168
169 if (set == nullptr) {
170 qDebug() << "enabledAll has null";
171 continue;
172 }
173
174 if (!set->getIsKnownIgnored()) {
175 set->setIsKnown(true);
176 }
177
178 set->setEnabled(true);
179 }
180 }
181
markAllAsKnown()182 void SetList::markAllAsKnown()
183 {
184 for (int i = 0; i < size(); ++i) {
185 CardSetPtr set = at(i);
186 if (set && !set->getIsKnown() && !set->getIsKnownIgnored()) {
187 set->setIsKnown(true);
188 set->setEnabled(false);
189 } else if (set && set->getIsKnownIgnored() && !set->getEnabled()) {
190 set->setEnabled(true);
191 }
192 }
193 }
194
guessSortKeys()195 void SetList::guessSortKeys()
196 {
197 // sort by release date DESC; invalid dates to the bottom.
198 QDate distantFuture(2050, 1, 1);
199 int aHundredYears = 36500;
200 for (int i = 0; i < size(); ++i) {
201 CardSetPtr set = at(i);
202 if (set.isNull()) {
203 qDebug() << "guessSortKeys set is null";
204 continue;
205 }
206
207 QDate date = set->getReleaseDate();
208 if (date.isNull()) {
209 set->setSortKey(static_cast<unsigned int>(aHundredYears));
210 } else {
211 set->setSortKey(static_cast<unsigned int>(date.daysTo(distantFuture)));
212 }
213 }
214 }
215
CardInfoPerSet(const CardSetPtr & _set)216 CardInfoPerSet::CardInfoPerSet(const CardSetPtr &_set) : set(_set)
217 {
218 }
219
CardInfo(const QString & _name,const QString & _text,bool _isToken,QVariantHash _properties,const QList<CardRelation * > & _relatedCards,const QList<CardRelation * > & _reverseRelatedCards,CardInfoPerSetMap _sets,bool _cipt,int _tableRow,bool _upsideDownArt)220 CardInfo::CardInfo(const QString &_name,
221 const QString &_text,
222 bool _isToken,
223 QVariantHash _properties,
224 const QList<CardRelation *> &_relatedCards,
225 const QList<CardRelation *> &_reverseRelatedCards,
226 CardInfoPerSetMap _sets,
227 bool _cipt,
228 int _tableRow,
229 bool _upsideDownArt)
230 : name(_name), text(_text), isToken(_isToken), properties(std::move(_properties)), relatedCards(_relatedCards),
231 reverseRelatedCards(_reverseRelatedCards), sets(std::move(_sets)), cipt(_cipt), tableRow(_tableRow),
232 upsideDownArt(_upsideDownArt)
233 {
234 pixmapCacheKey = QLatin1String("card_") + name;
235 simpleName = CardInfo::simplifyName(name);
236
237 refreshCachedSetNames();
238 }
239
~CardInfo()240 CardInfo::~CardInfo()
241 {
242 PictureLoader::clearPixmapCache(smartThis);
243 }
244
newInstance(const QString & _name,const QString & _text,bool _isToken,QVariantHash _properties,const QList<CardRelation * > & _relatedCards,const QList<CardRelation * > & _reverseRelatedCards,CardInfoPerSetMap _sets,bool _cipt,int _tableRow,bool _upsideDownArt)245 CardInfoPtr CardInfo::newInstance(const QString &_name,
246 const QString &_text,
247 bool _isToken,
248 QVariantHash _properties,
249 const QList<CardRelation *> &_relatedCards,
250 const QList<CardRelation *> &_reverseRelatedCards,
251 CardInfoPerSetMap _sets,
252 bool _cipt,
253 int _tableRow,
254 bool _upsideDownArt)
255 {
256 CardInfoPtr ptr(new CardInfo(_name, _text, _isToken, std::move(_properties), _relatedCards, _reverseRelatedCards,
257 _sets, _cipt, _tableRow, _upsideDownArt));
258 ptr->setSmartPointer(ptr);
259
260 for (const CardInfoPerSet &set : _sets) {
261 set.getPtr()->append(ptr);
262 }
263
264 return ptr;
265 }
266
getCorrectedName() const267 QString CardInfo::getCorrectedName() const
268 {
269 QString result = name;
270 // Fire // Ice, Circle of Protection: Red, "Ach! Hans, Run!", Who/What/When/Where/Why, Question Elemental?
271 return result.remove(" // ").remove(':').remove('"').remove('?').replace('/', ' ');
272 }
273
addToSet(const CardSetPtr & _set,const CardInfoPerSet _info)274 void CardInfo::addToSet(const CardSetPtr &_set, const CardInfoPerSet _info)
275 {
276 _set->append(smartThis);
277 sets.insert(_set->getShortName(), _info);
278
279 refreshCachedSetNames();
280 }
281
refreshCachedSetNames()282 void CardInfo::refreshCachedSetNames()
283 {
284 QStringList setList;
285 // update the cached list of set names
286 for (const auto &set : sets) {
287 if (set.getPtr()->getEnabled()) {
288 setList << set.getPtr()->getShortName();
289 }
290 }
291 setsNames = setList.join(", ");
292 }
293
simplifyName(const QString & name)294 QString CardInfo::simplifyName(const QString &name)
295 {
296 static const QRegularExpression spaceOrSplit("(\\s+|\\/\\/.*)");
297 static const QRegularExpression nonAlnum("[^a-z0-9]");
298
299 QString simpleName = name.toLower();
300
301 // remove spaces and right halves of split cards
302 simpleName.remove(spaceOrSplit);
303
304 // So Aetherling would work, but not Ætherling since 'Æ' would get replaced
305 // with nothing.
306 simpleName.replace("æ", "ae");
307
308 // Replace Jötun Grunt with Jotun Grunt.
309 simpleName = simpleName.normalized(QString::NormalizationForm_KD);
310
311 // remove all non alphanumeric characters from the name
312 simpleName.remove(nonAlnum);
313 return simpleName;
314 }
315
getColorChar() const316 const QChar CardInfo::getColorChar() const
317 {
318 QString colors = getColors();
319 switch (colors.size()) {
320 case 0:
321 return QChar();
322 case 1:
323 return colors.at(0);
324 default:
325 return QChar('m');
326 }
327 }
328
CardDatabase(QObject * parent)329 CardDatabase::CardDatabase(QObject *parent) : QObject(parent), loadStatus(NotLoaded)
330 {
331 qRegisterMetaType<CardInfoPtr>("CardInfoPtr");
332 qRegisterMetaType<CardInfoPtr>("CardSetPtr");
333
334 // add new parsers here
335 availableParsers << new CockatriceXml4Parser;
336 availableParsers << new CockatriceXml3Parser;
337
338 for (auto &parser : availableParsers) {
339 connect(parser, SIGNAL(addCard(CardInfoPtr)), this, SLOT(addCard(CardInfoPtr)), Qt::DirectConnection);
340 connect(parser, SIGNAL(addSet(CardSetPtr)), this, SLOT(addSet(CardSetPtr)), Qt::DirectConnection);
341 }
342
343 connect(&SettingsCache::instance(), SIGNAL(cardDatabasePathChanged()), this, SLOT(loadCardDatabases()));
344 }
345
~CardDatabase()346 CardDatabase::~CardDatabase()
347 {
348 clear();
349 qDeleteAll(availableParsers);
350 }
351
clear()352 void CardDatabase::clear()
353 {
354 clearDatabaseMutex->lock();
355
356 QHashIterator<QString, CardInfoPtr> i(cards);
357 while (i.hasNext()) {
358 i.next();
359 if (i.value()) {
360 removeCard(i.value());
361 }
362 }
363
364 cards.clear();
365 simpleNameCards.clear();
366
367 sets.clear();
368 ICardDatabaseParser::clearSetlist();
369
370 loadStatus = NotLoaded;
371
372 clearDatabaseMutex->unlock();
373 }
374
addCard(CardInfoPtr card)375 void CardDatabase::addCard(CardInfoPtr card)
376 {
377 if (card == nullptr) {
378 qDebug() << "addCard(nullptr)";
379 return;
380 }
381
382 // if card already exists just add the new set property
383 if (cards.contains(card->getName())) {
384 CardInfoPtr sameCard = cards[card->getName()];
385 for (const CardInfoPerSet &set : card->getSets()) {
386 sameCard->addToSet(set.getPtr(), set);
387 }
388 return;
389 }
390
391 addCardMutex->lock();
392 cards.insert(card->getName(), card);
393 simpleNameCards.insert(card->getSimpleName(), card);
394 addCardMutex->unlock();
395 emit cardAdded(card);
396 }
397
removeCard(CardInfoPtr card)398 void CardDatabase::removeCard(CardInfoPtr card)
399 {
400 if (card.isNull()) {
401 qDebug() << "removeCard(nullptr)";
402 return;
403 }
404
405 for (auto *cardRelation : card->getRelatedCards())
406 cardRelation->deleteLater();
407
408 for (auto *cardRelation : card->getReverseRelatedCards())
409 cardRelation->deleteLater();
410
411 for (auto *cardRelation : card->getReverseRelatedCards2Me())
412 cardRelation->deleteLater();
413
414 removeCardMutex->lock();
415 cards.remove(card->getName());
416 simpleNameCards.remove(card->getSimpleName());
417 removeCardMutex->unlock();
418 emit cardRemoved(card);
419 }
420
getCard(const QString & cardName) const421 CardInfoPtr CardDatabase::getCard(const QString &cardName) const
422 {
423 return getCardFromMap(cards, cardName);
424 }
425
getCards(const QStringList & cardNames) const426 QList<CardInfoPtr> CardDatabase::getCards(const QStringList &cardNames) const
427 {
428 QList<CardInfoPtr> cardInfos;
429 foreach (QString cardName, cardNames) {
430 CardInfoPtr ptr = getCardFromMap(cards, cardName);
431 if (ptr)
432 cardInfos.append(ptr);
433 }
434
435 return cardInfos;
436 }
437
getCardBySimpleName(const QString & cardName) const438 CardInfoPtr CardDatabase::getCardBySimpleName(const QString &cardName) const
439 {
440 return getCardFromMap(simpleNameCards, CardInfo::simplifyName(cardName));
441 }
442
guessCard(const QString & cardName) const443 CardInfoPtr CardDatabase::guessCard(const QString &cardName) const
444 {
445 CardInfoPtr temp = getCard(cardName);
446 if (temp == nullptr) { // get card by simple name instead
447 temp = getCardBySimpleName(cardName);
448 if (temp == nullptr) { // still could not find the card, so simplify the cardName too
449 QString simpleCardName = CardInfo::simplifyName(cardName);
450 temp = getCardBySimpleName(simpleCardName);
451 }
452 }
453 return temp; // returns nullptr if not found
454 }
455
getSet(const QString & setName)456 CardSetPtr CardDatabase::getSet(const QString &setName)
457 {
458 if (sets.contains(setName)) {
459 return sets.value(setName);
460 } else {
461 CardSetPtr newSet = CardSet::newInstance(setName);
462 sets.insert(setName, newSet);
463 return newSet;
464 }
465 }
466
addSet(CardSetPtr set)467 void CardDatabase::addSet(CardSetPtr set)
468 {
469 sets.insert(set->getShortName(), set);
470 }
471
getSetList() const472 SetList CardDatabase::getSetList() const
473 {
474 SetList result;
475 QHashIterator<QString, CardSetPtr> i(sets);
476 while (i.hasNext()) {
477 i.next();
478 result << i.value();
479 }
480 return result;
481 }
482
getCardFromMap(const CardNameMap & cardMap,const QString & cardName) const483 CardInfoPtr CardDatabase::getCardFromMap(const CardNameMap &cardMap, const QString &cardName) const
484 {
485 if (cardMap.contains(cardName))
486 return cardMap.value(cardName);
487
488 return {};
489 }
490
loadFromFile(const QString & fileName)491 LoadStatus CardDatabase::loadFromFile(const QString &fileName)
492 {
493 QFile file(fileName);
494 file.open(QIODevice::ReadOnly);
495 if (!file.isOpen()) {
496 return FileError;
497 }
498
499 for (auto parser : availableParsers) {
500 file.reset();
501 if (parser->getCanParseFile(fileName, file)) {
502 file.reset();
503 parser->parseFile(file);
504 return Ok;
505 }
506 }
507
508 return Invalid;
509 }
510
loadCardDatabase(const QString & path)511 LoadStatus CardDatabase::loadCardDatabase(const QString &path)
512 {
513 LoadStatus tempLoadStatus = NotLoaded;
514 if (!path.isEmpty()) {
515 loadFromFileMutex->lock();
516 tempLoadStatus = loadFromFile(path);
517 loadFromFileMutex->unlock();
518 }
519
520 qDebug() << "[CardDatabase] loadCardDatabase(): Path =" << path << "Status =" << tempLoadStatus
521 << "Cards =" << cards.size() << "Sets=" << sets.size();
522
523 return tempLoadStatus;
524 }
525
loadCardDatabases()526 LoadStatus CardDatabase::loadCardDatabases()
527 {
528 reloadDatabaseMutex->lock();
529
530 qDebug() << "CardDatabase::loadCardDatabases start";
531
532 clear(); // remove old db
533
534 loadStatus = loadCardDatabase(SettingsCache::instance().getCardDatabasePath()); // load main card database
535 loadCardDatabase(SettingsCache::instance().getTokenDatabasePath()); // load tokens database
536 loadCardDatabase(SettingsCache::instance().getSpoilerCardDatabasePath()); // load spoilers database
537
538 // find all custom card databases, recursively & following symlinks
539 // then load them alphabetically
540 QDirIterator customDatabaseIterator(SettingsCache::instance().getCustomCardDatabasePath(), QStringList() << "*.xml",
541 QDir::Files, QDirIterator::Subdirectories | QDirIterator::FollowSymlinks);
542 QStringList databasePaths;
543 while (customDatabaseIterator.hasNext()) {
544 customDatabaseIterator.next();
545 databasePaths.push_back(customDatabaseIterator.filePath());
546 }
547 databasePaths.sort();
548
549 for (auto i = 0; i < databasePaths.size(); ++i) {
550 const auto &databasePath = databasePaths.at(i);
551 qDebug() << "Loading Custom Set" << i << "(" << databasePath << ")";
552 loadCardDatabase(databasePath);
553 }
554
555 // AFTER all the cards have been loaded
556
557 // resolve the reverse-related tags
558 refreshCachedReverseRelatedCards();
559
560 if (loadStatus == Ok) {
561 checkUnknownSets(); // update deck editors, etc
562 qDebug() << "CardDatabase::loadCardDatabases success";
563 } else {
564 qDebug() << "CardDatabase::loadCardDatabases failed";
565 emit cardDatabaseLoadingFailed(); // bring up the settings dialog
566 }
567
568 reloadDatabaseMutex->unlock();
569 return loadStatus;
570 }
571
refreshCachedReverseRelatedCards()572 void CardDatabase::refreshCachedReverseRelatedCards()
573 {
574 for (const CardInfoPtr &card : cards)
575 card->resetReverseRelatedCards2Me();
576
577 for (const CardInfoPtr &card : cards) {
578 if (card->getReverseRelatedCards().isEmpty()) {
579 continue;
580 }
581
582 foreach (CardRelation *cardRelation, card->getReverseRelatedCards()) {
583 const QString &targetCard = cardRelation->getName();
584 if (!cards.contains(targetCard)) {
585 continue;
586 }
587
588 auto *newCardRelation = new CardRelation(card->getName(), cardRelation->getDoesAttach(),
589 cardRelation->getIsCreateAllExclusion(),
590 cardRelation->getIsVariable(), cardRelation->getDefaultCount());
591 cards.value(targetCard)->addReverseRelatedCards2Me(newCardRelation);
592 }
593 }
594 }
595
getAllMainCardTypes() const596 QStringList CardDatabase::getAllMainCardTypes() const
597 {
598 QSet<QString> types;
599 QHashIterator<QString, CardInfoPtr> cardIterator(cards);
600 while (cardIterator.hasNext()) {
601 types.insert(cardIterator.next().value()->getMainCardType());
602 }
603 return types.values();
604 }
605
checkUnknownSets()606 void CardDatabase::checkUnknownSets()
607 {
608 SetList sets = getSetList();
609
610 if (sets.getEnabledSetsNum()) {
611 // if some sets are first found on this run, ask the user
612 int numUnknownSets = sets.getUnknownSetsNum();
613 QStringList unknownSetNames = sets.getUnknownSetsNames();
614 if (numUnknownSets > 0) {
615 emit cardDatabaseNewSetsFound(numUnknownSets, unknownSetNames);
616 } else {
617 sets.markAllAsKnown();
618 }
619 } else {
620 // No set enabled. Probably this is the first time running trice
621 sets.guessSortKeys();
622 sets.sortByKey();
623 sets.enableAll();
624 notifyEnabledSetsChanged();
625
626 emit cardDatabaseAllNewSetsEnabled();
627 }
628 }
629
enableAllUnknownSets()630 void CardDatabase::enableAllUnknownSets()
631 {
632 SetList sets = getSetList();
633 sets.enableAllUnknown();
634 }
635
markAllSetsAsKnown()636 void CardDatabase::markAllSetsAsKnown()
637 {
638 SetList sets = getSetList();
639 sets.markAllAsKnown();
640 }
641
notifyEnabledSetsChanged()642 void CardDatabase::notifyEnabledSetsChanged()
643 {
644 // refresh the list of cached set names
645 for (const CardInfoPtr &card : cards)
646 card->refreshCachedSetNames();
647
648 // inform the carddatabasemodels that they need to re-check their list of cards
649 emit cardDatabaseEnabledSetsChanged();
650 }
651
saveCustomTokensToFile()652 bool CardDatabase::saveCustomTokensToFile()
653 {
654 QString fileName =
655 SettingsCache::instance().getCustomCardDatabasePath() + "/" + CardDatabase::TOKENS_SETNAME + ".xml";
656
657 SetNameMap tmpSets;
658 CardSetPtr customTokensSet = getSet(CardDatabase::TOKENS_SETNAME);
659 tmpSets.insert(CardDatabase::TOKENS_SETNAME, customTokensSet);
660
661 CardNameMap tmpCards;
662 for (const CardInfoPtr &card : cards) {
663 if (card->getSets().contains(CardDatabase::TOKENS_SETNAME)) {
664 tmpCards.insert(card->getName(), card);
665 }
666 }
667
668 availableParsers.first()->saveToFile(tmpSets, tmpCards, fileName);
669 return true;
670 }
671
CardRelation(const QString & _name,bool _doesAttach,bool _isCreateAllExclusion,bool _isVariableCount,int _defaultCount)672 CardRelation::CardRelation(const QString &_name,
673 bool _doesAttach,
674 bool _isCreateAllExclusion,
675 bool _isVariableCount,
676 int _defaultCount)
677 : name(_name), doesAttach(_doesAttach), isCreateAllExclusion(_isCreateAllExclusion),
678 isVariableCount(_isVariableCount), defaultCount(_defaultCount)
679 {
680 }
681
resetReverseRelatedCards2Me()682 void CardInfo::resetReverseRelatedCards2Me()
683 {
684 foreach (CardRelation *cardRelation, this->getReverseRelatedCards2Me()) {
685 cardRelation->deleteLater();
686 }
687 reverseRelatedCardsToMe = QList<CardRelation *>();
688 }
689
690 // Back-compatibility methods. Remove ASAP
getCardType() const691 const QString CardInfo::getCardType() const
692 {
693 return getProperty(Mtg::CardType);
694 }
setCardType(const QString & value)695 void CardInfo::setCardType(const QString &value)
696 {
697 setProperty(Mtg::CardType, value);
698 }
getCmc() const699 const QString CardInfo::getCmc() const
700 {
701 return getProperty(Mtg::ConvertedManaCost);
702 }
getColors() const703 const QString CardInfo::getColors() const
704 {
705 return getProperty(Mtg::Colors);
706 }
setColors(const QString & value)707 void CardInfo::setColors(const QString &value)
708 {
709 setProperty(Mtg::Colors, value);
710 }
getLoyalty() const711 const QString CardInfo::getLoyalty() const
712 {
713 return getProperty(Mtg::Loyalty);
714 }
getMainCardType() const715 const QString CardInfo::getMainCardType() const
716 {
717 return getProperty(Mtg::MainCardType);
718 }
getManaCost() const719 const QString CardInfo::getManaCost() const
720 {
721 return getProperty(Mtg::ManaCost);
722 }
getPowTough() const723 const QString CardInfo::getPowTough() const
724 {
725 return getProperty(Mtg::PowTough);
726 }
setPowTough(const QString & value)727 void CardInfo::setPowTough(const QString &value)
728 {
729 setProperty(Mtg::PowTough, value);
730 }
731