Skip to content

Commit 09556cf

Browse files
KoBeWitGautot
authored andcommitted
Make scan for projects threaded
1 parent 24f0c71 commit 09556cf

File tree

3 files changed

+107
-19
lines changed

3 files changed

+107
-19
lines changed

editor/project_manager/project_list.cpp

+88-15
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,10 @@
4141
#include "editor/project_manager/project_tag.h"
4242
#include "editor/themes/editor_scale.h"
4343
#include "scene/gui/button.h"
44+
#include "scene/gui/dialogs.h"
4445
#include "scene/gui/label.h"
4546
#include "scene/gui/line_edit.h"
47+
#include "scene/gui/progress_bar.h"
4648
#include "scene/gui/texture_button.h"
4749
#include "scene/gui/texture_rect.h"
4850
#include "scene/resources/image_texture.h"
@@ -358,21 +360,70 @@ bool ProjectList::project_feature_looks_like_version(const String &p_feature) {
358360
void ProjectList::_notification(int p_what) {
359361
switch (p_what) {
360362
case NOTIFICATION_PROCESS: {
361-
// Load icons as a coroutine to speed up launch when you have hundreds of projects
363+
// Load icons as a coroutine to speed up launch when you have hundreds of projects.
362364
if (_icon_load_index < _projects.size()) {
363365
Item &item = _projects.write[_icon_load_index];
364366
if (item.control->should_load_project_icon()) {
365367
_load_project_icon(_icon_load_index);
366368
}
367369
_icon_load_index++;
368370

371+
// Scan directories in thread to avoid blocking the window.
372+
} else if (scan_data && scan_data->scan_in_progress.is_set()) {
373+
// Wait for the thread.
369374
} else {
370375
set_process(false);
376+
if (scan_data) {
377+
_scan_finished();
378+
}
371379
}
372380
} break;
373381
}
374382
}
375383

384+
// Projects scan.
385+
386+
void ProjectList::_scan_thread(void *p_scan_data) {
387+
ScanData *scan_data = static_cast<ScanData *>(p_scan_data);
388+
389+
for (const String &base_path : scan_data->paths_to_scan) {
390+
print_verbose(vformat("Scanning for projects in \"%s\".", base_path));
391+
_scan_folder_recursive(base_path, &scan_data->found_projects, scan_data->scan_in_progress);
392+
393+
if (!scan_data->scan_in_progress.is_set()) {
394+
print_verbose("Scan aborted.");
395+
break;
396+
}
397+
}
398+
print_verbose(vformat("Found %d project(s).", scan_data->found_projects.size()));
399+
scan_data->scan_in_progress.clear();
400+
}
401+
402+
void ProjectList::_scan_finished() {
403+
if (scan_data->scan_in_progress.is_set()) {
404+
// Abort scanning.
405+
scan_data->scan_in_progress.clear();
406+
}
407+
408+
scan_data->thread->wait_to_finish();
409+
memdelete(scan_data->thread);
410+
if (scan_progress) {
411+
scan_progress->hide();
412+
}
413+
414+
for (const String &E : scan_data->found_projects) {
415+
add_project(E, false);
416+
}
417+
memdelete(scan_data);
418+
scan_data = nullptr;
419+
420+
save_config();
421+
422+
if (ProjectManager::get_singleton()->is_initialized()) {
423+
update_project_list();
424+
}
425+
}
426+
376427
// Initialization & loading.
377428

378429
void ProjectList::_migrate_config() {
@@ -624,25 +675,39 @@ void ProjectList::find_projects(const String &p_path) {
624675
}
625676

626677
void ProjectList::find_projects_multiple(const PackedStringArray &p_paths) {
627-
List<String> projects;
678+
if (!scan_progress && is_inside_tree()) {
679+
scan_progress = memnew(AcceptDialog);
680+
scan_progress->set_title(TTR("Scanning"));
681+
scan_progress->set_ok_button_text(TTR("Cancel"));
628682

629-
for (int i = 0; i < p_paths.size(); i++) {
630-
const String &base_path = p_paths.get(i);
631-
print_verbose(vformat("Scanning for projects in \"%s\".", base_path));
683+
VBoxContainer *vb = memnew(VBoxContainer);
684+
scan_progress->add_child(vb);
632685

633-
_scan_folder_recursive(base_path, &projects);
634-
print_verbose(vformat("Found %d project(s).", projects.size()));
635-
}
686+
Label *label = memnew(Label);
687+
label->set_text(TTR("Scanning for projects..."));
688+
vb->add_child(label);
636689

637-
for (const String &E : projects) {
638-
add_project(E, false);
690+
ProgressBar *progress = memnew(ProgressBar);
691+
progress->set_indeterminate(true);
692+
vb->add_child(progress);
693+
694+
add_child(scan_progress);
695+
scan_progress->connect(SceneStringName(confirmed), callable_mp(this, &ProjectList::_scan_finished));
696+
scan_progress->connect("canceled", callable_mp(this, &ProjectList::_scan_finished));
639697
}
640698

641-
save_config();
699+
scan_data = memnew(ScanData);
700+
scan_data->paths_to_scan = p_paths;
701+
scan_data->scan_in_progress.set();
642702

643-
if (ProjectManager::get_singleton()->is_initialized()) {
644-
update_project_list();
703+
scan_data->thread = memnew(Thread);
704+
scan_data->thread->start(_scan_thread, scan_data);
705+
706+
if (scan_progress) {
707+
scan_progress->reset_size();
708+
scan_progress->popup_centered();
645709
}
710+
set_process(true);
646711
}
647712

648713
void ProjectList::load_project_list() {
@@ -656,16 +721,24 @@ void ProjectList::load_project_list() {
656721
}
657722
}
658723

659-
void ProjectList::_scan_folder_recursive(const String &p_path, List<String> *r_projects) {
724+
void ProjectList::_scan_folder_recursive(const String &p_path, List<String> *r_projects, const SafeFlag &p_scan_active) {
725+
if (!p_scan_active.is_set()) {
726+
return;
727+
}
728+
660729
Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
661730
Error error = da->change_dir(p_path);
662731
ERR_FAIL_COND_MSG(error != OK, vformat("Failed to open the path \"%s\" for scanning (code %d).", p_path, error));
663732

664733
da->list_dir_begin();
665734
String n = da->get_next();
666735
while (!n.is_empty()) {
736+
if (!p_scan_active.is_set()) {
737+
return;
738+
}
739+
667740
if (da->current_is_dir() && n[0] != '.') {
668-
_scan_folder_recursive(da->get_current_dir().path_join(n), r_projects);
741+
_scan_folder_recursive(da->get_current_dir().path_join(n), r_projects, p_scan_active);
669742
} else if (n == "project.godot") {
670743
r_projects->push_back(da->get_current_dir());
671744
}

editor/project_manager/project_list.h

+16-1
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
#include "scene/gui/box_container.h"
3636
#include "scene/gui/scroll_container.h"
3737

38+
class AcceptDialog;
3839
class Button;
3940
class Label;
4041
class ProjectList;
@@ -176,6 +177,20 @@ class ProjectList : public ScrollContainer {
176177

177178
VBoxContainer *project_list_vbox = nullptr;
178179

180+
// Projects scan.
181+
182+
struct ScanData {
183+
Thread *thread = nullptr;
184+
PackedStringArray paths_to_scan;
185+
List<String> found_projects;
186+
SafeFlag scan_in_progress;
187+
};
188+
ScanData *scan_data = nullptr;
189+
AcceptDialog *scan_progress = nullptr;
190+
191+
static void _scan_thread(void *p_scan_data);
192+
void _scan_finished();
193+
179194
// Initialization & loading.
180195

181196
void _migrate_config();
@@ -186,7 +201,7 @@ class ProjectList : public ScrollContainer {
186201

187202
// Project list updates.
188203

189-
void _scan_folder_recursive(const String &p_path, List<String> *r_projects);
204+
static void _scan_folder_recursive(const String &p_path, List<String> *r_projects, const SafeFlag &p_scan_active);
190205

191206
// Project list items.
192207

scene/gui/progress_bar.cpp

+3-3
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ void ProgressBar::_notification(int p_what) {
6161
Size2 size = get_size();
6262
real_t fill_size = MIN(size.width, size.height) * 2;
6363

64-
if (Engine::get_singleton()->is_editor_hint() && !editor_preview_indeterminate) {
64+
if (is_part_of_edited_scene() && !editor_preview_indeterminate) {
6565
// Center the filled bar when we're not previewing the animation.
6666
_inderminate_fill_progress = (MAX(size.width, size.height) / 2) + (fill_size / 2);
6767
}
@@ -217,7 +217,7 @@ void ProgressBar::set_indeterminate(bool p_indeterminate) {
217217
indeterminate = p_indeterminate;
218218
_inderminate_fill_progress = 0;
219219

220-
bool should_process = !Engine::get_singleton()->is_editor_hint() || editor_preview_indeterminate;
220+
bool should_process = !is_part_of_edited_scene() || editor_preview_indeterminate;
221221
set_process_internal(indeterminate && should_process);
222222

223223
notify_property_list_changed();
@@ -235,7 +235,7 @@ void ProgressBar::set_editor_preview_indeterminate(bool p_preview_indeterminate)
235235
}
236236
editor_preview_indeterminate = p_preview_indeterminate;
237237

238-
if (Engine::get_singleton()->is_editor_hint()) {
238+
if (is_part_of_edited_scene()) {
239239
_inderminate_fill_progress = 0;
240240
set_process_internal(indeterminate && editor_preview_indeterminate);
241241
queue_redraw();

0 commit comments

Comments
 (0)