Basemap-Legende: Auswertung und Legendenelement im Drucklayout (#88)
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>
This commit is contained in:
@@ -409,3 +409,113 @@ def create_progress_dialog(total: int, title: str = "Fortschritt", label: str =
|
||||
"""von Test abgesehen, weil vernachlässigbar; HD 18.09.2026"""
|
||||
return ProgressDialog(total, title, label)
|
||||
|
||||
|
||||
|
||||
def ask_mehrfachauswahl(
|
||||
titel: str,
|
||||
hinweis: str,
|
||||
eintraege: list[dict],
|
||||
vorauswahl: set[str] | list[str],
|
||||
parent: Any = None,
|
||||
) -> Optional[list[str]]:
|
||||
"""Zeigt eine Liste mit Häkchen, in der Einträge an- und abgewählt werden.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
eintraege :
|
||||
Dicts mit ``schluessel`` und ``text``, optional ``gruppe`` (Zwischenüberschrift; Einträge
|
||||
einer Gruppe müssen aufeinander folgen) und ``icon`` (z. B. Symbolvorschau).
|
||||
vorauswahl :
|
||||
Schlüssel der anfangs angehakten Einträge.
|
||||
|
||||
Returns
|
||||
-------
|
||||
list[str] | None
|
||||
Schlüssel der angehakten Einträge in Listenreihenfolge, ``None`` bei Abbruch.
|
||||
Im Mock-Modus die Vorauswahl.
|
||||
"""
|
||||
vorauswahl = set(vorauswahl)
|
||||
if QT_VERSION == 0: # Mock-Modus
|
||||
return [e["schluessel"] for e in eintraege if e["schluessel"] in vorauswahl]
|
||||
|
||||
from sn_basis.functions.qt_wrapper import (
|
||||
QDialog, QDialogButtonBox, QFont, QHBoxLayout, QLabel, QListWidget, QListWidgetItem, QPushButton,
|
||||
QVBoxLayout, DialogAccepted, ItemIsEnabled, ItemIsUserCheckable, CheckStateChecked,
|
||||
CheckStateUnchecked, UserRole,
|
||||
)
|
||||
|
||||
dialog = QDialog(parent)
|
||||
dialog.setWindowTitle(titel)
|
||||
layout = QVBoxLayout(dialog)
|
||||
|
||||
beschriftung = QLabel(hinweis)
|
||||
beschriftung.setWordWrap(True)
|
||||
layout.addWidget(beschriftung)
|
||||
|
||||
suche = QLineEdit()
|
||||
suche.setPlaceholderText("Suche …")
|
||||
layout.addWidget(suche)
|
||||
|
||||
liste = QListWidget()
|
||||
kopf_schrift = QFont()
|
||||
kopf_schrift.setBold(True)
|
||||
zeilen: list[tuple[Any, dict]] = []
|
||||
koepfe: dict[str, Any] = {}
|
||||
letzte_gruppe = None
|
||||
for eintrag in eintraege:
|
||||
gruppe = eintrag.get("gruppe")
|
||||
if gruppe and gruppe != letzte_gruppe:
|
||||
kopf = QListWidgetItem(gruppe)
|
||||
kopf.setFlags(ItemIsEnabled)
|
||||
kopf.setFont(kopf_schrift)
|
||||
liste.addItem(kopf)
|
||||
koepfe[gruppe] = kopf
|
||||
letzte_gruppe = gruppe
|
||||
zeile = QListWidgetItem(eintrag["text"])
|
||||
if eintrag.get("icon") is not None:
|
||||
zeile.setIcon(eintrag["icon"])
|
||||
zeile.setFlags(ItemIsUserCheckable | ItemIsEnabled)
|
||||
zeile.setCheckState(CheckStateChecked if eintrag["schluessel"] in vorauswahl else CheckStateUnchecked)
|
||||
zeile.setData(UserRole, eintrag["schluessel"])
|
||||
liste.addItem(zeile)
|
||||
zeilen.append((zeile, eintrag))
|
||||
layout.addWidget(liste, 1)
|
||||
|
||||
def _filtern(text: str) -> None:
|
||||
suchtext = text.strip().lower()
|
||||
sichtbare_gruppen = set()
|
||||
for zeile, eintrag in zeilen:
|
||||
treffer = not suchtext or suchtext in eintrag["text"].lower() \
|
||||
or suchtext in (eintrag.get("gruppe") or "").lower()
|
||||
zeile.setHidden(not treffer)
|
||||
if treffer:
|
||||
sichtbare_gruppen.add(eintrag.get("gruppe"))
|
||||
for gruppe, kopf in koepfe.items():
|
||||
kopf.setHidden(gruppe not in sichtbare_gruppen)
|
||||
|
||||
def _alle_setzen(zustand: Any) -> None:
|
||||
for zeile, _ in zeilen:
|
||||
if not zeile.isHidden():
|
||||
zeile.setCheckState(zustand)
|
||||
|
||||
suche.textChanged.connect(_filtern)
|
||||
|
||||
knopfzeile = QHBoxLayout()
|
||||
alle = QPushButton("Alle auswählen")
|
||||
alle.clicked.connect(lambda *_: _alle_setzen(CheckStateChecked))
|
||||
keine = QPushButton("Keine auswählen")
|
||||
keine.clicked.connect(lambda *_: _alle_setzen(CheckStateUnchecked))
|
||||
knopfzeile.addWidget(alle)
|
||||
knopfzeile.addWidget(keine)
|
||||
knopfzeile.addStretch(1)
|
||||
layout.addLayout(knopfzeile)
|
||||
|
||||
knoepfe = QDialogButtonBox(QDialogButtonBox.StandardButton.Ok | QDialogButtonBox.StandardButton.Cancel)
|
||||
knoepfe.accepted.connect(dialog.accept)
|
||||
knoepfe.rejected.connect(dialog.reject)
|
||||
layout.addWidget(knoepfe)
|
||||
dialog.resize(460, 560)
|
||||
|
||||
if exec_dialog(dialog) != DialogAccepted:
|
||||
return None
|
||||
return [eintrag["schluessel"] for zeile, eintrag in zeilen if zeile.checkState() == CheckStateChecked]
|
||||
|
||||
Reference in New Issue
Block a user