""" 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 def teardown_verfahrensgebiet_listener() -> None: """ Trennt globale Event-Listener vom QgsProject-Singleton. Diese Funktion ist idempotent und kann mehrfach aufgerufen werden. """ global _listener_installed if not _listener_installed: return try: project = QgsProject.instance() if project is None: return try: project.layersAdded.disconnect(_on_layers_added) except Exception: pass try: project.layerRemoved.disconnect(_on_layer_removed) except Exception: pass for signal_name in ("readProject", "newProjectCreated", "cleared"): signal = getattr(project, signal_name, None) if signal is None: continue try: signal.disconnect(_on_project_changed) except Exception: pass except RuntimeError: pass except Exception: pass finally: _listener_installed = False