2026-01-08 00:35:31 -05:00
|
|
|
#include "settings.h"
|
|
|
|
|
#include "logmanager.h"
|
|
|
|
|
#include <QCoreApplication>
|
|
|
|
|
#include <QStandardPaths>
|
|
|
|
|
#include <QDir>
|
2026-01-08 00:54:57 -05:00
|
|
|
#include <QFileInfo>
|
2026-01-08 00:35:31 -05:00
|
|
|
|
|
|
|
|
// Built-in themes
|
|
|
|
|
static const QMap<QString, Theme> s_themes = {
|
|
|
|
|
{"XPlor Dark", {
|
|
|
|
|
"XPlor Dark",
|
|
|
|
|
"#ad0c0c", // accentColor (red)
|
|
|
|
|
"#8a0a0a", // accentColorDark
|
|
|
|
|
"#c41010", // accentColorLight
|
|
|
|
|
"#1e1e1e", // backgroundColor
|
|
|
|
|
"#2d2d30", // panelColor
|
|
|
|
|
"#3c3c3c", // borderColor
|
|
|
|
|
"#d4d4d4", // textColor
|
|
|
|
|
"#888888" // textColorMuted
|
|
|
|
|
}},
|
|
|
|
|
{"Midnight Blue", {
|
|
|
|
|
"Midnight Blue",
|
|
|
|
|
"#0078d4", // accentColor (blue)
|
|
|
|
|
"#005a9e", // accentColorDark
|
|
|
|
|
"#1890ff", // accentColorLight
|
|
|
|
|
"#1a1a2e", // backgroundColor
|
|
|
|
|
"#16213e", // panelColor
|
|
|
|
|
"#0f3460", // borderColor
|
|
|
|
|
"#e0e0e0", // textColor
|
|
|
|
|
"#7f8c8d" // textColorMuted
|
|
|
|
|
}},
|
|
|
|
|
{"Forest Green", {
|
|
|
|
|
"Forest Green",
|
|
|
|
|
"#2e7d32", // accentColor (green)
|
|
|
|
|
"#1b5e20", // accentColorDark
|
|
|
|
|
"#43a047", // accentColorLight
|
|
|
|
|
"#1a1f1a", // backgroundColor
|
|
|
|
|
"#2d332d", // panelColor
|
|
|
|
|
"#3c4a3c", // borderColor
|
|
|
|
|
"#d4d8d4", // textColor
|
|
|
|
|
"#88918a" // textColorMuted
|
|
|
|
|
}},
|
|
|
|
|
{"Purple Haze", {
|
|
|
|
|
"Purple Haze",
|
|
|
|
|
"#7b1fa2", // accentColor (purple)
|
|
|
|
|
"#4a148c", // accentColorDark
|
|
|
|
|
"#9c27b0", // accentColorLight
|
|
|
|
|
"#1a1a1e", // backgroundColor
|
|
|
|
|
"#2d2d35", // panelColor
|
|
|
|
|
"#3c3c4a", // borderColor
|
|
|
|
|
"#d4d4dc", // textColor
|
|
|
|
|
"#8888a0" // textColorMuted
|
|
|
|
|
}},
|
|
|
|
|
{"Orange Sunset", {
|
|
|
|
|
"Orange Sunset",
|
|
|
|
|
"#e65100", // accentColor (orange)
|
|
|
|
|
"#bf360c", // accentColorDark
|
|
|
|
|
"#ff6d00", // accentColorLight
|
|
|
|
|
"#1e1a18", // backgroundColor
|
|
|
|
|
"#302820", // panelColor
|
|
|
|
|
"#4a3c30", // borderColor
|
|
|
|
|
"#d8d4d0", // textColor
|
|
|
|
|
"#908880" // textColorMuted
|
|
|
|
|
}},
|
|
|
|
|
{"Classic Dark", {
|
|
|
|
|
"Classic Dark",
|
|
|
|
|
"#505050", // accentColor (gray)
|
|
|
|
|
"#404040", // accentColorDark
|
|
|
|
|
"#606060", // accentColorLight
|
|
|
|
|
"#1e1e1e", // backgroundColor
|
|
|
|
|
"#252526", // panelColor
|
|
|
|
|
"#3c3c3c", // borderColor
|
|
|
|
|
"#d4d4d4", // textColor
|
|
|
|
|
"#888888" // textColorMuted
|
|
|
|
|
}}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Settings& Settings::instance()
|
|
|
|
|
{
|
|
|
|
|
static Settings instance;
|
|
|
|
|
return instance;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Settings::Settings(QObject *parent)
|
|
|
|
|
: QObject(parent)
|
|
|
|
|
, m_settings(QSettings::NativeFormat, QSettings::UserScope,
|
|
|
|
|
QCoreApplication::organizationName(),
|
|
|
|
|
QCoreApplication::applicationName())
|
|
|
|
|
{
|
|
|
|
|
// Set up debug checker for LogManager
|
|
|
|
|
LogManager::instance().setDebugChecker([this]() {
|
|
|
|
|
return debugLoggingEnabled();
|
|
|
|
|
});
|
2026-01-11 12:09:31 -05:00
|
|
|
|
|
|
|
|
// Set up log-to-file checker for LogManager
|
|
|
|
|
LogManager::instance().setLogToFileChecker([this]() {
|
|
|
|
|
return logToFileEnabled();
|
|
|
|
|
});
|
2026-01-08 00:35:31 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Settings::sync()
|
|
|
|
|
{
|
|
|
|
|
m_settings.sync();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Theme
|
|
|
|
|
QString Settings::currentTheme() const
|
|
|
|
|
{
|
|
|
|
|
return m_settings.value("Appearance/Theme", "XPlor Dark").toString();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Settings::setCurrentTheme(const QString& themeName)
|
|
|
|
|
{
|
|
|
|
|
if (s_themes.contains(themeName)) {
|
|
|
|
|
m_settings.setValue("Appearance/Theme", themeName);
|
|
|
|
|
emit themeChanged(s_themes[themeName]);
|
|
|
|
|
emit settingsChanged();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Theme Settings::theme() const
|
|
|
|
|
{
|
|
|
|
|
return getTheme(currentTheme());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QStringList Settings::availableThemes() const
|
|
|
|
|
{
|
|
|
|
|
return s_themes.keys();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Theme Settings::getTheme(const QString& name)
|
|
|
|
|
{
|
|
|
|
|
if (s_themes.contains(name)) {
|
|
|
|
|
return s_themes[name];
|
|
|
|
|
}
|
|
|
|
|
return s_themes["XPlor Dark"];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// General
|
|
|
|
|
QString Settings::exportDirectory() const
|
|
|
|
|
{
|
|
|
|
|
QString defaultPath = QCoreApplication::applicationDirPath() + "/exports";
|
|
|
|
|
return m_settings.value("General/ExportDirectory", defaultPath).toString();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Settings::setExportDirectory(const QString& path)
|
|
|
|
|
{
|
|
|
|
|
m_settings.setValue("General/ExportDirectory", path);
|
|
|
|
|
emit settingsChanged();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Settings::autoExportOnParse() const
|
|
|
|
|
{
|
|
|
|
|
return m_settings.value("General/AutoExportOnParse", true).toBool();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Settings::setAutoExportOnParse(bool enable)
|
|
|
|
|
{
|
|
|
|
|
m_settings.setValue("General/AutoExportOnParse", enable);
|
|
|
|
|
emit settingsChanged();
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-08 00:54:57 -05:00
|
|
|
// Tools
|
|
|
|
|
QString Settings::quickBmsPath() const
|
|
|
|
|
{
|
|
|
|
|
QString path = m_settings.value("Tools/QuickBmsPath").toString();
|
|
|
|
|
if (path.isEmpty() || !QFileInfo::exists(path)) {
|
|
|
|
|
path = findQuickBms();
|
|
|
|
|
}
|
|
|
|
|
return path;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Settings::setQuickBmsPath(const QString& path)
|
|
|
|
|
{
|
|
|
|
|
m_settings.setValue("Tools/QuickBmsPath", path);
|
|
|
|
|
emit settingsChanged();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString Settings::findQuickBms()
|
|
|
|
|
{
|
|
|
|
|
// Common locations to search for QuickBMS
|
|
|
|
|
QStringList searchPaths = {
|
|
|
|
|
QCoreApplication::applicationDirPath() + "/quickbms.exe",
|
|
|
|
|
QCoreApplication::applicationDirPath() + "/tools/quickbms.exe",
|
|
|
|
|
QCoreApplication::applicationDirPath() + "/quickbms/quickbms.exe",
|
|
|
|
|
"C:/Program Files/QuickBMS/quickbms.exe",
|
|
|
|
|
"C:/Program Files (x86)/QuickBMS/quickbms.exe",
|
|
|
|
|
"C:/QuickBMS/quickbms.exe",
|
|
|
|
|
QDir::homePath() + "/QuickBMS/quickbms.exe",
|
|
|
|
|
"E:/Software/QuickBMS/quickbms.exe", // Legacy path
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Also check PATH environment
|
|
|
|
|
QString pathEnv = qEnvironmentVariable("PATH");
|
|
|
|
|
QStringList pathDirs = pathEnv.split(';', Qt::SkipEmptyParts);
|
|
|
|
|
for (const QString& dir : pathDirs) {
|
|
|
|
|
searchPaths.append(dir + "/quickbms.exe");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (const QString& path : searchPaths) {
|
|
|
|
|
if (QFileInfo::exists(path)) {
|
|
|
|
|
return QDir::cleanPath(path);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return QString(); // Not found
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-11 12:09:31 -05:00
|
|
|
|
|
|
|
|
QString Settings::pythonPath() const
|
|
|
|
|
{
|
|
|
|
|
QString path = m_settings.value("Tools/PythonPath").toString();
|
|
|
|
|
if (path.isEmpty() || !QFileInfo::exists(path)) {
|
|
|
|
|
path = findPython();
|
|
|
|
|
}
|
|
|
|
|
return path;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Settings::setPythonPath(const QString& path)
|
|
|
|
|
{
|
|
|
|
|
m_settings.setValue("Tools/PythonPath", path);
|
|
|
|
|
emit settingsChanged();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString Settings::findPython()
|
|
|
|
|
{
|
|
|
|
|
// Common locations to search for Python
|
|
|
|
|
QStringList searchPaths = {
|
|
|
|
|
"python",
|
|
|
|
|
"python3",
|
|
|
|
|
"C:/Python312/python.exe",
|
|
|
|
|
"C:/Python311/python.exe",
|
|
|
|
|
"C:/Python310/python.exe",
|
|
|
|
|
"C:/Program Files/Python312/python.exe",
|
|
|
|
|
"C:/Program Files/Python311/python.exe",
|
|
|
|
|
QDir::homePath() + "/AppData/Local/Programs/Python/Python312/python.exe",
|
|
|
|
|
QDir::homePath() + "/AppData/Local/Programs/Python/Python311/python.exe",
|
|
|
|
|
"/usr/bin/python3",
|
|
|
|
|
"/usr/bin/python",
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
QString pathEnv = qEnvironmentVariable("PATH");
|
|
|
|
|
#ifdef Q_OS_WIN
|
|
|
|
|
QStringList pathDirs = pathEnv.split(';', Qt::SkipEmptyParts);
|
|
|
|
|
#else
|
|
|
|
|
QStringList pathDirs = pathEnv.split(':', Qt::SkipEmptyParts);
|
|
|
|
|
#endif
|
|
|
|
|
for (const QString& dir : pathDirs) {
|
|
|
|
|
searchPaths.append(dir + "/python.exe");
|
|
|
|
|
searchPaths.append(dir + "/python3.exe");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (const QString& path : searchPaths) {
|
|
|
|
|
if (QFileInfo::exists(path)) {
|
|
|
|
|
return QDir::cleanPath(path);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return QString();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString Settings::scriptsDirectory() const
|
|
|
|
|
{
|
|
|
|
|
QString defaultPath = QCoreApplication::applicationDirPath() + "/scripts";
|
|
|
|
|
return m_settings.value("Tools/ScriptsDirectory", defaultPath).toString();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Settings::setScriptsDirectory(const QString& path)
|
|
|
|
|
{
|
|
|
|
|
m_settings.setValue("Tools/ScriptsDirectory", path);
|
|
|
|
|
emit settingsChanged();
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-08 00:35:31 -05:00
|
|
|
// Debug/Logging
|
|
|
|
|
bool Settings::debugLoggingEnabled() const
|
|
|
|
|
{
|
|
|
|
|
return m_settings.value("Debug/LoggingEnabled", false).toBool();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Settings::setDebugLoggingEnabled(bool enable)
|
|
|
|
|
{
|
|
|
|
|
m_settings.setValue("Debug/LoggingEnabled", enable);
|
2026-01-11 12:09:31 -05:00
|
|
|
m_settings.sync(); // Ensure immediate persistence
|
2026-01-08 00:35:31 -05:00
|
|
|
emit debugLoggingChanged(enable);
|
|
|
|
|
emit settingsChanged();
|
2026-01-11 12:09:31 -05:00
|
|
|
|
|
|
|
|
// Provide immediate feedback in log panel
|
|
|
|
|
if (enable) {
|
|
|
|
|
LogManager::instance().addEntry("[SETTINGS] Debug logging ENABLED - parse a file to see debug output");
|
|
|
|
|
} else {
|
|
|
|
|
LogManager::instance().addEntry("[SETTINGS] Debug logging DISABLED");
|
|
|
|
|
}
|
2026-01-08 00:35:31 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Settings::verboseParsingEnabled() const
|
|
|
|
|
{
|
|
|
|
|
return m_settings.value("Debug/VerboseParsing", false).toBool();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Settings::setVerboseParsingEnabled(bool enable)
|
|
|
|
|
{
|
|
|
|
|
m_settings.setValue("Debug/VerboseParsing", enable);
|
2026-01-11 12:09:31 -05:00
|
|
|
m_settings.sync(); // Ensure immediate persistence
|
2026-01-08 00:35:31 -05:00
|
|
|
emit settingsChanged();
|
2026-01-11 12:09:31 -05:00
|
|
|
|
|
|
|
|
// Provide immediate feedback in log panel
|
|
|
|
|
if (enable) {
|
|
|
|
|
LogManager::instance().addEntry("[SETTINGS] Verbose parsing ENABLED");
|
|
|
|
|
} else {
|
|
|
|
|
LogManager::instance().addEntry("[SETTINGS] Verbose parsing DISABLED");
|
|
|
|
|
}
|
2026-01-08 00:35:31 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Settings::logToFileEnabled() const
|
|
|
|
|
{
|
|
|
|
|
return m_settings.value("Debug/LogToFile", false).toBool();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Settings::setLogToFileEnabled(bool enable)
|
|
|
|
|
{
|
|
|
|
|
m_settings.setValue("Debug/LogToFile", enable);
|
2026-01-11 12:09:31 -05:00
|
|
|
m_settings.sync(); // Ensure immediate persistence
|
2026-01-08 00:35:31 -05:00
|
|
|
emit settingsChanged();
|
2026-01-11 12:09:31 -05:00
|
|
|
|
|
|
|
|
// Provide immediate feedback in log panel
|
|
|
|
|
if (enable) {
|
|
|
|
|
LogManager::instance().addEntry("[SETTINGS] Log to file ENABLED");
|
|
|
|
|
} else {
|
|
|
|
|
LogManager::instance().addEntry("[SETTINGS] Log to file DISABLED");
|
|
|
|
|
}
|
2026-01-08 00:35:31 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// View
|
|
|
|
|
QString Settings::fontFamily() const
|
|
|
|
|
{
|
|
|
|
|
return m_settings.value("View/FontFamily", "Segoe UI").toString();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Settings::setFontFamily(const QString& family)
|
|
|
|
|
{
|
|
|
|
|
m_settings.setValue("View/FontFamily", family);
|
|
|
|
|
emit settingsChanged();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int Settings::fontSize() const
|
|
|
|
|
{
|
|
|
|
|
return m_settings.value("View/FontSize", 10).toInt();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Settings::setFontSize(int size)
|
|
|
|
|
{
|
|
|
|
|
m_settings.setValue("View/FontSize", size);
|
|
|
|
|
emit settingsChanged();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int Settings::viewZoom() const
|
|
|
|
|
{
|
|
|
|
|
return m_settings.value("View/Zoom", 100).toInt();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Settings::setViewZoom(int zoom)
|
|
|
|
|
{
|
|
|
|
|
m_settings.setValue("View/Zoom", zoom);
|
|
|
|
|
emit settingsChanged();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Tree Widget
|
|
|
|
|
bool Settings::showItemCounts() const
|
|
|
|
|
{
|
|
|
|
|
return m_settings.value("Tree/ShowItemCounts", true).toBool();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Settings::setShowItemCounts(bool show)
|
|
|
|
|
{
|
|
|
|
|
m_settings.setValue("Tree/ShowItemCounts", show);
|
|
|
|
|
emit settingsChanged();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Settings::collapseByDefault() const
|
|
|
|
|
{
|
|
|
|
|
return m_settings.value("Tree/CollapseByDefault", true).toBool();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Settings::setCollapseByDefault(bool collapse)
|
|
|
|
|
{
|
|
|
|
|
m_settings.setValue("Tree/CollapseByDefault", collapse);
|
|
|
|
|
emit settingsChanged();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Settings::groupByExtension() const
|
|
|
|
|
{
|
|
|
|
|
return m_settings.value("Tree/GroupByExtension", false).toBool();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Settings::setGroupByExtension(bool group)
|
|
|
|
|
{
|
|
|
|
|
m_settings.setValue("Tree/GroupByExtension", group);
|
|
|
|
|
emit settingsChanged();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Settings::naturalSorting() const
|
|
|
|
|
{
|
|
|
|
|
return m_settings.value("Tree/NaturalSorting", true).toBool();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Settings::setNaturalSorting(bool enable)
|
|
|
|
|
{
|
|
|
|
|
m_settings.setValue("Tree/NaturalSorting", enable);
|
|
|
|
|
emit settingsChanged();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Hex Viewer
|
|
|
|
|
int Settings::hexBytesPerLine() const
|
|
|
|
|
{
|
|
|
|
|
return m_settings.value("HexViewer/BytesPerLine", 16).toInt();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Settings::setHexBytesPerLine(int bytes)
|
|
|
|
|
{
|
|
|
|
|
m_settings.setValue("HexViewer/BytesPerLine", bytes);
|
|
|
|
|
emit settingsChanged();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Settings::hexShowAscii() const
|
|
|
|
|
{
|
|
|
|
|
return m_settings.value("HexViewer/ShowAscii", true).toBool();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Settings::setHexShowAscii(bool show)
|
|
|
|
|
{
|
|
|
|
|
m_settings.setValue("HexViewer/ShowAscii", show);
|
|
|
|
|
emit settingsChanged();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Audio Preview
|
|
|
|
|
bool Settings::audioAutoPlay() const
|
|
|
|
|
{
|
|
|
|
|
return m_settings.value("Audio/AutoPlay", false).toBool();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Settings::setAudioAutoPlay(bool enable)
|
|
|
|
|
{
|
|
|
|
|
m_settings.setValue("Audio/AutoPlay", enable);
|
|
|
|
|
emit settingsChanged();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Image Preview
|
|
|
|
|
bool Settings::imageShowGrid() const
|
|
|
|
|
{
|
|
|
|
|
return m_settings.value("Image/ShowGrid", false).toBool();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Settings::setImageShowGrid(bool show)
|
|
|
|
|
{
|
|
|
|
|
m_settings.setValue("Image/ShowGrid", show);
|
|
|
|
|
emit settingsChanged();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Settings::imageAutoZoom() const
|
|
|
|
|
{
|
|
|
|
|
return m_settings.value("Image/AutoZoom", true).toBool();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Settings::setImageAutoZoom(bool enable)
|
|
|
|
|
{
|
|
|
|
|
m_settings.setValue("Image/AutoZoom", enable);
|
|
|
|
|
emit settingsChanged();
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-11 12:09:31 -05:00
|
|
|
// File Type Associations
|
|
|
|
|
static const QStringList s_defaultTextExtensions = {
|
|
|
|
|
"txt", "xml", "json", "csv", "cfg", "ini", "log",
|
|
|
|
|
"html", "htm", "css", "js", "lua", "py", "sh", "bat",
|
|
|
|
|
"md", "yaml", "yml", "gsc", "csc", "arena", "vision"
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const QStringList s_defaultImageExtensions = {
|
|
|
|
|
"tga", "dds", "png", "jpg", "jpeg", "bmp", "xbtex", "iwi"
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const QStringList s_defaultAudioExtensions = {
|
|
|
|
|
"wav", "wave", "mp3", "ogg", "flac", "raw"
|
|
|
|
|
};
|
|
|
|
|
static const QStringList s_defaultListExtensions = {
|
|
|
|
|
"str"
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
QStringList Settings::textFileExtensions() const
|
|
|
|
|
{
|
|
|
|
|
QStringList exts = m_settings.value("FileTypes/Text").toStringList();
|
|
|
|
|
if (exts.isEmpty()) {
|
|
|
|
|
return s_defaultTextExtensions;
|
|
|
|
|
}
|
|
|
|
|
return exts;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Settings::setTextFileExtensions(const QStringList& extensions)
|
|
|
|
|
{
|
|
|
|
|
m_settings.setValue("FileTypes/Text", extensions);
|
|
|
|
|
emit settingsChanged();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QStringList Settings::imageFileExtensions() const
|
|
|
|
|
{
|
|
|
|
|
QStringList exts = m_settings.value("FileTypes/Image").toStringList();
|
|
|
|
|
if (exts.isEmpty()) {
|
|
|
|
|
return s_defaultImageExtensions;
|
|
|
|
|
}
|
|
|
|
|
return exts;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Settings::setImageFileExtensions(const QStringList& extensions)
|
|
|
|
|
{
|
|
|
|
|
m_settings.setValue("FileTypes/Image", extensions);
|
|
|
|
|
emit settingsChanged();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QStringList Settings::audioFileExtensions() const
|
|
|
|
|
{
|
|
|
|
|
QStringList exts = m_settings.value("FileTypes/Audio").toStringList();
|
|
|
|
|
if (exts.isEmpty()) {
|
|
|
|
|
return s_defaultAudioExtensions;
|
|
|
|
|
}
|
|
|
|
|
return exts;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Settings::setAudioFileExtensions(const QStringList& extensions)
|
|
|
|
|
{
|
|
|
|
|
m_settings.setValue("FileTypes/Audio", extensions);
|
|
|
|
|
emit settingsChanged();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QStringList Settings::listFileExtensions() const
|
|
|
|
|
{
|
|
|
|
|
QStringList exts = m_settings.value("FileTypes/List").toStringList();
|
|
|
|
|
if (exts.isEmpty()) {
|
|
|
|
|
return s_defaultListExtensions;
|
|
|
|
|
}
|
|
|
|
|
return exts;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Settings::setListFileExtensions(const QStringList& extensions)
|
|
|
|
|
{
|
|
|
|
|
m_settings.setValue("FileTypes/List", extensions);
|
|
|
|
|
emit settingsChanged();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString Settings::viewerForExtension(const QString& extension) const
|
|
|
|
|
{
|
|
|
|
|
QString ext = extension.toLower();
|
|
|
|
|
if (ext.startsWith('.')) {
|
|
|
|
|
ext = ext.mid(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (textFileExtensions().contains(ext, Qt::CaseInsensitive)) {
|
|
|
|
|
return "text";
|
|
|
|
|
}
|
|
|
|
|
if (imageFileExtensions().contains(ext, Qt::CaseInsensitive)) {
|
|
|
|
|
return "image";
|
|
|
|
|
}
|
|
|
|
|
if (audioFileExtensions().contains(ext, Qt::CaseInsensitive)) {
|
|
|
|
|
return "audio";
|
|
|
|
|
}
|
|
|
|
|
if (listFileExtensions().contains(ext, Qt::CaseInsensitive)) {
|
|
|
|
|
return "list";
|
|
|
|
|
}
|
|
|
|
|
return "hex"; // Default to hex viewer
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Settings::setViewerForExtension(const QString& extension, const QString& viewer)
|
|
|
|
|
{
|
|
|
|
|
QString ext = extension.toLower();
|
|
|
|
|
if (ext.startsWith('.')) {
|
|
|
|
|
ext = ext.mid(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Remove from all lists first
|
|
|
|
|
QStringList textExts = textFileExtensions();
|
|
|
|
|
QStringList imageExts = imageFileExtensions();
|
|
|
|
|
QStringList audioExts = audioFileExtensions();
|
|
|
|
|
QStringList listExts = listFileExtensions();
|
|
|
|
|
|
|
|
|
|
textExts.removeAll(ext);
|
|
|
|
|
imageExts.removeAll(ext);
|
|
|
|
|
audioExts.removeAll(ext);
|
|
|
|
|
listExts.removeAll(ext);
|
|
|
|
|
|
|
|
|
|
// Add to appropriate list
|
|
|
|
|
if (viewer == "text") {
|
|
|
|
|
textExts.append(ext);
|
|
|
|
|
} else if (viewer == "image") {
|
|
|
|
|
imageExts.append(ext);
|
|
|
|
|
} else if (viewer == "audio") {
|
|
|
|
|
audioExts.append(ext);
|
|
|
|
|
} else if (viewer == "list") {
|
|
|
|
|
listExts.append(ext);
|
|
|
|
|
}
|
|
|
|
|
// "hex" means don't add to any list
|
|
|
|
|
|
|
|
|
|
setTextFileExtensions(textExts);
|
|
|
|
|
setImageFileExtensions(imageExts);
|
|
|
|
|
setAudioFileExtensions(audioExts);
|
|
|
|
|
setListFileExtensions(listExts);
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-08 00:35:31 -05:00
|
|
|
// Window State
|
|
|
|
|
QByteArray Settings::windowGeometry() const
|
|
|
|
|
{
|
|
|
|
|
return m_settings.value("Window/Geometry").toByteArray();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Settings::setWindowGeometry(const QByteArray& geometry)
|
|
|
|
|
{
|
|
|
|
|
m_settings.setValue("Window/Geometry", geometry);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QByteArray Settings::windowState() const
|
|
|
|
|
{
|
|
|
|
|
return m_settings.value("Window/State").toByteArray();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Settings::setWindowState(const QByteArray& state)
|
|
|
|
|
{
|
|
|
|
|
m_settings.setValue("Window/State", state);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Recent Files
|
|
|
|
|
QStringList Settings::recentFiles() const
|
|
|
|
|
{
|
|
|
|
|
return m_settings.value("RecentFiles/List").toStringList();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Settings::addRecentFile(const QString& path)
|
|
|
|
|
{
|
|
|
|
|
QStringList files = recentFiles();
|
|
|
|
|
files.removeAll(path);
|
|
|
|
|
files.prepend(path);
|
|
|
|
|
while (files.size() > 10) {
|
|
|
|
|
files.removeLast();
|
|
|
|
|
}
|
|
|
|
|
m_settings.setValue("RecentFiles/List", files);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Settings::clearRecentFiles()
|
|
|
|
|
{
|
|
|
|
|
m_settings.setValue("RecentFiles/List", QStringList());
|
|
|
|
|
}
|
2026-01-08 00:43:52 -05:00
|
|
|
|
|
|
|
|
void Settings::resetToDefaults()
|
|
|
|
|
{
|
|
|
|
|
// Clear all settings
|
|
|
|
|
m_settings.clear();
|
|
|
|
|
|
|
|
|
|
// Apply default theme immediately
|
|
|
|
|
emit themeChanged(s_themes["XPlor Dark"]);
|
|
|
|
|
emit settingsChanged();
|
|
|
|
|
|
|
|
|
|
sync();
|
|
|
|
|
}
|