Fassung 0.7.0: Landkreis-Linkliste, oFB liest nur, Untergruppen, 403 meldet nicht ab

- Auswahl über GET /tgen/auswahl (Manager seit 06.10.2026): oben die eigenen Landkreise
  („… — Linkliste des Landkreises“), dann die Verfahren; als oFB die Verfahren des Landkreises
  mit „(nur lesen)“. Älterer Server ohne die Route: Rückfall auf /tgen.
- Landkreis gewählt: „Liste holen“ lädt die Linkliste des ganzen Landkreises; „Layer laden“
  erklärt, dass es für einen Landkreis keine Verfahrenslayer gibt.
- 401 und 403 getrennt: nur 401 (AuthError) meldet ab, 403 (KeinZugriff) zeigt eine Meldung.
  Bis 0.6.0 verwarf jedes 403 den gespeicherten API-Key.
- OGC-Sammlungen mit vln:schreibbar: false werden schreibgeschützt geladen; Meldungen für Stil
  und Verkehrszeichen nennen „nur lesen“ als Grund.
- Linkliste: Gruppe › Untergruppe › Layer im Ebenenbaum (linkliste.zielgruppe), Untergruppe
  auch in der Dienstliste.
- README: Abschnitt „Geodienste aus der Linkliste“; Tests ohne Netz:
  tools/headless_linkliste_test.py (neu), tools/headless_panel_test.py erweitert — beide grün
  mit QGIS 4.2 offscreen.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
KAI
2026-10-06 22:44:36 +02:00
co-authored by Claude Opus 5.5
parent c84bd6e378
commit a56bf7c397
10 changed files with 331 additions and 69 deletions
+42 -15
View File
@@ -34,6 +34,18 @@ PANEL_TITEL = "VLN Karten"
PANEL_OBJEKT = "VlnKartenPanel"
def ist_landkreis(vkz):
"""Steht ``vkz`` für einen Landkreis (oFB, 10–100) statt für ein Verfahren?
Landkreise stehen seit 0.7.0 oben in der Auswahl — gewählt lädt man dort nur die
Linkliste des Landkreises, keine Verfahrenslayer.
"""
try:
return 10 <= int(vkz) <= 100
except (TypeError, ValueError):
return False
def _klein(widget):
"""Hinweistexte eine Stufe kleiner und gedämpft — wie in QGIS-Panels üblich.
@@ -237,15 +249,17 @@ class VlnPanel(QDockWidget):
knopf.blockSignals(False)
def _bau_dienste(self):
"""Die Linkliste des gewählten Verfahrens — vierstufig gepflegt, hier nur geladen.
"""Die Linkliste des gewählten Verfahrens oder Landkreises — gepflegt landesweit und vom
Landkreis, hier nur geladen.
Die Liste kommt fertig aufgelöst vom Server (landesweit, Landkreis, Team, Verfahren);
je Zeile steht die Herkunft dabei, damit man sieht, wo ein Dienst herkommt.
Die Liste kommt fertig aufgelöst vom Server; je Zeile stehen Gruppe, Untergruppe und
Herkunft dabei, damit man sieht, wo ein Dienst herkommt.
"""
kasten = QGroupBox("Geodienste (Linkliste)")
lage = QVBoxLayout(kasten)
lage.setSpacing(6)
lage.addWidget(_klein(QLabel("WMS-, WFS- und ArcGIS-Dienste für dieses Verfahren.")))
lage.addWidget(_klein(QLabel("WMS-, WFS- und ArcGIS-Dienste für dieses Verfahren "
"oder den gewählten Landkreis.")))
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
@@ -276,11 +290,14 @@ class VlnPanel(QDockWidget):
self.dienste_liste.item(i).setCheckState(ziel)
def set_dienste(self, dienste):
"""Die geholte Liste anzeigen: Name, Gruppe und Herkunft, alle zunächst angehakt."""
"""Die geholte Liste anzeigen: Name, Gruppe › Untergruppe und Herkunft, alle zunächst
angehakt."""
self.dienste_liste.clear()
for d in dienste or []:
text = "%s · %s · %s" % (d.get("name"), d.get("gruppe_name") or "",
d.get("herkunft_text") or "")
gruppe = d.get("gruppe_name") or ""
if d.get("untergruppe"):
gruppe = "%s › %s" % (gruppe, d.get("untergruppe"))
text = "%s · %s · %s" % (d.get("name"), gruppe, d.get("herkunft_text") or "")
if d.get("stil"):
text += " · mit Stil"
eintrag = QListWidgetItem(text)
@@ -304,8 +321,8 @@ class VlnPanel(QDockWidget):
lage = QVBoxLayout(kasten)
lage.setSpacing(6)
self.stil_knopf = QPushButton("Stil des aktiven Layers speichern")
self.stil_knopf.setToolTip("Den Stil dieses Verfahrens darf jeder speichern, der das "
"Verfahren sieht")
self.stil_knopf.setToolTip("Den Stil dieses Verfahrens darf speichern, wer im Verfahren "
"schreiben darf (nicht bei „nur lesen“)")
self.stil_knopf.clicked.connect(lambda: self._ruf("save_style"))
self.vorlage_haken = QCheckBox("als Vorlage für alle Verfahren")
self.vorlage_haken.setToolTip("Gilt dann für diese Art in jedem Verfahren, z. B. für "
@@ -344,12 +361,22 @@ class VlnPanel(QDockWidget):
self.dienste_liste.clear()
self._stumm = False
def set_verfahren(self, verfahren):
"""``verfahren``: Liste von ``{"vkz":…, "name":…}`` aus der API."""
self._verfahren = [
("%s — %s" % (v["vkz"], v["name"]) if v.get("name") else str(v["vkz"]), v["vkz"])
for v in verfahren
]
def set_verfahren(self, verfahren, aemter=()):
"""Die Auswahl füllen.
:param verfahren: ``[{"vkz", "name", "zugriff"}]`` aus der API; ``zugriff == "lesen"``
bekommt den Zusatz „nur lesen“ (oFB: Verfahren des eigenen Landkreises).
:param aemter: ``[{"vkz", "name"}]`` — die eigenen Landkreise stehen oben; gewählt lädt
man dort nur die Linkliste des Landkreises.
"""
eintraege = [("%s — Linkliste des Landkreises" % (a.get("name") or a["vkz"]), a["vkz"])
for a in aemter]
for v in verfahren:
text = "%s — %s" % (v["vkz"], v["name"]) if v.get("name") else str(v["vkz"])
if v.get("zugriff") == "lesen":
text += " (nur lesen)"
eintraege.append((text, v["vkz"]))
self._verfahren = eintraege
self._liste_fuellen()
def set_status(self, text):