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