Merge pull request #7164 from Techjar/gamelist-multiselect
Qt/GameList: Reimplement multiselection functionality from WX
This commit is contained in:
commit
bd28bf6b1e
|
@ -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,11 +195,52 @@ void GameList::MakeGridView()
|
|||
|
||||
void GameList::ShowContextMenu(const QPoint&)
|
||||
{
|
||||
const auto game = GetSelectedGame();
|
||||
if (!game)
|
||||
if (!GetSelectedGame())
|
||||
return;
|
||||
|
||||
QMenu* menu = new QMenu(this);
|
||||
|
||||
if (HasMultipleSelected())
|
||||
{
|
||||
bool wii_saves = true;
|
||||
bool compress = false;
|
||||
bool decompress = false;
|
||||
|
||||
for (const auto& game : GetSelectedGames())
|
||||
{
|
||||
DiscIO::Platform platform = game->GetPlatform();
|
||||
|
||||
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 (platform != DiscIO::Platform::WiiWAD && platform != DiscIO::Platform::WiiDisc)
|
||||
wii_saves = false;
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
if (wii_saves)
|
||||
{
|
||||
AddAction(menu, tr("Export Wii saves (Experimental)"), this, &GameList::ExportWiiSave);
|
||||
menu->addSeparator();
|
||||
}
|
||||
|
||||
AddAction(menu, tr("Delete selected ISOs..."), this, &GameList::DeleteFile);
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto game = GetSelectedGame();
|
||||
DiscIO::Platform platform = game->GetPlatform();
|
||||
|
||||
if (platform != DiscIO::Platform::ELFOrDOL)
|
||||
|
@ -215,9 +257,9 @@ void GameList::ShowContextMenu(const QPoint&)
|
|||
const auto blob_type = game->GetBlobType();
|
||||
|
||||
if (blob_type == DiscIO::BlobType::GCZ)
|
||||
AddAction(menu, tr("Decompress ISO..."), this, &GameList::CompressISO);
|
||||
AddAction(menu, tr("Decompress ISO..."), this, [this] { CompressISO(true); });
|
||||
else if (blob_type == DiscIO::BlobType::PLAIN)
|
||||
AddAction(menu, tr("Compress ISO..."), this, &GameList::CompressISO);
|
||||
AddAction(menu, tr("Compress ISO..."), this, [this] { CompressISO(false); });
|
||||
|
||||
QAction* change_disc = AddAction(menu, tr("Change &Disc"), this, &GameList::ChangeDisc);
|
||||
|
||||
|
@ -252,7 +294,8 @@ void GameList::ShowContextMenu(const QPoint&)
|
|||
if (!Core::IsRunning())
|
||||
wad_uninstall_action->setEnabled(WiiUtils::IsTitleInstalled(game->GetTitleID()));
|
||||
|
||||
connect(&Settings::Instance(), &Settings::EmulationStateChanged, menu, [=](Core::State state) {
|
||||
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()));
|
||||
|
@ -273,8 +316,9 @@ void GameList::ShowContextMenu(const QPoint&)
|
|||
|
||||
QAction* netplay_host = new QAction(tr("Host with NetPlay"), menu);
|
||||
|
||||
connect(netplay_host, &QAction::triggered,
|
||||
[this, game] { emit NetPlayHost(QString::fromStdString(game->GetUniqueIdentifier())); });
|
||||
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);
|
||||
|
@ -282,6 +326,7 @@ void GameList::ShowContextMenu(const QPoint&)
|
|||
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();
|
||||
auto files = GetSelectedGames();
|
||||
|
||||
const bool compressed = (file->GetBlobType() == DiscIO::BlobType::GCZ);
|
||||
bool wii_warning_given = false;
|
||||
for (QMutableListIterator<std::shared_ptr<const UICommon::GameFile>> it(files); it.hasNext();)
|
||||
{
|
||||
auto file = it.next();
|
||||
|
||||
if (!compressed && file->GetPlatform() == DiscIO::Platform::WiiDisc)
|
||||
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;
|
||||
}
|
||||
|
||||
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 "
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
QString dst_path = QFileDialog::getSaveFileName(
|
||||
if (files.size() == 0)
|
||||
return; // We shouldn't get here normally...
|
||||
|
||||
QString dst_dir;
|
||||
QString dst_path;
|
||||
|
||||
if (files.size() > 1)
|
||||
{
|
||||
dst_dir = QFileDialog::getExistingDirectory(
|
||||
this,
|
||||
compressed ? tr("Select where you want to save the decompressed image") :
|
||||
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
|
||||
{
|
||||
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(QString::fromStdString(file->GetGameID()))
|
||||
.append(compressed ? QStringLiteral(".gcm") : QStringLiteral(".gcz")),
|
||||
compressed ? tr("Uncompressed GC/Wii images (*.iso *.gcm)") :
|
||||
.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 (dst_path.isEmpty())
|
||||
return;
|
||||
for (const auto& file : files)
|
||||
{
|
||||
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);
|
||||
|
||||
QProgressDialog progress_dialog(compressed ? tr("Decompressing...") : tr("Compressing..."),
|
||||
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 (compressed)
|
||||
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)
|
||||
{
|
||||
QMessageBox(QMessageBox::Information, tr("Success!"), tr("Successfully compressed image."),
|
||||
QMessageBox::Ok, this)
|
||||
.exec();
|
||||
}
|
||||
else
|
||||
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);
|
||||
|
@ -445,16 +568,18 @@ void GameList::DeleteFile()
|
|||
confirm_dialog.setStandardButtons(QMessageBox::Yes | QMessageBox::Cancel);
|
||||
|
||||
if (confirm_dialog.exec() == QMessageBox::Yes)
|
||||
{
|
||||
for (const auto& game : GetSelectedGames())
|
||||
{
|
||||
bool deletion_successful = false;
|
||||
|
||||
while (!deletion_successful)
|
||||
{
|
||||
deletion_successful = File::Delete(game);
|
||||
deletion_successful = File::Delete(game->GetFilePath());
|
||||
|
||||
if (deletion_successful)
|
||||
{
|
||||
m_model->RemoveGame(game);
|
||||
m_model->RemoveGame(game->GetFilePath());
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -470,6 +595,10 @@ void GameList::DeleteFile()
|
|||
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;
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
Loading…
Reference in New Issue