diff --git a/functions/verfahrensgebiet_manager.py b/functions/verfahrensgebiet_manager.py new file mode 100644 index 0000000..9b5a78a --- /dev/null +++ b/functions/verfahrensgebiet_manager.py @@ -0,0 +1,173 @@ +""" +sn_basis/functions/verfahrensgebiet_manager.py + +Zentrale Verwaltung des Verfahrensgebiet-Layers für alle sn_-Plugins. + +Die Variable `sn_verfahrensgebiet_layer` wird automatisch aktualisiert, wenn: +- Ein Layer mit dem Namen "Verfahrensgebiet" ins Projekt geladen wird +- Das Projekt neu geladen wird +- Der Layer aus dem Projekt gelöscht wird + +Nutzer können diese Auswahl über das Dropdown in sn_verfahrensgebiet/working_tab +manuell überschreiben. +""" + +from typing import Optional + +from sn_basis.functions.qgiscore_wrapper import QgsProject, QGIS_AVAILABLE +from sn_basis.functions.variable_wrapper import get_variable, set_variable + + +# --------------------------------------------------------- +# Globale State für Listener-Registrierung +# --------------------------------------------------------- + +_listener_installed = False + + +# --------------------------------------------------------- +# Zentrale Verwaltung +# --------------------------------------------------------- + +def get_verfahrensgebiet_layer_id() -> Optional[str]: + """ + Gibt die Layer-ID des aktuellen Verfahrensgebiet-Layers zurück. + + Returns + ------- + Optional[str] + Die Layer-ID oder None, wenn keine Variable gesetzt ist. + """ + value = get_variable("verfahrensgebiet_layer", scope="project") + return value if value else None + + +def set_verfahrensgebiet_layer_id(layer_id: str) -> None: + """ + Setzt die Layer-ID des Verfahrensgebiet-Layers (von Nutzer-Auswahl im Dropdown). + + Parameters + ---------- + layer_id : str + Die eindeutige Layer-ID des gewählten Layers. + """ + set_variable("verfahrensgebiet_layer", layer_id, scope="project") + + +def _find_verfahrensgebiet_layer(): + """ + Sucht einen Layer mit dem Namen 'Verfahrensgebiet' im aktuellen Projekt. + + Returns + ------- + tuple[Optional[layer], Optional[str]] + (Layer-Objekt, Layer-ID) oder (None, None), wenn nicht gefunden. + """ + if not QGIS_AVAILABLE: + return None, None + + try: + project = QgsProject.instance() + layers = project.mapLayersByName("Verfahrensgebiet") + + if layers: + # Nutze den ersten (bzw. zuletzt hinzugefügten) Layer mit diesem Namen + layer = layers[0] + return layer, layer.id() + except Exception: + pass + + return None, None + + +def _update_verfahrensgebiet_from_project() -> bool: + """ + Sucht automatisch nach einem Layer namens 'Verfahrensgebiet' im Projekt + und aktualisiert die Variable `sn_verfahrensgebiet_layer`. + + Diese Funktion wird aufgerufen bei: + - layersAdded Signal + - readProject Signal (Projekt-Reload) + - Projekt-Neuerstellung + + Returns + ------- + bool + True, wenn ein Layer gefunden und gespeichert wurde, False sonst. + """ + layer, layer_id = _find_verfahrensgebiet_layer() + + if layer and layer_id: + set_variable("verfahrensgebiet_layer", layer_id, scope="project") + return True + else: + # Layer nicht gefunden: Variable zurücksetzen + set_variable("verfahrensgebiet_layer", "", scope="project") + return False + + +def _on_layers_added(layers) -> None: + """Signal-Handler für QgsProject.layersAdded""" + _update_verfahrensgebiet_from_project() + + +def _on_layer_removed(layer_id: str) -> None: + """Signal-Handler für QgsProject.layerRemoved""" + # Prüfe, ob der entfernte Layer der aktuelle Verfahrensgebiet-Layer war + current_id = get_verfahrensgebiet_layer_id() + if current_id and current_id == layer_id: + # Layer wurde entfernt; versuche, neu zu suchen + _update_verfahrensgebiet_from_project() + + +def _on_project_changed() -> None: + """Signal-Handler für QgsProject.readProject, newProjectCreated, cleared""" + _update_verfahrensgebiet_from_project() + + +# --------------------------------------------------------- +# Listener-Setup +# --------------------------------------------------------- + +def setup_verfahrensgebiet_listener() -> None: + """ + Registriert globale Event-Listener auf dem QgsProject-Singleton. + + Diese Funktion sollte EINMAL beim Plugin-Start aufgerufen werden + (z.B. in sn_basis.main.BasisPlugin.initGui()). + + Listener: + - layersAdded: automatische Aktualisierung, wenn Layer hinzugefügt werden + - layerRemoved: Validierung, wenn Layer gelöscht werden + - readProject: Neuinitialisierung beim Projekt-Reload + """ + global _listener_installed + + if _listener_installed: + return # Bereits registriert + + if not QGIS_AVAILABLE: + return # QGIS nicht verfügbar + + try: + project = QgsProject.instance() + + # Verbinde Signale + project.layersAdded.connect(_on_layers_added) + project.layerRemoved.connect(_on_layer_removed) + + # readProject wird emittiert, wenn Projekt geladen wird + # newProjectCreated wird emittiert bei neuem Projekt + # cleared wird emittiert, wenn Projekt gelöscht wird + for signal_name in ("readProject", "newProjectCreated", "cleared"): + signal = getattr(project, signal_name, None) + if signal is not None: + signal.connect(_on_project_changed) + + _listener_installed = True + + # Initial: versuche, existierenden Layer zu finden + _update_verfahrensgebiet_from_project() + + except Exception: + pass diff --git a/main.py b/main.py index 414820f..a5d3d1a 100644 --- a/main.py +++ b/main.py @@ -4,6 +4,7 @@ from qgis.utils import plugins from sn_basis.functions.qt_wrapper import QCoreApplication from sn_basis.functions.sys_wrapper import getattr_safe +from sn_basis.functions.verfahrensgebiet_manager import setup_verfahrensgebiet_listener from sn_basis.ui.navigation import Navigation @@ -34,6 +35,10 @@ class BasisPlugin: """ self.ui = Navigation() self.ui.init_ui() + + # Zentrale Verwaltung des Verfahrensgebiet-Layers starten + setup_verfahrensgebiet_listener() + for name, plugin in plugins.items(): if name.startswith("sn_") and name != "sn_basis": try: diff --git a/modules/print_logic.py b/modules/print_logic.py index 9598ff9..3cf372a 100644 --- a/modules/print_logic.py +++ b/modules/print_logic.py @@ -68,7 +68,11 @@ class PrintLogic: def _resolve_layer_from_project(self) -> object | None: project = QgsProject.instance() - layer_id = (get_variable("verfahrensgebietslayer", scope="project") or "").strip() + # Primär: neue zentrale Variable aus sn_verfahrensgebiet_manager + layer_id = (get_variable("verfahrensgebiet_layer", scope="project") or "").strip() + # Rückwärtskompatibilität zu älteren Projekten + if not layer_id: + layer_id = (get_variable("verfahrensgebietslayer", scope="project") or "").strip() if not layer_id: layer_id = (get_variable("tab_a_layer_id", scope="project") or "").strip() if not layer_id: @@ -610,6 +614,9 @@ class PrintLogic: if layer_for_extent is not None: layer_id = getattr(layer_for_extent, "id", lambda: "")() or "" if layer_id: + # Neu: zentrale Variable + set_variable("verfahrensgebiet_layer", layer_id, scope="project") + # Alt: Rückwärtskompatibilität set_variable("verfahrensgebietslayer", layer_id, scope="project") kartenbild_w = extent.width() * 1000.0 / massstab_zahl