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

Lisaa kaava #25

Merged
merged 8 commits into from
Oct 28, 2024
Merged
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
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -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
<a href="https://www.flaticon.com/free-icons/open" title="open icons">Open icons created by Smashicons - Flaticon</a>
<a href="https://www.flaticon.com/free-icons/land-use" title="land use icons">Land use icons created by Fusion5085 - Flaticon</a>
63 changes: 63 additions & 0 deletions arho_feature_template/core/new_plan.py
Original file line number Diff line number Diff line change
@@ -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("")
62 changes: 62 additions & 0 deletions arho_feature_template/core/update_plan.py
Original file line number Diff line number Diff line change
@@ -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
31 changes: 31 additions & 0 deletions arho_feature_template/plugin.py
Original file line number Diff line number Diff line change
@@ -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:
Binary file added arho_feature_template/resources/icons/city.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added arho_feature_template/resources/icons/folder.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -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
Empty file.
3 changes: 3 additions & 0 deletions arho_feature_template/utils/misc_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import os

PLUGIN_PATH = os.path.dirname(os.path.dirname(__file__))