From c8b723b653ee09c80bc3258e93f526f1410486ad Mon Sep 17 00:00:00 2001 From: erik Date: Fri, 11 Sep 2026 17:37:58 +0200 Subject: [PATCH] =?UTF-8?q?Geodienste=20aus=20der=20Linkliste=20laden=20?= =?UTF-8?q?=E2=80=94=20je=20Verfahren,=20aus=20der=20Seitenleiste?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 " 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=" 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 --- tools/headless_dienste_test.py | 89 ++++++++++++++ vln_karten/linkliste.py | 205 +++++++++++++++++++++++++++++++++ vln_karten/panel.py | 74 +++++++++++- vln_karten/plugin.py | 53 +++++++++ 4 files changed, 417 insertions(+), 4 deletions(-) create mode 100644 tools/headless_dienste_test.py create mode 100644 vln_karten/linkliste.py diff --git a/tools/headless_dienste_test.py b/tools/headless_dienste_test.py new file mode 100644 index 0000000..0fffa0e --- /dev/null +++ b/tools/headless_dienste_test.py @@ -0,0 +1,89 @@ +# -*- coding: utf-8 -*- +"""Die Linkliste im Plugin: holen, Layer bauen, Stil anwenden — gegen die echte Schnittstelle. + +Aufruf (macOS, QGIS 4.2 im Bundle; VLN_TOKEN = API-Key aus dem Login): + + APP=/Applications/QGIS-final-4_2_0.app; LIB="$APP/Contents/Resources/python3.12" + QT_QPA_PLATFORM=offscreen PROJ_DATA="$APP/Contents/Resources/qgis/proj" \\ + PYTHONPATH="$LIB:$LIB/lib-dynload:$LIB/site-packages" \\ + "$APP/Contents/MacOS/python3.12" tools/headless_dienste_test.py +""" +import os, sys, tempfile, time +sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) +from qgis.core import QgsApplication, QgsNetworkAccessManager, QgsProject + +app = QgsApplication([], True) +QgsApplication.setPrefixPath("/Applications/QGIS-final-4_2_0.app/Contents/MacOS", True) +QgsApplication.setPluginPath("/Applications/QGIS-final-4_2_0.app/Contents/PlugIns/qgis") +app.initQgis() +from qgis.PyQt.QtNetwork import QNetworkProxyFactory, QNetworkDiskCache +QNetworkProxyFactory.setUseSystemConfiguration(False) +c = QNetworkDiskCache(); c.setCacheDirectory(tempfile.mkdtemp()) +QgsNetworkAccessManager.instance().setCache(c) + +from vln_karten import linkliste as LL +from vln_karten.api_client import KartenApiClient + +BASE, KEY, VKZ = "https://api.flurneuordnung-sachsen.de/v2", os.environ["VLN_TOKEN"], "27027" +FEHLER = [] + + +def pruefe(b, t): + print((" OK " if b else " FEHL ") + t) + if not b: + FEHLER.append(t) + + +client = KartenApiClient(base_url=BASE, api_key=KEY) +print("== 1) Liste holen ==") +t = time.time() +dienste = LL.dienste_laden(client, VKZ) +pruefe(len(dienste) > 0, "%d Dienste in %.2f s" % (len(dienste), time.time() - t)) +pruefe(all({"name", "provider", "url", "herkunft"} <= set(d) for d in dienste), + "alle Felder vorhanden, die der Layerbau braucht") + +print("== 2) Layer bauen, je Anbieter einer ==") +gebaut = {} +for d in dienste: + p = d["provider"] + if p in gebaut: + continue + t = time.time() + lyr = LL.layer_bauen(d) + ok = lyr is not None and lyr.isValid() + gebaut[p] = ok + pruefe(ok, "%-5s %-34s %s (%.1f s)" % (p, d["name"][:34], + "gueltig" if ok else (lyr.error().message()[:60] if lyr else "kein Layer"), + time.time() - t)) + if ok and hasattr(lyr, "featureCount"): + print(" Features:", lyr.featureCount()) + +print("== 3) Stil aus der Datenbank anwenden ==") +mit_stil = [d for d in dienste if d.get("stil")] +if mit_stil: + d = mit_stil[0] + lyr = LL.layer_bauen(d) + if lyr is not None and lyr.isValid(): + vorher = lyr.renderer().type() if hasattr(lyr, "renderer") and lyr.renderer() else "-" + ok, meldung = LL.stil_anwenden(lyr, BASE, d["id"], KEY) + nachher = lyr.renderer().type() if hasattr(lyr, "renderer") and lyr.renderer() else "-" + pruefe(ok, "Stil fuer '%s': %s (Renderer %s -> %s)" % (d["name"], meldung or "angewendet", + vorher, nachher)) + else: + print(" (Layer nicht gueltig, Stil nicht pruefbar)") +else: + print(" (kein Eintrag mit Stil)") + +print("== 4) ohne Stil meldet sauber ==") +ohne = [d for d in dienste if not d.get("stil")] +if ohne: + lyr = LL.layer_bauen(ohne[0]) + if lyr is not None and lyr.isValid(): + ok, meldung = LL.stil_anwenden(lyr, BASE, ohne[0]["id"], KEY) + pruefe(not ok and "kein Stil" in meldung, "Meldung statt Fehler: %s" % meldung) + +app.exitQgis() +print("== %d Fehler ==" % len(FEHLER)) +for f in FEHLER: + print(" -", f) +sys.exit(1 if FEHLER else 0) diff --git a/vln_karten/linkliste.py b/vln_karten/linkliste.py new file mode 100644 index 0000000..b02f8c8 --- /dev/null +++ b/vln_karten/linkliste.py @@ -0,0 +1,205 @@ +# -*- coding: utf-8 -*- +"""Linkliste der Geodienste — die Dienste eines Verfahrens als QGIS-Layer. + +Die Liste kommt vom VLN-Manager (``GET /v2/linkliste?vkz=…``) und ist dort vierstufig gepflegt: +landesweit, Landkreis, Team und Verfahren erben aufeinander. Das Plugin bekommt bereits die +**aufgelöste** Liste — es muss nichts zusammenrechnen, sondern nur laden. Je Eintrag steht dabei, +woher er stammt (``herkunft``), damit man in QGIS sieht, ob ein Dienst landesweit gilt oder nur +für dieses eine Verfahren eingetragen wurde. + +Vier Anbieter kommen vor, jeder braucht in QGIS eine andere Datenquelle: + +========== ================================================================ +``wms`` ``QgsRasterLayer`` mit ``crs``/``format``/``layers``/``url`` +``wfs`` ``QgsVectorLayer`` mit ``typename`` (Anbieter ``WFS``) +``rest`` ``QgsVectorLayer`` auf den ArcGIS-FeatureServer +``geojson`` ``QgsVectorLayer`` über ``ogr`` (Datei oder Adresse) +========== ================================================================ + +Der Stil liegt beim Eintrag in der Datenbank und kommt über +``GET /v2/linkliste/{id}/style.qml``; ohne Stil bleibt die QGIS-Vorgabe. +""" +import os +import tempfile + +from qgis.PyQt.QtCore import Qt, QTimer, QUrl +from qgis.PyQt.QtNetwork import QNetworkRequest +from qgis.PyQt.QtWidgets import QProgressBar +from qgis.core import ( + Qgis, + QgsApplication, + QgsBlockingNetworkRequest, + QgsNetworkAccessManager, + QgsDataSourceUri, + QgsProject, + QgsRasterLayer, + QgsVectorLayer, +) + +from .api_client import ApiError + +#: Gruppenname im Ebenenbaum — alle Dienste eines Verfahrens landen darunter. +GRUPPE = "Geodienste" + +#: Vorgaben für WMS-Anfragen; dieselben Werte nutzt das Web-GIS (karte/doku/hintergrund.md). +WMS_FORMAT = "image/png" +WMS_CRS = "EPSG:25833" + + +def dienste_laden(client, vkz): + """``GET /linkliste?vkz=…`` -> Liste der aufgelösten Einträge. + + :raises ApiError: wenn die Antwort nicht das erwartete Format hat. + """ + daten = client._request("GET", "/linkliste?vkz=%s" % vkz) + zeilen = daten.get("dienste") if isinstance(daten, dict) else None + if not isinstance(zeilen, list): + raise ApiError("Antwort von /linkliste hat ein unerwartetes Format.") + return zeilen + + +def stil_url(base_url, eintrag_id): + return "%s/linkliste/%s/style.qml" % (base_url.rstrip("/"), eintrag_id) + + +def stil_anwenden(layer, base_url, eintrag_id, api_key=None): + """Den Stil des Eintrags holen und anwenden. Ohne Stil (404) bleibt alles, wie es ist. + + :returns: ``(True, "")`` oder ``(False, Meldung)``. + """ + req = QNetworkRequest(QUrl(stil_url(base_url, eintrag_id))) + if api_key: + req.setRawHeader(b"X-API-Key", api_key.encode("utf-8")) + blk = QgsBlockingNetworkRequest() + fehler = blk.get(req) + antwort = blk.reply() + code = antwort.attribute(QNetworkRequest.Attribute.HttpStatusCodeAttribute) + # Ein 404 kommt beim blockierenden Aufruf als Transportfehler an — erst den Statuscode + # ansehen, sonst meldet das Plugin einen Fehler, wo schlicht kein Stil hinterlegt ist. + if code == 404: + return False, "kein Stil hinterlegt" + if fehler != QgsBlockingNetworkRequest.NoError and not code: + return False, blk.errorMessage() + if code != 200: + return False, "HTTP %s" % code + pfad = os.path.join(tempfile.gettempdir(), "vln_dienst_%s.qml" % eintrag_id) + with open(pfad, "wb") as fh: + fh.write(bytes(antwort.content())) + meldung, ok = layer.loadNamedStyle(pfad) + if ok: + layer.triggerRepaint() + return bool(ok), "" if ok else meldung + + +def layer_bauen(eintrag, zeit_ms=20000): + """Einen Eintrag der Linkliste in einen QGIS-Layer verwandeln. + + Die Adressform ist die, die sich in ``Plugin_SN_Basis/modules/LayerLoader.py`` bewährt hat: + schlicht ``url=``, bei WFS zusätzlich ``typename=``. Ein selbst gebautes + ``QgsDataSourceUri`` mit ``crs``/``format`` führte beim ArcGIS-Anbieter dazu, dass der + Layer nach einer Minute ungültig zurückkam (gemessen 11.09.2026). + + :param zeit_ms: Netzwerk-Zeitlimit für die netzgebundenen Anbieter. + :returns: Layer oder ``None``, wenn der Anbieter unbekannt ist. + """ + name = str(eintrag.get("name") or "Dienst") + provider = str(eintrag.get("provider") or "").lower() + url = str(eintrag.get("url") or "").strip() + ebene = str(eintrag.get("layer") or "").strip() + + if provider in ("wms", "wfs", "rest"): + try: + verwalter = QgsNetworkAccessManager.instance() + if hasattr(verwalter, "setTimeout"): + verwalter.setTimeout(zeit_ms) + except Exception: # noqa: BLE001 + pass + + if provider == "wms": + uri = url if url.lower().startswith("url=") else "url=" + url + if ebene and "layers=" not in uri: + uri = "layers=%s format=%s crs=%s %s" % (ebene, WMS_FORMAT, WMS_CRS, uri) + return QgsRasterLayer(uri, name, "wms") + + if provider == "wfs": + basis = url[4:] if url.lower().startswith("url=") else url + uri = "url=" + basis + if ebene: + uri += " typename=" + ebene + return QgsVectorLayer(uri, name, "WFS") + + if provider == "rest": + # Die Adresse zeigt meist schon auf den Layer (…/FeatureServer/3). Fehlt der Index, + # wird der aus der Liste angehängt, sonst 0 — der Anbieter braucht einen. + ziel = url.rstrip("/") + if ziel.lower().endswith("/featureserver") or ziel.lower().endswith("/mapserver"): + ziel = "%s/%s" % (ziel, ebene or "0") + return QgsVectorLayer("url=" + ziel, name, "arcgisfeatureserver") + + if provider in ("geojson", "ogr"): + return QgsVectorLayer(url, name, "ogr") + + return None + + +def dienste_hinzufuegen(iface, base_url, vkz, vkz_name, dienste, api_key=None, nur_ids=None): + """Die Dienste als Layer in die Gruppe „Geodienste“ hängen — **schrittweise**. + + Wie beim Laden der Verfahrenslayer wird je Ereignisschleifen-Durchlauf genau ein Layer + angelegt: WMS- und WFS-Anbieter fragen beim Anlegen ihre Capabilities ab, und bei zwanzig + Diensten friert die Oberfläche sonst sichtbar ein. Untergruppen entstehen je Gruppe der + Liste (Hintergrund, Wasser, Natur …), damit der Ebenenbaum lesbar bleibt. + + :param nur_ids: nur diese Einträge laden (``None`` = alle). + :returns: die Meldung mit dem Fortschrittsbalken. + """ + auswahl = [d for d in dienste if nur_ids is None or int(d.get("id", 0)) in nur_ids] + projekt = QgsProject.instance() + wurzel = projekt.layerTreeRoot() + oben_name = ("%s %s %s" % (GRUPPE, vkz, vkz_name or "")).strip() + oben = wurzel.findGroup(oben_name) or wurzel.insertGroup(0, oben_name) + untergruppen = {} + + balken = QProgressBar() + balken.setMaximum(max(1, len(auswahl))) + balken.setValue(0) + balken.setAlignment(Qt.AlignmentFlag.AlignLeft | Qt.AlignmentFlag.AlignVCenter) + meldung = iface.messageBar().createMessage("VLN Karten", "Geodienste werden geladen …") + meldung.layout().addWidget(balken) + iface.messageBar().pushWidget(meldung, Qgis.Info) + + zustand = {"i": 0, "geladen": 0, "fehler": []} + + def schritt(): + if zustand["i"] >= len(auswahl): + iface.messageBar().popWidget(meldung) + text = "%d Geodienste geladen." % zustand["geladen"] + if zustand["fehler"]: + text += " %d nicht ladbar: %s" % (len(zustand["fehler"]), + ", ".join(zustand["fehler"][:3])) + iface.messageBar().pushMessage( + "VLN Karten", text, + level=Qgis.Success if zustand["geladen"] else Qgis.Warning, duration=10) + return + eintrag = auswahl[zustand["i"]] + zustand["i"] += 1 + gruppe_name = str(eintrag.get("gruppe_name") or "Sonstiges") + if gruppe_name not in untergruppen: + untergruppen[gruppe_name] = (oben.findGroup(gruppe_name) + or oben.addGroup(gruppe_name)) + layer = layer_bauen(eintrag) + if layer is not None and layer.isValid(): + if eintrag.get("stil"): + stil_anwenden(layer, base_url, eintrag.get("id"), api_key) + projekt.addMapLayer(layer, False) + untergruppen[gruppe_name].addLayer(layer) + zustand["geladen"] += 1 + else: + zustand["fehler"].append(str(eintrag.get("name") or "?")) + balken.setValue(zustand["i"]) + meldung.setText("Geodienste werden geladen … %d von %d (%s)" + % (zustand["i"], len(auswahl), eintrag.get("name"))) + QTimer.singleShot(0, schritt) + + QTimer.singleShot(0, schritt) + return meldung diff --git a/vln_karten/panel.py b/vln_karten/panel.py index fcb0b0b..d92260b 100644 --- a/vln_karten/panel.py +++ b/vln_karten/panel.py @@ -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): diff --git a/vln_karten/plugin.py b/vln_karten/plugin.py index 4348b23..b5f1a5b 100644 --- a/vln_karten/plugin.py +++ b/vln_karten/plugin.py @@ -19,6 +19,7 @@ from qgis.core import Qgis, QgsDataSourceUri, QgsProject from .api_client import ApiError, AuthError, KartenApiClient from .panel import VlnPanel from .login_dialog import LoginDialog, SETTINGS_GROUP +from . import linkliste from . import ogc_layers MENU_TITLE = "&VLN Karten" @@ -50,6 +51,8 @@ class VlnKartenPlugin: "verfahren_gewaehlt": self.on_verfahren_changed, "load_ogc": self.run_load_ogc, "save_edits": self.run_save_edits, + "dienste_holen": self.run_dienste_holen, + "dienste_laden": self.run_dienste_laden, "save_style": self.run_save_style, }, ) @@ -288,6 +291,56 @@ class VlnKartenPlugin: if self.panel is not None: self.panel.set_status("%d von %d Layern gespeichert." % (len(gespeichert), len(offen))) + def run_dienste_holen(self): + """Die Linkliste des gewählten Verfahrens holen und in der Seitenleiste anzeigen. + + Der Server liefert sie bereits aufgelöst: landesweit, Landkreis, Team und Verfahren + sind zusammengeführt, geerbte Einträge tragen ihre Herkunft. Das Plugin rechnet nichts + nach, es zeigt und lädt. + """ + if not self._ensure_logged_in(): + return + vkz = self._current_vkz() + if not vkz: + self._show_error("Kein Verfahren", "Bitte zuerst ein Verfahren auswählen.") + return + try: + dienste = linkliste.dienste_laden(self.client, vkz) + except AuthError: + self._handle_session_expired() + return + except ApiError as exc: + self._show_error("Linkliste", str(exc)) + return + self.panel.set_dienste(dienste) + herkunft = {} + for d in dienste: + herkunft[d.get("herkunft_text") or "?"] = herkunft.get(d.get("herkunft_text") or "?", 0) + 1 + text = ", ".join("%d %s" % (n, k) for k, n in herkunft.items()) or "nichts hinterlegt" + self.panel.set_status("%d Geodienste: %s" % (len(dienste), text)) + self.iface.messageBar().pushMessage( + "VLN Karten", "%d Geodienste für dieses Verfahren (%s)." % (len(dienste), text), + level=Qgis.Info, duration=6) + + def run_dienste_laden(self): + """Die angehakten Dienste als Layer in die Gruppe „Geodienste" hängen.""" + if not self._ensure_logged_in(): + return + vkz = self._current_vkz() + if not vkz: + self._show_error("Kein Verfahren", "Bitte zuerst ein Verfahren auswählen.") + return + gewaehlt = self.panel.gewaehlte_dienste() + if not gewaehlt: + self._show_error("Nichts ausgewählt", + "Bitte zuerst die Liste holen und dann die gewünschten Dienste " + "anhaken.") + return + linkliste.dienste_hinzufuegen( + self.iface, self.client.base_url, vkz, self.panel.aktueller_text(), gewaehlt, + api_key=self.client.api_key) + self.panel.set_status("%d Geodienste werden geladen …" % len(gewaehlt)) + def run_save_style(self): """Den Stil des aktiven OGC-Layers auf den Server zurückschreiben.