"""sn_verfahrensgebiet/ui/tabs/working_tab.py – Bearbeitungs-Tab. Verwaltet die Verfahrensgebiet-Abgrenzung und ALKIS-Integration. """ from sn_basis.functions.qt_wrapper import QWidget, QVBoxLayout, QHBoxLayout, QLabel, QPushButton, QMessageBox from sn_basis.functions.qt_wrapper import Qt from sn_basis.functions import Qgis, QgsProject #QgsMessageLog from sn_basis.functions.qgisui_wrapper import QgsMapLayerComboBox from sn_basis.functions.qgiscore_wrapper import QgsMapLayerProxyModel from sn_basis.functions.verfahrensgebiet_manager import get_verfahrensgebiet_layer_id, set_verfahrensgebiet_layer_id from sn_basis.functions.dialog_wrapper import show_info_dialog from sn_basis.modules.Pruefmanager import Pruefmanager from sn_basis.modules.pruef_ergebnis import pruef_ergebnis from qgis.utils import iface from sn_verfahrensgebiet.functions.verfahrensgebiet_alkis import verfahrensgebiet_alkis, LoadStatus from sn_verfahrensgebiet.functions.flurstueck_alkis import flurstueck_alkis from sn_verfahrensgebiet.functions.verfahrensgebiet_edit_service import ( pruefe_flurstueck_layer, pruefe_auswahl, erstelle_verfahrensgebiet_aus_auswahl, ergaenze_verfahrensgebiet, entferne_aus_verfahrensgebiet, ersetze_verfahrensgebiet, ) from sn_basis.functions.message_wrapper import success, info, warning, error from sn_basis.functions.ly_style_wrapper import apply_style class WorkingTab(QWidget): """Tab für die Verfahrensgebiet-Bearbeitung und Verwaltung. Attributes: tab_title: Anzeigetitel des Tabs ("Bearbeitung") """ tab_title = "Bearbeitung" def __init__(self, parent=None): super().__init__(parent) layout = QVBoxLayout() layout.setAlignment(Qt.AlignmentFlag.AlignTop) # Abschnitt 1: Verfahrensgebiet laden row_verf_header = QHBoxLayout() lbl_verf = QLabel("Verfahrensgebiet") self.haken_verf = self._haken_label() row_verf_header.addWidget(lbl_verf) row_verf_header.addWidget(self.haken_verf) row_verf_header.addStretch() layout.addLayout(row_verf_header) row_verf_buttons = QHBoxLayout() self.btn_verf_alkis = QPushButton("Aus ALKIS laden") self.btn_verf_shape = QPushButton("Aus Shape laden") row_verf_buttons.addWidget(self.btn_verf_alkis) row_verf_buttons.addWidget(self.btn_verf_shape) layout.addLayout(row_verf_buttons) # Abschnitt 1b: Verfahrensgebiet-Layer auswählen row_layer_label = QHBoxLayout() lbl_layer = QLabel("Oder: Verfahrensgebiet-Layer auswählen") lbl_layer.setStyleSheet("font-style: italic; color: gray; margin-top: 8px;") row_layer_label.addWidget(lbl_layer) row_layer_label.addStretch() layout.addLayout(row_layer_label) self.verf_layer_combo = QgsMapLayerComboBox(self) self.verf_layer_combo.setFilters(QgsMapLayerProxyModel.VectorLayer) self.verf_layer_combo.setToolTip("Wähle den Verfahrensgebiet-Layer, oder lasse es leer für Automatik") self.verf_layer_combo.layerChanged.connect(self._on_verf_layer_changed) layout.addWidget(self.verf_layer_combo) # Abschnitt 2: Flurstücke row_flurst_header = QHBoxLayout() lbl_flurst = QLabel("Flurstücke") self.haken_flurst = self._haken_label() row_flurst_header.addWidget(lbl_flurst) row_flurst_header.addWidget(self.haken_flurst) row_flurst_header.addStretch() layout.addLayout(row_flurst_header) row_flurst_buttons = QHBoxLayout() self.btn_flurst_alkis = QPushButton("Aus ALKIS laden") self.btn_flurst_shape = QPushButton("Aus Shape laden") row_flurst_buttons.addWidget(self.btn_flurst_alkis) row_flurst_buttons.addWidget(self.btn_flurst_shape) layout.addLayout(row_flurst_buttons) # Abschnitt 3: Verfahrensgebiet erstellen row_verf_erstellen_header = QHBoxLayout() lbl_verf_erstellen = QLabel("Verfahrensgebiet erstellen") row_verf_erstellen_header.addWidget(lbl_verf_erstellen) row_verf_erstellen_header.addStretch() layout.addLayout(row_verf_erstellen_header) row_verf_erstellen_buttons = QHBoxLayout() self.btn_verf_aus_auswahl = QPushButton("aus Auswahl") self.btn_verf_aus_liste = QPushButton("Aus Liste") row_verf_erstellen_buttons.addWidget(self.btn_verf_aus_auswahl) row_verf_erstellen_buttons.addWidget(self.btn_verf_aus_liste) layout.addLayout(row_verf_erstellen_buttons) layout.addStretch() self.setLayout(layout) # Pruefmanager für interaktive Entscheidungen (Ergänzen/Entfernen/Ersetzen) self.pruefmanager = Pruefmanager(ui_modus="qgis", parent=self) # Signale verbinden self.btn_verf_alkis.clicked.connect(self.handle_verf_alkis) self.btn_flurst_alkis.clicked.connect(self.handle_flurst_alkis) self.btn_verf_aus_auswahl.clicked.connect(self.handle_verf_aus_auswahl) self.btn_verf_aus_liste.clicked.connect(self.handle_verf_aus_liste) # self.btn_verf_shape.clicked.connect(self.handle_verf_shape) # self.btn_flurst_shape.clicked.connect(self.handle_flurst_shape) # Beim Init: aktuelle Verfahrensgebiet-Layer-ID laden und im Dropdown anzeigen self._restore_verf_layer_selection() def handle_verf_alkis(self): self._set_busy(self.btn_verf_alkis, True, "Aus ALKIS laden") try: layer, status = verfahrensgebiet_alkis(self) if not layer or not layer.isValid(): set_verfahrensgebiet_layer_id("") return if status in (LoadStatus.FIRST, LoadStatus.RELOAD): QgsProject.instance().addMapLayer(layer) iface.mapCanvas().setExtent(layer.extent()) apply_style(layer, "verfahrensgebiet.qml") iface.mapCanvas().refresh() self.setze_haken(self.haken_verf, True) self.verf_layer_combo.setLayer(layer) self._on_verf_layer_changed(layer) msg = "erstmalig geladen" if status == LoadStatus.FIRST else "neu geladen" success("Verfahrensgebiet", f"Layer wurde {msg}.", duration=5) elif status == LoadStatus.KEEP: self.verf_layer_combo.setLayer(layer) self._on_verf_layer_changed(layer) info("Verfahrensgebiet", "Vorhandener Layer wurde behalten.", duration=4) elif status == LoadStatus.NONE: self._on_verf_layer_changed(None) warning("Verfahrensgebiet", "Layer konnte nicht geladen werden.", duration=None) finally: self._set_busy(self.btn_verf_alkis, False, "Aus ALKIS laden") def _set_busy(self, button: QPushButton, busy: bool, original_text: str = "Aus ALKIS laden") -> None: """Setzt den Busy-State eines Buttons. Parameters ---------- button : Der zu sperrende/entsperrende Button. busy : bool True zum Sperren (Text → "Lade ..."), False zum Freigeben. original_text : str Text, der nach dem Freigeben wiederhergestellt wird. Jeder Button gibt seinen eigenen Originaltext explizit an. """ button.setEnabled(not busy) button.setText("Lade ..." if busy else original_text) def _haken_label(self) -> QLabel: label = QLabel() label.setFixedSize(20, 20) label.setAlignment(Qt.AlignmentFlag.AlignCenter) label.setText("") # Start ohne Haken return label def setze_haken(self, label: QLabel, aktiv: bool): """Zeigt oder entfernt den grünen Haken (Unicode), ohne Theme-Icons.""" if aktiv: label.setText("✓") label.setStyleSheet("color: #2ea043; font-weight: bold;") else: label.setText("") label.setStyleSheet("") def _on_verf_layer_changed(self, layer) -> None: """Callback: Nutzer hat einen anderen Layer im Dropdown gewählt.""" if layer and layer.isValid(): # Speichere die Layer-ID in der zentralen Variable set_verfahrensgebiet_layer_id(layer.id()) else: # Layer is None oder invalid; leere die Variable set_verfahrensgebiet_layer_id("") def _restore_verf_layer_selection(self) -> None: """Beim Tab-Init: Lade die zuletzt gespeicherte Verfahrensgebiet-Layer-ID.""" layer_id = get_verfahrensgebiet_layer_id() if layer_id: try: project = QgsProject.instance() layer = project.mapLayer(layer_id) if layer and layer.isValid(): self.verf_layer_combo.setLayer(layer) except Exception: pass # ------------------------------------------------------------------ # Flurstücke-Handler # ------------------------------------------------------------------ def handle_flurst_alkis(self) -> None: """Lädt Flurstücke aus ALKIS-WFS anhand von Gemarkungsschlüsseln.""" self._set_busy(self.btn_flurst_alkis, True, "Aus ALKIS laden") try: layer, status = flurstueck_alkis(self) if not layer or not layer.isValid(): return if status in (LoadStatus.FIRST, LoadStatus.RELOAD): QgsProject.instance().addMapLayer(layer) # iface.mapCanvas().setExtent(layer.extent()) # Kartenausschnitt bleibt unverändert apply_style(layer, "GIS_Flst_Beschriftung_ALKIS_NAS.qml") iface.mapCanvas().refresh() self.setze_haken(self.haken_flurst, True) msg = "erstmalig geladen" if status == LoadStatus.FIRST else "neu geladen" success("Flurstücke", f"Layer wurde {msg}.", duration=5) elif status == LoadStatus.KEEP: self.setze_haken(self.haken_flurst, True) info("Flurstücke", "Vorhandener Layer wurde behalten.", duration=4) finally: self._set_busy(self.btn_flurst_alkis, False, "Aus ALKIS laden") # ------------------------------------------------------------------ # Verfahrensgebiet-erstellen-Handler # ------------------------------------------------------------------ def handle_verf_aus_auswahl(self) -> None: """Erstellt oder aktualisiert den Verfahrensgebiet-Layer aus der Flurstück-Auswahl.""" self._set_busy(self.btn_verf_aus_auswahl, True, "aus Auswahl") try: # 1. Aktiven Layer ermitteln active_layer = iface.activeLayer() if not active_layer: warning( "Verfahrensgebiet erstellen", "Kein aktiver Layer. Bitte den Flurstück-Layer aktivieren.", duration=None, ) return # 2. Vorbedingungen via Layerpruefer ergebnis = pruefe_flurstueck_layer(active_layer) if not ergebnis.ok: warning("Verfahrensgebiet erstellen", ergebnis.meldung, duration=None) return # 3. Auswahl prüfen ergebnis_auswahl = pruefe_auswahl(active_layer) if not ergebnis_auswahl.ok: warning("Verfahrensgebiet erstellen", ergebnis_auswahl.meldung, duration=None) return # 4. Bestehenden Verfahrensgebiet-Layer prüfen existing_layers = QgsProject.instance().mapLayersByName("Verfahrensgebiet") if not existing_layers: # Erstlauf: neuen Memory-Layer erzeugen layer, erfolgreich, fehlgeschlagen = erstelle_verfahrensgebiet_aus_auswahl( active_layer ) if not layer or not layer.isValid(): error("Verfahrensgebiet erstellen", "Layer konnte nicht erstellt werden.") return QgsProject.instance().addMapLayer(layer) apply_style(layer, "verfahrensgebiet.qml") iface.mapCanvas().refresh() self.verf_layer_combo.setLayer(layer) self._on_verf_layer_changed(layer) self.setze_haken(self.haken_verf, True) QMessageBox.information( self, "Verfahrensgebiet erstellt", f"Verfahrensgebiet aus Auswahl erstellt.\n" f"Erfolgreich: {erfolgreich}\n" f"Fehlgeschlagen: {fehlgeschlagen}", ) return # 5. Bestehender Layer: Nutzerentscheidung via Pruefmanager entscheidung_ergebnis = self.pruefmanager.verarbeite( pruef_ergebnis( ok=False, aktion="verfahrensgebiet_layer_existiert", meldung=( "Ein Verfahrensgebiet-Layer existiert bereits.\n" "Was soll mit der Auswahl geschehen?" ), kontext=existing_layers[0], ) ) aktion = entscheidung_ergebnis.aktion verf_layer = existing_layers[0] if aktion == "verfahrensgebiet_abbrechen" or not entscheidung_ergebnis.ok: return elif aktion == "verfahrensgebiet_ergaenzen": _, hinzugefuegt, bereits_vorhanden, fehlgeschlagen = ergaenze_verfahrensgebiet( verf_layer, active_layer ) apply_style(verf_layer, "verfahrensgebiet.qml") iface.mapCanvas().refresh() self.setze_haken(self.haken_verf, True) QMessageBox.information( self, "Flurstücke ergänzt", f"Hinzugefügt: {hinzugefuegt}\n" f"Bereits vorhanden (übersprungen): {bereits_vorhanden}\n" f"Fehlgeschlagen: {fehlgeschlagen}", ) elif aktion == "verfahrensgebiet_entfernen": _, entfernt, nicht_enthalten, fehlgeschlagen = entferne_aus_verfahrensgebiet( verf_layer, active_layer ) apply_style(verf_layer, "verfahrensgebiet.qml") iface.mapCanvas().refresh() QMessageBox.information( self, "Flurstücke entfernt", f"Entfernt: {entfernt}\n" f"Nicht im Verfahrensgebiet (übersprungen): {nicht_enthalten}\n" f"Fehlgeschlagen: {fehlgeschlagen}", ) elif aktion == "verfahrensgebiet_ersetzen": for lyr in existing_layers: QgsProject.instance().removeMapLayer(lyr.id()) layer, erfolgreich, fehlgeschlagen = ersetze_verfahrensgebiet(active_layer) if not layer or not layer.isValid(): error("Verfahrensgebiet erstellen", "Layer konnte nicht erstellt werden.") return QgsProject.instance().addMapLayer(layer) apply_style(layer, "verfahrensgebiet.qml") iface.mapCanvas().refresh() self.verf_layer_combo.setLayer(layer) self._on_verf_layer_changed(layer) self.setze_haken(self.haken_verf, True) QMessageBox.information( self, "Verfahrensgebiet ersetzt", f"Verfahrensgebiet neu erstellt.\n" f"Erfolgreich: {erfolgreich}\n" f"Fehlgeschlagen: {fehlgeschlagen}", ) finally: self._set_busy(self.btn_verf_aus_auswahl, False, "aus Auswahl") def handle_verf_aus_liste(self) -> None: """Platzhalter – Verfahrensgebiet aus Liste erstellen (noch nicht implementiert).""" show_info_dialog( "Noch nicht implementiert", "Die Funktion 'Aus Liste' steht in einer zukünftigen Version zur Verfügung.", parent=self, )