Merge pull request #77471 from AThousandShips/help_search_index

Cache `TreeItem`s between runs in `EditorHelpSearch`
This commit is contained in:
Yuri Sizov 2024-01-17 18:52:19 +01:00
commit 039bc52df9
2 changed files with 122 additions and 42 deletions

View File

@ -48,7 +48,7 @@ void EditorHelpSearch::_update_results() {
search_flags |= SEARCH_SHOW_HIERARCHY; search_flags |= SEARCH_SHOW_HIERARCHY;
} }
search = Ref<Runner>(memnew(Runner(results_tree, results_tree, term, search_flags))); search = Ref<Runner>(memnew(Runner(results_tree, results_tree, &tree_cache, term, search_flags)));
set_process(true); set_process(true);
} }
@ -96,6 +96,7 @@ void EditorHelpSearch::_notification(int p_what) {
switch (p_what) { switch (p_what) {
case NOTIFICATION_VISIBILITY_CHANGED: { case NOTIFICATION_VISIBILITY_CHANGED: {
if (!is_visible()) { if (!is_visible()) {
tree_cache.clear();
callable_mp(results_tree, &Tree::clear).call_deferred(); // Wait for the Tree's mouse event propagation. callable_mp(results_tree, &Tree::clear).call_deferred(); // Wait for the Tree's mouse event propagation.
get_ok_button()->set_disabled(true); get_ok_button()->set_disabled(true);
EditorSettings::get_singleton()->set_project_metadata("dialog_bounds", "search_help", Rect2(get_position(), get_size())); EditorSettings::get_singleton()->set_project_metadata("dialog_bounds", "search_help", Rect2(get_position(), get_size()));
@ -258,6 +259,13 @@ EditorHelpSearch::EditorHelpSearch() {
vbox->add_child(results_tree, true); vbox->add_child(results_tree, true);
} }
void EditorHelpSearch::TreeCache::clear() {
for (const KeyValue<String, TreeItem *> &E : item_cache) {
memdelete(E.value);
}
item_cache.clear();
}
bool EditorHelpSearch::Runner::_is_class_disabled_by_feature_profile(const StringName &p_class) { bool EditorHelpSearch::Runner::_is_class_disabled_by_feature_profile(const StringName &p_class) {
Ref<EditorFeatureProfile> profile = EditorFeatureProfileManager::get_singleton()->get_current_profile(); Ref<EditorFeatureProfile> profile = EditorFeatureProfileManager::get_singleton()->get_current_profile();
if (profile.is_null()) { if (profile.is_null()) {
@ -436,11 +444,42 @@ bool EditorHelpSearch::Runner::_phase_match_classes() {
return iterator_stack.is_empty(); return iterator_stack.is_empty();
} }
void EditorHelpSearch::Runner::_populate_cache() {
root_item = results_tree->get_root();
if (root_item) {
LocalVector<TreeItem *> stack;
// Add children of root item to stack.
for (TreeItem *child = root_item->get_first_child(); child; child = child->get_next()) {
stack.push_back(child);
}
// Traverse stack and cache items.
while (!stack.is_empty()) {
TreeItem *cur_item = stack[stack.size() - 1];
stack.resize(stack.size() - 1);
// Add to the cache.
tree_cache->item_cache.insert(cur_item->get_metadata(0).operator String(), cur_item);
// Add any children to the stack.
for (TreeItem *child = cur_item->get_first_child(); child; child = child->get_next()) {
stack.push_back(child);
}
// Remove from parent.
cur_item->get_parent()->remove_child(cur_item);
}
} else {
root_item = results_tree->create_item();
}
}
bool EditorHelpSearch::Runner::_phase_class_items_init() { bool EditorHelpSearch::Runner::_phase_class_items_init() {
iterator_match = matches.begin(); iterator_match = matches.begin();
results_tree->clear(); _populate_cache();
root_item = results_tree->create_item();
class_items.clear(); class_items.clear();
return true; return true;
@ -618,27 +657,54 @@ TreeItem *EditorHelpSearch::Runner::_create_class_hierarchy(const ClassMatch &p_
return class_item; return class_item;
} }
bool EditorHelpSearch::Runner::_find_or_create_item(TreeItem *p_parent, const String &p_item_meta, TreeItem *&r_item) {
// Attempt to find in cache.
if (tree_cache->item_cache.has(p_item_meta)) {
r_item = tree_cache->item_cache[p_item_meta];
// Remove from cache.
tree_cache->item_cache.erase(p_item_meta);
// Add to tree.
p_parent->add_child(r_item);
return false;
} else {
// Otherwise create item.
r_item = results_tree->create_item(p_parent);
return true;
}
}
TreeItem *EditorHelpSearch::Runner::_create_class_item(TreeItem *p_parent, const DocData::ClassDoc *p_doc, bool p_gray) { TreeItem *EditorHelpSearch::Runner::_create_class_item(TreeItem *p_parent, const DocData::ClassDoc *p_doc, bool p_gray) {
String tooltip = DTR(p_doc->brief_description.strip_edges()); String tooltip = DTR(p_doc->brief_description.strip_edges());
TreeItem *item = results_tree->create_item(p_parent); const String item_meta = "class_name:" + p_doc->name;
item->set_icon(0, EditorNode::get_singleton()->get_class_icon(p_doc->name));
item->set_text(0, p_doc->name); TreeItem *item = nullptr;
item->set_text(1, TTR("Class")); if (_find_or_create_item(p_parent, item_meta, item)) {
item->set_tooltip_text(0, tooltip); item->set_icon(0, EditorNode::get_singleton()->get_class_icon(p_doc->name));
item->set_tooltip_text(1, tooltip); item->set_text(0, p_doc->name);
item->set_metadata(0, "class_name:" + p_doc->name); item->set_text(1, TTR("Class"));
item->set_tooltip_text(0, tooltip);
item->set_tooltip_text(1, tooltip);
item->set_metadata(0, item_meta);
if (p_doc->is_deprecated) {
Ref<Texture2D> error_icon = ui_service->get_editor_theme_icon(SNAME("StatusError"));
item->add_button(0, error_icon, 0, false, TTR("This class is marked as deprecated."));
} else if (p_doc->is_experimental) {
Ref<Texture2D> warning_icon = ui_service->get_editor_theme_icon(SNAME("NodeWarning"));
item->add_button(0, warning_icon, 0, false, TTR("This class is marked as experimental."));
}
}
if (p_gray) { if (p_gray) {
item->set_custom_color(0, disabled_color); item->set_custom_color(0, disabled_color);
item->set_custom_color(1, disabled_color); item->set_custom_color(1, disabled_color);
} } else {
item->clear_custom_color(0);
if (p_doc->is_deprecated) { item->clear_custom_color(1);
Ref<Texture2D> error_icon = ui_service->get_editor_theme_icon("StatusError");
item->add_button(0, error_icon, 0, false, TTR("This class is marked as deprecated."));
} else if (p_doc->is_experimental) {
Ref<Texture2D> warning_icon = ui_service->get_editor_theme_icon("NodeWarning");
item->add_button(0, warning_icon, 0, false, TTR("This class is marked as experimental."));
} }
_match_item(item, p_doc->name); _match_item(item, p_doc->name);
@ -679,30 +745,29 @@ TreeItem *EditorHelpSearch::Runner::_create_theme_property_item(TreeItem *p_pare
} }
TreeItem *EditorHelpSearch::Runner::_create_member_item(TreeItem *p_parent, const String &p_class_name, const String &p_icon, const String &p_name, const String &p_text, const String &p_type, const String &p_metatype, const String &p_tooltip, bool is_deprecated, bool is_experimental) { TreeItem *EditorHelpSearch::Runner::_create_member_item(TreeItem *p_parent, const String &p_class_name, const String &p_icon, const String &p_name, const String &p_text, const String &p_type, const String &p_metatype, const String &p_tooltip, bool is_deprecated, bool is_experimental) {
Ref<Texture2D> icon; const String item_meta = "class_" + p_metatype + ":" + p_class_name + ":" + p_name;
String text;
if (search_flags & SEARCH_SHOW_HIERARCHY) { TreeItem *item = nullptr;
icon = ui_service->get_editor_theme_icon(p_icon); if (_find_or_create_item(p_parent, item_meta, item)) {
text = p_text; item->set_icon(0, ui_service->get_editor_theme_icon(p_icon));
} else { item->set_text(1, TTRGET(p_type));
icon = ui_service->get_editor_theme_icon(p_icon); item->set_tooltip_text(0, p_tooltip);
text = p_class_name + "." + p_text; item->set_tooltip_text(1, p_tooltip);
item->set_metadata(0, item_meta);
if (is_deprecated) {
Ref<Texture2D> error_icon = ui_service->get_editor_theme_icon(SNAME("StatusError"));
item->add_button(0, error_icon, 0, false, TTR("This member is marked as deprecated."));
} else if (is_experimental) {
Ref<Texture2D> warning_icon = ui_service->get_editor_theme_icon(SNAME("NodeWarning"));
item->add_button(0, warning_icon, 0, false, TTR("This member is marked as experimental."));
}
} }
TreeItem *item = results_tree->create_item(p_parent); if (search_flags & SEARCH_SHOW_HIERARCHY) {
item->set_icon(0, icon); item->set_text(0, p_text);
item->set_text(0, text); } else {
item->set_text(1, TTRGET(p_type)); item->set_text(0, p_class_name + "." + p_text);
item->set_tooltip_text(0, p_tooltip);
item->set_tooltip_text(1, p_tooltip);
item->set_metadata(0, "class_" + p_metatype + ":" + p_class_name + ":" + p_name);
if (is_deprecated) {
Ref<Texture2D> error_icon = ui_service->get_editor_theme_icon("StatusError");
item->add_button(0, error_icon, 0, false, TTR("This member is marked as deprecated."));
} else if (is_experimental) {
Ref<Texture2D> warning_icon = ui_service->get_editor_theme_icon("NodeWarning");
item->add_button(0, warning_icon, 0, false, TTR("This member is marked as experimental."));
} }
_match_item(item, p_name); _match_item(item, p_name);
@ -721,9 +786,10 @@ bool EditorHelpSearch::Runner::work(uint64_t slot) {
return true; return true;
} }
EditorHelpSearch::Runner::Runner(Control *p_icon_service, Tree *p_results_tree, const String &p_term, int p_search_flags) : EditorHelpSearch::Runner::Runner(Control *p_icon_service, Tree *p_results_tree, TreeCache *p_tree_cache, const String &p_term, int p_search_flags) :
ui_service(p_icon_service), ui_service(p_icon_service),
results_tree(p_results_tree), results_tree(p_results_tree),
tree_cache(p_tree_cache),
term((p_search_flags & SEARCH_CASE_SENSITIVE) == 0 ? p_term.strip_edges().to_lower() : p_term.strip_edges()), term((p_search_flags & SEARCH_CASE_SENSITIVE) == 0 ? p_term.strip_edges().to_lower() : p_term.strip_edges()),
search_flags(p_search_flags), search_flags(p_search_flags),
disabled_color(ui_service->get_theme_color(SNAME("font_disabled_color"), EditorStringName(Editor))) { disabled_color(ui_service->get_theme_color(SNAME("font_disabled_color"), EditorStringName(Editor))) {

View File

@ -67,6 +67,16 @@ class EditorHelpSearch : public ConfirmationDialog {
class Runner; class Runner;
Ref<Runner> search; Ref<Runner> search;
struct TreeCache {
HashMap<String, TreeItem *> item_cache;
void clear();
~TreeCache() {
clear();
}
} tree_cache;
void _update_results(); void _update_results();
void _search_box_gui_input(const Ref<InputEvent> &p_event); void _search_box_gui_input(const Ref<InputEvent> &p_event);
@ -117,6 +127,7 @@ class EditorHelpSearch::Runner : public RefCounted {
Control *ui_service = nullptr; Control *ui_service = nullptr;
Tree *results_tree = nullptr; Tree *results_tree = nullptr;
TreeCache *tree_cache = nullptr;
String term; String term;
Vector<String> terms; Vector<String> terms;
int search_flags; int search_flags;
@ -134,6 +145,9 @@ class EditorHelpSearch::Runner : public RefCounted {
bool _is_class_disabled_by_feature_profile(const StringName &p_class); bool _is_class_disabled_by_feature_profile(const StringName &p_class);
void _populate_cache();
bool _find_or_create_item(TreeItem *p_parent, const String &p_item_meta, TreeItem *&r_item);
bool _slice(); bool _slice();
bool _phase_match_classes_init(); bool _phase_match_classes_init();
bool _phase_match_classes(); bool _phase_match_classes();
@ -162,7 +176,7 @@ class EditorHelpSearch::Runner : public RefCounted {
public: public:
bool work(uint64_t slot = 100000); bool work(uint64_t slot = 100000);
Runner(Control *p_icon_service, Tree *p_results_tree, const String &p_term, int p_search_flags); Runner(Control *p_icon_service, Tree *p_results_tree, TreeCache *p_tree_cache, const String &p_term, int p_search_flags);
}; };
#endif // EDITOR_HELP_SEARCH_H #endif // EDITOR_HELP_SEARCH_H