diff --git a/include/config.h b/include/config.h index 4ec23b52..96086749 100644 --- a/include/config.h +++ b/include/config.h @@ -274,8 +274,8 @@ public: void setDefaultSecondaryTileset(QString tilesetName); void setFilePath(QString pathId, QString path); void setFilePath(ProjectFilePath pathId, QString path); - QString getFilePath(QString defaultPath, bool allowDefault = true); - QString getFilePath(ProjectFilePath pathId, bool allowDefault = true); + QString getFilePath(QString defaultPath, bool customOnly = false); + QString getFilePath(ProjectFilePath pathId, bool customOnly = false); void setPrefabFilepath(QString filepath); QString getPrefabFilepath(); void setPrefabImportPrompted(bool prompted); diff --git a/include/ui/projectsettingseditor.h b/include/ui/projectsettingseditor.h index 5f4fcd31..83fe741e 100644 --- a/include/ui/projectsettingseditor.h +++ b/include/ui/projectsettingseditor.h @@ -30,6 +30,7 @@ private: bool hasUnsavedChanges = false; bool projectNeedsReload = false; bool refreshing = false; + const QString baseDir; void initUi(); void connectSignals(); @@ -42,6 +43,7 @@ private: bool promptRestoreDefaults(); void createProjectPathsTable(); + QString chooseProjectFile(const QString &defaultFilepath); private slots: void dialogButtonClicked(QAbstractButton *button); diff --git a/src/config.cpp b/src/config.cpp index 9592ca63..8c51de9f 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -804,18 +804,29 @@ void ProjectConfig::setFilePath(QString defaultPath, QString newPath) { this->setFilePath(reverseDefaultPaths(defaultPath), newPath); } -QString ProjectConfig::getFilePath(ProjectFilePath pathId, bool allowDefault) { - if (this->filePaths.contains(pathId)) { - return this->filePaths[pathId]; - } else if (allowDefault && defaultPaths.contains(pathId)) { - return defaultPaths[pathId].second; - } else { - return QString(); +QString ProjectConfig::getFilePath(ProjectFilePath pathId, bool customOnly) { + const QString customPath = this->filePaths.value(pathId); + + // When reading custom filepaths for the settings editor we don't care + // about the default path or whether the custom path exists. + if (customOnly) + return customPath; + + if (!customPath.isEmpty()) { + // A custom filepath has been specified. If the file/folder exists, use that. + const QString absCustomPath = this->projectDir + QDir::separator() + customPath; + if (QFileInfo::exists(absCustomPath)) { + return customPath; + } else { + logError(QString("Custom project filepath '%1' not found. Using default.").arg(absCustomPath)); + } } + return defaultPaths.contains(pathId) ? defaultPaths[pathId].second : QString(); + } -QString ProjectConfig::getFilePath(QString defaultPath, bool allowDefault) { - return this->getFilePath(reverseDefaultPaths(defaultPath), allowDefault); +QString ProjectConfig::getFilePath(QString defaultPath, bool customOnly) { + return this->getFilePath(reverseDefaultPaths(defaultPath), customOnly); } void ProjectConfig::setBaseGameVersion(BaseGameVersion baseGameVersion) { diff --git a/src/ui/projectsettingseditor.cpp b/src/ui/projectsettingseditor.cpp index 502eaca9..cfd330eb 100644 --- a/src/ui/projectsettingseditor.cpp +++ b/src/ui/projectsettingseditor.cpp @@ -14,7 +14,8 @@ ProjectSettingsEditor::ProjectSettingsEditor(QWidget *parent, Project *project) : QMainWindow(parent), ui(new Ui::ProjectSettingsEditor), - project(project) + project(project), + baseDir(userConfig.getProjectDir() + QDir::separator()) { ui->setupUi(this); setAttribute(Qt::WA_DeleteOnClose); @@ -84,25 +85,54 @@ void ProjectSettingsEditor::createProjectPathsTable() { name->setAlignment(Qt::AlignBottom); name->setText(pathPair.first); - // Editable area of the path - auto path = new QLineEdit(); - path->setObjectName(pathPair.first); // Used when saving the paths - path->setPlaceholderText(pathPair.second); - path->setClearButtonEnabled(true); + // Filepath line edit + auto lineEdit = new QLineEdit(); + lineEdit->setObjectName(pathPair.first); // Used when saving the paths + lineEdit->setPlaceholderText(pathPair.second); + lineEdit->setClearButtonEnabled(true); + + // "Choose file" button auto button = new QToolButton(); button->setIcon(QIcon(":/icons/folder.ico")); - // TODO: file prompt - //connect(button, &QAbstractButton::clicked, this, &ProjectSettingsEditor::); + connect(button, &QAbstractButton::clicked, [this, lineEdit](bool) { + const QString path = this->chooseProjectFile(lineEdit->placeholderText()); + if (!path.isEmpty()) { + lineEdit->setText(path); + this->markEdited(); + } + }); // Add to list auto editArea = new QWidget(); auto layout = new QHBoxLayout(editArea); - layout->addWidget(path); + layout->addWidget(lineEdit); layout->addWidget(button); ui->layout_ProjectPaths->addRow(name, editArea); } } +QString ProjectSettingsEditor::chooseProjectFile(const QString &defaultFilepath) { + const QString startDir = this->baseDir + defaultFilepath; + + QString path; + if (defaultFilepath.endsWith("/")){ + // Default filepath is a folder, choose a new folder + path = QFileDialog::getExistingDirectory(this, "Choose Project File Folder", startDir) + QDir::separator(); + } else{ + // Default filepath is not a folder, choose a new file + path = QFileDialog::getOpenFileName(this, "Choose Project File", startDir); + } + + if (!path.startsWith(this->baseDir)){ + // Most of Porymap's file-parsing code for project files will assume that filepaths + // are relative to the root project folder, so we enforce that here. + QMessageBox::warning(this, "Failed to set custom filepath", + QString("Custom filepaths must be inside the root project folder '%1'").arg(this->baseDir)); + return QString(); + } + return path.remove(0, this->baseDir.length()); +} + void ProjectSettingsEditor::restoreWindowState() { logInfo("Restoring project settings editor geometry from previous session."); const QMap geometry = porymapConfig.getProjectSettingsEditorGeometry(); @@ -149,7 +179,7 @@ void ProjectSettingsEditor::refresh() { ui->lineEdit_BorderMetatiles->setText(projectConfig.getNewMapBorderMetatileIdsString()); ui->lineEdit_PrefabsPath->setText(projectConfig.getPrefabFilepath()); for (auto lineEdit : ui->scrollAreaContents_ProjectPaths->findChildren()) - lineEdit->setText(projectConfig.getFilePath(lineEdit->objectName(), false)); + lineEdit->setText(projectConfig.getFilePath(lineEdit->objectName(), true)); this->refreshing = false; // Allow signals } @@ -221,9 +251,8 @@ void ProjectSettingsEditor::choosePrefabsFileClicked(bool) { this->project->setImportExportPath(filepath); // Display relative path if this file is in the project folder - const QString projectDir = projectConfig.getProjectDir() + QDir::separator(); - if (filepath.startsWith(projectDir)) - filepath.remove(0, projectDir.length()); + if (filepath.startsWith(this->baseDir)) + filepath.remove(0, this->baseDir.length()); ui->lineEdit_PrefabsPath->setText(filepath); this->hasUnsavedChanges = true; }