Improve file move and copy operations
This commit is contained in:
parent
5922b2149e
commit
4941d5f534
|
@ -30,11 +30,14 @@
|
|||
|
||||
#include "editor_dir_dialog.h"
|
||||
|
||||
#include "core/io/dir_access.h"
|
||||
#include "core/os/keyboard.h"
|
||||
#include "core/os/os.h"
|
||||
#include "editor/editor_file_system.h"
|
||||
#include "editor/editor_scale.h"
|
||||
#include "editor/editor_settings.h"
|
||||
#include "scene/gui/check_box.h"
|
||||
#include "scene/gui/tree.h"
|
||||
#include "servers/display_server.h"
|
||||
|
||||
void EditorDirDialog::_update_dir(TreeItem *p_item, EditorFileSystemDirectory *p_dir, const String &p_select_path) {
|
||||
|
@ -56,8 +59,6 @@ void EditorDirDialog::_update_dir(TreeItem *p_item, EditorFileSystemDirectory *p
|
|||
p_item->set_text(0, p_dir->get_name());
|
||||
}
|
||||
|
||||
//this should be handled by EditorFileSystem already
|
||||
//bool show_hidden = EDITOR_GET("filesystem/file_dialog/show_hidden_files");
|
||||
updating = false;
|
||||
for (int i = 0; i < p_dir->get_subdir_count(); i++) {
|
||||
TreeItem *ti = tree->create_item(p_item);
|
||||
|
@ -78,6 +79,10 @@ void EditorDirDialog::reload(const String &p_path) {
|
|||
must_reload = false;
|
||||
}
|
||||
|
||||
bool EditorDirDialog::is_copy_pressed() const {
|
||||
return copy->is_pressed();
|
||||
}
|
||||
|
||||
void EditorDirDialog::_notification(int p_what) {
|
||||
switch (p_what) {
|
||||
case NOTIFICATION_ENTER_TREE: {
|
||||
|
@ -107,6 +112,14 @@ void EditorDirDialog::_notification(int p_what) {
|
|||
}
|
||||
}
|
||||
|
||||
void EditorDirDialog::_copy_toggled(bool p_pressed) {
|
||||
if (p_pressed) {
|
||||
set_ok_button_text(TTR("Copy"));
|
||||
} else {
|
||||
set_ok_button_text(TTR("Move"));
|
||||
}
|
||||
}
|
||||
|
||||
void EditorDirDialog::_item_collapsed(Object *p_item) {
|
||||
TreeItem *item = Object::cast_to<TreeItem>(p_item);
|
||||
|
||||
|
@ -172,8 +185,7 @@ void EditorDirDialog::_make_dir_confirm() {
|
|||
mkdirerr->popup_centered(Size2(250, 80) * EDSCALE);
|
||||
} else {
|
||||
opened_paths.insert(dir);
|
||||
//reload(dir.path_join(makedirname->get_text()));
|
||||
EditorFileSystem::get_singleton()->scan_changes(); //we created a dir, so rescan changes
|
||||
EditorFileSystem::get_singleton()->scan_changes(); // We created a dir, so rescan changes.
|
||||
}
|
||||
makedirname->set_text(""); // reset label
|
||||
}
|
||||
|
@ -186,11 +198,19 @@ EditorDirDialog::EditorDirDialog() {
|
|||
set_title(TTR("Choose a Directory"));
|
||||
set_hide_on_ok(false);
|
||||
|
||||
tree = memnew(Tree);
|
||||
add_child(tree);
|
||||
VBoxContainer *vb = memnew(VBoxContainer);
|
||||
add_child(vb);
|
||||
|
||||
tree = memnew(Tree);
|
||||
vb->add_child(tree);
|
||||
tree->set_v_size_flags(Control::SIZE_EXPAND_FILL);
|
||||
tree->connect("item_activated", callable_mp(this, &EditorDirDialog::_item_activated));
|
||||
|
||||
copy = memnew(CheckBox);
|
||||
vb->add_child(copy);
|
||||
copy->set_text(TTR("Copy File(s)"));
|
||||
copy->connect("toggled", callable_mp(this, &EditorDirDialog::_copy_toggled));
|
||||
|
||||
makedir = add_button(TTR("Create Folder"), DisplayServer::get_singleton()->get_swap_cancel_ok(), "makedir");
|
||||
makedir->connect("pressed", callable_mp(this, &EditorDirDialog::_make_dir));
|
||||
|
||||
|
@ -200,7 +220,6 @@ EditorDirDialog::EditorDirDialog() {
|
|||
|
||||
VBoxContainer *makevb = memnew(VBoxContainer);
|
||||
makedialog->add_child(makevb);
|
||||
//makedialog->set_child_rect(makevb);
|
||||
|
||||
makedirname = memnew(LineEdit);
|
||||
makevb->add_margin_child(TTR("Name:"), makedirname);
|
||||
|
@ -211,5 +230,5 @@ EditorDirDialog::EditorDirDialog() {
|
|||
mkdirerr->set_text(TTR("Could not create folder."));
|
||||
add_child(mkdirerr);
|
||||
|
||||
set_ok_button_text(TTR("Choose"));
|
||||
set_ok_button_text(TTR("Move"));
|
||||
}
|
||||
|
|
|
@ -31,10 +31,12 @@
|
|||
#ifndef EDITOR_DIR_DIALOG_H
|
||||
#define EDITOR_DIR_DIALOG_H
|
||||
|
||||
#include "core/io/dir_access.h"
|
||||
#include "editor/editor_file_system.h"
|
||||
#include "scene/gui/dialogs.h"
|
||||
#include "scene/gui/tree.h"
|
||||
|
||||
class CheckBox;
|
||||
class EditorFileSystemDirectory;
|
||||
class Tree;
|
||||
class TreeItem;
|
||||
|
||||
class EditorDirDialog : public ConfirmationDialog {
|
||||
GDCLASS(EditorDirDialog, ConfirmationDialog);
|
||||
|
@ -48,7 +50,9 @@ class EditorDirDialog : public ConfirmationDialog {
|
|||
|
||||
Tree *tree = nullptr;
|
||||
bool updating = false;
|
||||
CheckBox *copy = nullptr;
|
||||
|
||||
void _copy_toggled(bool p_pressed);
|
||||
void _item_collapsed(Object *p_item);
|
||||
void _item_activated();
|
||||
void _update_dir(TreeItem *p_item, EditorFileSystemDirectory *p_dir, const String &p_select_path = String());
|
||||
|
@ -66,6 +70,8 @@ protected:
|
|||
|
||||
public:
|
||||
void reload(const String &p_path = "");
|
||||
bool is_copy_pressed() const;
|
||||
|
||||
EditorDirDialog();
|
||||
};
|
||||
|
||||
|
|
|
@ -1454,6 +1454,29 @@ void FileSystemDock::_update_project_settings_after_move(const HashMap<String, S
|
|||
ProjectSettings::get_singleton()->save();
|
||||
}
|
||||
|
||||
String FileSystemDock::_get_unique_name(const FileOrFolder &p_entry, const String &p_at_path) {
|
||||
String new_path;
|
||||
String new_path_base;
|
||||
|
||||
if (p_entry.is_file) {
|
||||
new_path = p_at_path.path_join(p_entry.path.get_file());
|
||||
new_path_base = new_path.get_basename() + " (%d)." + new_path.get_extension();
|
||||
} else {
|
||||
PackedStringArray path_split = p_entry.path.split("/");
|
||||
new_path = p_at_path.path_join(path_split[path_split.size() - 2]);
|
||||
new_path_base = new_path + " (%d)";
|
||||
}
|
||||
|
||||
int exist_counter = 1;
|
||||
Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_RESOURCES);
|
||||
while (da->file_exists(new_path) || da->dir_exists(new_path)) {
|
||||
exist_counter++;
|
||||
new_path = vformat(new_path_base, exist_counter);
|
||||
}
|
||||
|
||||
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;
|
||||
|
@ -1658,8 +1681,9 @@ void FileSystemDock::_duplicate_operation_confirm() {
|
|||
_rescan();
|
||||
}
|
||||
|
||||
void FileSystemDock::_move_with_overwrite() {
|
||||
_move_operation_confirm(to_move_path, true);
|
||||
void FileSystemDock::_overwrite_dialog_action(bool p_overwrite) {
|
||||
overwrite_dialog->hide();
|
||||
_move_operation_confirm(to_move_path, to_move_or_copy, p_overwrite ? OVERWRITE_REPLACE : OVERWRITE_RENAME);
|
||||
}
|
||||
|
||||
Vector<String> FileSystemDock::_check_existing() {
|
||||
|
@ -1681,14 +1705,21 @@ Vector<String> FileSystemDock::_check_existing() {
|
|||
return conflicting_items;
|
||||
}
|
||||
|
||||
void FileSystemDock::_move_operation_confirm(const String &p_to_path, bool p_overwrite) {
|
||||
if (!p_overwrite) {
|
||||
void FileSystemDock::_move_dialog_confirm(const String &p_path) {
|
||||
_move_operation_confirm(p_path, move_dialog->is_copy_pressed());
|
||||
}
|
||||
|
||||
void FileSystemDock::_move_operation_confirm(const String &p_to_path, bool p_copy, Overwrite p_overwrite) {
|
||||
if (p_overwrite == OVERWRITE_UNDECIDED) {
|
||||
to_move_path = p_to_path;
|
||||
to_move_or_copy = p_copy;
|
||||
|
||||
Vector<String> conflicting_items = _check_existing();
|
||||
if (!conflicting_items.is_empty()) {
|
||||
// Ask to do something.
|
||||
overwrite_dialog->set_text(vformat(
|
||||
TTR("The following files or folders conflict with items in the target location '%s':\n\n%s\n\nDo you wish to overwrite them?"),
|
||||
p_copy ? TTR("The following files or folders conflict with items in the target location '%s':\n\n%s\n\nDo you wish to overwrite them or rename the copied files?")
|
||||
: TTR("The following files or folders conflict with items in the target location '%s':\n\n%s\n\nDo you wish to overwrite them or rename the moved files?"),
|
||||
to_move_path,
|
||||
String("\n").join(conflicting_items)));
|
||||
overwrite_dialog->popup_centered();
|
||||
|
@ -1696,43 +1727,71 @@ void FileSystemDock::_move_operation_confirm(const String &p_to_path, bool p_ove
|
|||
}
|
||||
}
|
||||
|
||||
// Check groups.
|
||||
Vector<String> new_paths;
|
||||
new_paths.resize(to_move.size());
|
||||
for (int i = 0; i < to_move.size(); i++) {
|
||||
if (to_move[i].is_file && EditorFileSystem::get_singleton()->is_group_file(to_move[i].path)) {
|
||||
EditorFileSystem::get_singleton()->move_group_file(to_move[i].path, p_to_path.path_join(to_move[i].path.get_file()));
|
||||
if (p_overwrite == OVERWRITE_RENAME) {
|
||||
new_paths.write[i] = _get_unique_name(to_move[i], p_to_path);
|
||||
} else {
|
||||
new_paths.write[i] = p_to_path.path_join(to_move[i].path.get_file());
|
||||
}
|
||||
}
|
||||
|
||||
HashMap<String, String> file_renames;
|
||||
HashMap<String, String> folder_renames;
|
||||
bool is_moved = false;
|
||||
for (int i = 0; i < to_move.size(); i++) {
|
||||
String old_path = to_move[i].path.ends_with("/") ? to_move[i].path.substr(0, to_move[i].path.length() - 1) : to_move[i].path;
|
||||
String new_path = p_to_path.path_join(old_path.get_file());
|
||||
if (old_path != new_path) {
|
||||
_try_move_item(to_move[i], new_path, file_renames, folder_renames);
|
||||
is_moved = true;
|
||||
if (p_copy) {
|
||||
bool is_copied = false;
|
||||
for (int i = 0; i < to_move.size(); i++) {
|
||||
String old_path = to_move[i].path.ends_with("/") ? to_move[i].path.substr(0, to_move[i].path.length() - 1) : to_move[i].path;
|
||||
const String &new_path = new_paths[i];
|
||||
|
||||
if (old_path != new_path) {
|
||||
_try_duplicate_item(to_move[i], new_paths[i]);
|
||||
is_copied = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (is_moved) {
|
||||
int current_tab = EditorNode::get_singleton()->get_current_tab();
|
||||
_save_scenes_after_move(file_renames); // Save scenes before updating.
|
||||
_update_dependencies_after_move(file_renames);
|
||||
_update_resource_paths_after_move(file_renames);
|
||||
_update_project_settings_after_move(file_renames);
|
||||
_update_favorites_list_after_move(file_renames, folder_renames);
|
||||
if (is_copied) {
|
||||
_rescan();
|
||||
}
|
||||
} else {
|
||||
// Check groups.
|
||||
for (int i = 0; i < to_move.size(); i++) {
|
||||
if (to_move[i].is_file && EditorFileSystem::get_singleton()->is_group_file(to_move[i].path)) {
|
||||
EditorFileSystem::get_singleton()->move_group_file(to_move[i].path, new_paths[i]);
|
||||
}
|
||||
}
|
||||
|
||||
EditorNode::get_singleton()->set_current_tab(current_tab);
|
||||
bool is_moved = false;
|
||||
HashMap<String, String> file_renames;
|
||||
HashMap<String, String> folder_renames;
|
||||
|
||||
print_verbose("FileSystem: calling rescan.");
|
||||
_rescan();
|
||||
for (int i = 0; i < to_move.size(); i++) {
|
||||
String old_path = to_move[i].path.ends_with("/") ? to_move[i].path.substr(0, to_move[i].path.length() - 1) : to_move[i].path;
|
||||
const String &new_path = new_paths[i];
|
||||
if (old_path != new_path) {
|
||||
_try_move_item(to_move[i], new_path, file_renames, folder_renames);
|
||||
is_moved = true;
|
||||
}
|
||||
}
|
||||
|
||||
print_verbose("FileSystem: saving moved scenes.");
|
||||
_save_scenes_after_move(file_renames);
|
||||
if (is_moved) {
|
||||
int current_tab = EditorNode::get_singleton()->get_current_tab();
|
||||
_save_scenes_after_move(file_renames); // Save scenes before updating.
|
||||
_update_dependencies_after_move(file_renames);
|
||||
_update_resource_paths_after_move(file_renames);
|
||||
_update_project_settings_after_move(file_renames);
|
||||
_update_favorites_list_after_move(file_renames, folder_renames);
|
||||
|
||||
path = p_to_path;
|
||||
current_path->set_text(path);
|
||||
EditorNode::get_singleton()->set_current_tab(current_tab);
|
||||
|
||||
print_verbose("FileSystem: calling rescan.");
|
||||
_rescan();
|
||||
|
||||
print_verbose("FileSystem: saving moved scenes.");
|
||||
_save_scenes_after_move(file_renames);
|
||||
|
||||
path = p_to_path;
|
||||
current_path->set_text(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1950,7 +2009,7 @@ void FileSystemDock::_file_option(int p_option, const Vector<String> &p_selected
|
|||
} break;
|
||||
|
||||
case FILE_MOVE: {
|
||||
// Move the files to a given location.
|
||||
// Move or copy the files to a given location.
|
||||
to_move.clear();
|
||||
Vector<String> collapsed_paths = _remove_self_included_paths(p_selected);
|
||||
for (int i = collapsed_paths.size() - 1; i >= 0; i--) {
|
||||
|
@ -1960,7 +2019,7 @@ void FileSystemDock::_file_option(int p_option, const Vector<String> &p_selected
|
|||
}
|
||||
}
|
||||
if (to_move.size() > 0) {
|
||||
move_dialog->popup_centered_ratio();
|
||||
move_dialog->popup_centered_ratio(0.4);
|
||||
}
|
||||
} break;
|
||||
|
||||
|
@ -2425,28 +2484,7 @@ void FileSystemDock::drop_data_fw(const Point2 &p_point, const Variant &p_data,
|
|||
}
|
||||
if (!to_move.is_empty()) {
|
||||
if (Input::get_singleton()->is_key_pressed(Key::CTRL)) {
|
||||
for (int i = 0; i < to_move.size(); i++) {
|
||||
String new_path;
|
||||
String new_path_base;
|
||||
|
||||
if (to_move[i].is_file) {
|
||||
new_path = to_dir.path_join(to_move[i].path.get_file());
|
||||
new_path_base = new_path.get_basename() + " (%d)." + new_path.get_extension();
|
||||
} else {
|
||||
PackedStringArray path_split = to_move[i].path.split("/");
|
||||
new_path = to_dir.path_join(path_split[path_split.size() - 2]);
|
||||
new_path_base = new_path + " (%d)";
|
||||
}
|
||||
|
||||
int exist_counter = 1;
|
||||
Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_RESOURCES);
|
||||
while (da->file_exists(new_path) || da->dir_exists(new_path)) {
|
||||
exist_counter++;
|
||||
new_path = vformat(new_path_base, exist_counter);
|
||||
}
|
||||
_try_duplicate_item(to_move[i], new_path);
|
||||
}
|
||||
_rescan();
|
||||
_move_operation_confirm(to_dir, true);
|
||||
} else {
|
||||
_move_operation_confirm(to_dir);
|
||||
}
|
||||
|
@ -2637,7 +2675,7 @@ void FileSystemDock::_file_and_folders_fill_popup(PopupMenu *p_popup, Vector<Str
|
|||
}
|
||||
|
||||
if (p_paths.size() > 1 || p_paths[0] != "res://") {
|
||||
p_popup->add_icon_item(get_theme_icon(SNAME("MoveUp"), SNAME("EditorIcons")), TTR("Move To..."), FILE_MOVE);
|
||||
p_popup->add_icon_item(get_theme_icon(SNAME("MoveUp"), SNAME("EditorIcons")), TTR("Move/Duplicate To..."), FILE_MOVE);
|
||||
p_popup->add_icon_shortcut(get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")), ED_GET_SHORTCUT("filesystem_dock/delete"), FILE_REMOVE);
|
||||
}
|
||||
|
||||
|
@ -3278,9 +3316,8 @@ FileSystemDock::FileSystemDock() {
|
|||
add_child(remove_dialog);
|
||||
|
||||
move_dialog = memnew(EditorDirDialog);
|
||||
move_dialog->set_ok_button_text(TTR("Move"));
|
||||
add_child(move_dialog);
|
||||
move_dialog->connect("dir_selected", callable_mp(this, &FileSystemDock::_move_operation_confirm).bind(false));
|
||||
move_dialog->connect("dir_selected", callable_mp(this, &FileSystemDock::_move_dialog_confirm));
|
||||
|
||||
rename_dialog = memnew(ConfirmationDialog);
|
||||
VBoxContainer *rename_dialog_vb = memnew(VBoxContainer);
|
||||
|
@ -3294,9 +3331,10 @@ FileSystemDock::FileSystemDock() {
|
|||
rename_dialog->connect("confirmed", callable_mp(this, &FileSystemDock::_rename_operation_confirm));
|
||||
|
||||
overwrite_dialog = memnew(ConfirmationDialog);
|
||||
overwrite_dialog->set_ok_button_text(TTR("Overwrite"));
|
||||
add_child(overwrite_dialog);
|
||||
overwrite_dialog->connect("confirmed", callable_mp(this, &FileSystemDock::_move_with_overwrite));
|
||||
overwrite_dialog->set_ok_button_text(TTR("Overwrite"));
|
||||
overwrite_dialog->add_button(TTR("Keep Both"), true)->connect("pressed", callable_mp(this, &FileSystemDock::_overwrite_dialog_action).bind(false));
|
||||
overwrite_dialog->connect("confirmed", callable_mp(this, &FileSystemDock::_overwrite_dialog_action).bind(true));
|
||||
|
||||
duplicate_dialog = memnew(ConfirmationDialog);
|
||||
VBoxContainer *duplicate_dialog_vb = memnew(VBoxContainer);
|
||||
|
|
|
@ -104,6 +104,12 @@ private:
|
|||
FILE_NEW_SCENE,
|
||||
};
|
||||
|
||||
enum Overwrite {
|
||||
OVERWRITE_UNDECIDED,
|
||||
OVERWRITE_REPLACE,
|
||||
OVERWRITE_RENAME,
|
||||
};
|
||||
|
||||
FileSortOption file_sort = FILE_SORT_NAME;
|
||||
|
||||
VBoxContainer *scanning_vb = nullptr;
|
||||
|
@ -173,6 +179,7 @@ private:
|
|||
FileOrFolder to_duplicate;
|
||||
Vector<FileOrFolder> to_move;
|
||||
String to_move_path;
|
||||
bool to_move_or_copy = false;
|
||||
|
||||
Vector<String> history;
|
||||
int history_pos;
|
||||
|
@ -227,6 +234,7 @@ private:
|
|||
void _save_scenes_after_move(const HashMap<String, String> &p_renames) const;
|
||||
void _update_favorites_list_after_move(const HashMap<String, String> &p_files_renames, const HashMap<String, String> &p_folders_renames) const;
|
||||
void _update_project_settings_after_move(const HashMap<String, String> &p_renames) const;
|
||||
String _get_unique_name(const FileOrFolder &p_entry, const String &p_at_path);
|
||||
|
||||
void _resource_removed(const Ref<Resource> &p_resource);
|
||||
void _file_removed(String p_file);
|
||||
|
@ -237,9 +245,10 @@ private:
|
|||
void _make_scene_confirm();
|
||||
void _rename_operation_confirm();
|
||||
void _duplicate_operation_confirm();
|
||||
void _move_with_overwrite();
|
||||
void _overwrite_dialog_action(bool p_overwrite);
|
||||
Vector<String> _check_existing();
|
||||
void _move_operation_confirm(const String &p_to_path, bool p_overwrite = false);
|
||||
void _move_dialog_confirm(const String &p_path);
|
||||
void _move_operation_confirm(const String &p_to_path, bool p_copy = false, Overwrite p_overwrite = OVERWRITE_UNDECIDED);
|
||||
|
||||
void _tree_rmb_option(int p_option);
|
||||
void _file_list_rmb_option(int p_option);
|
||||
|
|
Loading…
Reference in New Issue