BROR-Mehrfachauswahl, zweistufiger Fortschrittsdialog, Landkreis-Fallback

- Fortschrittsdialog beim Laden aus ALKIS schließt jetzt zuverlässig bei
  jedem Abbruch (progress.close() zentral im finally-Block).
- Fortschrittsanzeige in zwei Dialoge aufgeteilt: Suche (1 Schritt) läuft
  und schließt separat, bevor der eigentliche Workflow (Gemarkung/
  Flurstücke/Vergleich, 6 Schritte) startet – auch während des BROR-
  Auswahldialogs läuft kein störender Hintergrund-Fortschrittsbalken mehr.
- verfahrensgebiet_alkis() in Suche-/Auswahl-Phasen aufgeteilt, damit
  mehrere gefundene BauRaumOderBodenordnungsrecht-Objekte gemeinsam
  ausgewählt und verschmolzen werden können (öffentliche Signatur
  unverändert).
- Neu: Landkreis-weite Suche als Fallback, wenn keine Verfahrensnummer
  gesetzt ist (Landkreiskennzahl aus Projektvariable), mit Mehrfach-
  auswahl/"Alle auswählen" und "Nur laden"-Option (überspringt den
  restlichen Workflow). Gruppierung der Auswahl nach VKZ, damit je
  Verfahren ein eigenes Feature entsteht statt eines Gesamt-Blobs.
- Tests entsprechend angepasst/ergänzt (29 Tests in
  test_verfahrensgebiet_alkis_komplett.py, davon 3 neu für den
  Landkreis-Fallback).
