Merge pull request #3294 from spxtr/DQt2-GameProxyModel
DolphinQt2: Use a proxy model for the GameList
This commit is contained in:
commit
97231aa221
|
@ -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)
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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,46 +19,22 @@ 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());
|
}
|
||||||
|
return QVariant();
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariant GameListModel::headerData(int section, Qt::Orientation orientation, int role) const
|
QVariant GameListModel::headerData(int section, Qt::Orientation orientation, int role) const
|
||||||
|
@ -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
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
|
@ -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;
|
||||||
|
};
|
|
@ -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,
|
||||||
|
|
Loading…
Reference in New Issue