From deb60b1bc2abc86b953a8f70d406dfb011d2fd59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20Br=C3=BCbach?= Date: Tue, 24 Jun 2025 21:23:27 +0200 Subject: [PATCH] Add the option to background the oracle wizard, add an option to automatically launch oracle wizard in background every X days since last launch. --- cockatrice/src/client/ui/window_main.cpp | 32 ++++++++++++- cockatrice/src/client/ui/window_main.h | 5 +- cockatrice/src/dialogs/dlg_settings.cpp | 27 +++++++++-- cockatrice/src/dialogs/dlg_settings.h | 4 ++ cockatrice/src/settings/cache_settings.cpp | 21 ++++++++ cockatrice/src/settings/cache_settings.h | 24 ++++++++++ oracle/src/main.cpp | 15 ++++-- oracle/src/oraclewizard.cpp | 56 +++++++++++++++++++--- oracle/src/oraclewizard.h | 19 +++++++- oracle/src/pagetemplates.cpp | 2 +- oracle/src/pagetemplates.h | 5 +- 11 files changed, 190 insertions(+), 20 deletions(-) diff --git a/cockatrice/src/client/ui/window_main.cpp b/cockatrice/src/client/ui/window_main.cpp index 883d54dc1..bbe8b356a 100644 --- a/cockatrice/src/client/ui/window_main.cpp +++ b/cockatrice/src/client/ui/window_main.cpp @@ -691,6 +691,7 @@ void MainWindow::retranslateUi() aTips->setText(tr("&Tip of the Day")); aUpdate->setText(tr("Check for Client Updates")); aCheckCardUpdates->setText(tr("Check for Card Updates...")); + aCheckCardUpdatesBackground->setText(tr("Check for Card Updates (Automatic)")); aStatusBar->setText(tr("Show Status Bar")); aViewLog->setText(tr("View &Debug Log")); aOpenSettingsFolder->setText(tr("Open Settings Folder")); @@ -744,6 +745,8 @@ void MainWindow::createActions() connect(aUpdate, &QAction::triggered, this, &MainWindow::actUpdate); aCheckCardUpdates = new QAction(this); connect(aCheckCardUpdates, &QAction::triggered, this, &MainWindow::actCheckCardUpdates); + aCheckCardUpdatesBackground = new QAction(this); + connect(aCheckCardUpdatesBackground, &QAction::triggered, this, &MainWindow::actCheckCardUpdatesBackground); aStatusBar = new QAction(this); aStatusBar->setCheckable(true); aStatusBar->setChecked(SettingsCache::instance().getShowStatusBar()); @@ -825,6 +828,7 @@ void MainWindow::createMenus() helpMenu->addSeparator(); helpMenu->addAction(aUpdate); helpMenu->addAction(aCheckCardUpdates); + helpMenu->addAction(aCheckCardUpdatesBackground); helpMenu->addSeparator(); helpMenu->addAction(aStatusBar); helpMenu->addAction(aViewLog); @@ -943,6 +947,11 @@ void MainWindow::startupConfigCheck() } else { // previous config from this version found qCInfo(WindowMainStartupVersionLog) << "Startup: found config with current version"; + + if (SettingsCache::instance().getCardUpdateCheckRequired()) { + actCheckCardUpdatesBackground(); + } + const auto reloadOk1 = QtConcurrent::run([] { CardDatabaseManager::getInstance()->loadCardDatabases(); }); // Run the tips dialog only on subsequent startups. @@ -1151,6 +1160,16 @@ void MainWindow::cardDatabaseAllNewSetsEnabled() /* CARD UPDATER */ void MainWindow::actCheckCardUpdates() +{ + createCardUpdateProcess(); +} + +void MainWindow::actCheckCardUpdatesBackground() +{ + createCardUpdateProcess(true); +} + +void MainWindow::createCardUpdateProcess(bool background) { if (cardUpdateProcess) { QMessageBox::information(this, tr("Information"), tr("A card database update is already running.")); @@ -1213,13 +1232,19 @@ void MainWindow::actCheckCardUpdates() return; } - cardUpdateProcess->start(updaterCmd, QStringList()); + if (!background) { + cardUpdateProcess->start(updaterCmd, QStringList()); + } else { + cardUpdateProcess->start(updaterCmd, QStringList("-b")); + statusBar()->showMessage(tr("Card database update running.")); + } } void MainWindow::exitCardDatabaseUpdate() { cardUpdateProcess->deleteLater(); cardUpdateProcess = nullptr; + statusBar()->clearMessage(); const auto reloadOk1 = QtConcurrent::run([] { CardDatabaseManager::getInstance()->loadCardDatabases(); }); } @@ -1256,8 +1281,11 @@ void MainWindow::cardUpdateError(QProcess::ProcessError err) QMessageBox::warning(this, tr("Error"), tr("The card database updater exited with an error:\n%1").arg(error)); } -void MainWindow::cardUpdateFinished(int, QProcess::ExitStatus) +void MainWindow::cardUpdateFinished(int, QProcess::ExitStatus exitStatus) { + if (exitStatus == QProcess::NormalExit) { + SettingsCache::instance().setLastCardUpdateCheck(QDateTime::currentDateTime().date()); + } exitCardDatabaseUpdate(); } diff --git a/cockatrice/src/client/ui/window_main.h b/cockatrice/src/client/ui/window_main.h index a5bc1f20b..420aac214 100644 --- a/cockatrice/src/client/ui/window_main.h +++ b/cockatrice/src/client/ui/window_main.h @@ -56,6 +56,7 @@ class MainWindow : public QMainWindow Q_OBJECT public slots: void actCheckCardUpdates(); + void actCheckCardUpdatesBackground(); void actCheckServerUpdates(); void actCheckClientUpdates(); private slots: @@ -131,6 +132,7 @@ private: { return "oracle"; }; + void createCardUpdateProcess(bool background = false); void exitCardDatabaseUpdate(); void startLocalGame(int numberPlayers); @@ -141,7 +143,8 @@ private: QAction *aConnect, *aDisconnect, *aRegister, *aForgotPassword, *aSinglePlayer, *aWatchReplay, *aFullScreen; QAction *aManageSets, *aEditTokens, *aOpenCustomFolder, *aOpenCustomsetsFolder, *aAddCustomSet, *aReloadCardDatabase; - QAction *aTips, *aUpdate, *aCheckCardUpdates, *aStatusBar, *aViewLog, *aOpenSettingsFolder; + QAction *aTips, *aUpdate, *aCheckCardUpdates, *aCheckCardUpdatesBackground, *aStatusBar, *aViewLog, + *aOpenSettingsFolder; TabSupervisor *tabSupervisor; WndSets *wndSets; diff --git a/cockatrice/src/dialogs/dlg_settings.cpp b/cockatrice/src/dialogs/dlg_settings.cpp index 0b0b86260..5d9b848e0 100644 --- a/cockatrice/src/dialogs/dlg_settings.cpp +++ b/cockatrice/src/dialogs/dlg_settings.cpp @@ -71,6 +71,10 @@ GeneralSettingsPage::GeneralSettingsPage() // updates SettingsCache &settings = SettingsCache::instance(); startupUpdateCheckCheckBox.setChecked(settings.getCheckUpdatesOnStartup()); + startupCardUpdateCheckCheckBox.setChecked(settings.getCheckCardUpdatesOnStartup()); + cardUpdateCheckIntervalSpinBox.setMinimum(1); + cardUpdateCheckIntervalSpinBox.setMaximum(30); + cardUpdateCheckIntervalSpinBox.setValue(settings.getCardUpdateCheckInterval()); updateNotificationCheckBox.setChecked(settings.getNotifyAboutUpdates()); newVersionOracleCheckBox.setChecked(settings.getNotifyAboutNewVersion()); @@ -83,6 +87,10 @@ GeneralSettingsPage::GeneralSettingsPage() &GeneralSettingsPage::languageBoxChanged); connect(&startupUpdateCheckCheckBox, &QCheckBox::QT_STATE_CHANGED, &settings, &SettingsCache::setCheckUpdatesOnStartup); + connect(&startupCardUpdateCheckCheckBox, &QCheckBox::QT_STATE_CHANGED, &settings, + &SettingsCache::setCheckCardUpdatesOnStartup); + connect(&cardUpdateCheckIntervalSpinBox, &QSpinBox::valueChanged, &settings, + &SettingsCache::setCardUpdateCheckInterval); connect(&updateNotificationCheckBox, &QCheckBox::QT_STATE_CHANGED, &settings, &SettingsCache::setNotifyAboutUpdate); connect(&newVersionOracleCheckBox, &QCheckBox::QT_STATE_CHANGED, &settings, &SettingsCache::setNotifyAboutNewVersion); @@ -95,9 +103,13 @@ GeneralSettingsPage::GeneralSettingsPage() personalGrid->addWidget(&updateReleaseChannelLabel, 2, 0); personalGrid->addWidget(&updateReleaseChannelBox, 2, 1); personalGrid->addWidget(&startupUpdateCheckCheckBox, 4, 0, 1, 2); - personalGrid->addWidget(&updateNotificationCheckBox, 5, 0, 1, 2); - personalGrid->addWidget(&newVersionOracleCheckBox, 6, 0, 1, 2); - personalGrid->addWidget(&showTipsOnStartup, 7, 0, 1, 2); + personalGrid->addWidget(&startupCardUpdateCheckCheckBox, 5, 0, 1, 2); + personalGrid->addWidget(&cardUpdateCheckIntervalLabel, 6, 0); + personalGrid->addWidget(&cardUpdateCheckIntervalSpinBox, 6, 1); + personalGrid->addWidget(&lastCardUpdateCheckDateLabel, 7, 1); + personalGrid->addWidget(&updateNotificationCheckBox, 8, 0, 1, 2); + personalGrid->addWidget(&newVersionOracleCheckBox, 9, 0, 1, 2); + personalGrid->addWidget(&showTipsOnStartup, 10, 0, 1, 2); personalGroupBox = new QGroupBox; personalGroupBox->setLayout(personalGrid); @@ -341,6 +353,9 @@ void GeneralSettingsPage::retranslateUi() tokenDatabasePathLabel.setText(tr("Token database:")); updateReleaseChannelLabel.setText(tr("Update channel")); startupUpdateCheckCheckBox.setText(tr("Check for client updates on startup")); + startupCardUpdateCheckCheckBox.setText(tr("Automatically update card database in the background on startup.")); + cardUpdateCheckIntervalLabel.setText(tr("Check for card database updates every")); + cardUpdateCheckIntervalSpinBox.setSuffix(tr(" days")); updateNotificationCheckBox.setText(tr("Notify if a feature supported by the server is missing in my client")); newVersionOracleCheckBox.setText(tr("Automatically run Oracle when running a new version of Cockatrice")); showTipsOnStartup.setText(tr("Show tips on startup")); @@ -348,6 +363,12 @@ void GeneralSettingsPage::retranslateUi() const auto &settings = SettingsCache::instance(); + QDate lastCheckDate = settings.getLastCardUpdateCheck(); + int daysAgo = lastCheckDate.daysTo(QDate::currentDate()); + + lastCardUpdateCheckDateLabel.setText( + tr("Last update check on %1 (%2 days ago)").arg(lastCheckDate.toString()).arg(daysAgo)); + // We can't change the strings after they're put into the QComboBox, so this is our workaround int oldIndex = updateReleaseChannelBox.currentIndex(); updateReleaseChannelBox.clear(); diff --git a/cockatrice/src/dialogs/dlg_settings.h b/cockatrice/src/dialogs/dlg_settings.h index f0b9c62c9..6b2b7ce9b 100644 --- a/cockatrice/src/dialogs/dlg_settings.h +++ b/cockatrice/src/dialogs/dlg_settings.h @@ -71,6 +71,10 @@ private: QGroupBox *pathsGroupBox; QComboBox languageBox; QCheckBox startupUpdateCheckCheckBox; + QCheckBox startupCardUpdateCheckCheckBox; + QLabel cardUpdateCheckIntervalLabel; + QSpinBox cardUpdateCheckIntervalSpinBox; + QLabel lastCardUpdateCheckDateLabel; QCheckBox updateNotificationCheckBox; QCheckBox newVersionOracleCheckBox; QComboBox updateReleaseChannelBox; diff --git a/cockatrice/src/settings/cache_settings.cpp b/cockatrice/src/settings/cache_settings.cpp index 4b2e854d7..8398c408a 100644 --- a/cockatrice/src/settings/cache_settings.cpp +++ b/cockatrice/src/settings/cache_settings.cpp @@ -194,6 +194,9 @@ SettingsCache::SettingsCache() mbDownloadSpoilers = settings->value("personal/downloadspoilers", false).toBool(); checkUpdatesOnStartup = settings->value("personal/startupUpdateCheck", true).toBool(); + checkCardUpdatesOnStartup = settings->value("personal/startupCardUpdateCheck", true).toBool(); + cardUpdateCheckInterval = settings->value("personal/cardUpdateCheckInterval", 7).toInt(); + lastCardUpdateCheck = settings->value("personal/lastCardUpdateCheck", QDateTime::currentDateTime().date()).toDate(); notifyAboutUpdates = settings->value("personal/updatenotification", true).toBool(); notifyAboutNewVersion = settings->value("personal/newversionnotification", true).toBool(); updateReleaseChannel = settings->value("personal/updatereleasechannel", 0).toInt(); @@ -1363,6 +1366,24 @@ void SettingsCache::setCheckUpdatesOnStartup(QT_STATE_CHANGED_T value) settings->setValue("personal/startupUpdateCheck", checkUpdatesOnStartup); } +void SettingsCache::setCheckCardUpdatesOnStartup(QT_STATE_CHANGED_T value) +{ + checkCardUpdatesOnStartup = static_cast(value); + settings->setValue("personal/startupCardUpdateCheck", checkCardUpdatesOnStartup); +} + +void SettingsCache::setCardUpdateCheckInterval(int value) +{ + cardUpdateCheckInterval = value; + settings->setValue("personal/cardUpdateCheckInterval", cardUpdateCheckInterval); +} + +void SettingsCache::setLastCardUpdateCheck(QDate value) +{ + lastCardUpdateCheck = value; + settings->setValue("personal/lastCardUpdateCheck", lastCardUpdateCheck); +} + void SettingsCache::setRememberGameSettings(const bool _rememberGameSettings) { rememberGameSettings = _rememberGameSettings; diff --git a/cockatrice/src/settings/cache_settings.h b/cockatrice/src/settings/cache_settings.h index aaf40edf8..960d8a138 100644 --- a/cockatrice/src/settings/cache_settings.h +++ b/cockatrice/src/settings/cache_settings.h @@ -13,6 +13,7 @@ #include "servers_settings.h" #include "shortcuts_settings.h" +#include #include #include #include @@ -198,6 +199,9 @@ private: bool tabVisualDeckStorageOpen, tabServerOpen, tabAccountOpen, tabDeckStorageOpen, tabReplaysOpen, tabAdminOpen, tabLogOpen; bool checkUpdatesOnStartup; + bool checkCardUpdatesOnStartup; + int cardUpdateCheckInterval; + QDate lastCardUpdateCheck; bool notifyAboutUpdates; bool notifyAboutNewVersion; bool showTipsOnStartup; @@ -438,6 +442,23 @@ public: { return checkUpdatesOnStartup; } + bool getCheckCardUpdatesOnStartup() const + { + return checkCardUpdatesOnStartup; + } + int getCardUpdateCheckInterval() const + { + return cardUpdateCheckInterval; + } + QDate getLastCardUpdateCheck() const + { + return lastCardUpdateCheck; + } + bool getCardUpdateCheckRequired() const + { + return getLastCardUpdateCheck().daysTo(QDateTime::currentDateTime().date()) >= getCardUpdateCheckInterval() && + getLastCardUpdateCheck() != QDateTime::currentDateTime().date(); + } bool getNotifyAboutUpdates() const { return notifyAboutUpdates; @@ -1007,6 +1028,9 @@ public slots: void setDefaultStartingLifeTotal(const int _defaultStartingLifeTotal); void setRememberGameSettings(const bool _rememberGameSettings); void setCheckUpdatesOnStartup(QT_STATE_CHANGED_T value); + void setCheckCardUpdatesOnStartup(QT_STATE_CHANGED_T value); + void setCardUpdateCheckInterval(int value); + void setLastCardUpdateCheck(QDate value); void setNotifyAboutUpdate(QT_STATE_CHANGED_T _notifyaboutupdate); void setNotifyAboutNewVersion(QT_STATE_CHANGED_T _notifyaboutnewversion); void setUpdateReleaseChannelIndex(int value); diff --git a/oracle/src/main.cpp b/oracle/src/main.cpp index 009a099ac..19007a3ca 100644 --- a/oracle/src/main.cpp +++ b/oracle/src/main.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include QTranslator *translator, *qtTranslator; @@ -16,6 +17,7 @@ ThemeManager *themeManager; const QString translationPrefix = "oracle"; QString translationPath; bool isSpoilersOnly; +bool isBackgrounded; void installNewTranslator() { @@ -57,10 +59,13 @@ int main(int argc, char *argv[]) // 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); + QCommandLineOption spoilersOnlyOption("s", QCoreApplication::translate("main", "Only run in spoiler mode")); + QCommandLineOption backgroundOption("b", QCoreApplication::translate("main", "Run in no-confirm background mode")); + parser.addOption(spoilersOnlyOption); + parser.addOption(backgroundOption); parser.process(app); - isSpoilersOnly = parser.isSet(showProgressOption); + isSpoilersOnly = parser.isSet(spoilersOnlyOption); + isBackgrounded = parser.isSet(backgroundOption); #ifdef Q_OS_MAC translationPath = qApp->applicationDirPath() + "/../Resources/translations"; @@ -85,5 +90,9 @@ int main(int argc, char *argv[]) wizard.show(); + if (isBackgrounded) { + QTimer::singleShot(0, &wizard, [&wizard]() { wizard.runInBackground(); }); + } + return app.exec(); } diff --git a/oracle/src/oraclewizard.cpp b/oracle/src/oraclewizard.cpp index bea87dde2..0fdd4b8f1 100644 --- a/oracle/src/oraclewizard.cpp +++ b/oracle/src/oraclewizard.cpp @@ -64,15 +64,23 @@ OracleWizard::OracleWizard(QWidget *parent) : QWizard(parent) nam = new QNetworkAccessManager(this); + QList pages; + if (!isSpoilersOnly) { - addPage(new IntroPage); - addPage(new LoadSetsPage); - addPage(new SaveSetsPage); - addPage(new LoadTokensPage); - addPage(new OutroPage); + pages << new IntroPage << new LoadSetsPage << new SaveSetsPage << new LoadTokensPage << new OutroPage; } else { - addPage(new LoadSpoilersPage); - addPage(new OutroPage); + pages << new LoadSpoilersPage << new OutroPage; + } + + for (OracleWizardPage *page : pages) { + addPage(page); + + // Connect background auto-advance + connect(page, &OracleWizardPage::readyToContinue, this, [this]() { + if (backgroundMode) { + next(); + } + }); } retranslateUi(); @@ -169,6 +177,13 @@ IntroPage::IntroPage(QWidget *parent) : OracleWizardPage(parent) setLayout(layout); } +void IntroPage::initializePage() +{ + if (wizard()->backgroundMode) { + emit readyToContinue(); + } +} + QStringList IntroPage::findQmFiles() { QDir dir(translationPath); @@ -212,6 +227,14 @@ void OutroPage::retranslateUi() tr("If the card databases don't reload automatically, restart the Cockatrice client.")); } +void OutroPage::initializePage() +{ + if (wizard()->backgroundMode) { + wizard()->accept(); + exit(0); + } +} + LoadSetsPage::LoadSetsPage(QWidget *parent) : OracleWizardPage(parent) { urlRadioButton = new QRadioButton(this); @@ -252,6 +275,12 @@ void LoadSetsPage::initializePage() progressLabel->hide(); progressBar->hide(); + + if (wizard()->backgroundMode) { + if (isEnabled()) { + validatePage(); + } + } } void LoadSetsPage::retranslateUi() @@ -616,6 +645,10 @@ void SaveSetsPage::initializePage() if (!wizard()->importer->startImport()) { QMessageBox::critical(this, tr("Error"), tr("No set has been imported.")); } + + if (wizard()->backgroundMode) { + emit readyToContinue(); + } } void SaveSetsPage::retranslateUi() @@ -691,6 +724,15 @@ bool SaveSetsPage::validatePage() return true; } +void LoadTokensPage::initializePage() +{ + SimpleDownloadFilePage::initializePage(); + + if (wizard()->backgroundMode) { + emit readyToContinue(); + } +} + QString LoadTokensPage::getDefaultUrl() { return TOKENS_URL; diff --git a/oracle/src/oraclewizard.h b/oracle/src/oraclewizard.h index 35f1a233e..0bd644ba7 100644 --- a/oracle/src/oraclewizard.h +++ b/oracle/src/oraclewizard.h @@ -3,6 +3,7 @@ #include #include +#include #include #include @@ -56,12 +57,20 @@ public: } bool saveTokensToFile(const QString &fileName); + void runInBackground() + { + backgroundMode = true; + hide(); + currentPage()->initializePage(); + } + public: OracleImporter *importer; QSettings *settings; QNetworkAccessManager *nam; bool downloadedPlainXml = false; QByteArray xmlData; + bool backgroundMode = false; private slots: void updateLanguage(); @@ -92,6 +101,9 @@ private: private slots: void languageBoxChanged(int index); + +protected slots: + void initializePage() override; }; class OutroPage : public OracleWizardPage @@ -102,6 +114,8 @@ public: { } void retranslateUi() override; +protected: + void initializePage() override; }; class LoadSetsPage : public OracleWizardPage @@ -167,7 +181,7 @@ class LoadSpoilersPage : public SimpleDownloadFilePage { Q_OBJECT public: - explicit LoadSpoilersPage(QWidget * = nullptr){}; + explicit LoadSpoilersPage(QWidget * = nullptr) {}; void retranslateUi() override; protected: @@ -182,7 +196,7 @@ class LoadTokensPage : public SimpleDownloadFilePage { Q_OBJECT public: - explicit LoadTokensPage(QWidget * = nullptr){}; + explicit LoadTokensPage(QWidget * = nullptr) {}; void retranslateUi() override; protected: @@ -191,6 +205,7 @@ protected: QString getDefaultSavePath() override; QString getWindowTitle() override; QString getFileType() override; + void initializePage() override; }; #endif diff --git a/oracle/src/pagetemplates.cpp b/oracle/src/pagetemplates.cpp index 858fd8022..d9ce3300f 100644 --- a/oracle/src/pagetemplates.cpp +++ b/oracle/src/pagetemplates.cpp @@ -70,7 +70,7 @@ bool SimpleDownloadFilePage::validatePage() QUrl url = QUrl::fromUserInput(urlLineEdit->text()); if (!url.isValid()) { - QMessageBox::critical(this, tr("Error"), tr("The provided URL is not valid.")); + QMessageBox::critical(this, tr("Error"), tr("The provided URL is not valid: ") + url.toString()); return false; } diff --git a/oracle/src/pagetemplates.h b/oracle/src/pagetemplates.h index a65559ae0..0c11c25bd 100644 --- a/oracle/src/pagetemplates.h +++ b/oracle/src/pagetemplates.h @@ -13,9 +13,12 @@ class OracleWizardPage : public QWizardPage { Q_OBJECT public: - explicit OracleWizardPage(QWidget *parent = nullptr) : QWizardPage(parent){}; + explicit OracleWizardPage(QWidget *parent = nullptr) : QWizardPage(parent) {}; virtual void retranslateUi() = 0; +signals: + void readyToContinue(); + protected: inline OracleWizard *wizard() {