Skip to content

Commit 38b316c

Browse files
committed
Implement attribute saving for feature template form:
- plan features are saved - plan regulation groups are saved - plan regulations are saved Notes: - saving additional information for regulations is not implemented yet - saving value ranges for regulations is not implemented yet - saving files for regulations is not implemented yet - reading saved features into forms and updating them is not implemented yet - saving regulation groups in new plan regulation group form is not implemented yet - using existing regulation groups for plan features is not implemented yet - plan feature target layer selection is hard coded for now - underground type is hard coded for now - plan organisation needs to be set to Toimija code layer to make a new plan - PlanRegulationSet could be refactored into PlanTypeLayer class - save_data methods could be refactored to reduce code repetition
1 parent 44ee1ba commit 38b316c

10 files changed

+209
-145
lines changed

arho_feature_template/core/feature_template_library.py

+2-10
Original file line numberDiff line numberDiff line change
@@ -157,16 +157,8 @@ def ask_for_feature_attributes(self, feature: QgsFeature) -> None:
157157
if not self.active_template:
158158
return
159159

160-
attribute_form = TemplateAttributeForm(self.active_template.config)
161-
162-
if attribute_form.exec_():
163-
layer = get_vector_layer_from_project(self.active_template.config.feature.layer)
164-
# Save the feature
165-
attribute_form.set_feature_attributes(feature)
166-
167-
layer.beginEditCommand("Create feature from template")
168-
layer.addFeature(feature)
169-
layer.commitChanges(stopEditing=False)
160+
attribute_form = TemplateAttributeForm(self.active_template.config, feature)
161+
attribute_form.exec_()
170162

171163
def get_library_names(self) -> list[str]:
172164
return list(self.library_configs.keys())

arho_feature_template/core/models.py

+75-6
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import yaml
1111

1212
from arho_feature_template.exceptions import ConfigSyntaxError
13+
from arho_feature_template.project.layers.plan_layers import PlanFeatureLayer, PlanRegulationLayer, RegulationGroupLayer
1314
from arho_feature_template.qgis_plugin_tools.tools.resources import resources_path
1415
from arho_feature_template.utils.misc_utils import get_layer_by_name, iface
1516

@@ -219,20 +220,38 @@ class Regulation:
219220
files: list[str] = field(default_factory=list)
220221
theme: str | None = None
221222
topic_tag: str | None = None
223+
regulation_group_id_: int | None = None
222224
id_: int | None = None
223225
# value_string: str | None
224226
# value_number: Number | None
225227
# value_number_pair: tuple[Number, Number] | None
226228

229+
def save_data(self):
230+
feature = PlanRegulationLayer.feature_from_model(self)
231+
layer = PlanRegulationLayer.get_from_project()
232+
233+
if not layer.isEditable():
234+
layer.startEditing()
235+
layer.beginEditCommand("Kaavamääräyksen lisäys" if self.id_ is None else "Kaavamääräyksen muokkaus")
236+
237+
if self.id_ is None:
238+
layer.addFeature(feature)
239+
else:
240+
layer.updateFeature(feature)
241+
242+
layer.endEditCommand()
243+
layer.commitChanges(stopEditing=False)
244+
245+
# TODO: associations?
246+
227247

228248
@dataclass
229249
class RegulationGroup:
230-
type_code: str | None
250+
type_code: str
231251
name: str | None
232252
short_name: str | None
233253
color_code: str | None
234-
letter_code: str | None
235-
regulations: list[Regulation]
254+
regulations: list[Regulation] = field(default_factory=list)
236255
id_: int | None = None
237256

238257
@classmethod
@@ -254,26 +273,76 @@ def from_config_data(cls, data: dict) -> RegulationGroup:
254273
files=reg_data.get("files") if reg_data.get("files") else [],
255274
theme=reg_data.get("theme"),
256275
topic_tag=reg_data.get("topic_tag"),
276+
regulation_group_id_=None,
257277
id_=None,
258278
)
259279
)
260280
else:
261281
iface.messageBar().pushWarning("", f"Could not find plan regulation {reg_code}!")
262282
return cls(
263-
type_code=None,
283+
type_code="landUseRegulations",
264284
name=data.get("name"),
265-
short_name=data.get("color_code"),
285+
short_name=data.get("short_name"),
266286
color_code=data.get("color_code"),
267-
letter_code=data.get("letter_code"),
268287
regulations=regulations,
269288
id_=None,
270289
)
271290

