Geodienste aus der Linkliste laden — je Verfahren, aus der Seitenleiste

Erik, 11.09.2026: "als angemeldeter Nutzer TG-spezifisch die Dienste aus der
Linkliste einbinden".

- vln_karten/linkliste.py (neu): holt GET /v2/linkliste?vkz=…, baut je Anbieter
  den passenden Layer (wms, wfs, rest/ArcGIS, geojson/ogr), wendet den beim
  Eintrag hinterlegten QML-Stil an und haengt alles schrittweise in die Gruppe
  "Geodienste <VKZ> <Name>" mit Untergruppen je Listengruppe.
- Seitenleiste: neuer Block "Geodienste (Linkliste)" mit Liste holen, Haken je
  Dienst (Name, Gruppe, Herkunft, Stil-Hinweis), alle an/aus und Ausgewaehlte
  laden.
- Die Liste kommt fertig aufgeloest vom Server; das Plugin rechnet nichts nach.

Zwei Dinge, die der Test gezeigt hat (tools/headless_dienste_test.py, QGIS 4.2
ohne Fenster gegen die Live-Schnittstelle):

* Die Adressform muss schlicht "url=<Adresse>" sein, wie in
  Plugin_SN_Basis/modules/LayerLoader.py. Mit einem selbst gebauten
  QgsDataSourceUri (crs, format) kam der ArcGIS-Layer erst nach 60 s und
  ungueltig zurueck; jetzt 0,4 s und 4457 Objekte.
* Ein 404 auf style.qml erreicht QgsBlockingNetworkRequest als Transportfehler.
  Erst den Statuscode ansehen, sonst meldet das Plugin einen Fehler, wo schlicht
  kein Stil hinterlegt ist.

Testlauf 11.09.2026: 44 Dienste in 0,8 s, Layer gueltig, Stil angewendet,
"kein Stil hinterlegt" sauber gemeldet — 0 Fehler.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
erik
2026-09-11 17:37:58 +02:00
co-authored by Claude Opus 5
parent 6b0ce65c61
commit c8b723b653
4 changed files with 417 additions and 4 deletions
+70 -4
View File
@@ -11,8 +11,9 @@ Aufbau von oben nach unten:
1. Anmeldung — Status + Knopf (Anmelden/Abmelden)
2. Verfahren — Suchfeld (filtert) + Auswahlliste
3. Layer — Auswahl der Gruppen, laden, Änderungen speichern
4. Darstellung — Stil speichern (mit Häkchen „für alle Verfahren")
5. Statuszeile
4. Geodienste — die Linkliste des Verfahrens: auswählen und als Layer laden
5. Darstellung — Stil speichern (mit Häkchen „für alle Verfahren")
6. Statuszeile
Der frühere GeoJSON-Weg (Kopie laden, später als Ganzes hochladen) ist am 08.09.2026
entfallen (Erik: „das Speichern via OGC einbauen, GeoJSON nicht mehr verwenden"). Über
@@ -22,7 +23,8 @@ nur die offenen Bearbeitungssitzungen.
from qgis.PyQt.QtCore import Qt
from qgis.PyQt.QtWidgets import (QCheckBox, QComboBox, QDockWidget, QFrame, QGroupBox,
QHBoxLayout, QLabel, QLineEdit, QPushButton, QSizePolicy,
QHBoxLayout, QLabel, QLineEdit, QListWidget,
QListWidgetItem, QPushButton, QSizePolicy,
QVBoxLayout, QWidget)
PANEL_TITEL = "VLN Karten"
@@ -64,6 +66,7 @@ class VlnPanel(QDockWidget):
aussen.addWidget(self._bau_anmeldung())
aussen.addWidget(self._bau_verfahren())
aussen.addWidget(self._bau_layer())
aussen.addWidget(self._bau_dienste())
aussen.addWidget(self._bau_darstellung())
aussen.addStretch(1)
aussen.addWidget(self._bau_status())
@@ -143,6 +146,66 @@ class VlnPanel(QDockWidget):
"jede Änderung sofort zurück.")))
return kasten
def _bau_dienste(self):
"""Die Linkliste des gewählten Verfahrens — vierstufig gepflegt, 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.
"""
kasten = QGroupBox("Geodienste (Linkliste)")
lage = QVBoxLayout(kasten)
lage.setSpacing(6)
lage.addWidget(_klein(QLabel("WMS-, WFS- und ArcGIS-Dienste für dieses Verfahren.")))
self.dienste_liste = QListWidget()
self.dienste_liste.setMinimumHeight(140)
self.dienste_liste.setToolTip("Angehakte Dienste werden geladen")
lage.addWidget(self.dienste_liste)
zeile = QHBoxLayout()
self.dienste_holen_knopf = QPushButton("Liste holen")
self.dienste_holen_knopf.clicked.connect(lambda: self._ruf("dienste_holen"))
self.dienste_laden_knopf = QPushButton("Ausgewählte laden")
self.dienste_laden_knopf.clicked.connect(lambda: self._ruf("dienste_laden"))
zeile.addWidget(self.dienste_holen_knopf)
zeile.addWidget(self.dienste_laden_knopf)
lage.addLayout(zeile)
self.dienste_alle = QPushButton("alle an- oder abwählen")
self.dienste_alle.setFlat(True)
self.dienste_alle.clicked.connect(self._dienste_umschalten)
lage.addWidget(self.dienste_alle)
return kasten
def _dienste_umschalten(self):
"""Alles an, wenn noch etwas aus ist; sonst alles aus."""
etwas_aus = any(self.dienste_liste.item(i).checkState() != Qt.CheckState.Checked
for i in range(self.dienste_liste.count()))
ziel = Qt.CheckState.Checked if etwas_aus else Qt.CheckState.Unchecked
for i in range(self.dienste_liste.count()):
self.dienste_liste.item(i).setCheckState(ziel)
def set_dienste(self, dienste):
"""Die geholte Liste anzeigen: Name, Gruppe 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 "")
if d.get("stil"):
text += " · mit Stil"
eintrag = QListWidgetItem(text)
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 ""))
self.dienste_liste.addItem(eintrag)
def gewaehlte_dienste(self):
"""Die angehakten Einträge als Liste der Server-Datensätze."""
aus = []
for i in range(self.dienste_liste.count()):
e = self.dienste_liste.item(i)
if e.checkState() == Qt.CheckState.Checked:
aus.append(e.data(Qt.ItemDataRole.UserRole))
return aus
def _bau_darstellung(self):
kasten = QGroupBox("Darstellung")
lage = QVBoxLayout(kasten)
@@ -174,7 +237,9 @@ class VlnPanel(QDockWidget):
self.login_knopf.setVisible(not angemeldet)
self.logout_knopf.setVisible(angemeldet)
for widget in (self.filter_feld, self.combo, self.ogc_knopf, self.speichern_knopf,
self.stil_knopf, self.vorlage_haken, *self.gruppen_haken.values()):
self.stil_knopf, self.vorlage_haken, self.dienste_holen_knopf,
self.dienste_laden_knopf, self.dienste_alle, self.dienste_liste,
*self.gruppen_haken.values()):
widget.setEnabled(angemeldet)
if not angemeldet:
self._stumm = True
@@ -182,6 +247,7 @@ class VlnPanel(QDockWidget):
self.combo.clear()
self.combo.addItem("— bitte anmelden —", None)
self.filter_feld.clear()
self.dienste_liste.clear()
self._stumm = False
def set_verfahren(self, verfahren):