Files
Plugin_SN_Plan41/ui/tab_b_ui.py
2026-03-20 10:37:08 +01:00

258 lines
9.2 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/tab_b_ui.py UI für Tab B (Druck)
"""
from __future__ import annotations
from typing import Optional
from sn_basis.functions.qt_wrapper import (
QWidget,
QVBoxLayout,
QLabel,
QComboBox,
)
from sn_basis.functions.qgiscore_wrapper import QgsProject
from sn_basis.functions.qgisui_wrapper import iface
from sn_basis.functions.variable_wrapper import get_variable, set_variable
# Services (werden von DockWidget injiziert)
from sn_basis.modules.Pruefmanager import Pruefmanager
from sn_basis.modules.DataGrabber import DataGrabber
from sn_plan41.ui.tab_b_logic import (
TabBLogic,
MASSSTAB_WIE_KARTENFENSTER,
PLOTMASSSTAB_BY_AUSWAHL,
ANSICHT_WIE_KARTENFENSTER,
)
THEMA_VAR = "tab_b_thema"
THEMA_PLACEHOLDER = "Thema wählen"
THEMA_38 = "§38"
THEMA_41 = "§41"
MASSSTAB_VAR = "tab_b_massstab"
ANSICHT_VAR = "tab_b_ansicht"
class TabB(QWidget):
"""
UI-Klasse für Tab B (Druck) des Plan41-Plugins.
Zuständig für:
- Auswahl des Druckthemas
- Auswahl der Druckparameter
- Start der Vorlagenanlage (Druck über QGIS-Druckfunktion)
Services (Pruefmanager, DataGrabber) werden zur Laufzeit vom DockWidget injiziert.
Alle fachlichen Prüfungen laufen über den zentralen Pruefmanager.
"""
tab_title = "Druck" #: Tab-Titel für BaseDockWidget
def __init__(self, parent: Optional[QWidget] = None):
"""
Initialisiert die UI-Struktur.
Services werden später über :meth:`set_services` injiziert.
:param parent: Parent-Widget (typischerweise DockWidget)
"""
super().__init__(parent)
# Services (werden von DockWidget gesetzt)
self.pruefmanager: Optional[Pruefmanager] = None
self.logic: Optional[TabBLogic] = None
self._thema_combo: Optional[QComboBox] = None
self._massstab_combo: Optional[QComboBox] = None
self._ansicht_combo: Optional[QComboBox] = None
self._theme_signal_connected = False
self._build_ui()
self._restore_state()
self._connect_theme_collection_signals()
def set_services(self, pruefmanager: Pruefmanager, data_grabber: DataGrabber) -> None:
"""Injiziert Services vom übergeordneten DockWidget."""
_ = data_grabber
self.pruefmanager = pruefmanager
self.logic = TabBLogic(pruefmanager=self.pruefmanager)
if self._thema_combo:
self.logic.set_kartenname_for_thema(self._thema_combo.currentText())
if self._massstab_combo:
self.logic.set_plotmassstab_for_auswahl(
self._massstab_combo.currentText(),
self._get_current_canvas_scale(),
)
if self._ansicht_combo:
self.logic.set_view_for_auswahl(self._ansicht_combo.currentText())
def _build_ui(self) -> None:
"""Erstellt die reduzierte UI für die Themenauswahl."""
main_layout = QVBoxLayout()
main_layout.setSpacing(4)
main_layout.setContentsMargins(4, 4, 4, 4)
thema_label = QLabel("Thema")
thema_label.setStyleSheet("font-weight: bold; margin-top: 6px;")
main_layout.addWidget(thema_label)
self._thema_combo = QComboBox(self)
self._thema_combo.addItem(THEMA_PLACEHOLDER)
self._thema_combo.addItem(THEMA_38)
self._thema_combo.addItem(THEMA_41)
self._thema_combo.currentTextChanged.connect(self._on_thema_changed)
main_layout.addWidget(self._thema_combo)
massstab_label = QLabel("Maßstab")
massstab_label.setStyleSheet("font-weight: bold; margin-top: 6px;")
main_layout.addWidget(massstab_label)
self._massstab_combo = QComboBox(self)
self._massstab_combo.addItem(MASSSTAB_WIE_KARTENFENSTER)
self._massstab_combo.addItems(list(PLOTMASSSTAB_BY_AUSWAHL.keys()))
self._massstab_combo.currentTextChanged.connect(self._on_massstab_changed)
main_layout.addWidget(self._massstab_combo)
ansicht_label = QLabel("Ansicht")
ansicht_label.setStyleSheet("font-weight: bold; margin-top: 6px;")
main_layout.addWidget(ansicht_label)
self._ansicht_combo = QComboBox(self)
self._ansicht_combo.addItem(ANSICHT_WIE_KARTENFENSTER)
self._ansicht_combo.addItems(self._get_gespeicherte_ansichten())
self._ansicht_combo.currentTextChanged.connect(self._on_ansicht_changed)
main_layout.addWidget(self._ansicht_combo)
main_layout.addStretch(1)
self.setLayout(main_layout)
def _restore_state(self) -> None:
"""Stellt die gespeicherten Combobox-Zustände wieder her."""
if not self._thema_combo or not self._massstab_combo or not self._ansicht_combo:
return
saved_thema = get_variable(THEMA_VAR, scope="project")
if saved_thema in (THEMA_38, THEMA_41):
self._thema_combo.setCurrentText(saved_thema)
else:
self._thema_combo.setCurrentText(THEMA_PLACEHOLDER)
saved_massstab = get_variable(MASSSTAB_VAR, scope="project")
valid_massstaebe = [MASSSTAB_WIE_KARTENFENSTER, *PLOTMASSSTAB_BY_AUSWAHL.keys()]
if saved_massstab in valid_massstaebe:
self._massstab_combo.setCurrentText(saved_massstab)
else:
self._massstab_combo.setCurrentText(MASSSTAB_WIE_KARTENFENSTER)
aktuelle_themen = [ANSICHT_WIE_KARTENFENSTER, *self._get_gespeicherte_ansichten()]
self._ansicht_combo.clear()
self._ansicht_combo.addItems(aktuelle_themen)
saved_ansicht = get_variable(ANSICHT_VAR, scope="project")
if saved_ansicht in aktuelle_themen:
self._ansicht_combo.setCurrentText(saved_ansicht)
else:
self._ansicht_combo.setCurrentText(ANSICHT_WIE_KARTENFENSTER)
def _on_thema_changed(self, value: str) -> None:
"""Persistiert die Themenauswahl und setzt den Kartennamen."""
if value in (THEMA_38, THEMA_41):
set_variable(THEMA_VAR, value, scope="project")
else:
set_variable(THEMA_VAR, "", scope="project")
if self.logic:
self.logic.set_kartenname_for_thema(value)
def _on_massstab_changed(self, value: str) -> None:
"""Persistiert Maßstabsauswahl und setzt ``sn_plotmassstab``."""
set_variable(MASSSTAB_VAR, value, scope="project")
if self.logic:
self.logic.set_plotmassstab_for_auswahl(value, self._get_current_canvas_scale())
def _on_ansicht_changed(self, value: str) -> None:
"""Persistiert die Ansichtsauswahl und setzt ``sn_view``."""
set_variable(ANSICHT_VAR, value, scope="project")
if self.logic:
self.logic.set_view_for_auswahl(value)
def _connect_theme_collection_signals(self) -> None:
"""Verbindet Signale der Theme-Collection für Live-Aktualisierung der Ansichtsliste."""
if self._theme_signal_connected:
return
try:
theme_collection = QgsProject.instance().mapThemeCollection()
except Exception:
return
if theme_collection is None:
return
connected_any = False
for signal_name in ("mapThemesChanged", "changed", "themeChanged"):
signal = getattr(theme_collection, signal_name, None)
if signal is None:
continue
try:
signal.connect(self._refresh_ansicht_combo_live)
connected_any = True
except Exception:
pass
self._theme_signal_connected = connected_any
def _refresh_ansicht_combo_live(self, *args) -> None:
"""Aktualisiert die Ansicht-Combobox bei Änderungen gespeicherter Layerthemen."""
_ = args
if not self._ansicht_combo:
return
vorherige_auswahl = self._ansicht_combo.currentText() or ANSICHT_WIE_KARTENFENSTER
eintraege = [ANSICHT_WIE_KARTENFENSTER, *self._get_gespeicherte_ansichten()]
self._ansicht_combo.blockSignals(True)
self._ansicht_combo.clear()
self._ansicht_combo.addItems(eintraege)
if vorherige_auswahl in eintraege:
self._ansicht_combo.setCurrentText(vorherige_auswahl)
else:
self._ansicht_combo.setCurrentText(ANSICHT_WIE_KARTENFENSTER)
self._ansicht_combo.blockSignals(False)
self._on_ansicht_changed(self._ansicht_combo.currentText())
def _get_gespeicherte_ansichten(self) -> list[str]:
"""Liefert die Namen der im Projekt gespeicherten Layerthemen."""
try:
theme_collection = QgsProject.instance().mapThemeCollection()
if theme_collection is None:
return []
themes = theme_collection.mapThemes()
except Exception:
return []
namen: list[str] = []
for theme_name in themes:
name = str(theme_name or "").strip()
if name and name not in namen:
namen.append(name)
return namen
def _get_current_canvas_scale(self) -> float | None:
"""Liest den aktuellen Maßstab aus der Kartensicht."""
try:
canvas = iface.mapCanvas()
if canvas is None:
return None
scale = canvas.scale()
return float(scale) if scale else None
except Exception:
return None