Merge pull request 'Drei getrennte Flurstuecke-Ladelogiken auf eine konsolidiert (#47)' (#49) from bugfix/47-flurstuecke-ladelogik-konsolidieren into unstable
Reviewed-on: AG_QGIS/Plugin_SN_Verfahrensgebiet#49
This commit is contained in:
@@ -1,3 +1,4 @@
|
|||||||
|
- Intern: Der Button "aus gewählten Gemarkungen laden" nutzt jetzt dieselbe Ladelogik wie "Flurstücke laden" (flurstueck_alkis) statt einer eigenen, parallelen Implementierung – konsolidiert drei bisher getrennte Code-Pfade zum Flurstücke-Laden auf einen (#47)
|
||||||
- Bugfix: Flurstücke aus ALKIS an bestehenden Layer anhängen überspringt jetzt bereits vorhandene Flurstücke (Abgleich über flurstueckskennzeichen), statt sie doppelt zu laden – betrifft sowohl den Dialog in "Flurstücke laden" als auch den Button "aus gewählten Gemarkungen laden" (#28)
|
- Bugfix: Flurstücke aus ALKIS an bestehenden Layer anhängen überspringt jetzt bereits vorhandene Flurstücke (Abgleich über flurstueckskennzeichen), statt sie doppelt zu laden – betrifft sowohl den Dialog in "Flurstücke laden" als auch den Button "aus gewählten Gemarkungen laden" (#28)
|
||||||
- Fortschrittsdialog beim Laden aus ALKIS schließt jetzt zuverlässig bei jedem Abbruch (Bugfix)
|
- Fortschrittsdialog beim Laden aus ALKIS schließt jetzt zuverlässig bei jedem Abbruch (Bugfix)
|
||||||
- Fortschrittsanzeige beim Laden aus ALKIS in zwei Dialoge aufgeteilt (Suche / eigentlicher Ladevorgang), inkl. eigenem Suchschritt
|
- Fortschrittsanzeige beim Laden aus ALKIS in zwei Dialoge aufgeteilt (Suche / eigentlicher Ladevorgang), inkl. eigenem Suchschritt
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ def _check_existing_flurstueck_layer(tab_widget):
|
|||||||
return None, LoadStatus.NONE
|
return None, LoadStatus.NONE
|
||||||
|
|
||||||
|
|
||||||
def vorhandene_kennzeichen(layer) -> set:
|
def _vorhandene_kennzeichen(layer) -> set:
|
||||||
"""Liefert die ``flurstueckskennzeichen``-Werte, die ``layer`` bereits enthält.
|
"""Liefert die ``flurstueckskennzeichen``-Werte, die ``layer`` bereits enthält.
|
||||||
|
|
||||||
Fehlt das Feld, wird eine leere Menge zurückgegeben (kein Abgleich möglich).
|
Fehlt das Feld, wird eine leere Menge zurückgegeben (kein Abgleich möglich).
|
||||||
@@ -171,6 +171,7 @@ def flurstueck_alkis(
|
|||||||
vorgabe_namen: Optional[List[str]] = None,
|
vorgabe_namen: Optional[List[str]] = None,
|
||||||
bbox=None,
|
bbox=None,
|
||||||
ohne_dialog: bool = False,
|
ohne_dialog: bool = False,
|
||||||
|
ohne_schluessel_abfrage: bool = False,
|
||||||
) -> Tuple[Optional[QgsVectorLayer], LoadStatus]:
|
) -> Tuple[Optional[QgsVectorLayer], LoadStatus]:
|
||||||
"""Lädt Flurstücke aus dem ALKIS-WFS anhand von Gemarkungsschlüsseln.
|
"""Lädt Flurstücke aus dem ALKIS-WFS anhand von Gemarkungsschlüsseln.
|
||||||
|
|
||||||
@@ -184,17 +185,27 @@ def flurstueck_alkis(
|
|||||||
Eltern-Widget für Dialoge.
|
Eltern-Widget für Dialoge.
|
||||||
vorgabe_schluessel : list of str, optional
|
vorgabe_schluessel : list of str, optional
|
||||||
Vorausgefüllte Gemarkungsnummern (4-stellig). Im Dialog als Standard
|
Vorausgefüllte Gemarkungsnummern (4-stellig). Im Dialog als Standard
|
||||||
angezeigt; bei ``ohne_dialog=True`` direkt verwendet.
|
angezeigt; bei ``ohne_dialog=True`` oder ``ohne_schluessel_abfrage=True``
|
||||||
|
direkt verwendet.
|
||||||
vorgabe_namen : list of str, optional
|
vorgabe_namen : list of str, optional
|
||||||
Menschenlesbare Gemarkungsbezeichnungen für den Dialog-Hinweistext.
|
Menschenlesbare Gemarkungsbezeichnungen für den Dialog-Hinweistext.
|
||||||
bbox :
|
bbox :
|
||||||
Nicht mehr verwendet (WFS unterstützt keinen BBox-Filter). Bleibt
|
Nicht mehr verwendet (WFS unterstützt keinen BBox-Filter). Bleibt
|
||||||
für Rückwärtskompatibilität in der Signatur erhalten.
|
für Rückwärtskompatibilität in der Signatur erhalten.
|
||||||
ohne_dialog : bool, optional
|
ohne_dialog : bool, optional
|
||||||
``True``: Überspringt die Gemarkungsschlüssel-Nutzerabfrage und verwendet
|
``True``: Überspringt sowohl die Gemarkungsschlüssel-Nutzerabfrage (wie
|
||||||
``vorgabe_schluessel`` direkt. Vorhandene Layer werden ohne Rückfrage
|
``ohne_schluessel_abfrage``) als auch die Rückfrage bei einem bereits
|
||||||
ersetzt. Gedacht für die automatische Pipeline
|
vorhandenen Layer – dieser wird dann immer ersetzt. Gedacht für die
|
||||||
(``verfahrensgebiet_alkis_komplett``). Standard: ``False``.
|
automatischen Pipelines (``verfahrensgebiet_alkis_komplett``,
|
||||||
|
``verfahrensgebiet_shape_komplett``). Standard: ``False``.
|
||||||
|
ohne_schluessel_abfrage : bool, optional
|
||||||
|
``True``: Überspringt nur die Gemarkungsschlüssel-Nutzerabfrage und
|
||||||
|
verwendet ``vorgabe_schluessel`` direkt; die Rückfrage bei einem
|
||||||
|
bereits vorhandenen Layer (Überschreiben/Anhängen/Abbrechen, inkl.
|
||||||
|
Dedup beim Anhängen) bleibt aktiv. Für Aufrufer, die die Schlüssel
|
||||||
|
bereits anderweitig ermittelt haben (z. B. aus einer Layer-Auswahl),
|
||||||
|
aber trotzdem interaktiv mit einem bestehenden Layer umgehen wollen.
|
||||||
|
Wirkungslos, wenn ``ohne_dialog=True`` gesetzt ist. Standard: ``False``.
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
-------
|
-------
|
||||||
@@ -220,8 +231,8 @@ def flurstueck_alkis(
|
|||||||
append_target = existing
|
append_target = existing
|
||||||
|
|
||||||
# --- Schritt 2: Gemarkungsschlüssel bestimmen -------------------------
|
# --- Schritt 2: Gemarkungsschlüssel bestimmen -------------------------
|
||||||
if ohne_dialog:
|
if ohne_dialog or ohne_schluessel_abfrage:
|
||||||
# Pipeline-Modus: vorgabe_schluessel direkt verwenden, kein Dialog
|
# vorgabe_schluessel direkt verwenden, kein ask_text-Dialog
|
||||||
if not vorgabe_schluessel:
|
if not vorgabe_schluessel:
|
||||||
return None, LoadStatus.NONE
|
return None, LoadStatus.NONE
|
||||||
schluessel_liste = [s.strip() for s in vorgabe_schluessel if s.strip()]
|
schluessel_liste = [s.strip() for s in vorgabe_schluessel if s.strip()]
|
||||||
@@ -272,7 +283,7 @@ def flurstueck_alkis(
|
|||||||
alle_feats = list(layer.getFeatures())
|
alle_feats = list(layer.getFeatures())
|
||||||
neue_feats = alle_feats
|
neue_feats = alle_feats
|
||||||
if layer.fields().indexFromName(FELD_FLURSTUECKSKENNZEICHEN) >= 0:
|
if layer.fields().indexFromName(FELD_FLURSTUECKSKENNZEICHEN) >= 0:
|
||||||
vorhandene = vorhandene_kennzeichen(append_target)
|
vorhandene = _vorhandene_kennzeichen(append_target)
|
||||||
neue_feats = [
|
neue_feats = [
|
||||||
f for f in alle_feats
|
f for f in alle_feats
|
||||||
if str(f[FELD_FLURSTUECKSKENNZEICHEN] or "").strip() not in vorhandene
|
if str(f[FELD_FLURSTUECKSKENNZEICHEN] or "").strip() not in vorhandene
|
||||||
|
|||||||
@@ -311,6 +311,28 @@ class TestFlurstueckAlkis(unittest.TestCase):
|
|||||||
self.assertIsNotNone(layer)
|
self.assertIsNotNone(layer)
|
||||||
self.assertEqual(status, LoadStatus.FIRST)
|
self.assertEqual(status, LoadStatus.FIRST)
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------ #
|
||||||
|
# 10. ohne_schluessel_abfrage: vorgabe_schluessel direkt, kein ask_text (#47)
|
||||||
|
# ------------------------------------------------------------------ #
|
||||||
|
@patch("sn_verfahrensgebiet.functions.flurstueck_alkis.lade_flurstuecke_per_gemarkung")
|
||||||
|
@patch("sn_verfahrensgebiet.functions.flurstueck_alkis.QgsProject.instance")
|
||||||
|
@patch("sn_verfahrensgebiet.functions.flurstueck_alkis.ask_text")
|
||||||
|
def test_ohne_schluessel_abfrage_ueberspringt_ask_text(
|
||||||
|
self, mock_ask_text, mock_project, mock_lade
|
||||||
|
):
|
||||||
|
"""ohne_schluessel_abfrage=True verwendet vorgabe_schluessel direkt, ohne ask_text aufzurufen."""
|
||||||
|
mock_project.return_value = _DummyProject()
|
||||||
|
geladen = _DummyFlstLayer([_DummyFlstFeature("110001_0001__00001")])
|
||||||
|
mock_lade.return_value = geladen
|
||||||
|
|
||||||
|
layer, status = flurstueck_alkis(
|
||||||
|
None, vorgabe_schluessel=["1234", "5678"], ohne_schluessel_abfrage=True
|
||||||
|
)
|
||||||
|
|
||||||
|
mock_ask_text.assert_not_called()
|
||||||
|
self.assertIs(layer, geladen)
|
||||||
|
self.assertEqual(status, LoadStatus.FIRST)
|
||||||
|
mock_lade.assert_called_once_with(["1234", "5678"])
|
||||||
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
@@ -422,6 +444,28 @@ class TestFlurstueckAlkisAnhaengenDedup(unittest.TestCase):
|
|||||||
self.assertEqual(status, LoadStatus.APPEND)
|
self.assertEqual(status, LoadStatus.APPEND)
|
||||||
self.assertEqual(len(bestehend.added), 2)
|
self.assertEqual(len(bestehend.added), 2)
|
||||||
|
|
||||||
|
@patch("sn_verfahrensgebiet.functions.flurstueck_alkis.lade_flurstuecke_per_gemarkung")
|
||||||
|
@patch("sn_verfahrensgebiet.functions.flurstueck_alkis._check_existing_flurstueck_layer")
|
||||||
|
@patch("sn_verfahrensgebiet.functions.flurstueck_alkis.ask_text")
|
||||||
|
def test_ohne_schluessel_abfrage_append_dedup(self, mock_ask_text, mock_check, mock_lade):
|
||||||
|
"""ohne_schluessel_abfrage=True: Anhängen dedupliziert trotzdem, ohne nach Schlüsseln zu fragen (#47)."""
|
||||||
|
bestehend = _DummyFlstLayer([_DummyFlstFeature("110001_0001__00001")])
|
||||||
|
neu_geladen = _DummyFlstLayer([
|
||||||
|
_DummyFlstFeature("110001_0001__00001"), # bereits vorhanden
|
||||||
|
_DummyFlstFeature("110001_0002__00007"), # neu
|
||||||
|
])
|
||||||
|
mock_check.return_value = (bestehend, LoadStatus.APPEND)
|
||||||
|
mock_lade.return_value = neu_geladen
|
||||||
|
|
||||||
|
layer, status = flurstueck_alkis(
|
||||||
|
None, vorgabe_schluessel=["0001", "0002"], ohne_schluessel_abfrage=True
|
||||||
|
)
|
||||||
|
|
||||||
|
mock_ask_text.assert_not_called()
|
||||||
|
self.assertEqual(status, LoadStatus.APPEND)
|
||||||
|
self.assertEqual(len(bestehend.added), 1)
|
||||||
|
self.assertEqual(bestehend.added[0][FELD_FLURSTUECKSKENNZEICHEN], "110001_0002__00007")
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|||||||
+59
-94
@@ -15,7 +15,6 @@ if "qgis" not in sys.modules:
|
|||||||
sys.modules["qgis.utils"] = qgis_utils
|
sys.modules["qgis.utils"] = qgis_utils
|
||||||
|
|
||||||
from sn_verfahrensgebiet.ui.tabs.working_tab import WorkingTab, LoadStatus
|
from sn_verfahrensgebiet.ui.tabs.working_tab import WorkingTab, LoadStatus
|
||||||
from sn_verfahrensgebiet.functions.flurstueck_alkis import FLST_LAYER_NAME, FELD_FLURSTUECKSKENNZEICHEN
|
|
||||||
|
|
||||||
|
|
||||||
class _DummyLayer:
|
class _DummyLayer:
|
||||||
@@ -106,68 +105,6 @@ class _DummyGemarkungenLayer:
|
|||||||
return list(self._selected)
|
return list(self._selected)
|
||||||
|
|
||||||
|
|
||||||
class _DummyFlstFeatureWT:
|
|
||||||
def __init__(self, kennzeichen):
|
|
||||||
self._kennzeichen = kennzeichen
|
|
||||||
|
|
||||||
def __getitem__(self, key):
|
|
||||||
if key == FELD_FLURSTUECKSKENNZEICHEN:
|
|
||||||
return self._kennzeichen
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
class _DummyFlstFieldsWT:
|
|
||||||
def indexFromName(self, name):
|
|
||||||
return 0 if name == FELD_FLURSTUECKSKENNZEICHEN else -1
|
|
||||||
|
|
||||||
|
|
||||||
class _DummyTempLayer:
|
|
||||||
"""Rückgabe von lade_flurstuecke_per_gemarkung in Tests."""
|
|
||||||
|
|
||||||
def __init__(self, features):
|
|
||||||
self._features = list(features)
|
|
||||||
|
|
||||||
def getFeatures(self):
|
|
||||||
return list(self._features)
|
|
||||||
|
|
||||||
def fields(self):
|
|
||||||
return _DummyFlstFieldsWT()
|
|
||||||
|
|
||||||
def isValid(self):
|
|
||||||
return True
|
|
||||||
|
|
||||||
def featureCount(self):
|
|
||||||
return len(self._features)
|
|
||||||
|
|
||||||
|
|
||||||
class _DummyExistingFlstLayer:
|
|
||||||
"""Bereits im Projekt vorhandener Flurstück-Layer, zeichnet addFeatures() auf."""
|
|
||||||
|
|
||||||
def __init__(self, features):
|
|
||||||
self._features = list(features)
|
|
||||||
self.added = None
|
|
||||||
|
|
||||||
def getFeatures(self):
|
|
||||||
return list(self._features)
|
|
||||||
|
|
||||||
def fields(self):
|
|
||||||
return _DummyFlstFieldsWT()
|
|
||||||
|
|
||||||
def dataProvider(self):
|
|
||||||
layer = self
|
|
||||||
|
|
||||||
class _Provider:
|
|
||||||
def addFeatures(self, feats):
|
|
||||||
layer.added = list(feats)
|
|
||||||
layer._features.extend(feats)
|
|
||||||
return True
|
|
||||||
|
|
||||||
return _Provider()
|
|
||||||
|
|
||||||
def updateExtents(self):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class TestWorkingTab(unittest.TestCase):
|
class TestWorkingTab(unittest.TestCase):
|
||||||
|
|
||||||
def _make_tab(self):
|
def _make_tab(self):
|
||||||
@@ -264,54 +201,82 @@ class TestWorkingTab(unittest.TestCase):
|
|||||||
mock_set_layer_id.assert_called_once_with("")
|
mock_set_layer_id.assert_called_once_with("")
|
||||||
|
|
||||||
# ------------------------------------------------------------------
|
# ------------------------------------------------------------------
|
||||||
# handle_flurst_aus_gemarkungen
|
# handle_flurst_alkis / handle_flurst_aus_gemarkungen (#47: eine gemeinsame
|
||||||
|
# Ladelogik in flurstueck_alkis(), hier wird nur noch die Anbindung geprüft)
|
||||||
# ------------------------------------------------------------------
|
# ------------------------------------------------------------------
|
||||||
|
|
||||||
@patch("sn_verfahrensgebiet.ui.tabs.working_tab.success")
|
@patch("sn_verfahrensgebiet.ui.tabs.working_tab.success")
|
||||||
@patch("sn_verfahrensgebiet.ui.tabs.working_tab.lade_flurstuecke_per_gemarkung")
|
@patch("sn_verfahrensgebiet.ui.tabs.working_tab.apply_style")
|
||||||
@patch("sn_verfahrensgebiet.ui.tabs.working_tab.QMessageBox")
|
@patch("sn_verfahrensgebiet.ui.tabs.working_tab.flurstueck_alkis")
|
||||||
@patch("sn_verfahrensgebiet.ui.tabs.working_tab.QgsProject.instance")
|
@patch("sn_verfahrensgebiet.ui.tabs.working_tab.QgsProject.instance")
|
||||||
@patch("sn_verfahrensgebiet.ui.tabs.working_tab.iface")
|
@patch("sn_verfahrensgebiet.ui.tabs.working_tab.iface")
|
||||||
def test_handle_flurst_aus_gemarkungen_anhaengen_ueberspringt_vorhandene(
|
def test_handle_flurst_alkis_first_load_uebernimmt_layer(
|
||||||
self, mock_iface, mock_project_instance, mock_msgbox_cls, mock_lade, mock_success
|
self, mock_iface, mock_project_instance, mock_flurstueck_alkis, mock_apply_style, mock_success
|
||||||
):
|
):
|
||||||
"""Anhängen über den Gemarkungen-Button überspringt bereits vorhandene flurstueckskennzeichen (#28)."""
|
"""Erstmaliges Laden über 'Flurstücke laden' fügt den Layer dem Projekt hinzu."""
|
||||||
tab = self._make_tab()
|
tab = self._make_tab()
|
||||||
mock_iface.mapCanvas.return_value = _DummyCanvas()
|
mock_iface.mapCanvas.return_value = _DummyCanvas()
|
||||||
|
project = _DummyProject()
|
||||||
|
mock_project_instance.return_value = project
|
||||||
|
layer = _DummyLayer(valid=True, layer_id="flst_first")
|
||||||
|
mock_flurstueck_alkis.return_value = (layer, LoadStatus.FIRST)
|
||||||
|
|
||||||
|
tab.handle_flurst_alkis()
|
||||||
|
|
||||||
|
mock_flurstueck_alkis.assert_called_once_with(tab)
|
||||||
|
self.assertIn(layer, project.added)
|
||||||
|
mock_success.assert_called_once()
|
||||||
|
|
||||||
|
@patch("sn_verfahrensgebiet.ui.tabs.working_tab.success")
|
||||||
|
@patch("sn_verfahrensgebiet.ui.tabs.working_tab.flurstueck_alkis")
|
||||||
|
@patch("sn_verfahrensgebiet.ui.tabs.working_tab.QgsProject.instance")
|
||||||
|
@patch("sn_verfahrensgebiet.ui.tabs.working_tab.iface")
|
||||||
|
def test_handle_flurst_aus_gemarkungen_ruft_flurstueck_alkis_ohne_schluessel_abfrage(
|
||||||
|
self, mock_iface, mock_project_instance, mock_flurstueck_alkis, mock_success
|
||||||
|
):
|
||||||
|
"""Der Gemarkungen-Auswahl-Button ruft dieselbe Ladefunktion mit ohne_schluessel_abfrage=True auf (#47)."""
|
||||||
|
tab = self._make_tab()
|
||||||
|
mock_iface.mapCanvas.return_value = _DummyCanvas()
|
||||||
gem_feat = _DummyGemFeature("110001", "Musterstadt")
|
gem_feat = _DummyGemFeature("110001", "Musterstadt")
|
||||||
gem_layer = _DummyGemarkungenLayer([gem_feat])
|
gem_layer = _DummyGemarkungenLayer([gem_feat])
|
||||||
bestehend = _DummyExistingFlstLayer([_DummyFlstFeatureWT("110001_0001__00001")])
|
project = types.SimpleNamespace(
|
||||||
|
mapLayersByName=lambda name: [gem_layer] if name == "Gemarkungen" else []
|
||||||
def map_layers_by_name(name):
|
|
||||||
if name == "Gemarkungen":
|
|
||||||
return [gem_layer]
|
|
||||||
if name == FLST_LAYER_NAME:
|
|
||||||
return [bestehend]
|
|
||||||
return []
|
|
||||||
|
|
||||||
project = types.SimpleNamespace(mapLayersByName=map_layers_by_name)
|
|
||||||
mock_project_instance.return_value = project
|
|
||||||
|
|
||||||
btn_anhaengen = object()
|
|
||||||
msg_instance = mock_msgbox_cls.return_value
|
|
||||||
msg_instance.addButton.side_effect = (
|
|
||||||
lambda text, role: btn_anhaengen if text == "Anhängen" else object()
|
|
||||||
)
|
)
|
||||||
msg_instance.clickedButton.return_value = btn_anhaengen
|
mock_project_instance.return_value = project
|
||||||
|
layer = _DummyLayer(valid=True, layer_id="flst_append")
|
||||||
neu_geladen = _DummyTempLayer([
|
mock_flurstueck_alkis.return_value = (layer, LoadStatus.APPEND)
|
||||||
_DummyFlstFeatureWT("110001_0001__00001"), # bereits vorhanden
|
|
||||||
_DummyFlstFeatureWT("110001_0002__00007"), # neu
|
|
||||||
])
|
|
||||||
mock_lade.return_value = neu_geladen
|
|
||||||
|
|
||||||
tab.handle_flurst_aus_gemarkungen()
|
tab.handle_flurst_aus_gemarkungen()
|
||||||
|
|
||||||
self.assertEqual(len(bestehend.added), 1)
|
mock_flurstueck_alkis.assert_called_once()
|
||||||
self.assertEqual(bestehend.added[0][FELD_FLURSTUECKSKENNZEICHEN], "110001_0002__00007")
|
_args, kwargs = mock_flurstueck_alkis.call_args
|
||||||
|
self.assertEqual(kwargs.get("vorgabe_schluessel"), ["0001"])
|
||||||
|
self.assertEqual(kwargs.get("vorgabe_namen"), ["Musterstadt"])
|
||||||
|
self.assertTrue(kwargs.get("ohne_schluessel_abfrage"))
|
||||||
mock_success.assert_called_once()
|
mock_success.assert_called_once()
|
||||||
|
|
||||||
|
@patch("sn_verfahrensgebiet.ui.tabs.working_tab.error")
|
||||||
|
@patch("sn_verfahrensgebiet.ui.tabs.working_tab.success")
|
||||||
|
@patch("sn_verfahrensgebiet.ui.tabs.working_tab.flurstueck_alkis")
|
||||||
|
@patch("sn_verfahrensgebiet.ui.tabs.working_tab.QgsProject.instance")
|
||||||
|
def test_handle_flurst_aus_gemarkungen_abbruch_zeigt_keine_zusaetzliche_meldung(
|
||||||
|
self, mock_project_instance, mock_flurstueck_alkis, mock_success, mock_error
|
||||||
|
):
|
||||||
|
"""Bricht flurstueck_alkis() ab (None, NONE), zeigt der Button keine eigene Meldung – flurstueck_alkis() hat das schon getan (#47)."""
|
||||||
|
tab = self._make_tab()
|
||||||
|
gem_feat = _DummyGemFeature("110001", "Musterstadt")
|
||||||
|
gem_layer = _DummyGemarkungenLayer([gem_feat])
|
||||||
|
project = types.SimpleNamespace(
|
||||||
|
mapLayersByName=lambda name: [gem_layer] if name == "Gemarkungen" else []
|
||||||
|
)
|
||||||
|
mock_project_instance.return_value = project
|
||||||
|
mock_flurstueck_alkis.return_value = (None, LoadStatus.NONE)
|
||||||
|
|
||||||
|
tab.handle_flurst_aus_gemarkungen()
|
||||||
|
|
||||||
|
mock_success.assert_not_called()
|
||||||
|
mock_error.assert_not_called()
|
||||||
|
|
||||||
# ------------------------------------------------------------------
|
# ------------------------------------------------------------------
|
||||||
# handle_grenz_alkis
|
# handle_grenz_alkis
|
||||||
# ------------------------------------------------------------------
|
# ------------------------------------------------------------------
|
||||||
|
|||||||
+26
-91
@@ -15,14 +15,7 @@ from sn_basis.modules.pruef_ergebnis import pruef_ergebnis
|
|||||||
from qgis.utils import iface
|
from qgis.utils import iface
|
||||||
|
|
||||||
from sn_verfahrensgebiet.functions.verfahrensgebiet_alkis import LoadStatus
|
from sn_verfahrensgebiet.functions.verfahrensgebiet_alkis import LoadStatus
|
||||||
from sn_verfahrensgebiet.functions.flurstueck_alkis import (
|
from sn_verfahrensgebiet.functions.flurstueck_alkis import flurstueck_alkis
|
||||||
flurstueck_alkis,
|
|
||||||
lade_flurstuecke_per_gemarkung,
|
|
||||||
vorhandene_kennzeichen,
|
|
||||||
ALKIS_SF_URL,
|
|
||||||
FLST_LAYER_NAME,
|
|
||||||
FELD_FLURSTUECKSKENNZEICHEN,
|
|
||||||
)
|
|
||||||
from sn_verfahrensgebiet.functions.verfahrensgebiet_alkis_komplett import (
|
from sn_verfahrensgebiet.functions.verfahrensgebiet_alkis_komplett import (
|
||||||
verfahrensgebiet_alkis_komplett,
|
verfahrensgebiet_alkis_komplett,
|
||||||
BROR_LAYER_NAME,
|
BROR_LAYER_NAME,
|
||||||
@@ -394,6 +387,25 @@ class WorkingTab(QWidget):
|
|||||||
# Flurstücke-Handler
|
# Flurstücke-Handler
|
||||||
# ------------------------------------------------------------------
|
# ------------------------------------------------------------------
|
||||||
|
|
||||||
|
def _uebernimm_flurstuecke_ergebnis(self, layer, status) -> None:
|
||||||
|
"""Übernimmt das Ergebnis von flurstueck_alkis() ins Projekt (FIRST/RELOAD/APPEND/KEEP)."""
|
||||||
|
if status in (LoadStatus.FIRST, LoadStatus.RELOAD):
|
||||||
|
QgsProject.instance().addMapLayer(layer)
|
||||||
|
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)
|
||||||
|
|
||||||
|
elif status == LoadStatus.APPEND:
|
||||||
|
self.setze_haken(self.haken_flurst, True)
|
||||||
|
iface.mapCanvas().refresh()
|
||||||
|
success("Flurstücke", "Features wurden an den vorhandenen Layer angehängt.", duration=5)
|
||||||
|
|
||||||
def handle_flurst_alkis(self) -> None:
|
def handle_flurst_alkis(self) -> None:
|
||||||
"""Lädt Flurstücke aus ALKIS-WFS anhand von Gemarkungsschlüsseln."""
|
"""Lädt Flurstücke aus ALKIS-WFS anhand von Gemarkungsschlüsseln."""
|
||||||
self._set_busy(self.btn_flurst_alkis, True, "Aus ALKIS laden")
|
self._set_busy(self.btn_flurst_alkis, True, "Aus ALKIS laden")
|
||||||
@@ -401,25 +413,7 @@ class WorkingTab(QWidget):
|
|||||||
layer, status = flurstueck_alkis(self)
|
layer, status = flurstueck_alkis(self)
|
||||||
if not layer or not layer.isValid():
|
if not layer or not layer.isValid():
|
||||||
return
|
return
|
||||||
|
self._uebernimm_flurstuecke_ergebnis(layer, status)
|
||||||
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)
|
|
||||||
|
|
||||||
elif status == LoadStatus.APPEND:
|
|
||||||
self.setze_haken(self.haken_flurst, True)
|
|
||||||
iface.mapCanvas().refresh()
|
|
||||||
success("Flurstücke", "Features wurden an den vorhandenen Layer angehängt.", duration=5)
|
|
||||||
|
|
||||||
finally:
|
finally:
|
||||||
self._set_busy(self.btn_flurst_alkis, False, "Aus ALKIS laden")
|
self._set_busy(self.btn_flurst_alkis, False, "Aus ALKIS laden")
|
||||||
|
|
||||||
@@ -493,79 +487,20 @@ class WorkingTab(QWidget):
|
|||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
# Prüfen ob bereits ein Flurstücke-Layer vorhanden → 3-Knopf-Dialog
|
# Flurstücke laden – Schlüssel bereits bekannt, aber bei bestehendem Layer
|
||||||
existing_flst = project.mapLayersByName(FLST_LAYER_NAME)
|
# trotzdem interaktiv nachfragen (Überschreiben/Anhängen/Abbrechen, inkl. Dedup)
|
||||||
if existing_flst:
|
|
||||||
msg_box = QMessageBox(self)
|
|
||||||
msg_box.setWindowTitle("Layer bereits vorhanden")
|
|
||||||
msg_box.setText(
|
|
||||||
f"Der Layer '{FLST_LAYER_NAME}' existiert bereits.\nWas soll geschehen?"
|
|
||||||
)
|
|
||||||
btn_ueberschreiben = msg_box.addButton("Überschreiben", QMessageBox.ButtonRole.DestructiveRole)
|
|
||||||
btn_anhaengen = msg_box.addButton("Anhängen", QMessageBox.ButtonRole.AcceptRole)
|
|
||||||
btn_abbrechen = msg_box.addButton("Abbrechen", QMessageBox.ButtonRole.RejectRole)
|
|
||||||
msg_box.setDefaultButton(btn_abbrechen)
|
|
||||||
msg_box.exec()
|
|
||||||
clicked = msg_box.clickedButton()
|
|
||||||
if clicked is btn_abbrechen:
|
|
||||||
return
|
|
||||||
if clicked is btn_anhaengen:
|
|
||||||
temp_layer = lade_flurstuecke_per_gemarkung(vorgabe_schluessel)
|
|
||||||
if not temp_layer or not temp_layer.isValid() or temp_layer.featureCount() == 0:
|
|
||||||
error(
|
|
||||||
"Flurstücke",
|
|
||||||
f"Flurstücke konnten nicht geladen werden – WFS-Dienst ({ALKIS_SF_URL}) "
|
|
||||||
f"nicht erreichbar oder keine Features für die gewählten Gemarkungen.",
|
|
||||||
duration=0,
|
|
||||||
)
|
|
||||||
return
|
|
||||||
neue_feats = list(temp_layer.getFeatures())
|
|
||||||
if temp_layer.fields().indexFromName(FELD_FLURSTUECKSKENNZEICHEN) >= 0:
|
|
||||||
vorhandene = vorhandene_kennzeichen(existing_flst[0])
|
|
||||||
neue_feats = [
|
|
||||||
f for f in neue_feats
|
|
||||||
if str(f[FELD_FLURSTUECKSKENNZEICHEN] or "").strip() not in vorhandene
|
|
||||||
]
|
|
||||||
existing_flst[0].dataProvider().addFeatures(neue_feats)
|
|
||||||
existing_flst[0].updateExtents()
|
|
||||||
iface.mapCanvas().refresh()
|
|
||||||
self.setze_haken(self.haken_flurst, True)
|
|
||||||
success(
|
|
||||||
"Flurstücke",
|
|
||||||
f"{len(neue_feats)} neue Features wurden an den vorhandenen Layer angehängt.",
|
|
||||||
duration=5,
|
|
||||||
)
|
|
||||||
return
|
|
||||||
# else: Überschreiben → fall-through zum flurstueck_alkis(ohne_dialog=True)-Aufruf
|
|
||||||
|
|
||||||
# Flurstücke direkt laden (kein Dialog)
|
|
||||||
layer, status = flurstueck_alkis(
|
layer, status = flurstueck_alkis(
|
||||||
self,
|
self,
|
||||||
vorgabe_schluessel=vorgabe_schluessel,
|
vorgabe_schluessel=vorgabe_schluessel,
|
||||||
vorgabe_namen=vorgabe_namen,
|
vorgabe_namen=vorgabe_namen,
|
||||||
ohne_dialog=True,
|
ohne_schluessel_abfrage=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
if not layer or not layer.isValid():
|
if not layer or not layer.isValid():
|
||||||
error(
|
# flurstueck_alkis() hat bei Abbruch/Fehler bereits selbst eine Meldung gezeigt.
|
||||||
"Flurstücke",
|
|
||||||
f"Flurstücke konnten nicht geladen werden – WFS-Dienst ({ALKIS_SF_URL}) "
|
|
||||||
f"nicht erreichbar oder keine Features für die gewählten Gemarkungen.",
|
|
||||||
duration=0,
|
|
||||||
)
|
|
||||||
return
|
return
|
||||||
|
|
||||||
if status in (LoadStatus.FIRST, LoadStatus.RELOAD):
|
self._uebernimm_flurstuecke_ergebnis(layer, status)
|
||||||
project.addMapLayer(layer)
|
|
||||||
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:
|
finally:
|
||||||
self._set_busy(self.btn_flurst_aus_gemarkungen, False, "aus gewählten Gemarkungen laden")
|
self._set_busy(self.btn_flurst_aus_gemarkungen, False, "aus gewählten Gemarkungen laden")
|
||||||
|
|||||||
Reference in New Issue
Block a user