2021-12-13 12:12:54 +00:00
|
|
|
/* PCSX2 - PS2 Emulator for PCs
|
|
|
|
* Copyright (C) 2002-2022 PCSX2 Dev Team
|
|
|
|
*
|
|
|
|
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
|
|
|
* of the GNU Lesser General Public License as published by the Free Software Found-
|
|
|
|
* ation, either version 3 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
|
|
|
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
|
|
|
* PURPOSE. See the GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License along with PCSX2.
|
|
|
|
* If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "PrecompiledHeader.h"
|
|
|
|
|
|
|
|
#include <QtCore/QAbstractTableModel>
|
|
|
|
#include <QtCore/QDebug>
|
|
|
|
#include <QtCore/QSettings>
|
|
|
|
#include <QtCore/QUrl>
|
|
|
|
#include <QtWidgets/QCheckBox>
|
|
|
|
#include <QtWidgets/QFileDialog>
|
|
|
|
#include <QtWidgets/QHeaderView>
|
|
|
|
#include <QtWidgets/QMenu>
|
|
|
|
#include <QtWidgets/QMessageBox>
|
|
|
|
#include <algorithm>
|
|
|
|
|
|
|
|
#include "GameListSettingsWidget.h"
|
|
|
|
#include "MainWindow.h"
|
|
|
|
#include "QtHost.h"
|
|
|
|
#include "QtUtils.h"
|
|
|
|
|
2022-02-15 14:29:18 +00:00
|
|
|
GameListSettingsWidget::GameListSettingsWidget(SettingsDialog* dialog, QWidget* parent)
|
2021-12-13 12:12:54 +00:00
|
|
|
: QWidget(parent)
|
|
|
|
{
|
|
|
|
m_ui.setupUi(this);
|
|
|
|
|
|
|
|
m_ui.searchDirectoryList->setSelectionMode(QAbstractItemView::SingleSelection);
|
|
|
|
m_ui.searchDirectoryList->setSelectionBehavior(QAbstractItemView::SelectRows);
|
|
|
|
m_ui.searchDirectoryList->setAlternatingRowColors(true);
|
|
|
|
m_ui.searchDirectoryList->setShowGrid(false);
|
|
|
|
m_ui.searchDirectoryList->horizontalHeader()->setHighlightSections(false);
|
|
|
|
m_ui.searchDirectoryList->verticalHeader()->hide();
|
|
|
|
m_ui.searchDirectoryList->setCurrentIndex({});
|
|
|
|
m_ui.searchDirectoryList->setContextMenuPolicy(Qt::ContextMenuPolicy::CustomContextMenu);
|
|
|
|
|
|
|
|
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.addExcludedPath, &QPushButton::clicked, this, &GameListSettingsWidget::onAddExcludedPathButtonClicked);
|
|
|
|
connect(m_ui.removeExcludedPath, &QPushButton::clicked, this,
|
|
|
|
&GameListSettingsWidget::onRemoveExcludedPathButtonClicked);
|
|
|
|
connect(m_ui.rescanAllGames, &QPushButton::clicked, this, &GameListSettingsWidget::onRescanAllGamesClicked);
|
|
|
|
connect(m_ui.scanForNewGames, &QPushButton::clicked, this, &GameListSettingsWidget::onScanForNewGamesClicked);
|
|
|
|
|
|
|
|
refreshDirectoryList();
|
|
|
|
refreshExclusionList();
|
|
|
|
}
|
|
|
|
|
|
|
|
GameListSettingsWidget::~GameListSettingsWidget() = default;
|
|
|
|
|
|
|
|
bool GameListSettingsWidget::addExcludedPath(const std::string& path)
|
|
|
|
{
|
|
|
|
if (!QtHost::AddBaseValueToStringList("GameList", "ExcludedPaths", path.c_str()))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
m_ui.excludedPaths->addItem(QString::fromStdString(path));
|
|
|
|
g_main_window->refreshGameList(false);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void GameListSettingsWidget::refreshExclusionList()
|
|
|
|
{
|
|
|
|
m_ui.excludedPaths->clear();
|
|
|
|
|
|
|
|
const std::vector<std::string> paths(QtHost::GetBaseStringListSetting("GameList", "ExcludedPaths"));
|
|
|
|
for (const std::string& path : paths)
|
|
|
|
m_ui.excludedPaths->addItem(QString::fromStdString(path));
|
|
|
|
}
|
|
|
|
|
|
|
|
void GameListSettingsWidget::resizeEvent(QResizeEvent* event)
|
|
|
|
{
|
|
|
|
QWidget::resizeEvent(event);
|
|
|
|
|
|
|
|
QtUtils::ResizeColumnsForTableView(m_ui.searchDirectoryList, {-1, 100});
|
|
|
|
}
|
|
|
|
|
|
|
|
void GameListSettingsWidget::addPathToTable(const std::string& path, bool recursive)
|
|
|
|
{
|
|
|
|
const int row = m_ui.searchDirectoryList->rowCount();
|
|
|
|
m_ui.searchDirectoryList->insertRow(row);
|
|
|
|
|
|
|
|
QTableWidgetItem* item = new QTableWidgetItem();
|
|
|
|
item->setText(QString::fromStdString(path));
|
|
|
|
m_ui.searchDirectoryList->setItem(row, 0, item);
|
|
|
|
|
|
|
|
QCheckBox* cb = new QCheckBox(m_ui.searchDirectoryList);
|
|
|
|
m_ui.searchDirectoryList->setCellWidget(row, 1, cb);
|
|
|
|
cb->setChecked(recursive);
|
|
|
|
|
|
|
|
connect(cb, &QCheckBox::stateChanged, [this, item](int state) {
|
|
|
|
const std::string path(item->text().toStdString());
|
|
|
|
if (state == Qt::Checked)
|
|
|
|
{
|
|
|
|
QtHost::RemoveBaseValueFromStringList("GameList", "Paths", path.c_str());
|
|
|
|
QtHost::AddBaseValueToStringList("GameList", "RecursivePaths", path.c_str());
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
QtHost::RemoveBaseValueFromStringList("GameList", "RecursivePaths", path.c_str());
|
|
|
|
QtHost::AddBaseValueToStringList("GameList", "Paths", path.c_str());
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
void GameListSettingsWidget::refreshDirectoryList()
|
|
|
|
{
|
|
|
|
QSignalBlocker sb(m_ui.searchDirectoryList);
|
|
|
|
while (m_ui.searchDirectoryList->rowCount() > 0)
|
|
|
|
m_ui.searchDirectoryList->removeRow(0);
|
|
|
|
|
|
|
|
std::vector<std::string> path_list = QtHost::GetBaseStringListSetting("GameList", "Paths");
|
|
|
|
for (const std::string& entry : path_list)
|
|
|
|
addPathToTable(entry, false);
|
|
|
|
|
|
|
|
path_list = QtHost::GetBaseStringListSetting("GameList", "RecursivePaths");
|
|
|
|
for (const std::string& entry : path_list)
|
|
|
|
addPathToTable(entry, true);
|
|
|
|
|
|
|
|
m_ui.searchDirectoryList->sortByColumn(0, Qt::AscendingOrder);
|
|
|
|
}
|
|
|
|
|
|
|
|
void GameListSettingsWidget::addSearchDirectory(const QString& path, bool recursive)
|
|
|
|
{
|
|
|
|
const std::string spath(path.toStdString());
|
|
|
|
QtHost::RemoveBaseValueFromStringList("GameList", recursive ? "Paths" : "RecursivePaths", spath.c_str());
|
|
|
|
QtHost::AddBaseValueToStringList("GameList", recursive ? "RecursivePaths" : "Paths", spath.c_str());
|
|
|
|
refreshDirectoryList();
|
|
|
|
g_main_window->refreshGameList(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
void GameListSettingsWidget::removeSearchDirectory(const QString& path)
|
|
|
|
{
|
|
|
|
const std::string spath(path.toStdString());
|
|
|
|
if (!QtHost::RemoveBaseValueFromStringList("GameList", "Paths", spath.c_str()) &&
|
|
|
|
!QtHost::RemoveBaseValueFromStringList("GameList", "RecursivePaths", spath.c_str()))
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
refreshDirectoryList();
|
|
|
|
g_main_window->refreshGameList(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
void GameListSettingsWidget::onDirectoryListContextMenuRequested(const QPoint& point)
|
|
|
|
{
|
|
|
|
QModelIndexList selection = m_ui.searchDirectoryList->selectionModel()->selectedIndexes();
|
|
|
|
if (selection.size() < 1)
|
|
|
|
return;
|
|
|
|
|
|
|
|
const int row = selection[0].row();
|
|
|
|
|
|
|
|
QMenu menu;
|
|
|
|
menu.addAction(tr("Remove"), [this]() { onRemoveSearchDirectoryButtonClicked(); });
|
|
|
|
menu.addSeparator();
|
|
|
|
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));
|
|
|
|
}
|
|
|
|
|
|
|
|
void GameListSettingsWidget::addSearchDirectory(QWidget* parent_widget)
|
|
|
|
{
|
|
|
|
QString dir =
|
|
|
|
QDir::toNativeSeparators(QFileDialog::getExistingDirectory(parent_widget, tr("Select Search Directory")));
|
|
|
|
|
|
|
|
if (dir.isEmpty())
|
|
|
|
return;
|
|
|
|
|
|
|
|
QMessageBox::StandardButton selection =
|
|
|
|
QMessageBox::question(this, tr("Scan Recursively?"),
|
|
|
|
tr("Would you like to scan the directory \"%1\" recursively?\n\nScanning recursively takes "
|
|
|
|
"more time, but will identify files in subdirectories.")
|
|
|
|
.arg(dir),
|
|
|
|
QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel);
|
|
|
|
if (selection == QMessageBox::Cancel)
|
|
|
|
return;
|
|
|
|
|
|
|
|
const bool recursive = (selection == QMessageBox::Yes);
|
|
|
|
addSearchDirectory(dir, recursive);
|
|
|
|
}
|
|
|
|
|
|
|
|
void GameListSettingsWidget::onAddSearchDirectoryButtonClicked()
|
|
|
|
{
|
|
|
|
addSearchDirectory(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
void GameListSettingsWidget::onRemoveSearchDirectoryButtonClicked()
|
|
|
|
{
|
|
|
|
const int row = m_ui.searchDirectoryList->currentRow();
|
|
|
|
QTableWidgetItem* item = (row >= 0) ? m_ui.searchDirectoryList->takeItem(row, 0) : nullptr;
|
|
|
|
if (!item)
|
|
|
|
return;
|
|
|
|
|
|
|
|
removeSearchDirectory(item->text());
|
|
|
|
delete item;
|
|
|
|
}
|
|
|
|
|
|
|
|
void GameListSettingsWidget::onAddExcludedPathButtonClicked()
|
|
|
|
{
|
|
|
|
QString path =
|
|
|
|
QDir::toNativeSeparators(QFileDialog::getOpenFileName(QtUtils::GetRootWidget(this), tr("Select Path")));
|
|
|
|
if (path.isEmpty())
|
|
|
|
return;
|
|
|
|
|
|
|
|
addExcludedPath(path.toStdString());
|
|
|
|
}
|
|
|
|
|
|
|
|
void GameListSettingsWidget::onRemoveExcludedPathButtonClicked()
|
|
|
|
{
|
|
|
|
const int row = m_ui.excludedPaths->currentRow();
|
|
|
|
QListWidgetItem* item = (row >= 0) ? m_ui.excludedPaths->takeItem(row) : 0;
|
|
|
|
if (!item)
|
|
|
|
return;
|
|
|
|
|
|
|
|
QtHost::RemoveBaseValueFromStringList("GameList", "ExcludedPaths", item->text().toUtf8().constData());
|
|
|
|
delete item;
|
|
|
|
|
|
|
|
g_main_window->refreshGameList(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
void GameListSettingsWidget::onRescanAllGamesClicked()
|
|
|
|
{
|
|
|
|
g_main_window->refreshGameList(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
void GameListSettingsWidget::onScanForNewGamesClicked()
|
|
|
|
{
|
|
|
|
g_main_window->refreshGameList(false);
|
|
|
|
}
|