diff --git a/arho_feature_template/gui/new_plan_regulation_group_form.py b/arho_feature_template/gui/new_plan_regulation_group_form.py new file mode 100644 index 0000000..fb2c223 --- /dev/null +++ b/arho_feature_template/gui/new_plan_regulation_group_form.py @@ -0,0 +1,70 @@ +from __future__ import annotations + +from importlib import resources +from typing import TYPE_CHECKING + +from qgis.PyQt import uic +from qgis.PyQt.QtWidgets import QDialog, QTreeWidget, QTreeWidgetItem + +from arho_feature_template.gui.new_plan_regulation_widget import NewPlanRegulationWidget + +if TYPE_CHECKING: + from qgis.PyQt.QtWidgets import QBoxLayout, QWidget + +ui_path = resources.files(__package__) / "new_plan_regulation_group_form.ui" +FormClass, _ = uic.loadUiType(ui_path) + + +class NewPlanRegulationGroupForm(QDialog, FormClass): # type: ignore + """Form to create a new plan regulation group.""" + + def __init__(self): + super().__init__() + self.setupUi(self) + + # TYPES + self.plan_regulations_view: QTreeWidget + self.plan_regulations_scroll_area_contents: QWidget + self.plan_regulations_layout: QBoxLayout + + # INIT + self.initialize_plan_regulations() + self.plan_regulations_view.itemDoubleClicked.connect(self.add_selected_plan_regulation) + + def initialize_plan_regulations(self): + # NOTE: Replace the dummy plan regulation codes below with codes from DB + plan_regulation_codes = { + "category 1": ["regulation 1", "regulation 2"], + "category 2": ["regulation 3"], + "category 3": ["regulation 4", "regulation 5", "regulation 6"], + } + + # Initialize categories + for category_name, plan_regulations in plan_regulation_codes.items(): + category_item = QTreeWidgetItem() + category_item.setText(0, category_name) + self.plan_regulations_view.addTopLevelItem(category_item) + + # Initialize plan regulations under the categories + for plan_regulation_type in plan_regulations: + plan_regulation_item = QTreeWidgetItem(category_item) + plan_regulation_item.setText(0, plan_regulation_type) + self.plan_regulations_view.addTopLevelItem(plan_regulation_item) + + def add_selected_plan_regulation(self, item: QTreeWidgetItem, column: int): + # If user double clicked category, don't add plan regulation + if not item.parent(): + return + self.add_plan_regulation(item.text(column)) + + def add_plan_regulation(self, regulation_type: str): + new_plan_regulation_widget = NewPlanRegulationWidget( + regulation_type=regulation_type, parent=self.plan_regulations_scroll_area_contents + ) + new_plan_regulation_widget.delete_signal.connect(self.delete_plan_regulation) + index = self.plan_regulations_layout.count() - 1 + self.plan_regulations_layout.insertWidget(index, new_plan_regulation_widget) + + def delete_plan_regulation(self, plan_regulation_widget: NewPlanRegulationWidget): + self.plan_regulations_layout.removeWidget(plan_regulation_widget) + plan_regulation_widget.deleteLater() diff --git a/arho_feature_template/gui/new_plan_regulation_group_form.ui b/arho_feature_template/gui/new_plan_regulation_group_form.ui new file mode 100644 index 0000000..7fff8e6 --- /dev/null +++ b/arho_feature_template/gui/new_plan_regulation_group_form.ui @@ -0,0 +1,199 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>Dialog</class> + <widget class="QDialog" name="Dialog"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>769</width> + <height>535</height> + </rect> + </property> + <property name="windowTitle"> + <string>Luo kaavamääräysryhmä</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout_2"> + <item> + <widget class="QTabWidget" name="tabs"> + <property name="currentIndex"> + <number>0</number> + </property> + <widget class="QWidget" name="plan_regulation_group_info_tab"> + <attribute name="title"> + <string>Kaavamääräysryhmän tiedot</string> + </attribute> + <layout class="QVBoxLayout" name="verticalLayout_3"> + <item> + <widget class="QScrollArea" name="scrollArea"> + <property name="widgetResizable"> + <bool>true</bool> + </property> + <widget class="QWidget" name="scrollAreaWidgetContents"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>727</width> + <height>435</height> + </rect> + </property> + <layout class="QFormLayout" name="formLayout"> + <item row="0" column="0"> + <widget class="QLabel" name="label_2"> + <property name="text"> + <string>Kaavamääräyksen otsikko</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QLineEdit" name="heading"/> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="label_3"> + <property name="text"> + <string>Kirjaintunnus</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QLineEdit" name="code"/> + </item> + <item row="2" column="0"> + <widget class="QLabel" name="label"> + <property name="text"> + <string>Ryhmänumero</string> + </property> + </widget> + </item> + <item row="2" column="1"> + <widget class="QLineEdit" name="group_number"/> + </item> + <item row="3" column="0"> + <widget class="QLabel" name="label_5"> + <property name="text"> + <string>Värikoodi</string> + </property> + </widget> + </item> + <item row="3" column="1"> + <widget class="QLineEdit" name="color_code"/> + </item> + </layout> + </widget> + </widget> + </item> + </layout> + </widget> + <widget class="QWidget" name="plan_regulations_tab"> + <attribute name="title"> + <string>Kaavamääräykset</string> + </attribute> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <widget class="QTreeWidget" name="plan_regulations_view"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Maximum" vsizetype="Expanding"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <attribute name="headerVisible"> + <bool>false</bool> + </attribute> + <column> + <property name="text"> + <string notr="true">1</string> + </property> + </column> + </widget> + </item> + <item> + <widget class="QScrollArea" name="plan_regulations_scroll_area"> + <property name="widgetResizable"> + <bool>true</bool> + </property> + <widget class="QWidget" name="plan_regulations_scroll_area_contents"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>98</width> + <height>28</height> + </rect> + </property> + <layout class="QVBoxLayout" name="plan_regulations_layout"> + <item> + <spacer name="verticalSpacer"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>574</height> + </size> + </property> + </spacer> + </item> + </layout> + </widget> + </widget> + </item> + </layout> + </widget> + <widget class="QWidget" name="recommendations_tab"> + <attribute name="title"> + <string>Suositukset</string> + </attribute> + <layout class="QVBoxLayout" name="verticalLayout_4"> + <item> + <widget class="QScrollArea" name="scrollArea_2"> + <property name="widgetResizable"> + <bool>true</bool> + </property> + <widget class="QWidget" name="scrollAreaWidgetContents_2"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>98</width> + <height>28</height> + </rect> + </property> + </widget> + </widget> + </item> + </layout> + </widget> + </widget> + </item> + <item> + <widget class="QDialogButtonBox" name="button_box"> + <property name="standardButtons"> + <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> + </property> + </widget> + </item> + </layout> + </widget> + <resources/> + <connections> + <connection> + <sender>button_box</sender> + <signal>rejected()</signal> + <receiver>Dialog</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel"> + <x>384</x> + <y>513</y> + </hint> + <hint type="destinationlabel"> + <x>384</x> + <y>267</y> + </hint> + </hints> + </connection> + </connections> +</ui> diff --git a/arho_feature_template/gui/new_plan_regulation_widget.py b/arho_feature_template/gui/new_plan_regulation_widget.py new file mode 100644 index 0000000..74a8df8 --- /dev/null +++ b/arho_feature_template/gui/new_plan_regulation_widget.py @@ -0,0 +1,124 @@ +from __future__ import annotations + +from enum import Enum +from importlib import resources +from typing import TYPE_CHECKING + +from qgis.core import QgsApplication +from qgis.gui import QgsDoubleSpinBox, QgsFileWidget, QgsSpinBox +from qgis.PyQt import uic +from qgis.PyQt.QtCore import pyqtSignal +from qgis.PyQt.QtWidgets import QComboBox, QFormLayout, QHBoxLayout, QLineEdit, QMenu, QSizePolicy, QTextEdit, QWidget + +if TYPE_CHECKING: + from qgis.PyQt.QtWidgets import QPushButton + +ui_path = resources.files(__package__) / "new_plan_regulation_widget.ui" +FormClass, _ = uic.loadUiType(ui_path) + + +class InputTypes(Enum): + TEXT_VALUE = 1 + NUMERIC_VALUE = 2 + CODE_VALUE = 3 + + TEXT_INFO = 4 + NUMERIC_INFO = 5 + CODE_INFO = 6 + + REGULATION_NUMBER = 7 + RELATED_FILE = 8 + + +class NewPlanRegulationWidget(QWidget, FormClass): # type: ignore + """A widget representation of a plan regulation.""" + + delete_signal = pyqtSignal(QWidget) + + def __init__(self, regulation_type: str, parent=None): + super().__init__(parent) + self.setupUi(self) + + # TYPES + self.plan_regulation_type: QLineEdit + self.form_layout: QFormLayout + + self.add_input_btn: QPushButton + self.add_additional_information_btn: QPushButton + self.add_regulation_number_btn: QPushButton + self.add_file_btn: QPushButton + self.del_btn: QPushButton + + # INIT + self.widgets: dict[InputTypes, list[QWidget]] = {} + self.plan_regulation_type.setText(regulation_type) + self.init_buttons() + + def request_delete(self): + self.delete_signal.emit(self) + + def init_buttons(self): + self.del_btn.setIcon(QgsApplication.getThemeIcon("mActionDeleteSelected.svg")) + self.del_btn.clicked.connect(self.request_delete) + + input_menu = QMenu() + input_menu.addAction("Teksti").triggered.connect(lambda: self.add_input_field(InputTypes.TEXT_VALUE)) + input_menu.addAction("Numeerinen").triggered.connect(lambda: self.add_input_field(InputTypes.NUMERIC_VALUE)) + input_menu.addAction("Koodi").triggered.connect(lambda: self.add_input_field(InputTypes.CODE_VALUE)) + self.add_input_btn.setMenu(input_menu) + + additional_info_menu = QMenu() + additional_info_menu.addAction("Teksti").triggered.connect(lambda: self.add_input_field(InputTypes.TEXT_INFO)) + additional_info_menu.addAction("Numeerinen").triggered.connect( + lambda: self.add_input_field(InputTypes.NUMERIC_INFO) + ) + additional_info_menu.addAction("Koodi").triggered.connect(lambda: self.add_input_field(InputTypes.CODE_INFO)) + self.add_additional_information_btn.setMenu(additional_info_menu) + + self.add_regulation_number_btn.clicked.connect(lambda: self.add_input_field(InputTypes.REGULATION_NUMBER)) + self.add_file_btn.clicked.connect(lambda: self.add_input_field(InputTypes.RELATED_FILE)) + + def add_input_field(self, input_field_type: InputTypes): + if input_field_type == InputTypes.TEXT_VALUE: + inputs = QTextEdit() + self.form_layout.addRow("Tekstiarvo", inputs) + elif input_field_type == InputTypes.NUMERIC_VALUE: + value_widget = QgsDoubleSpinBox() # Or QgsSpinBox? + value_widget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) + unit_widget = QLineEdit() + inputs = QHBoxLayout() + inputs.addWidget(value_widget) + inputs.addWidget(unit_widget) + self.form_layout.addRow("Numeerinen arvo", inputs) + elif input_field_type == InputTypes.CODE_VALUE: + code_widget = QComboBox() + code_widget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) + value_widget = QLineEdit() + inputs = QHBoxLayout() + inputs.addWidget(code_widget) + inputs.addWidget(value_widget) + # TODO: inputs.addItems() + self.form_layout.addRow("Koodiarvo", inputs) + + elif input_field_type == InputTypes.TEXT_INFO: + inputs = QTextEdit() + self.form_layout.addRow("Lisätieto", inputs) + elif input_field_type == InputTypes.NUMERIC_INFO: + inputs = QgsDoubleSpinBox() + self.form_layout.addRow("Lisätieto", inputs) + elif input_field_type == InputTypes.CODE_INFO: + inputs = QComboBox() + # TODO: inputs.addItems() + self.form_layout.addRow("Lisätieto", inputs) + + elif input_field_type == InputTypes.REGULATION_NUMBER: + inputs = QgsSpinBox() + self.form_layout.addRow("Määräysnumero", inputs) + elif input_field_type == InputTypes.RELATED_FILE: + inputs = QgsFileWidget() + self.form_layout.addRow("Liiteasiakirja", inputs) + + if self.widgets.get(input_field_type) is None: + self.widgets[input_field_type] = [inputs] + else: + self.widgets[input_field_type].append(inputs) diff --git a/arho_feature_template/gui/new_plan_regulation_widget.ui b/arho_feature_template/gui/new_plan_regulation_widget.ui new file mode 100644 index 0000000..95b91b2 --- /dev/null +++ b/arho_feature_template/gui/new_plan_regulation_widget.ui @@ -0,0 +1,152 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>Form</class> + <widget class="QWidget" name="Form"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>694</width> + <height>108</height> + </rect> + </property> + <property name="windowTitle"> + <string>Form</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <layout class="QFormLayout" name="form_layout"> + <item row="0" column="0"> + <widget class="QLabel" name="label_4"> + <property name="text"> + <string>Kaavamääräyslaji</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <widget class="QLineEdit" name="plan_regulation_type"/> + </item> + <item> + <widget class="QPushButton" name="del_btn"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="maximumSize"> + <size> + <width>30</width> + <height>16777215</height> + </size> + </property> + <property name="text"> + <string/> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_2"> + <item> + <widget class="QPushButton" name="add_input_btn"> + <property name="text"> + <string>Arvo</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="add_additional_information_btn"> + <property name="text"> + <string>Lisätieto</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="add_regulation_number_btn"> + <property name="text"> + <string>Määräysnumero</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="add_file_btn"> + <property name="text"> + <string>Liiteasiakirja</string> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer_3"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_4"> + <item> + <spacer name="horizontalSpacer_4"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Fixed</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="Line" name="line"> + <property name="minimumSize"> + <size> + <width>0</width> + <height>20</height> + </size> + </property> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer_5"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Fixed</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> + </layout> + </widget> + <resources/> + <connections/> +</ui> diff --git a/arho_feature_template/plugin.py b/arho_feature_template/plugin.py index 7079fd9..ad9488a 100644 --- a/arho_feature_template/plugin.py +++ b/arho_feature_template/plugin.py @@ -9,6 +9,7 @@ from arho_feature_template.core.feature_template_library import FeatureTemplater, TemplateGeometryDigitizeMapTool from arho_feature_template.core.plan_manager import PlanManager +from arho_feature_template.gui.new_plan_regulation_group_form import NewPlanRegulationGroupForm from arho_feature_template.qgis_plugin_tools.tools.custom_logging import setup_logger, teardown_logger from arho_feature_template.qgis_plugin_tools.tools.i18n import setup_translation from arho_feature_template.qgis_plugin_tools.tools.resources import plugin_name @@ -162,6 +163,14 @@ def initGui(self) -> None: # noqa N802 add_to_toolbar=True, ) + self.new_plan_regulation_group = self.add_action( + "", + text="Luo kaavamääräysryhmä", + triggered_callback=self.open_plan_regulation_group_form, + add_to_menu=True, + add_to_toolbar=True, + ) + def on_map_tool_changed(self, new_tool: QgsMapTool, old_tool: QgsMapTool) -> None: # noqa: ARG002 if not isinstance(new_tool, TemplateGeometryDigitizeMapTool): self.template_dock_action.setChecked(False) @@ -186,3 +195,7 @@ def dock_visibility_changed(self, visible: bool) -> None: # noqa: FBT001 def toggle_template_dock(self, show: bool) -> None: # noqa: FBT001 self.templater.template_dock.setUserVisible(show) + + def open_plan_regulation_group_form(self): + self.new_plan_regulation_group_dialog = NewPlanRegulationGroupForm() + self.new_plan_regulation_group_dialog.exec_()