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:
@@ -872,6 +872,261 @@ except Exception:
|
||||
|
||||
QgsJsonExporter = _MockQgsJsonExporter
|
||||
|
||||
# ---------------------------------------------------------
|
||||
# Vektorkacheln, Ausdrücke, Symbole und Legende (Basemap-Legende, Basis #88)
|
||||
# Eigener Block, damit ein fehlendes Symbol den übrigen Wrapper nicht in den Mock-Modus zwingt.
|
||||
# ---------------------------------------------------------
|
||||
|
||||
QgsVectorTileLayer: Type[Any]
|
||||
QgsSelectionContext: Type[Any]
|
||||
QgsTileXYZ: Type[Any]
|
||||
QgsExpression: Type[Any]
|
||||
QgsExpressionContext: Type[Any]
|
||||
QgsExpressionContextScope: Type[Any]
|
||||
QgsProperty: Type[Any]
|
||||
QgsCategorizedSymbolRenderer: Type[Any]
|
||||
QgsRendererCategory: Type[Any]
|
||||
QgsLegendRenderer: Type[Any]
|
||||
QgsLegendStyle: Type[Any]
|
||||
QgsMapLayer: Type[Any]
|
||||
QgsApplication: Type[Any]
|
||||
QgsSymbolLayerUtils: Type[Any]
|
||||
QgsLayoutMeasurement: Type[Any]
|
||||
QgsLayoutUtils: Type[Any]
|
||||
SELECT_BEHAVIOR_SET: Any = None
|
||||
SELECT_RELATION_INTERSECT: Any = None
|
||||
PROPERTY_TYPE_EXPRESSION: Any = None
|
||||
LEGEND_STYLE_HIDDEN: Any = None
|
||||
LEGEND_STYLE_SUBGROUP: Any = None
|
||||
STYLE_CATEGORIES_SYMBOLOGIE_BESCHRIFTUNG: Any = None
|
||||
VECTOR_TILES_AVAILABLE = False
|
||||
|
||||
try:
|
||||
from qgis.core import (
|
||||
QgsVectorTileLayer as _QgsVectorTileLayer,
|
||||
QgsSelectionContext as _QgsSelectionContext,
|
||||
QgsTileXYZ as _QgsTileXYZ,
|
||||
QgsExpression as _QgsExpression,
|
||||
QgsExpressionContext as _QgsExpressionContext,
|
||||
QgsExpressionContextScope as _QgsExpressionContextScope,
|
||||
QgsProperty as _QgsProperty,
|
||||
QgsCategorizedSymbolRenderer as _QgsCategorizedSymbolRenderer,
|
||||
QgsRendererCategory as _QgsRendererCategory,
|
||||
QgsLegendRenderer as _QgsLegendRenderer,
|
||||
QgsLegendStyle as _QgsLegendStyle,
|
||||
QgsMapLayer as _QgsMapLayer,
|
||||
QgsApplication as _QgsApplication,
|
||||
QgsSymbolLayerUtils as _QgsSymbolLayerUtils,
|
||||
QgsLayoutMeasurement as _QgsLayoutMeasurement,
|
||||
QgsLayoutUtils as _QgsLayoutUtils,
|
||||
Qgis as _QgisVT,
|
||||
)
|
||||
|
||||
QgsVectorTileLayer = _QgsVectorTileLayer
|
||||
QgsSelectionContext = _QgsSelectionContext
|
||||
QgsTileXYZ = _QgsTileXYZ
|
||||
QgsExpression = _QgsExpression
|
||||
QgsExpressionContext = _QgsExpressionContext
|
||||
QgsExpressionContextScope = _QgsExpressionContextScope
|
||||
QgsProperty = _QgsProperty
|
||||
QgsCategorizedSymbolRenderer = _QgsCategorizedSymbolRenderer
|
||||
QgsRendererCategory = _QgsRendererCategory
|
||||
QgsLegendRenderer = _QgsLegendRenderer
|
||||
QgsLegendStyle = _QgsLegendStyle
|
||||
QgsMapLayer = _QgsMapLayer
|
||||
QgsApplication = _QgsApplication
|
||||
QgsSymbolLayerUtils = _QgsSymbolLayerUtils
|
||||
QgsLayoutMeasurement = _QgsLayoutMeasurement
|
||||
QgsLayoutUtils = _QgsLayoutUtils
|
||||
|
||||
SELECT_BEHAVIOR_SET = _QgisVT.SelectBehavior.SetSelection
|
||||
SELECT_RELATION_INTERSECT = _QgisVT.SelectGeometryRelationship.Intersect
|
||||
PROPERTY_TYPE_EXPRESSION = getattr(getattr(_QgsProperty, "Type", None), "ExpressionBasedProperty", None)
|
||||
if PROPERTY_TYPE_EXPRESSION is None:
|
||||
PROPERTY_TYPE_EXPRESSION = getattr(_QgsProperty, "ExpressionBasedProperty", None)
|
||||
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)
|
||||
STYLE_CATEGORIES_SYMBOLOGIE_BESCHRIFTUNG = _kategorie.Symbology | _kategorie.Labeling
|
||||
VECTOR_TILES_AVAILABLE = True
|
||||
|
||||
except Exception:
|
||||
VECTOR_TILES_AVAILABLE = False
|
||||
|
||||
class _MockQgsVectorTileLayer:
|
||||
"""Platzhalter: Vektorkachel-Layer gibt es im Mock-Modus nicht."""
|
||||
|
||||
class _MockQgsSelectionContext:
|
||||
def __init__(self):
|
||||
self._scale = 0.0
|
||||
|
||||
def setScale(self, scale: float) -> None:
|
||||
self._scale = scale
|
||||
|
||||
def scale(self) -> float:
|
||||
return self._scale
|
||||
|
||||
class _MockQgsTileXYZ:
|
||||
def __init__(self, column: int = 0, row: int = 0, zoom: int = 0):
|
||||
self._column, self._row, self._zoom = column, row, zoom
|
||||
|
||||
def column(self) -> int:
|
||||
return self._column
|
||||
|
||||
def row(self) -> int:
|
||||
return self._row
|
||||
|
||||
def zoomLevel(self) -> int:
|
||||
return self._zoom
|
||||
|
||||
class _MockQgsExpression:
|
||||
def __init__(self, text: str = ""):
|
||||
self._text = text
|
||||
|
||||
def prepare(self, context: Any) -> bool:
|
||||
return True
|
||||
|
||||
def evaluate(self, context: Any = None) -> Any:
|
||||
return True
|
||||
|
||||
class _MockQgsExpressionContextScope:
|
||||
def __init__(self, name: str = ""):
|
||||
self._variables: dict[str, Any] = {}
|
||||
|
||||
def setVariable(self, name: str, value: Any, *args: Any) -> None:
|
||||
self._variables[name] = value
|
||||
|
||||
def variable(self, name: str) -> Any:
|
||||
return self._variables.get(name)
|
||||
|
||||
class _MockQgsExpressionContext:
|
||||
def __init__(self):
|
||||
self._scopes: list[Any] = []
|
||||
self._feature: Any = None
|
||||
|
||||
def appendScope(self, scope: Any) -> None:
|
||||
self._scopes.append(scope)
|
||||
|
||||
def setFeature(self, feature: Any) -> None:
|
||||
self._feature = feature
|
||||
|
||||
class _MockQgsProperty:
|
||||
def __init__(self, value: Any = None):
|
||||
self._value = value
|
||||
|
||||
@staticmethod
|
||||
def fromValue(value: Any) -> "_MockQgsProperty":
|
||||
return _MockQgsProperty(value)
|
||||
|
||||
class _MockQgsRendererCategory:
|
||||
def __init__(self, value: Any = None, symbol: Any = None, label: str = ""):
|
||||
self._value, self._symbol, self._label = value, symbol, label
|
||||
|
||||
def value(self) -> Any:
|
||||
return self._value
|
||||
|
||||
def symbol(self) -> Any:
|
||||
return self._symbol
|
||||
|
||||
def label(self) -> str:
|
||||
return self._label
|
||||
|
||||
class _MockQgsCategorizedSymbolRenderer:
|
||||
def __init__(self, attribute: str = "", categories: list | None = None):
|
||||
self._attribute = attribute
|
||||
self._categories = list(categories or [])
|
||||
|
||||
def categories(self) -> list:
|
||||
return list(self._categories)
|
||||
|
||||
class _MockQgsLegendStyle:
|
||||
Hidden = 0
|
||||
Group = 1
|
||||
Subgroup = 2
|
||||
|
||||
class _MockQgsLegendRenderer:
|
||||
@staticmethod
|
||||
def setNodeLegendStyle(node: Any, style: Any) -> None:
|
||||
setattr(node, "_legend_style", style)
|
||||
|
||||
class _MockQgsMapLayer:
|
||||
class StyleCategory:
|
||||
Symbology = 1
|
||||
Labeling = 2
|
||||
|
||||
class _MockQgsApplication:
|
||||
@staticmethod
|
||||
def qgisSettingsDirPath() -> str:
|
||||
return ""
|
||||
|
||||
class _MockQgsSymbolLayerUtils:
|
||||
@staticmethod
|
||||
def symbolPreviewIcon(symbol: Any, size: Any, *args: Any) -> Any:
|
||||
return None
|
||||
|
||||
QgsVectorTileLayer = _MockQgsVectorTileLayer
|
||||
QgsSelectionContext = _MockQgsSelectionContext
|
||||
QgsTileXYZ = _MockQgsTileXYZ
|
||||
QgsExpression = _MockQgsExpression
|
||||
QgsExpressionContext = _MockQgsExpressionContext
|
||||
QgsExpressionContextScope = _MockQgsExpressionContextScope
|
||||
QgsProperty = _MockQgsProperty
|
||||
QgsCategorizedSymbolRenderer = _MockQgsCategorizedSymbolRenderer
|
||||
QgsRendererCategory = _MockQgsRendererCategory
|
||||
QgsLegendRenderer = _MockQgsLegendRenderer
|
||||
QgsLegendStyle = _MockQgsLegendStyle
|
||||
QgsMapLayer = _MockQgsMapLayer
|
||||
QgsApplication = _MockQgsApplication
|
||||
QgsSymbolLayerUtils = _MockQgsSymbolLayerUtils
|
||||
|
||||
class _MockQgsLayoutMeasurement:
|
||||
def __init__(self, length: float = 0.0, units: Any = None):
|
||||
self._length = length
|
||||
|
||||
def length(self) -> float:
|
||||
return self._length
|
||||
|
||||
QgsLayoutMeasurement = _MockQgsLayoutMeasurement
|
||||
|
||||
class _MockQgsLayoutUtils:
|
||||
@staticmethod
|
||||
def createRenderContextForLayout(layout: Any, painter: Any, dpi: float = -1) -> Any:
|
||||
return None
|
||||
|
||||
QgsLayoutUtils = _MockQgsLayoutUtils
|
||||
|
||||
# QgsRectangle hatte im allgemeinen Mock-Block keinen Ersatz (nur Typannotation).
|
||||
if "QgsRectangle" not in globals():
|
||||
class _MockQgsRectangle:
|
||||
def __init__(self, x_min: float = 0.0, y_min: float = 0.0, x_max: float = 0.0, y_max: float = 0.0):
|
||||
self._werte = (x_min, y_min, x_max, y_max)
|
||||
|
||||
def xMinimum(self) -> float:
|
||||
return self._werte[0]
|
||||
|
||||
def yMinimum(self) -> float:
|
||||
return self._werte[1]
|
||||
|
||||
def xMaximum(self) -> float:
|
||||
return self._werte[2]
|
||||
|
||||
def yMaximum(self) -> float:
|
||||
return self._werte[3]
|
||||
|
||||
def width(self) -> float:
|
||||
return self._werte[2] - self._werte[0]
|
||||
|
||||
def height(self) -> float:
|
||||
return self._werte[3] - self._werte[1]
|
||||
|
||||
QgsRectangle = _MockQgsRectangle
|
||||
SELECT_BEHAVIOR_SET = 0
|
||||
SELECT_RELATION_INTERSECT = 0
|
||||
PROPERTY_TYPE_EXPRESSION = 2
|
||||
LEGEND_STYLE_HIDDEN = _MockQgsLegendStyle.Hidden
|
||||
LEGEND_STYLE_SUBGROUP = _MockQgsLegendStyle.Subgroup
|
||||
STYLE_CATEGORIES_SYMBOLOGIE_BESCHRIFTUNG = 3
|
||||
|
||||
# ---------------------------------------------------------
|
||||
# Netzwerk
|
||||
# ---------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user