summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/yuzu/install_dialog.cpp16
-rw-r--r--src/yuzu/install_dialog.h5
-rw-r--r--src/yuzu/main.cpp399
-rw-r--r--src/yuzu/main.h14
4 files changed, 238 insertions, 196 deletions
diff --git a/src/yuzu/install_dialog.cpp b/src/yuzu/install_dialog.cpp
index fac158c25..5f3b4c963 100644
--- a/src/yuzu/install_dialog.cpp
+++ b/src/yuzu/install_dialog.cpp
@@ -22,7 +22,7 @@ InstallDialog::InstallDialog(QWidget* parent, const QStringList& files) : QDialo
22 item->setCheckState(Qt::Checked); 22 item->setCheckState(Qt::Checked);
23 } 23 }
24 24
25 file_list->setMinimumWidth((file_list->sizeHintForColumn(0) * 6) / 5); 25 file_list->setMinimumWidth((file_list->sizeHintForColumn(0) * 10) / 9);
26 26
27 vbox_layout = new QVBoxLayout; 27 vbox_layout = new QVBoxLayout;
28 28
@@ -54,19 +54,23 @@ InstallDialog::InstallDialog(QWidget* parent, const QStringList& files) : QDialo
54 54
55InstallDialog::~InstallDialog() = default; 55InstallDialog::~InstallDialog() = default;
56 56
57QStringList InstallDialog::GetFilenames() const { 57QStringList InstallDialog::GetFiles() const {
58 QStringList filenames; 58 QStringList files;
59 59
60 for (int i = 0; i < file_list->count(); ++i) { 60 for (int i = 0; i < file_list->count(); ++i) {
61 const QListWidgetItem* item = file_list->item(i); 61 const QListWidgetItem* item = file_list->item(i);
62 if (item->checkState() == Qt::Checked) { 62 if (item->checkState() == Qt::Checked) {
63 filenames.append(item->data(Qt::UserRole).toString()); 63 files.append(item->data(Qt::UserRole).toString());
64 } 64 }
65 } 65 }
66 66
67 return filenames; 67 return files;
68} 68}
69 69
70bool InstallDialog::ShouldOverwriteFiles() const { 70bool InstallDialog::ShouldOverwriteFiles() const {
71 return overwrite_files->isChecked(); 71 return overwrite_files->isChecked();
72} \ No newline at end of file 72}
73
74int InstallDialog::GetMinimumWidth() const {
75 return file_list->width();
76}
diff --git a/src/yuzu/install_dialog.h b/src/yuzu/install_dialog.h
index 3eaa9e60a..55a458ba8 100644
--- a/src/yuzu/install_dialog.h
+++ b/src/yuzu/install_dialog.h
@@ -20,8 +20,9 @@ public:
20 explicit InstallDialog(QWidget* parent, const QStringList& files); 20 explicit InstallDialog(QWidget* parent, const QStringList& files);
21 ~InstallDialog() override; 21 ~InstallDialog() override;
22 22
23 QStringList GetFilenames() const; 23 QStringList GetFiles() const;
24 bool ShouldOverwriteFiles() const; 24 bool ShouldOverwriteFiles() const;
25 int GetMinimumWidth() const;
25 26
26private: 27private:
27 QListWidget* file_list; 28 QListWidget* file_list;
@@ -32,4 +33,4 @@ private:
32 QLabel* description; 33 QLabel* description;
33 QCheckBox* overwrite_files; 34 QCheckBox* overwrite_files;
34 QDialogButtonBox* buttons; 35 QDialogButtonBox* buttons;
35}; \ No newline at end of file 36};
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index 45ddc3baf..4539cbe0d 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -1599,28 +1599,107 @@ void GMainWindow::OnMenuInstallToNAND() {
1599 tr("Installable Switch File (*.nca *.nsp *.xci);;Nintendo Content Archive " 1599 tr("Installable Switch File (*.nca *.nsp *.xci);;Nintendo Content Archive "
1600 "(*.nca);;Nintendo Submission Package (*.nsp);;NX Cartridge " 1600 "(*.nca);;Nintendo Submission Package (*.nsp);;NX Cartridge "
1601 "Image (*.xci)"); 1601 "Image (*.xci)");
1602 QStringList files = QFileDialog::getOpenFileNames(this, tr("Install Files"),
1603 UISettings::values.roms_path, file_filter);
1604 1602
1605 if (files.isEmpty()) { 1603 QStringList filenames = QFileDialog::getOpenFileNames(
1604 this, tr("Install Files"), UISettings::values.roms_path, file_filter);
1605
1606 if (filenames.isEmpty()) {
1606 return; 1607 return;
1607 } 1608 }
1608 1609
1609 InstallDialog installDialog(this, files); 1610 InstallDialog installDialog(this, filenames);
1610 if (installDialog.exec() == QDialog::Rejected) { 1611 if (installDialog.exec() == QDialog::Rejected) {
1611 return; 1612 return;
1612 } 1613 }
1613 1614
1614 const QStringList filenames = installDialog.GetFilenames(); 1615 const QStringList files = installDialog.GetFiles();
1615 const bool overwrite_files = installDialog.ShouldOverwriteFiles(); 1616 const bool overwrite_files = installDialog.ShouldOverwriteFiles();
1616 1617
1617 int count = 0; 1618 int count = 0;
1618 int total_count = filenames.size(); 1619 const int total_count = filenames.size();
1619 bool is_progressdialog_created = false; 1620
1621 QStringList new_files{}; // Newly installed files that do not yet exist in the NAND
1622 QStringList overwritten_files{}; // Files that overwrote those existing in the NAND
1623 QStringList existing_files{}; // Files that were not installed as they already exist in the NAND
1624 QStringList failed_files{}; // Files that failed to install due to errors
1625
1626 ui.action_Install_File_NAND->setEnabled(false);
1627
1628 QProgressDialog install_progress(QStringLiteral(""), tr("Cancel"), 0, total_count, this);
1629 install_progress.setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint &
1630 ~Qt::WindowMaximizeButtonHint);
1631 install_progress.setAutoClose(false);
1632 install_progress.setFixedWidth(installDialog.GetMinimumWidth());
1633 install_progress.show();
1634
1635 for (const QString& file : files) {
1636 install_progress.setWindowTitle(tr("%n file(s) remaining", "", total_count - count));
1637 install_progress.setLabelText(
1638 tr("Installing file \"%1\"...").arg(QFileInfo(file).fileName()));
1639
1640 QFuture<InstallResult> future;
1641 InstallResult result;
1642
1643 if (file.endsWith(QStringLiteral("xci"), Qt::CaseInsensitive) ||
1644 file.endsWith(QStringLiteral("nsp"), Qt::CaseInsensitive)) {
1645 future = QtConcurrent::run([this, &file, &overwrite_files, &install_progress] {
1646 return InstallNSPXCI(file, overwrite_files, install_progress);
1647 });
1648
1649 while (!future.isFinished()) {
1650 QCoreApplication::processEvents();
1651 }
1652
1653 result = future.result();
1654 } else {
1655 result = InstallNCA(file, overwrite_files, install_progress);
1656 }
1620 1657
1621 const auto qt_raw_copy = [this, &count, &total_count, &is_progressdialog_created]( 1658 switch (result) {
1622 const FileSys::VirtualFile& src, const FileSys::VirtualFile& dest, 1659 case InstallResult::Success:
1623 std::size_t block_size) { 1660 new_files.append(QFileInfo(file).fileName());
1661 break;
1662 case InstallResult::Overwrite:
1663 overwritten_files.append(QFileInfo(file).fileName());
1664 break;
1665 case InstallResult::AlreadyExists:
1666 existing_files.append(QFileInfo(file).fileName());
1667 break;
1668 case InstallResult::Failure:
1669 failed_files.append(QFileInfo(file).fileName());
1670 break;
1671 }
1672
1673 install_progress.setValue(++count);
1674 std::this_thread::sleep_for(std::chrono::milliseconds(10));
1675 }
1676
1677 install_progress.close();
1678
1679 const QString install_results =
1680 (new_files.isEmpty() ? QStringLiteral("")
1681 : tr("%n file(s) were newly installed\n", "", new_files.size())) +
1682 (overwritten_files.isEmpty()
1683 ? QStringLiteral("")
1684 : tr("%n file(s) were overwritten\n", "", overwritten_files.size())) +
1685 (existing_files.isEmpty()
1686 ? QStringLiteral("")
1687 : tr("%n file(s) already exist in NAND\n", "", existing_files.size())) +
1688 (failed_files.isEmpty() ? QStringLiteral("")
1689 : tr("%n file(s) failed to install\n", "", failed_files.size()));
1690
1691 QMessageBox::information(this, tr("Install Results"), install_results);
1692 game_list->PopulateAsync(UISettings::values.game_dirs);
1693 FileUtil::DeleteDirRecursively(FileUtil::GetUserPath(FileUtil::UserPath::CacheDir) + DIR_SEP +
1694 "game_list");
1695 ui.action_Install_File_NAND->setEnabled(true);
1696}
1697
1698InstallResult GMainWindow::InstallNSPXCI(const QString& filename, bool overwrite_files,
1699 QProgressDialog& install_progress) {
1700 const auto qt_raw_copy = [this, &install_progress](const FileSys::VirtualFile& src,
1701 const FileSys::VirtualFile& dest,
1702 std::size_t block_size) {
1624 if (src == nullptr || dest == nullptr) { 1703 if (src == nullptr || dest == nullptr) {
1625 return false; 1704 return false;
1626 } 1705 }
@@ -1629,204 +1708,154 @@ void GMainWindow::OnMenuInstallToNAND() {
1629 } 1708 }
1630 1709
1631 std::array<u8, 0x1000> buffer{}; 1710 std::array<u8, 0x1000> buffer{};
1632 const int progress_maximum = static_cast<int>(src->GetSize() / buffer.size());
1633
1634 if (!is_progressdialog_created) {
1635 ui.action_Install_File_NAND->setEnabled(false);
1636 install_progress = new QProgressDialog(
1637 tr("Installing file \"%1\"...").arg(QString::fromStdString(src->GetName())),
1638 tr("Cancel"), 0, progress_maximum, this);
1639 install_progress->setWindowTitle(
1640 tr("%n file(s) remaining", "", total_count - count - 1));
1641 install_progress->setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint &
1642 ~Qt::WindowMaximizeButtonHint);
1643 install_progress->setAutoClose(false);
1644 is_progressdialog_created = true;
1645 } else {
1646 install_progress->setWindowTitle(
1647 tr("%n file(s) remaining", "", total_count - count - 1));
1648 install_progress->setLabelText(
1649 tr("Installing file \"%1\"...").arg(QString::fromStdString(src->GetName())));
1650 install_progress->setMaximum(progress_maximum);
1651 }
1652 1711
1653 for (std::size_t i = 0; i < src->GetSize(); i += buffer.size()) { 1712 for (std::size_t i = 0; i < src->GetSize(); i += buffer.size()) {
1654 if (install_progress->wasCanceled()) { 1713 if (install_progress.wasCanceled()) {
1655 dest->Resize(0); 1714 dest->Resize(0);
1656 return false; 1715 return false;
1657 } 1716 }
1658 1717
1659 const int progress_value = static_cast<int>(i / buffer.size());
1660 install_progress->setValue(progress_value);
1661
1662 const auto read = src->Read(buffer.data(), buffer.size(), i); 1718 const auto read = src->Read(buffer.data(), buffer.size(), i);
1663 dest->Write(buffer.data(), read, i); 1719 dest->Write(buffer.data(), read, i);
1664 } 1720 }
1665
1666 return true; 1721 return true;
1667 }; 1722 };
1668 1723
1669 const auto success = [this, &count, &is_progressdialog_created]() { 1724 std::shared_ptr<FileSys::NSP> nsp;
1670 if (is_progressdialog_created) { 1725 if (filename.endsWith(QStringLiteral("nsp"), Qt::CaseInsensitive)) {
1671 install_progress->close(); 1726 nsp = std::make_shared<FileSys::NSP>(
1672 } 1727 vfs->OpenFile(filename.toStdString(), FileSys::Mode::Read));
1673 QMessageBox::information(this, tr("Successfully Installed"), 1728 if (nsp->IsExtractedType()) {
1674 tr("%n file(s) successfully installed", "", count)); 1729 return InstallResult::Failure;
1675 game_list->PopulateAsync(UISettings::values.game_dirs);
1676 FileUtil::DeleteDirRecursively(FileUtil::GetUserPath(FileUtil::UserPath::CacheDir) +
1677 DIR_SEP + "game_list");
1678 ui.action_Install_File_NAND->setEnabled(true);
1679 };
1680
1681 const auto failed = [this, &is_progressdialog_created](const QString& file) {
1682 if (is_progressdialog_created) {
1683 install_progress->close();
1684 } 1730 }
1685 QMessageBox::warning( 1731 } else {
1686 this, tr("Failed to Install %1").arg(QFileInfo(file).fileName()), 1732 const auto xci = std::make_shared<FileSys::XCI>(
1687 tr("There was an error while attempting to install the provided file. It " 1733 vfs->OpenFile(filename.toStdString(), FileSys::Mode::Read));
1688 "could have an incorrect format or be missing metadata. Please " 1734 nsp = xci->GetSecurePartitionNSP();
1689 "double-check your file and try again.")); 1735 }
1690 game_list->PopulateAsync(UISettings::values.game_dirs); 1736
1691 ui.action_Install_File_NAND->setEnabled(true); 1737 if (nsp->GetStatus() != Loader::ResultStatus::Success) {
1692 }; 1738 return InstallResult::Failure;
1693 1739 }
1694 const auto overwrite = [this](const QString& file) { 1740 const auto res =
1695 return QMessageBox::question( 1741 Core::System::GetInstance().GetFileSystemController().GetUserNANDContents()->InstallEntry(
1696 this, tr("Failed to Install %1").arg(QFileInfo(file).fileName()), 1742 *nsp, false, qt_raw_copy);
1697 tr("The file you are attempting to install already exists " 1743 if (res == FileSys::InstallResult::Success) {
1698 "in the cache. Would you like to overwrite it?")) == QMessageBox::Yes; 1744 return InstallResult::Success;
1699 }; 1745 } else if (res == FileSys::InstallResult::ErrorAlreadyExists) {
1700 1746 if (overwrite_files) {
1701 for (const QString& filename : filenames) { 1747 const auto res2 = Core::System::GetInstance()
1702 if (filename.endsWith(QStringLiteral("xci"), Qt::CaseInsensitive) || 1748 .GetFileSystemController()
1703 filename.endsWith(QStringLiteral("nsp"), Qt::CaseInsensitive)) { 1749 .GetUserNANDContents()
1704 std::shared_ptr<FileSys::NSP> nsp; 1750 ->InstallEntry(*nsp, true, qt_raw_copy);
1705 if (filename.endsWith(QStringLiteral("nsp"), Qt::CaseInsensitive)) { 1751 if (res2 != FileSys::InstallResult::Success) {
1706 nsp = std::make_shared<FileSys::NSP>( 1752 return InstallResult::Failure;
1707 vfs->OpenFile(filename.toStdString(), FileSys::Mode::Read));
1708 if (nsp->IsExtractedType()) {
1709 failed(filename);
1710 break;
1711 }
1712 } else {
1713 const auto xci = std::make_shared<FileSys::XCI>(
1714 vfs->OpenFile(filename.toStdString(), FileSys::Mode::Read));
1715 nsp = xci->GetSecurePartitionNSP();
1716 }
1717
1718 if (nsp->GetStatus() != Loader::ResultStatus::Success) {
1719 failed(filename);
1720 break;
1721 }
1722 const auto res = Core::System::GetInstance()
1723 .GetFileSystemController()
1724 .GetUserNANDContents()
1725 ->InstallEntry(*nsp, false, qt_raw_copy);
1726 if (res == FileSys::InstallResult::Success) {
1727 ++count;
1728 } else if (res == FileSys::InstallResult::ErrorAlreadyExists) {
1729 if (overwrite_files && overwrite(filename)) {
1730 const auto res2 = Core::System::GetInstance()
1731 .GetFileSystemController()
1732 .GetUserNANDContents()
1733 ->InstallEntry(*nsp, true, qt_raw_copy);
1734 if (res2 != FileSys::InstallResult::Success) {
1735 failed(filename);
1736 break;
1737 }
1738 ++count;
1739 } else {
1740 --total_count;
1741 }
1742 } else {
1743 failed(filename);
1744 break;
1745 } 1753 }
1754 return InstallResult::Overwrite;
1746 } else { 1755 } else {
1747 const auto nca = std::make_shared<FileSys::NCA>( 1756 return InstallResult::AlreadyExists;
1748 vfs->OpenFile(filename.toStdString(), FileSys::Mode::Read)); 1757 }
1749 const auto id = nca->GetStatus(); 1758 } else {
1750 1759 return InstallResult::Failure;
1751 // Game updates necessary are missing base RomFS 1760 }
1752 if (id != Loader::ResultStatus::Success && 1761}
1753 id != Loader::ResultStatus::ErrorMissingBKTRBaseRomFS) {
1754 failed(filename);
1755 break;
1756 }
1757 1762
1758 const QStringList tt_options{tr("System Application"), 1763InstallResult GMainWindow::InstallNCA(const QString& filename, bool overwrite_files,
1759 tr("System Archive"), 1764 QProgressDialog& install_progress) {
1760 tr("System Application Update"), 1765 const auto qt_raw_copy = [this, &install_progress](const FileSys::VirtualFile& src,
1761 tr("Firmware Package (Type A)"), 1766 const FileSys::VirtualFile& dest,
1762 tr("Firmware Package (Type B)"), 1767 std::size_t block_size) {
1763 tr("Game"), 1768 if (src == nullptr || dest == nullptr) {
1764 tr("Game Update"), 1769 return false;
1765 tr("Game DLC"), 1770 }
1766 tr("Delta Title")}; 1771 if (!dest->Resize(src->GetSize())) {
1767 bool ok; 1772 return false;
1768 const auto item = QInputDialog::getItem( 1773 }
1769 this, tr("Select NCA Install Type..."),
1770 tr("Please select the type of title you would like to install this NCA as:\n(In "
1771 "most instances, the default 'Game' is fine.)"),
1772 tt_options, 5, false, &ok);
1773
1774 auto index = tt_options.indexOf(item);
1775 if (!ok || index == -1) {
1776 QMessageBox::warning(this, tr("Failed to Install"),
1777 tr("The title type you selected for the NCA is invalid."));
1778 break;
1779 }
1780 1774
1781 // If index is equal to or past Game, add the jump in TitleType. 1775 std::array<u8, 0x1000> buffer{};
1782 if (index >= 5) {
1783 index += static_cast<size_t>(FileSys::TitleType::Application) -
1784 static_cast<size_t>(FileSys::TitleType::FirmwarePackageB);
1785 }
1786 1776
1787 FileSys::InstallResult res; 1777 for (std::size_t i = 0; i < src->GetSize(); i += buffer.size()) {
1788 if (index >= static_cast<s32>(FileSys::TitleType::Application)) { 1778 if (install_progress.wasCanceled()) {
1789 res = Core::System::GetInstance() 1779 dest->Resize(0);
1790 .GetFileSystemController() 1780 return false;
1791 .GetUserNANDContents()
1792 ->InstallEntry(*nca, static_cast<FileSys::TitleType>(index), false,
1793 qt_raw_copy);
1794 } else {
1795 res = Core::System::GetInstance()
1796 .GetFileSystemController()
1797 .GetSystemNANDContents()
1798 ->InstallEntry(*nca, static_cast<FileSys::TitleType>(index), false,
1799 qt_raw_copy);
1800 } 1781 }
1801 1782
1802 if (res == FileSys::InstallResult::Success) { 1783 const auto read = src->Read(buffer.data(), buffer.size(), i);
1803 ++count; 1784 dest->Write(buffer.data(), read, i);
1804 } else if (res == FileSys::InstallResult::ErrorAlreadyExists) {
1805 if (overwrite_files && overwrite(filename)) {
1806 const auto res2 =
1807 Core::System::GetInstance()
1808 .GetFileSystemController()
1809 .GetUserNANDContents()
1810 ->InstallEntry(*nca, static_cast<FileSys::TitleType>(index), true,
1811 qt_raw_copy);
1812 if (res2 != FileSys::InstallResult::Success) {
1813 failed(filename);
1814 break;
1815 }
1816 ++count;
1817 } else {
1818 --total_count;
1819 }
1820 } else {
1821 failed(filename);
1822 break;
1823 }
1824 } 1785 }
1786 return true;
1787 };
1825 1788
1826 // Return success only on the last file 1789 const auto nca =
1827 if (filename == filenames.last()) { 1790 std::make_shared<FileSys::NCA>(vfs->OpenFile(filename.toStdString(), FileSys::Mode::Read));
1828 success(); 1791 const auto id = nca->GetStatus();
1792
1793 // Game updates necessary are missing base RomFS
1794 if (id != Loader::ResultStatus::Success &&
1795 id != Loader::ResultStatus::ErrorMissingBKTRBaseRomFS) {
1796 return InstallResult::Failure;
1797 }
1798
1799 const QStringList tt_options{tr("System Application"),
1800 tr("System Archive"),
1801 tr("System Application Update"),
1802 tr("Firmware Package (Type A)"),
1803 tr("Firmware Package (Type B)"),
1804 tr("Game"),
1805 tr("Game Update"),
1806 tr("Game DLC"),
1807 tr("Delta Title")};
1808 bool ok;
1809 const auto item = QInputDialog::getItem(
1810 this, tr("Select NCA Install Type..."),
1811 tr("Please select the type of title you would like to install this NCA as:\n(In "
1812 "most instances, the default 'Game' is fine.)"),
1813 tt_options, 5, false, &ok);
1814
1815 auto index = tt_options.indexOf(item);
1816 if (!ok || index == -1) {
1817 QMessageBox::warning(this, tr("Failed to Install"),
1818 tr("The title type you selected for the NCA is invalid."));
1819 return InstallResult::Failure;
1820 }
1821
1822 // If index is equal to or past Game, add the jump in TitleType.
1823 if (index >= 5) {
1824 index += static_cast<size_t>(FileSys::TitleType::Application) -
1825 static_cast<size_t>(FileSys::TitleType::FirmwarePackageB);
1826 }
1827
1828 FileSys::InstallResult res;
1829 if (index >= static_cast<s32>(FileSys::TitleType::Application)) {
1830 res = Core::System::GetInstance()
1831 .GetFileSystemController()
1832 .GetUserNANDContents()
1833 ->InstallEntry(*nca, static_cast<FileSys::TitleType>(index), false, qt_raw_copy);
1834 } else {
1835 res = Core::System::GetInstance()
1836 .GetFileSystemController()
1837 .GetSystemNANDContents()
1838 ->InstallEntry(*nca, static_cast<FileSys::TitleType>(index), false, qt_raw_copy);
1839 }
1840
1841 if (res == FileSys::InstallResult::Success) {
1842 return InstallResult::Success;
1843 } else if (res == FileSys::InstallResult::ErrorAlreadyExists) {
1844 if (overwrite_files) {
1845 const auto res2 =
1846 Core::System::GetInstance()
1847 .GetFileSystemController()
1848 .GetUserNANDContents()
1849 ->InstallEntry(*nca, static_cast<FileSys::TitleType>(index), true, qt_raw_copy);
1850 if (res2 != FileSys::InstallResult::Success) {
1851 return InstallResult::Failure;
1852 }
1853 return InstallResult::Overwrite;
1854 } else {
1855 return InstallResult::AlreadyExists;
1829 } 1856 }
1857 } else {
1858 return InstallResult::Failure;
1830 } 1859 }
1831} 1860}
1832 1861
diff --git a/src/yuzu/main.h b/src/yuzu/main.h
index 55d072e96..deea8170d 100644
--- a/src/yuzu/main.h
+++ b/src/yuzu/main.h
@@ -48,6 +48,13 @@ enum class EmulatedDirectoryTarget {
48 SDMC, 48 SDMC,
49}; 49};
50 50
51enum class InstallResult {
52 Success,
53 Overwrite,
54 AlreadyExists,
55 Failure,
56};
57
51enum class ReinitializeKeyBehavior { 58enum class ReinitializeKeyBehavior {
52 NoWarning, 59 NoWarning,
53 Warning, 60 Warning,
@@ -219,6 +226,10 @@ private slots:
219 226
220private: 227private:
221 std::optional<u64> SelectRomFSDumpTarget(const FileSys::ContentProvider&, u64 program_id); 228 std::optional<u64> SelectRomFSDumpTarget(const FileSys::ContentProvider&, u64 program_id);
229 InstallResult InstallNSPXCI(const QString& filename, bool overwrite_files,
230 QProgressDialog& install_progress);
231 InstallResult InstallNCA(const QString& filename, bool overwrite_files,
232 QProgressDialog& install_progress);
222 void UpdateWindowTitle(const std::string& title_name = {}, 233 void UpdateWindowTitle(const std::string& title_name = {},
223 const std::string& title_version = {}); 234 const std::string& title_version = {});
224 void UpdateStatusBar(); 235 void UpdateStatusBar();
@@ -273,9 +284,6 @@ private:
273 284
274 HotkeyRegistry hotkey_registry; 285 HotkeyRegistry hotkey_registry;
275 286
276 // Install to NAND progress dialog
277 QProgressDialog* install_progress;
278
279protected: 287protected:
280 void dropEvent(QDropEvent* event) override; 288 void dropEvent(QDropEvent* event) override;
281 void dragEnterEvent(QDragEnterEvent* event) override; 289 void dragEnterEvent(QDragEnterEvent* event) override;