Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Kaavakohdetemplaattien toteutus ja kirjastojen alustaminen projektin lukemisen jälkeen #130

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 25 additions & 3 deletions arho_feature_template/core/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import yaml

from arho_feature_template.exceptions import ConfigSyntaxError
from arho_feature_template.project.layers.code_layers import UndergroundTypeLayer
from arho_feature_template.qgis_plugin_tools.tools.resources import resources_path
from arho_feature_template.utils.misc_utils import LANGUAGE, get_layer_by_name, iface

Expand Down Expand Up @@ -45,7 +46,20 @@ class FeatureTemplateLibrary:
feature_templates: list[PlanFeature]

@classmethod
def from_config_file(cls, config_fp: Path) -> FeatureTemplateLibrary:
def find_matching_group_config(cls, group_name: str, regulation_group_libraries: list[RegulationGroupLibrary]):
for library in regulation_group_libraries:
for category in library.regulation_group_categories:
for group in category.regulation_groups:
if group.name == group_name:
return group
return None

@classmethod
def from_config_file(
cls, config_fp: Path, regulation_group_libraries: list[RegulationGroupLibrary]
) -> FeatureTemplateLibrary:
get_underground_id = UndergroundTypeLayer.get_attribute_value_by_another_attribute_value

with config_fp.open(encoding="utf-8") as f:
data = yaml.safe_load(f)
try:
Expand All @@ -56,11 +70,19 @@ def from_config_file(cls, config_fp: Path) -> FeatureTemplateLibrary:
feature_templates=[
PlanFeature(
geom=None,
type_of_underground_id=feature_data.get("type_of_underground"), # Need ID conversion?
type_of_underground_id=(
get_underground_id("id", "value", feature_data.get("type_of_underground"))
if feature_data.get("type_of_underground")
else None
),
layer_name=feature_data.get("layer_name"),
name=feature_data.get("name"),
description=feature_data.get("description"),
regulation_groups=[], # feature_data.get("regulation_groups"), # Handle regulation group creaton
regulation_groups=[
group
for group_name in feature_data.get("regulation_groups", [])
if (group := cls.find_matching_group_config(group_name, regulation_group_libraries))
],
plan_id=None,
id_=None,
)
Expand Down
56 changes: 38 additions & 18 deletions arho_feature_template/core/plan_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
from arho_feature_template.gui.dialogs.serialize_plan import SerializePlan
from arho_feature_template.gui.docks.new_feature_dock import NewFeatureDock
from arho_feature_template.gui.tools.inspect_plan_features_tool import InspectPlanFeatures
from arho_feature_template.project.layers.code_layers import PlanRegulationGroupTypeLayer
from arho_feature_template.project.layers.code_layers import PlanRegulationGroupTypeLayer, code_layers
from arho_feature_template.project.layers.plan_layers import (
LandUseAreaLayer,
LandUsePointLayer,
Expand Down Expand Up @@ -79,14 +79,11 @@ def __init__(self):
self.json_plan_path = None
self.json_plan_outline_path = None

# Initialize libraries
self.feature_template_libraries = [
FeatureTemplateLibrary.from_config_file(file) for file in feature_template_library_config_files()
]
self.regulation_group_libraries = None
self.feature_template_libraries = []
self.regulation_group_libraries = []

# Initialize new feature dock
self.new_feature_dock = NewFeatureDock(self.feature_template_libraries)
self.new_feature_dock = NewFeatureDock()
self.new_feature_dock.tool_activated.connect(self.add_new_plan_feature)
self.new_feature_dock.hide()

Expand All @@ -107,13 +104,36 @@ def __init__(self):
self.lambda_service = LambdaService()
self.lambda_service.jsons_received.connect(self.save_plan_jsons)

def get_regulation_group_libraries(self):
# Lazy initialization of regulation_group_libraries to avoid reading regulation code layer too early
if self.regulation_group_libraries is None:
self.regulation_group_libraries = [
RegulationGroupLibrary.from_config_file(file) for file in regulation_group_library_config_files()
]
return self.regulation_group_libraries
def initialize_from_project(self):
# # If project is not open, don't try to initialize
# # NOTE: QgsProject.instance(), QgsProject().fileInfo() and QgsProject().fileIName()
# # don't seem to work as indicators whether a project is open?
# if not QgsProject.instance() or not QgsProject().fileInfo():
# return
self.initialize_libraries()

def check_required_layers(self):
missing_layers = []
for layer in code_layers + plan_layers:
if not layer.exists():
missing_layers.append(layer.name) # noqa: PERF401
if len(missing_layers) > 0: # noqa: SIM103
# iface.messageBar().pushWarning("", f"Project is missing required layers: {', '.join(missing_layers)}")
return False
return True

def initialize_libraries(self):
if not self.check_required_layers():
return

self.regulation_group_libraries = [
RegulationGroupLibrary.from_config_file(file) for file in regulation_group_library_config_files()
]
self.feature_template_libraries = [
FeatureTemplateLibrary.from_config_file(file, self.regulation_group_libraries)
for file in feature_template_library_config_files()
]
self.new_feature_dock.initialize_feature_template_libraries(self.feature_template_libraries)

def toggle_identify_plan_features(self, activate: bool): # noqa: FBT001
if activate:
Expand Down Expand Up @@ -179,7 +199,7 @@ def edit_plan(self):
return
plan_model = PlanLayer.model_from_feature(feature)

attribute_form = PlanAttributeForm(plan_model, self.get_regulation_group_libraries())
attribute_form = PlanAttributeForm(plan_model, self.regulation_group_libraries)
if attribute_form.exec_():
feature = save_plan(attribute_form.model)

Expand Down Expand Up @@ -210,7 +230,7 @@ def _plan_geom_digitized(self, feature: QgsFeature):
return

plan_model = Plan(geom=feature.geometry())
attribute_form = PlanAttributeForm(plan_model, self.get_regulation_group_libraries())
attribute_form = PlanAttributeForm(plan_model, self.regulation_group_libraries)
if attribute_form.exec_():
feature = save_plan(attribute_form.model)
plan_to_be_activated = feature["id"]
Expand All @@ -237,7 +257,7 @@ def _plan_feature_geom_digitized(self, feature: QgsFeature):

plan_feature.geom = feature.geometry()
attribute_form = PlanFeatureForm(
plan_feature, title, [*self.get_regulation_group_libraries(), regulation_group_library_from_active_plan()]
plan_feature, title, [*self.regulation_group_libraries, regulation_group_library_from_active_plan()]
)
if attribute_form.exec_():
save_plan_feature(attribute_form.model)
Expand All @@ -249,7 +269,7 @@ def edit_plan_feature(self, feature: QgsFeature, layer_name: str):
# Geom editing handled with basic QGIS vertex editing?
title = plan_feature.name if plan_feature.name else layer_name
attribute_form = PlanFeatureForm(
plan_feature, title, [*self.get_regulation_group_libraries(), regulation_group_library_from_active_plan()]
plan_feature, title, [*self.regulation_group_libraries, regulation_group_library_from_active_plan()]
)
if attribute_form.exec_():
save_plan_feature(attribute_form.model)
Expand Down
28 changes: 17 additions & 11 deletions arho_feature_template/gui/docks/new_feature_dock.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from __future__ import annotations

from importlib import resources
from typing import TYPE_CHECKING

Expand All @@ -21,7 +23,7 @@
class NewFeatureDock(QgsDockWidget, DockClass): # type: ignore
tool_activated = pyqtSignal()

def __init__(self, feature_template_libraries: list):
def __init__(self):
super().__init__()
self.setupUi(self)

Expand All @@ -41,11 +43,8 @@ def __init__(self, feature_template_libraries: list):
self.active_feature_type: str | None = None
self.active_feature_layer: str | None = None
self.active_template: PlanFeature | None = None
self.feature_template_libraries: list[FeatureTemplateLibrary] = feature_template_libraries
self.library_selection.addItems([library.name for library in self.feature_template_libraries])
self.feature_template_libraries: list[FeatureTemplateLibrary] | None = None
self.library_selection.currentIndexChanged.connect(self.set_active_feature_template_library)
if len(self.feature_template_libraries) > 0:
self.set_active_feature_template_library(0)

self.template_list.setSelectionMode(self.template_list.SingleSelection)
self.search_box.valueChanged.connect(self.filter_plan_feature_templates)
Expand All @@ -54,6 +53,12 @@ def __init__(self, feature_template_libraries: list):
self.template_list.clicked.connect(self.on_template_item_clicked)
self.new_feature_grid.active_feature_type_changed.connect(self.on_active_feature_type_changed)

def initialize_feature_template_libraries(self, feature_template_libraries: list[FeatureTemplateLibrary]):
self.feature_template_libraries = feature_template_libraries
self.library_selection.clear()
self.library_selection.addItems([library.name for library in self.feature_template_libraries])
self.set_active_feature_template_library(0)

def on_active_feature_type_changed(self, feature_name: str, layer_name: str):
self.active_feature_type = feature_name if feature_name else None
self.active_feature_layer = layer_name if layer_name else None
Expand Down Expand Up @@ -100,9 +105,10 @@ def deactivate_and_clear_selections(self):
self.template_list.clearSelection()

def set_active_feature_template_library(self, index: int) -> None:
self.template_list.clear()
library = self.feature_template_libraries[index]
for feature_template in library.feature_templates:
item = QListWidgetItem(feature_template.name)
item.setData(Qt.UserRole, feature_template)
self.template_list.addItem(item)
if self.feature_template_libraries and len(self.feature_template_libraries) > 0:
self.template_list.clear()
library = self.feature_template_libraries[index]
for feature_template in library.feature_templates:
item = QListWidgetItem(feature_template.name)
item.setData(Qt.UserRole, feature_template)
self.template_list.addItem(item)
22 changes: 13 additions & 9 deletions arho_feature_template/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,27 +127,30 @@ def add_action(
def initGui(self) -> None: # noqa N802
# plan_icon_path = os.path.join(PLUGIN_PATH, "resources/icons/city.png") # A placeholder icon
# load_icon_path = os.path.join(PLUGIN_PATH, "resources/icons/folder.png") # A placeholder icon
# icons to consider:
# icon=QgsApplication.getThemeIcon("mActionStreamingDigitize.svg"),
# icon=QgsApplication.getThemeIcon("mIconGeometryCollectionLayer.svg"),
# icon=QgsApplication.getThemeIcon("mActionSharingExport.svg"),

self.plan_manager = PlanManager()

iface.addDockWidget(Qt.RightDockWidgetArea, self.plan_manager.new_feature_dock)
self.plan_manager.new_feature_dock.setUserVisible(False)

self.plan_manager.new_feature_dock.visibilityChanged.connect(self.dock_visibility_changed)

iface.mapCanvas().mapToolSet.connect(self.plan_manager.plan_digitize_map_tool.deactivate)

self.validation_dock = ValidationDock()
iface.addDockWidget(Qt.RightDockWidgetArea, self.validation_dock)
self.validation_dock.setUserVisible(False)

self.validation_dock.visibilityChanged.connect(self.validation_dock_visibility_changed)

# icons to consider:
# icon=QgsApplication.getThemeIcon("mActionStreamingDigitize.svg"),
# icon=QgsApplication.getThemeIcon("mIconGeometryCollectionLayer.svg"),
# icon=QgsApplication.getThemeIcon("mActionSharingExport.svg"),
iface.mapCanvas().mapToolSet.connect(self.plan_manager.plan_digitize_map_tool.deactivate)

# Try initializing the plugin immediately in case the project is already open
self.plan_manager.initialize_from_project()

# (Re)initialize whenever a project is opened
iface.projectRead.connect(self.plan_manager.initialize_from_project)

# Add main plugin action to the toolbar
self.new_land_use_plan_action = self.add_action(
text="Luo kaava",
icon=QgsApplication.getThemeIcon("mActionNewMap.svg"),
Expand Down Expand Up @@ -251,6 +254,7 @@ def unload(self) -> None:
# Handle signals
self.plan_manager.new_feature_dock.visibilityChanged.disconnect()
iface.mapCanvas().mapToolSet.disconnect()
iface.projectRead.disconnect()

# Handle actions
for action in self.actions:
Expand Down
16 changes: 14 additions & 2 deletions arho_feature_template/project/layers/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,29 @@
from abc import ABC
from typing import TYPE_CHECKING, Any, ClassVar, Generator

from qgis.core import QgsFeatureRequest
from qgis.core import QgsFeatureRequest, QgsProject, QgsVectorLayer

from arho_feature_template.utils.project_utils import get_vector_layer_from_project

if TYPE_CHECKING:
from qgis.core import QgsFeature, QgsFeatureIterator, QgsVectorLayer
from qgis.core import QgsFeature, QgsFeatureIterator


class AbstractLayer(ABC):
name: ClassVar[str]

@classmethod
def exists(cls) -> bool:
project = QgsProject.instance()
if not project:
return False

layers = project.mapLayersByName(cls.name)
if not layers:
return False

return bool([layer for layer in layers if isinstance(layer, QgsVectorLayer)])

@classmethod
def get_from_project(cls) -> QgsVectorLayer:
return get_vector_layer_from_project(cls.name)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ feature_templates:

- name: Asuin-, liike- ja toimistorakennusten alue
layer_name: Aluevaraus
regulation_groups:
- Asuin-, liike- ja toimistorakennusten alue

- name: Sitovan tonttijaon mukainen tontti
layer_name: Osa-alue
Expand Down
Loading