Skip to content

Commit c7b0c5e

Browse files
committed
add TreeWithSearchWidget, use it in new plan regulation form, plan feature form and plan attribute form
1 parent 0578565 commit c7b0c5e

8 files changed

+114
-204
lines changed

arho_feature_template/core/plan_manager.py

+1-3
Original file line numberDiff line numberDiff line change
@@ -166,9 +166,7 @@ def _plan_geom_digitized(self, feature: QgsFeature):
166166
if not plan_layer:
167167
return
168168

169-
attribute_form = PlanAttributeForm(
170-
[*self.regulation_group_libraries, regulation_group_library_from_active_plan()]
171-
)
169+
attribute_form = PlanAttributeForm(self.regulation_group_libraries)
172170
if attribute_form.exec_():
173171
plan_attributes = attribute_form.get_plan_attributes()
174172
plan_attributes.geom = feature.geometry()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
from __future__ import annotations
2+
3+
from qgis.gui import QgsFilterLineEdit
4+
from qgis.PyQt.QtWidgets import QSizePolicy, QTreeWidget, QTreeWidgetItem, QVBoxLayout, QWidget
5+
6+
7+
class TreeWithSearchWidget(QWidget):
8+
"""A widget combining a QTreeWidget and QgsFilterLineEdit."""
9+
10+
def __init__(self):
11+
super().__init__()
12+
self.search = QgsFilterLineEdit(self)
13+
self.search.setShowClearButton(True)
14+
self.search.setShowSearchIcon(True)
15+
self.search.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Fixed)
16+
self.search.valueChanged.connect(self.filter_tree_items)
17+
18+
self.tree = QTreeWidget(self)
19+
self.tree.setHeaderHidden(True)
20+
self.tree.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Expanding)
21+
22+
layout = QVBoxLayout()
23+
layout.addWidget(self.search)
24+
layout.addWidget(self.tree)
25+
self.setLayout(layout)
26+
27+
self.setContentsMargins(0, 0, 0, 0)
28+
layout.setContentsMargins(0, 0, 0, 0)
29+
30+
def filter_tree_items(self):
31+
search_text = self.search.value().lower()
32+
33+
# Iterate over all group (top-level) items in the tree
34+
for i in range(self.tree.topLevelItemCount()):
35+
group_item = self.tree.topLevelItem(i)
36+
group_item.setHidden(True) # Initially hide the top-level item
37+
38+
matches_group = search_text in group_item.text(0).lower()
39+
if matches_group:
40+
# If group matches, show it and all its children
41+
self.show_all_children(group_item)
42+
group_item.setHidden(False)
43+
else:
44+
# Otherwise, recursively filter its children
45+
matches_child = self.filter_children(group_item, search_text)
46+
group_item.setHidden(not matches_child)
47+
48+
def filter_children(self, parent_item: QTreeWidgetItem, search_text: str) -> bool:
49+
"""Recursively filter children and return True if any child matches."""
50+
has_match = False
51+
for i in range(parent_item.childCount()):
52+
child = parent_item.child(i)
53+
matches = search_text in child.text(0).lower()
54+
child.setHidden(not matches)
55+
56+
if child.childCount() > 0:
57+
matches |= self.filter_children(child, search_text)
58+
59+
if matches:
60+
has_match = True
61+
62+
return has_match
63+
64+
def show_all_children(self, parent_item: QTreeWidgetItem):
65+
"""Show the parent item and all its children recursively."""
66+
parent_item.setHidden(False)
67+
for i in range(parent_item.childCount()):
68+
child = parent_item.child(i)
69+
child.setHidden(False)
70+
if child.childCount() > 0:
71+
self.show_all_children(child)

arho_feature_template/gui/dialogs/new_plan_regulation_group_form.py

+9-5
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,11 @@
55