This commit is contained in:
Michael Otto
2026-08-27 15:14:07 +02:00
parent 2cf0cda199
commit 148d4dfa15
5 changed files with 457 additions and 97 deletions
+120 -45
View File
@@ -54,7 +54,10 @@ from sn_basis.functions.dialog_wrapper import (
)
from sn_verfahrensgebiet.functions.verfahrensgebiet_alkis import (
verfahrensgebiet_alkis,
_suche_verfahrensgebiet_features,
_baue_layer_aus_kombinationen,
_suche_landkreis_kombinationen,
_baue_layer_aus_landkreis_auswahl,
LoadStatus,
)
from sn_verfahrensgebiet.functions.gemarkung_alkis import (
@@ -258,15 +261,25 @@ def verfahrensgebiet_alkis_komplett(
"""Vollständiger VG-Lade-Workflow: ALKIS-VG → Gemarkungen →
Flurstücke → Verschneidung → Flächenvergleich → opt. Umringsprüfung.
Schrittfolge:
Zwei Fortschrittsdialoge nacheinander:
1. ``verfahrensgebiet_alkis(tab_widget)`` – BROR-Objekt als Memory-Layer.
2. ``gemarkung_schluessel_und_namen_von_vg_geometrie(geom)`` – Schlüssel.
3. ``flurstueck_alkis(...)`` – Flurstücke laden.
4. ``_select_by_location(...)`` – räumliche Selektion.
5. ``erstelle_verfahrensgebiet_aus_auswahl(...)`` – enriched Layer.
6. ``_vergleiche_flaechen(...)`` – Flächenvergleich als Gate.
7. Ggf. ``umringspruefung(...)`` nach Nutzerbestätigung.
- **Dialog 1** ("Verfahrensgebiet(e) in ALKIS ermitteln/suchen"): läuft
während ``_suche_verfahrensgebiet_features(tab_widget)`` (ALKIS-WFS
durchsuchen) und wird danach immer geschlossen – auch wenn anschließend
der BROR-Auswahldialog erscheint (kein Fortschrittsdialog läuft
währenddessen parallel zum Auswahldialog).
- **Dialog 2** (eigentlicher Workflow, 6 Schritte): startet erst, nachdem
das Verfahrensgebiet feststeht (direkt nach Dialog 1 bei eindeutigem
Treffer/KEEP, oder erst nach Bestätigung des Auswahldialogs mit OK).
Schrittfolge in Dialog 2:
1. ``gemarkung_schluessel_und_namen_von_vg_geometrie(geom)`` – Schlüssel.
2. ``flurstueck_alkis(...)`` – Flurstücke laden.
3. ``_select_by_location(...)`` – räumliche Selektion.
4. ``erstelle_verfahrensgebiet_aus_auswahl(...)`` – enriched Layer.
5. ``_vergleiche_flaechen(...)`` – Flächenvergleich als Gate.
6. Ggf. ``umringspruefung(...)`` nach Nutzerbestätigung.
Der BROR-Layer (``BauRaumOderBodenordnungsrecht (ALKIS)``) bleibt bei Erfolg
im Projekt. Bei Abbruch/Fehler wird er entfernt, falls er in diesem
@@ -290,26 +303,74 @@ def verfahrensgebiet_alkis_komplett(
alkis_vg_layer = None
bror_was_added_by_us = False
abgeschlossen = False
progress = None
# Fortschrittsdialog für den Basisworkflow (7 Schritte)
progress = create_progress_dialog(
7, "Verfahrensgebiet laden", "Initialisierung …"
)
verfahrensnummer = get_variable("verfahrensnummer")
landkreis_kennzahl = get_variable("landkreis_kennzahl")
if not verfahrensnummer and not landkreis_kennzahl:
QMessageBox.critical(
tab_widget,
"Fehler",
"Weder eine Verfahrensnummer noch ein Landkreis ist in den "
"Projekteigenschaften eingetragen!",
)
return None, None, None, LoadStatus.NONE
landkreis_modus = not verfahrensnummer
# ------------------------------------------------------------------
# Dialog 1: Verfahrensgebiet(e) in ALKIS ermitteln/suchen
# ------------------------------------------------------------------
if landkreis_modus:
such_label = f"Objekte in Landkreis {landkreis_kennzahl} ermitteln/suchen …"
else:
such_label = "Verfahrensgebiet(e) in ALKIS ermitteln/suchen …"
progress_suche = create_progress_dialog(1, "Verfahrensgebiet laden", such_label)
try:
progress_suche.set_value(0)
if progress_suche.is_canceled():
return None, None, None, LoadStatus.NONE
if landkreis_modus:
vorab_layer, vg_status, kombinationen, crs = _suche_landkreis_kombinationen(
tab_widget, landkreis_kennzahl
)
else:
vorab_layer, vg_status, kombinationen, crs = _suche_verfahrensgebiet_features(tab_widget)
finally:
# Dialog 1 schließt hier immer – egal ob eine Auswahl folgt oder nicht.
progress_suche.close()
nur_laden = False
try:
# ------------------------------------------------------------------
# Schritt 1: VG aus ALKIS laden (BROR-Objekt → Memory-Layer)
# ------------------------------------------------------------------
progress.set_label("Schritt 1/6: Verfahrensgebiet aus ALKIS laden …")
progress.set_value(0)
if progress.is_canceled():
return None, None, None, LoadStatus.NONE
alkis_vg_layer, vg_status, _ = verfahrensgebiet_alkis(tab_widget)
progress.raise_to_front()
if vg_status == LoadStatus.NONE or not alkis_vg_layer:
return None, None, None, LoadStatus.NONE
if vorab_layer is not None or not kombinationen:
# KEEP oder Fehler/Abbruch bereits in Phase 1 entschieden
if vg_status == LoadStatus.NONE or not vorab_layer:
return None, None, None, LoadStatus.NONE
alkis_vg_layer = vorab_layer
elif landkreis_modus:
# ------------------------------------------------------------------
# Objekt(e) des Landkreises auswählen – kein eigener Fortschritts-
# dialog währenddessen, nur der Auswahldialog selbst.
# ------------------------------------------------------------------
alkis_vg_layer, vg_status, nur_laden = _baue_layer_aus_landkreis_auswahl(
tab_widget, kombinationen, crs, vg_status
)
if vg_status == LoadStatus.NONE or not alkis_vg_layer:
return None, None, None, LoadStatus.NONE
else:
# ------------------------------------------------------------------
# Verfahrensgebiet auswählen (bei mehreren Treffern) – kein eigener
# Fortschrittsdialog währenddessen, nur der Auswahldialog selbst.
# ------------------------------------------------------------------
alkis_vg_layer, vg_status, _ = _baue_layer_aus_kombinationen(
tab_widget, kombinationen, crs, vg_status
)
if vg_status == LoadStatus.NONE or not alkis_vg_layer:
return None, None, None, LoadStatus.NONE
# BROR-Layer umbenennen, um Namenskonflikt mit enriched VG-Layer zu vermeiden
alkis_vg_layer.setName(BROR_LAYER_NAME)
@@ -318,12 +379,25 @@ def verfahrensgebiet_alkis_komplett(
project.addMapLayer(alkis_vg_layer)
bror_was_added_by_us = True
progress.set_value(1)
if nur_laden:
# Nutzer hat "Nur laden" angehakt – kein Dialog 2, kein weiterer
# Workflow (Gemarkung/Flurstücke/Vergleich).
abgeschlossen = True
return alkis_vg_layer, None, None, vg_status
# ------------------------------------------------------------------
# Schritt 2: Gemarkungsschlüssel per Geometrie-Spatial-Join ermitteln
# Dialog 2: eigentlicher Fortschrittsdialog für die restlichen Schritte
# (startet erst jetzt, nach erfolgreicher Auswahl/Übernahme des VG)
# ------------------------------------------------------------------
progress.set_label("Schritt 2/6: Gemarkungsschlüssel ermitteln …")
progress = create_progress_dialog(
6, "Verfahrensgebiet laden", "Initialisierung …"
)
# ------------------------------------------------------------------
# Schritt 1: Gemarkungsschlüssel per Geometrie-Spatial-Join ermitteln
# ------------------------------------------------------------------
progress.set_label("Schritt 1/6: Gemarkungen ermitteln und laden …")
progress.set_value(0)
if progress.is_canceled():
return None, None, None, LoadStatus.NONE
@@ -344,12 +418,12 @@ def verfahrensgebiet_alkis_komplett(
duration=5,
)
progress.set_value(2)
progress.set_value(1)
# ------------------------------------------------------------------
# Schritt 3: Flurstücke laden (mit Nutzer-Dialog, Vorschlag befüllt)
# Schritt 2: Flurstücke laden (mit Nutzer-Dialog, Vorschlag befüllt)
# ------------------------------------------------------------------
progress.set_label("Schritt 3/6: Flurstücke aus ALKIS laden …")
progress.set_label("Schritt 2/6: Flurstücke aus ALKIS laden …")
if progress.is_canceled():
return None, None, None, LoadStatus.NONE
@@ -363,12 +437,12 @@ def verfahrensgebiet_alkis_komplett(
if flst_status == LoadStatus.NONE or not flst_layer:
return None, None, None, LoadStatus.NONE
progress.set_value(3)
progress.set_value(2)
# ------------------------------------------------------------------
# Schritt 4: Räumliche Selektion
# Schritt 3: Räumliche Selektion
# ------------------------------------------------------------------
progress.set_label("Schritt 4/6: Flurstücke räumlich selektieren …")
progress.set_label("Schritt 3/6: Flurstücke räumlich selektieren …")
if progress.is_canceled():
return None, None, None, LoadStatus.NONE
@@ -383,12 +457,12 @@ def verfahrensgebiet_alkis_komplett(
)
return None, flst_layer, None, LoadStatus.NONE
progress.set_value(4)
progress.set_value(3)
# ------------------------------------------------------------------
# Schritt 5: Enriched Memory-Layer aus Auswahl erzeugen
# Schritt 4: Enriched Memory-Layer aus Auswahl erzeugen
# ------------------------------------------------------------------
progress.set_label("Schritt 5/6: Verfahrensgebiet-Layer erzeugen …")
progress.set_label("Schritt 4/6: Verfahrensgebiet-Layer erzeugen …")
if progress.is_canceled():
return None, None, None, LoadStatus.NONE
@@ -407,12 +481,12 @@ def verfahrensgebiet_alkis_komplett(
vkz = get_variable("verfahrensnummer") or ""
_fuege_vkz_feld_hinzu(enriched_layer, vkz)
progress.set_value(5)
progress.set_value(4)
# ------------------------------------------------------------------
# Schritt 6: Flächenvergleich als Gate
# Schritt 5: Flächenvergleich als Gate
# ------------------------------------------------------------------
progress.set_label("Schritt 6/6: Flächenvergleich …")
progress.set_label("Schritt 5/6: Flächenvergleich …")
if progress.is_canceled():
return None, None, None, LoadStatus.NONE
@@ -421,11 +495,10 @@ def verfahrensgebiet_alkis_komplett(
alkis_vg_layer, enriched_layer, toleranz
)
progress.set_value(6)
progress.set_value(5)
if stimmt_ueberein:
progress.set_value(7)
progress.close()
progress.set_value(6)
show_info_dialog(
"Flächenvergleich",
"Verfahrensgebiet mit erwarteter Geometrie erzeugt",
@@ -437,7 +510,6 @@ def verfahrensgebiet_alkis_komplett(
# ------------------------------------------------------------------
# Flächenabweichung → 3-Optionen-Dialog
# ------------------------------------------------------------------
progress.close()
diff = abs(bror_flaeche - vg_flaeche)
entscheidung = ask_detailpruefung_oder_vg_laden(
tab_widget,
@@ -563,6 +635,9 @@ def verfahrensgebiet_alkis_komplett(
return enriched_layer, flst_layer, alkis_vg_layer, vg_status
finally:
# Dialog 2 (falls erstellt) bei jedem Ausgang (Erfolg, Abbruch, Fehler) schließen
if progress is not None:
progress.close()
# WFS-Temp-Layer stets aus dem Projekt entfernen
_entferne_hilfs_layer(project, "TempVerfahrensgebiet")
# BROR-Layer bei Fehler/Abbruch entfernen (nur wenn in diesem Lauf hinzugefügt)