From ee3d64145ce76022485bea61a0cad0ada88059fb Mon Sep 17 00:00:00 2001 From: spycrab Date: Thu, 22 Mar 2018 12:20:15 +0100 Subject: [PATCH] Qt: Improve updater --- Source/Core/DolphinQt2/CMakeLists.txt | 1 + Source/Core/DolphinQt2/DolphinQt2.vcxproj | 3 + Source/Core/DolphinQt2/Main.cpp | 35 +------- Source/Core/DolphinQt2/Settings.cpp | 15 ++++ Source/Core/DolphinQt2/Settings.h | 5 ++ .../Core/DolphinQt2/Settings/GeneralPane.cpp | 84 ++++++++++++++++++ Source/Core/DolphinQt2/Settings/GeneralPane.h | 2 + Source/Core/DolphinQt2/Updater.cpp | 88 +++++++++++++++++++ Source/Core/DolphinQt2/Updater.h | 24 +++++ Source/Core/UICommon/AutoUpdate.cpp | 23 ++--- Source/Core/UICommon/AutoUpdate.h | 2 + 11 files changed, 240 insertions(+), 42 deletions(-) create mode 100644 Source/Core/DolphinQt2/Updater.cpp create mode 100644 Source/Core/DolphinQt2/Updater.h diff --git a/Source/Core/DolphinQt2/CMakeLists.txt b/Source/Core/DolphinQt2/CMakeLists.txt index f4b7ca78e9..52af9c951d 100644 --- a/Source/Core/DolphinQt2/CMakeLists.txt +++ b/Source/Core/DolphinQt2/CMakeLists.txt @@ -117,6 +117,7 @@ set(SRCS TAS/Shared.cpp TAS/StickWidget.cpp TAS/IRWidget.cpp + Updater.cpp ) list(APPEND LIBS core uicommon) diff --git a/Source/Core/DolphinQt2/DolphinQt2.vcxproj b/Source/Core/DolphinQt2/DolphinQt2.vcxproj index 711d452eec..3fe5e2613d 100644 --- a/Source/Core/DolphinQt2/DolphinQt2.vcxproj +++ b/Source/Core/DolphinQt2/DolphinQt2.vcxproj @@ -127,6 +127,7 @@ + @@ -196,6 +197,7 @@ + @@ -294,6 +296,7 @@ + diff --git a/Source/Core/DolphinQt2/Main.cpp b/Source/Core/DolphinQt2/Main.cpp index 567732cf2d..46ea5fa353 100644 --- a/Source/Core/DolphinQt2/Main.cpp +++ b/Source/Core/DolphinQt2/Main.cpp @@ -21,7 +21,7 @@ #include "DolphinQt2/Resources.h" #include "DolphinQt2/Settings.h" #include "DolphinQt2/Translation.h" -#include "UICommon/AutoUpdate.h" +#include "DolphinQt2/Updater.h" #include "UICommon/CommandLineParse.h" #include "UICommon/UICommon.h" @@ -63,35 +63,6 @@ static bool QtMsgAlertHandler(const char* caption, const char* text, bool yes_no }); } -// TODO: This should be replaced with something in a background thread, it performs a blocking -// HTTP query. It also needs a proper UI, and many other things. But right now it needs to be -// manually enabled through INI, so all these problems are ignored :) -class QtAutoUpdateChecker : public AutoUpdateChecker -{ -public: - explicit QtAutoUpdateChecker(QWidget* parent) : m_parent(parent) {} -protected: - void OnUpdateAvailable(const NewVersionInformation& info) override - { - QMessageBox prompt(m_parent); - - prompt.setIcon(QMessageBox::Question); - prompt.setStandardButtons(QMessageBox::Yes | QMessageBox::No); - prompt.setText(QString::fromUtf8("Update Dolphin to version %1?") - .arg(QString::fromStdString(info.new_shortrev))); - - const int answer = prompt.exec(); - if (answer == QMessageBox::Yes) - { - TriggerUpdate(info); - m_parent->close(); - } - } - -private: - QWidget* m_parent; -}; - // N.B. On Windows, this should be called from WinMain. Link against qtmain and specify // /SubSystem:Windows int main(int argc, char* argv[]) @@ -188,8 +159,8 @@ int main(int argc, char* argv[]) } #endif - QtAutoUpdateChecker updater(&win); - updater.CheckForUpdate(); + auto* updater = new Updater(&win); + updater->start(); retval = app.exec(); } diff --git a/Source/Core/DolphinQt2/Settings.cpp b/Source/Core/DolphinQt2/Settings.cpp index 4e8581b9de..155af29f63 100644 --- a/Source/Core/DolphinQt2/Settings.cpp +++ b/Source/Core/DolphinQt2/Settings.cpp @@ -312,3 +312,18 @@ QFont Settings::GetDebugFont() const return QSettings().value(QStringLiteral("debugger/font"), default_font).value(); } + +void Settings::SetAutoUpdateTrack(const QString& mode) +{ + if (mode == GetAutoUpdateTrack()) + return; + + SConfig::GetInstance().m_auto_update_track = mode.toStdString(); + + emit AutoUpdateTrackChanged(mode); +} + +QString Settings::GetAutoUpdateTrack() const +{ + return QString::fromStdString(SConfig::GetInstance().m_auto_update_track); +} diff --git a/Source/Core/DolphinQt2/Settings.h b/Source/Core/DolphinQt2/Settings.h index c85c070ef7..5e37eadd25 100644 --- a/Source/Core/DolphinQt2/Settings.h +++ b/Source/Core/DolphinQt2/Settings.h @@ -98,6 +98,10 @@ public: QFont GetDebugFont() const; void SetDebugFont(QFont font); + // Auto-Update + QString GetAutoUpdateTrack() const; + void SetAutoUpdateTrack(const QString& mode); + // Other GameListModel* GetGameListModel() const; signals: @@ -119,6 +123,7 @@ signals: void CodeVisibilityChanged(bool visible); void DebugModeToggled(bool enabled); void DebugFontChanged(QFont font); + void AutoUpdateTrackChanged(const QString& mode); private: bool m_controller_state_needed = false; diff --git a/Source/Core/DolphinQt2/Settings/GeneralPane.cpp b/Source/Core/DolphinQt2/Settings/GeneralPane.cpp index f3aab10eab..464fd07790 100644 --- a/Source/Core/DolphinQt2/Settings/GeneralPane.cpp +++ b/Source/Core/DolphinQt2/Settings/GeneralPane.cpp @@ -20,6 +20,17 @@ #include "Core/ConfigManager.h" #include "Core/PowerPC/PowerPC.h" #include "DolphinQt2/Settings.h" +#include "UICommon/AutoUpdate.h" + +constexpr int AUTO_UPDATE_DISABLE_INDEX = 0; +constexpr int AUTO_UPDATE_STABLE_INDEX = 1; +constexpr int AUTO_UPDATE_BETA_INDEX = 2; +constexpr int AUTO_UPDATE_DEV_INDEX = 3; + +constexpr const char* AUTO_UPDATE_DISABLE_STRING = ""; +constexpr const char* AUTO_UPDATE_STABLE_STRING = "stable"; +constexpr const char* AUTO_UPDATE_BETA_STRING = "beta"; +constexpr const char* AUTO_UPDATE_DEV_STRING = "dev"; GeneralPane::GeneralPane(QWidget* parent) : QWidget(parent) { @@ -34,6 +45,10 @@ void GeneralPane::CreateLayout() m_main_layout = new QVBoxLayout; // Create layout here CreateBasic(); + + if (AutoUpdateChecker::SystemSupportsAutoUpdates()) + CreateAutoUpdate(); + #if defined(USE_ANALYTICS) && USE_ANALYTICS CreateAnalytics(); #endif @@ -48,6 +63,16 @@ void GeneralPane::ConnectLayout() { connect(m_checkbox_dualcore, &QCheckBox::clicked, this, &GeneralPane::OnSaveConfig); connect(m_checkbox_cheats, &QCheckBox::clicked, this, &GeneralPane::OnSaveConfig); + + if (AutoUpdateChecker::SystemSupportsAutoUpdates()) + { + connect(m_combobox_update_track, + static_cast(&QComboBox::currentIndexChanged), this, + &GeneralPane::OnSaveConfig); + connect(&Settings::Instance(), &Settings::AutoUpdateTrackChanged, this, + &GeneralPane::LoadConfig); + } + // Advanced connect(m_combobox_speedlimit, static_cast(&QComboBox::activated), @@ -96,6 +121,22 @@ void GeneralPane::CreateBasic() speed_limit_layout->addRow(tr("&Speed Limit:"), m_combobox_speedlimit); } +void GeneralPane::CreateAutoUpdate() +{ + auto* auto_update_group = new QGroupBox(tr("Auto Update Settings")); + auto* layout = new QFormLayout; + auto_update_group->setLayout(layout); + m_main_layout->addWidget(auto_update_group); + + m_combobox_update_track = new QComboBox(this); + + layout->addRow(tr("&Auto Update:"), m_combobox_update_track); + + for (const QString& option : {tr("Don't Update"), tr("Stable (once a year)"), + tr("Beta (once a month)"), tr("Dev (multiple times a day)")}) + m_combobox_update_track->addItem(option); +} + #if defined(USE_ANALYTICS) && USE_ANALYTICS void GeneralPane::CreateAnalytics() { @@ -135,6 +176,20 @@ void GeneralPane::CreateAdvanced() void GeneralPane::LoadConfig() { + if (AutoUpdateChecker::SystemSupportsAutoUpdates()) + { + const auto track = Settings::Instance().GetAutoUpdateTrack().toStdString(); + + if (track == AUTO_UPDATE_DISABLE_STRING) + m_combobox_update_track->setCurrentIndex(AUTO_UPDATE_DISABLE_INDEX); + else if (track == AUTO_UPDATE_STABLE_STRING) + m_combobox_update_track->setCurrentIndex(AUTO_UPDATE_STABLE_INDEX); + else if (track == AUTO_UPDATE_BETA_STRING) + m_combobox_update_track->setCurrentIndex(AUTO_UPDATE_BETA_INDEX); + else + m_combobox_update_track->setCurrentIndex(AUTO_UPDATE_DEV_INDEX); + } + #if defined(USE_ANALYTICS) && USE_ANALYTICS m_checkbox_enable_analytics->setChecked(SConfig::GetInstance().m_analytics_enabled); #endif @@ -164,8 +219,37 @@ void GeneralPane::LoadConfig() } } +static QString UpdateTrackFromIndex(int index) +{ + QString value; + + switch (index) + { + case AUTO_UPDATE_DISABLE_INDEX: + value = QString::fromStdString(AUTO_UPDATE_DISABLE_STRING); + break; + case AUTO_UPDATE_STABLE_INDEX: + value = QString::fromStdString(AUTO_UPDATE_STABLE_STRING); + break; + case AUTO_UPDATE_BETA_INDEX: + value = QString::fromStdString(AUTO_UPDATE_BETA_STRING); + break; + case AUTO_UPDATE_DEV_INDEX: + value = QString::fromStdString(AUTO_UPDATE_DEV_STRING); + break; + } + + return value; +} + void GeneralPane::OnSaveConfig() { + if (AutoUpdateChecker::SystemSupportsAutoUpdates()) + { + Settings::Instance().SetAutoUpdateTrack( + UpdateTrackFromIndex(m_combobox_update_track->currentIndex())); + } + #if defined(USE_ANALYTICS) && USE_ANALYTICS SConfig::GetInstance().m_analytics_enabled = m_checkbox_enable_analytics->isChecked(); #endif diff --git a/Source/Core/DolphinQt2/Settings/GeneralPane.h b/Source/Core/DolphinQt2/Settings/GeneralPane.h index 1afd973358..79b5c30677 100644 --- a/Source/Core/DolphinQt2/Settings/GeneralPane.h +++ b/Source/Core/DolphinQt2/Settings/GeneralPane.h @@ -24,6 +24,7 @@ private: void CreateLayout(); void ConnectLayout(); void CreateBasic(); + void CreateAutoUpdate(); void CreateAdvanced(); void LoadConfig(); @@ -32,6 +33,7 @@ private: // Widgets QVBoxLayout* m_main_layout; QComboBox* m_combobox_speedlimit; + QComboBox* m_combobox_update_track; QCheckBox* m_checkbox_dualcore; QCheckBox* m_checkbox_cheats; QLabel* m_label_speedlimit; diff --git a/Source/Core/DolphinQt2/Updater.cpp b/Source/Core/DolphinQt2/Updater.cpp new file mode 100644 index 0000000000..7a6352d19b --- /dev/null +++ b/Source/Core/DolphinQt2/Updater.cpp @@ -0,0 +1,88 @@ +// Copyright 2018 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#include "DolphinQt2/Updater.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "Common/Version.h" +#include "DolphinQt2/QtUtils/RunOnObject.h" +#include "DolphinQt2/Settings.h" + +Updater::Updater(QWidget* parent) : m_parent(parent) +{ + connect(this, &QThread::finished, this, &QObject::deleteLater); +} + +void Updater::run() +{ + CheckForUpdate(); +} + +void Updater::OnUpdateAvailable(const NewVersionInformation& info) +{ + bool later = false; + + int choice = RunOnObject(m_parent, [&] { + QDialog* dialog = new QDialog(m_parent); + dialog->setWindowTitle(tr("Update available")); + + auto* label = new QLabel( + tr("

