Turn things in common into separate libs.

Took 2 hours 27 minutes
This commit is contained in:
Lukas Brübach 2025-10-04 15:10:20 +02:00
parent 53d80efab8
commit 01378b8314
389 changed files with 336 additions and 233 deletions

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,56 @@
#include "../include/settings/card_counter_settings.h"
#include <QColor>
#include <QSettings>
#include <QtMath>
CardCounterSettings::CardCounterSettings(const QString &settingsPath, QObject *parent)
: SettingsManager(settingsPath + "global.ini", parent)
{
}
void CardCounterSettings::setColor(int counterId, const QColor &color)
{
QString key = QString("cards/counters/%1/color").arg(counterId);
if (settings.value(key).value<QColor>() == color)
return;
settings.setValue(key, color);
emit colorChanged(counterId, color);
}
QColor CardCounterSettings::color(int counterId) const
{
QColor defaultColor;
if (counterId < 6) {
// Preserve legacy colors
defaultColor = QColor::fromHsv(counterId * 60, 150, 255);
} else {
// Future-proof support for more counters with pseudo-random colors
int h = (counterId * 37) % 360;
int s = 128 + 64 * qSin((counterId * 97) * 0.1); // 64-192
int v = 196 + 32 * qSin((counterId * 101) * 0.07); // 164-228
defaultColor = QColor::fromHsv(h, s, v);
}
return settings.value(QString("cards/counters/%1/color").arg(counterId), defaultColor).value<QColor>();
}
QString CardCounterSettings::displayName(int counterId) const
{
// Currently, card counters name are fixed to A, B, ..., Z, AA, AB, ...
auto nChars = 1 + counterId / 26;
QString str;
str.resize(nChars);
for (auto it = str.rbegin(); it != str.rend(); ++it) {
*it = QChar('A' + (counterId) % 26);
counterId /= 26;
}
return str;
}

View file

@ -0,0 +1,36 @@
#include "../include/settings/card_database_settings.h"
CardDatabaseSettings::CardDatabaseSettings(const QString &settingPath, QObject *parent)
: SettingsManager(settingPath + "cardDatabase.ini", parent)
{
}
void CardDatabaseSettings::setSortKey(QString shortName, unsigned int sortKey)
{
setValue(sortKey, "sortkey", "sets", std::move(shortName));
}
void CardDatabaseSettings::setEnabled(QString shortName, bool enabled)
{
setValue(enabled, "enabled", "sets", std::move(shortName));
}
void CardDatabaseSettings::setIsKnown(QString shortName, bool isknown)
{
setValue(isknown, "isknown", "sets", std::move(shortName));
}
unsigned int CardDatabaseSettings::getSortKey(QString shortName)
{
return getValue("sortkey", "sets", std::move(shortName)).toUInt();
}
bool CardDatabaseSettings::isEnabled(QString shortName)
{
return getValue("enabled", "sets", std::move(shortName)).toBool();
}
bool CardDatabaseSettings::isKnown(QString shortName)
{
return getValue("isknown", "sets", std::move(shortName)).toBool();
}

View file

@ -0,0 +1,21 @@
#include "../include/settings/card_override_settings.h"
CardOverrideSettings::CardOverrideSettings(const QString &settingPath, QObject *parent)
: SettingsManager(settingPath + "cardPreferenceOverrides.ini", parent)
{
}
void CardOverrideSettings::setCardPreferenceOverride(const CardRef &cardRef)
{
setValue(cardRef.providerId, cardRef.name, "cards");
}
void CardOverrideSettings::deleteCardPreferenceOverride(const QString &cardName)
{
deleteValue(cardName, "cards");
}
QString CardOverrideSettings::getCardPreferenceOverride(const QString &cardName)
{
return getValue(cardName, "cards").toString();
}

View file

@ -0,0 +1,32 @@
#include "../include/settings/debug_settings.h"
#include <QtCore/QFile>
DebugSettings::DebugSettings(const QString &settingPath, QObject *parent)
: SettingsManager(settingPath + "debug.ini", parent)
{
// Create the default debug.ini if it doesn't exist yet
if (!QFile(settingPath + "debug.ini").exists()) {
QFile::copy(":/resources/config/debug.ini", settingPath + "debug.ini");
}
}
bool DebugSettings::getShowCardId()
{
return getValue("showCardId", "debug").toBool();
}
bool DebugSettings::getLocalGameOnStartup()
{
return getValue("onStartup", "localgame").toBool();
}
int DebugSettings::getLocalGamePlayerCount()
{
return getValue("playerCount", "localgame").toInt();
}
QString DebugSettings::getDeckPathForPlayer(const QString &playerName)
{
return getValue(playerName, "localgame", "deck").toString();
}

View file

@ -0,0 +1,29 @@
#include "../include/settings/download_settings.h"
#include "../include/settings/settings_manager.h"
const QStringList DownloadSettings::DEFAULT_DOWNLOAD_URLS = {
"https://api.scryfall.com/cards/!set:uuid!?format=image&face=!prop:side!",
"https://api.scryfall.com/cards/multiverse/!set:muid!?format=image",
"https://gatherer.wizards.com/Handlers/Image.ashx?multiverseid=!set:muid!&type=card",
"https://gatherer.wizards.com/Handlers/Image.ashx?name=!name!&type=card"};
DownloadSettings::DownloadSettings(const QString &settingPath, QObject *parent = nullptr)
: SettingsManager(settingPath + "downloads.ini", parent)
{
}
void DownloadSettings::setDownloadUrls(const QStringList &downloadURLs)
{
setValue(QVariant::fromValue(downloadURLs), "urls", "downloads");
}
QStringList DownloadSettings::getAllURLs()
{
return getValue("urls", "downloads").toStringList();
}
void DownloadSettings::resetToDefaultURLs()
{
setValue(QVariant::fromValue(DEFAULT_DOWNLOAD_URLS), "urls", "downloads");
}

View file

