mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2024-11-14 21:37:52 -07:00
Merge pull request #5353 from spycrab/qt_contextmenu
Qt: Add missing gamelist contextmenu options
This commit is contained in:
commit
e9571106c2
@ -8,10 +8,14 @@
|
||||
#include <QImage>
|
||||
#include <QSharedPointer>
|
||||
|
||||
#include "Common/Assert.h"
|
||||
#include "Common/FileUtil.h"
|
||||
#include "Common/NandPaths.h"
|
||||
#include "Core/ConfigManager.h"
|
||||
#include "Core/HW/WiiSaveCrypted.h"
|
||||
#include "DiscIO/Blob.h"
|
||||
#include "DiscIO/Enums.h"
|
||||
#include "DiscIO/NANDContentLoader.h"
|
||||
#include "DiscIO/Volume.h"
|
||||
#include "DiscIO/VolumeCreator.h"
|
||||
#include "DolphinQt2/GameList/GameFile.h"
|
||||
@ -144,6 +148,7 @@ bool GameFile::TryLoadVolume()
|
||||
|
||||
m_game_id = QString::fromStdString(volume->GetGameID());
|
||||
std::string maker_id = volume->GetMakerID();
|
||||
volume->GetTitleID(&m_title_id);
|
||||
m_maker = QString::fromStdString(DiscIO::GetCompanyFromID(maker_id));
|
||||
m_maker_id = QString::fromStdString(maker_id);
|
||||
m_revision = volume->GetRevision();
|
||||
@ -291,6 +296,53 @@ QString GameFile::GetLanguage(DiscIO::Language lang) const
|
||||
}
|
||||
}
|
||||
|
||||
bool GameFile::IsInstalled() const
|
||||
{
|
||||
_assert_(m_platform == DiscIO::Platform::WII_WAD);
|
||||
|
||||
const std::string content_dir =
|
||||
Common::GetTitleContentPath(m_title_id, Common::FromWhichRoot::FROM_CONFIGURED_ROOT);
|
||||
|
||||
if (!File::IsDirectory(content_dir))
|
||||
return false;
|
||||
|
||||
// Since this isn't IOS and we only need a simple way to figure out if a title is installed,
|
||||
// we make the (reasonable) assumption that having more than just the TMD in the content
|
||||
// directory means that the title is installed.
|
||||
const auto entries = File::ScanDirectoryTree(content_dir, false);
|
||||
return std::any_of(entries.children.begin(), entries.children.end(),
|
||||
[](const auto& file) { return file.virtualName != "title.tmd"; });
|
||||
}
|
||||
|
||||
bool GameFile::Install()
|
||||
{
|
||||
_assert_(m_platform == DiscIO::Platform::WII_WAD);
|
||||
|
||||
return DiscIO::CNANDContentManager::Access().Install_WiiWAD(m_path.toStdString());
|
||||
}
|
||||
|
||||
bool GameFile::Uninstall()
|
||||
{
|
||||
_assert_(m_platform == DiscIO::Platform::WII_WAD);
|
||||
|
||||
return DiscIO::CNANDContentManager::Access().RemoveTitle(m_title_id,
|
||||
Common::FROM_CONFIGURED_ROOT);
|
||||
}
|
||||
|
||||
bool GameFile::ExportWiiSave()
|
||||
{
|
||||
return CWiiSaveCrypted::ExportWiiSave(m_title_id);
|
||||
}
|
||||
|
||||
QString GameFile::GetWiiFSPath() const
|
||||
{
|
||||
_assert_(m_platform != DiscIO::Platform::GAMECUBE_DISC);
|
||||
|
||||
const std::string path = Common::GetTitleDataPath(m_title_id, Common::FROM_CONFIGURED_ROOT);
|
||||
|
||||
return QString::fromStdString(path);
|
||||
}
|
||||
|
||||
// Convert an integer size to a friendly string representation.
|
||||
QString FormatSize(qint64 size)
|
||||
{
|
||||
|
@ -38,6 +38,7 @@ public:
|
||||
QString GetGameID() const { return m_game_id; }
|
||||
QString GetMakerID() const { return m_maker_id; }
|
||||
QString GetMaker() const { return m_maker; }
|
||||
u64 GetTitleID() const { return m_title_id; }
|
||||
u16 GetRevision() const { return m_revision; }
|
||||
QString GetInternalName() const { return m_internal_name; }
|
||||
u8 GetDiscNumber() const { return m_disc_number; }
|
||||
@ -52,6 +53,8 @@ public:
|
||||
DiscIO::Country GetCountryID() const { return m_country; }
|
||||
QString GetCountry() const;
|
||||
DiscIO::BlobType GetBlobType() const { return m_blob_type; }
|
||||
QString GetWiiFSPath() const;
|
||||
bool IsInstalled() const;
|
||||
// Banner details
|
||||
QString GetLanguage(DiscIO::Language lang) const;
|
||||
QList<DiscIO::Language> GetAvailableLanguages() const;
|
||||
@ -65,6 +68,10 @@ public:
|
||||
QString GetLongName(DiscIO::Language lang) const { return m_long_names[lang]; }
|
||||
QString GetLongMaker(DiscIO::Language lang) const { return m_long_makers[lang]; }
|
||||
QString GetDescription(DiscIO::Language lang) const { return m_descriptions[lang]; }
|
||||
bool Install();
|
||||
bool Uninstall();
|
||||
bool ExportWiiSave();
|
||||
|
||||
private:
|
||||
QString GetBannerString(const QMap<DiscIO::Language, QString>& m) const;
|
||||
|
||||
@ -90,6 +97,7 @@ private:
|
||||
QString m_maker;
|
||||
QString m_maker_id;
|
||||
u16 m_revision = 0;
|
||||
u64 m_title_id = 0;
|
||||
QString m_internal_name;
|
||||
QMap<DiscIO::Language, QString> m_short_names;
|
||||
QMap<DiscIO::Language, QString> m_long_names;
|
||||
|
@ -3,11 +3,19 @@
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <QDesktopServices>
|
||||
#include <QDir>
|
||||
#include <QErrorMessage>
|
||||
#include <QFileDialog>
|
||||
#include <QFileInfo>
|
||||
#include <QHeaderView>
|
||||
#include <QKeyEvent>
|
||||
#include <QMenu>
|
||||
#include <QMessageBox>
|
||||
#include <QProgressDialog>
|
||||
#include <QUrl>
|
||||
|
||||
#include "Common/FileUtil.h"
|
||||
#include "DiscIO/Blob.h"
|
||||
#include "DiscIO/Enums.h"
|
||||
|
||||
#include "DolphinQt2/Config/PropertiesDialog.h"
|
||||
@ -16,6 +24,8 @@
|
||||
#include "DolphinQt2/GameList/TableDelegate.h"
|
||||
#include "DolphinQt2/Settings.h"
|
||||
|
||||
static bool CompressCB(const std::string&, float, void*);
|
||||
|
||||
GameList::GameList(QWidget* parent) : QStackedWidget(parent)
|
||||
{
|
||||
m_model = new GameListModel(this);
|
||||
@ -105,18 +115,47 @@ void GameList::MakeListView()
|
||||
|
||||
void GameList::ShowContextMenu(const QPoint&)
|
||||
{
|
||||
const auto game = GetSelectedGame();
|
||||
if (game.isEmpty())
|
||||
return;
|
||||
|
||||
QMenu* menu = new QMenu(this);
|
||||
DiscIO::Platform platform = GameFile(GetSelectedGame()).GetPlatformID();
|
||||
DiscIO::Platform platform = GameFile(game).GetPlatformID();
|
||||
menu->addAction(tr("Properties"), this, SLOT(OpenProperties()));
|
||||
menu->addAction(tr("Wiki"), this, SLOT(OpenWiki()));
|
||||
menu->addSeparator();
|
||||
|
||||
if (platform == DiscIO::Platform::GAMECUBE_DISC || platform == DiscIO::Platform::WII_DISC)
|
||||
{
|
||||
menu->addAction(tr("Properties"), this, SLOT(OpenProperties()));
|
||||
menu->addAction(tr("Open Wiki Page"), this, SLOT(OpenWiki()));
|
||||
menu->addAction(tr("Set as Default ISO"), this, SLOT(SetDefaultISO()));
|
||||
menu->addAction(tr("Default ISO"), this, SLOT(SetDefaultISO()));
|
||||
const auto blob_type = GameFile(game).GetBlobType();
|
||||
|
||||
if (blob_type == DiscIO::BlobType::GCZ)
|
||||
menu->addAction(tr("Decompress ISO"), this, SLOT(DecompressISO()));
|
||||
else if (blob_type == DiscIO::BlobType::PLAIN)
|
||||
menu->addAction(tr("Compress ISO"), this, SLOT(CompressISO()));
|
||||
|
||||
menu->addSeparator();
|
||||
}
|
||||
else
|
||||
if (platform == DiscIO::Platform::WII_WAD)
|
||||
{
|
||||
return;
|
||||
menu->addAction(tr("Install to the NAND"), this, SLOT(InstallWAD()));
|
||||
|
||||
if (GameFile(game).IsInstalled())
|
||||
menu->addAction(tr("Uninstall from the NAND"), this, SLOT(UninstallWAD()));
|
||||
|
||||
menu->addSeparator();
|
||||
}
|
||||
|
||||
if (platform == DiscIO::Platform::WII_WAD || platform == DiscIO::Platform::WII_DISC)
|
||||
{
|
||||
menu->addAction(tr("Open Wii save folder"), this, SLOT(OpenSaveFolder()));
|
||||
menu->addAction(tr("Export Wii save (Experimental)"), this, SLOT(ExportWiiSave()));
|
||||
menu->addSeparator();
|
||||
}
|
||||
|
||||
menu->addAction(tr("Open Containing Folder"), this, SLOT(OpenContainingFolder()));
|
||||
menu->addAction(tr("Remove File"), this, SLOT(DeleteFile()));
|
||||
menu->exec(QCursor::pos());
|
||||
}
|
||||
|
||||
@ -126,6 +165,18 @@ void GameList::OpenProperties()
|
||||
properties->show();
|
||||
}
|
||||
|
||||
void GameList::ExportWiiSave()
|
||||
{
|
||||
QMessageBox result_dialog(this);
|
||||
|
||||
const bool success = GameFile(GetSelectedGame()).ExportWiiSave();
|
||||
|
||||
result_dialog.setIcon(success ? QMessageBox::Information : QMessageBox::Critical);
|
||||
result_dialog.setText(success ? tr("Successfully exported save files") :
|
||||
tr("Failed to export save files!"));
|
||||
result_dialog.exec();
|
||||
}
|
||||
|
||||
void GameList::OpenWiki()
|
||||
{
|
||||
QString game_id = GameFile(GetSelectedGame()).GetGameID();
|
||||
@ -133,11 +184,160 @@ void GameList::OpenWiki()
|
||||
QDesktopServices::openUrl(QUrl(url));
|
||||
}
|
||||
|
||||
void GameList::CompressISO()
|
||||
{
|
||||
const auto original_path = GetSelectedGame();
|
||||
auto file = GameFile(original_path);
|
||||
|
||||
const bool compressed = (file.GetBlobType() == DiscIO::BlobType::GCZ);
|
||||
|
||||
if (!compressed && file.GetPlatformID() == DiscIO::Platform::WII_DISC)
|
||||
{
|
||||
QMessageBox wii_warning(this);
|
||||
wii_warning.setIcon(QMessageBox::Warning);
|
||||
wii_warning.setText(tr("Are you sure?"));
|
||||
wii_warning.setInformativeText(
|
||||
tr("Compressing a Wii disc image will irreversibly change the compressed copy by removing "
|
||||
"padding data. Your disc image will still work."));
|
||||
wii_warning.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
|
||||
|
||||
if (wii_warning.exec() == QMessageBox::No)
|
||||
return;
|
||||
}
|
||||
|
||||
QString dst_path = QFileDialog::getSaveFileName(
|
||||
this, compressed ? tr("Select where you want to save the decompressed image") :
|
||||
tr("Select where you want to save the compressed image"),
|
||||
QFileInfo(GetSelectedGame())
|
||||
.dir()
|
||||
.absoluteFilePath(file.GetGameID())
|
||||
.append(compressed ? QStringLiteral(".gcm") : QStringLiteral(".gcz")),
|
||||
compressed ? tr("Uncompressed GC/Wii images (*.iso *.gcm") :
|
||||
tr("Compressed GC/Wii images (*.gcz)"));
|
||||
|
||||
if (dst_path.isEmpty())
|
||||
return;
|
||||
|
||||
QProgressDialog progress_dialog(compressed ? tr("Decompressing...") : tr("Compressing..."),
|
||||
tr("Abort"), 0, 100, this);
|
||||
progress_dialog.setWindowModality(Qt::WindowModal);
|
||||
|
||||
bool good;
|
||||
|
||||
if (compressed)
|
||||
{
|
||||
good = DiscIO::DecompressBlobToFile(original_path.toStdString(), dst_path.toStdString(),
|
||||
&CompressCB, &progress_dialog);
|
||||
}
|
||||
else
|
||||
{
|
||||
good = DiscIO::CompressFileToBlob(original_path.toStdString(), dst_path.toStdString(),
|
||||
file.GetPlatformID() == DiscIO::Platform::WII_DISC ? 1 : 0,
|
||||
16384, &CompressCB, &progress_dialog);
|
||||
}
|
||||
|
||||
if (good)
|
||||
{
|
||||
QMessageBox(QMessageBox::Information, tr("Success!"), tr("Successfully compressed image."),
|
||||
QMessageBox::Ok, this)
|
||||
.exec();
|
||||
}
|
||||
else
|
||||
{
|
||||
QErrorMessage(this).showMessage(tr("Dolphin failed to complete the requested action."));
|
||||
}
|
||||
}
|
||||
|
||||
void GameList::InstallWAD()
|
||||
{
|
||||
QMessageBox result_dialog(this);
|
||||
|
||||
const bool success = GameFile(GetSelectedGame()).Install();
|
||||
|
||||
result_dialog.setIcon(success ? QMessageBox::Information : QMessageBox::Critical);
|
||||
result_dialog.setText(success ? tr("Succesfully installed title to the NAND") :
|
||||
tr("Failed to install title to the NAND"));
|
||||
result_dialog.exec();
|
||||
}
|
||||
|
||||
void GameList::UninstallWAD()
|
||||
{
|
||||
QMessageBox warning_dialog(this);
|
||||
|
||||
warning_dialog.setIcon(QMessageBox::Information);
|
||||
warning_dialog.setText(tr("Uninstalling the WAD will remove the currently installed version of "
|
||||
"this title from the NAND without deleting its save data. Continue?"));
|
||||
warning_dialog.setStandardButtons(QMessageBox::No | QMessageBox::Yes);
|
||||
|
||||
if (warning_dialog.exec() == QMessageBox::No)
|
||||
return;
|
||||
|
||||
QMessageBox result_dialog(this);
|
||||
|
||||
const bool success = GameFile(GetSelectedGame()).Uninstall();
|
||||
|
||||
result_dialog.setIcon(success ? QMessageBox::Information : QMessageBox::Critical);
|
||||
result_dialog.setText(success ? tr("Succesfully removed title from the NAND") :
|
||||
tr("Failed to remove title from the NAND"));
|
||||
result_dialog.exec();
|
||||
}
|
||||
|
||||
void GameList::SetDefaultISO()
|
||||
{
|
||||
Settings().SetDefaultGame(GetSelectedGame());
|
||||
}
|
||||
|
||||
void GameList::OpenContainingFolder()
|
||||
{
|
||||
QUrl url = QUrl::fromLocalFile(QFileInfo(GetSelectedGame()).dir().absolutePath());
|
||||
QDesktopServices::openUrl(url);
|
||||
}
|
||||
|
||||
void GameList::OpenSaveFolder()
|
||||
{
|
||||
QUrl url = QUrl::fromLocalFile(GameFile(GetSelectedGame()).GetWiiFSPath());
|
||||
QDesktopServices::openUrl(url);
|
||||
}
|
||||
|
||||
void GameList::DeleteFile()
|
||||
{
|
||||
const auto game = GetSelectedGame();
|
||||
QMessageBox confirm_dialog(this);
|
||||
|
||||
confirm_dialog.setIcon(QMessageBox::Warning);
|
||||
confirm_dialog.setText(tr("Are you sure you want to delete this file?"));
|
||||
confirm_dialog.setInformativeText(tr("You won't be able to undo this!"));
|
||||
confirm_dialog.setStandardButtons(QMessageBox::Yes | QMessageBox::Cancel);
|
||||
|
||||
if (confirm_dialog.exec() == QMessageBox::Yes)
|
||||
{
|
||||
bool deletion_successful = false;
|
||||
|
||||
while (!deletion_successful)
|
||||
{
|
||||
deletion_successful = File::Delete(game.toStdString());
|
||||
|
||||
if (deletion_successful)
|
||||
{
|
||||
m_model->RemoveGame(game);
|
||||
}
|
||||
else
|
||||
{
|
||||
QMessageBox error_dialog(this);
|
||||
|
||||
error_dialog.setIcon(QMessageBox::Critical);
|
||||
error_dialog.setText(tr("Failed to delete the selected file."));
|
||||
error_dialog.setInformativeText(tr("Check whether you have the permissions required to "
|
||||
"delete the file or whether it's still in use."));
|
||||
error_dialog.setStandardButtons(QMessageBox::Retry | QMessageBox::Abort);
|
||||
|
||||
if (error_dialog.exec() == QMessageBox::Abort)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QString GameList::GetSelectedGame() const
|
||||
{
|
||||
QAbstractItemView* view;
|
||||
@ -189,3 +389,13 @@ void GameList::keyReleaseEvent(QKeyEvent* event)
|
||||
else
|
||||
QStackedWidget::keyReleaseEvent(event);
|
||||
}
|
||||
|
||||
static bool CompressCB(const std::string& text, float percent, void* ptr)
|
||||
{
|
||||
if (ptr == nullptr)
|
||||
return false;
|
||||
auto* progress_dialog = static_cast<QProgressDialog*>(ptr);
|
||||
|
||||
progress_dialog->setValue(percent * 100);
|
||||
return !progress_dialog->wasCanceled();
|
||||
}
|
||||
|
@ -29,9 +29,16 @@ public slots:
|
||||
void SetViewColumn(int col, bool view) { m_table->setColumnHidden(col, !view); }
|
||||
private slots:
|
||||
void ShowContextMenu(const QPoint&);
|
||||
void OpenContainingFolder();
|
||||
void OpenProperties();
|
||||
void OpenSaveFolder();
|
||||
void OpenWiki();
|
||||
void SetDefaultISO();
|
||||
void DeleteFile();
|
||||
void InstallWAD();
|
||||
void UninstallWAD();
|
||||
void ExportWiiSave();
|
||||
void CompressISO();
|
||||
|
||||
signals:
|
||||
void GameSelected();
|
||||
|
@ -4,10 +4,13 @@
|
||||
|
||||
#include <QAction>
|
||||
#include <QDesktopServices>
|
||||
#include <QFileDialog>
|
||||
#include <QMessageBox>
|
||||
#include <QUrl>
|
||||
|
||||
#include "Core/State.h"
|
||||
#include "DolphinQt2/AboutDialog.h"
|
||||
#include "DolphinQt2/GameList/GameFile.h"
|
||||
#include "DolphinQt2/MenuBar.h"
|
||||
#include "DolphinQt2/Settings.h"
|
||||
|
||||
@ -17,7 +20,7 @@ MenuBar::MenuBar(QWidget* parent) : QMenuBar(parent)
|
||||
AddEmulationMenu();
|
||||
addMenu(tr("Movie"));
|
||||
addMenu(tr("Options"));
|
||||
addMenu(tr("Tools"));
|
||||
AddToolsMenu();
|
||||
AddViewMenu();
|
||||
AddHelpMenu();
|
||||
|
||||
@ -71,6 +74,12 @@ void MenuBar::AddFileMenu()
|
||||
m_exit_action = file_menu->addAction(tr("Exit"), this, SIGNAL(Exit()));
|
||||
}
|
||||
|
||||
void MenuBar::AddToolsMenu()
|
||||
{
|
||||
QMenu* tools_menu = addMenu(tr("Tools"));
|
||||
m_wad_install_action = tools_menu->addAction(tr("Install WAD..."), this, SLOT(InstallWAD()));
|
||||
}
|
||||
|
||||
void MenuBar::AddEmulationMenu()
|
||||
{
|
||||
QMenu* emu_menu = addMenu(tr("Emulation"));
|
||||
@ -206,3 +215,27 @@ void MenuBar::AddTableColumnsMenu(QMenu* view_menu)
|
||||
action->setCheckable(true);
|
||||
}
|
||||
}
|
||||
|
||||
void MenuBar::InstallWAD()
|
||||
{
|
||||
QString wad_file = QFileDialog::getOpenFileName(this, tr("Select a title to install to NAND"),
|
||||
QString(), tr("WAD files (*.wad)"));
|
||||
|
||||
if (wad_file.isEmpty())
|
||||
return;
|
||||
|
||||
QMessageBox result_dialog(this);
|
||||
|
||||
if (GameFile(wad_file).Install())
|
||||
{
|
||||
result_dialog.setIcon(QMessageBox::Information);
|
||||
result_dialog.setText(tr("Successfully installed title to the NAND"));
|
||||
}
|
||||
else
|
||||
{
|
||||
result_dialog.setIcon(QMessageBox::Critical);
|
||||
result_dialog.setText(tr("Failed to install title to the NAND!"));
|
||||
}
|
||||
|
||||
result_dialog.exec();
|
||||
}
|
||||
|
@ -50,6 +50,9 @@ public slots:
|
||||
void EmulationStopped();
|
||||
void UpdateStateSlotMenu();
|
||||
|
||||
// Tools
|
||||
void InstallWAD();
|
||||
|
||||
private:
|
||||
void AddFileMenu();
|
||||
|
||||
@ -62,12 +65,16 @@ private:
|
||||
void AddGameListTypeSection(QMenu* view_menu);
|
||||
void AddTableColumnsMenu(QMenu* view_menu);
|
||||
|
||||
void AddToolsMenu();
|
||||
void AddHelpMenu();
|
||||
|
||||
// File
|
||||
QAction* m_open_action;
|
||||
QAction* m_exit_action;
|
||||
|
||||
// Tools
|
||||
QAction* m_wad_install_action;
|
||||
|
||||
// Emulation
|
||||
QAction* m_play_action;
|
||||
QAction* m_pause_action;
|
||||
|
Loading…
Reference in New Issue
Block a user