From 40d1866b051f24b42e5de37c08b300214a0092a6 Mon Sep 17 00:00:00 2001 From: MillionOstrich <31486600+MillionOstrich@users.noreply.github.com> Date: Sun, 1 Oct 2017 23:24:49 +0100 Subject: [PATCH] Rework DependencyRemoveDialog for deleting folders DependencyRemoveDialog now takes two lists (files and folders) to delete. Sort the folders above files in DependencyRemoveDialog & use some more icons. Stop files which will be deleted from also being listed as having broken dependencies. Add right-click option for removing folder to filesystem folder tree. --- editor/dependency_editor.cpp | 158 +++++++++++++++++++++++------------ editor/dependency_editor.h | 27 +++++- editor/filesystem_dock.cpp | 37 ++++---- editor/filesystem_dock.h | 1 + 4 files changed, 151 insertions(+), 72 deletions(-) diff --git a/editor/dependency_editor.cpp b/editor/dependency_editor.cpp index 5305c4f256f..64f1c4ccb26 100644 --- a/editor/dependency_editor.cpp +++ b/editor/dependency_editor.cpp @@ -337,92 +337,142 @@ DependencyEditorOwners::DependencyEditorOwners() { /////////////////////// -void DependencyRemoveDialog::_fill_owners(EditorFileSystemDirectory *efsd) { +void DependencyRemoveDialog::_find_files_in_removed_folder(EditorFileSystemDirectory *efsd, const String &p_folder) { + if (!efsd) + return; + for (int i = 0; i < efsd->get_subdir_count(); ++i) { + _find_files_in_removed_folder(efsd->get_subdir(i), p_folder); + } + for (int i = 0; i < efsd->get_file_count(); i++) { + String file = efsd->get_file_path(i); + ERR_FAIL_COND(all_remove_files.has(file)); //We are deleting a directory which is contained in a directory we are deleting... + all_remove_files[file] = p_folder; //Point the file to the ancestor directory we are deleting so we know what to parent it under in the tree. + } +} + +void DependencyRemoveDialog::_find_all_removed_dependencies(EditorFileSystemDirectory *efsd, Vector &p_removed) { if (!efsd) return; for (int i = 0; i < efsd->get_subdir_count(); i++) { - _fill_owners(efsd->get_subdir(i)); + _find_all_removed_dependencies(efsd->get_subdir(i), p_removed); } for (int i = 0; i < efsd->get_file_count(); i++) { + const String path = efsd->get_file_path(i); - Vector deps = efsd->get_file_deps(i); - //print_line(":::"+efsd->get_file_path(i)); - Set met; - for (int j = 0; j < deps.size(); j++) { - if (files.has(deps[j])) { - met.insert(deps[j]); - } - } - if (!met.size()) + //It doesn't matter if a file we are about to delete will have some of its dependencies removed too + if (all_remove_files.has(path)) continue; - exist = true; - - Ref icon; - String type = efsd->get_file_type(i); - if (!has_icon(type, "EditorIcons")) { - icon = get_icon("Object", "EditorIcons"); - } else { - icon = get_icon(type, "EditorIcons"); - } - - for (Set::Element *E = met.front(); E; E = E->next()) { - - String which = E->get(); - if (!files[which]) { - TreeItem *ti = owners->create_item(owners->get_root()); - ti->set_text(0, which.get_file()); - files[which] = ti; + Vector all_deps = efsd->get_file_deps(i); + for (int j = 0; j < all_deps.size(); ++j) { + if (all_remove_files.has(all_deps[j])) { + RemovedDependency dep; + dep.file = path; + dep.file_type = efsd->get_file_type(i); + dep.dependency = all_deps[j]; + dep.dependency_folder = all_remove_files[all_deps[j]]; + p_removed.push_back(dep); } - TreeItem *ti = owners->create_item(files[which]); - ti->set_text(0, efsd->get_file_path(i)); - ti->set_icon(0, icon); } } } -void DependencyRemoveDialog::show(const Vector &to_erase) { - - exist = false; +void DependencyRemoveDialog::_build_removed_dependency_tree(const Vector &p_removed) { owners->clear(); - files.clear(); owners->create_item(); // root - for (int i = 0; i < to_erase.size(); i++) { - files[to_erase[i]] = NULL; + + Map tree_items; + for (int i = 0; i < p_removed.size(); i++) { + RemovedDependency rd = p_removed[i]; + + //Ensure that the dependency is already in the tree + if (!tree_items.has(rd.dependency)) { + if (rd.dependency_folder.length() > 0) { + //Ensure the ancestor folder is already in the tree + if (!tree_items.has(rd.dependency_folder)) { + TreeItem *folder_item = owners->create_item(owners->get_root()); + folder_item->set_text(0, rd.dependency_folder); + folder_item->set_icon(0, get_icon("Folder", "EditorIcons")); + tree_items[rd.dependency_folder] = folder_item; + } + TreeItem *dependency_item = owners->create_item(tree_items[rd.dependency_folder]); + dependency_item->set_text(0, rd.dependency); + dependency_item->set_icon(0, get_icon("Warning", "EditorIcons")); + tree_items[rd.dependency] = dependency_item; + } else { + TreeItem *dependency_item = owners->create_item(owners->get_root()); + dependency_item->set_text(0, rd.dependency); + dependency_item->set_icon(0, get_icon("Warning", "EditorIcons")); + tree_items[rd.dependency] = dependency_item; + } + } + + //List this file under this dependency + Ref icon = has_icon(rd.file_type, "EditorIcons") ? get_icon(rd.file_type, "EditorIcons") : get_icon("Object", "EditorIcons"); + TreeItem *file_item = owners->create_item(tree_items[rd.dependency]); + file_item->set_text(0, rd.file); + file_item->set_icon(0, icon); + } +} + +void DependencyRemoveDialog::show(const Vector &p_folders, const Vector &p_files) { + all_remove_files.clear(); + to_delete.clear(); + owners->clear(); + + for (int i = 0; i < p_folders.size(); ++i) { + String folder = p_folders[i].ends_with("/") ? p_folders[i] : (p_folders[i] + "/"); + _find_files_in_removed_folder(EditorFileSystem::get_singleton()->get_filesystem_path(folder), folder); + to_delete.push_back(folder); + } + for (int i = 0; i < p_files.size(); ++i) { + all_remove_files[p_files[i]] = String(); + to_delete.push_back(p_files[i]); } - _fill_owners(EditorFileSystem::get_singleton()->get_filesystem()); + Vector removed_deps; + _find_all_removed_dependencies(EditorFileSystem::get_singleton()->get_filesystem(), removed_deps); + removed_deps.sort(); - if (exist) { - owners->show(); - text->set_text(TTR("The files being removed are required by other resources in order for them to work.\nRemove them anyway? (no undo)")); - popup_centered_minsize(Size2(500, 220)); - } else { + if (removed_deps.empty()) { owners->hide(); text->set_text(TTR("Remove selected files from the project? (no undo)")); popup_centered_minsize(Size2(400, 100)); + } else { + _build_removed_dependency_tree(removed_deps); + owners->show(); + text->set_text(TTR("The files being removed are required by other resources in order for them to work.\nRemove them anyway? (no undo)")); + popup_centered_minsize(Size2(500, 350)); } } void DependencyRemoveDialog::ok_pressed() { - - bool changed = false; - - for (Map::Element *E = files.front(); E; E = E->next()) { - - if (ResourceCache::has(E->key())) { - Resource *res = ResourceCache::get(E->key()); + bool files_only = true; + for (int i = 0; i < to_delete.size(); ++i) { + if (to_delete[i].ends_with("/")) { + files_only = false; + } else if (ResourceCache::has(to_delete[i])) { + Resource *res = ResourceCache::get(to_delete[i]); res->set_path(""); //clear reference to path } - String fpath = OS::get_singleton()->get_resource_dir() + E->key().replace_first("res://", "/"); - OS::get_singleton()->move_to_trash(fpath); - changed = true; + + String path = OS::get_singleton()->get_resource_dir() + to_delete[i].replace_first("res://", "/"); + print_line("Moving to trash: " + path); + Error err = OS::get_singleton()->move_to_trash(path); + if (err != OK) { + EditorNode::get_singleton()->add_io_error(TTR("Cannot remove:\n") + to_delete[i] + "\n"); + } } - if (changed) { + if (files_only) { + //If we only deleted files we should only need to tell the file system about the files we touched. + for (int i = 0; i < to_delete.size(); ++i) { + EditorFileSystem::get_singleton()->update_file(to_delete[i]); + } + } else { EditorFileSystem::get_singleton()->scan_changes(); } } diff --git a/editor/dependency_editor.h b/editor/dependency_editor.h index 4dfb9de2685..c7e9baa5c2c 100644 --- a/editor/dependency_editor.h +++ b/editor/dependency_editor.h @@ -84,14 +84,33 @@ class DependencyRemoveDialog : public ConfirmationDialog { Label *text; Tree *owners; - bool exist; - Map files; - void _fill_owners(EditorFileSystemDirectory *efsd); + + Map all_remove_files; + Vector to_delete; + + struct RemovedDependency { + String file; + String file_type; + String dependency; + String dependency_folder; + + bool operator<(const RemovedDependency &p_other) const { + if (dependency_folder.empty() != p_other.dependency_folder.empty()) { + return p_other.dependency_folder.empty(); + } else { + return dependency < p_other.dependency; + } + } + }; + + void _find_files_in_removed_folder(EditorFileSystemDirectory *efsd, const String &p_folder); + void _find_all_removed_dependencies(EditorFileSystemDirectory *efsd, Vector &p_removed); + void _build_removed_dependency_tree(const Vector &p_removed); void ok_pressed(); public: - void show(const Vector &to_erase); + void show(const Vector &p_folders, const Vector &p_files); DependencyRemoveDialog(); }; diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp index 028ea395ce9..d1b79cca170 100644 --- a/editor/filesystem_dock.cpp +++ b/editor/filesystem_dock.cpp @@ -937,26 +937,25 @@ void FileSystemDock::_file_option(int p_option) { rename_dialog_text->grab_focus(); } break; case FILE_REMOVE: { - - Vector torem; + Vector remove_files; + Vector remove_folders; for (int i = 0; i < files->get_item_count(); i++) { - String path = files->get_item_metadata(i); - if (!files->is_selected(i)) - continue; - torem.push_back(path); + if (files->is_selected(i) && path != "res://") { + if (path.ends_with("/")) { + remove_folders.push_back(path); + } else { + remove_files.push_back(path); + } + } } - if (torem.empty()) { - EditorNode::get_singleton()->show_warning(TTR("No files selected!")); - break; + if (remove_files.size() + remove_folders.size() > 0) { + remove_dialog->show(remove_folders, remove_files); + //1) find if used + //2) warn } - - remove_dialog->show(torem); - //1) find if used - //2) warn - } break; case FILE_INFO: { @@ -1044,6 +1043,15 @@ void FileSystemDock::_folder_option(int p_option) { rename_dialog_text->grab_focus(); } } break; + case FOLDER_REMOVE: { + Vector remove_folders; + Vector remove_files; + String path = item->get_metadata(tree->get_selected_column()); + if (path != "res://") { + remove_folders.push_back(path); + remove_dialog->show(remove_folders, remove_files); + } + } break; case FOLDER_COPY_PATH: { String path = item->get_metadata(tree->get_selected_column()); OS::get_singleton()->set_clipboard(path); @@ -1099,6 +1107,7 @@ void FileSystemDock::_dir_rmb_pressed(const Vector2 &p_pos) { if (fpath != "res://") { folder_options->add_item(TTR("Rename.."), FOLDER_RENAME); folder_options->add_item(TTR("Move To.."), FOLDER_MOVE); + folder_options->add_item(TTR("Delete"), FOLDER_REMOVE); } folder_options->add_separator(); folder_options->add_item(TTR("Show In File Manager"), FOLDER_SHOW_IN_EXPLORER); diff --git a/editor/filesystem_dock.h b/editor/filesystem_dock.h index 1491e1c7a74..e2d1a691377 100644 --- a/editor/filesystem_dock.h +++ b/editor/filesystem_dock.h @@ -81,6 +81,7 @@ private: FOLDER_COLLAPSE_ALL, FOLDER_MOVE, FOLDER_RENAME, + FOLDER_REMOVE, FOLDER_SHOW_IN_EXPLORER, FOLDER_COPY_PATH };