@ -0,0 +1,208 @@
#include "../include/settings/game_filters_settings.h"
#include <QCryptographicHash>
#include <QTime>
GameFiltersSettings::GameFiltersSettings(const QString &settingPath, QObject *parent)
: SettingsManager(settingPath + "gamefilters.ini", parent)
{
}
/*
* The game type might contain special characters, so to use it in
* QSettings we just hash it.
*/
QString GameFiltersSettings::hashGameType(const QString &gameType) const
{
return QCryptographicHash::hash(gameType.toUtf8(), QCryptographicHash::Md5).toHex();
}
void GameFiltersSettings::setHideBuddiesOnlyGames(bool hide)
{
setValue(hide, "hide_buddies_only_games", "filter_games");
}
bool GameFiltersSettings::isHideBuddiesOnlyGames()
{
QVariant previous = getValue("hide_buddies_only_games", "filter_games");
return previous == QVariant() || previous.toBool();
}
void GameFiltersSettings::setHideFullGames(bool hide)
{
setValue(hide, "hide_full_games", "filter_games");
}
bool GameFiltersSettings::isHideFullGames()
{
QVariant previous = getValue("hide_full_games", "filter_games");
return !(previous == QVariant()) && previous.toBool();
}
void GameFiltersSettings::setHideGamesThatStarted(bool hide)
{
setValue(hide, "hide_games_that_started", "filter_games");
}
bool GameFiltersSettings::isHideGamesThatStarted()
{
QVariant previous = getValue("hide_games_that_started", "filter_games");
return !(previous == QVariant()) && previous.toBool();
}
void GameFiltersSettings::setHidePasswordProtectedGames(bool hide)
{
setValue(hide, "hide_password_protected_games", "filter_games");
}
bool GameFiltersSettings::isHidePasswordProtectedGames()
{
QVariant previous = getValue("hide_password_protected_games", "filter_games");
return previous == QVariant() || previous.toBool();
}
void GameFiltersSettings::setHideIgnoredUserGames(bool hide)
{
setValue(hide, "hide_ignored_user_games", "filter_games");
}
bool GameFiltersSettings::isHideIgnoredUserGames()
{
QVariant previous = getValue("hide_ignored_user_games", "filter_games");
return !(previous == QVariant()) && previous.toBool();
}
void GameFiltersSettings::setHideNotBuddyCreatedGames(bool hide)
{
setValue(hide, "hide_not_buddy_created_games", "filter_games");
}
bool GameFiltersSettings::isHideNotBuddyCreatedGames()
{
QVariant previous = getValue("hide_not_buddy_created_games", "filter_games");
return !(previous == QVariant()) && previous.toBool();
}
void GameFiltersSettings::setHideOpenDecklistGames(bool hide)
{
setValue(hide, "hide_open_decklist_games", "filter_games");
}
bool GameFiltersSettings::isHideOpenDecklistGames()
{
QVariant previous = getValue("hide_open_decklist_games", "filter_games");
return !(previous == QVariant()) && previous.toBool();
}
void GameFiltersSettings::setGameNameFilter(QString gameName)
{
setValue(gameName, "game_name_filter", "filter_games");
}
QString GameFiltersSettings::getGameNameFilter()
{
return getValue("game_name_filter", "filter_games").toString();
}
void GameFiltersSettings::setCreatorNameFilter(QString creatorName)
{
setValue(creatorName, "creator_name_filter", "filter_games");
}
QString GameFiltersSettings::getCreatorNameFilter()
{
return getValue("creator_name_filter", "filter_games").toString();
}
void GameFiltersSettings::setMinPlayers(int min)
{
setValue(min, "min_players", "filter_games");
}
int GameFiltersSettings::getMinPlayers()
{
QVariant previous = getValue("min_players", "filter_games");
return previous == QVariant() ? 1 : previous.toInt();
}
void GameFiltersSettings::setMaxPlayers(int max)
{
setValue(max, "max_players", "filter_games");
}
int GameFiltersSettings::getMaxPlayers()
{
QVariant previous = getValue("max_players", "filter_games");
return previous == QVariant() ? 99 : previous.toInt();
}
void GameFiltersSettings::setMaxGameAge(const QTime &maxGameAge)
{
setValue(maxGameAge, "max_game_age_time", "filter_games");
}
QTime GameFiltersSettings::getMaxGameAge()
{
QVariant previous = getValue("max_game_age_time", "filter_games");
return previous.toTime();
}
void GameFiltersSettings::setGameTypeEnabled(QString gametype, bool enabled)
{
setValue(enabled, "game_type/" + hashGameType(gametype), "filter_games");
}
void GameFiltersSettings::setGameHashedTypeEnabled(QString gametypeHASHED, bool enabled)
{
setValue(enabled, gametypeHASHED, "filter_games");
}
bool GameFiltersSettings::isGameTypeEnabled(QString gametype)
{
QVariant previous = getValue("game_type/" + hashGameType(gametype), "filter_games");
return previous == QVariant() ? false : previous.toBool();
}
void GameFiltersSettings::setShowOnlyIfSpectatorsCanWatch(bool show)
{
setValue(show, "show_only_if_spectators_can_watch", "filter_games");
}
bool GameFiltersSettings::isShowOnlyIfSpectatorsCanWatch()
{
QVariant previous = getValue("show_only_if_spectators_can_watch", "filter_games");
return previous == QVariant() ? false : previous.toBool();
}
void GameFiltersSettings::setShowSpectatorPasswordProtected(bool show)
{
setValue(show, "show_spectator_password_protected", "filter_games");
}
bool GameFiltersSettings::isShowSpectatorPasswordProtected()
{
QVariant previous = getValue("show_spectator_password_protected", "filter_games");
return previous == QVariant() ? true : previous.toBool();
}
void GameFiltersSettings::setShowOnlyIfSpectatorsCanChat(bool show)
{
setValue(show, "show_only_if_spectators_can_chat", "filter_games");
}
bool GameFiltersSettings::isShowOnlyIfSpectatorsCanChat()
{
QVariant previous = getValue("show_only_if_spectators_can_chat", "filter_games");
return previous == QVariant() ? true : previous.toBool();
}
void GameFiltersSettings::setShowOnlyIfSpectatorsCanSeeHands(bool show)
{
setValue(show, "show_only_if_spectators_can_see_hands", "filter_games");
}
bool GameFiltersSettings::isShowOnlyIfSpectatorsCanSeeHands()
{
QVariant previous = getValue("show_only_if_spectators_can_see_hands", "filter_games");
return previous == QVariant() ? true : previous.toBool();
}

