From bdd64a6c6b2a26d1986050595d10e2fbab2bfe2d Mon Sep 17 00:00:00 2001 From: GriffinR Date: Sat, 14 Dec 2024 16:22:28 -0500 Subject: [PATCH] Use applicationName() for window titles, clean up some remaining TODO items --- forms/newlayoutdialog.ui | 16 +++++- forms/newmapdialog.ui | 26 ++++++++-- forms/newnamedialog.ui | 9 ++-- forms/newtilesetdialog.ui | 21 +++++--- include/core/map.h | 2 +- include/core/maplayout.h | 2 - include/lib/collapsiblesection.h | 2 +- include/mainwindow.h | 6 ++- include/project.h | 5 +- src/lib/collapsiblesection.cpp | 4 +- src/mainwindow.cpp | 68 ++++++++++++++++---------- src/project.cpp | 83 +++++++++++++++++++++++--------- src/ui/customscriptseditor.cpp | 4 +- src/ui/maplistmodels.cpp | 21 +++++--- src/ui/newlayoutdialog.cpp | 27 +++-------- src/ui/newmapdialog.cpp | 69 +++++++++----------------- src/ui/newnamedialog.cpp | 1 - src/ui/newtilesetdialog.cpp | 1 - src/ui/prefab.cpp | 2 +- src/ui/projectsettingseditor.cpp | 2 +- src/ui/regionmapeditor.cpp | 2 +- src/ui/shortcutseditor.cpp | 2 +- src/ui/tileseteditor.cpp | 4 +- src/ui/wildmonchart.cpp | 2 +- 24 files changed, 221 insertions(+), 160 deletions(-) diff --git a/forms/newlayoutdialog.ui b/forms/newlayoutdialog.ui index bfbc9b02..42c7733c 100644 --- a/forms/newlayoutdialog.ui +++ b/forms/newlayoutdialog.ui @@ -13,9 +13,21 @@ New Layout Options + + true + + + true + + + QFrame::Shape::NoFrame + + + QFrame::Shadow::Plain + true @@ -24,8 +36,8 @@ 0 0 - 238 - 107 + 240 + 109 diff --git a/forms/newmapdialog.ui b/forms/newmapdialog.ui index 3e133dfd..6b32810a 100644 --- a/forms/newmapdialog.ui +++ b/forms/newmapdialog.ui @@ -6,16 +6,31 @@ 0 0 - 255 - 320 + 559 + 614 New Map Options + + true + + + true + + + QFrame::Shape::NoFrame + + + QFrame::Shadow::Plain + + + QAbstractScrollArea::SizeAdjustPolicy::AdjustToContents + true @@ -24,8 +39,8 @@ 0 0 - 229 - 228 + 535 + 550 @@ -42,6 +57,9 @@ + + QLayout::SizeConstraint::SetMinAndMaxSize + 0 diff --git a/forms/newnamedialog.ui b/forms/newnamedialog.ui index 6fa6b56d..fa6cb5ae 100644 --- a/forms/newnamedialog.ui +++ b/forms/newnamedialog.ui @@ -10,15 +10,12 @@ 87 + + true + - - QFrame::Shape::NoFrame - - - QFrame::Shadow::Plain - 0 diff --git a/forms/newtilesetdialog.ui b/forms/newtilesetdialog.ui index 1fed2558..3b898761 100644 --- a/forms/newtilesetdialog.ui +++ b/forms/newtilesetdialog.ui @@ -13,16 +13,25 @@ Add new Tileset + + true + - - QFrame::Shape::StyledPanel - - - QFrame::Shadow::Raised - + + 0 + + + 0 + + + 0 + + + 0 + diff --git a/include/core/map.h b/include/core/map.h index 6e953877..9cc2a69b 100644 --- a/include/core/map.h +++ b/include/core/map.h @@ -107,7 +107,7 @@ public: private: QString m_name; QString m_constantName; - QString m_layoutId; // TODO: Why do we do half this->layout()->id and half this->layoutId. Should these ever be different? + QString m_layoutId; QString m_sharedEventsMap = ""; QString m_sharedScriptsMap = ""; diff --git a/include/core/maplayout.h b/include/core/maplayout.h index 7761d7fc..1579b4ad 100644 --- a/include/core/maplayout.h +++ b/include/core/maplayout.h @@ -14,8 +14,6 @@ class LayoutPixmapItem; class CollisionPixmapItem; class BorderMetatilesPixmapItem; -// TODO: Privatize members as appropriate - class Layout : public QObject { Q_OBJECT public: diff --git a/include/lib/collapsiblesection.h b/include/lib/collapsiblesection.h index 584e44cb..73169303 100644 --- a/include/lib/collapsiblesection.h +++ b/include/lib/collapsiblesection.h @@ -41,7 +41,7 @@ public: explicit CollapsibleSection(const QString& title = "", const bool expanded = false, const int animationDuration = 0, QWidget* parent = 0); void setContentLayout(QLayout* contentLayout); - void setTitle(QString title); + void setTitle(const QString &title); bool isExpanded() const { return this->expanded; } public slots: diff --git a/include/mainwindow.h b/include/mainwindow.h index 1e8c53bb..0eac8947 100644 --- a/include/mainwindow.h +++ b/include/mainwindow.h @@ -31,6 +31,7 @@ #include "updatepromoter.h" #include "aboutporymap.h" #include "mapheaderform.h" +#include "newlayoutdialog.h" @@ -350,8 +351,11 @@ private: void openNewMapDialog(); void openDuplicateMapDialog(const QString &mapName); + NewLayoutDialog* createNewLayoutDialog(const Layout *layoutToCopy = nullptr); void openNewLayoutDialog(); void openDuplicateLayoutDialog(const QString &layoutId); + void openNewMapGroupDialog(); + void openNewAreaDialog(); void openSubWindow(QWidget * window); void scrollMapList(MapTree *list, const QString &itemName); void scrollMapListToCurrentMap(MapTree *list); @@ -370,8 +374,6 @@ private: void refreshRecentProjectsMenu(); void updateMapList(); - void mapListAddGroup(); - void mapListAddArea(); void openMapListItem(const QModelIndex &index); void saveMapListTab(int index); diff --git a/include/project.h b/include/project.h index 895f9979..9c9fdf33 100644 --- a/include/project.h +++ b/include/project.h @@ -111,7 +111,7 @@ public: QStringList secondaryTilesetLabels; QStringList tilesetLabelsOrdered; - Blockdata readBlockdata(QString); + Blockdata readBlockdata(QString, bool *ok = nullptr); bool loadBlockdata(Layout *); bool loadLayoutBorder(Layout *); @@ -121,6 +121,7 @@ public: bool readMapGroups(); void addNewMapGroup(const QString &groupName); + QString mapNameToMapGroup(const QString &mapName); struct NewMapSettings { QString name; @@ -141,6 +142,8 @@ public: Layout *createNewLayout(const Layout::Settings &layoutSettings, const Layout* toDuplicate = nullptr); Tileset *createNewTileset(const QString &friendlyName, bool secondary, bool checkerboardFill); bool isIdentifierUnique(const QString &identifier) const; + bool isValidNewIdentifier(const QString &identifier) const; + QString toUniqueIdentifier(const QString &identifier) const; QString getProjectTitle(); bool readWildMonData(); diff --git a/src/lib/collapsiblesection.cpp b/src/lib/collapsiblesection.cpp index 34dfb780..8ad8560a 100644 --- a/src/lib/collapsiblesection.cpp +++ b/src/lib/collapsiblesection.cpp @@ -119,9 +119,9 @@ void CollapsibleSection::setContentLayout(QLayout* contentLayout) updateAnimationTargets(); } -void CollapsibleSection::setTitle(QString title) +void CollapsibleSection::setTitle(const QString &title) { - toggleButton->setText(std::move(title)); + toggleButton->setText(title); } int CollapsibleSection::getContentHeight() const diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 629a582f..65a323e2 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -24,7 +24,6 @@ #include "config.h" #include "filedialog.h" #include "newmapdialog.h" -#include "newlayoutdialog.h" #include "newtilesetdialog.h" #include "newnamedialog.h" @@ -69,7 +68,7 @@ MainWindow::MainWindow(QWidget *parent) : QCoreApplication::setOrganizationName("pret"); QCoreApplication::setApplicationName("porymap"); QCoreApplication::setApplicationVersion(PORYMAP_VERSION); - QApplication::setApplicationDisplayName("porymap"); + QApplication::setApplicationDisplayName(QApplication::applicationName()); QApplication::setWindowIcon(QIcon(":/icons/porymap-icon-2.ico")); ui->setupUi(this); @@ -448,8 +447,8 @@ void MainWindow::initMapList() { connect(ui->mapListToolBar_Layouts, &MapListToolBar::filterCleared, this, &MainWindow::scrollMapListToCurrentLayout); // Connect the "add folder" button in each of the map lists - connect(ui->mapListToolBar_Groups, &MapListToolBar::addFolderClicked, this, &MainWindow::mapListAddGroup); - connect(ui->mapListToolBar_Areas, &MapListToolBar::addFolderClicked, this, &MainWindow::mapListAddArea); + connect(ui->mapListToolBar_Groups, &MapListToolBar::addFolderClicked, this, &MainWindow::openNewMapGroupDialog); + connect(ui->mapListToolBar_Areas, &MapListToolBar::addFolderClicked, this, &MainWindow::openNewAreaDialog); connect(ui->mapListToolBar_Layouts, &MapListToolBar::addFolderClicked, this, &MainWindow::openNewLayoutDialog); connect(ui->mapListContainer, &QTabWidget::currentChanged, this, &MainWindow::saveMapListTab); @@ -699,14 +698,14 @@ bool MainWindow::checkProjectSanity() { void MainWindow::showProjectOpenFailure() { QString errorMsg = QString("There was an error opening the project. Please see %1 for full error details.").arg(getLogPath()); - QMessageBox error(QMessageBox::Critical, "porymap", errorMsg, QMessageBox::Ok, this); + QMessageBox error(QMessageBox::Critical, QApplication::applicationName(), errorMsg, QMessageBox::Ok, this); error.setDetailedText(getMostRecentError()); error.exec(); } // Alert the user that one or more maps have been excluded while loading the project. void MainWindow::showMapsExcludedAlert(const QStringList &excludedMapNames) { - QMessageBox msgBox(QMessageBox::Icon::Warning, "porymap", "", QMessageBox::Ok, this); + QMessageBox msgBox(QMessageBox::Icon::Warning, QApplication::applicationName(), "", QMessageBox::Ok, this); QString errorMsg; if (excludedMapNames.length() == 1) { @@ -880,7 +879,7 @@ bool MainWindow::userSetMap(QString map_name) { if (map_name == editor->project->getDynamicMapName()) { QMessageBox msgBox(QMessageBox::Icon::Warning, - "Cannot Open Map", + QApplication::applicationName(), QString("The map '%1' can't be opened, it's a placeholder to indicate the specified map will be set programmatically.").arg(map_name), QMessageBox::Ok, this); @@ -890,7 +889,7 @@ bool MainWindow::userSetMap(QString map_name) { if (!setMap(map_name)) { QMessageBox msgBox(QMessageBox::Icon::Critical, - "Error Opening Map", + QApplication::applicationName(), QString("There was an error opening map %1.\n\nPlease see %2 for full error details.").arg(map_name).arg(getLogPath()), QMessageBox::Ok, this); @@ -952,7 +951,7 @@ void MainWindow::setLayoutOnlyMode(bool layoutOnly) { bool MainWindow::userSetLayout(QString layoutId) { if (!setLayout(layoutId)) { QMessageBox msgBox(QMessageBox::Icon::Critical, - "Error Opening Layout", + QApplication::applicationName(), QString("There was an error opening layout %1.\n\nPlease see %2 for full error details.").arg(layoutId).arg(getLogPath()), QMessageBox::Ok, this); @@ -1310,13 +1309,13 @@ void MainWindow::onOpenMapListContextMenu(const QPoint &point) { menu.exec(QCursor::pos()); } -void MainWindow::mapListAddGroup() { +void MainWindow::openNewMapGroupDialog() { auto dialog = new NewNameDialog("New Group Name", this->editor->project, this); connect(dialog, &NewNameDialog::applied, this->editor->project, &Project::addNewMapGroup); dialog->open(); } -void MainWindow::mapListAddArea() { +void MainWindow::openNewAreaDialog() { auto dialog = new NewNameDialog("New Area Name", this->editor->project, this); dialog->setNamePrefix(projectConfig.getIdentifier(ProjectIdentifier::define_map_section_prefix)); connect(dialog, &NewNameDialog::applied, this->editor->project, &Project::addNewMapsec); @@ -1388,9 +1387,11 @@ void MainWindow::setLocationComboBoxes(const QStringList &locations) { } void MainWindow::onNewTilesetCreated(Tileset *tileset) { - QString message = QString("Created a new tileset named %1.").arg(tileset->name); - logInfo(message); - statusBar()->showMessage(message); + logInfo(QString("Created a new tileset named %1.").arg(tileset->name)); + + // Unlike creating a new map or layout (which immediately opens the new item) + // creating a new tileset has no visual feedback that it succeeded, so we show a message. + QMessageBox::information(this, QApplication::applicationName(), QString( "New tileset created at '%1'!").arg(tileset->getExpectedDir())); // Refresh tileset combo boxes if (!tileset->is_secondary) { @@ -1413,24 +1414,40 @@ void MainWindow::openDuplicateMapDialog(const QString &mapName) { auto dialog = new NewMapDialog(this->editor->project, map, this); dialog->open(); } else { - //TODO + QMessageBox msgBox(QMessageBox::Icon::Critical, + QApplication::applicationName(), + QString("Unable to duplicate '%1'.\n\nPlease see %2 for full error details.").arg(mapName).arg(getLogPath()), + QMessageBox::Ok, + this); + msgBox.setDetailedText(getMostRecentError()); + msgBox.exec(); } } -void MainWindow::openNewLayoutDialog() { - auto dialog = new NewLayoutDialog(this->editor->project, this); +NewLayoutDialog* MainWindow::createNewLayoutDialog(const Layout *layoutToCopy) { + auto dialog = new NewLayoutDialog(this->editor->project, layoutToCopy, this); connect(dialog, &NewLayoutDialog::applied, this, &MainWindow::userSetLayout); + return dialog; +} + +void MainWindow::openNewLayoutDialog() { + auto dialog = createNewLayoutDialog(); dialog->open(); } void MainWindow::openDuplicateLayoutDialog(const QString &layoutId) { auto layout = this->editor->project->loadLayout(layoutId); if (layout) { - auto dialog = new NewLayoutDialog(this->editor->project, layout, this); - connect(dialog, &NewLayoutDialog::applied, this, &MainWindow::userSetLayout); + auto dialog = createNewLayoutDialog(layout); dialog->open(); } else { - //TODO + QMessageBox msgBox(QMessageBox::Icon::Critical, + QApplication::applicationName(), + QString("Unable to duplicate '%1'.\n\nPlease see %2 for full error details.").arg(layoutId).arg(getLogPath()), + QMessageBox::Ok, + this); + msgBox.setDetailedText(getMostRecentError()); + msgBox.exec(); } } @@ -1675,7 +1692,7 @@ void MainWindow::setClipboardData(OrderedJson::object object) { QClipboard *clipboard = QGuiApplication::clipboard(); QString newText; int indent = 0; - object["application"] = "porymap"; + object["application"] = QApplication::applicationName(); OrderedJson data(object); data.dump(newText, &indent); clipboard->setText(newText); @@ -1714,7 +1731,7 @@ void MainWindow::paste() { QJsonObject pasteObject = pasteJsonDoc.object(); //OrderedJson::object pasteObject = pasteJson.object_items(); - if (pasteObject["application"].toString() != "porymap") { + if (pasteObject["application"].toString() != QApplication::applicationName()) { return; } @@ -2530,8 +2547,7 @@ void MainWindow::on_actionImport_Map_from_Advance_Map_1_92_triggered() { return; } - auto dialog = new NewLayoutDialog(this->editor->project, mapLayout, this); - connect(dialog, &NewLayoutDialog::applied, this, &MainWindow::userSetLayout); + auto dialog = createNewLayoutDialog(mapLayout); connect(dialog, &NewLayoutDialog::finished, [mapLayout] { mapLayout->deleteLater(); }); dialog->open(); } @@ -2858,7 +2874,7 @@ void MainWindow::onWarpBehaviorWarningClicked() { "You can disable this warning or edit the list of behaviors that silence this warning under Options -> Project Settings..." "

