Merge pull request #86271 from YuriSizov/pm-optimize-multiple-ways-of-scanning
Optimize scanning routines in the project manager
This commit is contained in:
commit
5f641541ea
2 changed files with 97 additions and 113 deletions
|
@ -1249,6 +1249,7 @@ struct ProjectListComparator {
|
|||
}
|
||||
};
|
||||
|
||||
const char *ProjectList::SIGNAL_LIST_CHANGED = "list_changed";
|
||||
const char *ProjectList::SIGNAL_SELECTION_CHANGED = "selection_changed";
|
||||
const char *ProjectList::SIGNAL_PROJECT_ASK_OPEN = "project_ask_open";
|
||||
|
||||
|
@ -1356,7 +1357,7 @@ ProjectList::Item ProjectList::load_project_data(const String &p_path, bool p_fa
|
|||
return Item(project_name, description, tags, p_path, icon, main_scene, unsupported_features, last_edited, p_favorite, grayed, missing, config_version);
|
||||
}
|
||||
|
||||
void ProjectList::migrate_config() {
|
||||
void ProjectList::_migrate_config() {
|
||||
// Proposal #1637 moved the project list from editor settings to a separate config file
|
||||
// If the new config file doesn't exist, populate it from EditorSettings
|
||||
if (FileAccess::exists(_config_path)) {
|
||||
|
@ -1388,9 +1389,10 @@ void ProjectList::migrate_config() {
|
|||
save_config();
|
||||
}
|
||||
|
||||
void ProjectList::load_projects() {
|
||||
void ProjectList::update_project_list() {
|
||||
// This is a full, hard reload of the list. Don't call this unless really required, it's expensive.
|
||||
// If you have 150 projects, it may read through 150 files on your disk at once + load 150 icons.
|
||||
// FIXME: Does it really have to be a full, hard reload? Runtime updates should be made much cheaper.
|
||||
|
||||
// Clear whole list
|
||||
for (int i = 0; i < _projects.size(); ++i) {
|
||||
|
@ -1421,6 +1423,7 @@ void ProjectList::load_projects() {
|
|||
update_dock_menu();
|
||||
|
||||
set_v_scroll(0);
|
||||
emit_signal(SNAME(SIGNAL_LIST_CHANGED));
|
||||
}
|
||||
|
||||
void ProjectList::update_dock_menu() {
|
||||
|
@ -1678,6 +1681,48 @@ void ProjectList::erase_missing_projects() {
|
|||
save_config();
|
||||
}
|
||||
|
||||
void ProjectList::_scan_folder_recursive(const String &p_path, List<String> *r_projects) {
|
||||
Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
|
||||
Error error = da->change_dir(p_path);
|
||||
ERR_FAIL_COND_MSG(error != OK, vformat("Failed to open the path \"%s\" for scanning (code %d).", p_path, error));
|
||||
|
||||
da->list_dir_begin();
|
||||
String n = da->get_next();
|
||||
while (!n.is_empty()) {
|
||||
if (da->current_is_dir() && n[0] != '.') {
|
||||
_scan_folder_recursive(da->get_current_dir().path_join(n), r_projects);
|
||||
} else if (n == "project.godot") {
|
||||
r_projects->push_back(da->get_current_dir());
|
||||
}
|
||||
n = da->get_next();
|
||||
}
|
||||
da->list_dir_end();
|
||||
}
|
||||
|
||||
void ProjectList::find_projects(const String &p_path) {
|
||||
PackedStringArray paths = { p_path };
|
||||
find_projects_multiple(paths);
|
||||
}
|
||||
|
||||
void ProjectList::find_projects_multiple(const PackedStringArray &p_paths) {
|
||||
List<String> projects;
|
||||
|
||||
for (int i = 0; i < p_paths.size(); i++) {
|
||||
const String &base_path = p_paths.get(i);
|
||||
print_verbose(vformat("Scanning for projects in \"%s\".", base_path));
|
||||
|
||||
_scan_folder_recursive(base_path, &projects);
|
||||
print_verbose(vformat("Found %d project(s).", projects.size()));
|
||||
}
|
||||
|
||||
for (const String &E : projects) {
|
||||
add_project(E, false);
|
||||
}
|
||||
|
||||
save_config();
|
||||
update_project_list();
|
||||
}
|
||||
|
||||
int ProjectList::refresh_project(const String &dir_path) {
|
||||
// Reloads information about a specific project.
|
||||
// If it wasn't loaded and should be in the list, it is added (i.e new project).
|
||||
|
@ -1916,6 +1961,7 @@ void ProjectList::_show_project(const String &p_path) {
|
|||
}
|
||||
|
||||
void ProjectList::_bind_methods() {
|
||||
ADD_SIGNAL(MethodInfo(SIGNAL_LIST_CHANGED));
|
||||
ADD_SIGNAL(MethodInfo(SIGNAL_SELECTION_CHANGED));
|
||||
ADD_SIGNAL(MethodInfo(SIGNAL_PROJECT_ASK_OPEN));
|
||||
}
|
||||
|
@ -1926,6 +1972,7 @@ ProjectList::ProjectList() {
|
|||
add_child(_scroll_children);
|
||||
|
||||
_config_path = EditorPaths::get_singleton()->get_data_dir().path_join("projects.cfg");
|
||||
_migrate_config();
|
||||
}
|
||||
|
||||
/// Project Manager.
|
||||
|
@ -2213,15 +2260,6 @@ void ProjectManager::shortcut_input(const Ref<InputEvent> &p_ev) {
|
|||
}
|
||||
}
|
||||
|
||||
void ProjectManager::_load_recent_projects() {
|
||||
_project_list->set_search_term(search_box->get_text().strip_edges());
|
||||
_project_list->load_projects();
|
||||
|
||||
_update_project_buttons();
|
||||
|
||||
tabs->set_current_tab(0);
|
||||
}
|
||||
|
||||
void ProjectManager::_on_projects_updated() {
|
||||
Vector<ProjectList::Item> selected_projects = _project_list->get_selected_projects();
|
||||
int index = 0;
|
||||
|
@ -2459,30 +2497,6 @@ void ProjectManager::_run_project() {
|
|||
}
|
||||
}
|
||||
|
||||
void ProjectManager::_scan_dir(const String &path) {
|
||||
Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
|
||||
Error error = da->change_dir(path);
|
||||
ERR_FAIL_COND_MSG(error != OK, "Could not scan directory at: " + path);
|
||||
da->list_dir_begin();
|
||||
String n = da->get_next();
|
||||
while (!n.is_empty()) {
|
||||
if (da->current_is_dir() && !n.begins_with(".")) {
|
||||
_scan_dir(da->get_current_dir().path_join(n));
|
||||
} else if (n == "project.godot") {
|
||||
_project_list->add_project(da->get_current_dir(), false);
|
||||
}
|
||||
n = da->get_next();
|
||||
}
|
||||
da->list_dir_end();
|
||||
}
|
||||
|
||||
void ProjectManager::_scan_begin(const String &p_base) {
|
||||
print_line("Scanning projects at: " + p_base);
|
||||
_scan_dir(p_base);
|
||||
_project_list->save_config();
|
||||
_load_recent_projects();
|
||||
}
|
||||
|
||||
void ProjectManager::_scan_projects() {
|
||||
scan_dir->popup_file_dialog();
|
||||
}
|
||||
|
@ -2682,54 +2696,26 @@ void ProjectManager::_install_project(const String &p_zip_path, const String &p_
|
|||
}
|
||||
|
||||
void ProjectManager::_files_dropped(PackedStringArray p_files) {
|
||||
// TODO: Support installing multiple ZIPs at the same time?
|
||||
if (p_files.size() == 1 && p_files[0].ends_with(".zip")) {
|
||||
const String file = p_files[0].get_file();
|
||||
_install_project(p_files[0], file.substr(0, file.length() - 4).capitalize());
|
||||
const String &file = p_files[0];
|
||||
_install_project(file, file.get_file().get_basename().capitalize());
|
||||
return;
|
||||
}
|
||||
|
||||
HashSet<String> folders_set;
|
||||
Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
|
||||
for (int i = 0; i < p_files.size(); i++) {
|
||||
String file = p_files[i];
|
||||
const String &file = p_files[i];
|
||||
folders_set.insert(da->dir_exists(file) ? file : file.get_base_dir());
|
||||
}
|
||||
if (folders_set.size() > 0) {
|
||||
PackedStringArray folders;
|
||||
for (const String &E : folders_set) {
|
||||
folders.push_back(E);
|
||||
}
|
||||
ERR_FAIL_COND(folders_set.size() == 0); // This can't really happen, we consume every dropped file path above.
|
||||
|
||||
bool confirm = true;
|
||||
if (folders.size() == 1) {
|
||||
Ref<DirAccess> dir = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
|
||||
if (dir->change_dir(folders[0]) == OK) {
|
||||
dir->list_dir_begin();
|
||||
String file = dir->get_next();
|
||||
while (confirm && !file.is_empty()) {
|
||||
if (!dir->current_is_dir() && file.ends_with("project.godot")) {
|
||||
confirm = false;
|
||||
}
|
||||
file = dir->get_next();
|
||||
}
|
||||
dir->list_dir_end();
|
||||
}
|
||||
}
|
||||
if (confirm) {
|
||||
multi_scan_ask->get_ok_button()->disconnect("pressed", callable_mp(this, &ProjectManager::_scan_multiple_folders));
|
||||
multi_scan_ask->get_ok_button()->connect("pressed", callable_mp(this, &ProjectManager::_scan_multiple_folders).bind(folders));
|
||||
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();
|
||||
} else {
|
||||
_scan_multiple_folders(folders);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ProjectManager::_scan_multiple_folders(PackedStringArray p_files) {
|
||||
for (int i = 0; i < p_files.size(); i++) {
|
||||
_scan_begin(p_files.get(i));
|
||||
PackedStringArray folders;
|
||||
for (const String &E : folders_set) {
|
||||
folders.push_back(E);
|
||||
}
|
||||
_project_list->find_projects_multiple(folders);
|
||||
}
|
||||
|
||||
void ProjectManager::_on_order_option_changed(int p_idx) {
|
||||
|
@ -2770,11 +2756,6 @@ void ProjectManager::_on_search_term_submitted(const String &p_text) {
|
|||
_open_selected_projects_ask();
|
||||
}
|
||||
|
||||
void ProjectManager::_bind_methods() {
|
||||
ClassDB::bind_method("_update_project_buttons", &ProjectManager::_update_project_buttons);
|
||||
ClassDB::bind_method("_version_button_pressed", &ProjectManager::_version_button_pressed);
|
||||
}
|
||||
|
||||
void ProjectManager::_open_asset_library() {
|
||||
asset_library->disable_community_support();
|
||||
tabs->set_current_tab(1);
|
||||
|
@ -2900,8 +2881,8 @@ ProjectManager::ProjectManager() {
|
|||
vb->add_child(center_box);
|
||||
|
||||
tabs = memnew(TabContainer);
|
||||
center_box->add_child(tabs);
|
||||
tabs->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT);
|
||||
center_box->add_child(tabs);
|
||||
tabs->connect("tab_changed", callable_mp(this, &ProjectManager::_on_tab_changed));
|
||||
|
||||
local_projects_vb = memnew(VBoxContainer);
|
||||
|
@ -2980,10 +2961,11 @@ ProjectManager::ProjectManager() {
|
|||
search_tree_hb->add_child(search_panel);
|
||||
|
||||
_project_list = memnew(ProjectList);
|
||||
_project_list->connect(ProjectList::SIGNAL_SELECTION_CHANGED, callable_mp(this, &ProjectManager::_update_project_buttons));
|
||||
_project_list->connect(ProjectList::SIGNAL_PROJECT_ASK_OPEN, callable_mp(this, &ProjectManager::_open_selected_projects_ask));
|
||||
_project_list->set_horizontal_scroll_mode(ScrollContainer::SCROLL_MODE_DISABLED);
|
||||
search_panel->add_child(_project_list);
|
||||
_project_list->connect(ProjectList::SIGNAL_LIST_CHANGED, callable_mp(this, &ProjectManager::_update_project_buttons));
|
||||
_project_list->connect(ProjectList::SIGNAL_SELECTION_CHANGED, callable_mp(this, &ProjectManager::_update_project_buttons));
|
||||
_project_list->connect(ProjectList::SIGNAL_PROJECT_ASK_OPEN, callable_mp(this, &ProjectManager::_open_selected_projects_ask));
|
||||
|
||||
// The side bar with the edit, run, rename, etc. buttons.
|
||||
VBoxContainer *tree_vb = memnew(VBoxContainer);
|
||||
|
@ -3129,7 +3111,7 @@ ProjectManager::ProjectManager() {
|
|||
scan_dir->set_title(TTR("Select a Folder to Scan")); // must be after mode or it's overridden
|
||||
scan_dir->set_current_dir(EDITOR_GET("filesystem/directories/default_project_path"));
|
||||
add_child(scan_dir);
|
||||
scan_dir->connect("dir_selected", callable_mp(this, &ProjectManager::_scan_begin));
|
||||
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"));
|
||||
|
@ -3163,10 +3145,6 @@ ProjectManager::ProjectManager() {
|
|||
multi_run_ask->get_ok_button()->connect("pressed", callable_mp(this, &ProjectManager::_run_project_confirm));
|
||||
add_child(multi_run_ask);
|
||||
|
||||
multi_scan_ask = memnew(ConfirmationDialog);
|
||||
multi_scan_ask->set_ok_button_text(TTR("Scan"));
|
||||
add_child(multi_scan_ask);
|
||||
|
||||
ask_update_settings = memnew(ConfirmationDialog);
|
||||
ask_update_settings->set_autowrap(true);
|
||||
ask_update_settings->get_ok_button()->connect("pressed", callable_mp(this, &ProjectManager::_confirm_update_settings));
|
||||
|
@ -3275,29 +3253,36 @@ ProjectManager::ProjectManager() {
|
|||
create_tag_btn->connect("pressed", callable_mp((Window *)create_tag_dialog, &Window::popup_centered).bind(Vector2i(500, 0) * EDSCALE));
|
||||
}
|
||||
|
||||
_project_list->migrate_config();
|
||||
_load_recent_projects();
|
||||
// Initialize project list.
|
||||
{
|
||||
Ref<DirAccess> dir_access = DirAccess::create(DirAccess::AccessType::ACCESS_FILESYSTEM);
|
||||
|
||||
Ref<DirAccess> dir_access = DirAccess::create(DirAccess::AccessType::ACCESS_FILESYSTEM);
|
||||
|
||||
String default_project_path = EDITOR_GET("filesystem/directories/default_project_path");
|
||||
if (!dir_access->dir_exists(default_project_path)) {
|
||||
Error error = dir_access->make_dir_recursive(default_project_path);
|
||||
if (error != OK) {
|
||||
ERR_PRINT("Could not create default project directory at: " + default_project_path);
|
||||
}
|
||||
}
|
||||
|
||||
String autoscan_path = EDITOR_GET("filesystem/directories/autoscan_project_path");
|
||||
if (!autoscan_path.is_empty()) {
|
||||
if (dir_access->dir_exists(autoscan_path)) {
|
||||
_scan_begin(autoscan_path);
|
||||
} else {
|
||||
Error error = dir_access->make_dir_recursive(autoscan_path);
|
||||
String default_project_path = EDITOR_GET("filesystem/directories/default_project_path");
|
||||
if (!default_project_path.is_empty() && !dir_access->dir_exists(default_project_path)) {
|
||||
Error error = dir_access->make_dir_recursive(default_project_path);
|
||||
if (error != OK) {
|
||||
ERR_PRINT("Could not create project autoscan directory at: " + autoscan_path);
|
||||
ERR_PRINT("Could not create default project directory at: " + default_project_path);
|
||||
}
|
||||
}
|
||||
|
||||
bool scanned_for_projects = false; // Scanning will update the list automatically.
|
||||
|
||||
String autoscan_path = EDITOR_GET("filesystem/directories/autoscan_project_path");
|
||||
if (!autoscan_path.is_empty()) {
|
||||
if (dir_access->dir_exists(autoscan_path)) {
|
||||
_project_list->find_projects(autoscan_path);
|
||||
scanned_for_projects = true;
|
||||
} else {
|
||||
Error error = dir_access->make_dir_recursive(autoscan_path);
|
||||
if (error != OK) {
|
||||
ERR_PRINT("Could not create project autoscan directory at: " + autoscan_path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!scanned_for_projects) {
|
||||
_project_list->update_project_list();
|
||||
}
|
||||
}
|
||||
|
||||
SceneTree::get_singleton()->get_root()->connect("files_dropped", callable_mp(this, &ProjectManager::_files_dropped));
|
||||
|
|
|
@ -267,6 +267,9 @@ private:
|
|||
void _favorite_pressed(Node *p_hb);
|
||||
void _show_project(const String &p_path);
|
||||
|
||||
void _migrate_config();
|
||||
void _scan_folder_recursive(const String &p_path, List<String> *r_projects);
|
||||
|
||||
void _clear_project_selection();
|
||||
void _toggle_project(int p_index);
|
||||
void _select_project_nocheck(int p_index);
|
||||
|
@ -288,12 +291,15 @@ protected:
|
|||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
static const char *SIGNAL_LIST_CHANGED;
|
||||
static const char *SIGNAL_SELECTION_CHANGED;
|
||||
static const char *SIGNAL_PROJECT_ASK_OPEN;
|
||||
|
||||
void load_projects();
|
||||
void update_project_list();
|
||||
int get_project_count() const;
|
||||
|
||||
void find_projects(const String &p_path);
|
||||
void find_projects_multiple(const PackedStringArray &p_paths);
|
||||
void sort_projects();
|
||||
|
||||
void add_project(const String &dir_path, bool favorite);
|
||||
|
@ -316,7 +322,6 @@ public:
|
|||
void set_order_option(int p_option);
|
||||
|
||||
void update_dock_menu();
|
||||
void migrate_config();
|
||||
void save_config();
|
||||
|
||||
ProjectList();
|
||||
|
@ -369,7 +374,6 @@ class ProjectManager : public Control {
|
|||
ConfirmationDialog *erase_missing_ask = nullptr;
|
||||
ConfirmationDialog *multi_open_ask = nullptr;
|
||||
ConfirmationDialog *multi_run_ask = nullptr;
|
||||
ConfirmationDialog *multi_scan_ask = nullptr;
|
||||
ConfirmationDialog *ask_full_convert_dialog = nullptr;
|
||||
ConfirmationDialog *ask_update_settings = nullptr;
|
||||
ConfirmationDialog *open_templates = nullptr;
|
||||
|
@ -425,12 +429,8 @@ class ProjectManager : public Control {
|
|||
void _set_new_tag_name(const String p_name);
|
||||
void _create_new_tag();
|
||||
|
||||
void _load_recent_projects();
|
||||
void _on_project_created(const String &dir);
|
||||
void _on_projects_updated();
|
||||
void _scan_multiple_folders(PackedStringArray p_files);
|
||||
void _scan_begin(const String &p_base);
|
||||
void _scan_dir(const String &path);
|
||||
|
||||
void _install_project(const String &p_zip_path, const String &p_title);
|
||||
|
||||
|
@ -449,7 +449,6 @@ class ProjectManager : public Control {
|
|||
|
||||
protected:
|
||||
void _notification(int p_what);
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
static ProjectManager *get_singleton() { return singleton; }
|
||||
|
|
Loading…
Reference in a new issue