diff --git a/Source/Core/DolphinQt2/CMakeLists.txt b/Source/Core/DolphinQt2/CMakeLists.txt
index 10b26d5fe4..35bbb61284 100644
--- a/Source/Core/DolphinQt2/CMakeLists.txt
+++ b/Source/Core/DolphinQt2/CMakeLists.txt
@@ -19,6 +19,8 @@ set(SRCS
Resources.cpp
Settings.cpp
ToolBar.cpp
+ WiiUpdate.cpp
+ WiiUpdate.h
Config/ControllersWindow.cpp
Config/FilesystemWidget.cpp
Config/InfoWidget.cpp
diff --git a/Source/Core/DolphinQt2/DolphinQt2.vcxproj b/Source/Core/DolphinQt2/DolphinQt2.vcxproj
index 34d79d5228..20e251a3b0 100644
--- a/Source/Core/DolphinQt2/DolphinQt2.vcxproj
+++ b/Source/Core/DolphinQt2/DolphinQt2.vcxproj
@@ -164,6 +164,7 @@
+
@@ -185,6 +186,7 @@
+
diff --git a/Source/Core/DolphinQt2/MainWindow.cpp b/Source/Core/DolphinQt2/MainWindow.cpp
index b57ac4f134..de38910faa 100644
--- a/Source/Core/DolphinQt2/MainWindow.cpp
+++ b/Source/Core/DolphinQt2/MainWindow.cpp
@@ -30,7 +30,6 @@
#include "DolphinQt2/AboutDialog.h"
#include "DolphinQt2/Config/ControllersWindow.h"
-
#include "DolphinQt2/Config/Mapping/MappingWindow.h"
#include "DolphinQt2/Config/SettingsWindow.h"
#include "DolphinQt2/Host.h"
@@ -39,6 +38,7 @@
#include "DolphinQt2/QtUtils/WindowActivationEventFilter.h"
#include "DolphinQt2/Resources.h"
#include "DolphinQt2/Settings.h"
+#include "DolphinQt2/WiiUpdate.h"
#include "InputCommon/ControllerInterface/ControllerInterface.h"
@@ -165,6 +165,9 @@ void MainWindow::ConnectMenuBar()
// Options
connect(m_menu_bar, &MenuBar::ConfigureHotkeys, this, &MainWindow::ShowHotkeyDialog);
+ // Tools
+ connect(m_menu_bar, &MenuBar::PerformOnlineUpdate, this, &MainWindow::PerformOnlineUpdate);
+
// View
connect(m_menu_bar, &MenuBar::ShowTable, m_game_list, &GameList::SetTableView);
connect(m_menu_bar, &MenuBar::ShowList, m_game_list, &GameList::SetListView);
@@ -530,6 +533,13 @@ void MainWindow::SetStateSlot(int slot)
m_state_slot = slot;
}
+void MainWindow::PerformOnlineUpdate(const std::string& region)
+{
+ WiiUpdate::PerformOnlineUpdate(region, this);
+ // Since the update may have installed a newer system menu, refresh the tools menu.
+ m_menu_bar->UpdateToolsMenu(false);
+}
+
bool MainWindow::eventFilter(QObject* object, QEvent* event)
{
if (event->type() == QEvent::Close && !Stop())
diff --git a/Source/Core/DolphinQt2/MainWindow.h b/Source/Core/DolphinQt2/MainWindow.h
index 7a69972ec9..0cd572790d 100644
--- a/Source/Core/DolphinQt2/MainWindow.h
+++ b/Source/Core/DolphinQt2/MainWindow.h
@@ -56,6 +56,8 @@ private slots:
void StateSaveOldest();
void SetStateSlot(int slot);
+ void PerformOnlineUpdate(const std::string& region);
+
void FullScreen();
void ScreenShot();
diff --git a/Source/Core/DolphinQt2/MenuBar.cpp b/Source/Core/DolphinQt2/MenuBar.cpp
index 011649e0e1..888a5d8400 100644
--- a/Source/Core/DolphinQt2/MenuBar.cpp
+++ b/Source/Core/DolphinQt2/MenuBar.cpp
@@ -9,6 +9,9 @@
#include
#include
+#include "Core/CommonTitles.h"
+#include "Core/IOS/ES/ES.h"
+#include "Core/IOS/IOS.h"
#include "Core/State.h"
#include "DolphinQt2/AboutDialog.h"
#include "DolphinQt2/GameList/GameFile.h"
@@ -43,6 +46,7 @@ void MenuBar::EmulationStarted()
m_state_load_menu->setEnabled(true);
m_state_save_menu->setEnabled(true);
UpdateStateSlotMenu();
+ UpdateToolsMenu(true);
}
void MenuBar::EmulationPaused()
{
@@ -66,6 +70,7 @@ void MenuBar::EmulationStopped()
m_state_load_menu->setEnabled(false);
m_state_save_menu->setEnabled(false);
UpdateStateSlotMenu();
+ UpdateToolsMenu(false);
}
void MenuBar::AddFileMenu()
@@ -79,6 +84,17 @@ void MenuBar::AddToolsMenu()
{
QMenu* tools_menu = addMenu(tr("Tools"));
m_wad_install_action = tools_menu->addAction(tr("Install WAD..."), this, SLOT(InstallWAD()));
+
+ m_perform_online_update_menu = tools_menu->addMenu(tr("Perform Online System Update"));
+ m_perform_online_update_for_current_region = m_perform_online_update_menu->addAction(
+ tr("Current Region"), [this] { emit PerformOnlineUpdate(""); });
+ m_perform_online_update_menu->addSeparator();
+ m_perform_online_update_menu->addAction(tr("Europe"),
+ [this] { emit PerformOnlineUpdate("EUR"); });
+ m_perform_online_update_menu->addAction(tr("Japan"), [this] { emit PerformOnlineUpdate("JPN"); });
+ m_perform_online_update_menu->addAction(tr("Korea"), [this] { emit PerformOnlineUpdate("KOR"); });
+ m_perform_online_update_menu->addAction(tr("United States"),
+ [this] { emit PerformOnlineUpdate("USA"); });
}
void MenuBar::AddEmulationMenu()
@@ -248,6 +264,20 @@ void MenuBar::AddTableColumnsMenu(QMenu* view_menu)
}
}
+void MenuBar::UpdateToolsMenu(bool emulation_started)
+{
+ const bool enable_wii_tools = !emulation_started || !Settings::Instance().IsWiiGameRunning();
+ m_perform_online_update_menu->setEnabled(enable_wii_tools);
+ if (enable_wii_tools)
+ {
+ IOS::HLE::Kernel ios;
+ const auto tmd = ios.GetES()->FindInstalledTMD(Titles::SYSTEM_MENU);
+ for (QAction* action : m_perform_online_update_menu->actions())
+ action->setEnabled(!tmd.IsValid());
+ m_perform_online_update_for_current_region->setEnabled(tmd.IsValid());
+ }
+}
+
void MenuBar::InstallWAD()
{
QString wad_file = QFileDialog::getOpenFileName(this, tr("Select a title to install to NAND"),
diff --git a/Source/Core/DolphinQt2/MenuBar.h b/Source/Core/DolphinQt2/MenuBar.h
index a0346f4277..426c7748d6 100644
--- a/Source/Core/DolphinQt2/MenuBar.h
+++ b/Source/Core/DolphinQt2/MenuBar.h
@@ -4,6 +4,8 @@
#pragma once
+#include
+
#include
#include
@@ -38,6 +40,8 @@ signals:
void StateSaveOldest();
void SetStateSlot(int slot);
+ void PerformOnlineUpdate(const std::string& region);
+
// Options
void ConfigureHotkeys();
@@ -53,6 +57,7 @@ public slots:
void EmulationPaused();
void EmulationStopped();
void UpdateStateSlotMenu();
+ void UpdateToolsMenu(bool emulation_started);
// Tools
void InstallWAD();
@@ -79,6 +84,8 @@ private:
// Tools
QAction* m_wad_install_action;
+ QMenu* m_perform_online_update_menu;
+ QAction* m_perform_online_update_for_current_region;
// Emulation
QAction* m_play_action;
diff --git a/Source/Core/DolphinQt2/WiiUpdate.cpp b/Source/Core/DolphinQt2/WiiUpdate.cpp
new file mode 100644
index 0000000000..d709e44b50
--- /dev/null
+++ b/Source/Core/DolphinQt2/WiiUpdate.cpp
@@ -0,0 +1,119 @@
+// Copyright 2017 Dolphin Emulator Project
+// Licensed under GPLv2+
+// Refer to the license.txt file included.
+
+#include "DolphinQt2/WiiUpdate.h"
+
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+
+#include "Common/FileUtil.h"
+#include "Common/Flag.h"
+#include "Core/Core.h"
+#include "Core/WiiUtils.h"
+#include "DiscIO/NANDImporter.h"
+
+namespace WiiUpdate
+{
+void PerformOnlineUpdate(const std::string& region, QWidget* parent)
+{
+ const int confirm = QMessageBox::question(
+ parent, QObject::tr("Confirm"),
+ QObject::tr("Connect to the Internet and perform an online system update?"));
+ if (confirm != QMessageBox::Yes)
+ return;
+
+ // Do not allow the user to close the dialog. Instead, wait until the update is finished
+ // or cancelled.
+ class UpdateProgressDialog final : public QProgressDialog
+ {
+ public:
+ using QProgressDialog::QProgressDialog;
+
+ protected:
+ void reject() override {}
+ };
+
+ UpdateProgressDialog dialog{parent};
+ dialog.setLabelText(QObject::tr("Preparing to update...\nThis can take a while."));
+ dialog.setWindowTitle(QObject::tr("Updating"));
+ // QProgressDialog doesn't set its minimum size correctly.
+ dialog.setMinimumSize(360, 150);
+
+ // QProgressDialog doesn't allow us to disable the cancel button when it's pressed,
+ // so we have to pass it our own push button. Note: the dialog takes ownership of it.
+ auto* cancel_button = new QPushButton(QObject::tr("&Cancel"), parent);
+ dialog.setCancelButton(cancel_button);
+ Common::Flag was_cancelled;
+ QObject::disconnect(&dialog, &QProgressDialog::canceled, &dialog, &QProgressDialog::cancel);
+ QObject::connect(&dialog, &QProgressDialog::canceled, [&] {
+ dialog.setLabelText(QObject::tr("Finishing the update...\nThis can take a while."));
+ cancel_button->setEnabled(false);
+ was_cancelled.Set();
+ });
+
+ std::future result = std::async(std::launch::async, [&] {
+ const WiiUtils::UpdateResult res = WiiUtils::DoOnlineUpdate(
+ [&](size_t processed, size_t total, u64 title_id) {
+ Core::QueueHostJob(
+ [&dialog, &was_cancelled, processed, total, title_id]() {
+ if (was_cancelled.IsSet())
+ return;
+
+ dialog.setRange(0, static_cast(total));
+ dialog.setValue(static_cast(processed));
+ dialog.setLabelText(QObject::tr("Updating title %1...\nThis can take a while.")
+ .arg(title_id, 16, 16, QLatin1Char('0')));
+ },
+ true);
+ return !was_cancelled.IsSet();
+ },
+ region);
+ Core::QueueHostJob([&dialog] { dialog.close(); }, true);
+ return res;
+ });
+
+ dialog.exec();
+
+ switch (result.get())
+ {
+ case WiiUtils::UpdateResult::Succeeded:
+ QMessageBox::information(parent, QObject::tr("Update completed"),
+ QObject::tr("The emulated Wii console has been updated."));
+ DiscIO::NANDImporter().ExtractCertificates(File::GetUserPath(D_WIIROOT_IDX));
+ break;
+ case WiiUtils::UpdateResult::AlreadyUpToDate:
+ QMessageBox::information(parent, QObject::tr("Update completed"),
+ QObject::tr("The emulated Wii console is already up-to-date."));
+ DiscIO::NANDImporter().ExtractCertificates(File::GetUserPath(D_WIIROOT_IDX));
+ break;
+ case WiiUtils::UpdateResult::ServerFailed:
+ QMessageBox::critical(parent, QObject::tr("Update failed"),
+ QObject::tr("Could not download update information from Nintendo. "
+ "Please check your Internet connection and try again."));
+ break;
+ case WiiUtils::UpdateResult::DownloadFailed:
+ QMessageBox::critical(parent, QObject::tr("Update failed"),
+ QObject::tr("Could not download update files from Nintendo. "
+ "Please check your Internet connection and try again."));
+ break;
+ case WiiUtils::UpdateResult::ImportFailed:
+ QMessageBox::critical(parent, QObject::tr("Update failed"),
+ QObject::tr("Could not install an update to the Wii system memory. "
+ "Please refer to logs for more information."));
+ break;
+ case WiiUtils::UpdateResult::Cancelled:
+ QMessageBox::warning(
+ parent, QObject::tr("Update cancelled"),
+ QObject::tr("The update has been cancelled. It is strongly recommended to "
+ "finish it in order to avoid inconsistent system software versions."));
+ break;
+ }
+}
+}; // namespace WiiUpdate
diff --git a/Source/Core/DolphinQt2/WiiUpdate.h b/Source/Core/DolphinQt2/WiiUpdate.h
new file mode 100644
index 0000000000..ea7428ebc2
--- /dev/null
+++ b/Source/Core/DolphinQt2/WiiUpdate.h
@@ -0,0 +1,14 @@
+// Copyright 2017 Dolphin Emulator Project
+// Licensed under GPLv2+
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include
+
+class QWidget;
+
+namespace WiiUpdate
+{
+void PerformOnlineUpdate(const std::string& region, QWidget* parent = nullptr);
+}; // namespace WiiUpdate