Files
Plugin_SN_Plan41/ui/layout.py

202 lines
9.0 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
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, "
"<a href=\"https://www.govdata.de/dl-de/by-2-0\">dl-de/by-2-0</a><br><br>"
"Quelle Fachdaten: Darstellung auf der Grundlage von Daten und mit Erlaubnis des "
"Sächsischen Landesamtes für Umwelt, Landwirtschaft und Geologie<br><br>"
"Basemap:<br><br>"
"© GeoBasis-DE / <a href=\"https://www.bkg.bund.de\">BKG</a> ([%year($now)%]) "
"<a href=\"https://creativecommons.org/licences/by/4.0/\">CC BY 4.0</a> "
"mit teilweise angepasster Signatur<br>"
)
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