From 23e5cfbe5bec9e8a4d07f6f1915af37f0b829b4f Mon Sep 17 00:00:00 2001 From: Haoyu Qiu Date: Sat, 27 Apr 2024 11:38:26 +0800 Subject: [PATCH] Improve Remove Missing of project manager --- editor/project_manager.cpp | 35 +++---- editor/project_manager.h | 6 +- editor/project_manager/project_list.cpp | 19 ++-- editor/project_manager/project_list.h | 3 +- .../project_manager/remove_missing_dialog.cpp | 98 +++++++++++++++++++ .../project_manager/remove_missing_dialog.h | 56 +++++++++++ 6 files changed, 185 insertions(+), 32 deletions(-) create mode 100644 editor/project_manager/remove_missing_dialog.cpp create mode 100644 editor/project_manager/remove_missing_dialog.h diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp index 00aa78f34217..41e95c9057b1 100644 --- a/editor/project_manager.cpp +++ b/editor/project_manager.cpp @@ -31,11 +31,8 @@ #include "project_manager.h" #include "core/config/project_settings.h" -#include "core/io/config_file.h" #include "core/io/dir_access.h" #include "core/io/file_access.h" -#include "core/io/resource_saver.h" -#include "core/io/stream_peer_tls.h" #include "core/os/keyboard.h" #include "core/os/os.h" #include "core/os/time.h" @@ -51,12 +48,10 @@ #include "editor/project_manager/project_list.h" #include "editor/project_manager/project_tag.h" #include "editor/project_manager/quick_settings_dialog.h" -#include "editor/themes/editor_icons.h" +#include "editor/project_manager/remove_missing_dialog.h" #include "editor/themes/editor_scale.h" #include "editor/themes/editor_theme_manager.h" #include "main/main.h" -#include "scene/gui/check_box.h" -#include "scene/gui/color_rect.h" #include "scene/gui/flow_container.h" #include "scene/gui/line_edit.h" #include "scene/gui/margin_container.h" @@ -64,7 +59,6 @@ #include "scene/gui/panel_container.h" #include "scene/gui/rich_text_label.h" #include "scene/gui/separator.h" -#include "scene/gui/texture_rect.h" #include "scene/main/window.h" #include "scene/theme/theme_db.h" #include "servers/display_server.h" @@ -661,8 +655,7 @@ void ProjectManager::_erase_project() { } void ProjectManager::_erase_missing_projects() { - erase_missing_ask->set_text(TTR("Remove all missing projects from the list?\nThe project folders' contents won't be modified.")); - erase_missing_ask->popup_centered(); + remove_missing_dialog->show_dialog(project_list->get_missing_project_paths()); } void ProjectManager::_erase_project_confirm() { @@ -671,8 +664,8 @@ void ProjectManager::_erase_project_confirm() { _update_list_placeholder(); } -void ProjectManager::_erase_missing_projects_confirm() { - project_list->erase_missing_projects(); +void ProjectManager::_erase_missing_projects_confirm(const Vector &p_paths) { + project_list->erase_missing_projects(p_paths); _update_project_buttons(); _update_list_placeholder(); } @@ -695,7 +688,7 @@ void ProjectManager::_update_project_buttons() { manage_tags_btn->set_disabled(empty_selection || is_missing_project_selected || selected_projects.size() > 1); run_btn->set_disabled(empty_selection || is_missing_project_selected); - erase_missing_btn->set_disabled(!project_list->is_any_project_missing()); + erase_missing_btn->set_visible(project_list->is_any_project_missing()); } void ProjectManager::_on_projects_updated() { @@ -1231,6 +1224,12 @@ ProjectManager::ProjectManager() { scan_btn->connect(SceneStringName(pressed), callable_mp(this, &ProjectManager::_scan_projects)); hb->add_child(scan_btn); + erase_missing_btn = memnew(Button); + erase_missing_btn->set_text(TTR("Clean")); + erase_missing_btn->set_tooltip_text(TTR("Remove missing projects.")); + erase_missing_btn->connect("pressed", callable_mp(this, &ProjectManager::_erase_missing_projects)); + hb->add_child(erase_missing_btn); + loading_label = memnew(Label(TTR("Loading, please wait..."))); loading_label->set_h_size_flags(Control::SIZE_EXPAND_FILL); loading_label->hide(); @@ -1374,11 +1373,6 @@ ProjectManager::ProjectManager() { Control *filler = memnew(Control); filler->set_v_size_flags(Control::SIZE_EXPAND_FILL); project_list_sidebar->add_child(filler); - - erase_missing_btn = memnew(Button); - erase_missing_btn->set_text(TTR("Remove Missing")); - erase_missing_btn->connect(SceneStringName(pressed), callable_mp(this, &ProjectManager::_erase_missing_projects)); - project_list_sidebar->add_child(erase_missing_btn); } } @@ -1444,10 +1438,9 @@ ProjectManager::ProjectManager() { add_child(scan_dir); scan_dir->connect("dir_selected", callable_mp(project_list, &ProjectList::find_projects)); - erase_missing_ask = memnew(ConfirmationDialog); - erase_missing_ask->set_ok_button_text(TTR("Remove All")); - erase_missing_ask->get_ok_button()->connect(SceneStringName(pressed), callable_mp(this, &ProjectManager::_erase_missing_projects_confirm)); - add_child(erase_missing_ask); + remove_missing_dialog = memnew(RemoveMissingDialog); + remove_missing_dialog->connect("remove_missing_projects", callable_mp(this, &ProjectManager::_erase_missing_projects_confirm)); + add_child(remove_missing_dialog); erase_ask = memnew(ConfirmationDialog); erase_ask->set_ok_button_text(TTR("Remove")); diff --git a/editor/project_manager.h b/editor/project_manager.h index 669b5d8b6c57..8a34f66d6e89 100644 --- a/editor/project_manager.h +++ b/editor/project_manager.h @@ -32,7 +32,6 @@ #define PROJECT_MANAGER_H #include "scene/gui/dialogs.h" -#include "scene/gui/scroll_container.h" class CheckBox; class EditorAbout; @@ -48,6 +47,7 @@ class PanelContainer; class ProjectDialog; class ProjectList; class QuickSettingsDialog; +class RemoveMissingDialog; class RichTextLabel; class TabContainer; class VBoxContainer; @@ -165,7 +165,7 @@ class ProjectManager : public Control { // Comment out for now until we have a better warning system to // ensure users delete their project only. //CheckBox *delete_project_contents = nullptr; - ConfirmationDialog *erase_missing_ask = nullptr; + RemoveMissingDialog *remove_missing_dialog = nullptr; ConfirmationDialog *multi_open_ask = nullptr; ConfirmationDialog *multi_run_ask = nullptr; @@ -184,7 +184,7 @@ class ProjectManager : public Control { void _erase_project(); void _erase_missing_projects(); void _erase_project_confirm(); - void _erase_missing_projects_confirm(); + void _erase_missing_projects_confirm(const Vector &p_paths); void _update_project_buttons(); void _on_project_created(const String &dir); diff --git a/editor/project_manager/project_list.cpp b/editor/project_manager/project_list.cpp index 32f088ec60e2..5496e2a98e52 100644 --- a/editor/project_manager/project_list.cpp +++ b/editor/project_manager/project_list.cpp @@ -897,6 +897,16 @@ Vector ProjectList::get_selected_projects() const { return items; } +Vector ProjectList::get_missing_project_paths() const { + Vector paths; + for (const Item &project : _projects) { + if (project.missing) { + paths.push_back(project.path); + } + } + return paths; +} + const HashSet &ProjectList::get_selected_project_keys() const { // Faster if that's all you need return _selected_project_paths; @@ -963,22 +973,17 @@ bool ProjectList::is_any_project_missing() const { return false; } -void ProjectList::erase_missing_projects() { - if (_projects.is_empty()) { - return; - } - +void ProjectList::erase_missing_projects(const Vector &p_paths) { int deleted_count = 0; int remaining_count = 0; for (int i = 0; i < _projects.size(); ++i) { const Item &item = _projects[i]; - if (item.missing) { + if (item.missing && p_paths.has(item.path)) { _remove_project(i, true); --i; ++deleted_count; - } else { ++remaining_count; } diff --git a/editor/project_manager/project_list.h b/editor/project_manager/project_list.h index 981df0f3a00d..c0111577a796 100644 --- a/editor/project_manager/project_list.h +++ b/editor/project_manager/project_list.h @@ -240,6 +240,7 @@ class ProjectList : public ScrollContainer { void select_project(int p_index); void select_first_visible_project(); Vector get_selected_projects() const; + Vector get_missing_project_paths() const; const HashSet &get_selected_project_keys() const; int get_single_selected_index() const; void erase_selected_projects(bool p_delete_project_contents); @@ -247,7 +248,7 @@ class ProjectList : public ScrollContainer { // Missing projects. bool is_any_project_missing() const; - void erase_missing_projects(); + void erase_missing_projects(const Vector &p_paths); // Project list sorting and filtering. diff --git a/editor/project_manager/remove_missing_dialog.cpp b/editor/project_manager/remove_missing_dialog.cpp new file mode 100644 index 000000000000..247466760ad9 --- /dev/null +++ b/editor/project_manager/remove_missing_dialog.cpp @@ -0,0 +1,98 @@ +/**************************************************************************/ +/* remove_missing_dialog.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#include "remove_missing_dialog.h" + +#include "editor/themes/editor_scale.h" +#include "scene/gui/box_container.h" +#include "scene/gui/label.h" +#include "scene/gui/tree.h" + +void RemoveMissingDialog::_on_item_edited() { + bool has_checked = false; + for (TreeItem *item = tree->get_root()->get_next_visible(); item != nullptr; item = item->get_next_visible()) { + if (item->is_checked(0)) { + has_checked = true; + break; + } + } + get_ok_button()->set_disabled(!has_checked); +} + +void RemoveMissingDialog::_bind_methods() { + ADD_SIGNAL(MethodInfo("remove_missing_projects", PropertyInfo(Variant::PACKED_STRING_ARRAY, "paths"))); +} + +void RemoveMissingDialog::ok_pressed() { + Vector paths; + for (TreeItem *item = tree->get_root()->get_next_visible(); item != nullptr; item = item->get_next_visible()) { + if (item->is_checked(0)) { + paths.push_back(item->get_text(0)); + } + } + hide(); + emit_signal("remove_missing_projects", paths); +} + +void RemoveMissingDialog::show_dialog(const Vector &p_paths) { + tree->clear(); + + TreeItem *root = tree->create_item(); + + for (const String &path : p_paths) { + TreeItem *item = tree->create_item(root); + item->set_cell_mode(0, TreeItem::CELL_MODE_CHECK); + item->set_editable(0, true); + item->set_checked(0, true); + item->set_text(0, path); + } + + popup_centered_clamped(Size2(480, 260) * EDSCALE); +} + +RemoveMissingDialog::RemoveMissingDialog() { + set_title(TTR("Remove Missing")); + set_hide_on_ok(false); + + VBoxContainer *vb = memnew(VBoxContainer); + add_child(vb); + + vb->add_child(memnew(Label(TTR("The following paths will be removed from the project list.")))); + + tree = memnew(Tree); + tree->set_custom_minimum_size(Size2(0, 100) * EDSCALE); + tree->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED); + tree->set_h_scroll_enabled(false); + tree->set_v_size_flags(Control::SIZE_EXPAND_FILL); + tree->set_hide_root(true); + tree->set_select_mode(Tree::SELECT_ROW); + tree->connect("item_edited", callable_mp(this, &RemoveMissingDialog::_on_item_edited)); + vb->add_child(tree); +} diff --git a/editor/project_manager/remove_missing_dialog.h b/editor/project_manager/remove_missing_dialog.h new file mode 100644 index 000000000000..01ab56327365 --- /dev/null +++ b/editor/project_manager/remove_missing_dialog.h @@ -0,0 +1,56 @@ +/**************************************************************************/ +/* remove_missing_dialog.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#ifndef REMOVE_MISSING_DIALOG_H +#define REMOVE_MISSING_DIALOG_H + +#include "scene/gui/dialogs.h" + +class Tree; + +class RemoveMissingDialog : public ConfirmationDialog { + GDCLASS(RemoveMissingDialog, ConfirmationDialog); + + Tree *tree; + + void _on_item_edited(); + +protected: + static void _bind_methods(); + + virtual void ok_pressed() override; + +public: + void show_dialog(const Vector &p_paths); + + RemoveMissingDialog(); +}; + +#endif // REMOVE_MISSING_DIALOG_H