View file

@ -0,0 +1,207 @@
#include "../include/settings/layouts_settings.h"
LayoutsSettings::LayoutsSettings(const QString &settingPath, QObject *parent)
: SettingsManager(settingPath + "layouts.ini", parent)
{
}
const QByteArray LayoutsSettings::getDeckEditorLayoutState()
{
return getValue("layouts/deckEditor_state").toByteArray();
}
void LayoutsSettings::setDeckEditorLayoutState(const QByteArray &value)
{
setValue(value, "layouts/deckEditor_state");
}
const QByteArray LayoutsSettings::getDeckEditorGeometry()
{
return getValue("layouts/deckEditor_geometry").toByteArray();
}
void LayoutsSettings::setDeckEditorGeometry(const QByteArray &value)
{
setValue(value, "layouts/deckEditor_geometry");
}
QSize LayoutsSettings::getDeckEditorCardSize()
{
QVariant previous = getValue("layouts/deckEditor_CardSize");
return previous == QVariant() ? QSize(250, 500) : previous.toSize();
}
void LayoutsSettings::setDeckEditorCardSize(const QSize &value)
{
setValue(value, "layouts/deckEditor_CardSize");
}
QSize LayoutsSettings::getDeckEditorDeckSize()
{
QVariant previous = getValue("layouts/deckEditor_DeckSize");
return previous == QVariant() ? QSize(250, 360) : previous.toSize();
}
void LayoutsSettings::setDeckEditorDeckSize(const QSize &value)
{
setValue(value, "layouts/deckEditor_DeckSize");
}
QSize LayoutsSettings::getDeckEditorPrintingSelectorSize()
{
QVariant previous = getValue("layouts/deckEditor_PrintingSelectorSize");
return previous == QVariant() ? QSize(525, 250) : previous.toSize();
}
void LayoutsSettings::setDeckEditorPrintingSelectorSize(const QSize &value)
{
setValue(value, "layouts/deckEditor_PrintingSelectorSize");
}
QSize LayoutsSettings::getDeckEditorFilterSize()
{
QVariant previous = getValue("layouts/deckEditor_FilterSize");
return previous == QVariant() ? QSize(250, 250) : previous.toSize();
}
void LayoutsSettings::setDeckEditorFilterSize(const QSize &value)
{
setValue(value, "layouts/deckEditor_FilterSize");
}
const QByteArray LayoutsSettings::getDeckEditorDbHeaderState()
{
return getValue("layouts/deckEditorDbHeader_state").toByteArray();
}
void LayoutsSettings::setDeckEditorDbHeaderState(const QByteArray &value)
{
setValue(value, "layouts/deckEditorDbHeader_state");
}
const QByteArray LayoutsSettings::getSetsDialogHeaderState()
{
return getValue("layouts/setsDialogHeader_state").toByteArray();
}
void LayoutsSettings::setSetsDialogHeaderState(const QByteArray &value)
{
setValue(value, "layouts/setsDialogHeader_state");
}
void LayoutsSettings::setGamePlayAreaGeometry(const QByteArray &value)
{
setValue(value, "layouts/gameplayarea_geometry");
}
void LayoutsSettings::setGamePlayAreaState(const QByteArray &value)
{
setValue(value, "layouts/gameplayarea_state");
}
const QByteArray LayoutsSettings::getGamePlayAreaLayoutState()
{
return getValue("layouts/gameplayarea_state").toByteArray();
}
const QByteArray LayoutsSettings::getGamePlayAreaGeometry()
{
return getValue("layouts/gameplayarea_geometry").toByteArray();
}
const QSize LayoutsSettings::getGameCardInfoSize()
{
QVariant previous = getValue("layouts/gameplayarea_CardInfoSize");
return previous == QVariant() ? QSize(250, 360) : previous.toSize();
}
void LayoutsSettings::setGameCardInfoSize(const QSize &value)
{
setValue(value, "layouts/gameplayarea_CardInfoSize");
}
const QSize LayoutsSettings::getGameMessageLayoutSize()
{
QVariant previous = getValue("layouts/gameplayarea_MessageLayoutSize");
return previous == QVariant() ? QSize(250, 250) : previous.toSize();
}
void LayoutsSettings::setGameMessageLayoutSize(const QSize &value)
{
setValue(value, "layouts/gameplayarea_MessageLayoutSize");
}
const QSize LayoutsSettings::getGamePlayerListSize()
{
QVariant previous = getValue("layouts/gameplayarea_PlayerListSize");
return previous == QVariant() ? QSize(250, 50) : previous.toSize();
}
void LayoutsSettings::setGamePlayerListSize(const QSize &value)
{
setValue(value, "layouts/gameplayarea_PlayerListSize");
}
void LayoutsSettings::setReplayPlayAreaGeometry(const QByteArray &value)
{
setValue(value, "layouts/replayplayarea_geometry");
}
void LayoutsSettings::setReplayPlayAreaState(const QByteArray &value)
{
setValue(value, "layouts/replayplayarea_state");
}
const QByteArray LayoutsSettings::getReplayPlayAreaLayoutState()
{
return getValue("layouts/replayplayarea_state").toByteArray();
}
const QByteArray LayoutsSettings::getReplayPlayAreaGeometry()
{
return getValue("layouts/replayplayarea_geometry").toByteArray();
}
const QSize LayoutsSettings::getReplayCardInfoSize()
{
QVariant previous = getValue("layouts/replayplayarea_CardInfoSize");
return previous == QVariant() ? QSize(250, 360) : previous.toSize();
}
void LayoutsSettings::setReplayCardInfoSize(const QSize &value)
{
setValue(value, "layouts/replayplayarea_CardInfoSize");
}
const QSize LayoutsSettings::getReplayMessageLayoutSize()
{
QVariant previous = getValue("layouts/replayplayarea_MessageLayoutSize");
return previous == QVariant() ? QSize(250, 200) : previous.toSize();
}
void LayoutsSettings::setReplayMessageLayoutSize(const QSize &value)
{
setValue(value, "layouts/replayplayarea_MessageLayoutSize");
}
const QSize LayoutsSettings::getReplayPlayerListSize()
{
QVariant previous = getValue("layouts/replayplayarea_PlayerListSize");
return previous == QVariant() ? QSize(250, 50) : previous.toSize();
}
void LayoutsSettings::setReplayPlayerListSize(const QSize &value)
{
setValue(value, "layouts/replayplayarea_PlayerListSize");
}
const QSize LayoutsSettings::getReplayReplaySize()
{
QVariant previous = getValue("layouts/replayplayarea_ReplaySize");
return previous == QVariant() ? QSize(900, 100) : previous.toSize();
}
void LayoutsSettings::setReplayReplaySize(const QSize &value)
{
setValue(value, "layouts/replayplayarea_ReplaySize");
}

