From 1d8fb79e1133e7f8a8774a89db25de82897dac82 Mon Sep 17 00:00:00 2001 From: ctrlaltca Date: Mon, 3 Jun 2019 03:47:37 +0200 Subject: [PATCH] Misc startup improvement (#3740) * Misc startup improvement * fix paths * clangiftw * reworked save sets dialog * Unified load and save steps for tokens and spoilers; added "finished" page * linting1 * linting2 * wording * undo layout change * wording * fix spoiler path again * simplify phrase * lint * lint fix Signed-off-by: Zach Halpern --- cockatrice/src/settingscache.cpp | 4 +- cockatrice/src/settingscache.h | 1 + cockatrice/src/spoilerbackgroundupdater.cpp | 4 +- cockatrice/src/window_main.cpp | 71 ++-- cockatrice/src/window_main.h | 16 +- cockatrice/src/window_sets.cpp | 1 - oracle/CMakeLists.txt | 1 + oracle/src/oraclewizard.cpp | 442 +++----------------- oracle/src/oraclewizard.h | 108 ++--- oracle/src/pagetemplates.cpp | 196 +++++++++ oracle/src/pagetemplates.h | 62 +++ 11 files changed, 402 insertions(+), 504 deletions(-) create mode 100644 oracle/src/pagetemplates.cpp create mode 100644 oracle/src/pagetemplates.h diff --git a/cockatrice/src/settingscache.cpp b/cockatrice/src/settingscache.cpp index 8583885a..01b68657 100644 --- a/cockatrice/src/settingscache.cpp +++ b/cockatrice/src/settingscache.cpp @@ -275,8 +275,8 @@ SettingsCache::SettingsCache() spectatorsCanTalk = settings->value("game/spectatorscantalk", false).toBool(); spectatorsCanSeeEverything = settings->value("game/spectatorscanseeeverything", false).toBool(); rememberGameSettings = settings->value("game/remembergamesettings", true).toBool(); - clientID = settings->value("personal/clientid", "notset").toString(); - clientVersion = settings->value("personal/clientversion", "notset").toString(); + clientID = settings->value("personal/clientid", CLIENT_INFO_NOT_SET).toString(); + clientVersion = settings->value("personal/clientversion", CLIENT_INFO_NOT_SET).toString(); knownMissingFeatures = settings->value("interface/knownmissingfeatures", "").toString(); } diff --git a/cockatrice/src/settingscache.h b/cockatrice/src/settingscache.h index 0dca177f..ca951cd7 100644 --- a/cockatrice/src/settingscache.h +++ b/cockatrice/src/settingscache.h @@ -21,6 +21,7 @@ class ReleaseChannel; #define DEFAULT_LANG_CODE "en" #define DEFAULT_LANG_NAME "English" +#define CLIENT_INFO_NOT_SET "notset" #define DEFAULT_FONT_SIZE 12 diff --git a/cockatrice/src/spoilerbackgroundupdater.cpp b/cockatrice/src/spoilerbackgroundupdater.cpp index 6c6003c6..0bcdbbbc 100644 --- a/cockatrice/src/spoilerbackgroundupdater.cpp +++ b/cockatrice/src/spoilerbackgroundupdater.cpp @@ -24,9 +24,9 @@ SpoilerBackgroundUpdater::SpoilerBackgroundUpdater(QObject *apParent) : QObject( 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); + } else { + qDebug() << "Spoilers Disabled"; } } diff --git a/cockatrice/src/window_main.cpp b/cockatrice/src/window_main.cpp index c6e43cb3..2de8227e 100644 --- a/cockatrice/src/window_main.cpp +++ b/cockatrice/src/window_main.cpp @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -838,31 +839,54 @@ MainWindow::MainWindow(QWidget *parent) SLOT(cardDatabaseNewSetsFound(int, QStringList))); connect(db, SIGNAL(cardDatabaseAllNewSetsEnabled()), this, SLOT(cardDatabaseAllNewSetsEnabled())); - if (!settingsCache->getDownloadSpoilersStatus()) { - qDebug() << "Spoilers Disabled"; - QtConcurrent::run(db, &CardDatabase::loadCardDatabases); - } - tip = new DlgTipOfTheDay(); - if (tip->successfulInit && settingsCache->getShowTipsOnStartup() && tip->newTipsAvailable) { - tip->show(); - } - // Only run the check updater if the user wants it (defaults to on) - if (settingsCache->getNotifyAboutNewVersion()) { - auto versionUpdater = new MainUpdateHelper(); - connect(versionUpdater, SIGNAL(newVersionDetected(QString)), this, SLOT(alertForcedOracleRun(QString))); - QtConcurrent::run(versionUpdater, &MainUpdateHelper::testForNewVersion); + // run startup check async + QTimer::singleShot(0, this, &MainWindow::startupConfigCheck); +} + +void MainWindow::startupConfigCheck() +{ + if (settingsCache->getClientVersion() == CLIENT_INFO_NOT_SET) { + // no config found, 99% new clean install + qDebug() << "Startup: old client version empty, assuming first start after clean install"; + alertForcedOracleRun(VERSION_STRING, false); + } else if (settingsCache->getClientVersion() != VERSION_STRING) { + // config found, from another (presumably older) version + qDebug() << "Startup: old client version" << settingsCache->getClientVersion() + << "differs, assuming first start after update"; + if (settingsCache->getNotifyAboutNewVersion()) { + alertForcedOracleRun(VERSION_STRING, true); + } + } else { + // previous config from this version found + qDebug() << "Startup: found config with current version"; + QtConcurrent::run(db, &CardDatabase::loadCardDatabases); + + // Run the tips dialog only on subsequent startups. + // On the first run after an install/update the startup is already crowded enough + if (tip->successfulInit && settingsCache->getShowTipsOnStartup() && tip->newTipsAvailable) { + tip->raise(); + tip->show(); + } } } -void MainWindow::alertForcedOracleRun(const QString &newVersion) +void MainWindow::alertForcedOracleRun(const QString &version, bool isUpdate) { - settingsCache->setClientVersion(newVersion); - QMessageBox::information(this, tr("New Version"), - tr("Congratulations on updating to Cockatrice %1!\n" - "Oracle will now launch to update your card database.") - .arg(newVersion)); + settingsCache->setClientVersion(version); + if (isUpdate) { + QMessageBox::information(this, tr("New Version"), + tr("Congratulations on updating to Cockatrice %1!\n" + "Oracle will now launch to update your card database.") + .arg(version)); + } else { + QMessageBox::information(this, tr("Cockatrice installed"), + tr("Congratulations on installing Cockatrice %1!\n" + "Oracle will now launch to install the initial card database.") + .arg(version)); + } + actCheckCardUpdates(); actCheckServerUpdates(); } @@ -1123,8 +1147,6 @@ void MainWindow::cardUpdateFinished(int, QProcess::ExitStatus) cardUpdateProcess->deleteLater(); cardUpdateProcess = nullptr; - QMessageBox::information(this, tr("Information"), - tr("Update completed successfully.\nCockatrice will now reload the card database.")); QtConcurrent::run(db, &CardDatabase::loadCardDatabases); } @@ -1317,10 +1339,3 @@ void MainWindow::promptForgotPasswordReset() dlg.getPlayerName(), dlg.getToken(), dlg.getPassword()); } } - -void MainUpdateHelper::testForNewVersion() -{ - if (settingsCache->getClientVersion() != VERSION_STRING) { - emit newVersionDetected(VERSION_STRING); - } -} diff --git a/cockatrice/src/window_main.h b/cockatrice/src/window_main.h index 66787129..137d5825 100644 --- a/cockatrice/src/window_main.h +++ b/cockatrice/src/window_main.h @@ -102,7 +102,8 @@ private slots: void actManageSets(); void actEditTokens(); - void alertForcedOracleRun(const QString &); + void startupConfigCheck(); + void alertForcedOracleRun(const QString &version, bool isUpdate); private: static const QString appName; @@ -154,17 +155,4 @@ protected: QString extractInvalidUsernameMessage(QString &in); }; -class MainUpdateHelper : public QObject -{ - Q_OBJECT - -signals: - void newVersionDetected(QString); - -public: - explicit MainUpdateHelper() = default; - ~MainUpdateHelper() override = default; - void testForNewVersion(); -}; - #endif diff --git a/cockatrice/src/window_sets.cpp b/cockatrice/src/window_sets.cpp index 95ac6ba4..b463b0e3 100644 --- a/cockatrice/src/window_sets.cpp +++ b/cockatrice/src/window_sets.cpp @@ -214,7 +214,6 @@ void WndSets::actSave() { model->save(db); PictureLoader::clearPixmapCache(); - QMessageBox::information(this, tr("Success"), tr("The sets database has been saved successfully.")); close(); } diff --git a/oracle/CMakeLists.txt b/oracle/CMakeLists.txt index 22907762..0ef36662 100644 --- a/oracle/CMakeLists.txt +++ b/oracle/CMakeLists.txt @@ -11,6 +11,7 @@ SET(oracle_SOURCES src/main.cpp src/oraclewizard.cpp src/oracleimporter.cpp + src/pagetemplates.cpp src/qt-json/json.cpp ../cockatrice/src/carddatabase.cpp ../cockatrice/src/pictureloader.cpp diff --git a/oracle/src/oraclewizard.cpp b/oracle/src/oraclewizard.cpp index ef244544..1f874416 100644 --- a/oracle/src/oraclewizard.cpp +++ b/oracle/src/oraclewizard.cpp @@ -57,15 +57,17 @@ OracleWizard::OracleWizard(QWidget *parent) : QWizard(parent) importer = new OracleImporter(settingsCache->getDataPath(), this); + nam = new QNetworkAccessManager(this); + if (!isSpoilersOnly) { addPage(new IntroPage); addPage(new LoadSetsPage); addPage(new SaveSetsPage); addPage(new LoadTokensPage); - addPage(new SaveTokensPage); + addPage(new OutroPage); } else { addPage(new LoadSpoilersPage); - addPage(new SaveSpoilersPage); + addPage(new OutroPage); } retranslateUi(); @@ -89,8 +91,6 @@ void OracleWizard::changeEvent(QEvent *event) void OracleWizard::retranslateUi() { setWindowTitle(tr("Oracle Importer")); - QWizard::setButtonText(QWizard::FinishButton, tr("Save")); - for (int i = 0; i < pageIds().count(); i++) { dynamic_cast(page(i))->retranslateUi(); } @@ -195,7 +195,15 @@ void IntroPage::retranslateUi() versionLabel->setText(tr("Version:") + QString(" %1").arg(VERSION_STRING)); } -LoadSetsPage::LoadSetsPage(QWidget *parent) : OracleWizardPage(parent), nam(nullptr) +void OutroPage::retranslateUi() +{ + setTitle(tr("Finished")); + setSubTitle(tr("The wizard has finished.") + "
" + + tr("You can now start using Cockatrice with the newly updated cards.") + "

" + + tr("If the card databases don't reload automatically, restart the Cockatrice client.")); +} + +LoadSetsPage::LoadSetsPage(QWidget *parent) : OracleWizardPage(parent) { urlRadioButton = new QRadioButton(this); fileRadioButton = new QRadioButton(this); @@ -240,7 +248,7 @@ void LoadSetsPage::initializePage() void LoadSetsPage::retranslateUi() { setTitle(tr("Source selection")); - setSubTitle(tr("Please specify a source for the list of sets and cards. " + setSubTitle(tr("Please specify a compatible source for the list of sets and cards. " "You can specify a URL address that will be downloaded or " "use an existing file from your computer.")); @@ -330,10 +338,7 @@ bool LoadSetsPage::validatePage() void LoadSetsPage::downloadSetsFile(QUrl url) { - if (!nam) { - nam = new QNetworkAccessManager(this); - } - QNetworkReply *reply = nam->get(QNetworkRequest(url)); + QNetworkReply *reply = wizard()->nam->get(QNetworkRequest(url)); connect(reply, SIGNAL(finished()), this, SLOT(actDownloadFinishedSetsFile())); connect(reply, SIGNAL(downloadProgress(qint64, qint64)), this, SLOT(actDownloadProgressSetsFile(qint64, qint64))); @@ -478,8 +483,7 @@ void LoadSetsPage::zipDownloadFailed(const QString &message) QMessageBox::StandardButton reply; reply = static_cast(QMessageBox::question( - this, tr("Error"), - message + "
" + tr("Do you want to try to download a fresh copy of the uncompressed file instead?"), + this, tr("Error"), message + "
" + tr("Do you want to download the uncompressed file instead?"), QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes)); if (reply == QMessageBox::Yes) { @@ -507,15 +511,19 @@ void LoadSetsPage::importFinished() SaveSetsPage::SaveSetsPage(QWidget *parent) : OracleWizardPage(parent) { + pathLabel = new QLabel(this); + saveLabel = new QLabel(this); + defaultPathCheckBox = new QCheckBox(this); - defaultPathCheckBox->setChecked(true); messageLog = new QTextEdit(this); messageLog->setReadOnly(true); auto *layout = new QGridLayout(this); - layout->addWidget(defaultPathCheckBox, 0, 0); - layout->addWidget(messageLog, 1, 0); + layout->addWidget(messageLog, 0, 0); + layout->addWidget(saveLabel, 1, 0); + layout->addWidget(pathLabel, 2, 0); + layout->addWidget(defaultPathCheckBox, 3, 0); setLayout(layout); } @@ -540,10 +548,13 @@ void SaveSetsPage::initializePage() void SaveSetsPage::retranslateUi() { setTitle(tr("Sets imported")); - setSubTitle(tr("The following sets has been imported. " - "Press \"Save\" to save the imported cards to the Cockatrice database.")); + setSubTitle(tr("The following sets have been found:")); + + saveLabel->setText(tr("Press \"Save\" to store the imported cards in the Cockatrice database.")); + pathLabel->setText(tr("The card database will be saved at the following location:") + "
" + + settingsCache->getCardDatabasePath()); + defaultPathCheckBox->setText(tr("Save to a custom path (not recommended)")); - defaultPathCheckBox->setText(tr("Save to the default path (recommended)")); setButtonText(QWizard::NextButton, tr("&Save")); } @@ -569,9 +580,9 @@ bool SaveSetsPage::validatePage() do { QString fileName; if (defaultPathCheckBox->isChecked()) { - fileName = defaultPath; - } else { fileName = QFileDialog::getSaveFileName(this, windowName, defaultPath, fileType); + } else { + fileName = defaultPath; } if (fileName.isEmpty()) { @@ -586,409 +597,84 @@ bool SaveSetsPage::validatePage() if (wizard()->importer->saveToFile(fileName)) { ok = true; - QMessageBox::information(this, tr("Success"), - tr("The card database has been saved successfully to\n%1").arg(fileName)); } else { QMessageBox::critical(this, tr("Error"), tr("The file could not be saved to %1").arg(fileName)); - ; - if (defaultPathCheckBox->isChecked()) { - defaultPathCheckBox->setChecked(false); - } } } while (!ok); return true; } -LoadSpoilersPage::LoadSpoilersPage(QWidget *parent) : OracleWizardPage(parent), nam(nullptr) +QString LoadTokensPage::getDefaultUrl() { - 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(urlLineEdit, 0, 1); - layout->addWidget(urlButton, 1, 1, Qt::AlignRight); - layout->addWidget(progressLabel, 2, 0); - layout->addWidget(progressBar, 2, 1); + return TOKENS_URL; } -void LoadSpoilersPage::actRestoreDefaultUrl() +QString LoadTokensPage::getCustomUrlSettingsKey() { - urlLineEdit->setText(SPOILERS_URL); + return "tokensurl"; } -void LoadSpoilersPage::initializePage() +QString LoadTokensPage::getDefaultSavePath() { - urlLineEdit->setText(wizard()->settings->value("spoilersurl", SPOILERS_URL).toString()); - - progressLabel->hide(); - progressBar->hide(); + return settingsCache->getTokenDatabasePath(); } -void LoadSpoilersPage::actDownloadProgressSpoilersFile(qint64 received, qint64 total) +QString LoadTokensPage::getWindowTitle() { - if (total > 0) { - progressBar->setMaximum(static_cast(total)); - progressBar->setValue(static_cast(received)); - } - - progressLabel->setText(tr("Downloading (%1MB)").arg((int)received / (1024 * 1024))); + return tr("Save token database"); } -void LoadSpoilersPage::actDownloadFinishedSpoilersFile() +QString LoadTokensPage::getFileType() { - // Check for server reply - auto *reply = dynamic_cast(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(urlLineEdit, 0, 1); - layout->addWidget(urlButton, 1, 1, Qt::AlignRight); - layout->addWidget(progressLabel, 2, 0); - layout->addWidget(progressBar, 2, 1); - - setLayout(layout); -} - -void LoadTokensPage::initializePage() -{ - urlLineEdit->setText(wizard()->settings->value("tokensurl", TOKENS_URL).toString()); - - progressLabel->hide(); - progressBar->hide(); + return tr("XML; token database (*.xml)"); } void LoadTokensPage::retranslateUi() { - setTitle(tr("Tokens source selection")); - setSubTitle(tr("Please specify a source for the list of tokens.")); + setTitle(tr("Tokens import")); + setSubTitle(tr("Please specify a compatible source for token data.")); urlLabel->setText(tr("Download URL:")); urlButton->setText(tr("Restore default URL")); + pathLabel->setText(tr("The token database will be saved at the following location:") + "
" + + settingsCache->getTokenDatabasePath()); + defaultPathCheckBox->setText(tr("Save to a custom path (not recommended)")); } -void LoadTokensPage::actRestoreDefaultUrl() +QString LoadSpoilersPage::getDefaultUrl() { - urlLineEdit->setText(TOKENS_URL); + return SPOILERS_URL; } -bool LoadTokensPage::validatePage() +QString LoadSpoilersPage::getCustomUrlSettingsKey() { - // 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); - - downloadTokensFile(url); - return false; + return "spoilersurl"; } -void LoadTokensPage::downloadTokensFile(QUrl url) +QString LoadSpoilersPage::getDefaultSavePath() { - if (!nam) { - nam = new QNetworkAccessManager(this); - } - QNetworkReply *reply = nam->get(QNetworkRequest(url)); - - connect(reply, SIGNAL(finished()), this, SLOT(actDownloadFinishedTokensFile())); - connect(reply, SIGNAL(downloadProgress(qint64, qint64)), this, SLOT(actDownloadProgressTokensFile(qint64, qint64))); + return settingsCache->getTokenDatabasePath(); } -void LoadTokensPage::actDownloadProgressTokensFile(qint64 received, qint64 total) +QString LoadSpoilersPage::getWindowTitle() { - if (total > 0) { - progressBar->setMaximum(static_cast(total)); - progressBar->setValue(static_cast(received)); - } - progressLabel->setText(tr("Downloading (%1MB)").arg((int)received / (1024 * 1024))); + return tr("Save spoiler database"); } -void LoadTokensPage::actDownloadFinishedTokensFile() +QString LoadSpoilersPage::getFileType() { - // check for a reply - auto *reply = dynamic_cast(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(); - downloadTokensFile(redirectUrl); - reply->deleteLater(); - return; - } - - progressLabel->hide(); - progressBar->hide(); - - // save tokens.xml url, but only if the user customized it and download was successfull - if (urlLineEdit->text() != QString(TOKENS_URL)) { - wizard()->settings->setValue("tokensurl", urlLineEdit->text()); - } else { - wizard()->settings->remove("tokensurl"); - } - - wizard()->setTokensData(reply->readAll()); - reply->deleteLater(); - - wizard()->enableButtons(); - setEnabled(true); - progressLabel->hide(); - progressBar->hide(); - - wizard()->next(); + return tr("XML; spoiler database (*.xml)"); } -SaveSpoilersPage::SaveSpoilersPage(QWidget *parent) : OracleWizardPage(parent) +void LoadSpoilersPage::retranslateUi() { - defaultPathCheckBox = new QCheckBox(this); - defaultPathCheckBox->setChecked(true); + setTitle(tr("Spoilers import")); + setSubTitle(tr("Please specify a compatible source for spoiler data.")); - auto *layout = new QGridLayout(this); - layout->addWidget(defaultPathCheckBox, 0, 0); - - setLayout(layout); + urlLabel->setText(tr("Download URL:")); + urlButton->setText(tr("Restore default URL")); + pathLabel->setText(tr("The spoiler database will be saved at the following location:") + "
" + + settingsCache->getSpoilerCardDatabasePath()); + defaultPathCheckBox->setText(tr("Save to a custom path (not recommended)")); } - -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); - - setLayout(layout); -} - -void SaveTokensPage::retranslateUi() -{ - setTitle(tr("Tokens imported")); - setSubTitle(tr("The tokens has been imported. " - "Press \"Save\" to save the imported tokens to the Cockatrice tokens database.")); - - defaultPathCheckBox->setText(tr("Save to the default path (recommended)")); -} - -bool SaveTokensPage::validatePage() -{ - bool ok = false; - QString defaultPath = settingsCache->getTokenDatabasePath(); - QString windowName = tr("Save token database"); - QString fileType = tr("XML; token 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; - QMessageBox::information(this, tr("Success"), - tr("The token database has been saved successfully to\n%1").arg(fileName)); - } else { - QMessageBox::critical(this, tr("Error"), tr("The file could not be saved to %1").arg(fileName)); - ; - if (defaultPathCheckBox->isChecked()) { - defaultPathCheckBox->setChecked(false); - } - } - } while (!ok); - - return true; -} \ No newline at end of file diff --git a/oracle/src/oraclewizard.h b/oracle/src/oraclewizard.h index f3275998..89a90495 100644 --- a/oracle/src/oraclewizard.h +++ b/oracle/src/oraclewizard.h @@ -19,6 +19,8 @@ class QVBoxLayout; class OracleImporter; class QSettings; +#include "pagetemplates.h" + class OracleWizard : public QWizard { Q_OBJECT @@ -41,6 +43,7 @@ public: public: OracleImporter *importer; QSettings *settings; + QNetworkAccessManager *nam; private slots: void updateLanguage(); @@ -52,20 +55,6 @@ protected: void changeEvent(QEvent *event) override; }; -class OracleWizardPage : public QWizardPage -{ - Q_OBJECT -public: - explicit OracleWizardPage(QWidget *parent = nullptr) : QWizardPage(parent){}; - virtual void retranslateUi() = 0; - -protected: - inline OracleWizard *wizard() - { - return (OracleWizard *)QWizardPage::wizard(); - }; -}; - class IntroPage : public OracleWizardPage { Q_OBJECT @@ -85,6 +74,16 @@ private slots: void languageBoxChanged(int index); }; +class OutroPage : public OracleWizardPage +{ + Q_OBJECT +public: + explicit OutroPage(QWidget * = nullptr) + { + } + void retranslateUi() override; +}; + class LoadSetsPage : public OracleWizardPage { Q_OBJECT @@ -108,7 +107,6 @@ private: QLabel *progressLabel; QProgressBar *progressBar; - QNetworkAccessManager *nam; QFutureWatcher watcher; QFuture future; @@ -131,6 +129,8 @@ public: private: QTextEdit *messageLog; QCheckBox *defaultPathCheckBox; + QLabel *pathLabel; + QLabel *saveLabel; protected: void initializePage() override; @@ -141,84 +141,34 @@ private slots: void updateTotalProgress(int cardsImported, int setIndex, const QString &setName); }; -class LoadSpoilersPage : public OracleWizardPage +class LoadSpoilersPage : public SimpleDownloadFilePage { Q_OBJECT public: - explicit LoadSpoilersPage(QWidget *parent = nullptr); + explicit LoadSpoilersPage(QWidget * = nullptr){}; void retranslateUi() override; -private: - QLabel *urlLabel; - QLineEdit *urlLineEdit; - QPushButton *urlButton; - QLabel *progressLabel; - QProgressBar *progressBar; - QNetworkAccessManager *nam; - -private slots: - void actRestoreDefaultUrl(); - void actDownloadProgressSpoilersFile(qint64 received, qint64 total); - void actDownloadFinishedSpoilersFile(); - protected: - void initializePage() override; - bool validatePage() override; - void downloadSpoilersFile(QUrl url); + QString getDefaultUrl() override; + QString getCustomUrlSettingsKey() override; + QString getDefaultSavePath() override; + QString getWindowTitle() override; + QString getFileType() override; }; -class SaveSpoilersPage : public OracleWizardPage +class LoadTokensPage : public SimpleDownloadFilePage { 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); + explicit LoadTokensPage(QWidget * = 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: - void actRestoreDefaultUrl(); - void actDownloadProgressTokensFile(qint64 received, qint64 total); - void actDownloadFinishedTokensFile(); -}; - -class SaveTokensPage : public OracleWizardPage -{ - Q_OBJECT -public: - explicit SaveTokensPage(QWidget *parent = nullptr); - void retranslateUi() override; - -private: - QCheckBox *defaultPathCheckBox; - -protected: - bool validatePage() override; + QString getDefaultUrl() override; + QString getCustomUrlSettingsKey() override; + QString getDefaultSavePath() override; + QString getWindowTitle() override; + QString getFileType() override; }; #endif \ No newline at end of file diff --git a/oracle/src/pagetemplates.cpp b/oracle/src/pagetemplates.cpp new file mode 100644 index 00000000..01220310 --- /dev/null +++ b/oracle/src/pagetemplates.cpp @@ -0,0 +1,196 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "oraclewizard.h" +#include "pagetemplates.h" + +SimpleDownloadFilePage::SimpleDownloadFilePage(QWidget *parent) : OracleWizardPage(parent) +{ + 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())); + + defaultPathCheckBox = new QCheckBox(this); + + pathLabel = new QLabel(this); + pathLabel->setTextInteractionFlags(Qt::TextSelectableByMouse); + + auto *layout = new QGridLayout(this); + layout->addWidget(urlLabel, 0, 0); + layout->addWidget(urlLineEdit, 0, 1); + layout->addWidget(urlButton, 1, 1, Qt::AlignRight); + layout->addWidget(pathLabel, 2, 0, 1, 2); + layout->addWidget(defaultPathCheckBox, 3, 0, 1, 2); + layout->addWidget(progressLabel, 4, 0); + layout->addWidget(progressBar, 4, 1); + + setLayout(layout); +} + +void SimpleDownloadFilePage::initializePage() +{ + // get custom url from settings if any; otherwise use default url + urlLineEdit->setText(wizard()->settings->value(getCustomUrlSettingsKey(), getDefaultUrl()).toString()); + + progressLabel->hide(); + progressBar->hide(); +} + +void SimpleDownloadFilePage::actRestoreDefaultUrl() +{ + urlLineEdit->setText(getDefaultUrl()); +} + +bool SimpleDownloadFilePage::validatePage() +{ + // if data has already been downloaded, pass directly to the "save" step + if (!downloadData.isEmpty()) { + if (saveToFile()) { + return true; + } else { + wizard()->enableButtons(); + return false; + } + } + + 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(); + downloadFile(url); + return false; +} + +void SimpleDownloadFilePage::downloadFile(QUrl url) +{ + QNetworkReply *reply = wizard()->nam->get(QNetworkRequest(url)); + + connect(reply, SIGNAL(finished()), this, SLOT(actDownloadFinished())); + connect(reply, SIGNAL(downloadProgress(qint64, qint64)), this, SLOT(actDownloadProgress(qint64, qint64))); +} + +void SimpleDownloadFilePage::actDownloadProgress(qint64 received, qint64 total) +{ + if (total > 0) { + progressBar->setMaximum(static_cast(total)); + progressBar->setValue(static_cast(received)); + } + progressLabel->setText(tr("Downloading (%1MB)").arg((int)received / (1024 * 1024))); +} + +void SimpleDownloadFilePage::actDownloadFinished() +{ + // check for a reply + auto *reply = dynamic_cast(sender()); + QNetworkReply::NetworkError errorCode = reply->error(); + if (errorCode != QNetworkReply::NoError) { + QMessageBox::critical(this, tr("Error"), tr("Network error: %1.").arg(reply->errorString())); + wizard()->enableButtons(); + 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(); + downloadFile(redirectUrl); + reply->deleteLater(); + return; + } + + // save downlaoded file url, but only if the user customized it and download was successfull + if (urlLineEdit->text() != getDefaultUrl()) { + wizard()->settings->setValue(getCustomUrlSettingsKey(), urlLineEdit->text()); + } else { + wizard()->settings->remove(getCustomUrlSettingsKey()); + } + + downloadData = reply->readAll(); + reply->deleteLater(); + + wizard()->enableButtons(); + progressLabel->hide(); + progressBar->hide(); + + wizard()->next(); +} + +bool SimpleDownloadFilePage::saveToFile() +{ + bool ok = false; + QString defaultPath = getDefaultSavePath(); + QString windowName = getWindowTitle(); + QString fileType = getFileType(); + + do { + QString fileName; + if (defaultPathCheckBox->isChecked()) { + fileName = QFileDialog::getSaveFileName(this, windowName, defaultPath, fileType); + } else { + fileName = defaultPath; + } + + if (fileName.isEmpty()) { + return false; + } + + QFileInfo fi(fileName); + QDir fileDir(fi.path()); + if (!fileDir.exists() && !fileDir.mkpath(fileDir.absolutePath())) { + return false; + } + + if (internalSaveToFile(fileName)) { + ok = true; + } else { + QMessageBox::critical(this, tr("Error"), tr("The file could not be saved to %1").arg(fileName)); + } + } while (!ok); + + // clean saved downloadData + downloadData = QByteArray(); + return true; +} + +bool SimpleDownloadFilePage::internalSaveToFile(const QString &fileName) +{ + QFile file(fileName); + if (!file.open(QIODevice::WriteOnly)) { + qDebug() << "File open (w) failed for" << fileName; + return false; + } + + if (file.write(downloadData) == -1) { + qDebug() << "File write (w) failed for" << fileName; + return false; + } + + file.close(); + return true; +} diff --git a/oracle/src/pagetemplates.h b/oracle/src/pagetemplates.h new file mode 100644 index 00000000..a65559ae --- /dev/null +++ b/oracle/src/pagetemplates.h @@ -0,0 +1,62 @@ +#ifndef PAGETEMPLATES_H +#define PAGETEMPLATES_H + +#include + +class OracleWizard; +class QCheckBox; +class QLabel; +class QLineEdit; +class QProgressBar; + +class OracleWizardPage : public QWizardPage +{ + Q_OBJECT +public: + explicit OracleWizardPage(QWidget *parent = nullptr) : QWizardPage(parent){}; + virtual void retranslateUi() = 0; + +protected: + inline OracleWizard *wizard() + { + return (OracleWizard *)QWizardPage::wizard(); + }; +}; + +class SimpleDownloadFilePage : public OracleWizardPage +{ + Q_OBJECT +public: + explicit SimpleDownloadFilePage(QWidget *parent = nullptr); + +protected: + void initializePage() override; + bool validatePage() override; + void downloadFile(QUrl url); + virtual QString getDefaultUrl() = 0; + virtual QString getCustomUrlSettingsKey() = 0; + virtual QString getDefaultSavePath() = 0; + virtual QString getWindowTitle() = 0; + virtual QString getFileType() = 0; + bool saveToFile(); + bool internalSaveToFile(const QString &fileName); + +protected: + QByteArray downloadData; + QLabel *urlLabel; + QLabel *pathLabel; + QLineEdit *urlLineEdit; + QPushButton *urlButton; + QLabel *progressLabel; + QProgressBar *progressBar; + QCheckBox *defaultPathCheckBox; + +signals: + void parsedDataReady(); +private slots: + void actRestoreDefaultUrl(); + void actDownloadProgress(qint64 received, qint64 total); + void actDownloadFinished(); +}; + +#endif // PAGETEMPLATES_H