diff --git a/cockatrice/src/interface/window_main.cpp b/cockatrice/src/interface/window_main.cpp index 815cec1d2..57d6e8b15 100644 --- a/cockatrice/src/interface/window_main.cpp +++ b/cockatrice/src/interface/window_main.cpp @@ -1253,7 +1253,7 @@ void MainWindow::createCardUpdateProcess(bool background) << dir.absoluteFilePath(binaryName); QMessageBox::warning(this, tr("Error"), tr("Unable to run the card database updater: ") + dir.absoluteFilePath(binaryName)); - exitCardDatabaseUpdate(); + exitCardDatabaseUpdate(false); emit cardDatabaseUpdateFinished(false); return; } @@ -1330,7 +1330,7 @@ void MainWindow::cardUpdateStandardError() } } -void MainWindow::exitCardDatabaseUpdate() +void MainWindow::exitCardDatabaseUpdate(bool doReload) { if (!cardUpdateProcess) { return; @@ -1339,9 +1339,11 @@ void MainWindow::exitCardDatabaseUpdate() cardUpdateProcess = nullptr; statusBar()->clearMessage(); - // This can be the first successful load of the session (e.g. the onboarding - // download), so it must own the set check for that load. - reloadCardDatabaseAndCheckSets(); + if (doReload) { + // This can be the first successful load of the session (e.g. the onboarding + // download), so it must own the set check for that load. + reloadCardDatabaseAndCheckSets(); + } } void MainWindow::reloadCardDatabaseAndCheckSets() @@ -1387,7 +1389,7 @@ void MainWindow::cardUpdateError(QProcess::ProcessError err) } qCWarning(CardDatabaseUpdateLog) << "The card database updater exited with an error:" << error; - exitCardDatabaseUpdate(); + exitCardDatabaseUpdate(false); QMessageBox::warning(this, tr("Error"), tr("The card database updater exited with an error:\n%1").arg(error)); emit cardDatabaseUpdateFinished(false); } @@ -1400,12 +1402,14 @@ void MainWindow::cardUpdateFinished(int exitCode, QProcess::ExitStatus exitStatu cardUpdateProgressOutput(); // drain any progress lines not yet parsed const bool success = (exitStatus == QProcess::NormalExit) && (exitCode == 0); - if (exitStatus == QProcess::NormalExit) { + if (success) { SettingsCache::instance().updates().setLastCardUpdateCheck(QDateTime::currentDateTime().date()); + } else if (exitStatus == QProcess::NormalExit) { + statusBar()->showMessage(tr("Card database update cancelled."), 10000); } qCInfo(CardDatabaseUpdateLog) << "The card database updater finished with exit code" << exitCode << "exit status" << static_cast(exitStatus) << "success:" << success; - exitCardDatabaseUpdate(); + exitCardDatabaseUpdate(success); notifyCardUpdateFinishedFromTray(success); emit cardDatabaseUpdateFinished(success); } diff --git a/cockatrice/src/interface/window_main.h b/cockatrice/src/interface/window_main.h index ee8873000..2b6ed5633 100644 --- a/cockatrice/src/interface/window_main.h +++ b/cockatrice/src/interface/window_main.h @@ -157,7 +157,7 @@ private: return "oracle"; } void createCardUpdateProcess(bool background = false); - void exitCardDatabaseUpdate(); + void exitCardDatabaseUpdate(bool doReload); /** * @brief Reloads the card database on a worker thread and runs checkUnknownSets() once the finished * snapshot has been swapped in. diff --git a/oracle/src/main.cpp b/oracle/src/main.cpp index cae2ee37d..bf56df5c9 100644 --- a/oracle/src/main.cpp +++ b/oracle/src/main.cpp @@ -85,5 +85,8 @@ int main(int argc, char *argv[]) QTimer::singleShot(0, &wizard, [&wizard]() { wizard.runInBackground(); }); } - return app.exec(); + const int execResult = app.exec(); + // A cancel only counts when nothing was written yet: closing the wizard + // after the card database was already saved on disk is still an update. + return (wizard.wasCancelled() && !wizard.hasSavedDatabase()) ? 1 : execResult; } diff --git a/oracle/src/oraclewizard.cpp b/oracle/src/oraclewizard.cpp index 05f08ce64..d2b3a71a4 100644 --- a/oracle/src/oraclewizard.cpp +++ b/oracle/src/oraclewizard.cpp @@ -128,12 +128,20 @@ void OracleWizard::accept() void OracleWizard::reject() { + cancelled = true; + // The wizard is being closed while a page may still run a worker on the // importer. Ask it to stop before the wizard (and the importer child) is // destroyed, so the worker thread never touches freed memory. if (auto *active = dynamic_cast(currentPage())) { active->cancelWork(); } + + const auto replies = nam->findChildren(); + for (QNetworkReply *reply : replies) { + reply->abort(); + } + QWizard::reject(); } diff --git a/oracle/src/oraclewizard.h b/oracle/src/oraclewizard.h index ea652bdc5..b1dc5eab2 100644 --- a/oracle/src/oraclewizard.h +++ b/oracle/src/oraclewizard.h @@ -20,6 +20,19 @@ public: explicit OracleWizard(QWidget *parent = nullptr); void accept() override; void reject() override; + bool wasCancelled() + { + return cancelled; + } + /** @brief Records that the card database was written to disk, so a later cancel still counts as an update. */ + void markDatabaseSaved() + { + databaseSaved = true; + } + bool hasSavedDatabase() + { + return databaseSaved; + } void enableButtons(); void disableButtons(); void retranslateUi(); @@ -67,6 +80,8 @@ private: QByteArray tokensData; QString cardSourceUrl; QString cardSourceVersion; + bool cancelled = false; + bool databaseSaved = false; void migrateOracleSettings(); /** diff --git a/oracle/src/pages.cpp b/oracle/src/pages.cpp index 8c286fb46..ed8e04d1a 100644 --- a/oracle/src/pages.cpp +++ b/oracle/src/pages.cpp @@ -484,6 +484,10 @@ void LoadSetsPage::actDownloadFinishedSetsFile() { // check for a reply auto *reply = dynamic_cast(sender()); + if (wizard()->wasCancelled()) { + reply->deleteLater(); + return; + } auto errorCode = reply->error(); if (errorCode != QNetworkReply::NoError) { QMessageBox::critical(this, tr("Error"), tr("Network error: %1.").arg(reply->errorString())); @@ -895,6 +899,7 @@ bool SaveSetsPage::validatePage() return false; } + wizard()->markDatabaseSaved(); return true; } diff --git a/oracle/src/pagetemplates.cpp b/oracle/src/pagetemplates.cpp index d37818dcb..dcc8e070c 100644 --- a/oracle/src/pagetemplates.cpp +++ b/oracle/src/pagetemplates.cpp @@ -178,6 +178,10 @@ void SimpleDownloadFilePage::actDownloadFinished() { // check for a reply auto *reply = dynamic_cast(sender()); + if (wizard()->wasCancelled()) { + reply->deleteLater(); + return; + } QNetworkReply::NetworkError errorCode = reply->error(); if (errorCode != QNetworkReply::NoError) { QMessageBox::critical(this, tr("Error"), tr("Network error: %1.").arg(reply->errorString())); @@ -242,6 +246,7 @@ bool SimpleDownloadFilePage::saveToFile() // clean saved downloadData downloadData = QByteArray(); + wizard()->markDatabaseSaved(); return true; }