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.