Linkliste: Kartenwahl hakt die passenden Dienste vor
Erik, 06.10.2026: neben dem Thema eine zweite Gliederung — für welche Karten ein Dienst gedacht ist (Wege- und Gewässerplan, Neugestaltungsgrundsätze, Wertermittlung; mehrfach). Der Manager liefert dafür je Eintrag `karten` und den Katalog unter GET /linkliste/karten. Über der Dienstliste steht jetzt je Karte ein Häkchen (Katalog vom Server, Rückfall auf die drei Karten bei älterem Server). Eine oder mehrere Karten gewählt: angehakt sind die Dienste mit mindestens einer passenden Karte (linkliste.vorhaken), ohne Wahl alle wie bisher; von Hand nachjustieren bleibt möglich, eine neu geholte Liste übernimmt die Wahl. Karten im Tooltip. Fassung bleibt 0.7.0 (noch nicht ausgeliefert). Tests ohne Netz erweitert, beide grün. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -272,6 +272,10 @@ mit den Häkchen (Erik, 06.10.2026).
|
||||
- **Ausgewählte laden** hängt die angehakten Dienste schrittweise unter „Geodienste <vkz> <Name>“
|
||||
ein: Gruppe › Untergruppe › Layer (`linkliste.zielgruppe`); ohne Untergruppe direkt unter die
|
||||
Gruppe. Ein hinterlegter Stil kommt über `GET /linkliste/{id}/style.qml`.
|
||||
- **Für Karte** (seit 0.7.0): über der Liste je Karte ein Häkchen — Wege- und Gewässerplan,
|
||||
Neugestaltungsgrundsätze, Wertermittlung (Katalog vom Server, `GET /linkliste/karten`). Eine
|
||||
oder mehrere Karten gewählt: angehakt sind die Dienste, die der Landkreis bzw. die landesweite
|
||||
Pflege dieser Karte zugeordnet hat (`linkliste.vorhaken`); nachjustieren von Hand bleibt möglich.
|
||||
- Anbieter: WMS (`QgsRasterLayer`), WFS, ArcGIS REST (FeatureServer) und GeoJSON/OGR.
|
||||
- **Nur lesen:** eine oFB sieht die Verfahren ihres Landkreises; deren OGC-Sammlungen tragen
|
||||
`vln:schreibbar: false` und werden schreibgeschützt geladen (`layer.setReadOnly(True)`).
|
||||
|
||||
@@ -91,6 +91,26 @@ pruefe(zweiter.name() == "Biotope" and len(oben.children()) == 2 and len(natur.c
|
||||
"zweiter Ladelauf legt nichts doppelt an")
|
||||
pruefe(sonst.name() == "Sonstiges" and not sonst.children(), "ohne Untergruppe direkt in die Gruppe")
|
||||
|
||||
print("== Karten: Katalog und Vorhaken ==")
|
||||
from vln_karten.linkliste import KARTEN_VORGABE, karten_laden, vorhaken
|
||||
d = [{"name": "A", "karten": ["p41"]}, {"name": "B", "karten": ["ngg", "we"]}, {"name": "C"}]
|
||||
pruefe(vorhaken(d, []) == [True, True, True], "ohne Kartenwahl alles angehakt")
|
||||
pruefe(vorhaken(d, ["p41"]) == [True, False, False], "Wege- und Gewässerplan: nur A")
|
||||
pruefe(vorhaken(d, ["p41", "we"]) == [True, True, False], "zwei Karten: A und B (mehrfach)")
|
||||
k = ac.KartenApiClient(api_key="pruef")
|
||||
k._request = lambda m, p, **kw: {"karten": [{"schluessel": "p41", "name": "Wege- und Gewässerplan"},
|
||||
{"schluessel": "kas", "name": "Karte alter Stand"}]}
|
||||
pruefe([x["schluessel"] for x in karten_laden(k)] == ["p41", "kas"],
|
||||
"Katalog vom Server (neue Karte ohne neue Plugin-Fassung)")
|
||||
|
||||
|
||||
def kein_katalog(m, p, **kw):
|
||||
raise ac.ApiError("GET /linkliste/karten lieferte HTTP 404", 404)
|
||||
|
||||
|
||||
k._request = kein_katalog
|
||||
pruefe(karten_laden(k) == KARTEN_VORGABE, "aelterer Server: Vorgabe der drei Karten")
|
||||
|
||||
print("== Ergebnis: %d Fehler ==" % len(FEHLER))
|
||||
for f in FEHLER:
|
||||
print(" -", f)
|
||||
|
||||
@@ -88,6 +88,27 @@ panel.set_dienste([{"name": "Denkmal Punkte", "gruppe_name": "Kultur", "untergru
|
||||
pruefe(panel.dienste_liste.item(0).text().startswith("Denkmal Punkte · Kultur › Denkmal · "),
|
||||
"Untergruppe in der Dienstliste: %r" % panel.dienste_liste.item(0).text())
|
||||
pruefe(panel.dienste_liste.item(1).text().startswith("Wald · Natur · "), "ohne Untergruppe wie bisher")
|
||||
|
||||
print("== Karten: Wahl hakt vor ==")
|
||||
from vln_karten.linkliste import KARTEN_VORGABE
|
||||
panel.set_karten(KARTEN_VORGABE)
|
||||
pruefe(list(panel.karten_haken) == ["p41", "ngg", "we"] and panel.karten_beschriftung.isVisibleTo(panel),
|
||||
"je Karte ein Haekchen")
|
||||
panel.set_dienste([{"name": "Biotope", "gruppe_name": "Natur", "karten": ["ngg"]},
|
||||
{"name": "Wege", "gruppe_name": "Verkehr", "karten": ["p41", "ngg"]},
|
||||
{"name": "Bodenwert", "gruppe_name": "Boden", "karten": ["we"]}])
|
||||
an = lambda: [panel.dienste_liste.item(i).checkState() == Qt.CheckState.Checked
|
||||
for i in range(panel.dienste_liste.count())]
|
||||
pruefe(an() == [True, True, True], "ohne Wahl alles angehakt")
|
||||
panel.karten_haken["p41"].setChecked(True)
|
||||
pruefe(an() == [False, True, False], "Wege- und Gewaesserplan: nur passende: %r" % an())
|
||||
panel.karten_haken["we"].setChecked(True)
|
||||
pruefe(an() == [False, True, True], "zwei Karten zugleich: %r" % an())
|
||||
panel.set_dienste([{"name": "Neu", "karten": ["we"]}, {"name": "Ohne"}])
|
||||
pruefe(an() == [True, False], "neue Liste uebernimmt die Kartenwahl: %r" % an())
|
||||
pruefe("Karten: Wertermittlung" in panel.dienste_liste.item(0).toolTip(), "Karten im Tooltip")
|
||||
for haken in panel.karten_haken.values():
|
||||
haken.setChecked(False)
|
||||
panel.set_angemeldet(False)
|
||||
GERUFEN.clear()
|
||||
|
||||
|
||||
@@ -47,6 +47,46 @@ WMS_FORMAT = "image/png"
|
||||
WMS_CRS = "EPSG:25833"
|
||||
|
||||
|
||||
#: Rückfall, wenn der Server den Kartenkatalog noch nicht kennt (Manager vor dem 06.10.2026).
|
||||
KARTEN_VORGABE = [{"schluessel": "p41", "name": "Wege- und Gewässerplan"},
|
||||
{"schluessel": "ngg", "name": "Neugestaltungsgrundsätze"},
|
||||
{"schluessel": "we", "name": "Wertermittlung"}]
|
||||
|
||||
|
||||
def karten_laden(client):
|
||||
"""``GET /linkliste/karten`` -> ``[{schluessel, name}]`` — für welche Karten ein Dienst
|
||||
gedacht sein kann (Erik, 06.10.2026). Ein älterer Server kennt die Route nicht: dann die
|
||||
Vorgabe; kommt dort eine Karte dazu, braucht das Plugin keine neue Fassung.
|
||||
"""
|
||||
try:
|
||||
daten = client._request("GET", "/linkliste/karten")
|
||||
except ApiError as exc:
|
||||
if getattr(exc, "status", None) in (400, 404, 405):
|
||||
return list(KARTEN_VORGABE)
|
||||
raise
|
||||
zeilen = daten.get("karten") if isinstance(daten, dict) else None
|
||||
if not isinstance(zeilen, list):
|
||||
return list(KARTEN_VORGABE)
|
||||
return [{"schluessel": str(z.get("schluessel")), "name": str(z.get("name") or z.get("schluessel"))}
|
||||
for z in zeilen if isinstance(z, dict) and z.get("schluessel")]
|
||||
|
||||
|
||||
def vorhaken(dienste, gewaehlt):
|
||||
"""Welche Dienste für die gewählten Karten angehakt werden.
|
||||
|
||||
Ohne Kartenwahl alle (wie bisher); sonst jeder Dienst, der mindestens einer gewählten Karte
|
||||
zugeordnet ist. Nachjustieren von Hand bleibt möglich — das hier ist nur die Vorbelegung.
|
||||
|
||||
:param dienste: Einträge der Liste (je ``karten``: Liste von Schlüsseln).
|
||||
:param gewaehlt: Schlüssel der gewählten Karten.
|
||||
:returns: Liste ``bool`` in der Reihenfolge von ``dienste``.
|
||||
"""
|
||||
gewaehlt = set(gewaehlt or ())
|
||||
if not gewaehlt:
|
||||
return [True] * len(dienste)
|
||||
return [bool(gewaehlt & set(d.get("karten") or ())) for d in dienste]
|
||||
|
||||
|
||||
def dienste_laden(client, vkz):
|
||||
"""``GET /linkliste?vkz=…`` -> Liste der aufgelösten Einträge.
|
||||
|
||||
|
||||
@@ -15,6 +15,6 @@ category=Web
|
||||
icon=
|
||||
experimental=True
|
||||
deprecated=False
|
||||
changelog=0.7.0 Linkliste mit Untergruppen (Gruppe › Untergruppe › Layer) und für den ganzen Landkreis; Auswahl über /tgen/auswahl: als oFB die Verfahren des Landkreises „nur lesen“, Layer dort schreibgeschützt; ein 403 meldet nicht mehr ab.
|
||||
changelog=0.7.0 Linkliste mit Untergruppen (Gruppe › Untergruppe › Layer), Kartenwahl (Wege- und Gewässerplan, Neugestaltungsgrundsätze, Wertermittlung) hakt passende Dienste vor, Linkliste auch für den ganzen Landkreis; Auswahl über /tgen/auswahl: als oFB die Verfahren des Landkreises „nur lesen“, Layer dort schreibgeschützt; ein 403 meldet nicht mehr ab.
|
||||
0.6.0 Widmungen und Verkehrszeichen: eigene Layergruppe, Schildgrafiken vom Server (lokal abgelegt), Palette mit Suche, Werkzeuge „Schild setzen" und „Zusatzzeichen"; Seitenleiste rollt statt das QGIS-Fenster zu strecken (Issue #1).
|
||||
0.5.0 Geodienste aus der Linkliste, Stile speichern, Seitenleiste statt Werkzeugleiste.
|
||||
|
||||
+47
-2
@@ -260,6 +260,16 @@ class VlnPanel(QDockWidget):
|
||||
lage.setSpacing(6)
|
||||
lage.addWidget(_klein(QLabel("WMS-, WFS- und ArcGIS-Dienste für dieses Verfahren "
|
||||
"oder den gewählten Landkreis.")))
|
||||
# Kartenwahl (Erik, 06.10.2026): hakt vor, was für die gewählte Karte gedacht ist.
|
||||
# Die Häkchen entstehen erst mit dem Katalog vom Server (set_karten).
|
||||
self.karten_haken = {}
|
||||
self._karten_namen = {}
|
||||
self.karten_zeile = QHBoxLayout()
|
||||
self.karten_zeile.setSpacing(10)
|
||||
self.karten_beschriftung = _klein(QLabel("Für Karte:"))
|
||||
self.karten_beschriftung.setVisible(False)
|
||||
self.karten_zeile.addWidget(self.karten_beschriftung)
|
||||
lage.addLayout(self.karten_zeile)
|
||||
self.dienste_liste = QListWidget()
|
||||
# Bewusst niedrig: die Mindesthoehe aller Kaesten zusammen ist die Mindesthoehe des
|
||||
# Docks (s. Rollflaeche im Konstruktor). 140 px hier machten die Seitenleiste auf
|
||||
@@ -289,6 +299,37 @@ class VlnPanel(QDockWidget):
|
||||
for i in range(self.dienste_liste.count()):
|
||||
self.dienste_liste.item(i).setCheckState(ziel)
|
||||
|
||||
def set_karten(self, katalog):
|
||||
"""Die Kartenwahl aufbauen: je Karte ein Häkchen; eine Wahl hakt die passenden Dienste vor.
|
||||
|
||||
:param katalog: ``[{schluessel, name}]`` vom Server (``GET /linkliste/karten``).
|
||||
"""
|
||||
for haken in self.karten_haken.values():
|
||||
self.karten_zeile.removeWidget(haken)
|
||||
haken.deleteLater()
|
||||
self.karten_haken = {}
|
||||
self._karten_namen = {}
|
||||
for k in katalog or []:
|
||||
haken = QCheckBox(str(k.get("name") or k.get("schluessel")))
|
||||
haken.setToolTip("Dienste für diese Karte vorhaken")
|
||||
haken.stateChanged.connect(lambda _zustand: self._karten_anwenden())
|
||||
self.karten_zeile.addWidget(haken)
|
||||
self.karten_haken[str(k.get("schluessel"))] = haken
|
||||
self._karten_namen[str(k.get("schluessel"))] = str(k.get("name") or k.get("schluessel"))
|
||||
self.karten_beschriftung.setVisible(bool(self.karten_haken))
|
||||
|
||||
def gewaehlte_karten(self):
|
||||
"""Schlüssel der angehakten Karten."""
|
||||
return [k for k, haken in self.karten_haken.items() if haken.isChecked()]
|
||||
|
||||
def _karten_anwenden(self):
|
||||
"""Die Dienste nach der Kartenwahl vorhaken (ohne Wahl: alle)."""
|
||||
from .linkliste import vorhaken
|
||||
eintraege = [self.dienste_liste.item(i) for i in range(self.dienste_liste.count())]
|
||||
daten = [e.data(Qt.ItemDataRole.UserRole) or {} for e in eintraege]
|
||||
for eintrag, an in zip(eintraege, vorhaken(daten, self.gewaehlte_karten())):
|
||||
eintrag.setCheckState(Qt.CheckState.Checked if an else Qt.CheckState.Unchecked)
|
||||
|
||||
def set_dienste(self, dienste):
|
||||
"""Die geholte Liste anzeigen: Name, Gruppe › Untergruppe und Herkunft, alle zunächst
|
||||
angehakt."""
|
||||
@@ -304,8 +345,12 @@ class VlnPanel(QDockWidget):
|
||||
eintrag.setFlags(eintrag.flags() | Qt.ItemFlag.ItemIsUserCheckable)
|
||||
eintrag.setCheckState(Qt.CheckState.Checked)
|
||||
eintrag.setData(Qt.ItemDataRole.UserRole, d)
|
||||
eintrag.setToolTip("%s\n%s" % (d.get("url"), d.get("beschreibung") or ""))
|
||||
karten = ", ".join(self._karten_namen.get(k, k) for k in (d.get("karten") or []))
|
||||
eintrag.setToolTip("%s\n%s%s" % (d.get("url"), d.get("beschreibung") or "",
|
||||
("\nKarten: " + karten) if karten else ""))
|
||||
self.dienste_liste.addItem(eintrag)
|
||||
if self.gewaehlte_karten():
|
||||
self._karten_anwenden()
|
||||
|
||||
def gewaehlte_dienste(self):
|
||||
"""Die angehakten Einträge als Liste der Server-Datensätze."""
|
||||
@@ -350,7 +395,7 @@ class VlnPanel(QDockWidget):
|
||||
self.schild_knopf, self.zusatz_knopf, self.palette, self.blatt_combo,
|
||||
self.stil_knopf, self.vorlage_haken, self.dienste_holen_knopf,
|
||||
self.dienste_laden_knopf, self.dienste_alle, self.dienste_liste,
|
||||
*self.gruppen_haken.values()):
|
||||
*self.gruppen_haken.values(), *self.karten_haken.values()):
|
||||
widget.setEnabled(angemeldet)
|
||||
if not angemeldet:
|
||||
self._stumm = True
|
||||
|
||||
@@ -397,6 +397,12 @@ class VlnKartenPlugin:
|
||||
except ApiError as exc:
|
||||
self._show_error("Linkliste", str(exc))
|
||||
return
|
||||
if not self.panel.karten_haken:
|
||||
# Kartenkatalog einmal je Sitzung; ohne ihn bleibt es beim Anhaken von Hand.
|
||||
try:
|
||||
self.panel.set_karten(linkliste.karten_laden(self.client))
|
||||
except ApiError:
|
||||
self.panel.set_karten(linkliste.KARTEN_VORGABE)
|
||||
self.panel.set_dienste(dienste)
|
||||
herkunft = {}
|
||||
for d in dienste:
|
||||
|
||||
Reference in New Issue
Block a user