diff --git a/arho_feature_template/gui/components/plan_regulation_group_widget.py b/arho_feature_template/gui/components/plan_regulation_group_widget.py
index 880f8b9f..cf4883c8 100644
--- a/arho_feature_template/gui/components/plan_regulation_group_widget.py
+++ b/arho_feature_template/gui/components/plan_regulation_group_widget.py
@@ -1,22 +1,23 @@
from __future__ import annotations
from importlib import resources
-from typing import TYPE_CHECKING
+from typing import TYPE_CHECKING, cast
from qgis.core import QgsApplication
from qgis.PyQt import uic
from qgis.PyQt.QtCore import pyqtSignal
-from qgis.PyQt.QtGui import QIcon
-from qgis.PyQt.QtWidgets import QWidget
+from qgis.PyQt.QtGui import QIcon, QPixmap
+from qgis.PyQt.QtWidgets import QHBoxLayout, QLabel, QSizePolicy, QWidget
-from arho_feature_template.core.models import Proposition, Regulation, RegulationGroup
+from arho_feature_template.core.models import PlanFeature, Proposition, Regulation, RegulationGroup
from arho_feature_template.gui.components.plan_proposition_widget import PropositionWidget
from arho_feature_template.gui.components.plan_regulation_widget import RegulationWidget
from arho_feature_template.project.layers.code_layers import PlanRegulationGroupTypeLayer
+from arho_feature_template.project.layers.plan_layers import RegulationGroupAssociationLayer
from arho_feature_template.qgis_plugin_tools.tools.resources import resources_path
if TYPE_CHECKING:
- from qgis.PyQt.QtWidgets import QFormLayout, QFrame, QLabel, QLineEdit, QPushButton
+ from qgis.PyQt.QtWidgets import QFormLayout, QFrame, QLineEdit, QPushButton
ui_path = resources.files(__package__) / "plan_regulation_group_widget.ui"
FormClass, _ = uic.loadUiType(ui_path)
@@ -28,7 +29,7 @@ class RegulationGroupWidget(QWidget, FormClass): # type: ignore
open_as_form_signal = pyqtSignal(QWidget)
delete_signal = pyqtSignal(QWidget)
- def __init__(self, regulation_group: RegulationGroup, layer_name: str):
+ def __init__(self, regulation_group: RegulationGroup, plan_feature: PlanFeature):
super().__init__()
self.setupUi(self)
@@ -42,11 +43,16 @@ def __init__(self, regulation_group: RegulationGroup, layer_name: str):
self.regulation_group_details_layout: QFormLayout
# INIT
+ self.frame.setObjectName("frame") # Set unique name to avoid style cascading
self.regulation_widgets: list[RegulationWidget] = []
self.proposition_widgets: list[PropositionWidget] = []
+ self.link_label_icon: QLabel | None = None
+ self.link_label_text: QLabel | None = None
- regulation_group.type_code_id = PlanRegulationGroupTypeLayer.get_id_by_feature_layer_name(layer_name)
+ self.plan_feature = plan_feature
+ self.layer_name = cast(str, plan_feature.layer_name)
self.from_model(regulation_group)
+ self.regulation_group.type_code_id = PlanRegulationGroupTypeLayer.get_id_by_feature_layer_name(self.layer_name)
self.edit_btn.setIcon(QIcon(resources_path("icons", "settings.svg")))
self.edit_btn.clicked.connect(lambda: self.open_as_form_signal.emit(self))
@@ -69,6 +75,19 @@ def from_model(self, regulation_group: RegulationGroup):
for proposition in regulation_group.propositions:
self.add_proposition_widget(proposition)
+ # Remove existing indicators if reinitializing
+ self.unset_existing_regulation_group_style()
+
+ if regulation_group.id_:
+ other_linked_features_count = len(
+ RegulationGroupAssociationLayer.get_associations_for_regulation_group_exclude_feature(
+ cast(str, regulation_group.id_), cast(str, self.plan_feature.id_), self.layer_name
+ )
+ )
+ if other_linked_features_count > 0:
+ # Set indicators that regulation group exists in the plan already and is assigned for other features
+ self.set_existing_regulation_group_style(other_linked_features_count)
+
def add_regulation_widget(self, regulation: Regulation) -> RegulationWidget:
widget = RegulationWidget(regulation=regulation, parent=self.frame)
widget.delete_signal.connect(self.delete_regulation_widget)
@@ -93,6 +112,44 @@ def delete_proposition_widget(self, proposition_widget: RegulationWidget):
self.proposition_widgets.remove(proposition_widget)
proposition_widget.deleteLater()
+ def set_existing_regulation_group_style(self, other_linked_features_count: int):
+ tooltip = (
+ "Kaavamääräysryhmä on tallennettu kaavaan. Ryhmän tietojen muokkaaminen vaikuttaa muihin "
+ "kaavakohteisiin, joille ryhmä on lisätty."
+ )
+ layout = QHBoxLayout()
+
+ self.link_label_icon = QLabel()
+ self.link_label_icon.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Fixed)
+ self.link_label_icon.setPixmap(QPixmap(resources_path("icons", "linked_img_small.png")))
+ self.link_label_icon.setToolTip(tooltip)
+ layout.addWidget(self.link_label_icon)
+
+ self.link_label_text = QLabel()
+ self.link_label_text.setObjectName("text_label") # Set unique name to avoid style cascading
+ self.link_label_text.setText(
+ f"Kaavamääräysryhmä on käytössä myös {other_linked_features_count} toisella kaavakohteella"
+ )
+ self.link_label_text.setWordWrap(True)
+ self.link_label_text.setStyleSheet("#text_label { color: #4b8db2; }")
+ self.link_label_text.setToolTip(tooltip)
+ layout.addWidget(self.link_label_text)
+
+ self.frame.layout().insertLayout(1, layout)
+
+ self.setStyleSheet("#frame { border: 2px solid #4b8db2; }")
+
+ def unset_existing_regulation_group_style(self):
+ if self.link_label_icon:
+ self.link_label_icon.deleteLater()
+ self.link_label_icon = None
+
+ if self.link_label_text:
+ self.link_label_text.deleteLater()
+ self.link_label_text = None
+
+ self.setStyleSheet("")
+
def into_model(self) -> RegulationGroup:
return RegulationGroup(
type_code_id=self.regulation_group.type_code_id,
diff --git a/arho_feature_template/gui/components/plan_regulation_group_widget.ui b/arho_feature_template/gui/components/plan_regulation_group_widget.ui
index ab36df91..bda291f6 100644
--- a/arho_feature_template/gui/components/plan_regulation_group_widget.ui
+++ b/arho_feature_template/gui/components/plan_regulation_group_widget.ui
@@ -6,8 +6,8 @@
0
0
- 420
- 129
+ 467
+ 130
diff --git a/arho_feature_template/gui/dialogs/plan_feature_form.py b/arho_feature_template/gui/dialogs/plan_feature_form.py
index bf594904..d945fd86 100644
--- a/arho_feature_template/gui/dialogs/plan_feature_form.py
+++ b/arho_feature_template/gui/dialogs/plan_feature_form.py
@@ -1,7 +1,7 @@
from __future__ import annotations
from importlib import resources
-from typing import TYPE_CHECKING, cast
+from typing import TYPE_CHECKING
from qgis.PyQt import uic
from qgis.PyQt.QtCore import Qt
@@ -78,7 +78,6 @@ def __init__(
# Initialize attributes from template
self.plan_feature = plan_feature
- self.layer_name = plan_feature.layer_name # Should always have a layer name
if plan_feature.name:
self.feature_name.setText(plan_feature.name)
@@ -105,7 +104,7 @@ def add_selected_plan_regulation_group(self, item: QTreeWidgetItem, column: int)
self.add_plan_regulation_group(regulation_group)
def add_plan_regulation_group(self, definition: RegulationGroup):
- regulation_group_widget = RegulationGroupWidget(definition, cast(str, self.layer_name))
+ regulation_group_widget = RegulationGroupWidget(definition, self.plan_feature)
regulation_group_widget.delete_signal.connect(self.remove_plan_regulation_group)
regulation_group_widget.open_as_form_signal.connect(self.open_plan_regulation_group_form)
self._remove_spacer()
@@ -141,7 +140,7 @@ def into_model(self) -> PlanFeature:
type_of_underground_id=self.feature_type_of_underground.value(),
description=self.feature_description.toPlainText(),
geom=self.plan_feature.geom,
- layer_name=self.layer_name,
+ layer_name=self.plan_feature.layer_name,
regulation_groups=[reg_group_widget.into_model() for reg_group_widget in self.regulation_group_widgets],
id_=self.plan_feature.id_,
)
diff --git a/arho_feature_template/gui/dialogs/plan_regulation_group_form.py b/arho_feature_template/gui/dialogs/plan_regulation_group_form.py
index cf432294..5fcd32b6 100644
--- a/arho_feature_template/gui/dialogs/plan_regulation_group_form.py
+++ b/arho_feature_template/gui/dialogs/plan_regulation_group_form.py
@@ -6,7 +6,17 @@
from qgis.core import QgsApplication
from qgis.PyQt import uic
from qgis.PyQt.QtCore import Qt
-from qgis.PyQt.QtWidgets import QDialog, QDialogButtonBox, QTextBrowser, QTreeWidgetItem, QVBoxLayout
+from qgis.PyQt.QtGui import QPixmap
+from qgis.PyQt.QtWidgets import (
+ QDialog,
+ QDialogButtonBox,
+ QHBoxLayout,
+ QLabel,
+ QSizePolicy,
+ QTextBrowser,
+ QTreeWidgetItem,
+ QVBoxLayout,
+)
from arho_feature_template.core.models import (
Proposition,
@@ -19,6 +29,8 @@
from arho_feature_template.gui.components.plan_regulation_widget import RegulationWidget
from arho_feature_template.gui.components.tree_with_search_widget import TreeWithSearchWidget
from arho_feature_template.project.layers.code_layers import PlanRegulationGroupTypeLayer
+from arho_feature_template.project.layers.plan_layers import RegulationGroupAssociationLayer
+from arho_feature_template.qgis_plugin_tools.tools.resources import resources_path
if TYPE_CHECKING:
from qgis.gui import QgsSpinBox
@@ -49,6 +61,8 @@ def __init__(self, regulation_group: RegulationGroup):
self.regulations_layout: QBoxLayout
self.regulation_info: QTextBrowser
+ self.regulation_group_info_tab: QWidget
+
self.propositions_layout: QVBoxLayout
self.propositions_scroll_contents: QWidget
self.add_proposition_btn: QPushButton
@@ -90,6 +104,36 @@ def __init__(self, regulation_group: RegulationGroup):
for proposition in self.regulation_group.propositions:
self.add_proposition(proposition)
+ if self.regulation_group.id_:
+ feat_count = len(
+ list(
+ RegulationGroupAssociationLayer.get_associations_for_regulation_group(
+ str(self.regulation_group.id_)
+ )
+ )
+ )
+ tooltip = (
+ "Kaavamääräysryhmä on tallennettu kaavaan. Ryhmän tietojen muokkaaminen vaikuttaa "
+ "kaavakohteisiin, joille ryhmä on lisätty."
+ )
+ layout = QHBoxLayout()
+
+ self.link_label_icon = QLabel()
+ self.link_label_icon.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Fixed)
+ self.link_label_icon.setPixmap(QPixmap(resources_path("icons", "linked_img_small.png")))
+ self.link_label_icon.setToolTip(tooltip)
+ layout.addWidget(self.link_label_icon)
+
+ self.link_label_text = QLabel()
+ self.link_label_text.setObjectName("text_label") # Set unique name to avoid style cascading
+ self.link_label_text.setText(f"Kaavamääräysryhmä on käytössä yhteensä {feat_count} kaavakohteella")
+ self.link_label_text.setWordWrap(True)
+ self.link_label_text.setStyleSheet("#text_label { color: #4b8db2; }")
+ self.link_label_text.setToolTip(tooltip)
+ layout.addWidget(self.link_label_text)
+
+ self.regulation_group_info_tab.layout().insertLayout(1, layout)
+
def _initalize_regulation_from_config(self, config: RegulationConfig, parent: QTreeWidgetItem | None = None):
item = self.regulations_selection_widget.add_item_to_tree(config.name, config, parent)
diff --git a/arho_feature_template/gui/dialogs/plan_regulation_group_form.ui b/arho_feature_template/gui/dialogs/plan_regulation_group_form.ui
index 973d0e46..fddd83fb 100644
--- a/arho_feature_template/gui/dialogs/plan_regulation_group_form.ui
+++ b/arho_feature_template/gui/dialogs/plan_regulation_group_form.ui
@@ -25,83 +25,81 @@
-
-
-
- true
+
+
-
+
+
+ Otsikko
+
+
+
+ -
+
+
+ -
+
+
+ Lyhyt nimi
+
+
+
+ -
+
+
+ -
+
+
+ Ryhmänumero
+
+
+
+ -
+
+
+ NULL
+
+
+ 999
+
+
+ false
+
+
+
+ -
+
+
+ Värikoodi
+
+
+
+ -
+
+
+ -
+
+
+ Tyyppi
+
+
+
+ -
+
+
+
+
+ -
+
+
+ Qt::Vertical
-
-
-
- 0
- 0
- 851
- 577
-
-
-
-
-
-
-
- Otsikko
-
-
-
- -
-
-
- -
-
-
- Lyhyt nimi
-
-
-
- -
-
-
- -
-
-
- Ryhmänumero
-
-
-
- -
-
-
- Värikoodi
-
-
-
- -
-
-
- -
-
-
- Tyyppi
-
-
-
- -
-
-
- -
-
-
- NULL
-
-
- 999
-
-
- false
-
-
-
-
-
-
+
+
+ 20
+ 40
+
+
+
@@ -156,8 +154,8 @@ p, li { white-space: pre-wrap; }
0
0
- 587
- 577
+ 38
+ 18
@@ -195,8 +193,8 @@ p, li { white-space: pre-wrap; }
0
0
- 851
- 577
+ 120
+ 49
diff --git a/arho_feature_template/project/layers/plan_layers.py b/arho_feature_template/project/layers/plan_layers.py
index f8a08db4..3657541e 100644
--- a/arho_feature_template/project/layers/plan_layers.py
+++ b/arho_feature_template/project/layers/plan_layers.py
@@ -286,6 +286,17 @@ def get_associations_for_feature(cls, feature_id: str, layer_name: str) -> Gener
def get_associations_for_regulation_group(cls, group_id: str) -> Generator[QgsFeature]:
return cls.get_features_by_attribute_value("plan_regulation_group_id", group_id)
+ @classmethod
+ def get_associations_for_regulation_group_exclude_feature(
+ cls, group_id: str, excluded_feature_id: str, excluded_feature_layer_name: str
+ ) -> list[QgsFeature]:
+ attribute = RegulationGroupAssociationLayer.layer_name_to_attribute_map.get(excluded_feature_layer_name)
+ return [
+ association
+ for association in cls.get_associations_for_regulation_group(group_id)
+ if association[attribute] != excluded_feature_id
+ ]
+
@classmethod
def get_group_ids_for_feature(cls, feature_id: str, layer_name: str) -> Generator[str]:
attribute = cls.layer_name_to_attribute_map.get(layer_name)
@@ -326,7 +337,7 @@ def feature_from_model(cls, model: Regulation) -> QgsFeature:
feature["unit"] = model.config.unit
feature["text_value"] = {LANGUAGE: model.value if isinstance(model.value, str) else ""}
feature["numeric_value"] = model.value if isinstance(model.value, Number) else NULL
- feature["name"] = {LANGUAGE: model.topic_tag if model.topic_tag else ""}
+ # feature["name"] = {LANGUAGE: model.topic_tag if model.topic_tag else ""}
feature["type_of_verbal_plan_regulation_id"] = model.verbal_regulation_type_id
feature["id"] = model.id_ if model.id_ else feature["id"]
# feature["plan_theme_id"]
diff --git a/arho_feature_template/resources/icons/linked_img.png b/arho_feature_template/resources/icons/linked_img.png
new file mode 100644
index 00000000..1080f719
Binary files /dev/null and b/arho_feature_template/resources/icons/linked_img.png differ
diff --git a/arho_feature_template/resources/icons/linked_img_small.png b/arho_feature_template/resources/icons/linked_img_small.png
new file mode 100644
index 00000000..dced74f9
Binary files /dev/null and b/arho_feature_template/resources/icons/linked_img_small.png differ