Ver código fonte

Merge pull request #80473 from KoBeWi/they're_the_same_picture

Unify make dir and duplicate dialogs
Rémi Verschelde 11 meses atrás
pai
commit
3b41f73105

+ 61 - 33
editor/directory_create_dialog.cpp

@@ -39,33 +39,48 @@
 #include "scene/gui/label.h"
 #include "scene/gui/line_edit.h"
 
-static String sanitize_input(const String &p_path) {
+String DirectoryCreateDialog::_sanitize_input(const String &p_path) const {
 	String path = p_path.strip_edges();
-	if (path.ends_with("/")) {
-		path = path.left(path.length() - 1);
+	if (mode == MODE_DIRECTORY) {
+		path = path.trim_suffix("/");
 	}
 	return path;
 }
 
 String DirectoryCreateDialog::_validate_path(const String &p_path) const {
 	if (p_path.is_empty()) {
-		return TTR("Folder name cannot be empty.");
+		return TTR("Name cannot be empty.");
 	}
-
-	if (p_path.contains("\\") || p_path.contains(":") || p_path.contains("*") ||
-			p_path.contains("|") || p_path.contains(">")) {
-		return TTR("Folder name contains invalid characters.");
+	if (mode == MODE_FILE && p_path.ends_with("/")) {
+		return TTR("File name can't end with /.");
 	}
 
-	for (const String &part : p_path.split("/")) {
+	const PackedStringArray splits = p_path.split("/");
+	for (int i = 0; i < splits.size(); i++) {
+		const String &part = splits[i];
+		bool is_file = mode == MODE_FILE && i == splits.size() - 1;
+
 		if (part.is_empty()) {
-			return TTR("Folder name cannot be empty.");
+			if (is_file) {
+				return TTR("File name cannot be empty.");
+			} else {
+				return TTR("Folder name cannot be empty.");
+			}
 		}
-		if (part.ends_with(" ") || part[0] == ' ') {
-			return TTR("Folder name cannot begin or end with a space.");
+		if (part.contains("\\") || part.contains(":") || part.contains("*") ||
+				part.contains("|") || part.contains(">") || part.ends_with(".") || part.ends_with(" ")) {
+			if (is_file) {
+				return TTR("File name contains invalid characters.");
+			} else {
+				return TTR("Folder name contains invalid characters.");
+			}
 		}
 		if (part[0] == '.') {
-			return TTR("Folder name cannot begin with a dot.");
+			if (is_file) {
+				return TTR("File name begins with a dot.");
+			} else {
+				return TTR("Folder name begins with a dot.");
+			}
 		}
 	}
 
@@ -82,12 +97,18 @@ String DirectoryCreateDialog::_validate_path(const String &p_path) const {
 }
 
 void DirectoryCreateDialog::_on_dir_path_changed() {
-	const String path = sanitize_input(dir_path->get_text());
+	const String path = _sanitize_input(dir_path->get_text());
 	const String error = _validate_path(path);
 
 	if (error.is_empty()) {
 		if (path.contains("/")) {
-			validation_panel->set_message(EditorValidationPanel::MSG_ID_DEFAULT, TTR("Using slashes in folder names will create subfolders recursively."), EditorValidationPanel::MSG_OK);
+			if (mode == MODE_DIRECTORY) {
+				validation_panel->set_message(EditorValidationPanel::MSG_ID_DEFAULT, TTR("Using slashes in folder names will create subfolders recursively."), EditorValidationPanel::MSG_OK);
+			} else {
+				validation_panel->set_message(EditorValidationPanel::MSG_ID_DEFAULT, TTR("Using slashes in path will create the file in subfolder, creating new subfolders if necessary."), EditorValidationPanel::MSG_OK);
+			}
+		} else if (mode == MODE_FILE) {
+			validation_panel->set_message(EditorValidationPanel::MSG_ID_DEFAULT, TTR("File name is valid."), EditorValidationPanel::MSG_OK);
 		}
 	} else {
 		validation_panel->set_message(EditorValidationPanel::MSG_ID_DEFAULT, error, EditorValidationPanel::MSG_ERROR);
@@ -95,18 +116,13 @@ void DirectoryCreateDialog::_on_dir_path_changed() {
 }
 
 void DirectoryCreateDialog::ok_pressed() {
-	const String path = sanitize_input(dir_path->get_text());
+	const String path = _sanitize_input(dir_path->get_text());
 
 	// The OK button should be disabled if the path is invalid, but just in case.
 	const String error = _validate_path(path);
 	ERR_FAIL_COND_MSG(!error.is_empty(), error);
 
-	Error err = EditorFileSystem::get_singleton()->make_dir_recursive(path, base_dir);
-	if (err == OK) {
-		emit_signal(SNAME("dir_created"), base_dir.path_join(path));
-	} else {
-		EditorNode::get_singleton()->show_warning(TTR("Could not create folder."));
-	}
+	accept_callback.call(base_dir.path_join(path));
 	hide();
 }
 
@@ -115,28 +131,40 @@ void DirectoryCreateDialog::_post_popup() {
 	dir_path->grab_focus();
 }
 
-void DirectoryCreateDialog::config(const String &p_base_dir) {
+void DirectoryCreateDialog::config(const String &p_base_dir, const Callable &p_accept_callback, int p_mode, const String &p_title, const String &p_default_name) {
+	set_title(p_title);
 	base_dir = p_base_dir;
-	label->set_text(vformat(TTR("Create new folder in %s:"), base_dir));
-	dir_path->set_text("new folder");
-	dir_path->select_all();
+	base_path_label->set_text(vformat(TTR("Base path: %s"), base_dir));
+	accept_callback = p_accept_callback;
+	mode = p_mode;
+
+	dir_path->set_text(p_default_name);
 	validation_panel->update();
-}
 
-void DirectoryCreateDialog::_bind_methods() {
-	ADD_SIGNAL(MethodInfo("dir_created", PropertyInfo(Variant::STRING, "path")));
+	if (p_mode == MODE_FILE) {
+		int extension_pos = p_default_name.rfind(".");
+		if (extension_pos > -1) {
+			dir_path->select(0, extension_pos);
+			return;
+		}
+	}
+	dir_path->select_all();
 }
 
 DirectoryCreateDialog::DirectoryCreateDialog() {
-	set_title(TTR("Create Folder"));
 	set_min_size(Size2i(480, 0) * EDSCALE);
 
 	VBoxContainer *vb = memnew(VBoxContainer);
 	add_child(vb);
 
-	label = memnew(Label);
-	label->set_text_overrun_behavior(TextServer::OVERRUN_TRIM_WORD_ELLIPSIS);
-	vb->add_child(label);
+	base_path_label = memnew(Label);
+	base_path_label->set_text_overrun_behavior(TextServer::OVERRUN_TRIM_WORD_ELLIPSIS);
+	vb->add_child(base_path_label);
+
+	Label *name_label = memnew(Label);
+	name_label->set_text(TTR("Name:"));
+	name_label->set_theme_type_variation("HeaderSmall");
+	vb->add_child(name_label);
 
 	dir_path = memnew(LineEdit);
 	vb->add_child(dir_path);

+ 12 - 4
editor/directory_create_dialog.h

@@ -40,23 +40,31 @@ class LineEdit;
 class DirectoryCreateDialog : public ConfirmationDialog {
 	GDCLASS(DirectoryCreateDialog, ConfirmationDialog);
 
+public:
+	enum Mode {
+		MODE_FILE,
+		MODE_DIRECTORY,
+	};
+
+private:
 	String base_dir;
+	Callable accept_callback;
+	int mode = MODE_FILE;
 
-	Label *label = nullptr;
+	Label *base_path_label = nullptr;
 	LineEdit *dir_path = nullptr;
 	EditorValidationPanel *validation_panel = nullptr;
 
+	String _sanitize_input(const String &p_input) const;
 	String _validate_path(const String &p_path) const;
 	void _on_dir_path_changed();
 
 protected:
-	static void _bind_methods();
-
 	virtual void ok_pressed() override;
 	virtual void _post_popup() override;
 
 public:
-	void config(const String &p_base_dir);
+	void config(const String &p_base_dir, const Callable &p_accept_callback, int p_mode, const String &p_title, const String &p_default_name = "");
 
 	DirectoryCreateDialog();
 };

+ 34 - 56
editor/filesystem_dock.cpp

@@ -1865,35 +1865,18 @@ 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
+void FileSystemDock::_duplicate_operation_confirm(const String &p_path) {
+	String base_dir = p_path.trim_suffix("/").get_base_dir();
 	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;
-	}
+	if (!da->dir_exists(base_dir)) {
+		Error err = da->make_dir_recursive(base_dir);
 
-	_try_duplicate_item(to_duplicate, new_path);
+		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, p_path);
 
 	// Rescan everything.
 	print_verbose("FileSystem: calling rescan.");
@@ -2531,24 +2514,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;
+			}
+
+			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_INFO: {
@@ -2563,7 +2544,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;
 
@@ -2793,6 +2775,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, 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;
 }
@@ -4282,17 +4271,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);
 

+ 2 - 3
editor/filesystem_dock.h

@@ -183,8 +183,6 @@ private:
 	DependencyRemoveDialog *remove_dialog = nullptr;
 
 	EditorDirDialog *move_dialog = nullptr;
-	ConfirmationDialog *duplicate_dialog = nullptr;
-	LineEdit *duplicate_dialog_text = nullptr;
 	DirectoryCreateDialog *make_dir_dialog = nullptr;
 
 	ConfirmationDialog *overwrite_dialog = nullptr;
@@ -291,7 +289,7 @@ private:
 	void _resource_created();
 	void _make_scene_confirm();
 	void _rename_operation_confirm();
-	void _duplicate_operation_confirm();
+	void _duplicate_operation_confirm(const String &p_path);
 	void _overwrite_dialog_action(bool p_overwrite);
 	void _convert_dialog_action();
 	Vector<String> _check_existing();
@@ -384,6 +382,7 @@ public:
 	void navigate_to_path(const String &p_path);
 	void focus_on_path();
 	void focus_on_filter();
+	void create_directory(const String &p_path, const String &p_base_dir);
 
 	ScriptCreateDialog *get_script_create_dialog() const;
 

+ 5 - 3
editor/gui/editor_dir_dialog.cpp

@@ -175,11 +175,14 @@ void EditorDirDialog::ok_pressed() {
 void EditorDirDialog::_make_dir() {
 	TreeItem *ti = tree->get_selected();
 	ERR_FAIL_NULL(ti);
-	makedialog->config(ti->get_metadata(0));
+	const String &directory = ti->get_metadata(0);
+	makedialog->config(directory, callable_mp(this, &EditorDirDialog::_make_dir_confirm).bind(directory), DirectoryCreateDialog::MODE_DIRECTORY, "new folder");
 	makedialog->popup_centered();
 }
 
-void EditorDirDialog::_make_dir_confirm(const String &p_path) {
+void EditorDirDialog::_make_dir_confirm(const String &p_path, const String &p_base_dir) {
+	FileSystemDock::get_singleton()->create_directory(p_path, p_base_dir);
+
 	// Multiple level of directories can be created at once.
 	String base_dir = p_path.get_base_dir();
 	while (true) {
@@ -228,5 +231,4 @@ EditorDirDialog::EditorDirDialog() {
 
 	makedialog = memnew(DirectoryCreateDialog);
 	add_child(makedialog);
-	makedialog->connect("dir_created", callable_mp(this, &EditorDirDialog::_make_dir_confirm));
 }

+ 1 - 1
editor/gui/editor_dir_dialog.h

@@ -56,7 +56,7 @@ class EditorDirDialog : public ConfirmationDialog {
 	void _update_dir(const Color &p_default_folder_color, const Dictionary &p_assigned_folder_colors, const HashMap<String, Color> &p_folder_colors, bool p_is_dark_theme, TreeItem *p_item, EditorFileSystemDirectory *p_dir, const String &p_select_path = String());
 
 	void _make_dir();
-	void _make_dir_confirm(const String &p_path);
+	void _make_dir_confirm(const String &p_path, const String &p_base_dir);
 
 	void _copy_pressed();
 	void ok_pressed() override;