Merge pull request #734 from GriffinRichards/config-file

Fix some issues with config loading
This commit is contained in:
GriffinR 2025-05-22 14:28:13 -04:00 committed by GitHub
commit 947142e370
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 79 additions and 86 deletions

View File

@ -29,11 +29,21 @@ class KeyValueConfigBase
{
public:
bool save();
void load();
virtual ~KeyValueConfigBase();
bool load(const QString &dir = QString());
void setRoot(const QString &dir);
QString root() const { return m_root; }
QString filepath() const { return m_filepath; }
QString filename() const { return m_filename; }
explicit KeyValueConfigBase(const QString &filename)
: m_root(QString()),
m_filename(filename),
m_filepath(filename)
{ };
virtual ~KeyValueConfigBase() {};
virtual void reset() = 0;
protected:
virtual QString getConfigFilepath() = 0;
virtual void parseConfigKeyValue(QString key, QString value) = 0;
virtual QMap<QString, QString> getKeyValueMap() = 0;
virtual void init() = 0;
@ -43,14 +53,16 @@ protected:
static int getConfigInteger(const QString &key, const QString &value, int min = INT_MIN, int max = INT_MAX, int defaultValue = 0);
static uint32_t getConfigUint32(const QString &key, const QString &value, uint32_t min = 0, uint32_t max = UINT_MAX, uint32_t defaultValue = 0);
static QColor getConfigColor(const QString &key, const QString &value, const QColor &defaultValue = Qt::black);
QString m_root;
QString m_filename;
QString m_filepath;
};
class PorymapConfig: public KeyValueConfigBase
{
public:
PorymapConfig() {
reset();
}
PorymapConfig();
virtual void reset() override {
this->recentProjects.clear();
this->projectManuallyClosed = false;
@ -167,7 +179,6 @@ public:
std::set<LogType> statusBarLogTypes;
protected:
virtual QString getConfigFilepath() override;
virtual void parseConfigKeyValue(QString key, QString value) override;
virtual QMap<QString, QString> getKeyValueMap() override;
virtual void init() override {};
@ -318,9 +329,7 @@ enum ProjectFilePath {
class ProjectConfig: public KeyValueConfigBase
{
public:
ProjectConfig() {
reset();
}
ProjectConfig();
virtual void reset() override {
this->baseGameVersion = BaseGameVersion::pokeemerald;
// Reset non-version-specific settings
@ -365,6 +374,7 @@ public:
static QString getPlayerIconPath(BaseGameVersion baseGameVersion, int character);
static QIcon getPlayerIcon(BaseGameVersion baseGameVersion, int character);
QString projectDir() const { return m_root; } // Alias for root()
void reset(BaseGameVersion baseGameVersion);
void setFilePath(ProjectFilePath pathId, const QString &path);
void setFilePath(const QString &pathId, const QString &path);
@ -387,7 +397,6 @@ public:
QMap<QString, QString> getPokemonIconPaths();
BaseGameVersion baseGameVersion;
QString projectDir;
bool usePoryScript;
bool useCustomBorderSize;
bool eventWeatherTriggerEnabled;
@ -435,7 +444,6 @@ public:
QMap<QString,QString> globalConstants;
protected:
virtual QString getConfigFilepath() override;
virtual void parseConfigKeyValue(QString key, QString value) override;
virtual QMap<QString, QString> getKeyValueMap() override;
virtual void init() override;
@ -454,27 +462,25 @@ extern ProjectConfig projectConfig;
class UserConfig: public KeyValueConfigBase
{
public:
UserConfig() {
reset();
}
UserConfig();
virtual void reset() override {
this->recentMapOrLayout = QString();
this->useEncounterJson = true;
this->customScripts.clear();
this->readKeys.clear();
}
QString projectDir() const { return m_root; } // Alias for root()
void parseCustomScripts(QString input);
QString outputCustomScripts();
void setCustomScripts(QStringList scripts, QList<bool> enabled);
QStringList getCustomScriptPaths();
QList<bool> getCustomScriptsEnabled();
QString projectDir;
QString recentMapOrLayout;
bool useEncounterJson;
protected:
virtual QString getConfigFilepath() override;
virtual void parseConfigKeyValue(QString key, QString value) override;
virtual QMap<QString, QString> getKeyValueMap() override;
virtual void init() override;
@ -496,10 +502,7 @@ class Shortcut;
class ShortcutsConfig : public KeyValueConfigBase
{
public:
ShortcutsConfig() :
user_shortcuts({ }),
default_shortcuts({ })
{ }
ShortcutsConfig();
virtual void reset() override { user_shortcuts.clear(); }
@ -512,7 +515,6 @@ public:
QList<QKeySequence> userShortcuts(const QObject *object) const;
protected:
virtual QString getConfigFilepath() override;
virtual void parseConfigKeyValue(QString key, QString value) override;
virtual QMap<QString, QString> getKeyValueMap() override;
virtual void init() override { };

View File

@ -386,7 +386,6 @@ private:
void scrollMapListToCurrentLayout(MapTree *list);
void scrollCurrentMapListToItem(const QString &itemName);
void showFileWatcherWarning();
QString getExistingDirectory(QString);
bool openProject(QString dir, bool initial = false);
bool closeProject();
void showRecentError(const QString &baseMessage);

View File

@ -203,17 +203,26 @@ ProjectFilePath reverseDefaultPaths(QString str) {
return static_cast<ProjectFilePath>(-1);
}
KeyValueConfigBase::~KeyValueConfigBase() {
void KeyValueConfigBase::setRoot(const QString &root) {
m_root = root;
QDir dir(m_root);
if (!m_root.isEmpty() && !dir.exists()) {
dir.mkpath(m_root);
}
m_filepath = dir.absoluteFilePath(m_filename);
}
void KeyValueConfigBase::load() {
bool KeyValueConfigBase::load(const QString &root) {
if (!root.isEmpty()) {
setRoot(root);
}
reset();
QFile file(this->getConfigFilepath());
if (!file.exists()) {
QFile file(this->filepath());
if (file.exists() && !file.open(QIODevice::ReadOnly)) {
logError(QString("Could not open config file '%1': ").arg(this->filepath()) + file.errorString());
return false;
} else if (file.size() == 0) {
this->init();
} else if (!file.open(QIODevice::ReadOnly)) {
logError(QString("Could not open config file '%1': ").arg(this->getConfigFilepath()) + file.errorString());
}
QTextStream in(&file);
@ -231,7 +240,7 @@ void KeyValueConfigBase::load() {
QRegularExpressionMatch match = re.match(line);
if (!match.hasMatch()) {
logWarn(QString("Invalid config line in %1: '%2'").arg(this->getConfigFilepath()).arg(line));
logWarn(QString("Invalid config line in %1: '%2'").arg(this->filepath()).arg(line));
continue;
}
@ -240,6 +249,7 @@ void KeyValueConfigBase::load() {
this->setUnreadKeys();
file.close();
return true;
}
bool KeyValueConfigBase::save() {
@ -249,9 +259,9 @@ bool KeyValueConfigBase::save() {
text += QString("%1=%2\n").arg(it.key()).arg(it.value());
}
QFile file(this->getConfigFilepath());
QFile file(this->filepath());
if (!file.open(QIODevice::WriteOnly)) {
logError(QString("Could not open config file '%1' for writing: ").arg(this->getConfigFilepath()) + file.errorString());
logError(QString("Could not open config file '%1' for writing: ").arg(this->filepath()) + file.errorString());
return false;
}
@ -300,16 +310,9 @@ QColor KeyValueConfigBase::getConfigColor(const QString &key, const QString &val
PorymapConfig porymapConfig;
QString PorymapConfig::getConfigFilepath() {
// porymap config file is in the same directory as porymap itself.
QString settingsPath = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
QDir dir(settingsPath);
if (!dir.exists())
dir.mkpath(settingsPath);
QString configPath = dir.absoluteFilePath("porymap.cfg");
return configPath;
PorymapConfig::PorymapConfig() : KeyValueConfigBase(QStringLiteral("porymap.cfg")) {
reset();
setRoot(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation));
}
void PorymapConfig::parseConfigKeyValue(QString key, QString value) {
@ -330,7 +333,7 @@ void PorymapConfig::parseConfigKeyValue(QString key, QString value) {
bool ok;
int tab = key.mid(QStringLiteral("map_list_hide_empty_enabled/").length()).toInt(&ok, 0);
if (!ok) {
logWarn(QString("Invalid config key found in config file %1: '%2'").arg(this->getConfigFilepath()).arg(key));
logWarn(QString("Invalid config key found in config file %1: '%2'").arg(this->filepath()).arg(key));
return;
}
this->mapListHideEmptyEnabled.insert(tab, getConfigBool(key, value));
@ -485,7 +488,7 @@ void PorymapConfig::parseConfigKeyValue(QString key, QString value) {
this->statusBarLogTypes.insert(type);
}
} else {
logWarn(QString("Invalid config key found in config file %1: '%2'").arg(this->getConfigFilepath()).arg(key));
logWarn(QString("Invalid config key found in config file %1: '%2'").arg(this->filepath()).arg(key));
}
}
@ -773,9 +776,8 @@ QIcon ProjectConfig::getPlayerIcon(BaseGameVersion baseGameVersion, int characte
ProjectConfig projectConfig;
QString ProjectConfig::getConfigFilepath() {
// porymap config file is in the same directory as porymap itself.
return QDir(this->projectDir).filePath("porymap.project.cfg");
ProjectConfig::ProjectConfig() : KeyValueConfigBase(QStringLiteral("porymap.project.cfg")) {
reset();
}
void ProjectConfig::parseConfigKeyValue(QString key, QString value) {
@ -871,14 +873,14 @@ void ProjectConfig::parseConfigKeyValue(QString key, QString value) {
if (k != static_cast<ProjectFilePath>(-1)) {
this->setFilePath(k, value);
} else {
logWarn(QString("Invalid config key found in config file %1: '%2'").arg(this->getConfigFilepath()).arg(key));
logWarn(QString("Invalid config key found in config file %1: '%2'").arg(this->filepath()).arg(key));
}
} else if (key.startsWith("ident/")) {
auto identifierId = reverseDefaultIdentifier(key.mid(QStringLiteral("ident/").length()));
if (identifierId != static_cast<ProjectIdentifier>(-1)) {
this->setIdentifier(identifierId, value);
} else {
logWarn(QString("Invalid config key found in config file %1: '%2'").arg(this->getConfigFilepath()).arg(key));
logWarn(QString("Invalid config key found in config file %1: '%2'").arg(this->filepath()).arg(key));
}
} else if (key.startsWith("global_constant/")) {
this->globalConstants.insert(key.mid(QStringLiteral("global_constant/").length()), value);
@ -935,7 +937,7 @@ void ProjectConfig::parseConfigKeyValue(QString key, QString value) {
} else if (key == "forced_major_version") {
this->forcedMajorVersion = getConfigInteger(key, value);
} else {
logWarn(QString("Invalid config key found in config file %1: '%2'").arg(this->getConfigFilepath()).arg(key));
logWarn(QString("Invalid config key found in config file %1: '%2'").arg(this->filepath()).arg(key));
}
readKeys.append(key);
}
@ -1048,7 +1050,7 @@ QMap<QString, QString> ProjectConfig::getKeyValueMap() {
}
void ProjectConfig::init() {
QString dirName = QDir(this->projectDir).dirName().toLower();
QString dirName = QDir(this->projectDir()).dirName().toLower();
BaseGameVersion version = stringToBaseGameVersion(dirName);
if (version != BaseGameVersion::none) {
@ -1107,7 +1109,7 @@ QString ProjectConfig::getFilePath(ProjectFilePath pathId) {
QString customPath = this->getCustomFilePath(pathId);
if (!customPath.isEmpty()) {
// A custom filepath has been specified. If the file/folder exists, use that.
const QString baseDir = this->projectDir + "/";
const QString baseDir = this->projectDir() + "/";
if (customPath.startsWith(baseDir)) {
customPath.remove(0, baseDir.length());
}
@ -1201,9 +1203,8 @@ QMap<QString, QString> ProjectConfig::getPokemonIconPaths() {
UserConfig userConfig;
QString UserConfig::getConfigFilepath() {
// porymap config file is in the same directory as porymap itself.
return QDir(this->projectDir).filePath("porymap.user.cfg");
UserConfig::UserConfig() : KeyValueConfigBase(QStringLiteral("porymap.user.cfg")) {
reset();
}
void UserConfig::parseConfigKeyValue(QString key, QString value) {
@ -1214,7 +1215,7 @@ void UserConfig::parseConfigKeyValue(QString key, QString value) {
} else if (key == "custom_scripts") {
this->parseCustomScripts(value);
} else {
logWarn(QString("Invalid config key found in config file %1: '%2'").arg(this->getConfigFilepath()).arg(key));
logWarn(QString("Invalid config key found in config file %1: '%2'").arg(this->filepath()).arg(key));
}
readKeys.append(key);
}
@ -1283,15 +1284,10 @@ QList<bool> UserConfig::getCustomScriptsEnabled() {
ShortcutsConfig shortcutsConfig;
QString ShortcutsConfig::getConfigFilepath() {
QString settingsPath = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
QDir dir(settingsPath);
if (!dir.exists())
dir.mkpath(settingsPath);
QString configPath = dir.absoluteFilePath("porymap.shortcuts.cfg");
return configPath;
ShortcutsConfig::ShortcutsConfig() : KeyValueConfigBase(QStringLiteral("porymap.shortcuts.cfg")),
user_shortcuts({ }),
default_shortcuts({ }) {
setRoot(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation));
}
void ShortcutsConfig::parseConfigKeyValue(QString key, QString value) {

View File

@ -176,7 +176,7 @@ QStringList Map::getScriptLabels(Event::Group group) {
QString Map::getScriptsFilepath() const {
const bool usePoryscript = projectConfig.usePoryScript;
auto path = QDir::cleanPath(QString("%1/%2/%3/scripts")
.arg(projectConfig.projectDir)
.arg(projectConfig.projectDir())
.arg(projectConfig.getFilePath(ProjectFilePath::data_map_folders))
.arg(!m_sharedScriptsMap.isEmpty() ? m_sharedScriptsMap : m_name));
auto extension = Project::getScriptFileExtension(usePoryscript);
@ -188,7 +188,7 @@ QString Map::getScriptsFilepath() const {
QString Map::getJsonFilepath(const QString &mapName) {
return QDir::cleanPath(QString("%1/%2/%3/map.json")
.arg(projectConfig.projectDir)
.arg(projectConfig.projectDir())
.arg(projectConfig.getFilePath(ProjectFilePath::data_map_folders))
.arg(mapName));
}

View File

@ -2339,7 +2339,7 @@ void Editor::openMapJson(const QString &mapName) const {
}
void Editor::openLayoutJson(const QString &layoutId) const {
QString path = QDir::cleanPath(QString("%1/%2").arg(projectConfig.projectDir).arg(projectConfig.getFilePath(ProjectFilePath::json_layouts)));
QString path = QDir::cleanPath(QString("%1/%2").arg(projectConfig.projectDir()).arg(projectConfig.getFilePath(ProjectFilePath::json_layouts)));
QString idField = QString("\"id\": \"%1\",").arg(layoutId);
openInTextEditor(path, ParseUtil::getJsonLineNumber(path, idField));
}

View File

@ -728,10 +728,11 @@ bool MainWindow::openProject(QString dir, bool initial) {
porysplash->start();
porysplash->showLoadingMessage("config");
userConfig.projectDir = dir;
userConfig.load();
projectConfig.projectDir = dir;
projectConfig.load();
if (!projectConfig.load(dir) || !userConfig.load(dir)) {
showProjectOpenFailure();
porysplash->stop();
return false;
}
porysplash->showLoadingMessage("custom scripts");
Scripting::init(this);
@ -992,13 +993,8 @@ void MainWindow::showFileWatcherWarning() {
this->fileWatcherWarning->exec();
}
QString MainWindow::getExistingDirectory(QString dir) {
return FileDialog::getExistingDirectory(this, "Open Directory", dir, QFileDialog::ShowDirsOnly);
}
void MainWindow::on_action_Open_Project_triggered()
{
QString dir = getExistingDirectory(!projectConfig.projectDir.isEmpty() ? userConfig.projectDir : ".");
void MainWindow::on_action_Open_Project_triggered() {
QString dir = FileDialog::getExistingDirectory(this, QStringLiteral("Choose Project Folder"));
if (!dir.isEmpty())
openProject(dir);
}
@ -3010,7 +3006,7 @@ void MainWindow::reloadScriptEngine() {
Scripting::init(this);
Scripting::populateGlobalObject(this);
// Lying to the scripts here, simulating a project reload
Scripting::cb_ProjectOpened(projectConfig.projectDir);
Scripting::cb_ProjectOpened(projectConfig.projectDir());
if (this->editor) {
if (this->editor->layout)
Scripting::cb_LayoutOpened(this->editor->layout->name);

View File

@ -3375,7 +3375,7 @@ QString Project::getExistingFilepath(QString filepath) {
if (filepath.isEmpty() || QFile::exists(filepath))
return filepath;
filepath = QDir::cleanPath(projectConfig.projectDir + QDir::separator() + filepath);
filepath = QDir::cleanPath(projectConfig.projectDir() + QDir::separator() + filepath);
if (QFile::exists(filepath))
return filepath;

View File

@ -11,7 +11,7 @@
CustomScriptsEditor::CustomScriptsEditor(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::CustomScriptsEditor),
baseDir(userConfig.projectDir + "/")
baseDir(userConfig.projectDir() + "/")
{
ui->setupUi(this);
setAttribute(Qt::WA_DeleteOnClose);

View File

@ -94,7 +94,7 @@ void Prefab::savePrefabs() {
QFileInfo info(filepath);
if (info.isRelative()) {
filepath = QDir::cleanPath(projectConfig.projectDir + QDir::separator() + filepath);
filepath = QDir::cleanPath(projectConfig.projectDir() + QDir::separator() + filepath);
}
QFile prefabsFile(filepath);
if (!prefabsFile.open(QIODevice::WriteOnly)) {
@ -297,7 +297,7 @@ bool Prefab::tryImportDefaultPrefabs(QWidget * parent, BaseGameVersion version,
if (fileInfo.suffix().isEmpty())
filepath += ".json";
if (fileInfo.isRelative()) {
absFilepath = QDir::cleanPath(projectConfig.projectDir + QDir::separator() + filepath);
absFilepath = QDir::cleanPath(projectConfig.projectDir() + QDir::separator() + filepath);
} else {
absFilepath = filepath;
}

View File

@ -21,7 +21,7 @@ ProjectSettingsEditor::ProjectSettingsEditor(QWidget *parent, Project *project)
QMainWindow(parent),
ui(new Ui::ProjectSettingsEditor),
project(project),
baseDir(projectConfig.projectDir + "/")
baseDir(projectConfig.projectDir() + "/")
{
ui->setupUi(this);
setAttribute(Qt::WA_DeleteOnClose);