summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaylily-Zeleen <daylily-zeleen@foxmail.com>2022-12-07 11:33:35 +0800
committerDaylily-Zeleen <daylily-zeleen@foxmail.com>2023-04-25 11:29:32 +0800
commitb12ced0a2693d4983e08716005d4a854fce116f1 (patch)
tree67b799386354d016777ecb2a43e9e43372405632
parent6f1a52b017930afb851691e6852ce40eb93c30a9 (diff)
downloadredot-engine-b12ced0a2693d4983e08716005d4a854fce116f1.tar.gz
Implement and expose OS::shell_show_in_file_manager()
-rw-r--r--core/core_bind.cpp10
-rw-r--r--core/core_bind.h1
-rw-r--r--core/os/os.cpp9
-rw-r--r--core/os/os.h1
-rw-r--r--doc/classes/OS.xml11
-rw-r--r--editor/editor_node.cpp10
-rw-r--r--editor/export/export_template_manager.cpp2
-rw-r--r--editor/filesystem_dock.cpp5
-rw-r--r--editor/gui/editor_file_dialog.cpp5
-rw-r--r--editor/project_manager.cpp2
-rw-r--r--platform/windows/os_windows.cpp45
-rw-r--r--platform/windows/os_windows.h1
12 files changed, 87 insertions, 15 deletions
diff --git a/core/core_bind.cpp b/core/core_bind.cpp
index f2eb7823e2..3fce665763 100644
--- a/core/core_bind.cpp
+++ b/core/core_bind.cpp
@@ -257,6 +257,15 @@ Error OS::shell_open(String p_uri) {
return ::OS::get_singleton()->shell_open(p_uri);
}
+Error OS::shell_show_in_file_manager(String p_path, bool p_open_folder) {
+ if (p_path.begins_with("res://")) {
+ WARN_PRINT("Attempting to explore file path with the \"res://\" protocol. Use `ProjectSettings.globalize_path()` to convert a Godot-specific path to a system path before opening it with `OS.shell_show_in_file_manager()`.");
+ } else if (p_path.begins_with("user://")) {
+ WARN_PRINT("Attempting to explore file path with the \"user://\" protocol. Use `ProjectSettings.globalize_path()` to convert a Godot-specific path to a system path before opening it with `OS.shell_show_in_file_manager()`.");
+ }
+ return ::OS::get_singleton()->shell_show_in_file_manager(p_path, p_open_folder);
+}
+
String OS::read_string_from_stdin() {
return ::OS::get_singleton()->get_stdin_string();
}
@@ -549,6 +558,7 @@ void OS::_bind_methods() {
ClassDB::bind_method(D_METHOD("create_instance", "arguments"), &OS::create_instance);
ClassDB::bind_method(D_METHOD("kill", "pid"), &OS::kill);
ClassDB::bind_method(D_METHOD("shell_open", "uri"), &OS::shell_open);
+ ClassDB::bind_method(D_METHOD("shell_show_in_file_manager", "file_or_dir_path", "open_folder"), &OS::shell_show_in_file_manager, DEFVAL(true));
ClassDB::bind_method(D_METHOD("is_process_running", "pid"), &OS::is_process_running);
ClassDB::bind_method(D_METHOD("get_process_id"), &OS::get_process_id);
diff --git a/core/core_bind.h b/core/core_bind.h
index 675da48591..65e455a92e 100644
--- a/core/core_bind.h
+++ b/core/core_bind.h
@@ -152,6 +152,7 @@ public:
int create_instance(const Vector<String> &p_arguments);
Error kill(int p_pid);
Error shell_open(String p_uri);
+ Error shell_show_in_file_manager(String p_path, bool p_open_folder = true);
bool is_process_running(int p_pid) const;
int get_process_id() const;
diff --git a/core/os/os.cpp b/core/os/os.cpp
index ef7d860d19..7b6c8dc1ca 100644
--- a/core/os/os.cpp
+++ b/core/os/os.cpp
@@ -281,6 +281,15 @@ Error OS::shell_open(String p_uri) {
return ERR_UNAVAILABLE;
}
+Error OS::shell_show_in_file_manager(String p_path, bool p_open_folder) {
+ if (!p_path.begins_with("file://")) {
+ p_path = String("file://") + p_path;
+ }
+ if (!p_path.ends_with("/")) {
+ p_path = p_path.get_base_dir();
+ }
+ return shell_open(p_path);
+}
// implement these with the canvas?
uint64_t OS::get_static_memory_usage() const {
diff --git a/core/os/os.h b/core/os/os.h
index d77890d89d..0201b6edd7 100644
--- a/core/os/os.h
+++ b/core/os/os.h
@@ -163,6 +163,7 @@ public:
virtual void vibrate_handheld(int p_duration_ms = 500) {}
virtual Error shell_open(String p_uri);
+ virtual Error shell_show_in_file_manager(String p_path, bool p_open_folder = true);
virtual Error set_cwd(const String &p_cwd);
virtual bool has_environment(const String &p_var) const = 0;
diff --git a/doc/classes/OS.xml b/doc/classes/OS.xml
index 28c6247338..d34ef6ea11 100644
--- a/doc/classes/OS.xml
+++ b/doc/classes/OS.xml
@@ -639,6 +639,17 @@
[b]Note:[/b] This method is implemented on Android, iOS, Web, Linux, macOS and Windows.
</description>
</method>
+ <method name="shell_show_in_file_manager">
+ <return type="int" enum="Error" />
+ <param index="0" name="file_or_dir_path" type="String" />
+ <param index="1" name="open_folder" type="bool" default="true" />
+ <description>
+ Requests the OS to open file manager, then navigate to the given [param file_or_dir_path] and select the target file or folder.
+ If [param file_or_dir_path] is a valid directory path, and [param open_folder] is [code]true[/code], the method will open explorer and enter the target folder without selecting anything.
+ Use [method ProjectSettings.globalize_path] to convert a [code]res://[/code] or [code]user://[/code] path into a system path for use with this method.
+ [b]Note:[/b] Currently this method is only implemented on Windows. On other platforms, it will fallback to [method shell_open] with a directory path for [param file_or_dir_path].
+ </description>
+ </method>
<method name="unset_environment" qualifiers="const">
<return type="void" />
<param index="0" name="variable" type="String" />
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index f2f1285799..58356a45c4 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -2995,10 +2995,10 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
case RUN_USER_DATA_FOLDER: {
// Ensure_user_data_dir() to prevent the edge case: "Open User Data Folder" won't work after the project was renamed in ProjectSettingsEditor unless the project is saved.
OS::get_singleton()->ensure_user_data_dir();
- OS::get_singleton()->shell_open(String("file://") + OS::get_singleton()->get_user_data_dir());
+ OS::get_singleton()->shell_show_in_file_manager(OS::get_singleton()->get_user_data_dir(), true);
} break;
case FILE_EXPLORE_ANDROID_BUILD_TEMPLATES: {
- OS::get_singleton()->shell_open("file://" + ProjectSettings::get_singleton()->get_resource_path().path_join("android"));
+ OS::get_singleton()->shell_show_in_file_manager(ProjectSettings::get_singleton()->get_resource_path().path_join("android"), true);
} break;
case FILE_QUIT:
case RUN_PROJECT_MANAGER:
@@ -3070,10 +3070,10 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
editor_settings_dialog->popup_edit_settings();
} break;
case SETTINGS_EDITOR_DATA_FOLDER: {
- OS::get_singleton()->shell_open(String("file://") + EditorPaths::get_singleton()->get_data_dir());
+ OS::get_singleton()->shell_show_in_file_manager(EditorPaths::get_singleton()->get_data_dir(), true);
} break;
case SETTINGS_EDITOR_CONFIG_FOLDER: {
- OS::get_singleton()->shell_open(String("file://") + EditorPaths::get_singleton()->get_config_dir());
+ OS::get_singleton()->shell_show_in_file_manager(EditorPaths::get_singleton()->get_config_dir(), true);
} break;
case SETTINGS_MANAGE_EXPORT_TEMPLATES: {
export_template_manager->popup_manager();
@@ -3176,7 +3176,7 @@ void EditorNode::_screenshot(bool p_use_utc) {
NodePath path = String("user://") + name;
_save_screenshot(path);
if (EDITOR_GET("interface/editor/automatically_open_screenshots")) {
- OS::get_singleton()->shell_open(String("file://") + ProjectSettings::get_singleton()->globalize_path(path));
+ OS::get_singleton()->shell_show_in_file_manager(ProjectSettings::get_singleton()->globalize_path(path), true);
}
}
diff --git a/editor/export/export_template_manager.cpp b/editor/export/export_template_manager.cpp
index 725dc1d6bb..e551b0531a 100644
--- a/editor/export/export_template_manager.cpp
+++ b/editor/export/export_template_manager.cpp
@@ -620,7 +620,7 @@ void ExportTemplateManager::_installed_table_button_cbk(Object *p_item, int p_co
void ExportTemplateManager::_open_template_folder(const String &p_version) {
const String &templates_dir = EditorPaths::get_singleton()->get_export_templates_dir();
- OS::get_singleton()->shell_open("file://" + templates_dir.path_join(p_version));
+ OS::get_singleton()->shell_show_in_file_manager(templates_dir.path_join(p_version), true);
}
void ExportTemplateManager::popup_manager() {
diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp
index 066e8cb84e..445a54e346 100644
--- a/editor/filesystem_dock.cpp
+++ b/editor/filesystem_dock.cpp
@@ -1881,11 +1881,8 @@ void FileSystemDock::_file_option(int p_option, const Vector<String> &p_selected
fpath = p_selected[0];
}
- if (!fpath.ends_with("/")) {
- fpath = fpath.get_base_dir();
- }
String dir = ProjectSettings::get_singleton()->globalize_path(fpath);
- OS::get_singleton()->shell_open(String("file://") + dir);
+ OS::get_singleton()->shell_show_in_file_manager(dir, true);
} break;
case FILE_OPEN_EXTERNAL: {
diff --git a/editor/gui/editor_file_dialog.cpp b/editor/gui/editor_file_dialog.cpp
index 62e0520799..a7ddb984e0 100644
--- a/editor/gui/editor_file_dialog.cpp
+++ b/editor/gui/editor_file_dialog.cpp
@@ -713,11 +713,8 @@ void EditorFileDialog::_item_menu_id_pressed(int p_option) {
// Specific item was clicked. Open folders directly, or the folder containing a selected file.
Dictionary item_meta = item_list->get_item_metadata(idx);
path = ProjectSettings::get_singleton()->globalize_path(item_meta["path"]);
- if (!item_meta["dir"]) {
- path = path.get_base_dir();
- }
}
- OS::get_singleton()->shell_open(String("file://") + path);
+ OS::get_singleton()->shell_show_in_file_manager(path, true);
} break;
}
}
diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp
index e8cea14ce6..9abb51acae 100644
--- a/editor/project_manager.cpp
+++ b/editor/project_manager.cpp
@@ -1827,7 +1827,7 @@ void ProjectList::_favorite_pressed(Node *p_hb) {
}
void ProjectList::_show_project(const String &p_path) {
- OS::get_singleton()->shell_open(String("file://") + p_path);
+ OS::get_singleton()->shell_show_in_file_manager(p_path, true);
}
void ProjectList::_bind_methods() {
diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp
index 456240ba2d..bda6d48f57 100644
--- a/platform/windows/os_windows.cpp
+++ b/platform/windows/os_windows.cpp
@@ -1313,6 +1313,51 @@ Error OS_Windows::shell_open(String p_uri) {
}
}
+Error OS_Windows::shell_show_in_file_manager(String p_path, bool p_open_folder) {
+ p_path = p_path.trim_suffix("file://");
+
+ bool open_folder = false;
+ if (DirAccess::dir_exists_absolute(p_path) && p_open_folder) {
+ open_folder = true;
+ }
+
+ if (p_path.begins_with("\"")) {
+ p_path = String("\"") + p_path;
+ }
+ if (p_path.ends_with("\"")) {
+ p_path = p_path + String("\"");
+ }
+ p_path = p_path.replace("/", "\\");
+
+ INT_PTR ret = OK;
+ if (open_folder) {
+ ret = (INT_PTR)ShellExecuteW(nullptr, nullptr, L"explorer.exe", LPCWSTR(p_path.utf16().get_data()), nullptr, SW_SHOWNORMAL);
+ } else {
+ ret = (INT_PTR)ShellExecuteW(nullptr, nullptr, L"explorer.exe", LPCWSTR((String("/select,") + p_path).utf16().get_data()), nullptr, SW_SHOWNORMAL);
+ }
+
+ if (ret > 32) {
+ return OK;
+ } else {
+ switch (ret) {
+ case ERROR_FILE_NOT_FOUND:
+ case SE_ERR_DLLNOTFOUND:
+ return ERR_FILE_NOT_FOUND;
+ case ERROR_PATH_NOT_FOUND:
+ return ERR_FILE_BAD_PATH;
+ case ERROR_BAD_FORMAT:
+ return ERR_FILE_CORRUPT;
+ case SE_ERR_ACCESSDENIED:
+ return ERR_UNAUTHORIZED;
+ case 0:
+ case SE_ERR_OOM:
+ return ERR_OUT_OF_MEMORY;
+ default:
+ return FAILED;
+ }
+ }
+}
+
String OS_Windows::get_locale() const {
const _WinLocale *wl = &_win_locales[0];
diff --git a/platform/windows/os_windows.h b/platform/windows/os_windows.h
index 05110c2614..5880521357 100644
--- a/platform/windows/os_windows.h
+++ b/platform/windows/os_windows.h
@@ -212,6 +212,7 @@ public:
virtual String get_unique_id() const override;
virtual Error shell_open(String p_uri) override;
+ virtual Error shell_show_in_file_manager(String p_path, bool p_open_folder) override;
void run();