diff --git a/src/duckstation-qt/CMakeLists.txt b/src/duckstation-qt/CMakeLists.txt
index 32cba8593..29796c9ff 100644
--- a/src/duckstation-qt/CMakeLists.txt
+++ b/src/duckstation-qt/CMakeLists.txt
@@ -87,8 +87,6 @@ set(SRCS
gamelistmodel.h
gamelistrefreshthread.cpp
gamelistrefreshthread.h
- gamelistsearchdirectoriesmodel.cpp
- gamelistsearchdirectoriesmodel.h
gamelistsettingswidget.cpp
gamelistsettingswidget.h
gamelistsettingswidget.ui
diff --git a/src/duckstation-qt/duckstation-qt.vcxproj b/src/duckstation-qt/duckstation-qt.vcxproj
index 01e89f29a..a21b7a00b 100644
--- a/src/duckstation-qt/duckstation-qt.vcxproj
+++ b/src/duckstation-qt/duckstation-qt.vcxproj
@@ -23,7 +23,6 @@
-
@@ -72,7 +71,6 @@
-
@@ -240,7 +238,6 @@
-
diff --git a/src/duckstation-qt/duckstation-qt.vcxproj.filters b/src/duckstation-qt/duckstation-qt.vcxproj.filters
index 2277aa219..3de628b98 100644
--- a/src/duckstation-qt/duckstation-qt.vcxproj.filters
+++ b/src/duckstation-qt/duckstation-qt.vcxproj.filters
@@ -22,7 +22,6 @@
-
@@ -118,9 +117,6 @@
moc
-
- moc
-
moc
@@ -225,7 +221,6 @@
-
diff --git a/src/duckstation-qt/gamelistsearchdirectoriesmodel.cpp b/src/duckstation-qt/gamelistsearchdirectoriesmodel.cpp
deleted file mode 100644
index 4cf667164..000000000
--- a/src/duckstation-qt/gamelistsearchdirectoriesmodel.cpp
+++ /dev/null
@@ -1,184 +0,0 @@
-// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin
-// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
-
-#include "gamelistsearchdirectoriesmodel.h"
-#include "mainwindow.h"
-#include "qthost.h"
-#include "qtutils.h"
-#include
-
-GameListSearchDirectoriesModel::GameListSearchDirectoriesModel(EmuThread* host_interface)
- : m_host_interface(host_interface)
-{
- loadFromSettings();
-}
-
-GameListSearchDirectoriesModel::~GameListSearchDirectoriesModel() = default;
-
-int GameListSearchDirectoriesModel::columnCount(const QModelIndex& parent) const
-{
- if (parent.isValid())
- return 0;
-
- return 2;
-}
-
-QVariant GameListSearchDirectoriesModel::headerData(int section, Qt::Orientation orientation,
- int role /*= Qt::DisplayRole*/) const
-{
- if (orientation != Qt::Horizontal || role != Qt::DisplayRole)
- return {};
-
- if (section == 0)
- return tr("Path");
- else
- return tr("Recursive");
-}
-
-int GameListSearchDirectoriesModel::rowCount(const QModelIndex& parent) const
-{
- if (parent.isValid())
- return 0;
-
- return static_cast(m_entries.size());
-}
-
-QVariant GameListSearchDirectoriesModel::data(const QModelIndex& index, int role /*= Qt::DisplayRole*/) const
-{
- if (!index.isValid())
- return {};
-
- const int row = index.row();
- const int column = index.column();
- if (row < 0 || row >= static_cast(m_entries.size()))
- return {};
-
- const Entry& entry = m_entries[row];
- if (role == Qt::CheckStateRole)
- {
- if (column == 1)
- return entry.recursive ? Qt::Checked : Qt::Unchecked;
- }
- else if (role == Qt::DisplayRole)
- {
- if (column == 0)
- return entry.path;
- }
-
- return {};
-}
-
-bool GameListSearchDirectoriesModel::setData(const QModelIndex& index, const QVariant& value, int role)
-{
- if (!index.isValid())
- return false;
-
- const int row = index.row();
- const int column = index.column();
- if (row < 0 || row >= static_cast(m_entries.size()))
- return false;
-
- if (column != 1 || role == Qt::CheckStateRole)
- return false;
-
- Entry& entry = m_entries[row];
- entry.recursive = value == Qt::Checked;
- saveToSettings();
- g_main_window->refreshGameList(false);
- return true;
-}
-
-void GameListSearchDirectoriesModel::addEntry(const QString& path, bool recursive)
-{
- auto existing = std::find_if(m_entries.begin(), m_entries.end(), [path](const Entry& e) { return e.path == path; });
- if (existing != m_entries.end())
- {
- const int row = static_cast(existing - m_entries.begin());
- existing->recursive = recursive;
- dataChanged(index(row, 1), index(row, 1), QVector{Qt::CheckStateRole});
- }
- else
- {
- beginInsertRows(QModelIndex(), static_cast(m_entries.size()), static_cast(m_entries.size()));
- m_entries.push_back({path, recursive});
- endInsertRows();
- }
-
- saveToSettings();
- g_main_window->refreshGameList(false);
-}
-
-void GameListSearchDirectoriesModel::removeEntry(int row)
-{
- if (row < 0 || row >= static_cast(m_entries.size()))
- return;
-
- beginRemoveRows(QModelIndex(), row, row);
- m_entries.erase(m_entries.begin() + row);
- endRemoveRows();
-
- saveToSettings();
- g_main_window->refreshGameList(false);
-}
-
-bool GameListSearchDirectoriesModel::isEntryRecursive(int row) const
-{
- return (row < 0 || row >= static_cast(m_entries.size())) ? false : m_entries[row].recursive;
-}
-
-void GameListSearchDirectoriesModel::setEntryRecursive(int row, bool recursive)
-{
- if (row < 0 || row >= static_cast(m_entries.size()))
- return;
-
- m_entries[row].recursive = recursive;
- emit dataChanged(index(row, 1), index(row, 1), {Qt::CheckStateRole});
-
- saveToSettings();
- g_main_window->refreshGameList(false);
-}
-
-void GameListSearchDirectoriesModel::openEntryInExplorer(QWidget* parent, int row) const
-{
- if (row < 0 || row >= static_cast(m_entries.size()))
- return;
-
- QtUtils::OpenURL(parent, QUrl::fromLocalFile(m_entries[row].path));
-}
-
-void GameListSearchDirectoriesModel::loadFromSettings()
-{
- std::vector path_list = Host::GetBaseStringListSetting("GameList", "Paths");
- for (std::string& entry : path_list)
- m_entries.push_back({QString::fromStdString(entry), false});
-
- path_list = Host::GetBaseStringListSetting("GameList", "RecursivePaths");
- for (std::string& entry : path_list)
- m_entries.push_back({QString::fromStdString(entry), true});
-}
-
-void GameListSearchDirectoriesModel::saveToSettings()
-{
- std::vector paths;
- std::vector recursive_paths;
-
- for (const Entry& entry : m_entries)
- {
- if (entry.recursive)
- recursive_paths.push_back(entry.path.toStdString());
- else
- paths.push_back(entry.path.toStdString());
- }
-
- if (paths.empty())
- Host::DeleteBaseSettingValue("GameList", "Paths");
- else
- Host::SetBaseStringListSettingValue("GameList", "Paths", paths);
-
- if (recursive_paths.empty())
- Host::DeleteBaseSettingValue("GameList", "RecursivePaths");
- else
- Host::SetBaseStringListSettingValue("GameList", "RecursivePaths", recursive_paths);
-
- Host::CommitBaseSettingChanges();
-}
diff --git a/src/duckstation-qt/gamelistsearchdirectoriesmodel.h b/src/duckstation-qt/gamelistsearchdirectoriesmodel.h
deleted file mode 100644
index b1a27680c..000000000
--- a/src/duckstation-qt/gamelistsearchdirectoriesmodel.h
+++ /dev/null
@@ -1,44 +0,0 @@
-// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin
-// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
-
-#pragma once
-#include
-#include
-#include
-
-class EmuThread;
-
-class GameListSearchDirectoriesModel : public QAbstractTableModel
-{
- Q_OBJECT
-
-public:
- GameListSearchDirectoriesModel(EmuThread* host_interface);
- ~GameListSearchDirectoriesModel();
-
- int columnCount(const QModelIndex& parent) const override;
- QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
- int rowCount(const QModelIndex& parent) const override;
- QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
- bool setData(const QModelIndex& index, const QVariant& value, int role) override;
-
- void addEntry(const QString& path, bool recursive);
- void removeEntry(int row);
-
- bool isEntryRecursive(int row) const;
- void setEntryRecursive(int row, bool recursive);
-
- void openEntryInExplorer(QWidget* parent, int row) const;
- void loadFromSettings();
- void saveToSettings();
-
-private:
- struct Entry
- {
- QString path;
- bool recursive;
- };
-
- EmuThread* m_host_interface;
- std::vector m_entries;
-};
diff --git a/src/duckstation-qt/gamelistsettingswidget.cpp b/src/duckstation-qt/gamelistsettingswidget.cpp
index 2593f96b8..f38132e31 100644
--- a/src/duckstation-qt/gamelistsettingswidget.cpp
+++ b/src/duckstation-qt/gamelistsettingswidget.cpp
@@ -1,9 +1,8 @@
-// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin
+// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
#include "gamelistsettingswidget.h"
#include "core/game_list.h"
-#include "gamelistsearchdirectoriesmodel.h"
#include "mainwindow.h"
#include "qthost.h"
#include "qtutils.h"
@@ -16,6 +15,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -26,8 +26,6 @@ GameListSettingsWidget::GameListSettingsWidget(SettingsWindow* dialog, QWidget*
{
m_ui.setupUi(this);
- m_search_directories_model = new GameListSearchDirectoriesModel(g_emu_thread);
- m_ui.searchDirectoryList->setModel(m_search_directories_model);
m_ui.searchDirectoryList->setSelectionMode(QAbstractItemView::SingleSelection);
m_ui.searchDirectoryList->setSelectionBehavior(QAbstractItemView::SelectRows);
m_ui.searchDirectoryList->setAlternatingRowColors(true);
@@ -37,14 +35,13 @@ GameListSettingsWidget::GameListSettingsWidget(SettingsWindow* dialog, QWidget*
m_ui.searchDirectoryList->setCurrentIndex({});
m_ui.searchDirectoryList->setContextMenuPolicy(Qt::ContextMenuPolicy::CustomContextMenu);
- connect(m_ui.searchDirectoryList, &QTableView::clicked, this, &GameListSettingsWidget::onDirectoryListItemClicked);
- connect(m_ui.searchDirectoryList, &QTableView::customContextMenuRequested, this,
+ connect(m_ui.searchDirectoryList, &QTableWidget::customContextMenuRequested, this,
&GameListSettingsWidget::onDirectoryListContextMenuRequested);
connect(m_ui.addSearchDirectoryButton, &QPushButton::clicked, this,
&GameListSettingsWidget::onAddSearchDirectoryButtonClicked);
connect(m_ui.removeSearchDirectoryButton, &QPushButton::clicked, this,
&GameListSettingsWidget::onRemoveSearchDirectoryButtonClicked);
- connect(m_ui.searchDirectoryList->selectionModel(), &QItemSelectionModel::selectionChanged, this,
+ connect(m_ui.searchDirectoryList, &QTableWidget::itemSelectionChanged, this,
&GameListSettingsWidget::onSearchDirectoriesSelectionChanged);
connect(m_ui.addExcludedFile, &QPushButton::clicked, this, &GameListSettingsWidget::onAddExcludedFileButtonClicked);
connect(m_ui.addExcludedFolder, &QPushButton::clicked, this,
@@ -56,6 +53,7 @@ GameListSettingsWidget::GameListSettingsWidget(SettingsWindow* dialog, QWidget*
connect(m_ui.rescanAllGames, &QPushButton::clicked, this, &GameListSettingsWidget::onRescanAllGamesClicked);
connect(m_ui.scanForNewGames, &QPushButton::clicked, this, &GameListSettingsWidget::onScanForNewGamesClicked);
+ refreshDirectoryList();
refreshExclusionList();
}
@@ -83,24 +81,95 @@ void GameListSettingsWidget::refreshExclusionList()
m_ui.removeExcludedPath->setEnabled(false);
}
-void GameListSettingsWidget::resizeEvent(QResizeEvent* event)
+bool GameListSettingsWidget::event(QEvent* event)
{
- QWidget::resizeEvent(event);
+ bool res = QWidget::event(event);
- QtUtils::ResizeColumnsForTableView(m_ui.searchDirectoryList, {-1, 100});
+ switch (event->type())
+ {
+ case QEvent::LayoutRequest:
+ case QEvent::Resize:
+ QtUtils::ResizeColumnsForTableView(m_ui.searchDirectoryList, {-1, 100});
+ break;
+
+ default:
+ break;
+ }
+
+ return res;
}
-void GameListSettingsWidget::onDirectoryListItemClicked(const QModelIndex& index)
+void GameListSettingsWidget::addPathToTable(const std::string& path, bool recursive)
{
- if (!index.isValid())
- return;
+ const int row = m_ui.searchDirectoryList->rowCount();
+ m_ui.searchDirectoryList->insertRow(row);
- const int row = index.row();
- const int column = index.column();
- if (column != 1)
- return;
+ QTableWidgetItem* item = new QTableWidgetItem();
+ item->setText(QString::fromStdString(path));
+ item->setFlags(item->flags() & ~(Qt::ItemIsEditable));
+ m_ui.searchDirectoryList->setItem(row, 0, item);
- m_search_directories_model->setEntryRecursive(row, !m_search_directories_model->isEntryRecursive(row));
+ QCheckBox* cb = new QCheckBox(m_ui.searchDirectoryList);
+ m_ui.searchDirectoryList->setCellWidget(row, 1, cb);
+ cb->setChecked(recursive);
+
+ connect(cb, &QCheckBox::checkStateChanged, this, [item](Qt::CheckState state) {
+ const std::string path(item->text().toStdString());
+ if (state == Qt::Checked)
+ {
+ Host::RemoveValueFromBaseStringListSetting("GameList", "Paths", path.c_str());
+ Host::AddValueToBaseStringListSetting("GameList", "RecursivePaths", path.c_str());
+ }
+ else
+ {
+ Host::RemoveValueFromBaseStringListSetting("GameList", "RecursivePaths", path.c_str());
+ Host::AddValueToBaseStringListSetting("GameList", "Paths", path.c_str());
+ }
+ Host::CommitBaseSettingChanges();
+ g_main_window->refreshGameList(false);
+ });
+}
+
+void GameListSettingsWidget::refreshDirectoryList()
+{
+ QSignalBlocker sb(m_ui.searchDirectoryList);
+ while (m_ui.searchDirectoryList->rowCount() > 0)
+ m_ui.searchDirectoryList->removeRow(0);
+
+ std::vector path_list = Host::GetBaseStringListSetting("GameList", "Paths");
+ for (const std::string& entry : path_list)
+ addPathToTable(entry, false);
+
+ path_list = Host::GetBaseStringListSetting("GameList", "RecursivePaths");
+ for (const std::string& entry : path_list)
+ addPathToTable(entry, true);
+
+ m_ui.searchDirectoryList->sortByColumn(0, Qt::AscendingOrder);
+ m_ui.removeSearchDirectoryButton->setEnabled(false);
+}
+
+void GameListSettingsWidget::addSearchDirectory(const QString& path, bool recursive)
+{
+ const std::string spath(path.toStdString());
+ Host::RemoveValueFromBaseStringListSetting("GameList", recursive ? "Paths" : "RecursivePaths", spath.c_str());
+ Host::AddValueToBaseStringListSetting("GameList", recursive ? "RecursivePaths" : "Paths", spath.c_str());
+ Host::CommitBaseSettingChanges();
+ refreshDirectoryList();
+ g_main_window->refreshGameList(false);
+}
+
+void GameListSettingsWidget::removeSearchDirectory(const QString& path)
+{
+ const std::string spath(path.toStdString());
+ if (!Host::RemoveValueFromBaseStringListSetting("GameList", "Paths", spath.c_str()) &&
+ !Host::RemoveValueFromBaseStringListSetting("GameList", "RecursivePaths", spath.c_str()))
+ {
+ return;
+ }
+
+ Host::CommitBaseSettingChanges();
+ refreshDirectoryList();
+ g_main_window->refreshGameList(false);
}
void GameListSettingsWidget::onDirectoryListContextMenuRequested(const QPoint& point)
@@ -112,10 +181,11 @@ void GameListSettingsWidget::onDirectoryListContextMenuRequested(const QPoint& p
const int row = selection[0].row();
QMenu menu;
- menu.addAction(tr("Remove"), [this, row]() { m_search_directories_model->removeEntry(row); });
+ menu.addAction(tr("Remove"), [this]() { onRemoveSearchDirectoryButtonClicked(); });
menu.addSeparator();
- menu.addAction(tr("Open Directory..."),
- [this, row]() { m_search_directories_model->openEntryInExplorer(this, row); });
+ menu.addAction(tr("Open Directory..."), [this, row]() {
+ QtUtils::OpenURL(this, QUrl::fromLocalFile(m_ui.searchDirectoryList->item(row, 0)->text()));
+ });
menu.exec(m_ui.searchDirectoryList->mapToGlobal(point));
}
@@ -137,7 +207,7 @@ void GameListSettingsWidget::addSearchDirectory(QWidget* parent_widget)
return;
const bool recursive = (selection == QMessageBox::Yes);
- m_search_directories_model->addEntry(dir, recursive);
+ addSearchDirectory(dir, recursive);
}
void GameListSettingsWidget::onAddSearchDirectoryButtonClicked()
@@ -147,12 +217,13 @@ void GameListSettingsWidget::onAddSearchDirectoryButtonClicked()
void GameListSettingsWidget::onRemoveSearchDirectoryButtonClicked()
{
- QModelIndexList selection = m_ui.searchDirectoryList->selectionModel()->selectedIndexes();
- if (selection.size() < 1)
+ const int row = m_ui.searchDirectoryList->currentRow();
+ QTableWidgetItem* item = (row >= 0) ? m_ui.searchDirectoryList->takeItem(row, 0) : nullptr;
+ if (!item)
return;
- const int row = selection[0].row();
- m_search_directories_model->removeEntry(row);
+ removeSearchDirectory(item->text());
+ delete item;
}
void GameListSettingsWidget::onSearchDirectoriesSelectionChanged()
diff --git a/src/duckstation-qt/gamelistsettingswidget.h b/src/duckstation-qt/gamelistsettingswidget.h
index d1aa19eab..1427c3a7b 100644
--- a/src/duckstation-qt/gamelistsettingswidget.h
+++ b/src/duckstation-qt/gamelistsettingswidget.h
@@ -1,14 +1,13 @@
-// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin
+// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
#pragma once
-#include
#include
+#include
#include "ui_gamelistsettingswidget.h"
class SettingsWindow;
-class GameListSearchDirectoriesModel;
class GameListSettingsWidget : public QWidget
{
@@ -25,7 +24,6 @@ public Q_SLOTS:
void addSearchDirectory(QWidget* parent_widget);
private Q_SLOTS:
- void onDirectoryListItemClicked(const QModelIndex& index);
void onDirectoryListContextMenuRequested(const QPoint& point);
void onAddSearchDirectoryButtonClicked();
void onRemoveSearchDirectoryButtonClicked();
@@ -38,10 +36,13 @@ private Q_SLOTS:
void onRescanAllGamesClicked();
protected:
- void resizeEvent(QResizeEvent* event);
+ bool event(QEvent* event) override;
private:
- Ui::GameListSettingsWidget m_ui;
+ void addPathToTable(const std::string& path, bool recursive);
+ void refreshDirectoryList();
+ void addSearchDirectory(const QString& path, bool recursive);
+ void removeSearchDirectory(const QString& path);
- GameListSearchDirectoriesModel* m_search_directories_model = nullptr;
+ Ui::GameListSettingsWidget m_ui;
};
diff --git a/src/duckstation-qt/gamelistsettingswidget.ui b/src/duckstation-qt/gamelistsettingswidget.ui
index 0bd3dc6ce..180469183 100644
--- a/src/duckstation-qt/gamelistsettingswidget.ui
+++ b/src/duckstation-qt/gamelistsettingswidget.ui
@@ -59,6 +59,9 @@
+
+ Qt::ToolButtonTextBesideIcon
+
-
@@ -75,12 +78,26 @@
+
+ Qt::ToolButtonTextBesideIcon
+
-
-
+
+
+
+ Search Directory
+
+
+
+
+ Scan Recursively
+
+
+
-