a-la-karte/src/gamemodel.cpp

492 lines
11 KiB
C++
Raw Normal View History

// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: 2024 A-La-Karte Contributors
#include "gamemodel.h"
#include <algorithm>
GameModel::GameModel(QObject *parent)
: QAbstractListModel(parent)
{
}
int GameModel::rowCount(const QModelIndex &parent) const
{
if (parent.isValid()) {
return 0;
}
return m_filteredGames.count();
}
QVariant GameModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid() || index.row() < 0 || index.row() >= m_filteredGames.count()) {
return {};
}
Game *game = m_filteredGames.at(index.row());
switch (role) {
case IdRole:
return game->id();
case NameRole:
case Qt::DisplayRole:
return game->name();
case DescriptionRole:
return game->description();
case DeveloperRole:
return game->developer();
case PublisherRole:
return game->publisher();
case CoverUrlRole:
return game->coverUrl();
case IconUrlRole:
return game->iconUrl();
case LaunchCommandRole:
return game->launchCommand();
case PlatformRole:
return game->platform();
case PlatformIdRole:
return game->platformId();
case LastPlayedRole:
return game->lastPlayed();
case PlayTimeRole:
return game->playTime();
case FavoriteRole:
return game->favorite();
case HiddenRole:
return game->hidden();
case InstalledRole:
return game->installed();
case RunningRole:
return game->running();
case GameObjectRole:
return QVariant::fromValue(game);
}
return {};
}
bool GameModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
if (!index.isValid() || index.row() < 0 || index.row() >= m_filteredGames.count()) {
return false;
}
Game *game = m_filteredGames.at(index.row());
switch (role) {
case FavoriteRole:
game->setFavorite(value.toBool());
break;
case HiddenRole:
game->setHidden(value.toBool());
break;
default:
return false;
}
Q_EMIT dataChanged(index, index, {role});
return true;
}
Qt::ItemFlags GameModel::flags(const QModelIndex &index) const
{
if (!index.isValid()) {
return Qt::NoItemFlags;
}
return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable;
}
QHash<int, QByteArray> GameModel::roleNames() const
{
return {{IdRole, "gameId"},
{NameRole, "name"},
{DescriptionRole, "description"},
{DeveloperRole, "developer"},
{PublisherRole, "publisher"},
{CoverUrlRole, "coverUrl"},
{IconUrlRole, "iconUrl"},
{LaunchCommandRole, "launchCommand"},
{PlatformRole, "platform"},
{PlatformIdRole, "platformId"},
{LastPlayedRole, "lastPlayed"},
{PlayTimeRole, "playTime"},
{FavoriteRole, "favorite"},
{HiddenRole, "hidden"},
{InstalledRole, "installed"},
{RunningRole, "running"},
{GameObjectRole, "gameObject"}};
}
int GameModel::count() const
{
return m_filteredGames.count();
}
QString GameModel::filterText() const
{
return m_filterText;
}
void GameModel::setFilterText(const QString &text)
{
if (m_filterText != text) {
m_filterText = text;
applyFilter();
Q_EMIT filterTextChanged();
}
}
QString GameModel::filterPlatform() const
{
return m_filterPlatform;
}
void GameModel::setFilterPlatform(const QString &platform)
{
if (m_filterPlatform != platform) {
m_filterPlatform = platform;
applyFilter();
Q_EMIT filterPlatformChanged();
}
}
bool GameModel::showHidden() const
{
return m_showHidden;
}
void GameModel::setShowHidden(bool show)
{
if (m_showHidden != show) {
m_showHidden = show;
applyFilter();
Q_EMIT showHiddenChanged();
}
}
bool GameModel::favoritesOnly() const
{
return m_favoritesOnly;
}
void GameModel::setFavoritesOnly(bool favorites)
{
if (m_favoritesOnly != favorites) {
m_favoritesOnly = favorites;
applyFilter();
Q_EMIT favoritesOnlyChanged();
}
}
GameModel::SortMode GameModel::sortMode() const
{
return m_sortMode;
}
void GameModel::setSortMode(SortMode mode)
{
if (m_sortMode != mode) {
m_sortMode = mode;
applySort();
Q_EMIT sortModeChanged();
}
}
void GameModel::addGame(Game *game)
{
if (!game)
return;
// Check for duplicates
for (Game *existing : m_games) {
if (existing->id() == game->id()) {
if (!game->parent()) {
game->setParent(this);
}
game->deleteLater();
return;
}
}
game->setParent(this);
connect(
game,
&Game::nameChanged,
this,
[this]() {
applyFilter();
},
Qt::QueuedConnection);
connect(
game,
&Game::developerChanged,
this,
[this]() {
applyFilter();
},
Qt::QueuedConnection);
connect(
game,
&Game::publisherChanged,
this,
[this]() {
applyFilter();
},
Qt::QueuedConnection);
connect(
game,
&Game::favoriteChanged,
this,
[this]() {
applyFilter();
},
Qt::QueuedConnection);
connect(
game,
&Game::hiddenChanged,
this,
[this]() {
applyFilter();
},
Qt::QueuedConnection);
connect(
game,
&Game::platformChanged,
this,
[this]() {
applyFilter();
},
Qt::QueuedConnection);
connect(
game,
&Game::lastPlayedChanged,
this,
[this]() {
applyFilter();
},
Qt::QueuedConnection);
connect(
game,
&Game::playTimeChanged,
this,
[this]() {
applyFilter();
},
Qt::QueuedConnection);
m_games.append(game);
applyFilter();
}
void GameModel::removeGame(const QString &id)
{
for (int i = 0; i < m_games.count(); ++i) {
if (m_games.at(i)->id() == id) {
int filteredIndex = m_filteredGames.indexOf(m_games.at(i));
if (filteredIndex >= 0) {
beginRemoveRows(QModelIndex(), filteredIndex, filteredIndex);
m_filteredGames.removeAt(filteredIndex);
endRemoveRows();
}
Game *game = m_games.takeAt(i);
if (game) {
game->deleteLater();
}
Q_EMIT countChanged();
return;
}
}
}
Game *GameModel::gameAt(int index) const
{
if (index < 0 || index >= m_filteredGames.count()) {
return nullptr;
}
return m_filteredGames.at(index);
}
Game *GameModel::gameById(const QString &id) const
{
for (Game *game : m_games) {
if (game->id() == id) {
return game;
}
}
return nullptr;
}
void GameModel::clear()
{
beginResetModel();
for (Game *game : m_games) {
if (game) {
game->deleteLater();
}
}
m_games.clear();
m_filteredGames.clear();
endResetModel();
Q_EMIT countChanged();
}
QStringList GameModel::platforms() const
{
QStringList result;
for (Game *game : m_games) {
if (!result.contains(game->platform())) {
result.append(game->platform());
}
}
result.sort();
return result;
}
QList<Game *> GameModel::allGames() const
{
return m_games;
}
bool GameModel::hasPlatformPrefix(const QString &platformPrefix) const
{
if (platformPrefix.isEmpty()) {
return false;
}
for (Game *game : m_games) {
if (!game) {
continue;
}
if (game->platform().startsWith(platformPrefix)) {
return true;
}
}
return false;
}
int GameModel::removeByPlatformPrefix(const QString &platformPrefix)
{
if (platformPrefix.isEmpty()) {
return 0;
}
bool hasMatch = false;
for (Game *game : m_games) {
if (!game) {
continue;
}
if (game->platform().startsWith(platformPrefix)) {
hasMatch = true;
break;
}
}
if (!hasMatch) {
return 0;
}
beginResetModel();
int removed = 0;
for (int i = m_games.count() - 1; i >= 0; --i) {
Game *game = m_games.at(i);
if (!game) {
continue;
}
if (game->platform().startsWith(platformPrefix)) {
m_games.takeAt(i)->deleteLater();
removed++;
}
}
m_filteredGames.clear();
for (Game *game : m_games) {
if (matchesFilter(game)) {
m_filteredGames.append(game);
}
}
applySort();
endResetModel();
if (removed > 0) {
Q_EMIT countChanged();
}
return removed;
}
bool GameModel::matchesFilter(Game *game) const
{
if (!m_showHidden && game->hidden()) {
return false;
}
if (m_favoritesOnly && !game->favorite()) {
return false;
}
if (!m_filterPlatform.isEmpty() && game->platform() != m_filterPlatform) {
return false;
}
if (!m_filterText.isEmpty()) {
bool matches = game->name().contains(m_filterText, Qt::CaseInsensitive) || game->developer().contains(m_filterText, Qt::CaseInsensitive)
|| game->publisher().contains(m_filterText, Qt::CaseInsensitive);
if (!matches) {
return false;
}
}
return true;
}
void GameModel::applyFilter()
{
beginResetModel();
m_filteredGames.clear();
for (Game *game : m_games) {
if (matchesFilter(game)) {
m_filteredGames.append(game);
}
}
applySort();
endResetModel();
Q_EMIT countChanged();
}
void GameModel::applySort()
{
std::sort(m_filteredGames.begin(), m_filteredGames.end(), [this](Game *a, Game *b) {
// Favorites always first
if (a->favorite() != b->favorite()) {
return a->favorite();
}
switch (m_sortMode) {
case SortByName:
return a->name().compare(b->name(), Qt::CaseInsensitive) < 0;
case SortByLastPlayed:
return a->lastPlayed() > b->lastPlayed();
case SortByPlayTime:
return a->playTime() > b->playTime();
case SortByPlatform:
if (a->platform() != b->platform()) {
return a->platform() < b->platform();
}
return a->name().compare(b->name(), Qt::CaseInsensitive) < 0;
case SortByRecent:
return a->lastPlayed() > b->lastPlayed();
}
return false;
});
}