View file

@ -0,0 +1,26 @@
#include "../include/settings/message_settings.h"
MessageSettings::MessageSettings(const QString &settingPath, QObject *parent)
: SettingsManager(settingPath + "messages.ini", parent)
{
}
QString MessageSettings::getMessageAt(int index)
{
return getValue(QString("msg%1").arg(index), "messages").toString();
}
int MessageSettings::getCount()
{
return getValue("count", "messages").toInt();
}
void MessageSettings::setCount(int count)
{
setValue(count, "count", "messages");
}
void MessageSettings::setMessageAt(int index, QString message)
{
setValue(message, QString("msg%1").arg(index), "messages");
}

View file

@ -0,0 +1,42 @@
#include "../include/settings/recents_settings.h"
#define MAX_RECENT_DECK_COUNT 10
RecentsSettings::RecentsSettings(const QString &settingPath, QObject *parent)
: SettingsManager(settingPath + "recents.ini", parent)
{
}
QStringList RecentsSettings::getRecentlyOpenedDeckPaths()
{
return getValue("deckpaths", "deckbuilder").toStringList();
}
void RecentsSettings::clearRecentlyOpenedDeckPaths()
{
deleteValue("deckpaths", "deckbuilder");
emit recentlyOpenedDeckPathsChanged();
}
void RecentsSettings::updateRecentlyOpenedDeckPaths(const QString &deckPath)
{
auto deckPaths = getValue("deckpaths", "deckbuilder").toStringList();
deckPaths.removeAll(deckPath);
deckPaths.prepend(deckPath);
while (deckPaths.size() > MAX_RECENT_DECK_COUNT) {
deckPaths.removeLast();
}
setValue(deckPaths, "deckpaths", "deckbuilder");
emit recentlyOpenedDeckPathsChanged();
}
QString RecentsSettings::getLatestDeckDirPath()
{
return getValue("latestDeckDir", "dirs").toString();
}
void RecentsSettings::setLatestDeckDirPath(const QString &dirPath)
{
setValue(dirPath, "latestDeckDir", "dirs");
}

View file

