Compare commits
4
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0a906d3ac7 | ||
|
|
39f8209b9d | ||
|
|
3c0e6e5a19 | ||
|
|
c93776d19e |
@@ -261,12 +261,12 @@ def _baue_layer_aus_landkreis_auswahl(tab_widget, kombinationen: dict, crs: str,
|
|||||||
"""Auswahl + Bau für den Landkreis-Fallback.
|
"""Auswahl + Bau für den Landkreis-Fallback.
|
||||||
|
|
||||||
Zeigt :func:`~sn_verfahrensgebiet.functions.verfahrensgebiet_dialoge.ask_landkreis_objekte`
|
Zeigt :func:`~sn_verfahrensgebiet.functions.verfahrensgebiet_dialoge.ask_landkreis_objekte`
|
||||||
(Mehrfachauswahl inkl. "Alle auswählen" und "Nur laden"-Checkbox). Die
|
(Mehrfachauswahl inkl. "Alle auswählen"). Die ausgewählten Kombinationen
|
||||||
ausgewählten Kombinationen werden anhand der ersten 5 Zeichen von
|
werden anhand der ersten 5 Zeichen von ``bezeichnung`` (= die eigentliche
|
||||||
``bezeichnung`` (= die eigentliche VKZ) gruppiert; je Gruppe wird EIN
|
VKZ) gruppiert; je Gruppe wird EIN Feature erzeugt (Geometrien der
|
||||||
Feature erzeugt (Geometrien der Gruppe verschmolzen). Damit entsteht bei
|
Gruppe verschmolzen). Damit entsteht bei Auswahl mehrerer/aller Objekte
|
||||||
Auswahl mehrerer/aller Objekte eines Landkreises ein Layer mit mehreren
|
eines Landkreises ein Layer mit mehreren Features – einem je
|
||||||
Features – einem je tatsächlichem Verfahren, nicht ein Gesamt-Blob.
|
tatsächlichem Verfahren, nicht ein Gesamt-Blob.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
tab_widget: Parent-Widget für Dialoge und Meldungen
|
tab_widget: Parent-Widget für Dialoge und Meldungen
|
||||||
@@ -275,13 +275,12 @@ def _baue_layer_aus_landkreis_auswahl(tab_widget, kombinationen: dict, crs: str,
|
|||||||
status: Lade-Status aus Phase 1 (FIRST/RELOAD), wird durchgereicht
|
status: Lade-Status aus Phase 1 (FIRST/RELOAD), wird durchgereicht
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Tuple[Optional[QgsVectorLayer], LoadStatus, bool]:
|
Tuple[Optional[QgsVectorLayer], LoadStatus]: ``(layer, status)``.
|
||||||
``(layer, status, nur_laden)``.
|
|
||||||
"""
|
"""
|
||||||
key_list = sorted(kombinationen.keys())
|
key_list = sorted(kombinationen.keys())
|
||||||
selected_keys, nur_laden = ask_landkreis_objekte(tab_widget, key_list)
|
selected_keys = ask_landkreis_objekte(tab_widget, key_list)
|
||||||
if not selected_keys:
|
if not selected_keys:
|
||||||
return None, LoadStatus.NONE, False
|
return None, LoadStatus.NONE
|
||||||
|
|
||||||
# Nach VKZ (erste 5 Zeichen der bezeichnung) gruppieren
|
# Nach VKZ (erste 5 Zeichen der bezeichnung) gruppieren
|
||||||
vkz_gruppen: dict[str, list] = {}
|
vkz_gruppen: dict[str, list] = {}
|
||||||
@@ -322,12 +321,12 @@ def _baue_layer_aus_landkreis_auswahl(tab_widget, kombinationen: dict, crs: str,
|
|||||||
|
|
||||||
if not neue_features:
|
if not neue_features:
|
||||||
QMessageBox.critical(tab_widget, "Fehler", "Keine Geometrien zum Verschmelzen gefunden.")
|
QMessageBox.critical(tab_widget, "Fehler", "Keine Geometrien zum Verschmelzen gefunden.")
|
||||||
return None, LoadStatus.NONE, False
|
return None, LoadStatus.NONE
|
||||||
|
|
||||||
pr.addFeatures(neue_features)
|
pr.addFeatures(neue_features)
|
||||||
memory_layer.updateExtents()
|
memory_layer.updateExtents()
|
||||||
|
|
||||||
return memory_layer, status, nur_laden
|
return memory_layer, status
|
||||||
|
|
||||||
|
|
||||||
def verfahrensgebiet_alkis(tab_widget, skip_existing_check: bool = False):
|
def verfahrensgebiet_alkis(tab_widget, skip_existing_check: bool = False):
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ from sn_basis.functions.dialog_wrapper import (
|
|||||||
create_progress_dialog,
|
create_progress_dialog,
|
||||||
show_info_dialog,
|
show_info_dialog,
|
||||||
ask_detailpruefung_oder_vg_laden,
|
ask_detailpruefung_oder_vg_laden,
|
||||||
|
ask_yes_no,
|
||||||
)
|
)
|
||||||
from sn_basis.functions.landkreise import LANDKREISE, ALLE_LANDKREISE
|
from sn_basis.functions.landkreise import LANDKREISE, ALLE_LANDKREISE
|
||||||
from sn_basis.functions.ly_style_wrapper import apply_style
|
from sn_basis.functions.ly_style_wrapper import apply_style
|
||||||
@@ -273,9 +274,13 @@ def verfahrensgebiet_alkis_komplett(
|
|||||||
durchsuchen) und wird danach immer geschlossen – auch wenn anschließend
|
durchsuchen) und wird danach immer geschlossen – auch wenn anschließend
|
||||||
der BROR-Auswahldialog erscheint (kein Fortschrittsdialog läuft
|
der BROR-Auswahldialog erscheint (kein Fortschrittsdialog läuft
|
||||||
währenddessen parallel zum Auswahldialog).
|
währenddessen parallel zum Auswahldialog).
|
||||||
|
- **STOP** (Zwischenabfrage "Weiter?"): erscheint nach dem Laden/Übernehmen
|
||||||
|
des BROR-Objekts, bevor Dialog 2 startet. Bei "Nein" bricht der Ablauf
|
||||||
|
ab, das BROR-Objekt bleibt aber im Projekt (ersetzt die frühere
|
||||||
|
"Nur Objekte laden"-Option des Landkreis-Auswahldialogs).
|
||||||
- **Dialog 2** (eigentlicher Workflow, 6 Schritte): startet erst, nachdem
|
- **Dialog 2** (eigentlicher Workflow, 6 Schritte): startet erst, nachdem
|
||||||
das Verfahrensgebiet feststeht (direkt nach Dialog 1 bei eindeutigem
|
das Verfahrensgebiet feststeht und die Stop-Abfrage mit "Ja" bestätigt
|
||||||
Treffer/KEEP, oder erst nach Bestätigung des Auswahldialogs mit OK).
|
wurde.
|
||||||
|
|
||||||
Schrittfolge in Dialog 2:
|
Schrittfolge in Dialog 2:
|
||||||
|
|
||||||
@@ -351,8 +356,6 @@ def verfahrensgebiet_alkis_komplett(
|
|||||||
# Dialog 1 schließt hier immer – egal ob eine Auswahl folgt oder nicht.
|
# Dialog 1 schließt hier immer – egal ob eine Auswahl folgt oder nicht.
|
||||||
progress_suche.close()
|
progress_suche.close()
|
||||||
|
|
||||||
nur_laden = False
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if vorab_layer is not None or not kombinationen:
|
if vorab_layer is not None or not kombinationen:
|
||||||
# KEEP oder Fehler/Abbruch bereits in Phase 1 entschieden
|
# KEEP oder Fehler/Abbruch bereits in Phase 1 entschieden
|
||||||
@@ -364,7 +367,7 @@ def verfahrensgebiet_alkis_komplett(
|
|||||||
# Objekt(e) des Landkreises auswählen – kein eigener Fortschritts-
|
# Objekt(e) des Landkreises auswählen – kein eigener Fortschritts-
|
||||||
# dialog währenddessen, nur der Auswahldialog selbst.
|
# dialog währenddessen, nur der Auswahldialog selbst.
|
||||||
# ------------------------------------------------------------------
|
# ------------------------------------------------------------------
|
||||||
alkis_vg_layer, vg_status, nur_laden = _baue_layer_aus_landkreis_auswahl(
|
alkis_vg_layer, vg_status = _baue_layer_aus_landkreis_auswahl(
|
||||||
tab_widget, kombinationen, crs, vg_status
|
tab_widget, kombinationen, crs, vg_status
|
||||||
)
|
)
|
||||||
if vg_status == LoadStatus.NONE or not alkis_vg_layer:
|
if vg_status == LoadStatus.NONE or not alkis_vg_layer:
|
||||||
@@ -387,12 +390,21 @@ def verfahrensgebiet_alkis_komplett(
|
|||||||
project.addMapLayer(alkis_vg_layer)
|
project.addMapLayer(alkis_vg_layer)
|
||||||
bror_was_added_by_us = True
|
bror_was_added_by_us = True
|
||||||
# Style direkt nach dem Laden anwenden – unabhängig vom weiteren
|
# Style direkt nach dem Laden anwenden – unabhängig vom weiteren
|
||||||
# Ablauf, damit auch "Nur Objekte laden" den Style erhält.
|
# Ablauf, damit auch bei "Nein" auf die Stop-Abfrage der Style
|
||||||
|
# gesetzt ist.
|
||||||
apply_style(alkis_vg_layer, BROR_STYLE_QML)
|
apply_style(alkis_vg_layer, BROR_STYLE_QML)
|
||||||
|
|
||||||
if nur_laden:
|
# ------------------------------------------------------------------
|
||||||
# Nutzer hat "Nur laden" angehakt – kein Dialog 2, kein weiterer
|
# STOP: Zwischenabfrage nach dem Laden des BROR-Objekts, bevor mit
|
||||||
# Workflow (Gemarkung/Flurstücke/Vergleich).
|
# Gemarkung/Flurstücke/Flächenvergleich fortgefahren wird (ersetzt
|
||||||
|
# die frühere "Nur Objekte laden"-Option).
|
||||||
|
# ------------------------------------------------------------------
|
||||||
|
if not ask_yes_no(
|
||||||
|
"Verfahrensgebiet laden",
|
||||||
|
f"Layer '{alkis_vg_layer.name()}' wurde geladen. Weiter?",
|
||||||
|
default=True,
|
||||||
|
parent=tab_widget,
|
||||||
|
):
|
||||||
abgeschlossen = True
|
abgeschlossen = True
|
||||||
return alkis_vg_layer, None, None, vg_status
|
return alkis_vg_layer, None, None, vg_status
|
||||||
|
|
||||||
|
|||||||
@@ -101,15 +101,15 @@ def ask_bror_kombinationen(
|
|||||||
def ask_landkreis_objekte(
|
def ask_landkreis_objekte(
|
||||||
parent: Any,
|
parent: Any,
|
||||||
kombinationen: list[tuple[str, str]],
|
kombinationen: list[tuple[str, str]],
|
||||||
) -> tuple[list[tuple[str, str]], bool]:
|
) -> list[tuple[str, str]]:
|
||||||
"""Zeigt Dialog zur Auswahl eines, mehrerer oder aller BROR-Objekte eines
|
"""Zeigt Dialog zur Auswahl eines, mehrerer oder aller BROR-Objekte eines
|
||||||
Landkreises (Fallback, wenn keine Verfahrensnummer gesetzt ist).
|
Landkreises (Fallback, wenn keine Verfahrensnummer gesetzt ist).
|
||||||
|
|
||||||
Wie :func:`ask_bror_kombinationen`, zusätzlich mit einer "Alle
|
Wie :func:`ask_bror_kombinationen`, zusätzlich mit einer "Alle
|
||||||
auswählen"-Checkbox (da hier potenziell deutlich mehr Treffer als bei der
|
auswählen"-Checkbox (da hier potenziell deutlich mehr Treffer als bei der
|
||||||
VKZ-Suche auftreten) und einer "Nur laden"-Checkbox, mit der gesteuert
|
VKZ-Suche auftreten). Ob nach dem Laden der weitere Workflow
|
||||||
wird, ob nach dem Laden der weitere Workflow (Gemarkung/Flurstücke/
|
(Gemarkung/Flurstücke/Flächenvergleich) fortgesetzt wird, klärt eine
|
||||||
Flächenvergleich) fortgesetzt werden soll.
|
separate Stop-Abfrage nach dem Laden – nicht mehr dieser Dialog.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
@@ -120,16 +120,16 @@ def ask_landkreis_objekte(
|
|||||||
|
|
||||||
Returns
|
Returns
|
||||||
-------
|
-------
|
||||||
tuple[list[tuple[str, str]], bool]
|
list[tuple[str, str]]
|
||||||
``(ausgewaehlte_kombinationen, nur_laden)``. ``([], False)`` bei
|
Die gewählten ``(adv_name, bezeichnung)``-Tupel. Leere Liste bei
|
||||||
Abbruch oder wenn nichts ausgewählt wurde.
|
Abbruch oder wenn nichts ausgewählt wurde.
|
||||||
"""
|
"""
|
||||||
if not kombinationen:
|
if not kombinationen:
|
||||||
return [], False
|
return []
|
||||||
|
|
||||||
if QT_VERSION == 0: # Mock-Modus
|
if QT_VERSION == 0: # Mock-Modus
|
||||||
print(f"Mock-Modus: ask_landkreis_objekte → {kombinationen[:1]}")
|
print(f"Mock-Modus: ask_landkreis_objekte → {kombinationen[:1]}")
|
||||||
return kombinationen[:1], False
|
return kombinationen[:1]
|
||||||
|
|
||||||
dialog = QDialog(parent)
|
dialog = QDialog(parent)
|
||||||
dialog.setWindowTitle("Verfahrensgebiete aus Landkreis laden")
|
dialog.setWindowTitle("Verfahrensgebiete aus Landkreis laden")
|
||||||
@@ -204,9 +204,6 @@ def ask_landkreis_objekte(
|
|||||||
mehrfachauswahl_hinweis = QLabel("<small>Mehrfachauswahl mit Strg + Umschalt</small>")
|
mehrfachauswahl_hinweis = QLabel("<small>Mehrfachauswahl mit Strg + Umschalt</small>")
|
||||||
layout.addWidget(mehrfachauswahl_hinweis)
|
layout.addWidget(mehrfachauswahl_hinweis)
|
||||||
|
|
||||||
nur_laden_checkbox = QCheckBox("Nur Objekte laden (ohne weitere Prüfungen)")
|
|
||||||
layout.addWidget(nur_laden_checkbox)
|
|
||||||
|
|
||||||
buttons = QDialogButtonBox(QDialogButtonBox.StandardButton.Ok | QDialogButtonBox.StandardButton.Cancel)
|
buttons = QDialogButtonBox(QDialogButtonBox.StandardButton.Ok | QDialogButtonBox.StandardButton.Cancel)
|
||||||
buttons.accepted.connect(dialog.accept)
|
buttons.accepted.connect(dialog.accept)
|
||||||
buttons.rejected.connect(dialog.reject)
|
buttons.rejected.connect(dialog.reject)
|
||||||
@@ -235,11 +232,11 @@ def ask_landkreis_objekte(
|
|||||||
dialog.resize(breite, dialog.sizeHint().height())
|
dialog.resize(breite, dialog.sizeHint().height())
|
||||||
|
|
||||||
if exec_dialog(dialog) != DialogAccepted:
|
if exec_dialog(dialog) != DialogAccepted:
|
||||||
return [], False
|
return []
|
||||||
|
|
||||||
ausgewaehlte_zeilen = sorted(set(item.row() for item in table.selectedItems()))
|
ausgewaehlte_zeilen = sorted(set(item.row() for item in table.selectedItems()))
|
||||||
ausgewaehlt = [(table.item(row, 1).text(), table.item(row, 0).text()) for row in ausgewaehlte_zeilen]
|
ausgewaehlt = [(table.item(row, 1).text(), table.item(row, 0).text()) for row in ausgewaehlte_zeilen]
|
||||||
return ausgewaehlt, nur_laden_checkbox.isChecked()
|
return ausgewaehlt
|
||||||
|
|
||||||
|
|
||||||
def ask_landkreis_auswahl(
|
def ask_landkreis_auswahl(
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ oder kein Ergebnis liefert, bricht den Workflow ab.
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
import re
|
||||||
import shutil
|
import shutil
|
||||||
import tempfile
|
import tempfile
|
||||||
import zipfile
|
import zipfile
|
||||||
@@ -106,6 +107,57 @@ _GEBIETSTYP_LAYER_NAMEN = {
|
|||||||
# Interne Hilfsfunktionen
|
# Interne Hilfsfunktionen
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
def _normalisiere_feldname(name: str) -> str:
|
||||||
|
"""Normalisiert einen Feldnamen für den toleranten Vergleich.
|
||||||
|
|
||||||
|
Entfernt alle Zeichen außer Buchstaben/Ziffern (z.B. Punkte, Leerzeichen,
|
||||||
|
Unterstriche) und wandelt in Kleinbuchstaben um. Hintergrund: manche
|
||||||
|
Shape-Exporte liefern den Feldnamen ``FBSchl`` mit einem angehängten
|
||||||
|
Punkt (``FBSchl.``) oder abweichender Groß-/Kleinschreibung, wodurch ein
|
||||||
|
exakter Namensvergleich das Feld fälschlich als fehlend meldet (#44).
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
name :
|
||||||
|
Roher Feldname.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
str
|
||||||
|
Normalisierter Feldname (nur Kleinbuchstaben/Ziffern).
|
||||||
|
"""
|
||||||
|
return re.sub(r"[^a-zA-Z0-9]", "", name).lower()
|
||||||
|
|
||||||
|
|
||||||
|
def _finde_fbschl_index(raw_layer) -> int:
|
||||||
|
"""Sucht den Feldindex von ``FBSchl`` tolerant gegenüber Abweichungen im
|
||||||
|
Namen (Groß-/Kleinschreibung, angehängte Sonderzeichen wie ein Punkt).
|
||||||
|
|
||||||
|
Versucht zuerst den exakten Namen; schlägt das fehl, wird über alle
|
||||||
|
Felder mit normalisiertem Namensvergleich gesucht (siehe
|
||||||
|
:func:`_normalisiere_feldname`).
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
raw_layer :
|
||||||
|
Dateibasierter Shapefile-Layer.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
int
|
||||||
|
Feldindex, oder ``-1`` wenn kein passendes Feld gefunden wurde.
|
||||||
|
"""
|
||||||
|
idx = raw_layer.fields().indexFromName(FBSCHL_FELD)
|
||||||
|
if idx >= 0:
|
||||||
|
return idx
|
||||||
|
|
||||||
|
ziel = _normalisiere_feldname(FBSCHL_FELD)
|
||||||
|
for feld_idx, feld in enumerate(raw_layer.fields()):
|
||||||
|
if _normalisiere_feldname(feld.name()) == ziel:
|
||||||
|
return feld_idx
|
||||||
|
return -1
|
||||||
|
|
||||||
|
|
||||||
def _ermittle_gebietstyp_aus_fbschl(raw_layer) -> Tuple[Optional[str], Optional[str]]:
|
def _ermittle_gebietstyp_aus_fbschl(raw_layer) -> Tuple[Optional[str], Optional[str]]:
|
||||||
"""Prüft das Feld ``FBSchl`` und ermittelt den Gebietstyp.
|
"""Prüft das Feld ``FBSchl`` und ermittelt den Gebietstyp.
|
||||||
|
|
||||||
@@ -113,6 +165,10 @@ def _ermittle_gebietstyp_aus_fbschl(raw_layer) -> Tuple[Optional[str], Optional[
|
|||||||
zurück, damit der Aufrufer Fehler mehrerer Dateien sammeln und am Ende
|
zurück, damit der Aufrufer Fehler mehrerer Dateien sammeln und am Ende
|
||||||
gemeinsam anzeigen kann.
|
gemeinsam anzeigen kann.
|
||||||
|
|
||||||
|
Die Feldsuche ist tolerant gegenüber Abweichungen im Namen (z.B. ein
|
||||||
|
angehängter Punkt ``FBSchl.`` in manchen Shape-Exporten, siehe #44) –
|
||||||
|
siehe :func:`_finde_fbschl_index`.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
raw_layer :
|
raw_layer :
|
||||||
@@ -127,7 +183,7 @@ def _ermittle_gebietstyp_aus_fbschl(raw_layer) -> Tuple[Optional[str], Optional[
|
|||||||
``fehlertext`` beschreibt die Ursache (fehlendes Feld oder
|
``fehlertext`` beschreibt die Ursache (fehlendes Feld oder
|
||||||
unbekannter Wert).
|
unbekannter Wert).
|
||||||
"""
|
"""
|
||||||
idx = raw_layer.fields().indexFromName(FBSCHL_FELD)
|
idx = _finde_fbschl_index(raw_layer)
|
||||||
if idx < 0:
|
if idx < 0:
|
||||||
return None, f"Feld '{FBSCHL_FELD}' fehlt (Shape entspricht nicht dem erwarteten Inhalt)."
|
return None, f"Feld '{FBSCHL_FELD}' fehlt (Shape entspricht nicht dem erwarteten Inhalt)."
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user