Cockatrice/cockatrice/src/client/settings/cache_settings.cpp
BruebachL 827e44a4d3
[DeckEditor] Use CommanderSpellbook.com to estimate bracket if format is 'commander' (#6415)
* [DeckEditor] Use CommanderSpellbook.com to estimate bracket if format is 'commander'

Took 2 minutes

Took 16 minutes

* Convert json data holder to structs, rename variables, extract widget

- Extract bracket estimation UI from DeckEditorDeckDockWidget into a
  new CommanderBracketWidget
- Move CommanderSpellbook integration settings from CardsDisplaySettings
  to DeckEditorSettings (matching the settings refactor on master)
- Rename CommanderSpellbook integration variables to drop the redundant
  'DeckEditor' prefix

Took 4 minutes

# Commit time for manual adjustment:
# Took 6 minutes

# Commit time for manual adjustment:
# Took 8 minutes

---------

Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
2026-08-09 00:46:17 +02:00

457 lines
15 KiB
C++

#include "cache_settings.h"
#include "../network/update/client/release_channel.h"
#include "card_counter_settings.h"
#include "shortcuts_settings.h"
#include "version_string.h"
#include <QDebug>
#include <QDir>
#include <QFile>
#include <QGlobalStatic>
#include <QSettings>
#include <QStandardPaths>
#include <libcockatrice/settings/appearance_settings.h>
#include <libcockatrice/settings/cache_storage_settings.h>
#include <libcockatrice/settings/card_database_settings.h>
#include <libcockatrice/settings/card_override_settings.h>
#include <libcockatrice/settings/cards_display_settings.h>
#include <libcockatrice/settings/chat_settings.h>
#include <libcockatrice/settings/commander_bracket_settings.h>
#include <libcockatrice/settings/debug_settings.h>
#include <libcockatrice/settings/deck_editor_settings.h>
#include <libcockatrice/settings/download_settings.h>
#include <libcockatrice/settings/game_filters_settings.h>
#include <libcockatrice/settings/game_settings.h>
#include <libcockatrice/settings/interface_settings.h>
#include <libcockatrice/settings/layouts_settings.h>
#include <libcockatrice/settings/message_settings.h>
#include <libcockatrice/settings/network_settings.h>
#include <libcockatrice/settings/paths_settings.h>
#include <libcockatrice/settings/personal_settings.h>
#include <libcockatrice/settings/recents_settings.h>
#include <libcockatrice/settings/servers_settings.h>
#include <libcockatrice/settings/settings_migration.h>
#include <libcockatrice/settings/sound_settings.h>
#include <libcockatrice/settings/tabs_settings.h>
#include <libcockatrice/settings/updates_settings.h>
#include <libcockatrice/settings/visual_deck_storage_settings.h>
#include <utility>
Q_GLOBAL_STATIC(SettingsCache, settingsCache)
SettingsCache &SettingsCache::instance()
{
return *settingsCache; // returns a QT managed singleton reference
}
QString SettingsCache::getDataPath()
{
if (isPortableBuild) {
return qApp->applicationDirPath() + "/data";
} else {
return QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation);
}
}
QString SettingsCache::getSettingsPath()
{
return getDataPath() + "/settings/";
}
QString SettingsCache::getCachePath() const
{
if (isPortableBuild) {
return qApp->applicationDirPath() + "/cache";
} else {
return QStandardPaths::writableLocation(QStandardPaths::CacheLocation);
}
}
QString SettingsCache::getNetworkCachePath() const
{
return getCachePath() + "/downloaded/";
}
QString SettingsCache::getSafeConfigPath(QString configEntry, QString defaultPath) const
{
QString tmp = settings->value(configEntry).toString();
// if the config settings is empty or refers to a not-existing folder,
// ensure that the defaut path exists and return it
if (tmp.isEmpty() || !QDir(tmp).exists()) {
if (!QDir().mkpath(defaultPath)) {
qCInfo(SettingsCacheLog) << "[SettingsCache] Could not create folder:" << defaultPath;
}
tmp = defaultPath;
}
return tmp;
}
QString SettingsCache::getSafeConfigFilePath(QString configEntry, QString defaultPath) const
{
QString tmp = settings->value(configEntry).toString();
// if the config settings is empty or refers to a not-existing file,
// return the default Path
if (!QFile::exists(tmp) || tmp.isEmpty()) {
tmp = std::move(defaultPath);
}
return tmp;
}
SettingsCache::SettingsCache()
{
// first, figure out if we are running in portable mode
isPortableBuild = QFile::exists(qApp->applicationDirPath() + "/portable.dat");
if (isPortableBuild) {
qCInfo(SettingsCacheLog) << "Portable mode enabled";
}
QString settingsPath = getSettingsPath();
settings = new QSettings(settingsPath + "global.ini", QSettings::IniFormat, this);
// Migrate from legacy NativeFormat settings to per-class INI files (runs at most once)
if (!isPortableBuild) {
SettingsMigration::migrateLegacySettings(settingsPath);
}
// Migrate settings from global.ini to per-class INI files (runs at most once)
SettingsMigration::migrateSettingsFromGlobalIni(settingsPath);
shortcutsSettings = new ShortcutsSettings(settingsPath, this);
cardDatabaseSettings = new CardDatabaseSettings(settingsPath, this);
serversSettings = new ServersSettings(settingsPath, this);
messageSettings = new MessageSettings(settingsPath, this);
gameFiltersSettings = new GameFiltersSettings(settingsPath, this);
layoutsSettings = new LayoutsSettings(settingsPath, this);
downloadSettings = new DownloadSettings(settingsPath, this);
recentsSettings = new RecentsSettings(settingsPath, this);
cardOverrideSettings = new CardOverrideSettings(settingsPath, this);
debugSettings = new DebugSettings(settingsPath, this);
cardCounterSettings = new CardCounterSettings(settingsPath, this);
tabsSettings = new TabsSettings(settingsPath, this);
soundSettings = new SoundSettings(settingsPath, this);
gameSettings = new GameSettings(settingsPath, this);
chatSettings = new ChatSettings(settingsPath, this);
cacheStorageSettings = new CacheStorageSettings(settingsPath, this);
updatesSettings = new UpdatesSettings(settingsPath, this);
personalSettings = new PersonalSettings(settingsPath, this);
cardsDisplaySettings = new CardsDisplaySettings(settingsPath, this);
interfaceSettings = new InterfaceSettings(settingsPath, this);
deckEditorSettings = new DeckEditorSettings(settingsPath, this);
pathsSettings = new PathsSettings(settingsPath, this);
visualDeckStorageSettings = new VisualDeckStorageSettings(settingsPath, this);
appearanceSettings = new AppearanceSettings(settingsPath, this);
networkSettings = new NetworkSettings(settingsPath, this);
commanderBracketSettings = new CommanderBracketSettings(settingsPath, this);
// Forward ICardDatabasePathProvider signal from PathsSettings
connect(pathsSettings, &PathsSettings::cardDatabasePathChanged, this,
&ICardDatabasePathProvider::cardDatabasePathChanged);
// updates - don't reorder them or their index in the settings won't match
// append channels one by one, or msvc will add them in the wrong order.
releaseChannels << new StableReleaseChannel();
releaseChannels << new BetaReleaseChannel();
themeName = appearanceSettings->getThemeName();
auto definitions = commanderBracketSettings->loadDefinitions();
if (definitions.isEmpty()) {
definitions = CommanderBracketSettings::defaultDefinitions();
}
commanderBracketSettings->reloadDefinitions(definitions);
loadPaths();
}
void SettingsCache::setThemeName(const QString &_themeName)
{
themeName = _themeName;
appearanceSettings->setThemeName(themeName);
emit themeChanged();
}
QStringList SettingsCache::getCountries() const
{
static const QStringList countries = {
"ad", "ae", "af", "ag", "ai", "al", "am", "ao", "aq", "ar", "as", "at", "au", "aw", "ax", "az", "ba", "bb",
"bd", "be", "bf", "bg", "bh", "bi", "bj", "bl", "bm", "bn", "bo", "bq", "br", "bs", "bt", "bv", "bw", "by",
"bz", "ca", "cc", "cd", "cf", "cg", "ch", "ci", "ck", "cl", "cm", "cn", "co", "cr", "cu", "cv", "cw", "cx",
"cy", "cz", "de", "dj", "dk", "dm", "do", "dz", "ec", "ee", "eg", "eh", "er", "es", "et", "eu", "fi", "fj",
"fk", "fm", "fo", "fr", "ga", "gb", "gd", "ge", "gf", "gg", "gh", "gi", "gl", "gm", "gn", "gp", "gq", "gr",
"gs", "gt", "gu", "gw", "gy", "hk", "hm", "hn", "hr", "ht", "hu", "id", "ie", "il", "im", "in", "io", "iq",
"ir", "is", "it", "je", "jm", "jo", "jp", "ke", "kg", "kh", "ki", "km", "kn", "kp", "kr", "kw", "ky", "kz",
"la", "lb", "lc", "li", "lk", "lr", "ls", "lt", "lu", "lv", "ly", "ma", "mc", "md", "me", "mf", "mg", "mh",
"mk", "ml", "mm", "mn", "mo", "mp", "mq", "mr", "ms", "mt", "mu", "mv", "mw", "mx", "my", "mz", "na", "nc",
"ne", "nf", "ng", "ni", "nl", "no", "np", "nr", "nu", "nz", "om", "pa", "pe", "pf", "pg", "ph", "pk", "pl",
"pm", "pn", "pr", "ps", "pt", "pw", "py", "qa", "re", "ro", "rs", "ru", "rw", "sa", "sb", "sc", "sd", "se",
"sg", "sh", "si", "sj", "sk", "sl", "sm", "sn", "so", "sr", "ss", "st", "sv", "sx", "sy", "sz", "tc", "td",
"tf", "tg", "th", "tj", "tk", "tl", "tm", "tn", "to", "tr", "tt", "tv", "tw", "tz", "ua", "ug", "um", "us",
"uy", "uz", "va", "vc", "ve", "vg", "vi", "vn", "vu", "wf", "ws", "xk", "ye", "yt", "za", "zm", "zw"};
return countries;
}
void SettingsCache::loadPaths()
{
QString dataPath = getDataPath();
QSettings pathsIni(getSettingsPath() + "paths.ini", QSettings::IniFormat);
auto computePath = [&](const QString &key, const QString &defaultPath) -> QString {
QString val = pathsIni.value("paths/" + key).toString();
if (val.isEmpty() || !QDir(val).exists()) {
if (!QDir().mkpath(defaultPath)) {
qCInfo(SettingsCacheLog) << "[SettingsCache] Could not create folder:" << defaultPath;
}
val = defaultPath;
pathsIni.setValue("paths/" + key, val);
}
return val;
};
auto computeFilePath = [&](const QString &key, const QString &defaultPath) -> QString {
QString val = pathsIni.value("paths/" + key).toString();
if (!QFile::exists(val) || val.isEmpty()) {
val = defaultPath;
pathsIni.setValue("paths/" + key, val);
}
return val;
};
computePath("decks", dataPath + "/decks/");
computePath("filters", dataPath + "/filters/");
computePath("replays", dataPath + "/replays/");
computePath("themes", dataPath + "/themes/");
computePath("pics", dataPath + "/pics/");
computePath("redirects", getCachePath() + "/redirects/");
// customPicsPath derived from picsPath
QString picsPath = pathsIni.value("paths/pics").toString();
if (picsPath.endsWith("/")) {
computePath("customPics", picsPath + "CUSTOM/");
} else {
computePath("customPics", picsPath + "/CUSTOM/");
}
computePath("customSets", dataPath + "/customsets/");
computeFilePath("cardDatabase", dataPath + "/cards.xml");
computeFilePath("tokenDatabase", dataPath + "/tokens.xml");
computeFilePath("spoilerDatabase", dataPath + "/spoiler.xml");
}
void SettingsCache::resetPaths()
{
QStringList databasePaths{pathsSettings->getCustomCardDatabasePath(), pathsSettings->getCardDatabasePath(),
pathsSettings->getSpoilerCardDatabasePath(), pathsSettings->getTokenDatabasePath()};
QString picsPath_ = pathsSettings->getPicsPath();
QSettings pathsIni(getSettingsPath() + "paths.ini", QSettings::IniFormat);
pathsIni.remove("paths");
loadPaths();
if (databasePaths != QStringList{pathsSettings->getCustomCardDatabasePath(), pathsSettings->getCardDatabasePath(),
pathsSettings->getSpoilerCardDatabasePath(),
pathsSettings->getTokenDatabasePath()}) {
emit cardDatabasePathChanged();
}
if (picsPath_ != pathsSettings->getPicsPath()) {
emit pathsSettings->picsPathChanged();
}
}
// ICardDatabasePathProvider - delegate to pathsSettings
QString SettingsCache::getCustomCardDatabasePath() const
{
return pathsSettings->getCustomCardDatabasePath();
}
QString SettingsCache::getCardDatabasePath() const
{
return pathsSettings->getCardDatabasePath();
}
QString SettingsCache::getSpoilerCardDatabasePath() const
{
return pathsSettings->getSpoilerCardDatabasePath();
}
QString SettingsCache::getTokenDatabasePath() const
{
return pathsSettings->getTokenDatabasePath();
}
// INetworkSettingsProvider - delegate to sub-objects
int SettingsCache::getKeepAlive() const
{
return networkSettings->getKeepAlive();
}
int SettingsCache::getTimeOut() const
{
return networkSettings->getTimeOut();
}
bool SettingsCache::getNotifyAboutUpdates() const
{
return updatesSettings->getNotifyAboutUpdates();
}
void SettingsCache::setKnownMissingFeatures(const QString &_knownMissingFeatures)
{
networkSettings->setKnownMissingFeatures(_knownMissingFeatures);
}
QString SettingsCache::getKnownMissingFeatures()
{
return networkSettings->getKnownMissingFeatures();
}
QString SettingsCache::getClientID()
{
return networkSettings->getClientID();
}
// Release channels
ReleaseChannel *SettingsCache::getUpdateReleaseChannel() const
{
return releaseChannels.at(qMax(0, updatesSettings->getUpdateReleaseChannelIndex()));
}
QList<ReleaseChannel *> SettingsCache::getUpdateReleaseChannels() const
{
return releaseChannels;
}
int SettingsCache::getUpdateReleaseChannelIndex() const
{
return updatesSettings->getUpdateReleaseChannelIndex();
}
// Sub-settings accessors
ShortcutsSettings &SettingsCache::shortcuts() const
{
return *shortcutsSettings;
}
CardDatabaseSettings &SettingsCache::cardDatabase() const
{
return *cardDatabaseSettings;
}
ServersSettings &SettingsCache::servers() const
{
return *serversSettings;
}
MessageSettings &SettingsCache::messages() const
{
return *messageSettings;
}
GameFiltersSettings &SettingsCache::gameFilters() const
{
return *gameFiltersSettings;
}
LayoutsSettings &SettingsCache::layouts() const
{
return *layoutsSettings;
}
DownloadSettings &SettingsCache::downloads() const
{
return *downloadSettings;
}
RecentsSettings &SettingsCache::recents() const
{
return *recentsSettings;
}
CardOverrideSettings &SettingsCache::cardOverrides() const
{
return *cardOverrideSettings;
}
DebugSettings &SettingsCache::debug() const
{
return *debugSettings;
}
CardCounterSettings &SettingsCache::cardCounters() const
{
return *cardCounterSettings;
}
TabsSettings &SettingsCache::tabs() const
{
return *tabsSettings;
}
SoundSettings &SettingsCache::sound() const
{
return *soundSettings;
}
GameSettings &SettingsCache::game() const
{
return *gameSettings;
}
ChatSettings &SettingsCache::chat() const
{
return *chatSettings;
}
CacheStorageSettings &SettingsCache::cacheStorage() const
{
return *cacheStorageSettings;
}
UpdatesSettings &SettingsCache::updates() const
{
return *updatesSettings;
}
PersonalSettings &SettingsCache::personal() const
{
return *personalSettings;
}
CardsDisplaySettings &SettingsCache::cardsDisplay() const
{
return *cardsDisplaySettings;
}
InterfaceSettings &SettingsCache::userInterface() const
{
return *interfaceSettings;
}
PathsSettings &SettingsCache::paths() const
{
return *pathsSettings;
}
DeckEditorSettings &SettingsCache::deckEditor() const
{
return *deckEditorSettings;
}
VisualDeckStorageSettings &SettingsCache::visualDeckStorage() const
{
return *visualDeckStorageSettings;
}
AppearanceSettings &SettingsCache::appearance() const
{
return *appearanceSettings;
}
NetworkSettings &SettingsCache::network() const
{
return *networkSettings;
}