GameList: Fix duplicate selections with ctrl+a in grid view

Make grid view use selectedRow() instead of selectedIndexes() to ensure
one selection per game.
This commit is contained in:
Dentomologist 2021-10-19 14:39:32 -07:00
parent 13985b774e
commit 1e4b2daedb
2 changed files with 34 additions and 27 deletions

View File

@ -286,6 +286,16 @@ void GameList::MakeGridView()
m_grid = new QListView(this); m_grid = new QListView(this);
m_grid->setModel(m_grid_proxy); m_grid->setModel(m_grid_proxy);
m_grid->setSelectionMode(QAbstractItemView::ExtendedSelection); m_grid->setSelectionMode(QAbstractItemView::ExtendedSelection);
// Row in this context refers to the full set of columns (banner, title, region, etc.) associated
// with a single game rather than multiple games presented visually on the same row. Even though
// most of these elements are hidden in grid view selecting all of them allows us to use
// selectedRow() which only returns rows where all elements are selected. In addition to improving
// consistency with list view this avoids an edge case where clicking a game in grid mode selected
// only the first element of the row but ctrl+a selected every element of the row, making a bunch
// of duplicate selections for each game.
m_grid->setSelectionBehavior(QAbstractItemView::SelectRows);
m_grid->setViewMode(QListView::IconMode); m_grid->setViewMode(QListView::IconMode);
m_grid->setResizeMode(QListView::Adjust); m_grid->setResizeMode(QListView::Adjust);
m_grid->setUniformItemSizes(true); m_grid->setUniformItemSizes(true);
@ -790,23 +800,30 @@ void GameList::ChangeDisc()
Core::RunAsCPUThread([file_path = game->GetFilePath()] { DVDInterface::ChangeDisc(file_path); }); Core::RunAsCPUThread([file_path = game->GetFilePath()] { DVDInterface::ChangeDisc(file_path); });
} }
std::shared_ptr<const UICommon::GameFile> GameList::GetSelectedGame() const QAbstractItemView* GameList::GetActiveView() const
{ {
QAbstractItemView* view;
QSortFilterProxyModel* proxy;
if (currentWidget() == m_list) if (currentWidget() == m_list)
{ {
view = m_list; return m_list;
proxy = m_list_proxy;
} }
else return m_grid;
}
QSortFilterProxyModel* GameList::GetActiveProxyModel() const
{
if (currentWidget() == m_list)
{ {
view = m_grid; return m_list_proxy;
proxy = m_grid_proxy;
} }
QItemSelectionModel* sel_model = view->selectionModel(); return m_grid_proxy;
}
std::shared_ptr<const UICommon::GameFile> GameList::GetSelectedGame() const
{
QItemSelectionModel* const sel_model = GetActiveView()->selectionModel();
if (sel_model->hasSelection()) if (sel_model->hasSelection())
{ {
QSortFilterProxyModel* const proxy = GetActiveProxyModel();
QModelIndex model_index = proxy->mapToSource(sel_model->selectedIndexes()[0]); QModelIndex model_index = proxy->mapToSource(sel_model->selectedIndexes()[0]);
return m_model.GetGameFile(model_index.row()); return m_model.GetGameFile(model_index.row());
} }
@ -815,27 +832,15 @@ std::shared_ptr<const UICommon::GameFile> GameList::GetSelectedGame() const
QList<std::shared_ptr<const UICommon::GameFile>> GameList::GetSelectedGames() const 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; QList<std::shared_ptr<const UICommon::GameFile>> selected_list;
QItemSelectionModel* sel_model = view->selectionModel(); QItemSelectionModel* const sel_model = GetActiveView()->selectionModel();
if (sel_model->hasSelection()) if (sel_model->hasSelection())
{ {
QModelIndexList index_list = const QModelIndexList index_list = sel_model->selectedRows();
currentWidget() == m_list ? sel_model->selectedRows() : sel_model->selectedIndexes();
for (const auto& index : index_list) for (const auto& index : index_list)
{ {
QModelIndex model_index = proxy->mapToSource(index); const QModelIndex model_index = GetActiveProxyModel()->mapToSource(index);
selected_list.push_back(m_model.GetGameFile(model_index.row())); selected_list.push_back(m_model.GetGameFile(model_index.row()));
} }
} }
@ -844,8 +849,7 @@ QList<std::shared_ptr<const UICommon::GameFile>> GameList::GetSelectedGames() co
bool GameList::HasMultipleSelected() const bool GameList::HasMultipleSelected() const
{ {
return currentWidget() == m_list ? m_list->selectionModel()->selectedRows().size() > 1 : return GetActiveView()->selectionModel()->selectedRows().size() > 1;
m_grid->selectionModel()->selectedIndexes().size() > 1;
} }
std::shared_ptr<const UICommon::GameFile> GameList::FindGame(const std::string& path) const std::shared_ptr<const UICommon::GameFile> GameList::FindGame(const std::string& path) const

View File

@ -9,6 +9,7 @@
#include "DolphinQt/GameList/GameListModel.h" #include "DolphinQt/GameList/GameListModel.h"
class QAbstractItemView;
class QLabel; class QLabel;
class QListView; class QListView;
class QSortFilterProxyModel; class QSortFilterProxyModel;
@ -87,6 +88,8 @@ private:
void MakeEmptyView(); void MakeEmptyView();
// We only have two views, just use a bool to distinguish. // We only have two views, just use a bool to distinguish.
void SetPreferredView(bool list); void SetPreferredView(bool list);
QAbstractItemView* GetActiveView() const;
QSortFilterProxyModel* GetActiveProxyModel() const;
void ConsiderViewChange(); void ConsiderViewChange();
void UpdateFont(); void UpdateFont();