3939#include < OvUI/Widgets/Buttons/Button.h>
4040#include < OvUI/Widgets/Layout/Group.h>
4141#include < OvUI/Widgets/Texts/TextClickable.h>
42+ #include < OvUI/Widgets/Texts/TextColored.h>
4243#include < OvUI/Widgets/Visual/Image.h>
4344#include < OvUI/Widgets/Visual/Separator.h>
4445
@@ -135,6 +136,15 @@ namespace
135136 return !relativePath.empty () && *relativePath.begin () != " .." ;
136137 }
137138
139+ bool ValidateFolderPath (const std::filesystem::path& p_path, const std::string& p_actionName)
140+ {
141+ if (std::filesystem::exists (p_path) && std::filesystem::is_directory (p_path))
142+ return true ;
143+
144+ OVLOG_ERROR (std::format (" Cannot perform '{}' because the target folder was deleted externally" , p_actionName));
145+ return false ;
146+ }
147+
138148 class TexturePreview : public OvUI ::Plugins::IPlugin
139149 {
140150 private:
@@ -185,6 +195,13 @@ namespace
185195 nameEditor.selectAllOnClick = true ;
186196
187197 renameMenu.ClickedEvent +=[this , &nameEditor] {
198+ // Check if the item still exists before allowing rename
199+ if (!std::filesystem::exists (filePath))
200+ {
201+ OVLOG_ERROR (" Cannot rename this item because it was deleted externally" );
202+ return ;
203+ }
204+
188205 nameEditor.content = filePath.stem ().string ();
189206
190207 if (!std::filesystem::is_directory (filePath))
@@ -198,6 +215,12 @@ namespace
198215
199216 nameEditor.EnterPressedEvent += [this ](std::string p_newName)
200217 {
218+ if (!std::filesystem::exists (filePath))
219+ {
220+ OVLOG_ERROR (" Cannot complete rename because the item was deleted externally" );
221+ return ;
222+ }
223+
201224 if (!std::filesystem::is_directory (filePath))
202225 {
203226 p_newName += filePath.extension ().string ();
@@ -257,6 +280,9 @@ namespace
257280
258281 void CreateNewShader (const std::string& p_shaderName, std::optional<const std::string_view> p_type)
259282 {
283+ if (!ValidateFolderPath (filePath, " Create shader" ))
284+ return ;
285+
260286 const auto finalPath = FindAvailableFilePath (filePath / (p_shaderName + " .ovfx" ));
261287
262288 if (p_type.has_value ())
@@ -296,6 +322,9 @@ namespace
296322 std::optional<std::function<void (OvCore::Resources::Material&)>> p_setupCallback
297323 )
298324 {
325+ if (!ValidateFolderPath (filePath, " Create material" ))
326+ return ;
327+
299328 OvCore::Resources::Material material;
300329
301330 if (p_type.has_value ())
@@ -342,6 +371,8 @@ namespace
342371 auto & showInExplorer = CreateWidget<OvUI::Widgets::Menu::MenuItem>(" Show in explorer" );
343372 showInExplorer.ClickedEvent += [this ]
344373 {
374+ if (!ValidateFolderPath (filePath, " Show in explorer" ))
375+ return ;
345376 OvTools::Utils::SystemCalls::ShowInExplorer (filePath.string ());
346377 };
347378
@@ -350,6 +381,9 @@ namespace
350381 auto & importAssetHere = CreateWidget<OvUI::Widgets::Menu::MenuItem>(" Import Here..." );
351382 importAssetHere.ClickedEvent += [this ]
352383 {
384+ if (!ValidateFolderPath (filePath, " Import" ))
385+ return ;
386+
353387 if (EDITOR_EXEC (ImportAssetAtLocation (filePath.string ())))
354388 {
355389 OvUI::Widgets::Layout::TreeNode* pluginOwner = reinterpret_cast <OvUI::Widgets::Layout::TreeNode*>(userData);
@@ -412,13 +446,17 @@ namespace
412446 createAtmosphereMaterialMenu.ClickedEvent += [&createAtmosphereMaterial] { createAtmosphereMaterial.content = " " ; };
413447
414448 createFolder.EnterPressedEvent += [this ](std::string newFolderName) {
449+ if (!ValidateFolderPath (filePath, " Create folder" ))
450+ return ;
415451 const auto finalPath = FindAvailableFilePath (filePath / newFolderName);
416452 std::filesystem::create_directory (finalPath);
417453 ItemAddedEvent.Invoke (finalPath);
418454 Close ();
419455 };
420456
421457 createScene.EnterPressedEvent += [this ](std::string newSceneName) {
458+ if (!ValidateFolderPath (filePath, " Create scene" ))
459+ return ;
422460 const auto finalPath = FindAvailableFilePath (filePath / (newSceneName + " .ovscene" ));
423461
424462 auto emptyScene = OvCore::SceneSystem::Scene{};
@@ -432,6 +470,8 @@ namespace
432470 };
433471
434472 createPartialShader.EnterPressedEvent += [this ](std::string newShaderName) {
473+ if (!ValidateFolderPath (filePath, " Create shader" ))
474+ return ;
435475 const auto finalPath = FindAvailableFilePath (filePath / (newShaderName + " .ovfxh" ));
436476
437477 {
@@ -443,6 +483,8 @@ namespace
443483 };
444484
445485 createScript.EnterPressedEvent += [this ](std::string p_newName) {
486+ if (!ValidateFolderPath (filePath, " Create script" ))
487+ return ;
446488 std::erase_if (p_newName, [](char c) {
447489 return std::find (kAllowedFilenameChars .begin (), kAllowedFilenameChars .end (), c) == kAllowedFilenameChars .end ();
448490 });
@@ -507,8 +549,9 @@ namespace
507549 {
508550 EDITOR_EXEC (PropagateFolderDestruction (filePath.string ()));
509551 std::filesystem::remove_all (filePath);
510- DestroyedEvent.Invoke (filePath);
511552 }
553+
554+ DestroyedEvent.Invoke (filePath);
512555 }
513556 }
514557
@@ -1045,6 +1088,13 @@ void OvEditor::Panels::AssetBrowser::ConsiderItem(OvUI::Widgets::Layout::TreeNod
10451088 treeNode.OpenedEvent += [this , &treeNode, path, p_isEngineItem] {
10461089 treeNode.RemoveAllWidgets ();
10471090 std::filesystem::path updatedPath = std::filesystem::path{path}.parent_path () / treeNode.name ;
1091+
1092+ if (!std::filesystem::exists (updatedPath) || !std::filesystem::is_directory (updatedPath))
1093+ {
1094+ OVLOG_ERROR (" Folder was deleted externally: " + updatedPath.string ());
1095+ return ;
1096+ }
1097+
10481098 ParseFolder (treeNode, std::filesystem::directory_entry (updatedPath), p_isEngineItem);
10491099 };
10501100
0 commit comments