Beim Erstellen einer §38-/§41-Vorlage wertet BasemapLegende die Kacheln des sichtbaren basemap.de-Layers im Verfahrensgebiet (wahlweise Druckbereich) kachelweise über selectByGeometry aus, prüft die Renderer-Styles mit derselben Zoomlogik wie QGIS und bildet daraus Legendeneinträge. Ein Mehrfachauswahl-Dialog (neu: ask_mehrfachauswahl) lässt Kategorien abwählen; die Auswahl wird im Projekt gemerkt. Die gewählten Einträge stehen mit der Signatur des Projektlayers (zoomabhängige Werte festgeschrieben) in einem eigenen Legendenelement über der Quellenangabe. Ein eigenes Element ist nötig, weil die nach Karteninhalt filternde Hauptlegende die Hilfslayer ausblenden würde. Wrapper um die nötigen QGIS-/Qt-Symbole mit Mock ergänzt (eigener Block in qgiscore_wrapper; QgsRectangle hatte bisher keinen Mock). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
472 lines
19 KiB
Python
472 lines
19 KiB
Python
"""
|
||
sn_basis/modules/basemap_legende.py – Legende für den basemap.de-Vektorkachel-Layer
|
||
|
||
QGIS erzeugt für Vektorkachel-Layer keine Legende. Dieses Modul wertet aus, welche
|
||
Objekte des Basemap-Layers im Auswertebereich (Verfahrensgebiet oder Druckbereich)
|
||
tatsächlich dargestellt werden, lässt den Nutzer Kategorien abwählen und schreibt die
|
||
gewählten Kategorien mit der Signatur des Projektlayers in ein eigenes Legendenelement
|
||
des Drucklayouts (``basemap_legende_layout``).
|
||
|
||
Ablauf und Festlegungen: Konzept ``docs/konzept/10_basemap_legende.md`` im Projektwissen,
|
||
Ticket Plugin_SN_Basis #88.
|
||
|
||
Aufbau:
|
||
- reine Logik ohne QGIS (Katalog, Zuordnung Style → Legendeneintrag, Vorauswahl) – im
|
||
Mock-Modus getestet,
|
||
- QGIS-Anbindung: Layer-Erkennung und Auswertebereich hier, Kachelauswertung über
|
||
``selectByGeometry`` in ``basemap_kacheln``,
|
||
- ``BasemapLegende.aktualisiere(layout)`` als Einstieg für Druck-Tab und Vorlagenerstellung.
|
||
"""
|
||
from __future__ import annotations
|
||
|
||
import json
|
||
import os
|
||
from dataclasses import dataclass, field
|
||
from typing import Any, Callable, Iterable
|
||
|
||
from sn_basis.functions.qgiscore_wrapper import QgsCoordinateTransform, QgsGeometry, QgsProject
|
||
from sn_basis.functions.variable_wrapper import get_variable, set_variable
|
||
from sn_basis.modules.basemap_kacheln import ( # noqa: F401 – StilInfo/ObjektInfo gehören zur Schnittstelle
|
||
ObjektInfo,
|
||
StilInfo,
|
||
anzahl_kacheln,
|
||
qgis_filterpruefer,
|
||
sammle_objekte,
|
||
stile_aus_layer,
|
||
zoomstufen,
|
||
)
|
||
|
||
# ---------------------------------------------------------
|
||
# Konstanten und Schnittstellen
|
||
# ---------------------------------------------------------
|
||
|
||
BASEMAP_URL_KENNUNG = "gdz_basemapde_vektor"
|
||
BASEMAP_NAME_RUECKFALL = "basemap.de"
|
||
|
||
AUSWERTEBEREICH_VERFAHRENSGEBIET = "verfahrensgebiet"
|
||
AUSWERTEBEREICH_DRUCKBEREICH = "druckbereich"
|
||
AUSWERTEBEREICHE = {
|
||
AUSWERTEBEREICH_VERFAHRENSGEBIET: "Verfahrensgebiet",
|
||
AUSWERTEBEREICH_DRUCKBEREICH: "Druckbereich (Kartenausschnitt der Vorlage)",
|
||
}
|
||
|
||
# Projektvariablen (ohne Präfix sn_, siehe variable_wrapper)
|
||
AUSWERTEBEREICH_VAR = "basemap_auswertebereich"
|
||
LEGENDE_ERZEUGEN_VAR = "basemap_legende_erzeugen"
|
||
AUSWAHL_VAR = "basemap_legende_auswahl"
|
||
|
||
GRUPPE_SONSTIGES = "Sonstiges"
|
||
# Ab dieser Kachelzahl wird vor der Auswertung nachgefragt (je Kachel ein Netzabruf).
|
||
KACHELN_NACHFRAGEN_AB = 400
|
||
|
||
_STANDARD_KATALOG = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))),
|
||
"data", "basemap_legende.json")
|
||
|
||
|
||
# ---------------------------------------------------------
|
||
# Datenklassen
|
||
# ---------------------------------------------------------
|
||
|
||
@dataclass
|
||
class LegendenEintrag:
|
||
"""Ein Eintrag der Basemap-Legende."""
|
||
|
||
schluessel: str
|
||
bezeichnung: str
|
||
gruppe: str
|
||
symbol_stile: list[str]
|
||
treffer: list[str] = field(default_factory=list)
|
||
bekannt: bool = True
|
||
|
||
|
||
# ---------------------------------------------------------
|
||
# Katalog und Zuordnung (ohne QGIS)
|
||
# ---------------------------------------------------------
|
||
|
||
class Katalog:
|
||
"""Legendenkatalog aus ``data/basemap_legende.json`` mit Index Style-ID → Eintrag."""
|
||
|
||
def __init__(self, daten: dict):
|
||
self.daten = daten
|
||
self.gruppen: list[str] = list(daten.get("gruppen", []))
|
||
if GRUPPE_SONSTIGES not in self.gruppen:
|
||
self.gruppen.append(GRUPPE_SONSTIGES)
|
||
self.eintraege: list[dict] = list(daten.get("eintraege", []))
|
||
self._nie = set(daten.get("nie_in_legende", []))
|
||
self._praefixe = tuple(daten.get("nie_in_legende_praefixe", []))
|
||
self._index: dict[str, dict] = {}
|
||
self._reihenfolge: dict[str, int] = {}
|
||
for position, eintrag in enumerate(self.eintraege):
|
||
self._reihenfolge[eintrag["schluessel"]] = position
|
||
for stil_id in eintrag.get("treffer_stile", []):
|
||
self._index[stil_id] = eintrag
|
||
|
||
@classmethod
|
||
def laden(cls, pfad: str | None = None) -> "Katalog":
|
||
with open(pfad or _STANDARD_KATALOG, encoding="utf-8") as datei:
|
||
return cls(json.load(datei))
|
||
|
||
def ist_ausgeschlossen(self, stil_name: str) -> bool:
|
||
return stil_name in self._nie or (bool(self._praefixe) and stil_name.startswith(self._praefixe))
|
||
|
||
def eintrag_fuer(self, stil_name: str) -> dict | None:
|
||
return self._index.get(stil_name)
|
||
|
||
def sortierschluessel(self, eintrag: LegendenEintrag) -> tuple[int, int, str]:
|
||
gruppe = self.gruppen.index(eintrag.gruppe) if eintrag.gruppe in self.gruppen else len(self.gruppen)
|
||
return gruppe, self._reihenfolge.get(eintrag.schluessel, len(self._reihenfolge)), eintrag.bezeichnung
|
||
|
||
|
||
def stil_ist_aktiv(stil: StilInfo, zoom: int) -> bool:
|
||
"""Wie ``QgsVectorTileBasicRendererStyle.isActive``: eingeschaltet und Zoomstufe im Bereich."""
|
||
return (
|
||
stil.aktiv
|
||
and (stil.min_zoom < 0 or zoom >= stil.min_zoom)
|
||
and (stil.max_zoom < 0 or zoom <= stil.max_zoom)
|
||
)
|
||
|
||
|
||
def ermittle_getroffene_stile(
|
||
objekte: Iterable[ObjektInfo],
|
||
stile: Iterable[StilInfo],
|
||
zoom: int,
|
||
filter_trifft: Callable[[str, ObjektInfo], bool],
|
||
) -> dict[str, int]:
|
||
"""Ermittelt, welche Renderer-Styles die Objekte bei der Zoomstufe tatsächlich zeichnen.
|
||
|
||
Ein Style zeichnet ein Objekt, wenn er aktiv ist, zum Quell-Layer passt (leerer
|
||
Layername = alle Layer), denselben Geometrietyp hat und sein Filterausdruck zutrifft.
|
||
|
||
Returns
|
||
-------
|
||
dict[str, int]
|
||
Style-Name → Anzahl der gezeichneten (entdoppelten) Objekte.
|
||
"""
|
||
je_layer: dict[str, list[StilInfo]] = {}
|
||
for stil in stile:
|
||
if stil_ist_aktiv(stil, zoom):
|
||
je_layer.setdefault(stil.layer_name, []).append(stil)
|
||
|
||
treffer: dict[str, int] = {}
|
||
for objekt in objekte:
|
||
for stil in je_layer.get(objekt.layer_name, []) + je_layer.get("", []):
|
||
if stil.geometrie != objekt.geometrie:
|
||
continue
|
||
if stil.filter and not filter_trifft(stil.filter, objekt):
|
||
continue
|
||
treffer[stil.name] = treffer.get(stil.name, 0) + 1
|
||
return treffer
|
||
|
||
|
||
def bilde_eintraege(getroffene_stile: Iterable[str], katalog: Katalog) -> list[LegendenEintrag]:
|
||
"""Fasst getroffene Styles zu Legendeneinträgen zusammen, sortiert nach Gruppe und Katalog.
|
||
|
||
Ausgeschlossene Styles (Beschriftungen, Hintergrund) entfallen. Styles, die der Katalog
|
||
nicht kennt (eigene Ergänzungen, neue Basemap-Version), bilden je einen Eintrag in der
|
||
Gruppe „Sonstiges“.
|
||
"""
|
||
eintraege: dict[str, LegendenEintrag] = {}
|
||
for stil_name in getroffene_stile:
|
||
if katalog.ist_ausgeschlossen(stil_name):
|
||
continue
|
||
daten = katalog.eintrag_fuer(stil_name)
|
||
if daten is None:
|
||
schluessel = f"stil:{stil_name}"
|
||
eintrag = eintraege.setdefault(schluessel, LegendenEintrag(
|
||
schluessel=schluessel,
|
||
bezeichnung=stil_name.replace("_", " "),
|
||
gruppe=GRUPPE_SONSTIGES,
|
||
symbol_stile=[stil_name],
|
||
bekannt=False,
|
||
))
|
||
else:
|
||
eintrag = eintraege.setdefault(daten["schluessel"], LegendenEintrag(
|
||
schluessel=daten["schluessel"],
|
||
bezeichnung=daten.get("bezeichnung", daten["schluessel"]),
|
||
gruppe=daten.get("gruppe", GRUPPE_SONSTIGES),
|
||
symbol_stile=list(daten.get("symbol_stile", [])),
|
||
))
|
||
eintrag.treffer.append(stil_name)
|
||
return sorted(eintraege.values(), key=katalog.sortierschluessel)
|
||
|
||
|
||
def lies_auswahl() -> dict[str, list[str]]:
|
||
"""Liest die zuletzt im Dialog getroffene Auswahl aus der Projektvariable."""
|
||
roh = get_variable(AUSWAHL_VAR, scope="project") or ""
|
||
try:
|
||
daten = json.loads(roh) if roh else {}
|
||
except (TypeError, ValueError):
|
||
daten = {}
|
||
if not isinstance(daten, dict):
|
||
daten = {}
|
||
return {
|
||
"ausgeblendet": [str(s) for s in daten.get("ausgeblendet", [])],
|
||
"eingeblendet": [str(s) for s in daten.get("eingeblendet", [])],
|
||
}
|
||
|
||
|
||
def vorauswahl(eintraege: Iterable[LegendenEintrag], gespeichert: dict[str, list[str]] | None = None) -> set[str]:
|
||
"""Bestimmt die vorausgewählten Einträge für den Dialog.
|
||
|
||
Zuletzt abgewählte Einträge bleiben abgewählt, zuletzt gewählte bleiben gewählt. Sonst gilt:
|
||
Katalogeinträge sind gewählt, unbekannte Styles („Sonstiges“) abgewählt.
|
||
"""
|
||
gespeichert = gespeichert or {"ausgeblendet": [], "eingeblendet": []}
|
||
aus = set(gespeichert.get("ausgeblendet", []))
|
||
ein = set(gespeichert.get("eingeblendet", []))
|
||
auswahl = set()
|
||
for eintrag in eintraege:
|
||
if eintrag.schluessel in aus:
|
||
continue
|
||
if eintrag.bekannt or eintrag.schluessel in ein:
|
||
auswahl.add(eintrag.schluessel)
|
||
return auswahl
|
||
|
||
|
||
def merke_auswahl(eintraege: Iterable[LegendenEintrag], gewaehlt: Iterable[str]) -> None:
|
||
"""Speichert die Dialogauswahl in der Projektvariable (ergänzt die bisherige Auswahl)."""
|
||
gewaehlt = set(gewaehlt)
|
||
bisher = lies_auswahl()
|
||
aus = set(bisher["ausgeblendet"])
|
||
ein = set(bisher["eingeblendet"])
|
||
for eintrag in eintraege:
|
||
if eintrag.schluessel in gewaehlt:
|
||
aus.discard(eintrag.schluessel)
|
||
ein.add(eintrag.schluessel)
|
||
else:
|
||
ein.discard(eintrag.schluessel)
|
||
aus.add(eintrag.schluessel)
|
||
set_variable(AUSWAHL_VAR, json.dumps({"ausgeblendet": sorted(aus), "eingeblendet": sorted(ein)}),
|
||
scope="project")
|
||
|
||
|
||
def lies_auswertebereich() -> str:
|
||
wert = (get_variable(AUSWERTEBEREICH_VAR, scope="project") or "").strip()
|
||
return wert if wert in AUSWERTEBEREICHE else AUSWERTEBEREICH_VERFAHRENSGEBIET
|
||
|
||
|
||
def setze_auswertebereich(bereich: str) -> None:
|
||
if bereich not in AUSWERTEBEREICHE:
|
||
raise ValueError(f"Unbekannter Auswertebereich: {bereich}")
|
||
set_variable(AUSWERTEBEREICH_VAR, bereich, scope="project")
|
||
|
||
|
||
def legende_erzeugen_aktiv() -> bool:
|
||
"""Ob beim Erstellen einer Vorlage eine Basemap-Legende erzeugt wird (Standard: ja)."""
|
||
return (get_variable(LEGENDE_ERZEUGEN_VAR, scope="project") or "1").strip() != "0"
|
||
|
||
|
||
def setze_legende_erzeugen(aktiv: bool) -> None:
|
||
set_variable(LEGENDE_ERZEUGEN_VAR, "1" if aktiv else "0", scope="project")
|
||
|
||
|
||
# ---------------------------------------------------------
|
||
# Basemap-Layer erkennen
|
||
# ---------------------------------------------------------
|
||
|
||
def _aufruf(objekt: Any, methode: str, standard: Any = None) -> Any:
|
||
funktion = getattr(objekt, methode, None)
|
||
if not callable(funktion):
|
||
return standard
|
||
try:
|
||
return funktion()
|
||
except Exception:
|
||
return standard
|
||
|
||
|
||
def ist_basemap_layer(layer: Any) -> bool:
|
||
"""Erkennt den basemap.de-Vektorkachel-Layer.
|
||
|
||
Maßgeblich ist ein Vektorkachel-Layer (hat ``tileMatrixSet``), dessen Quelle die
|
||
basemap.de-Kennung enthält; der Layername dient nur als Rückfall, weil Nutzer Layer
|
||
umbenennen.
|
||
"""
|
||
if layer is None or not callable(getattr(layer, "tileMatrixSet", None)):
|
||
return False
|
||
quelle = str(_aufruf(layer, "source", "") or "").lower()
|
||
if BASEMAP_URL_KENNUNG in quelle:
|
||
return True
|
||
return BASEMAP_NAME_RUECKFALL in str(_aufruf(layer, "name", "") or "").lower()
|
||
|
||
|
||
def sichtbare_layer_der_karte(map_item: Any, project: Any) -> list[Any]:
|
||
"""Liefert die Layer, die eine Layoutkarte darstellt (Kartenthema, feste Layerliste oder Layerbaum)."""
|
||
if _aufruf(map_item, "followVisibilityPreset", False):
|
||
thema = _aufruf(map_item, "followVisibilityPresetName", "")
|
||
sammlung = _aufruf(project, "mapThemeCollection")
|
||
if thema and sammlung is not None:
|
||
try:
|
||
return list(sammlung.mapThemeVisibleLayers(thema))
|
||
except Exception:
|
||
pass
|
||
if _aufruf(map_item, "keepLayerSet", False):
|
||
layer = _aufruf(map_item, "layers", []) or []
|
||
if layer:
|
||
return list(layer)
|
||
wurzel = _aufruf(project, "layerTreeRoot")
|
||
knoten = _aufruf(wurzel, "findLayers", []) or []
|
||
return [k.layer() for k in knoten if _aufruf(k, "isVisible", False) and _aufruf(k, "layer") is not None]
|
||
|
||
|
||
def finde_basemap_layer(layer: Iterable[Any]) -> list[Any]:
|
||
return [l for l in layer if ist_basemap_layer(l)]
|
||
|
||
|
||
# ---------------------------------------------------------
|
||
# Auswertebereich
|
||
# ---------------------------------------------------------
|
||
|
||
def auswertegeometrie(
|
||
bereich: str,
|
||
map_item: Any,
|
||
project: Any,
|
||
ziel_crs: Any,
|
||
) -> tuple[Any | None, str]:
|
||
"""Bestimmt die Auswertegeometrie im Ziel-KBS.
|
||
|
||
Returns
|
||
-------
|
||
(geometrie, tatsächlicher Bereich)
|
||
Ohne Verfahrensgebiet wird auf den Druckbereich zurückgefallen.
|
||
"""
|
||
from sn_basis.functions.verfahrensgebiet_manager import get_verfahrensgebiet_layer_id
|
||
|
||
geometrie, quell_crs, genutzt = None, None, AUSWERTEBEREICH_DRUCKBEREICH
|
||
if bereich == AUSWERTEBEREICH_VERFAHRENSGEBIET:
|
||
layer_id = get_verfahrensgebiet_layer_id()
|
||
vg_layer = project.mapLayer(layer_id) if layer_id else None
|
||
if vg_layer is not None:
|
||
teile = [f.geometry() for f in vg_layer.getFeatures() if f.hasGeometry()]
|
||
if teile:
|
||
geometrie = QgsGeometry.unaryUnion(teile)
|
||
quell_crs = vg_layer.crs()
|
||
genutzt = AUSWERTEBEREICH_VERFAHRENSGEBIET
|
||
if geometrie is None:
|
||
geometrie = QgsGeometry.fromRect(map_item.extent())
|
||
quell_crs = map_item.crs()
|
||
if geometrie is None or geometrie.isEmpty():
|
||
return None, genutzt
|
||
geometrie = QgsGeometry(geometrie)
|
||
geometrie.transform(QgsCoordinateTransform(quell_crs, ziel_crs, project))
|
||
return geometrie, genutzt
|
||
|
||
|
||
# ---------------------------------------------------------
|
||
# Ablauf
|
||
# ---------------------------------------------------------
|
||
|
||
class BasemapLegende:
|
||
"""Erzeugt bzw. aktualisiert die Basemap-Legende eines Drucklayouts.
|
||
|
||
Dialog, Fortschritt und Rückfragen werden injiziert, damit der Ablauf ohne QGIS-Oberfläche
|
||
testbar bleibt.
|
||
"""
|
||
|
||
def __init__(
|
||
self,
|
||
project: Any | None = None,
|
||
katalog: Katalog | None = None,
|
||
dialog: Callable[..., list[str] | None] | None = None,
|
||
fortschritt_fabrik: Callable[..., Any] | None = None,
|
||
bestaetigen: Callable[[str, str], bool] | None = None,
|
||
melden: Callable[[str, str], None] | None = None,
|
||
) -> None:
|
||
from sn_basis.functions.dialog_wrapper import ask_mehrfachauswahl, ask_yes_no, create_progress_dialog
|
||
from sn_basis.functions.message_wrapper import info
|
||
|
||
self.project = project or QgsProject.instance()
|
||
self.katalog = katalog or Katalog.laden()
|
||
self.dialog = dialog or ask_mehrfachauswahl
|
||
self.fortschritt_fabrik = fortschritt_fabrik or create_progress_dialog
|
||
self.bestaetigen = bestaetigen or (lambda titel, text: ask_yes_no(titel, text, default=False))
|
||
self.melden = melden or (lambda titel, text: info(titel, text))
|
||
|
||
def ermittle_eintraege(self, layer: Any, geometrie: Any, massstab: float) -> list[LegendenEintrag] | None:
|
||
"""Wertet die Kacheln aus und bildet die Legendeneinträge (``None`` bei Abbruch)."""
|
||
kachelzahl = anzahl_kacheln(layer, geometrie, massstab)
|
||
if kachelzahl >= KACHELN_NACHFRAGEN_AB and not self.bestaetigen(
|
||
"Basemap-Legende",
|
||
f"Für die Basemap-Legende müssen {kachelzahl} Kacheln ausgewertet werden. "
|
||
"Das kann einige Minuten dauern. Fortfahren?",
|
||
):
|
||
return None
|
||
fortschritt = self.fortschritt_fabrik(kachelzahl, "Basemap-Legende", "Kacheln werden ausgewertet …")
|
||
|
||
def melde_fortschritt(nummer: int, gesamt: int) -> bool:
|
||
fortschritt.set_value(nummer)
|
||
return not fortschritt.is_canceled()
|
||
|
||
try:
|
||
objekte = sammle_objekte(layer, geometrie, massstab, fortschritt=melde_fortschritt)
|
||
finally:
|
||
fortschritt.close()
|
||
if objekte is None:
|
||
return None
|
||
_, darstellungszoom, kachelzoom_bruch = zoomstufen(layer, massstab)
|
||
getroffen = ermittle_getroffene_stile(
|
||
objekte, stile_aus_layer(layer), darstellungszoom,
|
||
qgis_filterpruefer(kachelzoom_bruch, darstellungszoom),
|
||
)
|
||
return bilde_eintraege(getroffen, self.katalog)
|
||
|
||
def aktualisiere(self, layout: Any, bereich: str | None = None) -> dict:
|
||
"""Erzeugt bzw. ersetzt die Basemap-Legende im Layout.
|
||
|
||
Returns
|
||
-------
|
||
dict
|
||
``status`` (``ok``, ``kein_layer``, ``keine_karte``, ``keine_eintraege``, ``abgebrochen``),
|
||
``meldung`` und ``anzahl`` (gewählte Einträge).
|
||
"""
|
||
from sn_basis.modules import basemap_legende_layout as ausgabe
|
||
|
||
map_item = ausgabe.hauptkarte(layout)
|
||
if map_item is None:
|
||
return {"status": "keine_karte", "meldung": "Das Layout enthält keine Karte.", "anzahl": 0}
|
||
basemap = finde_basemap_layer(sichtbare_layer_der_karte(map_item, self.project))
|
||
if not basemap:
|
||
return {"status": "kein_layer", "meldung": "Kein sichtbarer Basemap-Layer in der Karte.", "anzahl": 0}
|
||
layer = basemap[0]
|
||
if len(basemap) > 1:
|
||
self.melden("Basemap-Legende", f"Mehrere Basemap-Layer sichtbar – ausgewertet wird „{layer.name()}“.")
|
||
|
||
bereich = bereich or lies_auswertebereich()
|
||
geometrie, genutzt = auswertegeometrie(bereich, map_item, self.project, layer.crs())
|
||
if geometrie is None:
|
||
return {"status": "keine_eintraege", "meldung": "Kein Auswertebereich vorhanden.", "anzahl": 0}
|
||
if genutzt != bereich:
|
||
self.melden("Basemap-Legende", "Kein Verfahrensgebiet gesetzt – ausgewertet wird der Druckbereich.")
|
||
|
||
massstab = map_item.scale()
|
||
eintraege = self.ermittle_eintraege(layer, geometrie, massstab)
|
||
if eintraege is None:
|
||
return {"status": "abgebrochen", "meldung": "Auswertung abgebrochen.", "anzahl": 0}
|
||
if not eintraege:
|
||
return {"status": "keine_eintraege", "meldung": "Im Auswertebereich wurden keine Basemap-Objekte gefunden.",
|
||
"anzahl": 0}
|
||
|
||
_, darstellungszoom, kachelzoom_bruch = zoomstufen(layer, massstab)
|
||
symbole = ausgabe.baue_symbole(layer, eintraege, darstellungszoom, kachelzoom_bruch)
|
||
dialog_eintraege = [
|
||
{"schluessel": e.schluessel, "text": e.bezeichnung, "gruppe": e.gruppe,
|
||
"icon": ausgabe.vorschau_icon(symbole.get(e.schluessel))}
|
||
for e in eintraege
|
||
]
|
||
gewaehlt = self.dialog(
|
||
"Basemap-Legende",
|
||
f"Im {AUSWERTEBEREICHE[genutzt].split(' (')[0]} kommen diese Kategorien der Basemap vor.\n"
|
||
"Abgewählte Kategorien erscheinen nicht in der Legende.",
|
||
dialog_eintraege,
|
||
vorauswahl(eintraege, lies_auswahl()),
|
||
)
|
||
if gewaehlt is None:
|
||
return {"status": "abgebrochen", "meldung": "Auswahl abgebrochen.", "anzahl": 0}
|
||
merke_auswahl(eintraege, gewaehlt)
|
||
gewaehlte_eintraege = [e for e in eintraege if e.schluessel in set(gewaehlt)]
|
||
hinweis = ausgabe.schreibe_legende(layout, map_item, gewaehlte_eintraege, symbole, self.project,
|
||
bereich=genutzt, massstab=massstab)
|
||
if hinweis:
|
||
self.melden("Basemap-Legende", hinweis)
|
||
anzahl = len(gewaehlte_eintraege)
|
||
return {"status": "ok", "meldung": f"{anzahl} Einträge in der Basemap-Legende.", "anzahl": anzahl}
|