merged with master

This commit is contained in:
Fabio Bas
2015-08-31 22:48:14 +02:00
416 changed files with 65983 additions and 19400 deletions

View File

@@ -65,39 +65,37 @@ CardInfo *OracleImporter::addCard(const QString &setName,
const QString &cardPT,
int cardLoyalty,
const QString &cardText,
const QStringList & colors)
const QStringList & colors,
const QStringList & relatedCards,
bool upsideDown
)
{
QStringList cardTextRows = cardText.split("\n");
bool splitCard = false;
if (cardName.contains('(')) {
cardName.remove(QRegExp(" \\(.*\\)"));
splitCard = true;
}
// Workaround for card name weirdness
if (cardName.contains("XX"))
cardName.remove("XX");
cardName = cardName.replace("Æ", "AE");
cardName = cardName.replace("", "'");
// Remove {} around mana costs
cardCost.remove(QChar('{'));
cardCost.remove(QChar('}'));
CardInfo *card;
CardInfo * card;
if (cards.contains(cardName)) {
card = cards.value(cardName);
if (splitCard && !card->getText().contains(cardText))
card->setText(card->getText() + "\n---\n" + cardText);
} else {
// Remove {} around mana costs
cardCost.remove(QChar('{'));
cardCost.remove(QChar('}'));
// detect mana generator artifacts
bool mArtifact = false;
if (cardType.endsWith("Artifact"))
for (int i = 0; i < cardTextRows.size(); ++i)
if (cardTextRows[i].contains("{T}") && cardTextRows[i].contains("to your mana pool"))
mArtifact = true;
// detect cards that enter the field tapped
bool cipt = cardText.contains("Hideaway") || (cardText.contains(cardName + " enters the battlefield tapped") && !cardText.contains(cardName + " enters the battlefield tapped unless"));
card = new CardInfo(this, cardName, isToken, cardCost, cmc, cardType, cardPT, cardText, colors, cardLoyalty, cipt);
// insert the card and its properties
card = new CardInfo(this, cardName, isToken, cardCost, cmc, cardType, cardPT, cardText, colors, relatedCards, upsideDown, cardLoyalty, cipt);
int tableRow = 1;
QString mainCardType = card->getMainCardType();
if ((mainCardType == "Land") || mArtifact)
@@ -147,101 +145,149 @@ int OracleImporter::importTextSpoiler(CardSet *set, const QVariant &data)
QString cardPT;
QString cardText;
QStringList colors;
QStringList relatedCards;
int cardId;
int cardLoyalty;
bool cardIsToken = false;
bool upsideDown = false;
QMap<int, QVariantMap> splitCards;
while (it.hasNext()) {
while (it.hasNext())
{
map = it.next().toMap();
if(0 == QString::compare(map.value("layout").toString(), QString("split"), Qt::CaseInsensitive))
QString layout = map.value("layout").toString();
if(layout == "token")
continue;
if(layout == "split")
{
// Split card handling
// Enqueue split card for later 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;
// determine which subcard is the first one in the split
QStringList names=map.contains("names") ? map.value("names").toStringList() : QStringList("");
if(names.count()>0 &&
map.contains("name") &&
0 == QString::compare(map.value("name").toString(), names.at(0)))
{
// map is the left part of the split card, tmpMap is right part
card1 = &map;
card2 = &tmpMap;
} else {
//tmpMap is the left part of the split card, map is right part
card1 = &tmpMap;
card2 = &map;
}
// add first card's data
cardName = card1->contains("name") ? card1->value("name").toString() : QString("");
cardCost = card1->contains("manaCost") ? card1->value("manaCost").toString() : QString("");
cmc = card1->contains("cmc") ? card1->value("cmc").toString() : QString("0");
cardType = card1->contains("type") ? card1->value("type").toString() : QString("");
cardPT = card1->contains("power") || card1->contains("toughness") ? card1->value("power").toString() + QString('/') + card1->value("toughness").toString() : QString("");
cardText = card1->contains("text") ? card1->value("text").toString() : QString("");
// add second card's data
cardName += card2->contains("name") ? QString(" // ") + card2->value("name").toString() : QString("");
cardCost += card2->contains("manaCost") ? QString(" // ") + card2->value("manaCost").toString() : QString("");
cmc += card2->contains("cmc") ? QString(" // ") + card2->value("cmc").toString() : QString("0");
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("");
cardText += card2->contains("text") ? QString("\n\n---\n\n") + card2->value("text").toString() : QString("");
colors.clear();
extractColors(card1->value("colors").toStringList(), colors);
extractColors(card2->value("colors").toStringList(), colors);
colors.removeDuplicates();
} else {
// first card of a pair; enqueue for later merging
// Conditional on cardId because promo prints have no muid - see #640
if (cardId)
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("");
cmc = map.contains("cmc") ? map.value("cmc").toString() : QString("0");
cardType = map.contains("type") ? map.value("type").toString() : QString("");
cardPT = map.contains("power") || map.contains("toughness") ? map.value("power").toString() + QString('/') + map.value("toughness").toString() : QString("");
cardText = map.contains("text") ? map.value("text").toString() : QString("");
cardId = map.contains("multiverseid") ? map.value("multiverseid").toInt() : 0;
cardLoyalty = map.contains("loyalty") ? map.value("loyalty").toInt() : 0;
cardIsToken = map.value("layout") == "token";
colors.clear();
extractColors(map.value("colors").toStringList(), colors);
// Distinguish Vanguard cards from regular cards of the same name.
if (map.value("layout") == "vanguard") {
cardName += " Avatar";
}
if (cardId)
splitCards.insertMulti(cardId, map);
continue;
}
if (!cardIsToken) {
CardInfo *card = addCard(set->getShortName(), cardName, cardIsToken, cardId, cardCost, cmc, cardType, cardPT, cardLoyalty, cardText, colors);
// normal cards handling
cardName = map.contains("name") ? map.value("name").toString() : QString("");
cardCost = map.contains("manaCost") ? map.value("manaCost").toString() : QString("");
cmc = map.contains("cmc") ? map.value("cmc").toString() : QString("0");
cardType = map.contains("type") ? map.value("type").toString() : QString("");
cardPT = map.contains("power") || map.contains("toughness") ? map.value("power").toString() + QString('/') + map.value("toughness").toString() : QString("");
cardText = map.contains("text") ? map.value("text").toString() : QString("");
cardId = map.contains("multiverseid") ? map.value("multiverseid").toInt() : 0;
cardLoyalty = map.contains("loyalty") ? map.value("loyalty").toInt() : 0;
relatedCards = map.contains("names") ? map.value("names").toStringList() : QStringList();
relatedCards.removeAll(cardName);
if (!set->contains(card)) {
card->addToSet(set);
cards++;
}
if(0 == QString::compare(map.value("layout").toString(), QString("flip"), Qt::CaseInsensitive))
{
QStringList cardNames = map.contains("names") ? map.value("names").toStringList() : QStringList();
upsideDown = (cardNames.indexOf(cardName) > 0);
} else {
upsideDown = false;
}
colors.clear();
extractColors(map.value("colors").toStringList(), colors);
CardInfo *card = addCard(set->getShortName(), cardName, false, cardId, cardCost, cmc, cardType, cardPT, cardLoyalty, cardText, colors, relatedCards, upsideDown);
if (!set->contains(card)) {
card->addToSet(set);
cards++;
}
}
// split cards handling - get all unique card muids
QList<int> muids = splitCards.uniqueKeys();
foreach(int muid, muids)
{
// get all cards for this specific muid
QList<QVariantMap> maps = splitCards.values(muid);
QStringList names;
// now, reorder the cards using the ordered list of names
QMap<int, QVariantMap> orderedMaps;
foreach(QVariantMap map, maps)
{
if(names.isEmpty())
names = map.contains("names") ? map.value("names").toStringList() : QStringList();
QString name = map.value("name").toString();
int index = names.indexOf(name);
orderedMaps.insertMulti(index, map);
}
// clean variables
cardName = "";
cardCost = "";
cmc = "";
cardType = "";
cardPT = "";
cardText = "";
colors.clear();
// this is currently an integer; can't accept 2 values
cardLoyalty = 0;
// loop cards and merge their contents
QString prefix = QString(" // ");
QString prefix2 = QString("\n\n---\n\n");
foreach(QVariantMap map, orderedMaps.values())
{
if(map.contains("name"))
{
if(!cardName.isEmpty())
cardName += prefix;
cardName += map.value("name").toString();
}
if(map.contains("manaCost"))
{
if(!cardCost.isEmpty())
cardCost += prefix;
cardCost += map.value("manaCost").toString();
}
if(map.contains("cmc"))
{
if(!cmc.isEmpty())
cmc += prefix;
cmc += map.value("cmc").toString();
}
if(map.contains("type"))
{
if(!cardType.isEmpty())
cardType += prefix;
cardType += map.value("type").toString();
}
if(map.contains("power") || map.contains("toughness"))
{
if(!cardPT.isEmpty())
cardPT += prefix;
cardPT += map.value("power").toString() + QString('/') + map.value("toughness").toString();
}
if(map.contains("text"))
{
if(!cardText.isEmpty())
cardText += prefix2;
cardText += map.value("text").toString();
}
extractColors(map.value("colors").toStringList(), colors);
}
colors.removeDuplicates();
relatedCards = QStringList();
upsideDown = false;
// add the card
CardInfo *card = addCard(set->getShortName(), cardName, false, muid, cardCost, cmc, cardType, cardPT, cardLoyalty, cardText, colors, relatedCards, upsideDown);
if (!set->contains(card)) {
card->addToSet(set);
cards++;
}
}
return cards;
}

View File

@@ -29,7 +29,7 @@ private:
QVariantMap setsMap;
QString dataDir;
CardInfo *addCard(const QString &setName, QString cardName, bool isToken, int cardId, QString &cardCost, QString &cmc, const QString &cardType, const QString &cardPT, int cardLoyalty, const QString &cardText, const QStringList & colors);
CardInfo *addCard(const QString &setName, QString cardName, bool isToken, int cardId, QString &cardCost, QString &cmc, const QString &cardType, const QString &cardPT, int cardLoyalty, const QString &cardText, const QStringList & colors, const QStringList & relatedCards, bool upsideDown);
signals:
void setIndexChanged(int cardsImported, int setIndex, const QString &setName);
void dataReadProgress(int bytesRead, int totalBytes);

View File

@@ -39,6 +39,8 @@
#define ALLSETS_URL "http://mtgjson.com/json/AllSets.json"
#endif
#define TOKENS_URL "https://raw.githubusercontent.com/Cockatrice/Magic-Token/master/tokens.xml"
OracleWizard::OracleWizard(QWidget *parent)
: QWizard(parent)
@@ -57,6 +59,8 @@ OracleWizard::OracleWizard(QWidget *parent)
addPage(new IntroPage);
addPage(new LoadSetsPage);
addPage(new SaveSetsPage);
addPage(new LoadTokensPage);
addPage(new SaveTokensPage);
retranslateUi();
}
@@ -100,6 +104,23 @@ void OracleWizard::disableButtons()
button(QWizard::BackButton)->setDisabled(true);
}
bool OracleWizard::saveTokensToFile(const QString & fileName)
{
QFile file(fileName);
if(!file.open(QIODevice::WriteOnly))
{
qDebug() << "File open (w) failed for" << fileName;
return false;
}
if(file.write(tokensData) == -1)
{
qDebug() << "File write (w) failed for" << fileName;
return false;
}
file.close();
return true;
}
IntroPage::IntroPage(QWidget *parent)
: OracleWizardPage(parent)
{
@@ -150,11 +171,10 @@ void IntroPage::languageBoxChanged(int index)
void IntroPage::retranslateUi()
{
setTitle(tr("Introduction"));
label->setText(tr("This wizard will import the list of sets and cards "
"that will be used by Cockatrice.<br/>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."));
label->setText(tr("This wizard will import the list of sets, cards, and tokens "
"that will be used by Cockatrice."
"\nYou will need to specify a URL or a filename that "
"will be used as a source."));
languageLabel->setText(tr("Language:"));
}
@@ -205,12 +225,12 @@ void LoadSetsPage::retranslateUi()
{
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 "
"You can specify a URL address that will be downloaded or "
"use an existing file from your computer."));
urlRadioButton->setText(tr("Download url:"));
urlRadioButton->setText(tr("Download URL:"));
fileRadioButton->setText(tr("Local file:"));
urlButton->setText(tr("Restore default url"));
urlButton->setText(tr("Restore default URL"));
fileButton->setText(tr("Choose file..."));
}
@@ -251,7 +271,7 @@ bool LoadSetsPage::validatePage()
QUrl url = QUrl::fromUserInput(urlLineEdit->text());
if(!url.isValid())
{
QMessageBox::critical(this, tr("Error"), tr("The provided url is not valid."));
QMessageBox::critical(this, tr("Error"), tr("The provided URL is not valid."));
return false;
}
@@ -302,7 +322,7 @@ void LoadSetsPage::actDownloadProgressSetsFile(qint64 received, qint64 total)
progressBar->setMaximum(total);
progressBar->setValue(received);
}
progressLabel->setText(tr("Downloading (%1MB)").arg((int) received / 1048576));
progressLabel->setText(tr("Downloading (%1MB)").arg((int) received / (1024 * 1024)));
}
void LoadSetsPage::actDownloadFinishedSetsFile()
@@ -529,3 +549,203 @@ bool SaveSetsPage::validatePage()
return true;
}
LoadTokensPage::LoadTokensPage(QWidget *parent)
: OracleWizardPage(parent), nam(0)
{
urlLabel = new QLabel(this);
urlLineEdit = new QLineEdit(this);
progressLabel = new QLabel(this);
progressBar = new QProgressBar(this);
urlButton = new QPushButton(this);
connect(urlButton, SIGNAL(clicked()), this, SLOT(actRestoreDefaultUrl()));
QGridLayout *layout = new QGridLayout(this);
layout->addWidget(urlLabel, 0, 0);
layout->addWidget(urlLineEdit, 0, 1);
layout->addWidget(urlButton, 1, 1, Qt::AlignRight);
layout->addWidget(progressLabel, 2, 0);
layout->addWidget(progressBar, 2, 1);
setLayout(layout);
}
void LoadTokensPage::initializePage()
{
urlLineEdit->setText(wizard()->settings->value("tokensurl", TOKENS_URL).toString());
progressLabel->hide();
progressBar->hide();
}
void LoadTokensPage::retranslateUi()
{
setTitle(tr("Tokens source selection"));
setSubTitle(tr("Please specify a source for the list of tokens. "
"You can specify a URL address that will be downloaded or "
"use an existing file from your computer."));
urlLabel->setText(tr("Download URL:"));
urlButton->setText(tr("Restore default URL"));
}
void LoadTokensPage::actRestoreDefaultUrl()
{
urlLineEdit->setText(TOKENS_URL);
}
bool LoadTokensPage::validatePage()
{
// once the import is finished, we call next(); skip validation
if(wizard()->hasTokensData())
return true;
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(actDownloadFinishedTokensFile()));
connect(reply, SIGNAL(downloadProgress(qint64, qint64)), this, SLOT(actDownloadProgressTokensFile(qint64, qint64)));
return false;
}
void LoadTokensPage::actDownloadProgressTokensFile(qint64 received, qint64 total)
{
if(total > 0)
{
progressBar->setMaximum(total);
progressBar->setValue(received);
}
progressLabel->setText(tr("Downloading (%1MB)").arg((int) received / (1024 * 1024)));
}
void LoadTokensPage::actDownloadFinishedTokensFile()
{
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 tokens.xml url, but only if the user customized it and download was successfull
if(urlLineEdit->text() != QString(TOKENS_URL))
wizard()->settings->setValue("tokensurl", urlLineEdit->text());
else
wizard()->settings->remove("tokensurl");
wizard()->setTokensData(reply->readAll());
reply->deleteLater();
wizard()->enableButtons();
setEnabled(true);
progressLabel->hide();
progressBar->hide();
wizard()->next();
}
SaveTokensPage::SaveTokensPage(QWidget *parent)
: OracleWizardPage(parent)
{
defaultPathCheckBox = new QCheckBox(this);
defaultPathCheckBox->setChecked(true);
QGridLayout *layout = new QGridLayout(this);
layout->addWidget(defaultPathCheckBox, 0, 0);
setLayout(layout);
}
void SaveTokensPage::retranslateUi()
{
setTitle(tr("Tokens imported"));
setSubTitle(tr("The tokens has been imported. "
"Press \"Save\" to save the imported tokens to the Cockatrice tokens database."));
defaultPathCheckBox->setText(tr("Save to the default path (recommended)"));
}
bool SaveTokensPage::validatePage()
{
bool ok = false;
const QString dataDir =
#if QT_VERSION < 0x050000
QDesktopServices::storageLocation(QDesktopServices::DataLocation);
#else
QStandardPaths::standardLocations(QStandardPaths::DataLocation).first();
#endif
QSettings* settings = new QSettings(this);
QString defaultPath = settings->value("paths/tokendatabase").toString();
QString windowName = tr("Save token database");
QString fileType = tr("XML; token database (*.xml)");
do {
QString fileName;
if (defaultPath.isEmpty()) {
if (defaultPathCheckBox->isChecked())
fileName = dataDir + "/tokens.xml";
else
fileName = QFileDialog::getSaveFileName(this, windowName, dataDir + "/tokens.xml", fileType);
settings->setValue("paths/tokendatabase", fileName);
}
else {
if (defaultPathCheckBox->isChecked())
fileName = defaultPath;
else
fileName = QFileDialog::getSaveFileName(this, windowName, defaultPath, fileType);
}
if (fileName.isEmpty()) {
return false;
}
QFileInfo fi(fileName);
QDir fileDir(fi.path());
if (!fileDir.exists() && !fileDir.mkpath(fileDir.absolutePath())) {
return false;
}
if (wizard()->saveTokensToFile(fileName))
{
ok = true;
QMessageBox::information(this,
tr("Success"),
tr("The token database has been saved successfully to\n%1").arg(fileName));
} else {
QMessageBox::critical(this, tr("Error"), tr("The file could not be saved to %1").arg(fileName));;
if (defaultPathCheckBox->isChecked())
defaultPathCheckBox->setChecked(false);
}
} while (!ok);
return true;
}

