""" sn_plan41/ui/layout.py – Aufbau von Drucklayouts für Plan41. """ from __future__ import annotations import math from typing import Any from sn_basis.functions.qt_wrapper import QFont from sn_basis.functions.qgiscore_wrapper import ( QgsLayoutItem, QgsLayoutItemLabel, QgsLayoutItemMap, QgsLayoutPoint, QgsLayoutSize, QgsPrintLayout, QgsProject, QgsUnitTypes, ) from sn_basis.functions.qgisui_wrapper import open_layout_designer MM = QgsUnitTypes.LayoutMillimeters class Layout: """Erzeugt ein QGIS-Layout für den Druck.""" def __init__(self, project: Any | None = None) -> None: self.project = project or QgsProject.instance() def create_single_page_layout( self, name: str, page_width_mm: float, page_height_mm: float, map_width_mm: float, map_height_mm: float, extent: Any, plotmassstab: float, thema: str = "", ) -> Any: """Erzeugt ein einseitiges Layout und öffnet es im Designer.""" print(f"[Layout] create_single_page_layout: name='{name}', " f"page=({page_width_mm}x{page_height_mm}), map=({map_width_mm:.1f}x{map_height_mm:.1f}), " f"massstab={plotmassstab}, thema='{thema}'") layout_manager = self.project.layoutManager() print(f"[Layout] layoutManager: {layout_manager!r}") existing_layout = layout_manager.layoutByName(name) if existing_layout is not None: raise ValueError(f"Eine Vorlage mit der Bezeichnung '{name}' existiert bereits.") layout = QgsPrintLayout(self.project) layout.initializeDefaults() layout.setName(name) print(f"[Layout] QgsPrintLayout erstellt: {layout!r}") page = layout.pageCollection().page(0) page.setPageSize(QgsLayoutSize(page_width_mm, page_height_mm, MM)) print(f"[Layout] Seitengröße gesetzt: {page_width_mm}x{page_height_mm} mm") map_left_mm = 10.0 map_top_mm = 10.0 map_right_mm = map_left_mm + map_width_mm map_bottom_mm = map_top_mm + map_height_mm print( f"[Layout] Kartenbild-Kanten: rechts={map_right_mm:.1f} mm, unten={map_bottom_mm:.1f} mm" ) hauptkarte = QgsLayoutItemMap(layout) hauptkarte.setId("Hauptkarte") print(f"[Layout] QgsLayoutItemMap erstellt") # Zum Layout hinzufügen, BEVOR Eigenschaften gesetzt werden layout.addLayoutItem(hauptkarte) print("[Layout] Hauptkarte zum Layout hinzugefügt") # Position und Größe setzen hauptkarte.attemptMove(QgsLayoutPoint(map_left_mm, map_top_mm, MM)) hauptkarte.attemptResize(QgsLayoutSize(map_width_mm, map_height_mm, MM)) print(f"[Layout] Position und Größe gesetzt: pos=({map_left_mm}, {map_top_mm}), size=({map_width_mm:.1f}x{map_height_mm:.1f})") # Extent und Maßstab setzen x_min = getattr(extent, "xMinimum", lambda: float("nan"))() y_min = getattr(extent, "yMinimum", lambda: float("nan"))() x_max = getattr(extent, "xMaximum", lambda: float("nan"))() y_max = getattr(extent, "yMaximum", lambda: float("nan"))() print(f"[Layout] Extent input: xmin={x_min}, ymin={y_min}, xmax={x_max}, ymax={y_max}") if extent is not None and hasattr(extent, "isNull") and callable(extent.isNull) and not extent.isNull(): try: hauptkarte.setExtent(extent) print(f"[Layout] setExtent() erfolgreich") except Exception as exc: print(f"[Layout] WARN: setExtent() fehlgeschlagen: {exc}") else: print(f"[Layout] WARN: Extent nicht gültig/callable, setExtent übersprungen") # Maßstab setzen (NACH Extent) if isinstance(plotmassstab, (int, float)) and math.isfinite(plotmassstab) and plotmassstab > 0: try: hauptkarte.setScale(plotmassstab) print(f"[Layout] setScale({plotmassstab}) erfolgreich") except Exception as exc: print(f"[Layout] WARN: setScale({plotmassstab}) fehlgeschlagen: {exc}") else: print(f"[Layout] WARN: ungültiger plotmassstab={plotmassstab!r}, setScale übersprungen") # Rahmen aktivieren set_frame_enabled = getattr(hauptkarte, "setFrameEnabled", None) if callable(set_frame_enabled): try: set_frame_enabled(True) print(f"[Layout] Rahmen aktiviert") except Exception as exc: print(f"[Layout] WARN: setFrameEnabled fehlgeschlagen: {exc}") set_frame_stroke_width = getattr(hauptkarte, "setFrameStrokeWidth", None) if callable(set_frame_stroke_width): try: set_frame_stroke_width(0.5) print(f"[Layout] Rahmenstrichbreite auf 0.5 mm gesetzt") except Exception as exc: print(f"[Layout] WARN: setFrameStrokeWidth(0.5) fehlgeschlagen: {exc}") # Kartenthema setzen if thema and thema != "aktuell": follow_theme = getattr(hauptkarte, "setFollowVisibilityPreset", None) set_theme_name = getattr(hauptkarte, "setFollowVisibilityPresetName", None) if callable(follow_theme): try: follow_theme(True) print(f"[Layout] setFollowVisibilityPreset(True)") except Exception as exc: print(f"[Layout] WARN: setFollowVisibilityPreset fehlgeschlagen: {exc}") if callable(set_theme_name): try: set_theme_name(thema) print(f"[Layout] Kartenthema auf '{thema}' gesetzt") except Exception as exc: print(f"[Layout] WARN: setFollowVisibilityPresetName('{thema}') fehlgeschlagen: {exc}") else: print(f"[Layout] Kartenthema nicht gesetzt (thema='{thema}')") # Erst nach allen Properties: LayerSet einfrieren für Export set_keep_layer_set = getattr(hauptkarte, "setKeepLayerSet", None) if callable(set_keep_layer_set): try: set_keep_layer_set(True) print("[Layout] setKeepLayerSet(True) – Layerset für Export erhalten") except Exception as exc: print(f"[Layout] WARN: setKeepLayerSet fehlgeschlagen: {exc}") # Refresh-Strategie (optional, nur wenn vorhanden) set_refresh_strategy = getattr(hauptkarte, "setRefreshStrategy", None) if callable(set_refresh_strategy): refresh_cache = getattr(hauptkarte, "RefreshLaterOnly", None) or getattr(hauptkarte, "RefreshWhenRequested", None) or 0 if refresh_cache is not None: try: set_refresh_strategy(refresh_cache) print(f"[Layout] setRefreshStrategy({refresh_cache}) gesetzt") except Exception as exc: print(f"[Layout] WARN: setRefreshStrategy fehlgeschlagen: {exc}") print(f"[Layout] Hauptkarte vollständig konfiguriert") quellenangabe = QgsLayoutItemLabel(layout) quellenangabe.setId("Quellenangabe") quellenangabe.setText( "Quelle Geobasisdaten: GeoSN, " "dl-de/by-2-0

