Browse Source

Merge pull request #9304 from Noshyaar/pr-save

EditorNode: add Save/Discard/Cancel dialog
Rémi Verschelde 8 years ago
parent
commit
4e12bf19cc
3 changed files with 181 additions and 73 deletions
  1. 172 73
      editor/editor_node.cpp
  2. 6 0
      editor/editor_node.h
  3. 3 0
      editor/editor_settings.cpp

+ 172 - 73
editor/editor_node.cpp

@@ -961,6 +961,23 @@ void EditorNode::_save_scene(String p_file, int idx) {
 	}
 }
 
+void EditorNode::_save_all_scenes() {
+
+	for (int i = 0; i < editor_data.get_edited_scene_count(); i++) {
+		Node *scene = editor_data.get_edited_scene_root(i);
+		if (scene && scene->get_filename() != "") {
+			// save in background if in the script editor
+			if (i != editor_data.get_edited_scene() || _get_current_main_editor() == EDITOR_SCRIPT) {
+				_save_scene(scene->get_filename(), i);
+			} else {
+				_save_scene_with_preview(scene->get_filename());
+			}
+		} // else: ignore new scenes
+	}
+
+	_save_default_environment();
+}
+
 void EditorNode::_import_action(const String &p_action) {
 #if 0
 	import_confirmation->hide();
@@ -1117,14 +1134,26 @@ void EditorNode::_dialog_action(String p_file) {
 
 			get_undo_redo()->clear_history();
 		} break;
+		case FILE_CLOSE:
+		case FILE_CLOSE_ALL_AND_QUIT:
+		case FILE_CLOSE_ALL_AND_RUN_PROJECT_MANAGER:
+		case SCENE_TAB_CLOSE:
 		case FILE_SAVE_SCENE:
 		case FILE_SAVE_AS_SCENE: {
 
+			int scene_idx = (current_option == FILE_SAVE_SCENE || current_option == FILE_SAVE_AS_SCENE) ? -1 : tab_closing;
+
 			if (file->get_mode() == EditorFileDialog::MODE_SAVE_FILE) {
 
 				//_save_scene(p_file);
 				_save_default_environment();
-				_save_scene_with_preview(p_file);
+				if (scene_idx != editor_data.get_edited_scene() || _get_current_main_editor() == EDITOR_SCRIPT)
+					_save_scene(p_file, scene_idx);
+				else
+					_save_scene_with_preview(p_file);
+
+				if (scene_idx != -1)
+					_discard_changes();
 			}
 
 		} break;
@@ -1887,42 +1916,45 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
 			open_request(previous_scenes.back()->get());
 
 		} break;
