diff options
Diffstat (limited to 'editor/project_manager.cpp')
-rw-r--r-- | editor/project_manager.cpp | 135 |
1 files changed, 107 insertions, 28 deletions
diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp index 095ec891cd..b0baf954d2 100644 --- a/editor/project_manager.cpp +++ b/editor/project_manager.cpp @@ -765,7 +765,7 @@ public: set_title(TTR("Install Project:") + " " + zip_title); get_ok()->set_text(TTR("Install & Edit")); - name_container->hide(); + name_container->show(); install_path_container->hide(); rasterizer_container->hide(); project_path->grab_focus(); @@ -798,7 +798,7 @@ public: create_dir = memnew(Button); pnhb->add_child(create_dir); - create_dir->set_text(TTR("Create folder")); + create_dir->set_text(TTR("Create Folder")); create_dir->connect("pressed", this, "_create_folder"); path_container = memnew(VBoxContainer); @@ -987,6 +987,24 @@ void ProjectManager::_update_project_buttons() { open_btn->set_disabled(empty_selection); rename_btn->set_disabled(empty_selection); run_btn->set_disabled(empty_selection); + + bool missing_projects = false; + Map<String, String> list_all_projects; + for (int i = 0; i < scroll_children->get_child_count(); i++) { + HBoxContainer *hb = Object::cast_to<HBoxContainer>(scroll_children->get_child(i)); + if (hb) { + list_all_projects.insert(hb->get_meta("name"), hb->get_meta("main_scene")); + } + } + for (Map<String, String>::Element *E = list_all_projects.front(); E; E = E->next()) { + String project_name = E->key().replace(":::", ":/").replace("::", "/") + "/project.godot"; + if (!FileAccess::exists(project_name)) { + missing_projects = true; + break; + } + } + + erase_missing_btn->set_visible(missing_projects); } void ProjectManager::_panel_input(const Ref<InputEvent> &p_ev, Node *p_hb) { @@ -1530,13 +1548,13 @@ void ProjectManager::_open_selected_projects_ask() { // Check if the config_version property was empty or 0 if (config_version == 0) { - ask_update_settings->set_text(vformat(TTR("The following project settings file does not specify the version of Godot through which it was created.\n\n%s\n\nIf you proceed with opening it, it will be converted to Godot's current configuration file format.\nWarning: You will not be able to open the project with previous versions of the engine anymore."), conf)); + ask_update_settings->set_text(vformat(TTR("The following project settings file does not specify the version of Godot through which it was created.\n\n%s\n\nIf you proceed with opening it, it will be converted to Godot's current configuration file format.\nWarning: You won't be able to open the project with previous versions of the engine anymore."), conf)); ask_update_settings->popup_centered_minsize(); return; } // Check if we need to convert project settings from an earlier engine version if (config_version < ProjectSettings::CONFIG_VERSION) { - ask_update_settings->set_text(vformat(TTR("The following project settings file was generated by an older engine version, and needs to be converted for this version:\n\n%s\n\nDo you want to convert it?\nWarning: You will not be able to open the project with previous versions of the engine anymore."), conf)); + ask_update_settings->set_text(vformat(TTR("The following project settings file was generated by an older engine version, and needs to be converted for this version:\n\n%s\n\nDo you want to convert it?\nWarning: You won't be able to open the project with previous versions of the engine anymore."), conf)); ask_update_settings->popup_centered_minsize(); return; } @@ -1557,7 +1575,7 @@ void ProjectManager::_run_project_confirm() { const String &selected_main = E->get(); if (selected_main == "") { - run_error_diag->set_text(TTR("Can't run project: no main scene defined.\nPlease edit the project and set the main scene in \"Project Settings\" under the \"Application\" category.")); + run_error_diag->set_text(TTR("Can't run project: no main scene defined.\nPlease edit the project and set the main scene in the Project Settings under the \"Application\" category.")); run_error_diag->popup_centered(); return; } @@ -1597,7 +1615,7 @@ void ProjectManager::_run_project() { } if (selected_list.size() > 1) { - multi_run_ask->set_text(TTR("Are you sure to run more than one project?")); + multi_run_ask->set_text(vformat(TTR("Are you sure to run %d projects at once?"), selected_list.size())); multi_run_ask->popup_centered_minsize(); } else { _run_project_confirm(); @@ -1609,40 +1627,28 @@ void ProjectManager::_show_project(const String &p_path) { OS::get_singleton()->shell_open(String("file://") + p_path); } -void ProjectManager::_scan_dir(DirAccess *da, float pos, float total, List<String> *r_projects) { - - List<String> subdirs; +void ProjectManager::_scan_dir(const String &path, List<String> *r_projects) { + DirAccess *da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + da->change_dir(path); da->list_dir_begin(); String n = da->get_next(); while (n != String()) { if (da->current_is_dir() && !n.begins_with(".")) { - subdirs.push_front(n); + _scan_dir(da->get_current_dir().plus_file(n), r_projects); } else if (n == "project.godot") { r_projects->push_back(da->get_current_dir()); } n = da->get_next(); } da->list_dir_end(); - int m = 0; - for (List<String>::Element *E = subdirs.front(); E; E = E->next()) { - - da->change_dir(E->get()); - - float slice = total / subdirs.size(); - _scan_dir(da, pos + slice * m, slice, r_projects); - da->change_dir(".."); - m++; - } + memdelete(da); } void ProjectManager::_scan_begin(const String &p_base) { print_line("Scanning projects at: " + p_base); List<String> projects; - DirAccess *da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); - da->change_dir(p_base); - _scan_dir(da, 0, 1, &projects); - memdelete(da); + _scan_dir(p_base, &projects); print_line("Found " + itos(projects.size()) + " projects."); for (List<String>::Element *E = projects.front(); E; E = E->next()) { @@ -1700,15 +1706,61 @@ void ProjectManager::_erase_project_confirm() { _load_recent_projects(); } +void ProjectManager::_erase_missing_projects_confirm() { + + Map<String, String> list_all_projects; + for (int i = 0; i < scroll_children->get_child_count(); i++) { + HBoxContainer *hb = Object::cast_to<HBoxContainer>(scroll_children->get_child(i)); + if (hb) { + list_all_projects.insert(hb->get_meta("name"), hb->get_meta("main_scene")); + } + } + + if (list_all_projects.size() == 0) { + return; + } + + int deleted_projects = 0; + int remaining_projects = 0; + for (Map<String, String>::Element *E = list_all_projects.front(); E; E = E->next()) { + String project_name = E->key().replace(":::", ":/").replace("::", "/") + "/project.godot"; + if (!FileAccess::exists(project_name)) { + deleted_projects++; + EditorSettings::get_singleton()->erase("projects/" + E->key()); + EditorSettings::get_singleton()->erase("favorite_projects/" + E->key()); + } else { + remaining_projects++; + } + } + print_line("Deleted " + itos(deleted_projects) + " projects, remaining " + itos(remaining_projects) + " projects"); + EditorSettings::get_singleton()->save(); + selected_list.clear(); + last_clicked = ""; + _load_recent_projects(); +} + void ProjectManager::_erase_project() { if (selected_list.size() == 0) return; - erase_ask->set_text(TTR("Remove project from the list? (Folder contents will not be modified)")); + String confirm_message; + if (selected_list.size() >= 2) { + confirm_message = vformat(TTR("Remove %d projects from the list?\nThe project folders' contents won't be modified."), selected_list.size()); + } else { + confirm_message = TTR("Remove this project from the list?\nThe project folder's contents won't be modified."); + } + + erase_ask->set_text(confirm_message); erase_ask->popup_centered_minsize(); } +void ProjectManager::_erase_missing_projects() { + + erase_missing_ask->set_text(TTR("Remove all missing projects from the list? (Folders contents will not be modified)")); + erase_missing_ask->popup_centered_minsize(); +} + void ProjectManager::_language_selected(int p_id) { String lang = language_btn->get_item_metadata(p_id); @@ -1716,7 +1768,7 @@ void ProjectManager::_language_selected(int p_id) { language_btn->set_text(lang); language_btn->set_icon(get_icon("Environment", "EditorIcons")); - language_restart_ask->set_text(TTR("Language changed.\nThe UI will update next time the editor or project manager starts.")); + language_restart_ask->set_text(TTR("Language changed.\nThe interface will update after restarting the editor or project manager.")); language_restart_ask->popup_centered(); } @@ -1777,7 +1829,8 @@ void ProjectManager::_files_dropped(PoolStringArray p_files, int p_screen) { if (confirm) { multi_scan_ask->get_ok()->disconnect("pressed", this, "_scan_multiple_folders"); multi_scan_ask->get_ok()->connect("pressed", this, "_scan_multiple_folders", varray(folders)); - multi_scan_ask->set_text(vformat(TTR("You are about the scan %s folders for existing Godot projects. Do you confirm?"), folders.size())); + multi_scan_ask->set_text( + vformat(TTR("Are you sure to scan %s folders for existing Godot projects?\nThis could take a while."), folders.size())); multi_scan_ask->popup_centered_minsize(); } else { _scan_multiple_folders(folders); @@ -1804,7 +1857,9 @@ void ProjectManager::_bind_methods() { ClassDB::bind_method("_new_project", &ProjectManager::_new_project); ClassDB::bind_method("_rename_project", &ProjectManager::_rename_project); ClassDB::bind_method("_erase_project", &ProjectManager::_erase_project); + ClassDB::bind_method("_erase_missing_projects", &ProjectManager::_erase_missing_projects); ClassDB::bind_method("_erase_project_confirm", &ProjectManager::_erase_project_confirm); + ClassDB::bind_method("_erase_missing_projects_confirm", &ProjectManager::_erase_missing_projects_confirm); ClassDB::bind_method("_language_selected", &ProjectManager::_language_selected); ClassDB::bind_method("_restart_confirm", &ProjectManager::_restart_confirm); ClassDB::bind_method("_exit_dialog", &ProjectManager::_exit_dialog); @@ -2042,6 +2097,12 @@ ProjectManager::ProjectManager() { erase->connect("pressed", this, "_erase_project"); erase_btn = erase; + Button *erase_missing = memnew(Button); + erase_missing->set_text(TTR("Remove Missing")); + tree_vb->add_child(erase_missing); + erase_missing->connect("pressed", this, "_erase_missing_projects"); + erase_missing_btn = erase_missing; + tree_vb->add_spacer(); if (StreamPeerSSL::is_available()) { @@ -2093,6 +2154,19 @@ ProjectManager::ProjectManager() { Button *cancel = memnew(Button); cancel->set_text(TTR("Exit")); cancel->set_custom_minimum_size(Size2(100, 1) * EDSCALE); + +#ifndef OSX_ENABLED + // Pressing Command + Q quits the Project Manager + // This is handled by the platform implementation on macOS, + // so only define the shortcut on other platforms + InputEventKey *quit_key = memnew(InputEventKey); + quit_key->set_command(true); + quit_key->set_scancode(KEY_Q); + ShortCut *quit_shortcut = memnew(ShortCut); + quit_shortcut->set_shortcut(quit_key); + cancel->set_shortcut(quit_shortcut); +#endif + cc->add_child(cancel); cancel->connect("pressed", this, "_exit_dialog"); vb->add_child(cc); @@ -2105,6 +2179,11 @@ ProjectManager::ProjectManager() { language_restart_ask->get_cancel()->set_text(TTR("Continue")); gui_base->add_child(language_restart_ask); + erase_missing_ask = memnew(ConfirmationDialog); + erase_missing_ask->get_ok()->set_text(TTR("Remove All")); + erase_missing_ask->get_ok()->connect("pressed", this, "_erase_missing_projects_confirm"); + gui_base->add_child(erase_missing_ask); + erase_ask = memnew(ConfirmationDialog); erase_ask->get_ok()->set_text(TTR("Remove")); erase_ask->get_ok()->connect("pressed", this, "_erase_project_confirm"); @@ -2153,7 +2232,7 @@ ProjectManager::ProjectManager() { gui_base->add_child(dialog_error); open_templates = memnew(ConfirmationDialog); - open_templates->set_text(TTR("You don't currently have any projects.\nWould you like to explore the official example projects in the Asset Library?")); + open_templates->set_text(TTR("You currently don't have any projects.\nWould you like to explore official example projects in the Asset Library?")); open_templates->get_ok()->set_text(TTR("Open Asset Library")); open_templates->connect("confirmed", this, "_open_asset_library"); add_child(open_templates); |