-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtree_with_search_widget.py
88 lines (70 loc) · 3.24 KB
/
tree_with_search_widget.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
from __future__ import annotations
from typing import Any
from qgis.gui import QgsFilterLineEdit
from qgis.PyQt.QtCore import Qt
from qgis.PyQt.QtWidgets import QSizePolicy, QTreeWidget, QTreeWidgetItem, QVBoxLayout, QWidget
class TreeWithSearchWidget(QWidget):
"""A widget combining a QTreeWidget and QgsFilterLineEdit."""
def __init__(self):
super().__init__()
self.search = QgsFilterLineEdit(self)
self.search.setShowClearButton(True)
self.search.setShowSearchIcon(True)
self.search.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Fixed)
self.search.valueChanged.connect(self.filter_tree_items)
self.tree = QTreeWidget(self)
self.tree.setHeaderHidden(True)
self.tree.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Expanding)
layout = QVBoxLayout()
layout.addWidget(self.search)
layout.addWidget(self.tree)
self.setLayout(layout)
self.setContentsMargins(0, 0, 0, 0)
layout.setContentsMargins(0, 0, 0, 0)
def add_item_to_tree(
self, text: str | None, model: Any | None = None, parent: QTreeWidgetItem | None = None
) -> QTreeWidgetItem:
item = QTreeWidgetItem(parent)
if text:
item.setText(0, text)
item.setToolTip(0, text) # Set text as tooltip in case the tree width is not enough to show item text
if model:
item.setData(0, Qt.UserRole, model)
if not parent:
self.tree.addTopLevelItem(item)
return item
def filter_tree_items(self):
search_text = self.search.value().lower()
# Iterate over all group (top-level) items in the tree
for i in range(self.tree.topLevelItemCount()):
group_item = self.tree.topLevelItem(i)
group_item.setHidden(True) # Initially hide the top-level item
matches_group = search_text in group_item.text(0).lower()
if matches_group:
# If group matches, show it and all its children
self.show_all_children(group_item)
group_item.setHidden(False)
else:
# Otherwise, recursively filter its children
matches_child = self.filter_children(group_item, search_text)
group_item.setHidden(not matches_child)
def filter_children(self, parent_item: QTreeWidgetItem, search_text: str) -> bool:
"""Recursively filter children and return True if any child matches."""
has_match = False
for i in range(parent_item.childCount()):
child = parent_item.child(i)
matches = search_text in child.text(0).lower()
child.setHidden(not matches)
if child.childCount() > 0:
matches |= self.filter_children(child, search_text)
if matches:
has_match = True
return has_match
def show_all_children(self, parent_item: QTreeWidgetItem):
"""Show the parent item and all its children recursively."""
parent_item.setHidden(False)
for i in range(parent_item.childCount()):
child = parent_item.child(i)
child.setHidden(False)
if child.childCount() > 0:
self.show_all_children(child)