View File

@@ -27,6 +27,9 @@ public:
void enableButtons();
void disableButtons();
void retranslateUi();
void setTokensData(QByteArray _tokensData) { tokensData = _tokensData; }
bool hasTokensData() { return !tokensData.isEmpty(); }
bool saveTokensToFile(const QString & fileName);
public:
OracleImporter *importer;
QSettings * settings;
@@ -35,6 +38,7 @@ private slots:
private:
QStringList findQmFiles();
QString languageName(const QString &qmFile);
QByteArray tokensData;
protected:
void changeEvent(QEvent *event);
};
@@ -115,4 +119,38 @@ private slots:
void updateTotalProgress(int cardsImported, int setIndex, const QString &setName);
};
class LoadTokensPage : public OracleWizardPage
{
Q_OBJECT
public:
LoadTokensPage(QWidget *parent = 0);
void retranslateUi();
protected:
void initializePage();
bool validatePage();
private:
QLabel *urlLabel;
QLineEdit *urlLineEdit;
QPushButton *urlButton;
QLabel *progressLabel;
QProgressBar * progressBar;
QNetworkAccessManager *nam;
private slots:
void actRestoreDefaultUrl();
void actDownloadProgressTokensFile(qint64 received, qint64 total);
void actDownloadFinishedTokensFile();
};
class SaveTokensPage : public OracleWizardPage
{
Q_OBJECT
public:
SaveTokensPage(QWidget *parent = 0);
void retranslateUi();
private:
QCheckBox * defaultPathCheckBox;
protected:
bool validatePage();
};
#endif