Add global constants settings

This commit is contained in:
GriffinR 2025-04-22 15:57:17 -04:00
parent 8fc9e05359
commit b7e19a427d
12 changed files with 402 additions and 28 deletions

89
forms/newdefinedialog.ui Normal file
View File

@ -0,0 +1,89 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>NewDefineDialog</class>
<widget class="QDialog" name="NewDefineDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>252</width>
<height>124</height>
</rect>
</property>
<property name="modal">
<bool>true</bool>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QFrame" name="form">
<layout class="QFormLayout" name="formLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item row="0" column="0">
<widget class="QLabel" name="label_Name">
<property name="text">
<string>Name</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="lineEdit_Name">
<property name="clearButtonEnabled">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLabel" name="label_NameError">
<property name="visible">
<bool>false</bool>
</property>
<property name="styleSheet">
<string notr="true">color: rgb(255, 0, 0)</string>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="lineEdit_Value"/>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_Value">
<property name="text">
<string>Value</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::StandardButton::Cancel|QDialogButtonBox::StandardButton::Ok</set>
</property>
<property name="centerButtons">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -21,7 +21,7 @@
<item>
<widget class="QTabWidget" name="mainTabs">
<property name="currentIndex">
<number>0</number>
<number>4</number>
</property>
<widget class="QWidget" name="tab_General">
<attribute name="title">
@ -1582,19 +1582,21 @@
<height>499</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_10">
<item>
<widget class="QToolButton" name="button_HelpFiles">
<property name="text">
<string>...</string>
<layout class="QGridLayout" name="gridLayout_10" rowstretch="1,2,8">
<item row="0" column="1">
<spacer name="horizontalSpacer_5">
<property name="orientation">
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="icon">
<iconset resource="../resources/images.qrc">
<normaloff>:/icons/help.ico</normaloff>:/icons/help.ico</iconset>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</widget>
</spacer>
</item>
<item>
<item row="2" column="0" colspan="3">
<widget class="QWidget" name="widget_ProjectPaths" native="true">
<layout class="QVBoxLayout" name="verticalLayout_6">
<property name="spacing">
@ -1626,7 +1628,7 @@
<x>0</x>
<y>0</y>
<width>544</width>
<height>437</height>
<height>338</height>
</rect>
</property>
<layout class="QFormLayout" name="layout_ProjectPaths">
@ -1646,6 +1648,34 @@
</layout>
</widget>
</item>
<item row="0" column="2">
<widget class="QPushButton" name="button_AddGlobalConstantsFile">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Add additional C files containing #defines or enums. These will be used to resolve unknown symbols during project launch.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Add Global Constants File...</string>
</property>
<property name="icon">
<iconset resource="../resources/images.qrc">
<normaloff>:/icons/add.ico</normaloff>:/icons/add.ico</iconset>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QToolButton" name="button_HelpFiles">
<property name="text">
<string>...</string>
</property>
<property name="icon">
<iconset resource="../resources/images.qrc">
<normaloff>:/icons/help.ico</normaloff>:/icons/help.ico</iconset>
</property>
</widget>
</item>
<item row="1" column="0" colspan="3">
<layout class="QGridLayout" name="gridLayout_GlobalConstantsFiles"/>
</item>
</layout>
</widget>
</widget>
@ -1671,8 +1701,8 @@
<height>499</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_19">
<item>
<layout class="QGridLayout" name="gridLayout_11">
<item row="0" column="0">
<widget class="QToolButton" name="button_HelpIdentifiers">
<property name="text">
<string>...</string>
@ -1683,7 +1713,7 @@
</property>
</widget>
</item>
<item>
<item row="2" column="0" colspan="3">
<widget class="QWidget" name="widget_Identifiers" native="true">
<layout class="QVBoxLayout" name="verticalLayout_20">
<property name="spacing">
@ -1715,7 +1745,7 @@
<x>0</x>
<y>0</y>
<width>544</width>
<height>437</height>
<height>421</height>
</rect>
</property>
<layout class="QFormLayout" name="layout_Identifiers">
@ -1735,6 +1765,36 @@
</layout>
</widget>
</item>
<item row="0" column="2">
<widget class="QPushButton" name="button_AddGlobalConstant">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Add an additional #define name and expression. This may be used to evaluate other #defines during project launch.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Add Global Constant...</string>
</property>
<property name="icon">
<iconset resource="../resources/images.qrc">
<normaloff>:/icons/add.ico</normaloff>:/icons/add.ico</iconset>
</property>
</widget>
</item>
<item row="0" column="1">
<spacer name="horizontalSpacer_7">
<property name="orientation">
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="0" colspan="3">
<layout class="QGridLayout" name="gridLayout_GlobalConstants"/>
</item>
</layout>
</widget>
</widget>

