Files
Plugin_SN_Verfahrensgebiet/ui/tabs/working_tab.py
T

605 lines
26 KiB
Python
Raw Normal View History

2026-04-20 14:33:13 +02:00
"""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, create_progress_dialog
2026-04-21 21:50:26 +02:00
from sn_basis.modules.Pruefmanager import Pruefmanager
from sn_basis.modules.pruef_ergebnis import pruef_ergebnis
2025-11-18 16:10:58 +01:00
from qgis.utils import iface
2026-04-22 14:53:45 +02:00
from sn_verfahrensgebiet.functions.verfahrensgebiet_alkis import LoadStatus
2026-04-21 21:50:26 +02:00
from sn_verfahrensgebiet.functions.flurstueck_alkis import flurstueck_alkis
2026-04-22 14:53:45 +02:00
from sn_verfahrensgebiet.functions.verfahrensgebiet_alkis_komplett import verfahrensgebiet_alkis_komplett
2026-05-05 21:17:19 +02:00
from sn_verfahrensgebiet.functions.grenzpunkt_alkis import grenzpunkte_gemarkungsweise, JOINED_LAYER_NAME
2026-06-23 12:57:35 +02:00
from sn_verfahrensgebiet.functions.gemarkung_alkis import (
gemarkung_schluessel_und_namen_von_vg_geometrie,
lade_gemarkungen_layer,
)
2026-05-05 21:17:19 +02:00
from sn_verfahrensgebiet.functions.umringstatistik_grenzpunkte import umringstatistik_grenzpunkte
2026-04-21 21:50:26 +02:00
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
2025-11-18 16:10:58 +01:00
class WorkingTab(QWidget):
2026-04-20 14:33:13 +02:00
"""Tab für die Verfahrensgebiet-Bearbeitung und Verwaltung.
Attributes:
tab_title: Anzeigetitel des Tabs ("Bearbeitung")
"""
2025-11-18 16:10:58 +01:00
tab_title = "Bearbeitung"
def __init__(self, parent=None):
super().__init__(parent)
layout = QVBoxLayout()
layout.setAlignment(Qt.AlignmentFlag.AlignTop)
2026-04-21 21:50:26 +02:00
# Abschnitt 1: Verfahrensgebiet laden
2025-11-18 16:10:58 +01:00
row_verf_header = QHBoxLayout()
lbl_verf = QLabel("<b>Verfahrensgebiet</b>")
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)
2026-04-21 21:50:26 +02:00
# Abschnitt 2: Flurstücke
2025-11-18 16:10:58 +01:00
row_flurst_header = QHBoxLayout()
lbl_flurst = QLabel("<b>Flurstücke</b>")
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)
2026-06-23 12:57:35 +02:00
# Abschnitt 2b: Gemarkungen
row_gem_header = QHBoxLayout()
lbl_gem = QLabel("<b>Gemarkungen</b>")
self.haken_gem = self._haken_label()
row_gem_header.addWidget(lbl_gem)
row_gem_header.addWidget(self.haken_gem)
row_gem_header.addStretch()
layout.addLayout(row_gem_header)
row_gem_buttons = QHBoxLayout()
self.btn_gem_alkis = QPushButton("Aus ALKIS laden")
row_gem_buttons.addWidget(self.btn_gem_alkis)
layout.addLayout(row_gem_buttons)
# Abschnitt 2c: Grenzpunkte
2026-04-22 14:53:45 +02:00
row_grenz_header = QHBoxLayout()
lbl_grenz = QLabel("<b>Grenzpunkte</b>")
self.haken_grenz = self._haken_label()
row_grenz_header.addWidget(lbl_grenz)
row_grenz_header.addWidget(self.haken_grenz)
row_grenz_header.addStretch()
layout.addLayout(row_grenz_header)
row_grenz_buttons = QHBoxLayout()
self.btn_grenz_alkis = QPushButton("Grenzpunkte aus ALKIS laden")
row_grenz_buttons.addWidget(self.btn_grenz_alkis)
layout.addLayout(row_grenz_buttons)
2026-05-05 21:17:19 +02:00
row_umring_buttons = QHBoxLayout()
self.btn_umring_statistik = QPushButton("Umringstatistik Grenzpunkte")
row_umring_buttons.addWidget(self.btn_umring_statistik)
layout.addLayout(row_umring_buttons)
2026-04-21 21:50:26 +02:00
# Abschnitt 3: Verfahrensgebiet erstellen
row_verf_erstellen_header = QHBoxLayout()
lbl_verf_erstellen = QLabel("<b>Verfahrensgebiet erstellen</b>")
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)
2025-11-18 16:10:58 +01:00
layout.addStretch()
self.setLayout(layout)
2026-04-21 21:50:26 +02:00
# Pruefmanager für interaktive Entscheidungen (Ergänzen/Entfernen/Ersetzen)
self.pruefmanager = Pruefmanager(ui_modus="qgis", parent=self)
2025-11-18 16:10:58 +01:00
# Signale verbinden
self.btn_verf_alkis.clicked.connect(self.handle_verf_alkis)
2026-04-21 21:50:26 +02:00
self.btn_flurst_alkis.clicked.connect(self.handle_flurst_alkis)
2026-06-23 12:57:35 +02:00
self.btn_gem_alkis.clicked.connect(self.handle_gem_alkis)
2026-04-22 14:53:45 +02:00
self.btn_grenz_alkis.clicked.connect(self.handle_grenz_alkis)
2026-05-05 21:17:19 +02:00
self.btn_umring_statistik.clicked.connect(self.handle_umringstatistik)
2026-04-21 21:50:26 +02:00
self.btn_verf_aus_auswahl.clicked.connect(self.handle_verf_aus_auswahl)
self.btn_verf_aus_liste.clicked.connect(self.handle_verf_aus_liste)
2025-11-18 16:10:58 +01:00
# 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()
2026-04-22 14:53:45 +02:00
def handle_verf_alkis(self) -> None:
2026-04-23 22:24:14 +02:00
"""Startet den vollständigen VG-Lade-Workflow (ALKIS → Gemarkungen → Flurstücke →
Verschneidung → Flächenvergleich → opt. Umringsprüfung).
2026-04-22 14:53:45 +02:00
Delegiert an :func:`~sn_verfahrensgebiet.functions.verfahrensgebiet_alkis_komplett.verfahrensgebiet_alkis_komplett`.
2026-04-23 22:24:14 +02:00
Nach Erfolg werden enriched VG-Layer, Flurstücks-Layer und BROR-Layer
ins Projekt eingefügt, Styles angewendet und die UI-Elemente aktualisiert.
2026-04-22 14:53:45 +02:00
"""
2026-04-21 21:50:26 +02:00
self._set_busy(self.btn_verf_alkis, True, "Aus ALKIS laden")
2025-11-18 16:10:58 +01:00
try:
2026-04-23 22:24:14 +02:00
enriched_layer, flst_layer, bror_layer, status = verfahrensgebiet_alkis_komplett(self)
2026-04-22 14:53:45 +02:00
if status == LoadStatus.NONE or not enriched_layer:
set_verfahrensgebiet_layer_id("")
2025-11-18 16:10:58 +01:00
return
2026-04-22 14:53:45 +02:00
project = QgsProject.instance()
2026-04-22 14:53:45 +02:00
# Flurstücks-Layer ins Projekt (sofern neu geladen)
if flst_layer and flst_layer.isValid():
existing_flst = project.mapLayersByName(flst_layer.name())
if not existing_flst:
project.addMapLayer(flst_layer)
apply_style(flst_layer, "GIS_Flst_Beschriftung_ALKIS_NAS.qml")
self.setze_haken(self.haken_flurst, True)
2025-11-18 16:10:58 +01:00
# BROR-Layer: QML-Stil anwenden
2026-04-23 22:24:14 +02:00
if bror_layer and bror_layer.isValid():
apply_style(bror_layer, "BauRaumOderBodenordnungsrecht.qml")
2026-04-23 22:24:14 +02:00
# Enriched VG-Layer ins Projekt (ggf. bereits registriert, z.B. bei "als VG laden")
if not project.mapLayer(enriched_layer.id()):
project.addMapLayer(enriched_layer)
2026-04-22 14:53:45 +02:00
apply_style(enriched_layer, "verfahrensgebiet.qml")
iface.mapCanvas().setExtent(enriched_layer.extent())
iface.mapCanvas().refresh()
self.setze_haken(self.haken_verf, True)
2026-04-22 14:53:45 +02:00
self.verf_layer_combo.setLayer(enriched_layer)
self._on_verf_layer_changed(enriched_layer)
2025-11-18 16:10:58 +01:00
2026-04-22 14:53:45 +02:00
msg = "erstmalig geladen" if status == LoadStatus.FIRST else "neu geladen"
success("Verfahrensgebiet", f"Layer wurde {msg} (inkl. Flurstücksverschneidung).", duration=5)
2025-11-18 16:10:58 +01:00
finally:
2026-04-21 21:50:26 +02:00
self._set_busy(self.btn_verf_alkis, False, "Aus ALKIS laden")
2025-11-18 16:10:58 +01:00
2026-04-21 21:50:26 +02:00
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.
"""
2025-11-18 16:10:58 +01:00
button.setEnabled(not busy)
2026-04-21 21:50:26 +02:00
button.setText("Lade ..." if busy else original_text)
2025-11-18 16:10:58 +01:00
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
2026-04-21 21:50:26 +02:00
# ------------------------------------------------------------------
# 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")
2026-06-23 12:57:35 +02:00
# ------------------------------------------------------------------
# Gemarkungen-Handler
# ------------------------------------------------------------------
def handle_gem_alkis(self) -> None:
"""Lädt den KatasterBezirk-Layer aus dem vereinfachten ALKIS-WFS
als Layer „Gemarkungen" ins Projekt.
Ist ein Layer namens „Gemarkungen" bereits vorhanden, wird er behalten
und eine Info-Meldung angezeigt (kein doppeltes Laden).
"""
self._set_busy(self.btn_gem_alkis, True, "Aus ALKIS laden")
try:
existing = QgsProject.instance().mapLayersByName("Gemarkungen")
if existing:
self.setze_haken(self.haken_gem, True)
info("Gemarkungen", "Layer 'Gemarkungen' ist bereits im Projekt vorhanden.", duration=4)
return
layer = lade_gemarkungen_layer()
if not layer:
warning(
"Gemarkungen",
"Layer konnte nicht geladen werden – Dienst nicht erreichbar oder ungültig.",
duration=6,
)
return
QgsProject.instance().addMapLayer(layer)
apply_style(layer, "gemarkungen_beschriftet.qml")
self.setze_haken(self.haken_gem, True)
success("Gemarkungen", "Layer 'Gemarkungen' wurde geladen.", duration=4)
finally:
self._set_busy(self.btn_gem_alkis, False, "Aus ALKIS laden")
2026-04-21 21:50:26 +02:00
# ------------------------------------------------------------------
# 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,
)
2026-04-22 14:53:45 +02:00
# ------------------------------------------------------------------
# Grenzpunkt-Handler
# ------------------------------------------------------------------
def handle_grenz_alkis(self) -> None:
"""Lädt Grenzpunkte gemarkungsweise aus ALKIS.
2026-04-22 14:53:45 +02:00
Verwendet denselben Gemarkungsfilter wie "Verfahrensgebiet aus ALKIS laden":
Die Gemarkungsschlüssel werden per Spatial-Join aus der Geometrie des
aktuell gewählten Verfahrensgebiet-Layers abgeleitet.
2026-04-22 14:53:45 +02:00
"""
# ------------------------------------------------------------------ #
# Schritt 0: Fortschrittsdialog sofort anzeigen #
# ------------------------------------------------------------------ #
# 4 Vorbereitungsschritte (Geometrie, Gemarkungen, Hits, Laden) –
# die genaue Schrittzahl wird in grenzpunkte_gemarkungsweise verfeinert.
prog = create_progress_dialog(
4, "Grenzpunkte aus ALKIS laden", "Verfahrensgebiet prüfen …"
)
prog.set_value(0)
# Verfahrensgebiet-Layer aus dem Dropdown holen
vg_layer = self.verf_layer_combo.currentLayer()
if not vg_layer or not vg_layer.isValid():
prog.close()
warning(
"Grenzpunkte",
"Kein Verfahrensgebiet-Layer gewählt. Bitte zuerst ein Verfahrensgebiet laden.",
duration=6,
)
return
# Geometrie des ersten Features als Suchgeometrie
feats = list(vg_layer.getFeatures())
if not feats:
prog.close()
warning("Grenzpunkte", "Verfahrensgebiet-Layer enthält keine Features.", duration=5)
return
# Geometrie über alle Features vereinen
from qgis.core import QgsGeometry # type: ignore[import]
vg_geom = QgsGeometry.unaryUnion([f.geometry() for f in feats if f.hasGeometry()])
if not vg_geom or vg_geom.isEmpty():
prog.close()
warning("Grenzpunkte", "Verfahrensgebiet-Layer hat keine Geometrie.", duration=5)
return
prog.set_label("Gemarkungsschlüssel per WFS ermitteln …")
prog.set_value(1)
if prog.is_canceled():
return
# Gemarkungsschlüssel per Spatial-Join ermitteln (identisch zu VG-Workflow)
schluessel_namen = gemarkung_schluessel_und_namen_von_vg_geometrie(vg_geom)
schluessel_liste = [nr for nr, _ in schluessel_namen]
if not schluessel_liste:
prog.close()
warning(
"Grenzpunkte",
"Keine Gemarkungen für das Verfahrensgebiet gefunden. "
"Bitte Netzwerkverbindung prüfen.",
duration=6,
)
return
prog.set_label(f"{len(schluessel_liste)} Gemarkung(en) gefunden – Grenzpunkte laden …")
prog.set_value(2)
if prog.is_canceled():
return
self._set_busy(self.btn_grenz_alkis, True, "Grenzpunkte aus ALKIS laden")
prog.close() # Vorbereitungs-Dialog schließen; grenzpunkte_gemarkungsweise öffnet eigenen
try:
joined_layer = grenzpunkte_gemarkungsweise(self, schluessel_liste, vg_geom=vg_geom)
if joined_layer and joined_layer.isValid():
iface.mapCanvas().refresh()
self.setze_haken(self.haken_grenz, True)
2026-05-06 11:43:44 +02:00
QMessageBox.information(
self,
"Grenzpunkte geladen",
f"Grenzpunkte erfolgreich geladen ({joined_layer.featureCount()} Objekte).",
2026-05-06 11:43:44 +02:00
)
elif joined_layer is None:
error(
"Grenzpunkte",
"Laden fehlgeschlagen – WFS- oder Netzwerkfehler. "
"Details unter Ansicht -> Bedienfelder -> Protokollnachrichten "
"(Kategorie 'sn_verfahrensgebiet'). "
"Bitte prüfen Sie ggf. die Proxy-Einstellungen.",
duration=0,
)
finally:
self._set_busy(self.btn_grenz_alkis, False, "Grenzpunkte aus ALKIS laden")
2026-04-23 22:24:14 +02:00
2026-05-05 21:17:19 +02:00
def handle_umringstatistik(self) -> None:
"""Klassifiziert Grenzpunkte auf dem VG-Umring nach Lagegenauigkeit.
Sucht den vorhandenen ``Grenzpunkte (ALKIS)``-Layer im Projekt und
kombiniert ihn mit dem gewählten Verfahrensgebiet-Layer, um die
Umringstatistik zu berechnen.
"""
# 1. Grenzpunkte-Layer aus dem Projekt holen
project = QgsProject.instance()
gp_layers = project.mapLayersByName(JOINED_LAYER_NAME)
if not gp_layers:
warning(
"Umringstatistik",
f"Kein Layer '{JOINED_LAYER_NAME}' im Projekt gefunden. "
"Bitte zuerst 'Grenzpunkte aus ALKIS laden' ausführen.",
duration=8,
)
return
grenzpunkte_layer = gp_layers[0]
# 2. Verfahrensgebiet-Layer aus Dropdown
vg_layer = self.verf_layer_combo.currentLayer()
if not vg_layer or not vg_layer.isValid():
warning(
"Umringstatistik",
"Kein Verfahrensgebiet-Layer gewählt. Bitte zuerst ein Verfahrensgebiet laden.",
duration=6,
)
return
self._set_busy(self.btn_umring_statistik, True, "Umringstatistik Grenzpunkte")
try:
result_layer = umringstatistik_grenzpunkte(self, grenzpunkte_layer, vg_layer)
if result_layer and result_layer.isValid():
iface.mapCanvas().refresh()
finally:
self._set_busy(self.btn_umring_statistik, False, "Umringstatistik Grenzpunkte")
2026-04-23 22:24:14 +02:00
# ---------------------------------------------------------------------------
# Modul-Hilfsfunktionen
# ---------------------------------------------------------------------------