66
from qgis.PyQt import uic
77
from qgis.PyQt.QtCore import Qt
8-
from qgis.PyQt.QtWidgets import QDialog, QDialogButtonBox, QTextBrowser, QTreeWidget, QTreeWidgetItem
8+
from qgis.PyQt.QtWidgets import QDialog, QDialogButtonBox, QTextBrowser, QTreeWidgetItem, QVBoxLayout
99

1010
from arho_feature_template.core.models import Regulation, RegulationConfig, RegulationGroup, RegulationLibrary
1111
from arho_feature_template.gui.components.plan_regulation_widget import RegulationWidget
12+
from arho_feature_template.gui.components.tree_with_search_widget import TreeWithSearchWidget
1213
from arho_feature_template.project.layers.code_layers import PlanRegulationGroupTypeLayer
1314

1415
if TYPE_CHECKING:
@@ -35,19 +36,22 @@ def __init__(self):
3536
self.color_code: QLineEdit
3637
self.type_of_regulation_group: CodeComboBox
3738

38-
self.regulations_view: QTreeWidget
39+
self.regulations_tree_layout: QVBoxLayout
3940
self.regulations_scroll_area_contents: QWidget
4041
self.regulations_layout: QBoxLayout
4142
self.regulation_info: QTextBrowser
4243

4344
self.button_box: QDialogButtonBox
4445

4546
# INIT
47+
self.regulations_selection_widget = TreeWithSearchWidget()
48+
self.regulations_tree_layout.insertWidget(1, self.regulations_selection_widget)
49+
self.regulations_selection_widget.tree.itemDoubleClicked.connect(self.add_selected_regulation)
50+
self.regulations_selection_widget.tree.itemClicked.connect(self.update_selected_regulation)
4651
self.initialize_regulations()
52+
4753
self.type_of_regulation_group.populate_from_code_layer(PlanRegulationGroupTypeLayer)
4854
self.type_of_regulation_group.removeItem(0) # Remove NULL from combobox as underground data is required
49-
self.regulations_view.itemDoubleClicked.connect(self.add_selected_regulation)
50-
self.regulations_view.itemClicked.connect(self.update_selected_regulation)
5155
self.button_box.accepted.connect(self._on_ok_clicked)
5256
self.regulation_widgets: list[RegulationWidget] = []
5357
self.save_as_config = False
@@ -58,7 +62,7 @@ def _initalize_regulation_from_config(self, config: RegulationConfig, parent: QT
5862
tree_item.setData(0, Qt.UserRole, config)
5963

6064
if parent is None:
61-
self.regulations_view.addTopLevelItem(tree_item)
65+
self.regulations_selection_widget.tree.addTopLevelItem(tree_item)
6266

6367
# Initialize plan regulations recursively
6468
if config.child_regulations:

arho_feature_template/gui/dialogs/new_plan_regulation_group_form.ui

+1-46
Original file line numberDiff line numberDiff line change
@@ -111,54 +111,14 @@
111111
</attribute>
112112
<layout class="QHBoxLayout" name="horizontalLayout">
113113
<item>
114-
<layout class="QVBoxLayout" name="verticalLayout">
114+
<layout class="QVBoxLayout" name="regulations_tree_layout">
115115
<item>
116116
<widget class="QLabel" name="label_6">
117117
<property name="text">
118118
<string>Kaavamääräykset</string>
119119
</property>
120120
</widget>
121121
</item>
122-
<item>
123-
<widget class="QgsFilterLineEdit" name="mLineEdit">
124-
<property name="enabled">
125-
<bool>false</bool>
126-
</property>
127-
<property name="sizePolicy">
128-
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
129-
<horstretch>0</horstretch>
130-
<verstretch>0</verstretch>
131-
</sizepolicy>
132-
</property>
133-
<property name="placeholderText">
134-
<string>Suodata kaavamääräyksiä</string>
135-
</property>
136-
<property name="showSearchIcon">
137-
<bool>true</bool>
138-
</property>
139-
<property name="qgisRelation" stdset="0">
140-
<string notr="true"/>
141-
</property>
142-
</widget>
143-
</item>
144-
<item>
145-
<widget class="QTreeWidget" name="regulations_view">
146-
<property name="sizePolicy">
147-
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
148-
<horstretch>0</horstretch>
149-
<verstretch>0</verstretch>
150-
</sizepolicy>
151-
</property>
152-
<attribute name="headerVisible">
153-
<bool>false</bool>
154-
</attribute>
155-
<column>
156-
<property name="text">
157-
<string notr="true">1</string>
158-
</property>
159-
</column>
160-
</widget>
161-
</item>
162122
<item>
163123
<widget class="QLabel" name="label_4">
164124
<property name="text">
@@ -256,11 +216,6 @@ p, li { white-space: pre-wrap; }
256216
</layout>
257217
</widget>
258218
<customwidgets>
259-
<customwidget>
260-
<class>QgsFilterLineEdit</class>
261-
<extends>QLineEdit</extends>
262-
<header>qgsfilterlineedit.h</header>
263-
</customwidget>
264219
<customwidget>
265220
<class>QgsSpinBox</class>
266221
<extends>QSpinBox</extends>

arho_feature_template/gui/dialogs/plan_attribute_form.py

+7-5
Original file line numberDiff line numberDiff line change
@@ -13,20 +13,20 @@
1313
QSizePolicy,
1414
QSpacerItem,
1515
QTextEdit,
16-
QTreeWidget,
1716
QTreeWidgetItem,
1817
)
1918

