diff --git a/CHANGELOG.md b/CHANGELOG.md index 0135ff6c..14e9ec95 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ and this project somewhat adheres to [Semantic Versioning](https://semver.org/sp - The dimensions of the current metatile selection are now displayed above the metatile selector. - The 'Change Dimensions' button was replaced with a Resize tool button. Resizing is also now available under the `Edit` menu, and can be assigned a shortcut. - Some UI changes to prioritize horizontal space for the map. +- `map_groups.json` is only saved when relevant changes are made, which should improve the average project compile time after saving with Porymap. ### Fixed - Fix actions triggered with the use of `utility.registerAction` calling all functions across plug-ins with the registered name, rather than just the function in the script that registered it. diff --git a/include/project.h b/include/project.h index 9772b99b..716046ea 100644 --- a/include/project.h +++ b/include/project.h @@ -31,8 +31,6 @@ public: public: QString root; - QStringList groupNames; - QMap groupNameToMapNames; QStringList healLocationSaveOrder; QMap> healLocations; QMap mapConstantsToMapNames; @@ -76,6 +74,11 @@ public: bool isLoadedMap(const QString &mapName) const { return this->loadedMapNames.contains(mapName); } bool isUnsavedMap(const QString &mapName) const; + const QStringList& mapGroups() const { return this->groupNames; } + QStringList mapNamesInMapGroup(const QString& mapGroupName) const { return this->groupNameToMapNames.value(mapGroupName); } + void setMapGroups(const QStringList& orderedGroupNames, const QMap& groupNameToMapNames); + bool isMapGroup(const QString &mapGroupName) const { return this->groupNames.contains(mapGroupName); } + // Note: This does not guarantee the map is loaded. Map* getMap(const QString &mapName) { return this->maps.value(mapName); } Map* loadMap(const QString &mapName); @@ -163,7 +166,6 @@ public: void setMapsecDisplayName(const QString &idName, const QString &displayName); bool hasUnsavedChanges(); - bool hasUnsavedDataChanges = false; bool loadMapEvent(Map *map, QJsonObject json, Event::Type defaultType = Event::Type::None); bool loadMapData(Map*); @@ -316,8 +318,13 @@ private: QSet failedFileWatchPaths; - const QRegularExpression re_gbapalExtension; - const QRegularExpression re_bppExtension; + // TODO: Unless it makes a worthwhile performance difference, these should really be + // combined into a single OrderedMap. + QStringList groupNames; + QMap groupNameToMapNames; + + bool hasUnsavedDataChanges = false; + bool hasUnsavedMapGroupChanges = false; struct EventGraphics { diff --git a/src/project.cpp b/src/project.cpp index 6367687b..a6430eac 100644 --- a/src/project.cpp +++ b/src/project.cpp @@ -558,6 +558,8 @@ Map *Project::createNewMap(const Project::NewMapSettings &settings, const Map* t addNewMapsec(map->header()->location()); this->groupNameToMapNames[settings.group].append(map->name()); + // We don't mark that map groups has been edited until the new map is saved + this->mapConstantsToMapNames.insert(map->constantName(), map->name()); this->alphabeticalMapNames.append(map->name()); Util::numericalModeSort(this->alphabeticalMapNames); @@ -916,6 +918,8 @@ void Project::resetFileWatcher() { } bool Project::saveMapGroups() { + if (!this->hasUnsavedMapGroupChanges) return true; + QString mapGroupsFilepath = QString("%1/%2").arg(root).arg(projectConfig.getFilePath(ProjectFilePath::json_map_groups)); QFile mapGroupsFile(mapGroupsFilepath); if (!mapGroupsFile.open(QIODevice::WriteOnly)) { @@ -950,6 +954,8 @@ bool Project::saveMapGroups() { OrderedJsonDoc jsonDoc(&mapGroupJson); jsonDoc.dump(&mapGroupsFile); mapGroupsFile.close(); + + this->hasUnsavedMapGroupChanges = false; return true; } @@ -1361,6 +1367,9 @@ bool Project::saveMap(Map *map, bool skipLayout) { text += QString("\t.include \"%1/text.inc\"\n").arg(folderPath); } appendTextFile(root + "/" + projectConfig.getFilePath(ProjectFilePath::data_event_scripts), text); + + // First time saving this map, we need to update the map groups data + this->hasUnsavedMapGroupChanges = true; } // Create map.json for map data. @@ -2032,11 +2041,17 @@ void Project::addNewMapGroup(const QString &groupName) { this->groupNames.append(groupName); this->groupNameToMapNames.insert(groupName, QStringList()); - this->hasUnsavedDataChanges = true; + this->hasUnsavedMapGroupChanges = true; emit mapGroupAdded(groupName); } +void Project::setMapGroups(const QStringList& orderedGroupNames, const QMap& groupNameToMapNames) { + this->groupNames = orderedGroupNames; + this->groupNameToMapNames = groupNameToMapNames; + this->hasUnsavedMapGroupChanges = true; +} + QString Project::mapNameToMapGroup(const QString &mapName) const { for (auto it = this->groupNameToMapNames.constBegin(); it != this->groupNameToMapNames.constEnd(); it++) { if (it.value().contains(mapName)) { @@ -3547,7 +3562,7 @@ void Project::applyParsedLimits() { } bool Project::hasUnsavedChanges() { - if (this->hasUnsavedDataChanges) + if (this->hasUnsavedDataChanges || this->hasUnsavedMapGroupChanges) return true; // Check layouts for unsaved changes diff --git a/src/ui/maplistmodels.cpp b/src/ui/maplistmodels.cpp index c80ca353..987fded6 100644 --- a/src/ui/maplistmodels.cpp +++ b/src/ui/maplistmodels.cpp @@ -213,9 +213,9 @@ MapGroupModel::MapGroupModel(Project *project, QObject *parent) : MapListModel(p this->folderTypeName = "map_group"; this->editable = true; - for (const auto &groupName : this->project->groupNames) { + for (const auto &groupName : this->project->mapGroups()) { insertMapFolderItem(groupName); - for (const auto &mapName : this->project->groupNameToMapNames.value(groupName)) { + for (const auto &mapName : this->project->mapNamesInMapGroup(groupName)) { insertMapItem(mapName, groupName); } } @@ -376,7 +376,6 @@ bool MapGroupModel::dropMimeData(const QMimeData *data, Qt::DropAction action, i void MapGroupModel::updateProject() { if (!this->project) return; - // Temporary objects in case of failure, so we won't modify the project unless it succeeds. QStringList groupNames; QMap groupNameToMapNames; @@ -394,10 +393,7 @@ void MapGroupModel::updateProject() { groupNameToMapNames[groupName].append(mapName); } } - - this->project->groupNames = groupNames; - this->project->groupNameToMapNames = groupNameToMapNames; - this->project->hasUnsavedDataChanges = true; + this->project->setMapGroups(groupNames, groupNameToMapNames); } void MapGroupModel::removeItem(QStandardItem *item) { diff --git a/src/ui/newmapdialog.cpp b/src/ui/newmapdialog.cpp index ea043999..bec74d7c 100644 --- a/src/ui/newmapdialog.cpp +++ b/src/ui/newmapdialog.cpp @@ -41,7 +41,7 @@ NewMapDialog::NewMapDialog(Project *project, const Map *mapToCopy, QWidget *pare settings->layout.id = project->toUniqueIdentifier(Layout::layoutConstantFromName(settings->name)); ui->newLayoutForm->initUi(project); - ui->comboBox_Group->addItems(project->groupNames); + ui->comboBox_Group->addItems(project->mapGroups()); ui->comboBox_LayoutID->addItems(project->layoutIds()); auto validator = new IdentifierValidator(this); @@ -176,7 +176,7 @@ bool NewMapDialog::validateGroup(bool allowEmpty) { QString errorText; if (groupName.isEmpty()) { if (!allowEmpty) errorText = QString("%1 cannot be empty.").arg(ui->label_Group->text()); - } else if (!this->project->groupNames.contains(groupName) && !this->project->isIdentifierUnique(groupName)) { + } else if (!this->project->isMapGroup(groupName) && !this->project->isIdentifierUnique(groupName)) { errorText = QString("%1 must either be the name of an existing map group, or a unique identifier for a new map group.").arg(ui->label_Group->text()); }