Merge pull request #3294 from spxtr/DQt2-GameProxyModel

DolphinQt2: Use a proxy model for the GameList
This commit is contained in:
Scott Mansell 2015-11-30 07:48:54 +13:00
commit 97231aa221
7 changed files with 153 additions and 89 deletions

View File

@ -13,6 +13,7 @@ set(SRCS
GameList/GameList.cpp GameList/GameList.cpp
GameList/GameTracker.cpp GameList/GameTracker.cpp
GameList/GameListModel.cpp GameList/GameListModel.cpp
GameList/GameListProxyModel.cpp
) )
list(APPEND LIBS core uicommon) list(APPEND LIBS core uicommon)

View File

@ -6,12 +6,14 @@
#include "Core/ConfigManager.h" #include "Core/ConfigManager.h"
#include "DolphinQt2/GameList/GameList.h" #include "DolphinQt2/GameList/GameList.h"
#include "DolphinQt2/GameList/GameListProxyModel.h"
GameList::GameList(QWidget* parent): QStackedWidget(parent) GameList::GameList(QWidget* parent): QStackedWidget(parent)
{ {
m_model = new GameListModel(this); m_model = new GameListModel(this);
m_proxy = new QSortFilterProxyModel(this); m_proxy = new GameListProxyModel(this);
m_proxy->setSourceModel(m_model); m_proxy->setSourceModel(m_model);
m_proxy->setSortCaseSensitivity(Qt::CaseInsensitive);
MakeTableView(); MakeTableView();
MakeListView(); MakeListView();
@ -36,31 +38,25 @@ void GameList::MakeTableView()
m_table->setSortingEnabled(true); m_table->setSortingEnabled(true);
m_table->setCurrentIndex(QModelIndex()); m_table->setCurrentIndex(QModelIndex());
// These fixed column widths make it so that the DisplayRole is cut // FIXME These icon image are overly wide and should be cut down to size,
// off, which lets us see the icon but sort by the actual value. // then we can remove these lines.
// It's a bit of a hack. To do it right we need to subclass
// QSortFilterProxyModel and not show those items.
m_table->setColumnWidth(GameListModel::COL_PLATFORM, 52); m_table->setColumnWidth(GameListModel::COL_PLATFORM, 52);
m_table->setColumnWidth(GameListModel::COL_COUNTRY, 38); m_table->setColumnWidth(GameListModel::COL_COUNTRY, 38);
m_table->setColumnWidth(GameListModel::COL_RATING, 52); m_table->setColumnWidth(GameListModel::COL_RATING, 52);
// This column is for the icon view. Hide it.
m_table->setColumnHidden(GameListModel::COL_LARGE_ICON, true); m_table->setColumnHidden(GameListModel::COL_LARGE_ICON, true);
m_table->horizontalHeader()->setSectionResizeMode( QHeaderView* header = m_table->horizontalHeader();
GameListModel::COL_PLATFORM, QHeaderView::Fixed); header->setSectionResizeMode(GameListModel::COL_PLATFORM, QHeaderView::Fixed);
m_table->horizontalHeader()->setSectionResizeMode( header->setSectionResizeMode(GameListModel::COL_COUNTRY, QHeaderView::Fixed);
GameListModel::COL_COUNTRY, QHeaderView::Fixed); header->setSectionResizeMode(GameListModel::COL_ID, QHeaderView::ResizeToContents);
m_table->horizontalHeader()->setSectionResizeMode( header->setSectionResizeMode(GameListModel::COL_BANNER, QHeaderView::ResizeToContents);
GameListModel::COL_ID, QHeaderView::ResizeToContents); header->setSectionResizeMode(GameListModel::COL_TITLE, QHeaderView::Stretch);
m_table->horizontalHeader()->setSectionResizeMode( header->setSectionResizeMode(GameListModel::COL_MAKER, QHeaderView::Stretch);
GameListModel::COL_TITLE, QHeaderView::Stretch); header->setSectionResizeMode(GameListModel::COL_SIZE, QHeaderView::ResizeToContents);
m_table->horizontalHeader()->setSectionResizeMode( header->setSectionResizeMode(GameListModel::COL_DESCRIPTION, QHeaderView::Stretch);
GameListModel::COL_MAKER, QHeaderView::ResizeToContents); header->setSectionResizeMode(GameListModel::COL_RATING, QHeaderView::Fixed);
m_table->horizontalHeader()->setSectionResizeMode(
GameListModel::COL_SIZE, QHeaderView::ResizeToContents);
m_table->horizontalHeader()->setSectionResizeMode(
GameListModel::COL_DESCRIPTION, QHeaderView::Stretch);
m_table->horizontalHeader()->setSectionResizeMode(
GameListModel::COL_RATING, QHeaderView::Fixed);
} }
void GameList::MakeListView() void GameList::MakeListView()

View File

