summaryrefslogtreecommitdiff
path: root/Source/Core
diff options
context:
space:
mode:
authorspycrab <spycrab@users.noreply.github.com>2018-06-29 11:14:28 +0200
committerGitHub <noreply@github.com>2018-06-29 11:14:28 +0200
commitbd28bf6b1e44463465da58268d2ca32bf3fe74ac (patch)
tree8c149cb24ca06050e9ffe9dde2d474fc6c481f6d /Source/Core
parenta595ac6b27d01eef0cad2c7981d9206c29890d6b (diff)
parent9a26cc18c90eef3830b830e8a8f66d4ffe9989b7 (diff)
Merge pull request #7164 from Techjar/gamelist-multiselect
Qt/GameList: Reimplement multiselection functionality from WX
Diffstat (limited to 'Source/Core')
-rw-r--r--Source/Core/DolphinQt2/GameList/GameList.cpp430
-rw-r--r--Source/Core/DolphinQt2/GameList/GameList.h4
2 files changed, 300 insertions, 134 deletions
diff --git a/Source/Core/DolphinQt2/GameList/GameList.cpp b/Source/Core/DolphinQt2/GameList/GameList.cpp
index 39d9ce053a..18e999079c 100644
--- a/Source/Core/DolphinQt2/GameList/GameList.cpp
+++ b/Source/Core/DolphinQt2/GameList/GameList.cpp
@@ -75,7 +75,7 @@ void GameList::MakeListView()
m_list = new QTableView(this);
m_list->setModel(m_list_proxy);
- m_list->setSelectionMode(QAbstractItemView::SingleSelection);
+ m_list->setSelectionMode(QAbstractItemView::ExtendedSelection);
m_list->setSelectionBehavior(QAbstractItemView::SelectRows);
m_list->setAlternatingRowColors(true);
m_list->setShowGrid(false);
@@ -180,6 +180,7 @@ void GameList::MakeGridView()
{
m_grid = new QListView(this);
m_grid->setModel(m_grid_proxy);
+ m_grid->setSelectionMode(QAbstractItemView::ExtendedSelection);
m_grid->setViewMode(QListView::IconMode);
m_grid->setResizeMode(QListView::Adjust);
m_grid->setUniformItemSizes(true);
@@ -194,94 +195,138 @@ void GameList::MakeGridView()
void GameList::ShowContextMenu(const QPoint&)
{
- const auto game = GetSelectedGame();
- if (!game)
+ if (!GetSelectedGame())
return;
QMenu* menu = new QMenu(this);
- DiscIO::Platform platform = game->GetPlatform();
- if (platform != DiscIO::Platform::ELFOrDOL)
+ if (HasMultipleSelected())
{
- AddAction(menu, tr("&Properties"), this, &GameList::OpenProperties);
- AddAction(menu, tr("&Wiki"), this, &GameList::OpenWiki);
+ bool wii_saves = true;
+ bool compress = false;
+ bool decompress = false;
- menu->addSeparator();
- }
+ for (const auto& game : GetSelectedGames())
+ {
+ DiscIO::Platform platform = game->GetPlatform();
- if (platform == DiscIO::Platform::GameCubeDisc || platform == DiscIO::Platform::WiiDisc)
- {
- AddAction(menu, tr("Set as &default ISO"), this, &GameList::SetDefaultISO);
- const auto blob_type = game->GetBlobType();
+ if (platform == DiscIO::Platform::GameCubeDisc || platform == DiscIO::Platform::WiiDisc)
+ {
+ const auto blob_type = game->GetBlobType();
+ if (blob_type == DiscIO::BlobType::GCZ)
+ decompress = true;
+ else if (blob_type == DiscIO::BlobType::PLAIN)
+ compress = true;
+ }
- if (blob_type == DiscIO::BlobType::GCZ)
- AddAction(menu, tr("Decompress ISO..."), this, &GameList::CompressISO);
- else if (blob_type == DiscIO::BlobType::PLAIN)
- AddAction(menu, tr("Compress ISO..."), this, &GameList::CompressISO);
+ if (platform != DiscIO::Platform::WiiWAD && platform != DiscIO::Platform::WiiDisc)
+ wii_saves = false;
+ }
- QAction* change_disc = AddAction(menu, tr("Change &Disc"), this, &GameList::ChangeDisc);
+ if (compress)
+ AddAction(menu, tr("Compress selected ISOs..."), this, [this] { CompressISO(false); });
+ if (decompress)
+ AddAction(menu, tr("Decompress selected ISOs..."), this, [this] { CompressISO(true); });
+ if (compress || decompress)
+ menu->addSeparator();
- connect(&Settings::Instance(), &Settings::EmulationStateChanged, change_disc,
- [change_disc] { change_disc->setEnabled(Core::IsRunning()); });
- change_disc->setEnabled(Core::IsRunning());
+ if (wii_saves)
+ {
+ AddAction(menu, tr("Export Wii saves (Experimental)"), this, &GameList::ExportWiiSave);
+ menu->addSeparator();
+ }
- menu->addSeparator();
+ AddAction(menu, tr("Delete selected ISOs..."), this, &GameList::DeleteFile);
}
-
- if (platform == DiscIO::Platform::WiiDisc)
+ else
{
- auto* perform_disc_update = AddAction(menu, tr("Perform System Update"), this, [this] {
- WiiUpdate::PerformDiscUpdate(GetSelectedGame()->GetFilePath(), this);
- });
- perform_disc_update->setEnabled(!Core::IsRunning() || !SConfig::GetInstance().bWii);
- }
+ const auto game = GetSelectedGame();
+ DiscIO::Platform platform = game->GetPlatform();
- if (platform == DiscIO::Platform::WiiWAD)
- {
- QAction* wad_install_action = new QAction(tr("Install to the NAND"), menu);
- QAction* wad_uninstall_action = new QAction(tr("Uninstall from the NAND"), menu);
+ if (platform != DiscIO::Platform::ELFOrDOL)
+ {
+ AddAction(menu, tr("&Properties"), this, &GameList::OpenProperties);
+ AddAction(menu, tr("&Wiki"), this, &GameList::OpenWiki);
- connect(wad_install_action, &QAction::triggered, this, &GameList::InstallWAD);
- connect(wad_uninstall_action, &QAction::triggered, this, &GameList::UninstallWAD);
+ menu->addSeparator();
+ }
- for (QAction* a : {wad_install_action, wad_uninstall_action})
+ if (platform == DiscIO::Platform::GameCubeDisc || platform == DiscIO::Platform::WiiDisc)
{
- a->setEnabled(!Core::IsRunning());
- menu->addAction(a);
+ AddAction(menu, tr("Set as &default ISO"), this, &GameList::SetDefaultISO);
+ const auto blob_type = game->GetBlobType();
+
+ if (blob_type == DiscIO::BlobType::GCZ)
+ AddAction(menu, tr("Decompress ISO..."), this, [this] { CompressISO(true); });
+ else if (blob_type == DiscIO::BlobType::PLAIN)
+ AddAction(menu, tr("Compress ISO..."), this, [this] { CompressISO(false); });
+
+ QAction* change_disc = AddAction(menu, tr("Change &Disc"), this, &GameList::ChangeDisc);
+
+ connect(&Settings::Instance(), &Settings::EmulationStateChanged, change_disc,
+ [change_disc] { change_disc->setEnabled(Core::IsRunning()); });
+ change_disc->setEnabled(Core::IsRunning());
+
+ menu->addSeparator();
}
- if (!Core::IsRunning())
- wad_uninstall_action->setEnabled(WiiUtils::IsTitleInstalled(game->GetTitleID()));
- connect(&Settings::Instance(), &Settings::EmulationStateChanged, menu, [=](Core::State state) {
- wad_install_action->setEnabled(state == Core::State::Uninitialized);
- wad_uninstall_action->setEnabled(state == Core::State::Uninitialized &&
- WiiUtils::IsTitleInstalled(game->GetTitleID()));
- });
+ if (platform == DiscIO::Platform::WiiDisc)
+ {
+ auto* perform_disc_update = AddAction(menu, tr("Perform System Update"), this, [this] {
+ WiiUpdate::PerformDiscUpdate(GetSelectedGame()->GetFilePath(), this);
+ });
+ perform_disc_update->setEnabled(!Core::IsRunning() || !SConfig::GetInstance().bWii);
+ }
- menu->addSeparator();
- }
+ if (platform == DiscIO::Platform::WiiWAD)
+ {
+ QAction* wad_install_action = new QAction(tr("Install to the NAND"), menu);
+ QAction* wad_uninstall_action = new QAction(tr("Uninstall from the NAND"), menu);
- if (platform == DiscIO::Platform::WiiWAD || platform == DiscIO::Platform::WiiDisc)
- {
- AddAction(menu, tr("Open Wii &save folder"), this, &GameList::OpenSaveFolder);
- AddAction(menu, tr("Export Wii save (Experimental)"), this, &GameList::ExportWiiSave);
- menu->addSeparator();
- }
+ connect(wad_install_action, &QAction::triggered, this, &GameList::InstallWAD);
+ connect(wad_uninstall_action, &QAction::triggered, this, &GameList::UninstallWAD);
+
+ for (QAction* a : {wad_install_action, wad_uninstall_action})
+ {
+ a->setEnabled(!Core::IsRunning());
+ menu->addAction(a);
+ }
+ if (!Core::IsRunning())
+ wad_uninstall_action->setEnabled(WiiUtils::IsTitleInstalled(game->GetTitleID()));
- AddAction(menu, tr("Open &containing folder"), this, &GameList::OpenContainingFolder);
- AddAction(menu, tr("Delete File..."), this, &GameList::DeleteFile);
+ connect(&Settings::Instance(), &Settings::EmulationStateChanged, menu,
+ [=](Core::State state) {
+ wad_install_action->setEnabled(state == Core::State::Uninitialized);
+ wad_uninstall_action->setEnabled(state == Core::State::Uninitialized &&
+ WiiUtils::IsTitleInstalled(game->GetTitleID()));
+ });
- QAction* netplay_host = new QAction(tr("Host with NetPlay"), menu);
+ menu->addSeparator();
+ }
- connect(netplay_host, &QAction::triggered,
- [this, game] { emit NetPlayHost(QString::fromStdString(game->GetUniqueIdentifier())); });
+ if (platform == DiscIO::Platform::WiiWAD || platform == DiscIO::Platform::WiiDisc)
+ {
+ AddAction(menu, tr("Open Wii &save folder"), this, &GameList::OpenSaveFolder);
+ AddAction(menu, tr("Export Wii save (Experimental)"), this, &GameList::ExportWiiSave);
+ menu->addSeparator();
+ }
- connect(&Settings::Instance(), &Settings::EmulationStateChanged, menu, [=](Core::State state) {
- netplay_host->setEnabled(state == Core::State::Uninitialized);
- });
- netplay_host->setEnabled(!Core::IsRunning());
+ AddAction(menu, tr("Open &containing folder"), this, &GameList::OpenContainingFolder);
+ AddAction(menu, tr("Delete File..."), this, &GameList::DeleteFile);
+
+ QAction* netplay_host = new QAction(tr("Host with NetPlay"), menu);
- menu->addAction(netplay_host);
+ connect(netplay_host, &QAction::triggered, [this, game] {
+ emit NetPlayHost(QString::fromStdString(game->GetUniqueIdentifier()));
+ });
+
+ connect(&Settings::Instance(), &Settings::EmulationStateChanged, menu, [=](Core::State state) {
+ netplay_host->setEnabled(state == Core::State::Uninitialized);
+ });
+ netplay_host->setEnabled(!Core::IsRunning());
+
+ menu->addAction(netplay_host);
+ }
menu->exec(QCursor::pos());
}
@@ -303,10 +348,25 @@ void GameList::ExportWiiSave()
if (export_dir.isEmpty())
return;
- if (WiiSave::Export(GetSelectedGame()->GetTitleID(), export_dir.toStdString()))
- QMessageBox::information(this, tr("Save Export"), tr("Successfully exported save files"));
+ QList<std::string> failed;
+ for (const auto& game : GetSelectedGames())
+ {
+ if (!WiiSave::Export(game->GetTitleID(), export_dir.toStdString()))
+ failed.push_back(game->GetName());
+ }
+
+ if (!failed.isEmpty())
+ {
+ QString failed_str;
+ for (const std::string& str : failed)
+ failed_str.append(QStringLiteral("\n")).append(QString::fromStdString(str));
+ QMessageBox::critical(this, tr("Save Export"),
+ tr("Failed to export the following save files:") + failed_str);
+ }
else
- QMessageBox::critical(this, tr("Save Export"), tr("Failed to export save files."));
+ {
+ QMessageBox::information(this, tr("Save Export"), tr("Successfully exported save files"));
+ }
}
void GameList::OpenWiki()
@@ -316,69 +376,133 @@ void GameList::OpenWiki()
QDesktopServices::openUrl(QUrl(url));
}
-void GameList::CompressISO()
+void GameList::CompressISO(bool decompress)
{
- auto file = GetSelectedGame();
- const auto original_path = file->GetFilePath();
-
- const bool compressed = (file->GetBlobType() == DiscIO::BlobType::GCZ);
+ auto files = GetSelectedGames();
- if (!compressed && file->GetPlatform() == DiscIO::Platform::WiiDisc)
+ bool wii_warning_given = false;
+ for (QMutableListIterator<std::shared_ptr<const UICommon::GameFile>> it(files); it.hasNext();)
{
- 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. Continue?"));
- wii_warning.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
-
- if (wii_warning.exec() == QMessageBox::No)
- return;
- }
+ auto file = it.next();
- 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(QString::fromStdString(GetSelectedGame()->GetFilePath()))
- .dir()
- .absoluteFilePath(QString::fromStdString(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;
+ if ((file->GetPlatform() != DiscIO::Platform::GameCubeDisc &&
+ file->GetPlatform() != DiscIO::Platform::WiiDisc) ||
+ (decompress && file->GetBlobType() != DiscIO::BlobType::GCZ) ||
+ (!decompress && file->GetBlobType() != DiscIO::BlobType::PLAIN))
+ {
+ it.remove();
+ continue;
+ }
- QProgressDialog progress_dialog(compressed ? tr("Decompressing...") : tr("Compressing..."),
- tr("Abort"), 0, 100, this);
- progress_dialog.setWindowModality(Qt::WindowModal);
+ if (!wii_warning_given && !decompress && file->GetPlatform() == DiscIO::Platform::WiiDisc)
+ {
+ 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. Continue?"));
+ wii_warning.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
+
+ if (wii_warning.exec() == QMessageBox::No)
+ return;
+
+ wii_warning_given = true;
+ }
+ }
- bool good;
+ if (files.size() == 0)
+ return; // We shouldn't get here normally...
- if (compressed)
+ QString dst_dir;
+ QString dst_path;
+
+ if (files.size() > 1)
{
- good = DiscIO::DecompressBlobToFile(original_path, dst_path.toStdString(), &CompressCB,
- &progress_dialog);
+ dst_dir = QFileDialog::getExistingDirectory(
+ this,
+ decompress ? tr("Select where you want to save the decompressed images") :
+ tr("Select where you want to save the compressed images"),
+ QFileInfo(QString::fromStdString(GetSelectedGame()->GetFilePath())).dir().absolutePath());
+
+ if (dst_dir.isEmpty())
+ return;
}
else
{
- good = DiscIO::CompressFileToBlob(original_path, dst_path.toStdString(),
- file->GetPlatform() == DiscIO::Platform::WiiDisc ? 1 : 0,
- 16384, &CompressCB, &progress_dialog);
+ dst_path = QFileDialog::getSaveFileName(
+ this,
+ decompress ? tr("Select where you want to save the decompressed image") :
+ tr("Select where you want to save the compressed image"),
+ QFileInfo(QString::fromStdString(GetSelectedGame()->GetFilePath()))
+ .dir()
+ .absoluteFilePath(
+ QFileInfo(QString::fromStdString(files[0]->GetFilePath())).completeBaseName())
+ .append(decompress ? QStringLiteral(".gcm") : QStringLiteral(".gcz")),
+ decompress ? tr("Uncompressed GC/Wii images (*.iso *.gcm)") :
+ tr("Compressed GC/Wii images (*.gcz)"));
}
- if (good)
+ for (const auto& file : files)
{
- 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."));
+ const auto original_path = file->GetFilePath();
+ if (files.size() > 1)
+ {
+ dst_path =
+ QDir(dst_dir)
+ .absoluteFilePath(QFileInfo(QString::fromStdString(original_path)).completeBaseName())
+ .append(decompress ? QStringLiteral(".gcm") : QStringLiteral(".gcz"));
+ QFileInfo dst_info = QFileInfo(dst_path);
+ if (dst_info.exists())
+ {
+ QMessageBox confirm_replace(this);
+ confirm_replace.setIcon(QMessageBox::Warning);
+ confirm_replace.setText(tr("The file %1 already exists.\n"
+ "Do you wish to replace it?")
+ .arg(dst_info.fileName()));
+ confirm_replace.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
+
+ if (confirm_replace.exec() == QMessageBox::No)
+ continue;
+ }
+ }
+
+ QProgressDialog progress_dialog(decompress ? tr("Decompressing...") : tr("Compressing..."),
+ tr("Abort"), 0, 100, this);
+ progress_dialog.setWindowModality(Qt::WindowModal);
+
+ bool good;
+
+ if (decompress)
+ {
+ if (files.size() > 1)
+ progress_dialog.setLabelText(tr("Decompressing...") + QStringLiteral("\n") +
+ QFileInfo(QString::fromStdString(original_path)).fileName());
+ good = DiscIO::DecompressBlobToFile(original_path, dst_path.toStdString(), &CompressCB,
+ &progress_dialog);
+ }
+ else
+ {
+ if (files.size() > 1)
+ progress_dialog.setLabelText(tr("Compressing...") + QStringLiteral("\n") +
+ QFileInfo(QString::fromStdString(original_path)).fileName());
+ good = DiscIO::CompressFileToBlob(original_path, dst_path.toStdString(),
+ file->GetPlatform() == DiscIO::Platform::WiiDisc ? 1 : 0,
+ 16384, &CompressCB, &progress_dialog);
+ }
+
+ if (!good)
+ {
+ QErrorMessage(this).showMessage(tr("Dolphin failed to complete the requested action."));
+ return;
+ }
}
+
+ QMessageBox(QMessageBox::Information, tr("Success!"),
+ decompress ? tr("Successfully decompressed %n image(s).", "", files.size()) :
+ tr("Successfully compressed %n image(s).", "", files.size()),
+ QMessageBox::Ok, this)
+ .exec();
}
void GameList::InstallWAD()
@@ -435,7 +559,6 @@ void GameList::OpenSaveFolder()
void GameList::DeleteFile()
{
- const std::string game = GetSelectedGame()->GetFilePath();
QMessageBox confirm_dialog(this);
confirm_dialog.setIcon(QMessageBox::Warning);
@@ -446,29 +569,35 @@ void GameList::DeleteFile()
if (confirm_dialog.exec() == QMessageBox::Yes)
{
- bool deletion_successful = false;
-
- while (!deletion_successful)
+ for (const auto& game : GetSelectedGames())
{
- deletion_successful = File::Delete(game);
+ bool deletion_successful = false;
- if (deletion_successful)
+ while (!deletion_successful)
{
- m_model->RemoveGame(game);
+ deletion_successful = File::Delete(game->GetFilePath());
+
+ if (deletion_successful)
+ {
+ m_model->RemoveGame(game->GetFilePath());
+ }
+ 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;
+ }
}
- 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;
- }
+ if (!deletion_successful)
+ break; // Something is wrong, so we should abort the whole thing
}
}
}
@@ -501,6 +630,41 @@ std::shared_ptr<const UICommon::GameFile> GameList::GetSelectedGame() const
return {};
}
+QList<std::shared_ptr<const UICommon::GameFile>> GameList::GetSelectedGames() const
+{
+ QAbstractItemView* view;
+ QSortFilterProxyModel* proxy;
+ if (currentWidget() == m_list)
+ {
+ view = m_list;
+ proxy = m_list_proxy;
+ }
+ else
+ {
+ view = m_grid;
+ proxy = m_grid_proxy;
+ }
+ QList<std::shared_ptr<const UICommon::GameFile>> selected_list;
+ QItemSelectionModel* sel_model = view->selectionModel();
+ if (sel_model->hasSelection())
+ {
+ QModelIndexList index_list =
+ currentWidget() == m_list ? sel_model->selectedRows() : sel_model->selectedIndexes();
+ for (const auto& index : index_list)
+ {
+ QModelIndex model_index = proxy->mapToSource(index);
+ selected_list.push_back(m_model->GetGameFile(model_index.row()));
+ }
+ }
+ return selected_list;
+}
+
+bool GameList::HasMultipleSelected() const
+{
+ return currentWidget() == m_list ? m_list->selectionModel()->selectedRows().size() > 1 :
+ m_grid->selectionModel()->selectedIndexes().size() > 1;
+}
+
void GameList::SetPreferredView(bool list)
{
m_prefer_list = list;
diff --git a/Source/Core/DolphinQt2/GameList/GameList.h b/Source/Core/DolphinQt2/GameList/GameList.h
index de66469f98..9758a05c30 100644
--- a/Source/Core/DolphinQt2/GameList/GameList.h
+++ b/Source/Core/DolphinQt2/GameList/GameList.h
@@ -25,6 +25,8 @@ public:
~GameList();
std::shared_ptr<const UICommon::GameFile> GetSelectedGame() const;
+ QList<std::shared_ptr<const UICommon::GameFile>> GetSelectedGames() const;
+ bool HasMultipleSelected() const;
void SetListView() { SetPreferredView(true); }
void SetGridView() { SetPreferredView(false); }
@@ -53,7 +55,7 @@ private:
void InstallWAD();
void UninstallWAD();
void ExportWiiSave();
- void CompressISO();
+ void CompressISO(bool decompress);
void ChangeDisc();
void UpdateColumnVisibility();