From 57e164d45c641c5fdd4b3d0c09557d6a697c5047 Mon Sep 17 00:00:00 2001 From: Syny Date: Fri, 17 Apr 2026 14:56:06 -0400 Subject: [PATCH 1/4] fix crash expand on deleted folder --- .../OvEditor/src/OvEditor/Panels/AssetBrowser.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/Sources/OvEditor/src/OvEditor/Panels/AssetBrowser.cpp b/Sources/OvEditor/src/OvEditor/Panels/AssetBrowser.cpp index 01ca8fe62..42ebe02e1 100644 --- a/Sources/OvEditor/src/OvEditor/Panels/AssetBrowser.cpp +++ b/Sources/OvEditor/src/OvEditor/Panels/AssetBrowser.cpp @@ -38,6 +38,7 @@ #include #include #include +#include #include #include @@ -1060,6 +1061,18 @@ void OvEditor::Panels::AssetBrowser::ConsiderItem(OvUI::Widgets::Layout::TreeNod treeNode.OpenedEvent += [this, &treeNode, path, p_isEngineItem] { treeNode.RemoveAllWidgets(); std::filesystem::path updatedPath = std::filesystem::path{path}.parent_path() / treeNode.name; + + // Check if the directory still exists + if (!std::filesystem::exists(updatedPath) || !std::filesystem::is_directory(updatedPath)) + { + // Show error message to the user + auto& errorText = treeNode.CreateWidget( + "[MISSING] Folder was deleted externally", + OvUI::Types::Color{1.0f, 0.3f, 0.3f, 1.0f} + ); + return; + } + ParseFolder(treeNode, std::filesystem::directory_entry(updatedPath), p_isEngineItem); }; From e46334d50fede30fd0b5aa7db307ee9870fd0bd6 Mon Sep 17 00:00:00 2001 From: Syny Date: Fri, 17 Apr 2026 15:13:07 -0400 Subject: [PATCH 2/4] deleting a deleted externally folder removes it from the asset browser --- Sources/OvEditor/src/OvEditor/Panels/AssetBrowser.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Sources/OvEditor/src/OvEditor/Panels/AssetBrowser.cpp b/Sources/OvEditor/src/OvEditor/Panels/AssetBrowser.cpp index 42ebe02e1..07ba75b06 100644 --- a/Sources/OvEditor/src/OvEditor/Panels/AssetBrowser.cpp +++ b/Sources/OvEditor/src/OvEditor/Panels/AssetBrowser.cpp @@ -507,8 +507,9 @@ namespace { EDITOR_EXEC(PropagateFolderDestruction(filePath.string())); std::filesystem::remove_all(filePath); - DestroyedEvent.Invoke(filePath); } + + DestroyedEvent.Invoke(filePath); } } From 56f23fe7ba4ff0092e4887fa1d74a60916425f48 Mon Sep 17 00:00:00 2001 From: Syny Date: Fri, 17 Apr 2026 18:54:01 -0400 Subject: [PATCH 3/4] fixed context menu operation on deleted folder --- .../src/OvEditor/Panels/AssetBrowser.cpp | 77 +++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/Sources/OvEditor/src/OvEditor/Panels/AssetBrowser.cpp b/Sources/OvEditor/src/OvEditor/Panels/AssetBrowser.cpp index dbe4f0133..ed4b8beba 100644 --- a/Sources/OvEditor/src/OvEditor/Panels/AssetBrowser.cpp +++ b/Sources/OvEditor/src/OvEditor/Panels/AssetBrowser.cpp @@ -136,6 +136,27 @@ namespace return !relativePath.empty() && *relativePath.begin() != ".."; } + bool ShowPathDeletedError(const std::string& p_actionName) + { + if (!std::filesystem::exists(std::filesystem::path(p_actionName))) + { + using namespace OvWindowing::Dialogs; + MessageBox errorMessage( + "Action failed", + "Cannot perform this action because the target folder was deleted externally", + MessageBox::EMessageType::ERROR, + MessageBox::EButtonLayout::OK + ); + return true; + } + return false; + } + + bool ValidateFolderPath(const std::filesystem::path& p_path) + { + return std::filesystem::exists(p_path) && std::filesystem::is_directory(p_path); + } + class TexturePreview : public OvUI::Plugins::IPlugin { private: @@ -186,6 +207,19 @@ namespace nameEditor.selectAllOnClick = true; renameMenu.ClickedEvent +=[this, &nameEditor] { + // Check if the item still exists before allowing rename + if (!std::filesystem::exists(filePath)) + { + using namespace OvWindowing::Dialogs; + MessageBox errorMessage( + "Rename failed", + "Cannot rename this item because it was deleted externally", + MessageBox::EMessageType::ERROR, + MessageBox::EButtonLayout::OK + ); + return; + } + nameEditor.content = filePath.stem().string(); if (!std::filesystem::is_directory(filePath)) @@ -258,6 +292,12 @@ namespace void CreateNewShader(const std::string& p_shaderName, std::optional p_type) { + if (!ValidateFolderPath(filePath)) + { + ShowPathDeletedError("Create shader"); + return; + } + const auto finalPath = FindAvailableFilePath(filePath / (p_shaderName + ".ovfx")); if (p_type.has_value()) @@ -297,6 +337,12 @@ namespace std::optional> p_setupCallback ) { + if (!ValidateFolderPath(filePath)) + { + ShowPathDeletedError("Create material"); + return; + } + OvCore::Resources::Material material; if (p_type.has_value()) @@ -343,6 +389,11 @@ namespace auto& showInExplorer = CreateWidget("Show in explorer"); showInExplorer.ClickedEvent += [this] { + if (!ValidateFolderPath(filePath)) + { + ShowPathDeletedError("Show in explorer"); + return; + } OvTools::Utils::SystemCalls::ShowInExplorer(filePath.string()); }; @@ -351,6 +402,12 @@ namespace auto& importAssetHere = CreateWidget("Import Here..."); importAssetHere.ClickedEvent += [this] { + if (!ValidateFolderPath(filePath)) + { + ShowPathDeletedError("Import"); + return; + } + if (EDITOR_EXEC(ImportAssetAtLocation(filePath.string()))) { OvUI::Widgets::Layout::TreeNode* pluginOwner = reinterpret_cast(userData); @@ -413,6 +470,11 @@ namespace createAtmosphereMaterialMenu.ClickedEvent += [&createAtmosphereMaterial] { createAtmosphereMaterial.content = ""; }; createFolder.EnterPressedEvent += [this](std::string newFolderName) { + if (!ValidateFolderPath(filePath)) + { + ShowPathDeletedError("Create folder"); + return; + } const auto finalPath = FindAvailableFilePath(filePath / newFolderName); std::filesystem::create_directory(finalPath); ItemAddedEvent.Invoke(finalPath); @@ -420,6 +482,11 @@ namespace }; createScene.EnterPressedEvent += [this](std::string newSceneName) { + if (!ValidateFolderPath(filePath)) + { + ShowPathDeletedError("Create scene"); + return; + } const auto finalPath = FindAvailableFilePath(filePath / (newSceneName + ".ovscene")); auto emptyScene = OvCore::SceneSystem::Scene{}; @@ -433,6 +500,11 @@ namespace }; createPartialShader.EnterPressedEvent += [this](std::string newShaderName) { + if (!ValidateFolderPath(filePath)) + { + ShowPathDeletedError("Create shader"); + return; + } const auto finalPath = FindAvailableFilePath(filePath / (newShaderName + ".ovfxh")); { @@ -444,6 +516,11 @@ namespace }; createScript.EnterPressedEvent += [this](std::string p_newName) { + if (!ValidateFolderPath(filePath)) + { + ShowPathDeletedError("Create script"); + return; + } std::erase_if(p_newName, [](char c) { return std::find(kAllowedFilenameChars.begin(), kAllowedFilenameChars.end(), c) == kAllowedFilenameChars.end(); }); From cf6804eaab4086371a0ef50be34e6848e19faff3 Mon Sep 17 00:00:00 2001 From: Syny Date: Sat, 18 Apr 2026 15:01:38 -0400 Subject: [PATCH 4/4] ovlog_error - rename no longer crashes --- .../src/OvEditor/Panels/AssetBrowser.cpp | 81 +++++-------------- 1 file changed, 20 insertions(+), 61 deletions(-) diff --git a/Sources/OvEditor/src/OvEditor/Panels/AssetBrowser.cpp b/Sources/OvEditor/src/OvEditor/Panels/AssetBrowser.cpp index ed4b8beba..1434881a8 100644 --- a/Sources/OvEditor/src/OvEditor/Panels/AssetBrowser.cpp +++ b/Sources/OvEditor/src/OvEditor/Panels/AssetBrowser.cpp @@ -136,25 +136,13 @@ namespace return !relativePath.empty() && *relativePath.begin() != ".."; } - bool ShowPathDeletedError(const std::string& p_actionName) + bool ValidateFolderPath(const std::filesystem::path& p_path, const std::string& p_actionName) { - if (!std::filesystem::exists(std::filesystem::path(p_actionName))) - { - using namespace OvWindowing::Dialogs; - MessageBox errorMessage( - "Action failed", - "Cannot perform this action because the target folder was deleted externally", - MessageBox::EMessageType::ERROR, - MessageBox::EButtonLayout::OK - ); + if (std::filesystem::exists(p_path) && std::filesystem::is_directory(p_path)) return true; - } - return false; - } - bool ValidateFolderPath(const std::filesystem::path& p_path) - { - return std::filesystem::exists(p_path) && std::filesystem::is_directory(p_path); + OVLOG_ERROR(std::format("Cannot perform '{}' because the target folder was deleted externally", p_actionName)); + return false; } class TexturePreview : public OvUI::Plugins::IPlugin @@ -210,13 +198,7 @@ namespace // Check if the item still exists before allowing rename if (!std::filesystem::exists(filePath)) { - using namespace OvWindowing::Dialogs; - MessageBox errorMessage( - "Rename failed", - "Cannot rename this item because it was deleted externally", - MessageBox::EMessageType::ERROR, - MessageBox::EButtonLayout::OK - ); + OVLOG_ERROR("Cannot rename this item because it was deleted externally"); return; } @@ -233,6 +215,12 @@ namespace nameEditor.EnterPressedEvent += [this](std::string p_newName) { + if (!std::filesystem::exists(filePath)) + { + OVLOG_ERROR("Cannot complete rename because the item was deleted externally"); + return; + } + if (!std::filesystem::is_directory(filePath)) { p_newName += filePath.extension().string(); @@ -292,11 +280,8 @@ namespace void CreateNewShader(const std::string& p_shaderName, std::optional p_type) { - if (!ValidateFolderPath(filePath)) - { - ShowPathDeletedError("Create shader"); + if (!ValidateFolderPath(filePath, "Create shader")) return; - } const auto finalPath = FindAvailableFilePath(filePath / (p_shaderName + ".ovfx")); @@ -337,11 +322,8 @@ namespace std::optional> p_setupCallback ) { - if (!ValidateFolderPath(filePath)) - { - ShowPathDeletedError("Create material"); + if (!ValidateFolderPath(filePath, "Create material")) return; - } OvCore::Resources::Material material; @@ -389,11 +371,8 @@ namespace auto& showInExplorer = CreateWidget("Show in explorer"); showInExplorer.ClickedEvent += [this] { - if (!ValidateFolderPath(filePath)) - { - ShowPathDeletedError("Show in explorer"); + if (!ValidateFolderPath(filePath, "Show in explorer")) return; - } OvTools::Utils::SystemCalls::ShowInExplorer(filePath.string()); }; @@ -402,11 +381,8 @@ namespace auto& importAssetHere = CreateWidget("Import Here..."); importAssetHere.ClickedEvent += [this] { - if (!ValidateFolderPath(filePath)) - { - ShowPathDeletedError("Import"); + if (!ValidateFolderPath(filePath, "Import")) return; - } if (EDITOR_EXEC(ImportAssetAtLocation(filePath.string()))) { @@ -470,11 +446,8 @@ namespace createAtmosphereMaterialMenu.ClickedEvent += [&createAtmosphereMaterial] { createAtmosphereMaterial.content = ""; }; createFolder.EnterPressedEvent += [this](std::string newFolderName) { - if (!ValidateFolderPath(filePath)) - { - ShowPathDeletedError("Create folder"); + if (!ValidateFolderPath(filePath, "Create folder")) return; - } const auto finalPath = FindAvailableFilePath(filePath / newFolderName); std::filesystem::create_directory(finalPath); ItemAddedEvent.Invoke(finalPath); @@ -482,11 +455,8 @@ namespace }; createScene.EnterPressedEvent += [this](std::string newSceneName) { - if (!ValidateFolderPath(filePath)) - { - ShowPathDeletedError("Create scene"); + if (!ValidateFolderPath(filePath, "Create scene")) return; - } const auto finalPath = FindAvailableFilePath(filePath / (newSceneName + ".ovscene")); auto emptyScene = OvCore::SceneSystem::Scene{}; @@ -500,11 +470,8 @@ namespace }; createPartialShader.EnterPressedEvent += [this](std::string newShaderName) { - if (!ValidateFolderPath(filePath)) - { - ShowPathDeletedError("Create shader"); + if (!ValidateFolderPath(filePath, "Create shader")) return; - } const auto finalPath = FindAvailableFilePath(filePath / (newShaderName + ".ovfxh")); { @@ -516,11 +483,8 @@ namespace }; createScript.EnterPressedEvent += [this](std::string p_newName) { - if (!ValidateFolderPath(filePath)) - { - ShowPathDeletedError("Create script"); + if (!ValidateFolderPath(filePath, "Create script")) return; - } std::erase_if(p_newName, [](char c) { return std::find(kAllowedFilenameChars.begin(), kAllowedFilenameChars.end(), c) == kAllowedFilenameChars.end(); }); @@ -1125,14 +1089,9 @@ void OvEditor::Panels::AssetBrowser::ConsiderItem(OvUI::Widgets::Layout::TreeNod treeNode.RemoveAllWidgets(); std::filesystem::path updatedPath = std::filesystem::path{path}.parent_path() / treeNode.name; - // Check if the directory still exists if (!std::filesystem::exists(updatedPath) || !std::filesystem::is_directory(updatedPath)) { - // Show error message to the user - auto& errorText = treeNode.CreateWidget( - "[MISSING] Folder was deleted externally", - OvUI::Types::Color{1.0f, 0.3f, 0.3f, 1.0f} - ); + OVLOG_ERROR("Folder was deleted externally: " + updatedPath.string()); return; }