View File

@ -346,6 +346,7 @@ public:
this->unusedTileSplit = 0x0000;
this->maxEventsPerGroup = 255;
this->globalConstantsFilepaths.clear();
this->globalConstants.clear();
this->identifiers.clear();
this->readKeys.clear();
}
@ -419,6 +420,7 @@ public:
QList<uint32_t> warpBehaviors;
int maxEventsPerGroup;
QStringList globalConstantsFilepaths;
QMap<QString,QString> globalConstants;
protected:
virtual QString getConfigFilepath() override;

View File

@ -58,7 +58,8 @@ public:
QMap<QString, int> readCDefinesByRegex(const QString &filename, const QSet<QString> &regexList, QString *error = nullptr);
QMap<QString, int> readCDefinesByName(const QString &filename, const QSet<QString> &names, QString *error = nullptr);
QStringList readCDefineNames(const QString &filename, const QSet<QString> &regexList, QString *error = nullptr);
void loadGlobalCDefines(const QString &filename, QString *error = nullptr);
void loadGlobalCDefinesFromFile(const QString &filename, QString *error = nullptr);
void loadGlobalCDefines(const QMap<QString,QString> &defines);
void resetGlobalCDefines();
OrderedMap<QString, QHash<QString, QString>> readCStructs(const QString &, const QString & = "", const QHash<int, QString>& = {});
QList<QStringList> getLabelMacros(const QList<QStringList>&, const QString&);

View File

@ -0,0 +1,32 @@
#ifndef NEWDEFINEDIALOG_H
#define NEWDEFINEDIALOG_H
#include <QDialog>
#include <QAbstractButton>
namespace Ui {
class NewDefineDialog;
}
class NewDefineDialog : public QDialog
{
Q_OBJECT
public:
explicit NewDefineDialog(QWidget *parent = nullptr);
~NewDefineDialog();
virtual void accept() override;
signals:
void createdDefine(const QString &name, const QString &expression);
private:
Ui::NewDefineDialog *ui;
bool validateName(bool allowEmpty = false);
void onNameChanged(const QString &name);
void dialogButtonClicked(QAbstractButton *button);
};
#endif // NEWDEFINEDIALOG_H

View File

@ -67,6 +67,12 @@ private:
void setWarpBehaviorsList(QStringList list);
void openFilesHelp();
void openIdentifiersHelp();
void addNewGlobalConstantsFilepath();
void addGlobalConstantsFilepath(const QString &filepath);
QStringList getGlobalConstantsFilepaths();
void addNewGlobalConstant();
void addGlobalConstant(const QString &name, const QString &expression);
QMap<QString,QString> getGlobalConstants();
private slots:
void dialogButtonClicked(QAbstractButton *button);

View File