" ); - QMessageBox msgBox(QMessageBox::Information, "porymap", text, QMessageBox::Close, this); + QMessageBox msgBox(QMessageBox::Information, QApplication::applicationName(), text, QMessageBox::Close, this); QPushButton *settings = msgBox.addButton("Open Settings...", QMessageBox::ActionRole); msgBox.setDefaultButton(QMessageBox::Close); msgBox.setTextFormat(Qt::RichText); @@ -3074,7 +3090,7 @@ bool MainWindow::closeProject() { if (this->editor->project->hasUnsavedChanges()) { QMessageBox::StandardButton result = QMessageBox::question( - this, "porymap", "The project has been modified, save changes?", + this, QApplication::applicationName(), "The project has been modified, save changes?", QMessageBox::No | QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Yes); if (result == QMessageBox::Yes) { diff --git a/src/project.cpp b/src/project.cpp index 0ad2114e..0a66c0e8 100644 --- a/src/project.cpp +++ b/src/project.cpp @@ -367,13 +367,7 @@ Map *Project::createNewMap(const Project::NewMapSettings &settings, const Map* t 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); + map->setConstantName(toUniqueIdentifier(Map::mapConstantFromName(map->name()))); Layout *layout = this->mapLayouts.value(settings.layout.id); if (!layout) { @@ -402,13 +396,15 @@ Map *Project::createNewMap(const Project::NewMapSettings &settings, const Map* t } else { // Adding map to a map group that doesn't exist yet. // Create the group, and we already know the map will be last in the list. - addNewMapGroup(settings.group); + if (isValidNewIdentifier(settings.group)) { + addNewMapGroup(settings.group); + } mapNamePos = this->mapNames.length(); } const QString location = map->header()->location(); - if (!this->mapSectionIdNames.contains(location) && isIdentifierUnique(location)) { - // Unrecognized MAPSEC value. Add it. + if (!this->mapSectionIdNames.contains(location) && isValidNewIdentifier(location)) { + // Unrecognized MAPSEC name, we can automatically add a new MAPSEC for it. addNewMapsec(location); } @@ -555,7 +551,6 @@ bool Project::readMapLayouts() { .arg(layoutsLabel)); } - QStringList failedLayoutNames; // TODO: Populate for (int i = 0; i < layouts.size(); i++) { QJsonObject layoutObj = layouts[i].toObject(); if (layoutObj.isEmpty()) @@ -1124,9 +1119,16 @@ Tileset* Project::loadTileset(QString label, Tileset *tileset) { } bool Project::loadBlockdata(Layout *layout) { + bool ok = true; QString path = QString("%1/%2").arg(root).arg(layout->blockdata_path); - layout->blockdata = readBlockdata(path); - layout->lastCommitBlocks.blocks = layout->blockdata; + auto blockdata = readBlockdata(path, &ok); + if (!ok) { + logError(QString("Failed to load layout blockdata from '%1'").arg(path)); + return false; + } + + layout->blockdata = blockdata; + layout->lastCommitBlocks.blocks = blockdata; layout->lastCommitBlocks.layoutDimensions = QSize(layout->getWidth(), layout->getHeight()); if (layout->blockdata.count() != layout->getWidth() * layout->getHeight()) { @@ -1153,9 +1155,16 @@ void Project::setNewLayoutBlockdata(Layout *layout) { } bool Project::loadLayoutBorder(Layout *layout) { + bool ok = true; QString path = QString("%1/%2").arg(root).arg(layout->border_path); - layout->border = readBlockdata(path); - layout->lastCommitBlocks.border = layout->border; + auto blockdata = readBlockdata(path, &ok); + if (!ok) { + logError(QString("Failed to load layout border from '%1'").arg(path)); + return false; + } + + layout->border = blockdata; + layout->lastCommitBlocks.border = blockdata; layout->lastCommitBlocks.borderDimensions = QSize(layout->getBorderWidth(), layout->getBorderHeight()); int borderLength = layout->getBorderWidth() * layout->getBorderHeight(); @@ -1471,7 +1480,6 @@ Tileset *Project::createNewTileset(const QString &friendlyName, bool secondary, // Set default tiles image QImage tilesImage(":/images/blank_tileset.png"); tileset->loadTilesImage(&tilesImage); - //exportIndexed4BPPPng(tileset->tilesImage, tileset->tilesImagePath); // TODO: Make sure we can now properly handle the 8bpp images that get written without this. // Create default metatiles const int numMetatiles = tileset->is_secondary ? (Project::getNumMetatilesTotal() - Project::getNumMetatilesPrimary()) : Project::getNumMetatilesPrimary(); @@ -1580,7 +1588,7 @@ void Project::loadTilesetMetatileLabels(Tileset* tileset) { } } -Blockdata Project::readBlockdata(QString path) { +Blockdata Project::readBlockdata(QString path, bool *ok) { Blockdata blockdata; QFile file(path); if (file.open(QIODevice::ReadOnly)) { @@ -1589,8 +1597,10 @@ Blockdata Project::readBlockdata(QString path) { uint16_t word = static_cast((data[i] & 0xff) + ((data[i + 1] & 0xff) << 8)); blockdata.append(word); } + if (ok) *ok = true; } else { - logError(QString("Failed to open blockdata path '%1'").arg(path)); + // Failed + if (ok) *ok = false; } return blockdata; @@ -1918,6 +1928,16 @@ void Project::addNewMapGroup(const QString &groupName) { emit mapGroupAdded(groupName); } +QString Project::mapNameToMapGroup(const QString &mapName) { + for (auto it = this->groupNameToMapNames.constBegin(); it != this->groupNameToMapNames.constEnd(); it++) { + const QStringList mapNames = it.value(); + if (mapNames.contains(mapName)) { + return it.key(); + } + } + return QString(); +} + // 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. @@ -1946,22 +1966,41 @@ bool Project::isIdentifierUnique(const QString &identifier) const { return true; } +// For some arbitrary string, return true if it's both a valid identifier name +// and not one that's already in-use. +bool Project::isValidNewIdentifier(const QString &identifier) const { + static const QRegularExpression re_identifier("[A-Za-z_]+[\\w]*"); + QRegularExpressionMatch match = re_identifier.match(identifier); + return match.hasMatch() && isIdentifierUnique(identifier); +} + +// Assumes 'identifier' is a valid name. If 'identifier' is unique, returns 'identifier'. +// Otherwise returns the identifier with a numbered suffix added to make it unique. +QString Project::toUniqueIdentifier(const QString &identifier) const { + int suffix = 2; + QString uniqueIdentifier = identifier; + while (!isIdentifierUnique(uniqueIdentifier)) { + uniqueIdentifier = QString("%1_%2").arg(identifier).arg(suffix++); + } + return uniqueIdentifier; +} + QString Project::getNewMapName() const { // Ensure default name/ID doesn't already exist. - int i = 0; + int suffix = 1; QString newMapName; do { - newMapName = QString("NewMap%1").arg(++i); + newMapName = QString("NewMap%1").arg(suffix++); } while (!isIdentifierUnique(newMapName) || !isIdentifierUnique(Map::mapConstantFromName(newMapName))); return newMapName; } QString Project::getNewLayoutName() const { // Ensure default name/ID doesn't already exist. - int i = 0; + int suffix = 1; QString newLayoutName; do { - newLayoutName = QString("NewLayout%1").arg(++i); + newLayoutName = QString("NewLayout%1").arg(suffix++); } while (!isIdentifierUnique(newLayoutName) || !isIdentifierUnique(Layout::layoutConstantFromName(newLayoutName))); return newLayoutName; } diff --git a/src/ui/customscriptseditor.cpp b/src/ui/customscriptseditor.cpp index 284ea333..c3c412c2 100644 --- a/src/ui/customscriptseditor.cpp +++ b/src/ui/customscriptseditor.cpp @@ -185,7 +185,7 @@ void CustomScriptsEditor::displayNewScript(QString filepath) { // Verify new script path is not already in list for (int i = 0; i < ui->list->count(); i++) { if (filepath == this->getScriptFilepath(ui->list->item(i), false)) { - QMessageBox::information(this, "", QString("The script '%1' is already loaded").arg(filepath)); + QMessageBox::information(this, QApplication::applicationName(), QString("The script '%1' is already loaded").arg(filepath)); return; } } @@ -219,7 +219,7 @@ void CustomScriptsEditor::openScript(QListWidgetItem * item) { const QString path = this->getScriptFilepath(item); QFileInfo fileInfo(path); if (!fileInfo.exists() || !fileInfo.isFile()){ - QMessageBox::warning(this, "", QString("Failed to open script '%1'").arg(path)); + QMessageBox::warning(this, QApplication::applicationName(), QString("Failed to open script '%1'").arg(path)); return; } Editor::openInTextEditor(path); diff --git a/src/ui/maplistmodels.cpp b/src/ui/maplistmodels.cpp index 0f352f4f..dc1e3d7e 100644 --- a/src/ui/maplistmodels.cpp +++ b/src/ui/maplistmodels.cpp @@ -115,21 +115,30 @@ QStandardItem *MapListModel::createMapFolderItem(const QString &folderName, QSta } QStandardItem *MapListModel::insertMapItem(const QString &mapName, const QString &folderName) { - // Disallow adding MAP_DYNAMIC to the map list. - if (mapName == this->project->getDynamicMapName()) + if (mapName.isEmpty() || mapName == this->project->getDynamicMapName()) // Disallow adding MAP_DYNAMIC to the map list. return nullptr; - QStandardItem *folder = this->mapFolderItems[folderName]; - if (!folder) folder = insertMapFolderItem(folderName); - QStandardItem *map = createMapItem(mapName); - folder->appendRow(map); + + QStandardItem *folder = this->mapFolderItems[folderName]; + if (!folder) { + // Folder doesn't exist yet, add it. + folder = insertMapFolderItem(folderName); + } + // If folder is still nullptr here it's because we failed to create it. + if (folder) { + folder->appendRow(map); + } + if (this->sortingEnabled) this->sort(0, Qt::AscendingOrder); return map; } QStandardItem *MapListModel::insertMapFolderItem(const QString &folderName) { + if (folderName.isEmpty()) + return nullptr; + QStandardItem *item = createMapFolderItem(folderName); this->root->appendRow(item); if (this->sortingEnabled) diff --git a/src/ui/newlayoutdialog.cpp b/src/ui/newlayoutdialog.cpp index 79af74e5..086bc346 100644 --- a/src/ui/newlayoutdialog.cpp +++ b/src/ui/newlayoutdialog.cpp @@ -19,31 +19,18 @@ NewLayoutDialog::NewLayoutDialog(Project *project, const Layout *layoutToCopy, Q layoutToCopy(layoutToCopy) { setAttribute(Qt::WA_DeleteOnClose); - setModal(true); ui->setupUi(this); this->project = project; + Layout::Settings *settings = &project->newLayoutSettings; - QString newName; - QString newId; + // Note: 'layoutToCopy' will have an empty name if it's an import from AdvanceMap 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: If 'layoutToCopy' is an imported AdvanceMap layout it won't have - // a name, so it uses the default new layout name instead. - int i = 2; - do { - newName = QString("%1_%2").arg(this->layoutToCopy->name).arg(i++); - newId = Layout::layoutConstantFromName(newName); - } while (!project->isIdentifierUnique(newName) || !project->isIdentifierUnique(newId)); + settings->name = project->toUniqueIdentifier(this->layoutToCopy->name); } else { - newName = project->getNewLayoutName(); - newId = Layout::layoutConstantFromName(newName); + settings->name = project->getNewLayoutName(); } - - // 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; + // Generate a unique Layout constant + settings->id = project->toUniqueIdentifier(Layout::layoutConstantFromName(settings->name)); ui->newLayoutForm->initUi(project); @@ -166,8 +153,6 @@ void NewLayoutDialog::accept() { } ui->label_GenericError->setVisible(false); - // TODO: See if we can get away with emitting this from Project so that we don't need to connect - // to this signal every time we create the dialog. emit applied(layout->id); QDialog::accept(); } diff --git a/src/ui/newmapdialog.cpp b/src/ui/newmapdialog.cpp index 5d9c7413..caf98060 100644 --- a/src/ui/newmapdialog.cpp +++ b/src/ui/newmapdialog.cpp @@ -20,33 +20,28 @@ NewMapDialog::NewMapDialog(Project *project, const Map *mapToCopy, QWidget *pare mapToCopy(mapToCopy) { setAttribute(Qt::WA_DeleteOnClose); - setModal(true); ui->setupUi(this); this->project = project; + Project::NewMapSettings *settings = &project->newMapSettings; - 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)); + // Copy settings from the map we're duplicating + if (this->mapToCopy->layout()){ + settings->layout = this->mapToCopy->layout()->settings(); + } + settings->header = *this->mapToCopy->header(); + settings->group = project->mapNameToMapGroup(this->mapToCopy->name()); + settings->name = project->toUniqueIdentifier(this->mapToCopy->name()); + } else { // Not duplicating a map, get a generic new map name. - newMapName = project->getNewMapName(); - newLayoutId = Layout::layoutConstantFromName(newMapName); + // The rest of the settings are preserved in the project between sessions. + settings->name = project->getNewMapName(); } - - // 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; + // Generate a unique Layout constant + settings->layout.id = project->toUniqueIdentifier(Layout::layoutConstantFromName(settings->name)); ui->newLayoutForm->initUi(project); - ui->comboBox_Group->addItems(project->groupNames); ui->comboBox_LayoutID->addItems(project->layoutIds); @@ -66,12 +61,10 @@ NewMapDialog::NewMapDialog(Project *project, const Map *mapToCopy, QWidget *pare this->headerSection = new CollapsibleSection("Header Data", porymapConfig.newMapHeaderSectionExpanded, 150, this); this->headerSection->setContentLayout(sectionLayout); ui->layout_HeaderData->addWidget(this->headerSection); - ui->layout_HeaderData->addItem(new QSpacerItem(0, 0, QSizePolicy::Ignored, QSizePolicy::Expanding)); connect(ui->buttonBox, &QDialogButtonBox::clicked, this, &NewMapDialog::dialogButtonClicked); refresh(); - adjustSize(); } // Adding new map to an existing map list folder. Initialize settings accordingly. @@ -115,12 +108,7 @@ void NewMapDialog::refresh() { 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->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); } @@ -135,29 +123,22 @@ void NewMapDialog::saveSettings() { settings->canFlyTo = ui->checkBox_CanFlyTo->isChecked(); settings->header = this->headerForm->headerData(); - // This dialog doesn't give users the option to give new layouts a name. - // If a new layout is being created we'll generate a unique layout name using the map name and a suffix. + // This dialog doesn't give users the option to give new layouts a name, we generate one using the map name. // (an older iteration of this dialog gave users an option to name new layouts, but it's extra clutter for // something the majority of users creating a map won't need. If they want to give a specific name to a layout // they can create the layout first, then create a new map that uses that layout.) const Layout *layout = this->project->mapLayouts.value(settings->layout.id); if (!layout) { - const QString baseLayoutName = QString("%1%2").arg(settings->name).arg(Layout::defaultSuffix()); - QString newLayoutName = baseLayoutName; - int i = 2; - while (!this->project->isIdentifierUnique(newLayoutName)) { - newLayoutName = QString("%1_%2").arg(baseLayoutName).arg(i++); - } - settings->layout.name = newLayoutName; + const QString newLayoutName = QString("%1%2").arg(settings->name).arg(Layout::defaultSuffix()); + settings->layout.name = this->project->toUniqueIdentifier(newLayoutName); } else { // Pre-existing layout. The layout name won't be read, but we'll make sure it's correct anyway. settings->layout.name = layout->name; } - // Folders for new layouts created for new maps use the map name, rather than the layout name. - // There's no real reason for this, aside from maintaining consistency with the default layout - // folder names that do this (i.e., if you create "MyMap", you'll get a 'data/layouts/MyMap/', - // rather than 'data/layouts/MyMap_Layout/'). + // Folders for new layouts created for new maps use the map name, rather than the layout name + // (i.e., if you create "MyMap", you'll get a 'data/layouts/MyMap/', rather than 'data/layouts/MyMap_Layout/'). + // There's no real reason for this, aside from maintaining consistency with the default layout folder names that do this. settings->layout.folderName = settings->name; porymapConfig.newMapHeaderSectionExpanded = this->headerSection->isExpanded(); @@ -216,14 +197,8 @@ bool NewMapDialog::validateLayoutID(bool allowEmpty) { QString errorText; if (layoutId.isEmpty()) { 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->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)) { - errorText = QString("%1 must either be the ID for an existing layout, or a unique identifier for a new layout.").arg(ui->label_LayoutID->text()); - } + } else if (!this->project->layoutIds.contains(layoutId) && !this->project->isIdentifierUnique(layoutId)) { + errorText = QString("%1 must either be the ID for an existing layout, or a unique identifier for a new layout.").arg(ui->label_LayoutID->text()); } bool isValid = errorText.isEmpty(); diff --git a/src/ui/newnamedialog.cpp b/src/ui/newnamedialog.cpp index d5800daa..8f9cdc42 100644 --- a/src/ui/newnamedialog.cpp +++ b/src/ui/newnamedialog.cpp @@ -10,7 +10,6 @@ NewNameDialog::NewNameDialog(const QString &label, Project* project, QWidget *pa ui(new Ui::NewNameDialog) { setAttribute(Qt::WA_DeleteOnClose); - setModal(true); ui->setupUi(this); this->project = project; diff --git a/src/ui/newtilesetdialog.cpp b/src/ui/newtilesetdialog.cpp index 1ddd975d..1e8c569f 100644 --- a/src/ui/newtilesetdialog.cpp +++ b/src/ui/newtilesetdialog.cpp @@ -11,7 +11,6 @@ NewTilesetDialog::NewTilesetDialog(Project* project, QWidget *parent) : symbolPrefix(projectConfig.getIdentifier(ProjectIdentifier::symbol_tilesets_prefix)) { setAttribute(Qt::WA_DeleteOnClose); - setModal(true); ui->setupUi(this); this->project = project; diff --git a/src/ui/prefab.cpp b/src/ui/prefab.cpp index 10642178..e1fc83e9 100644 --- a/src/ui/prefab.cpp +++ b/src/ui/prefab.cpp @@ -303,7 +303,7 @@ bool Prefab::tryImportDefaultPrefabs(QWidget * parent, BaseGameVersion version, // into their project. QMessageBox::StandardButton prompt = QMessageBox::question(parent, - "Import Default Prefabs", + QApplication::applicationName(), QString("Would you like to import the default prefabs for %1? %2.") .arg(projectConfig.getBaseGameVersionString(version)) .arg(fileWarning), diff --git a/src/ui/projectsettingseditor.cpp b/src/ui/projectsettingseditor.cpp index 346591f4..58d808ca 100644 --- a/src/ui/projectsettingseditor.cpp +++ b/src/ui/projectsettingseditor.cpp @@ -395,7 +395,7 @@ QString ProjectSettingsEditor::chooseProjectFile(const QString &defaultFilepath) 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", + QMessageBox::warning(this, QApplication::applicationName(), QString("Custom filepaths must be inside the root project folder '%1'").arg(this->baseDir)); return QString(); } diff --git a/src/ui/regionmapeditor.cpp b/src/ui/regionmapeditor.cpp index cb0f6d44..f0415726 100644 --- a/src/ui/regionmapeditor.cpp +++ b/src/ui/regionmapeditor.cpp @@ -1265,7 +1265,7 @@ void RegionMapEditor::closeEvent(QCloseEvent *event) if (this->modified()) { QMessageBox::StandardButton result = QMessageBox::question( this, - "porymap", + QApplication::applicationName(), "The region map has been modified, save changes?", QMessageBox::No | QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Yes); diff --git a/src/ui/shortcutseditor.cpp b/src/ui/shortcutseditor.cpp index 30f9d62a..36bc30d0 100644 --- a/src/ui/shortcutseditor.cpp +++ b/src/ui/shortcutseditor.cpp @@ -158,7 +158,7 @@ void ShortcutsEditor::promptUserOnDuplicateFound(MultiKeyEdit *sender, MultiKeyE .arg(duplicateKeySequence.toString()).arg(siblingLabel); const auto result = QMessageBox::question( - this, "porymap", message, QMessageBox::Yes | QMessageBox::No, QMessageBox::No); + this, QApplication::applicationName(), message, QMessageBox::Yes | QMessageBox::No, QMessageBox::No); if (result == QMessageBox::Yes) removeKeySequence(duplicateKeySequence, sibling); diff --git a/src/ui/tileseteditor.cpp b/src/ui/tileseteditor.cpp index f3c4a1c9..0603e8cb 100644 --- a/src/ui/tileseteditor.cpp +++ b/src/ui/tileseteditor.cpp @@ -57,7 +57,7 @@ void TilesetEditor::updateTilesets(QString primaryTilesetLabel, QString secondar if (this->hasUnsavedChanges) { QMessageBox::StandardButton result = QMessageBox::question( this, - "porymap", + QApplication::applicationName(), "Tileset has been modified, save changes?", QMessageBox::No | QMessageBox::Yes, QMessageBox::Yes); @@ -726,7 +726,7 @@ void TilesetEditor::closeEvent(QCloseEvent *event) if (this->hasUnsavedChanges) { QMessageBox::StandardButton result = QMessageBox::question( this, - "porymap", + QApplication::applicationName(), "Tileset has been modified, save changes?", QMessageBox::No | QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Yes); diff --git a/src/ui/wildmonchart.cpp b/src/ui/wildmonchart.cpp index 32ff9bc9..80c41f81 100644 --- a/src/ui/wildmonchart.cpp +++ b/src/ui/wildmonchart.cpp @@ -465,7 +465,7 @@ void WildMonChart::showHelpDialog() { informativeText = levelTabInfo; } - QMessageBox msgBox(QMessageBox::Information, "porymap", text, QMessageBox::Close, this); + QMessageBox msgBox(QMessageBox::Information, QApplication::applicationName(), text, QMessageBox::Close, this); msgBox.setTextFormat(Qt::RichText); msgBox.setInformativeText(informativeText); msgBox.exec();