Automatic Spoiler Season (#2991)

* oracle now can be run in spoiler or normal mode

* tests for travis

* only run on relaunch

* spoilers in client (not oracle now) and tray icon shows when done

* spoiler status will be checked before downloading spoiler file

* only download if they care about spoilers

* reload db on spoiler download

* manual update button, code cleanup, and fix enabling sets when new

* cleanup, nullchecks, and fixes to spoiler

* reload DB even if not in spoiler season; necessary as we have a check elsewhere to prevent the reload if spoiler check happens

* Implement changes from 2991#issuecomment-356169374

* Change implicit nullptrs, alert on file deletion, minor changes

* make reload thread safe and minor changes from 2991#issuecomment-356450302

* Fix locking

* Disable update now button while process running
This commit is contained in:
Zach H 2018-01-10 13:27:43 -05:00 committed by GitHub
parent 51ec593759
commit d19744236e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
23 changed files with 2106 additions and 913 deletions

View file

@ -116,6 +116,7 @@ SET(cockatrice_SOURCES
src/logger.cpp src/logger.cpp
src/releasechannel.cpp src/releasechannel.cpp
src/userconnection_information.cpp src/userconnection_information.cpp
src/spoilerbackgroundupdater.cpp
${VERSION_STRING_CPP} ${VERSION_STRING_CPP}
) )

File diff suppressed because it is too large Load diff

View file

@ -8,6 +8,7 @@
#include <QDataStream> #include <QDataStream>
#include <QList> #include <QList>
#include <QXmlStreamReader> #include <QXmlStreamReader>
#include <QBasicMutex>
class CardDatabase; class CardDatabase;
class CardInfo; class CardInfo;
@ -18,159 +19,173 @@ typedef QMap<QString, QString> QStringMap;
// If we don't typedef this, CardInfo::CardInfo will refuse to compile on OS X < 10.9 // If we don't typedef this, CardInfo::CardInfo will refuse to compile on OS X < 10.9
typedef QMap<QString, int> MuidMap; typedef QMap<QString, int> MuidMap;
class CardSet : public QList<CardInfo *> { class CardSet : public QList<CardInfo *>
private: {
QString shortName, longName; private:
unsigned int sortKey; QString shortName, longName;
QDate releaseDate; unsigned int sortKey;
QString setType; QDate releaseDate;
bool enabled, isknown; QString setType;
public: bool enabled, isknown;
CardSet(const QString &_shortName = QString(), const QString &_longName = QString(), const QString &_setType = QString(), const QDate &_releaseDate = QDate());
QString getCorrectedShortName() const;
QString getShortName() const { return shortName; }
QString getLongName() const { return longName; }
QString getSetType() const { return setType; }
QDate getReleaseDate() const { return releaseDate; }
void setLongName(QString & _longName) { longName = _longName; }
void setSetType(QString & _setType) { setType = _setType; }
void setReleaseDate(QDate & _releaseDate) { releaseDate = _releaseDate; }
void loadSetOptions(); public:
int getSortKey() const { return sortKey; } explicit CardSet(const QString &_shortName = QString(), const QString &_longName = QString(), const QString &_setType = QString(), const QDate &_releaseDate = QDate());
void setSortKey(unsigned int _sortKey); QString getCorrectedShortName() const;
bool getEnabled() const { return enabled; } QString getShortName() const { return shortName; }
void setEnabled(bool _enabled); QString getLongName() const { return longName; }
bool getIsKnown() const { return isknown; } QString getSetType() const { return setType; }
void setIsKnown(bool _isknown); QDate getReleaseDate() const { return releaseDate; }
//Determine incomplete sets. void setLongName(QString & _longName) { longName = _longName; }
bool getIsKnownIgnored() const { return longName.length() + setType.length() + releaseDate.toString().length() == 0 ; } void setSetType(QString & _setType) { setType = _setType; }
void setReleaseDate(QDate & _releaseDate) { releaseDate = _releaseDate; }
void loadSetOptions();
int getSortKey() const { return sortKey; }
void setSortKey(unsigned int _sortKey);
bool getEnabled() const { return enabled; }
void setEnabled(bool _enabled);
bool getIsKnown() const { return isknown; }
void setIsKnown(bool _isknown);
//Determine incomplete sets.
bool getIsKnownIgnored() const { return longName.length() + setType.length() + releaseDate.toString().length() == 0 ; }
}; };
class SetList : public QList<CardSet *> { class SetList : public QList<CardSet *>
private: {
class KeyCompareFunctor; private:
public: class KeyCompareFunctor;
void sortByKey();
void guessSortKeys(); public:
void enableAllUnknown(); void sortByKey();
void enableAll(); void guessSortKeys();
void markAllAsKnown(); void enableAllUnknown();
int getEnabledSetsNum(); void enableAll();
int getUnknownSetsNum(); void markAllAsKnown();
QStringList getUnknownSetsNames(); int getEnabledSetsNum();
int getUnknownSetsNum();
QStringList getUnknownSetsNames();
}; };
class CardInfo : public QObject { class CardInfo : public QObject
{
Q_OBJECT Q_OBJECT
private: private:
QString name; QString name;
/* /*
* The name without punctuation or capitalization, for better card tag name * The name without punctuation or capitalization, for better card tag name
* recognition. * recognition.
*/ */
QString simpleName; QString simpleName;
bool isToken; bool isToken;
SetList sets; SetList sets;
QString manacost; QString manacost;
QString cmc; QString cmc;
QString cardtype; QString cardtype;
QString powtough; QString powtough;
QString text; QString text;
QStringList colors; QStringList colors;
// the cards i'm related to
QList<CardRelation *> relatedCards;
// the card i'm reverse-related to
QList<CardRelation *> reverseRelatedCards;
// the cards thare are reverse-related to me
QList<CardRelation *> reverseRelatedCardsToMe;
QString setsNames;
bool upsideDownArt;
int loyalty;
QStringMap customPicURLs;
MuidMap muIds;
QStringMap collectorNumbers;
QStringMap rarities;
bool cipt;
int tableRow;
QString pixmapCacheKey;
public:
CardInfo(const QString &_name = QString(),
bool _isToken = false,
const QString &_manacost = QString(),
const QString &_cmc = QString(),
const QString &_cardtype = QString(),
const QString &_powtough = QString(),
const QString &_text = QString(),
const QStringList &_colors = QStringList(),
const QList<CardRelation *> &_relatedCards = QList<CardRelation *>(),
const QList<CardRelation *> &_reverseRelatedCards = QList<CardRelation *>(),
bool _upsideDownArt = false,
int _loyalty = 0,
bool _cipt = false,
int _tableRow = 0,
const SetList &_sets = SetList(),
const QStringMap &_customPicURLs = QStringMap(),
MuidMap muids = MuidMap(),
QStringMap _collectorNumbers = QStringMap(),
QStringMap _rarities = QStringMap()
);
~CardInfo();
inline const QString &getName() const { return name; }
inline const QString &getSetsNames() const { return setsNames; }
const QString &getSimpleName() const { return simpleName; }
bool getIsToken() const { return isToken; }
const SetList &getSets() const { return sets; }
inline const QString &getManaCost() const { return manacost; }
inline const QString &getCmc() const { return cmc; }
inline const QString &getCardType() const { return cardtype; }
inline const QString &getPowTough() const { return powtough; }
const QString &getText() const { return text; }
const QString &getPixmapCacheKey() const { return pixmapCacheKey; }
const int &getLoyalty() const { return loyalty; }
bool getCipt() const { return cipt; }
void setManaCost(const QString &_manaCost) { manacost = _manaCost; emit cardInfoChanged(this); }
void setCmc(const QString &_cmc) { cmc = _cmc; emit cardInfoChanged(this); }
void setCardType(const QString &_cardType) { cardtype = _cardType; emit cardInfoChanged(this); }
void setPowTough(const QString &_powTough) { powtough = _powTough; emit cardInfoChanged(this); }
void setText(const QString &_text) { text = _text; emit cardInfoChanged(this); }
void setColors(const QStringList &_colors) { colors = _colors; emit cardInfoChanged(this); }
const QChar getColorChar() const;
const QStringList &getColors() const { return colors; }
const QList<CardRelation *> &getRelatedCards() const { return relatedCards; }
const QList<CardRelation *> &getReverseRelatedCards() const { return reverseRelatedCards; }
const QList<CardRelation *> &getReverseRelatedCards2Me() const { return reverseRelatedCardsToMe; }
void resetReverseRelatedCards2Me();
void addReverseRelatedCards2Me(CardRelation * cardRelation) { reverseRelatedCardsToMe.append(cardRelation); }
bool getUpsideDownArt() const { return upsideDownArt; }
QString getCustomPicURL(const QString &set) const { return customPicURLs.value(set); }
int getMuId(const QString &set) const { return muIds.value(set); }
QString getCollectorNumber(const QString &set) const { return collectorNumbers.value(set); }
QString getRarity(const QString &set) const { return rarities.value(set); }
QStringMap getRarities() const { return rarities; }
QString getMainCardType() const;
QString getCorrectedName() const;
int getTableRow() const { return tableRow; }
void setTableRow(int _tableRow) { tableRow = _tableRow; }
void setLoyalty(int _loyalty) { loyalty = _loyalty; emit cardInfoChanged(this); }
void setCustomPicURL(const QString &_set, const QString &_customPicURL) { customPicURLs.insert(_set, _customPicURL); }
void setMuId(const QString &_set, const int &_muId) { muIds.insert(_set, _muId); }
void setSetNumber(const QString &_set, const QString &_setNumber) { collectorNumbers.insert(_set, _setNumber); }
void setRarity(const QString &_set, const QString &_setNumber) { rarities.insert(_set, _setNumber); }
void addToSet(CardSet *set);
void emitPixmapUpdated() { emit pixmapUpdated(); }
void refreshCachedSetNames();
/** // the cards i'm related to
* Simplify a name to have no punctuation and lowercase all letters, for QList<CardRelation *> relatedCards;
* less strict name-matching.
*/ // the card i'm reverse-related to
static QString simplifyName(const QString &name); QList<CardRelation *> reverseRelatedCards;
signals:
void pixmapUpdated(); // the cards thare are reverse-related to me
void cardInfoChanged(CardInfo *card); QList<CardRelation *> reverseRelatedCardsToMe;
QString setsNames;
bool upsideDownArt;
int loyalty;
QStringMap customPicURLs;
MuidMap muIds;
QStringMap collectorNumbers;
QStringMap rarities;
bool cipt;
int tableRow;
QString pixmapCacheKey;
public:
explicit CardInfo(const QString &_name = QString(),
bool _isToken = false,
const QString &_manacost = QString(),
const QString &_cmc = QString(),
const QString &_cardtype = QString(),
const QString &_powtough = QString(),
const QString &_text = QString(),
const QStringList &_colors = QStringList(),
const QList<CardRelation *> &_relatedCards = QList<CardRelation *>(),
const QList<CardRelation *> &_reverseRelatedCards = QList<CardRelation *>(),
bool _upsideDownArt = false,
int _loyalty = 0,
bool _cipt = false,
int _tableRow = 0,
const SetList &_sets = SetList(),
const QStringMap &_customPicURLs = QStringMap(),
MuidMap muids = MuidMap(),
QStringMap _collectorNumbers = QStringMap(),
QStringMap _rarities = QStringMap()
);
~CardInfo() override;
inline const QString &getName() const { return name; }
inline const QString &getSetsNames() const { return setsNames; }
const QString &getSimpleName() const { return simpleName; }
bool getIsToken() const { return isToken; }
const SetList &getSets() const { return sets; }
inline const QString &getManaCost() const { return manacost; }
inline const QString &getCmc() const { return cmc; }
inline const QString &getCardType() const { return cardtype; }
inline const QString &getPowTough() const { return powtough; }
const QString &getText() const { return text; }
const QString &getPixmapCacheKey() const { return pixmapCacheKey; }
const int &getLoyalty() const { return loyalty; }
bool getCipt() const { return cipt; }
//void setManaCost(const QString &_manaCost) { manacost = _manaCost; emit cardInfoChanged(this); }
//void setCmc(const QString &_cmc) { cmc = _cmc; emit cardInfoChanged(this); }
void setCardType(const QString &_cardType) { cardtype = _cardType; emit cardInfoChanged(this); }
void setPowTough(const QString &_powTough) { powtough = _powTough; emit cardInfoChanged(this); }
void setText(const QString &_text) { text = _text; emit cardInfoChanged(this); }
void setColors(const QStringList &_colors) { colors = _colors; emit cardInfoChanged(this); }
const QChar getColorChar() const;
const QStringList &getColors() const { return colors; }
const QList<CardRelation *> &getRelatedCards() const { return relatedCards; }
const QList<CardRelation *> &getReverseRelatedCards() const { return reverseRelatedCards; }
const QList<CardRelation *> &getReverseRelatedCards2Me() const { return reverseRelatedCardsToMe; }
void resetReverseRelatedCards2Me();
void addReverseRelatedCards2Me(CardRelation * cardRelation) { reverseRelatedCardsToMe.append(cardRelation); }
bool getUpsideDownArt() const { return upsideDownArt; }
QString getCustomPicURL(const QString &set) const { return customPicURLs.value(set); }
int getMuId(const QString &set) const { return muIds.value(set); }
QString getCollectorNumber(const QString &set) const { return collectorNumbers.value(set); }
QString getRarity(const QString &set) const { return rarities.value(set); }
QStringMap getRarities() const { return rarities; }
QString getMainCardType() const;
QString getCorrectedName() const;
int getTableRow() const { return tableRow; }
void setTableRow(int _tableRow) { tableRow = _tableRow; }
//void setLoyalty(int _loyalty) { loyalty = _loyalty; emit cardInfoChanged(this); }
//void setCustomPicURL(const QString &_set, const QString &_customPicURL) { customPicURLs.insert(_set, _customPicURL); }
void setMuId(const QString &_set, const int &_muId) { muIds.insert(_set, _muId); }
void setSetNumber(const QString &_set, const QString &_setNumber) { collectorNumbers.insert(_set, _setNumber); }
void setRarity(const QString &_set, const QString &_setNumber) { rarities.insert(_set, _setNumber); }
void addToSet(CardSet *set);
void emitPixmapUpdated() { emit pixmapUpdated(); }
void refreshCachedSetNames();
/**
* Simplify a name to have no punctuation and lowercase all letters, for
* less strict name-matching.
*/
static QString simplifyName(const QString &name);
signals:
void pixmapUpdated();
void cardInfoChanged(CardInfo *card);
}; };
enum LoadStatus { Ok, VersionTooOld, Invalid, NotLoaded, FileError, NoCards }; enum LoadStatus { Ok, VersionTooOld, Invalid, NotLoaded, FileError, NoCards };
@ -178,97 +193,106 @@ enum LoadStatus { Ok, VersionTooOld, Invalid, NotLoaded, FileError, NoCards };
typedef QHash<QString, CardInfo *> CardNameMap; typedef QHash<QString, CardInfo *> CardNameMap;
typedef QHash<QString, CardSet *> SetNameMap; typedef QHash<QString, CardSet *> SetNameMap;
class CardDatabase : public QObject { class CardDatabase : public QObject
{
Q_OBJECT Q_OBJECT
protected: protected:
/* /*
* The cards, indexed by name. * The cards, indexed by name.
*/ */
CardNameMap cards; CardNameMap cards;
/** /**
* The cards, indexed by their simple name. * The cards, indexed by their simple name.
*/ */
CardNameMap simpleNameCards; CardNameMap simpleNameCards;
/* /*
* The sets, indexed by short name. * The sets, indexed by short name.
*/ */
SetNameMap sets; SetNameMap sets;
LoadStatus loadStatus; LoadStatus loadStatus;
private: private:
static const int versionNeeded; static const int versionNeeded;
void loadCardsFromXml(QXmlStreamReader &xml); void loadCardsFromXml(QXmlStreamReader &xml);
void loadSetsFromXml(QXmlStreamReader &xml); void loadSetsFromXml(QXmlStreamReader &xml);
CardInfo *getCardFromMap(const CardNameMap &cardMap, const QString &cardName) const; CardInfo *getCardFromMap(const CardNameMap &cardMap, const QString &cardName) const;
void checkUnknownSets(); void checkUnknownSets();
void refreshCachedReverseRelatedCards(); void refreshCachedReverseRelatedCards();
public:
static const char* TOKENS_SETNAME;
CardDatabase(QObject *parent = 0); QBasicMutex *reloadDatabaseMutex = new QBasicMutex(),
~CardDatabase(); *clearDatabaseMutex = new QBasicMutex(),
void clear(); *loadFromFileMutex = new QBasicMutex(),
void addCard(CardInfo *card); *addCardMutex = new QBasicMutex(),
void removeCard(CardInfo *card); *removeCardMutex = new QBasicMutex();
CardInfo *getCard(const QString &cardName) const;
QList <CardInfo *> getCards(const QStringList &cardNames) const;
/* public:
* Get a card by its simple name. The name will be simplified in this static const char* TOKENS_SETNAME;
* function, so you don't need to simplify it beforehand.
*/
CardInfo *getCardBySimpleName(const QString &cardName) const;
CardSet *getSet(const QString &setName); explicit CardDatabase(QObject *parent = nullptr);
QList<CardInfo *> getCardList() const { return cards.values(); } ~CardDatabase() override;
SetList getSetList() const; void clear();
LoadStatus loadFromFile(const QString &fileName); void addCard(CardInfo *card);
bool saveToFile(const QString &fileName, bool tokens = false); void removeCard(CardInfo *card);
bool saveCustomTokensToFile(); CardInfo *getCard(const QString &cardName) const;
QStringList getAllColors() const; QList <CardInfo *> getCards(const QStringList &cardNames) const;
QStringList getAllMainCardTypes() const;
LoadStatus getLoadStatus() const { return loadStatus; }
void enableAllUnknownSets();
void markAllSetsAsKnown();
void notifyEnabledSetsChanged();
public slots: /*
LoadStatus loadCardDatabases(); * Get a card by its simple name. The name will be simplified in this
private slots: * function, so you don't need to simplify it beforehand.
LoadStatus loadCardDatabase(const QString &path); */
signals: CardInfo *getCardBySimpleName(const QString &cardName) const;
void cardDatabaseLoadingFailed();
void cardDatabaseNewSetsFound(int numUnknownSets, QStringList unknownSetsNames); CardSet *getSet(const QString &setName);
void cardDatabaseAllNewSetsEnabled(); QList<CardInfo *> getCardList() const { return cards.values(); }
void cardDatabaseEnabledSetsChanged(); SetList getSetList() const;
void cardAdded(CardInfo *card); LoadStatus loadFromFile(const QString &fileName);
void cardRemoved(CardInfo *card); bool saveToFile(const QString &fileName, bool tokens = false);
bool saveCustomTokensToFile();
QStringList getAllColors() const;
QStringList getAllMainCardTypes() const;
LoadStatus getLoadStatus() const { return loadStatus; }
void enableAllUnknownSets();
void markAllSetsAsKnown();
void notifyEnabledSetsChanged();
public slots:
LoadStatus loadCardDatabases();
private slots:
LoadStatus loadCardDatabase(const QString &path);
signals:
void cardDatabaseLoadingFailed();
void cardDatabaseNewSetsFound(int numUnknownSets, QStringList unknownSetsNames);
void cardDatabaseAllNewSetsEnabled();
void cardDatabaseEnabledSetsChanged();
void cardAdded(CardInfo *card);
void cardRemoved(CardInfo *card);
}; };
class CardRelation : public QObject { class CardRelation : public QObject
{
Q_OBJECT Q_OBJECT
private: private:
QString name; QString name;
bool doesAttach; bool doesAttach;
bool isCreateAllExclusion; bool isCreateAllExclusion;
bool isVariableCount; bool isVariableCount;
int defaultCount; int defaultCount;
public: public:
CardRelation(const QString &_name = QString(), explicit CardRelation(const QString &_name = QString(),
bool _doesAttach = false, bool _doesAttach = false,
bool _isCreateAllExclusion = false, bool _isCreateAllExclusion = false,
bool _isVariableCount = false, bool _isVariableCount = false,
int _defaultCount = 1 int _defaultCount = 1
); );
inline const QString &getName() const { return name; }
bool getDoesAttach() const { return doesAttach; }
bool getCanCreateAnother() const { return !doesAttach; }
bool getIsCreateAllExclusion() const { return isCreateAllExclusion; }
bool getIsVariable() const { return isVariableCount; }
int getDefaultCount() const { return defaultCount; }
};
inline const QString &getName() const { return name; }
bool getDoesAttach() const { return doesAttach; }
bool getCanCreateAnother() const { return !doesAttach; }
bool getIsCreateAllExclusion() const { return isCreateAllExclusion; }
bool getIsVariable() const { return isVariableCount; }
int getDefaultCount() const { return defaultCount; }
};
#endif #endif

