Merge remote-tracking branch 'upstream/master' into cmake_qt5
This commit is contained in:
commit
5c13c06982
34 changed files with 1505 additions and 1221 deletions
|
@ -109,9 +109,3 @@ option(WITH_ORACLE "build oracle" ON)
|
||||||
if(WITH_ORACLE)
|
if(WITH_ORACLE)
|
||||||
add_subdirectory(oracle)
|
add_subdirectory(oracle)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Compile testclient (default off)
|
|
||||||
option(WITH_TESTCLIENT "build testclient" OFF)
|
|
||||||
if (WITH_TESTCLIENT)
|
|
||||||
add_subdirectory(testclient)
|
|
||||||
endif()
|
|
|
@ -9,6 +9,7 @@ class CardInfo;
|
||||||
|
|
||||||
class AbstractCardDragItem : public QObject, public QGraphicsItem {
|
class AbstractCardDragItem : public QObject, public QGraphicsItem {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
Q_INTERFACES(QGraphicsItem)
|
||||||
protected:
|
protected:
|
||||||
AbstractCardItem *item;
|
AbstractCardItem *item;
|
||||||
QPointF hotSpot;
|
QPointF hotSpot;
|
||||||
|
|
|
@ -9,6 +9,7 @@ class QAction;
|
||||||
|
|
||||||
class AbstractCounter : public QObject, public QGraphicsItem {
|
class AbstractCounter : public QObject, public QGraphicsItem {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
Q_INTERFACES(QGraphicsItem)
|
||||||
protected:
|
protected:
|
||||||
Player *player;
|
Player *player;
|
||||||
int id;
|
int id;
|
||||||
|
|
|
@ -11,6 +11,7 @@ class ArrowTarget;
|
||||||
|
|
||||||
class ArrowItem : public QObject, public QGraphicsItem {
|
class ArrowItem : public QObject, public QGraphicsItem {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
Q_INTERFACES(QGraphicsItem)
|
||||||
private:
|
private:
|
||||||
QPainterPath path;
|
QPainterPath path;
|
||||||
QMenu *menu;
|
QMenu *menu;
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
#include <QNetworkRequest>
|
#include <QNetworkRequest>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
|
||||||
const int CardDatabase::versionNeeded = 2;
|
const int CardDatabase::versionNeeded = 3;
|
||||||
|
|
||||||
CardSet::CardSet(const QString &_shortName, const QString &_longName)
|
CardSet::CardSet(const QString &_shortName, const QString &_longName)
|
||||||
: shortName(_shortName), longName(_longName)
|
: shortName(_shortName), longName(_longName)
|
||||||
|
@ -80,8 +80,10 @@ bool PictureToLoad::nextSet()
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
PictureLoader::PictureLoader(const QString &__picsPath, bool _picDownload, QObject *parent)
|
PictureLoader::PictureLoader(const QString &__picsPath, bool _picDownload, bool _picDownloadHq, QObject *parent)
|
||||||
: QObject(parent), _picsPath(__picsPath), picDownload(_picDownload), downloadRunning(false), loadQueueRunning(false)
|
: QObject(parent),
|
||||||
|
_picsPath(__picsPath), picDownload(_picDownload), picDownloadHq(_picDownloadHq),
|
||||||
|
downloadRunning(false), loadQueueRunning(false)
|
||||||
{
|
{
|
||||||
connect(this, SIGNAL(startLoadQueue()), this, SLOT(processLoadQueue()), Qt::QueuedConnection);
|
connect(this, SIGNAL(startLoadQueue()), this, SLOT(processLoadQueue()), Qt::QueuedConnection);
|
||||||
|
|
||||||
|
@ -135,6 +137,20 @@ void PictureLoader::processLoadQueue()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString PictureLoader::getPicUrl(CardInfo *card)
|
||||||
|
{
|
||||||
|
if (!picDownload) return 0;
|
||||||
|
|
||||||
|
QString picUrl = picDownloadHq ? settingsCache->getPicUrlHq() : settingsCache->getPicUrl();
|
||||||
|
picUrl.replace("!name!", QUrl::toPercentEncoding(card->getCorrectedName()));
|
||||||
|
CardSet *set = card->getPreferredSet();
|
||||||
|
picUrl.replace("!setcode!", QUrl::toPercentEncoding(set->getShortName()));
|
||||||
|
picUrl.replace("!setname!", QUrl::toPercentEncoding(set->getLongName()));
|
||||||
|
picUrl.replace("!cardid!", QUrl::toPercentEncoding(QString::number(card->getPreferredMuId())));
|
||||||
|
|
||||||
|
return picUrl;
|
||||||
|
}
|
||||||
|
|
||||||
void PictureLoader::startNextPicDownload()
|
void PictureLoader::startNextPicDownload()
|
||||||
{
|
{
|
||||||
if (cardsToDownload.isEmpty()) {
|
if (cardsToDownload.isEmpty()) {
|
||||||
|
@ -146,27 +162,24 @@ void PictureLoader::startNextPicDownload()
|
||||||
downloadRunning = true;
|
downloadRunning = true;
|
||||||
|
|
||||||
cardBeingDownloaded = cardsToDownload.takeFirst();
|
cardBeingDownloaded = cardsToDownload.takeFirst();
|
||||||
QString picUrl;
|
|
||||||
if (cardBeingDownloaded.getStripped())
|
// TODO: Do something useful when picUrl is 0 or empty, etc
|
||||||
picUrl = cardBeingDownloaded.getCard()->getPicURLSt(cardBeingDownloaded.getSetName());
|
QString picUrl = getPicUrl(cardBeingDownloaded.getCard());
|
||||||
else if (cardBeingDownloaded.getHq()) {
|
|
||||||
picUrl = cardBeingDownloaded.getCard()->getPicURLHq(cardBeingDownloaded.getSetName());
|
|
||||||
if (picUrl.isEmpty()) {
|
|
||||||
picUrl = cardBeingDownloaded.getCard()->getPicURL(cardBeingDownloaded.getSetName());
|
|
||||||
cardBeingDownloaded.setHq(false);
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
picUrl = cardBeingDownloaded.getCard()->getPicURL(cardBeingDownloaded.getSetName());
|
|
||||||
QUrl url(picUrl);
|
QUrl url(picUrl);
|
||||||
|
|
||||||
QNetworkRequest req(url);
|
QNetworkRequest req(url);
|
||||||
qDebug() << "starting picture download:" << req.url();
|
qDebug() << "starting picture download:" << cardBeingDownloaded.getCard()->getName() << "Url:" << req.url();
|
||||||
networkManager->get(req);
|
networkManager->get(req);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PictureLoader::picDownloadFinished(QNetworkReply *reply)
|
void PictureLoader::picDownloadFinished(QNetworkReply *reply)
|
||||||
{
|
{
|
||||||
QString picsPath = _picsPath;
|
QString picsPath = _picsPath;
|
||||||
|
if (reply->error()) {
|
||||||
|
qDebug() << "Download failed:" << reply->errorString();
|
||||||
|
}
|
||||||
|
|
||||||
const QByteArray &picData = reply->readAll();
|
const QByteArray &picData = reply->readAll();
|
||||||
QImage testImage;
|
QImage testImage;
|
||||||
if (testImage.loadFromData(picData)) {
|
if (testImage.loadFromData(picData)) {
|
||||||
|
@ -232,6 +245,12 @@ void PictureLoader::setPicDownload(bool _picDownload)
|
||||||
picDownload = _picDownload;
|
picDownload = _picDownload;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PictureLoader::setPicDownloadHq(bool _picDownloadHq)
|
||||||
|
{
|
||||||
|
QMutexLocker locker(&mutex);
|
||||||
|
picDownloadHq = _picDownloadHq;
|
||||||
|
}
|
||||||
|
|
||||||
CardInfo::CardInfo(CardDatabase *_db,
|
CardInfo::CardInfo(CardDatabase *_db,
|
||||||
const QString &_name,
|
const QString &_name,
|
||||||
bool _isToken,
|
bool _isToken,
|
||||||
|
@ -244,22 +263,18 @@ CardInfo::CardInfo(CardDatabase *_db,
|
||||||
bool _cipt,
|
bool _cipt,
|
||||||
int _tableRow,
|
int _tableRow,
|
||||||
const SetList &_sets,
|
const SetList &_sets,
|
||||||
const QMap<QString, QString> &_picURLs,
|
QMap<QString, int> _muIds)
|
||||||
const QMap<QString, QString> &_picURLsHq,
|
|
||||||
const QMap<QString, QString> &_picURLsSt)
|
|
||||||
: db(_db),
|
: db(_db),
|
||||||
name(_name),
|
name(_name),
|
||||||
isToken(_isToken),
|
isToken(_isToken),
|
||||||
sets(_sets),
|
sets(_sets),
|
||||||
|
muIds(_muIds),
|
||||||
manacost(_manacost),
|
manacost(_manacost),
|
||||||
cardtype(_cardtype),
|
cardtype(_cardtype),
|
||||||
powtough(_powtough),
|
powtough(_powtough),
|
||||||
text(_text),
|
text(_text),
|
||||||
colors(_colors),
|
colors(_colors),
|
||||||
loyalty(_loyalty),
|
loyalty(_loyalty),
|
||||||
picURLs(_picURLs),
|
|
||||||
picURLsHq(_picURLsHq),
|
|
||||||
picURLsSt(_picURLsSt),
|
|
||||||
cipt(_cipt),
|
cipt(_cipt),
|
||||||
tableRow(_tableRow),
|
tableRow(_tableRow),
|
||||||
pixmap(NULL)
|
pixmap(NULL)
|
||||||
|
@ -284,6 +299,8 @@ QString CardInfo::getMainCardType() const
|
||||||
int pos;
|
int pos;
|
||||||
if ((pos = result.indexOf('-')) != -1)
|
if ((pos = result.indexOf('-')) != -1)
|
||||||
result.remove(pos, result.length());
|
result.remove(pos, result.length());
|
||||||
|
if ((pos = result.indexOf("—")) != -1)
|
||||||
|
result.remove(pos, result.length());
|
||||||
if ((pos = result.indexOf("//")) != -1)
|
if ((pos = result.indexOf("//")) != -1)
|
||||||
result.remove(pos, result.length());
|
result.remove(pos, result.length());
|
||||||
result = result.simplified();
|
result = result.simplified();
|
||||||
|
@ -315,13 +332,6 @@ void CardInfo::addToSet(CardSet *set)
|
||||||
sets << set;
|
sets << set;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString CardInfo::getPicURL() const
|
|
||||||
{
|
|
||||||
SetList sortedSets = sets;
|
|
||||||
sortedSets.sortByKey();
|
|
||||||
return picURLs.value(sortedSets.first()->getShortName());
|
|
||||||
}
|
|
||||||
|
|
||||||
QPixmap *CardInfo::loadPixmap()
|
QPixmap *CardInfo::loadPixmap()
|
||||||
{
|
{
|
||||||
if (pixmap)
|
if (pixmap)
|
||||||
|
@ -400,18 +410,33 @@ void CardInfo::updatePixmapCache()
|
||||||
emit pixmapUpdated();
|
emit pixmapUpdated();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CardSet* CardInfo::getPreferredSet()
|
||||||
|
{
|
||||||
|
SetList sortedSets = sets;
|
||||||
|
sortedSets.sortByKey();
|
||||||
|
return sortedSets.first();
|
||||||
|
}
|
||||||
|
|
||||||
|
int CardInfo::getPreferredMuId()
|
||||||
|
{
|
||||||
|
return muIds[getPreferredSet()->getShortName()];
|
||||||
|
}
|
||||||
|
|
||||||
QXmlStreamWriter &operator<<(QXmlStreamWriter &xml, const CardInfo *info)
|
QXmlStreamWriter &operator<<(QXmlStreamWriter &xml, const CardInfo *info)
|
||||||
{
|
{
|
||||||
xml.writeStartElement("card");
|
xml.writeStartElement("card");
|
||||||
xml.writeTextElement("name", info->getName());
|
xml.writeTextElement("name", info->getName());
|
||||||
|
|
||||||
const SetList &sets = info->getSets();
|
const SetList &sets = info->getSets();
|
||||||
|
QString tmpString;
|
||||||
|
QString tmpSet;
|
||||||
for (int i = 0; i < sets.size(); i++) {
|
for (int i = 0; i < sets.size(); i++) {
|
||||||
xml.writeStartElement("set");
|
xml.writeStartElement("set");
|
||||||
xml.writeAttribute("picURL", info->getPicURL(sets[i]->getShortName()));
|
|
||||||
xml.writeAttribute("picURLHq", info->getPicURLHq(sets[i]->getShortName()));
|
tmpSet=sets[i]->getShortName();
|
||||||
xml.writeAttribute("picURLSt", info->getPicURLSt(sets[i]->getShortName()));
|
xml.writeAttribute("muId", QString::number(info->getMuId(tmpSet)));
|
||||||
xml.writeCharacters(sets[i]->getShortName());
|
|
||||||
|
xml.writeCharacters(tmpSet);
|
||||||
xml.writeEndElement();
|
xml.writeEndElement();
|
||||||
}
|
}
|
||||||
const QStringList &colors = info->getColors();
|
const QStringList &colors = info->getColors();
|
||||||
|
@ -436,18 +461,19 @@ QXmlStreamWriter &operator<<(QXmlStreamWriter &xml, const CardInfo *info)
|
||||||
}
|
}
|
||||||
|
|
||||||
CardDatabase::CardDatabase(QObject *parent)
|
CardDatabase::CardDatabase(QObject *parent)
|
||||||
: QObject(parent), loadSuccess(false), noCard(0)
|
: QObject(parent), loadStatus(NotLoaded), noCard(0)
|
||||||
{
|
{
|
||||||
connect(settingsCache, SIGNAL(picsPathChanged()), this, SLOT(picsPathChanged()));
|
connect(settingsCache, SIGNAL(picsPathChanged()), this, SLOT(picsPathChanged()));
|
||||||
connect(settingsCache, SIGNAL(cardDatabasePathChanged()), this, SLOT(loadCardDatabase()));
|
connect(settingsCache, SIGNAL(cardDatabasePathChanged()), this, SLOT(loadCardDatabase()));
|
||||||
connect(settingsCache, SIGNAL(tokenDatabasePathChanged()), this, SLOT(loadTokenDatabase()));
|
connect(settingsCache, SIGNAL(tokenDatabasePathChanged()), this, SLOT(loadTokenDatabase()));
|
||||||
connect(settingsCache, SIGNAL(picDownloadChanged()), this, SLOT(picDownloadChanged()));
|
connect(settingsCache, SIGNAL(picDownloadChanged()), this, SLOT(picDownloadChanged()));
|
||||||
|
connect(settingsCache, SIGNAL(picDownloadHqChanged()), this, SLOT(picDownloadHqChanged()));
|
||||||
|
|
||||||
loadCardDatabase();
|
loadCardDatabase();
|
||||||
loadTokenDatabase();
|
loadTokenDatabase();
|
||||||
|
|
||||||
pictureLoaderThread = new QThread;
|
pictureLoaderThread = new QThread;
|
||||||
pictureLoader = new PictureLoader(settingsCache->getPicsPath(), settingsCache->getPicDownload());
|
pictureLoader = new PictureLoader(settingsCache->getPicsPath(), settingsCache->getPicDownload(), settingsCache->getPicDownloadHq());
|
||||||
pictureLoader->moveToThread(pictureLoaderThread);
|
pictureLoader->moveToThread(pictureLoaderThread);
|
||||||
connect(pictureLoader, SIGNAL(imageLoaded(CardInfo *, const QImage &)), this, SLOT(imageLoaded(CardInfo *, const QImage &)));
|
connect(pictureLoader, SIGNAL(imageLoaded(CardInfo *, const QImage &)), this, SLOT(imageLoaded(CardInfo *, const QImage &)));
|
||||||
pictureLoaderThread->start(QThread::LowPriority);
|
pictureLoaderThread->start(QThread::LowPriority);
|
||||||
|
@ -572,7 +598,7 @@ void CardDatabase::loadCardsFromXml(QXmlStreamReader &xml)
|
||||||
if (xml.name() == "card") {
|
if (xml.name() == "card") {
|
||||||
QString name, manacost, type, pt, text;
|
QString name, manacost, type, pt, text;
|
||||||
QStringList colors;
|
QStringList colors;
|
||||||
QMap<QString, QString> picURLs, picURLsHq, picURLsSt;
|
QMap<QString, int> muids;
|
||||||
SetList sets;
|
SetList sets;
|
||||||
int tableRow = 0;
|
int tableRow = 0;
|
||||||
int loyalty = 0;
|
int loyalty = 0;
|
||||||
|
@ -592,14 +618,12 @@ void CardDatabase::loadCardsFromXml(QXmlStreamReader &xml)
|
||||||
else if (xml.name() == "text")
|
else if (xml.name() == "text")
|
||||||
text = xml.readElementText();
|
text = xml.readElementText();
|
||||||
else if (xml.name() == "set") {
|
else if (xml.name() == "set") {
|
||||||
QString picURL = xml.attributes().value("picURL").toString();
|
QXmlStreamAttributes attrs = xml.attributes();
|
||||||
QString picURLHq = xml.attributes().value("picURLHq").toString();
|
|
||||||
QString picURLSt = xml.attributes().value("picURLSt").toString();
|
|
||||||
QString setName = xml.readElementText();
|
QString setName = xml.readElementText();
|
||||||
sets.append(getSet(setName));
|
sets.append(getSet(setName));
|
||||||
picURLs.insert(setName, picURL);
|
if (attrs.hasAttribute("muId")) {
|
||||||
picURLsHq.insert(setName, picURLHq);
|
muids[setName] = attrs.value("muId").toString().toInt();
|
||||||
picURLsSt.insert(setName, picURLSt);
|
}
|
||||||
} else if (xml.name() == "color")
|
} else if (xml.name() == "color")
|
||||||
colors << xml.readElementText();
|
colors << xml.readElementText();
|
||||||
else if (xml.name() == "tablerow")
|
else if (xml.name() == "tablerow")
|
||||||
|
@ -611,17 +635,17 @@ void CardDatabase::loadCardsFromXml(QXmlStreamReader &xml)
|
||||||
else if (xml.name() == "token")
|
else if (xml.name() == "token")
|
||||||
isToken = xml.readElementText().toInt();
|
isToken = xml.readElementText().toInt();
|
||||||
}
|
}
|
||||||
cardHash.insert(name, new CardInfo(this, name, isToken, manacost, type, pt, text, colors, loyalty, cipt, tableRow, sets, picURLs, picURLsHq, picURLsSt));
|
cardHash.insert(name, new CardInfo(this, name, isToken, manacost, type, pt, text, colors, loyalty, cipt, tableRow, sets, muids));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CardDatabase::loadFromFile(const QString &fileName, bool tokens)
|
LoadStatus CardDatabase::loadFromFile(const QString &fileName, bool tokens)
|
||||||
{
|
{
|
||||||
QFile file(fileName);
|
QFile file(fileName);
|
||||||
file.open(QIODevice::ReadOnly);
|
file.open(QIODevice::ReadOnly);
|
||||||
if (!file.isOpen())
|
if (!file.isOpen())
|
||||||
return false;
|
return FileError;
|
||||||
|
|
||||||
if (tokens) {
|
if (tokens) {
|
||||||
QMutableHashIterator<QString, CardInfo *> i(cardHash);
|
QMutableHashIterator<QString, CardInfo *> i(cardHash);
|
||||||
|
@ -655,9 +679,12 @@ bool CardDatabase::loadFromFile(const QString &fileName, bool tokens)
|
||||||
while (!xml.atEnd()) {
|
while (!xml.atEnd()) {
|
||||||
if (xml.readNext() == QXmlStreamReader::StartElement) {
|
if (xml.readNext() == QXmlStreamReader::StartElement) {
|
||||||
if (xml.name() != "cockatrice_carddatabase")
|
if (xml.name() != "cockatrice_carddatabase")
|
||||||
return false;
|
return Invalid;
|
||||||
if (xml.attributes().value("version").toString().toInt() < versionNeeded)
|
int version = xml.attributes().value("version").toString().toInt();
|
||||||
return false;
|
if (version < versionNeeded) {
|
||||||
|
qDebug() << "loadFromFile(): Version too old: " << version;
|
||||||
|
return VersionTooOld;
|
||||||
|
}
|
||||||
while (!xml.atEnd()) {
|
while (!xml.atEnd()) {
|
||||||
if (xml.readNext() == QXmlStreamReader::EndElement)
|
if (xml.readNext() == QXmlStreamReader::EndElement)
|
||||||
break;
|
break;
|
||||||
|
@ -669,7 +696,10 @@ bool CardDatabase::loadFromFile(const QString &fileName, bool tokens)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
qDebug() << cardHash.size() << "cards in" << setHash.size() << "sets loaded";
|
qDebug() << cardHash.size() << "cards in" << setHash.size() << "sets loaded";
|
||||||
return !cardHash.isEmpty();
|
|
||||||
|
if (cardHash.isEmpty()) return NoCards;
|
||||||
|
|
||||||
|
return Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CardDatabase::saveToFile(const QString &fileName, bool tokens)
|
bool CardDatabase::saveToFile(const QString &fileName, bool tokens)
|
||||||
|
@ -717,13 +747,23 @@ void CardDatabase::picDownloadChanged()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CardDatabase::loadCardDatabase(const QString &path, bool tokens)
|
void CardDatabase::picDownloadHqChanged()
|
||||||
{
|
{
|
||||||
bool tempLoadSuccess = false;
|
pictureLoader->setPicDownloadHq(settingsCache->getPicDownloadHq());
|
||||||
if (!path.isEmpty())
|
if (settingsCache->getPicDownloadHq()) {
|
||||||
tempLoadSuccess = loadFromFile(path, tokens);
|
QHashIterator<QString, CardInfo *> cardIterator(cardHash);
|
||||||
|
while (cardIterator.hasNext())
|
||||||
|
cardIterator.next().value()->clearPixmapCacheMiss();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (tempLoadSuccess) {
|
LoadStatus CardDatabase::loadCardDatabase(const QString &path, bool tokens)
|
||||||
|
{
|
||||||
|
LoadStatus tempLoadStatus = NotLoaded;
|
||||||
|
if (!path.isEmpty())
|
||||||
|
tempLoadStatus = loadFromFile(path, tokens);
|
||||||
|
|
||||||
|
if (tempLoadStatus == Ok) {
|
||||||
SetList allSets;
|
SetList allSets;
|
||||||
QHashIterator<QString, CardSet *> setsIterator(setHash);
|
QHashIterator<QString, CardSet *> setsIterator(setHash);
|
||||||
while (setsIterator.hasNext())
|
while (setsIterator.hasNext())
|
||||||
|
@ -735,10 +775,13 @@ bool CardDatabase::loadCardDatabase(const QString &path, bool tokens)
|
||||||
emit cardListChanged();
|
emit cardListChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!tokens)
|
if (!tokens) {
|
||||||
loadSuccess = tempLoadSuccess;
|
loadStatus = tempLoadStatus;
|
||||||
|
qDebug() << "loadCardDatabase(): Status = " << loadStatus;
|
||||||
|
}
|
||||||
|
|
||||||
return tempLoadSuccess;
|
|
||||||
|
return tempLoadStatus;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CardDatabase::loadCardDatabase()
|
void CardDatabase::loadCardDatabase()
|
||||||
|
|
|
@ -53,10 +53,8 @@ public:
|
||||||
bool getStripped() const { return stripped; }
|
bool getStripped() const { return stripped; }
|
||||||
QString getSetName() const { return sortedSets[setIndex]->getShortName(); }
|
QString getSetName() const { return sortedSets[setIndex]->getShortName(); }
|
||||||
bool nextSet();
|
bool nextSet();
|
||||||
|
|
||||||
bool getHq() const { return hq; }
|
bool getHq() const { return hq; }
|
||||||
void setHq(bool _hq) { hq = _hq; }
|
void setHq(bool _hq) { hq = _hq; }
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class PictureLoader : public QObject {
|
class PictureLoader : public QObject {
|
||||||
|
@ -68,13 +66,15 @@ private:
|
||||||
QNetworkAccessManager *networkManager;
|
QNetworkAccessManager *networkManager;
|
||||||
QList<PictureToLoad> cardsToDownload;
|
QList<PictureToLoad> cardsToDownload;
|
||||||
PictureToLoad cardBeingDownloaded;
|
PictureToLoad cardBeingDownloaded;
|
||||||
bool picDownload, downloadRunning, loadQueueRunning;
|
bool picDownload, picDownloadHq, downloadRunning, loadQueueRunning;
|
||||||
void startNextPicDownload();
|
void startNextPicDownload();
|
||||||
|
QString getPicUrl(CardInfo* card);
|
||||||
public:
|
public:
|
||||||
PictureLoader(const QString &__picsPath, bool _picDownload, QObject *parent = 0);
|
PictureLoader(const QString &__picsPath, bool _picDownload, bool _picDownloadHq, QObject *parent = 0);
|
||||||
~PictureLoader();
|
~PictureLoader();
|
||||||
void setPicsPath(const QString &path);
|
void setPicsPath(const QString &path);
|
||||||
void setPicDownload(bool _picDownload);
|
void setPicDownload(bool _picDownload);
|
||||||
|
void setPicDownloadHq(bool _picDownloadHq);
|
||||||
void loadImage(CardInfo *card, bool stripped);
|
void loadImage(CardInfo *card, bool stripped);
|
||||||
private slots:
|
private slots:
|
||||||
void picDownloadFinished(QNetworkReply *reply);
|
void picDownloadFinished(QNetworkReply *reply);
|
||||||
|
@ -99,7 +99,7 @@ private:
|
||||||
QString text;
|
QString text;
|
||||||
QStringList colors;
|
QStringList colors;
|
||||||
int loyalty;
|
int loyalty;
|
||||||
QMap<QString, QString> picURLs, picURLsHq, picURLsSt;
|
QMap<QString, int> muIds;
|
||||||
bool cipt;
|
bool cipt;
|
||||||
int tableRow;
|
int tableRow;
|
||||||
QPixmap *pixmap;
|
QPixmap *pixmap;
|
||||||
|
@ -117,9 +117,7 @@ public:
|
||||||
bool _cipt = false,
|
bool _cipt = false,
|
||||||
int _tableRow = 0,
|
int _tableRow = 0,
|
||||||
const SetList &_sets = SetList(),
|
const SetList &_sets = SetList(),
|
||||||
const QStringMap &_picURLs = QStringMap(),
|
QMap<QString, int> muids = QMap<QString, int>());
|
||||||
const QStringMap &_picURLsHq = QStringMap(),
|
|
||||||
const QStringMap &_picURLsSt = QStringMap());
|
|
||||||
~CardInfo();
|
~CardInfo();
|
||||||
const QString &getName() const { return name; }
|
const QString &getName() const { return name; }
|
||||||
bool getIsToken() const { return isToken; }
|
bool getIsToken() const { return isToken; }
|
||||||
|
@ -136,25 +134,21 @@ public:
|
||||||
void setText(const QString &_text) { text = _text; emit cardInfoChanged(this); }
|
void setText(const QString &_text) { text = _text; emit cardInfoChanged(this); }
|
||||||
void setColors(const QStringList &_colors) { colors = _colors; emit cardInfoChanged(this); }
|
void setColors(const QStringList &_colors) { colors = _colors; emit cardInfoChanged(this); }
|
||||||
const QStringList &getColors() const { return colors; }
|
const QStringList &getColors() const { return colors; }
|
||||||
QString getPicURL(const QString &set) const { return picURLs.value(set); }
|
int getMuId(const QString &set) const { return muIds.value(set); }
|
||||||
QString getPicURLHq(const QString &set) const { return picURLsHq.value(set); }
|
|
||||||
QString getPicURLSt(const QString &set) const { return picURLsSt.value(set); }
|
|
||||||
QString getPicURL() const;
|
|
||||||
const QMap<QString, QString> &getPicURLs() const { return picURLs; }
|
|
||||||
QString getMainCardType() const;
|
QString getMainCardType() const;
|
||||||
QString getCorrectedName() const;
|
QString getCorrectedName() const;
|
||||||
int getTableRow() const { return tableRow; }
|
int getTableRow() const { return tableRow; }
|
||||||
void setTableRow(int _tableRow) { tableRow = _tableRow; }
|
void setTableRow(int _tableRow) { tableRow = _tableRow; }
|
||||||
void setLoyalty(int _loyalty) { loyalty = _loyalty; emit cardInfoChanged(this); }
|
void setLoyalty(int _loyalty) { loyalty = _loyalty; emit cardInfoChanged(this); }
|
||||||
void setPicURL(const QString &_set, const QString &_picURL) { picURLs.insert(_set, _picURL); }
|
void setMuId(const QString &_set, const int &_muId) { muIds.insert(_set, _muId); }
|
||||||
void setPicURLHq(const QString &_set, const QString &_picURL) { picURLsHq.insert(_set, _picURL); }
|
|
||||||
void setPicURLSt(const QString &_set, const QString &_picURL) { picURLsSt.insert(_set, _picURL); }
|
|
||||||
void addToSet(CardSet *set);
|
void addToSet(CardSet *set);
|
||||||
QPixmap *loadPixmap();
|
QPixmap *loadPixmap();
|
||||||
QPixmap *getPixmap(QSize size);
|
QPixmap *getPixmap(QSize size);
|
||||||
void clearPixmapCache();
|
void clearPixmapCache();
|
||||||
void clearPixmapCacheMiss();
|
void clearPixmapCacheMiss();
|
||||||
void imageLoaded(const QImage &image);
|
void imageLoaded(const QImage &image);
|
||||||
|
CardSet *getPreferredSet();
|
||||||
|
int getPreferredMuId();
|
||||||
public slots:
|
public slots:
|
||||||
void updatePixmapCache();
|
void updatePixmapCache();
|
||||||
signals:
|
signals:
|
||||||
|
@ -162,16 +156,18 @@ signals:
|
||||||
void cardInfoChanged(CardInfo *card);
|
void cardInfoChanged(CardInfo *card);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum LoadStatus { Ok, VersionTooOld, Invalid, NotLoaded, FileError, NoCards };
|
||||||
|
|
||||||
class CardDatabase : public QObject {
|
class CardDatabase : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
protected:
|
protected:
|
||||||
QHash<QString, CardInfo *> cardHash;
|
QHash<QString, CardInfo *> cardHash;
|
||||||
QHash<QString, CardSet *> setHash;
|
QHash<QString, CardSet *> setHash;
|
||||||
bool loadSuccess;
|
|
||||||
CardInfo *noCard;
|
CardInfo *noCard;
|
||||||
|
|
||||||
QThread *pictureLoaderThread;
|
QThread *pictureLoaderThread;
|
||||||
PictureLoader *pictureLoader;
|
PictureLoader *pictureLoader;
|
||||||
|
LoadStatus loadStatus;
|
||||||
private:
|
private:
|
||||||
static const int versionNeeded;
|
static const int versionNeeded;
|
||||||
void loadCardsFromXml(QXmlStreamReader &xml);
|
void loadCardsFromXml(QXmlStreamReader &xml);
|
||||||
|
@ -186,19 +182,21 @@ public:
|
||||||
CardSet *getSet(const QString &setName);
|
CardSet *getSet(const QString &setName);
|
||||||
QList<CardInfo *> getCardList() const { return cardHash.values(); }
|
QList<CardInfo *> getCardList() const { return cardHash.values(); }
|
||||||
SetList getSetList() const;
|
SetList getSetList() const;
|
||||||
bool loadFromFile(const QString &fileName, bool tokens = false);
|
LoadStatus loadFromFile(const QString &fileName, bool tokens = false);
|
||||||
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;
|
||||||
bool getLoadSuccess() const { return loadSuccess; }
|
LoadStatus getLoadStatus() const { return loadStatus; }
|
||||||
|
bool getLoadSuccess() const { return loadStatus == Ok; }
|
||||||
void cacheCardPixmaps(const QStringList &cardNames);
|
void cacheCardPixmaps(const QStringList &cardNames);
|
||||||
void loadImage(CardInfo *card);
|
void loadImage(CardInfo *card);
|
||||||
public slots:
|
public slots:
|
||||||
void clearPixmapCache();
|
void clearPixmapCache();
|
||||||
bool loadCardDatabase(const QString &path, bool tokens = false);
|
LoadStatus loadCardDatabase(const QString &path, bool tokens = false);
|
||||||
private slots:
|
private slots:
|
||||||
void imageLoaded(CardInfo *card, QImage image);
|
void imageLoaded(CardInfo *card, QImage image);
|
||||||
void picDownloadChanged();
|
void picDownloadChanged();
|
||||||
|
void picDownloadHqChanged();
|
||||||
void picsPathChanged();
|
void picsPathChanged();
|
||||||
|
|
||||||
void loadCardDatabase();
|
void loadCardDatabase();
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
|
#include <QDebug>
|
||||||
#include "deck_loader.h"
|
#include "deck_loader.h"
|
||||||
#include "decklist.h"
|
#include "decklist.h"
|
||||||
|
|
||||||
|
@ -48,7 +49,16 @@ bool DeckLoader::loadFromFile(const QString &fileName, FileFormat fmt)
|
||||||
bool result = false;
|
bool result = false;
|
||||||
switch (fmt) {
|
switch (fmt) {
|
||||||
case PlainTextFormat: result = loadFromFile_Plain(&file); break;
|
case PlainTextFormat: result = loadFromFile_Plain(&file); break;
|
||||||
case CockatriceFormat: result = loadFromFile_Native(&file); break;
|
case CockatriceFormat:
|
||||||
|
result = loadFromFile_Native(&file);
|
||||||
|
qDebug() << "Loaded from" << fileName << "-" << result;
|
||||||
|
if (!result) {
|
||||||
|
qDebug() << "Retying as plain format";
|
||||||
|
file.seek(0);
|
||||||
|
result = loadFromFile_Plain(&file);
|
||||||
|
fmt = PlainTextFormat;
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
if (result) {
|
if (result) {
|
||||||
lastFileName = fileName;
|
lastFileName = fileName;
|
||||||
|
@ -56,6 +66,7 @@ bool DeckLoader::loadFromFile(const QString &fileName, FileFormat fmt)
|
||||||
|
|
||||||
emit deckLoaded();
|
emit deckLoaded();
|
||||||
}
|
}
|
||||||
|
qDebug() << "Deck was loaded -" << result;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
#include "deck_loader.h"
|
#include "deck_loader.h"
|
||||||
|
|
||||||
DeckListModel::DeckListModel(QObject *parent)
|
DeckListModel::DeckListModel(QObject *parent)
|
||||||
: QAbstractItemModel(parent)
|
: QAbstractItemModel(parent), lastKnownColumn(1), lastKnownOrder(Qt::AscendingOrder)
|
||||||
{
|
{
|
||||||
deckList = new DeckLoader;
|
deckList = new DeckLoader;
|
||||||
connect(deckList, SIGNAL(deckLoaded()), this, SLOT(rebuildTree()));
|
connect(deckList, SIGNAL(deckLoaded()), this, SLOT(rebuildTree()));
|
||||||
|
@ -275,23 +275,20 @@ QModelIndex DeckListModel::addCard(const QString &cardName, const QString &zoneN
|
||||||
QString cardType = info->getMainCardType();
|
QString cardType = info->getMainCardType();
|
||||||
InnerDecklistNode *cardTypeNode = createNodeIfNeeded(cardType, zoneNode);
|
InnerDecklistNode *cardTypeNode = createNodeIfNeeded(cardType, zoneNode);
|
||||||
|
|
||||||
|
QModelIndex parentIndex = nodeToIndex(cardTypeNode);
|
||||||
DecklistModelCardNode *cardNode = dynamic_cast<DecklistModelCardNode *>(cardTypeNode->findChild(cardName));
|
DecklistModelCardNode *cardNode = dynamic_cast<DecklistModelCardNode *>(cardTypeNode->findChild(cardName));
|
||||||
if (!cardNode) {
|
if (!cardNode) {
|
||||||
DecklistCardNode *decklistCard = deckList->addCard(cardName, zoneName);
|
DecklistCardNode *decklistCard = deckList->addCard(cardName, zoneName);
|
||||||
QModelIndex parentIndex = nodeToIndex(cardTypeNode);
|
|
||||||
beginInsertRows(parentIndex, cardTypeNode->size(), cardTypeNode->size());
|
beginInsertRows(parentIndex, cardTypeNode->size(), cardTypeNode->size());
|
||||||
cardNode = new DecklistModelCardNode(decklistCard, cardTypeNode);
|
cardNode = new DecklistModelCardNode(decklistCard, cardTypeNode);
|
||||||
endInsertRows();
|
endInsertRows();
|
||||||
sort(1);
|
|
||||||
emitRecursiveUpdates(parentIndex);
|
|
||||||
return nodeToIndex(cardNode);
|
|
||||||
} else {
|
} else {
|
||||||
cardNode->setNumber(cardNode->getNumber() + 1);
|
cardNode->setNumber(cardNode->getNumber() + 1);
|
||||||
QModelIndex ind = nodeToIndex(cardNode);
|
|
||||||
emitRecursiveUpdates(ind);
|
|
||||||
deckList->updateDeckHash();
|
deckList->updateDeckHash();
|
||||||
return ind;
|
|
||||||
}
|
}
|
||||||
|
sort(lastKnownColumn, lastKnownOrder);
|
||||||
|
emitRecursiveUpdates(parentIndex);
|
||||||
|
return nodeToIndex(cardNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
QModelIndex DeckListModel::nodeToIndex(AbstractDecklistNode *node) const
|
QModelIndex DeckListModel::nodeToIndex(AbstractDecklistNode *node) const
|
||||||
|
@ -327,9 +324,24 @@ void DeckListModel::sortHelper(InnerDecklistNode *node, Qt::SortOrder order)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeckListModel::sort(int /*column*/, Qt::SortOrder order)
|
void DeckListModel::sort(int column, Qt::SortOrder order)
|
||||||
{
|
{
|
||||||
|
lastKnownColumn = column;
|
||||||
|
lastKnownOrder = order;
|
||||||
|
|
||||||
emit layoutAboutToBeChanged();
|
emit layoutAboutToBeChanged();
|
||||||
|
DeckSortMethod sortMethod;
|
||||||
|
switch(column) {
|
||||||
|
case 0:
|
||||||
|
sortMethod = ByNumber;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
sortMethod = ByName;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
sortMethod = ByPrice;
|
||||||
|
}
|
||||||
|
root->setSortMethod(sortMethod);
|
||||||
sortHelper(root, order);
|
sortHelper(root, order);
|
||||||
emit layoutChanged();
|
emit layoutChanged();
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,6 +55,8 @@ public:
|
||||||
private:
|
private:
|
||||||
DeckLoader *deckList;
|
DeckLoader *deckList;
|
||||||
InnerDecklistNode *root;
|
InnerDecklistNode *root;
|
||||||
|
int lastKnownColumn;
|
||||||
|
Qt::SortOrder lastKnownOrder;
|
||||||
InnerDecklistNode *createNodeIfNeeded(const QString &name, InnerDecklistNode *parent);
|
InnerDecklistNode *createNodeIfNeeded(const QString &name, InnerDecklistNode *parent);
|
||||||
QModelIndex nodeToIndex(AbstractDecklistNode *node) const;
|
QModelIndex nodeToIndex(AbstractDecklistNode *node) const;
|
||||||
DecklistModelCardNode *findCardNode(const QString &cardName, const QString &zoneName) const;
|
DecklistModelCardNode *findCardNode(const QString &cardName, const QString &zoneName) const;
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#include <QInputDialog>
|
#include <QInputDialog>
|
||||||
#include <QSpinBox>
|
#include <QSpinBox>
|
||||||
#include <QDialogButtonBox>
|
#include <QDialogButtonBox>
|
||||||
|
#include <QDebug>
|
||||||
#include "carddatabase.h"
|
#include "carddatabase.h"
|
||||||
#include "dlg_settings.h"
|
#include "dlg_settings.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
|
@ -40,13 +41,18 @@ GeneralSettingsPage::GeneralSettingsPage()
|
||||||
picDownloadCheckBox = new QCheckBox;
|
picDownloadCheckBox = new QCheckBox;
|
||||||
picDownloadCheckBox->setChecked(settingsCache->getPicDownload());
|
picDownloadCheckBox->setChecked(settingsCache->getPicDownload());
|
||||||
|
|
||||||
|
picDownloadHqCheckBox = new QCheckBox;
|
||||||
|
picDownloadHqCheckBox->setChecked(settingsCache->getPicDownloadHq());
|
||||||
|
|
||||||
connect(languageBox, SIGNAL(currentIndexChanged(int)), this, SLOT(languageBoxChanged(int)));
|
connect(languageBox, SIGNAL(currentIndexChanged(int)), this, SLOT(languageBoxChanged(int)));
|
||||||
connect(picDownloadCheckBox, SIGNAL(stateChanged(int)), settingsCache, SLOT(setPicDownload(int)));
|
connect(picDownloadCheckBox, SIGNAL(stateChanged(int)), settingsCache, SLOT(setPicDownload(int)));
|
||||||
|
connect(picDownloadHqCheckBox, SIGNAL(stateChanged(int)), settingsCache, SLOT(setPicDownloadHq(int)));
|
||||||
|
|
||||||
QGridLayout *personalGrid = new QGridLayout;
|
QGridLayout *personalGrid = new QGridLayout;
|
||||||
personalGrid->addWidget(languageLabel, 0, 0);
|
personalGrid->addWidget(languageLabel, 0, 0);
|
||||||
personalGrid->addWidget(languageBox, 0, 1);
|
personalGrid->addWidget(languageBox, 0, 1);
|
||||||
personalGrid->addWidget(picDownloadCheckBox, 1, 0, 1, 2);
|
personalGrid->addWidget(picDownloadCheckBox, 1, 0, 1, 2);
|
||||||
|
personalGrid->addWidget(picDownloadHqCheckBox, 2, 0, 1, 2);
|
||||||
|
|
||||||
personalGroupBox = new QGroupBox;
|
personalGroupBox = new QGroupBox;
|
||||||
personalGroupBox->setLayout(personalGrid);
|
personalGroupBox->setLayout(personalGrid);
|
||||||
|
@ -183,6 +189,7 @@ void GeneralSettingsPage::retranslateUi()
|
||||||
personalGroupBox->setTitle(tr("Personal settings"));
|
personalGroupBox->setTitle(tr("Personal settings"));
|
||||||
languageLabel->setText(tr("Language:"));
|
languageLabel->setText(tr("Language:"));
|
||||||
picDownloadCheckBox->setText(tr("Download card pictures on the fly"));
|
picDownloadCheckBox->setText(tr("Download card pictures on the fly"));
|
||||||
|
picDownloadHqCheckBox->setText(tr("Download high-quality card pictures"));
|
||||||
pathsGroupBox->setTitle(tr("Paths"));
|
pathsGroupBox->setTitle(tr("Paths"));
|
||||||
deckPathLabel->setText(tr("Decks directory:"));
|
deckPathLabel->setText(tr("Decks directory:"));
|
||||||
replaysPathLabel->setText(tr("Replays directory:"));
|
replaysPathLabel->setText(tr("Replays directory:"));
|
||||||
|
@ -698,17 +705,65 @@ void DlgSettings::changeEvent(QEvent *event)
|
||||||
|
|
||||||
void DlgSettings::closeEvent(QCloseEvent *event)
|
void DlgSettings::closeEvent(QCloseEvent *event)
|
||||||
{
|
{
|
||||||
if (!db->getLoadSuccess())
|
bool showLoadError = true;
|
||||||
if (QMessageBox::critical(this, tr("Error"), tr("Your card database is invalid. Would you like to go back and set the correct path?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
|
QString loadErrorMessage = tr("Unknown Error loading card database");
|
||||||
|
LoadStatus loadStatus = db->getLoadStatus();
|
||||||
|
qDebug() << "Card Database load status: " << loadStatus;
|
||||||
|
switch(loadStatus) {
|
||||||
|
case Ok:
|
||||||
|
showLoadError = false;
|
||||||
|
break;
|
||||||
|
case Invalid:
|
||||||
|
loadErrorMessage =
|
||||||
|
tr("Your card database is invalid.\n\n"
|
||||||
|
"Cockatrice may not function correctly with an invalid database\n\n"
|
||||||
|
"You may need to rerun oracle to update your card database.\n\n"
|
||||||
|
"Would you like to change your database location setting?");
|
||||||
|
break;
|
||||||
|
case VersionTooOld:
|
||||||
|
loadErrorMessage =
|
||||||
|
tr("Your card database version is too old.\n\n"
|
||||||
|
"This can cause problems loading card information or images\n\n"
|
||||||
|
"Usually this can be fixed by rerunning oracle to to update your card database.\n\n"
|
||||||
|
"Would you like to change your database location setting?");
|
||||||
|
break;
|
||||||
|
case NotLoaded:
|
||||||
|
loadErrorMessage =
|
||||||
|
tr("Your card database did not finish loading\n\n"
|
||||||
|
"Please file a ticket at http://github.com/Daenyth/Cockatrice/issues with your cards.xml attached\n\n"
|
||||||
|
"Would you like to change your database location setting?");
|
||||||
|
break;
|
||||||
|
case FileError:
|
||||||
|
loadErrorMessage =
|
||||||
|
tr("File Error loading your card database.\n\n"
|
||||||
|
"Would you like to change your database location setting?");
|
||||||
|
break;
|
||||||
|
case NoCards:
|
||||||
|
loadErrorMessage =
|
||||||
|
tr("Your card database was loaded but contains no cards.\n\n"
|
||||||
|
"Would you like to change your database location setting?");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
loadErrorMessage =
|
||||||
|
tr("Unknown card database load status\n\n"
|
||||||
|
"Please file a ticket at http://github.com/Daenyth/Cockatrice/issues\n\n"
|
||||||
|
"Would you like to change your database location setting?");
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (showLoadError)
|
||||||
|
if (QMessageBox::critical(this, tr("Error"), loadErrorMessage, QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
|
||||||
event->ignore();
|
event->ignore();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!QDir(settingsCache->getDeckPath()).exists() || settingsCache->getDeckPath().isEmpty())
|
if (!QDir(settingsCache->getDeckPath()).exists() || settingsCache->getDeckPath().isEmpty())
|
||||||
|
// TODO: Prompt to create it
|
||||||
if (QMessageBox::critical(this, tr("Error"), tr("The path to your deck directory is invalid. Would you like to go back and set the correct path?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
|
if (QMessageBox::critical(this, tr("Error"), tr("The path to your deck directory is invalid. Would you like to go back and set the correct path?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
|
||||||
event->ignore();
|
event->ignore();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!QDir(settingsCache->getPicsPath()).exists() || settingsCache->getPicsPath().isEmpty())
|
if (!QDir(settingsCache->getPicsPath()).exists() || settingsCache->getPicsPath().isEmpty())
|
||||||
|
// TODO: Prompt to create it
|
||||||
if (QMessageBox::critical(this, tr("Error"), tr("The path to your card pictures directory is invalid. Would you like to go back and set the correct path?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
|
if (QMessageBox::critical(this, tr("Error"), tr("The path to your card pictures directory is invalid. Would you like to go back and set the correct path?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
|
||||||
event->ignore();
|
event->ignore();
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -40,6 +40,7 @@ private:
|
||||||
QGroupBox *personalGroupBox, *pathsGroupBox;
|
QGroupBox *personalGroupBox, *pathsGroupBox;
|
||||||
QComboBox *languageBox;
|
QComboBox *languageBox;
|
||||||
QCheckBox *picDownloadCheckBox;
|
QCheckBox *picDownloadCheckBox;
|
||||||
|
QCheckBox *picDownloadHqCheckBox;
|
||||||
QLabel *languageLabel, *deckPathLabel, *replaysPathLabel, *picsPathLabel, *cardDatabasePathLabel, *tokenDatabasePathLabel;
|
QLabel *languageLabel, *deckPathLabel, *replaysPathLabel, *picsPathLabel, *cardDatabasePathLabel, *tokenDatabasePathLabel;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -74,6 +74,14 @@ void installNewTranslator()
|
||||||
qApp->installTranslator(translator);
|
qApp->installTranslator(translator);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool settingsValid()
|
||||||
|
{
|
||||||
|
return QDir(settingsCache->getDeckPath()).exists() &&
|
||||||
|
!settingsCache->getDeckPath().isEmpty() &&
|
||||||
|
QDir(settingsCache->getPicsPath()).exists() &&
|
||||||
|
!settingsCache->getPicsPath().isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
QApplication app(argc, argv);
|
QApplication app(argc, argv);
|
||||||
|
@ -142,14 +150,14 @@ int main(int argc, char *argv[])
|
||||||
QDir().mkpath(dataDir + "/pics");
|
QDir().mkpath(dataDir + "/pics");
|
||||||
settingsCache->setPicsPath(dataDir + "/pics");
|
settingsCache->setPicsPath(dataDir + "/pics");
|
||||||
}
|
}
|
||||||
if (!db->getLoadSuccess() || !QDir(settingsCache->getDeckPath()).exists() || settingsCache->getDeckPath().isEmpty() || settingsCache->getPicsPath().isEmpty() || !QDir(settingsCache->getPicsPath()).exists()) {
|
if (!settingsValid() || db->getLoadStatus() != Ok) {
|
||||||
|
qDebug("main(): invalid settings or load status");
|
||||||
DlgSettings dlgSettings;
|
DlgSettings dlgSettings;
|
||||||
dlgSettings.show();
|
dlgSettings.show();
|
||||||
app.exec();
|
app.exec();
|
||||||
startMainProgram = (db->getLoadSuccess() && QDir(settingsCache->getDeckPath()).exists() && !settingsCache->getDeckPath().isEmpty() && QDir(settingsCache->getPicsPath()).exists() && !settingsCache->getPicsPath().isEmpty());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (startMainProgram) {
|
if (settingsValid()) {
|
||||||
qDebug("main(): starting main program");
|
qDebug("main(): starting main program");
|
||||||
soundEngine = new SoundEngine;
|
soundEngine = new SoundEngine;
|
||||||
qDebug("main(): SoundEngine constructor finished");
|
qDebug("main(): SoundEngine constructor finished");
|
||||||
|
|
|
@ -11,6 +11,7 @@ class GameCommand;
|
||||||
|
|
||||||
class PhaseButton : public QObject, public QGraphicsItem {
|
class PhaseButton : public QObject, public QGraphicsItem {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
Q_INTERFACES(QGraphicsItem)
|
||||||
private:
|
private:
|
||||||
QString name;
|
QString name;
|
||||||
bool active, highlightable;
|
bool active, highlightable;
|
||||||
|
@ -39,6 +40,7 @@ protected:
|
||||||
|
|
||||||
class PhasesToolbar : public QObject, public QGraphicsItem {
|
class PhasesToolbar : public QObject, public QGraphicsItem {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
Q_INTERFACES(QGraphicsItem)
|
||||||
private:
|
private:
|
||||||
QList<PhaseButton *> buttonList;
|
QList<PhaseButton *> buttonList;
|
||||||
PhaseButton *nextTurnButton;
|
PhaseButton *nextTurnButton;
|
||||||
|
|
|
@ -58,6 +58,7 @@ class PendingCommand;
|
||||||
|
|
||||||
class PlayerArea : public QObject, public QGraphicsItem {
|
class PlayerArea : public QObject, public QGraphicsItem {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
Q_INTERFACES(QGraphicsItem)
|
||||||
private:
|
private:
|
||||||
QBrush bgPixmapBrush;
|
QBrush bgPixmapBrush;
|
||||||
QRectF bRect;
|
QRectF bRect;
|
||||||
|
@ -76,6 +77,7 @@ public:
|
||||||
|
|
||||||
class Player : public QObject, public QGraphicsItem {
|
class Player : public QObject, public QGraphicsItem {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
Q_INTERFACES(QGraphicsItem)
|
||||||
signals:
|
signals:
|
||||||
void openDeckEditor(const DeckLoader *deck);
|
void openDeckEditor(const DeckLoader *deck);
|
||||||
void newCardAdded(AbstractCardItem *card);
|
void newCardAdded(AbstractCardItem *card);
|
||||||
|
|
|
@ -27,7 +27,7 @@ void PriceUpdater::updatePrices()
|
||||||
QString q = "http://blacklotusproject.com/json/?cards=";
|
QString q = "http://blacklotusproject.com/json/?cards=";
|
||||||
QStringList cards = deck->getCardList();
|
QStringList cards = deck->getCardList();
|
||||||
for (int i = 0; i < cards.size(); ++i) {
|
for (int i = 0; i < cards.size(); ++i) {
|
||||||
q += cards[i] + "|";
|
q += cards[i].toLower() + "|";
|
||||||
}
|
}
|
||||||
QUrl url(q.replace(' ', '+'));
|
QUrl url(q.replace(' ', '+'));
|
||||||
|
|
||||||
|
|
|
@ -19,8 +19,12 @@ SettingsCache::SettingsCache()
|
||||||
playerBgPath = settings->value("zonebg/playerarea").toString();
|
playerBgPath = settings->value("zonebg/playerarea").toString();
|
||||||
cardBackPicturePath = settings->value("paths/cardbackpicture").toString();
|
cardBackPicturePath = settings->value("paths/cardbackpicture").toString();
|
||||||
|
|
||||||
mainWindowGeometry = settings->value("interface/main_window_geometry").toByteArray();
|
|
||||||
picDownload = settings->value("personal/picturedownload", true).toBool();
|
picDownload = settings->value("personal/picturedownload", true).toBool();
|
||||||
|
picDownloadHq = settings->value("personal/picturedownloadhq", false).toBool();
|
||||||
|
picUrl = settings->value("personal/picUrl", PIC_URL_DEFAULT).toString();
|
||||||
|
picUrlHq = settings->value("personal/picUrlHq", PIC_URL_HQ_DEFAULT).toString();
|
||||||
|
|
||||||
|
mainWindowGeometry = settings->value("interface/main_window_geometry").toByteArray();
|
||||||
notificationsEnabled = settings->value("interface/notificationsenabled", true).toBool();
|
notificationsEnabled = settings->value("interface/notificationsenabled", true).toBool();
|
||||||
doubleClickToPlay = settings->value("interface/doubleclicktoplay", true).toBool();
|
doubleClickToPlay = settings->value("interface/doubleclicktoplay", true).toBool();
|
||||||
playToStack = settings->value("interface/playtostack", false).toBool();
|
playToStack = settings->value("interface/playtostack", false).toBool();
|
||||||
|
@ -125,6 +129,25 @@ void SettingsCache::setPicDownload(int _picDownload)
|
||||||
emit picDownloadChanged();
|
emit picDownloadChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SettingsCache::setPicDownloadHq(int _picDownloadHq)
|
||||||
|
{
|
||||||
|
picDownloadHq = _picDownloadHq;
|
||||||
|
settings->setValue("personal/picturedownloadhq", picDownloadHq);
|
||||||
|
emit picDownloadHqChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SettingsCache::setPicUrl(const QString &_picUrl)
|
||||||
|
{
|
||||||
|
picUrl = _picUrl;
|
||||||
|
settings->setValue("personal/picUrl", picUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SettingsCache::setPicUrlHq(const QString &_picUrlHq)
|
||||||
|
{
|
||||||
|
picUrlHq = _picUrlHq;
|
||||||
|
settings->setValue("personal/picUrlHq", picUrlHq);
|
||||||
|
}
|
||||||
|
|
||||||
void SettingsCache::setNotificationsEnabled(int _notificationsEnabled)
|
void SettingsCache::setNotificationsEnabled(int _notificationsEnabled)
|
||||||
{
|
{
|
||||||
notificationsEnabled = _notificationsEnabled;
|
notificationsEnabled = _notificationsEnabled;
|
||||||
|
@ -219,6 +242,7 @@ void SettingsCache::setPriceTagFeature(int _priceTagFeature)
|
||||||
{
|
{
|
||||||
priceTagFeature = _priceTagFeature;
|
priceTagFeature = _priceTagFeature;
|
||||||
settings->setValue("deckeditor/pricetags", priceTagFeature);
|
settings->setValue("deckeditor/pricetags", priceTagFeature);
|
||||||
|
emit priceTagFeatureChanged(priceTagFeature);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SettingsCache::setIgnoreUnregisteredUsers(bool _ignoreUnregisteredUsers)
|
void SettingsCache::setIgnoreUnregisteredUsers(bool _ignoreUnregisteredUsers)
|
||||||
|
|
|
@ -3,6 +3,9 @@
|
||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
|
||||||
|
#define PIC_URL_DEFAULT "http://gatherer.wizards.com/Handlers/Image.ashx?multiverseid=!cardid!&type=card"
|
||||||
|
#define PIC_URL_HQ_DEFAULT "http://mtgimage.com/multiverseid/!cardid!.jpg"
|
||||||
|
|
||||||
class QSettings;
|
class QSettings;
|
||||||
|
|
||||||
class SettingsCache : public QObject {
|
class SettingsCache : public QObject {
|
||||||
|
@ -18,12 +21,14 @@ signals:
|
||||||
void playerBgPathChanged();
|
void playerBgPathChanged();
|
||||||
void cardBackPicturePathChanged();
|
void cardBackPicturePathChanged();
|
||||||
void picDownloadChanged();
|
void picDownloadChanged();
|
||||||
|
void picDownloadHqChanged();
|
||||||
void displayCardNamesChanged();
|
void displayCardNamesChanged();
|
||||||
void horizontalHandChanged();
|
void horizontalHandChanged();
|
||||||
void invertVerticalCoordinateChanged();
|
void invertVerticalCoordinateChanged();
|
||||||
void minPlayersForMultiColumnLayoutChanged();
|
void minPlayersForMultiColumnLayoutChanged();
|
||||||
void soundEnabledChanged();
|
void soundEnabledChanged();
|
||||||
void soundPathChanged();
|
void soundPathChanged();
|
||||||
|
void priceTagFeatureChanged(int enabled);
|
||||||
void ignoreUnregisteredUsersChanged();
|
void ignoreUnregisteredUsersChanged();
|
||||||
private:
|
private:
|
||||||
QSettings *settings;
|
QSettings *settings;
|
||||||
|
@ -33,6 +38,7 @@ private:
|
||||||
QString deckPath, replaysPath, picsPath, cardDatabasePath, tokenDatabasePath;
|
QString deckPath, replaysPath, picsPath, cardDatabasePath, tokenDatabasePath;
|
||||||
QString handBgPath, stackBgPath, tableBgPath, playerBgPath, cardBackPicturePath;
|
QString handBgPath, stackBgPath, tableBgPath, playerBgPath, cardBackPicturePath;
|
||||||
bool picDownload;
|
bool picDownload;
|
||||||
|
bool picDownloadHq;
|
||||||
bool notificationsEnabled;
|
bool notificationsEnabled;
|
||||||
bool doubleClickToPlay;
|
bool doubleClickToPlay;
|
||||||
bool playToStack;
|
bool playToStack;
|
||||||
|
@ -48,6 +54,8 @@ private:
|
||||||
QString soundPath;
|
QString soundPath;
|
||||||
bool priceTagFeature;
|
bool priceTagFeature;
|
||||||
bool ignoreUnregisteredUsers;
|
bool ignoreUnregisteredUsers;
|
||||||
|
QString picUrl;
|
||||||
|
QString picUrlHq;
|
||||||
public:
|
public:
|
||||||
SettingsCache();
|
SettingsCache();
|
||||||
const QByteArray &getMainWindowGeometry() const { return mainWindowGeometry; }
|
const QByteArray &getMainWindowGeometry() const { return mainWindowGeometry; }
|
||||||
|
@ -63,6 +71,7 @@ public:
|
||||||
QString getPlayerBgPath() const { return playerBgPath; }
|
QString getPlayerBgPath() const { return playerBgPath; }
|
||||||
QString getCardBackPicturePath() const { return cardBackPicturePath; }
|
QString getCardBackPicturePath() const { return cardBackPicturePath; }
|
||||||
bool getPicDownload() const { return picDownload; }
|
bool getPicDownload() const { return picDownload; }
|
||||||
|
bool getPicDownloadHq() const { return picDownloadHq; }
|
||||||
bool getNotificationsEnabled() const { return notificationsEnabled; }
|
bool getNotificationsEnabled() const { return notificationsEnabled; }
|
||||||
bool getDoubleClickToPlay() const { return doubleClickToPlay; }
|
bool getDoubleClickToPlay() const { return doubleClickToPlay; }
|
||||||
bool getPlayToStack() const { return playToStack; }
|
bool getPlayToStack() const { return playToStack; }
|
||||||
|
@ -79,6 +88,8 @@ public:
|
||||||
QString getSoundPath() const { return soundPath; }
|
QString getSoundPath() const { return soundPath; }
|
||||||
bool getPriceTagFeature() const { return priceTagFeature; }
|
bool getPriceTagFeature() const { return priceTagFeature; }
|
||||||
bool getIgnoreUnregisteredUsers() const { return ignoreUnregisteredUsers; }
|
bool getIgnoreUnregisteredUsers() const { return ignoreUnregisteredUsers; }
|
||||||
|
QString getPicUrl() const { return picUrl; }
|
||||||
|
QString getPicUrlHq() const { return picUrlHq; }
|
||||||
public slots:
|
public slots:
|
||||||
void setMainWindowGeometry(const QByteArray &_mainWindowGeometry);
|
void setMainWindowGeometry(const QByteArray &_mainWindowGeometry);
|
||||||
void setLang(const QString &_lang);
|
void setLang(const QString &_lang);
|
||||||
|
@ -93,6 +104,7 @@ public slots:
|
||||||
void setPlayerBgPath(const QString &_playerBgPath);
|
void setPlayerBgPath(const QString &_playerBgPath);
|
||||||
void setCardBackPicturePath(const QString &_cardBackPicturePath);
|
void setCardBackPicturePath(const QString &_cardBackPicturePath);
|
||||||
void setPicDownload(int _picDownload);
|
void setPicDownload(int _picDownload);
|
||||||
|
void setPicDownloadHq(int _picDownloadHq);
|
||||||
void setNotificationsEnabled(int _notificationsEnabled);
|
void setNotificationsEnabled(int _notificationsEnabled);
|
||||||
void setDoubleClickToPlay(int _doubleClickToPlay);
|
void setDoubleClickToPlay(int _doubleClickToPlay);
|
||||||
void setPlayToStack(int _playToStack);
|
void setPlayToStack(int _playToStack);
|
||||||
|
@ -109,6 +121,8 @@ public slots:
|
||||||
void setSoundPath(const QString &_soundPath);
|
void setSoundPath(const QString &_soundPath);
|
||||||
void setPriceTagFeature(int _priceTagFeature);
|
void setPriceTagFeature(int _priceTagFeature);
|
||||||
void setIgnoreUnregisteredUsers(bool _ignoreUnregisteredUsers);
|
void setIgnoreUnregisteredUsers(bool _ignoreUnregisteredUsers);
|
||||||
|
void setPicUrl(const QString &_picUrl);
|
||||||
|
void setPicUrlHq(const QString &_picUrlHq);
|
||||||
};
|
};
|
||||||
|
|
||||||
extern SettingsCache *settingsCache;
|
extern SettingsCache *settingsCache;
|
||||||
|
|
|
@ -132,6 +132,8 @@ TabDeckEditor::TabDeckEditor(TabSupervisor *_tabSupervisor, QWidget *parent)
|
||||||
deckView = new QTreeView();
|
deckView = new QTreeView();
|
||||||
deckView->setModel(deckModel);
|
deckView->setModel(deckModel);
|
||||||
deckView->setUniformRowHeights(true);
|
deckView->setUniformRowHeights(true);
|
||||||
|
deckView->setSortingEnabled(true);
|
||||||
|
deckView->sortByColumn(1, Qt::AscendingOrder);
|
||||||
deckView->header()->setResizeMode(QHeaderView::ResizeToContents);
|
deckView->header()->setResizeMode(QHeaderView::ResizeToContents);
|
||||||
deckView->installEventFilter(&deckViewKeySignals);
|
deckView->installEventFilter(&deckViewKeySignals);
|
||||||
connect(deckView->selectionModel(), SIGNAL(currentRowChanged(const QModelIndex &, const QModelIndex &)), this, SLOT(updateCardInfoRight(const QModelIndex &, const QModelIndex &)));
|
connect(deckView->selectionModel(), SIGNAL(currentRowChanged(const QModelIndex &, const QModelIndex &)), this, SLOT(updateCardInfoRight(const QModelIndex &, const QModelIndex &)));
|
||||||
|
@ -170,6 +172,7 @@ TabDeckEditor::TabDeckEditor(TabSupervisor *_tabSupervisor, QWidget *parent)
|
||||||
connect(aUpdatePrices, SIGNAL(triggered()), this, SLOT(actUpdatePrices()));
|
connect(aUpdatePrices, SIGNAL(triggered()), this, SLOT(actUpdatePrices()));
|
||||||
if (!settingsCache->getPriceTagFeature())
|
if (!settingsCache->getPriceTagFeature())
|
||||||
aUpdatePrices->setVisible(false);
|
aUpdatePrices->setVisible(false);
|
||||||
|
connect(settingsCache, SIGNAL(priceTagFeatureChanged(int)), this, SLOT(setPriceTagFeatureEnabled(int)));
|
||||||
|
|
||||||
QToolBar *deckToolBar = new QToolBar;
|
QToolBar *deckToolBar = new QToolBar;
|
||||||
deckToolBar->setOrientation(Qt::Vertical);
|
deckToolBar->setOrientation(Qt::Vertical);
|
||||||
|
@ -633,6 +636,11 @@ void TabDeckEditor::actDecrement()
|
||||||
offsetCountAtIndex(currentIndex, -1);
|
offsetCountAtIndex(currentIndex, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TabDeckEditor::setPriceTagFeatureEnabled(int enabled)
|
||||||
|
{
|
||||||
|
aUpdatePrices->setVisible(enabled);
|
||||||
|
}
|
||||||
|
|
||||||
void TabDeckEditor::actUpdatePrices()
|
void TabDeckEditor::actUpdatePrices()
|
||||||
{
|
{
|
||||||
aUpdatePrices->setDisabled(true);
|
aUpdatePrices->setDisabled(true);
|
||||||
|
@ -655,7 +663,7 @@ void TabDeckEditor::setDeck(DeckLoader *_deck)
|
||||||
nameEdit->setText(deckModel->getDeckList()->getName());
|
nameEdit->setText(deckModel->getDeckList()->getName());
|
||||||
commentsEdit->setText(deckModel->getDeckList()->getComments());
|
commentsEdit->setText(deckModel->getDeckList()->getComments());
|
||||||
updateHash();
|
updateHash();
|
||||||
deckModel->sort(1);
|
deckModel->sort(deckView->header()->sortIndicatorSection(), deckView->header()->sortIndicatorOrder());
|
||||||
deckView->expandAll();
|
deckView->expandAll();
|
||||||
setModified(false);
|
setModified(false);
|
||||||
|
|
||||||
|
|
|
@ -67,6 +67,7 @@ private slots:
|
||||||
void saveDeckRemoteFinished(const Response &r);
|
void saveDeckRemoteFinished(const Response &r);
|
||||||
void filterViewCustomContextMenu(const QPoint &point);
|
void filterViewCustomContextMenu(const QPoint &point);
|
||||||
void filterRemove(QAction *action);
|
void filterRemove(QAction *action);
|
||||||
|
void setPriceTagFeatureEnabled(int enabled);
|
||||||
private:
|
private:
|
||||||
CardInfo *currentCardInfo() const;
|
CardInfo *currentCardInfo() const;
|
||||||
void addCardHelper(QString zoneName);
|
void addCardHelper(QString zoneName);
|
||||||
|
|
|
@ -11,6 +11,7 @@ class QGraphicsSceneWheelEvent;
|
||||||
|
|
||||||
class ZoneViewZone : public SelectZone, public QGraphicsLayoutItem {
|
class ZoneViewZone : public SelectZone, public QGraphicsLayoutItem {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
Q_INTERFACES(QGraphicsLayoutItem)
|
||||||
private:
|
private:
|
||||||
QRectF bRect, optimumRect;
|
QRectF bRect, optimumRect;
|
||||||
int minRows, numberCards;
|
int minRows, numberCards;
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#include <QTextStream>
|
#include <QTextStream>
|
||||||
#include <QVariant>
|
#include <QVariant>
|
||||||
#include <QCryptographicHash>
|
#include <QCryptographicHash>
|
||||||
|
#include <QDebug>
|
||||||
#include "decklist.h"
|
#include "decklist.h"
|
||||||
|
|
||||||
SideboardPlan::SideboardPlan(const QString &_name, const QList<MoveCard_ToZone> &_moveList)
|
SideboardPlan::SideboardPlan(const QString &_name, const QList<MoveCard_ToZone> &_moveList)
|
||||||
|
@ -104,6 +105,13 @@ QString InnerDecklistNode::visibleNameFromName(const QString &_name)
|
||||||
return _name;
|
return _name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void InnerDecklistNode::setSortMethod(DeckSortMethod method)
|
||||||
|
{
|
||||||
|
sortMethod = method;
|
||||||
|
for (int i = 0; i < size(); i++)
|
||||||
|
at(i)->setSortMethod(method);
|
||||||
|
}
|
||||||
|
|
||||||
QString InnerDecklistNode::getVisibleName() const
|
QString InnerDecklistNode::getVisibleName() const
|
||||||
{
|
{
|
||||||
return visibleNameFromName(name);
|
return visibleNameFromName(name);
|
||||||
|
@ -163,21 +171,95 @@ float InnerDecklistNode::recursivePrice(bool countTotalCards) const
|
||||||
}
|
}
|
||||||
|
|
||||||
bool InnerDecklistNode::compare(AbstractDecklistNode *other) const
|
bool InnerDecklistNode::compare(AbstractDecklistNode *other) const
|
||||||
|
{
|
||||||
|
switch (sortMethod) {
|
||||||
|
case 0:
|
||||||
|
return compareNumber(other);
|
||||||
|
case 1:
|
||||||
|
return compareName(other);
|
||||||
|
case 2:
|
||||||
|
return comparePrice(other);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool InnerDecklistNode::compareNumber(AbstractDecklistNode *other) const
|
||||||
{
|
{
|
||||||
InnerDecklistNode *other2 = dynamic_cast<InnerDecklistNode *>(other);
|
InnerDecklistNode *other2 = dynamic_cast<InnerDecklistNode *>(other);
|
||||||
if (other2)
|
if (other2) {
|
||||||
return (getName() > other->getName());
|
int n1 = recursiveCount(true);
|
||||||
else
|
int n2 = other2->recursiveCount(true);
|
||||||
|
return (n1 != n2) ? (n1 > n2) : compareName(other);
|
||||||
|
} else {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool InnerDecklistNode::compareName(AbstractDecklistNode *other) const
|
||||||
|
{
|
||||||
|
InnerDecklistNode *other2 = dynamic_cast<InnerDecklistNode *>(other);
|
||||||
|
if (other2) {
|
||||||
|
return (getName() > other2->getName());
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool InnerDecklistNode::comparePrice(AbstractDecklistNode *other) const
|
||||||
|
{
|
||||||
|
InnerDecklistNode *other2 = dynamic_cast<InnerDecklistNode *>(other);
|
||||||
|
if (other2) {
|
||||||
|
int p1 = 100*recursivePrice(true);
|
||||||
|
int p2 = 100*other2->recursivePrice(true);
|
||||||
|
return (p1 != p2) ? (p1 > p2) : compareName(other);
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AbstractDecklistCardNode::compare(AbstractDecklistNode *other) const
|
bool AbstractDecklistCardNode::compare(AbstractDecklistNode *other) const
|
||||||
|
{
|
||||||
|
switch (sortMethod) {
|
||||||
|
case ByNumber:
|
||||||
|
return compareNumber(other);
|
||||||
|
case ByName:
|
||||||
|
return compareName(other);
|
||||||
|
case ByPrice:
|
||||||
|
return compareTotalPrice(other);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AbstractDecklistCardNode::compareNumber(AbstractDecklistNode *other) const
|
||||||
{
|
{
|
||||||
AbstractDecklistCardNode *other2 = dynamic_cast<AbstractDecklistCardNode *>(other);
|
AbstractDecklistCardNode *other2 = dynamic_cast<AbstractDecklistCardNode *>(other);
|
||||||
if (other2)
|
if (other2) {
|
||||||
return (getName() > other->getName());
|
int n1 = getNumber();
|
||||||
else
|
int n2 = other2->getNumber();
|
||||||
|
return (n1 != n2) ? (n1 > n2) : compareName(other);
|
||||||
|
} else {
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AbstractDecklistCardNode::compareName(AbstractDecklistNode *other) const
|
||||||
|
{
|
||||||
|
AbstractDecklistCardNode *other2 = dynamic_cast<AbstractDecklistCardNode *>(other);
|
||||||
|
if (other2) {
|
||||||
|
return (getName() > other2->getName());
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AbstractDecklistCardNode::compareTotalPrice(AbstractDecklistNode *other) const
|
||||||
|
{
|
||||||
|
AbstractDecklistCardNode *other2 = dynamic_cast<AbstractDecklistCardNode *>(other);
|
||||||
|
if (other2) {
|
||||||
|
int p1 = 100*getTotalPrice();
|
||||||
|
int p2 = 100*other2->getTotalPrice();
|
||||||
|
return (p1 != p2) ? (p1 > p2) : compareName(other);
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class InnerDecklistNode::compareFunctor {
|
class InnerDecklistNode::compareFunctor {
|
||||||
|
@ -360,6 +442,11 @@ void DeckList::write(QXmlStreamWriter *xml)
|
||||||
|
|
||||||
bool DeckList::loadFromXml(QXmlStreamReader *xml)
|
bool DeckList::loadFromXml(QXmlStreamReader *xml)
|
||||||
{
|
{
|
||||||
|
if (xml->error()) {
|
||||||
|
qDebug() << "Error loading deck from xml: " << xml->errorString();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
cleanList();
|
cleanList();
|
||||||
while (!xml->atEnd()) {
|
while (!xml->atEnd()) {
|
||||||
xml->readNext();
|
xml->readNext();
|
||||||
|
@ -374,6 +461,10 @@ bool DeckList::loadFromXml(QXmlStreamReader *xml)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
updateDeckHash();
|
updateDeckHash();
|
||||||
|
if (xml->error()) {
|
||||||
|
qDebug() << "Error loading deck from xml: " << xml->errorString();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -396,8 +487,7 @@ QString DeckList::writeToString_Native()
|
||||||
bool DeckList::loadFromFile_Native(QIODevice *device)
|
bool DeckList::loadFromFile_Native(QIODevice *device)
|
||||||
{
|
{
|
||||||
QXmlStreamReader xml(device);
|
QXmlStreamReader xml(device);
|
||||||
loadFromXml(&xml);
|
return loadFromXml(&xml);
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DeckList::saveToFile_Native(QIODevice *device)
|
bool DeckList::saveToFile_Native(QIODevice *device)
|
||||||
|
@ -462,10 +552,10 @@ bool DeckList::loadFromStream_Plain(QTextStream &in)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
QString cardName = line.mid(i + 1);
|
QString cardName = line.mid(i + 1);
|
||||||
// Common differences between cockatrice's card names
|
// Common differences between cockatrice's card names
|
||||||
// and what's commonly used in decklists
|
// and what's commonly used in decklists
|
||||||
rx.setPattern("’");
|
rx.setPattern("’");
|
||||||
cardName.replace(rx, "'");
|
cardName.replace(rx, "'");
|
||||||
rx.setPattern("Æ");
|
rx.setPattern("Æ");
|
||||||
cardName.replace(rx, "AE");
|
cardName.replace(rx, "AE");
|
||||||
rx.setPattern("^Aether");
|
rx.setPattern("^Aether");
|
||||||
|
|
|
@ -35,12 +35,16 @@ public:
|
||||||
void setMoveList(const QList<MoveCard_ToZone> &_moveList);
|
void setMoveList(const QList<MoveCard_ToZone> &_moveList);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum DeckSortMethod { ByNumber, ByName, ByPrice };
|
||||||
|
|
||||||
class AbstractDecklistNode {
|
class AbstractDecklistNode {
|
||||||
protected:
|
protected:
|
||||||
InnerDecklistNode *parent;
|
InnerDecklistNode *parent;
|
||||||
|
DeckSortMethod sortMethod;
|
||||||
public:
|
public:
|
||||||
AbstractDecklistNode(InnerDecklistNode *_parent = 0);
|
AbstractDecklistNode(InnerDecklistNode *_parent = 0);
|
||||||
virtual ~AbstractDecklistNode() { }
|
virtual ~AbstractDecklistNode() { }
|
||||||
|
virtual void setSortMethod(DeckSortMethod method) { sortMethod = method; }
|
||||||
virtual QString getName() const = 0;
|
virtual QString getName() const = 0;
|
||||||
InnerDecklistNode *getParent() const { return parent; }
|
InnerDecklistNode *getParent() const { return parent; }
|
||||||
int depth() const;
|
int depth() const;
|
||||||
|
@ -59,6 +63,7 @@ public:
|
||||||
InnerDecklistNode(const QString &_name = QString(), InnerDecklistNode *_parent = 0) : AbstractDecklistNode(_parent), name(_name) { }
|
InnerDecklistNode(const QString &_name = QString(), InnerDecklistNode *_parent = 0) : AbstractDecklistNode(_parent), name(_name) { }
|
||||||
InnerDecklistNode(InnerDecklistNode *other, InnerDecklistNode *_parent = 0);
|
InnerDecklistNode(InnerDecklistNode *other, InnerDecklistNode *_parent = 0);
|
||||||
virtual ~InnerDecklistNode();
|
virtual ~InnerDecklistNode();
|
||||||
|
void setSortMethod(DeckSortMethod method);
|
||||||
QString getName() const { return name; }
|
QString getName() const { return name; }
|
||||||
void setName(const QString &_name) { name = _name; }
|
void setName(const QString &_name) { name = _name; }
|
||||||
static QString visibleNameFromName(const QString &_name);
|
static QString visibleNameFromName(const QString &_name);
|
||||||
|
@ -69,6 +74,9 @@ public:
|
||||||
int recursiveCount(bool countTotalCards = false) const;
|
int recursiveCount(bool countTotalCards = false) const;
|
||||||
float recursivePrice(bool countTotalCards = false) const;
|
float recursivePrice(bool countTotalCards = false) const;
|
||||||
bool compare(AbstractDecklistNode *other) const;
|
bool compare(AbstractDecklistNode *other) const;
|
||||||
|
bool compareNumber(AbstractDecklistNode *other) const;
|
||||||
|
bool compareName(AbstractDecklistNode *other) const;
|
||||||
|
bool comparePrice(AbstractDecklistNode *other) const;
|
||||||
QVector<QPair<int, int> > sort(Qt::SortOrder order = Qt::AscendingOrder);
|
QVector<QPair<int, int> > sort(Qt::SortOrder order = Qt::AscendingOrder);
|
||||||
|
|
||||||
bool readElement(QXmlStreamReader *xml);
|
bool readElement(QXmlStreamReader *xml);
|
||||||
|
@ -87,6 +95,9 @@ public:
|
||||||
float getTotalPrice() const { return getNumber() * getPrice(); }
|
float getTotalPrice() const { return getNumber() * getPrice(); }
|
||||||
int height() const { return 0; }
|
int height() const { return 0; }
|
||||||
bool compare(AbstractDecklistNode *other) const;
|
bool compare(AbstractDecklistNode *other) const;
|
||||||
|
bool compareNumber(AbstractDecklistNode *other) const;
|
||||||
|
bool compareName(AbstractDecklistNode *other) const;
|
||||||
|
bool compareTotalPrice(AbstractDecklistNode *other) const;
|
||||||
|
|
||||||
bool readElement(QXmlStreamReader *xml);
|
bool readElement(QXmlStreamReader *xml);
|
||||||
void writeElement(QXmlStreamWriter *xml);
|
void writeElement(QXmlStreamWriter *xml);
|
||||||
|
|
689
doc/sets.xml
689
doc/sets.xml
|
@ -1,333 +1,254 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<cockatrice_setdatabase version="20130507">
|
<cockatrice_setdatabase version="20110126">
|
||||||
<picture_url>http://gatherer.wizards.com/Handlers/Image.ashx?multiverseid=!cardid!&type=card</picture_url>
|
<picture_url>http://gatherer.wizards.com/Handlers/Image.ashx?multiverseid=!cardid!&type=card</picture_url>
|
||||||
<set_url>http://gatherer.wizards.com/Pages/Search/Default.aspx?output=spoiler&method=text&set=["!longname!"]&special=true</set_url>
|
<!-- <picture_url_hq>http://mtgimage.com/multiverseid/!cardid!.jpg</picture_url_hq> -->
|
||||||
<set import="1">
|
<set_url>http://mtgjson.com/json/!name!.json</set_url>
|
||||||
<name>10E</name>
|
|
||||||
<longname>Tenth Edition</longname>
|
|
||||||
</set>
|
|
||||||
<set import="1">
|
|
||||||
<name>15ANN</name>
|
|
||||||
<longname>15th Anniversary</longname>
|
|
||||||
</set>
|
|
||||||
<set import="1">
|
|
||||||
<name>4E</name>
|
|
||||||
<longname>Fourth Edition</longname>
|
|
||||||
</set>
|
|
||||||
<set import="1">
|
|
||||||
<name>5DN</name>
|
|
||||||
<longname>Fifth Dawn</longname>
|
|
||||||
</set>
|
|
||||||
<set import="1">
|
|
||||||
<name>5E</name>
|
|
||||||
<longname>Fifth Edition</longname>
|
|
||||||
</set>
|
|
||||||
<set import="1">
|
|
||||||
<name>6E</name>
|
|
||||||
<longname>Classic Sixth Edition</longname>
|
|
||||||
</set>
|
|
||||||
<set import="1">
|
|
||||||
<name>7E</name>
|
|
||||||
<longname>Seventh Edition</longname>
|
|
||||||
</set>
|
|
||||||
<set import="1">
|
|
||||||
<name>8EB</name>
|
|
||||||
<longname>Eighth Edition Box Set</longname>
|
|
||||||
</set>
|
|
||||||
<set import="1">
|
|
||||||
<name>8E</name>
|
|
||||||
<longname>Eighth Edition</longname>
|
|
||||||
</set>
|
|
||||||
<set import="1">
|
|
||||||
<name>9EB</name>
|
|
||||||
<longname>Ninth Edition Box Set</longname>
|
|
||||||
</set>
|
|
||||||
<set import="1">
|
|
||||||
<name>9E</name>
|
|
||||||
<longname>Ninth Edition</longname>
|
|
||||||
</set>
|
|
||||||
<set import="1">
|
|
||||||
<name>AI</name>
|
|
||||||
<longname>Alliances</longname>
|
|
||||||
</set>
|
|
||||||
<set import="1">
|
|
||||||
<name>ALA</name>
|
|
||||||
<longname>Shards of Alara</longname>
|
|
||||||
</set>
|
|
||||||
<set import="1">
|
|
||||||
<name>AL</name>
|
|
||||||
<longname>Limited Edition Alpha</longname>
|
|
||||||
</set>
|
|
||||||
<set import="1">
|
|
||||||
<name>AN</name>
|
|
||||||
<longname>Arabian Nights</longname>
|
|
||||||
</set>
|
|
||||||
<set import="1">
|
|
||||||
<name>APAC</name>
|
|
||||||
<longname>Asia Pacific Land Program</longname>
|
|
||||||
</set>
|
|
||||||
<set import="1">
|
|
||||||
<name>AP</name>
|
|
||||||
<longname>Apocalypse</longname>
|
|
||||||
</set>
|
|
||||||
<set import="1">
|
|
||||||
<name>AQ</name>
|
|
||||||
<longname>Antiquities</longname>
|
|
||||||
</set>
|
|
||||||
<set import="1">
|
<set import="1">
|
||||||
<name>ARB</name>
|
<name>ARB</name>
|
||||||
<longname>Alara Reborn</longname>
|
<longname>Alara Reborn</longname>
|
||||||
</set>
|
</set>
|
||||||
<set import="1">
|
<set import="1">
|
||||||
|
<name>ALL</name>
|
||||||
|
<longname>Alliances</longname>
|
||||||
|
</set>
|
||||||
|
<set import="1">
|
||||||
|
<name>ATQ</name>
|
||||||
|
<longname>Antiquities</longname>
|
||||||
|
</set>
|
||||||
|
<set import="1">
|
||||||
|
<name>APC</name>
|
||||||
|
<longname>Apocalypse</longname>
|
||||||
|
</set>
|
||||||
|
<set import="1">
|
||||||
|
<name>ARN</name>
|
||||||
|
<longname>Arabian Nights</longname>
|
||||||
|
</set>
|
||||||
|
<set import="0">
|
||||||
<name>ARC</name>
|
<name>ARC</name>
|
||||||
<longname>Archenemy</longname>
|
<longname>Archenemy</longname>
|
||||||
</set>
|
</set>
|
||||||
<set import="1">
|
|
||||||
<name>ARENA</name>
|
|
||||||
<longname>Arena League</longname>
|
|
||||||
</set>
|
|
||||||
<set import="1">
|
|
||||||
<name>AT</name>
|
|
||||||
<longname>Anthologies</longname>
|
|
||||||
</set>
|
|
||||||
<set import="1">
|
<set import="1">
|
||||||
<name>AVR</name>
|
<name>AVR</name>
|
||||||
<longname>Avacyn Restored</longname>
|
<longname>Avacyn Restored</longname>
|
||||||
</set>
|
</set>
|
||||||
<set import="1">
|
<set import="0">
|
||||||
<name>BD</name>
|
<name>BRB</name>
|
||||||
<longname>Beatdown Box Set</longname>
|
<longname>Battle Royale Box Set</longname>
|
||||||
</set>
|
</set>
|
||||||
<set import="1">
|
<set import="0">
|
||||||
<name>BE</name>
|
<name>BTD</name>
|
||||||
<longname>Limited Edition Beta</longname>
|
<longname>Beatdown Box Set</longname>
|
||||||
</set>
|
</set>
|
||||||
<set import="1">
|
<set import="1">
|
||||||
<name>BOK</name>
|
<name>BOK</name>
|
||||||
<longname>Betrayers of Kamigawa</longname>
|
<longname>Betrayers of Kamigawa</longname>
|
||||||
</set>
|
</set>
|
||||||
<set import="1">
|
<set import="1">
|
||||||
<name>BR</name>
|
<name>BNG</name>
|
||||||
<longname>Battle Royale Box Set</longname>
|
<longname>Born of the Gods</longname>
|
||||||
</set>
|
|
||||||
<set import="1">
|
|
||||||
<name>CED</name>
|
|
||||||
<longname>Collector's Edition</longname>
|
|
||||||
</set>
|
|
||||||
<set import="1">
|
|
||||||
<name>CEDI</name>
|
|
||||||
<longname>International Collectors' Edition</longname>
|
|
||||||
</set>
|
|
||||||
<set import="1">
|
|
||||||
<name>CFX</name>
|
|
||||||
<longname>Conflux</longname>
|
|
||||||
</set>
|
|
||||||
<set import="1">
|
|
||||||
<name>CH</name>
|
|
||||||
<longname>Chronicles</longname>
|
|
||||||
</set>
|
</set>
|
||||||
<set import="1">
|
<set import="1">
|
||||||
<name>CHK</name>
|
<name>CHK</name>
|
||||||
<longname>Champions of Kamigawa</longname>
|
<longname>Champions of Kamigawa</longname>
|
||||||
</set>
|
</set>
|
||||||
<set import="1">
|
<set import="1">
|
||||||
<name>CMA</name>
|
<name>CHR</name>
|
||||||
<longname>Commander's Arsenal</longname>
|
<longname>Chronicles</longname>
|
||||||
</set>
|
</set>
|
||||||
<set import="1">
|
<set import="1">
|
||||||
<name>CMD</name>
|
<name>6ED</name>
|
||||||
<longname>Commander</longname>
|
<longname>Classic Sixth Edition</longname>
|
||||||
</set>
|
</set>
|
||||||
<set import="1">
|
<set import="1">
|
||||||
<name>CP</name>
|
<name>CSP</name>
|
||||||
<longname>Champs</longname>
|
|
||||||
</set>
|
|
||||||
<set import="1">
|
|
||||||
<name>CS</name>
|
|
||||||
<longname>Coldsnap</longname>
|
<longname>Coldsnap</longname>
|
||||||
</set>
|
</set>
|
||||||
<set import="1">
|
<set import="1">
|
||||||
<name>CSTD</name>
|
<name>CON</name>
|
||||||
<longname>Coldsnap Theme Decks</longname>
|
<longname>Conflux</longname>
|
||||||
|
</set>
|
||||||
|
<set import="0">
|
||||||
|
<name>CMA</name>
|
||||||
|
<longname>Commander's Arsenal</longname>
|
||||||
|
</set>
|
||||||
|
<set import="0">^M
|
||||||
|
<name>C13</name>^M
|
||||||
|
<longname>Commander 2013 Edition</longname>^M
|
||||||
</set>
|
</set>
|
||||||
<set import="1">
|
<set import="1">
|
||||||
<name>DCILM</name>
|
<name>DST</name>
|
||||||
<longname>Legend Membership</longname>
|
<longname>Darksteel</longname>
|
||||||
</set>
|
|
||||||
<set import="1">
|
|
||||||
<name>DDF</name>
|
|
||||||
<longname>Duel Decks: Elspeth vs. Tezzeret</longname>
|
|
||||||
</set>
|
|
||||||
<set import="1">
|
|
||||||
<name>DDG</name>
|
|
||||||
<longname>Duel Decks: Knights vs. Dragons</longname>
|
|
||||||
</set>
|
|
||||||
<set import="1">
|
|
||||||
<name>DDH</name>
|
|
||||||
<longname>Duel Decks: Ajani vs. Nicol Bolas</longname>
|
|
||||||
</set>
|
|
||||||
<set import="1">
|
|
||||||
<name>DDI</name>
|
|
||||||
<longname>Duel Decks: Venser vs. Koth</longname>
|
|
||||||
</set>
|
|
||||||
<set import="1">
|
|
||||||
<name>DDJ</name>
|
|
||||||
<longname>Duel Decks: Izzet vs. Golgari</longname>
|
|
||||||
</set>
|
|
||||||
<set import="1">
|
|
||||||
<name>DDK</name>
|
|
||||||
<longname>Duel Decks: Sorin vs. Tibalt</longname>
|
|
||||||
</set>
|
|
||||||
<set import="1">
|
|
||||||
<name>DGM</name>
|
|
||||||
<longname>Dragon's Maze</longname>
|
|
||||||
</set>
|
|
||||||
<set import="1">
|
|
||||||
<name>DI</name>
|
|
||||||
<longname>Dissension</longname>
|
|
||||||
</set>
|
</set>
|
||||||
<set import="1">
|
<set import="1">
|
||||||
<name>DKA</name>
|
<name>DKA</name>
|
||||||
<longname>Dark Ascension</longname>
|
<longname>Dark Ascension</longname>
|
||||||
</set>
|
</set>
|
||||||
<set import="1">
|
<set import="1">
|
||||||
<name>DK</name>
|
<name>DIS</name>
|
||||||
<longname>The Dark</longname>
|
<longname>Dissension</longname>
|
||||||
</set>
|
</set>
|
||||||
<set import="1">
|
<set import="1">
|
||||||
<name>DM</name>
|
<name>DGM</name>
|
||||||
<longname>Deckmasters</longname>
|
<longname>Dragon's Maze</longname>
|
||||||
</set>
|
</set>
|
||||||
<set import="1">
|
<set import="0">
|
||||||
<name>DPA</name>
|
<name>DDH</name>
|
||||||
<longname>Duels of the Planeswalkers</longname>
|
<longname>Duel Decks: Ajani vs. Nicol Bolas</longname>
|
||||||
</set>
|
</set>
|
||||||
<set import="1">
|
<set import="0">
|
||||||
<name>DRC</name>
|
<name>DDC</name>
|
||||||
<longname>Dragon Con</longname>
|
|
||||||
</set>
|
|
||||||
<set import="1">
|
|
||||||
<name>DS</name>
|
|
||||||
<longname>Darksteel</longname>
|
|
||||||
</set>
|
|
||||||
<set import="1">
|
|
||||||
<name>DVD</name>
|
|
||||||
<longname>Duel Decks: Divine vs. Demonic</longname>
|
<longname>Duel Decks: Divine vs. Demonic</longname>
|
||||||
</set>
|
</set>
|
||||||
|
<set import="0">
|
||||||
|
<name>DDF</name>
|
||||||
|
<longname>Duel Decks: Elspeth vs. Tezzeret</longname>
|
||||||
|
</set>
|
||||||
|
<set import="0">
|
||||||
|
<name>EVG</name>
|
||||||
|
<longname>Duel Decks: Elves vs. Goblins</longname>
|
||||||
|
</set>
|
||||||
|
<set import="0">
|
||||||
|
<name>DDD</name>
|
||||||
|
<longname>Duel Decks: Garruk vs. Liliana</longname>
|
||||||
|
</set>
|
||||||
|
<set import="0">
|
||||||
|
<name>DDL</name>
|
||||||
|
<longname>Duel Decks: Heroes vs. Monsters</longname>
|
||||||
|
</set>
|
||||||
|
<set import="0">
|
||||||
|
<name>DDJ</name>
|
||||||
|
<longname>Duel Decks: Izzet vs. Golgari</longname>
|
||||||
|
</set>
|
||||||
|
<set import="0">
|
||||||
|
<name>DD2</name>
|
||||||
|
<longname>Duel Decks: Jace vs. Chandra</longname>
|
||||||
|
</set>
|
||||||
|
<set import="0">
|
||||||
|
<name>DDM</name>
|
||||||
|
<longname>Duel Decks: Jace vs. Vraska</longname>
|
||||||
|
</set>
|
||||||
|
<set import="0">
|
||||||
|
<name>DDG</name>
|
||||||
|
<longname>Duel Decks: Knights vs. Dragons</longname>
|
||||||
|
</set>
|
||||||
|
<set import="0">
|
||||||
|
<name>DDE</name>
|
||||||
|
<longname>Duel Decks: Phyrexia vs. the Coalition</longname>
|
||||||
|
</set>
|
||||||
|
<set import="0">
|
||||||
|
<name>DDK</name>
|
||||||
|
<longname>Duel Decks: Sorin vs. Tibalt</longname>
|
||||||
|
</set>
|
||||||
|
<set import="0">
|
||||||
|
<name>DDI</name>
|
||||||
|
<longname>Duel Decks: Venser vs. Koth</longname>
|
||||||
|
</set>
|
||||||
<set import="1">
|
<set import="1">
|
||||||
<name>EURO</name>
|
<name>8ED</name>
|
||||||
<longname>European Land Program</longname>
|
<longname>Eighth Edition</longname>
|
||||||
</set>
|
</set>
|
||||||
<set import="1">
|
<set import="1">
|
||||||
<name>EVE</name>
|
<name>EVE</name>
|
||||||
<longname>Eventide</longname>
|
<longname>Eventide</longname>
|
||||||
</set>
|
</set>
|
||||||
<set import="1">
|
<set import="1">
|
||||||
<name>EVG</name>
|
<name>EXO</name>
|
||||||
<longname>Duel Decks: Elves vs. Goblins</longname>
|
|
||||||
</set>
|
|
||||||
<set import="1">
|
|
||||||
<name>EX</name>
|
|
||||||
<longname>Exodus</longname>
|
<longname>Exodus</longname>
|
||||||
</set>
|
</set>
|
||||||
<set import="1">
|
<set import="1">
|
||||||
<name>FE</name>
|
<name>FEM</name>
|
||||||
<longname>Fallen Empires</longname>
|
<longname>Fallen Empires</longname>
|
||||||
</set>
|
</set>
|
||||||
<set import="1">
|
<set import="1">
|
||||||
<name>FNMP</name>
|
<name>5DN</name>
|
||||||
<longname>Friday Night Magic</longname>
|
<longname>Fifth Dawn</longname>
|
||||||
|
</set>
|
||||||
|
<set import="1">
|
||||||
|
<name>5ED</name>
|
||||||
|
<longname>Fifth Edition</longname>
|
||||||
|
</set>
|
||||||
|
<set import="1">
|
||||||
|
<name>4ED</name>
|
||||||
|
<longname>Fourth Edition</longname>
|
||||||
|
</set>
|
||||||
|
<set import="0">
|
||||||
|
<name>DRB</name>
|
||||||
|
<longname>From the Vault: Dragons</longname>
|
||||||
|
</set>
|
||||||
|
<set import="0">
|
||||||
|
<name>V09</name>
|
||||||
|
<longname>From the Vault: Exiled</longname>
|
||||||
|
</set>
|
||||||
|
<set import="0">
|
||||||
|
<name>V11</name>
|
||||||
|
<longname>From the Vault: Legends</longname>
|
||||||
|
</set>
|
||||||
|
<set import="0">
|
||||||
|
<name>V12</name>
|
||||||
|
<longname>From the Vault: Realms</longname>
|
||||||
|
</set>
|
||||||
|
<set import="0">
|
||||||
|
<name>V10</name>
|
||||||
|
<longname>From the Vault: Relics</longname>
|
||||||
|
</set>
|
||||||
|
<set import="0">
|
||||||
|
<name>V13</name>
|
||||||
|
<longname>From the Vault: Twenty</longname>
|
||||||
</set>
|
</set>
|
||||||
<set import="1">
|
<set import="1">
|
||||||
<name>FUT</name>
|
<name>FUT</name>
|
||||||
<longname>Future Sight</longname>
|
<longname>Future Sight</longname>
|
||||||
</set>
|
</set>
|
||||||
<set import="1">
|
<set import="1">
|
||||||
<name>FVD</name>
|
<name>GPT</name>
|
||||||
<longname>From the Vault: Dragons</longname>
|
|
||||||
</set>
|
|
||||||
<set import="1">
|
|
||||||
<name>FVE</name>
|
|
||||||
<longname>From the Vault: Exiled</longname>
|
|
||||||
</set>
|
|
||||||
<set import="1">
|
|
||||||
<name>FVL</name>
|
|
||||||
<longname>From the Vault: Legends</longname>
|
|
||||||
</set>
|
|
||||||
<set import="1">
|
|
||||||
<name>FVR</name>
|
|
||||||
<longname>From the Vault: Relics</longname>
|
|
||||||
</set>
|
|
||||||
<set import="1">
|
|
||||||
<name>GP</name>
|
|
||||||
<longname>Guildpact</longname>
|
<longname>Guildpact</longname>
|
||||||
</set>
|
</set>
|
||||||
<set import="1">
|
|
||||||
<name>GPX</name>
|
|
||||||
<longname>Grand Prix</longname>
|
|
||||||
</set>
|
|
||||||
<set import="1">
|
|
||||||
<name>GRC</name>
|
|
||||||
<longname>WPN/Gateway</longname>
|
|
||||||
</set>
|
|
||||||
<set import="1">
|
<set import="1">
|
||||||
<name>GTC</name>
|
<name>GTC</name>
|
||||||
<longname>Gatecrash</longname>
|
<longname>Gatecrash</longname>
|
||||||
</set>
|
</set>
|
||||||
<set import="1">
|
<set import="1">
|
||||||
<name>GURU</name>
|
<name>HML</name>
|
||||||
<longname>Guru</longname>
|
|
||||||
</set>
|
|
||||||
<set import="1">
|
|
||||||
<name>GVL</name>
|
|
||||||
<longname>Duel Decks: Garruk vs. Liliana</longname>
|
|
||||||
</set>
|
|
||||||
<set import="1">
|
|
||||||
<name>HHO</name>
|
|
||||||
<longname>Happy Holidays</longname>
|
|
||||||
</set>
|
|
||||||
<set import="1">
|
|
||||||
<name>HL</name>
|
|
||||||
<longname>Homelands</longname>
|
<longname>Homelands</longname>
|
||||||
</set>
|
</set>
|
||||||
<set import="1">
|
<set import="1">
|
||||||
<name>IA</name>
|
<name>ICE</name>
|
||||||
<longname>Ice Age</longname>
|
<longname>Ice Age</longname>
|
||||||
</set>
|
</set>
|
||||||
<set import="1">
|
|
||||||
<name>IN</name>
|
|
||||||
<longname>Invasion</longname>
|
|
||||||
</set>
|
|
||||||
<set import="1">
|
<set import="1">
|
||||||
<name>ISD</name>
|
<name>ISD</name>
|
||||||
<longname>Innistrad</longname>
|
<longname>Innistrad</longname>
|
||||||
</set>
|
</set>
|
||||||
<set import="1">
|
<set import="1">
|
||||||
<name>ITP</name>
|
<name>INV</name>
|
||||||
<longname>Introductory Two-Player Set</longname>
|
<longname>Invasion</longname>
|
||||||
</set>
|
</set>
|
||||||
<set import="1">
|
<set import="1">
|
||||||
<name>JR</name>
|
<name>JOU</name>
|
||||||
<longname>Judge Gift Program</longname>
|
<longname>Journey into Nyx</longname>
|
||||||
</set>
|
</set>
|
||||||
<set import="1">
|
<set import="1">
|
||||||
<name>JU</name>
|
<name>JUD</name>
|
||||||
<longname>Judgment</longname>
|
<longname>Judgment</longname>
|
||||||
</set>
|
</set>
|
||||||
<set import="1">
|
<set import="1">
|
||||||
<name>JVC</name>
|
<name>LEG</name>
|
||||||
<longname>Duel Decks: Jace vs. Chandra</longname>
|
|
||||||
</set>
|
|
||||||
<set import="1">
|
|
||||||
<name>LE</name>
|
|
||||||
<longname>Legions</longname>
|
|
||||||
</set>
|
|
||||||
<set import="1">
|
|
||||||
<name>LG</name>
|
|
||||||
<longname>Legends</longname>
|
<longname>Legends</longname>
|
||||||
</set>
|
</set>
|
||||||
<set import="1">
|
<set import="1">
|
||||||
<name>LW</name>
|
<name>LGN</name>
|
||||||
|
<longname>Legions</longname>
|
||||||
|
</set>
|
||||||
|
<set import="1">
|
||||||
|
<name>LEA</name>
|
||||||
|
<longname>Limited Edition Alpha</longname>
|
||||||
|
</set>
|
||||||
|
<set import="1">
|
||||||
|
<name>LEB</name>
|
||||||
|
<longname>Limited Edition Beta</longname>
|
||||||
|
</set>
|
||||||
|
<set import="1">
|
||||||
|
<name>LRW</name>
|
||||||
<longname>Lorwyn</longname>
|
<longname>Lorwyn</longname>
|
||||||
</set>
|
</set>
|
||||||
<set import="1">
|
<set import="1">
|
||||||
|
@ -347,63 +268,59 @@
|
||||||
<longname>Magic 2013</longname>
|
<longname>Magic 2013</longname>
|
||||||
</set>
|
</set>
|
||||||
<set import="1">
|
<set import="1">
|
||||||
<name>MBP</name>
|
<name>M14</name>
|
||||||
<longname>Media Inserts</longname>
|
<longname>Magic 2014 Core Set</longname>
|
||||||
|
</set>
|
||||||
|
<set import="0">
|
||||||
|
<name>CMD</name>
|
||||||
|
<longname>Magic: The Gathering-Commander</longname>
|
||||||
|
</set>
|
||||||
|
<set import="0">
|
||||||
|
<name>CNS</name>
|
||||||
|
<longname>Magic: The Gathering—Conspiracy</longname>
|
||||||
|
</set>
|
||||||
|
<set import="0">
|
||||||
|
<name>MED</name>
|
||||||
|
<longname>Masters Edition</longname>
|
||||||
|
</set>
|
||||||
|
<set import="0">
|
||||||
|
<name>ME2</name>
|
||||||
|
<longname>Masters Edition II</longname>
|
||||||
|
</set>
|
||||||
|
<set import="0">
|
||||||
|
<name>ME3</name>
|
||||||
|
<longname>Masters Edition III</longname>
|
||||||
|
</set>
|
||||||
|
<set import="0">
|
||||||
|
<name>ME4</name>
|
||||||
|
<longname>Masters Edition IV</longname>
|
||||||
|
</set>
|
||||||
|
<set import="1">
|
||||||
|
<name>MMQ</name>
|
||||||
|
<longname>Mercadian Masques</longname>
|
||||||
|
</set>
|
||||||
|
<set import="1">
|
||||||
|
<name>MIR</name>
|
||||||
|
<longname>Mirage</longname>
|
||||||
|
</set>
|
||||||
|
<set import="1">
|
||||||
|
<name>MRD</name>
|
||||||
|
<longname>Mirrodin</longname>
|
||||||
</set>
|
</set>
|
||||||
<set import="1">
|
<set import="1">
|
||||||
<name>MBS</name>
|
<name>MBS</name>
|
||||||
<longname>Mirrodin Besieged</longname>
|
<longname>Mirrodin Besieged</longname>
|
||||||
</set>
|
</set>
|
||||||
|
<set import="0">^M
|
||||||
|
<name>MMA</name>^M
|
||||||
|
<longname>Modern Masters</longname>^M
|
||||||
|
</set>^
|
||||||
<set import="1">
|
<set import="1">
|
||||||
<name>ME2</name>
|
<name>MOR</name>
|
||||||
<longname>MTGO Masters Edition II</longname>
|
|
||||||
</set>
|
|
||||||
<set import="1">
|
|
||||||
<name>ME3</name>
|
|
||||||
<longname>MTGO Masters Edition III</longname>
|
|
||||||
</set>
|
|
||||||
<set import="1">
|
|
||||||
<name>ME4</name>
|
|
||||||
<longname>MTGO Masters Edition IV</longname>
|
|
||||||
</set>
|
|
||||||
<set import="1">
|
|
||||||
<name>MED</name>
|
|
||||||
<longname>MTGO Masters Edition</longname>
|
|
||||||
</set>
|
|
||||||
<set import="1">
|
|
||||||
<name>MGBC</name>
|
|
||||||
<longname>Multiverse Gift Box Cards</longname>
|
|
||||||
</set>
|
|
||||||
<set import="1">
|
|
||||||
<name>MGDC</name>
|
|
||||||
<longname>Magic Game Day Cards</longname>
|
|
||||||
</set>
|
|
||||||
<set import="1">
|
|
||||||
<name>MI</name>
|
|
||||||
<longname>Mirrodin</longname>
|
|
||||||
</set>
|
|
||||||
<set import="1">
|
|
||||||
<name>MLP</name>
|
|
||||||
<longname>Magic: The Gathering Launch Parties</longname>
|
|
||||||
</set>
|
|
||||||
<set import="1">
|
|
||||||
<name>MM</name>
|
|
||||||
<longname>Mercadian Masques</longname>
|
|
||||||
</set>
|
|
||||||
<set import="1">
|
|
||||||
<name>MPRP</name>
|
|
||||||
<longname>Magic Player Rewards</longname>
|
|
||||||
</set>
|
|
||||||
<set import="1">
|
|
||||||
<name>MR</name>
|
|
||||||
<longname>Mirage</longname>
|
|
||||||
</set>
|
|
||||||
<set import="1">
|
|
||||||
<name>MT</name>
|
|
||||||
<longname>Morningtide</longname>
|
<longname>Morningtide</longname>
|
||||||
</set>
|
</set>
|
||||||
<set import="1">
|
<set import="1">
|
||||||
<name>NE</name>
|
<name>NMS</name>
|
||||||
<longname>Nemesis</longname>
|
<longname>Nemesis</longname>
|
||||||
</set>
|
</set>
|
||||||
<set import="1">
|
<set import="1">
|
||||||
|
@ -411,104 +328,80 @@
|
||||||
<longname>New Phyrexia</longname>
|
<longname>New Phyrexia</longname>
|
||||||
</set>
|
</set>
|
||||||
<set import="1">
|
<set import="1">
|
||||||
<name>OD</name>
|
<name>9ED</name>
|
||||||
|
<longname>Ninth Edition</longname>
|
||||||
|
</set>
|
||||||
|
<set import="1">
|
||||||
|
<name>ODY</name>
|
||||||
<longname>Odyssey</longname>
|
<longname>Odyssey</longname>
|
||||||
</set>
|
</set>
|
||||||
<set import="1">
|
<set import="1">
|
||||||
<name>ON</name>
|
<name>ONS</name>
|
||||||
<longname>Onslaught</longname>
|
<longname>Onslaught</longname>
|
||||||
</set>
|
</set>
|
||||||
<set import="1">
|
<set import="1">
|
||||||
<name>P3K</name>
|
<name>PLC</name>
|
||||||
<longname>Portal Three Kingdoms</longname>
|
<longname>Planar Chaos</longname>
|
||||||
</set>
|
</set>
|
||||||
<set import="1">
|
<set import="0">
|
||||||
|
<name>HOP</name>
|
||||||
|
<longname>Planechase</longname>
|
||||||
|
</set>
|
||||||
|
<set import="0">
|
||||||
<name>PC2</name>
|
<name>PC2</name>
|
||||||
<longname>Planechase 2012 Edition</longname>
|
<longname>Planechase 2012 Edition</longname>
|
||||||
</set>
|
</set>
|
||||||
<set import="1">
|
<set import="1">
|
||||||
<name>PC</name>
|
<name>PLS</name>
|
||||||
<longname>Planar Chaos</longname>
|
<longname>Planeshift</longname>
|
||||||
</set>
|
</set>
|
||||||
<set import="1">
|
<set import="1">
|
||||||
<name>PCH</name>
|
<name>POR</name>
|
||||||
<longname>Planechase</longname>
|
<longname>Portal</longname>
|
||||||
</set>
|
|
||||||
<set import="1">
|
|
||||||
<name>PD2</name>
|
|
||||||
<longname>Premium Deck Series: Fire and Lightning</longname>
|
|
||||||
</set>
|
|
||||||
<set import="1">
|
|
||||||
<name>PD3</name>
|
|
||||||
<longname>Premium Deck Series: Graveborn</longname>
|
|
||||||
</set>
|
|
||||||
<set import="1">
|
|
||||||
<name>PDS</name>
|
|
||||||
<longname>Premium Deck Series: Slivers</longname>
|
|
||||||
</set>
|
</set>
|
||||||
<set import="1">
|
<set import="1">
|
||||||
<name>PO2</name>
|
<name>PO2</name>
|
||||||
<longname>Portal Second Age</longname>
|
<longname>Portal Second Age</longname>
|
||||||
</set>
|
</set>
|
||||||
<set import="1">
|
<set import="1">
|
||||||
<name>PO</name>
|
<name>PTK</name>
|
||||||
<longname>Portal</longname>
|
<longname>Portal Three Kingdoms</longname>
|
||||||
|
</set>
|
||||||
|
<set import="0">
|
||||||
|
<name>PD2</name>
|
||||||
|
<longname>Premium Deck Series: Fire and Lightning</longname>
|
||||||
|
</set>
|
||||||
|
<set import="0">
|
||||||
|
<name>PD3</name>
|
||||||
|
<longname>Premium Deck Series: Graveborn</longname>
|
||||||
|
</set>
|
||||||
|
<set import="0">
|
||||||
|
<name>H09</name>
|
||||||
|
<longname>Premium Deck Series: Slivers</longname>
|
||||||
|
</set>
|
||||||
|
<set import="0">
|
||||||
|
<name>PPR</name>
|
||||||
|
<longname>Promo set for Gatherer</longname>
|
||||||
</set>
|
</set>
|
||||||
<set import="1">
|
<set import="1">
|
||||||
<name>POT</name>
|
<name>PCY</name>
|
||||||
<longname>Portal Demogame</longname>
|
|
||||||
</set>
|
|
||||||
<set import="1">
|
|
||||||
<name>PR</name>
|
|
||||||
<longname>Prophecy</longname>
|
<longname>Prophecy</longname>
|
||||||
</set>
|
</set>
|
||||||
<set import="1">
|
|
||||||
<name>PRO</name>
|
|
||||||
<longname>Pro Tour</longname>
|
|
||||||
</set>
|
|
||||||
<set import="1">
|
|
||||||
<name>PS</name>
|
|
||||||
<longname>Planeshift</longname>
|
|
||||||
</set>
|
|
||||||
<set import="1">
|
|
||||||
<name>PTC</name>
|
|
||||||
<longname>Prerelease Events</longname>
|
|
||||||
</set>
|
|
||||||
<set import="1">
|
|
||||||
<name>PVC</name>
|
|
||||||
<longname>Duel Decks: Phyrexia vs. The Coalition</longname>
|
|
||||||
</set>
|
|
||||||
<set import="1">
|
<set import="1">
|
||||||
<name>RAV</name>
|
<name>RAV</name>
|
||||||
<longname>Ravnica: City of Guilds</longname>
|
<longname>Ravnica: City of Guilds</longname>
|
||||||
</set>
|
</set>
|
||||||
<set import="1">
|
|
||||||
<name>REP</name>
|
|
||||||
<longname>Release Events</longname>
|
|
||||||
</set>
|
|
||||||
<set import="1">
|
|
||||||
<name>ROE</name>
|
|
||||||
<longname>Rise of the Eldrazi</longname>
|
|
||||||
</set>
|
|
||||||
<set import="1">
|
<set import="1">
|
||||||
<name>RTR</name>
|
<name>RTR</name>
|
||||||
<longname>Return to Ravnica</longname>
|
<longname>Return to Ravnica</longname>
|
||||||
</set>
|
</set>
|
||||||
<set import="1">
|
<set import="1">
|
||||||
<name>RV</name>
|
<name>3ED</name>
|
||||||
<longname>Revised Edition</longname>
|
<longname>Revised Edition</longname>
|
||||||
</set>
|
</set>
|
||||||
<set import="1">
|
<set import="1">
|
||||||
<name>SC</name>
|
<name>ROE</name>
|
||||||
<longname>Scourge</longname>
|
<longname>Rise of the Eldrazi</longname>
|
||||||
</set>
|
|
||||||
<set import="1">
|
|
||||||
<name>SH</name>
|
|
||||||
<longname>Stronghold</longname>
|
|
||||||
</set>
|
|
||||||
<set import="1">
|
|
||||||
<name>SHM</name>
|
|
||||||
<longname>Shadowmoor</longname>
|
|
||||||
</set>
|
</set>
|
||||||
<set import="1">
|
<set import="1">
|
||||||
<name>SOK</name>
|
<name>SOK</name>
|
||||||
|
@ -519,97 +412,97 @@
|
||||||
<longname>Scars of Mirrodin</longname>
|
<longname>Scars of Mirrodin</longname>
|
||||||
</set>
|
</set>
|
||||||
<set import="1">
|
<set import="1">
|
||||||
<name>ST2K</name>
|
<name>SCG</name>
|
||||||
<longname>Starter 2000</longname>
|
<longname>Scourge</longname>
|
||||||
</set>
|
</set>
|
||||||
<set import="1">
|
<set import="1">
|
||||||
<name>ST</name>
|
<name>7ED</name>
|
||||||
|
<longname>Seventh Edition</longname>
|
||||||
|
</set>
|
||||||
|
<set import="1">
|
||||||
|
<name>SHM</name>
|
||||||
|
<longname>Shadowmoor</longname>
|
||||||
|
</set>
|
||||||
|
<set import="1">
|
||||||
|
<name>ALA</name>
|
||||||
|
<longname>Shards of Alara</longname>
|
||||||
|
</set>
|
||||||
|
<set import="1">
|
||||||
|
<name>S99</name>
|
||||||
<longname>Starter 1999</longname>
|
<longname>Starter 1999</longname>
|
||||||
</set>
|
</set>
|
||||||
<set import="1">
|
<set import="1">
|
||||||
<name>SUM</name>
|
<name>S00</name>
|
||||||
<longname>Summer of Magic</longname>
|
<longname>Starter 2000</longname>
|
||||||
</set>
|
</set>
|
||||||
<set import="1">
|
<set import="1">
|
||||||
<name>SUS</name>
|
<name>STH</name>
|
||||||
<longname>Super Series</longname>
|
<longname>Stronghold</longname>
|
||||||
</set>
|
</set>
|
||||||
<set import="1">
|
<set import="1">
|
||||||
<name>THGT</name>
|
<name>TMP</name>
|
||||||
<longname>Two-Headed Giant Tournament</longname>
|
|
||||||
</set>
|
|
||||||
<set import="1">
|
|
||||||
<name>TP</name>
|
|
||||||
<longname>Tempest</longname>
|
<longname>Tempest</longname>
|
||||||
</set>
|
</set>
|
||||||
<set import="1">
|
<set import="1">
|
||||||
<name>TR</name>
|
<name>10E</name>
|
||||||
<longname>Torment</longname>
|
<longname>Tenth Edition</longname>
|
||||||
</set>
|
</set>
|
||||||
<set import="1">
|
<set import="1">
|
||||||
<name>TS</name>
|
<name>DRK</name>
|
||||||
|
<longname>The Dark</longname>
|
||||||
|
</set>
|
||||||
|
<set import="1">
|
||||||
|
<name>THS</name>
|
||||||
|
<longname>Theros</longname>
|
||||||
|
</set>
|
||||||
|
<set import="1">
|
||||||
|
<name>TSP</name>
|
||||||
<longname>Time Spiral</longname>
|
<longname>Time Spiral</longname>
|
||||||
</set>
|
</set>
|
||||||
<set import="1">
|
<set import="1">
|
||||||
<name>TSTS</name>
|
<name>TSB</name>
|
||||||
<longname>Time Spiral "Timeshifted"</longname>
|
<longname>Time Spiral "Timeshifted"</longname>
|
||||||
</set>
|
</set>
|
||||||
<set import="1">
|
<set import="1">
|
||||||
<name>UD</name>
|
<name>TOR</name>
|
||||||
<longname>Urza's Destiny</longname>
|
<longname>Torment</longname>
|
||||||
</set>
|
</set>
|
||||||
<set import="1">
|
<set import="0">
|
||||||
<name>UG</name>
|
<name>UGL</name>
|
||||||
<longname>Unglued</longname>
|
<longname>Unglued</longname>
|
||||||
</set>
|
</set>
|
||||||
<set import="1">
|
<set import="0">
|
||||||
<name>UHAA</name>
|
<name>UNH</name>
|
||||||
<longname>Unhinged Alternate Foils</longname>
|
|
||||||
</set>
|
|
||||||
<set import="1">
|
|
||||||
<name>UH</name>
|
|
||||||
<longname>Unhinged</longname>
|
<longname>Unhinged</longname>
|
||||||
</set>
|
</set>
|
||||||
<set import="1">
|
<set import="1">
|
||||||
<name>UL</name>
|
<name>2ED</name>
|
||||||
<longname>Urza's Legacy</longname>
|
|
||||||
</set>
|
|
||||||
<set import="1">
|
|
||||||
<name>UN</name>
|
|
||||||
<longname>Unlimited Edition</longname>
|
<longname>Unlimited Edition</longname>
|
||||||
</set>
|
</set>
|
||||||
<set import="1">
|
<set import="1">
|
||||||
<name>UQC</name>
|
<name>UDS</name>
|
||||||
<longname>Celebration Cards</longname>
|
<longname>Urza's Destiny</longname>
|
||||||
</set>
|
</set>
|
||||||
<set import="1">
|
<set import="1">
|
||||||
<name>US</name>
|
<name>ULG</name>
|
||||||
|
<longname>Urza's Legacy</longname>
|
||||||
|
</set>
|
||||||
|
<set import="1">
|
||||||
|
<name>USG</name>
|
||||||
<longname>Urza's Saga</longname>
|
<longname>Urza's Saga</longname>
|
||||||
</set>
|
</set>
|
||||||
<set import="1">
|
<set import="0">
|
||||||
<name>V12</name>
|
<name>VAN</name>
|
||||||
<longname>From the Vault: Realms</longname>
|
<longname>Vanguard</longname>
|
||||||
</set>
|
</set>
|
||||||
<set import="1">
|
<set import="1">
|
||||||
<name>VI</name>
|
<name>VIS</name>
|
||||||
<longname>Visions</longname>
|
<longname>Visions</longname>
|
||||||
</set>
|
</set>
|
||||||
<set import="1">
|
<set import="1">
|
||||||
<name>WL</name>
|
<name>WTH</name>
|
||||||
<longname>Weatherlight</longname>
|
<longname>Weatherlight</longname>
|
||||||
</set>
|
</set>
|
||||||
<set import="1">
|
|
||||||
<name>WMCQ</name>
|
|
||||||
<longname>World Magic Cup Qualifiers</longname>
|
|
||||||
</set>
|
|
||||||
<set import="1">
|
|
||||||
<name>WOTC</name>
|
|
||||||
<longname>WotC Online Store</longname>
|
|
||||||
</set>
|
|
||||||
<set import="1">
|
|
||||||
<name>WRL</name>
|
|
||||||
<longname>Worlds</longname>
|
|
||||||
</set>
|
|
||||||
<set import="1">
|
<set import="1">
|
||||||
<name>WWK</name>
|
<name>WWK</name>
|
||||||
<longname>Worldwake</longname>
|
<longname>Worldwake</longname>
|
||||||
|
|
Binary file not shown.
|
@ -224,7 +224,7 @@ Start the oracle.exe (the installer does this automatically) and let it generate
|
||||||
\end{enumerate}
|
\end{enumerate}
|
||||||
Congratulations, you may now use Cockatrice!
|
Congratulations, you may now use Cockatrice!
|
||||||
|
|
||||||
\subsubsection{Linux and BSD}
|
\subsubsection{Linux, BSD, OS X}
|
||||||
The following procedures have been tested with Debian Wheezy, Fedora 18, XUbuntu 13.10, FreeBSD 9.1 and 10.0.
|
The following procedures have been tested with Debian Wheezy, Fedora 18, XUbuntu 13.10, FreeBSD 9.1 and 10.0.
|
||||||
If you use Gentoo with KDE you have the needed prerequisites and may continue with downloading the source.
|
If you use Gentoo with KDE you have the needed prerequisites and may continue with downloading the source.
|
||||||
If you use Bodhi or Arch Linux (AUR) or another distribution that includes Cockatrice, you might install Cockatrice from the default packages -- though the package might be old,
|
If you use Bodhi or Arch Linux (AUR) or another distribution that includes Cockatrice, you might install Cockatrice from the default packages -- though the package might be old,
|
||||||
|
@ -239,6 +239,7 @@ Before you install new software, you should update your system. The following in
|
||||||
yum install qt-devel qt-mobility-devel protobuf-devel protobuf-compiler cmake}
|
yum install qt-devel qt-mobility-devel protobuf-devel protobuf-compiler cmake}
|
||||||
\item[FreeBSD 9] \shellcmd{pkg\_add -r qt4 qt4-linguist qt4-moc qt4-qmake qt4-rcc qt4-uic git cmake protobuf}
|
\item[FreeBSD 9] \shellcmd{pkg\_add -r qt4 qt4-linguist qt4-moc qt4-qmake qt4-rcc qt4-uic git cmake protobuf}
|
||||||
\item[FreeBSD 10] \shellcmd{pkg install qt4 qt4-linguist qt4-moc qt4-qmake qt4-rcc qt4-uic git cmake protobuf}
|
\item[FreeBSD 10] \shellcmd{pkg install qt4 qt4-linguist qt4-moc qt4-qmake qt4-rcc qt4-uic git cmake protobuf}
|
||||||
|
\item[OS X] \shellcmd{brew install qt cmake protobuf}
|
||||||
\end{description}
|
\end{description}
|
||||||
\item Download the sources from github via \\ \shellcmd{cd\\ git clone https://github.com/Daenyth/Cockatrice.git}
|
\item Download the sources from github via \\ \shellcmd{cd\\ git clone https://github.com/Daenyth/Cockatrice.git}
|
||||||
\item To compile the sources, change into the newly created directory, create a build directory and invoke cmake:\\
|
\item To compile the sources, change into the newly created directory, create a build directory and invoke cmake:\\
|
||||||
|
@ -253,9 +254,6 @@ make}\\
|
||||||
The default paths for decks, pics, cards and tokens are located in \\ \shellcmd{/home/<user>/.local/share/data/Cockatrice/Cockatrice}.
|
The default paths for decks, pics, cards and tokens are located in \\ \shellcmd{/home/<user>/.local/share/data/Cockatrice/Cockatrice}.
|
||||||
\end{enumerate}
|
\end{enumerate}
|
||||||
|
|
||||||
\subsubsection{MacOS X}
|
|
||||||
TODO, please contribute this section! See Linux section, then use the \shellcmd{prepareMacRelease.sh} script from Cockatrice.
|
|
||||||
|
|
||||||
\subsection{Building the Server}
|
\subsection{Building the Server}
|
||||||
You don't need your own server if you plan to play only. But as Cockatrice is open source you are free to run your own.
|
You don't need your own server if you plan to play only. But as Cockatrice is open source you are free to run your own.
|
||||||
The compilation works like already written above, but instead of invoking \shellcmd{cmake ..}, you have to do it like this:
|
The compilation works like already written above, but instead of invoking \shellcmd{cmake ..}, you have to do it like this:
|
||||||
|
@ -706,6 +704,8 @@ USE AT YOUR OWN RISK.
|
||||||
\begin{enumerate}
|
\begin{enumerate}
|
||||||
\item Open a command shell and install the prerequisites
|
\item Open a command shell and install the prerequisites
|
||||||
\begin{enumerate}
|
\begin{enumerate}
|
||||||
|
\item \shellcmd{cd /etc/yum.repos.d/}
|
||||||
|
\item \shellcmd{sudo wget http://kdeforge.unl.edu/apt/kde-redhat/epel/kde.repo}
|
||||||
\item \shellcmd{yum -y groupinstall "development tools"}
|
\item \shellcmd{yum -y groupinstall "development tools"}
|
||||||
\item \shellcmd{rpm -Uvh http://dl.fedoraproject.org/pub/epel/6/x86\_64/epel-release-6-8.noarch.rpm}
|
\item \shellcmd{rpm -Uvh http://dl.fedoraproject.org/pub/epel/6/x86\_64/epel-release-6-8.noarch.rpm}
|
||||||
\item \shellcmd{yum -y install qt-mysql qt-devel qt-mobility-devel protobuf-devel protobuf-compiler cmake28 libgcrypt-devel}
|
\item \shellcmd{yum -y install qt-mysql qt-devel qt-mobility-devel protobuf-devel protobuf-compiler cmake28 libgcrypt-devel}
|
||||||
|
|
|
@ -91,7 +91,7 @@ SectionEnd
|
||||||
|
|
||||||
Section "Start menu item" SecStartMenu
|
Section "Start menu item" SecStartMenu
|
||||||
createDirectory "$SMPROGRAMS\Cockatrice"
|
createDirectory "$SMPROGRAMS\Cockatrice"
|
||||||
createShortCut "$SMPROGRAMS\Cockatrice\Cockatrice.lnk" "$INSTDIR\cockatrice.exe"
|
createShortCut "$SMPROGRAMS\Cockatrice\Cockatrice.lnk" "$INSTDIR\cockatrice.exe" '--debug-output'
|
||||||
createShortCut "$SMPROGRAMS\Cockatrice\Oracle.lnk" "$INSTDIR\oracle.exe"
|
createShortCut "$SMPROGRAMS\Cockatrice\Oracle.lnk" "$INSTDIR\oracle.exe"
|
||||||
createShortCut "$SMPROGRAMS\Cockatrice\Usermanual.lnk" "$INSTDIR\Usermanual.pdf"
|
createShortCut "$SMPROGRAMS\Cockatrice\Usermanual.lnk" "$INSTDIR\Usermanual.pdf"
|
||||||
SectionEnd
|
SectionEnd
|
||||||
|
|
|
@ -9,10 +9,11 @@ set(DESKTOPDIR share/applications CACHE STRING "path to .desktop files")
|
||||||
|
|
||||||
SET(oracle_SOURCES
|
SET(oracle_SOURCES
|
||||||
src/main.cpp
|
src/main.cpp
|
||||||
|
src/oraclewizard.cpp
|
||||||
src/oracleimporter.cpp
|
src/oracleimporter.cpp
|
||||||
src/window_main.cpp
|
|
||||||
../cockatrice/src/carddatabase.cpp
|
../cockatrice/src/carddatabase.cpp
|
||||||
../cockatrice/src/settingscache.cpp
|
../cockatrice/src/settingscache.cpp
|
||||||
|
../cockatrice/src/qt-json/json.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
set(ORACLE_LIBS)
|
set(ORACLE_LIBS)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QTextCodec>
|
#include <QTextCodec>
|
||||||
#include "window_main.h"
|
#include "oraclewizard.h"
|
||||||
#include "settingscache.h"
|
#include "settingscache.h"
|
||||||
|
|
||||||
SettingsCache *settingsCache;
|
SettingsCache *settingsCache;
|
||||||
|
@ -12,13 +12,14 @@ int main(int argc, char *argv[])
|
||||||
QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8"));
|
QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8"));
|
||||||
|
|
||||||
QCoreApplication::setOrganizationName("Cockatrice");
|
QCoreApplication::setOrganizationName("Cockatrice");
|
||||||
QCoreApplication::setOrganizationDomain("cockatrice.de");
|
QCoreApplication::setOrganizationDomain("cockatrice");
|
||||||
|
// this can't be changed, as it influences the default savepath for cards.xml
|
||||||
QCoreApplication::setApplicationName("Cockatrice");
|
QCoreApplication::setApplicationName("Cockatrice");
|
||||||
|
|
||||||
settingsCache = new SettingsCache;
|
settingsCache = new SettingsCache;
|
||||||
|
|
||||||
WindowMain wnd;
|
OracleWizard wizard;
|
||||||
wnd.show();
|
wizard.show();
|
||||||
|
|
||||||
return app.exec();
|
return app.exec();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,330 +1,246 @@
|
||||||
#include "oracleimporter.h"
|
#include "oracleimporter.h"
|
||||||
#if QT_VERSION < 0x050000
|
#if QT_VERSION < 0x050000
|
||||||
#include <QtGui>
|
#include <QtGui>
|
||||||
#else
|
#else
|
||||||
#include <QtWidgets>
|
#include <QtWidgets>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <QtNetwork>
|
|
||||||
#include <QXmlStreamReader>
|
|
||||||
#include <QDomDocument>
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
|
||||||
|
#include "qt-json/json.h"
|
||||||
|
|
||||||
OracleImporter::OracleImporter(const QString &_dataDir, QObject *parent)
|
OracleImporter::OracleImporter(const QString &_dataDir, QObject *parent)
|
||||||
: CardDatabase(parent), dataDir(_dataDir), setIndex(-1)
|
: CardDatabase(parent), dataDir(_dataDir)
|
||||||
{
|
{
|
||||||
buffer = new QBuffer(this);
|
|
||||||
http = new QHttp(this);
|
|
||||||
connect(http, SIGNAL(requestFinished(int, bool)), this, SLOT(httpRequestFinished(int, bool)));
|
|
||||||
connect(http, SIGNAL(responseHeaderReceived(const QHttpResponseHeader &)), this, SLOT(readResponseHeader(const QHttpResponseHeader &)));
|
|
||||||
connect(http, SIGNAL(dataReadProgress(int, int)), this, SIGNAL(dataReadProgress(int, int)));
|
|
||||||
}
|
|
||||||
|
|
||||||
bool OracleImporter::readSetsFromFile(const QString &fileName)
|
|
||||||
{
|
|
||||||
QFile setsFile(fileName);
|
|
||||||
if (!setsFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
|
||||||
QMessageBox::critical(0, tr("Error"), tr("Cannot open file '%1'.").arg(fileName));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
QXmlStreamReader xml(&setsFile);
|
|
||||||
return readSetsFromXml(xml);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool OracleImporter::readSetsFromByteArray(const QByteArray &data)
|
bool OracleImporter::readSetsFromByteArray(const QByteArray &data)
|
||||||
{
|
{
|
||||||
QXmlStreamReader xml(data);
|
QList<SetToDownload> newSetList;
|
||||||
return readSetsFromXml(xml);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool OracleImporter::readSetsFromXml(QXmlStreamReader &xml)
|
bool ok;
|
||||||
{
|
setsMap = QtJson::Json::parse(QString(data), ok).toMap();
|
||||||
QList<SetToDownload> newSetList;
|
if (!ok) {
|
||||||
|
qDebug() << "error: QtJson::Json::parse()";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
QString edition;
|
QListIterator<QVariant> it(setsMap.values());
|
||||||
QString editionLong;
|
QVariantMap map;
|
||||||
QString editionURL;
|
|
||||||
while (!xml.atEnd()) {
|
QString edition;
|
||||||
if (xml.readNext() == QXmlStreamReader::EndElement)
|
QString editionLong;
|
||||||
break;
|
QVariant editionCards;
|
||||||
if (xml.name() == "set") {
|
bool import;
|
||||||
bool import = xml.attributes().value("import").toString().toInt();
|
|
||||||
while (!xml.atEnd()) {
|
while (it.hasNext()) {
|
||||||
if (xml.readNext() == QXmlStreamReader::EndElement)
|
map = it.next().toMap();
|
||||||
break;
|
edition = map.value("code").toString();
|
||||||
if (xml.name() == "name")
|
editionLong = map.value("name").toString();
|
||||||
edition = xml.readElementText();
|
editionCards = map.value("cards");
|
||||||
else if (xml.name() == "longname")
|
|
||||||
editionLong = xml.readElementText();
|
// core and expansion sets are marked to be imported by default
|
||||||
else if (xml.name() == "url")
|
import = (0 == QString::compare(map.value("type").toString(), QString("core"), Qt::CaseInsensitive) ||
|
||||||
editionURL = xml.readElementText();
|
0 == QString::compare(map.value("type").toString(), QString("expansion"), Qt::CaseInsensitive));
|
||||||
}
|
|
||||||
newSetList.append(SetToDownload(edition, editionLong, editionURL, import));
|
newSetList.append(SetToDownload(edition, editionLong, editionCards, import));
|
||||||
edition = editionLong = editionURL = QString();
|
}
|
||||||
} else if (xml.name() == "picture_url")
|
|
||||||
pictureUrl = xml.readElementText();
|
qSort(newSetList);
|
||||||
else if (xml.name() == "picture_url_hq")
|
|
||||||
pictureUrlHq = xml.readElementText();
|
if (newSetList.isEmpty())
|
||||||
else if (xml.name() == "picture_url_st")
|
return false;
|
||||||
pictureUrlSt = xml.readElementText();
|
allSets = newSetList;
|
||||||
else if (xml.name() == "set_url")
|
return true;
|
||||||
setUrl = xml.readElementText();
|
|
||||||
}
|
|
||||||
if (newSetList.isEmpty())
|
|
||||||
return false;
|
|
||||||
allSets = newSetList;
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CardInfo *OracleImporter::addCard(const QString &setName,
|
CardInfo *OracleImporter::addCard(const QString &setName,
|
||||||
QString cardName,
|
QString cardName,
|
||||||
bool isToken,
|
bool isToken,
|
||||||
int cardId,
|
int cardId,
|
||||||
const QString &cardCost,
|
QString &cardCost,
|
||||||
const QString &cardType,
|
const QString &cardType,
|
||||||
const QString &cardPT,
|
const QString &cardPT,
|
||||||
int cardLoyalty,
|
int cardLoyalty,
|
||||||
const QStringList &cardText)
|
const QStringList &cardText)
|
||||||
{
|
{
|
||||||
QString fullCardText = cardText.join("\n");
|
QString fullCardText = cardText.join("\n");
|
||||||
bool splitCard = false;
|
bool splitCard = false;
|
||||||
if (cardName.contains('(')) {
|
if (cardName.contains('(')) {
|
||||||
cardName.remove(QRegExp(" \\(.*\\)"));
|
cardName.remove(QRegExp(" \\(.*\\)"));
|
||||||
splitCard = true;
|
splitCard = true;
|
||||||
}
|
}
|
||||||
// Workaround for card name weirdness
|
// Workaround for card name weirdness
|
||||||
if (cardName.contains("XX"))
|
if (cardName.contains("XX"))
|
||||||
cardName.remove("XX");
|
cardName.remove("XX");
|
||||||
cardName = cardName.replace("Æ", "AE");
|
cardName = cardName.replace("Æ", "AE");
|
||||||
cardName = cardName.replace("’", "'");
|
cardName = cardName.replace("’", "'");
|
||||||
|
|
||||||
CardInfo *card;
|
// Remove {} around mana costs
|
||||||
if (cardHash.contains(cardName)) {
|
cardCost.remove(QChar('{'));
|
||||||
card = cardHash.value(cardName);
|
cardCost.remove(QChar('}'));
|
||||||
if (splitCard && !card->getText().contains(fullCardText))
|
|
||||||
card->setText(card->getText() + "\n---\n" + fullCardText);
|
|
||||||
} else {
|
|
||||||
bool mArtifact = false;
|
|
||||||
if (cardType.endsWith("Artifact"))
|
|
||||||
for (int i = 0; i < cardText.size(); ++i)
|
|
||||||
if (cardText[i].contains("{T}") && cardText[i].contains("to your mana pool"))
|
|
||||||
mArtifact = true;
|
|
||||||
|
|
||||||
QStringList colors;
|
CardInfo *card;
|
||||||
QStringList allColors = QStringList() << "W" << "U" << "B" << "R" << "G";
|
if (cardHash.contains(cardName)) {
|
||||||
for (int i = 0; i < allColors.size(); i++)
|
card = cardHash.value(cardName);
|
||||||
if (cardCost.contains(allColors[i]))
|
if (splitCard && !card->getText().contains(fullCardText))
|
||||||
colors << allColors[i];
|
card->setText(card->getText() + "\n---\n" + fullCardText);
|
||||||
|
} else {
|
||||||
|
bool mArtifact = false;
|
||||||
|
if (cardType.endsWith("Artifact"))
|
||||||
|
for (int i = 0; i < cardText.size(); ++i)
|
||||||
|
if (cardText[i].contains("{T}") && cardText[i].contains("to your mana pool"))
|
||||||
|
mArtifact = true;
|
||||||
|
|
||||||
if (cardText.contains(cardName + " is white."))
|
QStringList colors;
|
||||||
colors << "W";
|
QStringList allColors = QStringList() << "W" << "U" << "B" << "R" << "G";
|
||||||
if (cardText.contains(cardName + " is blue."))
|
for (int i = 0; i < allColors.size(); i++)
|
||||||
colors << "U";
|
if (cardCost.contains(allColors[i]))
|
||||||
if (cardText.contains(cardName + " is black."))
|
colors << allColors[i];
|
||||||
colors << "B";
|
|
||||||
if (cardText.contains(cardName + " is red."))
|
|
||||||
colors << "R";
|
|
||||||
if (cardText.contains(cardName + " is green."))
|
|
||||||
colors << "G";
|
|
||||||
|
|
||||||
bool cipt = (cardText.contains(cardName + " enters the battlefield tapped."));
|
if (cardText.contains(cardName + " is white."))
|
||||||
|
colors << "W";
|
||||||
|
if (cardText.contains(cardName + " is blue."))
|
||||||
|
colors << "U";
|
||||||
|
if (cardText.contains(cardName + " is black."))
|
||||||
|
colors << "B";
|
||||||
|
if (cardText.contains(cardName + " is red."))
|
||||||
|
colors << "R";
|
||||||
|
if (cardText.contains(cardName + " is green."))
|
||||||
|
colors << "G";
|
||||||
|
|
||||||
card = new CardInfo(this, cardName, isToken, cardCost, cardType, cardPT, fullCardText, colors, cardLoyalty, cipt);
|
bool cipt = (cardText.contains(cardName + " enters the battlefield tapped."));
|
||||||
int tableRow = 1;
|
|
||||||
QString mainCardType = card->getMainCardType();
|
|
||||||
if ((mainCardType == "Land") || mArtifact)
|
|
||||||
tableRow = 0;
|
|
||||||
else if ((mainCardType == "Sorcery") || (mainCardType == "Instant"))
|
|
||||||
tableRow = 3;
|
|
||||||
else if (mainCardType == "Creature")
|
|
||||||
tableRow = 2;
|
|
||||||
card->setTableRow(tableRow);
|
|
||||||
|
|
||||||
cardHash.insert(cardName, card);
|
card = new CardInfo(this, cardName, isToken, cardCost, cardType, cardPT, fullCardText, colors, cardLoyalty, cipt);
|
||||||
}
|
int tableRow = 1;
|
||||||
card->setPicURL(setName, getPictureUrl(pictureUrl, cardId, cardName, setName));
|
QString mainCardType = card->getMainCardType();
|
||||||
card->setPicURLHq(setName, getPictureUrl(pictureUrlHq, cardId, cardName, setName));
|
if ((mainCardType == "Land") || mArtifact)
|
||||||
card->setPicURLSt(setName, getPictureUrl(pictureUrlSt, cardId, cardName, setName));
|
tableRow = 0;
|
||||||
return card;
|
else if ((mainCardType == "Sorcery") || (mainCardType == "Instant"))
|
||||||
|
tableRow = 3;
|
||||||
|
else if (mainCardType == "Creature")
|
||||||
|
tableRow = 2;
|
||||||
|
card->setTableRow(tableRow);
|
||||||
|
|
||||||
|
cardHash.insert(cardName, card);
|
||||||
|
}
|
||||||
|
card->setMuId(setName, cardId);
|
||||||
|
|
||||||
|
return card;
|
||||||
}
|
}
|
||||||
|
|
||||||
int OracleImporter::importTextSpoiler(CardSet *set, const QByteArray &data)
|
int OracleImporter::importTextSpoiler(CardSet *set, const QVariant &data)
|
||||||
{
|
{
|
||||||
int cards = 0;
|
int cards = 0;
|
||||||
QString bufferContents(data);
|
|
||||||
|
|
||||||
// Workaround for ampersand bug in text spoilers
|
QListIterator<QVariant> it(data.toList());
|
||||||
int index = -1;
|
QVariantMap map;
|
||||||
while ((index = bufferContents.indexOf('&', index + 1)) != -1) {
|
QString cardName;
|
||||||
int semicolonIndex = bufferContents.indexOf(';', index);
|
QString cardCost;
|
||||||
if (semicolonIndex > 5) {
|
QString cardType;
|
||||||
bufferContents.insert(index + 1, "amp;");
|
QString cardPT;
|
||||||
index += 4;
|
QString cardText;
|
||||||
}
|
int cardId;
|
||||||
}
|
int cardLoyalty;
|
||||||
|
QMap<int, QVariantMap> splitCards;
|
||||||
|
|
||||||
QDomDocument doc;
|
while (it.hasNext()) {
|
||||||
QString errorMsg;
|
map = it.next().toMap();
|
||||||
int errorLine, errorColumn;
|
if(0 == QString::compare(map.value("layout").toString(), QString("split"), Qt::CaseInsensitive))
|
||||||
if (!doc.setContent(bufferContents, &errorMsg, &errorLine, &errorColumn))
|
{
|
||||||
qDebug() << "error:" << errorMsg << "line:" << errorLine << "column:" << errorColumn;
|
// Split card handling
|
||||||
|
cardId = map.contains("multiverseid") ? map.value("multiverseid").toInt() : 0;
|
||||||
|
if(splitCards.contains(cardId))
|
||||||
|
{
|
||||||
|
// merge two split cards
|
||||||
|
QVariantMap tmpMap = splitCards.take(cardId);
|
||||||
|
QVariantMap * card1 = 0, * card2 = 0;
|
||||||
|
// same cardid
|
||||||
|
cardId = map.contains("multiverseid") ? map.value("multiverseid").toInt() : 0;
|
||||||
|
// this is currently an integer; can't accept 2 values
|
||||||
|
cardLoyalty = 0;
|
||||||
|
|
||||||
QDomNodeList divs = doc.elementsByTagName("div");
|
// determine which subcard is the first one in the split
|
||||||
for (int i = 0; i < divs.size(); ++i) {
|
QStringList names=map.contains("names") ? map.value("names").toStringList() : QStringList("");
|
||||||
QDomElement div = divs.at(i).toElement();
|
if(names.count()>0 &&
|
||||||
QDomNode divClass = div.attributes().namedItem("class");
|
map.contains("name") &&
|
||||||
if (divClass.nodeValue() == "textspoiler") {
|
0 == QString::compare(map.value("name").toString(), names.at(0)))
|
||||||
QString cardName, cardCost, cardType, cardPT, cardText;
|
{
|
||||||
int cardId = 0;
|
// map is the left part of the split card, tmpMap is right part
|
||||||
int cardLoyalty = 0;
|
card1 = ↦
|
||||||
|
card2 = &tmpMap;
|
||||||
|
} else {
|
||||||
|
//tmpMap is the left part of the split card, map is right part
|
||||||
|
card1 = &tmpMap;
|
||||||
|
card2 = ↦
|
||||||
|
}
|
||||||
|
|
||||||
QDomNodeList trs = div.elementsByTagName("tr");
|
// add first card's data
|
||||||
for (int j = 0; j < trs.size(); ++j) {
|
cardName = card1->contains("name") ? card1->value("name").toString() : QString("");
|
||||||
QDomElement tr = trs.at(j).toElement();
|
cardCost = card1->contains("manaCost") ? card1->value("manaCost").toString() : QString("");
|
||||||
QDomNodeList tds = tr.elementsByTagName("td");
|
cardType = card1->contains("type") ? card1->value("type").toString() : QString("");
|
||||||
if (tds.size() != 2) {
|
cardPT = card1->contains("power") || card1->contains("toughness") ? card1->value("power").toString() + QString('/') + card1->value("toughness").toString() : QString("");
|
||||||
QStringList cardTextSplit = cardText.split("\n");
|
cardText = card1->contains("text") ? card1->value("text").toString() : QString("");
|
||||||
for (int i = 0; i < cardTextSplit.size(); ++i)
|
|
||||||
cardTextSplit[i] = cardTextSplit[i].trimmed();
|
|
||||||
|
|
||||||
CardInfo *card = addCard(set->getShortName(), cardName, false, cardId, cardCost, cardType, cardPT, cardLoyalty, cardTextSplit);
|
// add second card's data
|
||||||
if (!set->contains(card)) {
|
cardName += card2->contains("name") ? QString(" // ") + card2->value("name").toString() : QString("");
|
||||||
card->addToSet(set);
|
cardCost += card2->contains("manaCost") ? QString(" // ") + card2->value("manaCost").toString() : QString("");
|
||||||
cards++;
|
cardType += card2->contains("type") ? QString(" // ") + card2->value("type").toString() : QString("");
|
||||||
}
|
cardPT += card2->contains("power") || card2->contains("toughness") ? QString(" // ") + card2->value("power").toString() + QString('/') + card2->value("toughness").toString() : QString("");
|
||||||
cardName = cardCost = cardType = cardPT = cardText = QString();
|
cardText += card2->contains("text") ? QString("\n\n---\n\n") + card2->value("text").toString() : QString("");
|
||||||
} else {
|
} else {
|
||||||
QString v1 = tds.at(0).toElement().text().simplified();
|
// first card od a pair; enqueue for later merging
|
||||||
QString v2 = tds.at(1).toElement().text().replace(trUtf8("—"), "-");
|
splitCards.insert(cardId, map);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// normal cards handling
|
||||||
|
cardName = map.contains("name") ? map.value("name").toString() : QString("");
|
||||||
|
cardCost = map.contains("manaCost") ? map.value("manaCost").toString() : QString("");
|
||||||
|
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;
|
||||||
|
cardLoyalty = map.contains("loyalty") ? map.value("loyalty").toInt() : 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (v1 == "Name") {
|
CardInfo *card = addCard(set->getShortName(), cardName, false, cardId, cardCost, cardType, cardPT, cardLoyalty, cardText.split("\n"));
|
||||||
QDomElement a = tds.at(1).toElement().elementsByTagName("a").at(0).toElement();
|
|
||||||
QString href = a.attributes().namedItem("href").nodeValue();
|
if (!set->contains(card)) {
|
||||||
cardId = href.mid(href.indexOf("multiverseid=") + 13).toInt();
|
card->addToSet(set);
|
||||||
cardName = v2.simplified();
|
cards++;
|
||||||
} else if (v1 == "Cost:")
|
}
|
||||||
cardCost = v2.simplified();
|
}
|
||||||
else if (v1 == "Type:")
|
|
||||||
cardType = v2.simplified();
|
return cards;
|
||||||
else if (v1 == "Pow/Tgh:")
|
|
||||||
cardPT = v2.simplified().remove('(').remove(')');
|
|
||||||
else if (v1 == "Rules Text:")
|
|
||||||
cardText = v2.trimmed();
|
|
||||||
else if (v1 == "Loyalty:")
|
|
||||||
cardLoyalty = v2.trimmed().remove('(').remove(')').toInt();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return cards;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QString OracleImporter::getPictureUrl(QString url, int cardId, QString name, const QString &setName) const
|
int OracleImporter::startImport()
|
||||||
{
|
{
|
||||||
if ((name == "Island") || (name == "Swamp") || (name == "Mountain") || (name == "Plains") || (name == "Forest"))
|
clear();
|
||||||
name.append("1");
|
|
||||||
return url.replace("!cardid!", QString::number(cardId)).replace("!set!", setName).replace("!name!", name
|
int setCards = 0, setIndex= 0;
|
||||||
.replace("ö", "o")
|
QListIterator<SetToDownload> it(allSets);
|
||||||
// .remove('\'')
|
const SetToDownload * curSet;
|
||||||
.remove(" // ")
|
|
||||||
// .remove(',')
|
while (it.hasNext())
|
||||||
// .remove(':')
|
{
|
||||||
// .remove('.')
|
curSet = & it.next();
|
||||||
.remove(QRegExp("\\(.*\\)"))
|
if(!curSet->getImport())
|
||||||
.simplified()
|
continue;
|
||||||
// .replace(' ', '_')
|
|
||||||
// .replace('-', '_')
|
CardSet *set = new CardSet(curSet->getShortName(), curSet->getLongName());
|
||||||
);
|
if (!setHash.contains(set->getShortName()))
|
||||||
}
|
setHash.insert(set->getShortName(), set);
|
||||||
|
|
||||||
int OracleImporter::startDownload()
|
int setCards = importTextSpoiler(set, curSet->getCards());
|
||||||
{
|
|
||||||
clear();
|
++setIndex;
|
||||||
|
|
||||||
setsToDownload.clear();
|
emit setIndexChanged(setCards, setIndex, curSet->getLongName());
|
||||||
for (int i = 0; i < allSets.size(); ++i)
|
}
|
||||||
if (allSets[i].getImport())
|
|
||||||
setsToDownload.append(allSets[i]);
|
emit setIndexChanged(setCards, setIndex, QString());
|
||||||
|
|
||||||
if (setsToDownload.isEmpty())
|
// total number of sets
|
||||||
return 0;
|
return setIndex;
|
||||||
setIndex = 0;
|
|
||||||
emit setIndexChanged(0, 0, setsToDownload[0].getLongName());
|
|
||||||
|
|
||||||
downloadNextFile();
|
|
||||||
return setsToDownload.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
void OracleImporter::downloadNextFile()
|
|
||||||
{
|
|
||||||
QString urlString = setsToDownload[setIndex].getUrl();
|
|
||||||
if (urlString.isEmpty())
|
|
||||||
urlString = setUrl;
|
|
||||||
urlString = urlString.replace("!longname!", setsToDownload[setIndex].getLongName());
|
|
||||||
|
|
||||||
if (urlString.startsWith("http://")) {
|
|
||||||
QUrl url(urlString);
|
|
||||||
http->setHost(url.host(), QHttp::ConnectionModeHttp, url.port() == -1 ? 0 : url.port());
|
|
||||||
QString path = QUrl::toPercentEncoding(urlString.mid(url.host().size() + 7).replace(' ', '+'), "?!$&'()*+,;=:@/");
|
|
||||||
|
|
||||||
buffer->close();
|
|
||||||
buffer->setData(QByteArray());
|
|
||||||
buffer->open(QIODevice::ReadWrite | QIODevice::Text);
|
|
||||||
reqId = http->get(path, buffer);
|
|
||||||
} else {
|
|
||||||
QFile file(dataDir + "/" + urlString);
|
|
||||||
file.open(QIODevice::ReadOnly | QIODevice::Text);
|
|
||||||
|
|
||||||
buffer->close();
|
|
||||||
buffer->setData(file.readAll());
|
|
||||||
buffer->open(QIODevice::ReadWrite | QIODevice::Text);
|
|
||||||
reqId = 0;
|
|
||||||
httpRequestFinished(reqId, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void OracleImporter::httpRequestFinished(int requestId, bool error)
|
|
||||||
{
|
|
||||||
if (error) {
|
|
||||||
QMessageBox::information(0, tr("HTTP"), tr("Error."));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (requestId != reqId)
|
|
||||||
return;
|
|
||||||
|
|
||||||
CardSet *set = new CardSet(setsToDownload[setIndex].getShortName(), setsToDownload[setIndex].getLongName());
|
|
||||||
if (!setHash.contains(set->getShortName()))
|
|
||||||
setHash.insert(set->getShortName(), set);
|
|
||||||
|
|
||||||
buffer->seek(0);
|
|
||||||
buffer->close();
|
|
||||||
int cards = importTextSpoiler(set, buffer->data());
|
|
||||||
if (cards > 0)
|
|
||||||
++setIndex;
|
|
||||||
|
|
||||||
if (setIndex == setsToDownload.size()) {
|
|
||||||
emit setIndexChanged(cards, setIndex, QString());
|
|
||||||
setIndex = -1;
|
|
||||||
} else {
|
|
||||||
downloadNextFile();
|
|
||||||
emit setIndexChanged(cards, setIndex, setsToDownload[setIndex].getLongName());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void OracleImporter::readResponseHeader(const QHttpResponseHeader &responseHeader)
|
|
||||||
{
|
|
||||||
switch (responseHeader.statusCode()) {
|
|
||||||
case 200:
|
|
||||||
case 301:
|
|
||||||
case 302:
|
|
||||||
case 303:
|
|
||||||
case 307:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
QMessageBox::information(0, tr("HTTP"), tr("Download failed: %1.").arg(responseHeader.reasonPhrase()));
|
|
||||||
http->abort();
|
|
||||||
deleteLater();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,53 +1,42 @@
|
||||||
#ifndef ORACLEIMPORTER_H
|
#ifndef ORACLEIMPORTER_H
|
||||||
#define ORACLEIMPORTER_H
|
#define ORACLEIMPORTER_H
|
||||||
|
|
||||||
#include <carddatabase.h>
|
#include <QMap>
|
||||||
#include <QHttp>
|
|
||||||
|
|
||||||
class QBuffer;
|
#include <carddatabase.h>
|
||||||
class QXmlStreamReader;
|
|
||||||
|
|
||||||
class SetToDownload {
|
class SetToDownload {
|
||||||
private:
|
private:
|
||||||
QString shortName, longName, url;
|
QString shortName, longName;
|
||||||
bool import;
|
bool import;
|
||||||
|
QVariant cards;
|
||||||
public:
|
public:
|
||||||
const QString &getShortName() const { return shortName; }
|
const QString &getShortName() const { return shortName; }
|
||||||
const QString &getLongName() const { return longName; }
|
const QString &getLongName() const { return longName; }
|
||||||
const QString &getUrl() const { return url; }
|
const QVariant &getCards() const { return cards; }
|
||||||
bool getImport() const { return import; }
|
bool getImport() const { return import; }
|
||||||
void setImport(bool _import) { import = _import; }
|
void setImport(bool _import) { import = _import; }
|
||||||
SetToDownload(const QString &_shortName, const QString &_longName, const QString &_url, bool _import)
|
SetToDownload(const QString &_shortName, const QString &_longName, const QVariant &_cards, bool _import)
|
||||||
: shortName(_shortName), longName(_longName), url(_url), import(_import) { }
|
: shortName(_shortName), longName(_longName), cards(_cards), import(_import) { }
|
||||||
|
bool operator<(const SetToDownload &set) const { return longName.compare(set.longName, Qt::CaseInsensitive) < 0; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class OracleImporter : public CardDatabase {
|
class OracleImporter : public CardDatabase {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
private:
|
private:
|
||||||
QList<SetToDownload> allSets, setsToDownload;
|
QList<SetToDownload> allSets;
|
||||||
QString pictureUrl, pictureUrlHq, pictureUrlSt, setUrl;
|
QVariantMap setsMap;
|
||||||
QString dataDir;
|
QString dataDir;
|
||||||
int setIndex;
|
|
||||||
int reqId;
|
|
||||||
QBuffer *buffer;
|
|
||||||
QHttp *http;
|
|
||||||
QString getPictureUrl(QString url, int cardId, QString name, const QString &setName) const;
|
|
||||||
|
|
||||||
void downloadNextFile();
|
CardInfo *addCard(const QString &setName, QString cardName, bool isToken, int cardId, QString &cardCost, const QString &cardType, const QString &cardPT, int cardLoyalty, const QStringList &cardText);
|
||||||
bool readSetsFromXml(QXmlStreamReader &xml);
|
|
||||||
CardInfo *addCard(const QString &setName, QString cardName, bool isToken, int cardId, const QString &cardCost, const QString &cardType, const QString &cardPT, int cardLoyalty, const QStringList &cardText);
|
|
||||||
private slots:
|
|
||||||
void httpRequestFinished(int requestId, bool error);
|
|
||||||
void readResponseHeader(const QHttpResponseHeader &responseHeader);
|
|
||||||
signals:
|
signals:
|
||||||
void setIndexChanged(int cardsImported, int setIndex, const QString &nextSetName);
|
void setIndexChanged(int cardsImported, int setIndex, const QString &setName);
|
||||||
void dataReadProgress(int bytesRead, int totalBytes);
|
void dataReadProgress(int bytesRead, int totalBytes);
|
||||||
public:
|
public:
|
||||||
OracleImporter(const QString &_dataDir, QObject *parent = 0);
|
OracleImporter(const QString &_dataDir, QObject *parent = 0);
|
||||||
bool readSetsFromByteArray(const QByteArray &data);
|
bool readSetsFromByteArray(const QByteArray &data);
|
||||||
bool readSetsFromFile(const QString &fileName);
|
int startImport();
|
||||||
int startDownload();
|
int importTextSpoiler(CardSet *set, const QVariant &data);
|
||||||
int importTextSpoiler(CardSet *set, const QByteArray &data);
|
|
||||||
QList<SetToDownload> &getSets() { return allSets; }
|
QList<SetToDownload> &getSets() { return allSets; }
|
||||||
const QString &getDataDir() const { return dataDir; }
|
const QString &getDataDir() const { return dataDir; }
|
||||||
};
|
};
|
||||||
|
|
398
oracle/src/oraclewizard.cpp
Normal file
398
oracle/src/oraclewizard.cpp
Normal file
|
@ -0,0 +1,398 @@
|
||||||
|
#include <QtGui>
|
||||||
|
#include <QGridLayout>
|
||||||
|
#include <QDesktopServices>
|
||||||
|
#include <QNetworkAccessManager>
|
||||||
|
#include <QNetworkReply>
|
||||||
|
|
||||||
|
#include "oraclewizard.h"
|
||||||
|
#include "oracleimporter.h"
|
||||||
|
|
||||||
|
#define ALLSETS_URL "http://mtgjson.com/json/AllSets.json"
|
||||||
|
|
||||||
|
OracleWizard::OracleWizard(QWidget *parent)
|
||||||
|
: QWizard(parent)
|
||||||
|
{
|
||||||
|
settings = new QSettings(this);
|
||||||
|
importer = new OracleImporter(QDesktopServices::storageLocation(QDesktopServices::DataLocation), this);
|
||||||
|
|
||||||
|
addPage(new IntroPage);
|
||||||
|
addPage(new LoadSetsPage);
|
||||||
|
addPage(new ChooseSetsPage);
|
||||||
|
addPage(new SaveSetsPage);
|
||||||
|
|
||||||
|
setWindowTitle(tr("Oracle Importer"));
|
||||||
|
QWizard::setButtonText(QWizard::FinishButton, tr("Save"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void OracleWizard::accept()
|
||||||
|
{
|
||||||
|
QDialog::accept();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OracleWizard::enableButtons()
|
||||||
|
{
|
||||||
|
button(QWizard::NextButton)->setDisabled(false);
|
||||||
|
button(QWizard::BackButton)->setDisabled(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OracleWizard::disableButtons()
|
||||||
|
{
|
||||||
|
button(QWizard::NextButton)->setDisabled(true);
|
||||||
|
button(QWizard::BackButton)->setDisabled(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
IntroPage::IntroPage(QWidget *parent)
|
||||||
|
: OracleWizardPage(parent)
|
||||||
|
{
|
||||||
|
setTitle(tr("Introduction"));
|
||||||
|
|
||||||
|
label = new QLabel(tr("This wizard will import the list of sets and cards "
|
||||||
|
"that will be used by Cockatrice. You will need to "
|
||||||
|
"specify an url or a filename that will be used as a "
|
||||||
|
"source, and then choose the wanted sets from the list "
|
||||||
|
"of the available ones."),
|
||||||
|
this);
|
||||||
|
label->setWordWrap(true);
|
||||||
|
|
||||||
|
QVBoxLayout *layout = new QVBoxLayout(this);
|
||||||
|
layout->addWidget(label);
|
||||||
|
setLayout(layout);
|
||||||
|
}
|
||||||
|
|
||||||
|
LoadSetsPage::LoadSetsPage(QWidget *parent)
|
||||||
|
: OracleWizardPage(parent), nam(0)
|
||||||
|
{
|
||||||
|
setTitle(tr("Source selection"));
|
||||||
|
setSubTitle(tr("Please specify a source for the list of sets and cards. "
|
||||||
|
"You can specify an url address that will be download or "
|
||||||
|
"use an existing file from your computer."));
|
||||||
|
|
||||||
|
urlRadioButton = new QRadioButton(tr("Download url:"), this);
|
||||||
|
fileRadioButton = new QRadioButton(tr("Local file:"), this);
|
||||||
|
|
||||||
|
urlLineEdit = new QLineEdit(this);
|
||||||
|
fileLineEdit = new QLineEdit(this);
|
||||||
|
|
||||||
|
progressLabel = new QLabel(this);
|
||||||
|
progressBar = new QProgressBar(this);
|
||||||
|
|
||||||
|
urlRadioButton->setChecked(true);
|
||||||
|
|
||||||
|
fileButton = new QPushButton(tr("Choose file..."), this);
|
||||||
|
connect(fileButton, SIGNAL(clicked()), this, SLOT(actLoadSetsFile()));
|
||||||
|
|
||||||
|
QGridLayout *layout = new QGridLayout(this);
|
||||||
|
layout->addWidget(urlRadioButton, 0, 0);
|
||||||
|
layout->addWidget(urlLineEdit, 0, 1);
|
||||||
|
layout->addWidget(fileRadioButton, 1, 0);
|
||||||
|
layout->addWidget(fileLineEdit, 1, 1);
|
||||||
|
layout->addWidget(fileButton, 2, 1, Qt::AlignRight);
|
||||||
|
layout->addWidget(progressLabel, 3, 0);
|
||||||
|
layout->addWidget(progressBar, 3, 1);
|
||||||
|
|
||||||
|
connect(&watcher, SIGNAL(finished()), this, SLOT(importFinished()));
|
||||||
|
|
||||||
|
setLayout(layout);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LoadSetsPage::initializePage()
|
||||||
|
{
|
||||||
|
urlLineEdit->setText(wizard()->settings->value("allsetsurl", ALLSETS_URL).toString());
|
||||||
|
|
||||||
|
progressLabel->hide();
|
||||||
|
progressBar->hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
void LoadSetsPage::actLoadSetsFile()
|
||||||
|
{
|
||||||
|
QFileDialog dialog(this, tr("Load sets file"));
|
||||||
|
dialog.setFileMode(QFileDialog::ExistingFile);
|
||||||
|
dialog.setNameFilter("Sets JSON file (*.json)");
|
||||||
|
|
||||||
|
if(!fileLineEdit->text().isEmpty() && QFile::exists(fileLineEdit->text()))
|
||||||
|
dialog.selectFile(fileLineEdit->text());
|
||||||
|
|
||||||
|
if (!dialog.exec())
|
||||||
|
return;
|
||||||
|
|
||||||
|
fileLineEdit->setText(dialog.selectedFiles().at(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LoadSetsPage::validatePage()
|
||||||
|
{
|
||||||
|
// once the import is finished, we call next(); skip validation
|
||||||
|
if(wizard()->importer->getSets().count() > 0)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// else, try to import sets
|
||||||
|
if(urlRadioButton->isChecked())
|
||||||
|
{
|
||||||
|
QUrl url = QUrl::fromUserInput(urlLineEdit->text());
|
||||||
|
if(!url.isValid())
|
||||||
|
{
|
||||||
|
QMessageBox::critical(this, tr("Error"), tr("The provided url is not valid."));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
progressLabel->setText(tr("Downloading (0MB)"));
|
||||||
|
// show an infinite progressbar
|
||||||
|
progressBar->setMaximum(0);
|
||||||
|
progressBar->setMinimum(0);
|
||||||
|
progressBar->setValue(0);
|
||||||
|
progressLabel->show();
|
||||||
|
progressBar->show();
|
||||||
|
|
||||||
|
wizard()->disableButtons();
|
||||||
|
setEnabled(false);
|
||||||
|
|
||||||
|
if(!nam)
|
||||||
|
nam = new QNetworkAccessManager(this);
|
||||||
|
QNetworkReply *reply = nam->get(QNetworkRequest(url));
|
||||||
|
|
||||||
|
connect(reply, SIGNAL(finished()), this, SLOT(actDownloadFinishedSetsFile()));
|
||||||
|
connect(reply, SIGNAL(downloadProgress(qint64, qint64)), this, SLOT(actDownloadProgressSetsFile(qint64, qint64)));
|
||||||
|
|
||||||
|
} else if(fileRadioButton->isChecked()) {
|
||||||
|
QFile setsFile(fileLineEdit->text());
|
||||||
|
if(!setsFile.exists())
|
||||||
|
{
|
||||||
|
QMessageBox::critical(this, tr("Error"), tr("Please choose a file."));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!setsFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||||
|
QMessageBox::critical(0, tr("Error"), tr("Cannot open file '%1'.").arg(fileLineEdit->text()));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
wizard()->disableButtons();
|
||||||
|
setEnabled(false);
|
||||||
|
|
||||||
|
readSetsFromByteArray(setsFile.readAll());
|
||||||
|
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LoadSetsPage::actDownloadProgressSetsFile(qint64 received, qint64 total)
|
||||||
|
{
|
||||||
|
if(total > 0 && progressBar->maximum()==0)
|
||||||
|
{
|
||||||
|
progressBar->setMaximum(total);
|
||||||
|
progressBar->setValue(received);
|
||||||
|
}
|
||||||
|
progressLabel->setText(tr("Downloading (%1MB)").arg((int) received / 1048576));
|
||||||
|
}
|
||||||
|
|
||||||
|
void LoadSetsPage::actDownloadFinishedSetsFile()
|
||||||
|
{
|
||||||
|
progressLabel->hide();
|
||||||
|
progressBar->hide();
|
||||||
|
|
||||||
|
// check for a reply
|
||||||
|
QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
|
||||||
|
QNetworkReply::NetworkError errorCode = reply->error();
|
||||||
|
if (errorCode != QNetworkReply::NoError) {
|
||||||
|
QMessageBox::critical(this, tr("Error"), tr("Network error: %1.").arg(reply->errorString()));
|
||||||
|
|
||||||
|
wizard()->enableButtons();
|
||||||
|
setEnabled(true);
|
||||||
|
|
||||||
|
reply->deleteLater();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// save allsets.json url, but only if the user customized it and download was successfull
|
||||||
|
if(urlLineEdit->text() != QString(ALLSETS_URL))
|
||||||
|
wizard()->settings->setValue("allsetsurl", urlLineEdit->text());
|
||||||
|
else
|
||||||
|
wizard()->settings->remove("allsetsurl");
|
||||||
|
|
||||||
|
readSetsFromByteArray(reply->readAll());
|
||||||
|
reply->deleteLater();
|
||||||
|
}
|
||||||
|
|
||||||
|
void LoadSetsPage::readSetsFromByteArray(QByteArray data)
|
||||||
|
{
|
||||||
|
// show an infinite progressbar
|
||||||
|
progressBar->setMaximum(0);
|
||||||
|
progressBar->setMinimum(0);
|
||||||
|
progressBar->setValue(0);
|
||||||
|
progressLabel->setText(tr("Parsing file"));
|
||||||
|
progressLabel->show();
|
||||||
|
progressBar->show();
|
||||||
|
|
||||||
|
// Start the computation.
|
||||||
|
future = QtConcurrent::run(wizard()->importer, &OracleImporter::readSetsFromByteArray, data);
|
||||||
|
watcher.setFuture(future);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LoadSetsPage::importFinished()
|
||||||
|
{
|
||||||
|
wizard()->enableButtons();
|
||||||
|
setEnabled(true);
|
||||||
|
progressLabel->hide();
|
||||||
|
progressBar->hide();
|
||||||
|
|
||||||
|
if(watcher.future().result())
|
||||||
|
{
|
||||||
|
wizard()->next();
|
||||||
|
} else {
|
||||||
|
QMessageBox::critical(this, tr("Error"), tr("The file was retrieved successfully, but it does not contain any sets data."));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ChooseSetsPage::ChooseSetsPage(QWidget *parent)
|
||||||
|
: OracleWizardPage(parent)
|
||||||
|
{
|
||||||
|
setTitle(tr("Sets selection"));
|
||||||
|
setSubTitle(tr("The following sets has been found in the source file. "
|
||||||
|
"Please mark the sets that will be imported."));
|
||||||
|
|
||||||
|
checkBoxLayout = new QVBoxLayout;
|
||||||
|
|
||||||
|
QWidget *checkboxFrame = new QWidget(this);
|
||||||
|
checkboxFrame->setLayout(checkBoxLayout);
|
||||||
|
|
||||||
|
QScrollArea *checkboxArea = new QScrollArea(this);
|
||||||
|
checkboxArea->setWidget(checkboxFrame);
|
||||||
|
checkboxArea->setWidgetResizable(true);
|
||||||
|
|
||||||
|
checkAllButton = new QPushButton(tr("&Check all"));
|
||||||
|
connect(checkAllButton, SIGNAL(clicked()), this, SLOT(actCheckAll()));
|
||||||
|
uncheckAllButton = new QPushButton(tr("&Uncheck all"));
|
||||||
|
connect(uncheckAllButton, SIGNAL(clicked()), this, SLOT(actUncheckAll()));
|
||||||
|
|
||||||
|
QGridLayout *layout = new QGridLayout(this);
|
||||||
|
layout->addWidget(checkboxArea, 0, 0, 1, 2);
|
||||||
|
layout->addWidget(checkAllButton, 1, 0);
|
||||||
|
layout->addWidget(uncheckAllButton, 1, 1);
|
||||||
|
|
||||||
|
setLayout(layout);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChooseSetsPage::initializePage()
|
||||||
|
{
|
||||||
|
// populate checkbox list
|
||||||
|
for (int i = 0; i < checkBoxList.size(); ++i)
|
||||||
|
delete checkBoxList[i];
|
||||||
|
checkBoxList.clear();
|
||||||
|
|
||||||
|
QList<SetToDownload> &sets = wizard()->importer->getSets();
|
||||||
|
for (int i = 0; i < sets.size(); ++i) {
|
||||||
|
QCheckBox *checkBox = new QCheckBox(sets[i].getLongName());
|
||||||
|
checkBox->setChecked(sets[i].getImport());
|
||||||
|
connect(checkBox, SIGNAL(stateChanged(int)), this, SLOT(checkBoxChanged(int)));
|
||||||
|
checkBoxLayout->addWidget(checkBox);
|
||||||
|
checkBoxList << checkBox;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChooseSetsPage::checkBoxChanged(int state)
|
||||||
|
{
|
||||||
|
QCheckBox *checkBox = qobject_cast<QCheckBox *>(sender());
|
||||||
|
QList<SetToDownload> &sets = wizard()->importer->getSets();
|
||||||
|
for (int i = 0; i < sets.size(); ++i)
|
||||||
|
if (sets[i].getLongName() == checkBox->text()) {
|
||||||
|
sets[i].setImport(state);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChooseSetsPage::actCheckAll()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < checkBoxList.size(); ++i)
|
||||||
|
checkBoxList[i]->setChecked(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChooseSetsPage::actUncheckAll()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < checkBoxList.size(); ++i)
|
||||||
|
checkBoxList[i]->setChecked(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ChooseSetsPage::validatePage()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < checkBoxList.size(); ++i)
|
||||||
|
{
|
||||||
|
if(checkBoxList[i]->isChecked())
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
QMessageBox::critical(this, tr("Error"), tr("Please mark at least one set."));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
SaveSetsPage::SaveSetsPage(QWidget *parent)
|
||||||
|
: OracleWizardPage(parent)
|
||||||
|
{
|
||||||
|
setTitle(tr("Sets imported"));
|
||||||
|
setSubTitle(tr("The following sets has been imported. "
|
||||||
|
"Press \"Save\" to save the imported cards to the Cockatrice database."));
|
||||||
|
|
||||||
|
defaultPathCheckBox = new QCheckBox(this);
|
||||||
|
defaultPathCheckBox->setText(tr("Save to the default path (recommended)"));
|
||||||
|
defaultPathCheckBox->setChecked(true);
|
||||||
|
|
||||||
|
messageLog = new QTextEdit(this);
|
||||||
|
messageLog->setReadOnly(true);
|
||||||
|
|
||||||
|
QGridLayout *layout = new QGridLayout(this);
|
||||||
|
layout->addWidget(defaultPathCheckBox, 0, 0);
|
||||||
|
layout->addWidget(messageLog, 1, 0);
|
||||||
|
|
||||||
|
setLayout(layout);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SaveSetsPage::cleanupPage()
|
||||||
|
{
|
||||||
|
disconnect(wizard()->importer, SIGNAL(setIndexChanged(int, int, const QString &)), 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SaveSetsPage::initializePage()
|
||||||
|
{
|
||||||
|
messageLog->clear();
|
||||||
|
|
||||||
|
connect(wizard()->importer, SIGNAL(setIndexChanged(int, int, const QString &)), this, SLOT(updateTotalProgress(int, int, const QString &)));
|
||||||
|
|
||||||
|
if (!wizard()->importer->startImport())
|
||||||
|
QMessageBox::critical(this, tr("Error"), tr("No set has been imported."));
|
||||||
|
}
|
||||||
|
|
||||||
|
void SaveSetsPage::updateTotalProgress(int cardsImported, int setIndex, const QString &setName)
|
||||||
|
{
|
||||||
|
if (setName.isEmpty()) {
|
||||||
|
messageLog->append("<b>" + tr("Import finished: %1 cards.").arg(wizard()->importer->getCardList().size()) + "</b>");
|
||||||
|
} else {
|
||||||
|
messageLog->append(tr("%1: %2 cards imported").arg(setName).arg(cardsImported));
|
||||||
|
}
|
||||||
|
messageLog->verticalScrollBar()->setValue(messageLog->verticalScrollBar()->maximum());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SaveSetsPage::validatePage()
|
||||||
|
{
|
||||||
|
bool ok = false;
|
||||||
|
const QString dataDir = QDesktopServices::storageLocation(QDesktopServices::DataLocation);
|
||||||
|
QDir dir(dataDir);
|
||||||
|
if (!dir.exists())
|
||||||
|
dir.mkpath(dataDir);
|
||||||
|
QString savePath = dataDir + "/cards.xml";
|
||||||
|
do {
|
||||||
|
QString fileName;
|
||||||
|
if (savePath.isEmpty() || !defaultPathCheckBox->isChecked())
|
||||||
|
fileName = QFileDialog::getSaveFileName(this, tr("Save card database"), dataDir + "/cards.xml", tr("XML card database (*.xml)"));
|
||||||
|
else {
|
||||||
|
fileName = savePath;
|
||||||
|
savePath.clear();
|
||||||
|
}
|
||||||
|
if (fileName.isEmpty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (wizard()->importer->saveToFile(fileName))
|
||||||
|
ok = true;
|
||||||
|
else
|
||||||
|
QMessageBox::critical(this, tr("Error"), tr("The file could not be saved to the desired location."));
|
||||||
|
} while (!ok);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
114
oracle/src/oraclewizard.h
Normal file
114
oracle/src/oraclewizard.h
Normal file
|
@ -0,0 +1,114 @@
|
||||||
|
#ifndef ORACLEWIZARD_H
|
||||||
|
#define ORACLEWIZARD_H
|
||||||
|
|
||||||
|
#include <QWizard>
|
||||||
|
#include <QFutureWatcher>
|
||||||
|
#include <QFuture>
|
||||||
|
|
||||||
|
class QCheckBox;
|
||||||
|
class QGroupBox;
|
||||||
|
class QLabel;
|
||||||
|
class QLineEdit;
|
||||||
|
class QRadioButton;
|
||||||
|
class QProgressBar;
|
||||||
|
class QNetworkAccessManager;
|
||||||
|
class QTextEdit;
|
||||||
|
class QVBoxLayout;
|
||||||
|
class OracleImporter;
|
||||||
|
class QSettings;
|
||||||
|
|
||||||
|
class OracleWizard : public QWizard
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
OracleWizard(QWidget *parent = 0);
|
||||||
|
void accept();
|
||||||
|
void enableButtons();
|
||||||
|
void disableButtons();
|
||||||
|
public:
|
||||||
|
OracleImporter *importer;
|
||||||
|
QSettings * settings;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class OracleWizardPage : public QWizardPage
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
OracleWizardPage(QWidget *parent = 0): QWizardPage(parent) {};
|
||||||
|
protected:
|
||||||
|
inline OracleWizard *wizard() { return (OracleWizard*) QWizardPage::wizard(); };
|
||||||
|
};
|
||||||
|
|
||||||
|
class IntroPage : public OracleWizardPage
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
IntroPage(QWidget *parent = 0);
|
||||||
|
private:
|
||||||
|
QLabel *label;
|
||||||
|
};
|
||||||
|
|
||||||
|
class LoadSetsPage : public OracleWizardPage
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
LoadSetsPage(QWidget *parent = 0);
|
||||||
|
protected:
|
||||||
|
void initializePage();
|
||||||
|
bool validatePage();
|
||||||
|
void readSetsFromByteArray(QByteArray data);
|
||||||
|
private:
|
||||||
|
QRadioButton *urlRadioButton;
|
||||||
|
QRadioButton *fileRadioButton;
|
||||||
|
QLineEdit *urlLineEdit;
|
||||||
|
QLineEdit *fileLineEdit;
|
||||||
|
QPushButton *fileButton;
|
||||||
|
QLabel *progressLabel;
|
||||||
|
QProgressBar * progressBar;
|
||||||
|
|
||||||
|
QNetworkAccessManager *nam;
|
||||||
|
QFutureWatcher<bool> watcher;
|
||||||
|
QFuture<bool> future;
|
||||||
|
private slots:
|
||||||
|
void actLoadSetsFile();
|
||||||
|
void actDownloadProgressSetsFile(qint64 received, qint64 total);
|
||||||
|
void actDownloadFinishedSetsFile();
|
||||||
|
void importFinished();
|
||||||
|
};
|
||||||
|
|
||||||
|
class ChooseSetsPage : public OracleWizardPage
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
ChooseSetsPage(QWidget *parent = 0);
|
||||||
|
protected:
|
||||||
|
void initializePage();
|
||||||
|
bool validatePage();
|
||||||
|
private:
|
||||||
|
QPushButton *checkAllButton, *uncheckAllButton;
|
||||||
|
QVBoxLayout *checkBoxLayout;
|
||||||
|
QList<QCheckBox *> checkBoxList;
|
||||||
|
private slots:
|
||||||
|
void actCheckAll();
|
||||||
|
void actUncheckAll();
|
||||||
|
void checkBoxChanged(int state);
|
||||||
|
};
|
||||||
|
|
||||||
|
class SaveSetsPage : public OracleWizardPage
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
SaveSetsPage(QWidget *parent = 0);
|
||||||
|
private:
|
||||||
|
QTextEdit *messageLog;
|
||||||
|
QCheckBox * defaultPathCheckBox;
|
||||||
|
protected:
|
||||||
|
void initializePage();
|
||||||
|
void cleanupPage();
|
||||||
|
bool validatePage();
|
||||||
|
private slots:
|
||||||
|
void updateTotalProgress(int cardsImported, int setIndex, const QString &setName);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -1,256 +0,0 @@
|
||||||
#include <QApplication>
|
|
||||||
#include <QMenu>
|
|
||||||
#include <QMenuBar>
|
|
||||||
#include <QStatusBar>
|
|
||||||
#include <QLineEdit>
|
|
||||||
#include <QFileDialog>
|
|
||||||
#include <QMessageBox>
|
|
||||||
#include <QScrollArea>
|
|
||||||
#include <QTextEdit>
|
|
||||||
#include <QInputDialog>
|
|
||||||
#include <QLabel>
|
|
||||||
#include <QPushButton>
|
|
||||||
#include <QCheckBox>
|
|
||||||
#include <QProgressBar>
|
|
||||||
#include <QVBoxLayout>
|
|
||||||
#include <QDesktopServices>
|
|
||||||
#include <QNetworkAccessManager>
|
|
||||||
#include <QNetworkReply>
|
|
||||||
#include "window_main.h"
|
|
||||||
#include "oracleimporter.h"
|
|
||||||
|
|
||||||
const QString WindowMain::defaultSetsUrl = QString("http://www.woogerworks.com/files/sets.xml");
|
|
||||||
|
|
||||||
WindowMain::WindowMain(QWidget *parent)
|
|
||||||
: QMainWindow(parent)
|
|
||||||
{
|
|
||||||
#if QT_VERSION < 0x050000
|
|
||||||
importer = new OracleImporter(QDesktopServices::storageLocation(QDesktopServices::DataLocation), this);
|
|
||||||
#else
|
|
||||||
importer = new OracleImporter(QStandardPaths::standardLocations(QStandardPaths::DataLocation)).toString(), this);
|
|
||||||
#endif
|
|
||||||
nam = new QNetworkAccessManager(this);
|
|
||||||
|
|
||||||
checkBoxLayout = new QVBoxLayout;
|
|
||||||
|
|
||||||
QWidget *checkboxFrame = new QWidget;
|
|
||||||
checkboxFrame->setLayout(checkBoxLayout);
|
|
||||||
|
|
||||||
QScrollArea *checkboxArea = new QScrollArea;
|
|
||||||
checkboxArea->setWidget(checkboxFrame);
|
|
||||||
checkboxArea->setWidgetResizable(true);
|
|
||||||
|
|
||||||
checkAllButton = new QPushButton(tr("&Check all"));
|
|
||||||
connect(checkAllButton, SIGNAL(clicked()), this, SLOT(actCheckAll()));
|
|
||||||
uncheckAllButton = new QPushButton(tr("&Uncheck all"));
|
|
||||||
connect(uncheckAllButton, SIGNAL(clicked()), this, SLOT(actUncheckAll()));
|
|
||||||
|
|
||||||
QHBoxLayout *checkAllButtonLayout = new QHBoxLayout;
|
|
||||||
checkAllButtonLayout->addWidget(checkAllButton);
|
|
||||||
checkAllButtonLayout->addWidget(uncheckAllButton);
|
|
||||||
|
|
||||||
startButton = new QPushButton(tr("&Start download"));
|
|
||||||
connect(startButton, SIGNAL(clicked()), this, SLOT(actStart()));
|
|
||||||
|
|
||||||
QVBoxLayout *settingsLayout = new QVBoxLayout;
|
|
||||||
settingsLayout->addWidget(checkboxArea);
|
|
||||||
settingsLayout->addLayout(checkAllButtonLayout);
|
|
||||||
settingsLayout->addWidget(startButton);
|
|
||||||
|
|
||||||
totalLabel = new QLabel(tr("Total progress:"));
|
|
||||||
totalProgressBar = new QProgressBar;
|
|
||||||
nextSetLabel1 = new QLabel(tr("Current file:"));
|
|
||||||
nextSetLabel2 = new QLabel;
|
|
||||||
fileLabel = new QLabel(tr("Progress:"));
|
|
||||||
fileProgressBar = new QProgressBar;
|
|
||||||
|
|
||||||
messageLog = new QTextEdit;
|
|
||||||
messageLog->setReadOnly(true);
|
|
||||||
|
|
||||||
QGridLayout *grid = new QGridLayout;
|
|
||||||
grid->addWidget(totalLabel, 0, 0);
|
|
||||||
grid->addWidget(totalProgressBar, 0, 1);
|
|
||||||
grid->addWidget(nextSetLabel1, 1, 0);
|
|
||||||
grid->addWidget(nextSetLabel2, 1, 1);
|
|
||||||
grid->addWidget(fileLabel, 2, 0);
|
|
||||||
grid->addWidget(fileProgressBar, 2, 1);
|
|
||||||
grid->addWidget(messageLog, 3, 0, 1, 2);
|
|
||||||
|
|
||||||
QHBoxLayout *mainLayout = new QHBoxLayout;
|
|
||||||
mainLayout->addLayout(settingsLayout, 6);
|
|
||||||
mainLayout->addSpacing(10);
|
|
||||||
mainLayout->addLayout(grid, 10);
|
|
||||||
|
|
||||||
QWidget *centralWidget = new QWidget;
|
|
||||||
centralWidget->setLayout(mainLayout);
|
|
||||||
setCentralWidget(centralWidget);
|
|
||||||
|
|
||||||
connect(importer, SIGNAL(setIndexChanged(int, int, const QString &)), this, SLOT(updateTotalProgress(int, int, const QString &)));
|
|
||||||
connect(importer, SIGNAL(dataReadProgress(int, int)), this, SLOT(updateFileProgress(int, int)));
|
|
||||||
|
|
||||||
aLoadSetsFile = new QAction(tr("Load sets information from &file..."), this);
|
|
||||||
connect(aLoadSetsFile, SIGNAL(triggered()), this, SLOT(actLoadSetsFile()));
|
|
||||||
aDownloadSetsFile = new QAction(tr("&Download sets information..."), this);
|
|
||||||
connect(aDownloadSetsFile, SIGNAL(triggered()), this, SLOT(actDownloadSetsFile()));
|
|
||||||
aExit = new QAction(tr("E&xit"), this);
|
|
||||||
connect(aExit, SIGNAL(triggered()), this, SLOT(close()));
|
|
||||||
|
|
||||||
fileMenu = menuBar()->addMenu(tr("&File"));
|
|
||||||
fileMenu->addAction(aLoadSetsFile);
|
|
||||||
fileMenu->addAction(aDownloadSetsFile);
|
|
||||||
fileMenu->addSeparator();
|
|
||||||
fileMenu->addAction(aExit);
|
|
||||||
|
|
||||||
setWindowTitle(tr("Oracle importer"));
|
|
||||||
setMinimumSize(750, 500);
|
|
||||||
|
|
||||||
QStringList args = qApp->arguments();
|
|
||||||
if (args.contains("-dlsets"))
|
|
||||||
downloadSetsFile(defaultSetsUrl);
|
|
||||||
|
|
||||||
statusLabel = new QLabel;
|
|
||||||
statusBar()->addWidget(statusLabel);
|
|
||||||
statusLabel->setText(tr("Sets data not loaded."));
|
|
||||||
}
|
|
||||||
|
|
||||||
void WindowMain::updateSetList()
|
|
||||||
{
|
|
||||||
for (int i = 0; i < checkBoxList.size(); ++i)
|
|
||||||
delete checkBoxList[i];
|
|
||||||
checkBoxList.clear();
|
|
||||||
|
|
||||||
QList<SetToDownload> &sets = importer->getSets();
|
|
||||||
for (int i = 0; i < sets.size(); ++i) {
|
|
||||||
QCheckBox *checkBox = new QCheckBox(sets[i].getLongName());
|
|
||||||
checkBox->setChecked(sets[i].getImport());
|
|
||||||
connect(checkBox, SIGNAL(stateChanged(int)), this, SLOT(checkBoxChanged(int)));
|
|
||||||
checkBoxLayout->addWidget(checkBox);
|
|
||||||
checkBoxList << checkBox;
|
|
||||||
}
|
|
||||||
statusLabel->setText(tr("Ready."));
|
|
||||||
}
|
|
||||||
|
|
||||||
void WindowMain::actLoadSetsFile()
|
|
||||||
{
|
|
||||||
QFileDialog dialog(this, tr("Load sets file"));
|
|
||||||
dialog.setFileMode(QFileDialog::ExistingFile);
|
|
||||||
dialog.setNameFilter("Sets XML file (*.xml)");
|
|
||||||
if (!dialog.exec())
|
|
||||||
return;
|
|
||||||
|
|
||||||
QString fileName = dialog.selectedFiles().at(0);
|
|
||||||
if (importer->readSetsFromFile(fileName))
|
|
||||||
updateSetList();
|
|
||||||
else
|
|
||||||
QMessageBox::critical(this, tr("Error"), tr("This file does not contain any sets data."));
|
|
||||||
}
|
|
||||||
|
|
||||||
void WindowMain::actDownloadSetsFile()
|
|
||||||
{
|
|
||||||
QString url = QInputDialog::getText(this, tr("Load sets from URL"), tr("Please enter the URL of the sets file:"), QLineEdit::Normal, defaultSetsUrl);
|
|
||||||
if (!url.isEmpty())
|
|
||||||
downloadSetsFile(url);
|
|
||||||
}
|
|
||||||
|
|
||||||
void WindowMain::downloadSetsFile(const QString &url)
|
|
||||||
{
|
|
||||||
QNetworkReply *reply = nam->get(QNetworkRequest(url));
|
|
||||||
connect(reply, SIGNAL(finished()), this, SLOT(setsDownloadFinished()));
|
|
||||||
}
|
|
||||||
|
|
||||||
void WindowMain::setsDownloadFinished()
|
|
||||||
{
|
|
||||||
QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
|
|
||||||
QNetworkReply::NetworkError errorCode = reply->error();
|
|
||||||
if (errorCode == QNetworkReply::NoError) {
|
|
||||||
if (importer->readSetsFromByteArray(reply->readAll()))
|
|
||||||
updateSetList();
|
|
||||||
else
|
|
||||||
QMessageBox::critical(this, tr("Error"), tr("The file was retrieved successfully, but it does not contain any sets data."));
|
|
||||||
} else
|
|
||||||
QMessageBox::critical(this, tr("Error"), tr("Network error: %1.").arg(reply->errorString()));
|
|
||||||
reply->deleteLater();
|
|
||||||
}
|
|
||||||
|
|
||||||
void WindowMain::updateTotalProgress(int cardsImported, int setIndex, const QString &nextSetName)
|
|
||||||
{
|
|
||||||
if (setIndex != 0)
|
|
||||||
messageLog->append(QString("%1: %2 cards imported").arg(nextSetLabel2->text()).arg(cardsImported));
|
|
||||||
totalProgressBar->setValue(setIndex);
|
|
||||||
if (nextSetName.isEmpty()) {
|
|
||||||
QMessageBox::information(this, tr("Oracle importer"), tr("Import finished: %1 cards.").arg(importer->getCardList().size()));
|
|
||||||
bool ok = false;
|
|
||||||
#if QT_VERSION < 0x050000
|
|
||||||
const QString dataDir = QDesktopServices::storageLocation(QDesktopServices::DataLocation);
|
|
||||||
#else
|
|
||||||
const QString dataDir = QStandardPaths::standardLocations(QStandardPaths::DataLocation)).toString();
|
|
||||||
#endif
|
|
||||||
QDir dir(dataDir);
|
|
||||||
if (!dir.exists())
|
|
||||||
dir.mkpath(dataDir);
|
|
||||||
QString savePath = dataDir + "/cards.xml";
|
|
||||||
do {
|
|
||||||
QString fileName;
|
|
||||||
if (savePath.isEmpty())
|
|
||||||
fileName = QFileDialog::getSaveFileName(this, tr("Save card database"), dataDir + "/cards.xml", tr("XML card database (*.xml)"));
|
|
||||||
else {
|
|
||||||
fileName = savePath;
|
|
||||||
savePath.clear();
|
|
||||||
}
|
|
||||||
if (fileName.isEmpty()) {
|
|
||||||
qApp->quit();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (importer->saveToFile(fileName))
|
|
||||||
ok = true;
|
|
||||||
else
|
|
||||||
QMessageBox::critical(this, tr("Error"), tr("The file could not be saved to the desired location."));
|
|
||||||
} while (!ok);
|
|
||||||
qApp->quit();
|
|
||||||
} else {
|
|
||||||
nextSetLabel2->setText(nextSetName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void WindowMain::updateFileProgress(int bytesRead, int totalBytes)
|
|
||||||
{
|
|
||||||
fileProgressBar->setMaximum(totalBytes);
|
|
||||||
fileProgressBar->setValue(bytesRead);
|
|
||||||
}
|
|
||||||
|
|
||||||
void WindowMain::actCheckAll()
|
|
||||||
{
|
|
||||||
for (int i = 0; i < checkBoxList.size(); ++i)
|
|
||||||
checkBoxList[i]->setChecked(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void WindowMain::actUncheckAll()
|
|
||||||
{
|
|
||||||
for (int i = 0; i < checkBoxList.size(); ++i)
|
|
||||||
checkBoxList[i]->setChecked(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
void WindowMain::actStart()
|
|
||||||
{
|
|
||||||
int setsCount = importer->startDownload();
|
|
||||||
if (!setsCount) {
|
|
||||||
QMessageBox::critical(this, tr("Error"), tr("No sets to download selected."));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
for (int i = 0; i < checkBoxList.size(); ++i)
|
|
||||||
checkBoxList[i]->setEnabled(false);
|
|
||||||
startButton->setEnabled(false);
|
|
||||||
totalProgressBar->setMaximum(setsCount);
|
|
||||||
statusLabel->setText(tr("Downloading card data..."));
|
|
||||||
}
|
|
||||||
|
|
||||||
void WindowMain::checkBoxChanged(int state)
|
|
||||||
{
|
|
||||||
QCheckBox *checkBox = qobject_cast<QCheckBox *>(sender());
|
|
||||||
QList<SetToDownload> &sets = importer->getSets();
|
|
||||||
for (int i = 0; i < sets.size(); ++i)
|
|
||||||
if (sets[i].getLongName() == checkBox->text()) {
|
|
||||||
sets[i].setImport(state);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,52 +0,0 @@
|
||||||
#ifndef WINDOW_MAIN_H
|
|
||||||
#define WINDOW_MAIN_H
|
|
||||||
|
|
||||||
#include <QMainWindow>
|
|
||||||
#include <QList>
|
|
||||||
|
|
||||||
class OracleImporter;
|
|
||||||
class QLabel;
|
|
||||||
class QProgressBar;
|
|
||||||
class QTextEdit;
|
|
||||||
class QPushButton;
|
|
||||||
class QCheckBox;
|
|
||||||
class QVBoxLayout;
|
|
||||||
class QMenu;
|
|
||||||
class QAction;
|
|
||||||
class QNetworkAccessManager;
|
|
||||||
|
|
||||||
class WindowMain : public QMainWindow {
|
|
||||||
Q_OBJECT
|
|
||||||
private:
|
|
||||||
static const QString defaultSetsUrl;
|
|
||||||
|
|
||||||
OracleImporter *importer;
|
|
||||||
QNetworkAccessManager *nam;
|
|
||||||
|
|
||||||
QMenu *fileMenu;
|
|
||||||
QAction *aLoadSetsFile, *aDownloadSetsFile, *aExit;
|
|
||||||
QPushButton *checkAllButton, *uncheckAllButton, *startButton;
|
|
||||||
QLabel *totalLabel, *fileLabel, *nextSetLabel1, *nextSetLabel2;
|
|
||||||
QProgressBar *totalProgressBar, *fileProgressBar;
|
|
||||||
QTextEdit *messageLog;
|
|
||||||
QVBoxLayout *checkBoxLayout;
|
|
||||||
QList<QCheckBox *> checkBoxList;
|
|
||||||
QLabel *statusLabel;
|
|
||||||
|
|
||||||
void downloadSetsFile(const QString &url);
|
|
||||||
private slots:
|
|
||||||
void updateTotalProgress(int cardsImported, int setIndex, const QString &nextSetName);
|
|
||||||
void updateFileProgress(int bytesRead, int totalBytes);
|
|
||||||
void updateSetList();
|
|
||||||
void actCheckAll();
|
|
||||||
void actUncheckAll();
|
|
||||||
void actStart();
|
|
||||||
void actLoadSetsFile();
|
|
||||||
void actDownloadSetsFile();
|
|
||||||
void setsDownloadFinished();
|
|
||||||
void checkBoxChanged(int state);
|
|
||||||
public:
|
|
||||||
WindowMain(QWidget *parent = 0);
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
Loading…
Reference in a new issue