2025-12-19 14:29:52 +01:00
|
|
|
|
"""
|
|
|
|
|
|
sn_basis/functions/qgiscore_wrapper.py – zentrale QGIS-Core-Abstraktion
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
2026-02-14 22:14:33 +01:00
|
|
|
|
from typing import Type, Any, Optional
|
2025-12-19 14:29:52 +01:00
|
|
|
|
from sn_basis.functions.qt_wrapper import (
|
|
|
|
|
|
QUrl,
|
|
|
|
|
|
QEventLoop,
|
|
|
|
|
|
QNetworkRequest,
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
# ---------------------------------------------------------
|
|
|
|
|
|
# QGIS-Symbole (werden dynamisch gesetzt)
|
|
|
|
|
|
# ---------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
QgsProject: Type[Any]
|
|
|
|
|
|
QgsVectorLayer: Type[Any]
|
2026-02-14 22:14:33 +01:00
|
|
|
|
QgsRasterLayer: Type[Any]
|
2025-12-19 14:29:52 +01:00
|
|
|
|
QgsNetworkAccessManager: Type[Any]
|
|
|
|
|
|
Qgis: Type[Any]
|
2026-01-08 17:13:51 +01:00
|
|
|
|
QgsMapLayerProxyModel: Type[Any]
|
2026-02-14 22:14:33 +01:00
|
|
|
|
QgsVectorFileWriter: Type[Any] # neu: Schreib-API
|
2026-03-12 16:14:02 +01:00
|
|
|
|
QgsFeature: Type[Any]
|
|
|
|
|
|
QgsField: Type[Any]
|
|
|
|
|
|
QgsGeometry: Type[Any]
|
|
|
|
|
|
QgsFeatureRequest: Type[Any]
|
|
|
|
|
|
QgsCoordinateTransform: Type[Any]
|
|
|
|
|
|
QgsCoordinateReferenceSystem: Type[Any]
|
2026-03-20 14:01:57 +01:00
|
|
|
|
QgsPrintLayout: Type[Any]
|
|
|
|
|
|
QgsLayoutItemMap: Type[Any]
|
2026-04-10 21:30:44 +02:00
|
|
|
|
QgsLayoutItemMapGrid: Type[Any]
|
|
|
|
|
|
QgsTextFormat: Type[Any]
|
|
|
|
|
|
QgsTextBackgroundSettings: Type[Any]
|
2026-03-20 14:01:57 +01:00
|
|
|
|
QgsLayoutItemLabel: Type[Any]
|
2026-03-24 07:53:04 +01:00
|
|
|
|
QgsLayoutItemLegend: Type[Any]
|
2026-03-20 14:01:57 +01:00
|
|
|
|
QgsLayoutPoint: Type[Any]
|
|
|
|
|
|
QgsLayoutSize: Type[Any]
|
|
|
|
|
|
QgsUnitTypes: Type[Any]
|
|
|
|
|
|
QgsLayoutItem: Type[Any]
|
2025-12-19 14:29:52 +01:00
|
|
|
|
|
2026-04-10 21:30:44 +02:00
|
|
|
|
MAP_GRID_STYLE_MARKERS: Any = None
|
|
|
|
|
|
MAP_GRID_STYLE_FRAME_ANNOTATIONS: Any = None
|
|
|
|
|
|
MAP_GRID_FRAME_STYLE_INTERIOR_TICKS: Any = None
|
|
|
|
|
|
MAP_GRID_UNIT_MAP_UNIT: Any = None
|
|
|
|
|
|
MAP_GRID_ANNOTATION_FORMAT_DECIMAL: Any = None
|
|
|
|
|
|
MAP_GRID_ANNOTATION_DISPLAY_HIDE_ALL: Any = None
|
|
|
|
|
|
MAP_GRID_ANNOTATION_DISPLAY_SHOW_ALL: Any = None
|
|
|
|
|
|
MAP_GRID_ANNOTATION_DISPLAY_SHOW_X: Any = None
|
|
|
|
|
|
MAP_GRID_ANNOTATION_DISPLAY_SHOW_Y: Any = None
|
|
|
|
|
|
MAP_GRID_BORDER_LEFT: Any = None
|
|
|
|
|
|
MAP_GRID_BORDER_RIGHT: Any = None
|
|
|
|
|
|
MAP_GRID_BORDER_TOP: Any = None
|
|
|
|
|
|
MAP_GRID_BORDER_BOTTOM: Any = None
|
|
|
|
|
|
MAP_GRID_ANNOTATION_POSITION_INSIDE_FRAME: Any = None
|
|
|
|
|
|
TEXT_BACKGROUND_SHAPE_RECTANGLE: Any = None
|
|
|
|
|
|
TEXT_BACKGROUND_SIZE_BUFFER: Any = None
|
|
|
|
|
|
TEXT_RENDER_UNIT_MILLIMETERS: Any = None
|
|
|
|
|
|
TEXT_RENDER_UNIT_POINTS: Any = None
|
|
|
|
|
|
|
2025-12-19 14:29:52 +01:00
|
|
|
|
QGIS_AVAILABLE = False
|
|
|
|
|
|
|
|
|
|
|
|
# ---------------------------------------------------------
|
|
|
|
|
|
# Versuch: QGIS-Core importieren
|
|
|
|
|
|
# ---------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
|
from qgis.core import (
|
|
|
|
|
|
QgsProject as _QgsProject,
|
|
|
|
|
|
QgsVectorLayer as _QgsVectorLayer,
|
2026-02-14 22:14:33 +01:00
|
|
|
|
QgsRasterLayer as _QgsRasterLayer,
|
2025-12-19 14:29:52 +01:00
|
|
|
|
QgsNetworkAccessManager as _QgsNetworkAccessManager,
|
|
|
|
|
|
Qgis as _Qgis,
|
2026-02-14 22:14:33 +01:00
|
|
|
|
QgsMapLayerProxyModel as _QgsMaplLayerProxyModel,
|
|
|
|
|
|
QgsVectorFileWriter as _QgsVectorFileWriter,
|
2026-03-12 16:14:02 +01:00
|
|
|
|
QgsFeature as _QgsFeature,
|
2026-03-06 10:20:40 +01:00
|
|
|
|
QgsField as _QgsField,
|
2026-03-12 16:14:02 +01:00
|
|
|
|
QgsGeometry as _QgsGeometry,
|
|
|
|
|
|
QgsFeatureRequest as _QgsFeatureRequest,
|
|
|
|
|
|
QgsCoordinateTransform as _QgsCoordinateTransform,
|
|
|
|
|
|
QgsCoordinateReferenceSystem as _QgsCoordinateReferenceSystem,
|
2026-03-20 14:01:57 +01:00
|
|
|
|
QgsPrintLayout as _QgsPrintLayout,
|
|
|
|
|
|
QgsLayoutItemMap as _QgsLayoutItemMap,
|
2026-04-10 21:30:44 +02:00
|
|
|
|
QgsLayoutItemMapGrid as _QgsLayoutItemMapGrid,
|
|
|
|
|
|
QgsTextFormat as _QgsTextFormat,
|
|
|
|
|
|
QgsTextBackgroundSettings as _QgsTextBackgroundSettings,
|
2026-03-20 14:01:57 +01:00
|
|
|
|
QgsLayoutItemLabel as _QgsLayoutItemLabel,
|
2026-03-24 07:53:04 +01:00
|
|
|
|
QgsLayoutItemLegend as _QgsLayoutItemLegend,
|
2026-03-20 14:01:57 +01:00
|
|
|
|
QgsLayoutPoint as _QgsLayoutPoint,
|
|
|
|
|
|
QgsLayoutSize as _QgsLayoutSize,
|
|
|
|
|
|
QgsUnitTypes as _QgsUnitTypes,
|
|
|
|
|
|
QgsLayoutItem as _QgsLayoutItem,
|
2025-12-19 14:29:52 +01:00
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
QgsProject = _QgsProject
|
|
|
|
|
|
QgsVectorLayer = _QgsVectorLayer
|
2026-02-14 22:14:33 +01:00
|
|
|
|
QgsRasterLayer = _QgsRasterLayer
|
2025-12-19 14:29:52 +01:00
|
|
|
|
QgsNetworkAccessManager = _QgsNetworkAccessManager
|
|
|
|
|
|
Qgis = _Qgis
|
2026-02-14 22:14:33 +01:00
|
|
|
|
QgsMapLayerProxyModel = _QgsMaplLayerProxyModel
|
|
|
|
|
|
QgsVectorFileWriter = _QgsVectorFileWriter
|
2026-03-06 10:20:40 +01:00
|
|
|
|
QgsFeature = _QgsFeature
|
|
|
|
|
|
QgsField = _QgsField
|
2026-03-12 16:14:02 +01:00
|
|
|
|
QgsGeometry = _QgsGeometry
|
|
|
|
|
|
QgsFeatureRequest = _QgsFeatureRequest
|
|
|
|
|
|
QgsCoordinateTransform = _QgsCoordinateTransform
|
|
|
|
|
|
QgsCoordinateReferenceSystem = _QgsCoordinateReferenceSystem
|
2026-03-20 14:01:57 +01:00
|
|
|
|
QgsPrintLayout = _QgsPrintLayout
|
|
|
|
|
|
QgsLayoutItemMap = _QgsLayoutItemMap
|
2026-04-10 21:30:44 +02:00
|
|
|
|
QgsLayoutItemMapGrid = _QgsLayoutItemMapGrid
|
|
|
|
|
|
QgsTextFormat = _QgsTextFormat
|
|
|
|
|
|
QgsTextBackgroundSettings = _QgsTextBackgroundSettings
|
2026-03-20 14:01:57 +01:00
|
|
|
|
QgsLayoutItemLabel = _QgsLayoutItemLabel
|
2026-03-24 07:53:04 +01:00
|
|
|
|
QgsLayoutItemLegend = _QgsLayoutItemLegend
|
2026-03-20 14:01:57 +01:00
|
|
|
|
QgsLayoutPoint = _QgsLayoutPoint
|
|
|
|
|
|
QgsLayoutSize = _QgsLayoutSize
|
|
|
|
|
|
QgsUnitTypes = _QgsUnitTypes
|
|
|
|
|
|
QgsLayoutItem = _QgsLayoutItem
|
2025-12-19 14:29:52 +01:00
|
|
|
|
|
2026-04-10 21:30:44 +02:00
|
|
|
|
def _resolve_qgis_enum(*paths: tuple[Any, ...]) -> Any:
|
|
|
|
|
|
for path in paths:
|
|
|
|
|
|
value: Any = path[0]
|
|
|
|
|
|
ok = True
|
|
|
|
|
|
for name in path[1:]:
|
|
|
|
|
|
value = getattr(value, name, None)
|
|
|
|
|
|
if value is None:
|
|
|
|
|
|
ok = False
|
|
|
|
|
|
break
|
|
|
|
|
|
if ok:
|
|
|
|
|
|
return value
|
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
|
|
MAP_GRID_STYLE_MARKERS = _resolve_qgis_enum(
|
|
|
|
|
|
(_Qgis, "MapGridStyle", "Markers"),
|
|
|
|
|
|
(_QgsLayoutItemMapGrid, "Markers"),
|
|
|
|
|
|
)
|
|
|
|
|
|
MAP_GRID_STYLE_FRAME_ANNOTATIONS = _resolve_qgis_enum(
|
|
|
|
|
|
(_Qgis, "MapGridStyle", "FrameAndAnnotationsOnly"),
|
|
|
|
|
|
(_QgsLayoutItemMapGrid, "FrameAndAnnotationsOnly"),
|
|
|
|
|
|
(_Qgis, "MapGridStyle", "FrameAnnotations"),
|
|
|
|
|
|
(_QgsLayoutItemMapGrid, "FrameAnnotations"),
|
|
|
|
|
|
)
|
|
|
|
|
|
MAP_GRID_FRAME_STYLE_INTERIOR_TICKS = _resolve_qgis_enum(
|
|
|
|
|
|
(_Qgis, "MapGridFrameStyle", "InteriorTicks"),
|
|
|
|
|
|
(_QgsLayoutItemMapGrid, "InteriorTicks"),
|
|
|
|
|
|
)
|
|
|
|
|
|
MAP_GRID_UNIT_MAP_UNIT = _resolve_qgis_enum(
|
|
|
|
|
|
(_Qgis, "MapGridUnit", "MapUnits"),
|
|
|
|
|
|
(_QgsLayoutItemMapGrid, "MapUnits"),
|
|
|
|
|
|
(_Qgis, "MapGridUnit", "MapUnit"),
|
|
|
|
|
|
(_QgsLayoutItemMapGrid, "MapUnit"),
|
|
|
|
|
|
)
|
|
|
|
|
|
MAP_GRID_ANNOTATION_FORMAT_DECIMAL = _resolve_qgis_enum(
|
|
|
|
|
|
(_Qgis, "MapGridAnnotationFormat", "Decimal"),
|
|
|
|
|
|
(_QgsLayoutItemMapGrid, "Decimal"),
|
|
|
|
|
|
)
|
|
|
|
|
|
MAP_GRID_ANNOTATION_DISPLAY_HIDE_ALL = _resolve_qgis_enum(
|
|
|
|
|
|
(_Qgis, "MapGridComponentVisibility", "HideAll"),
|
|
|
|
|
|
(_QgsLayoutItemMapGrid, "HideAll"),
|
|
|
|
|
|
)
|
|
|
|
|
|
MAP_GRID_ANNOTATION_DISPLAY_SHOW_ALL = _resolve_qgis_enum(
|
|
|
|
|
|
(_Qgis, "MapGridComponentVisibility", "ShowAll"),
|
|
|
|
|
|
(_QgsLayoutItemMapGrid, "ShowAll"),
|
|
|
|
|
|
)
|
|
|
|
|
|
MAP_GRID_ANNOTATION_DISPLAY_SHOW_X = _resolve_qgis_enum(
|
|
|
|
|
|
(_Qgis, "MapGridComponentVisibility", "LongitudeOnly"),
|
|
|
|
|
|
(_QgsLayoutItemMapGrid, "LongitudeOnly"),
|
|
|
|
|
|
(_Qgis, "MapGridComponentVisibility", "ShowLongitudeOnly"),
|
|
|
|
|
|
(_QgsLayoutItemMapGrid, "ShowLongitudeOnly"),
|
|
|
|
|
|
)
|
|
|
|
|
|
MAP_GRID_ANNOTATION_DISPLAY_SHOW_Y = _resolve_qgis_enum(
|
|
|
|
|
|
(_Qgis, "MapGridComponentVisibility", "LatitudeOnly"),
|
|
|
|
|
|
(_QgsLayoutItemMapGrid, "LatitudeOnly"),
|
|
|
|
|
|
(_Qgis, "MapGridComponentVisibility", "ShowLatitudeOnly"),
|
|
|
|
|
|
(_QgsLayoutItemMapGrid, "ShowLatitudeOnly"),
|
|
|
|
|
|
)
|
|
|
|
|
|
MAP_GRID_BORDER_LEFT = _resolve_qgis_enum(
|
|
|
|
|
|
(_Qgis, "MapGridBorderSide", "Left"),
|
|
|
|
|
|
(_QgsLayoutItemMapGrid, "Left"),
|
|
|
|
|
|
)
|
|
|
|
|
|
MAP_GRID_BORDER_RIGHT = _resolve_qgis_enum(
|
|
|
|
|
|
(_Qgis, "MapGridBorderSide", "Right"),
|
|
|
|
|
|
(_QgsLayoutItemMapGrid, "Right"),
|
|
|
|
|
|
)
|
|
|
|
|
|
MAP_GRID_BORDER_TOP = _resolve_qgis_enum(
|
|
|
|
|
|
(_Qgis, "MapGridBorderSide", "Top"),
|
|
|
|
|
|
(_QgsLayoutItemMapGrid, "Top"),
|
|
|
|
|
|
)
|
|
|
|
|
|
MAP_GRID_BORDER_BOTTOM = _resolve_qgis_enum(
|
|
|
|
|
|
(_Qgis, "MapGridBorderSide", "Bottom"),
|
|
|
|
|
|
(_QgsLayoutItemMapGrid, "Bottom"),
|
|
|
|
|
|
)
|
|
|
|
|
|
MAP_GRID_ANNOTATION_POSITION_INSIDE_FRAME = _resolve_qgis_enum(
|
|
|
|
|
|
(_Qgis, "MapGridAnnotationPosition", "InsideMapFrame"),
|
|
|
|
|
|
(_QgsLayoutItemMapGrid, "InsideMapFrame"),
|
|
|
|
|
|
)
|
|
|
|
|
|
TEXT_BACKGROUND_SHAPE_RECTANGLE = _resolve_qgis_enum(
|
|
|
|
|
|
(_QgsTextBackgroundSettings, "ShapeRectangle"),
|
|
|
|
|
|
)
|
|
|
|
|
|
TEXT_BACKGROUND_SIZE_BUFFER = _resolve_qgis_enum(
|
|
|
|
|
|
(_QgsTextBackgroundSettings, "SizeBuffer"),
|
|
|
|
|
|
)
|
|
|
|
|
|
TEXT_RENDER_UNIT_MILLIMETERS = _resolve_qgis_enum(
|
|
|
|
|
|
(_Qgis, "RenderUnit", "Millimeters"),
|
|
|
|
|
|
(_QgsUnitTypes, "RenderMillimeters"),
|
|
|
|
|
|
)
|
|
|
|
|
|
TEXT_RENDER_UNIT_POINTS = _resolve_qgis_enum(
|
|
|
|
|
|
(_Qgis, "RenderUnit", "Points"),
|
|
|
|
|
|
(_QgsUnitTypes, "RenderPoints"),
|
|
|
|
|
|
)
|
|
|
|
|
|
|
2025-12-19 14:29:52 +01:00
|
|
|
|
QGIS_AVAILABLE = True
|
|
|
|
|
|
|
|
|
|
|
|
# ---------------------------------------------------------
|
|
|
|
|
|
# Mock-Modus
|
|
|
|
|
|
# ---------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
except Exception:
|
|
|
|
|
|
QGIS_AVAILABLE = False
|
|
|
|
|
|
|
2026-03-20 14:01:57 +01:00
|
|
|
|
class _MockLayoutManager:
|
|
|
|
|
|
def layoutByName(self, name: str):
|
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
|
|
def addLayout(self, layout: Any) -> bool:
|
|
|
|
|
|
return True
|
|
|
|
|
|
|
2025-12-19 14:29:52 +01:00
|
|
|
|
class _MockQgsProject:
|
|
|
|
|
|
def __init__(self):
|
|
|
|
|
|
self._variables = {}
|
2026-03-20 14:01:57 +01:00
|
|
|
|
self._layout_manager = _MockLayoutManager()
|
2025-12-19 14:29:52 +01:00
|
|
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
|
|
def instance() -> "_MockQgsProject":
|
|
|
|
|
|
return _MockQgsProject()
|
|
|
|
|
|
|
|
|
|
|
|
def read(self) -> bool:
|
|
|
|
|
|
return True
|
|
|
|
|
|
|
2026-03-20 14:01:57 +01:00
|
|
|
|
def layoutManager(self):
|
|
|
|
|
|
return self._layout_manager
|
|
|
|
|
|
|
2025-12-19 14:29:52 +01:00
|
|
|
|
QgsProject = _MockQgsProject
|
|
|
|
|
|
|
|
|
|
|
|
class _MockQgsVectorLayer:
|
|
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
|
|
|
|
self._valid = True
|
|
|
|
|
|
|
|
|
|
|
|
def isValid(self) -> bool:
|
|
|
|
|
|
return self._valid
|
|
|
|
|
|
|
|
|
|
|
|
def loadNamedStyle(self, path: str):
|
|
|
|
|
|
return True, ""
|
|
|
|
|
|
|
|
|
|
|
|
def triggerRepaint(self) -> None:
|
|
|
|
|
|
pass
|
|
|
|
|
|
|
2026-02-14 22:14:33 +01:00
|
|
|
|
def dataProvider(self):
|
|
|
|
|
|
return None
|
|
|
|
|
|
|
2025-12-19 14:29:52 +01:00
|
|
|
|
QgsVectorLayer = _MockQgsVectorLayer
|
|
|
|
|
|
|
|
|
|
|
|
class _MockQgsNetworkAccessManager:
|
|
|
|
|
|
@staticmethod
|
|
|
|
|
|
def instance():
|
|
|
|
|
|
return _MockQgsNetworkAccessManager()
|
|
|
|
|
|
|
|
|
|
|
|
def head(self, request: Any):
|
|
|
|
|
|
return None
|
|
|
|
|
|
|
2026-02-14 22:14:33 +01:00
|
|
|
|
class _MockQgsRasterLayer:
|
|
|
|
|
|
"""
|
|
|
|
|
|
Minimaler Mock für QgsRasterLayer, ausreichend für Tests und
|
|
|
|
|
|
um im Datenabruf ein Raster-Layer-Objekt im pruef_ergebnis kontext mitzugeben.
|
|
|
|
|
|
"""
|
|
|
|
|
|
def __init__(self, source: str, name: str = "Raster", provider: str = "wms"):
|
|
|
|
|
|
self.source = source
|
|
|
|
|
|
self._name = name
|
|
|
|
|
|
self.provider = provider
|
|
|
|
|
|
self._valid = True
|
|
|
|
|
|
|
|
|
|
|
|
def isValid(self) -> bool:
|
|
|
|
|
|
return self._valid
|
|
|
|
|
|
|
|
|
|
|
|
def name(self) -> str:
|
|
|
|
|
|
return self._name
|
|
|
|
|
|
|
|
|
|
|
|
def dataProvider(self):
|
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
|
|
QgsRasterLayer = _MockQgsRasterLayer
|
|
|
|
|
|
|
2026-03-20 14:01:57 +01:00
|
|
|
|
class _MockQgsPrintLayout:
|
|
|
|
|
|
def __init__(self, project: Any):
|
|
|
|
|
|
self.project = project
|
|
|
|
|
|
self._name = ""
|
|
|
|
|
|
self._page = _MockQgsLayoutPage()
|
2026-04-08 13:56:58 +02:00
|
|
|
|
self.items: list[Any] = []
|
2026-03-20 14:01:57 +01:00
|
|
|
|
|
|
|
|
|
|
def initializeDefaults(self) -> None:
|
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
def setName(self, name: str) -> None:
|
|
|
|
|
|
self._name = name
|
|
|
|
|
|
|
|
|
|
|
|
def pageCollection(self):
|
|
|
|
|
|
return self
|
|
|
|
|
|
|
|
|
|
|
|
def page(self, index: int):
|
|
|
|
|
|
return self._page
|
|
|
|
|
|
|
|
|
|
|
|
def addLayoutItem(self, item: Any) -> None:
|
2026-04-08 13:56:58 +02:00
|
|
|
|
self.items.append(item)
|
2026-03-20 14:01:57 +01:00
|
|
|
|
|
|
|
|
|
|
class _MockQgsLayoutPage:
|
|
|
|
|
|
def setPageSize(self, size: Any) -> None:
|
|
|
|
|
|
self.size = size
|
|
|
|
|
|
|
|
|
|
|
|
class _MockQgsLayoutItem:
|
|
|
|
|
|
class ReferencePoint:
|
|
|
|
|
|
LowerLeft = 0
|
|
|
|
|
|
|
|
|
|
|
|
class _MockQgsLayoutItemMap:
|
|
|
|
|
|
def __init__(self, layout: Any):
|
|
|
|
|
|
self.layout = layout
|
2026-04-08 13:56:58 +02:00
|
|
|
|
self.item_id = ""
|
|
|
|
|
|
self.extent = None
|
|
|
|
|
|
self.scale = None
|
|
|
|
|
|
self.follow_visibility_preset = False
|
|
|
|
|
|
self.follow_visibility_preset_name = ""
|
|
|
|
|
|
self.keep_layer_set = False
|
2026-04-10 21:30:44 +02:00
|
|
|
|
self._grids = _MockQgsLayoutItemMapGridStack(self)
|
2026-03-20 14:01:57 +01:00
|
|
|
|
|
|
|
|
|
|
def setId(self, item_id: str) -> None:
|
2026-04-08 13:56:58 +02:00
|
|
|
|
self.item_id = item_id
|
2026-03-20 14:01:57 +01:00
|
|
|
|
|
|
|
|
|
|
def setExtent(self, extent: Any) -> None:
|
2026-04-08 13:56:58 +02:00
|
|
|
|
self.extent = extent
|
2026-03-20 14:01:57 +01:00
|
|
|
|
|
|
|
|
|
|
def setScale(self, scale: float) -> None:
|
2026-04-08 13:56:58 +02:00
|
|
|
|
self.scale = scale
|
2026-03-20 14:01:57 +01:00
|
|
|
|
|
|
|
|
|
|
def attemptMove(self, point: Any) -> None:
|
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
def attemptResize(self, size: Any) -> None:
|
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
def setFollowVisibilityPreset(self, active: bool) -> None:
|
2026-04-08 13:56:58 +02:00
|
|
|
|
self.follow_visibility_preset = active
|
2026-03-20 14:01:57 +01:00
|
|
|
|
|
|
|
|
|
|
def setFollowVisibilityPresetName(self, name: str) -> None:
|
2026-04-08 13:56:58 +02:00
|
|
|
|
self.follow_visibility_preset_name = name
|
|
|
|
|
|
|
|
|
|
|
|
def setKeepLayerSet(self, enabled: bool) -> None:
|
|
|
|
|
|
self.keep_layer_set = enabled
|
2026-03-20 14:01:57 +01:00
|
|
|
|
|
2026-04-10 21:30:44 +02:00
|
|
|
|
def grids(self):
|
|
|
|
|
|
return self._grids
|
|
|
|
|
|
|
|
|
|
|
|
def updateBoundingRect(self) -> None:
|
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
def refresh(self) -> None:
|
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
class _MockQgsLayoutItemMapGrid:
|
|
|
|
|
|
Markers = "Markers"
|
|
|
|
|
|
FrameAndAnnotationsOnly = "FrameAndAnnotationsOnly"
|
|
|
|
|
|
InteriorTicks = "InteriorTicks"
|
|
|
|
|
|
MapUnits = "MapUnits"
|
|
|
|
|
|
Decimal = "Decimal"
|
|
|
|
|
|
HideAll = "HideAll"
|
|
|
|
|
|
ShowAll = "ShowAll"
|
|
|
|
|
|
LongitudeOnly = "LongitudeOnly"
|
|
|
|
|
|
LatitudeOnly = "LatitudeOnly"
|
|
|
|
|
|
Left = "Left"
|
|
|
|
|
|
Right = "Right"
|
|
|
|
|
|
Top = "Top"
|
|
|
|
|
|
Bottom = "Bottom"
|
|
|
|
|
|
InsideMapFrame = "InsideMapFrame"
|
|
|
|
|
|
|
|
|
|
|
|
def __init__(self, name: str, map_item: Any):
|
|
|
|
|
|
self.name = name
|
|
|
|
|
|
self.map_item = map_item
|
|
|
|
|
|
self.enabled = False
|
|
|
|
|
|
self.style = None
|
|
|
|
|
|
self.units = None
|
|
|
|
|
|
self.interval_x = None
|
|
|
|
|
|
self.interval_y = None
|
|
|
|
|
|
self.annotation_enabled = False
|
|
|
|
|
|
self.annotation_format = None
|
|
|
|
|
|
self.annotation_precision = None
|
|
|
|
|
|
self.annotation_display: dict[Any, Any] = {}
|
|
|
|
|
|
self.annotation_position: dict[Any, Any] = {}
|
|
|
|
|
|
self.frame_style = None
|
|
|
|
|
|
self.annotation_text_format = None
|
|
|
|
|
|
|
|
|
|
|
|
def setEnabled(self, enabled: bool) -> None:
|
|
|
|
|
|
self.enabled = enabled
|
|
|
|
|
|
|
|
|
|
|
|
def setStyle(self, style: Any) -> None:
|
|
|
|
|
|
self.style = style
|
|
|
|
|
|
|
|
|
|
|
|
def setUnits(self, units: Any) -> None:
|
|
|
|
|
|
self.units = units
|
|
|
|
|
|
|
|
|
|
|
|
def setIntervalX(self, interval: float) -> None:
|
|
|
|
|
|
self.interval_x = interval
|
|
|
|
|
|
|
|
|
|
|
|
def setIntervalY(self, interval: float) -> None:
|
|
|
|
|
|
self.interval_y = interval
|
|
|
|
|
|
|
|
|
|
|
|
def setAnnotationEnabled(self, enabled: bool) -> None:
|
|
|
|
|
|
self.annotation_enabled = enabled
|
|
|
|
|
|
|
|
|
|
|
|
def setAnnotationFormat(self, annotation_format: Any) -> None:
|
|
|
|
|
|
self.annotation_format = annotation_format
|
|
|
|
|
|
|
|
|
|
|
|
def setAnnotationPrecision(self, precision: int) -> None:
|
|
|
|
|
|
self.annotation_precision = precision
|
|
|
|
|
|
|
|
|
|
|
|
def setAnnotationDisplay(self, display: Any, border: Any) -> None:
|
|
|
|
|
|
self.annotation_display[border] = display
|
|
|
|
|
|
|
|
|
|
|
|
def setAnnotationPosition(self, position: Any, border: Any) -> None:
|
|
|
|
|
|
self.annotation_position[border] = position
|
|
|
|
|
|
|
|
|
|
|
|
def setFrameStyle(self, frame_style: Any) -> None:
|
|
|
|
|
|
self.frame_style = frame_style
|
|
|
|
|
|
|
|
|
|
|
|
def setAnnotationTextFormat(self, annotation_text_format: Any) -> None:
|
|
|
|
|
|
self.annotation_text_format = annotation_text_format
|
|
|
|
|
|
|
|
|
|
|
|
class _MockQgsTextBackgroundSettings:
|
|
|
|
|
|
ShapeRectangle = "ShapeRectangle"
|
|
|
|
|
|
SizeBuffer = "SizeBuffer"
|
|
|
|
|
|
|
|
|
|
|
|
def __init__(self):
|
|
|
|
|
|
self.enabled = False
|
|
|
|
|
|
self.shape_type = None
|
|
|
|
|
|
self.size_type = None
|
|
|
|
|
|
self.size = None
|
|
|
|
|
|
self.size_unit = None
|
|
|
|
|
|
self.offset = None
|
|
|
|
|
|
self.offset_unit = None
|
|
|
|
|
|
self.fill_color = None
|
|
|
|
|
|
|
|
|
|
|
|
def setEnabled(self, enabled: bool) -> None:
|
|
|
|
|
|
self.enabled = enabled
|
|
|
|
|
|
|
|
|
|
|
|
def setType(self, shape_type: Any) -> None:
|
|
|
|
|
|
self.shape_type = shape_type
|
|
|
|
|
|
|
|
|
|
|
|
def setSizeType(self, size_type: Any) -> None:
|
|
|
|
|
|
self.size_type = size_type
|
|
|
|
|
|
|
|
|
|
|
|
def setSize(self, size: Any) -> None:
|
|
|
|
|
|
self.size = size
|
|
|
|
|
|
|
|
|
|
|
|
def setSizeUnit(self, unit: Any) -> None:
|
|
|
|
|
|
self.size_unit = unit
|
|
|
|
|
|
|
|
|
|
|
|
def setOffset(self, offset: Any) -> None:
|
|
|
|
|
|
self.offset = offset
|
|
|
|
|
|
|
|
|
|
|
|
def setOffsetUnit(self, unit: Any) -> None:
|
|
|
|
|
|
self.offset_unit = unit
|
|
|
|
|
|
|
|
|
|
|
|
def setFillColor(self, color: Any) -> None:
|
|
|
|
|
|
self.fill_color = color
|
|
|
|
|
|
|
|
|
|
|
|
class _MockQgsTextFormat:
|
|
|
|
|
|
def __init__(self):
|
|
|
|
|
|
self.font = None
|
|
|
|
|
|
self.size = None
|
|
|
|
|
|
self.size_unit = None
|
|
|
|
|
|
self.background = None
|
|
|
|
|
|
|
|
|
|
|
|
def setFont(self, font: Any) -> None:
|
|
|
|
|
|
self.font = font
|
|
|
|
|
|
|
|
|
|
|
|
def setSize(self, size: float) -> None:
|
|
|
|
|
|
self.size = size
|
|
|
|
|
|
|
|
|
|
|
|
def setSizeUnit(self, unit: Any) -> None:
|
|
|
|
|
|
self.size_unit = unit
|
|
|
|
|
|
|
|
|
|
|
|
def setBackground(self, background: Any) -> None:
|
|
|
|
|
|
self.background = background
|
|
|
|
|
|
|
|
|
|
|
|
class _MockQgsLayoutItemMapGridStack:
|
|
|
|
|
|
def __init__(self, map_item: Any):
|
|
|
|
|
|
self.map_item = map_item
|
|
|
|
|
|
self._grids: list[_MockQgsLayoutItemMapGrid] = []
|
|
|
|
|
|
|
|
|
|
|
|
def addGrid(self, grid: Any) -> None:
|
|
|
|
|
|
self._grids.append(grid)
|
|
|
|
|
|
|
|
|
|
|
|
def removeGrid(self, grid_id: str) -> None:
|
|
|
|
|
|
self._grids = [grid for grid in self._grids if getattr(grid, "name", "") != grid_id]
|
|
|
|
|
|
|
|
|
|
|
|
def asList(self) -> list[Any]:
|
|
|
|
|
|
return list(self._grids)
|
|
|
|
|
|
|
2026-03-20 14:01:57 +01:00
|
|
|
|
class _MockQgsLayoutItemLabel:
|
|
|
|
|
|
ModeHtml = 1
|
|
|
|
|
|
|
|
|
|
|
|
def __init__(self, layout: Any):
|
|
|
|
|
|
self.layout = layout
|
|
|
|
|
|
|
|
|
|
|
|
def setId(self, item_id: str) -> None:
|
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
def setText(self, text: str) -> None:
|
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
def setMode(self, mode: Any) -> None:
|
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
def setFont(self, font: Any) -> None:
|
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
def setReferencePoint(self, point: Any) -> None:
|
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
def attemptMove(self, point: Any) -> None:
|
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
def attemptResize(self, size: Any) -> None:
|
|
|
|
|
|
pass
|
|
|
|
|
|
|
2026-03-24 07:53:04 +01:00
|
|
|
|
class _MockLegendRootGroup:
|
|
|
|
|
|
def __init__(self) -> None:
|
|
|
|
|
|
self.layers: list[Any] = []
|
|
|
|
|
|
|
|
|
|
|
|
def clear(self) -> None:
|
|
|
|
|
|
self.layers = []
|
|
|
|
|
|
|
|
|
|
|
|
def addLayer(self, layer: Any) -> None:
|
|
|
|
|
|
self.layers.append(layer)
|
|
|
|
|
|
|
|
|
|
|
|
class _MockLegendModel:
|
|
|
|
|
|
def __init__(self) -> None:
|
|
|
|
|
|
self._root_group = _MockLegendRootGroup()
|
|
|
|
|
|
|
|
|
|
|
|
def rootGroup(self) -> _MockLegendRootGroup:
|
|
|
|
|
|
return self._root_group
|
|
|
|
|
|
|
|
|
|
|
|
class _MockQgsLayoutItemLegend:
|
|
|
|
|
|
def __init__(self, layout: Any):
|
|
|
|
|
|
self.layout = layout
|
|
|
|
|
|
self._model = _MockLegendModel()
|
2026-04-08 13:56:58 +02:00
|
|
|
|
self.item_id = ""
|
|
|
|
|
|
self.object_name = ""
|
|
|
|
|
|
self.linked_map = None
|
|
|
|
|
|
self.auto_update_model = None
|
|
|
|
|
|
self.legend_filter_by_map_enabled = None
|
|
|
|
|
|
self.title = ""
|
2026-03-24 07:53:04 +01:00
|
|
|
|
|
|
|
|
|
|
def setId(self, item_id: str) -> None:
|
2026-04-08 13:56:58 +02:00
|
|
|
|
self.item_id = item_id
|
2026-03-24 07:53:04 +01:00
|
|
|
|
|
|
|
|
|
|
def setObjectName(self, name: str) -> None:
|
2026-04-08 13:56:58 +02:00
|
|
|
|
self.object_name = name
|
2026-03-24 07:53:04 +01:00
|
|
|
|
|
|
|
|
|
|
def setLinkedMap(self, map_item: Any) -> None:
|
2026-04-08 13:56:58 +02:00
|
|
|
|
self.linked_map = map_item
|
2026-03-24 07:53:04 +01:00
|
|
|
|
|
|
|
|
|
|
def setAutoUpdateModel(self, enabled: bool) -> None:
|
2026-04-08 13:56:58 +02:00
|
|
|
|
self.auto_update_model = enabled
|
2026-03-24 07:53:04 +01:00
|
|
|
|
|
|
|
|
|
|
def setLegendFilterByMapEnabled(self, enabled: bool) -> None:
|
2026-04-08 13:56:58 +02:00
|
|
|
|
self.legend_filter_by_map_enabled = enabled
|
2026-03-24 07:53:04 +01:00
|
|
|
|
|
|
|
|
|
|
def setTitle(self, title: str) -> None:
|
2026-04-08 13:56:58 +02:00
|
|
|
|
self.title = title
|
2026-03-24 07:53:04 +01:00
|
|
|
|
|
|
|
|
|
|
def setReferencePoint(self, point: Any) -> None:
|
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
def attemptMove(self, point: Any) -> None:
|
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
def attemptResize(self, size: Any) -> None:
|
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
def model(self) -> _MockLegendModel:
|
|
|
|
|
|
return self._model
|
|
|
|
|
|
|
|
|
|
|
|
def refresh(self) -> None:
|
|
|
|
|
|
pass
|
|
|
|
|
|
|
2026-03-20 14:01:57 +01:00
|
|
|
|
class _MockQgsLayoutPoint:
|
|
|
|
|
|
def __init__(self, x: float, y: float, unit: Any):
|
|
|
|
|
|
self.x = x
|
|
|
|
|
|
self.y = y
|
|
|
|
|
|
self.unit = unit
|
|
|
|
|
|
|
|
|
|
|
|
class _MockQgsLayoutSize:
|
|
|
|
|
|
def __init__(self, width: float, height: float, unit: Any):
|
|
|
|
|
|
self.width = width
|
|
|
|
|
|
self.height = height
|
|
|
|
|
|
self.unit = unit
|
|
|
|
|
|
|
|
|
|
|
|
class _MockQgsUnitTypes:
|
|
|
|
|
|
LayoutMillimeters = 0
|
|
|
|
|
|
|
|
|
|
|
|
QgsPrintLayout = _MockQgsPrintLayout
|
|
|
|
|
|
QgsLayoutItemMap = _MockQgsLayoutItemMap
|
2026-04-10 21:30:44 +02:00
|
|
|
|
QgsLayoutItemMapGrid = _MockQgsLayoutItemMapGrid
|
|
|
|
|
|
QgsTextFormat = _MockQgsTextFormat
|
|
|
|
|
|
QgsTextBackgroundSettings = _MockQgsTextBackgroundSettings
|
2026-03-20 14:01:57 +01:00
|
|
|
|
QgsLayoutItemLabel = _MockQgsLayoutItemLabel
|
2026-03-24 07:53:04 +01:00
|
|
|
|
QgsLayoutItemLegend = _MockQgsLayoutItemLegend
|
2026-03-20 14:01:57 +01:00
|
|
|
|
QgsLayoutPoint = _MockQgsLayoutPoint
|
|
|
|
|
|
QgsLayoutSize = _MockQgsLayoutSize
|
|
|
|
|
|
QgsUnitTypes = _MockQgsUnitTypes
|
|
|
|
|
|
QgsLayoutItem = _MockQgsLayoutItem
|
|
|
|
|
|
|
2026-04-10 21:30:44 +02:00
|
|
|
|
MAP_GRID_STYLE_MARKERS = _MockQgsLayoutItemMapGrid.Markers
|
|
|
|
|
|
MAP_GRID_STYLE_FRAME_ANNOTATIONS = _MockQgsLayoutItemMapGrid.FrameAndAnnotationsOnly
|
|
|
|
|
|
MAP_GRID_FRAME_STYLE_INTERIOR_TICKS = _MockQgsLayoutItemMapGrid.InteriorTicks
|
|
|
|
|
|
MAP_GRID_UNIT_MAP_UNIT = _MockQgsLayoutItemMapGrid.MapUnits
|
|
|
|
|
|
MAP_GRID_ANNOTATION_FORMAT_DECIMAL = _MockQgsLayoutItemMapGrid.Decimal
|
|
|
|
|
|
MAP_GRID_ANNOTATION_DISPLAY_HIDE_ALL = _MockQgsLayoutItemMapGrid.HideAll
|
|
|
|
|
|
MAP_GRID_ANNOTATION_DISPLAY_SHOW_ALL = _MockQgsLayoutItemMapGrid.ShowAll
|
|
|
|
|
|
MAP_GRID_ANNOTATION_DISPLAY_SHOW_X = _MockQgsLayoutItemMapGrid.LongitudeOnly
|
|
|
|
|
|
MAP_GRID_ANNOTATION_DISPLAY_SHOW_Y = _MockQgsLayoutItemMapGrid.LatitudeOnly
|
|
|
|
|
|
MAP_GRID_BORDER_LEFT = _MockQgsLayoutItemMapGrid.Left
|
|
|
|
|
|
MAP_GRID_BORDER_RIGHT = _MockQgsLayoutItemMapGrid.Right
|
|
|
|
|
|
MAP_GRID_BORDER_TOP = _MockQgsLayoutItemMapGrid.Top
|
|
|
|
|
|
MAP_GRID_BORDER_BOTTOM = _MockQgsLayoutItemMapGrid.Bottom
|
|
|
|
|
|
MAP_GRID_ANNOTATION_POSITION_INSIDE_FRAME = _MockQgsLayoutItemMapGrid.InsideMapFrame
|
|
|
|
|
|
TEXT_BACKGROUND_SHAPE_RECTANGLE = _MockQgsTextBackgroundSettings.ShapeRectangle
|
|
|
|
|
|
TEXT_BACKGROUND_SIZE_BUFFER = _MockQgsTextBackgroundSettings.SizeBuffer
|
|
|
|
|
|
TEXT_RENDER_UNIT_MILLIMETERS = "Millimeters"
|
|
|
|
|
|
TEXT_RENDER_UNIT_POINTS = "Points"
|
|
|
|
|
|
|
2026-04-08 14:36:20 +02:00
|
|
|
|
class _MockQgsFeature:
|
|
|
|
|
|
def __init__(self):
|
|
|
|
|
|
self._geometry = None
|
|
|
|
|
|
self._attributes = []
|
|
|
|
|
|
|
|
|
|
|
|
def setGeometry(self, geometry: Any) -> None:
|
|
|
|
|
|
self._geometry = geometry
|
|
|
|
|
|
|
|
|
|
|
|
def setAttributes(self, attributes: list[Any]) -> None:
|
|
|
|
|
|
self._attributes = attributes
|
|
|
|
|
|
|
|
|
|
|
|
class _MockQgsField:
|
|
|
|
|
|
def __init__(self, name: str = "", field_type: Any = None):
|
|
|
|
|
|
self.name = name
|
|
|
|
|
|
self.field_type = field_type
|
|
|
|
|
|
|
|
|
|
|
|
class _MockQgsGeometry:
|
|
|
|
|
|
@staticmethod
|
|
|
|
|
|
def unaryUnion(_geometries: list[Any]):
|
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
|
|
def isEmpty(self) -> bool:
|
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
|
|
QgsFeature = _MockQgsFeature
|
|
|
|
|
|
QgsField = _MockQgsField
|
|
|
|
|
|
QgsGeometry = _MockQgsGeometry
|
|
|
|
|
|
|
2026-03-12 16:14:02 +01:00
|
|
|
|
class _MockQgsFeatureRequest:
|
|
|
|
|
|
def __init__(self):
|
|
|
|
|
|
self._filter_rect = None
|
|
|
|
|
|
|
|
|
|
|
|
def setFilterRect(self, rect):
|
|
|
|
|
|
self._filter_rect = rect
|
|
|
|
|
|
return self
|
|
|
|
|
|
|
|
|
|
|
|
QgsFeatureRequest = _MockQgsFeatureRequest
|
|
|
|
|
|
|
|
|
|
|
|
class _MockQgsCoordinateTransform:
|
|
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
def transformBoundingBox(self, rect):
|
|
|
|
|
|
return rect
|
|
|
|
|
|
|
|
|
|
|
|
class _MockQgsCoordinateReferenceSystem:
|
|
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
QgsCoordinateTransform = _MockQgsCoordinateTransform
|
|
|
|
|
|
QgsCoordinateReferenceSystem = _MockQgsCoordinateReferenceSystem
|
|
|
|
|
|
|
2025-12-19 14:29:52 +01:00
|
|
|
|
QgsNetworkAccessManager = _MockQgsNetworkAccessManager
|
|
|
|
|
|
|
|
|
|
|
|
class _MockQgis:
|
|
|
|
|
|
class MessageLevel:
|
|
|
|
|
|
Success = 0
|
|
|
|
|
|
Info = 1
|
|
|
|
|
|
Warning = 2
|
|
|
|
|
|
Critical = 3
|
|
|
|
|
|
|
|
|
|
|
|
Qgis = _MockQgis
|
|
|
|
|
|
|
2026-01-08 17:13:51 +01:00
|
|
|
|
class _MockQgsMapLayerProxyModel:
|
|
|
|
|
|
# Layer-Typen (entsprechen QGIS-Konstanten)
|
|
|
|
|
|
NoLayer = 0
|
|
|
|
|
|
VectorLayer = 1
|
|
|
|
|
|
RasterLayer = 2
|
|
|
|
|
|
PluginLayer = 3
|
|
|
|
|
|
MeshLayer = 4
|
|
|
|
|
|
VectorTileLayer = 5
|
|
|
|
|
|
PointCloudLayer = 6
|
|
|
|
|
|
|
|
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
QgsMapLayerProxyModel = _MockQgsMapLayerProxyModel
|
2025-12-19 14:29:52 +01:00
|
|
|
|
|
2026-02-14 22:14:33 +01:00
|
|
|
|
# ---------------------------------------------------------
|
|
|
|
|
|
# Mock für QgsVectorFileWriter
|
|
|
|
|
|
# ---------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
class _MockSaveVectorOptions:
|
|
|
|
|
|
"""
|
|
|
|
|
|
Minimaler Ersatz für QgsVectorFileWriter.SaveVectorOptions.
|
|
|
|
|
|
Felder werden als einfache Attribute bereitgestellt.
|
|
|
|
|
|
"""
|
|
|
|
|
|
def __init__(self):
|
|
|
|
|
|
self.driverName: str = "GPKG"
|
|
|
|
|
|
self.layerName: Optional[str] = None
|
|
|
|
|
|
self.fileEncoding: str = "UTF-8"
|
|
|
|
|
|
# Action-Konstanten werden symbolisch verwendet
|
|
|
|
|
|
self.actionOnExistingFile: Optional[int] = None
|
|
|
|
|
|
|
|
|
|
|
|
class _MockQgsVectorFileWriter:
|
|
|
|
|
|
"""
|
|
|
|
|
|
Minimaler Mock für QgsVectorFileWriter mit der benötigten API:
|
|
|
|
|
|
- SaveVectorOptions (als Klasse)
|
|
|
|
|
|
- writeAsVectorFormatV3(layer, path, transformContext, options) -> error_code
|
|
|
|
|
|
- NoError (Konstante)
|
|
|
|
|
|
- CreateOrOverwriteFile / CreateOrOverwriteLayer (Konstanten)
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
|
# Fehlerkonstanten (0 = NoError)
|
|
|
|
|
|
NoError = 0
|
|
|
|
|
|
|
|
|
|
|
|
# Action-Konstanten (Werte nur symbolisch)
|
|
|
|
|
|
CreateOrOverwriteFile = 1
|
|
|
|
|
|
CreateOrOverwriteLayer = 2
|
|
|
|
|
|
|
|
|
|
|
|
# SaveVectorOptions-Klasse
|
|
|
|
|
|
SaveVectorOptions = _MockSaveVectorOptions
|
|
|
|
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
|
|
def writeAsVectorFormatV3(layer: Any, path: str, transform_context: Any, options: Any) -> int:
|
|
|
|
|
|
"""
|
|
|
|
|
|
Mock-Schreibfunktion.
|
|
|
|
|
|
|
|
|
|
|
|
Verhalten im Mock:
|
|
|
|
|
|
- Wenn 'layer' None oder options.layerName fehlt, geben wir NoError zurück,
|
|
|
|
|
|
aber schreiben nichts (Tests erwarten nur Rückgabecode).
|
|
|
|
|
|
- Diese Implementierung versucht nicht, echte Dateien zu schreiben.
|
|
|
|
|
|
- Rückgabewert: 0 (NoError) bei Erfolg, sonst eine positive Fehlernummer.
|
|
|
|
|
|
"""
|
|
|
|
|
|
try:
|
|
|
|
|
|
# Sehr einfache Validierung: wenn path leer -> Fehler
|
|
|
|
|
|
if not path:
|
|
|
|
|
|
return 999
|
|
|
|
|
|
# Simuliere Erfolg
|
|
|
|
|
|
return _MockQgsVectorFileWriter.NoError
|
|
|
|
|
|
except Exception:
|
|
|
|
|
|
return 999 # generischer Fehlercode
|
|
|
|
|
|
|
|
|
|
|
|
QgsVectorFileWriter = _MockQgsVectorFileWriter
|
|
|
|
|
|
|
2025-12-19 14:29:52 +01:00
|
|
|
|
# ---------------------------------------------------------
|
|
|
|
|
|
# Netzwerk
|
|
|
|
|
|
# ---------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
class NetworkReply:
|
|
|
|
|
|
"""
|
|
|
|
|
|
Minimaler Wrapper für Netzwerkantworten.
|
|
|
|
|
|
"""
|
|
|
|
|
|
def __init__(self, error: int):
|
|
|
|
|
|
self.error = error
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def network_head(url: str) -> NetworkReply | None:
|
|
|
|
|
|
"""
|
|
|
|
|
|
Führt einen HTTP-HEAD-Request aus.
|
|
|
|
|
|
|
|
|
|
|
|
Rückgabe:
|
|
|
|
|
|
- NetworkReply(error=0) → erreichbar
|
|
|
|
|
|
- NetworkReply(error!=0) → nicht erreichbar
|
|
|
|
|
|
- None → Netzwerk nicht verfügbar / Fehler beim Request
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
|
if not QGIS_AVAILABLE:
|
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
|
|
if QUrl is None or QNetworkRequest is None:
|
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
|
manager = QgsNetworkAccessManager.instance()
|
|
|
|
|
|
request = QNetworkRequest(QUrl(url))
|
|
|
|
|
|
reply = manager.head(request)
|
|
|
|
|
|
|
|
|
|
|
|
# synchron warten (kurz)
|
|
|
|
|
|
if QEventLoop is not None:
|
|
|
|
|
|
loop = QEventLoop()
|
|
|
|
|
|
reply.finished.connect(loop.quit)
|
|
|
|
|
|
loop.exec()
|
|
|
|
|
|
|
|
|
|
|
|
return NetworkReply(error=reply.error())
|
|
|
|
|
|
except Exception:
|
|
|
|
|
|
return None
|
2026-02-14 22:14:33 +01:00
|
|
|
|
|
|
|
|
|
|
# ---------------------------------------------------------
|
|
|
|
|
|
# Layer-Geometrie / Extent
|
|
|
|
|
|
# ---------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
def get_layer_extent(layer: Any) -> Any:
|
|
|
|
|
|
"""
|
|
|
|
|
|
Gibt die Ausdehnung (Extent) eines Layers zurück.
|
|
|
|
|
|
|
|
|
|
|
|
Diese Funktion kapselt den Zugriff auf ``layer.extent()`` und dient als
|
|
|
|
|
|
zentrale Abstraktion für alle Stellen, die die Bounding Box eines Layers
|
|
|
|
|
|
benötigen (z.B. für räumliche Filter im Datenabruf).
|
|
|
|
|
|
|
|
|
|
|
|
Verhalten
|
|
|
|
|
|
---------
|
|
|
|
|
|
- Wenn QGIS verfügbar ist und der Layer eine ``extent()``-Methode besitzt,
|
|
|
|
|
|
wird deren Rückgabewert zurückgegeben.
|
|
|
|
|
|
- Wenn QGIS nicht verfügbar ist oder der Layer keine ``extent()``-Methode
|
|
|
|
|
|
hat, wird ``None`` zurückgegeben.
|
|
|
|
|
|
"""
|
|
|
|
|
|
if not QGIS_AVAILABLE or layer is None:
|
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
|
|
extent_func = getattr(layer, "extent", None)
|
|
|
|
|
|
if callable(extent_func):
|
|
|
|
|
|
try:
|
|
|
|
|
|
return extent_func()
|
|
|
|
|
|
except Exception:
|
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
|
|
# ---------------------------------------------------------
|
|
|
|
|
|
# Buffer-Layer erzeugen
|
|
|
|
|
|
# ---------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
def create_buffer_layer(
|
|
|
|
|
|
source_layer: Any,
|
|
|
|
|
|
distance_m: float,
|
|
|
|
|
|
layer_name: str = "BufferLayer"
|
|
|
|
|
|
) -> Optional[Any]:
|
|
|
|
|
|
"""
|
|
|
|
|
|
Erzeugt einen Pufferlayer um alle Features eines Quelllayers.
|
|
|
|
|
|
|
|
|
|
|
|
Diese Funktion dient als zentrale Abstraktion für die Erzeugung eines
|
|
|
|
|
|
Pufferlayers in QGIS. Sie wird z.B. im Datenabruf verwendet, wenn der
|
|
|
|
|
|
Raumfilter ``"Pufferlayer"`` aktiv ist.
|
|
|
|
|
|
|
|
|
|
|
|
Verhalten
|
|
|
|
|
|
---------
|
|
|
|
|
|
- Wenn QGIS verfügbar ist und der ``source_layer`` gültig ist, wird ein
|
|
|
|
|
|
temporärer Vektorlayer erzeugt, der die gepufferten Geometrien enthält.
|
|
|
|
|
|
- Der Puffer wird in Metern angegeben.
|
|
|
|
|
|
- Der zurückgegebene Layer ist **nicht gespeichert**, sondern ein
|
|
|
|
|
|
temporärer Speicherlayer, der anschließend über den UI‑Wrapper ins
|
|
|
|
|
|
Projekt geladen werden kann.
|
|
|
|
|
|
- Wenn QGIS nicht verfügbar ist oder ein Fehler auftritt, wird ``None``
|
|
|
|
|
|
zurückgegeben.
|
|
|
|
|
|
"""
|
|
|
|
|
|
if not QGIS_AVAILABLE:
|
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
|
|
if source_layer is None or not hasattr(source_layer, "getFeatures"):
|
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
|
# Geometrien puffern
|
|
|
|
|
|
buffered_geoms = []
|
|
|
|
|
|
for feat in source_layer.getFeatures():
|
|
|
|
|
|
geom = feat.geometry()
|
|
|
|
|
|
if geom is None:
|
|
|
|
|
|
continue
|
|
|
|
|
|
buf = geom.buffer(distance_m, 8)
|
|
|
|
|
|
if buf is not None:
|
|
|
|
|
|
buffered_geoms.append(buf)
|
|
|
|
|
|
|
|
|
|
|
|
if not buffered_geoms:
|
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
|
|
# Neuen Memory-Layer erzeugen
|
|
|
|
|
|
crs = source_layer.crs().authid() if hasattr(source_layer, "crs") else "EPSG:4326"
|
|
|
|
|
|
mem_layer = QgsVectorLayer(f"Polygon?crs={crs}", layer_name, "memory")
|
|
|
|
|
|
|
|
|
|
|
|
prov = mem_layer.dataProvider()
|
|
|
|
|
|
prov.addAttributes([])
|
|
|
|
|
|
mem_layer.updateFields()
|
|
|
|
|
|
|
|
|
|
|
|
# Features hinzufügen
|
|
|
|
|
|
from qgis.core import QgsFeature
|
|
|
|
|
|
for geom in buffered_geoms:
|
|
|
|
|
|
f = QgsFeature()
|
|
|
|
|
|
f.setGeometry(geom)
|
|
|
|
|
|
prov.addFeature(f)
|
|
|
|
|
|
|
|
|
|
|
|
mem_layer.updateExtents()
|
|
|
|
|
|
return mem_layer
|
|
|
|
|
|
|
|
|
|
|
|
except Exception:
|
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
|
|
#Hilfsfunktion, keine qgiscore-Entsprechung
|
|
|
|
|
|
|
|
|
|
|
|
def layer_exists_in_gpkg(gpkg_path: str, layer_name: str) -> bool:
|
|
|
|
|
|
"""
|
|
|
|
|
|
Prüft, ob ein Layer mit dem Namen `layer_name` in `gpkg_path` existiert.
|
|
|
|
|
|
- bevorzugt: SQLite-Abfrage auf gpkg_contents
|
|
|
|
|
|
- fallback: kurzer Versuch, mit QgsVectorLayer zu laden (wenn QGIS verfügbar)
|
|
|
|
|
|
"""
|
|
|
|
|
|
import os, sqlite3
|
|
|
|
|
|
if not gpkg_path or not layer_name or not os.path.exists(gpkg_path):
|
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
|
|
# 1) SQLite-Check (schnell)
|
|
|
|
|
|
try:
|
|
|
|
|
|
conn = sqlite3.connect(gpkg_path)
|
|
|
|
|
|
cur = conn.cursor()
|
|
|
|
|
|
cur.execute("SELECT COUNT(1) FROM gpkg_contents WHERE table_name = ?", (layer_name,))
|
|
|
|
|
|
row = cur.fetchone()
|
|
|
|
|
|
conn.close()
|
|
|
|
|
|
if row and row[0] > 0:
|
|
|
|
|
|
return True
|
|
|
|
|
|
except Exception:
|
|
|
|
|
|
# falls sqlite fehlschlägt, weiter zum QGIS-Fallback
|
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
# 2) QGIS-Fallback: versuche kurz, den Layer zu laden
|
|
|
|
|
|
try:
|
|
|
|
|
|
if getattr(QgsVectorLayer, "__call__", None) and QGIS_AVAILABLE:
|
|
|
|
|
|
uri = f"{gpkg_path}|layername={layer_name}"
|
|
|
|
|
|
layer = QgsVectorLayer(uri, layer_name, "ogr")
|
|
|
|
|
|
return bool(layer and getattr(layer, "isValid", lambda: False)())
|
|
|
|
|
|
except Exception:
|
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
return False
|