Merge pull request #156 from arxanas/master

Fix #45: don't send tokens to deckstats.
This commit is contained in:
Gavin Bisesi 2014-07-23 08:41:15 -04:00
commit a50e7ba936
8 changed files with 108 additions and 56 deletions

View file

@ -684,42 +684,13 @@ CardInfo *CardDatabase::getCardFromMap(CardNameMap &cardMap, const QString &card
return 0; return 0;
} }
LoadStatus CardDatabase::loadFromFile(const QString &fileName, bool tokens) LoadStatus CardDatabase::loadFromFile(const QString &fileName)
{ {
QFile file(fileName); QFile file(fileName);
file.open(QIODevice::ReadOnly); file.open(QIODevice::ReadOnly);
if (!file.isOpen()) if (!file.isOpen())
return FileError; return FileError;
if (tokens) {
QMutableHashIterator<QString, CardInfo *> i(cards);
while (i.hasNext()) {
i.next();
if (i.value()->getIsToken()) {
removeCard(i.value());
delete i.value();
}
}
} else {
QHashIterator<QString, CardSet *> setIt(sets);
while (setIt.hasNext()) {
setIt.next();
delete setIt.value();
}
sets.clear();
QMutableHashIterator<QString, CardInfo *> i(cards);
while (i.hasNext()) {
i.next();
if (!i.value()->getIsToken()) {
removeCard(i.value());
delete i.value();
}
}
cards.clear();
simpleNameCards.clear();
}
QXmlStreamReader xml(&file); QXmlStreamReader xml(&file);
while (!xml.atEnd()) { while (!xml.atEnd()) {
if (xml.readNext() == QXmlStreamReader::StartElement) { if (xml.readNext() == QXmlStreamReader::StartElement) {
@ -771,8 +742,7 @@ bool CardDatabase::saveToFile(const QString &fileName, bool tokens)
QHashIterator<QString, CardInfo *> cardIterator(cards); QHashIterator<QString, CardInfo *> cardIterator(cards);
while (cardIterator.hasNext()) { while (cardIterator.hasNext()) {
CardInfo *card = cardIterator.next().value(); CardInfo *card = cardIterator.next().value();
if (card->getIsToken() == tokens) xml << card;
xml << card;
} }
xml.writeEndElement(); // cards xml.writeEndElement(); // cards
@ -806,7 +776,7 @@ LoadStatus CardDatabase::loadCardDatabase(const QString &path, bool tokens)
{ {
LoadStatus tempLoadStatus = NotLoaded; LoadStatus tempLoadStatus = NotLoaded;
if (!path.isEmpty()) if (!path.isEmpty())
tempLoadStatus = loadFromFile(path, tokens); tempLoadStatus = loadFromFile(path);
if (tempLoadStatus == Ok) { if (tempLoadStatus == Ok) {
SetList allSets; SetList allSets;

View file

@ -224,7 +224,7 @@ public:
CardSet *getSet(const QString &setName); CardSet *getSet(const QString &setName);
QList<CardInfo *> getCardList() const { return cards.values(); } QList<CardInfo *> getCardList() const { return cards.values(); }
SetList getSetList() const; SetList getSetList() const;
LoadStatus loadFromFile(const QString &fileName, bool tokens = false); LoadStatus loadFromFile(const QString &fileName);
bool saveToFile(const QString &fileName, bool tokens = false); bool saveToFile(const QString &fileName, bool tokens = false);
QStringList getAllColors() const; QStringList getAllColors() const;
QStringList getAllMainCardTypes() const; QStringList getAllMainCardTypes() const;

View file

@ -11,8 +11,10 @@
#include <QUrlQuery> #include <QUrlQuery>
#endif #endif
DeckStatsInterface::DeckStatsInterface(QObject *parent) DeckStatsInterface::DeckStatsInterface(
: QObject(parent) CardDatabase &_cardDatabase,
QObject *parent
) : QObject(parent), cardDatabase(_cardDatabase)
{ {
manager = new QNetworkAccessManager(this); manager = new QNetworkAccessManager(this);
connect(manager, SIGNAL(finished(QNetworkReply *)), this, SLOT(queryFinished(QNetworkReply *))); connect(manager, SIGNAL(finished(QNetworkReply *)), this, SLOT(queryFinished(QNetworkReply *)));
@ -43,24 +45,23 @@ void DeckStatsInterface::queryFinished(QNetworkReply *reply)
deleteLater(); deleteLater();
} }
void DeckStatsInterface::getAnalyzeRequestData(DeckList *deck, QByteArray *data)
{
DeckList deckWithoutTokens;
copyDeckWithoutTokens(*deck, deckWithoutTokens);
#if QT_VERSION < 0x050000 #if QT_VERSION < 0x050000
void DeckStatsInterface::getAnalyzeRequestData(DeckList *deck, QByteArray *data)
{
QUrl params; QUrl params;
params.addQueryItem("deck", deck->writeToString_Plain()); params.addQueryItem("deck", deckWithoutTokens.writeToString_Plain());
data->append(params.encodedQuery()); data->append(params.encodedQuery());
}
#else #else
void DeckStatsInterface::getAnalyzeRequestData(DeckList *deck, QByteArray *data)
{
QUrl params; QUrl params;
QUrlQuery urlQuery; QUrlQuery urlQuery;
urlQuery.addQueryItem("deck", deck->writeToString_Plain()); urlQuery.addQueryItem("deck", deckWithoutTokens.writeToString_Plain());
params.setQuery(urlQuery); params.setQuery(urlQuery);
data->append(params.query(QUrl::EncodeReserved)); data->append(params.query(QUrl::EncodeReserved));
}
#endif #endif
}
void DeckStatsInterface::analyzeDeck(DeckList *deck) void DeckStatsInterface::analyzeDeck(DeckList *deck)
{ {
@ -72,3 +73,30 @@ void DeckStatsInterface::analyzeDeck(DeckList *deck)
manager->post(request, data); manager->post(request, data);
} }
struct CopyIfNotAToken {
CardDatabase &cardDatabase;
DeckList &destination;
CopyIfNotAToken(
CardDatabase &_cardDatabase,
DeckList &_destination
) : cardDatabase(_cardDatabase), destination(_destination) {};
void operator()(
const InnerDecklistNode *node,
const DecklistCardNode *card
) const {
if (!cardDatabase.getCard(card->getName())->getIsToken()) {
destination.addCard(card->getName(), node->getName());
}
}
};
void DeckStatsInterface::copyDeckWithoutTokens(
const DeckList &source,
DeckList &destination
) {
CopyIfNotAToken copyIfNotAToken(cardDatabase, destination);
source.forEachCard(copyIfNotAToken);
}

View file

@ -1,6 +1,8 @@
#ifndef DECKSTATS_INTERFACE_H #ifndef DECKSTATS_INTERFACE_H
#define DECKSTATS_INTERFACE_H #define DECKSTATS_INTERFACE_H
#include "carddatabase.h"
#include "decklist.h"
#include <QObject> #include <QObject>
class QByteArray; class QByteArray;
@ -12,11 +14,21 @@ class DeckStatsInterface : public QObject {
Q_OBJECT Q_OBJECT
private: private:
QNetworkAccessManager *manager; QNetworkAccessManager *manager;
CardDatabase &cardDatabase;
/**
* Deckstats doesn't recognize token cards, and instead tries to find the
* closest non-token card instead. So we construct a new deck which has no
* tokens.
*/
void copyDeckWithoutTokens(const DeckList &source, DeckList& destination);
private slots: private slots:
void queryFinished(QNetworkReply *reply); void queryFinished(QNetworkReply *reply);
void getAnalyzeRequestData(DeckList *deck, QByteArray *data); void getAnalyzeRequestData(DeckList *deck, QByteArray *data);
public: public:
DeckStatsInterface(QObject *parent = 0); DeckStatsInterface(CardDatabase &_cardDatabase, QObject *parent = 0);
void analyzeDeck(DeckList *deck); void analyzeDeck(DeckList *deck);
}; };

View file

@ -512,7 +512,10 @@ void TabDeckEditor::actPrintDeck()
void TabDeckEditor::actAnalyzeDeck() void TabDeckEditor::actAnalyzeDeck()
{ {
DeckStatsInterface *interface = new DeckStatsInterface(this); // it deletes itself when done DeckStatsInterface *interface = new DeckStatsInterface(
*databaseModel->getDatabase(),
this
); // it deletes itself when done
interface->analyzeDeck(deckModel->getDeckList()); interface->analyzeDeck(deckModel->getDeckList());
} }

View file

@ -586,16 +586,30 @@ bool DeckList::loadFromFile_Plain(QIODevice *device)
return loadFromStream_Plain(in); return loadFromStream_Plain(in);
} }
struct WriteToStream {
QTextStream &stream;
WriteToStream(QTextStream &_stream) : stream(_stream) {}
void operator()(
const InnerDecklistNode *node,
const DecklistCardNode *card
) {
if (node->getName() == "side") {
stream << "SB: ";
}
stream << QString("%1 %2\n").arg(
card->getNumber()
).arg(
card->getName()
);
}
};
bool DeckList::saveToStream_Plain(QTextStream &out) bool DeckList::saveToStream_Plain(QTextStream &out)
{ {
// Support for this is only possible if the internal structure doesn't get more complicated. WriteToStream writeToStream(out);
for (int i = 0; i < root->size(); i++) { forEachCard(writeToStream);
InnerDecklistNode *node = dynamic_cast<InnerDecklistNode *>(root->at(i));
for (int j = 0; j < node->size(); j++) {
DecklistCardNode *card = dynamic_cast<DecklistCardNode *>(node->at(j));
out << QString("%1%2 %3\n").arg(node->getName() == "side" ? "SB: " : "").arg(card->getNumber()).arg(card->getName());
}
}
return true; return true;
} }

View file

@ -117,6 +117,7 @@ public:
QString getName() const { return name; } QString getName() const { return name; }
void setName(const QString &_name) { name = _name; } void setName(const QString &_name) { name = _name; }
float getPrice() const { return price; } float getPrice() const { return price; }
void setPrice(const float _price) { price = _price; } void setPrice(const float _price) { price = _price; }
}; };
@ -169,6 +170,28 @@ public:
InnerDecklistNode *getRoot() const { return root; } InnerDecklistNode *getRoot() const { return root; }
DecklistCardNode *addCard(const QString &cardName, const QString &zoneName); DecklistCardNode *addCard(const QString &cardName, const QString &zoneName);
bool deleteNode(AbstractDecklistNode *node, InnerDecklistNode *rootNode = 0); bool deleteNode(AbstractDecklistNode *node, InnerDecklistNode *rootNode = 0);
/**
* Calls a given function object for each card in the deck. It must
* take a InnerDecklistNode* as its first argument and a
* DecklistCardNode* as its second.
*/
template <typename Callback>
void forEachCard(Callback &callback) const {
// Support for this is only possible if the internal structure
// doesn't get more complicated.
for (int i = 0; i < root->size(); i++) {
const InnerDecklistNode *node =
dynamic_cast<InnerDecklistNode *>(root->at(i));
for (int j = 0; j < node->size(); j++) {
const DecklistCardNode *card =
dynamic_cast<DecklistCardNode *>(
node->at(j)
);
callback(node, card);
}
}
}
}; };
#endif #endif

View file

@ -141,6 +141,7 @@ int OracleImporter::importTextSpoiler(CardSet *set, const QVariant &data)
QString cardText; QString cardText;
int cardId; int cardId;
int cardLoyalty; int cardLoyalty;
bool cardIsToken = false;
QMap<int, QVariantMap> splitCards; QMap<int, QVariantMap> splitCards;
while (it.hasNext()) { while (it.hasNext()) {
@ -201,6 +202,7 @@ int OracleImporter::importTextSpoiler(CardSet *set, const QVariant &data)
cardText = map.contains("text") ? map.value("text").toString() : QString(""); cardText = map.contains("text") ? map.value("text").toString() : QString("");
cardId = map.contains("multiverseid") ? map.value("multiverseid").toInt() : 0; cardId = map.contains("multiverseid") ? map.value("multiverseid").toInt() : 0;
cardLoyalty = map.contains("loyalty") ? map.value("loyalty").toInt() : 0; cardLoyalty = map.contains("loyalty") ? map.value("loyalty").toInt() : 0;
cardIsToken = map.value("layout") == "token";
// Distinguish Vanguard cards from regular cards of the same name. // Distinguish Vanguard cards from regular cards of the same name.
if (map.value("layout") == "vanguard") { if (map.value("layout") == "vanguard") {
@ -208,7 +210,7 @@ int OracleImporter::importTextSpoiler(CardSet *set, const QVariant &data)
} }
} }
CardInfo *card = addCard(set->getShortName(), cardName, false, cardId, cardCost, cardType, cardPT, cardLoyalty, cardText.split("\n")); CardInfo *card = addCard(set->getShortName(), cardName, cardIsToken, cardId, cardCost, cardType, cardPT, cardLoyalty, cardText.split("\n"));
if (!set->contains(card)) { if (!set->contains(card)) {
card->addToSet(set); card->addToSet(set);