@ -0,0 +1,291 @@
#include "../include/settings/servers_settings.h"
#include <QDebug>
#include <utility>
ServersSettings::ServersSettings(const QString &settingPath, QObject *parent)
: SettingsManager(settingPath + "servers.ini", parent)
{
}
void ServersSettings::setPreviousHostLogin(int previous)
{
setValue(previous, "previoushostlogin", "server");
}
int ServersSettings::getPreviousHostLogin()
{
QVariant previous = getValue("previoushostlogin", "server");
return previous == QVariant() ? 1 : previous.toInt();
}
void ServersSettings::setPreviousHostList(QStringList list)
{
setValue(list, "previoushosts", "server");
}
QStringList ServersSettings::getPreviousHostList()
{
return getValue("previoushosts", "server").toStringList();
}
void ServersSettings::setPrevioushostName(const QString &name)
{
setValue(name, "previoushostName", "server");
}
QString ServersSettings::getSaveName(QString defaultname)
{
int index = getPrevioushostindex(getPrevioushostName());
QVariant saveName = getValue(QString("saveName%1").arg(index), "server", "server_details");
return saveName == QVariant() ? std::move(defaultname) : saveName.toString();
}
QString ServersSettings::getSite(QString defaultSite)
{
int index = getPrevioushostindex(getPrevioushostName());
QVariant site = getValue(QString("site%1").arg(index), "server", "server_details");
return site == QVariant() ? std::move(defaultSite) : site.toString();
}
QString ServersSettings::getPrevioushostName()
{
QVariant value = getValue("previoushostName", "server");
return value == QVariant() ? "Rooster Ranges" : value.toString();
}
int ServersSettings::getPrevioushostindex(const QString &saveName)
{
int size = getValue("totalServers", "server", "server_details").toInt();
for (int i = 0; i <= size; ++i)
if (saveName == getValue(QString("saveName%1").arg(i), "server", "server_details").toString())
return i;
return -1;
}
QString ServersSettings::getHostname(QString defaultHost)
{
int index = getPrevioushostindex(getPrevioushostName());
QVariant hostname = getValue(QString("server%1").arg(index), "server", "server_details");
return hostname == QVariant() ? std::move(defaultHost) : hostname.toString();
}
QString ServersSettings::getPort(QString defaultPort)
{
int index = getPrevioushostindex(getPrevioushostName());
QVariant port = getValue(QString("port%1").arg(index), "server", "server_details");
qCDebug(ServersSettingsLog) << "getPort() index = " << index << " port.val = " << port.toString();
return port == QVariant() ? std::move(defaultPort) : port.toString();
}
QString ServersSettings::getPlayerName(QString defaultName)
{
int index = getPrevioushostindex(getPrevioushostName());
QVariant name = getValue(QString("username%1").arg(index), "server", "server_details");
qCDebug(ServersSettingsLog) << "getPlayerName() index = " << index << " name.val = " << name.toString();
return name == QVariant() ? std::move(defaultName) : name.toString();
}
QString ServersSettings::getPassword()
{
int index = getPrevioushostindex(getPrevioushostName());
if (getSavePassword())
return getValue(QString("password%1").arg(index), "server", "server_details").toString();
return QString();
}
bool ServersSettings::getSavePassword()
{
int index = getPrevioushostindex(getPrevioushostName());
bool save = getValue(QString("savePassword%1").arg(index), "server", "server_details").toBool();
return save;
}
void ServersSettings::setAutoConnect(int autoconnect)
{
setValue(autoconnect, "auto_connect", "server");
}
int ServersSettings::getAutoConnect()
{
QVariant autoconnect = getValue("auto_connect", "server");
return autoconnect == QVariant() ? 0 : autoconnect.toInt();
}
void ServersSettings::setFPHostName(QString hostname)
{
setValue(hostname, "fphostname", "server");
}
QString ServersSettings::getFPHostname(QString defaultHost)
{
QVariant hostname = getValue("fphostname", "server");
return hostname == QVariant() ? std::move(defaultHost) : hostname.toString();
}
void ServersSettings::setFPPort(QString port)
{
setValue(port, "fpport", "server");
}
QString ServersSettings::getFPPort(QString defaultPort)
{
QVariant port = getValue("fpport", "server");
return port == QVariant() ? std::move(defaultPort) : port.toString();
}
void ServersSettings::setFPPlayerName(QString playerName)
{
setValue(playerName, "fpplayername", "server");
}
QString ServersSettings::getFPPlayerName(QString defaultName)
{
QVariant name = getValue("fpplayername", "server");
return name == QVariant() ? std::move(defaultName) : name.toString();
}
void ServersSettings::setClearDebugLogStatus(bool abIsChecked)
{
setValue(abIsChecked, "save_debug_log", "server");
}
bool ServersSettings::getClearDebugLogStatus(bool abDefaultValue)
{
QVariant cbFlushLog = getValue("save_debug_log", "server");
return cbFlushLog == QVariant() ? abDefaultValue : cbFlushLog.toBool();
}
void ServersSettings::addNewServer(const QString &saveName,
const QString &serv,
const QString &port,
const QString &username,
const QString &password,
bool savePassword,
const QString &site)
{
if (updateExistingServer(saveName, serv, port, username, password, savePassword, site))
return;
int index = getValue("totalServers", "server", "server_details").toInt() + 1;
setValue(saveName, QString("saveName%1").arg(index), "server", "server_details");
setValue(serv, QString("server%1").arg(index), "server", "server_details");
setValue(port, QString("port%1").arg(index), "server", "server_details");
setValue(username, QString("username%1").arg(index), "server", "server_details");
setValue(savePassword, QString("savePassword%1").arg(index), "server", "server_details");
setValue(index, "totalServers", "server", "server_details");
setValue(password, QString("password%1").arg(index), "server", "server_details");
setValue(site, QString("site%1").arg(index), "server", "server_details");
}
void ServersSettings::removeServer(QString servAddr)
{
int size = getValue("totalServers", "server", "server_details").toInt();
bool found = false;
for (int i = 0; i <= size; ++i) {
if (!found) {
// find entry and overwrite it
if (servAddr == getValue(QString("server%1").arg(i), "server", "server_details").toString()) {
found = true;
}
} else {
// move all other entries after it one back, overwriting the previous one
int previous = i - 1; // we delete only one entry
setValue(getValue(QString("server%1").arg(i), "server", "server_details"),
QString("server%1").arg(previous), "server", "server_details");
setValue(getValue(QString("port%1").arg(i), "server", "server_details"), QString("port%1").arg(previous),
"server", "server_details");
setValue(getValue(QString("username%1").arg(i), "server", "server_details"),
QString("username%1").arg(previous), "server", "server_details");
setValue(getValue(QString("savePassword%1").arg(i), "server", "server_details"),
QString("savePassword%1").arg(previous), "server", "server_details");
setValue(getValue(QString("password%1").arg(i), "server", "server_details"),
QString("password%1").arg(previous), "server", "server_details");
setValue(getValue(QString("saveName%1").arg(i), "server", "server_details"),
QString("saveName%1").arg(previous), "server", "server_details");
setValue(getValue(QString("site%1").arg(i), "server", "server_details"), QString("site%1").arg(previous),
"server", "server_details");
}
}
// if we have deleted an entry, adjust the total
if (found) {
setValue(size - 1, "totalServers", "server", "server_details");
// delete last value
deleteValue(QString("server%1").arg(size), "server", "server_details");
deleteValue(QString("port%1").arg(size), "server", "server_details");
deleteValue(QString("username%1").arg(size), "server", "server_details");
deleteValue(QString("savePassword%1").arg(size), "server", "server_details");
deleteValue(QString("password%1").arg(size), "server", "server_details");
deleteValue(QString("saveName%1").arg(size), "server", "server_details");
deleteValue(QString("site%1").arg(size), "server", "server_details");
}
}
/**
* Will only update fields with new values, ignores empty values
*/
bool ServersSettings::updateExistingServerWithoutLoss(QString saveName, QString serv, QString port, QString site)
{
int size = getValue("totalServers", "server", "server_details").toInt();
for (int i = 0; i <= size; ++i) {
if (serv == getValue(QString("server%1").arg(i), "server", "server_details").toString()) {
if (!port.isEmpty()) {
setValue(port, QString("port%1").arg(i), "server", "server_details");
}
if (!site.isEmpty()) {
setValue(site, QString("site%1").arg(i), "server", "server_details");
}
setValue(saveName, QString("saveName%1").arg(i), "server", "server_details");
return true;
}
}
return false;
}
bool ServersSettings::updateExistingServer(QString saveName,
QString serv,
QString port,
QString username,
QString password,
bool savePassword,
QString site)
{
int size = getValue("totalServers", "server", "server_details").toInt();
for (int i = 0; i <= size; ++i) {
if (serv == getValue(QString("server%1").arg(i), "server", "server_details").toString()) {
setValue(port, QString("port%1").arg(i), "server", "server_details");
if (!username.isEmpty()) {
setValue(username, QString("username%1").arg(i), "server", "server_details");
}
if (savePassword && !password.isEmpty()) {
setValue(password, QString("password%1").arg(i), "server", "server_details");
} else {
setValue(QString(), QString("password%1").arg(i), "server", "server_details");
}
if (!site.isEmpty()) {
setValue(site, QString("site%1").arg(i), "server", "server_details");
}
setValue(savePassword, QString("savePassword%1").arg(i), "server", "server_details");
setValue(saveName, QString("saveName%1").arg(i), "server", "server_details");
return true;
}
}
return false;
}

