mirror of https://github.com/godotengine/godot
Make scan for projects threaded
This commit is contained in:
parent
19e003bc08
commit
cb4ceb823c
|
|
@ -41,8 +41,10 @@
|
|||
#include "editor/project_manager/project_tag.h"
|
||||
#include "editor/themes/editor_scale.h"
|
||||
#include "scene/gui/button.h"
|
||||
#include "scene/gui/dialogs.h"
|
||||
#include "scene/gui/label.h"
|
||||
#include "scene/gui/line_edit.h"
|
||||
#include "scene/gui/progress_bar.h"
|
||||
#include "scene/gui/texture_button.h"
|
||||
#include "scene/gui/texture_rect.h"
|
||||
#include "scene/resources/image_texture.h"
|
||||
|
|
@ -358,7 +360,7 @@ bool ProjectList::project_feature_looks_like_version(const String &p_feature) {
|
|||
void ProjectList::_notification(int p_what) {
|
||||
switch (p_what) {
|
||||
case NOTIFICATION_PROCESS: {
|
||||
// Load icons as a coroutine to speed up launch when you have hundreds of projects
|
||||
// Load icons as a coroutine to speed up launch when you have hundreds of projects.
|
||||
if (_icon_load_index < _projects.size()) {
|
||||
Item &item = _projects.write[_icon_load_index];
|
||||
if (item.control->should_load_project_icon()) {
|
||||
|
|
@ -366,13 +368,62 @@ void ProjectList::_notification(int p_what) {
|
|||
}
|
||||
_icon_load_index++;
|
||||
|
||||
// Scan directories in thread to avoid blocking the window.
|
||||
} else if (scan_data && scan_data->scan_in_progress.is_set()) {
|
||||
// Wait for the thread.
|
||||
} else {
|
||||
set_process(false);
|
||||
if (scan_data) {
|
||||
_scan_finished();
|
||||
}
|
||||
}
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
// Projects scan.
|
||||
|
||||
void ProjectList::_scan_thread(void *p_scan_data) {
|
||||
ScanData *scan_data = static_cast<ScanData *>(p_scan_data);
|
||||
|
||||
for (const String &base_path : scan_data->paths_to_scan) {
|
||||
print_verbose(vformat("Scanning for projects in \"%s\".", base_path));
|
||||
_scan_folder_recursive(base_path, &scan_data->found_projects, scan_data->scan_in_progress);
|
||||
|
||||
if (!scan_data->scan_in_progress.is_set()) {
|
||||
print_verbose("Scan aborted.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
print_verbose(vformat("Found %d project(s).", scan_data->found_projects.size()));
|
||||
scan_data->scan_in_progress.clear();
|
||||
}
|
||||
|
||||
void ProjectList::_scan_finished() {
|
||||
if (scan_data->scan_in_progress.is_set()) {
|
||||
// Abort scanning.
|
||||
scan_data->scan_in_progress.clear();
|
||||
}
|
||||
|
||||
scan_data->thread->wait_to_finish();
|
||||
memdelete(scan_data->thread);
|
||||
if (scan_progress) {
|
||||
scan_progress->hide();
|
||||
}
|
||||
|
||||
for (const String &E : scan_data->found_projects) {
|
||||
add_project(E, false);
|
||||
}
|
||||
memdelete(scan_data);
|
||||
scan_data = nullptr;
|
||||
|
||||
save_config();
|
||||
|
||||
if (ProjectManager::get_singleton()->is_initialized()) {
|
||||
update_project_list();
|
||||
}
|
||||
}
|
||||
|
||||
// Initialization & loading.
|
||||
|
||||
void ProjectList::_migrate_config() {
|
||||
|
|
@ -624,25 +675,39 @@ void ProjectList::find_projects(const String &p_path) {
|
|||
}
|
||||
|
||||
void ProjectList::find_projects_multiple(const PackedStringArray &p_paths) {
|
||||
List<String> projects;
|
||||
if (!scan_progress && is_inside_tree()) {
|
||||
scan_progress = memnew(AcceptDialog);
|
||||
scan_progress->set_title(TTR("Scanning"));
|
||||
scan_progress->set_ok_button_text(TTR("Cancel"));
|
||||
|
||||
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));
|
||||
VBoxContainer *vb = memnew(VBoxContainer);
|
||||
scan_progress->add_child(vb);
|
||||
|
||||
_scan_folder_recursive(base_path, &projects);
|
||||
print_verbose(vformat("Found %d project(s).", projects.size()));
|
||||
Label *label = memnew(Label);
|
||||
label->set_text(TTR("Scanning for projects..."));
|
||||
vb->add_child(label);
|
||||
|
||||
ProgressBar *progress = memnew(ProgressBar);
|
||||
progress->set_indeterminate(true);
|
||||
vb->add_child(progress);
|
||||
|
||||
add_child(scan_progress);
|
||||
scan_progress->connect(SceneStringName(confirmed), callable_mp(this, &ProjectList::_scan_finished));
|
||||
scan_progress->connect("canceled", callable_mp(this, &ProjectList::_scan_finished));
|
||||
}
|
||||
|
||||
for (const String &E : projects) {
|
||||
add_project(E, false);
|
||||
}
|
||||
scan_data = memnew(ScanData);
|
||||
scan_data->paths_to_scan = p_paths;
|
||||
scan_data->scan_in_progress.set();
|
||||
|
||||
save_config();
|
||||
scan_data->thread = memnew(Thread);
|
||||
scan_data->thread->start(_scan_thread, scan_data);
|
||||
|
||||
if (ProjectManager::get_singleton()->is_initialized()) {
|
||||
update_project_list();
|
||||
if (scan_progress) {
|
||||
scan_progress->reset_size();
|
||||
scan_progress->popup_centered();
|
||||
}
|
||||
set_process(true);
|
||||
}
|
||||
|
||||
void ProjectList::load_project_list() {
|
||||
|
|
@ -656,7 +721,11 @@ void ProjectList::load_project_list() {
|
|||
}
|
||||
}
|
||||
|
||||
void ProjectList::_scan_folder_recursive(const String &p_path, List<String> *r_projects) {
|
||||
void ProjectList::_scan_folder_recursive(const String &p_path, List<String> *r_projects, const SafeFlag &p_scan_active) {
|
||||
if (!p_scan_active.is_set()) {
|
||||
return;
|
||||
}
|
||||
|
||||
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));
|
||||
|
|
@ -664,8 +733,12 @@ void ProjectList::_scan_folder_recursive(const String &p_path, List<String> *r_p
|
|||
da->list_dir_begin();
|
||||
String n = da->get_next();
|
||||
while (!n.is_empty()) {
|
||||
if (!p_scan_active.is_set()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (da->current_is_dir() && n[0] != '.') {
|
||||
_scan_folder_recursive(da->get_current_dir().path_join(n), r_projects);
|
||||
_scan_folder_recursive(da->get_current_dir().path_join(n), r_projects, p_scan_active);
|
||||
} else if (n == "project.godot") {
|
||||
r_projects->push_back(da->get_current_dir());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@
|
|||
#include "scene/gui/box_container.h"
|
||||
#include "scene/gui/scroll_container.h"
|
||||
|
||||
class AcceptDialog;
|
||||
class Button;
|
||||
class Label;
|
||||
class ProjectList;
|
||||
|
|
@ -176,6 +177,20 @@ private:
|
|||
|
||||
VBoxContainer *project_list_vbox = nullptr;
|
||||
|
||||
// Projects scan.
|
||||
|
||||
struct ScanData {
|
||||
Thread *thread = nullptr;
|
||||
PackedStringArray paths_to_scan;
|
||||
List<String> found_projects;
|
||||
SafeFlag scan_in_progress;
|
||||
};
|
||||
ScanData *scan_data = nullptr;
|
||||
AcceptDialog *scan_progress = nullptr;
|
||||
|
||||
static void _scan_thread(void *p_scan_data);
|
||||
void _scan_finished();
|
||||
|
||||
// Initialization & loading.
|
||||
|
||||
void _migrate_config();
|
||||
|
|
@ -186,7 +201,7 @@ private:
|
|||
|
||||
// Project list updates.
|
||||
|
||||
void _scan_folder_recursive(const String &p_path, List<String> *r_projects);
|
||||
static void _scan_folder_recursive(const String &p_path, List<String> *r_projects, const SafeFlag &p_scan_active);
|
||||
|
||||
// Project list items.
|
||||
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ void ProgressBar::_notification(int p_what) {
|
|||
Size2 size = get_size();
|
||||
real_t fill_size = MIN(size.width, size.height) * 2;
|
||||
|
||||
if (Engine::get_singleton()->is_editor_hint() && !editor_preview_indeterminate) {
|
||||
if (is_part_of_edited_scene() && !editor_preview_indeterminate) {
|
||||
// Center the filled bar when we're not previewing the animation.
|
||||
_inderminate_fill_progress = (MAX(size.width, size.height) / 2) + (fill_size / 2);
|
||||
}
|
||||
|
|
@ -217,7 +217,7 @@ void ProgressBar::set_indeterminate(bool p_indeterminate) {
|
|||
indeterminate = p_indeterminate;
|
||||
_inderminate_fill_progress = 0;
|
||||
|
||||
bool should_process = !Engine::get_singleton()->is_editor_hint() || editor_preview_indeterminate;
|
||||
bool should_process = !is_part_of_edited_scene() || editor_preview_indeterminate;
|
||||
set_process_internal(indeterminate && should_process);
|
||||
|
||||
notify_property_list_changed();
|
||||
|
|
@ -235,7 +235,7 @@ void ProgressBar::set_editor_preview_indeterminate(bool p_preview_indeterminate)
|
|||
}
|
||||
editor_preview_indeterminate = p_preview_indeterminate;
|
||||
|
||||
if (Engine::get_singleton()->is_editor_hint()) {
|
||||
if (is_part_of_edited_scene()) {
|
||||
_inderminate_fill_progress = 0;
|
||||
set_process_internal(indeterminate && editor_preview_indeterminate);
|
||||
queue_redraw();
|
||||
|
|
|
|||
Loading…
Reference in New Issue