Skip to content

Commit ca578da

Browse files
committed
improvements and fixes to saving attribute data
- add regulation group type selection and short name - fix versioned text input widget - fix numeric input widget - move data saving funcs to plan manager - add placeholder mapping logic to target plan feature layer selection
1 parent 4bf485c commit ca578da

11 files changed

+267
-112
lines changed

arho_feature_template/core/feature_template_library.py

+4-2
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
from qgis.PyQt.QtGui import QStandardItem, QStandardItemModel
1010
from qgis.utils import iface
1111

12+
from arho_feature_template.core.plan_manager import save_plan_feature
1213
from arho_feature_template.core.template_library_config import (
1314
FeatureTemplate,
1415
TemplateLibraryConfig,
@@ -157,8 +158,9 @@ def ask_for_feature_attributes(self, feature: QgsFeature) -> None:
157158
if not self.active_template:
158159
return
159160

160-
attribute_form = TemplateAttributeForm(self.active_template.config, feature)
161-
attribute_form.exec_()
161+
attribute_form = TemplateAttributeForm(self.active_template.config, feature.geometry())
162+
if attribute_form.exec_():
163+
save_plan_feature(attribute_form.model)
162164

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

arho_feature_template/core/models.py

+5-65
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
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
1413
from arho_feature_template.qgis_plugin_tools.tools.resources import resources_path
1514
from arho_feature_template.utils.misc_utils import get_layer_by_name, iface
1615

@@ -226,28 +225,10 @@ class Regulation:
226225
# value_number: Number | None
227226
# value_number_pair: tuple[Number, Number] | None
228227

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-
247228

248229
@dataclass
249230
class RegulationGroup:
250-
type_code: str
231+
type_code_id: str | None
251232
name: str | None
252233
short_name: str | None
253234
color_code: str | None
@@ -280,68 +261,27 @@ def from_config_data(cls, data: dict) -> RegulationGroup:
280261
else:
281262
iface.messageBar().pushWarning("", f"Could not find plan regulation {reg_code}!")
282263
return cls(
283-
type_code="landUseRegulations",
264+
type_code_id=data.get("type"), # NOTE: Might need to convert type code into type code ID here when
265+
# config file has type codes for regulation groups
284266
name=data.get("name"),
285267
short_name=data.get("short_name"),
286268
color_code=data.get("color_code"),
287269
regulations=regulations,
288270
id_=None,
289271
)
290272

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-
314-
# @classmethod
315-
# def from_database(cls) -> RegulationGroup:
316-
# pass
317-
318273

319274
@dataclass
320275
class PlanFeature:
321276
geom: QgsGeometry
322-
feature_layer_class: type[PlanFeatureLayer]
323277
type_of_underground_id: str
278+
layer_name: str | None = None
324279
name: str | None = None
325280
description: str | None = None
281+
regulation_groups: list[RegulationGroup] = field(default_factory=list)
326282
plan_id: int | None = None
327283
id_: int | None = None
328284

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-
345285

346286
@dataclass
347287
class Plan:

arho_feature_template/core/plan_manager.py

+96-5
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,18 @@
1818
from arho_feature_template.gui.load_plan_dialog import LoadPlanDialog
1919
from arho_feature_template.gui.plan_attribure_form import PlanAttributeForm
2020
from arho_feature_template.gui.serialize_plan import SerializePlan
21-
from arho_feature_template.project.layers.plan_layers import PlanLayer, RegulationGroupLayer, plan_layers
21+
from arho_feature_template.project.layers.plan_layers import (
22+
LandUseAreaLayer,
23+
LandUsePointLayer,
24+
LineLayer,
25+
OtherAreaLayer,
26+
OtherPointLayer,
27+
PlanFeatureLayer,
28+
PlanLayer,
29+
PlanRegulationLayer,
30+
RegulationGroupLayer,
31+
plan_layers,
32+
)
2233
from arho_feature_template.utils.db_utils import get_existing_database_connection_names
2334
from arho_feature_template.utils.misc_utils import (
2435
check_layer_changes,
@@ -29,7 +40,8 @@
2940
if TYPE_CHECKING:
3041
from qgis.core import QgsFeature
3142

32-
from arho_feature_template.core.models import Plan, RegulationGroup
43+
from arho_feature_template.core.models import Plan, PlanFeature, Regulation, RegulationGroup
44+
3345
logger = logging.getLogger(__name__)
3446

3547

@@ -179,6 +191,20 @@ def save_plan_jsons(self, plan_json, outline_json):
179191
)
180192

181193

194+
def _save_feature(feature: QgsFeature, layer: QgsVectorLayer, id_: int | None, edit_text: str = ""):
195+
if not layer.isEditable():
196+
layer.startEditing()
197+
layer.beginEditCommand(edit_text)
198+
199+
if id_ is None:
200+
layer.addFeature(feature)
201+
else:
202+
layer.updateFeature(feature)
203+
204+
layer.endEditCommand()
205+
layer.commitChanges(stopEditing=False)
206+
207+
182208
def save_plan(plan_data: Plan) -> QgsFeature:
183209
plan_layer = PlanLayer.get_from_project()
184210
in_edit_mode = plan_layer.isEditable()
@@ -208,11 +234,76 @@ def save_plan(plan_data: Plan) -> QgsFeature:
208234
return plan_feature
209235

210236

211-
def save_regulation_group(regulation_group: RegulationGroup, plan_id: str) -> QgsFeature:
212-
feature = RegulationGroupLayer.feature_from_model(regulation_group)
213-
feature["plan_id"] = plan_id
237+
def save_plan_feature(plan_feature: PlanFeature, plan_id: str | None = None) -> QgsFeature:
238+
layer_name_to_class_map: dict[str, type[PlanFeatureLayer]] = {
239+
LandUsePointLayer.name: LandUsePointLayer,
240+
OtherAreaLayer.name: OtherAreaLayer,
241+
OtherPointLayer.name: OtherPointLayer,
242+
LandUseAreaLayer.name: LandUseAreaLayer,
243+
LineLayer.name: LineLayer,
244+
}
245+
246+
if not plan_feature.layer_name:
247+
msg = "Cannot save plan feature without a target layer"
248+
raise ValueError(msg)
249+
layer_class = layer_name_to_class_map.get(plan_feature.layer_name)
250+
if not layer_class:
251+
msg = f"Could not find plan feature layer class for layer name {plan_feature.layer_name}"
252+
raise ValueError(msg)
253+
feature = layer_class.feature_from_model(plan_feature)
254+
layer = layer_class.get_from_project()
255+
256+
if plan_id:
257+
feature["plan_id"] = plan_id
258+
259+
_save_feature(
260+
feature=feature,
261+
layer=layer,
262+
id_=plan_feature.id_,
263+
edit_text="Kaavakohteen lisäys" if plan_feature.id_ is None else "Kaavakohteen muokkaus",
264+
)
265+
266+
# Handle regulation groups
267+
if plan_feature.regulation_groups:
268+
for group in plan_feature.regulation_groups:
269+
save_regulation_group(group)
270+
271+
return feature
272+
273+
274+
def save_regulation_group(regulation_group: RegulationGroup, plan_id: str | None = None) -> QgsFeature:
275+
feature = RegulationGroupLayer.feature_from_model(regulation_group, plan_id)
276+
layer = RegulationGroupLayer.get_from_project()
277+
278+
_save_feature(
279+
feature=feature,
280+
layer=layer,
281+
id_=regulation_group.id_,
282+
edit_text="Kaavamääräysryhmän lisäys" if regulation_group.id_ is None else "Kaavamääräysryhmän muokkaus",
283+
)
284+
285+
# Handle regulations
286+
if regulation_group.regulations:
287+
for regulation in regulation_group.regulations:
288+
regulation.regulation_group_id_ = feature["id"] # Updating regulation group ID
289+
save_regulation(regulation)
290+
214291
return feature
215292

216293

217294
def save_regulation_grop_assosiation(plan_id: str, regulation_group_id: str):
218295
pass
296+
297+
298+
def save_regulation(regulation: Regulation) -> QgsFeature:
299+
feature = PlanRegulationLayer.feature_from_model(regulation)
300+
layer = PlanRegulationLayer.get_from_project()
301+
302+
_save_feature(
303+
feature=feature,
304+
layer=layer,
305+
id_=regulation.id_,
306+
edit_text="Kaavamääräyksen lisäys" if regulation.id_ is None else "Kaavamääräyksen muokkaus",
307+
)
308+
309+
return feature

arho_feature_template/gui/plan_regulation_group_widget.py

+27-4
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,12 @@
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.code_layers import PlanRegulationGroupTypeLayer
1314

1415
if TYPE_CHECKING:
15-
from qgis.PyQt.QtWidgets import QFrame, QLineEdit, QPushButton
16+
from qgis.PyQt.QtWidgets import QFormLayout, QFrame, QLabel, QLineEdit, QPushButton
17+
18+
from arho_feature_template.gui.code_combobox import CodeComboBox
1619

1720
ui_path = resources.files(__package__) / "plan_regulation_group_widget.ui"
1821
FormClass, _ = uic.loadUiType(ui_path)
@@ -30,14 +33,32 @@ def __init__(self, regulation_group_data: RegulationGroup):
3033
# TYPES
3134
self.frame: QFrame
3235
self.name: QLineEdit
36+
self.short_name: QLineEdit
3337
self.del_btn: QPushButton
38+
self.type_of_regulation_group_label: QLabel
39+
self.type_of_regulation_group: CodeComboBox
40+
self.regulation_group_details_layout: QFormLayout
41+
# NOTE: Maybe user input is not needed and wanted for type of plan regulation group and it would be defined
42+
# by the plan feature directly (and hidden from user)
3443

3544
# INIT
3645
self.regulation_group_data = regulation_group_data
3746
self.regulation_widgets: list[RegulationWidget] = [
3847
self.add_regulation_widget(regulation) for regulation in self.regulation_group_data.regulations
3948
]
40-
self.name.setText(self.regulation_group_data.name)
49+
50+
# If regulation group type code is defined, delete selection for user
51+
if regulation_group_data.type_code_id:
52+
self.regulation_group_details_layout.removeWidget(self.type_of_regulation_group_label)
53+
self.regulation_group_details_layout.removeWidget(self.type_of_regulation_group)
54+
self.type_of_regulation_group_label.deleteLater()
55+
self.type_of_regulation_group.deleteLater()
56+
else:
57+
self.type_of_regulation_group.populate_from_code_layer(PlanRegulationGroupTypeLayer)
58+
self.type_of_regulation_group.removeItem(0) # Remove NULL from combobox as underground data is required
59+
60+
self.name.setText(self.regulation_group_data.name if self.regulation_group_data.name else "")
61+
self.short_name.setText(self.regulation_group_data.short_name if self.regulation_group_data.short_name else "")
4162
self.del_btn.setIcon(QgsApplication.getThemeIcon("mActionDeleteSelected.svg"))
4263
self.del_btn.clicked.connect(lambda: self.delete_signal.emit(self))
4364

@@ -54,9 +75,11 @@ def delete_regulation_widget(self, regulation_widget: RegulationWidget):
5475

5576
def into_model(self) -> RegulationGroup:
5677
return RegulationGroup(
57-
type_code=self.regulation_group_data.type_code,
78+
type_code_id=self.regulation_group_data.type_code_id
79+
if self.regulation_group_data.type_code_id
80+
else self.type_of_regulation_group.value(),
5881
name=self.name.text(),
59-
short_name=self.regulation_group_data.short_name,
82+
short_name=self.short_name.text(),
6083
color_code=self.regulation_group_data.color_code,
6184
regulations=[widget.into_model() for widget in self.regulation_widgets],
6285
id_=self.regulation_group_data.id_,

0 commit comments

Comments
 (0)