A new version of Dolphin is available!

Dolphin %1 is available for " + "download. " + "You are running %2.
Would you like to update?

Release Notes:

") + .arg(QString::fromStdString(info.new_shortrev)) + .arg(QString::fromStdString(Common::scm_desc_str))); + label->setTextFormat(Qt::RichText); + + auto* changelog = new QTextBrowser; + + changelog->setHtml(QString::fromStdString(info.changelog_html)); + changelog->setOpenExternalLinks(true); + changelog->setMinimumWidth(400); + + auto* update_later_check = new QCheckBox(tr("Update after closing Dolphin")); + + connect(update_later_check, &QCheckBox::toggled, [&](bool checked) { later = checked; }); + + auto* buttons = new QDialogButtonBox; + + auto* never_btn = + buttons->addButton(tr("Never Auto-Update"), QDialogButtonBox::DestructiveRole); + buttons->addButton(tr("Remind Me Later"), QDialogButtonBox::RejectRole); + buttons->addButton(tr("Install Update"), QDialogButtonBox::AcceptRole); + + auto* layout = new QVBoxLayout; + dialog->setLayout(layout); + + layout->addWidget(label); + layout->addWidget(changelog); + layout->addWidget(update_later_check); + layout->addWidget(buttons); + + connect(never_btn, &QPushButton::pressed, [dialog] { + Settings::Instance().SetAutoUpdateTrack(QStringLiteral("")); + dialog->reject(); + }); + + connect(buttons, &QDialogButtonBox::accepted, dialog, &QDialog::accept); + connect(buttons, &QDialogButtonBox::rejected, dialog, &QDialog::reject); + + return dialog->exec(); + }); + + if (choice == QDialog::Accepted) + { + TriggerUpdate(info); + + if (!later) + m_parent->close(); + } +} diff --git a/Source/Core/DolphinQt2/Updater.h b/Source/Core/DolphinQt2/Updater.h new file mode 100644 index 0000000000..9083dfede5 --- /dev/null +++ b/Source/Core/DolphinQt2/Updater.h @@ -0,0 +1,24 @@ +// Copyright 2018 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#pragma once + +#include + +#include "UICommon/AutoUpdate.h" + +class QWidget; + +class Updater : public QThread, public AutoUpdateChecker +{ + Q_OBJECT +public: + explicit Updater(QWidget* parent); + + void run() override; + void OnUpdateAvailable(const NewVersionInformation& info) override; + +private: + QWidget* m_parent; +}; diff --git a/Source/Core/UICommon/AutoUpdate.cpp b/Source/Core/UICommon/AutoUpdate.cpp index 3313b706fd..dc094f29ac 100644 --- a/Source/Core/UICommon/AutoUpdate.cpp +++ b/Source/Core/UICommon/AutoUpdate.cpp @@ -20,15 +20,6 @@ namespace { -bool SystemSupportsAutoUpdates() -{ -#ifdef _WIN32 - return true; -#else - return false; -#endif -} - #ifdef _WIN32 const char UPDATER_FILENAME[] = "Updater.exe"; @@ -57,10 +48,19 @@ void CleanupFromPreviousUpdate() #endif } // namespace +bool AutoUpdateChecker::SystemSupportsAutoUpdates() +{ +#ifdef _WIN32 + return true; +#else + return false; +#endif +} + void AutoUpdateChecker::CheckForUpdate() { // Don't bother checking if updates are not supported or not enabled. - if (SConfig::GetInstance().m_auto_update_track.empty() || !SystemSupportsAutoUpdates()) + if (!SystemSupportsAutoUpdates() || SConfig::GetInstance().m_auto_update_track.empty()) return; #ifdef _WIN32 @@ -104,7 +104,10 @@ void AutoUpdateChecker::CheckForUpdate() nvi.content_store_url = obj["content-store"].get(); nvi.new_shortrev = obj["new"].get()["name"].get(); nvi.new_hash = obj["new"].get()["hash"].get(); + // TODO: generate the HTML changelog from the JSON information. + nvi.changelog_html = "

TBD

"; + OnUpdateAvailable(nvi); } diff --git a/Source/Core/UICommon/AutoUpdate.h b/Source/Core/UICommon/AutoUpdate.h index 6266b6f9dc..b0de6006de 100644 --- a/Source/Core/UICommon/AutoUpdate.h +++ b/Source/Core/UICommon/AutoUpdate.h @@ -15,6 +15,8 @@ public: // update is available, does "nothing" otherwise. void CheckForUpdate(); + static bool SystemSupportsAutoUpdates(); + struct NewVersionInformation { // Name (5.0-1234) and revision hash of the new version.