Merge pull request #7455 from spycrab/qt_tags
Qt/GameList: Implement tag system
This commit is contained in:
commit
2bdee9b80b
|
@ -201,6 +201,7 @@ void SConfig::SaveGameListSettings(IniFile& ini)
|
||||||
gamelist->Set("ColumnID", m_showIDColumn);
|
gamelist->Set("ColumnID", m_showIDColumn);
|
||||||
gamelist->Set("ColumnRegion", m_showRegionColumn);
|
gamelist->Set("ColumnRegion", m_showRegionColumn);
|
||||||
gamelist->Set("ColumnSize", m_showSizeColumn);
|
gamelist->Set("ColumnSize", m_showSizeColumn);
|
||||||
|
gamelist->Set("ColumnTags", m_showTagsColumn);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SConfig::SaveCoreSettings(IniFile& ini)
|
void SConfig::SaveCoreSettings(IniFile& ini)
|
||||||
|
@ -475,6 +476,7 @@ void SConfig::LoadGameListSettings(IniFile& ini)
|
||||||
gamelist->Get("ColumnID", &m_showIDColumn, false);
|
gamelist->Get("ColumnID", &m_showIDColumn, false);
|
||||||
gamelist->Get("ColumnRegion", &m_showRegionColumn, true);
|
gamelist->Get("ColumnRegion", &m_showRegionColumn, true);
|
||||||
gamelist->Get("ColumnSize", &m_showSizeColumn, true);
|
gamelist->Get("ColumnSize", &m_showSizeColumn, true);
|
||||||
|
gamelist->Get("ColumnTags", &m_showTagsColumn, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SConfig::LoadCoreSettings(IniFile& ini)
|
void SConfig::LoadCoreSettings(IniFile& ini)
|
||||||
|
|
|
@ -270,6 +270,7 @@ struct SConfig
|
||||||
bool m_showIDColumn;
|
bool m_showIDColumn;
|
||||||
bool m_showRegionColumn;
|
bool m_showRegionColumn;
|
||||||
bool m_showSizeColumn;
|
bool m_showSizeColumn;
|
||||||
|
bool m_showTagsColumn;
|
||||||
|
|
||||||
std::string m_WirelessMac;
|
std::string m_WirelessMac;
|
||||||
bool m_PauseMovie;
|
bool m_PauseMovie;
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
#include <QFrame>
|
#include <QFrame>
|
||||||
#include <QHeaderView>
|
#include <QHeaderView>
|
||||||
|
#include <QInputDialog>
|
||||||
#include <QKeyEvent>
|
#include <QKeyEvent>
|
||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
#include <QListView>
|
#include <QListView>
|
||||||
|
@ -132,6 +133,7 @@ void GameList::MakeListView()
|
||||||
hor_header->setSectionResizeMode(GameListModel::COL_COUNTRY, QHeaderView::Fixed);
|
hor_header->setSectionResizeMode(GameListModel::COL_COUNTRY, QHeaderView::Fixed);
|
||||||
hor_header->setSectionResizeMode(GameListModel::COL_SIZE, QHeaderView::Fixed);
|
hor_header->setSectionResizeMode(GameListModel::COL_SIZE, QHeaderView::Fixed);
|
||||||
hor_header->setSectionResizeMode(GameListModel::COL_FILE_NAME, QHeaderView::Interactive);
|
hor_header->setSectionResizeMode(GameListModel::COL_FILE_NAME, QHeaderView::Interactive);
|
||||||
|
hor_header->setSectionResizeMode(GameListModel::COL_TAGS, QHeaderView::Interactive);
|
||||||
|
|
||||||
// There's some odd platform-specific behavior with default minimum section size
|
// There's some odd platform-specific behavior with default minimum section size
|
||||||
hor_header->setMinimumSectionSize(38);
|
hor_header->setMinimumSectionSize(38);
|
||||||
|
@ -174,6 +176,7 @@ void GameList::UpdateColumnVisibility()
|
||||||
m_list->setColumnHidden(GameListModel::COL_SIZE, !SConfig::GetInstance().m_showSizeColumn);
|
m_list->setColumnHidden(GameListModel::COL_SIZE, !SConfig::GetInstance().m_showSizeColumn);
|
||||||
m_list->setColumnHidden(GameListModel::COL_FILE_NAME,
|
m_list->setColumnHidden(GameListModel::COL_FILE_NAME,
|
||||||
!SConfig::GetInstance().m_showFileNameColumn);
|
!SConfig::GetInstance().m_showFileNameColumn);
|
||||||
|
m_list->setColumnHidden(GameListModel::COL_TAGS, !SConfig::GetInstance().m_showTagsColumn);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameList::MakeEmptyView()
|
void GameList::MakeEmptyView()
|
||||||
|
@ -336,6 +339,35 @@ void GameList::ShowContextMenu(const QPoint&)
|
||||||
menu->addAction(tr("Open &containing folder"), this, &GameList::OpenContainingFolder);
|
menu->addAction(tr("Open &containing folder"), this, &GameList::OpenContainingFolder);
|
||||||
menu->addAction(tr("Delete File..."), this, &GameList::DeleteFile);
|
menu->addAction(tr("Delete File..."), this, &GameList::DeleteFile);
|
||||||
|
|
||||||
|
menu->addSeparator();
|
||||||
|
|
||||||
|
auto* model = Settings::Instance().GetGameListModel();
|
||||||
|
|
||||||
|
auto* tags_menu = menu->addMenu(tr("Tags"));
|
||||||
|
|
||||||
|
auto path = game->GetFilePath();
|
||||||
|
auto game_tags = model->GetGameTags(path);
|
||||||
|
|
||||||
|
for (const auto& tag : model->GetAllTags())
|
||||||
|
{
|
||||||
|
auto* tag_action = tags_menu->addAction(tag);
|
||||||
|
|
||||||
|
tag_action->setCheckable(true);
|
||||||
|
tag_action->setChecked(game_tags.contains(tag));
|
||||||
|
|
||||||
|
connect(tag_action, &QAction::toggled, this, [this, path, tag, model](bool checked) {
|
||||||
|
if (!checked)
|
||||||
|
model->RemoveGameTag(path, tag);
|
||||||
|
else
|
||||||
|
model->AddGameTag(path, tag);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
menu->addAction(tr("New Tag..."), this, &GameList::NewTag);
|
||||||
|
menu->addAction(tr("Remove Tag..."), this, &GameList::DeleteTag);
|
||||||
|
|
||||||
|
menu->addSeparator();
|
||||||
|
|
||||||
QAction* netplay_host = new QAction(tr("Host with NetPlay"), menu);
|
QAction* netplay_host = new QAction(tr("Host with NetPlay"), menu);
|
||||||
|
|
||||||
connect(netplay_host, &QAction::triggered, [this, game] {
|
connect(netplay_host, &QAction::triggered, [this, game] {
|
||||||
|
@ -742,7 +774,8 @@ void GameList::OnColumnVisibilityToggled(const QString& row, bool visible)
|
||||||
{tr("File Name"), GameListModel::COL_FILE_NAME},
|
{tr("File Name"), GameListModel::COL_FILE_NAME},
|
||||||
{tr("Game ID"), GameListModel::COL_ID},
|
{tr("Game ID"), GameListModel::COL_ID},
|
||||||
{tr("Region"), GameListModel::COL_COUNTRY},
|
{tr("Region"), GameListModel::COL_COUNTRY},
|
||||||
{tr("File Size"), GameListModel::COL_SIZE}};
|
{tr("File Size"), GameListModel::COL_SIZE},
|
||||||
|
{tr("Tags"), GameListModel::COL_TAGS}};
|
||||||
|
|
||||||
m_list->setColumnHidden(rowname_to_col_index[row], !visible);
|
m_list->setColumnHidden(rowname_to_col_index[row], !visible);
|
||||||
}
|
}
|
||||||
|
@ -859,6 +892,26 @@ void GameList::OnHeaderViewChanged()
|
||||||
block = false;
|
block = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GameList::NewTag()
|
||||||
|
{
|
||||||
|
auto tag = QInputDialog::getText(this, tr("New tag"), tr("Name for a new tag:"));
|
||||||
|
|
||||||
|
if (tag.isEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
Settings::Instance().GetGameListModel()->NewTag(tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GameList::DeleteTag()
|
||||||
|
{
|
||||||
|
auto tag = QInputDialog::getText(this, tr("Remove tag"), tr("Name of the tag to remove:"));
|
||||||
|
|
||||||
|
if (tag.isEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
Settings::Instance().GetGameListModel()->DeleteTag(tag);
|
||||||
|
}
|
||||||
|
|
||||||
void GameList::SetSearchTerm(const QString& term)
|
void GameList::SetSearchTerm(const QString& term)
|
||||||
{
|
{
|
||||||
m_model->SetSearchTerm(term);
|
m_model->SetSearchTerm(term);
|
||||||
|
|
|
@ -60,6 +60,8 @@ private:
|
||||||
void ExportWiiSave();
|
void ExportWiiSave();
|
||||||
void CompressISO(bool decompress);
|
void CompressISO(bool decompress);
|
||||||
void ChangeDisc();
|
void ChangeDisc();
|
||||||
|
void NewTag();
|
||||||
|
void DeleteTag();
|
||||||
void UpdateColumnVisibility();
|
void UpdateColumnVisibility();
|
||||||
|
|
||||||
void ZoomIn();
|
void ZoomIn();
|
||||||
|
|
|
@ -42,6 +42,11 @@ GameListModel::GameListModel(QObject* parent) : QAbstractTableModel(parent)
|
||||||
emit layoutAboutToBeChanged();
|
emit layoutAboutToBeChanged();
|
||||||
emit layoutChanged();
|
emit layoutChanged();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
auto& settings = Settings::GetQSettings();
|
||||||
|
|
||||||
|
m_tag_list = settings.value(QStringLiteral("gamelist/tags")).toStringList();
|
||||||
|
m_game_tags = settings.value(QStringLiteral("gamelist/game_tags")).toMap();
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariant GameListModel::data(const QModelIndex& index, int role) const
|
QVariant GameListModel::data(const QModelIndex& index, int role) const
|
||||||
|
@ -117,6 +122,14 @@ QVariant GameListModel::data(const QModelIndex& index, int role) const
|
||||||
if (role == Qt::InitialSortOrderRole)
|
if (role == Qt::InitialSortOrderRole)
|
||||||
return static_cast<quint64>(game.GetFileSize());
|
return static_cast<quint64>(game.GetFileSize());
|
||||||
break;
|
break;
|
||||||
|
case COL_TAGS:
|
||||||
|
if (role == Qt::DisplayRole || role == Qt::InitialSortOrderRole)
|
||||||
|
{
|
||||||
|
auto tags = GetGameTags(game.GetFilePath());
|
||||||
|
tags.sort();
|
||||||
|
|
||||||
|
return tags.join(QStringLiteral(", "));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return QVariant();
|
return QVariant();
|
||||||
|
@ -143,6 +156,8 @@ QVariant GameListModel::headerData(int section, Qt::Orientation orientation, int
|
||||||
return tr("File Name");
|
return tr("File Name");
|
||||||
case COL_SIZE:
|
case COL_SIZE:
|
||||||
return tr("Size");
|
return tr("Size");
|
||||||
|
case COL_TAGS:
|
||||||
|
return tr("Tags");
|
||||||
}
|
}
|
||||||
return QVariant();
|
return QVariant();
|
||||||
}
|
}
|
||||||
|
@ -293,3 +308,57 @@ float GameListModel::GetScale() const
|
||||||
{
|
{
|
||||||
return m_scale;
|
return m_scale;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const QStringList& GameListModel::GetAllTags() const
|
||||||
|
{
|
||||||
|
return m_tag_list;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QStringList GameListModel::GetGameTags(const std::string& path) const
|
||||||
|
{
|
||||||
|
return m_game_tags[QString::fromStdString(path)].toStringList();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GameListModel::AddGameTag(const std::string& path, const QString& name)
|
||||||
|
{
|
||||||
|
auto tags = GetGameTags(path);
|
||||||
|
|
||||||
|
if (tags.contains(name))
|
||||||
|
return;
|
||||||
|
|
||||||
|
tags << name;
|
||||||
|
|
||||||
|
m_game_tags[QString::fromStdString(path)] = tags;
|
||||||
|
Settings::GetQSettings().setValue(QStringLiteral("gamelist/game_tags"), m_game_tags);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GameListModel::RemoveGameTag(const std::string& path, const QString& name)
|
||||||
|
{
|
||||||
|
auto tags = GetGameTags(path);
|
||||||
|
|
||||||
|
tags.removeAll(name);
|
||||||
|
|
||||||
|
m_game_tags[QString::fromStdString(path)] = tags;
|
||||||
|
|
||||||
|
Settings::GetQSettings().setValue(QStringLiteral("gamelist/game_tags"), m_game_tags);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GameListModel::NewTag(const QString& name)
|
||||||
|
{
|
||||||
|
if (m_tag_list.contains(name))
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_tag_list << name;
|
||||||
|
|
||||||
|
Settings::GetQSettings().setValue(QStringLiteral("gamelist/tags"), m_tag_list);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GameListModel::DeleteTag(const QString& name)
|
||||||
|
{
|
||||||
|
m_tag_list.removeAll(name);
|
||||||
|
|
||||||
|
for (const auto& file : m_game_tags.keys())
|
||||||
|
RemoveGameTag(file.toStdString(), name);
|
||||||
|
|
||||||
|
Settings::GetQSettings().setValue(QStringLiteral("gamelist/tags"), m_tag_list);
|
||||||
|
}
|
||||||
|
|
|
@ -8,7 +8,10 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include <QAbstractTableModel>
|
#include <QAbstractTableModel>
|
||||||
|
#include <QMap>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
#include <QStringList>
|
||||||
|
#include <QVariant>
|
||||||
|
|
||||||
#include "Core/TitleDatabase.h"
|
#include "Core/TitleDatabase.h"
|
||||||
|
|
||||||
|
@ -52,6 +55,7 @@ public:
|
||||||
COL_COUNTRY,
|
COL_COUNTRY,
|
||||||
COL_SIZE,
|
COL_SIZE,
|
||||||
COL_FILE_NAME,
|
COL_FILE_NAME,
|
||||||
|
COL_TAGS,
|
||||||
NUM_COLS
|
NUM_COLS
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -62,10 +66,22 @@ public:
|
||||||
void SetScale(float scale);
|
void SetScale(float scale);
|
||||||
float GetScale() const;
|
float GetScale() const;
|
||||||
|
|
||||||
|
const QStringList& GetAllTags() const;
|
||||||
|
const QStringList GetGameTags(const std::string& path) const;
|
||||||
|
|
||||||
|
void AddGameTag(const std::string& path, const QString& name);
|
||||||
|
void RemoveGameTag(const std::string& path, const QString& name);
|
||||||
|
|
||||||
|
void NewTag(const QString& name);
|
||||||
|
void DeleteTag(const QString& name);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Index in m_games, or -1 if it isn't found
|
// Index in m_games, or -1 if it isn't found
|
||||||
int FindGame(const std::string& path) const;
|
int FindGame(const std::string& path) const;
|
||||||
|
|
||||||
|
QStringList m_tag_list;
|
||||||
|
QMap<QString, QVariant> m_game_tags;
|
||||||
|
|
||||||
GameTracker m_tracker;
|
GameTracker m_tracker;
|
||||||
QList<std::shared_ptr<const UICommon::GameFile>> m_games;
|
QList<std::shared_ptr<const UICommon::GameFile>> m_games;
|
||||||
Core::TitleDatabase m_title_database;
|
Core::TitleDatabase m_title_database;
|
||||||
|
|
|
@ -570,7 +570,8 @@ void MenuBar::AddListColumnsMenu(QMenu* view_menu)
|
||||||
{tr("File Name"), &SConfig::GetInstance().m_showFileNameColumn},
|
{tr("File Name"), &SConfig::GetInstance().m_showFileNameColumn},
|
||||||
{tr("Game ID"), &SConfig::GetInstance().m_showIDColumn},
|
{tr("Game ID"), &SConfig::GetInstance().m_showIDColumn},
|
||||||
{tr("Region"), &SConfig::GetInstance().m_showRegionColumn},
|
{tr("Region"), &SConfig::GetInstance().m_showRegionColumn},
|
||||||
{tr("File Size"), &SConfig::GetInstance().m_showSizeColumn}};
|
{tr("File Size"), &SConfig::GetInstance().m_showSizeColumn},
|
||||||
|
{tr("Tags"), &SConfig::GetInstance().m_showTagsColumn}};
|
||||||
|
|
||||||
QActionGroup* column_group = new QActionGroup(this);
|
QActionGroup* column_group = new QActionGroup(this);
|
||||||
QMenu* cols_menu = view_menu->addMenu(tr("List Columns"));
|
QMenu* cols_menu = view_menu->addMenu(tr("List Columns"));
|
||||||
|
|
Loading…
Reference in New Issue