summaryrefslogtreecommitdiffstats
path: root/editor/filesystem_dock.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'editor/filesystem_dock.cpp')
-rw-r--r--editor/filesystem_dock.cpp525
1 files changed, 201 insertions, 324 deletions
diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp
index dd2eec6893..3921cde71e 100644
--- a/editor/filesystem_dock.cpp
+++ b/editor/filesystem_dock.cpp
@@ -203,9 +203,7 @@ Ref<Texture2D> FileSystemDock::_get_tree_item_icon(bool p_is_valid, const String
}
}
-bool FileSystemDock::_create_tree(TreeItem *p_parent, EditorFileSystemDirectory *p_dir, Vector<String> &uncollapsed_paths, bool p_select_in_favorites, bool p_unfold_path) {
- bool parent_should_expand = false;
-
+void FileSystemDock::_create_tree(TreeItem *p_parent, EditorFileSystemDirectory *p_dir, Vector<String> &uncollapsed_paths, bool p_select_in_favorites, bool p_unfold_path) {
// Create a tree item for the subdirectory.
TreeItem *subdirectory_item = tree->create_item(p_parent);
String dname = p_dir->get_name();
@@ -213,6 +211,7 @@ bool FileSystemDock::_create_tree(TreeItem *p_parent, EditorFileSystemDirectory
if (dname.is_empty()) {
dname = "res://";
+ resources_item = subdirectory_item;
}
// Set custom folder color (if applicable).
@@ -258,16 +257,13 @@ bool FileSystemDock::_create_tree(TreeItem *p_parent, EditorFileSystemDirectory
} else {
subdirectory_item->set_collapsed(!uncollapsed_paths.has(lpath));
}
- if (!searched_tokens.is_empty() && _matches_all_search_tokens(dname)) {
- parent_should_expand = true;
- }
// Create items for all subdirectories.
- bool reversed = file_sort == FILE_SORT_NAME_REVERSE;
+ bool reversed = file_sort == FileSortOption::FILE_SORT_NAME_REVERSE;
for (int i = reversed ? p_dir->get_subdir_count() - 1 : 0;
reversed ? i >= 0 : i < p_dir->get_subdir_count();
reversed ? i-- : i++) {
- parent_should_expand = (_create_tree(subdirectory_item, p_dir->get_subdir(i), uncollapsed_paths, p_select_in_favorites, p_unfold_path) || parent_should_expand);
+ _create_tree(subdirectory_item, p_dir->get_subdir(i), uncollapsed_paths, p_select_in_favorites, p_unfold_path);
}
// Create all items for the files in the subdirectory.
@@ -283,39 +279,28 @@ bool FileSystemDock::_create_tree(TreeItem *p_parent, EditorFileSystemDirectory
continue;
}
- String file_name = p_dir->get_file(i);
- if (!searched_tokens.is_empty()) {
- if (!_matches_all_search_tokens(file_name)) {
- // The searched string is not in the file name, we skip it.
- continue;
- } else {
- // We expand all parents.
- parent_should_expand = true;
- }
- }
-
- FileInfo fi;
- fi.name = p_dir->get_file(i);
- fi.type = p_dir->get_file_type(i);
- fi.icon_path = p_dir->get_file_icon_path(i);
- fi.import_broken = !p_dir->get_file_import_is_valid(i);
- fi.modified_time = p_dir->get_file_modified_time(i);
+ FileInfo file_info;
+ file_info.name = p_dir->get_file(i);
+ file_info.type = p_dir->get_file_type(i);
+ file_info.icon_path = p_dir->get_file_icon_path(i);
+ file_info.import_broken = !p_dir->get_file_import_is_valid(i);
+ file_info.modified_time = p_dir->get_file_modified_time(i);
- file_list.push_back(fi);
+ file_list.push_back(file_info);
}
// Sort the file list if needed.
- _sort_file_info_list(file_list);
+ sort_file_info_list(file_list, file_sort);
// Build the tree.
const int icon_size = get_theme_constant(SNAME("class_icon_size"), EditorStringName(Editor));
- for (const FileInfo &fi : file_list) {
+ for (const FileInfo &file_info : file_list) {
TreeItem *file_item = tree->create_item(subdirectory_item);
- const String file_metadata = lpath.path_join(fi.name);
- file_item->set_text(0, fi.name);
+ const String file_metadata = lpath.path_join(file_info.name);
+ file_item->set_text(0, file_info.name);
file_item->set_structured_text_bidi_override(0, TextServer::STRUCTURED_TEXT_FILE);
- file_item->set_icon(0, _get_tree_item_icon(!fi.import_broken, fi.type, fi.icon_path));
+ file_item->set_icon(0, _get_tree_item_icon(!file_info.import_broken, file_info.type, file_info.icon_path));
if (da->is_link(file_metadata)) {
file_item->set_icon_overlay(0, get_editor_theme_icon(SNAME("LinkOverlay")));
file_item->set_tooltip_text(0, vformat(TTR("Link to: %s"), da->read_link(file_metadata)));
@@ -346,24 +331,12 @@ bool FileSystemDock::_create_tree(TreeItem *p_parent, EditorFileSystemDirectory
subdirectory_item->set_as_cursor(0);
}
}
-
- if (!searched_tokens.is_empty()) {
- if (parent_should_expand) {
- subdirectory_item->set_collapsed(false);
- } else if (dname != "res://") {
- subdirectory_item->get_parent()->remove_child(subdirectory_item);
- memdelete(subdirectory_item);
- }
- }
-
- return parent_should_expand;
}
Vector<String> FileSystemDock::get_uncollapsed_paths() const {
Vector<String> uncollapsed_paths;
TreeItem *root = tree->get_root();
if (root) {
- TreeItem *favorites_item = root->get_first_child();
if (!favorites_item->is_collapsed()) {
uncollapsed_paths.push_back(favorites_item->get_metadata(0));
}
@@ -400,7 +373,7 @@ void FileSystemDock::_update_tree(const Vector<String> &p_uncollapsed_paths, boo
TreeItem *root = tree->create_item();
// Handles the favorites.
- TreeItem *favorites_item = tree->create_item(root);
+ favorites_item = tree->create_item(root);
favorites_item->set_icon(0, get_editor_theme_icon(SNAME("Favorites")));
favorites_item->set_text(0, TTR("Favorites:"));
favorites_item->set_metadata(0, "Favorites");
@@ -453,24 +426,22 @@ void FileSystemDock::_update_tree(const Vector<String> &p_uncollapsed_paths, boo
color = Color(1, 1, 1);
}
- if (searched_tokens.is_empty() || _matches_all_search_tokens(text)) {
- TreeItem *ti = tree->create_item(favorites_item);
- ti->set_text(0, text);
- ti->set_icon(0, icon);
- ti->set_icon_modulate(0, color);
- ti->set_tooltip_text(0, favorite);
- ti->set_selectable(0, true);
- ti->set_metadata(0, favorite);
- if (p_select_in_favorites && favorite == current_path) {
- ti->select(0);
- ti->set_as_cursor(0);
- }
- if (!favorite.ends_with("/")) {
- Array udata;
- udata.push_back(tree_update_id);
- udata.push_back(ti);
- EditorResourcePreview::get_singleton()->queue_resource_preview(favorite, this, "_tree_thumbnail_done", udata);
- }
+ TreeItem *ti = tree->create_item(favorites_item);
+ ti->set_text(0, text);
+ ti->set_icon(0, icon);
+ ti->set_icon_modulate(0, color);
+ ti->set_tooltip_text(0, favorite);
+ ti->set_selectable(0, true);
+ ti->set_metadata(0, favorite);
+ if (p_select_in_favorites && favorite == current_path) {
+ ti->select(0);
+ ti->set_as_cursor(0);
+ }
+ if (!favorite.ends_with("/")) {
+ Array udata;
+ udata.push_back(tree_update_id);
+ udata.push_back(ti);
+ EditorResourcePreview::get_singleton()->queue_resource_preview(favorite, this, "_tree_thumbnail_done", udata);
}
}
@@ -495,7 +466,7 @@ void FileSystemDock::_update_display_mode(bool p_force) {
if (p_force || old_display_mode != display_mode) {
switch (display_mode) {
case DISPLAY_MODE_TREE_ONLY:
- button_toggle_display_mode->set_icon(get_editor_theme_icon(SNAME("Panels1")));
+ button_toggle_display_mode->set_button_icon(get_editor_theme_icon(SNAME("Panels1")));
tree->show();
tree->set_v_size_flags(SIZE_EXPAND_FILL);
toolbar2_hbc->show();
@@ -512,7 +483,7 @@ void FileSystemDock::_update_display_mode(bool p_force) {
const int actual_offset = is_vertical ? split_box_offset_v : split_box_offset_h;
split_box->set_split_offset(actual_offset);
const StringName icon = is_vertical ? SNAME("Panels2") : SNAME("Panels2Alt");
- button_toggle_display_mode->set_icon(get_editor_theme_icon(icon));
+ button_toggle_display_mode->set_button_icon(get_editor_theme_icon(icon));
tree->show();
tree->set_v_size_flags(SIZE_EXPAND_FILL);
@@ -597,7 +568,7 @@ void FileSystemDock::_notification(int p_what) {
case NOTIFICATION_THEME_CHANGED: {
_update_display_mode(true);
- button_reload->set_icon(get_editor_theme_icon(SNAME("Reload")));
+ button_reload->set_button_icon(get_editor_theme_icon(SNAME("Reload")));
StringName mode_icon = "Panels1";
if (display_mode == DISPLAY_MODE_VSPLIT) {
@@ -605,28 +576,28 @@ void FileSystemDock::_notification(int p_what) {
} else if (display_mode == DISPLAY_MODE_HSPLIT) {
mode_icon = "Panels2Alt";
}
- button_toggle_display_mode->set_icon(get_editor_theme_icon(mode_icon));
+ button_toggle_display_mode->set_button_icon(get_editor_theme_icon(mode_icon));
if (file_list_display_mode == FILE_LIST_DISPLAY_LIST) {
- button_file_list_display_mode->set_icon(get_editor_theme_icon(SNAME("FileThumbnail")));
+ button_file_list_display_mode->set_button_icon(get_editor_theme_icon(SNAME("FileThumbnail")));
} else {
- button_file_list_display_mode->set_icon(get_editor_theme_icon(SNAME("FileList")));
+ button_file_list_display_mode->set_button_icon(get_editor_theme_icon(SNAME("FileList")));
}
tree_search_box->set_right_icon(get_editor_theme_icon(SNAME("Search")));
- tree_button_sort->set_icon(get_editor_theme_icon(SNAME("Sort")));
+ tree_button_sort->set_button_icon(get_editor_theme_icon(SNAME("Sort")));
file_list_search_box->set_right_icon(get_editor_theme_icon(SNAME("Search")));
- file_list_button_sort->set_icon(get_editor_theme_icon(SNAME("Sort")));
+ file_list_button_sort->set_button_icon(get_editor_theme_icon(SNAME("Sort")));
- button_dock_placement->set_icon(get_editor_theme_icon(SNAME("GuiTabMenuHl")));
+ button_dock_placement->set_button_icon(get_editor_theme_icon(SNAME("GuiTabMenuHl")));
if (is_layout_rtl()) {
- button_hist_next->set_icon(get_editor_theme_icon(SNAME("Back")));
- button_hist_prev->set_icon(get_editor_theme_icon(SNAME("Forward")));
+ button_hist_next->set_button_icon(get_editor_theme_icon(SNAME("Back")));
+ button_hist_prev->set_button_icon(get_editor_theme_icon(SNAME("Forward")));
} else {
- button_hist_next->set_icon(get_editor_theme_icon(SNAME("Forward")));
- button_hist_prev->set_icon(get_editor_theme_icon(SNAME("Back")));
+ button_hist_next->set_button_icon(get_editor_theme_icon(SNAME("Forward")));
+ button_hist_prev->set_button_icon(get_editor_theme_icon(SNAME("Back")));
}
overwrite_dialog_scroll->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SceneStringName(panel), "Tree"));
@@ -676,7 +647,6 @@ void FileSystemDock::_tree_multi_selected(Object *p_item, int p_column, bool p_s
return;
}
- TreeItem *favorites_item = tree->get_root()->get_first_child();
if (selected->get_parent() == favorites_item && !String(selected->get_metadata(0)).ends_with("/")) {
// Go to the favorites if we click in the favorites and the path has changed.
current_path = "Favorites";
@@ -771,6 +741,36 @@ void FileSystemDock::_navigate_to_path(const String &p_path, bool p_select_in_fa
}
}
+bool FileSystemDock::_update_filtered_items(TreeItem *p_tree_item) {
+ TreeItem *item = p_tree_item;
+ if (!item) {
+ item = tree->get_root();
+ }
+ ERR_FAIL_NULL_V(item, false);
+
+ bool keep_visible = false;
+ for (TreeItem *child = item->get_first_child(); child; child = child->get_next()) {
+ keep_visible = _update_filtered_items(child) || keep_visible;
+ }
+
+ if (searched_tokens.is_empty()) {
+ item->set_visible(true);
+ // Always uncollapse root (the hidden item above res:// and favorites).
+ item->set_collapsed(item != tree->get_root() && !uncollapsed_paths_before_search.has(item->get_metadata(0)));
+ return true;
+ }
+
+ if (keep_visible) {
+ item->set_collapsed(false);
+ } else {
+ // res:// and favorites are always visible.
+ keep_visible = item == resources_item || item == favorites_item;
+ keep_visible = keep_visible || _matches_all_search_tokens(item->get_text(0));
+ }
+ item->set_visible(keep_visible);
+ return keep_visible;
+}
+
void FileSystemDock::navigate_to_path(const String &p_path) {
file_list_search_box->clear();
_navigate_to_path(p_path);
@@ -818,11 +818,11 @@ void FileSystemDock::_toggle_file_display() {
void FileSystemDock::_set_file_display(bool p_active) {
if (p_active) {
file_list_display_mode = FILE_LIST_DISPLAY_LIST;
- button_file_list_display_mode->set_icon(get_editor_theme_icon(SNAME("FileThumbnail")));
+ button_file_list_display_mode->set_button_icon(get_editor_theme_icon(SNAME("FileThumbnail")));
button_file_list_display_mode->set_tooltip_text(TTR("View items as a grid of thumbnails."));
} else {
file_list_display_mode = FILE_LIST_DISPLAY_THUMBNAILS;
- button_file_list_display_mode->set_icon(get_editor_theme_icon(SNAME("FileList")));
+ button_file_list_display_mode->set_button_icon(get_editor_theme_icon(SNAME("FileList")));
button_file_list_display_mode->set_tooltip_text(TTR("View items as a list."));
}
@@ -860,19 +860,19 @@ void FileSystemDock::_search(EditorFileSystemDirectory *p_path, List<FileInfo> *
String file = p_path->get_file(i);
if (_matches_all_search_tokens(file)) {
- FileInfo fi;
- fi.name = file;
- fi.type = p_path->get_file_type(i);
- fi.path = p_path->get_file_path(i);
- fi.import_broken = !p_path->get_file_import_is_valid(i);
- fi.modified_time = p_path->get_file_modified_time(i);
-
- if (_is_file_type_disabled_by_feature_profile(fi.type)) {
+ FileInfo file_info;
+ file_info.name = file;
+ file_info.type = p_path->get_file_type(i);
+ file_info.path = p_path->get_file_path(i);
+ file_info.import_broken = !p_path->get_file_import_is_valid(i);
+ file_info.modified_time = p_path->get_file_modified_time(i);
+
+ if (_is_file_type_disabled_by_feature_profile(file_info.type)) {
// This type is disabled, will not appear here.
continue;
}
- matches->push_back(fi);
+ matches->push_back(file_info);
if (matches->size() > p_max_items) {
return;
}
@@ -880,45 +880,6 @@ void FileSystemDock::_search(EditorFileSystemDirectory *p_path, List<FileInfo> *
}
}
-struct FileSystemDock::FileInfoTypeComparator {
- bool operator()(const FileInfo &p_a, const FileInfo &p_b) const {
- return FileNoCaseComparator()(p_a.name.get_extension() + p_a.type + p_a.name.get_basename(), p_b.name.get_extension() + p_b.type + p_b.name.get_basename());
- }
-};
-
-struct FileSystemDock::FileInfoModifiedTimeComparator {
- bool operator()(const FileInfo &p_a, const FileInfo &p_b) const {
- return p_a.modified_time > p_b.modified_time;
- }
-};
-
-void FileSystemDock::_sort_file_info_list(List<FileSystemDock::FileInfo> &r_file_list) {
- // Sort the file list if needed.
- switch (file_sort) {
- case FILE_SORT_TYPE:
- r_file_list.sort_custom<FileInfoTypeComparator>();
- break;
- case FILE_SORT_TYPE_REVERSE:
- r_file_list.sort_custom<FileInfoTypeComparator>();
- r_file_list.reverse();
- break;
- case FILE_SORT_MODIFIED_TIME:
- r_file_list.sort_custom<FileInfoModifiedTimeComparator>();
- break;
- case FILE_SORT_MODIFIED_TIME_REVERSE:
- r_file_list.sort_custom<FileInfoModifiedTimeComparator>();
- r_file_list.reverse();
- break;
- case FILE_SORT_NAME_REVERSE:
- r_file_list.sort();
- r_file_list.reverse();
- break;
- default: // FILE_SORT_NAME
- r_file_list.sort();
- break;
- }
-}
-
void FileSystemDock::_update_file_list(bool p_keep_selection) {
// Register the previously current and selected items.
HashSet<String> previous_selection;
@@ -1005,22 +966,22 @@ void FileSystemDock::_update_file_list(bool p_keep_selection) {
int index;
EditorFileSystemDirectory *efd = EditorFileSystem::get_singleton()->find_file(favorite, &index);
- FileInfo fi;
- fi.name = favorite.get_file();
- fi.path = favorite;
+ FileInfo file_info;
+ file_info.name = favorite.get_file();
+ file_info.path = favorite;
if (efd) {
- fi.type = efd->get_file_type(index);
- fi.icon_path = efd->get_file_icon_path(index);
- fi.import_broken = !efd->get_file_import_is_valid(index);
- fi.modified_time = efd->get_file_modified_time(index);
+ file_info.type = efd->get_file_type(index);
+ file_info.icon_path = efd->get_file_icon_path(index);
+ file_info.import_broken = !efd->get_file_import_is_valid(index);
+ file_info.modified_time = efd->get_file_modified_time(index);
} else {
- fi.type = "";
- fi.import_broken = true;
- fi.modified_time = 0;
+ file_info.type = "";
+ file_info.import_broken = true;
+ file_info.modified_time = 0;
}
- if (searched_tokens.is_empty() || _matches_all_search_tokens(fi.name)) {
- file_list.push_back(fi);
+ if (searched_tokens.is_empty() || _matches_all_search_tokens(file_info.name)) {
+ file_list.push_back(file_info);
}
}
}
@@ -1077,7 +1038,7 @@ void FileSystemDock::_update_file_list(bool p_keep_selection) {
files->set_item_icon_modulate(-1, editor_is_dark_theme ? inherited_folder_color : inherited_folder_color * ITEM_COLOR_SCALE);
}
- bool reversed = file_sort == FILE_SORT_NAME_REVERSE;
+ bool reversed = file_sort == FileSortOption::FILE_SORT_NAME_REVERSE;
for (int i = reversed ? efd->get_subdir_count() - 1 : 0;
reversed ? i >= 0 : i < efd->get_subdir_count();
reversed ? i-- : i++) {
@@ -1099,21 +1060,21 @@ void FileSystemDock::_update_file_list(bool p_keep_selection) {
// Display the folder content.
for (int i = 0; i < efd->get_file_count(); i++) {
- FileInfo fi;
- fi.name = efd->get_file(i);
- fi.path = directory.path_join(fi.name);
- fi.type = efd->get_file_type(i);
- fi.icon_path = efd->get_file_icon_path(i);
- fi.import_broken = !efd->get_file_import_is_valid(i);
- fi.modified_time = efd->get_file_modified_time(i);
+ FileInfo file_info;
+ file_info.name = efd->get_file(i);
+ file_info.path = directory.path_join(file_info.name);
+ file_info.type = efd->get_file_type(i);
+ file_info.icon_path = efd->get_file_icon_path(i);
+ file_info.import_broken = !efd->get_file_import_is_valid(i);
+ file_info.modified_time = efd->get_file_modified_time(i);
- file_list.push_back(fi);
+ file_list.push_back(file_info);
}
}
}
// Sort the file list if needed.
- _sort_file_info_list(file_list);
+ sort_file_info_list(file_list, file_sort);
// Fills the ItemList control node from the FileInfos.
String main_scene = GLOBAL_GET("application/run/main_scene");
@@ -1485,6 +1446,13 @@ void FileSystemDock::_try_move_item(const FileOrFolder &p_item, const String &p_
}
}
+ if (p_item.is_file && FileAccess::exists(old_path + ".uid")) {
+ err = da->rename(old_path + ".uid", new_path + ".uid");
+ if (err != OK) {
+ EditorNode::get_singleton()->add_io_error(TTR("Error moving:") + "\n" + old_path + ".uid\n");
+ }
+ }
+
// Update scene if it is open.
for (int i = 0; i < file_changed_paths.size(); ++i) {
String new_item_path = p_item.is_file ? new_path : file_changed_paths[i].replace_first(old_path, new_path);
@@ -1530,76 +1498,22 @@ void FileSystemDock::_try_duplicate_item(const FileOrFolder &p_item, const Strin
EditorNode::get_singleton()->add_io_error(TTR("Cannot move a folder into itself.") + "\n" + old_path + "\n");
return;
}
- Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_RESOURCES);
if (p_item.is_file) {
print_verbose("Duplicating " + old_path + " -> " + new_path);
// Create the directory structure.
- da->make_dir_recursive(new_path.get_base_dir());
-
- if (FileAccess::exists(old_path + ".import")) {
- Error err = da->copy(old_path, new_path);
- if (err != OK) {
- EditorNode::get_singleton()->add_io_error(TTR("Error duplicating:") + "\n" + old_path + ": " + error_names[err] + "\n");
- return;
- }
-
- // Remove uid from .import file to avoid conflict.
- Ref<ConfigFile> cfg;
- cfg.instantiate();
- cfg->load(old_path + ".import");
- cfg->erase_section_key("remap", "uid");
- err = cfg->save(new_path + ".import");
- if (err != OK) {
- EditorNode::get_singleton()->add_io_error(TTR("Error duplicating:") + "\n" + old_path + ".import: " + error_names[err] + "\n");
- return;
- }
- } else {
- // Files which do not use an uid can just be copied.
- if (ResourceLoader::get_resource_uid(old_path) == ResourceUID::INVALID_ID) {
- Error err = da->copy(old_path, new_path);
- if (err != OK) {
- EditorNode::get_singleton()->add_io_error(TTR("Error duplicating:") + "\n" + old_path + ": " + error_names[err] + "\n");
- }
- return;
- }
+ EditorFileSystem::get_singleton()->make_dir_recursive(p_new_path.get_base_dir());
- // Load the resource and save it again in the new location (this generates a new UID).
- Error err;
- Ref<Resource> res = ResourceLoader::load(old_path, "", ResourceFormatLoader::CACHE_MODE_REUSE, &err);
- if (err == OK && res.is_valid()) {
- err = ResourceSaver::save(res, new_path, ResourceSaver::FLAG_COMPRESS);
- if (err != OK) {
- EditorNode::get_singleton()->add_io_error(TTR("Error duplicating:") + " " + vformat(TTR("Failed to save resource at %s: %s"), new_path, error_names[err]));
- }
- } else if (err != OK) {
- // When loading files like text files the error is OK but the resource is still null.
- // We can ignore such files.
- EditorNode::get_singleton()->add_io_error(TTR("Error duplicating:") + " " + vformat(TTR("Failed to load resource at %s: %s"), new_path, error_names[err]));
- }
+ Error err = EditorFileSystem::get_singleton()->copy_file(old_path, new_path);
+ if (err != OK) {
+ EditorNode::get_singleton()->add_io_error(TTR("Error duplicating:") + "\n" + old_path + ": " + error_names[err] + "\n");
}
} else {
- da->make_dir(new_path);
-
- // Recursively duplicate all files inside the folder.
- Ref<DirAccess> old_dir = DirAccess::open(old_path);
- ERR_FAIL_COND(old_dir.is_null());
-
- Ref<FileAccess> file_access = FileAccess::create(FileAccess::ACCESS_RESOURCES);
- old_dir->set_include_navigational(false);
- old_dir->list_dir_begin();
- for (String f = old_dir->_get_next(); !f.is_empty(); f = old_dir->_get_next()) {
- if (f.get_extension() == "import") {
- continue;
- }
- if (file_access->file_exists(old_path + f)) {
- _try_duplicate_item(FileOrFolder(old_path + f, true), new_path + f);
- } else if (da->dir_exists(old_path + f)) {
- _try_duplicate_item(FileOrFolder(old_path + f, false), new_path + f);
- }
+ Error err = EditorFileSystem::get_singleton()->copy_directory(old_path, new_path);
+ if (err != OK) {
+ EditorNode::get_singleton()->add_io_error(TTR("Error duplicating directory:") + "\n" + old_path + "\n");
}
- old_dir->list_dir_end();
}
}
@@ -1734,21 +1648,27 @@ String FileSystemDock::_get_unique_name(const FileOrFolder &p_entry, const Strin
return new_path;
}
-void FileSystemDock::_update_favorites_list_after_move(const HashMap<String, String> &p_files_renames, const HashMap<String, String> &p_folders_renames) const {
- Vector<String> favorites_list = EditorSettings::get_singleton()->get_favorites();
- Vector<String> new_favorites;
-
- for (const String &old_path : favorites_list) {
+void FileSystemDock::_update_favorites_after_move(const HashMap<String, String> &p_files_renames, const HashMap<String, String> &p_folders_renames) const {
+ Vector<String> favorite_files = EditorSettings::get_singleton()->get_favorites();
+ Vector<String> new_favorite_files;
+ for (const String &old_path : favorite_files) {
if (p_folders_renames.has(old_path)) {
- new_favorites.push_back(p_folders_renames[old_path]);
+ new_favorite_files.push_back(p_folders_renames[old_path]);
} else if (p_files_renames.has(old_path)) {
- new_favorites.push_back(p_files_renames[old_path]);
+ new_favorite_files.push_back(p_files_renames[old_path]);
} else {
- new_favorites.push_back(old_path);
+ new_favorite_files.push_back(old_path);
}
}
+ EditorSettings::get_singleton()->set_favorites(new_favorite_files);
- EditorSettings::get_singleton()->set_favorites(new_favorites);
+ HashMap<String, PackedStringArray> favorite_properties = EditorSettings::get_singleton()->get_favorite_properties();
+ for (const KeyValue<String, String> &KV : p_files_renames) {
+ if (favorite_properties.has(KV.key)) {
+ favorite_properties.replace_key(KV.key, KV.value);
+ }
+ }
+ EditorSettings::get_singleton()->set_favorite_properties(favorite_properties);
}
void FileSystemDock::_make_scene_confirm() {
@@ -1891,7 +1811,7 @@ void FileSystemDock::_rename_operation_confirm() {
_update_resource_paths_after_move(file_renames, uids);
_update_dependencies_after_move(file_renames, file_owners);
_update_project_settings_after_move(file_renames, folder_renames);
- _update_favorites_list_after_move(file_renames, folder_renames);
+ _update_favorites_after_move(file_renames, folder_renames);
EditorSceneTabs::get_singleton()->set_current_tab(current_tab);
@@ -1904,39 +1824,16 @@ void FileSystemDock::_rename_operation_confirm() {
_rescan();
}
-void FileSystemDock::_duplicate_operation_confirm() {
- String new_name = duplicate_dialog_text->get_text().strip_edges();
- if (new_name.length() == 0) {
- EditorNode::get_singleton()->show_warning(TTR("No name provided."));
- return;
- } else if (new_name.contains("/") || new_name.contains("\\") || new_name.contains(":")) {
- EditorNode::get_singleton()->show_warning(TTR("Name contains invalid characters."));
- return;
- } else if (new_name[0] == '.') {
- EditorNode::get_singleton()->show_warning(TTR("Name begins with a dot."));
- return;
- }
-
- String base_dir = to_duplicate.path.get_base_dir();
- // get_base_dir() returns "some/path" if the original path was "some/path/", so work it around.
- if (to_duplicate.path.ends_with("/")) {
- base_dir = base_dir.get_base_dir();
- }
-
- String new_path = base_dir.path_join(new_name);
-
- // Present a more user friendly warning for name conflict
- Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_RESOURCES);
- if (da->file_exists(new_path) || da->dir_exists(new_path)) {
- EditorNode::get_singleton()->show_warning(TTR("A file or folder with this name already exists."));
- return;
+void FileSystemDock::_duplicate_operation_confirm(const String &p_path) {
+ const String base_dir = p_path.trim_suffix("/").get_base_dir();
+ if (!DirAccess::dir_exists_absolute(base_dir)) {
+ Error err = EditorFileSystem::get_singleton()->make_dir_recursive(base_dir);
+ if (err != OK) {
+ EditorNode::get_singleton()->show_warning(vformat(TTR("Could not create base directory: %s"), error_names[err]));
+ return;
+ }
}
-
- _try_duplicate_item(to_duplicate, new_path);
-
- // Rescan everything.
- print_verbose("FileSystem: calling rescan.");
- _rescan();
+ _try_duplicate_item(to_duplicate, p_path);
}
void FileSystemDock::_overwrite_dialog_action(bool p_overwrite) {
@@ -2075,7 +1972,7 @@ void FileSystemDock::_move_operation_confirm(const String &p_to_path, bool p_cop
_update_resource_paths_after_move(file_renames, uids);
_update_dependencies_after_move(file_renames, file_owners);
_update_project_settings_after_move(file_renames, folder_renames);
- _update_favorites_list_after_move(file_renames, folder_renames);
+ _update_favorites_after_move(file_renames, folder_renames);
EditorSceneTabs::get_singleton()->set_current_tab(current_tab);
@@ -2131,7 +2028,6 @@ Vector<String> FileSystemDock::_tree_get_selected(bool remove_self_inclusion, bo
// Build a list of selected items with the active one at the first position.
Vector<String> selected_strings;
- TreeItem *favorites_item = tree->get_root()->get_first_child();
TreeItem *cursor_item = tree->get_selected();
if (cursor_item && (p_include_unselected_cursor || cursor_item->is_selected(0)) && cursor_item != favorites_item) {
selected_strings.push_back(cursor_item->get_metadata(0));
@@ -2570,27 +2466,22 @@ void FileSystemDock::_file_option(int p_option, const Vector<String> &p_selected
} break;
case FILE_DUPLICATE: {
- // Duplicate the selected files.
- for (int i = 0; i < p_selected.size(); i++) {
- to_duplicate.path = p_selected[i];
- to_duplicate.is_file = !to_duplicate.path.ends_with("/");
- if (to_duplicate.is_file) {
- String name = to_duplicate.path.get_file();
- duplicate_dialog->set_title(TTR("Duplicating file:") + " " + name);
- duplicate_dialog_text->set_text(name);
- duplicate_dialog_text->select(0, name.rfind("."));
- } else {
- String name = to_duplicate.path.substr(0, to_duplicate.path.length() - 1).get_file();
- duplicate_dialog->set_title(TTR("Duplicating folder:") + " " + name);
- duplicate_dialog_text->set_text(name);
- duplicate_dialog_text->select(0, name.length());
- }
- duplicate_dialog->popup_centered(Size2(250, 80) * EDSCALE);
- duplicate_dialog_text->grab_focus();
+ if (p_selected.size() != 1) {
+ return;
}
- } break;
- case FILE_INFO: {
+ to_duplicate.path = p_selected[0];
+ to_duplicate.is_file = !to_duplicate.path.ends_with("/");
+ if (to_duplicate.is_file) {
+ String name = to_duplicate.path.get_file();
+ make_dir_dialog->config(to_duplicate.path.get_base_dir(), callable_mp(this, &FileSystemDock::_duplicate_operation_confirm),
+ DirectoryCreateDialog::MODE_FILE, TTR("Duplicating file:") + " " + name, name);
+ } else {
+ String name = to_duplicate.path.trim_suffix("/").get_file();
+ make_dir_dialog->config(to_duplicate.path.trim_suffix("/").get_base_dir(), callable_mp(this, &FileSystemDock::_duplicate_operation_confirm),
+ DirectoryCreateDialog::MODE_DIRECTORY, TTR("Duplicating folder:") + " " + name, name);
+ }
+ make_dir_dialog->popup_centered();
} break;
case FILE_REIMPORT: {
@@ -2602,7 +2493,8 @@ void FileSystemDock::_file_option(int p_option, const Vector<String> &p_selected
if (!directory.ends_with("/")) {
directory = directory.get_base_dir();
}
- make_dir_dialog->config(directory);
+ make_dir_dialog->config(directory, callable_mp(this, &FileSystemDock::create_directory).bind(directory),
+ DirectoryCreateDialog::MODE_DIRECTORY, TTR("Create Folder"), "new folder");
make_dir_dialog->popup_centered();
} break;
@@ -2744,16 +2636,12 @@ void FileSystemDock::_search_changed(const String &p_text, const Control *p_from
tree_search_box->set_text(searched_string);
}
- bool unfold_path = (p_text.is_empty() && !current_path.is_empty());
- switch (display_mode) {
- case DISPLAY_MODE_TREE_ONLY: {
- _update_tree(searched_tokens.is_empty() ? uncollapsed_paths_before_search : Vector<String>(), false, false, unfold_path);
- } break;
- case DISPLAY_MODE_HSPLIT:
- case DISPLAY_MODE_VSPLIT: {
- _update_file_list(false);
- _update_tree(searched_tokens.is_empty() ? uncollapsed_paths_before_search : Vector<String>(), false, false, unfold_path);
- } break;
+ _update_filtered_items();
+ if (display_mode == DISPLAY_MODE_HSPLIT || display_mode == DISPLAY_MODE_VSPLIT) {
+ _update_file_list(false);
+ }
+ if (searched_tokens.is_empty()) {
+ _navigate_to_path(current_path);
}
}
@@ -2832,6 +2720,13 @@ void FileSystemDock::focus_on_filter() {
}
}
+void FileSystemDock::create_directory(const String &p_path, const String &p_base_dir) {
+ Error err = EditorFileSystem::get_singleton()->make_dir_recursive(p_path.trim_prefix(p_base_dir), p_base_dir);
+ if (err != OK) {
+ EditorNode::get_singleton()->show_warning(vformat(TTR("Could not create folder: %s"), error_names[err]));
+ }
+}
+
ScriptCreateDialog *FileSystemDock::get_script_create_dialog() const {
return make_script_dialog;
}
@@ -2886,7 +2781,6 @@ Variant FileSystemDock::get_drag_data_fw(const Point2 &p_point, Control *p_from)
// Check if the first selected is in favorite.
TreeItem *selected = tree->get_next_selected(tree->get_root());
while (selected) {
- TreeItem *favorites_item = tree->get_root()->get_first_child();
if (selected == favorites_item) {
// The "Favorites" item is not draggable.
return Variant();
@@ -2938,10 +2832,6 @@ bool FileSystemDock::can_drop_data_fw(const Point2 &p_point, const Variant &p_da
}
int drop_section = tree->get_drop_section_at_position(p_point);
- TreeItem *favorites_item = tree->get_root()->get_first_child();
-
- TreeItem *resources_item = favorites_item->get_next();
-
if (ti == favorites_item) {
return (drop_section == 1); // The parent, first fav.
}
@@ -3022,9 +2912,6 @@ void FileSystemDock::drop_data_fw(const Point2 &p_point, const Variant &p_data,
int drop_position;
Vector<String> drag_files = drag_data["files"];
- TreeItem *favorites_item = tree->get_root()->get_first_child();
- TreeItem *resources_item = favorites_item->get_next();
-
if (ti == favorites_item) {
// Drop on the favorite folder.
drop_position = 0;
@@ -3452,7 +3339,6 @@ void FileSystemDock::_file_and_folders_fill_popup(PopupMenu *p_popup, const Vect
[[maybe_unused]] bool added_separator = false;
if (favorites_list.has(fpath)) {
- TreeItem *favorites_item = tree->get_root()->get_first_child();
TreeItem *cursor_item = tree->get_selected();
bool is_item_in_favorites = false;
while (cursor_item != nullptr) {
@@ -3481,7 +3367,7 @@ void FileSystemDock::_file_and_folders_fill_popup(PopupMenu *p_popup, const Vect
const bool is_directory = fpath.ends_with("/");
p_popup->add_icon_shortcut(get_editor_theme_icon(SNAME("Terminal")), ED_GET_SHORTCUT("filesystem_dock/open_in_terminal"), FILE_OPEN_IN_TERMINAL);
- p_popup->set_item_text(p_popup->get_item_index(FILE_OPEN_IN_TERMINAL), is_directory ? TTR("Open in Terminal") : TTR("Open Containing Folder in Terminal"));
+ p_popup->set_item_text(p_popup->get_item_index(FILE_OPEN_IN_TERMINAL), is_directory ? TTR("Open in Terminal") : TTR("Open Folder in Terminal"));
if (!is_directory) {
p_popup->add_icon_shortcut(get_editor_theme_icon(SNAME("ExternalLink")), ED_GET_SHORTCUT("filesystem_dock/open_in_external_program"), FILE_OPEN_EXTERNAL);
@@ -3935,7 +3821,7 @@ void FileSystemDock::_project_settings_changed() {
}
void FileSystemDock::set_file_sort(FileSortOption p_file_sort) {
- for (int i = 0; i != FILE_SORT_MAX; i++) {
+ for (int i = 0; i != (int)FileSortOption::FILE_SORT_MAX; i++) {
tree_button_sort->get_popup()->set_item_checked(i, (i == (int)p_file_sort));
file_list_button_sort->get_popup()->set_item_checked(i, (i == (int)p_file_sort));
}
@@ -3965,13 +3851,13 @@ MenuButton *FileSystemDock::_create_file_menu_button() {
PopupMenu *p = button->get_popup();
p->connect(SceneStringName(id_pressed), callable_mp(this, &FileSystemDock::_file_sort_popup));
- p->add_radio_check_item(TTR("Sort by Name (Ascending)"), FILE_SORT_NAME);
- p->add_radio_check_item(TTR("Sort by Name (Descending)"), FILE_SORT_NAME_REVERSE);
- p->add_radio_check_item(TTR("Sort by Type (Ascending)"), FILE_SORT_TYPE);
- p->add_radio_check_item(TTR("Sort by Type (Descending)"), FILE_SORT_TYPE_REVERSE);
- p->add_radio_check_item(TTR("Sort by Last Modified"), FILE_SORT_MODIFIED_TIME);
- p->add_radio_check_item(TTR("Sort by First Modified"), FILE_SORT_MODIFIED_TIME_REVERSE);
- p->set_item_checked(file_sort, true);
+ p->add_radio_check_item(TTR("Sort by Name (Ascending)"), (int)FileSortOption::FILE_SORT_NAME);
+ p->add_radio_check_item(TTR("Sort by Name (Descending)"), (int)FileSortOption::FILE_SORT_NAME_REVERSE);
+ p->add_radio_check_item(TTR("Sort by Type (Ascending)"), (int)FileSortOption::FILE_SORT_TYPE);
+ p->add_radio_check_item(TTR("Sort by Type (Descending)"), (int)FileSortOption::FILE_SORT_TYPE_REVERSE);
+ p->add_radio_check_item(TTR("Sort by Last Modified"), (int)FileSortOption::FILE_SORT_MODIFIED_TIME);
+ p->add_radio_check_item(TTR("Sort by First Modified"), (int)FileSortOption::FILE_SORT_MODIFIED_TIME_REVERSE);
+ p->set_item_checked((int)file_sort, true);
return button;
}
@@ -4041,7 +3927,7 @@ void FileSystemDock::save_layout_to_config(Ref<ConfigFile> p_layout, const Strin
p_layout->set_value(p_section, "dock_filesystem_h_split_offset", get_h_split_offset());
p_layout->set_value(p_section, "dock_filesystem_v_split_offset", get_v_split_offset());
p_layout->set_value(p_section, "dock_filesystem_display_mode", get_display_mode());
- p_layout->set_value(p_section, "dock_filesystem_file_sort", get_file_sort());
+ p_layout->set_value(p_section, "dock_filesystem_file_sort", (int)get_file_sort());
p_layout->set_value(p_section, "dock_filesystem_file_list_display_mode", get_file_list_display_mode());
PackedStringArray selected_files = get_selected_paths();
p_layout->set_value(p_section, "dock_filesystem_selected_paths", selected_files);
@@ -4110,17 +3996,17 @@ FileSystemDock::FileSystemDock() {
// `KeyModifierMask::CMD_OR_CTRL | Key::C` conflicts with other editor shortcuts.
ED_SHORTCUT("filesystem_dock/copy_path", TTR("Copy Path"), KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::SHIFT | Key::C);
- ED_SHORTCUT("filesystem_dock/copy_absolute_path", TTR("Copy Absolute Path"));
- ED_SHORTCUT("filesystem_dock/copy_uid", TTR("Copy UID"));
+ ED_SHORTCUT("filesystem_dock/copy_absolute_path", TTR("Copy Absolute Path"), KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::ALT | Key::C);
+ ED_SHORTCUT("filesystem_dock/copy_uid", TTR("Copy UID"), KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::ALT | KeyModifierMask::SHIFT | Key::C);
ED_SHORTCUT("filesystem_dock/duplicate", TTR("Duplicate..."), KeyModifierMask::CMD_OR_CTRL | Key::D);
ED_SHORTCUT("filesystem_dock/delete", TTR("Delete"), Key::KEY_DELETE);
ED_SHORTCUT("filesystem_dock/rename", TTR("Rename..."), Key::F2);
ED_SHORTCUT_OVERRIDE("filesystem_dock/rename", "macos", Key::ENTER);
#if !defined(ANDROID_ENABLED) && !defined(WEB_ENABLED)
// Opening the system file manager or opening in an external program is not supported on the Android and web editors.
- ED_SHORTCUT("filesystem_dock/show_in_explorer", TTR("Open in File Manager"));
- ED_SHORTCUT("filesystem_dock/open_in_external_program", TTR("Open in External Program"));
- ED_SHORTCUT("filesystem_dock/open_in_terminal", TTR("Open in Terminal"));
+ ED_SHORTCUT("filesystem_dock/show_in_explorer", TTR("Open in File Manager"), KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::ALT | Key::R);
+ ED_SHORTCUT("filesystem_dock/open_in_external_program", TTR("Open in External Program"), KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::ALT | Key::E);
+ ED_SHORTCUT("filesystem_dock/open_in_terminal", TTR("Open in Terminal"), KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::ALT | Key::T);
#endif
// Properly translating color names would require a separate HashMap, so for simplicity they are provided as comments.
@@ -4142,22 +4028,25 @@ FileSystemDock::FileSystemDock() {
add_child(top_vbc);
HBoxContainer *toolbar_hbc = memnew(HBoxContainer);
- toolbar_hbc->add_theme_constant_override("separation", 0);
top_vbc->add_child(toolbar_hbc);
+ HBoxContainer *nav_hbc = memnew(HBoxContainer);
+ nav_hbc->add_theme_constant_override("separation", 0);
+ toolbar_hbc->add_child(nav_hbc);
+
button_hist_prev = memnew(Button);
button_hist_prev->set_flat(true);
button_hist_prev->set_disabled(true);
button_hist_prev->set_focus_mode(FOCUS_NONE);
button_hist_prev->set_tooltip_text(TTR("Go to previous selected folder/file."));
- toolbar_hbc->add_child(button_hist_prev);
+ nav_hbc->add_child(button_hist_prev);
button_hist_next = memnew(Button);
button_hist_next->set_flat(true);
button_hist_next->set_disabled(true);
button_hist_next->set_focus_mode(FOCUS_NONE);
button_hist_next->set_tooltip_text(TTR("Go to next selected folder/file."));
- toolbar_hbc->add_child(button_hist_next);
+ nav_hbc->add_child(button_hist_next);
current_path_line_edit = memnew(LineEdit);
current_path_line_edit->set_structured_text_bidi_override(TextServer::STRUCTURED_TEXT_FILE);
@@ -4180,13 +4069,12 @@ FileSystemDock::FileSystemDock() {
toolbar_hbc->add_child(button_toggle_display_mode);
button_dock_placement = memnew(Button);
- button_dock_placement->set_flat(true);
+ button_dock_placement->set_theme_type_variation("FlatMenuButton");
button_dock_placement->connect(SceneStringName(pressed), callable_mp(this, &FileSystemDock::_change_bottom_dock_placement));
button_dock_placement->hide();
toolbar_hbc->add_child(button_dock_placement);
toolbar2_hbc = memnew(HBoxContainer);
- toolbar2_hbc->add_theme_constant_override("separation", 0);
top_vbc->add_child(toolbar2_hbc);
tree_search_box = memnew(LineEdit);
@@ -4252,7 +4140,7 @@ FileSystemDock::FileSystemDock() {
path_hb->add_child(file_list_button_sort);
button_file_list_display_mode = memnew(Button);
- button_file_list_display_mode->set_flat(true);
+ button_file_list_display_mode->set_theme_type_variation("FlatMenuButton");
path_hb->add_child(button_file_list_display_mode);
files = memnew(FileSystemList);
@@ -4319,17 +4207,6 @@ FileSystemDock::FileSystemDock() {
overwrite_dialog_footer = memnew(Label);
overwrite_dialog_vb->add_child(overwrite_dialog_footer);
- duplicate_dialog = memnew(ConfirmationDialog);
- VBoxContainer *duplicate_dialog_vb = memnew(VBoxContainer);
- duplicate_dialog->add_child(duplicate_dialog_vb);
-
- duplicate_dialog_text = memnew(LineEdit);
- duplicate_dialog_vb->add_margin_child(TTR("Name:"), duplicate_dialog_text);
- duplicate_dialog->set_ok_button_text(TTR("Duplicate"));
- add_child(duplicate_dialog);
- duplicate_dialog->register_text_enter(duplicate_dialog_text);
- duplicate_dialog->connect(SceneStringName(confirmed), callable_mp(this, &FileSystemDock::_duplicate_operation_confirm));
-
make_dir_dialog = memnew(DirectoryCreateDialog);
add_child(make_dir_dialog);