2019
from arho_feature_template.core.models import Plan, RegulationGroup, RegulationGroupLibrary
2120
from arho_feature_template.gui.components.plan_regulation_group_widget import RegulationGroupWidget
21+
from arho_feature_template.gui.components.tree_with_search_widget import TreeWithSearchWidget
2222
from arho_feature_template.project.layers.code_layers import (
2323
LifeCycleStatusLayer,
2424
OrganisationLayer,
2525
PlanTypeLayer,
2626
)
2727

2828
if TYPE_CHECKING:
29-
from qgis.PyQt.QtWidgets import QComboBox, QLineEdit, QTextEdit, QTreeWidget, QWidget
29+
from qgis.PyQt.QtWidgets import QComboBox, QLineEdit, QTextEdit, QVBoxLayout, QWidget
3030

3131
from arho_feature_template.gui.components.code_combobox import CodeComboBox, HierarchicalCodeComboBox
3232

@@ -47,7 +47,7 @@ class PlanAttributeForm(QDialog, FormClass): # type: ignore
4747

4848
plan_regulation_group_scrollarea_contents: QWidget
4949
plan_regulation_group_libraries_combobox: QComboBox
50-
plan_regulation_groups_tree: QTreeWidget
50+
regulation_groups_tree_layout: QVBoxLayout
5151

5252
button_box: QDialogButtonBox
5353

