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,15 +19,17 @@ 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: private:
QString shortName, longName; QString shortName, longName;
unsigned int sortKey; unsigned int sortKey;
QDate releaseDate; QDate releaseDate;
QString setType; QString setType;
bool enabled, isknown; bool enabled, isknown;
public: public:
CardSet(const QString &_shortName = QString(), const QString &_longName = QString(), const QString &_setType = QString(), const QDate &_releaseDate = QDate()); explicit CardSet(const QString &_shortName = QString(), const QString &_longName = QString(), const QString &_setType = QString(), const QDate &_releaseDate = QDate());
QString getCorrectedShortName() const; QString getCorrectedShortName() const;
QString getShortName() const { return shortName; } QString getShortName() const { return shortName; }
QString getLongName() const { return longName; } QString getLongName() const { return longName; }
@ -43,13 +46,16 @@ public:
void setEnabled(bool _enabled); void setEnabled(bool _enabled);
bool getIsKnown() const { return isknown; } bool getIsKnown() const { return isknown; }
void setIsKnown(bool _isknown); void setIsKnown(bool _isknown);
//Determine incomplete sets. //Determine incomplete sets.
bool getIsKnownIgnored() const { return longName.length() + setType.length() + releaseDate.toString().length() == 0 ; } bool getIsKnownIgnored() const { return longName.length() + setType.length() + releaseDate.toString().length() == 0 ; }
}; };
class SetList : public QList<CardSet *> { class SetList : public QList<CardSet *>
{
private: private:
class KeyCompareFunctor; class KeyCompareFunctor;
public: public:
void sortByKey(); void sortByKey();
void guessSortKeys(); void guessSortKeys();
@ -61,7 +67,8 @@ public:
QStringList getUnknownSetsNames(); QStringList getUnknownSetsNames();
}; };
class CardInfo : public QObject { class CardInfo : public QObject
{
Q_OBJECT Q_OBJECT
private: private:
QString name; QString name;
@ -80,13 +87,18 @@ private:
QString powtough; QString powtough;
QString text; QString text;
QStringList colors; QStringList colors;
// the cards i'm related to // the cards i'm related to
QList<CardRelation *> relatedCards; QList<CardRelation *> relatedCards;
// the card i'm reverse-related to // the card i'm reverse-related to
QList<CardRelation *> reverseRelatedCards; QList<CardRelation *> reverseRelatedCards;
// the cards thare are reverse-related to me // the cards thare are reverse-related to me
QList<CardRelation *> reverseRelatedCardsToMe; QList<CardRelation *> reverseRelatedCardsToMe;
QString setsNames; QString setsNames;
bool upsideDownArt; bool upsideDownArt;
int loyalty; int loyalty;
QStringMap customPicURLs; QStringMap customPicURLs;
@ -96,8 +108,9 @@ private:
bool cipt; bool cipt;
int tableRow; int tableRow;
QString pixmapCacheKey; QString pixmapCacheKey;
public: public:
CardInfo(const QString &_name = QString(), explicit CardInfo(const QString &_name = QString(),
bool _isToken = false, bool _isToken = false,
const QString &_manacost = QString(), const QString &_manacost = QString(),
const QString &_cmc = QString(), const QString &_cmc = QString(),
@ -117,7 +130,8 @@ public:
QStringMap _collectorNumbers = QStringMap(), QStringMap _collectorNumbers = QStringMap(),
QStringMap _rarities = QStringMap() QStringMap _rarities = QStringMap()
); );
~CardInfo(); ~CardInfo() override;
inline const QString &getName() const { return name; } inline const QString &getName() const { return name; }
inline const QString &getSetsNames() const { return setsNames; } inline const QString &getSetsNames() const { return setsNames; }
const QString &getSimpleName() const { return simpleName; } const QString &getSimpleName() const { return simpleName; }
@ -131,8 +145,8 @@ public:
const QString &getPixmapCacheKey() const { return pixmapCacheKey; } const QString &getPixmapCacheKey() const { return pixmapCacheKey; }
const int &getLoyalty() const { return loyalty; } const int &getLoyalty() const { return loyalty; }
bool getCipt() const { return cipt; } bool getCipt() const { return cipt; }
void setManaCost(const QString &_manaCost) { manacost = _manaCost; emit cardInfoChanged(this); } //void setManaCost(const QString &_manaCost) { manacost = _manaCost; emit cardInfoChanged(this); }
void setCmc(const QString &_cmc) { cmc = _cmc; emit cardInfoChanged(this); } //void setCmc(const QString &_cmc) { cmc = _cmc; emit cardInfoChanged(this); }
void setCardType(const QString &_cardType) { cardtype = _cardType; emit cardInfoChanged(this); } void setCardType(const QString &_cardType) { cardtype = _cardType; emit cardInfoChanged(this); }
void setPowTough(const QString &_powTough) { powtough = _powTough; emit cardInfoChanged(this); } void setPowTough(const QString &_powTough) { powtough = _powTough; emit cardInfoChanged(this); }
void setText(const QString &_text) { text = _text; emit cardInfoChanged(this); } void setText(const QString &_text) { text = _text; emit cardInfoChanged(this); }
@ -154,8 +168,8 @@ public:
QString getCorrectedName() const; QString getCorrectedName() const;
int getTableRow() const { return tableRow; } int getTableRow() const { return tableRow; }
void setTableRow(int _tableRow) { tableRow = _tableRow; } void setTableRow(int _tableRow) { tableRow = _tableRow; }
void setLoyalty(int _loyalty) { loyalty = _loyalty; emit cardInfoChanged(this); } //void setLoyalty(int _loyalty) { loyalty = _loyalty; emit cardInfoChanged(this); }
void setCustomPicURL(const QString &_set, const QString &_customPicURL) { customPicURLs.insert(_set, _customPicURL); } //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 setMuId(const QString &_set, const int &_muId) { muIds.insert(_set, _muId); }
void setSetNumber(const QString &_set, const QString &_setNumber) { collectorNumbers.insert(_set, _setNumber); } 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 setRarity(const QString &_set, const QString &_setNumber) { rarities.insert(_set, _setNumber); }
@ -168,6 +182,7 @@ public:
* less strict name-matching. * less strict name-matching.
*/ */
static QString simplifyName(const QString &name); static QString simplifyName(const QString &name);
signals: signals:
void pixmapUpdated(); void pixmapUpdated();
void cardInfoChanged(CardInfo *card); void cardInfoChanged(CardInfo *card);
@ -178,7 +193,8 @@ 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:
/* /*
@ -205,11 +221,18 @@ private:
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();
QBasicMutex *reloadDatabaseMutex = new QBasicMutex(),
*clearDatabaseMutex = new QBasicMutex(),
*loadFromFileMutex = new QBasicMutex(),
*addCardMutex = new QBasicMutex(),
*removeCardMutex = new QBasicMutex();
public: public:
static const char* TOKENS_SETNAME; static const char* TOKENS_SETNAME;
CardDatabase(QObject *parent = 0); explicit CardDatabase(QObject *parent = nullptr);
~CardDatabase(); ~CardDatabase() override;
void clear(); void clear();
void addCard(CardInfo *card); void addCard(CardInfo *card);
void removeCard(CardInfo *card); void removeCard(CardInfo *card);
@ -248,7 +271,8 @@ signals:
void cardRemoved(CardInfo *card); void cardRemoved(CardInfo *card);
}; };
class CardRelation : public QObject { class CardRelation : public QObject
{
Q_OBJECT Q_OBJECT
private: private:
QString name; QString name;
@ -257,12 +281,13 @@ private:
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; } inline const QString &getName() const { return name; }
bool getDoesAttach() const { return doesAttach; } bool getDoesAttach() const { return doesAttach; }
bool getCanCreateAnother() const { return !doesAttach; } bool getCanCreateAnother() const { return !doesAttach; }
@ -270,5 +295,4 @@ public:
bool getIsVariable() const { return isVariableCount; } bool getIsVariable() const { return isVariableCount; }
int getDefaultCount() const { return defaultCount; } 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);
@ -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,7 +990,8 @@ 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: case Ok:
showLoadError = false; showLoadError = false;
break; break;
@ -925,23 +1033,36 @@ void DlgSettings::closeEvent(QCloseEvent *event)
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,16 +26,19 @@ class QSpinBox;
class QSlider; class QSlider;
class QSpinBox; class QSpinBox;
class AbstractSettingsPage : public QWidget { class AbstractSettingsPage : public QWidget
{
public: public:
virtual void retranslateUi() = 0; 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: private slots:
void deckPathButtonClicked(); void deckPathButtonClicked();
void replaysPathButtonClicked(); void replaysPathButtonClicked();
@ -47,6 +50,7 @@ private slots:
void setEnabledStatus(bool); void setEnabledStatus(bool);
void defaultUrlRestoreButtonClicked(); void defaultUrlRestoreButtonClicked();
void fallbackUrlRestoreButtonClicked(); void fallbackUrlRestoreButtonClicked();
private: private:
QStringList findQmFiles(); QStringList findQmFiles();
QString languageName(const QString &qmFile); QString languageName(const QString &qmFile);
@ -80,10 +84,12 @@ private:
QPushButton fallbackUrlRestoreButton; 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: private:
QLabel themeLabel; QLabel themeLabel;
QComboBox themeBox; QComboBox themeBox;
@ -100,15 +106,18 @@ private:
QGroupBox *tableGroupBox; QGroupBox *tableGroupBox;
QSpinBox minPlayersForMultiColumnLayoutEdit; QSpinBox minPlayersForMultiColumnLayoutEdit;
QSpinBox maxFontSizeForCardsEdit; QSpinBox maxFontSizeForCardsEdit;
public: public:
AppearanceSettingsPage(); AppearanceSettingsPage();
void retranslateUi(); 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: private:
QCheckBox notificationsEnabledCheckBox; QCheckBox notificationsEnabledCheckBox;
QCheckBox specNotificationsEnabledCheckBox; QCheckBox specNotificationsEnabledCheckBox;
@ -121,25 +130,43 @@ private:
public: public:
UserInterfaceSettingsPage(); UserInterfaceSettingsPage();
void retranslateUi(); void retranslateUi() override;
}; };
class DeckEditorSettingsPage : public AbstractSettingsPage { class DeckEditorSettingsPage : public AbstractSettingsPage
{
Q_OBJECT Q_OBJECT
public: public:
DeckEditorSettingsPage(); DeckEditorSettingsPage();
void retranslateUi(); void retranslateUi() override;
QString getLastUpdateTime();
private slots: private slots:
signals: void setSpoilersEnabled(bool);
void spoilerPathButtonClicked();
void updateSpoilers();
void unlockSettings();
private: private:
QGroupBox *generalGroupBox; 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: private slots:
void actAdd(); void actAdd();
void actRemove(); void actRemove();
@ -147,6 +174,7 @@ private slots:
void updateHighlightColor(const QString &value); void updateHighlightColor(const QString &value);
void updateTextColor(int value); void updateTextColor(int value);
void updateTextHighlightColor(int value); void updateTextHighlightColor(int value);
private: private:
QListWidget *messageList; QListWidget *messageList;
QAction *aAdd; QAction *aAdd;
@ -175,11 +203,13 @@ private:
void updateHighlightPreview(); void updateHighlightPreview();
}; };
class SoundSettingsPage : public AbstractSettingsPage { class SoundSettingsPage : public AbstractSettingsPage
{
Q_OBJECT Q_OBJECT
public: public:
SoundSettingsPage(); SoundSettingsPage();
void retranslateUi(); void retranslateUi() override;
private: private:
QLabel themeLabel; QLabel themeLabel;
QComboBox themeBox; QComboBox themeBox;
@ -189,19 +219,23 @@ private:
QLabel masterVolumeLabel; QLabel masterVolumeLabel;
QSlider *masterVolumeSlider; QSlider *masterVolumeSlider;
QSpinBox *masterVolumeSpinBox; QSpinBox *masterVolumeSpinBox;
private slots: private slots:
void masterVolumeChanged(int value); void masterVolumeChanged(int value);
void themeBoxChanged(int index); 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: private slots:
void changePage(QListWidgetItem *current, QListWidgetItem *previous); void changePage(QListWidgetItem *current, QListWidgetItem *previous);
void updateLanguage(); void updateLanguage();
private: private:
QListWidget *contentsWidget; QListWidget *contentsWidget;
QStackedWidget *pagesWidget; QStackedWidget *pagesWidget;
@ -209,9 +243,10 @@ private:
QListWidgetItem *shortcutsButton; QListWidgetItem *shortcutsButton;
void createIcons(); void createIcons();
void retranslateUi(); void retranslateUi();
protected: protected:
void changeEvent(QEvent *event); void changeEvent(QEvent *event) override;
void closeEvent(QCloseEvent *event); 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,8 +712,13 @@ 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()));
if (! settingsCache->getDownloadSpoilersStatus())
{
qDebug() << "Spoilers Disabled";
QtConcurrent::run(db, &CardDatabase::loadCardDatabases); 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,7 +884,6 @@ void MainWindow::cardDatabaseAllNewSetsEnabled()
} }
/* CARD UPDATER */ /* CARD UPDATER */
void MainWindow::actCheckCardUpdates() void MainWindow::actCheckCardUpdates()
{ {
if (cardUpdateProcess) if (cardUpdateProcess)
@ -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);
if (! isSpoilersOnly)
{
addPage(new IntroPage); addPage(new IntroPage);
addPage(new LoadSetsPage); addPage(new LoadSetsPage);
addPage(new SaveSetsPage); addPage(new SaveSetsPage);
addPage(new LoadTokensPage); addPage(new LoadTokensPage);
addPage(new SaveTokensPage); 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,8 +85,10 @@ 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()
{ {
@ -103,17 +115,18 @@ bool OracleWizard::saveTokensToFile(const QString & fileName)
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);
@ -151,7 +169,9 @@ 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);
@ -246,10 +265,14 @@ void LoadSetsPage::actLoadSetsFile()
#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));
} }
@ -258,7 +281,9 @@ 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())
@ -282,7 +307,9 @@ 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())
{ {
@ -290,8 +317,9 @@ bool LoadSetsPage::validatePage()
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()));
@ -318,8 +349,8 @@ 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);
@ -353,9 +386,13 @@ void LoadSetsPage::actDownloadFinishedSetsFile()
// 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,14 +413,15 @@ 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;
} }
@ -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);
@ -449,13 +489,14 @@ void LoadSetsPage::importFinished()
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,8 +523,10 @@ 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);
@ -590,7 +794,9 @@ 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())
@ -617,7 +823,9 @@ 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()));
@ -628,8 +836,8 @@ 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);
@ -663,9 +873,13 @@ void LoadTokensPage::actDownloadFinishedTokensFile()
// 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,32 +988,46 @@ 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);
return true; return true;

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;
@ -22,34 +23,36 @@ 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: public:
OracleImporter *importer; OracleImporter *importer;
QSettings *settings; QSettings *settings;
private slots: private slots:
void updateLanguage(); void updateLanguage();
private:
QStringList findQmFiles();
QString languageName(const QString &qmFile);
QByteArray tokensData;
protected:
void changeEvent(QEvent *event);
};
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: protected:
inline OracleWizard *wizard() { return (OracleWizard*) QWizardPage::wizard(); }; inline OracleWizard *wizard() { return (OracleWizard*) QWizardPage::wizard(); };
}; };
@ -58,14 +61,17 @@ 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: private:
QStringList findQmFiles(); QStringList findQmFiles();
QString languageName(const QString &qmFile); QString languageName(const QString &qmFile);
private: private:
QLabel *label, *languageLabel, *versionLabel; QLabel *label, *languageLabel, *versionLabel;
QComboBox *languageBox; QComboBox *languageBox;
private slots: private slots:
void languageBoxChanged(int index); void languageBoxChanged(int index);
}; };
@ -74,13 +80,15 @@ 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: protected:
void initializePage(); void initializePage() override;
bool validatePage(); bool validatePage() override;
void readSetsFromByteArray(QByteArray data); void readSetsFromByteArray(QByteArray data);
void downloadSetsFile(QUrl url); void downloadSetsFile(QUrl url);
private: private:
QRadioButton *urlRadioButton; QRadioButton *urlRadioButton;
QRadioButton *fileRadioButton; QRadioButton *fileRadioButton;
@ -94,6 +102,7 @@ private:
QNetworkAccessManager *nam; QNetworkAccessManager *nam;
QFutureWatcher<bool> watcher; QFutureWatcher<bool> watcher;
QFuture<bool> future; QFuture<bool> future;
private slots: private slots:
void actLoadSetsFile(); void actLoadSetsFile();
void actRestoreDefaultUrl(); void actRestoreDefaultUrl();
@ -107,37 +116,82 @@ 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: private:
QTextEdit *messageLog; QTextEdit *messageLog;
QCheckBox *defaultPathCheckBox; QCheckBox *defaultPathCheckBox;
protected: protected:
void initializePage(); void initializePage() override;
void cleanupPage(); void cleanupPage() override;
bool validatePage(); bool validatePage() override;
private slots: private slots:
void updateTotalProgress(int cardsImported, int setIndex, const QString &setName); void updateTotalProgress(int cardsImported, int setIndex, const QString &setName);
}; };
class LoadTokensPage : public OracleWizardPage class LoadSpoilersPage : public OracleWizardPage
{ {
Q_OBJECT Q_OBJECT
public: public:
LoadTokensPage(QWidget *parent = 0); explicit LoadSpoilersPage(QWidget *parent = nullptr);
void retranslateUi(); void retranslateUi() override;
protected:
void initializePage();
bool validatePage();
void downloadTokensFile(QUrl url);
private: private:
QLabel *urlLabel; QLabel *urlLabel;
QLineEdit *urlLineEdit; QLineEdit *urlLineEdit;
QPushButton *urlButton; QPushButton *urlButton;
QLabel *progressLabel; QLabel *progressLabel;
QProgressBar *progressBar; QProgressBar *progressBar;
QNetworkAccessManager *nam; 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
{
Q_OBJECT
public:
explicit LoadTokensPage(QWidget *parent = nullptr);
void retranslateUi() override;
protected:
void initializePage() override;
bool validatePage() override;
void downloadTokensFile(QUrl url);
private:
QLabel *urlLabel;
QLineEdit *urlLineEdit;
QPushButton *urlButton;
QLabel *progressLabel;
QProgressBar *progressBar;
QNetworkAccessManager *nam;
private slots: private slots:
void actRestoreDefaultUrl(); void actRestoreDefaultUrl();
void actDownloadProgressTokensFile(qint64 received, qint64 total); void actDownloadProgressTokensFile(qint64 received, qint64 total);
@ -148,11 +202,14 @@ 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: private:
QCheckBox *defaultPathCheckBox; QCheckBox *defaultPathCheckBox;
protected: protected:
bool validatePage(); 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>