citra_qt/game_list: Specify string conversions explicitly

This commit is contained in:
FearlessTobi 2019-11-09 02:46:23 +01:00
parent 6cf0043830
commit 9c1535621a
4 changed files with 71 additions and 63 deletions

View File

@ -27,7 +27,6 @@
#include "citra_qt/game_list_worker.h" #include "citra_qt/game_list_worker.h"
#include "citra_qt/main.h" #include "citra_qt/main.h"
#include "citra_qt/uisettings.h" #include "citra_qt/uisettings.h"
#include "common/common_paths.h"
#include "common/logging/log.h" #include "common/logging/log.h"
#include "core/file_sys/archive_extsavedata.h" #include "core/file_sys/archive_extsavedata.h"
#include "core/file_sys/archive_source_sd_savedata.h" #include "core/file_sys/archive_source_sd_savedata.h"
@ -54,7 +53,7 @@ bool GameListSearchField::KeyReleaseEater::eventFilter(QObject* obj, QEvent* eve
return QObject::eventFilter(obj, event); return QObject::eventFilter(obj, event);
} else { } else {
gamelist->search_field->edit_filter->clear(); gamelist->search_field->edit_filter->clear();
edit_filter_text = ""; edit_filter_text.clear();
} }
break; break;
} }
@ -67,9 +66,9 @@ bool GameListSearchField::KeyReleaseEater::eventFilter(QObject* obj, QEvent* eve
QString file_path = gamelist->getLastFilterResultItem(); QString file_path = gamelist->getLastFilterResultItem();
// To avoid loading error dialog loops while confirming them using enter // To avoid loading error dialog loops while confirming them using enter
// Also users usually want to run a diffrent game after closing one // Also users usually want to run a different game after closing one
gamelist->search_field->edit_filter->setText(""); gamelist->search_field->edit_filter->clear();
edit_filter_text = ""; edit_filter_text.clear();
emit gamelist->GameChosen(file_path); emit gamelist->GameChosen(file_path);
} else { } else {
return QObject::eventFilter(obj, event); return QObject::eventFilter(obj, event);
@ -96,7 +95,7 @@ void GameListSearchField::setFilterResult(int visible, int total) {
result_text = tr("results"); result_text = tr("results");
} }
label_filter_result->setText( label_filter_result->setText(
QString("%1 %2 %3 %4").arg(visible).arg(result_of_text).arg(total).arg(result_text)); QStringLiteral("%1 %2 %3 %4").arg(visible).arg(result_of_text).arg(total).arg(result_text));
} }
QString GameList::getLastFilterResultItem() const { QString GameList::getLastFilterResultItem() const {
@ -119,7 +118,7 @@ QString GameList::getLastFilterResultItem() const {
} }
void GameListSearchField::clear() { void GameListSearchField::clear() {
edit_filter->setText(""); edit_filter->clear();
} }
void GameListSearchField::setFocus() { void GameListSearchField::setFocus() {
@ -129,25 +128,26 @@ void GameListSearchField::setFocus() {
} }
GameListSearchField::GameListSearchField(GameList* parent) : QWidget{parent} { GameListSearchField::GameListSearchField(GameList* parent) : QWidget{parent} {
KeyReleaseEater* keyReleaseEater = new KeyReleaseEater(parent); auto* const key_release_eater = new KeyReleaseEater(parent);
layout_filter = new QHBoxLayout; layout_filter = new QHBoxLayout;
layout_filter->setMargin(8); layout_filter->setMargin(8);
label_filter = new QLabel; label_filter = new QLabel;
label_filter->setText(tr("Filter:")); label_filter->setText(tr("Filter:"));
edit_filter = new QLineEdit; edit_filter = new QLineEdit;
edit_filter->setText(""); edit_filter->clear();
edit_filter->setPlaceholderText(tr("Enter pattern to filter")); edit_filter->setPlaceholderText(tr("Enter pattern to filter"));
edit_filter->installEventFilter(keyReleaseEater); edit_filter->installEventFilter(key_release_eater);
edit_filter->setClearButtonEnabled(true); edit_filter->setClearButtonEnabled(true);
connect(edit_filter, &QLineEdit::textChanged, parent, &GameList::onTextChanged); connect(edit_filter, &QLineEdit::textChanged, parent, &GameList::onTextChanged);
label_filter_result = new QLabel; label_filter_result = new QLabel;
button_filter_close = new QToolButton(this); button_filter_close = new QToolButton(this);
button_filter_close->setText("X"); button_filter_close->setText(QStringLiteral("X"));
button_filter_close->setCursor(Qt::ArrowCursor); button_filter_close->setCursor(Qt::ArrowCursor);
button_filter_close->setStyleSheet("QToolButton{ border: none; padding: 0px; color: " button_filter_close->setStyleSheet(
QStringLiteral("QToolButton{ border: none; padding: 0px; color: "
"#000000; font-weight: bold; background: #F0F0F0; }" "#000000; font-weight: bold; background: #F0F0F0; }"
"QToolButton:hover{ border: none; padding: 0px; color: " "QToolButton:hover{ border: none; padding: 0px; color: "
"#EEEEEE; font-weight: bold; background: #E81123}"); "#EEEEEE; font-weight: bold; background: #E81123}"));
connect(button_filter_close, &QToolButton::clicked, parent, &GameList::onFilterCloseClicked); connect(button_filter_close, &QToolButton::clicked, parent, &GameList::onFilterCloseClicked);
layout_filter->setSpacing(10); layout_filter->setSpacing(10);
layout_filter->addWidget(label_filter); layout_filter->addWidget(label_filter);
@ -167,7 +167,7 @@ GameListSearchField::GameListSearchField(GameList* parent) : QWidget{parent} {
*/ */
static bool ContainsAllWords(const QString& haystack, const QString& userinput) { static bool ContainsAllWords(const QString& haystack, const QString& userinput) {
const QStringList userinput_split = const QStringList userinput_split =
userinput.split(' ', QString::SplitBehavior::SkipEmptyParts); userinput.split(QLatin1Char{' '}, QString::SplitBehavior::SkipEmptyParts);
return std::all_of(userinput_split.begin(), userinput_split.end(), return std::all_of(userinput_split.begin(), userinput_split.end(),
[&haystack](const QString& s) { return haystack.contains(s); }); [&haystack](const QString& s) { return haystack.contains(s); });
@ -183,16 +183,16 @@ void GameList::onItemExpanded(const QModelIndex& item) {
} }
// Event in order to filter the gamelist after editing the searchfield // Event in order to filter the gamelist after editing the searchfield
void GameList::onTextChanged(const QString& newText) { void GameList::onTextChanged(const QString& new_text) {
const int folderCount = tree_view->model()->rowCount(); const int folder_count = tree_view->model()->rowCount();
QString edit_filter_text = newText.toLower(); QString edit_filter_text = new_text.toLower();
QStandardItem* folder; QStandardItem* folder;
int children_total = 0; int children_total = 0;
// If the searchfield is empty every item is visible // If the searchfield is empty every item is visible
// Otherwise the filter gets applied // Otherwise the filter gets applied
if (edit_filter_text.isEmpty()) { if (edit_filter_text.isEmpty()) {
for (int i = 0; i < folderCount; ++i) { for (int i = 0; i < folder_count; ++i) {
folder = item_model->item(i, 0); folder = item_model->item(i, 0);
const QModelIndex folder_index = folder->index(); const QModelIndex folder_index = folder->index();
const int children_count = folder->rowCount(); const int children_count = folder->rowCount();
@ -204,7 +204,7 @@ void GameList::onTextChanged(const QString& newText) {
search_field->setFilterResult(children_total, children_total); search_field->setFilterResult(children_total, children_total);
} else { } else {
int result_count = 0; int result_count = 0;
for (int i = 0; i < folderCount; ++i) { for (int i = 0; i < folder_count; ++i) {
folder = item_model->item(i, 0); folder = item_model->item(i, 0);
const QModelIndex folder_index = folder->index(); const QModelIndex folder_index = folder->index();
const int children_count = folder->rowCount(); const int children_count = folder->rowCount();
@ -213,10 +213,9 @@ void GameList::onTextChanged(const QString& newText) {
const QStandardItem* child = folder->child(j, 0); const QStandardItem* child = folder->child(j, 0);
const QString file_path = const QString file_path =
child->data(GameListItemPath::FullPathRole).toString().toLower(); child->data(GameListItemPath::FullPathRole).toString().toLower();
QString file_name = file_path.mid(file_path.lastIndexOf("/") + 1);
const QString file_title = const QString file_title =
child->data(GameListItemPath::LongTitleRole).toString().toLower(); child->data(GameListItemPath::LongTitleRole).toString().toLower();
const QString file_programmid = const QString file_program_id =
child->data(GameListItemPath::ProgramIdRole).toString().toLower(); child->data(GameListItemPath::ProgramIdRole).toString().toLower();
// Only items which filename in combination with its title contains all words // Only items which filename in combination with its title contains all words
@ -224,8 +223,11 @@ void GameList::onTextChanged(const QString& newText) {
// The search is case insensitive because of toLower() // The search is case insensitive because of toLower()
// I decided not to use Qt::CaseInsensitive in containsAllWords to prevent // I decided not to use Qt::CaseInsensitive in containsAllWords to prevent
// multiple conversions of edit_filter_text for each game in the gamelist // multiple conversions of edit_filter_text for each game in the gamelist
if (ContainsAllWords(file_name.append(' ').append(file_title), edit_filter_text) || const QString file_name =
(file_programmid.count() == 16 && edit_filter_text.contains(file_programmid))) { file_path.mid(file_path.lastIndexOf(QLatin1Char{'/'}) + 1) + QLatin1Char{' '} +
file_title;
if (ContainsAllWords(file_name, edit_filter_text) ||
(file_program_id.count() == 16 && edit_filter_text.contains(file_program_id))) {
tree_view->setRowHidden(j, folder_index, false); tree_view->setRowHidden(j, folder_index, false);
++result_count; ++result_count;
} else { } else {
@ -243,20 +245,23 @@ void GameList::onUpdateThemedIcons() {
switch (child->data(GameListItem::TypeRole).value<GameListItemType>()) { switch (child->data(GameListItem::TypeRole).value<GameListItemType>()) {
case GameListItemType::InstalledDir: case GameListItemType::InstalledDir:
child->setData(QIcon::fromTheme("sd_card").pixmap(48), Qt::DecorationRole); child->setData(QIcon::fromTheme(QStringLiteral("sd_card")).pixmap(48),
Qt::DecorationRole);
break; break;
case GameListItemType::SystemDir: case GameListItemType::SystemDir:
child->setData(QIcon::fromTheme("chip").pixmap(48), Qt::DecorationRole); child->setData(QIcon::fromTheme(QStringLiteral("chip")).pixmap(48), Qt::DecorationRole);
break; break;
case GameListItemType::CustomDir: { case GameListItemType::CustomDir: {
const UISettings::GameDir* game_dir = const UISettings::GameDir* game_dir =
child->data(GameListDir::GameDirRole).value<UISettings::GameDir*>(); child->data(GameListDir::GameDirRole).value<UISettings::GameDir*>();
const QString icon_name = QFileInfo::exists(game_dir->path) ? "folder" : "bad_folder"; const QString icon_name = QFileInfo::exists(game_dir->path)
? QStringLiteral("folder")
: QStringLiteral("bad_folder");
child->setData(QIcon::fromTheme(icon_name).pixmap(48), Qt::DecorationRole); child->setData(QIcon::fromTheme(icon_name).pixmap(48), Qt::DecorationRole);
break; break;
} }
case GameListItemType::AddDir: case GameListItemType::AddDir:
child->setData(QIcon::fromTheme("plus").pixmap(48), Qt::DecorationRole); child->setData(QIcon::fromTheme(QStringLiteral("plus")).pixmap(48), Qt::DecorationRole);
break; break;
} }
} }
@ -286,7 +291,7 @@ GameList::GameList(GMainWindow* parent) : QWidget{parent} {
tree_view->setSortingEnabled(true); tree_view->setSortingEnabled(true);
tree_view->setEditTriggers(QHeaderView::NoEditTriggers); tree_view->setEditTriggers(QHeaderView::NoEditTriggers);
tree_view->setContextMenuPolicy(Qt::CustomContextMenu); tree_view->setContextMenuPolicy(Qt::CustomContextMenu);
tree_view->setStyleSheet("QTreeView{ border: none; }"); tree_view->setStyleSheet(QStringLiteral("QTreeView{ border: none; }"));
item_model->insertColumns(0, COLUMN_COUNT); item_model->insertColumns(0, COLUMN_COUNT);
item_model->setHeaderData(COLUMN_NAME, Qt::Horizontal, tr("Name")); item_model->setHeaderData(COLUMN_NAME, Qt::Horizontal, tr("Name"));
@ -561,7 +566,7 @@ void GameList::AddPermDirPopup(QMenu& context_menu, QModelIndex selected) {
} }
void GameList::LoadCompatibilityList() { void GameList::LoadCompatibilityList() {
QFile compat_list{":compatibility_list/compatibility_list.json"}; QFile compat_list{QStringLiteral(":compatibility_list/compatibility_list.json")};
if (!compat_list.open(QFile::ReadOnly | QFile::Text)) { if (!compat_list.open(QFile::ReadOnly | QFile::Text)) {
LOG_ERROR(Frontend, "Unable to open game compatibility list"); LOG_ERROR(Frontend, "Unable to open game compatibility list");
@ -579,25 +584,27 @@ void GameList::LoadCompatibilityList() {
return; return;
} }
const QString string_content = content; const QJsonDocument json = QJsonDocument::fromJson(content);
QJsonDocument json = QJsonDocument::fromJson(string_content.toUtf8()); const QJsonArray arr = json.array();
QJsonArray arr = json.array();
for (const QJsonValueRef value : arr) { for (const QJsonValue value : arr) {
QJsonObject game = value.toObject(); const QJsonObject game = value.toObject();
const QString compatibility_key = QStringLiteral("compatibility");
if (game.contains("compatibility") && game["compatibility"].isDouble()) { if (!game.contains(compatibility_key) || !game[compatibility_key].isDouble()) {
int compatibility = game["compatibility"].toInt(); continue;
QString directory = game["directory"].toString();
QJsonArray ids = game["releases"].toArray();
for (const QJsonValueRef id_ref : ids) {
QJsonObject id_object = id_ref.toObject();
QString id = id_object["id"].toString();
compatibility_list.emplace(
id.toUpper().toStdString(),
std::make_pair(QString::number(compatibility), directory));
} }
const int compatibility = game[compatibility_key].toInt();
const QString directory = game[QStringLiteral("directory")].toString();
const QJsonArray ids = game[QStringLiteral("releases")].toArray();
for (const QJsonValue id_ref : ids) {
const QJsonObject id_object = id_ref.toObject();
const QString id = id_object[QStringLiteral("id")].toString();
compatibility_list.emplace(id.toUpper().toStdString(),
std::make_pair(QString::number(compatibility), directory));
} }
} }
} }
@ -645,8 +652,9 @@ void GameList::LoadInterfaceLayout() {
item_model->sort(header->sortIndicatorSection(), header->sortIndicatorOrder()); item_model->sort(header->sortIndicatorSection(), header->sortIndicatorOrder());
} }
const QStringList GameList::supported_file_extensions = {"3ds", "3dsx", "elf", "axf", const QStringList GameList::supported_file_extensions = {
"cci", "cxi", "app"}; QStringLiteral("3ds"), QStringLiteral("3dsx"), QStringLiteral("elf"), QStringLiteral("axf"),
QStringLiteral("cci"), QStringLiteral("cxi"), QStringLiteral("app")};
void GameList::RefreshGameDirectory() { void GameList::RefreshGameDirectory() {
if (!UISettings::values.game_dirs.isEmpty() && current_worker != nullptr) { if (!UISettings::values.game_dirs.isEmpty() && current_worker != nullptr) {
@ -670,7 +678,7 @@ QString GameList::FindGameByProgramID(QStandardItem* current_item, u64 program_i
return path; return path;
} }
} }
return ""; return QString();
} }
GameListPlaceholder::GameListPlaceholder(GMainWindow* parent) : QWidget{parent} { GameListPlaceholder::GameListPlaceholder(GMainWindow* parent) : QWidget{parent} {
@ -681,7 +689,7 @@ GameListPlaceholder::GameListPlaceholder(GMainWindow* parent) : QWidget{parent}
image = new QLabel; image = new QLabel;
text = new QLabel; text = new QLabel;
layout->setAlignment(Qt::AlignCenter); layout->setAlignment(Qt::AlignCenter);
image->setPixmap(QIcon::fromTheme("plus_folder").pixmap(200)); image->setPixmap(QIcon::fromTheme(QStringLiteral("plus_folder")).pixmap(200));
text->setText(tr("Double-click to add a new folder to the game list")); text->setText(tr("Double-click to add a new folder to the game list"));
QFont font = text->font(); QFont font = text->font();
@ -698,7 +706,7 @@ GameListPlaceholder::GameListPlaceholder(GMainWindow* parent) : QWidget{parent}
GameListPlaceholder::~GameListPlaceholder() = default; GameListPlaceholder::~GameListPlaceholder() = default;
void GameListPlaceholder::onUpdateThemedIcons() { void GameListPlaceholder::onUpdateThemedIcons() {
image->setPixmap(QIcon::fromTheme("plus_folder").pixmap(200)); image->setPixmap(QIcon::fromTheme(QStringLiteral("plus_folder")).pixmap(200));
} }
void GameListPlaceholder::mouseDoubleClickEvent(QMouseEvent* event) { void GameListPlaceholder::mouseDoubleClickEvent(QMouseEvent* event) {

View File

@ -81,7 +81,7 @@ signals:
private slots: private slots:
void onItemExpanded(const QModelIndex& item); void onItemExpanded(const QModelIndex& item);
void onTextChanged(const QString& newText); void onTextChanged(const QString& new_text);
void onFilterCloseClicked(); void onFilterCloseClicked();
void onUpdateThemedIcons(); void onUpdateThemedIcons();

View File

@ -244,13 +244,13 @@ public:
}; };
// clang-format off // clang-format off
static const std::map<QString, CompatStatus> status_data = { static const std::map<QString, CompatStatus> status_data = {
{"0", {"#5c93ed", QT_TR_NOOP("Perfect"), QT_TR_NOOP("Game functions flawless with no audio or graphical glitches, all tested functionality works as intended without\nany workarounds needed.")}}, {QStringLiteral("0"), {QStringLiteral("#5c93ed"), QT_TR_NOOP("Perfect"), QT_TR_NOOP("Game functions flawless with no audio or graphical glitches, all tested functionality works as intended without\nany workarounds needed.")}},
{"1", {"#47d35c", QT_TR_NOOP("Great"), QT_TR_NOOP("Game functions with minor graphical or audio glitches and is playable from start to finish. May require some\nworkarounds.")}}, {QStringLiteral("1"), {QStringLiteral("#47d35c"), QT_TR_NOOP("Great"), QT_TR_NOOP("Game functions with minor graphical or audio glitches and is playable from start to finish. May require some\nworkarounds.")}},
{"2", {"#94b242", QT_TR_NOOP("Okay"), QT_TR_NOOP("Game functions with major graphical or audio glitches, but game is playable from start to finish with\nworkarounds.")}}, {QStringLiteral("2"), {QStringLiteral("#94b242"), QT_TR_NOOP("Okay"), QT_TR_NOOP("Game functions with major graphical or audio glitches, but game is playable from start to finish with\nworkarounds.")}},
{"3", {"#f2d624", QT_TR_NOOP("Bad"), QT_TR_NOOP("Game functions, but with major graphical or audio glitches. Unable to progress in specific areas due to glitches\neven with workarounds.")}}, {QStringLiteral("3"), {QStringLiteral("#f2d624"), QT_TR_NOOP("Bad"), QT_TR_NOOP("Game functions, but with major graphical or audio glitches. Unable to progress in specific areas due to glitches\neven with workarounds.")}},
{"4", {"#ff0000", QT_TR_NOOP("Intro/Menu"), QT_TR_NOOP("Game is completely unplayable due to major graphical or audio glitches. Unable to progress past the Start\nScreen.")}}, {QStringLiteral("4"), {QStringLiteral("#ff0000"), QT_TR_NOOP("Intro/Menu"), QT_TR_NOOP("Game is completely unplayable due to major graphical or audio glitches. Unable to progress past the Start\nScreen.")}},
{"5", {"#828282", QT_TR_NOOP("Won't Boot"), QT_TR_NOOP("The game crashes when attempting to startup.")}}, {QStringLiteral("5"), {QStringLiteral("#828282"), QT_TR_NOOP("Won't Boot"), QT_TR_NOOP("The game crashes when attempting to startup.")}},
{"99", {"#000000", QT_TR_NOOP("Not Tested"), QT_TR_NOOP("The game has not yet been tested.")}}}; {QStringLiteral("99"), {QStringLiteral("#000000"), QT_TR_NOOP("Not Tested"), QT_TR_NOOP("The game has not yet been tested.")}}};
// clang-format on // clang-format on
auto iterator = status_data.find(compatibility); auto iterator = status_data.find(compatibility);

View File

@ -91,7 +91,7 @@ void GameListWorker::AddFstEntriesToGameList(const std::string& dir_path, unsign
auto it = FindMatchingCompatibilityEntry(compatibility_list, program_id); auto it = FindMatchingCompatibilityEntry(compatibility_list, program_id);
// The game list uses this as compatibility number for untested games // The game list uses this as compatibility number for untested games
QString compatibility("99"); QString compatibility(QStringLiteral("99"));
if (it != compatibility_list.end()) if (it != compatibility_list.end())
compatibility = it->second.first; compatibility = it->second.first;
@ -121,7 +121,7 @@ void GameListWorker::AddFstEntriesToGameList(const std::string& dir_path, unsign
void GameListWorker::run() { void GameListWorker::run() {
stop_processing = false; stop_processing = false;
for (UISettings::GameDir& game_dir : game_dirs) { for (UISettings::GameDir& game_dir : game_dirs) {
if (game_dir.path == "INSTALLED") { if (game_dir.path == QStringLiteral("INSTALLED")) {
QString games_path = QString games_path =
QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir)) + QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir)) +
"Nintendo " "Nintendo "
@ -138,7 +138,7 @@ void GameListWorker::run() {
emit DirEntryReady({game_list_dir}); emit DirEntryReady({game_list_dir});
AddFstEntriesToGameList(games_path.toStdString(), 2, game_list_dir); AddFstEntriesToGameList(games_path.toStdString(), 2, game_list_dir);
AddFstEntriesToGameList(demos_path.toStdString(), 2, game_list_dir); AddFstEntriesToGameList(demos_path.toStdString(), 2, game_list_dir);
} else if (game_dir.path == "SYSTEM") { } else if (game_dir.path == QStringLiteral("SYSTEM")) {
QString path = QString path =
QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::NANDDir)) + QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::NANDDir)) +
"00000000000000000000000000000000/title/00040010"; "00000000000000000000000000000000/title/00040010";