@@ -66,9 +66,11 @@ def __init__(self, regulation_group_libraries: list[RegulationGroupLibrary], par
6666
self.lifecycle_status_combo_box.currentIndexChanged.connect(self._check_required_fields)
6767

6868
self.scroll_area_spacer = None
69+
self.regulation_groups_selection_widget = TreeWithSearchWidget()
70+
self.regulation_groups_tree_layout.insertWidget(2, self.regulation_groups_selection_widget)
6971
self.regulation_group_widgets: list[RegulationGroupWidget] = []
7072
[self.init_plan_regulation_group_library(library) for library in regulation_group_libraries]
71-
self.plan_regulation_groups_tree.itemDoubleClicked.connect(self.add_selected_plan_regulation_group)
73+
self.regulation_groups_selection_widget.tree.itemDoubleClicked.connect(self.add_selected_plan_regulation_group)
7274

7375
self.button_box.button(QDialogButtonBox.Ok).setEnabled(False)
7476

@@ -119,7 +121,7 @@ def init_plan_regulation_group_library(self, library: RegulationGroupLibrary):
119121
for category in library.regulation_group_categories:
120122
category_item = QTreeWidgetItem()
121123
category_item.setText(0, category.name)
122-
self.plan_regulation_groups_tree.addTopLevelItem(category_item)
124+
self.regulation_groups_selection_widget.tree.addTopLevelItem(category_item)
123125
for group_definition in category.regulation_groups:
124126
regulation_group_item = QTreeWidgetItem(category_item)
125127
regulation_group_item.setText(0, group_definition.name)

arho_feature_template/gui/dialogs/plan_attribute_form.ui

+2-65
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,7 @@
243243
</property>
244244
<layout class="QHBoxLayout" name="horizontalLayout">
245245
<item>
246-
<layout class="QVBoxLayout" name="verticalLayout_5">
246+
<layout class="QVBoxLayout" name="regulation_groups_tree_layout">
247247
<item>
248248
<widget class="QLabel" name="label_6">
249249
<property name="text">
@@ -254,64 +254,6 @@
254254
<item>
255255
<widget class="QComboBox" name="plan_regulation_group_libraries_combobox"/>
256256
</item>
257-
<item>
258-
<widget class="QgsFilterLineEdit" name="mLineEdit">
259-
<property name="enabled">
260-
<bool>false</bool>
261-
</property>
262-
<property name="sizePolicy">
263-
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
264-
<horstretch>0</horstretch>
265-
<verstretch>0</verstretch>
266-
</sizepolicy>
267-
</property>
268-
<property name="placeholderText">
269-
<string>Suodata kaavamääräysryhmiä</string>
270-
</property>
271-
<property name="clearButtonEnabled">
272-
<bool>false</bool>
273-
</property>
274-
<property name="showSearchIcon">
275-
<bool>true</bool>
276-
</property>
277-
<property name="qgisRelation" stdset="0">
278-
<string notr="true"/>
279-
</property>
280-
</widget>
281-
</item>
282-
<item>
283-
<widget class="QTreeWidget" name="plan_regulation_groups_tree">
284-
<property name="sizePolicy">
285-
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
286-
<horstretch>0</horstretch>
287-
<verstretch>0</verstretch>
288-
</sizepolicy>
289-
</property>
290-
<property name="frameShape">
291-
<enum>QFrame::StyledPanel</enum>
292-
</property>
293-
<property name="frameShadow">
294-
<enum>QFrame::Sunken</enum>
295-
</property>
296-
<property name="editTriggers">
297-
<set>QAbstractItemView::NoEditTriggers</set>
298-
</property>
299-
<property name="dragDropMode">
300-
<enum>QAbstractItemView::NoDragDrop</enum>
301-
</property>
302-
<property name="alternatingRowColors">
303-
<bool>false</bool>
304-
</property>
305-
<attribute name="headerVisible">
306-
<bool>false</bool>
307-
</attribute>
308-
<column>
309-
<property name="text">
310-
<string/>
311-
</property>
312-
</column>
313-
</widget>
314-
</item>
315257
</layout>
316258
</item>
317259
<item>
@@ -333,7 +275,7 @@
333275
<rect>
334276
<x>0</x>
335277
<y>0</y>
336-
<width>541</width>
278+
<width>601</width>
337279
<height>493</height>
338280
</rect>
339281
</property>
@@ -369,11 +311,6 @@
369311
<header>qgscollapsiblegroupbox.h</header>
370312
<container>1</container>
371313
</customwidget>
372-
<customwidget>
373-
<class>QgsFilterLineEdit</class>
374-
<extends>QLineEdit</extends>
375-
<header>qgsfilterlineedit.h</header>
376-
</customwidget>
377314
<customwidget>
378315
<class>CodeComboBox</class>
379316
<extends>QComboBox</extends>

0 commit comments

Comments
 (0)