From e57a67aa5d79a0abbc54ceb6bb41e44f1a52191a Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Tue, 4 Feb 2025 13:29:13 +0100 Subject: [PATCH] Enable the drag and drop of a folder, which will add all files contained within --- ext/ghoul | 2 +- src/engine/openspaceengine.cpp | 103 ++++++++++++++++++++--------- src/scripting/scriptengine_lua.inl | 46 +++++-------- 3 files changed, 88 insertions(+), 63 deletions(-) diff --git a/ext/ghoul b/ext/ghoul index 96bf82e968..ba78ba69af 160000 --- a/ext/ghoul +++ b/ext/ghoul @@ -1 +1 @@ -Subproject commit 96bf82e9682ab924479fa72470e42f9a36f7ca60 +Subproject commit ba78ba69afcf737664e86152cbfb9ce86bb1ee98 diff --git a/src/engine/openspaceengine.cpp b/src/engine/openspaceengine.cpp index 67a612fa62..3787ed573e 100644 --- a/src/engine/openspaceengine.cpp +++ b/src/engine/openspaceengine.cpp @@ -1521,16 +1521,6 @@ void OpenSpaceEngine::touchExitCallback(TouchInput input) { } void OpenSpaceEngine::handleDragDrop(std::filesystem::path file) { - const ghoul::lua::LuaState s; - const std::filesystem::path path = absPath("${SCRIPTS}/drag_drop_handler.lua"); - const std::string p = path.string(); - int status = luaL_loadfile(s, p.c_str()); - if (status != LUA_OK) { - const std::string error = lua_tostring(s, -1); - LERROR(error); - return; - } - #ifdef WIN32 if (file.extension() == ".lnk") { LDEBUG(std::format("Replacing shell link path '{}'", file)); @@ -1538,33 +1528,84 @@ void OpenSpaceEngine::handleDragDrop(std::filesystem::path file) { } #endif // WIN32 - ghoul::lua::push(s, file); - lua_setglobal(s, "filename"); + const ghoul::lua::LuaState s; - std::filesystem::path basename = file.filename(); - ghoul::lua::push(s, std::move(basename)); - lua_setglobal(s, "basename"); + // This function will handle a specific file by providing the Lua script with + // information about the dropped file and then executing the drag_drop handler. The + // function returns whether the file was a valid drop target + auto handleFile = [&s](std::filesystem::path f) -> bool { + const std::filesystem::path path = absPath("${SCRIPTS}/drag_drop_handler.lua"); + const std::string p = path.string(); + int status = luaL_loadfile(s, p.c_str()); + if (status != LUA_OK) { + const std::string error = lua_tostring(s, -1); + LERROR(error); + return false; + } - std::string extension = file.extension().string(); - extension = ghoul::toLowerCase(extension); +#ifdef WIN32 + if (f.extension() == ".lnk") { + LDEBUG(std::format("Replacing shell link path '{}'", f)); + f = FileSys.resolveShellLink(f); + } +#endif // WIN32 - ghoul::lua::push(s, extension); - lua_setglobal(s, "extension"); + ghoul::lua::push(s, f); + lua_setglobal(s, "filename"); - status = lua_pcall(s, 0, 1, 0); - if (status != LUA_OK) { - const std::string error = lua_tostring(s, -1); - LERROR(error); - return; + std::filesystem::path basename = f.filename(); + ghoul::lua::push(s, std::move(basename)); + lua_setglobal(s, "basename"); + + std::string extension = f.extension().string(); + extension = ghoul::toLowerCase(extension); + + ghoul::lua::push(s, extension); + lua_setglobal(s, "extension"); + + int callStatus = lua_pcall(s, 0, 1, 0); + if (callStatus != LUA_OK) { + const std::string error = lua_tostring(s, -1); + LERROR(error); + } + + if (ghoul::lua::hasValue(s)) { + std::string script = ghoul::lua::value(s); + global::scriptEngine->queueScript(std::move(script)); + lua_settop(s, 0); + return true; + } + else { + lua_settop(s, 0); + return false; + } + }; + + if (std::filesystem::is_regular_file(file)) { + // If we have a single file, we can just execute it directly + const bool success = handleFile(file); + if (!success) { + LWARNING(std::format("Unhandled file dropped: {}", file)); + } } - - if (lua_isnil(s, -1)) { - LWARNING(std::format("Unhandled file dropped: {}", file)); - return; + else if (std::filesystem::is_directory(file)) { + // If the file is a directory, we want to recursively get all files and handle + // each of the files contained in the directory + std::vector files = ghoul::filesystem::walkDirectory( + file, + true, + false, + [](const std::filesystem::path& f) { + return std::filesystem::is_regular_file(f); + } + ); + for (const std::filesystem::path& f : files) { + // We ignore the return value here on purpose as we don't want to spam the log + // with potential uninteresting messages about every file that was not a valid + // target for a drag and drop operation + handleFile(f); + } } - - std::string script = ghoul::lua::value(s); - global::scriptEngine->queueScript(std::move(script)); } std::vector OpenSpaceEngine::encode() { diff --git a/src/scripting/scriptengine_lua.inl b/src/scripting/scriptengine_lua.inl index 0e24921205..5efbb088e8 100644 --- a/src/scripting/scriptengine_lua.inl +++ b/src/scripting/scriptengine_lua.inl @@ -143,34 +143,6 @@ namespace { } } -std::vector walkCommon(const std::filesystem::path& path, - bool recursive, bool sorted, - std::function filter) -{ - namespace fs = std::filesystem; - std::vector result; - if (fs::is_directory(path)) { - if (recursive) { - for (fs::directory_entry e : fs::recursive_directory_iterator(path)) { - if (filter(e)) { - result.push_back(e.path()); - } - } - } - else { - for (fs::directory_entry e : fs::directory_iterator(path)) { - if (filter(e)) { - result.push_back(e.path()); - } - } - } - } - if (sorted) { - std::sort(result.begin(), result.end()); - } - return result; -} - /** * Walks a directory and returns the contents of the directory as absolute paths. The * first argument is the path of the directory that should be walked, the second argument @@ -183,8 +155,12 @@ std::vector walkCommon(const std::filesystem::path& path, bool recursive = false, bool sorted = false) { + if (!std::filesystem::exists(path) && !std::filesystem::is_directory(path)) { + return std::vector(); + } + namespace fs = std::filesystem; - return walkCommon( + return ghoul::filesystem::walkDirectory( path, recursive, sorted, @@ -204,8 +180,12 @@ std::vector walkCommon(const std::filesystem::path& path, bool recursive = false, bool sorted = false) { + if (!std::filesystem::exists(path) && !std::filesystem::is_directory(path)) { + return std::vector(); + } + namespace fs = std::filesystem; - return walkCommon( + return ghoul::filesystem::walkDirectory( path, recursive, sorted, @@ -225,8 +205,12 @@ std::vector walkCommon(const std::filesystem::path& path, bool recursive = false, bool sorted = false) { + if (!std::filesystem::exists(path) && !std::filesystem::is_directory(path)) { + return std::vector(); + } + namespace fs = std::filesystem; - return walkCommon( + return ghoul::filesystem::walkDirectory( path, recursive, sorted,