@ -5,25 +5,6 @@
#include "DolphinQt2/Resources.h" #include "DolphinQt2/Resources.h"
#include "DolphinQt2/GameList/GameListModel.h" #include "DolphinQt2/GameList/GameListModel.h"
static QString FormatSize(qint64 size)
{
QStringList units{
QStringLiteral("KB"),
QStringLiteral("MB"),
QStringLiteral("GB"),
QStringLiteral("TB")
};
QStringListIterator i(units);
QString unit = QStringLiteral("B");
double num = (double) size;
while (num > 1024.0 && i.hasNext())
{
unit = i.next();
num /= 1024.0;
}
return QStringLiteral("%1 %2").arg(QString::number(num, 'f', 1)).arg(unit);
}
GameListModel::GameListModel(QObject* parent) GameListModel::GameListModel(QObject* parent)
: QAbstractTableModel(parent) : QAbstractTableModel(parent)
{ {
@ -38,45 +19,21 @@ QVariant GameListModel::data(const QModelIndex& index, int role) const
return QVariant(); return QVariant();
QSharedPointer<GameFile> game = m_games[index.row()]; QSharedPointer<GameFile> game = m_games[index.row()];
if (index.column() == COL_PLATFORM && role == Qt::DecorationRole) if (role == Qt::DisplayRole)
return QVariant(Resources::GetPlatform(game->GetPlatform())); {
else if (index.column() == COL_PLATFORM && role == Qt::DisplayRole) switch (index.column())
return QVariant(game->GetPlatform()); {
case COL_PLATFORM: return game->GetPlatform();
else if (index.column() == COL_TITLE && role == Qt::DecorationRole) case COL_BANNER: return game->GetBanner();
return QVariant(game->GetBanner()); case COL_TITLE: return game->GetLongName();
else if (index.column() == COL_TITLE && role == Qt::DisplayRole) case COL_ID: return game->GetUniqueID();
return QVariant(game->GetLongName()); case COL_DESCRIPTION: return game->GetDescription();
case COL_MAKER: return game->GetCompany();
else if (index.column() == COL_ID && role == Qt::DisplayRole) case COL_SIZE: return game->GetFileSize();
return QVariant(game->GetUniqueID()); case COL_COUNTRY: return game->GetCountry();
case COL_RATING: return game->GetRating();
else if (index.column() == COL_DESCRIPTION && role == Qt::DisplayRole) }
return QVariant(game->GetDescription()); }
else if (index.column() == COL_MAKER && role == Qt::DisplayRole)
return QVariant(game->GetCompany());
// FIXME this sorts lexicographically, not by size.
else if (index.column() == COL_SIZE && role == Qt::DisplayRole)
return QVariant(FormatSize(game->GetFileSize()));
else if (index.column() == COL_COUNTRY && role == Qt::DecorationRole)
return QVariant(Resources::GetCountry(game->GetCountry()));
else if (index.column() == COL_COUNTRY && role == Qt::DisplayRole)
return QVariant(game->GetCountry());
else if (index.column() == COL_RATING && role == Qt::DecorationRole)
return QVariant(Resources::GetRating(game->GetRating()));
else if (index.column() == COL_RATING && role == Qt::DisplayRole)
return QVariant(game->GetRating());
else if (index.column() == COL_LARGE_ICON && role == Qt::DecorationRole)
return QVariant(game->GetBanner().scaled(144, 48));
else if (index.column() == COL_LARGE_ICON && role == Qt::DisplayRole)
return QVariant(game->GetLongName());
else
return QVariant(); return QVariant();
} }
@ -87,14 +44,15 @@ QVariant GameListModel::headerData(int section, Qt::Orientation orientation, int
switch (section) switch (section)
{ {
case COL_TITLE: return QVariant(tr("Title")); case COL_TITLE: return tr("Title");
case COL_ID: return QVariant(tr("ID")); case COL_ID: return tr("ID");
case COL_DESCRIPTION: return QVariant(tr("Description")); case COL_BANNER: return tr("Banner");
case COL_MAKER: return QVariant(tr("Maker")); case COL_DESCRIPTION: return tr("Description");
case COL_SIZE: return QVariant(tr("Size")); case COL_MAKER: return tr("Maker");
case COL_RATING: return QVariant(tr("Quality")); case COL_SIZE: return tr("Size");
default: return QVariant(); case COL_RATING: return tr("Quality");
} }
return QVariant();
} }
int GameListModel::rowCount(const QModelIndex& parent) const int GameListModel::rowCount(const QModelIndex& parent) const

View File

