""" sn_plan41/ui/tab_a_ui.py – UI für Tab A (Daten) """ from typing import Optional from sn_basis.functions.qt_wrapper import ( # type: ignore QWidget, QVBoxLayout, QLabel, QPushButton, QToolButton, QFileDialog, QMessageBox, QTabWidget, ToolButtonTextBesideIcon, ArrowDown, ArrowRight, SizePolicyPreferred, SizePolicyMaximum, ) from sn_basis.functions.qgisui_wrapper import ( # type: ignore QgsFileWidget, QgsMapLayerComboBox, add_dock_widget, ) from sn_basis.functions.qgiscore_wrapper import ( # type: ignore QgsProject, QgsMapLayerProxyModel, ) from sn_basis.functions.message_wrapper import ( # type: ignore info, warning, error, ) from sn_basis.functions.dialog_wrapper import ask_yes_no # type: ignore from sn_basis.functions.sys_wrapper import file_exists # type: ignore from sn_plan41.ui.tab_a_logic import TabALogic # type: ignore class TabA(QWidget): """ UI-Klasse für Tab A (Daten). Enthält ausschließlich UI-Code und delegiert Logik an TabALogic. """ def __init__(self, parent=None, build_ui: bool=True): super().__init__(parent) self.parent=parent self.tab_title="Daten" self.logic = TabALogic() self.verfahrens_db: Optional[str] = None self.lokale_linkliste: Optional[str] = None if build_ui: self._build_ui() self._restore_state() # --------------------------------------------------------- # UI-Aufbau # --------------------------------------------------------- def _build_ui(self) -> None: main_layout = QVBoxLayout() main_layout.setSpacing(4) main_layout.setContentsMargins(4, 4, 4, 4) # ------------------------------- # Verfahrens-Datenbank # ------------------------------- self.group_button = QToolButton() self.group_button.setText("Verfahrens-Datenbank") self.group_button.setCheckable(True) self.group_button.setChecked(True) self.group_button.setToolButtonStyle(ToolButtonTextBesideIcon) self.group_button.setArrowType(ArrowDown) self.group_button.setStyleSheet("font-weight: bold;") self.group_button.toggled.connect(self._toggle_group) main_layout.addWidget(self.group_button) self.group_content = QWidget() self.group_content.setSizePolicy(SizePolicyPreferred, SizePolicyMaximum) group_layout = QVBoxLayout() group_layout.setSpacing(2) group_layout.setContentsMargins(10, 4, 4, 4) group_layout.addWidget(QLabel("bestehende Datei auswählen")) self.file_widget = QgsFileWidget() self.file_widget.setStorageMode(QgsFileWidget.GetFile) self.file_widget.setFilter("Geopackage (*.gpkg)") self.file_widget.fileChanged.connect(self._on_verfahrens_db_changed) group_layout.addWidget(self.file_widget) group_layout.addWidget(QLabel("-oder-")) self.btn_new = QPushButton("Neue Verfahrens-DB anlegen") self.btn_new.clicked.connect(self._create_new_gpkg) group_layout.addWidget(self.btn_new) self.group_content.setLayout(group_layout) main_layout.addWidget(self.group_content) # ------------------------------- # Optionale Linkliste # ------------------------------- self.optional_button = QToolButton() self.optional_button.setText("Optional: Lokale Linkliste") self.optional_button.setCheckable(True) self.optional_button.setChecked(False) self.optional_button.setToolButtonStyle(ToolButtonTextBesideIcon) self.optional_button.setArrowType(ArrowRight) self.optional_button.setStyleSheet("font-weight: bold; margin-top: 6px;") self.optional_button.toggled.connect(self._toggle_optional) main_layout.addWidget(self.optional_button) self.optional_content = QWidget() self.optional_content.setSizePolicy(SizePolicyPreferred, SizePolicyMaximum) optional_layout = QVBoxLayout() optional_layout.setSpacing(2) optional_layout.setContentsMargins(10, 4, 4, 20) optional_layout.addWidget(QLabel("(frei lassen für globale Linkliste)")) self.linkliste_widget = QgsFileWidget() self.linkliste_widget.setStorageMode(QgsFileWidget.GetFile) self.linkliste_widget.setFilter("Excelliste (*.xlsx)") self.linkliste_widget.fileChanged.connect(self._on_linkliste_changed) optional_layout.addWidget(self.linkliste_widget) self.optional_content.setLayout(optional_layout) self.optional_content.setVisible(False) main_layout.addWidget(self.optional_content) # ------------------------------- # Layer-Auswahl # ------------------------------- layer_label = QLabel("Verfahrensgebiet-Layer auswählen") layer_label.setStyleSheet("font-weight: bold; margin-top: 6px;") main_layout.addWidget(layer_label) self.layer_combo = QgsMapLayerComboBox() self.layer_combo.setSizePolicy(SizePolicyPreferred, SizePolicyMaximum) self.layer_combo.setFilters(QgsMapLayerProxyModel.VectorLayer) self.layer_combo.layerChanged.connect(self._on_layer_changed) main_layout.addWidget(self.layer_combo) main_layout.addStretch(1) self.setLayout(main_layout) # --------------------------------------------------------- # State Restore # --------------------------------------------------------- def _restore_state(self) -> None: db = self.logic.load_verfahrens_db() if db: self.verfahrens_db = db self.file_widget.setFilePath(db) self._update_group_color() link = self.logic.load_linkliste() if link: self.lokale_linkliste = link self.linkliste_widget.setFilePath(link) layer_id = self.logic.load_verfahrensgebiet_layer_id() if layer_id: layer = QgsProject.instance().mapLayer(layer_id) if layer: self.layer_combo.setLayer(layer) # --------------------------------------------------------- # UI-Callbacks # --------------------------------------------------------- def _toggle_group(self, checked: bool): """ Klappt den Gruppenbereich ein oder aus. """ if not hasattr(self, "group_button"): return self.group_button.setArrowType( ArrowDown if checked else ArrowRight ) self.group_content.setVisible(checked) def _toggle_optional(self, checked: bool): """ Klappt den optionalen Bereich ein oder aus. """ if not hasattr(self, "optional_button"): return self.group_button.setArrowType( ArrowDown if checked else ArrowRight ) self.optional_content.setVisible(checked) def _on_verfahrens_db_changed(self, path: str) -> None: if not path: self.verfahrens_db = None self.logic.set_verfahrens_db(None) self._update_group_color() return if not path.lower().endswith(".gpkg"): path += ".gpkg" self.file_widget.setFilePath(path) if not file_exists(path): warning("Datei nicht gefunden", f"Die Datei existiert nicht:\n{path}") self.file_widget.setFilePath("") return self.verfahrens_db = path self.logic.set_verfahrens_db(path) self._update_group_color() def _on_linkliste_changed(self, path: str) -> None: if not path: self.lokale_linkliste = None self.logic.set_linkliste(None) return if not path.lower().endswith(".xlsx"): path += ".xlsx" self.linkliste_widget.setFilePath(path) if not file_exists(path): warning("Datei nicht gefunden", f"Die Datei existiert nicht:\n{path}") self.linkliste_widget.setFilePath("") return self.lokale_linkliste = path self.logic.set_linkliste(path) def _on_layer_changed(self, layer) -> None: self.logic.save_verfahrensgebiet_layer(layer) def _create_new_gpkg(self) -> None: file_path, _ = QFileDialog.getSaveFileName( self, "Neue Verfahrens-Datenbank anlegen", "", "Geopackage (*.gpkg)", ) if not file_path: return if not file_path.lower().endswith(".gpkg"): file_path += ".gpkg" if file_exists(file_path): overwrite = ask_yes_no( "Datei existiert bereits", f"Die Datei existiert bereits:\n\n{file_path}\n\nSoll sie überschrieben werden?", default=False, parent=self, ) if not overwrite: return if not self.logic.create_new_verfahrens_db(file_path): error("Fehler", "Die Datei konnte nicht angelegt werden.") return self.verfahrens_db = file_path self.file_widget.setFilePath(file_path) self._update_group_color() info("Projekt-DB angelegt", f"Neue Projekt-Datenbank wurde angelegt:\n{file_path}") # --------------------------------------------------------- # UI-Helfer # --------------------------------------------------------- def _update_group_color(self): """ Aktualisiert die Darstellung der Gruppenüberschrift. """ if not hasattr(self, "group_button"): return if self.verfahrens_db: self.group_button.setStyleSheet("font-weight: bold;") else: self.group_button.setStyleSheet("")