From 96b90dc5e106717d9871e0e3ac88d76ddcd5aa34 Mon Sep 17 00:00:00 2001 From: GriffinR Date: Thu, 8 May 2025 20:43:52 -0400 Subject: [PATCH] Add 'Open in JSON' actions --- include/core/map.h | 5 ++++- include/core/parseutil.h | 2 ++ include/editor.h | 2 ++ include/project.h | 2 +- src/core/map.cpp | 15 +++++++++++---- src/core/parseutil.cpp | 22 +++++++++++++++++----- src/editor.cpp | 16 +++++++++++++--- src/mainwindow.cpp | 6 ++++++ src/project.cpp | 14 +++++++++----- 9 files changed, 65 insertions(+), 19 deletions(-) diff --git a/include/core/map.h b/include/core/map.h index 2ba172ce..6fd34a32 100644 --- a/include/core/map.h +++ b/include/core/map.h @@ -82,9 +82,12 @@ public: bool hasEvent(Event *) const; QStringList getScriptLabels(Event::Group group = Event::Group::None); - QString getScriptsFilePath() const; + QString getScriptsFilepath() const; void openScript(const QString &label); + static QString getJsonFilepath(const QString &mapName); + QString getJsonFilepath() const { return getJsonFilepath(m_name); } + void deleteConnections(); QList getConnections() const { return m_connections; } MapConnection* getConnection(const QString &direction) const; diff --git a/include/core/parseutil.h b/include/core/parseutil.h index 2edb9f78..c8ed3eb6 100644 --- a/include/core/parseutil.h +++ b/include/core/parseutil.h @@ -73,6 +73,8 @@ public: bool tryParseJsonFile(QJsonDocument *out, const QString &filepath, QString *error = nullptr); bool tryParseOrderedJsonFile(poryjson::Json::object *out, const QString &filepath, QString *error = nullptr); + static int getJsonLineNumber(const QString &filepath, const QString &searchText); + // Returns the 1-indexed line number for the definition of scriptLabel in the scripts file at filePath. // Returns 0 if a definition for scriptLabel cannot be found. static int getScriptLineNumber(const QString &filePath, const QString &scriptLabel); diff --git a/include/editor.h b/include/editor.h index 432084e8..40e0d1c5 100644 --- a/include/editor.h +++ b/include/editor.h @@ -184,6 +184,8 @@ public: void shouldReselectEvents(); void scaleMapView(int); static void openInTextEditor(const QString &path, int lineNum = 0); + void openMapJson(const QString &mapName) const; + void openLayoutJson(const QString &layoutId) const; void setCollisionGraphics(); enum ZValue { diff --git a/include/project.h b/include/project.h index 8b739858..33f29a11 100644 --- a/include/project.h +++ b/include/project.h @@ -218,7 +218,7 @@ public: static QString getScriptFileExtension(bool usePoryScript); QString getScriptDefaultString(bool usePoryScript, QString mapName) const; - QStringList getEventScriptsFilePaths() const; + QStringList getEventScriptsFilepaths() const; void insertGlobalScriptLabels(QStringList &scriptLabels) const; QString getDefaultPrimaryTilesetLabel() const; diff --git a/src/core/map.cpp b/src/core/map.cpp index c1905f0a..0292c7f5 100644 --- a/src/core/map.cpp +++ b/src/core/map.cpp @@ -142,13 +142,13 @@ void Map::invalidateScripts() { QStringList Map::getScriptLabels(Event::Group group) { if (!m_scriptsLoaded) { - const QString scriptsFilePath = getScriptsFilePath(); - m_scriptLabels = ParseUtil::getGlobalScriptLabels(scriptsFilePath); + const QString scriptsFilepath = getScriptsFilepath(); + m_scriptLabels = ParseUtil::getGlobalScriptLabels(scriptsFilepath); m_scriptsLoaded = true; // Track the scripts file for changes. Path may have changed, so stop tracking old files. m_scriptFileWatcher->removePaths(m_scriptFileWatcher->files()); - m_scriptFileWatcher->addPath(scriptsFilePath); + m_scriptFileWatcher->addPath(scriptsFilepath); } QStringList scriptLabels = m_scriptLabels; @@ -167,7 +167,7 @@ QStringList Map::getScriptLabels(Event::Group group) { return scriptLabels; } -QString Map::getScriptsFilePath() const { +QString Map::getScriptsFilepath() const { const bool usePoryscript = projectConfig.usePoryScript; auto path = QDir::cleanPath(QString("%1/%2/%3/scripts") .arg(projectConfig.projectDir) @@ -180,6 +180,13 @@ QString Map::getScriptsFilePath() const { return path; } +QString Map::getJsonFilepath(const QString &mapName) { + return QDir::cleanPath(QString("%1/%2/%3/map.json") + .arg(projectConfig.projectDir) + .arg(projectConfig.getFilePath(ProjectFilePath::data_map_folders)) + .arg(mapName)); +} + void Map::resetEvents() { m_events[Event::Group::Object].clear(); m_events[Event::Group::Warp].clear(); diff --git a/src/core/parseutil.cpp b/src/core/parseutil.cpp index 80252c13..27dc8c0d 100644 --- a/src/core/parseutil.cpp +++ b/src/core/parseutil.cpp @@ -819,14 +819,26 @@ bool ParseUtil::jsonToBool(const QJsonValue &value, bool * ok) { return false; } -int ParseUtil::getScriptLineNumber(const QString &filePath, const QString &scriptLabel) { +int ParseUtil::getJsonLineNumber(const QString &filepath, const QString &searchText) { + if (searchText.isEmpty()) + return 0; + + const QString text = readTextFile(filepath); + int index = text.indexOf(searchText); + if (index < 0) + return 0; + + return text.left(index).count('\n') + 1; +} + +int ParseUtil::getScriptLineNumber(const QString &filepath, const QString &scriptLabel) { if (scriptLabel.isEmpty()) return 0; - if (filePath.endsWith(".inc") || filePath.endsWith(".s")) - return getRawScriptLineNumber(readTextFile(filePath), scriptLabel); - else if (filePath.endsWith(".pory")) - return getPoryScriptLineNumber(readTextFile(filePath), scriptLabel); + if (filepath.endsWith(".inc") || filepath.endsWith(".s")) + return getRawScriptLineNumber(readTextFile(filepath), scriptLabel); + else if (filepath.endsWith(".pory")) + return getPoryScriptLineNumber(readTextFile(filepath), scriptLabel); return 0; } diff --git a/src/editor.cpp b/src/editor.cpp index f5759e35..eb465ff1 100644 --- a/src/editor.cpp +++ b/src/editor.cpp @@ -2272,13 +2272,13 @@ void Editor::deleteSelectedEvents() { } void Editor::openMapScripts() const { - openInTextEditor(map->getScriptsFilePath()); + openInTextEditor(map->getScriptsFilepath()); } void Editor::openScript(const QString &scriptLabel) const { // Find the location of scriptLabel. - QStringList scriptPaths(map->getScriptsFilePath()); - scriptPaths << project->getEventScriptsFilePaths(); + QStringList scriptPaths(map->getScriptsFilepath()); + scriptPaths << project->getEventScriptsFilepaths(); int lineNum = 0; QString scriptPath = scriptPaths.first(); for (const auto &path : scriptPaths) { @@ -2292,6 +2292,16 @@ void Editor::openScript(const QString &scriptLabel) const { openInTextEditor(scriptPath, lineNum); } +void Editor::openMapJson(const QString &mapName) const { + openInTextEditor(Map::getJsonFilepath(mapName)); +} + +void Editor::openLayoutJson(const QString &layoutId) const { + QString path = QDir::cleanPath(QString("%1/%2").arg(projectConfig.projectDir).arg(projectConfig.getFilePath(ProjectFilePath::json_layouts))); + QString idField = QString("\"id\": \"%1\",").arg(layoutId); + openInTextEditor(path, ParseUtil::getJsonLineNumber(path, idField)); +} + void Editor::openInTextEditor(const QString &path, int lineNum) { QString command = porymapConfig.textEditorGotoLine; if (command.isEmpty()) { diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 8ad5081c..55a42b64 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -1415,6 +1415,9 @@ void MainWindow::onOpenMapListContextMenu(const QPoint &point) { if (itemType == "map_name") { // Right-clicking on a map. openItemAction = menu.addAction("Open Map"); + connect(menu.addAction("Open JSON file"), &QAction::triggered, [this, itemName] { + this->editor->openMapJson(itemName); + }); menu.addSeparator(); copyListNameAction = menu.addAction("Copy Map Name"); copyToolTipAction = menu.addAction("Copy Map ID"); @@ -1442,6 +1445,9 @@ void MainWindow::onOpenMapListContextMenu(const QPoint &point) { } else if (itemType == "map_layout") { // Right-clicking on a map layout openItemAction = menu.addAction("Open Layout"); + connect(menu.addAction("Open JSON file"), &QAction::triggered, [this, itemName] { + this->editor->openLayoutJson(itemName); + }); menu.addSeparator(); copyListNameAction = menu.addAction("Copy Layout Name"); copyToolTipAction = menu.addAction("Copy Layout ID"); diff --git a/src/project.cpp b/src/project.cpp index ec2a8a6f..f2eb3281 100644 --- a/src/project.cpp +++ b/src/project.cpp @@ -330,7 +330,7 @@ QSet Project::getTopLevelMapFields() const { } bool Project::readMapJson(const QString &mapName, QJsonDocument * out) { - const QString mapFilepath = QString("%1%2/map.json").arg(projectConfig.getFilePath(ProjectFilePath::data_map_folders)).arg(mapName); + const QString mapFilepath = Map::getJsonFilepath(mapName); watchFile(mapFilepath); QString error; if (!parser.tryParseJsonFile(out, mapFilepath, &error)) { @@ -757,7 +757,11 @@ bool Project::saveMapLayouts() { } void Project::watchFile(const QString &filename) { - this->fileWatcher.addPath(QString("%1/%2").arg(this->root).arg(filename)); + if (!filename.startsWith(this->root)) { + this->fileWatcher.addPath(QString("%1/%2").arg(this->root).arg(filename)); + } else { + this->fileWatcher.addPath(filename); + } } void Project::watchFiles(const QStringList &filenames) { @@ -1284,7 +1288,7 @@ bool Project::saveMap(Map *map, bool skipLayout) { } // Create map.json for map data. - QString mapFilepath = fullPath + "/map.json"; + QString mapFilepath = map->getJsonFilepath(); QFile mapFile(mapFilepath); if (!mapFile.open(QIODevice::WriteOnly)) { logError(QString("Could not open '%1' for writing: %2").arg(mapFilepath).arg(mapFile.errorString())); @@ -2930,7 +2934,7 @@ bool Project::readEventScriptLabels() { this->globalScriptLabels.clear(); if (porymapConfig.loadAllEventScripts) { - for (const auto &filePath : getEventScriptsFilePaths()) + for (const auto &filePath : getEventScriptsFilepaths()) this->globalScriptLabels << ParseUtil::getGlobalScriptLabels(filePath); this->globalScriptLabels.sort(Qt::CaseInsensitive); @@ -2973,7 +2977,7 @@ QString Project::getScriptDefaultString(bool usePoryScript, QString mapName) con return QString("%1_MapScripts::\n\t.byte 0\n").arg(mapName); } -QStringList Project::getEventScriptsFilePaths() const { +QStringList Project::getEventScriptsFilepaths() const { QStringList filePaths(QDir::cleanPath(root + "/" + projectConfig.getFilePath(ProjectFilePath::data_event_scripts))); const QString scriptsDir = QDir::cleanPath(root + "/" + projectConfig.getFilePath(ProjectFilePath::data_scripts_folders)); const QString mapsDir = QDir::cleanPath(root + "/" + projectConfig.getFilePath(ProjectFilePath::data_map_folders));