@ -30,6 +30,7 @@ public:
{ {
COL_PLATFORM = 0, COL_PLATFORM = 0,
COL_ID, COL_ID,
COL_BANNER,
COL_TITLE, COL_TITLE,
COL_DESCRIPTION, COL_DESCRIPTION,
COL_MAKER, COL_MAKER,

View File

@ -0,0 +1,87 @@
// Copyright 2015 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include "DolphinQt2/Resources.h"
#include "DolphinQt2/GameList/GameListModel.h"
#include "DolphinQt2/GameList/GameListProxyModel.h"
static constexpr QSize NORMAL_BANNER_SIZE(96, 32);
static constexpr QSize LARGE_BANNER_SIZE(144, 48);
// Convert an integer size to a friendly string representation.
static QString FormatSize(qint64 size)
{
QStringList units{
QStringLiteral("KB"),
QStringLiteral("MB"),
QStringLiteral("GB"),
QStringLiteral("TB")
};
QStringListIterator i(units);
QString unit = QStringLiteral("B");
double num = (double) size;
while (num > 1024.0 && i.hasNext())
{
unit = i.next();
num /= 1024.0;
}
return QStringLiteral("%1 %2").arg(QString::number(num, 'f', 1)).arg(unit);
}
GameListProxyModel::GameListProxyModel(QObject* parent)
: QSortFilterProxyModel(parent)
{
}
QVariant GameListProxyModel::data(const QModelIndex& i, int role) const
{
QModelIndex source_index = mapToSource(i);
QVariant source_data = sourceModel()->data(source_index, Qt::DisplayRole);
if (role == Qt::DisplayRole)
{
switch (i.column())
{
// Sort by the integer but display the formatted string.
case GameListModel::COL_SIZE:
return FormatSize(source_data.toULongLong());
// These fall through to the underlying model.
case GameListModel::COL_ID:
case GameListModel::COL_TITLE:
case GameListModel::COL_DESCRIPTION:
case GameListModel::COL_MAKER:
return source_data;
// Show the title in the display role of the icon view.
case GameListModel::COL_LARGE_ICON:
return data(index(i.row(), GameListModel::COL_TITLE), Qt::DisplayRole);
}
}
else if (role == Qt::DecorationRole)
{
switch (i.column())
{
// Show icons in the decoration roles. This lets us sort by the
// underlying ints, but display just the icons without doing any
// fixed-width hacks.
case GameListModel::COL_PLATFORM:
return Resources::GetPlatform(source_data.toInt());
case GameListModel::COL_BANNER:
return source_data.value<QPixmap>().scaled(
NORMAL_BANNER_SIZE,
Qt::KeepAspectRatio,
Qt::SmoothTransformation);
case GameListModel::COL_COUNTRY:
return Resources::GetCountry(source_data.toInt());
case GameListModel::COL_RATING:
return Resources::GetRating(source_data.toInt());
// Show a scaled icon in the decoration role of the icon view.
case GameListModel::COL_LARGE_ICON:
return data(index(i.row(), GameListModel::COL_BANNER), Qt::DecorationRole)
.value<QPixmap>().scaled(
LARGE_BANNER_SIZE,
Qt::KeepAspectRatio,
Qt::SmoothTransformation);
}
}
return QVariant();
}

View File

@ -0,0 +1,19 @@
// Copyright 2015 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include <QSortFilterProxyModel>
// This subclass of QSortFilterProxyModel transforms the raw GameFile data
// into presentable icons, and allows for sorting and filtering.
// For instance, the GameListModel exposes country as an integer, so this
// class converts that into a flag, while still allowing sorting on the
// underlying integer.
class GameListProxyModel final : public QSortFilterProxyModel
{
Q_OBJECT
public:
GameListProxyModel(QObject* parent = nullptr);
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const;
};

View File

@ -71,6 +71,7 @@ void MainWindow::AddTableColumnsMenu(QMenu* view_menu)
QStringList col_names{ QStringList col_names{
tr("Platform"), tr("Platform"),
tr("ID"), tr("ID"),
tr("Banner"),
tr("Title"), tr("Title"),
tr("Description"), tr("Description"),
tr("Maker"), tr("Maker"),
@ -78,12 +79,13 @@ void MainWindow::AddTableColumnsMenu(QMenu* view_menu)
tr("Country"), tr("Country"),
tr("Quality") tr("Quality")
}; };
// TODO we'll need to update SConfig with another column. Then we can clean this // TODO we'll need to update SConfig with the extra columns. Then we can
// up significantly. // clean this up significantly.
QList<bool> show_cols{ QList<bool> show_cols{
SConfig::GetInstance().m_showSystemColumn, SConfig::GetInstance().m_showSystemColumn,
SConfig::GetInstance().m_showIDColumn, SConfig::GetInstance().m_showIDColumn,
SConfig::GetInstance().m_showBannerColumn, SConfig::GetInstance().m_showBannerColumn,
true,
false, false,
SConfig::GetInstance().m_showMakerColumn, SConfig::GetInstance().m_showMakerColumn,
SConfig::GetInstance().m_showSizeColumn, SConfig::GetInstance().m_showSizeColumn,