diff --git a/README.md b/README.md
index 6224972e..75c00774 100644
--- a/README.md
+++ b/README.md
@@ -61,3 +61,7 @@ the one with the path `.venv\Scripts\python.exe`.
This plugin is distributed under the terms of the [GNU General Public License, version 2](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html) license.
See [LICENSE](LICENSE) for more information.
+
+### Attributations
+Open icons created by Smashicons - Flaticon
+Land use icons created by Fusion5085 - Flaticon
diff --git a/arho_feature_template/core/new_plan.py b/arho_feature_template/core/new_plan.py
new file mode 100644
index 00000000..97dd5eea
--- /dev/null
+++ b/arho_feature_template/core/new_plan.py
@@ -0,0 +1,63 @@
+from qgis.core import QgsProject, QgsVectorLayer
+from qgis.utils import iface
+
+from arho_feature_template.core.update_plan import LandUsePlan, update_selected_plan
+
+
+class NewPlan:
+ def add_new_plan(self):
+ # Filtered layers are not editable, so clear filters first.
+ self.clear_all_filters()
+
+ layers = QgsProject.instance().mapLayersByName("Kaava")
+ if not layers:
+ iface.messageBar().pushMessage("Error", "Layer 'Kaava' not found", level=3)
+ return
+
+ kaava_layer = layers[0]
+
+ if not kaava_layer.isEditable():
+ kaava_layer.startEditing()
+
+ iface.setActiveLayer(kaava_layer)
+
+ iface.actionAddFeature().trigger()
+
+ # Connect the featureAdded signal
+ kaava_layer.featureAdded.connect(self.feature_added)
+
+ def feature_added(self):
+ kaava_layer = iface.activeLayer()
+ kaava_layer.featureAdded.disconnect()
+ feature_ids_before_commit = kaava_layer.allFeatureIds()
+ if kaava_layer.isEditable():
+ if not kaava_layer.commitChanges():
+ iface.messageBar().pushMessage("Error", "Failed to commit changes to the layer.", level=3)
+ return
+ else:
+ iface.messageBar().pushMessage("Error", "Layer is not editable.", level=3)
+ return
+
+ feature_ids_after_commit = kaava_layer.allFeatureIds()
+
+ # Find the new plan.id by comparing fids before and after commit.
+ new_feature_id = next((fid for fid in feature_ids_after_commit if fid not in feature_ids_before_commit), None)
+
+ if new_feature_id is not None:
+ new_feature = kaava_layer.getFeature(new_feature_id)
+
+ if new_feature.isValid():
+ feature_id_value = new_feature["id"]
+ update_selected_plan(LandUsePlan(feature_id_value))
+ else:
+ iface.messageBar().pushMessage("Error", "Invalid feature retrieved.", level=3)
+ else:
+ iface.messageBar().pushMessage("Error", "No new feature was added.", level=3)
+
+ def clear_all_filters(self):
+ """Clear filters for all vector layers in the project."""
+ layers = QgsProject.instance().mapLayers().values()
+
+ for layer in layers:
+ if isinstance(layer, QgsVectorLayer):
+ layer.setSubsetString("")
diff --git a/arho_feature_template/core/update_plan.py b/arho_feature_template/core/update_plan.py
new file mode 100644
index 00000000..d083090a
--- /dev/null
+++ b/arho_feature_template/core/update_plan.py
@@ -0,0 +1,62 @@
+from dataclasses import dataclass
+
+from qgis.core import QgsMapLayer, QgsProject, QgsVectorLayer
+from qgis.utils import iface
+
+
+# To be extended and moved
+@dataclass
+class LandUsePlan:
+ id: str
+
+
+# To be replaced later
+LAYER_PLAN_ID_MAP = {
+ "Kaava": "id",
+ "Maankäytön kohteet": "plan_id",
+ "Muut pisteet": "plan_id",
+ "Viivat": "plan_id",
+ "Aluevaraus": "plan_id",
+ "Osa-alue": "plan_id",
+}
+
+
+def update_selected_plan(new_plan: LandUsePlan):
+ """Update the project layers based on the selected land use plan."""
+ plan_id = new_plan.id
+
+ for layer_name, field_name in LAYER_PLAN_ID_MAP.items():
+ # Set the filter on each layer using the plan_id
+ set_filter_for_vector_layer(layer_name, field_name, plan_id)
+
+
+def set_filter_for_vector_layer(layer_name: str, field_name: str, field_value: str):
+ """Set a filter for the given vector layer."""
+ layers = QgsProject.instance().mapLayersByName(layer_name)
+
+ if not _check_layer_count(layers):
+ return
+
+ layer = layers[0]
+
+ expression = f"\"{field_name}\" = '{field_value}'"
+
+ # Apply the filter to the layer
+ if not layer.setSubsetString(expression):
+ iface.messageBar().pushMessage("Error", f"Failed to filter layer {layer_name} with query {expression}", level=3)
+
+
+def _check_layer_count(layers: list) -> bool:
+ """Check if any layers are returned."""
+ if not layers:
+ iface.messageBar().pushMessage("Error", "ERROR: No layers found with the specified name.", level=3)
+ return False
+ return True
+
+
+def _check_vector_layer(layer: QgsMapLayer) -> bool:
+ """Check if the given layer is a vector layer."""
+ if not isinstance(layer, QgsVectorLayer):
+ iface.messageBar().pushMessage("Error", f"Layer {layer.name()} is not a vector layer: {type(layer)}", level=3)
+ return False
+ return True
diff --git a/arho_feature_template/plugin.py b/arho_feature_template/plugin.py
index f06d83c2..e60d754d 100644
--- a/arho_feature_template/plugin.py
+++ b/arho_feature_template/plugin.py
@@ -1,5 +1,6 @@
from __future__ import annotations
+import os
from typing import TYPE_CHECKING, Callable, cast
from qgis.PyQt.QtCore import QCoreApplication, Qt, QTranslator
@@ -8,9 +9,11 @@
from qgis.utils import iface
from arho_feature_template.core.feature_template_library import FeatureTemplater, TemplateGeometryDigitizeMapTool
+from arho_feature_template.core.new_plan import NewPlan
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
+from arho_feature_template.utils.misc_utils import PLUGIN_PATH
if TYPE_CHECKING:
from qgis.gui import QgisInterface, QgsMapTool
@@ -25,6 +28,7 @@ class Plugin:
def __init__(self) -> None:
setup_logger(Plugin.name)
+ self.digitizing_tool = None
# initialize locale
locale, file_path = setup_translation()
@@ -120,6 +124,10 @@ def add_action(
def initGui(self) -> None: # noqa N802
self.templater = FeatureTemplater()
+ self.new_plan = NewPlan()
+
+ 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
iface.addDockWidget(Qt.RightDockWidgetArea, self.templater.template_dock)
self.templater.template_dock.visibilityChanged.connect(self.dock_visibility_changed)
@@ -136,10 +144,33 @@ def initGui(self) -> None: # noqa N802
add_to_toolbar=True,
)
+ self.new_land_use_plan_action = self.add_action(
+ plan_icon_path,
+ "Create New Plan",
+ self.digitize_new_plan,
+ add_to_menu=True,
+ add_to_toolbar=True,
+ status_tip="Create a new plan",
+ )
+
+ self.load_land_use_plan_action = self.add_action(
+ load_icon_path,
+ text="Load existing land use plan",
+ triggered_callback=self.load_existing_land_use_plan,
+ parent=iface.mainWindow(),
+ 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)
+ def digitize_new_plan(self):
+ self.new_plan.add_new_plan()
+
+ def load_existing_land_use_plan(self) -> None:
+ """Open existing land use plan."""
+
def unload(self) -> None:
"""Removes the plugin menu item and icon from QGIS GUI."""
for action in self.actions:
diff --git a/arho_feature_template/resources/icons/city.png b/arho_feature_template/resources/icons/city.png
new file mode 100644
index 00000000..ed82aaf6
Binary files /dev/null and b/arho_feature_template/resources/icons/city.png differ
diff --git a/arho_feature_template/resources/icons/folder.png b/arho_feature_template/resources/icons/folder.png
new file mode 100644
index 00000000..9eb2915f
Binary files /dev/null and b/arho_feature_template/resources/icons/folder.png differ
diff --git a/arho_feature_template/resources/template_libraries/asemakaava-sample.yaml b/arho_feature_template/resources/template_libraries/asemakaava-sample.yaml
index 00cdae85..b7901f8a 100644
--- a/arho_feature_template/resources/template_libraries/asemakaava-sample.yaml
+++ b/arho_feature_template/resources/template_libraries/asemakaava-sample.yaml
@@ -7,6 +7,7 @@ templates:
description: Kaavakohde ilman kikkareita
feature:
layer: land_use_area
+ # layer: Aluevaraus
attributes:
- attribute: name
- attribute: type_of_underground_id
@@ -15,6 +16,7 @@ templates:
description: Aluella kuvataan ...
feature:
layer: land_use_area
+ # layer: Aluevaraus
attributes:
- attribute: name
- attribute: type_of_underground_id
diff --git a/arho_feature_template/utils/__init__.py b/arho_feature_template/utils/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/arho_feature_template/utils/misc_utils.py b/arho_feature_template/utils/misc_utils.py
new file mode 100644
index 00000000..42f38d62
--- /dev/null
+++ b/arho_feature_template/utils/misc_utils.py
@@ -0,0 +1,3 @@
+import os
+
+PLUGIN_PATH = os.path.dirname(os.path.dirname(__file__))