From f1a4b78ca9177b29a02fde8992ef81488eb4ecfc Mon Sep 17 00:00:00 2001 From: GriffinR Date: Tue, 26 Nov 2024 15:33:56 -0500 Subject: [PATCH] Fix map duplication --- forms/newlayoutdialog.ui | 3 + forms/newmapdialog.ui | 154 +++++++++++++++-------------------- include/core/maplayout.h | 1 - include/project.h | 27 +++--- include/ui/newlayoutdialog.h | 6 +- include/ui/newmapdialog.h | 11 +-- src/project.cpp | 127 ++++++++++++++++------------- src/ui/newlayoutdialog.cpp | 101 ++++++++++++----------- src/ui/newmapdialog.cpp | 134 ++++++++++++++---------------- 9 files changed, 272 insertions(+), 292 deletions(-) diff --git a/forms/newlayoutdialog.ui b/forms/newlayoutdialog.ui index 53d950fe..d285bdb1 100644 --- a/forms/newlayoutdialog.ui +++ b/forms/newlayoutdialog.ui @@ -117,6 +117,9 @@ + + false + color: rgb(255, 0, 0) diff --git a/forms/newmapdialog.ui b/forms/newmapdialog.ui index e6aece18..3e133dfd 100644 --- a/forms/newmapdialog.ui +++ b/forms/newmapdialog.ui @@ -25,15 +25,40 @@ 0 0 229 - 306 + 228 10 + + + + Map Name + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + - + false @@ -48,29 +73,6 @@ - - - - true - - - QComboBox::InsertPolicy::NoInsert - - - - - - - color: rgb(255, 0, 0) - - - - - - true - - - @@ -87,57 +89,22 @@ - - - - <html><head/><body><p>The constant that will be used to refer to this map. It cannot be the same as any other existing map, and it must start with the specified prefix.</p></body></html> + + + + Layout ID - + - Map ID - - - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - - - Can Fly To - - - - - - - Map Name + Map Group - - - <html><head/><body><p>The name of the group this map will be added to.</p></body></html> - + true @@ -146,17 +113,7 @@ - - - - <html><head/><body><p>The name of the new map. The name cannot be the same as any other existing map.</p></body></html> - - - true - - - - + <html><head/><body><p>If checked, a Heal Location will be added to this map automatically.</p></body></html> @@ -166,8 +123,8 @@ - - + + false @@ -182,24 +139,40 @@ - + - - - - Map Group + + + + <html><head/><body><p>The name of the group this map will be added to.</p></body></html> + + + true + + + QComboBox::InsertPolicy::NoInsert - - + + - Layout ID + Can Fly To - + + + + <html><head/><body><p>The name of the new map. The name cannot be the same as any other existing map.</p></body></html> + + + true + + + + Qt::Orientation::Vertical @@ -218,6 +191,9 @@ + + false + color: rgb(255, 0, 0) diff --git a/include/core/maplayout.h b/include/core/maplayout.h index cfd093ef..5d717a43 100644 --- a/include/core/maplayout.h +++ b/include/core/maplayout.h @@ -74,7 +74,6 @@ public: QUndoStack editHistory; // to simplify new layout settings transfer between functions - // TODO: Make this the equivalent of struct MapHeader struct Settings { QString id; QString name; diff --git a/include/project.h b/include/project.h index 58e2d5a3..9b6f64bf 100644 --- a/include/project.h +++ b/include/project.h @@ -81,16 +81,6 @@ public: bool wildEncountersLoaded; bool saveEmptyMapsec; - struct NewMapSettings { - QString name; - QString id; - QString group; - bool canFlyTo; - Layout::Settings layout; - MapHeader header; - }; - NewMapSettings newMapSettings; - void set_root(QString); void clearMapCache(); @@ -132,10 +122,23 @@ public: bool readMapGroups(); void addNewMapGroup(const QString &groupName); + struct NewMapSettings { + QString name; + QString group; + bool canFlyTo; + Layout::Settings layout; + MapHeader header; + }; + NewMapSettings newMapSettings; + Layout::Settings newLayoutSettings; + + QString getNewMapName() const; + QString getNewLayoutName() const; + void initNewMapSettings(); + void initNewLayoutSettings(); + Map *createNewMap(const Project::NewMapSettings &mapSettings, const Map* toDuplicate = nullptr); Layout *createNewLayout(const Layout::Settings &layoutSettings, const Layout* toDuplicate = nullptr); - NewMapSettings getNewMapSettings() const; - Layout::Settings getNewLayoutSettings() const; bool isIdentifierUnique(const QString &identifier) const; QString getProjectTitle(); diff --git a/include/ui/newlayoutdialog.h b/include/ui/newlayoutdialog.h index ba4396b9..5fdb780f 100644 --- a/include/ui/newlayoutdialog.h +++ b/include/ui/newlayoutdialog.h @@ -30,10 +30,7 @@ signals: private: Ui::NewLayoutDialog *ui; Project *project; - Layout *importedLayout = nullptr; - - static Layout::Settings settings; - static bool initializedSettings; + const Layout *layoutToCopy; // Each of these validation functions will allow empty names up until `OK` is selected, // because clearing the text during editing is common and we don't want to flash errors for this. @@ -41,7 +38,6 @@ private: bool validateName(bool allowEmpty = false); void refresh(); - void saveSettings(); bool isExistingLayout() const; diff --git a/include/ui/newmapdialog.h b/include/ui/newmapdialog.h index 15dd3f6c..1d0f316f 100644 --- a/include/ui/newmapdialog.h +++ b/include/ui/newmapdialog.h @@ -19,8 +19,8 @@ class NewMapDialog : public QDialog Q_OBJECT public: explicit NewMapDialog(Project *project, QWidget *parent = nullptr); + explicit NewMapDialog(Project *project, const Map *mapToCopy = nullptr, QWidget *parent = nullptr); explicit NewMapDialog(Project *project, int mapListTab, const QString &mapListItem, QWidget *parent = nullptr); - explicit NewMapDialog(Project *project, const Map *mapToCopy, QWidget *parent = nullptr); ~NewMapDialog(); virtual void accept() override; @@ -30,26 +30,21 @@ private: Project *project; CollapsibleSection *headerSection; MapHeaderForm *headerForm; - Map *importedMap = nullptr; - - static Project::NewMapSettings settings; - static bool initializedSettings; + const Map *mapToCopy; // Each of these validation functions will allow empty names up until `OK` is selected, // because clearing the text during editing is common and we don't want to flash errors for this. - bool validateMapID(bool allowEmpty = false); bool validateName(bool allowEmpty = false); bool validateGroup(bool allowEmpty = false); bool validateLayoutID(bool allowEmpty = false); - void setUI(const Project::NewMapSettings &settings); + void refresh(); void saveSettings(); void setLayout(const Layout *mapLayout); private slots: void dialogButtonClicked(QAbstractButton *button); void on_lineEdit_Name_textChanged(const QString &); - void on_lineEdit_MapID_textChanged(const QString &); void on_comboBox_Group_currentTextChanged(const QString &text); void on_comboBox_LayoutID_currentTextChanged(const QString &text); }; diff --git a/src/project.cpp b/src/project.cpp index 3d8d3f9c..f6cddfec 100644 --- a/src/project.cpp +++ b/src/project.cpp @@ -106,6 +106,9 @@ bool Project::load() { && readEventGraphics() && readSongNames() && readMapGroups(); + + initNewLayoutSettings(); + initNewMapSettings(); applyParsedLimits(); return success; } @@ -366,16 +369,24 @@ bool Project::loadMapData(Map* map) { Map *Project::createNewMap(const Project::NewMapSettings &settings, const Map* toDuplicate) { Map *map = toDuplicate ? new Map(*toDuplicate) : new Map; map->setName(settings.name); - map->setConstantName(settings.id); map->setHeader(settings.header); map->setNeedsHealLocation(settings.canFlyTo); + // Generate a unique MAP constant. + int suffix = 2; + const QString baseMapConstant = Map::mapConstantFromName(map->name()); + QString mapConstant = baseMapConstant; + while (!isIdentifierUnique(mapConstant)) { + mapConstant = QString("%1_%2").arg(baseMapConstant).arg(suffix++); + } + map->setConstantName(mapConstant); + Layout *layout = this->mapLayouts.value(settings.layout.id); if (layout) { // Layout already exists map->setNeedsLayoutDir(false); // TODO: Remove this member? } else { - layout = createNewLayout(settings.layout); + layout = createNewLayout(settings.layout, toDuplicate ? toDuplicate->layout() : nullptr); } if (!layout) { delete map; @@ -1960,60 +1971,6 @@ void Project::addNewMapGroup(const QString &groupName) { emit mapGroupAdded(groupName); } -Project::NewMapSettings Project::getNewMapSettings() const { - // Ensure default name/ID doesn't already exist. - int i = 0; - QString newMapName; - QString newMapId; - do { - newMapName = QString("NewMap%1").arg(++i); - newMapId = Map::mapConstantFromName(newMapName); - } while (!isIdentifierUnique(newMapName) || !isIdentifierUnique(newMapId)); - - NewMapSettings settings; - settings.name = newMapName; - settings.id = newMapId; - settings.group = this->groupNames.at(0); - settings.canFlyTo = false; - settings.layout = getNewLayoutSettings(); - settings.layout.id = Layout::layoutConstantFromName(newMapName); - settings.layout.name = Layout::layoutNameFromMapName(newMapName); - settings.header.setSong(this->defaultSong); - settings.header.setLocation(this->mapSectionIdNames.value(0, "0")); - settings.header.setRequiresFlash(false); - settings.header.setWeather(this->weatherNames.value(0, "0")); - settings.header.setType(this->mapTypes.value(0, "0")); - settings.header.setBattleScene(this->mapBattleScenes.value(0, "0")); - settings.header.setShowsLocationName(true); - settings.header.setAllowsRunning(false); - settings.header.setAllowsBiking(false); - settings.header.setAllowsEscaping(false); - settings.header.setFloorNumber(0); - return settings; -} - -Layout::Settings Project::getNewLayoutSettings() const { - // Ensure default name/ID doesn't already exist. - int i = 0; - QString newLayoutName; - QString newLayoutId; - do { - newLayoutName = QString("NewLayout%1").arg(++i); - newLayoutId = Layout::layoutConstantFromName(newLayoutName); - } while (!isIdentifierUnique(newLayoutId) || !isIdentifierUnique(newLayoutName)); - - Layout::Settings settings; - settings.name = newLayoutName; - settings.id = newLayoutId; - settings.width = getDefaultMapDimension(); - settings.height = getDefaultMapDimension(); - settings.borderWidth = DEFAULT_BORDER_WIDTH; - settings.borderHeight = DEFAULT_BORDER_HEIGHT; - settings.primaryTilesetLabel = getDefaultPrimaryTilesetLabel(); - settings.secondaryTilesetLabel = getDefaultSecondaryTilesetLabel(); - return settings; -} - // When we ask the user to provide a new identifier for something (like a map name or MAPSEC id) // we use this to make sure that it doesn't collide with any known identifiers first. // Porymap knows of many more identifiers than this, but for simplicity we only check the lists that users can add to via Porymap. @@ -2040,6 +1997,64 @@ bool Project::isIdentifierUnique(const QString &identifier) const { return true; } +QString Project::getNewMapName() const { + // Ensure default name/ID doesn't already exist. + int i = 0; + QString newMapName; + do { + newMapName = QString("NewMap%1").arg(++i); + } while (!isIdentifierUnique(newMapName) || !isIdentifierUnique(Map::mapConstantFromName(newMapName))); + return newMapName; +} + +QString Project::getNewLayoutName() const { + // Ensure default name/ID doesn't already exist. + int i = 0; + QString newLayoutName; + do { + newLayoutName = QString("NewLayout%1").arg(++i); + } while (!isIdentifierUnique(newLayoutName) || !isIdentifierUnique(Layout::layoutConstantFromName(newLayoutName))); + return newLayoutName; +} + +void Project::initNewMapSettings() { + this->newMapSettings.name = getNewMapName(); + this->newMapSettings.group = this->groupNames.at(0); + this->newMapSettings.canFlyTo = false; + + this->newMapSettings.layout.name = Layout::layoutNameFromMapName(this->newMapSettings.name); + this->newMapSettings.layout.id = Layout::layoutConstantFromName(this->newMapSettings.name); + this->newMapSettings.layout.width = getDefaultMapDimension(); + this->newMapSettings.layout.height = getDefaultMapDimension(); + this->newMapSettings.layout.borderWidth = DEFAULT_BORDER_WIDTH; + this->newMapSettings.layout.borderHeight = DEFAULT_BORDER_HEIGHT; + this->newMapSettings.layout.primaryTilesetLabel = getDefaultPrimaryTilesetLabel(); + this->newMapSettings.layout.secondaryTilesetLabel = getDefaultSecondaryTilesetLabel(); + + this->newMapSettings.header.setSong(this->defaultSong); + this->newMapSettings.header.setLocation(this->mapSectionIdNames.value(0, "0")); + this->newMapSettings.header.setRequiresFlash(false); + this->newMapSettings.header.setWeather(this->weatherNames.value(0, "0")); + this->newMapSettings.header.setType(this->mapTypes.value(0, "0")); + this->newMapSettings.header.setBattleScene(this->mapBattleScenes.value(0, "0")); + this->newMapSettings.header.setShowsLocationName(true); + this->newMapSettings.header.setAllowsRunning(false); + this->newMapSettings.header.setAllowsBiking(false); + this->newMapSettings.header.setAllowsEscaping(false); + this->newMapSettings.header.setFloorNumber(0); +} + +void Project::initNewLayoutSettings() { + this->newLayoutSettings.name = getNewLayoutName(); + this->newLayoutSettings.id = Layout::layoutConstantFromName(this->newLayoutSettings.name); + this->newLayoutSettings.width = getDefaultMapDimension(); + this->newLayoutSettings.height = getDefaultMapDimension(); + this->newLayoutSettings.borderWidth = DEFAULT_BORDER_WIDTH; + this->newLayoutSettings.borderHeight = DEFAULT_BORDER_HEIGHT; + this->newLayoutSettings.primaryTilesetLabel = getDefaultPrimaryTilesetLabel(); + this->newLayoutSettings.secondaryTilesetLabel = getDefaultSecondaryTilesetLabel(); +} + Project::DataQualifiers Project::getDataQualifiers(QString text, QString label) { Project::DataQualifiers qualifiers; diff --git a/src/ui/newlayoutdialog.cpp b/src/ui/newlayoutdialog.cpp index de41a3d6..7b9d347f 100644 --- a/src/ui/newlayoutdialog.cpp +++ b/src/ui/newlayoutdialog.cpp @@ -9,30 +9,56 @@ const QString lineEdit_ErrorStylesheet = "QLineEdit { background-color: rgba(255, 0, 0, 25%) }"; -Layout::Settings NewLayoutDialog::settings = {}; -bool NewLayoutDialog::initializedSettings = false; - NewLayoutDialog::NewLayoutDialog(Project *project, QWidget *parent) : + NewLayoutDialog(project, nullptr, parent) +{} + +NewLayoutDialog::NewLayoutDialog(Project *project, const Layout *layoutToCopy, QWidget *parent) : QDialog(parent), - ui(new Ui::NewLayoutDialog) + ui(new Ui::NewLayoutDialog), + layoutToCopy(layoutToCopy) { setAttribute(Qt::WA_DeleteOnClose); setModal(true); ui->setupUi(this); - ui->label_GenericError->setVisible(false); this->project = project; - Layout::Settings newSettings = project->getNewLayoutSettings(); - if (!initializedSettings) { - // The first time this dialog is opened we initialize all the default settings. - settings = newSettings; - initializedSettings = true; + QString newName; + QString newId; + if (this->layoutToCopy && !this->layoutToCopy->name.isEmpty()) { + // Duplicating a layout, the initial name will be the base layout's name + // with a numbered suffix to make it unique. + // Note: Layouts imported with AdvanceMap have no name, so they'll use the default new layout name instead. + + // If the layout name ends with the default '_Layout' suffix we'll ignore it. + // This is because (normally) the ID for these layouts will not have this suffix, + // so you can end up in a situation where you might have Map_Layout and Map_2_Layout, + // and if you try to duplicate Map_Layout the next available name (because of ID collisions) + // would be Map_Layout_3 instead of Map_3_Layout. + QString baseName = this->layoutToCopy->name; + QString suffix = "_Layout"; + if (baseName.length() > suffix.length() && baseName.endsWith(suffix)) { + baseName.truncate(baseName.length() - suffix.length()); + } else { + suffix = ""; + } + + int i = 2; + do { + newName = QString("%1_%2%3").arg(baseName).arg(i).arg(suffix); + newId = QString("%1_%2").arg(this->layoutToCopy->id).arg(i); + i++; + } while (!project->isIdentifierUnique(newName) || !project->isIdentifierUnique(newId)); } else { - // On subsequent openings we only initialize the settings that should be unique, - // preserving all other settings from the last time the dialog was open. - settings.name = newSettings.name; - settings.id = newSettings.id; + newName = project->getNewLayoutName(); + newId = Layout::layoutConstantFromName(newName); } + + // We reset these settings for every session with the new layout dialog. + // The rest of the settings are preserved in the project between sessions. + project->newLayoutSettings.name = newName; + project->newLayoutSettings.id = newId; + ui->newLayoutForm->initUi(project); // Identifiers can only contain word characters, and cannot start with a digit. @@ -47,53 +73,34 @@ NewLayoutDialog::NewLayoutDialog(Project *project, QWidget *parent) : adjustSize(); } -// Creating new layout from an existing layout (e.g. via AdvanceMap import, or duplicating from map list). -NewLayoutDialog::NewLayoutDialog(Project *project, const Layout *layoutToCopy, QWidget *parent) : - NewLayoutDialog(project, parent) -{ - if (!layoutToCopy) - return; - - this->importedLayout = layoutToCopy->copy(); - if (!this->importedLayout->name.isEmpty()) { - // If the layout we're duplicating has a name and ID we'll initialize the name/ID fields - // using that name and add a suffix to make it unique. - // Layouts imported with AdvanceMap won't have a name/ID. - int i = 2; - do { - settings.name = QString("%1_%2").arg(this->importedLayout->name).arg(i); - settings.id = QString("%1_%2").arg(this->importedLayout->id).arg(i); - i++; - } while (!this->project->isIdentifierUnique(settings.name) || !this->project->isIdentifierUnique(settings.id)); - } - refresh(); -} - NewLayoutDialog::~NewLayoutDialog() { saveSettings(); - delete this->importedLayout; delete ui; } void NewLayoutDialog::refresh() { - if (this->importedLayout) { + const Layout::Settings *settings = &this->project->newLayoutSettings; + + if (this->layoutToCopy) { // If we're importing a layout then some settings will be enforced. - ui->newLayoutForm->setSettings(this->importedLayout->settings()); + ui->newLayoutForm->setSettings(this->layoutToCopy->settings()); ui->newLayoutForm->setDisabled(true); } else { - ui->newLayoutForm->setSettings(settings); + ui->newLayoutForm->setSettings(*settings); ui->newLayoutForm->setDisabled(false); } - ui->lineEdit_Name->setText(settings.name); - ui->lineEdit_LayoutID->setText(settings.id); + ui->lineEdit_Name->setText(settings->name); + ui->lineEdit_LayoutID->setText(settings->id); } void NewLayoutDialog::saveSettings() { - settings = ui->newLayoutForm->settings(); - settings.id = ui->lineEdit_LayoutID->text(); - settings.name = ui->lineEdit_Name->text(); + Layout::Settings *settings = &this->project->newLayoutSettings; + + *settings = ui->newLayoutForm->settings(); + settings->id = ui->lineEdit_LayoutID->text(); + settings->name = ui->lineEdit_Name->text(); } bool NewLayoutDialog::validateLayoutID(bool allowEmpty) { @@ -146,7 +153,7 @@ void NewLayoutDialog::dialogButtonClicked(QAbstractButton *button) { if (role == QDialogButtonBox::RejectRole){ reject(); } else if (role == QDialogButtonBox::ResetRole) { - settings = this->project->getNewLayoutSettings(); + this->project->initNewLayoutSettings(); refresh(); } else if (role == QDialogButtonBox::AcceptRole) { accept(); @@ -165,7 +172,7 @@ void NewLayoutDialog::accept() { // Update settings from UI saveSettings(); - Layout *layout = this->project->createNewLayout(settings, this->importedLayout); + Layout *layout = this->project->createNewLayout(this->project->newLayoutSettings, this->layoutToCopy); if (!layout) { ui->label_GenericError->setText(QString("Failed to create layout. See %1 for details.").arg(getLogPath())); ui->label_GenericError->setVisible(true); diff --git a/src/ui/newmapdialog.cpp b/src/ui/newmapdialog.cpp index 59fe0a16..e6d3101b 100644 --- a/src/ui/newmapdialog.cpp +++ b/src/ui/newmapdialog.cpp @@ -10,30 +10,41 @@ const QString lineEdit_ErrorStylesheet = "QLineEdit { background-color: rgba(255, 0, 0, 25%) }"; -Project::NewMapSettings NewMapDialog::settings = {}; -bool NewMapDialog::initializedSettings = false; - NewMapDialog::NewMapDialog(Project *project, QWidget *parent) : + NewMapDialog(project, nullptr, parent) +{} + +NewMapDialog::NewMapDialog(Project *project, const Map *mapToCopy, QWidget *parent) : QDialog(parent), - ui(new Ui::NewMapDialog) + ui(new Ui::NewMapDialog), + mapToCopy(mapToCopy) { setAttribute(Qt::WA_DeleteOnClose); setModal(true); ui->setupUi(this); - ui->label_GenericError->setVisible(false); this->project = project; - Project::NewMapSettings newSettings = project->getNewMapSettings(); - if (!initializedSettings) { - // The first time this dialog is opened we initialize all the default settings. - settings = newSettings; - initializedSettings = true; + QString newMapName; + QString newLayoutId; + if (this->mapToCopy) { + // Duplicating a map, the initial name will be the base map's name + // with a numbered suffix to make it unique. + int i = 2; + do { + newMapName = QString("%1_%2").arg(this->mapToCopy->name()).arg(i++); + newLayoutId = Layout::layoutConstantFromName(newMapName); + } while (!project->isIdentifierUnique(newMapName) || !project->isIdentifierUnique(newLayoutId)); } else { - // On subsequent openings we only initialize the settings that should be unique, - // preserving all other settings from the last time the dialog was open. - settings.name = newSettings.name; - settings.id = newSettings.id; + // Not duplicating a map, get a generic new map name. + newMapName = project->getNewMapName(); + newLayoutId = Layout::layoutConstantFromName(newMapName); } + + // We reset these settings for every session with the new map dialog. + // The rest of the settings are preserved in the project between sessions. + project->newMapSettings.name = newMapName; + project->newMapSettings.layout.id = newLayoutId; + ui->newLayoutForm->initUi(project); ui->comboBox_Group->addItems(project->groupNames); @@ -43,7 +54,6 @@ NewMapDialog::NewMapDialog(Project *project, QWidget *parent) : static const QRegularExpression re("[A-Za-z_]+[\\w]*"); auto validator = new QRegularExpressionValidator(re, this); ui->lineEdit_Name->setValidator(validator); - ui->lineEdit_MapID->setValidator(validator); ui->comboBox_Group->setValidator(validator); ui->comboBox_LayoutID->setValidator(validator); @@ -60,7 +70,7 @@ NewMapDialog::NewMapDialog(Project *project, QWidget *parent) : connect(ui->buttonBox, &QDialogButtonBox::clicked, this, &NewMapDialog::dialogButtonClicked); - setUI(settings); + refresh(); adjustSize(); // TODO: Save geometry? } @@ -79,52 +89,53 @@ NewMapDialog::NewMapDialog(Project *project, int mapListTab, const QString &mapL this->headerForm->setLocation(mapListItem); break; case MapListTab::Layouts: + // We specifically lock the layout ID because otherwise the setting would be overwritten when + // the user changes the map name (which will normally automatically update the layout ID to match). + // For the Group/Area settings above we don't care if the user changes them afterwards. ui->comboBox_LayoutID->setTextItem(mapListItem); + ui->comboBox_LayoutID->setDisabled(true); break; } } -NewMapDialog::NewMapDialog(Project *project, const Map *mapToCopy, QWidget *parent) : - NewMapDialog(project, parent) -{ - if (!mapToCopy) - return; - // TODO -} - NewMapDialog::~NewMapDialog() { saveSettings(); - delete this->importedMap; delete ui; } -void NewMapDialog::setUI(const Project::NewMapSettings &settings) { - ui->lineEdit_Name->setText(settings.name); - ui->lineEdit_MapID->setText(settings.id); - ui->comboBox_Group->setTextItem(settings.group); - ui->comboBox_LayoutID->setTextItem(settings.layout.id); - if (this->importedMap && this->importedMap->layout()) { +// Reload the UI from the last-saved settings. +void NewMapDialog::refresh() { + const Project::NewMapSettings *settings = &this->project->newMapSettings; + + ui->lineEdit_Name->setText(settings->name); + ui->comboBox_Group->setTextItem(settings->group); + + // If the layout combo box is disabled, it's because we're enforcing the setting. Leave it unchanged. + if (ui->comboBox_LayoutID->isEnabled()) + ui->comboBox_LayoutID->setTextItem(settings->layout.id); + + if (this->mapToCopy && this->mapToCopy->layout()) { // When importing a layout these settings shouldn't be changed. - ui->newLayoutForm->setSettings(this->importedMap->layout()->settings()); + ui->newLayoutForm->setSettings(this->mapToCopy->layout()->settings()); } else { - ui->newLayoutForm->setSettings(settings.layout); + ui->newLayoutForm->setSettings(settings->layout); } - ui->checkBox_CanFlyTo->setChecked(settings.canFlyTo); - this->headerForm->setHeaderData(settings.header); + ui->checkBox_CanFlyTo->setChecked(settings->canFlyTo); + this->headerForm->setHeaderData(settings->header); } void NewMapDialog::saveSettings() { - settings.name = ui->lineEdit_Name->text(); - settings.id = ui->lineEdit_MapID->text(); - settings.group = ui->comboBox_Group->currentText(); - settings.layout = ui->newLayoutForm->settings(); - settings.layout.id = ui->comboBox_LayoutID->currentText(); - // We don't provide full control for naming new layouts here (just via the ID). - // If a user wants to explicitly name a layout they can create it individually before creating the map. - settings.layout.name = Layout::layoutNameFromMapName(settings.name); // TODO: Verify uniqueness - settings.canFlyTo = ui->checkBox_CanFlyTo->isChecked(); - settings.header = this->headerForm->headerData(); + Project::NewMapSettings *settings = &this->project->newMapSettings; + + settings->name = ui->lineEdit_Name->text(); + settings->group = ui->comboBox_Group->currentText(); + settings->layout = ui->newLayoutForm->settings(); + settings->layout.id = ui->comboBox_LayoutID->currentText(); + settings->layout.name = Layout::layoutNameFromMapName(settings->name); // TODO: Verify uniqueness + settings->canFlyTo = ui->checkBox_CanFlyTo->isChecked(); + settings->header = this->headerForm->headerData(); + porymapConfig.newMapHeaderSectionExpanded = this->headerSection->isExpanded(); } @@ -138,30 +149,6 @@ void NewMapDialog::setLayout(const Layout *layout) { } } -bool NewMapDialog::validateMapID(bool allowEmpty) { - QString id = ui->lineEdit_MapID->text(); - const QString expectedPrefix = projectConfig.getIdentifier(ProjectIdentifier::define_map_prefix); - - QString errorText; - if (id.isEmpty() || id == expectedPrefix) { - if (!allowEmpty) errorText = QString("%1 cannot be empty.").arg(ui->label_MapID->text()); - } else if (!id.startsWith(expectedPrefix)) { - errorText = QString("%1 must start with '%2'.").arg(ui->label_MapID->text()).arg(expectedPrefix); - } else if (!this->project->isIdentifierUnique(id)) { - errorText = QString("%1 '%2' is not unique.").arg(ui->label_MapID->text()).arg(id); - } - - bool isValid = errorText.isEmpty(); - ui->label_MapIDError->setText(errorText); - ui->label_MapIDError->setVisible(!isValid); - ui->lineEdit_MapID->setStyleSheet(!isValid ? lineEdit_ErrorStylesheet : ""); - return isValid; -} - -void NewMapDialog::on_lineEdit_MapID_textChanged(const QString &) { - validateMapID(true); -} - bool NewMapDialog::validateName(bool allowEmpty) { QString name = ui->lineEdit_Name->text(); @@ -181,7 +168,6 @@ bool NewMapDialog::validateName(bool allowEmpty) { void NewMapDialog::on_lineEdit_Name_textChanged(const QString &text) { validateName(true); - ui->lineEdit_MapID->setText(Map::mapConstantFromName(text)); if (ui->comboBox_LayoutID->isEnabled()) { ui->comboBox_LayoutID->setCurrentText(Layout::layoutConstantFromName(text)); } @@ -216,7 +202,7 @@ bool NewMapDialog::validateLayoutID(bool allowEmpty) { if (!allowEmpty) errorText = QString("%1 cannot be empty.").arg(ui->label_LayoutID->text()); } else if (!this->project->isIdentifierUnique(layoutId)) { // Layout name is already in use by something. If we're duplicating a map this isn't allowed. - if (this->importedMap) { + if (this->mapToCopy) { errorText = QString("%1 is not unique.").arg(ui->label_LayoutID->text()); // If we're not duplicating a map this is ok as long as it's the name of an existing layout. } else if (!this->project->layoutIds.contains(layoutId)) { @@ -241,7 +227,8 @@ void NewMapDialog::dialogButtonClicked(QAbstractButton *button) { if (role == QDialogButtonBox::RejectRole){ reject(); } else if (role == QDialogButtonBox::ResetRole) { - setUI(this->project->getNewMapSettings()); + this->project->initNewMapSettings(); + refresh(); } else if (role == QDialogButtonBox::AcceptRole) { accept(); } @@ -251,7 +238,6 @@ void NewMapDialog::accept() { // Make sure to call each validation function so that all errors are shown at once. bool success = true; if (!ui->newLayoutForm->validate()) success = false; - if (!validateMapID()) success = false; if (!validateName()) success = false; if (!validateGroup()) success = false; if (!validateLayoutID()) success = false; @@ -261,7 +247,7 @@ void NewMapDialog::accept() { // Update settings from UI saveSettings(); - Map *map = this->project->createNewMap(settings, this->importedMap); + Map *map = this->project->createNewMap(this->project->newMapSettings, this->mapToCopy); if (!map) { ui->label_GenericError->setText(QString("Failed to create map. See %1 for details.").arg(getLogPath())); ui->label_GenericError->setVisible(true);