291+
def save_data(self):
292+
feature = RegulationGroupLayer.feature_from_model(self)
293+
layer = RegulationGroupLayer.get_from_project()
294+
295+
if not layer.isEditable():
296+
layer.startEditing()
297+
layer.beginEditCommand("Kaavamääräysryhmän lisäys" if self.id_ is None else "Kaavamääräysryhmän muokkaus")
298+
299+
if self.id_ is None:
300+
layer.addFeature(feature)
301+
else:
302+
layer.updateFeature(feature)
303+
304+
layer.endEditCommand()
305+
layer.commitChanges(stopEditing=False)
306+
307+
if self.regulations:
308+
for regulation in self.regulations:
309+
regulation.regulation_group_id_ = feature["id"] # Updating regulation group ID
310+
regulation.save_data()
311+
312+
# TODO: associations?
313+
272314
# @classmethod
273315
# def from_database(cls) -> RegulationGroup:
274316
# pass
275317

276318

319+
@dataclass
320+
class PlanFeature:
321+
geom: QgsGeometry
322+
feature_layer_class: type[PlanFeatureLayer]
323+
type_of_underground: int
324+
name: str | None = None
325+
description: str | None = None
326+
plan_id: int | None = None
327+
id_: int | None = None
328+
329+
def save_data(self):
330+
feature = self.feature_layer_class.feature_from_model(self)
331+
layer = self.feature_layer_class.get_from_project()
332+
333+
if not layer.isEditable():
334+
layer.startEditing()
335+
layer.beginEditCommand("Kaavakohteen lisäys" if self.id_ is None else "Kaavakohteen muokkaus")
336+
337+
if self.id_ is None:
338+
layer.addFeature(feature)
339+
else:
340+
layer.updateFeature(feature)
341+
342+
layer.endEditCommand()
343+
layer.commitChanges(stopEditing=False)
344+
345+
277346
@dataclass
278347
class Plan:
279348
name: str

arho_feature_template/core/plan_manager.py

+1
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,7 @@ def save_plan(plan_data: Plan) -> QgsFeature:
188188
edit_message = "Kaavan lisäys" if plan_data.id_ is None else "Kaavan muokkaus"
189189
plan_layer.beginEditCommand(edit_message)
190190

191+
# plan_data.organisation_id = "99e20d66-9730-4110-815f-5947d3f8abd3"
191192
plan_feature = PlanLayer.feature_from_model(plan_data)
192193

193194
if plan_data.id_ is None:

arho_feature_template/gui/plan_regulation_group_widget.py

+4-22
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010

1111
from arho_feature_template.core.models import Regulation, RegulationGroup
1212
from arho_feature_template.gui.plan_regulation_widget import RegulationWidget
13-
from arho_feature_template.project.layers.plan_layers import RegulationGroupLayer
1413

1514
if TYPE_CHECKING:
1615
from qgis.PyQt.QtWidgets import QFrame, QLineEdit, QPushButton
@@ -30,7 +29,7 @@ def __init__(self, regulation_group_data: RegulationGroup):
3029

3130
# TYPES
3231
self.frame: QFrame
33-
self.name: QLineEdit # "heading"
32+
self.name: QLineEdit
3433
self.del_btn: QPushButton
3534

3635
# INIT
@@ -53,29 +52,12 @@ def delete_regulation_widget(self, regulation_widget: RegulationWidget):
5352
self.regulation_widgets.remove(regulation_widget)
5453
regulation_widget.deleteLater()
5554

56-
def into_model(self, id_: int | None) -> RegulationGroup:
55+
def into_model(self) -> RegulationGroup:
5756
return RegulationGroup(
5857
type_code=self.regulation_group_data.type_code,
5958
name=self.name.text(),
6059
short_name=self.regulation_group_data.short_name,
6160
color_code=self.regulation_group_data.color_code,
62-
letter_code=self.regulation_group_data.letter_code,
63-
regulations=[widget.save_data(id_) for widget in self.regulation_widgets],
64-
id_=id_,
61+
regulations=[widget.into_model() for widget in self.regulation_widgets],
62+
id_=self.regulation_group_data.id_,
6563
)
66-
67-
def save_data(self):
68-
if not self.regulation_group_data.id_:
69-
new_feature = True
70-
id_ = "new_id_here" # TODO: Implement creating new ID
71-
else:
72-
new_feature = False
73-
id_ = self.regulation_group_data.id_
74-
75-
model = self.into_model(id_)
76-
regulation_feature = RegulationGroupLayer.feature_from_model(model)
77-
layer = RegulationGroupLayer.get_from_project()
78-
if new_feature:
79-
layer.addFeature(regulation_feature)
80-
else:
81-
layer.updateFeature(regulation_feature)