@ -104,6 +104,7 @@ SOURCES += src/core/advancemapparser.cpp \
src/ui/metatileselector.cpp \
src/ui/movablerect.cpp \
src/ui/movementpermissionsselector.cpp \
src/ui/newdefinedialog.cpp \
src/ui/neweventtoolbutton.cpp \
src/ui/newlayoutdialog.cpp \
src/ui/newlayoutform.cpp \
@ -216,6 +217,7 @@ HEADERS += include/core/advancemapparser.h \
include/ui/metatileselector.h \
include/ui/movablerect.h \
include/ui/movementpermissionsselector.h \
include/ui/newdefinedialog.h \
include/ui/neweventtoolbutton.h \
include/ui/newlayoutdialog.h \
include/ui/newlayoutform.h \
@ -269,6 +271,7 @@ FORMS += forms/mainwindow.ui \
forms/gridsettingsdialog.ui \
forms/mapheaderform.ui \
forms/maplisttoolbar.ui \
forms/newdefinedialog.ui \
forms/newlayoutdialog.ui \
forms/newlayoutform.ui \
forms/newlocationdialog.ui \

View File

@ -234,7 +234,7 @@ void KeyValueConfigBase::load() {
continue;
}
this->parseConfigKeyValue(match.captured("key").trimmed().toLower(), match.captured("value").trimmed());
this->parseConfigKeyValue(match.captured("key").trimmed(), match.captured("value").trimmed());
}
this->setUnreadKeys();
@ -840,6 +840,10 @@ void ProjectConfig::parseConfigKeyValue(QString key, QString value) {
} else {
logWarn(QString("Invalid config key found in config file %1: '%2'").arg(this->getConfigFilepath()).arg(key));
}
} else if (key.startsWith("global_constant/")) {
this->globalConstants.insert(key.mid(QStringLiteral("global_constant/").length()), value);
} else if (key == "global_constants_filepaths") {
this->globalConstantsFilepaths = value.split(",", Qt::SkipEmptyParts);
} else if (key == "prefabs_filepath") {
this->prefabFilepath = value;
} else if (key == "prefabs_import_prompted") {
@ -863,7 +867,7 @@ void ProjectConfig::parseConfigKeyValue(QString key, QString value) {
} else if (key == "event_icon_path_heal") {
this->eventIconPaths[Event::Group::Heal] = value;
} else if (key.startsWith("pokemon_icon_path/")) {
this->pokemonIconPaths.insert(key.mid(QStringLiteral("pokemon_icon_path/").length()).toUpper(), value);
this->pokemonIconPaths.insert(key.mid(QStringLiteral("pokemon_icon_path/").length()), value);
} else if (key == "collision_sheet_path") {
this->collisionSheetPath = value;
} else if (key == "collision_sheet_width") {
@ -970,12 +974,16 @@ QMap<QString, QString> ProjectConfig::getKeyValueMap() {
map.insert("event_icon_path_coord", this->eventIconPaths[Event::Group::Coord]);
map.insert("event_icon_path_bg", this->eventIconPaths[Event::Group::Bg]);
map.insert("event_icon_path_heal", this->eventIconPaths[Event::Group::Heal]);
for (auto i = this->pokemonIconPaths.cbegin(), end = this->pokemonIconPaths.cend(); i != end; i++){
const QString path = i.value();
if (!path.isEmpty()) map.insert("pokemon_icon_path/" + i.key(), path);
for (auto it = this->pokemonIconPaths.constBegin(); it != this->pokemonIconPaths.constEnd(); it++) {
const QString path = it.value();
if (!path.isEmpty()) map.insert("pokemon_icon_path/" + it.key(), path);
}
for (auto i = this->identifiers.cbegin(), end = this->identifiers.cend(); i != end; i++) {
map.insert("ident/"+defaultIdentifiers.value(i.key()).first, i.value());
for (auto it = this->globalConstants.constBegin(); it != this->globalConstants.constEnd(); it++) {
map.insert("global_constant/" + it.key(), it.value());
}
map.insert("global_constants_filepaths", this->globalConstantsFilepaths.join(","));
for (auto it = this->identifiers.constBegin(); it != this->identifiers.constEnd(); it++) {
map.insert("ident/"+defaultIdentifiers.value(it.key()).first, it.value());
}
map.insert("collision_sheet_path", this->collisionSheetPath);
map.insert("collision_sheet_width", QString::number(this->collisionSheetSize.width()));

View File

@ -483,7 +483,7 @@ QMap<QString, int> ParseUtil::evaluateCDefines(const QString &filename, const QS
const QString expression = defines.expressions.take(name);
if (expression == " ") continue;
this->curDefine = name;
filteredValues.insert(name, evaluateDefine(name, expression, &allValues, &defines.expressions));
filteredValues.insert(name, evaluateDefine(name, expression, &allValues, &defines.expressions)); // TODO: Unite map with global expressions? Allows users to overwrite project defines
logRecordedErrors(); // Only log errors for defines that Porymap is looking for
}
@ -509,8 +509,12 @@ QStringList ParseUtil::readCDefineNames(const QString &filename, const QSet<QStr
// Find any defines in the specified file and save their expressions.
// If any of these defines are encountered later by other define parsing functions then they'll be recognized and evaluated.
void ParseUtil::loadGlobalCDefines(const QString &filename, QString *error) {
this->globalDefineExpressions.insert(readCDefines(filename, {}, false, error).expressions);
void ParseUtil::loadGlobalCDefinesFromFile(const QString &filename, QString *error) {
loadGlobalCDefines(readCDefines(filename, {}, false, error).expressions);
}
void ParseUtil::loadGlobalCDefines(const QMap<QString,QString> &defines) {
this->globalDefineExpressions.insert(defines);
}
void ParseUtil::resetGlobalCDefines() {

View File

@ -2747,11 +2747,12 @@ bool Project::readGlobalConstants() {
this->parser.resetGlobalCDefines();
for (const auto &path : projectConfig.globalConstantsFilepaths) {
QString error;
this->parser.loadGlobalCDefines(path, &error);
this->parser.loadGlobalCDefinesFromFile(path, &error);
if (!error.isEmpty()) {
logWarn(QString("Failed to read global constants file '%1': %2").arg(path).arg(error));
}
}
this->parser.loadGlobalCDefines(projectConfig.globalConstants);
return true;
}

View File

@ -0,0 +1,60 @@
#include "newdefinedialog.h"
#include "ui_newdefinedialog.h"
#include "validator.h"
const QString lineEdit_ErrorStylesheet = "QLineEdit { background-color: rgba(255, 0, 0, 25%) }";
NewDefineDialog::NewDefineDialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::NewDefineDialog)
{
setAttribute(Qt::WA_DeleteOnClose);
ui->setupUi(this);
ui->lineEdit_Name->setValidator(new IdentifierValidator(this));
connect(ui->lineEdit_Name, &QLineEdit::textChanged, this, &NewDefineDialog::onNameChanged);
connect(ui->buttonBox, &QDialogButtonBox::clicked, this, &NewDefineDialog::dialogButtonClicked);
adjustSize();
}
NewDefineDialog::~NewDefineDialog()
{
delete ui;
}
void NewDefineDialog::onNameChanged(const QString &) {
validateName(true);
}
bool NewDefineDialog::validateName(bool allowEmpty) {
const QString name = ui->lineEdit_Name->text();
QString errorText;
if (name.isEmpty() && !allowEmpty) {
errorText = QString("%1 cannot be empty.").arg(ui->label_Name->text());
}
bool isValid = errorText.isEmpty();
ui->label_NameError->setText(errorText);
ui->label_NameError->setVisible(!isValid);
ui->lineEdit_Name->setStyleSheet(!isValid ? lineEdit_ErrorStylesheet : "");
return isValid;
}
void NewDefineDialog::dialogButtonClicked(QAbstractButton *button) {
auto role = ui->buttonBox->buttonRole(button);
if (role == QDialogButtonBox::RejectRole){
reject();
} else if (role == QDialogButtonBox::AcceptRole) {
accept();
}
}
void NewDefineDialog::accept() {
if (!validateName())
return;
emit createdDefine(ui->lineEdit_Name->text(), ui->lineEdit_Value->text());
QDialog::accept();
}

View File

@ -3,6 +3,7 @@
#include "noscrollcombobox.h"
#include "prefab.h"
#include "filedialog.h"
#include "newdefinedialog.h"
#include "utility.h"
#include <QAbstractButton>
@ -54,6 +55,9 @@ void ProjectSettingsEditor::connectSignals() {
connect(ui->button_AddWarpBehavior, &QAbstractButton::clicked, [this](bool) { this->updateWarpBehaviorsList(true); });
connect(ui->button_RemoveWarpBehavior, &QAbstractButton::clicked, [this](bool) { this->updateWarpBehaviorsList(false); });
connect(ui->button_AddGlobalConstantsFile, &QAbstractButton::clicked, this, &ProjectSettingsEditor::addNewGlobalConstantsFilepath);
connect(ui->button_AddGlobalConstant, &QAbstractButton::clicked, this, &ProjectSettingsEditor::addNewGlobalConstant);
// Connect file selection buttons
connect(ui->button_ChoosePrefabs, &QAbstractButton::clicked, [this](bool) { this->choosePrefabsFile(); });
connect(ui->button_CollisionGraphics, &QAbstractButton::clicked, [this](bool) { this->chooseImageFile(ui->lineEdit_CollisionGraphics); });
@ -501,6 +505,12 @@ void ProjectSettingsEditor::refresh() {
lineEdit->setText(projectConfig.getCustomFilePath(lineEdit->objectName()));
for (auto lineEdit : ui->scrollAreaContents_Identifiers->findChildren<QLineEdit*>())
lineEdit->setText(projectConfig.getCustomIdentifier(lineEdit->objectName()));
for (const auto &path : projectConfig.globalConstantsFilepaths) {
addGlobalConstantsFilepath(path);
}
for (auto it = projectConfig.globalConstants.constBegin(); it != projectConfig.globalConstants.constEnd(); it++) {
addGlobalConstant(it.key(), it.value());
}
// Set warp behaviors
QStringList behaviorNames;
@ -578,6 +588,10 @@ void ProjectSettingsEditor::save() {
for (auto lineEdit : ui->scrollAreaContents_Identifiers->findChildren<QLineEdit*>())
projectConfig.setIdentifier(lineEdit->objectName(), lineEdit->text());
// Save global constants
projectConfig.globalConstantsFilepaths = getGlobalConstantsFilepaths();
projectConfig.globalConstants = getGlobalConstants();
// Save warp behaviors
projectConfig.warpBehaviors.clear();
const QStringList behaviorNames = this->getWarpBehaviorsList();
@ -624,6 +638,100 @@ void ProjectSettingsEditor::chooseFile(QLineEdit * filepathEdit, const QString &
this->hasUnsavedChanges = true;
}
void ProjectSettingsEditor::addNewGlobalConstantsFilepath() {
QString filepath = stripProjectDir(FileDialog::getOpenFileName(this, "Choose Global Constants File"));
if (filepath.isEmpty() || getGlobalConstantsFilepaths().contains(filepath))
return;
addGlobalConstantsFilepath(filepath);
this->hasUnsavedChanges = true;
}
void ProjectSettingsEditor::addGlobalConstantsFilepath(const QString &filepath) {
auto filepathLabel = new QLabel(filepath, this);
filepathLabel->setFrameStyle(QFrame::Panel | QFrame::Raised);
filepathLabel->setTextInteractionFlags(Qt::TextSelectableByMouse); // TODO: This doesn't allow Copy shortcut from the keyboard to work
// TODO: Tool tips
int newRow = ui->gridLayout_GlobalConstantsFiles->rowCount();
ui->gridLayout_GlobalConstantsFiles->addWidget(filepathLabel, newRow, 0);
auto deleteButton = new QToolButton();
deleteButton->setIcon(QIcon(":/icons/delete.ico"));
connect(deleteButton, &QAbstractButton::clicked, [this, filepathLabel, deleteButton](bool) {
ui->gridLayout_GlobalConstantsFiles->removeWidget(filepathLabel);
ui->gridLayout_GlobalConstantsFiles->removeWidget(deleteButton);
delete filepathLabel;
delete deleteButton;
this->hasUnsavedChanges = true;
});
ui->gridLayout_GlobalConstantsFiles->addWidget(deleteButton, newRow, 1);
}
QStringList ProjectSettingsEditor::getGlobalConstantsFilepaths() {
QStringList paths;
for (int row = 1; row < ui->gridLayout_GlobalConstantsFiles->rowCount(); row++) {
auto item = ui->gridLayout_GlobalConstantsFiles->itemAtPosition(row, 0);
if (!item) continue;
auto pathLabel = dynamic_cast<QLabel*>(item->widget());
if (!pathLabel) continue;
paths.append(pathLabel->text());
}
return paths;
}
void ProjectSettingsEditor::addNewGlobalConstant() {
auto dialog = new NewDefineDialog(this);
connect(dialog, &NewDefineDialog::createdDefine, [this](const QString &name, const QString &expression) {
if (!getGlobalConstants().contains(name)) {
addGlobalConstant(name, expression);
this->hasUnsavedChanges = true;
}
});
dialog->open();
}
void ProjectSettingsEditor::addGlobalConstant(const QString &name, const QString &expression) {
// TODO: Tool tips
auto nameLabel = new QLabel(name, this);
nameLabel->setFrameStyle(QFrame::Panel | QFrame::Raised);
nameLabel->setTextInteractionFlags(Qt::TextSelectableByMouse); // TODO: This doesn't allow Copy shortcut from the keyboard to work
auto expressionLineEdit = new QLineEdit(expression, this);
int newRow = ui->gridLayout_GlobalConstants->rowCount();
ui->gridLayout_GlobalConstants->addWidget(nameLabel, newRow, 0);
ui->gridLayout_GlobalConstants->addWidget(expressionLineEdit, newRow, 1);
auto deleteButton = new QToolButton();
deleteButton->setIcon(QIcon(":/icons/delete.ico"));
connect(deleteButton, &QAbstractButton::clicked, [this, nameLabel, expressionLineEdit, deleteButton](bool) {
ui->gridLayout_GlobalConstants->removeWidget(nameLabel);
ui->gridLayout_GlobalConstants->removeWidget(expressionLineEdit);
ui->gridLayout_GlobalConstants->removeWidget(deleteButton);
delete nameLabel;
delete expressionLineEdit;
delete deleteButton;
this->hasUnsavedChanges = true;
});
ui->gridLayout_GlobalConstants->addWidget(deleteButton, newRow, 2);
}
QMap<QString,QString> ProjectSettingsEditor::getGlobalConstants() {
QMap<QString,QString> constants;
for (int row = 1; row < ui->gridLayout_GlobalConstants->rowCount(); row++) {
auto nameItem = ui->gridLayout_GlobalConstants->itemAtPosition(row, 0);
auto expressionItem = ui->gridLayout_GlobalConstants->itemAtPosition(row, 1);
if (!nameItem || !expressionItem) continue;
auto nameLabel = dynamic_cast<QLabel*>(nameItem->widget());
auto expressionLineEdit = dynamic_cast<QLineEdit*>(expressionItem->widget());
if (!nameLabel || !expressionLineEdit) continue;
constants.insert(nameLabel->text(), expressionLineEdit->text());
}
return constants;
}
// Display relative path if this file is in the project folder
QString ProjectSettingsEditor::stripProjectDir(QString s) {
if (s.startsWith(this->baseDir))