+		case FILE_CLOSE_ALL_AND_QUIT:
+		case FILE_CLOSE_ALL_AND_RUN_PROJECT_MANAGER:
 		case FILE_CLOSE: {
 
-			if (!p_confirmed && unsaved_cache) {
-				confirmation->get_ok()->set_text(TTR("Yes"));
-				//confirmation->get_cancel()->show();
-				confirmation->set_text(TTR("Close scene? (Unsaved changes will be lost)"));
-				confirmation->popup_centered_minsize();
+			if (!p_confirmed && (unsaved_cache || p_option == FILE_CLOSE_ALL_AND_QUIT || p_option == FILE_CLOSE_ALL_AND_RUN_PROJECT_MANAGER)) {
+				tab_closing = p_option == FILE_CLOSE ? editor_data.get_edited_scene() : _next_unsaved_scene();
+				String scene_filename = editor_data.get_edited_scene_root(tab_closing)->get_filename();
+				save_confirmation->get_ok()->set_text(TTR("Save & Close"));
+				save_confirmation->set_text(vformat(TTR("Save changes to '%s' before closing?"), scene_filename != "" ? scene_filename : "unsaved scene"));
+				save_confirmation->popup_centered_minsize();
 				break;
 			}
-
-			_remove_edited_scene();
-
-		} break;
-		case SCENE_TAB_CLOSE: {
-			_remove_scene(tab_closing);
-			_update_scene_tabs();
-			current_option = -1;
-		} break;
+		} // fallthrough
+		case SCENE_TAB_CLOSE:
 		case FILE_SAVE_SCENE: {
 
-			Node *scene = editor_data.get_edited_scene_root();
+			int scene_idx = (p_option == FILE_SAVE_SCENE) ? -1 : tab_closing;
+
+			Node *scene = editor_data.get_edited_scene_root(scene_idx);
 			if (scene && scene->get_filename() != "") {
 
 				// save in background if in the script editor
-				if (_get_current_main_editor() == EDITOR_SCRIPT) {
-					_save_scene(scene->get_filename());
+				if (scene_idx != editor_data.get_edited_scene() || _get_current_main_editor() == EDITOR_SCRIPT) {
+					_save_scene(scene->get_filename(), scene_idx);
 				} else {
 					_save_scene_with_preview(scene->get_filename());
 				}
-				return;
-			};
+
+				if (scene_idx != -1)
+					_discard_changes();
+
+				break;
+			}
 			// fallthrough to save_as
 		};
 		case FILE_SAVE_AS_SCENE: {
+			int scene_idx = (p_option == FILE_SAVE_SCENE || p_option == FILE_SAVE_AS_SCENE) ? -1 : tab_closing;
 
-			Node *scene = editor_data.get_edited_scene_root();
+			Node *scene = editor_data.get_edited_scene_root(scene_idx);
 
 			if (!scene) {
 
@@ -1958,7 +1990,7 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
 
 				String existing;
 				if (extensions.size()) {
-					String root_name(get_edited_scene()->get_name());
+					String root_name(scene->get_name());
 					existing = root_name + "." + extensions.front()->get().to_lower();
 				}
 				file->set_current_path(existing);
@@ -1969,19 +2001,8 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
 		} break;
 
 		case FILE_SAVE_ALL_SCENES: {
-			for (int i = 0; i < editor_data.get_edited_scene_count(); i++) {
-				Node *scene = editor_data.get_edited_scene_root(i);
-				if (scene && scene->get_filename() != "") {
-					// save in background if in the script editor
-					if (i != editor_data.get_edited_scene() || _get_current_main_editor() == EDITOR_SCRIPT) {
-						_save_scene(scene->get_filename(), i);
-					} else {
-						_save_scene_with_preview(scene->get_filename());
-					}
-				} // else: ignore new scenes
-			}
 
-			_save_default_environment();
+			_save_all_scenes();
 		} break;
 		case FILE_SAVE_BEFORE_RUN: {
 			if (!p_confirmed) {
@@ -2100,22 +2121,6 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
 
 		} break;
 
-		case FILE_QUIT: {
-
-			if (!p_confirmed) {
-
-				confirmation->get_ok()->set_text(TTR("Quit"));
-				//confirmation->get_cancel()->show();
-				confirmation->set_text(TTR("Exit the editor?"));
-				confirmation->popup_centered(Size2(180, 70) * EDSCALE);
-				break;
-			}
-
-			_menu_option_confirm(RUN_STOP, true);
-			exiting = true;
-			get_tree()->quit();
-
-		} break;
 		case FILE_EXTERNAL_OPEN_SCENE: {
 
 			if (unsaved_cache && !p_confirmed) {
@@ -2444,28 +2449,53 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
 
 			project_settings->popup_project_settings();
 		} break;
+		case FILE_QUIT:
 		case RUN_PROJECT_MANAGER: {
 
 			if (!p_confirmed) {
-				confirmation->get_ok()->set_text(TTR("Yes"));
-				confirmation->set_text(TTR("Open Project Manager? \n(Unsaved changes will be lost)"));
-				confirmation->popup_centered_minsize();
-				break;
-			}
+				if (_next_unsaved_scene() == -1) {
 
-			_menu_option_confirm(RUN_STOP, true);
-			exiting = true;
-			get_tree()->quit();
-			String exec = OS::get_singleton()->get_executable_path();
+					bool confirm = EDITOR_DEF("interface/quit_confirmation", true);
+					if (confirm) {
 
-			List<String> args;
-			args.push_back("-path");
-			args.push_back(exec.get_base_dir());
-			args.push_back("-pm");
+						confirmation->get_ok()->set_text(p_option == FILE_QUIT ? TTR("Quit") : TTR("Yes"));
+						confirmation->set_text(p_option == FILE_QUIT ? TTR("Exit the editor?") : TTR("Open Project Manager?"));
+						confirmation->popup_centered_minsize();
+					} else {
+						_discard_changes();
+					}
+				} else {
 
-			OS::ProcessID pid = 0;
-			Error err = OS::get_singleton()->execute(exec, args, false, &pid);
-			ERR_FAIL_COND(err);
+					bool save_each = EDITOR_DEF("interface/save_each_scene_on_quit", true);
+					if (save_each) {
+
+						_menu_option_confirm(p_option == FILE_QUIT ? FILE_CLOSE_ALL_AND_QUIT : FILE_CLOSE_ALL_AND_RUN_PROJECT_MANAGER, false);
+					} else {
+
+						String unsaved_scenes;
+						for (int i = 0; i < editor_data.get_edited_scene_count(); i++) {
+							int current = editor_data.get_edited_scene();
+							bool unsaved = (i == current) ? saved_version != editor_data.get_undo_redo().get_version() : editor_data.get_scene_version(i) != 0;
+							if (unsaved) {
+
+								String scene_filename = editor_data.get_edited_scene_root(i)->get_filename();
+								unsaved_scenes += "\n            " + scene_filename;
+							}
+						}
+
+						save_confirmation->get_ok()->set_text(TTR("Save & Quit"));
+						save_confirmation->set_text((p_option == FILE_QUIT ? TTR("Save changes to the following scene(s) before quitting?") : TTR("Save changes the following scene(s) before opening Project Manager?")) + unsaved_scenes);
+						save_confirmation->popup_centered_minsize();
+					}
+				}
+
+				break;
+			}
+
+			if (_next_unsaved_scene() != -1) {
+				_save_all_scenes();
+			}
+			_discard_changes();
 		} break;
 		case RUN_FILE_SERVER: {
 
@@ -2691,6 +2721,70 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
 	}
 }
 
+int EditorNode::_next_unsaved_scene() {
+
+	for (int i = 0; i < editor_data.get_edited_scene_count(); i++) {
+
+		int current = editor_data.get_edited_scene();
+		bool unsaved = (i == current) ? saved_version != editor_data.get_undo_redo().get_version() : editor_data.get_scene_version(i) != 0;
+		if (unsaved) {
+			return i;
+		}
+	}
+	return -1;
+}
+
+void EditorNode::_discard_changes(const String &p_str) {
+
+	switch (current_option) {
+
+		case FILE_CLOSE_ALL_AND_QUIT:
+		case FILE_CLOSE_ALL_AND_RUN_PROJECT_MANAGER:
+		case FILE_CLOSE:
+		case SCENE_TAB_CLOSE: {
+
+			_remove_scene(tab_closing);
+			_update_scene_tabs();
+
+			if (current_option == FILE_CLOSE_ALL_AND_QUIT || current_option == FILE_CLOSE_ALL_AND_RUN_PROJECT_MANAGER) {
+				int next_scene = _next_unsaved_scene();
+				if (next_scene == -1) {
+					current_option = current_option == FILE_CLOSE_ALL_AND_QUIT ? FILE_QUIT : RUN_PROJECT_MANAGER;
+					_discard_changes();
+				} else {
+					tab_closing = next_scene;
+					_menu_option_confirm(current_option, false);
+				}
+			} else {
+				current_option = -1;
+				save_confirmation->hide();
+			}
+		} break;
+		case FILE_QUIT: {
+
+			_menu_option_confirm(RUN_STOP, true);
+			exiting = true;
+			get_tree()->quit();
+		} break;
+		case RUN_PROJECT_MANAGER: {
+
+			_menu_option_confirm(RUN_STOP, true);
+			exiting = true;
+			get_tree()->quit();
+			String exec = OS::get_singleton()->get_executable_path();
+
+			List<String> args;
+			args.push_back("-path");
+			args.push_back(exec.get_base_dir());
+			args.push_back("-pm");
+
+			OS::ProcessID pid = 0;
+			Error err = OS::get_singleton()->execute(exec, args, false, &pid);
+			ERR_FAIL_COND(err);
+		} break;
+	}
+}
+
 void EditorNode::_update_debug_options() {
 
 	bool check_deploy_remote = EditorSettings::get_singleton()->get_project_metadata("debug_options", "run_deploy_remote_debug", false);
@@ -4262,19 +4356,17 @@ void EditorNode::_scene_tab_script_edited(int p_tab) {
 void EditorNode::_scene_tab_closed(int p_tab) {
 	current_option = SCENE_TAB_CLOSE;
 	tab_closing = p_tab;
+	Node *scene = editor_data.get_edited_scene_root(p_tab);
 
 	bool unsaved = (p_tab == editor_data.get_edited_scene()) ?
 						   saved_version != editor_data.get_undo_redo().get_version() :
 						   editor_data.get_scene_version(p_tab) != 0;
 	if (unsaved) {
-		confirmation->get_ok()->set_text(TTR("Yes"));
-
-		//confirmation->get_cancel()->show();
-		confirmation->set_text(TTR("Close scene? (Unsaved changes will be lost)"));
-		confirmation->popup_centered_minsize();
+		save_confirmation->get_ok()->set_text(TTR("Save & Close"));
+		save_confirmation->set_text(vformat(TTR("Save changes to '%s' before closing?"), scene->get_filename() != "" ? scene->get_filename() : "unsaved scene"));
+		save_confirmation->popup_centered_minsize();
 	} else {
-		_remove_scene(p_tab);
-		_update_scene_tabs();
+		_discard_changes();
 	}
 }
 
@@ -4892,6 +4984,7 @@ void EditorNode::_bind_methods() {
 	ClassDB::bind_method("_scene_tab_script_edited", &EditorNode::_scene_tab_script_edited);
 	ClassDB::bind_method("_set_main_scene_state", &EditorNode::_set_main_scene_state);
 	ClassDB::bind_method("_update_scene_tabs", &EditorNode::_update_scene_tabs);
+	ClassDB::bind_method("_discard_changes", &EditorNode::_discard_changes);
 
 	ClassDB::bind_method("_prepare_history", &EditorNode::_prepare_history);
 	ClassDB::bind_method("_select_history", &EditorNode::_select_history);
@@ -5891,6 +5984,12 @@ EditorNode::EditorNode() {
 	gui_base->add_child(confirmation);
 	confirmation->connect("confirmed", this, "_menu_confirm_current");
 
+	save_confirmation = memnew(ConfirmationDialog);
+	save_confirmation->add_button(TTR("Don't Save"), OS::get_singleton()->get_swap_ok_cancel(), "discard");
+	gui_base->add_child(save_confirmation);
+	save_confirmation->connect("confirmed", this, "_menu_confirm_current");
+	save_confirmation->connect("custom_action", this, "_discard_changes");
+
 	accept = memnew(AcceptDialog);
 	gui_base->add_child(accept);
 	accept->connect("confirmed", this, "_menu_confirm_current");

+ 6 - 0
editor/editor_node.h

@@ -140,6 +140,8 @@ private:
 		FILE_RUN_SCRIPT,
 		FILE_OPEN_PREV,
 		FILE_CLOSE,
+		FILE_CLOSE_ALL_AND_QUIT,
+		FILE_CLOSE_ALL_AND_RUN_PROJECT_MANAGER,
 		FILE_QUIT,
 		FILE_EXTERNAL_OPEN_SCENE,
 		EDIT_UNDO,
@@ -296,6 +298,7 @@ private:
 
 	//CallDialog *call_dialog;
 	ConfirmationDialog *confirmation;
+	ConfirmationDialog *save_confirmation;
 	ConfirmationDialog *import_confirmation;
 	ConfirmationDialog *open_recent_confirmation;
 	ConfirmationDialog *pick_main_scene;
@@ -465,6 +468,9 @@ private:
 	void _vp_resized();
 
 	void _save_scene(String p_file, int idx = -1);
+	void _save_all_scenes();
+	int _next_unsaved_scene();
+	void _discard_changes(const String &p_str = String());
 
 	void _instance_request(const Vector<String> &p_files);
 

+ 3 - 0
editor/editor_settings.cpp

@@ -517,6 +517,9 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
 
 	set("interface/separate_distraction_mode", false);
 
+	set("interface/save_each_scene_on_quit", true); // Regression
+	set("interface/quit_confirmation", true);
+
 	set("interface/theme/preset", 0);
 	hints["interface/theme/preset"] = PropertyInfo(Variant::INT, "interface/theme/preset", PROPERTY_HINT_ENUM, "Default,Grey,Godot 2,Arc,Custom", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED);
 	set("interface/theme/base_color", Color::html("#273241"));