arho_feature_template/gui/plan_regulation_widget.py

-14
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
MultilineTextInputWidget,
2525
SinglelineTextInputWidget,
2626
)
27-
from arho_feature_template.project.layers.plan_layers import PlanRegulationLayer
2827
from arho_feature_template.utils.misc_utils import get_additional_information_name, get_layer_by_name, iface
2928

3029
if TYPE_CHECKING:
@@ -34,7 +33,6 @@
3433
FormClass, _ = uic.loadUiType(ui_path)
3534

3635
# TO BE REPLACED
37-
ADDITIONAL_INFORMATION_TYPES_WITH_INPUT = ["kayttotarkoituskohdistus"]
3836
LANGUAGE = "fin"
3937

4038

@@ -87,7 +85,6 @@ def _init_widgets(self):
8785
value_type = self.config.value_type
8886
if value_type:
8987
self._add_value_input(value_type, self.config.unit, self.regulation.value)
90-
# if self.regulation else None)
9188

9289
# Additional information
9390
if self.regulation.additional_information:
@@ -267,14 +264,3 @@ def into_model(self) -> Regulation:
267264
topic_tag=self.topic_tag_widget.get_value() if self.topic_tag_widget else None,
268265
id_=self.regulation.id_,
269266
)
270-
271-
def save_data(self, regulation_group_id: int | None) -> Regulation:
272-
model = self.into_model()
273-
regulation_feature = PlanRegulationLayer.feat_from_model(model, regulation_group_id)
274-
layer = PlanRegulationLayer.get_from_project()
275-
if model.id_ is None:
276-
layer.addFeature(regulation_feature)
277-
else:
278-
layer.updateFeature(regulation_feature)
279-
280-
return model

arho_feature_template/gui/template_attribute_form.py

+40-10
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,18 @@
1515
QScrollArea,
1616
QSizePolicy,
1717
QSpacerItem,
18+
QTextEdit,
1819
QTreeWidget,
1920
QTreeWidgetItem,
2021
)
2122

22-
from arho_feature_template.core.models import RegulationGroup, RegulationGroupLibrary
23+
from arho_feature_template.core.models import PlanFeature, RegulationGroup, RegulationGroupLibrary
2324
from arho_feature_template.gui.plan_regulation_group_widget import RegulationGroupWidget
25+
from arho_feature_template.project.layers.plan_layers import LandUseAreaLayer, PlanFeatureLayer
2426
from arho_feature_template.qgis_plugin_tools.tools.resources import resources_path
2527

2628
if TYPE_CHECKING:
29+
from qgis.core import QgsFeature
2730
from qgis.PyQt.QtWidgets import QWidget
2831

2932
from arho_feature_template.core.template_library_config import FeatureTemplate
@@ -35,21 +38,29 @@
3538
class TemplateAttributeForm(QDialog, FormClass): # type: ignore
3639
"""Parent class for feature template forms for adding and modifying feature attribute data."""
3740

38-
def __init__(self, feature_template_config: FeatureTemplate):
41+
def __init__(
42+
self,
43+
feature_template_config: FeatureTemplate,
44+
base_feature: QgsFeature,
45+
feature_layer_class: type[PlanFeatureLayer] = LandUseAreaLayer, # NOTE: All are now saved to LandUseAreaLayer
46+
):
3947
super().__init__()
4048
self.setupUi(self)
4149

4250
# TYPES
51+
self.geom = base_feature.geometry()
52+
self.feature_layer_class = feature_layer_class
4353
self.feature_name: QLineEdit
44-
self.feature_description: QLineEdit
45-
self.feature_underground: QLineEdit
54+
self.feature_description: QTextEdit
55+
self.feature_type_of_underground: QComboBox
4656
self.plan_regulation_group_scrollarea: QScrollArea
4757
self.plan_regulation_group_scrollarea_contents: QWidget
4858
self.plan_regulation_group_libraries_combobox: QComboBox
4959
self.plan_regulation_groups_tree: QTreeWidget
5060
self.button_box: QDialogButtonBox
5161

