Basemap: Punktlinien in Karte und Legende sichtbar machen (#90)
basemap.de zeichnet Punktlinien mit Strichlänge 0 und runder Linienkappe (MapLibre-Muster); QGIS übernimmt das beim Import 1:1, Qt zeichnet Striche der Länge 0 aber nicht. Baumreihen, Hecken, Durchlässe, Seilbahnen u. a. (12 Styles) fehlten dadurch in Karte und Legende. Neues Modul basemap_stilkorrektur: korrigiere_punktlinien(layer) ersetzt Strichlänge 0 durch 0,01 im festen Strichmuster und in den array(...)-Mustern des zoomabhängigen Ausdrucks; idempotent, andere Styles unverändert. Ausgelöst per Knopf „Punktlinien korrigieren“ im Basemap-Bereich, sicherbar als Stilvorlage. Wrapper: PROPERTY_CUSTOM_DASH, QgsProperty.fromExpression im Mock. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
- Bugfix: Punktlinien des Basemap-Layers (Baumreihe, Hecke, Durchlass, Seilbahnen u. a., 12 Styles) wurden in Karte und Legende nicht gezeichnet – basemap.de nutzt Strichlänge 0 mit runder Kappe, Qt zeichnet Striche der Länge 0 nicht. Neuer Knopf „Punktlinien korrigieren“ im Basemap-Bereich des Druck-Tabs ersetzt die Strichlänge 0 durch 0,01 (festes Muster und zoomabhängiger Ausdruck); die Korrektur lässt sich als Stilvorlage sichern (#90)
|
||||
- Basemap-Legende für Drucklayouts (#88): Beim Erstellen einer §38-/§41-Vorlage wird ausgewertet, welche Objekte des basemap.de-Vektorkachel-Layers im Verfahrensgebiet (wahlweise im Druckbereich) tatsächlich dargestellt werden; ein Auswahldialog lässt Kategorien abwählen, die gewählten erscheinen mit der Signatur des Projektlayers in einem eigenen Legendenelement „Kartengrundlage (basemap.de)“ über der Quellenangabe. Zuordnung von 434 Basemap-Styles zu 190 Legendeneinträgen (Beschriftungen, Nummernschilder und Hintergrund ausgenommen) in `data/basemap_legende.json` (erzeugt mit `modules/basemap_katalog.py`, fachlich nachbearbeitet)
|
||||
- Neuer einklappbarer Bereich „Basemap“ im Druck-Tab: Auswertebereich, Basemap-Legende beim Erstellen an/aus, „Basemap-Legende aktualisieren“ für bestehende Vorlagen und lokale Stilvorlagen des Basemap-Layers (mehrere Varianten, laden, speichern, als Standard markieren, löschen) – z. B. einmal Hausnummern ausschalten und in jedem Projekt wieder laden (#88)
|
||||
- Neuer allgemeiner Dialog `ask_mehrfachauswahl` (Liste mit Häkchen, Gruppen, Suche, Symbolvorschau) in `functions/dialog_wrapper.py` (#88)
|
||||
|
||||
@@ -896,6 +896,7 @@ QgsLayoutUtils: Type[Any]
|
||||
SELECT_BEHAVIOR_SET: Any = None
|
||||
SELECT_RELATION_INTERSECT: Any = None
|
||||
PROPERTY_TYPE_EXPRESSION: Any = None
|
||||
PROPERTY_CUSTOM_DASH: Any = None
|
||||
LEGEND_STYLE_HIDDEN: Any = None
|
||||
LEGEND_STYLE_SUBGROUP: Any = None
|
||||
STYLE_CATEGORIES_SYMBOLOGIE_BESCHRIFTUNG: Any = None
|
||||
@@ -919,6 +920,7 @@ try:
|
||||
QgsSymbolLayerUtils as _QgsSymbolLayerUtils,
|
||||
QgsLayoutMeasurement as _QgsLayoutMeasurement,
|
||||
QgsLayoutUtils as _QgsLayoutUtils,
|
||||
QgsSymbolLayer as _QgsSymbolLayer,
|
||||
Qgis as _QgisVT,
|
||||
)
|
||||
|
||||
@@ -944,6 +946,12 @@ try:
|
||||
PROPERTY_TYPE_EXPRESSION = getattr(getattr(_QgsProperty, "Type", None), "ExpressionBasedProperty", None)
|
||||
if PROPERTY_TYPE_EXPRESSION is None:
|
||||
PROPERTY_TYPE_EXPRESSION = getattr(_QgsProperty, "ExpressionBasedProperty", None)
|
||||
# Schlüssel der datendefinierten Eigenschaft „eigenes Strichmuster“ als int (Basis #90);
|
||||
# propertyKeys() liefert ints, das Enum ist je nach QGIS-Version gescoped oder nicht.
|
||||
_strichmuster = getattr(getattr(_QgsSymbolLayer, "Property", None), "CustomDash", None)
|
||||
if _strichmuster is None:
|
||||
_strichmuster = getattr(_QgsSymbolLayer, "PropertyCustomDash", None)
|
||||
PROPERTY_CUSTOM_DASH = int(getattr(_strichmuster, "value", _strichmuster))
|
||||
LEGEND_STYLE_HIDDEN = getattr(getattr(_QgsLegendStyle, "Style", _QgsLegendStyle), "Hidden", None)
|
||||
LEGEND_STYLE_SUBGROUP = getattr(getattr(_QgsLegendStyle, "Style", _QgsLegendStyle), "Subgroup", None)
|
||||
_kategorie = getattr(_QgsMapLayer, "StyleCategory", _QgsMapLayer)
|
||||
@@ -1018,6 +1026,15 @@ except Exception:
|
||||
def fromValue(value: Any) -> "_MockQgsProperty":
|
||||
return _MockQgsProperty(value)
|
||||
|
||||
@staticmethod
|
||||
def fromExpression(expression: str, is_active: bool = True) -> "_MockQgsProperty":
|
||||
eigenschaft = _MockQgsProperty()
|
||||
eigenschaft._ausdruck = expression
|
||||
return eigenschaft
|
||||
|
||||
def expressionString(self) -> str:
|
||||
return getattr(self, "_ausdruck", "")
|
||||
|
||||
class _MockQgsRendererCategory:
|
||||
def __init__(self, value: Any = None, symbol: Any = None, label: str = ""):
|
||||
self._value, self._symbol, self._label = value, symbol, label
|
||||
@@ -1123,6 +1140,7 @@ except Exception:
|
||||
SELECT_BEHAVIOR_SET = 0
|
||||
SELECT_RELATION_INTERSECT = 0
|
||||
PROPERTY_TYPE_EXPRESSION = 2
|
||||
PROPERTY_CUSTOM_DASH = 36
|
||||
LEGEND_STYLE_HIDDEN = _MockQgsLegendStyle.Hidden
|
||||
LEGEND_STYLE_SUBGROUP = _MockQgsLegendStyle.Subgroup
|
||||
STYLE_CATEGORIES_SYMBOLOGIE_BESCHRIFTUNG = 3
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
"""
|
||||
sn_basis/modules/basemap_stilkorrektur.py – Darstellungsfehler des Basemap-Layers korrigieren
|
||||
|
||||
Punktlinien (Baumreihe, Hecke, Durchlass, Seilbahnen …) zeichnet basemap.de wie in MapLibre
|
||||
üblich mit einem Strichmuster der Strichlänge 0 und runder Linienkappe. QGIS übernimmt das beim
|
||||
Import der Style-JSON 1:1, Qt zeichnet Striche der Länge 0 aber nicht – die Objekte fehlen in
|
||||
Karte und Legende (Basis #90, geprüft mit QGIS 3.44 / PyQt 5.15). ``korrigiere_punktlinien``
|
||||
ersetzt die Strichlänge 0 durch ``MINDESTSTRICH`` – im festen Strichmuster und im
|
||||
zoomabhängigen Ausdruck. Mit runder Kappe ergibt das wieder runde Punkte.
|
||||
|
||||
Die Korrektur verändert die Darstellung des Layers im Projekt und wird nur auf Wunsch des
|
||||
Nutzers ausgeführt (Basemap-Bereich im Druck-Tab); sichern lässt sie sich als Stilvorlage.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
from typing import Any
|
||||
|
||||
from sn_basis.functions.qgiscore_wrapper import PROPERTY_CUSTOM_DASH, PROPERTY_TYPE_EXPRESSION, QgsProperty
|
||||
|
||||
# Kleinste Strichlänge (in Vielfachen der Linienbreite bzw. Mustereinheit), die Qt zeichnet.
|
||||
MINDESTSTRICH = 0.01
|
||||
|
||||
# array(...) mit reiner Zahlenliste, wie sie der QGIS-Konverter für line-dasharray erzeugt
|
||||
_ZAHLENFELD = re.compile(r"array\(\s*(-?\d+(?:\.\d+)?(?:\s*,\s*-?\d+(?:\.\d+)?)*)\s*\)")
|
||||
|
||||
|
||||
def _ist_null(wert: Any) -> bool:
|
||||
try:
|
||||
return float(wert) == 0.0
|
||||
except (TypeError, ValueError):
|
||||
return False
|
||||
|
||||
|
||||
def korrigiere_muster(werte: list) -> list:
|
||||
"""Ersetzt Strichlängen 0 (gerade Positionen) im Strichmuster; Lücken bleiben unverändert."""
|
||||
return [MINDESTSTRICH if i % 2 == 0 and _ist_null(w) else w for i, w in enumerate(werte)]
|
||||
|
||||
|
||||
def korrigiere_ausdruck(ausdruck: str) -> str:
|
||||
"""Ersetzt Strichlängen 0 in allen ``array(...)``-Strichmustern eines Ausdrucks."""
|
||||
def ersetze(treffer: re.Match) -> str:
|
||||
teile = [t.strip() for t in treffer.group(1).split(",")]
|
||||
neu = [str(MINDESTSTRICH) if i % 2 == 0 and _ist_null(t) else t for i, t in enumerate(teile)]
|
||||
return treffer.group(0) if neu == teile else f"array({','.join(neu)})"
|
||||
|
||||
return _ZAHLENFELD.sub(ersetze, ausdruck)
|
||||
|
||||
|
||||
def _korrigiere_symbol(symbol: Any) -> bool:
|
||||
"""Korrigiert alle Symbolebenen eines Symbols (auch Untersymbole). Liefert, ob sich etwas geändert hat."""
|
||||
geaendert = False
|
||||
for ebene in symbol.symbolLayers():
|
||||
nutzt_muster = getattr(ebene, "useCustomDashPattern", None)
|
||||
if callable(nutzt_muster) and nutzt_muster():
|
||||
alt = list(ebene.customDashVector())
|
||||
neu = korrigiere_muster(alt)
|
||||
if neu != alt:
|
||||
ebene.setCustomDashVector(neu)
|
||||
geaendert = True
|
||||
eigenschaften = ebene.dataDefinedProperties()
|
||||
if PROPERTY_CUSTOM_DASH in eigenschaften.propertyKeys():
|
||||
eigenschaft = eigenschaften.property(PROPERTY_CUSTOM_DASH)
|
||||
if eigenschaft.propertyType() == PROPERTY_TYPE_EXPRESSION:
|
||||
alt_ausdruck = eigenschaft.expressionString()
|
||||
neu_ausdruck = korrigiere_ausdruck(alt_ausdruck)
|
||||
if neu_ausdruck != alt_ausdruck:
|
||||
eigenschaften.setProperty(PROPERTY_CUSTOM_DASH, QgsProperty.fromExpression(neu_ausdruck))
|
||||
geaendert = True
|
||||
unter = ebene.subSymbol()
|
||||
if unter is not None and _korrigiere_symbol(unter):
|
||||
geaendert = True
|
||||
return geaendert
|
||||
|
||||
|
||||
def korrigiere_punktlinien(layer: Any) -> int:
|
||||
"""Macht Punktlinien des Basemap-Layers sichtbar.
|
||||
|
||||
Returns
|
||||
-------
|
||||
int
|
||||
Anzahl der korrigierten Renderer-Styles (0, wenn nichts zu tun war).
|
||||
"""
|
||||
renderer = layer.renderer()
|
||||
if renderer is None:
|
||||
return 0
|
||||
anzahl = 0
|
||||
for index, stil in enumerate(renderer.styles()):
|
||||
symbol = stil.symbol()
|
||||
if symbol is None:
|
||||
continue
|
||||
kopie = symbol.clone()
|
||||
if _korrigiere_symbol(kopie):
|
||||
stil.setSymbol(kopie)
|
||||
renderer.setStyle(index, stil)
|
||||
anzahl += 1
|
||||
if anzahl:
|
||||
layer.triggerRepaint()
|
||||
return anzahl
|
||||
@@ -161,6 +161,23 @@ class TestBasemapBereich(unittest.TestCase):
|
||||
layer, "Neu", {"ausgeblendet": ["wald"], "eingeblendet": []})
|
||||
bereich.aktualisieren.assert_called_once()
|
||||
|
||||
@patch("sn_basis.ui.widgets.basemap_bereich.success")
|
||||
@patch("sn_basis.ui.widgets.basemap_bereich.korrigiere_punktlinien", return_value=12)
|
||||
def test_punktlinien_korrigieren_meldet_anzahl(self, korrektur, erfolg):
|
||||
"""Prüft, dass „Punktlinien korrigieren“ den Basemap-Layer korrigiert und die Anzahl korrigierter Styles meldet."""
|
||||
layer = MagicMock()
|
||||
_bereich(layer=layer)._on_punktlinien_korrigieren()
|
||||
korrektur.assert_called_once_with(layer)
|
||||
self.assertIn("12", erfolg.call_args[0][1])
|
||||
|
||||
@patch("sn_basis.ui.widgets.basemap_bereich.warning")
|
||||
@patch("sn_basis.ui.widgets.basemap_bereich.korrigiere_punktlinien")
|
||||
def test_punktlinien_ohne_basemap_layer_warnt(self, korrektur, warnung):
|
||||
"""Prüft, dass ohne Basemap-Layer nichts korrigiert, sondern gewarnt wird."""
|
||||
_bereich(layer=None)._on_punktlinien_korrigieren()
|
||||
korrektur.assert_not_called()
|
||||
warnung.assert_called_once()
|
||||
|
||||
@patch("sn_basis.ui.widgets.basemap_bereich.warning")
|
||||
def test_stil_speichern_ohne_basemap_layer_warnt(self, warnung):
|
||||
"""Prüft, dass ohne Basemap-Layer keine Stilvorlage gespeichert, sondern gewarnt wird."""
|
||||
|
||||
@@ -0,0 +1,149 @@
|
||||
"""
|
||||
Tests für modules/basemap_stilkorrektur.py – Punktlinien des Basemap-Layers sichtbar machen (Basis #90).
|
||||
|
||||
basemap.de zeichnet Punktlinien mit Strichlänge 0 und runder Kappe; Qt zeichnet Striche der
|
||||
Länge 0 nicht. Die Korrektur ersetzt Strichlänge 0 durch einen kleinen Wert – im festen
|
||||
Strichmuster und im zoomabhängigen Ausdruck. Symbole und Layer sind Fakes; die Wirkung in
|
||||
Karte und Legende ist im QGIS-Test geprüft.
|
||||
"""
|
||||
import unittest
|
||||
|
||||
from sn_basis.functions.qgiscore_wrapper import PROPERTY_CUSTOM_DASH, PROPERTY_TYPE_EXPRESSION
|
||||
from sn_basis.modules.basemap_stilkorrektur import (
|
||||
MINDESTSTRICH,
|
||||
korrigiere_ausdruck,
|
||||
korrigiere_muster,
|
||||
korrigiere_punktlinien,
|
||||
)
|
||||
|
||||
# Ausdruck, wie ihn der QGIS-Konverter für line-dasharray mit Stopps erzeugt (gekürzt)
|
||||
AUSDRUCK_BAUMREIHE = (
|
||||
"array_to_string(array_foreach(CASE WHEN @vector_tile_zoom <= 12 THEN array(0,1.75) "
|
||||
"WHEN @vector_tile_zoom > 12 AND @vector_tile_zoom <= 14 THEN array(0,2) "
|
||||
"ELSE array(0,4) END,@element * (scale_linear(@vector_tile_zoom,14,17,3,8))),';')"
|
||||
)
|
||||
|
||||
|
||||
class _Eigenschaft:
|
||||
def __init__(self, ausdruck):
|
||||
self._ausdruck = ausdruck
|
||||
|
||||
def propertyType(self): return PROPERTY_TYPE_EXPRESSION
|
||||
def expressionString(self): return self._ausdruck
|
||||
|
||||
|
||||
class _Eigenschaften:
|
||||
def __init__(self, ausdruck=None):
|
||||
self.werte = {PROPERTY_CUSTOM_DASH: _Eigenschaft(ausdruck)} if ausdruck else {}
|
||||
|
||||
def propertyKeys(self): return list(self.werte)
|
||||
def property(self, schluessel): return self.werte[schluessel]
|
||||
|
||||
def setProperty(self, schluessel, eigenschaft):
|
||||
text = getattr(eigenschaft, "_ausdruck", None) or getattr(eigenschaft, "_value", None)
|
||||
self.werte[schluessel] = _Eigenschaft(text)
|
||||
|
||||
|
||||
class _Linie:
|
||||
def __init__(self, muster=None, ausdruck=None):
|
||||
self.muster = list(muster) if muster is not None else None
|
||||
self.eigenschaften = _Eigenschaften(ausdruck)
|
||||
|
||||
def useCustomDashPattern(self): return self.muster is not None
|
||||
def customDashVector(self): return list(self.muster or [])
|
||||
def setCustomDashVector(self, werte): self.muster = list(werte)
|
||||
def dataDefinedProperties(self): return self.eigenschaften
|
||||
def subSymbol(self): return None
|
||||
|
||||
|
||||
class _Symbol:
|
||||
def __init__(self, *ebenen): self.ebenen = list(ebenen)
|
||||
def symbolLayers(self): return self.ebenen
|
||||
def clone(self): return self # die Fakes prüfen nur das Ergebnis
|
||||
|
||||
|
||||
class _Stil:
|
||||
def __init__(self, name, symbol): self._name, self._symbol = name, symbol
|
||||
def styleName(self): return self._name
|
||||
def symbol(self): return self._symbol
|
||||
def setSymbol(self, symbol): self._symbol = symbol
|
||||
|
||||
|
||||
class _Renderer:
|
||||
def __init__(self, stile):
|
||||
self.stile = stile
|
||||
self.gesetzt = []
|
||||
|
||||
def styles(self): return list(self.stile)
|
||||
|
||||
def setStyle(self, index, stil):
|
||||
self.gesetzt.append(index)
|
||||
self.stile[index] = stil
|
||||
|
||||
|
||||
class _Layer:
|
||||
def __init__(self, stile):
|
||||
self._renderer = _Renderer(stile)
|
||||
self.neu_gezeichnet = 0
|
||||
|
||||
def renderer(self): return self._renderer
|
||||
def triggerRepaint(self): self.neu_gezeichnet += 1
|
||||
|
||||
|
||||
def _baumreihe():
|
||||
return _Stil("VegetationsL_Baumreihe", _Symbol(_Linie([0.0, 0.93], AUSDRUCK_BAUMREIHE)))
|
||||
|
||||
|
||||
class TestMusterUndAusdruck(unittest.TestCase):
|
||||
|
||||
def test_strichlaenge_null_im_festen_muster(self):
|
||||
"""Prüft, dass Strichlängen 0 (gerade Positionen) im Strichmuster ersetzt und Lücken der Länge 0 nicht verändert werden."""
|
||||
self.assertEqual(korrigiere_muster([0.0, 0.93]), [MINDESTSTRICH, 0.93])
|
||||
self.assertEqual(korrigiere_muster([2.0, 0.0, 0.0, 1.0]), [2.0, 0.0, MINDESTSTRICH, 1.0])
|
||||
self.assertEqual(korrigiere_muster([5.0, 2.0]), [5.0, 2.0])
|
||||
|
||||
def test_strichlaenge_null_im_zoomabhaengigen_ausdruck(self):
|
||||
"""Prüft, dass jede Strichlänge 0 in den array(...)-Mustern des Konverter-Ausdrucks ersetzt wird und der übrige Ausdruck gleich bleibt."""
|
||||
neu = korrigiere_ausdruck(AUSDRUCK_BAUMREIHE)
|
||||
self.assertNotIn("array(0,", neu)
|
||||
self.assertEqual(neu.count(f"array({MINDESTSTRICH},"), 3)
|
||||
self.assertIn("@element * (scale_linear(@vector_tile_zoom,14,17,3,8))", neu)
|
||||
self.assertEqual(korrigiere_ausdruck("array(3,0,1,2)"), "array(3,0,1,2)")
|
||||
self.assertEqual(korrigiere_ausdruck("array(1,0,0,2)"), f"array(1,0,{MINDESTSTRICH},2)")
|
||||
|
||||
|
||||
class TestLayerkorrektur(unittest.TestCase):
|
||||
|
||||
def test_punktlinien_werden_korrigiert_andere_styles_nicht(self):
|
||||
"""Prüft, dass nur Styles mit Strichlänge 0 korrigiert werden – Muster und Ausdruck – und die Anzahl zurückkommt."""
|
||||
weg = _Stil("Kontur_Wirtschaftsweg", _Symbol(_Linie()))
|
||||
strichlinie = _Stil("Grenze", _Symbol(_Linie([4.0, 2.0], "array_to_string(array(4,2),';')")))
|
||||
layer = _Layer([weg, _baumreihe(), strichlinie])
|
||||
|
||||
self.assertEqual(korrigiere_punktlinien(layer), 1)
|
||||
|
||||
linie = layer.renderer().styles()[1].symbol().symbolLayers()[0]
|
||||
self.assertEqual(linie.customDashVector(), [MINDESTSTRICH, 0.93])
|
||||
self.assertNotIn("array(0,", linie.dataDefinedProperties().property(PROPERTY_CUSTOM_DASH).expressionString())
|
||||
self.assertEqual(layer.renderer().gesetzt, [1])
|
||||
self.assertEqual(layer.neu_gezeichnet, 1)
|
||||
|
||||
def test_zweiter_lauf_korrigiert_nichts(self):
|
||||
"""Prüft, dass ein zweiter Lauf keine Styles mehr korrigiert und nicht neu zeichnen lässt."""
|
||||
layer = _Layer([_baumreihe()])
|
||||
korrigiere_punktlinien(layer)
|
||||
self.assertEqual(korrigiere_punktlinien(layer), 0)
|
||||
self.assertEqual(layer.neu_gezeichnet, 1)
|
||||
|
||||
def test_nur_ausdruck_ohne_festes_muster(self):
|
||||
"""Prüft, dass auch ein Style korrigiert wird, dessen Strichlänge 0 nur im zoomabhängigen Ausdruck steht."""
|
||||
layer = _Layer([_Stil("Hecke", _Symbol(_Linie([1.0, 2.0], "array_to_string(array(0,3),';')")))])
|
||||
self.assertEqual(korrigiere_punktlinien(layer), 1)
|
||||
|
||||
def test_layer_ohne_renderer(self):
|
||||
"""Prüft, dass ein Layer ohne Renderer 0 korrigierte Styles liefert."""
|
||||
self.assertEqual(korrigiere_punktlinien(type("L", (), {"renderer": lambda s: None})()), 0)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -2,8 +2,9 @@
|
||||
sn_basis/ui/widgets/basemap_bereich.py – einklappbarer Bereich „Basemap“ im Druck-Tab
|
||||
|
||||
Einstellungen der Basemap-Legende (Auswertebereich, Erzeugen beim Anlegen der Vorlage),
|
||||
„Basemap-Legende aktualisieren“ für bestehende Vorlagen und lokale Stilvorlagen des
|
||||
Basemap-Layers (laden, speichern, als Standard markieren, löschen). Basis #88.
|
||||
„Basemap-Legende aktualisieren“ für bestehende Vorlagen, lokale Stilvorlagen des
|
||||
Basemap-Layers (laden, speichern, als Standard markieren, löschen) und „Punktlinien
|
||||
korrigieren“ (Basis #90). Basis #88.
|
||||
|
||||
Die Handler enthalten nur Ablauf und Rückfragen; die Logik liegt in
|
||||
``modules/basemap_legende`` und ``modules/basemap_stilvorlagen``.
|
||||
@@ -30,6 +31,7 @@ from sn_basis.functions.qt_wrapper import (
|
||||
)
|
||||
from sn_basis.modules import basemap_legende as legende
|
||||
from sn_basis.modules.basemap_legende_layout import layouts_mit_basemap_legende
|
||||
from sn_basis.modules.basemap_stilkorrektur import korrigiere_punktlinien
|
||||
from sn_basis.modules.basemap_stilvorlagen import BasemapStilvorlagen
|
||||
|
||||
TITEL = "Basemap"
|
||||
@@ -109,6 +111,14 @@ class BasemapBereich(QWidget):
|
||||
zeile.addWidget(knopf_stil)
|
||||
spalte.addLayout(zeile)
|
||||
|
||||
self._punktlinien_btn = QPushButton("Punktlinien korrigieren", self)
|
||||
self._punktlinien_btn.setToolTip(
|
||||
"Baumreihen, Hecken, Durchlässe u. a. zeichnet QGIS aus dem Basemap-Stil nicht (Strichlänge 0). "
|
||||
"Korrigiert die Darstellung im Projekt; mit „Speichern unter …“ als Stilvorlage sichern."
|
||||
)
|
||||
self._punktlinien_btn.clicked.connect(lambda *_: self._on_punktlinien_korrigieren())
|
||||
spalte.addWidget(self._punktlinien_btn)
|
||||
|
||||
inhalt.setLayout(spalte)
|
||||
inhalt.setVisible(False)
|
||||
self._inhalt = inhalt
|
||||
@@ -162,6 +172,7 @@ class BasemapBereich(QWidget):
|
||||
self._layout_combo.clear()
|
||||
self._layout_combo.addItems(layouts_mit_basemap_legende(self._projekt()))
|
||||
self._aktualisieren_btn.setEnabled(layer is not None and self._layout_combo.count() > 0)
|
||||
self._punktlinien_btn.setEnabled(layer is not None)
|
||||
|
||||
self._stil_combo.clear()
|
||||
for vorlage in self._vorlagen().liste():
|
||||
@@ -196,6 +207,19 @@ class BasemapBereich(QWidget):
|
||||
elif ergebnis["status"] != "abgebrochen":
|
||||
info(TITEL, ergebnis["meldung"])
|
||||
|
||||
# --- Handler: Darstellung korrigieren ------------------------------
|
||||
|
||||
def _on_punktlinien_korrigieren(self) -> None:
|
||||
layer = self.basemap_layer()
|
||||
if layer is None:
|
||||
warning(TITEL, KEIN_LAYER_TEXT)
|
||||
return
|
||||
anzahl = korrigiere_punktlinien(layer)
|
||||
if anzahl:
|
||||
success(TITEL, f"{anzahl} Punktlinien-Styles korrigiert. Basemap-Legende ggf. aktualisieren.")
|
||||
else:
|
||||
info(TITEL, "Keine Punktlinien zu korrigieren.")
|
||||
|
||||
# --- Handler: Stilvorlagen ------------------------------------------
|
||||
|
||||
def _gewaehlte_vorlage(self) -> str:
|
||||
|
||||
Reference in New Issue
Block a user