View file

@ -16,8 +16,7 @@
#define PUBLIC_SERVERS_URL "https://github.com/Cockatrice/Cockatrice/wiki/Public-Servers" #define PUBLIC_SERVERS_URL "https://github.com/Cockatrice/Cockatrice/wiki/Public-Servers"
DlgConnect::DlgConnect(QWidget *parent) DlgConnect::DlgConnect(QWidget *parent) : QDialog(parent)
: QDialog(parent)
{ {
previousHostButton = new QRadioButton(tr("Known Hosts"), this); previousHostButton = new QRadioButton(tr("Known Hosts"), this);
previousHosts = new QComboBox(this); previousHosts = new QComboBox(this);
@ -64,7 +63,7 @@ DlgConnect::DlgConnect(QWidget *parent)
if (savePasswordCheckBox->isChecked()) if (savePasswordCheckBox->isChecked())
{ {
autoConnectCheckBox->setChecked(settingsCache->servers().getAutoConnect()); autoConnectCheckBox->setChecked(static_cast<bool>(settingsCache->servers().getAutoConnect()));
autoConnectCheckBox->setEnabled(true); autoConnectCheckBox->setEnabled(true);
} }
else else
@ -87,11 +86,11 @@ DlgConnect::DlgConnect(QWidget *parent)
btnCancel->setFixedWidth(100); btnCancel->setFixedWidth(100);
connect(btnCancel, SIGNAL(released()), this, SLOT(actCancel())); connect(btnCancel, SIGNAL(released()), this, SLOT(actCancel()));
QGridLayout *newHostLayout = new QGridLayout; auto *newHostLayout = new QGridLayout;
newHostLayout->addWidget(newHostButton, 0, 1); newHostLayout->addWidget(newHostButton, 0, 1);
newHostLayout->addWidget(publicServersLabel, 0, 2); newHostLayout->addWidget(publicServersLabel, 0, 2);
QGridLayout *connectionLayout = new QGridLayout; auto *connectionLayout = new QGridLayout;
connectionLayout->addWidget(previousHostButton, 0, 1); connectionLayout->addWidget(previousHostButton, 0, 1);
connectionLayout->addWidget(previousHosts, 1, 1); connectionLayout->addWidget(previousHosts, 1, 1);
connectionLayout->addLayout(newHostLayout, 2, 1, 1, 2); connectionLayout->addLayout(newHostLayout, 2, 1, 1, 2);
@ -103,7 +102,7 @@ DlgConnect::DlgConnect(QWidget *parent)
connectionLayout->addWidget(portEdit, 5, 1); connectionLayout->addWidget(portEdit, 5, 1);
connectionLayout->addWidget(autoConnectCheckBox, 6, 1); connectionLayout->addWidget(autoConnectCheckBox, 6, 1);
QGridLayout *buttons = new QGridLayout; auto *buttons = new QGridLayout;
buttons->addWidget(btnOk, 0, 0); buttons->addWidget(btnOk, 0, 0);
buttons->addWidget(btnForgotPassword, 0, 1); buttons->addWidget(btnForgotPassword, 0, 1);
buttons->addWidget(btnCancel, 0, 2); buttons->addWidget(btnCancel, 0, 2);
@ -111,7 +110,7 @@ DlgConnect::DlgConnect(QWidget *parent)
QGroupBox *restrictionsGroupBox = new QGroupBox(tr("Server")); QGroupBox *restrictionsGroupBox = new QGroupBox(tr("Server"));
restrictionsGroupBox->setLayout(connectionLayout); restrictionsGroupBox->setLayout(connectionLayout);
QGridLayout *loginLayout = new QGridLayout; auto *loginLayout = new QGridLayout;
loginLayout->addWidget(playernameLabel, 0, 0); loginLayout->addWidget(playernameLabel, 0, 0);
loginLayout->addWidget(playernameEdit, 0, 1); loginLayout->addWidget(playernameEdit, 0, 1);
loginLayout->addWidget(passwordLabel, 1, 0); loginLayout->addWidget(passwordLabel, 1, 0);
@ -124,12 +123,12 @@ DlgConnect::DlgConnect(QWidget *parent)
QGroupBox *btnGroupBox = new QGroupBox(tr("")); QGroupBox *btnGroupBox = new QGroupBox(tr(""));
btnGroupBox->setLayout(buttons); btnGroupBox->setLayout(buttons);
QGridLayout *grid = new QGridLayout; auto *grid = new QGridLayout;
grid->addWidget(restrictionsGroupBox, 0, 0); grid->addWidget(restrictionsGroupBox, 0, 0);
grid->addWidget(loginGroupBox, 1, 0); grid->addWidget(loginGroupBox, 1, 0);
grid->addWidget(btnGroupBox, 2, 0); grid->addWidget(btnGroupBox, 2, 0);
QVBoxLayout *mainLayout = new QVBoxLayout; auto *mainLayout = new QVBoxLayout;
mainLayout->addLayout(grid); mainLayout->addLayout(grid);
setLayout(mainLayout); setLayout(mainLayout);
@ -289,9 +288,9 @@ void DlgConnect::actCancel()
bool DeleteHighlightedItemWhenShiftDelPressedEventFilter::eventFilter(QObject *obj, QEvent *event) bool DeleteHighlightedItemWhenShiftDelPressedEventFilter::eventFilter(QObject *obj, QEvent *event)
{ {
if (event->type() == QEvent::KeyPress) { if (event->type() == QEvent::KeyPress) {
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event); auto *keyEvent = dynamic_cast<QKeyEvent *>(event);
if (keyEvent->key() == Qt::Key_Delete) { if (keyEvent->key() == Qt::Key_Delete) {
QComboBox* combobox = reinterpret_cast<QComboBox *>(obj); auto *combobox = reinterpret_cast<QComboBox *>(obj);
combobox->removeItem(combobox->currentIndex()); combobox->removeItem(combobox->currentIndex());
return true; return true;
} }

View file

@ -30,6 +30,7 @@
#include "releasechannel.h" #include "releasechannel.h"
#include "soundengine.h" #include "soundengine.h"
#include "sequenceEdit/shortcutstab.h" #include "sequenceEdit/shortcutstab.h"
#include "spoilerbackgroundupdater.h"
#define WIKI_CUSTOM_PIC_URL "https://github.com/Cockatrice/Cockatrice/wiki/Custom-Picture-Download-URLs" #define WIKI_CUSTOM_PIC_URL "https://github.com/Cockatrice/Cockatrice/wiki/Custom-Picture-Download-URLs"
@ -81,7 +82,7 @@ GeneralSettingsPage::GeneralSettingsPage()
setEnabledStatus(settingsCache->getPicDownload()); setEnabledStatus(settingsCache->getPicDownload());
QGridLayout *personalGrid = new QGridLayout; auto *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(&updateReleaseChannelLabel, 1, 0); personalGrid->addWidget(&updateReleaseChannelLabel, 1, 0);
@ -130,7 +131,7 @@ GeneralSettingsPage::GeneralSettingsPage()
QPushButton *tokenDatabasePathButton = new QPushButton("..."); QPushButton *tokenDatabasePathButton = new QPushButton("...");
connect(tokenDatabasePathButton, SIGNAL(clicked()), this, SLOT(tokenDatabasePathButtonClicked())); connect(tokenDatabasePathButton, SIGNAL(clicked()), this, SLOT(tokenDatabasePathButtonClicked()));
if(settingsCache->getIsPortableBuild()) if (settingsCache->getIsPortableBuild())
{ {
deckPathEdit->setEnabled(false); deckPathEdit->setEnabled(false);
replaysPathEdit->setEnabled(false); replaysPathEdit->setEnabled(false);
@ -145,7 +146,7 @@ GeneralSettingsPage::GeneralSettingsPage()
tokenDatabasePathButton->setVisible(false); tokenDatabasePathButton->setVisible(false);
} }
QGridLayout *pathsGrid = new QGridLayout; auto *pathsGrid = new QGridLayout;
pathsGrid->addWidget(&deckPathLabel, 0, 0); pathsGrid->addWidget(&deckPathLabel, 0, 0);
pathsGrid->addWidget(deckPathEdit, 0, 1); pathsGrid->addWidget(deckPathEdit, 0, 1);
pathsGrid->addWidget(deckPathButton, 0, 2); pathsGrid->addWidget(deckPathButton, 0, 2);
@ -164,7 +165,7 @@ GeneralSettingsPage::GeneralSettingsPage()
pathsGroupBox = new QGroupBox; pathsGroupBox = new QGroupBox;
pathsGroupBox->setLayout(pathsGrid); pathsGroupBox->setLayout(pathsGrid);
QVBoxLayout *mainLayout = new QVBoxLayout; auto *mainLayout = new QVBoxLayout;
mainLayout->addWidget(personalGroupBox); mainLayout->addWidget(personalGroupBox);
mainLayout->addWidget(pathsGroupBox); mainLayout->addWidget(pathsGroupBox);
@ -333,7 +334,7 @@ AppearanceSettingsPage::AppearanceSettingsPage()
connect(&themeBox, SIGNAL(currentIndexChanged(int)), this, SLOT(themeBoxChanged(int))); connect(&themeBox, SIGNAL(currentIndexChanged(int)), this, SLOT(themeBoxChanged(int)));
QGridLayout *themeGrid = new QGridLayout; auto *themeGrid = new QGridLayout;
themeGrid->addWidget(&themeLabel, 0, 0); themeGrid->addWidget(&themeLabel, 0, 0);
themeGrid->addWidget(&themeBox, 0, 1); themeGrid->addWidget(&themeBox, 0, 1);
@ -346,7 +347,7 @@ AppearanceSettingsPage::AppearanceSettingsPage()
cardScalingCheckBox.setChecked(settingsCache->getScaleCards()); cardScalingCheckBox.setChecked(settingsCache->getScaleCards());
connect(&cardScalingCheckBox, SIGNAL(stateChanged(int)), settingsCache, SLOT(setCardScaling(int))); connect(&cardScalingCheckBox, SIGNAL(stateChanged(int)), settingsCache, SLOT(setCardScaling(int)));
QGridLayout *cardsGrid = new QGridLayout; auto *cardsGrid = new QGridLayout;
cardsGrid->addWidget(&displayCardNamesCheckBox, 0, 0, 1, 2); cardsGrid->addWidget(&displayCardNamesCheckBox, 0, 0, 1, 2);
cardsGrid->addWidget(&cardScalingCheckBox, 1, 0, 1, 2); cardsGrid->addWidget(&cardScalingCheckBox, 1, 0, 1, 2);
@ -359,7 +360,7 @@ AppearanceSettingsPage::AppearanceSettingsPage()
leftJustifiedHandCheckBox.setChecked(settingsCache->getLeftJustified()); leftJustifiedHandCheckBox.setChecked(settingsCache->getLeftJustified());
connect(&leftJustifiedHandCheckBox, SIGNAL(stateChanged(int)), settingsCache, SLOT(setLeftJustified(int))); connect(&leftJustifiedHandCheckBox, SIGNAL(stateChanged(int)), settingsCache, SLOT(setLeftJustified(int)));
QGridLayout *handGrid = new QGridLayout; auto *handGrid = new QGridLayout;
handGrid->addWidget(&horizontalHandCheckBox, 0, 0, 1, 2); handGrid->addWidget(&horizontalHandCheckBox, 0, 0, 1, 2);
handGrid->addWidget(&leftJustifiedHandCheckBox, 1, 0, 1, 2); handGrid->addWidget(&leftJustifiedHandCheckBox, 1, 0, 1, 2);
@ -380,7 +381,7 @@ AppearanceSettingsPage::AppearanceSettingsPage()
maxFontSizeForCardsEdit.setMinimum(9); maxFontSizeForCardsEdit.setMinimum(9);
maxFontSizeForCardsEdit.setMaximum(100); maxFontSizeForCardsEdit.setMaximum(100);
QGridLayout *tableGrid = new QGridLayout; auto *tableGrid = new QGridLayout;
tableGrid->addWidget(&invertVerticalCoordinateCheckBox, 0, 0, 1, 2); tableGrid->addWidget(&invertVerticalCoordinateCheckBox, 0, 0, 1, 2);
tableGrid->addWidget(&minPlayersForMultiColumnLayoutLabel, 1, 0, 1, 1); tableGrid->addWidget(&minPlayersForMultiColumnLayoutLabel, 1, 0, 1, 1);
tableGrid->addWidget(&minPlayersForMultiColumnLayoutEdit, 1, 1, 1, 1); tableGrid->addWidget(&minPlayersForMultiColumnLayoutEdit, 1, 1, 1, 1);
@ -390,7 +391,7 @@ AppearanceSettingsPage::AppearanceSettingsPage()
tableGroupBox = new QGroupBox; tableGroupBox = new QGroupBox;
tableGroupBox->setLayout(tableGrid); tableGroupBox->setLayout(tableGrid);
QVBoxLayout *mainLayout = new QVBoxLayout; auto *mainLayout = new QVBoxLayout;
mainLayout->addWidget(themeGroupBox); mainLayout->addWidget(themeGroupBox);
mainLayout->addWidget(cardsGroupBox); mainLayout->addWidget(cardsGroupBox);
mainLayout->addWidget(handGroupBox); mainLayout->addWidget(handGroupBox);
@ -444,7 +445,7 @@ UserInterfaceSettingsPage::UserInterfaceSettingsPage()
annotateTokensCheckBox.setChecked(settingsCache->getAnnotateTokens()); annotateTokensCheckBox.setChecked(settingsCache->getAnnotateTokens());
connect(&annotateTokensCheckBox, SIGNAL(stateChanged(int)), settingsCache, SLOT(setAnnotateTokens(int))); connect(&annotateTokensCheckBox, SIGNAL(stateChanged(int)), settingsCache, SLOT(setAnnotateTokens(int)));
QGridLayout *generalGrid = new QGridLayout; auto *generalGrid = new QGridLayout;
generalGrid->addWidget(&notificationsEnabledCheckBox, 0, 0); generalGrid->addWidget(&notificationsEnabledCheckBox, 0, 0);
generalGrid->addWidget(&specNotificationsEnabledCheckBox, 1, 0); generalGrid->addWidget(&specNotificationsEnabledCheckBox, 1, 0);
generalGrid->addWidget(&doubleClickToPlayCheckBox, 2, 0); generalGrid->addWidget(&doubleClickToPlayCheckBox, 2, 0);
@ -457,13 +458,13 @@ UserInterfaceSettingsPage::UserInterfaceSettingsPage()
tapAnimationCheckBox.setChecked(settingsCache->getTapAnimation()); tapAnimationCheckBox.setChecked(settingsCache->getTapAnimation());
connect(&tapAnimationCheckBox, SIGNAL(stateChanged(int)), settingsCache, SLOT(setTapAnimation(int))); connect(&tapAnimationCheckBox, SIGNAL(stateChanged(int)), settingsCache, SLOT(setTapAnimation(int)));
QGridLayout *animationGrid = new QGridLayout; auto *animationGrid = new QGridLayout;
animationGrid->addWidget(&tapAnimationCheckBox, 0, 0); animationGrid->addWidget(&tapAnimationCheckBox, 0, 0);
animationGroupBox = new QGroupBox; animationGroupBox = new QGroupBox;
animationGroupBox->setLayout(animationGrid); animationGroupBox->setLayout(animationGrid);
QVBoxLayout *mainLayout = new QVBoxLayout; auto *mainLayout = new QVBoxLayout;
mainLayout->addWidget(generalGroupBox); mainLayout->addWidget(generalGroupBox);
mainLayout->addWidget(animationGroupBox); mainLayout->addWidget(animationGroupBox);
@ -486,25 +487,123 @@ void UserInterfaceSettingsPage::retranslateUi()
tapAnimationCheckBox.setText(tr("&Tap/untap animation")); tapAnimationCheckBox.setText(tr("&Tap/untap animation"));
} }
DeckEditorSettingsPage::DeckEditorSettingsPage() DeckEditorSettingsPage::DeckEditorSettingsPage()
{ {
QGridLayout *generalGrid = new QGridLayout; auto *lpGeneralGrid = new QGridLayout;
auto *lpSpoilerGrid = new QGridLayout;
generalGrid->addWidget(new QLabel(tr("Nothing is here... yet")), 0, 0); mcDownloadSpoilersCheckBox.setChecked(settingsCache->getDownloadSpoilersStatus());
generalGroupBox = new QGroupBox; mpSpoilerSavePathLineEdit = new QLineEdit(settingsCache->getSpoilerCardDatabasePath());
generalGroupBox->setLayout(generalGrid); mpSpoilerSavePathLineEdit->setReadOnly(true);
mpSpoilerPathButton = new QPushButton("...");
connect(mpSpoilerPathButton, SIGNAL(clicked()), this, SLOT(spoilerPathButtonClicked()));
QVBoxLayout *mainLayout = new QVBoxLayout; updateNowButton = new QPushButton(tr("Update Spoilers"));
mainLayout->addWidget(generalGroupBox); connect(updateNowButton, SIGNAL(clicked()), this, SLOT(updateSpoilers()));
setLayout(mainLayout); // Update the GUI depending on if the box is ticked or not
setSpoilersEnabled(mcDownloadSpoilersCheckBox.isChecked());
// Create the layout
lpGeneralGrid->addWidget(&mcGeneralMessageLabel, 0, 0);
lpSpoilerGrid->addWidget(&mcDownloadSpoilersCheckBox, 0, 0);
lpSpoilerGrid->addWidget(updateNowButton, 0, 2);
lpSpoilerGrid->addWidget(&mcSpoilerSaveLabel, 1, 0);
lpSpoilerGrid->addWidget(mpSpoilerSavePathLineEdit, 1, 1);
lpSpoilerGrid->addWidget(mpSpoilerPathButton, 1, 2);
lpSpoilerGrid->addWidget(&infoOnSpoilersLabel, 2, 0, 1, 3, Qt::AlignTop);
// On a change to the check box, hide/unhide the other fields
connect(&mcDownloadSpoilersCheckBox, SIGNAL(toggled(bool)), settingsCache, SLOT(setDownloadSpoilerStatus(bool)));
connect(&mcDownloadSpoilersCheckBox, SIGNAL(toggled(bool)), this, SLOT(setSpoilersEnabled(bool)));
mpGeneralGroupBox = new QGroupBox;
mpGeneralGroupBox->setLayout(lpGeneralGrid);
mpSpoilerGroupBox = new QGroupBox;
mpSpoilerGroupBox->setLayout(lpSpoilerGrid);
auto *lpMainLayout = new QVBoxLayout;
lpMainLayout->addWidget(mpGeneralGroupBox);
lpMainLayout->addWidget(mpSpoilerGroupBox);
setLayout(lpMainLayout);
}
void DeckEditorSettingsPage::updateSpoilers()
{
// Disable the button so the user can only press it once at a time
updateNowButton->setDisabled(true);
updateNowButton->setText(tr("Updating Spoilers"));
// Create a new SBU that will act as if the client was just reloaded
auto *sbu = new SpoilerBackgroundUpdater();
connect(sbu, SIGNAL(spoilerCheckerDone()), this, SLOT(unlockSettings()));
connect(sbu, SIGNAL(spoilersUpdatedSuccessfully()), this, SLOT(unlockSettings()));
}
void DeckEditorSettingsPage::unlockSettings()
{
updateNowButton->setDisabled(false);
updateNowButton->setText(tr("Update Spoilers"));
}
QString DeckEditorSettingsPage::getLastUpdateTime()
{
QString fileName = settingsCache->getSpoilerCardDatabasePath();
QFileInfo fi(fileName);
QDir fileDir(fi.path());
QFile file(fileName);
if (file.exists())
{
return fi.lastModified().toString("MMM d, hh:mm");
}
return QString();
}
void DeckEditorSettingsPage::spoilerPathButtonClicked()
{
QString lsPath = QFileDialog::getExistingDirectory(this, tr("Choose path"));
if (lsPath.isEmpty())
{
return;
}
mpSpoilerSavePathLineEdit->setText(lsPath + "/spoiler.xml");
settingsCache->setSpoilerDatabasePath(lsPath + "/spoiler.xml");
}
void DeckEditorSettingsPage::setSpoilersEnabled(bool anInput)
{
msDownloadSpoilersLabel.setEnabled(anInput);
mcSpoilerSaveLabel.setEnabled(anInput);
mpSpoilerSavePathLineEdit->setEnabled(anInput);
mpSpoilerPathButton->setEnabled(anInput);
updateNowButton->setEnabled(anInput);
infoOnSpoilersLabel.setEnabled(anInput);
if (! anInput)
{
SpoilerBackgroundUpdater::deleteSpoilerFile();
}
} }
void DeckEditorSettingsPage::retranslateUi() void DeckEditorSettingsPage::retranslateUi()
{ {
generalGroupBox->setTitle(tr("General")); mpSpoilerGroupBox->setTitle(tr("Spoilers"));
mcDownloadSpoilersCheckBox.setText(tr("Download Spoilers Automatically"));
mcSpoilerSaveLabel.setText(tr("Spoiler Location:"));
mcGeneralMessageLabel.setText(tr("Hey, something's here finally!"));
infoOnSpoilersLabel.setText(
tr("Last Updated") + ": " + getLastUpdateTime() + "\n\n" +
tr("Spoilers download automatically on launch") + "\n" +
tr("Press the button to manually update without relaunching") + "\n\n" +
tr("Do not close settings until manual update complete")
);
} }
MessagesSettingsPage::MessagesSettingsPage() MessagesSettingsPage::MessagesSettingsPage()
@ -545,7 +644,7 @@ MessagesSettingsPage::MessagesSettingsPage()
customAlertString->setText(settingsCache->getHighlightWords()); customAlertString->setText(settingsCache->getHighlightWords());
connect(customAlertString, SIGNAL(textChanged(QString)), settingsCache, SLOT(setHighlightWords(QString))); connect(customAlertString, SIGNAL(textChanged(QString)), settingsCache, SLOT(setHighlightWords(QString)));
QGridLayout *chatGrid = new QGridLayout; auto *chatGrid = new QGridLayout;
chatGrid->addWidget(&chatMentionCheckBox, 0, 0); chatGrid->addWidget(&chatMentionCheckBox, 0, 0);
chatGrid->addWidget(&invertMentionForeground, 0, 1); chatGrid->addWidget(&invertMentionForeground, 0, 1);
chatGrid->addWidget(mentionColor, 0, 2); chatGrid->addWidget(mentionColor, 0, 2);
@ -564,7 +663,7 @@ MessagesSettingsPage::MessagesSettingsPage()
updateHighlightPreview(); updateHighlightPreview();
connect(highlightColor, SIGNAL(textChanged(QString)), this, SLOT(updateHighlightColor(QString))); connect(highlightColor, SIGNAL(textChanged(QString)), this, SLOT(updateHighlightColor(QString)));
QGridLayout *highlightNotice = new QGridLayout; auto *highlightNotice = new QGridLayout;
highlightNotice->addWidget(highlightColor, 0, 2); highlightNotice->addWidget(highlightColor, 0, 2);
highlightNotice->addWidget(&invertHighlightForeground, 0, 1); highlightNotice->addWidget(&invertHighlightForeground, 0, 1);
highlightNotice->addWidget(&hexHighlightLabel, 1, 2); highlightNotice->addWidget(&hexHighlightLabel, 1, 2);
@ -586,19 +685,19 @@ MessagesSettingsPage::MessagesSettingsPage()
aRemove->setIcon(QPixmap("theme:icons/decrement")); aRemove->setIcon(QPixmap("theme:icons/decrement"));
connect(aRemove, SIGNAL(triggered()), this, SLOT(actRemove())); connect(aRemove, SIGNAL(triggered()), this, SLOT(actRemove()));
QToolBar *messageToolBar = new QToolBar; auto *messageToolBar = new QToolBar;
messageToolBar->setOrientation(Qt::Vertical); messageToolBar->setOrientation(Qt::Vertical);
messageToolBar->addAction(aAdd); messageToolBar->addAction(aAdd);
messageToolBar->addAction(aRemove); messageToolBar->addAction(aRemove);
QHBoxLayout *messageListLayout = new QHBoxLayout; auto *messageListLayout = new QHBoxLayout;
messageListLayout->addWidget(messageToolBar); messageListLayout->addWidget(messageToolBar);
messageListLayout->addWidget(messageList); messageListLayout->addWidget(messageList);
messageShortcuts = new QGroupBox; messageShortcuts = new QGroupBox;
messageShortcuts->setLayout(messageListLayout); messageShortcuts->setLayout(messageListLayout);
QVBoxLayout *mainLayout = new QVBoxLayout; auto *mainLayout = new QVBoxLayout;
mainLayout->addWidget(messageShortcuts); mainLayout->addWidget(messageShortcuts);
mainLayout->addWidget(chatGroupBox); mainLayout->addWidget(chatGroupBox);
@ -609,7 +708,8 @@ MessagesSettingsPage::MessagesSettingsPage()
retranslateUi(); retranslateUi();
} }
void MessagesSettingsPage::updateColor(const QString &value) { void MessagesSettingsPage::updateColor(const QString &value)
{
QColor colorToSet; QColor colorToSet;
colorToSet.setNamedColor("#" + value); colorToSet.setNamedColor("#" + value);
if (colorToSet.isValid()) { if (colorToSet.isValid()) {
@ -618,7 +718,8 @@ void MessagesSettingsPage::updateColor(const QString &value) {
} }
} }
void MessagesSettingsPage::updateHighlightColor(const QString &value) { void MessagesSettingsPage::updateHighlightColor(const QString &value)
{
QColor colorToSet; QColor colorToSet;
colorToSet.setNamedColor("#" + value); colorToSet.setNamedColor("#" + value);
if (colorToSet.isValid()) { if (colorToSet.isValid()) {
@ -627,22 +728,26 @@ void MessagesSettingsPage::updateHighlightColor(const QString &value) {
} }
} }
void MessagesSettingsPage::updateTextColor(int value) { void MessagesSettingsPage::updateTextColor(int value)
{
settingsCache->setChatMentionForeground(value); settingsCache->setChatMentionForeground(value);
updateMentionPreview(); updateMentionPreview();
} }
void MessagesSettingsPage::updateTextHighlightColor(int value) { void MessagesSettingsPage::updateTextHighlightColor(int value)
{
settingsCache->setChatHighlightForeground(value); settingsCache->setChatHighlightForeground(value);
updateHighlightPreview(); updateHighlightPreview();
} }
void MessagesSettingsPage::updateMentionPreview() { void MessagesSettingsPage::updateMentionPreview()
{
mentionColor->setStyleSheet("QLineEdit{background:#" + settingsCache->getChatMentionColor() + mentionColor->setStyleSheet("QLineEdit{background:#" + settingsCache->getChatMentionColor() +
";color: " + (settingsCache->getChatMentionForeground() ? "white" : "black") + ";}"); ";color: " + (settingsCache->getChatMentionForeground() ? "white" : "black") + ";}");
} }
void MessagesSettingsPage::updateHighlightPreview() { void MessagesSettingsPage::updateHighlightPreview()
{
highlightColor->setStyleSheet("QLineEdit{background:#" + settingsCache->getChatHighlightColor() + highlightColor->setStyleSheet("QLineEdit{background:#" + settingsCache->getChatHighlightColor() +
";color: " + (settingsCache->getChatHighlightForeground() ? "white" : "black") + ";}"); ";color: " + (settingsCache->getChatHighlightForeground() ? "white" : "black") + ";}");
} }
@ -725,7 +830,7 @@ SoundSettingsPage::SoundSettingsPage()
connect(masterVolumeSlider, SIGNAL(valueChanged(int)), masterVolumeSpinBox, SLOT(setValue(int))); connect(masterVolumeSlider, SIGNAL(valueChanged(int)), masterVolumeSpinBox, SLOT(setValue(int)));
connect(masterVolumeSpinBox, SIGNAL(valueChanged(int)), masterVolumeSlider, SLOT(setValue(int))); connect(masterVolumeSpinBox, SIGNAL(valueChanged(int)), masterVolumeSlider, SLOT(setValue(int)));
QGridLayout *soundGrid = new QGridLayout; auto *soundGrid = new QGridLayout;
soundGrid->addWidget(&soundEnabledCheckBox, 0, 0, 1, 3); soundGrid->addWidget(&soundEnabledCheckBox, 0, 0, 1, 3);
soundGrid->addWidget(&masterVolumeLabel, 1, 0); soundGrid->addWidget(&masterVolumeLabel, 1, 0);
soundGrid->addWidget(masterVolumeSlider, 1, 1); soundGrid->addWidget(masterVolumeSlider, 1, 1);
@ -737,7 +842,7 @@ SoundSettingsPage::SoundSettingsPage()
soundGroupBox = new QGroupBox; soundGroupBox = new QGroupBox;
soundGroupBox->setLayout(soundGrid); soundGroupBox->setLayout(soundGrid);
QVBoxLayout *mainLayout = new QVBoxLayout; auto *mainLayout = new QVBoxLayout;
mainLayout->addWidget(soundGroupBox); mainLayout->addWidget(soundGroupBox);
setLayout(mainLayout); setLayout(mainLayout);
@ -750,11 +855,13 @@ void SoundSettingsPage::themeBoxChanged(int index)
settingsCache->setSoundThemeName(themeDirs.at(index)); settingsCache->setSoundThemeName(themeDirs.at(index));
} }
void SoundSettingsPage::masterVolumeChanged(int value) { void SoundSettingsPage::masterVolumeChanged(int value)
{
masterVolumeSlider->setToolTip(QString::number(value)); masterVolumeSlider->setToolTip(QString::number(value));
} }
void SoundSettingsPage::retranslateUi() { void SoundSettingsPage::retranslateUi()
{
soundEnabledCheckBox.setText(tr("Enable &sounds")); soundEnabledCheckBox.setText(tr("Enable &sounds"));
themeLabel.setText(tr("Current sounds theme:")); themeLabel.setText(tr("Current sounds theme:"));
soundTestButton.setText(tr("Test system sound engine")); soundTestButton.setText(tr("Test system sound engine"));
@ -762,8 +869,7 @@ void SoundSettingsPage::retranslateUi() {
masterVolumeLabel.setText(tr("Master volume")); masterVolumeLabel.setText(tr("Master volume"));
} }
DlgSettings::DlgSettings(QWidget *parent) DlgSettings::DlgSettings(QWidget *parent) : QDialog(parent)
: QDialog(parent)
{ {
QRect rec = QApplication::desktop()->availableGeometry(); QRect rec = QApplication::desktop()->availableGeometry();
this->setMinimumSize(rec.width() / 2, rec.height() - 100); this->setMinimumSize(rec.width() / 2, rec.height() - 100);
@ -791,14 +897,14 @@ DlgSettings::DlgSettings(QWidget *parent)
createIcons(); createIcons();
contentsWidget->setCurrentRow(0); contentsWidget->setCurrentRow(0);
QVBoxLayout *vboxLayout = new QVBoxLayout; auto *vboxLayout = new QVBoxLayout;
vboxLayout->addWidget(contentsWidget); vboxLayout->addWidget(contentsWidget);
vboxLayout->addWidget(pagesWidget); vboxLayout->addWidget(pagesWidget);
QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok); auto *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok);
connect(buttonBox, SIGNAL(accepted()), this, SLOT(close())); connect(buttonBox, SIGNAL(accepted()), this, SLOT(close()));
QVBoxLayout *mainLayout = new QVBoxLayout; auto *mainLayout = new QVBoxLayout;
mainLayout->addLayout(vboxLayout); mainLayout->addLayout(vboxLayout);
mainLayout->addSpacing(12); mainLayout->addSpacing(12);
mainLayout->addWidget(buttonBox); mainLayout->addWidget(buttonBox);
@ -857,7 +963,8 @@ void DlgSettings::changePage(QListWidgetItem *current, QListWidgetItem *previous
pagesWidget->setCurrentIndex(contentsWidget->row(current)); pagesWidget->setCurrentIndex(contentsWidget->row(current));
} }
void DlgSettings::setTab(int index) { void DlgSettings::setTab(int index)
{
if (index <= contentsWidget->count()-1 && index >= 0) { if (index <= contentsWidget->count()-1 && index >= 0) {
changePage(contentsWidget->item(index), contentsWidget->currentItem()); changePage(contentsWidget->item(index), contentsWidget->currentItem());
contentsWidget->setCurrentRow(index); contentsWidget->setCurrentRow(index);
@ -883,65 +990,79 @@ void DlgSettings::closeEvent(QCloseEvent *event)
QString loadErrorMessage = tr("Unknown Error loading card database"); QString loadErrorMessage = tr("Unknown Error loading card database");
LoadStatus loadStatus = db->getLoadStatus(); LoadStatus loadStatus = db->getLoadStatus();
qDebug() << "Card Database load status: " << loadStatus; qDebug() << "Card Database load status: " << loadStatus;
switch(loadStatus) { switch(loadStatus)
case Ok: {
showLoadError = false; case Ok:
break; showLoadError = false;
case Invalid: break;
loadErrorMessage = case Invalid:
tr("Your card database is invalid.\n\n" loadErrorMessage =
"Cockatrice may not function correctly with an invalid database\n\n" tr("Your card database is invalid.\n\n"
"You may need to rerun oracle to update your card database.\n\n" "Cockatrice may not function correctly with an invalid database\n\n"
"Would you like to change your database location setting?"); "You may need to rerun oracle to update your card database.\n\n"
break; "Would you like to change your database location setting?");
case VersionTooOld: break;
loadErrorMessage = case VersionTooOld:
tr("Your card database version is too old.\n\n" loadErrorMessage =
"This can cause problems loading card information or images\n\n" tr("Your card database version is too old.\n\n"
"Usually this can be fixed by rerunning oracle to to update your card database.\n\n" "This can cause problems loading card information or images\n\n"
"Would you like to change your database location setting?"); "Usually this can be fixed by rerunning oracle to to update your card database.\n\n"
break; "Would you like to change your database location setting?");
case NotLoaded: break;
loadErrorMessage = case NotLoaded:
tr("Your card database did not finish loading\n\n" loadErrorMessage =
"Please file a ticket at http://github.com/Cockatrice/Cockatrice/issues with your cards.xml attached\n\n" tr("Your card database did not finish loading\n\n"
"Would you like to change your database location setting?"); "Please file a ticket at http://github.com/Cockatrice/Cockatrice/issues with your cards.xml attached\n\n"
break; "Would you like to change your database location setting?");
case FileError: break;
loadErrorMessage = case FileError:
tr("File Error loading your card database.\n\n" loadErrorMessage =
"Would you like to change your database location setting?"); tr("File Error loading your card database.\n\n"
break; "Would you like to change your database location setting?");
case NoCards: break;
loadErrorMessage = case NoCards:
tr("Your card database was loaded but contains no cards.\n\n" loadErrorMessage =
"Would you like to change your database location setting?"); tr("Your card database was loaded but contains no cards.\n\n"
break; "Would you like to change your database location setting?");
default: break;
loadErrorMessage = default:
tr("Unknown card database load status\n\n" loadErrorMessage =
"Please file a ticket at http://github.com/Cockatrice/Cockatrice/issues\n\n" tr("Unknown card database load status\n\n"
"Would you like to change your database location setting?"); "Please file a ticket at http://github.com/Cockatrice/Cockatrice/issues\n\n"
"Would you like to change your database location setting?");
break; break;
} }
if (showLoadError) if (showLoadError)
if (QMessageBox::critical(this, tr("Error"), loadErrorMessage, QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) { {
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 // 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 // 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;
} }
}
event->accept(); event->accept();
} }
@ -962,4 +1083,3 @@ void DlgSettings::retranslateUi()
contentsWidget->reset(); contentsWidget->reset();
} }

View file

@ -26,192 +26,227 @@ class QSpinBox;
class QSlider; class QSlider;
class QSpinBox; class QSpinBox;
class AbstractSettingsPage : public QWidget { class AbstractSettingsPage : public QWidget
public: {
virtual void retranslateUi() = 0; public:
virtual void retranslateUi() = 0;
}; };
class GeneralSettingsPage : public AbstractSettingsPage { class GeneralSettingsPage : public AbstractSettingsPage
{
Q_OBJECT Q_OBJECT
public: public:
GeneralSettingsPage(); GeneralSettingsPage();
void retranslateUi(); void retranslateUi() override;
private slots:
void deckPathButtonClicked(); private slots:
void replaysPathButtonClicked(); void deckPathButtonClicked();
void picsPathButtonClicked(); void replaysPathButtonClicked();
void clearDownloadedPicsButtonClicked(); void picsPathButtonClicked();
void cardDatabasePathButtonClicked(); void clearDownloadedPicsButtonClicked();
void tokenDatabasePathButtonClicked(); void cardDatabasePathButtonClicked();
void languageBoxChanged(int index); void tokenDatabasePathButtonClicked();
void setEnabledStatus(bool); void languageBoxChanged(int index);
void defaultUrlRestoreButtonClicked(); void setEnabledStatus(bool);
void fallbackUrlRestoreButtonClicked(); void defaultUrlRestoreButtonClicked();
private: void fallbackUrlRestoreButtonClicked();
QStringList findQmFiles();
QString languageName(const QString &qmFile); private:
QLineEdit *deckPathEdit; QStringList findQmFiles();
QLineEdit *replaysPathEdit; QString languageName(const QString &qmFile);
QLineEdit *picsPathEdit; QLineEdit *deckPathEdit;
QLineEdit *cardDatabasePathEdit; QLineEdit *replaysPathEdit;
QLineEdit *tokenDatabasePathEdit; QLineEdit *picsPathEdit;
QLineEdit *defaultUrlEdit; QLineEdit *cardDatabasePathEdit;
QLineEdit *fallbackUrlEdit; QLineEdit *tokenDatabasePathEdit;
QSpinBox pixmapCacheEdit; QLineEdit *defaultUrlEdit;
QGroupBox *personalGroupBox; QLineEdit *fallbackUrlEdit;
QGroupBox *pathsGroupBox; QSpinBox pixmapCacheEdit;
QComboBox languageBox; QGroupBox *personalGroupBox;
QCheckBox picDownloadCheckBox; QGroupBox *pathsGroupBox;
QCheckBox updateNotificationCheckBox; QComboBox languageBox;
QComboBox updateReleaseChannelBox; QCheckBox picDownloadCheckBox;
QLabel languageLabel; QCheckBox updateNotificationCheckBox;
QLabel pixmapCacheLabel; QComboBox updateReleaseChannelBox;
QLabel deckPathLabel; QLabel languageLabel;
QLabel replaysPathLabel; QLabel pixmapCacheLabel;
QLabel picsPathLabel; QLabel deckPathLabel;
QLabel cardDatabasePathLabel; QLabel replaysPathLabel;
QLabel tokenDatabasePathLabel; QLabel picsPathLabel;
QLabel defaultUrlLabel; QLabel cardDatabasePathLabel;
QLabel fallbackUrlLabel; QLabel tokenDatabasePathLabel;
QLabel urlLinkLabel; QLabel defaultUrlLabel;
QLabel updateReleaseChannelLabel; QLabel fallbackUrlLabel;
QPushButton clearDownloadedPicsButton; QLabel urlLinkLabel;
QPushButton defaultUrlRestoreButton; QLabel updateReleaseChannelLabel;
QPushButton fallbackUrlRestoreButton; QPushButton clearDownloadedPicsButton;
QPushButton defaultUrlRestoreButton;
QPushButton fallbackUrlRestoreButton;
}; };
class AppearanceSettingsPage : public AbstractSettingsPage { class AppearanceSettingsPage : public AbstractSettingsPage
{
Q_OBJECT Q_OBJECT
private slots: private slots:
void themeBoxChanged(int index); void themeBoxChanged(int index);
private:
QLabel themeLabel; private:
QComboBox themeBox; QLabel themeLabel;
QLabel minPlayersForMultiColumnLayoutLabel; QComboBox themeBox;
QLabel maxFontSizeForCardsLabel; QLabel minPlayersForMultiColumnLayoutLabel;
QCheckBox displayCardNamesCheckBox; QLabel maxFontSizeForCardsLabel;
QCheckBox cardScalingCheckBox; QCheckBox displayCardNamesCheckBox;
QCheckBox horizontalHandCheckBox; QCheckBox cardScalingCheckBox;
QCheckBox leftJustifiedHandCheckBox; QCheckBox horizontalHandCheckBox;
QCheckBox invertVerticalCoordinateCheckBox; QCheckBox leftJustifiedHandCheckBox;
QGroupBox *themeGroupBox; QCheckBox invertVerticalCoordinateCheckBox;
QGroupBox *cardsGroupBox; QGroupBox *themeGroupBox;
QGroupBox *handGroupBox; QGroupBox *cardsGroupBox;
QGroupBox *tableGroupBox; QGroupBox *handGroupBox;
QSpinBox minPlayersForMultiColumnLayoutEdit; QGroupBox *tableGroupBox;
QSpinBox maxFontSizeForCardsEdit; QSpinBox minPlayersForMultiColumnLayoutEdit;
public: QSpinBox maxFontSizeForCardsEdit;
AppearanceSettingsPage();
void retranslateUi(); public:
AppearanceSettingsPage();
void retranslateUi() override;
}; };
class UserInterfaceSettingsPage : public AbstractSettingsPage { class UserInterfaceSettingsPage : public AbstractSettingsPage
{
Q_OBJECT Q_OBJECT
private slots: private slots:
void setSpecNotificationEnabled(int); void setSpecNotificationEnabled(int);
private:
QCheckBox notificationsEnabledCheckBox;
QCheckBox specNotificationsEnabledCheckBox;
QCheckBox doubleClickToPlayCheckBox;
QCheckBox playToStackCheckBox;
QCheckBox annotateTokensCheckBox;
QCheckBox tapAnimationCheckBox;
QGroupBox *generalGroupBox;
QGroupBox *animationGroupBox;
public: private:
UserInterfaceSettingsPage(); QCheckBox notificationsEnabledCheckBox;
void retranslateUi(); QCheckBox specNotificationsEnabledCheckBox;
QCheckBox doubleClickToPlayCheckBox;
QCheckBox playToStackCheckBox;
QCheckBox annotateTokensCheckBox;
QCheckBox tapAnimationCheckBox;
QGroupBox *generalGroupBox;
QGroupBox *animationGroupBox;
public:
UserInterfaceSettingsPage();
void retranslateUi() override;
}; };
class DeckEditorSettingsPage : public AbstractSettingsPage { class DeckEditorSettingsPage : public AbstractSettingsPage
{
Q_OBJECT Q_OBJECT
public: public:
DeckEditorSettingsPage(); DeckEditorSettingsPage();
void retranslateUi(); void retranslateUi() override;
private slots: QString getLastUpdateTime();
signals:
private: private slots:
QGroupBox *generalGroupBox; void setSpoilersEnabled(bool);
void spoilerPathButtonClicked();
void updateSpoilers();
void unlockSettings();
private:
QCheckBox mcDownloadSpoilersCheckBox;
QLabel msDownloadSpoilersLabel;
QGroupBox *mpGeneralGroupBox;
QGroupBox *mpSpoilerGroupBox;
QLineEdit *mpSpoilerSavePathLineEdit;
QLabel mcSpoilerSaveLabel;
QLabel mcGeneralMessageLabel;
QLabel infoOnSpoilersLabel;
QPushButton *mpSpoilerPathButton;
QPushButton *updateNowButton;
}; };
class MessagesSettingsPage : public AbstractSettingsPage { class MessagesSettingsPage : public AbstractSettingsPage
{
Q_OBJECT Q_OBJECT
public: public:
MessagesSettingsPage(); MessagesSettingsPage();
void retranslateUi(); void retranslateUi() override;
private slots:
void actAdd();
void actRemove();
void updateColor(const QString &value);
void updateHighlightColor(const QString &value);
void updateTextColor(int value);
void updateTextHighlightColor(int value);
private:
QListWidget *messageList;
QAction *aAdd;
QAction *aRemove;
QCheckBox chatMentionCheckBox;
QCheckBox chatMentionCompleterCheckbox;
QCheckBox invertMentionForeground;
QCheckBox invertHighlightForeground;
QCheckBox ignoreUnregUsersMainChat;
QCheckBox ignoreUnregUserMessages;
QCheckBox messagePopups;
QCheckBox mentionPopups;
QCheckBox roomHistory;
QGroupBox *chatGroupBox;
QGroupBox *highlightGroupBox;
QGroupBox *messageShortcuts;
QLineEdit *mentionColor;
QLineEdit *highlightColor;
QLineEdit *customAlertString;
QLabel hexLabel;
QLabel hexHighlightLabel;
QLabel customAlertStringLabel;
void storeSettings(); private slots:
void updateMentionPreview(); void actAdd();
void updateHighlightPreview(); void actRemove();
void updateColor(const QString &value);
void updateHighlightColor(const QString &value);
void updateTextColor(int value);
void updateTextHighlightColor(int value);
private:
QListWidget *messageList;
QAction *aAdd;
QAction *aRemove;
QCheckBox chatMentionCheckBox;
QCheckBox chatMentionCompleterCheckbox;
QCheckBox invertMentionForeground;
QCheckBox invertHighlightForeground;
QCheckBox ignoreUnregUsersMainChat;
QCheckBox ignoreUnregUserMessages;
QCheckBox messagePopups;
QCheckBox mentionPopups;
QCheckBox roomHistory;
QGroupBox *chatGroupBox;
QGroupBox *highlightGroupBox;
QGroupBox *messageShortcuts;
QLineEdit *mentionColor;
QLineEdit *highlightColor;
QLineEdit *customAlertString;
QLabel hexLabel;
QLabel hexHighlightLabel;
QLabel customAlertStringLabel;
void storeSettings();
void updateMentionPreview();
void updateHighlightPreview();
}; };
class SoundSettingsPage : public AbstractSettingsPage { class SoundSettingsPage : public AbstractSettingsPage
{
Q_OBJECT Q_OBJECT
public: public:
SoundSettingsPage(); SoundSettingsPage();
void retranslateUi(); void retranslateUi() override;
private:
QLabel themeLabel; private:
QComboBox themeBox; QLabel themeLabel;
QGroupBox *soundGroupBox; QComboBox themeBox;
QPushButton soundTestButton; QGroupBox *soundGroupBox;
QCheckBox soundEnabledCheckBox; QPushButton soundTestButton;
QLabel masterVolumeLabel; QCheckBox soundEnabledCheckBox;
QSlider *masterVolumeSlider; QLabel masterVolumeLabel;
QSpinBox *masterVolumeSpinBox; QSlider *masterVolumeSlider;
private slots: QSpinBox *masterVolumeSpinBox;
void masterVolumeChanged(int value);
void themeBoxChanged(int index); private slots:
void masterVolumeChanged(int value);
void themeBoxChanged(int index);
}; };
class DlgSettings : public QDialog { class DlgSettings : public QDialog
{
Q_OBJECT Q_OBJECT
public: public:
DlgSettings(QWidget *parent = 0); explicit DlgSettings(QWidget *parent = nullptr);
void setTab(int index); void setTab(int index);
private slots:
void changePage(QListWidgetItem *current, QListWidgetItem *previous); private slots:
void updateLanguage(); void changePage(QListWidgetItem *current, QListWidgetItem *previous);
private: void updateLanguage();
QListWidget *contentsWidget;
QStackedWidget *pagesWidget; private:
QListWidgetItem *generalButton, *appearanceButton, *userInterfaceButton, *deckEditorButton, *messagesButton, *soundButton; QListWidget *contentsWidget;
QListWidgetItem *shortcutsButton; QStackedWidget *pagesWidget;
void createIcons(); QListWidgetItem *generalButton, *appearanceButton, *userInterfaceButton, *deckEditorButton, *messagesButton, *soundButton;
void retranslateUi(); QListWidgetItem *shortcutsButton;
protected: void createIcons();
void changeEvent(QEvent *event); void retranslateUi();
void closeEvent(QCloseEvent *event);
protected:
void changeEvent(QEvent *event) override;
void closeEvent(QCloseEvent *event) override;
}; };
#endif #endif

View file

@ -42,6 +42,7 @@
#include "soundengine.h" #include "soundengine.h"
#include "featureset.h" #include "featureset.h"
#include "logger.h" #include "logger.h"
#include "spoilerbackgroundupdater.h"
CardDatabase *db; CardDatabase *db;
QTranslator *translator, *qtTranslator; QTranslator *translator, *qtTranslator;
@ -129,6 +130,10 @@ int main(int argc, char *argv[])
settingsCache->setClientID(generateClientID()); settingsCache->setClientID(generateClientID());
// If spoiler mode is enabled, we will download the spoilers
// then reload the DB. otherwise just reload the DB
SpoilerBackgroundUpdater spoilerBackgroundUpdater;
ui.show(); ui.show();
qDebug("main(): ui.show() finished"); qDebug("main(): ui.show() finished");

View file

@ -7,6 +7,7 @@ class QSystemTrayIcon;
class SoundEngine; class SoundEngine;
extern CardDatabase *db; extern CardDatabase *db;
extern QSystemTrayIcon *trayIcon; extern QSystemTrayIcon *trayIcon;
extern QTranslator *translator; extern QTranslator *translator;
extern const QString translationPrefix; extern const QString translationPrefix;

View file

@ -1,36 +1,36 @@
#include "carddatabasesettings.h" #include "carddatabasesettings.h"
CardDatabaseSettings::CardDatabaseSettings(QString settingPath, QObject *parent) CardDatabaseSettings::CardDatabaseSettings(QString settingPath, QObject *parent) : SettingsManager(settingPath+"cardDatabase.ini", parent)
: SettingsManager(settingPath+"cardDatabase.ini", parent)
{ {
} }
void CardDatabaseSettings::setSortKey(QString shortName, unsigned int sortKey) void CardDatabaseSettings::setSortKey(QString shortName, unsigned int sortKey)
{ {
setValue(sortKey,"sortkey", "sets", shortName); setValue(sortKey, "sortkey", "sets", std::move(shortName));
} }
void CardDatabaseSettings::setEnabled(QString shortName, bool enabled) void CardDatabaseSettings::setEnabled(QString shortName, bool enabled)
{ {
setValue(enabled, "enabled", "sets", shortName); setValue(enabled, "enabled", "sets", std::move(shortName));
} }
void CardDatabaseSettings::setIsKnown(QString shortName, bool isknown) void CardDatabaseSettings::setIsKnown(QString shortName, bool isknown)
{ {
setValue(isknown, "isknown", "sets", shortName); setValue(isknown, "isknown", "sets", std::move(shortName));
} }
unsigned int CardDatabaseSettings::getSortKey(QString shortName) unsigned int CardDatabaseSettings::getSortKey(QString shortName)
{ {
return getValue("sortkey", "sets", shortName).toUInt(); return getValue("sortkey", "sets", std::move(shortName)).toUInt();
} }
bool CardDatabaseSettings::isEnabled(QString shortName) bool CardDatabaseSettings::isEnabled(QString shortName)
{ {
return getValue("enabled", "sets", shortName).toBool(); return getValue("enabled", "sets", std::move(shortName)).toBool();
} }
bool CardDatabaseSettings::isKnown(QString shortName) bool CardDatabaseSettings::isKnown(QString shortName)
{ {
return getValue("isknown", "sets", shortName).toBool(); return getValue("isknown", "sets", std::move(shortName)).toBool();
} }

View file

@ -1,43 +1,58 @@
#include "settingsmanager.h" #include "settingsmanager.h"
SettingsManager::SettingsManager(QString settingPath, QObject *parent) SettingsManager::SettingsManager(QString settingPath, QObject *parent) : QObject(parent), settings(settingPath, QSettings::IniFormat)
: QObject(parent),
settings(settingPath, QSettings::IniFormat)
{ {
} }
void SettingsManager::setValue(QVariant value, QString name, QString group, QString subGroup) void SettingsManager::setValue(QVariant value, QString name, QString group, QString subGroup)
{ {
if(!group.isEmpty()) if (!group.isEmpty())
{
settings.beginGroup(group); settings.beginGroup(group);
}
if(!subGroup.isEmpty()) if (!subGroup.isEmpty())
{
settings.beginGroup(subGroup); settings.beginGroup(subGroup);
}
settings.setValue(name, value); settings.setValue(name, value);
if(!subGroup.isEmpty()) if (!subGroup.isEmpty())
{
settings.endGroup(); settings.endGroup();
}
if(!group.isEmpty()) if (!group.isEmpty())
{
settings.endGroup(); settings.endGroup();
}
} }
QVariant SettingsManager::getValue(QString name, QString group, QString subGroup) QVariant SettingsManager::getValue(QString name, QString group, QString subGroup)
{ {
if(!group.isEmpty()) if (!group.isEmpty())
{
settings.beginGroup(group); settings.beginGroup(group);
}
if(!subGroup.isEmpty()) if (!subGroup.isEmpty())
{
settings.beginGroup(subGroup); settings.beginGroup(subGroup);
}
QVariant value = settings.value(name); QVariant value = settings.value(name);
if(!subGroup.isEmpty()) if (!subGroup.isEmpty())
{
settings.endGroup(); settings.endGroup();
}
if(!group.isEmpty()) if (!group.isEmpty())
{
settings.endGroup(); settings.endGroup();
}
return value; return value;
} }

View file

@ -171,6 +171,8 @@ SettingsCache::SettingsCache()
releaseChannels << new StableReleaseChannel(); releaseChannels << new StableReleaseChannel();
releaseChannels << new DevReleaseChannel(); releaseChannels << new DevReleaseChannel();
mbDownloadSpoilers = settings->value("personal/downloadspoilers", false).toBool();
notifyAboutUpdates = settings->value("personal/updatenotification", true).toBool(); notifyAboutUpdates = settings->value("personal/updatenotification", true).toBool();
updateReleaseChannel = settings->value("personal/updatereleasechannel", 0).toInt(); updateReleaseChannel = settings->value("personal/updatereleasechannel", 0).toInt();
@ -187,6 +189,7 @@ SettingsCache::SettingsCache()
cardDatabasePath = getSafeConfigFilePath("paths/carddatabase", dataPath + "/cards.xml"); cardDatabasePath = getSafeConfigFilePath("paths/carddatabase", dataPath + "/cards.xml");
tokenDatabasePath = getSafeConfigFilePath("paths/tokendatabase", dataPath + "/tokens.xml"); tokenDatabasePath = getSafeConfigFilePath("paths/tokendatabase", dataPath + "/tokens.xml");
spoilerDatabasePath = getSafeConfigFilePath("paths/spoilerdatabase", dataPath + "/spoiler.xml");
themeName = settings->value("theme/name").toString(); themeName = settings->value("theme/name").toString();
@ -348,6 +351,13 @@ void SettingsCache::setCardDatabasePath(const QString &_cardDatabasePath)
emit cardDatabasePathChanged(); emit cardDatabasePathChanged();
} }
void SettingsCache::setSpoilerDatabasePath(const QString &_spoilerDatabasePath)
{
spoilerDatabasePath = _spoilerDatabasePath;
settings->setValue("paths/spoilerdatabase", spoilerDatabasePath);
emit cardDatabasePathChanged();
}
void SettingsCache::setTokenDatabasePath(const QString &_tokenDatabasePath) void SettingsCache::setTokenDatabasePath(const QString &_tokenDatabasePath)
{ {
tokenDatabasePath = _tokenDatabasePath; tokenDatabasePath = _tokenDatabasePath;
@ -644,10 +654,17 @@ void SettingsCache::setRememberGameSettings(const bool _rememberGameSettings)
void SettingsCache::setNotifyAboutUpdate(int _notifyaboutupdate) void SettingsCache::setNotifyAboutUpdate(int _notifyaboutupdate)
{ {
notifyAboutUpdates = _notifyaboutupdate; notifyAboutUpdates = static_cast<bool>(_notifyaboutupdate);
settings->setValue("personal/updatenotification", notifyAboutUpdates); settings->setValue("personal/updatenotification", notifyAboutUpdates);
} }
void SettingsCache::setDownloadSpoilerStatus(bool _spoilerStatus)
{
mbDownloadSpoilers = _spoilerStatus;
settings->setValue("personal/downloadspoilers", mbDownloadSpoilers);
emit downloadSpoilerStatusChanged();
}
void SettingsCache::setUpdateReleaseChannel(int _updateReleaseChannel) void SettingsCache::setUpdateReleaseChannel(int _updateReleaseChannel)
{ {
updateReleaseChannel = _updateReleaseChannel; updateReleaseChannel = _updateReleaseChannel;

View file

@ -48,6 +48,8 @@ signals:
void pixmapCacheSizeChanged(int newSizeInMBs); void pixmapCacheSizeChanged(int newSizeInMBs);
void masterVolumeChanged(int value); void masterVolumeChanged(int value);
void chatMentionCompleterChanged(); void chatMentionCompleterChanged();
void downloadSpoilerTimeIndexChanged();
void downloadSpoilerStatusChanged();
private: private:
QSettings *settings; QSettings *settings;
ShortcutsSettings *shortcutsSettings; ShortcutsSettings *shortcutsSettings;
@ -60,8 +62,9 @@ private:
QByteArray mainWindowGeometry; QByteArray mainWindowGeometry;
QByteArray tokenDialogGeometry; QByteArray tokenDialogGeometry;
QString lang; QString lang;
QString deckPath, replaysPath, picsPath, customPicsPath, cardDatabasePath, customCardDatabasePath, tokenDatabasePath, themeName; QString deckPath, replaysPath, picsPath, customPicsPath, cardDatabasePath, customCardDatabasePath, spoilerDatabasePath, tokenDatabasePath, themeName;
bool notifyAboutUpdates; bool notifyAboutUpdates;
bool mbDownloadSpoilers;
int updateReleaseChannel; int updateReleaseChannel;
int maxFontSize; int maxFontSize;
bool picDownload; bool picDownload;
@ -130,6 +133,7 @@ public:
QString getCustomPicsPath() const { return customPicsPath; } QString getCustomPicsPath() const { return customPicsPath; }
QString getCustomCardDatabasePath() const { return customCardDatabasePath; } QString getCustomCardDatabasePath() const { return customCardDatabasePath; }
QString getCardDatabasePath() const { return cardDatabasePath; } QString getCardDatabasePath() const { return cardDatabasePath; }
QString getSpoilerCardDatabasePath() const { return spoilerDatabasePath; }
QString getTokenDatabasePath() const { return tokenDatabasePath; } QString getTokenDatabasePath() const { return tokenDatabasePath; }
QString getThemeName() const { return themeName; } QString getThemeName() const { return themeName; }
QString getChatMentionColor() const { return chatMentionColor; } QString getChatMentionColor() const { return chatMentionColor; }
@ -200,7 +204,10 @@ public:
GameFiltersSettings& gameFilters() const { return *gameFiltersSettings; } GameFiltersSettings& gameFilters() const { return *gameFiltersSettings; }
LayoutsSettings& layouts() const { return *layoutsSettings; } LayoutsSettings& layouts() const { return *layoutsSettings; }
bool getIsPortableBuild() const { return isPortableBuild; } bool getIsPortableBuild() const { return isPortableBuild; }
bool getDownloadSpoilersStatus() const { return mbDownloadSpoilers; }
public slots: public slots:
void setDownloadSpoilerStatus(bool _spoilerStatus);
void setMainWindowGeometry(const QByteArray &_mainWindowGeometry); void setMainWindowGeometry(const QByteArray &_mainWindowGeometry);
void setTokenDialogGeometry(const QByteArray &_tokenDialog); void setTokenDialogGeometry(const QByteArray &_tokenDialog);
void setLang(const QString &_lang); void setLang(const QString &_lang);
@ -208,6 +215,7 @@ public slots:
void setReplaysPath(const QString &_replaysPath); void setReplaysPath(const QString &_replaysPath);
void setPicsPath(const QString &_picsPath); void setPicsPath(const QString &_picsPath);
void setCardDatabasePath(const QString &_cardDatabasePath); void setCardDatabasePath(const QString &_cardDatabasePath);
void setSpoilerDatabasePath(const QString &_spoilerDatabasePath);
void setTokenDatabasePath(const QString &_tokenDatabasePath); void setTokenDatabasePath(const QString &_tokenDatabasePath);
void setThemeName(const QString &_themeName); void setThemeName(const QString &_themeName);
void setChatMentionColor(const QString &_chatMentionColor); void setChatMentionColor(const QString &_chatMentionColor);

View file

@ -0,0 +1,251 @@
#include <QDateTime>
#include <QDebug>
#include <QUrl>
#include <QNetworkReply>
#include <QMessageBox>
#include <QFile>
#include <QApplication>
#include <QtConcurrent>
#include <QCryptographicHash>
#include "spoilerbackgroundupdater.h"
#include "settingscache.h"
#include "carddatabase.h"
#include "main.h"
#include "window_main.h"
#define SPOILERS_STATUS_URL "https://raw.githubusercontent.com/Cockatrice/Magic-Spoiler/files/SpoilerSeasonEnabled"
#define SPOILERS_URL "https://raw.githubusercontent.com/Cockatrice/Magic-Spoiler/files/spoiler.xml"
SpoilerBackgroundUpdater::SpoilerBackgroundUpdater(QObject *apParent) : QObject(apParent), cardUpdateProcess(nullptr)
{
isSpoilerDownloadEnabled = settingsCache->getDownloadSpoilersStatus();
if (isSpoilerDownloadEnabled)
{
// Start the process of checking if we're in spoiler season
// File exists means we're in spoiler season
// We will load the database before attempting to download spoilers, incase they fail
QtConcurrent::run(db, &CardDatabase::loadCardDatabases);
startSpoilerDownloadProcess(SPOILERS_STATUS_URL, false);
}
}
void SpoilerBackgroundUpdater::startSpoilerDownloadProcess(QString url, bool saveResults)
{
auto spoilerURL = QUrl(url);
downloadFromURL(spoilerURL, saveResults);
}
void SpoilerBackgroundUpdater::downloadFromURL(QUrl url, bool saveResults)
{
auto *nam = new QNetworkAccessManager(this);
QNetworkReply *reply = nam->get(QNetworkRequest(url));
if (saveResults)
{
// This will write out to the file (used for spoiler.xml)
connect(reply, SIGNAL(finished()), this, SLOT(actDownloadFinishedSpoilersFile()));
}
else
{
// This will check the status (used to see if we're in spoiler season or not)
connect(reply, SIGNAL(finished()), this, SLOT(actCheckIfSpoilerSeasonEnabled()));
}
}
void SpoilerBackgroundUpdater::actDownloadFinishedSpoilersFile()
{
// Check for server reply
auto *reply = dynamic_cast<QNetworkReply *>(sender());
QNetworkReply::NetworkError errorCode = reply->error();
if (errorCode == QNetworkReply::NoError)
{
spoilerData = reply->readAll();
// Save the spoiler.xml file to the disk
saveDownloadedFile(spoilerData);
reply->deleteLater();
emit spoilerCheckerDone();
}
else
{
qDebug() << "Error downloading spoilers file" << errorCode;
emit spoilerCheckerDone();
}
}
bool SpoilerBackgroundUpdater::deleteSpoilerFile()
{
QString fileName = settingsCache->getSpoilerCardDatabasePath();
QFileInfo fi(fileName);
QDir fileDir(fi.path());
QFile file(fileName);
// Delete the spoiler.xml file
if (file.exists() && file.remove())
{
qDebug() << "Deleting spoiler.xml";
return true;
}
qDebug() << "Error: Spoiler.xml not found or not deleted";
return false;
}
void SpoilerBackgroundUpdater::actCheckIfSpoilerSeasonEnabled()
{
auto *response = dynamic_cast<QNetworkReply *>(sender());
QNetworkReply::NetworkError errorCode = response->error();
if (errorCode == QNetworkReply::ContentNotFoundError)
{
// Spoiler season is offline at this point, so the spoiler.xml file can be safely deleted
// The user should run Oracle to get the latest card information
if (deleteSpoilerFile() && trayIcon)
{
trayIcon->showMessage(tr("Spoilers season has ended"), tr("Deleting spoiler.xml. Please run Oracle"));
}
qDebug() << "Spoiler Season Offline";
emit spoilerCheckerDone();
}
else if (errorCode == QNetworkReply::NoError)
{
qDebug() << "Spoiler Service Online";
startSpoilerDownloadProcess(SPOILERS_URL, true);
}
else if (errorCode == QNetworkReply::HostNotFoundError)
{
if (trayIcon)
{
trayIcon->showMessage(tr("Spoilers download failed"), tr("No internet connection"));
}
qDebug() << "Spoiler download failed due to no internet connection";
emit spoilerCheckerDone();
}
else
{
if (trayIcon)
{
trayIcon->showMessage(tr("Spoilers download failed"), tr("Error") + " " + errorCode);
}
qDebug() << "Spoiler download failed with reason" << errorCode;
emit spoilerCheckerDone();
}
}
bool SpoilerBackgroundUpdater::saveDownloadedFile(QByteArray data)
{
QString fileName = settingsCache->getSpoilerCardDatabasePath();
QFileInfo fi(fileName);
QDir fileDir(fi.path());
if (!fileDir.exists() && !fileDir.mkpath(fileDir.absolutePath()))
{
return false;
}
// Check if the data matches. If it does, then spoilers are up to date.
if (getHash(fileName) == getHash(data))
{
if (trayIcon)
{
trayIcon->showMessage(tr("Spoilers already up to date"), tr("No new spoilers added"));
}
qDebug() << "Spoilers Up to Date";
return false;
}
QFile file(fileName);
if (!file.open(QIODevice::WriteOnly))
{
qDebug() << "Spoiler Service Error: File open (w) failed for" << fileName;
file.close();
return false;
}
if (file.write(data) == -1)
{
qDebug() << "Spoiler Service Error: File write (w) failed for" << fileName;
file.close();
return false;
}
file.close();
// Data written, so reload the card database
qDebug() << "Spoiler Service Data Written";
QtConcurrent::run(db, &CardDatabase::loadCardDatabases);
// If the user has notifications enabled, let them know
// when the database was last updated
if (trayIcon)
{
QList<QByteArray> lines = data.split('\n');
foreach (QByteArray line, lines)
{
if (line.indexOf("created:") > -1)
{
QString timeStamp = QString(line).replace("created:", "").trimmed();
timeStamp.chop(6); // Remove " (UTC)"
auto utcTime = QDateTime::fromString(timeStamp, QString("ddd, MMM dd yyyy, hh:mm:ss"));
utcTime.setTimeSpec(Qt::UTC);
QString localTime = utcTime.toLocalTime().toString("MMM d, hh:mm");
trayIcon->showMessage(tr("Spoilers have been updated!"), tr("Last change:") + " " + localTime);
emit spoilersUpdatedSuccessfully();
return true;
}
}
}
return true;
}
QByteArray SpoilerBackgroundUpdater::getHash(const QString fileName)
{
QFile file(fileName);
if (file.open(QFile::ReadOnly))
{
// Only read the first 512 bytes (enough to get the "created" tag)
const QByteArray bytes = file.read(512);
QCryptographicHash hash(QCryptographicHash::Algorithm::Md5);
hash.addData(bytes);
qDebug() << "File Hash =" << hash.result();
file.close();
return hash.result();
}
else
{
qDebug() << "getHash ReadOnly failed!";
file.close();
return QByteArray();
}
}
QByteArray SpoilerBackgroundUpdater::getHash(QByteArray data)
{
// Only read the first 512 bytes (enough to get the "created" tag)
const QByteArray bytes = data.left(512);
QCryptographicHash hash(QCryptographicHash::Algorithm::Md5);
hash.addData(bytes);
qDebug() << "Data Hash =" << hash.result();
return hash.result();
}

View file

@ -0,0 +1,35 @@
#ifndef COCKATRICE_SPOILER_DOWNLOADER_H
#define COCKATRICE_SPOILER_DOWNLOADER_H
#include <QObject>
#include <QProcess>
#include <QByteArray>
class SpoilerBackgroundUpdater : public QObject
{
Q_OBJECT
public:
explicit SpoilerBackgroundUpdater(QObject *apParent = nullptr);
inline QString getCardUpdaterBinaryName() { return "oracle"; };
QByteArray getHash(const QString fileName);
QByteArray getHash(QByteArray data);
static bool deleteSpoilerFile();
private slots:
void actDownloadFinishedSpoilersFile();
void actCheckIfSpoilerSeasonEnabled();
private:
bool isSpoilerDownloadEnabled;
QProcess *cardUpdateProcess;
QByteArray spoilerData;
void startSpoilerDownloadProcess(QString url, bool saveResults);
void downloadFromURL(QUrl url, bool saveResults);
bool saveDownloadedFile(QByteArray data);
signals:
void spoilersUpdatedSuccessfully();
void spoilerCheckerDone();
};
#endif //COCKATRICE_SPOILER_DOWNLOADER_H

View file

@ -76,11 +76,11 @@ const QStringList MainWindow::fileNameFilters = QStringList()
void MainWindow::updateTabMenu(const QList<QMenu *> &newMenuList) void MainWindow::updateTabMenu(const QList<QMenu *> &newMenuList)
{ {
for (int i = 0; i < tabMenus.size(); ++i) for (auto &tabMenu : tabMenus)
menuBar()->removeAction(tabMenus[i]->menuAction()); menuBar()->removeAction(tabMenu->menuAction());
tabMenus = newMenuList; tabMenus = newMenuList;
for (int i = 0; i < tabMenus.size(); ++i) for (auto &tabMenu : tabMenus)
menuBar()->insertMenu(helpMenu->menuAction(), tabMenus[i]); menuBar()->insertMenu(helpMenu->menuAction(), tabMenu);
} }
void MainWindow::processConnectionClosedEvent(const Event_ConnectionClosed &event) void MainWindow::processConnectionClosedEvent(const Event_ConnectionClosed &event)
@ -166,10 +166,10 @@ void MainWindow::activateAccepted()
void MainWindow::actConnect() void MainWindow::actConnect()
{ {
DlgConnect *dlg = new DlgConnect(this); auto *dlg = new DlgConnect(this);
connect(dlg, SIGNAL(sigStartForgotPasswordRequest()), this, SLOT(actForgotPasswordRequest())); connect(dlg, SIGNAL(sigStartForgotPasswordRequest()), this, SLOT(actForgotPasswordRequest()));
if (dlg->exec()) if (dlg->exec())
client->connectToServer(dlg->getHost(), dlg->getPort(), dlg->getPlayerName(), dlg->getPassword()); client->connectToServer(dlg->getHost(), static_cast<unsigned int>(dlg->getPort()), dlg->getPlayerName(), dlg->getPassword());
} }
void MainWindow::actRegister() void MainWindow::actRegister()
@ -179,7 +179,7 @@ void MainWindow::actRegister()
{ {
client->registerToServer( client->registerToServer(
dlg.getHost(), dlg.getHost(),
dlg.getPort(), static_cast<unsigned int>(dlg.getPort()),
dlg.getPlayerName(), dlg.getPlayerName(),
dlg.getPassword(), dlg.getPassword(),
dlg.getEmail(), dlg.getEmail(),
@ -220,7 +220,7 @@ void MainWindow::actSinglePlayer()
tabSupervisor->startLocal(localClients); tabSupervisor->startLocal(localClients);
Command_CreateGame createCommand; Command_CreateGame createCommand;
createCommand.set_max_players(numberPlayers); createCommand.set_max_players(static_cast<google::protobuf::uint32>(numberPlayers));
mainClient->sendCommand(mainClient->prepareRoomCommand(createCommand, 0)); mainClient->sendCommand(mainClient->prepareRoomCommand(createCommand, 0));
} }
@ -239,7 +239,7 @@ void MainWindow::actWatchReplay()
QByteArray buf = file.readAll(); QByteArray buf = file.readAll();
file.close(); file.close();
GameReplay *replay = new GameReplay; auto *replay = new GameReplay;
replay->ParseFromArray(buf.data(), buf.size()); replay->ParseFromArray(buf.data(), buf.size());
tabSupervisor->openReplay(replay); tabSupervisor->openReplay(replay);
@ -248,7 +248,7 @@ void MainWindow::actWatchReplay()
void MainWindow::localGameEnded() void MainWindow::localGameEnded()
{ {
delete localServer; delete localServer;
localServer = 0; localServer = nullptr;
aConnect->setEnabled(true); aConnect->setEnabled(true);
aRegister->setEnabled(true); aRegister->setEnabled(true);
@ -257,7 +257,7 @@ void MainWindow::localGameEnded()
void MainWindow::actDeckEditor() void MainWindow::actDeckEditor()
{ {
tabSupervisor->addDeckEditorTab(0); tabSupervisor->addDeckEditorTab(nullptr);
} }
void MainWindow::actFullScreen(bool checked) void MainWindow::actFullScreen(bool checked)
@ -655,7 +655,7 @@ void MainWindow::createMenus()
} }
MainWindow::MainWindow(QWidget *parent) MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent), localServer(0), bHasActivated(false), cardUpdateProcess(0), logviewDialog(0) : QMainWindow(parent), localServer(nullptr), bHasActivated(false), cardUpdateProcess(nullptr), logviewDialog(nullptr)
{ {
connect(settingsCache, SIGNAL(pixmapCacheSizeChanged(int)), this, SLOT(pixmapCacheSizeChanged(int))); connect(settingsCache, SIGNAL(pixmapCacheSizeChanged(int)), this, SLOT(pixmapCacheSizeChanged(int)));
pixmapCacheSizeChanged(settingsCache->getPixmapCacheSize()); pixmapCacheSizeChanged(settingsCache->getPixmapCacheSize());
@ -691,7 +691,7 @@ MainWindow::MainWindow(QWidget *parent)
connect(tabSupervisor, SIGNAL(setMenu(QList<QMenu *>)), this, SLOT(updateTabMenu(QList<QMenu *>))); connect(tabSupervisor, SIGNAL(setMenu(QList<QMenu *>)), this, SLOT(updateTabMenu(QList<QMenu *>)));
connect(tabSupervisor, SIGNAL(localGameEnded()), this, SLOT(localGameEnded())); connect(tabSupervisor, SIGNAL(localGameEnded()), this, SLOT(localGameEnded()));
connect(tabSupervisor, SIGNAL(showWindowIfHidden()), this, SLOT(showWindowIfHidden())); connect(tabSupervisor, SIGNAL(showWindowIfHidden()), this, SLOT(showWindowIfHidden()));
tabSupervisor->addDeckEditorTab(0); tabSupervisor->addDeckEditorTab(nullptr);
setCentralWidget(tabSupervisor); setCentralWidget(tabSupervisor);
@ -699,7 +699,7 @@ MainWindow::MainWindow(QWidget *parent)
resize(900, 700); resize(900, 700);
restoreGeometry(settingsCache->getMainWindowGeometry()); restoreGeometry(settingsCache->getMainWindowGeometry());
aFullScreen->setChecked(windowState() & Qt::WindowFullScreen); aFullScreen->setChecked(static_cast<bool>(windowState() & Qt::WindowFullScreen));
if (QSystemTrayIcon::isSystemTrayAvailable()) { if (QSystemTrayIcon::isSystemTrayAvailable()) {
createTrayActions(); createTrayActions();
@ -712,7 +712,12 @@ MainWindow::MainWindow(QWidget *parent)
connect(db, SIGNAL(cardDatabaseLoadingFailed()), this, SLOT(cardDatabaseLoadingFailed())); connect(db, SIGNAL(cardDatabaseLoadingFailed()), this, SLOT(cardDatabaseLoadingFailed()));
connect(db, SIGNAL(cardDatabaseNewSetsFound(int, QStringList)), this, SLOT(cardDatabaseNewSetsFound(int, QStringList))); connect(db, SIGNAL(cardDatabaseNewSetsFound(int, QStringList)), this, SLOT(cardDatabaseNewSetsFound(int, QStringList)));
connect(db, SIGNAL(cardDatabaseAllNewSetsEnabled()), this, SLOT(cardDatabaseAllNewSetsEnabled())); connect(db, SIGNAL(cardDatabaseAllNewSetsEnabled()), this, SLOT(cardDatabaseAllNewSetsEnabled()));
QtConcurrent::run(db, &CardDatabase::loadCardDatabases);
if (! settingsCache->getDownloadSpoilersStatus())
{
qDebug() << "Spoilers Disabled";
QtConcurrent::run(db, &CardDatabase::loadCardDatabases);
}
} }
MainWindow::~MainWindow() MainWindow::~MainWindow()
@ -727,7 +732,7 @@ MainWindow::~MainWindow()
} }
void MainWindow::createTrayIcon() { void MainWindow::createTrayIcon() {
QMenu *trayIconMenu = new QMenu(this); auto *trayIconMenu = new QMenu(this);
trayIconMenu->addAction(closeAction); trayIconMenu->addAction(closeAction);
trayIcon = new QSystemTrayIcon(this); trayIcon = new QSystemTrayIcon(this);
@ -754,7 +759,7 @@ void MainWindow::promptForgotPasswordChallenge()
{ {
DlgForgotPasswordChallenge dlg(this); DlgForgotPasswordChallenge dlg(this);
if (dlg.exec()) if (dlg.exec())
client->submitForgotPasswordChallengeToServer(dlg.getHost(),dlg.getPort(),dlg.getPlayerName(),dlg.getEmail()); client->submitForgotPasswordChallengeToServer(dlg.getHost(), static_cast<unsigned int>(dlg.getPort()), dlg.getPlayerName(), dlg.getEmail());
} }
@ -794,7 +799,7 @@ void MainWindow::changeEvent(QEvent *event)
if(settingsCache->servers().getAutoConnect()) { if(settingsCache->servers().getAutoConnect()) {
qDebug() << "Attempting auto-connect..."; qDebug() << "Attempting auto-connect...";
DlgConnect dlg(this); DlgConnect dlg(this);
client->connectToServer(dlg.getHost(), dlg.getPort(), dlg.getPlayerName(), dlg.getPassword()); client->connectToServer(dlg.getHost(), static_cast<unsigned int>(dlg.getPort()), dlg.getPlayerName(), dlg.getPassword());
} }
} }
} }
@ -856,11 +861,17 @@ void MainWindow::cardDatabaseNewSetsFound(int numUnknownSets, QStringList unknow
msgBox.exec(); msgBox.exec();
if (msgBox.clickedButton() == yesButton) { if (msgBox.clickedButton() == yesButton)
{
db->enableAllUnknownSets(); db->enableAllUnknownSets();
} else if (msgBox.clickedButton() == noButton) { QtConcurrent::run(db, &CardDatabase::loadCardDatabases);
}
else if (msgBox.clickedButton() == noButton)
{
db->markAllSetsAsKnown(); db->markAllSetsAsKnown();
} else if (msgBox.clickedButton() == settingsButton) { }
else if (msgBox.clickedButton() == settingsButton)
{
db->markAllSetsAsKnown(); db->markAllSetsAsKnown();
actEditSets(); actEditSets();
} }
@ -873,10 +884,9 @@ void MainWindow::cardDatabaseAllNewSetsEnabled()
} }
/* CARD UPDATER */ /* CARD UPDATER */
void MainWindow::actCheckCardUpdates() void MainWindow::actCheckCardUpdates()
{ {
if(cardUpdateProcess) if (cardUpdateProcess)
{ {
QMessageBox::information(this, tr("Information"), tr("A card database update is already running.")); QMessageBox::information(this, tr("Information"), tr("A card database update is already running."));
return; return;
@ -946,7 +956,7 @@ void MainWindow::cardUpdateError(QProcess::ProcessError err)
} }
cardUpdateProcess->deleteLater(); cardUpdateProcess->deleteLater();
cardUpdateProcess = 0; cardUpdateProcess = nullptr;
QMessageBox::warning(this, tr("Error"), tr("The card database updater exited with an error: %1").arg(error)); QMessageBox::warning(this, tr("Error"), tr("The card database updater exited with an error: %1").arg(error));
} }
@ -954,10 +964,9 @@ void MainWindow::cardUpdateError(QProcess::ProcessError err)
void MainWindow::cardUpdateFinished(int, QProcess::ExitStatus) void MainWindow::cardUpdateFinished(int, QProcess::ExitStatus)
{ {
cardUpdateProcess->deleteLater(); cardUpdateProcess->deleteLater();
cardUpdateProcess = 0; cardUpdateProcess = nullptr;
QMessageBox::information(this, tr("Information"), tr("Update completed successfully.\nCockatrice will now reload the card database.")); QMessageBox::information(this, tr("Information"), tr("Update completed successfully.\nCockatrice will now reload the card database."));
QtConcurrent::run(db, &CardDatabase::loadCardDatabases); QtConcurrent::run(db, &CardDatabase::loadCardDatabases);
} }
@ -989,7 +998,7 @@ void MainWindow::actOpenCustomFolder()
#if defined(Q_OS_MAC) #if defined(Q_OS_MAC)
QStringList scriptArgs; QStringList scriptArgs;
scriptArgs << QLatin1String("-e"); scriptArgs << QLatin1String("-e");
scriptArgs << QString::fromLatin1("tell application \"Finder\" to open POSIX file \"%1\"").arg(dir); scriptArgs << QString::fromLatin1(R"(tell application "Finder" to open POSIX file "%1")").arg(dir);
scriptArgs << QLatin1String("-e"); scriptArgs << QLatin1String("-e");
scriptArgs << QLatin1String("tell application \"Finder\" to activate"); scriptArgs << QLatin1String("tell application \"Finder\" to activate");
@ -1008,7 +1017,7 @@ void MainWindow::actOpenCustomsetsFolder()
#if defined(Q_OS_MAC) #if defined(Q_OS_MAC)
QStringList scriptArgs; QStringList scriptArgs;
scriptArgs << QLatin1String("-e"); scriptArgs << QLatin1String("-e");
scriptArgs << QString::fromLatin1("tell application \"Finder\" to open POSIX file \"%1\"").arg(dir); scriptArgs << QString::fromLatin1(R"(tell application "Finder" to open POSIX file "%1")").arg(dir);
scriptArgs << QLatin1String("-e"); scriptArgs << QLatin1String("-e");
scriptArgs << QLatin1String("tell application \"Finder\" to activate"); scriptArgs << QLatin1String("tell application \"Finder\" to activate");
@ -1025,16 +1034,20 @@ void MainWindow::actAddCustomSet()
QFileDialog dialog(this, tr("Load sets/cards"), QDir::homePath()); QFileDialog dialog(this, tr("Load sets/cards"), QDir::homePath());
dialog.setNameFilters(MainWindow::fileNameFilters); dialog.setNameFilters(MainWindow::fileNameFilters);
if (!dialog.exec()) if (!dialog.exec())
{
return; return;
}
QString fullFilePath = dialog.selectedFiles().at(0); QString fullFilePath = dialog.selectedFiles().at(0);
if (!QFile::exists(fullFilePath)) { if (!QFile::exists(fullFilePath))
{
QMessageBox::warning(this, tr("Load sets/cards"), tr("Selected file cannot be found.")); QMessageBox::warning(this, tr("Load sets/cards"), tr("Selected file cannot be found."));
return; return;
} }
if (QFileInfo(fullFilePath).suffix() != "xml") { // fileName = *.xml if (QFileInfo(fullFilePath).suffix() != "xml") // fileName = *.xml
{
QMessageBox::warning(this, tr("Load sets/cards"), tr("You can only import XML databases at this time.")); QMessageBox::warning(this, tr("Load sets/cards"), tr("You can only import XML databases at this time."));
return; return;
} }
@ -1042,7 +1055,7 @@ void MainWindow::actAddCustomSet()
QDir dir = settingsCache->getCustomCardDatabasePath(); QDir dir = settingsCache->getCustomCardDatabasePath();
int nextPrefix = getNextCustomSetPrefix(dir); int nextPrefix = getNextCustomSetPrefix(dir);
bool res = false; bool res;
QString fileName = QFileInfo(fullFilePath).fileName(); QString fileName = QFileInfo(fullFilePath).fileName();
if (fileName.compare("spoiler.xml", Qt::CaseInsensitive) == 0) if (fileName.compare("spoiler.xml", Qt::CaseInsensitive) == 0)
@ -1078,7 +1091,8 @@ void MainWindow::actAddCustomSet()
} }
} }
int MainWindow::getNextCustomSetPrefix(QDir dataDir) { int MainWindow::getNextCustomSetPrefix(QDir dataDir)
{
QStringList files = dataDir.entryList(); QStringList files = dataDir.entryList();
int maxIndex = 0; int maxIndex = 0;
@ -1094,7 +1108,7 @@ int MainWindow::getNextCustomSetPrefix(QDir dataDir) {
void MainWindow::actEditSets() void MainWindow::actEditSets()
{ {
WndSets *w = new WndSets; auto *w = new WndSets;
w->setWindowModality(Qt::WindowModal); w->setWindowModality(Qt::WindowModal);
w->show(); w->show();
} }
@ -1110,7 +1124,7 @@ void MainWindow::actForgotPasswordRequest()
{ {
DlgForgotPasswordRequest dlg(this); DlgForgotPasswordRequest dlg(this);
if (dlg.exec()) if (dlg.exec())
client->requestForgotPasswordToServer(dlg.getHost(), dlg.getPort(), dlg.getPlayerName()); client->requestForgotPasswordToServer(dlg.getHost(), static_cast<unsigned int>(dlg.getPort()), dlg.getPlayerName());
} }
void MainWindow::forgotPasswordSuccess() void MainWindow::forgotPasswordSuccess()
@ -1134,5 +1148,8 @@ void MainWindow::promptForgotPasswordReset()
QMessageBox::information(this, tr("Forgot Password"), tr("Activation request received, please check your email for an activation token.")); QMessageBox::information(this, tr("Forgot Password"), tr("Activation request received, please check your email for an activation token."));
DlgForgotPasswordReset dlg(this); DlgForgotPasswordReset dlg(this);
if (dlg.exec()) if (dlg.exec())
client->submitForgotPasswordResetToServer(dlg.getHost(), dlg.getPort(), dlg.getPlayerName(), dlg.getToken(), dlg.getPassword()); {
client->submitForgotPasswordResetToServer(dlg.getHost(), static_cast<unsigned int>(dlg.getPort()),
dlg.getPlayerName(), dlg.getToken(), dlg.getPassword());
}
} }

View file

@ -40,6 +40,8 @@ class DlgViewLog;
class MainWindow : public QMainWindow { class MainWindow : public QMainWindow {
Q_OBJECT Q_OBJECT
public slots:
void actCheckCardUpdates();
private slots: private slots:
void updateTabMenu(const QList<QMenu *> &newMenuList); void updateTabMenu(const QList<QMenu *> &newMenuList);
void statusChanged(ClientStatus _status); void statusChanged(ClientStatus _status);
@ -78,7 +80,6 @@ private slots:
void promptForgotPasswordChallenge(); void promptForgotPasswordChallenge();
void showWindowIfHidden(); void showWindowIfHidden();
void actCheckCardUpdates();
void cardUpdateError(QProcess::ProcessError err); void cardUpdateError(QProcess::ProcessError err);
void cardUpdateFinished(int exitCode, QProcess::ExitStatus exitStatus); void cardUpdateFinished(int exitCode, QProcess::ExitStatus exitStatus);
void refreshShortcuts(); void refreshShortcuts();

View file

@ -3,6 +3,7 @@
#include <QIcon> #include <QIcon>
#include <QTranslator> #include <QTranslator>
#include <QLibraryInfo> #include <QLibraryInfo>
#include <QCommandLineParser>
#include "main.h" #include "main.h"
#include "oraclewizard.h" #include "oraclewizard.h"
@ -15,6 +16,7 @@ ThemeManager *themeManager;
const QString translationPrefix = "oracle"; const QString translationPrefix = "oracle";
QString translationPath; QString translationPath;
bool isSpoilersOnly;
void installNewTranslator() void installNewTranslator()
{ {
@ -35,6 +37,13 @@ int main(int argc, char *argv[])
// this can't be changed, as it influences the default savepath for cards.xml // this can't be changed, as it influences the default savepath for cards.xml
QCoreApplication::setApplicationName("Cockatrice"); QCoreApplication::setApplicationName("Cockatrice");
// If the program is opened with the -s flag, it will only do spoilers. Otherwise it will do MTGJSON/Tokens
QCommandLineParser parser;
QCommandLineOption showProgressOption("s", QCoreApplication::translate("main", "Only run in spoiler mode"));
parser.addOption(showProgressOption);
parser.process(app);
isSpoilersOnly = parser.isSet(showProgressOption);
#ifdef Q_OS_MAC #ifdef Q_OS_MAC
translationPath = qApp->applicationDirPath() + "/../Resources/translations"; translationPath = qApp->applicationDirPath() + "/../Resources/translations";
#elif defined(Q_OS_WIN) #elif defined(Q_OS_WIN)

View file

@ -6,6 +6,7 @@ class QTranslator;
extern QTranslator *translator; extern QTranslator *translator;
extern const QString translationPrefix; extern const QString translationPrefix;
extern QString translationPath; extern QString translationPath;
extern bool isSpoilersOnly;
void installNewTranslator(); void installNewTranslator();

View file

@ -37,21 +37,28 @@
#endif #endif
#define TOKENS_URL "https://raw.githubusercontent.com/Cockatrice/Magic-Token/master/tokens.xml" #define TOKENS_URL "https://raw.githubusercontent.com/Cockatrice/Magic-Token/master/tokens.xml"
#define SPOILERS_URL "https://raw.githubusercontent.com/Cockatrice/Magic-Spoiler/files/spoiler.xml"
OracleWizard::OracleWizard(QWidget *parent) : QWizard(parent)
OracleWizard::OracleWizard(QWidget *parent)
: QWizard(parent)
{ {
settings = new QSettings(settingsCache->getSettingsPath()+"global.ini",QSettings::IniFormat, this); settings = new QSettings(settingsCache->getSettingsPath()+"global.ini",QSettings::IniFormat, this);
connect(settingsCache, SIGNAL(langChanged()), this, SLOT(updateLanguage())); connect(settingsCache, SIGNAL(langChanged()), this, SLOT(updateLanguage()));
importer = new OracleImporter(settingsCache->getDataPath(), this); importer = new OracleImporter(settingsCache->getDataPath(), this);
addPage(new IntroPage); if (! isSpoilersOnly)
addPage(new LoadSetsPage); {
addPage(new SaveSetsPage); addPage(new IntroPage);
addPage(new LoadTokensPage); addPage(new LoadSetsPage);
addPage(new SaveTokensPage); addPage(new SaveSetsPage);
addPage(new LoadTokensPage);
addPage(new SaveTokensPage);
}
else
{
addPage(new LoadSpoilersPage);
addPage(new SaveSpoilersPage);
}
retranslateUi(); retranslateUi();
} }
@ -65,7 +72,10 @@ void OracleWizard::updateLanguage()
void OracleWizard::changeEvent(QEvent *event) void OracleWizard::changeEvent(QEvent *event)
{ {
if (event->type() == QEvent::LanguageChange) if (event->type() == QEvent::LanguageChange)
{
retranslateUi(); retranslateUi();
}
QDialog::changeEvent(event); QDialog::changeEvent(event);
} }
@ -75,7 +85,9 @@ void OracleWizard::retranslateUi()
QWizard::setButtonText(QWizard::FinishButton, tr("Save")); QWizard::setButtonText(QWizard::FinishButton, tr("Save"));
for (int i = 0; i < pageIds().count(); i++) for (int i = 0; i < pageIds().count(); i++)
{
dynamic_cast<OracleWizardPage *>(page(i))->retranslateUi(); dynamic_cast<OracleWizardPage *>(page(i))->retranslateUi();
}
} }
void OracleWizard::accept() void OracleWizard::accept()
@ -98,22 +110,23 @@ void OracleWizard::disableButtons()
bool OracleWizard::saveTokensToFile(const QString & fileName) bool OracleWizard::saveTokensToFile(const QString & fileName)
{ {
QFile file(fileName); QFile file(fileName);
if(!file.open(QIODevice::WriteOnly)) if (!file.open(QIODevice::WriteOnly))
{ {
qDebug() << "File open (w) failed for" << fileName; qDebug() << "File open (w) failed for" << fileName;
return false; return false;
} }
if(file.write(tokensData) == -1)
if (file.write(tokensData) == -1)
{ {
qDebug() << "File write (w) failed for" << fileName; qDebug() << "File write (w) failed for" << fileName;
return false; return false;
} }
file.close(); file.close();
return true; return true;
} }
IntroPage::IntroPage(QWidget *parent) IntroPage::IntroPage(QWidget *parent) : OracleWizardPage(parent)
: OracleWizardPage(parent)
{ {
label = new QLabel(this); label = new QLabel(this);
label->setWordWrap(true); label->setWordWrap(true);
@ -122,16 +135,21 @@ IntroPage::IntroPage(QWidget *parent)
versionLabel = new QLabel(this); versionLabel = new QLabel(this);
languageBox = new QComboBox(this); languageBox = new QComboBox(this);
QString setLanguage = settingsCache->getLang(); QString setLanguage = settingsCache->getLang();
QStringList qmFiles = findQmFiles(); QStringList qmFiles = findQmFiles();
for (int i = 0; i < qmFiles.size(); i++) { for (int i = 0; i < qmFiles.size(); i++)
{
QString langName = languageName(qmFiles[i]); QString langName = languageName(qmFiles[i]);
languageBox->addItem(langName, qmFiles[i]); languageBox->addItem(langName, qmFiles[i]);
if ((qmFiles[i] == setLanguage) || (setLanguage.isEmpty() && langName == QCoreApplication::translate("i18n", DEFAULT_LANG_NAME))) if ((qmFiles[i] == setLanguage) || (setLanguage.isEmpty() && langName == QCoreApplication::translate("i18n", DEFAULT_LANG_NAME)))
{
languageBox->setCurrentIndex(i); languageBox->setCurrentIndex(i);
}
} }
connect(languageBox, SIGNAL(currentIndexChanged(int)), this, SLOT(languageBoxChanged(int))); connect(languageBox, SIGNAL(currentIndexChanged(int)), this, SLOT(languageBoxChanged(int)));
QGridLayout *layout = new QGridLayout(this); auto *layout = new QGridLayout(this);
layout->addWidget(label, 0, 0, 1, 2); layout->addWidget(label, 0, 0, 1, 2);
layout->addWidget(languageLabel, 1, 0); layout->addWidget(languageLabel, 1, 0);
layout->addWidget(languageBox, 1, 1); layout->addWidget(languageBox, 1, 1);
@ -150,8 +168,10 @@ QStringList IntroPage::findQmFiles()
QString IntroPage::languageName(const QString &qmFile) QString IntroPage::languageName(const QString &qmFile)
{ {
if(qmFile == DEFAULT_LANG_CODE) if (qmFile == DEFAULT_LANG_CODE)
{
return DEFAULT_LANG_NAME; return DEFAULT_LANG_NAME;
}
QTranslator translator; QTranslator translator;
translator.load(translationPrefix + "_" + qmFile + ".qm", translationPath); translator.load(translationPrefix + "_" + qmFile + ".qm", translationPath);
@ -173,8 +193,7 @@ void IntroPage::retranslateUi()
versionLabel->setText(tr("Version:") + QString(" %1").arg(VERSION_STRING)); versionLabel->setText(tr("Version:") + QString(" %1").arg(VERSION_STRING));
} }
LoadSetsPage::LoadSetsPage(QWidget *parent) LoadSetsPage::LoadSetsPage(QWidget *parent) : OracleWizardPage(parent), nam(nullptr)
: OracleWizardPage(parent), nam(0)
{ {
urlRadioButton = new QRadioButton(this); urlRadioButton = new QRadioButton(this);
fileRadioButton = new QRadioButton(this); fileRadioButton = new QRadioButton(this);
@ -193,7 +212,7 @@ LoadSetsPage::LoadSetsPage(QWidget *parent)
fileButton = new QPushButton(this); fileButton = new QPushButton(this);
connect(fileButton, SIGNAL(clicked()), this, SLOT(actLoadSetsFile())); connect(fileButton, SIGNAL(clicked()), this, SLOT(actLoadSetsFile()));
QGridLayout *layout = new QGridLayout(this); auto *layout = new QGridLayout(this);
layout->addWidget(urlRadioButton, 0, 0); layout->addWidget(urlRadioButton, 0, 0);
layout->addWidget(urlLineEdit, 0, 1); layout->addWidget(urlLineEdit, 0, 1);
layout->addWidget(urlButton, 1, 1, Qt::AlignRight); layout->addWidget(urlButton, 1, 1, Qt::AlignRight);
@ -245,11 +264,15 @@ void LoadSetsPage::actLoadSetsFile()
dialog.setNameFilter(tr("Sets JSON file (*.json)")); dialog.setNameFilter(tr("Sets JSON file (*.json)"));
#endif #endif
if(!fileLineEdit->text().isEmpty() && QFile::exists(fileLineEdit->text())) if (!fileLineEdit->text().isEmpty() && QFile::exists(fileLineEdit->text()))
{
dialog.selectFile(fileLineEdit->text()); dialog.selectFile(fileLineEdit->text());
}
if (!dialog.exec()) if (!dialog.exec())
{
return; return;
}
fileLineEdit->setText(dialog.selectedFiles().at(0)); fileLineEdit->setText(dialog.selectedFiles().at(0));
} }
@ -257,14 +280,16 @@ void LoadSetsPage::actLoadSetsFile()
bool LoadSetsPage::validatePage() bool LoadSetsPage::validatePage()
{ {
// once the import is finished, we call next(); skip validation // once the import is finished, we call next(); skip validation
if(wizard()->importer->getSets().count() > 0) if (wizard()->importer->getSets().count() > 0)
{
return true; return true;
}
// else, try to import sets // else, try to import sets
if(urlRadioButton->isChecked()) if (urlRadioButton->isChecked())
{ {
QUrl url = QUrl::fromUserInput(urlLineEdit->text()); QUrl url = QUrl::fromUserInput(urlLineEdit->text());
if(!url.isValid()) 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; return false;
@ -282,16 +307,19 @@ bool LoadSetsPage::validatePage()
setEnabled(false); setEnabled(false);
downloadSetsFile(url); downloadSetsFile(url);
} else if(fileRadioButton->isChecked()) { }
else if (fileRadioButton->isChecked())
{
QFile setsFile(fileLineEdit->text()); QFile setsFile(fileLineEdit->text());
if(!setsFile.exists()) if (!setsFile.exists())
{ {
QMessageBox::critical(this, tr("Error"), tr("Please choose a file.")); QMessageBox::critical(this, tr("Error"), tr("Please choose a file."));
return false; return false;
} }
if (!setsFile.open(QIODevice::ReadOnly)) { if (!setsFile.open(QIODevice::ReadOnly))
QMessageBox::critical(0, tr("Error"), tr("Cannot open file '%1'.").arg(fileLineEdit->text())); {
QMessageBox::critical(nullptr, tr("Error"), tr("Cannot open file '%1'.").arg(fileLineEdit->text()));
return false; return false;
} }
@ -301,13 +329,16 @@ bool LoadSetsPage::validatePage()
readSetsFromByteArray(setsFile.readAll()); readSetsFromByteArray(setsFile.readAll());
} }
return false; return false;
} }
void LoadSetsPage::downloadSetsFile(QUrl url) void LoadSetsPage::downloadSetsFile(QUrl url)
{ {
if(!nam) if (!nam)
{
nam = new QNetworkAccessManager(this); nam = new QNetworkAccessManager(this);
}
QNetworkReply *reply = nam->get(QNetworkRequest(url)); QNetworkReply *reply = nam->get(QNetworkRequest(url));
connect(reply, SIGNAL(finished()), this, SLOT(actDownloadFinishedSetsFile())); connect(reply, SIGNAL(finished()), this, SLOT(actDownloadFinishedSetsFile()));
@ -316,10 +347,10 @@ void LoadSetsPage::downloadSetsFile(QUrl url)
void LoadSetsPage::actDownloadProgressSetsFile(qint64 received, qint64 total) void LoadSetsPage::actDownloadProgressSetsFile(qint64 received, qint64 total)
{ {
if(total > 0) if (total > 0)
{ {
progressBar->setMaximum(total); progressBar->setMaximum(static_cast<int>(total));
progressBar->setValue(received); progressBar->setValue(static_cast<int>(received));
} }
progressLabel->setText(tr("Downloading (%1MB)").arg((int) received / (1024 * 1024))); progressLabel->setText(tr("Downloading (%1MB)").arg((int) received / (1024 * 1024)));
} }
@ -327,9 +358,10 @@ void LoadSetsPage::actDownloadProgressSetsFile(qint64 received, qint64 total)
void LoadSetsPage::actDownloadFinishedSetsFile() void LoadSetsPage::actDownloadFinishedSetsFile()
{ {
// check for a reply // check for a reply
QNetworkReply *reply = static_cast<QNetworkReply *>(sender()); auto *reply = dynamic_cast<QNetworkReply *>(sender());
QNetworkReply::NetworkError errorCode = reply->error(); QNetworkReply::NetworkError errorCode = reply->error();
if (errorCode != QNetworkReply::NoError) { if (errorCode != QNetworkReply::NoError)
{
QMessageBox::critical(this, tr("Error"), tr("Network error: %1.").arg(reply->errorString())); QMessageBox::critical(this, tr("Error"), tr("Network error: %1.").arg(reply->errorString()));
wizard()->enableButtons(); wizard()->enableButtons();
@ -340,7 +372,8 @@ void LoadSetsPage::actDownloadFinishedSetsFile()
} }
int statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); int statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
if (statusCode == 301 || statusCode == 302) { if (statusCode == 301 || statusCode == 302)
{
QUrl redirectUrl = reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl(); QUrl redirectUrl = reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl();
qDebug() << "following redirect url:" << redirectUrl.toString(); qDebug() << "following redirect url:" << redirectUrl.toString();
downloadSetsFile(redirectUrl); downloadSetsFile(redirectUrl);
@ -352,10 +385,14 @@ void LoadSetsPage::actDownloadFinishedSetsFile()
progressBar->hide(); progressBar->hide();
// save allsets.json url, but only if the user customized it and download was successfull // save allsets.json url, but only if the user customized it and download was successfull
if(urlLineEdit->text() != QString(ALLSETS_URL)) if (urlLineEdit->text() != QString(ALLSETS_URL))
{
wizard()->settings->setValue("allsetsurl", urlLineEdit->text()); wizard()->settings->setValue("allsetsurl", urlLineEdit->text());
}
else else
{
wizard()->settings->remove("allsetsurl"); wizard()->settings->remove("allsetsurl");
}
readSetsFromByteArray(reply->readAll()); readSetsFromByteArray(reply->readAll());
reply->deleteLater(); reply->deleteLater();
@ -376,19 +413,20 @@ void LoadSetsPage::readSetsFromByteArray(QByteArray data)
{ {
#ifdef HAS_ZLIB #ifdef HAS_ZLIB
// zipped file // zipped file
QBuffer *inBuffer = new QBuffer(&data); auto *inBuffer = new QBuffer(&data);
QBuffer *outBuffer = new QBuffer(this); auto *outBuffer = new QBuffer(this);
QString fileName; QString fileName;
UnZip::ErrorCode ec; UnZip::ErrorCode ec;
UnZip uz; UnZip uz;
ec = uz.openArchive(inBuffer); ec = uz.openArchive(inBuffer);
if (ec != UnZip::Ok) { if (ec != UnZip::Ok)
{
zipDownloadFailed(tr("Failed to open Zip archive: %1.").arg(uz.formatError(ec))); zipDownloadFailed(tr("Failed to open Zip archive: %1.").arg(uz.formatError(ec)));
return; return;
} }
if(uz.fileList().size() != 1) if (uz.fileList().size() != 1)
{ {
zipDownloadFailed(tr("Zip extraction failed: the Zip archive doesn't contain exactly one file.")); zipDownloadFailed(tr("Zip extraction failed: the Zip archive doesn't contain exactly one file."));
return; return;
@ -397,7 +435,8 @@ void LoadSetsPage::readSetsFromByteArray(QByteArray data)
outBuffer->open(QBuffer::ReadWrite); outBuffer->open(QBuffer::ReadWrite);
ec = uz.extractFile(fileName, outBuffer); ec = uz.extractFile(fileName, outBuffer);
if (ec != UnZip::Ok) { if (ec != UnZip::Ok)
{
zipDownloadFailed(tr("Zip extraction failed: %1.").arg(uz.formatError(ec))); zipDownloadFailed(tr("Zip extraction failed: %1.").arg(uz.formatError(ec)));
uz.closeArchive(); uz.closeArchive();
return; return;
@ -429,7 +468,8 @@ void LoadSetsPage::zipDownloadFailed(const QString &message)
progressBar->hide(); progressBar->hide();
QMessageBox::StandardButton reply; QMessageBox::StandardButton reply;
reply = QMessageBox::question(this, tr("Error"), message + "<br/>" + tr("Do you want to try to download a fresh copy of the uncompressed file instead?"), QMessageBox::Yes|QMessageBox::No, QMessageBox::Yes); reply = static_cast<QMessageBox::StandardButton>(QMessageBox::question(this, tr("Error"), message + "<br/>" + tr("Do you want to try to download a fresh copy of the uncompressed file instead?"), QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes));
if (reply == QMessageBox::Yes) if (reply == QMessageBox::Yes)
{ {
urlRadioButton->setChecked(true); urlRadioButton->setChecked(true);
@ -446,16 +486,17 @@ void LoadSetsPage::importFinished()
progressLabel->hide(); progressLabel->hide();
progressBar->hide(); progressBar->hide();
if(watcher.future().result()) if (watcher.future().result())
{ {
wizard()->next(); wizard()->next();
} else { }
else
{
QMessageBox::critical(this, tr("Error"), tr("The file was retrieved successfully, but it does not contain any sets data.")); QMessageBox::critical(this, tr("Error"), tr("The file was retrieved successfully, but it does not contain any sets data."));
} }
} }
SaveSetsPage::SaveSetsPage(QWidget *parent) SaveSetsPage::SaveSetsPage(QWidget *parent) : OracleWizardPage(parent)
: OracleWizardPage(parent)
{ {
defaultPathCheckBox = new QCheckBox(this); defaultPathCheckBox = new QCheckBox(this);
defaultPathCheckBox->setChecked(true); defaultPathCheckBox->setChecked(true);
@ -463,7 +504,7 @@ SaveSetsPage::SaveSetsPage(QWidget *parent)
messageLog = new QTextEdit(this); messageLog = new QTextEdit(this);
messageLog->setReadOnly(true); messageLog->setReadOnly(true);
QGridLayout *layout = new QGridLayout(this); auto *layout = new QGridLayout(this);
layout->addWidget(defaultPathCheckBox, 0, 0); layout->addWidget(defaultPathCheckBox, 0, 0);
layout->addWidget(messageLog, 1, 0); layout->addWidget(messageLog, 1, 0);
@ -472,7 +513,7 @@ SaveSetsPage::SaveSetsPage(QWidget *parent)
void SaveSetsPage::cleanupPage() void SaveSetsPage::cleanupPage()
{ {
disconnect(wizard()->importer, SIGNAL(setIndexChanged(int, int, const QString &)), 0, 0); disconnect(wizard()->importer, SIGNAL(setIndexChanged(int, int, const QString &)), nullptr, nullptr);
} }
void SaveSetsPage::initializePage() void SaveSetsPage::initializePage()
@ -482,7 +523,9 @@ void SaveSetsPage::initializePage()
connect(wizard()->importer, SIGNAL(setIndexChanged(int, int, const QString &)), this, SLOT(updateTotalProgress(int, int, const QString &))); connect(wizard()->importer, SIGNAL(setIndexChanged(int, int, const QString &)), this, SLOT(updateTotalProgress(int, int, const QString &)));
if (!wizard()->importer->startImport()) if (!wizard()->importer->startImport())
{
QMessageBox::critical(this, tr("Error"), tr("No set has been imported.")); QMessageBox::critical(this, tr("Error"), tr("No set has been imported."));
}
} }
void SaveSetsPage::retranslateUi() void SaveSetsPage::retranslateUi()
@ -496,11 +539,15 @@ void SaveSetsPage::retranslateUi()
void SaveSetsPage::updateTotalProgress(int cardsImported, int /* setIndex */, const QString &setName) void SaveSetsPage::updateTotalProgress(int cardsImported, int /* setIndex */, const QString &setName)
{ {
if (setName.isEmpty()) { if (setName.isEmpty())
{
messageLog->append("<b>" + tr("Import finished: %1 cards.").arg(wizard()->importer->getCardList().size()) + "</b>"); messageLog->append("<b>" + tr("Import finished: %1 cards.").arg(wizard()->importer->getCardList().size()) + "</b>");
} else { }
else
{
messageLog->append(tr("%1: %2 cards imported").arg(setName).arg(cardsImported)); messageLog->append(tr("%1: %2 cards imported").arg(setName).arg(cardsImported));
} }
messageLog->verticalScrollBar()->setValue(messageLog->verticalScrollBar()->maximum()); messageLog->verticalScrollBar()->setValue(messageLog->verticalScrollBar()->maximum());
} }
@ -511,39 +558,51 @@ bool SaveSetsPage::validatePage()
QString windowName = tr("Save card database"); QString windowName = tr("Save card database");
QString fileType = tr("XML; card database (*.xml)"); QString fileType = tr("XML; card database (*.xml)");
do { do
{
QString fileName; QString fileName;
if (defaultPathCheckBox->isChecked()) if (defaultPathCheckBox->isChecked())
{
fileName = defaultPath; fileName = defaultPath;
}
else else
{
fileName = QFileDialog::getSaveFileName(this, windowName, defaultPath, fileType); fileName = QFileDialog::getSaveFileName(this, windowName, defaultPath, fileType);
}
if (fileName.isEmpty()) if (fileName.isEmpty())
{
return false; return false;
}
QFileInfo fi(fileName); QFileInfo fi(fileName);
QDir fileDir(fi.path()); QDir fileDir(fi.path());
if (!fileDir.exists() && !fileDir.mkpath(fileDir.absolutePath())) { if (!fileDir.exists() && !fileDir.mkpath(fileDir.absolutePath()))
{
return false; return false;
} }
if (wizard()->importer->saveToFile(fileName)) if (wizard()->importer->saveToFile(fileName))
{ {
ok = true; ok = true;
QMessageBox::information(this, QMessageBox::information(this,
tr("Success"), tr("Success"),
tr("The card database has been saved successfully to\n%1").arg(fileName)); tr("The card database has been saved successfully to\n%1").arg(fileName));
} else { }
else
{
QMessageBox::critical(this, tr("Error"), tr("The file could not be saved to %1").arg(fileName));; QMessageBox::critical(this, tr("Error"), tr("The file could not be saved to %1").arg(fileName));;
if (defaultPathCheckBox->isChecked()) if (defaultPathCheckBox->isChecked())
{
defaultPathCheckBox->setChecked(false); defaultPathCheckBox->setChecked(false);
}
} }
} while (!ok); } while (!ok);
return true; return true;
} }
LoadTokensPage::LoadTokensPage(QWidget *parent) LoadSpoilersPage::LoadSpoilersPage(QWidget *parent) : OracleWizardPage(parent), nam(nullptr)
: OracleWizardPage(parent), nam(0)
{ {
urlLabel = new QLabel(this); urlLabel = new QLabel(this);
urlLineEdit = new QLineEdit(this); urlLineEdit = new QLineEdit(this);
@ -554,7 +613,152 @@ LoadTokensPage::LoadTokensPage(QWidget *parent)
urlButton = new QPushButton(this); urlButton = new QPushButton(this);
connect(urlButton, SIGNAL(clicked()), this, SLOT(actRestoreDefaultUrl())); connect(urlButton, SIGNAL(clicked()), this, SLOT(actRestoreDefaultUrl()));
QGridLayout *layout = new QGridLayout(this); auto *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);
}
void LoadSpoilersPage::actRestoreDefaultUrl()
{
urlLineEdit->setText(SPOILERS_URL);
}
void LoadSpoilersPage::initializePage()
{
urlLineEdit->setText(wizard()->settings->value("spoilersurl", SPOILERS_URL).toString());
progressLabel->hide();
progressBar->hide();
}
void LoadSpoilersPage::actDownloadProgressSpoilersFile(qint64 received, qint64 total)
{
if (total > 0)
{
progressBar->setMaximum(static_cast<int>(total));
progressBar->setValue(static_cast<int>(received));
}
progressLabel->setText(tr("Downloading (%1MB)").arg((int) received / (1024 * 1024)));
}
void LoadSpoilersPage::actDownloadFinishedSpoilersFile()
{
// Check for server reply
auto *reply = dynamic_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;
}
int statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
if (statusCode == 301 || statusCode == 302)
{
QUrl redirectUrl = reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl();
qDebug() << "following redirect url:" << redirectUrl.toString();
downloadSpoilersFile(redirectUrl);
reply->deleteLater();
return;
}
progressLabel->hide();
progressBar->hide();
// save spoiler.xml url, but only if the user customized it and download was successful
if (urlLineEdit->text() != QString(SPOILERS_URL))
{
wizard()->settings->setValue("spoilersurl", urlLineEdit->text());
}
else
{
wizard()->settings->remove("spoilersurl");
}
wizard()->setTokensData(reply->readAll());
reply->deleteLater();
wizard()->enableButtons();
setEnabled(true);
progressLabel->hide();
progressBar->hide();
wizard()->next();
}
void LoadSpoilersPage::downloadSpoilersFile(QUrl url)
{
if (!nam)
{
nam = new QNetworkAccessManager(this);
}
QNetworkReply *reply = nam->get(QNetworkRequest(url));
connect(reply, SIGNAL(finished()), this, SLOT(actDownloadFinishedSpoilersFile()));
connect(reply, SIGNAL(downloadProgress(qint64, qint64)), this, SLOT(actDownloadProgressSpoilersFile(qint64, qint64)));
}
bool LoadSpoilersPage::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);
downloadSpoilersFile(url);
return false;
}
void LoadSpoilersPage::retranslateUi()
{
setTitle(tr("Spoilers source selection"));
setSubTitle(tr("Please specify a spoiler source."));
urlLabel->setText(tr("Download URL:"));
urlButton->setText(tr("Restore default URL"));
}
LoadTokensPage::LoadTokensPage(QWidget *parent) : OracleWizardPage(parent), nam(nullptr)
{
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()));
auto *layout = new QGridLayout(this);
layout->addWidget(urlLabel, 0, 0); layout->addWidget(urlLabel, 0, 0);
layout->addWidget(urlLineEdit, 0, 1); layout->addWidget(urlLineEdit, 0, 1);
layout->addWidget(urlButton, 1, 1, Qt::AlignRight); layout->addWidget(urlButton, 1, 1, Qt::AlignRight);
@ -589,11 +793,13 @@ void LoadTokensPage::actRestoreDefaultUrl()
bool LoadTokensPage::validatePage() bool LoadTokensPage::validatePage()
{ {
// once the import is finished, we call next(); skip validation // once the import is finished, we call next(); skip validation
if(wizard()->hasTokensData()) if (wizard()->hasTokensData())
{
return true; return true;
}
QUrl url = QUrl::fromUserInput(urlLineEdit->text()); QUrl url = QUrl::fromUserInput(urlLineEdit->text());
if(!url.isValid()) 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; return false;
@ -616,8 +822,10 @@ bool LoadTokensPage::validatePage()
void LoadTokensPage::downloadTokensFile(QUrl url) void LoadTokensPage::downloadTokensFile(QUrl url)
{ {
if(!nam) if (!nam)
{
nam = new QNetworkAccessManager(this); nam = new QNetworkAccessManager(this);
}
QNetworkReply *reply = nam->get(QNetworkRequest(url)); QNetworkReply *reply = nam->get(QNetworkRequest(url));
connect(reply, SIGNAL(finished()), this, SLOT(actDownloadFinishedTokensFile())); connect(reply, SIGNAL(finished()), this, SLOT(actDownloadFinishedTokensFile()));
@ -626,10 +834,10 @@ void LoadTokensPage::downloadTokensFile(QUrl url)
void LoadTokensPage::actDownloadProgressTokensFile(qint64 received, qint64 total) void LoadTokensPage::actDownloadProgressTokensFile(qint64 received, qint64 total)
{ {
if(total > 0) if (total > 0)
{ {
progressBar->setMaximum(total); progressBar->setMaximum(static_cast<int>(total));
progressBar->setValue(received); progressBar->setValue(static_cast<int>(received));
} }
progressLabel->setText(tr("Downloading (%1MB)").arg((int) received / (1024 * 1024))); progressLabel->setText(tr("Downloading (%1MB)").arg((int) received / (1024 * 1024)));
} }
@ -637,9 +845,10 @@ void LoadTokensPage::actDownloadProgressTokensFile(qint64 received, qint64 total
void LoadTokensPage::actDownloadFinishedTokensFile() void LoadTokensPage::actDownloadFinishedTokensFile()
{ {
// check for a reply // check for a reply
QNetworkReply *reply = static_cast<QNetworkReply *>(sender()); auto *reply = dynamic_cast<QNetworkReply *>(sender());
QNetworkReply::NetworkError errorCode = reply->error(); QNetworkReply::NetworkError errorCode = reply->error();
if (errorCode != QNetworkReply::NoError) { if (errorCode != QNetworkReply::NoError)
{
QMessageBox::critical(this, tr("Error"), tr("Network error: %1.").arg(reply->errorString())); QMessageBox::critical(this, tr("Error"), tr("Network error: %1.").arg(reply->errorString()));
wizard()->enableButtons(); wizard()->enableButtons();
@ -650,7 +859,8 @@ void LoadTokensPage::actDownloadFinishedTokensFile()
} }
int statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); int statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
if (statusCode == 301 || statusCode == 302) { if (statusCode == 301 || statusCode == 302)
{
QUrl redirectUrl = reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl(); QUrl redirectUrl = reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl();
qDebug() << "following redirect url:" << redirectUrl.toString(); qDebug() << "following redirect url:" << redirectUrl.toString();
downloadTokensFile(redirectUrl); downloadTokensFile(redirectUrl);
@ -662,10 +872,14 @@ void LoadTokensPage::actDownloadFinishedTokensFile()
progressBar->hide(); progressBar->hide();
// save tokens.xml url, but only if the user customized it and download was successfull // save tokens.xml url, but only if the user customized it and download was successfull
if(urlLineEdit->text() != QString(TOKENS_URL)) if (urlLineEdit->text() != QString(TOKENS_URL))
{
wizard()->settings->setValue("tokensurl", urlLineEdit->text()); wizard()->settings->setValue("tokensurl", urlLineEdit->text());
}
else else
{
wizard()->settings->remove("tokensurl"); wizard()->settings->remove("tokensurl");
}
wizard()->setTokensData(reply->readAll()); wizard()->setTokensData(reply->readAll());
reply->deleteLater(); reply->deleteLater();
@ -678,13 +892,81 @@ void LoadTokensPage::actDownloadFinishedTokensFile()
wizard()->next(); wizard()->next();
} }
SaveTokensPage::SaveTokensPage(QWidget *parent) SaveSpoilersPage::SaveSpoilersPage(QWidget *parent) : OracleWizardPage(parent)
: OracleWizardPage(parent)
{ {
defaultPathCheckBox = new QCheckBox(this); defaultPathCheckBox = new QCheckBox(this);
defaultPathCheckBox->setChecked(true); defaultPathCheckBox->setChecked(true);
QGridLayout *layout = new QGridLayout(this); auto *layout = new QGridLayout(this);
layout->addWidget(defaultPathCheckBox, 0, 0);
setLayout(layout);
}
void SaveSpoilersPage::retranslateUi()
{
setTitle(tr("Spoilers imported"));
setSubTitle(tr("The spoilers file has been imported. "
"Press \"Save\" to save the imported spoilers to the Cockatrice card database."));
defaultPathCheckBox->setText(tr("Save to the default path (recommended)"));
}
bool SaveSpoilersPage::validatePage()
{
bool ok = false;
QString defaultPath = settingsCache->getSpoilerCardDatabasePath();
QString windowName = tr("Save spoiler database");
QString fileType = tr("XML; card database (*.xml)");
do
{
QString fileName;
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;
}
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;
}
SaveTokensPage::SaveTokensPage(QWidget *parent) : OracleWizardPage(parent)
{
defaultPathCheckBox = new QCheckBox(this);
defaultPathCheckBox->setChecked(true);
auto *layout = new QGridLayout(this);
layout->addWidget(defaultPathCheckBox, 0, 0); layout->addWidget(defaultPathCheckBox, 0, 0);
setLayout(layout); setLayout(layout);
@ -706,31 +988,45 @@ bool SaveTokensPage::validatePage()
QString windowName = tr("Save token database"); QString windowName = tr("Save token database");
QString fileType = tr("XML; token database (*.xml)"); QString fileType = tr("XML; token database (*.xml)");
do { do
{
QString fileName; QString fileName;
if (defaultPathCheckBox->isChecked()) if (defaultPathCheckBox->isChecked())
{
fileName = defaultPath; fileName = defaultPath;
}
else else
{
fileName = QFileDialog::getSaveFileName(this, windowName, defaultPath, fileType); fileName = QFileDialog::getSaveFileName(this, windowName, defaultPath, fileType);
}
if (fileName.isEmpty()) if (fileName.isEmpty())
{
return false; return false;
}
QFileInfo fi(fileName); QFileInfo fi(fileName);
QDir fileDir(fi.path()); QDir fileDir(fi.path());
if (!fileDir.exists() && !fileDir.mkpath(fileDir.absolutePath())) { if (!fileDir.exists() && !fileDir.mkpath(fileDir.absolutePath()))
{
return false; return false;
} }
if (wizard()->saveTokensToFile(fileName)) if (wizard()->saveTokensToFile(fileName))
{ {
ok = true; ok = true;
QMessageBox::information(this, QMessageBox::information(this,
tr("Success"), tr("Success"),
tr("The token database has been saved successfully to\n%1").arg(fileName)); tr("The token database has been saved successfully to\n%1").arg(fileName));
} else { }
else
{
QMessageBox::critical(this, tr("Error"), tr("The file could not be saved to %1").arg(fileName));; QMessageBox::critical(this, tr("Error"), tr("The file could not be saved to %1").arg(fileName));;
if (defaultPathCheckBox->isChecked()) if (defaultPathCheckBox->isChecked())
{
defaultPathCheckBox->setChecked(false); defaultPathCheckBox->setChecked(false);
}
} }
} while (!ok); } while (!ok);

View file

@ -4,6 +4,7 @@
#include <QWizard> #include <QWizard>
#include <QFutureWatcher> #include <QFutureWatcher>
#include <QFuture> #include <QFuture>
#include <utility>
class QCheckBox; class QCheckBox;
class QGroupBox; class QGroupBox;
@ -20,139 +21,195 @@ class QSettings;
class OracleWizard : public QWizard class OracleWizard : public QWizard
{ {
Q_OBJECT Q_OBJECT
public: public:
OracleWizard(QWidget *parent = 0); explicit OracleWizard(QWidget *parent = nullptr);
void accept(); void accept() override;
void enableButtons(); void enableButtons();
void disableButtons(); void disableButtons();
void retranslateUi(); void retranslateUi();
void setTokensData(QByteArray _tokensData) { tokensData = _tokensData; } void setTokensData(QByteArray _tokensData) { tokensData = std::move(_tokensData); }
bool hasTokensData() { return !tokensData.isEmpty(); } bool hasTokensData() { return !tokensData.isEmpty(); }
bool saveTokensToFile(const QString & fileName); bool saveTokensToFile(const QString & fileName);
public:
OracleImporter *importer;
QSettings * settings;
private slots:
void updateLanguage();
private:
QStringList findQmFiles();
QString languageName(const QString &qmFile);
QByteArray tokensData;
protected:
void changeEvent(QEvent *event);
};
public:
OracleImporter *importer;
QSettings *settings;
private slots:
void updateLanguage();
private:
QByteArray tokensData;
protected:
void changeEvent(QEvent *event) override;
};
class OracleWizardPage : public QWizardPage class OracleWizardPage : public QWizardPage
{ {
Q_OBJECT Q_OBJECT
public: public:
OracleWizardPage(QWidget *parent = 0): QWizardPage(parent) {}; explicit OracleWizardPage(QWidget *parent = nullptr): QWizardPage(parent) {};
virtual void retranslateUi() = 0; virtual void retranslateUi() = 0;
protected:
inline OracleWizard *wizard() { return (OracleWizard*) QWizardPage::wizard(); }; protected:
inline OracleWizard *wizard() { return (OracleWizard*) QWizardPage::wizard(); };
}; };
class IntroPage : public OracleWizardPage class IntroPage : public OracleWizardPage
{ {
Q_OBJECT Q_OBJECT
public: public:
IntroPage(QWidget *parent = 0); explicit IntroPage(QWidget *parent = nullptr);
void retranslateUi(); void retranslateUi() override;
private:
QStringList findQmFiles(); private:
QString languageName(const QString &qmFile); QStringList findQmFiles();
private: QString languageName(const QString &qmFile);
QLabel *label, *languageLabel, *versionLabel;
QComboBox *languageBox; private:
private slots: QLabel *label, *languageLabel, *versionLabel;
void languageBoxChanged(int index); QComboBox *languageBox;
private slots:
void languageBoxChanged(int index);
}; };
class LoadSetsPage : public OracleWizardPage class LoadSetsPage : public OracleWizardPage
{ {
Q_OBJECT Q_OBJECT
public: public:
LoadSetsPage(QWidget *parent = 0); explicit LoadSetsPage(QWidget *parent = nullptr);
void retranslateUi(); void retranslateUi() override;
protected:
void initializePage();
bool validatePage();
void readSetsFromByteArray(QByteArray data);
void downloadSetsFile(QUrl url);
private:
QRadioButton *urlRadioButton;
QRadioButton *fileRadioButton;
QLineEdit *urlLineEdit;
QLineEdit *fileLineEdit;
QPushButton *urlButton;
QPushButton *fileButton;
QLabel *progressLabel;
QProgressBar * progressBar;
QNetworkAccessManager *nam; protected:
QFutureWatcher<bool> watcher; void initializePage() override;
QFuture<bool> future; bool validatePage() override;
private slots: void readSetsFromByteArray(QByteArray data);
void actLoadSetsFile(); void downloadSetsFile(QUrl url);
void actRestoreDefaultUrl();
void actDownloadProgressSetsFile(qint64 received, qint64 total); private:
void actDownloadFinishedSetsFile(); QRadioButton *urlRadioButton;
void importFinished(); QRadioButton *fileRadioButton;
void zipDownloadFailed(const QString &message); QLineEdit *urlLineEdit;
QLineEdit *fileLineEdit;
QPushButton *urlButton;
QPushButton *fileButton;
QLabel *progressLabel;
QProgressBar *progressBar;
QNetworkAccessManager *nam;
QFutureWatcher<bool> watcher;
QFuture<bool> future;
private slots:
void actLoadSetsFile();
void actRestoreDefaultUrl();
void actDownloadProgressSetsFile(qint64 received, qint64 total);
void actDownloadFinishedSetsFile();
void importFinished();
void zipDownloadFailed(const QString &message);
}; };
class SaveSetsPage : public OracleWizardPage class SaveSetsPage : public OracleWizardPage
{ {
Q_OBJECT Q_OBJECT
public: public:
SaveSetsPage(QWidget *parent = 0); explicit SaveSetsPage(QWidget *parent = nullptr);
void retranslateUi(); void retranslateUi() override;
private:
QTextEdit *messageLog; private:
QCheckBox * defaultPathCheckBox; QTextEdit *messageLog;
protected: QCheckBox *defaultPathCheckBox;
void initializePage();
void cleanupPage(); protected:
bool validatePage(); void initializePage() override;
private slots: void cleanupPage() override;
void updateTotalProgress(int cardsImported, int setIndex, const QString &setName); bool validatePage() override;
private slots:
void updateTotalProgress(int cardsImported, int setIndex, const QString &setName);
};
class LoadSpoilersPage : public OracleWizardPage
{
Q_OBJECT
public:
explicit LoadSpoilersPage(QWidget *parent = nullptr);
void retranslateUi() override;
private:
QLabel *urlLabel;
QLineEdit *urlLineEdit;
QPushButton *urlButton;
QLabel *progressLabel;
QProgressBar *progressBar;
QNetworkAccessManager *nam;
private slots:
void actRestoreDefaultUrl();
void actDownloadProgressSpoilersFile(qint64 received, qint64 total);
void actDownloadFinishedSpoilersFile();
protected:
void initializePage() override;
bool validatePage() override;
void downloadSpoilersFile(QUrl url);
};
class SaveSpoilersPage : public OracleWizardPage
{
Q_OBJECT
public:
explicit SaveSpoilersPage(QWidget *parent = nullptr);
void retranslateUi() override;
private:
QCheckBox *defaultPathCheckBox;
protected:
bool validatePage() override;
}; };
class LoadTokensPage : public OracleWizardPage class LoadTokensPage : public OracleWizardPage
{ {
Q_OBJECT Q_OBJECT
public: public:
LoadTokensPage(QWidget *parent = 0); explicit LoadTokensPage(QWidget *parent = nullptr);
void retranslateUi(); void retranslateUi() override;
protected:
void initializePage();
bool validatePage();
void downloadTokensFile(QUrl url);
private:
QLabel *urlLabel;
QLineEdit *urlLineEdit;
QPushButton *urlButton;
QLabel *progressLabel;
QProgressBar * progressBar;
QNetworkAccessManager *nam; protected:
private slots: void initializePage() override;
void actRestoreDefaultUrl(); bool validatePage() override;
void actDownloadProgressTokensFile(qint64 received, qint64 total); void downloadTokensFile(QUrl url);
void actDownloadFinishedTokensFile();
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 class SaveTokensPage : public OracleWizardPage
{ {
Q_OBJECT Q_OBJECT
public: public:
SaveTokensPage(QWidget *parent = 0); explicit SaveTokensPage(QWidget *parent = nullptr);
void retranslateUi(); void retranslateUi() override;
private:
QCheckBox * defaultPathCheckBox; private:
protected: QCheckBox *defaultPathCheckBox;
bool validatePage();
protected:
bool validatePage() override;
}; };
#endif #endif

View file

@ -14,6 +14,7 @@ SettingsCache::~SettingsCache() { delete cardDatabaseSettings; };
QString SettingsCache::getCustomCardDatabasePath() const { return QString("%1/customsets/").arg(CARDDB_DATADIR); } QString SettingsCache::getCustomCardDatabasePath() const { return QString("%1/customsets/").arg(CARDDB_DATADIR); }
QString SettingsCache::getCardDatabasePath() const { return QString("%1/cards.xml").arg(CARDDB_DATADIR); } QString SettingsCache::getCardDatabasePath() const { return QString("%1/cards.xml").arg(CARDDB_DATADIR); }
QString SettingsCache::getTokenDatabasePath() const { return QString("%1/tokens.xml").arg(CARDDB_DATADIR); } QString SettingsCache::getTokenDatabasePath() const { return QString("%1/tokens.xml").arg(CARDDB_DATADIR); }
QString SettingsCache::getSpoilerCardDatabasePath() const { return QString("%1/spoiler.xml").arg(CARDDB_DATADIR); }
CardDatabaseSettings& SettingsCache::cardDatabase() const { return *cardDatabaseSettings; } CardDatabaseSettings& SettingsCache::cardDatabase() const { return *cardDatabaseSettings; }
SettingsCache *settingsCache; SettingsCache *settingsCache;

View file

@ -30,6 +30,7 @@ public:
QString getCustomCardDatabasePath() const; QString getCustomCardDatabasePath() const;
QString getCardDatabasePath() const; QString getCardDatabasePath() const;
QString getTokenDatabasePath() const; QString getTokenDatabasePath() const;
QString getSpoilerCardDatabasePath() const;
CardDatabaseSettings& cardDatabase() const; CardDatabaseSettings& cardDatabase() const;
signals: signals:
void cardDatabasePathChanged(); void cardDatabasePathChanged();

View file

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<cockatrice_carddatabase version="3">
<cards>
<card>
<name>Fluffy</name>
<set muId="311">CAT</set>
<color>G</color>
<manacost></manacost>
<cmc></cmc>
<type>Token</type>
<pt>0/1</pt>
<tablerow>0</tablerow>
<text></text>
<token>1</token>
</card>
</cards>
</cockatrice_carddatabase>