5262
# INIT
63+
self.regulation_group_widgets: list[RegulationGroupWidget] = []
5364
self.scroll_area_spacer = None
5465
self.setWindowTitle(feature_template_config.name)
5566
self.init_plan_regulation_group_libraries()
@@ -73,15 +84,17 @@ def add_selected_plan_regulation_group(self, item: QTreeWidgetItem, column: int)
7384
self.add_plan_regulation_group(regulation_group)
7485

7586
def add_plan_regulation_group(self, definition: RegulationGroup):
76-
new_plan_regulation_group = RegulationGroupWidget(definition)
77-
new_plan_regulation_group.delete_signal.connect(self.remove_plan_regulation_group)
87+
regulation_group_widget = RegulationGroupWidget(definition)
88+
regulation_group_widget.delete_signal.connect(self.remove_plan_regulation_group)
7889
self._remove_spacer()
79-
self.plan_regulation_group_scrollarea_contents.layout().addWidget(new_plan_regulation_group)
90+
self.plan_regulation_group_scrollarea_contents.layout().addWidget(regulation_group_widget)
91+
self.regulation_group_widgets.append(regulation_group_widget)
8092
self._add_spacer()
8193

82-
def remove_plan_regulation_group(self, plan_regulation_group_widget: RegulationGroupWidget):
83-
self.plan_regulation_group_scrollarea_contents.layout().removeWidget(plan_regulation_group_widget)
84-
plan_regulation_group_widget.deleteLater()
94+
def remove_plan_regulation_group(self, regulation_group_widget: RegulationGroupWidget):
95+
self.plan_regulation_group_scrollarea_contents.layout().removeWidget(regulation_group_widget)
96+
self.regulation_group_widgets.remove(regulation_group_widget)
97+
regulation_group_widget.deleteLater()
8598

8699
def init_plan_regulation_group_libraries(self):
87100
katja_asemakaava_path = Path(os.path.join(resources_path(), "katja_asemakaava.yaml"))
@@ -100,5 +113,22 @@ def init_plan_regulation_group_library(self, library: RegulationGroupLibrary):
100113
regulation_group_item.setText(0, group_definition.name)
101114
regulation_group_item.setData(0, Qt.UserRole, group_definition)
102115

116+
def into_model(self) -> PlanFeature:
117+
return PlanFeature(
118+
name=self.feature_name.text(),
119+
type_of_underground=self.feature_type_of_underground.currentIndex(),
120+
description=self.feature_description.toPlainText(),
121+
geom=self.geom,
122+
feature_layer_class=self.feature_layer_class,
123+
id_=None,
124+
)
125+
103126
def _on_ok_clicked(self):
127+
# Plan feature data
128+
self.into_model().save_data()
129+
130+
# Regulation group data
131+
for regulation_group_widget in self.regulation_group_widgets:
132+
regulation_group_widget.into_model().save_data()
133+
104134
self.accept()

arho_feature_template/gui/template_attribute_form.ui

+11-11
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,16 @@
4040
</property>
4141
</widget>
4242
</item>
43+
<item row="1" column="1">
44+
<widget class="QTextEdit" name="feature_description">
45+
<property name="sizePolicy">
46+
<sizepolicy hsizetype="Expanding" vsizetype="Maximum">
47+
<horstretch>0</horstretch>
48+
<verstretch>0</verstretch>
49+
</sizepolicy>
50+
</property>
51+
</widget>
52+
</item>
4353
<item row="2" column="0">
4454
<widget class="QLabel" name="feature_underground_label">
4555
<property name="text">
@@ -48,7 +58,7 @@
4858
</widget>
4959
</item>
5060
<item row="2" column="1">
51-
<widget class="QComboBox" name="feature_underground">
61+
<widget class="QComboBox" name="feature_type_of_underground">
5262
<item>
5363
<property name="text">
5464
<string>Maanpäällinen</string>
@@ -61,16 +71,6 @@
6171
</item>
6272
</widget>
6373
</item>
64-
<item row="1" column="1">
65-
<widget class="QTextEdit" name="feature_description">
66-
<property name="sizePolicy">
67-
<sizepolicy hsizetype="Expanding" vsizetype="Maximum">
68-
<horstretch>0</horstretch>
69-
<verstretch>0</verstretch>
70-
</sizepolicy>
71-
</property>
72-
</widget>
73-
</item>
7474
</layout>
7575
</widget>
7676
</item>

0 commit comments

Comments
 (0)