View file

@ -0,0 +1,82 @@
#include "../include/settings/settings_manager.h"
SettingsManager::SettingsManager(const QString &settingPath, QObject *parent)
: QObject(parent), settings(settingPath, QSettings::IniFormat)
{
}
void SettingsManager::setValue(const QVariant &value,
const QString &name,
const QString &group,
const QString &subGroup)
{
if (!group.isEmpty()) {
settings.beginGroup(group);
}
if (!subGroup.isEmpty()) {
settings.beginGroup(subGroup);
}
settings.setValue(name, value);
if (!subGroup.isEmpty()) {
settings.endGroup();
}
if (!group.isEmpty()) {
settings.endGroup();
}
}
void SettingsManager::deleteValue(const QString &name, const QString &group, const QString &subGroup)
{
if (!group.isEmpty()) {
settings.beginGroup(group);
}
if (!subGroup.isEmpty()) {
settings.beginGroup(subGroup);
}
settings.remove(name);
if (!subGroup.isEmpty()) {
settings.endGroup();
}
if (!group.isEmpty()) {
settings.endGroup();
}
}
QVariant SettingsManager::getValue(const QString &name, const QString &group, const QString &subGroup)
{
if (!group.isEmpty()) {
settings.beginGroup(group);
}
if (!subGroup.isEmpty()) {
settings.beginGroup(subGroup);
}
QVariant value = settings.value(name);
if (!subGroup.isEmpty()) {
settings.endGroup();
}
if (!group.isEmpty()) {
settings.endGroup();
}
return value;
}
/**
* Calls sync on the underlying QSettings object
*/
void SettingsManager::sync()
{
settings.sync();
}

View file

@ -0,0 +1,167 @@
#include "../include/settings/shortcut_treeview.h"
#include "../include/settings/cache_settings.h"
#include "../include/settings/shortcuts_settings.h"
#include <QHeaderView>
ShortcutFilterProxyModel::ShortcutFilterProxyModel(QObject *parent) : QSortFilterProxyModel(parent)
{
}
/**
* Appends the parent and source row together before doing the regex match.
*/
bool ShortcutFilterProxyModel::filterAcceptsRow(const int sourceRow, const QModelIndex &sourceParent) const
{
QModelIndex nameIndex = sourceModel()->index(sourceRow, filterKeyColumn(), sourceParent);
QModelIndex parentIndex = sourceModel()->index(sourceParent.row(), filterKeyColumn(), sourceParent.parent());
QString name = sourceModel()->data(nameIndex).toString();
QString parentName = sourceModel()->data(parentIndex).toString();
QString searchedString = parentName + " " + name;
return searchedString.contains(filterRegularExpression());
}
ShortcutTreeView::ShortcutTreeView(QWidget *parent) : QTreeView(parent)
{
// model
shortcutsModel = new QStandardItemModel(this);
shortcutsModel->setColumnCount(3);
populateShortcutsModel();
// filter proxy
proxyModel = new ShortcutFilterProxyModel(this);
proxyModel->setRecursiveFilteringEnabled(true);
proxyModel->setSourceModel(shortcutsModel);
proxyModel->setDynamicSortFilter(true);
proxyModel->setSortCaseSensitivity(Qt::CaseInsensitive);
proxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
proxyModel->setFilterKeyColumn(0);
QTreeView::setModel(proxyModel);
// treeview
hideColumn(2);
setUniformRowHeights(true);
setAlternatingRowColors(true);
setSortingEnabled(true);
proxyModel->sort(0, Qt::AscendingOrder);
header()->setSectionResizeMode(QHeaderView::Interactive);
header()->setSortIndicator(0, Qt::AscendingOrder);
setSelectionMode(SingleSelection);
setSelectionBehavior(SelectRows);
expandAll();
connect(&SettingsCache::instance().shortcuts(), &ShortcutsSettings::shortCutChanged, this,
&ShortcutTreeView::refreshShortcuts);
}
void ShortcutTreeView::populateShortcutsModel()
{
QHash<QString, QStandardItem *> parentItems;
QStandardItem *curParent = nullptr;
for (const auto &key : SettingsCache::instance().shortcuts().getAllShortcutKeys()) {
QString name = SettingsCache::instance().shortcuts().getShortcut(key).getName();
QString group = SettingsCache::instance().shortcuts().getShortcut(key).getGroupName();
QString shortcut = SettingsCache::instance().shortcuts().getShortcutString(key);
if (parentItems.contains(group)) {
curParent = parentItems.value(group);
} else {
curParent = new QStandardItem(group);
static QFont font = curParent->font();
font.setBold(true);
curParent->setFont(font);
parentItems.insert(group, curParent);
}
QList<QStandardItem *> list = {};
list << new QStandardItem(name) << new QStandardItem(shortcut) << new QStandardItem(key);
curParent->appendRow(list);
}
for (const auto &parent : parentItems) {
shortcutsModel->appendRow(parent);
}
}
void ShortcutTreeView::retranslateUi()
{
shortcutsModel->setHeaderData(0, Qt::Horizontal, tr("Action"));
shortcutsModel->setHeaderData(1, Qt::Horizontal, tr("Shortcut"));
refreshShortcuts();
}
/**
* Loops over the model and reloads all rows
*/
static void loopOverModel(QAbstractItemModel *model, const QModelIndex &parent = QModelIndex())
{
for (int r = 0; r < model->rowCount(parent); ++r) {
const auto friendlyNameIndex = model->index(r, 0, parent);
if (model->hasChildren(friendlyNameIndex)) {
const auto childIndex = model->index(0, 2, friendlyNameIndex);
const auto key = model->data(childIndex).toString();
const auto shortcutGroupName = SettingsCache::instance().shortcuts().getShortcut(key).getGroupName();
model->setData(friendlyNameIndex, shortcutGroupName);
loopOverModel(model, friendlyNameIndex);
} else {
const auto shortcutSequenceIndex = model->index(r, 1, parent);
const auto keyIndex = model->index(r, 2, parent);
const auto key = model->data(keyIndex).toString();
const auto shortcutKey = SettingsCache::instance().shortcuts().getShortcut(key).getName();
const auto shortcutSequence = SettingsCache::instance().shortcuts().getShortcutString(key);
model->setData(friendlyNameIndex, shortcutKey);
model->setData(shortcutSequenceIndex, shortcutSequence);
}
}
}
void ShortcutTreeView::refreshShortcuts()
{
loopOverModel(shortcutsModel);
}
void ShortcutTreeView::currentChanged(const QModelIndex &current, const QModelIndex & /* previous */)
{
QTreeView::scrollTo(current, QAbstractItemView::EnsureVisible);
if (current.parent().isValid()) {
auto shortcutName = model()->data(model()->index(current.row(), 2, current.parent())).toString();
emit currentItemChanged(shortcutName);
} else {
// emit empty string if the selection is a category header
emit currentItemChanged("");
}
}
/**
* The search string is split by word.
* A String is a match as long as it contains all the words in the search string in order
*/
void ShortcutTreeView::updateSearchString(const QString &searchString)
{
#if QT_VERSION > QT_VERSION_CHECK(5, 14, 0)
const auto skipEmptyParts = Qt::SkipEmptyParts;
#else
const auto skipEmptyParts = QString::SkipEmptyParts;
#endif
QStringList searchWords = searchString.split(" ", skipEmptyParts);
auto escapeRegex = [](const QString &s) { return QRegularExpression::escape(s); };
std::transform(searchWords.begin(), searchWords.end(), searchWords.begin(), escapeRegex);
auto regex = QRegularExpression(searchWords.join(".*"), QRegularExpression::CaseInsensitiveOption);
proxyModel->setFilterRegularExpression(regex);
expandAll();
}

