forked from Daniel/Plugin_SN_Plan41
202 lines
9.0 KiB
Python
202 lines
9.0 KiB
Python
"""
|
||
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
|