" "Quelle Fachdaten: Darstellung auf der Grundlage von Daten und mit Erlaubnis des " "Sächsischen Landesamtes für Umwelt, Landwirtschaft und Geologie

" "Basemap:

" "© GeoBasis-DE / BKG ([%year($now)%]) " "CC BY 4.0 " "mit teilweise angepasster Signatur
" ) set_mode = getattr(quellenangabe, "setMode", None) mode_html = getattr(QgsLayoutItemLabel, "ModeHtml", None) print(f"[Layout] QgsLayoutItemLabel.ModeHtml={mode_html!r}") if callable(set_mode) and mode_html is not None: set_mode(mode_html) quellenangabe.setFont(QFont("Arial", 12)) set_reference_point = getattr(quellenangabe, "setReferencePoint", None) lower_left = getattr(getattr(QgsLayoutItem, "ReferencePoint", object), "LowerLeft", None) print(f"[Layout] QgsLayoutItem.ReferencePoint.LowerLeft={lower_left!r}") if callable(set_reference_point) and lower_left is not None: set_reference_point(lower_left) quellenangabe_x_mm = map_right_mm + 20.0 quellenangabe_y_mm = map_bottom_mm - 120.0 quellenangabe.attemptMove(QgsLayoutPoint(quellenangabe_x_mm, quellenangabe_y_mm, MM)) quellenangabe.attemptResize(QgsLayoutSize(180.0, 100.0, MM)) layout.addLayoutItem(quellenangabe) print("[Layout] Quellenangabe zum Layout hinzugefügt") layout_manager.addLayout(layout) print("[Layout] Layout zum LayoutManager hinzugefügt") open_layout_designer(layout) print("[Layout] Layout Designer geöffnet") return layout