View file

@ -0,0 +1,263 @@
#include "../include/settings/shortcuts_settings.h"
#include <QDebug>
#include <QFile>
#include <QMessageBox>
#include <QStringList>
#include <utility>
ShortcutKey::ShortcutKey(const QString &_name, QList<QKeySequence> _sequence, ShortcutGroup::Groups _group)
: QList<QKeySequence>(_sequence), name(_name), group(_group)
{
}
ShortcutsSettings::ShortcutsSettings(const QString &settingsPath, QObject *parent) : QObject(parent)
{
shortCuts = defaultShortCuts;
settingsFilePath = settingsPath;
settingsFilePath.append("shortcuts.ini");
bool exists = QFile(settingsFilePath).exists();
QSettings shortCutsFile(settingsFilePath, QSettings::IniFormat);
if (exists) {
shortCutsFile.beginGroup(custom);
const QStringList customKeys = shortCutsFile.allKeys();
QMap<QString, QString> invalidItems;
for (QStringList::const_iterator it = customKeys.constBegin(); it != customKeys.constEnd(); ++it) {
QString stringSequence = shortCutsFile.value(*it).toString();
// check whether shortcut name exists
if (!shortCuts.contains(*it)) {
qCWarning(ShortcutsSettingsLog) << "Unknown shortcut name:" << *it;
continue;
}
// check whether shortcut is forbidden
if (isKeyAllowed(*it, stringSequence)) {
auto shortcut = getShortcut(*it);
shortcut.setSequence(parseSequenceString(stringSequence));
shortCuts.insert(*it, shortcut);
} else {
invalidItems.insert(*it, stringSequence);
}
}
shortCutsFile.endGroup();
if (!invalidItems.isEmpty()) {
// warning message in case of invalid items
QMessageBox msgBox;
msgBox.setIcon(QMessageBox::Warning);
msgBox.setText(tr("Your configuration file contained invalid shortcuts.\n"
"Please check your shortcut settings!"));
QString detailedMessage = tr("The following shortcuts have been set to default:\n");
for (QMap<QString, QString>::const_iterator item = invalidItems.constBegin();
item != invalidItems.constEnd(); ++item) {
detailedMessage += item.key() + " - \"" + item.value() + "\"\n";
}
msgBox.setDetailedText(detailedMessage);
msgBox.exec();
}
}
}
/// PR 5079 changes Textbox/unfocusTextBox to Player/unfocusTextBox and tab_game/aFocusChat to Player/aFocusChat.
/// A migration is necessary to let players keep their already configured shortcuts.
void ShortcutsSettings::migrateShortcuts()
{
if (QFile(settingsFilePath).exists()) {
QSettings shortCutsFile(settingsFilePath, QSettings::IniFormat);
shortCutsFile.beginGroup(custom);
if (shortCutsFile.contains("Textbox/unfocusTextBox")) {
qCInfo(ShortcutsSettingsLog)
<< "[ShortcutsSettings] Textbox/unfocusTextBox shortcut found. Migrating to Player/unfocusTextBox.";
QString unfocusTextBox = shortCutsFile.value("Textbox/unfocusTextBox", "").toString();
this->setShortcuts("Player/unfocusTextBox", unfocusTextBox);
shortCutsFile.remove("Textbox/unfocusTextBox");
}
if (shortCutsFile.contains("tab_game/aFocusChat")) {
qCInfo(ShortcutsSettingsLog)
<< "[ShortcutsSettings] tab_game/aFocusChat shortcut found. Migrating to Player/aFocusChat.";
QString aFocusChat = shortCutsFile.value("tab_game/aFocusChat", "").toString();
this->setShortcuts("Player/aFocusChat", aFocusChat);
shortCutsFile.remove("tab_game/aFocusChat");
}
// PR #5564 changes "MainWindow/aDeckEditor" to "Tabs/aTabDeckEditor"
if (shortCutsFile.contains("MainWindow/aDeckEditor")) {
qCInfo(ShortcutsSettingsLog) << "MainWindow/aDeckEditor shortcut found. Migrating to Tabs/aTabDeckEditor.";
QString keySequence = shortCutsFile.value("MainWindow/aDeckEditor", "").toString();
this->setShortcuts("Tabs/aTabDeckEditor", keySequence);
shortCutsFile.remove("MainWindow/aDeckEditor");
}
shortCutsFile.endGroup();
}
}
ShortcutKey ShortcutsSettings::getDefaultShortcut(const QString &name) const
{
return defaultShortCuts.value(name, ShortcutKey());
}
ShortcutKey ShortcutsSettings::getShortcut(const QString &name) const
{
if (shortCuts.contains(name)) {
return shortCuts.value(name);
}
return getDefaultShortcut(name);
}
/**
* Gets the first shortcut for the given action.
*
* NOTE: In most cases you should be using ShortcutsSettings::getShortcut instead,
* as that will return all shortcuts if there are multiple shortcuts.
* The only reason to use this method is if an object does not accept multiple shortcuts, such as with QButtons.
*/
QKeySequence ShortcutsSettings::getSingleShortcut(const QString &name) const
{
return getShortcut(name).at(0);
}
QString ShortcutsSettings::getDefaultShortcutString(const QString &name) const
{
return stringifySequence(getDefaultShortcut(name));
}
QString ShortcutsSettings::getShortcutString(const QString &name) const
{
return stringifySequence(getShortcut(name));
}
QString ShortcutsSettings::getShortcutFriendlyName(const QString &shortcutName) const
{
for (auto it = defaultShortCuts.cbegin(); it != defaultShortCuts.cend(); ++it) {
if (shortcutName == it.key()) {
return it.value().getName();
}
}
return {};
}
QString ShortcutsSettings::stringifySequence(const QList<QKeySequence> &Sequence) const
{
QStringList stringSequence;
for (const auto &i : Sequence) {
stringSequence.append(i.toString(QKeySequence::PortableText));
}
return stringSequence.join(sep);
}
QList<QKeySequence> ShortcutsSettings::parseSequenceString(const QString &stringSequence) const
{
QList<QKeySequence> SequenceList;
for (const QString &shortcut : stringSequence.split(sep)) {
SequenceList.append(QKeySequence(shortcut, QKeySequence::PortableText));
}
return SequenceList;
}
void ShortcutsSettings::setShortcuts(const QString &name, const QList<QKeySequence> &Sequence)
{
shortCuts[name].setSequence(Sequence);
QSettings shortCutsFile(settingsFilePath, QSettings::IniFormat);
shortCutsFile.beginGroup(custom);
shortCutsFile.setValue(name, stringifySequence(Sequence));
shortCutsFile.endGroup();
emit shortCutChanged();
}
void ShortcutsSettings::setShortcuts(const QString &name, const QKeySequence &Sequence)
{
setShortcuts(name, QList<QKeySequence>{Sequence});
}
void ShortcutsSettings::setShortcuts(const QString &name, const QString &sequences)
{
setShortcuts(name, parseSequenceString(sequences));
}
void ShortcutsSettings::resetAllShortcuts()
{
shortCuts = defaultShortCuts;
QSettings shortCutsFile(settingsFilePath, QSettings::IniFormat);
shortCutsFile.beginGroup(custom);
shortCutsFile.remove("");
shortCutsFile.endGroup();
emit shortCutChanged();
}
void ShortcutsSettings::clearAllShortcuts()
{
QSettings shortCutsFile(settingsFilePath, QSettings::IniFormat);
shortCutsFile.beginGroup(custom);
for (auto it = shortCuts.begin(); it != shortCuts.end(); ++it) {
it.value().setSequence(parseSequenceString(""));
shortCutsFile.setValue(it.key(), "");
}
shortCutsFile.endGroup();
emit shortCutChanged();
}
bool ShortcutsSettings::isKeyAllowed(const QString &name, const QString &sequences) const
{
// if the shortcut is not to be used in deck-editor then it doesn't matter
if (name.startsWith("Player") || name.startsWith("Replays")) {
return true;
}
QString checkSequence = sequences.split(sep).last();
QStringList forbiddenKeys{"Del", "Backspace", "Down", "Up", "Left", "Right",
"Return", "Enter", "Menu", "Ctrl+Alt+-", "Ctrl+Alt+=", "Ctrl+Alt+[",
"Ctrl+Alt+]", "Tab", "Space", "Shift+S", "Shift+Left", "Shift+Right"};
return !forbiddenKeys.contains(checkSequence);
}
/**
* Checks that the shortcut doesn't overlap with an existing shortcut
*
* @param name The name of the shortcut
* @param sequences The shortcut key sequence
* @return Whether the shortcut is valid.
*/
bool ShortcutsSettings::isValid(const QString &name, const QString &sequences) const
{
return findOverlaps(name, sequences).isEmpty();
}
/**
* Checks if the shortcut is a shortcut that is active in all windows
*/
static bool isAlwaysActiveShortcut(const QString &shortcutName)
{
return shortcutName.startsWith("MainWindow") || shortcutName.startsWith("Tabs");
}
QStringList ShortcutsSettings::findOverlaps(const QString &name, const QString &sequences) const
{
QString checkSequence = sequences.split(sep).last();
QString checkKey = name.left(name.indexOf("/"));
QStringList overlaps;
for (const auto &key : shortCuts.keys()) {
if (key.startsWith(checkKey) || isAlwaysActiveShortcut(key) || isAlwaysActiveShortcut(checkKey)) {
QString storedSequence = stringifySequence(shortCuts.value(key));
if (storedSequence.split(sep).contains(checkSequence)) {
overlaps.append(getShortcutFriendlyName(key));
}
}
}
return overlaps;
}