633 lines
24 KiB
Python
633 lines
24 KiB
Python
"""
|
||
sn_plan41/ui/tab_a_ui.py – UI für Tab A (Daten)
|
||
"""
|
||
|
||
from __future__ import annotations
|
||
|
||
from typing import Optional
|
||
|
||
from sn_basis.functions.qt_wrapper import (
|
||
QWidget,
|
||
QVBoxLayout,
|
||
QHBoxLayout,
|
||
QLabel,
|
||
QLineEdit,
|
||
QPushButton,
|
||
QToolButton,
|
||
QFileDialog,
|
||
QMessageBox,
|
||
ToolButtonTextBesideIcon,
|
||
ArrowDown,
|
||
ArrowRight,
|
||
SizePolicyPreferred,
|
||
SizePolicyMaximum,
|
||
QComboBox,
|
||
)
|
||
from sn_basis.functions.qgisui_wrapper import QgsFileWidget, QgsMapLayerComboBox
|
||
from sn_basis.functions.qgiscore_wrapper import QgsProject, QgsMapLayerProxyModel
|
||
from sn_basis.functions.variable_wrapper import get_variable, set_variable
|
||
from sn_basis.modules.pruef_ergebnis import pruef_ergebnis
|
||
|
||
# Services (werden von DockWidget injiziert)
|
||
from sn_basis.modules.Pruefmanager import Pruefmanager
|
||
from sn_basis.modules.DataGrabber import DataGrabber
|
||
from sn_basis.modules.Dateipruefer import Dateipruefer
|
||
from sn_plan41.ui.tab_a_logic import TabALogic
|
||
from sn_basis.modules.linkpruefer import Linkpruefer
|
||
from sn_basis.modules.stilpruefer import Stilpruefer
|
||
from sn_plan41.modules.vln_api_logic import VlnApiLogic
|
||
|
||
# Konstanten
|
||
RAUMFILTER_VAR = "Raumfilter"
|
||
RAUMFILTER_OPTIONS = ("Verfahrensgebiet", "Pufferlayer", "ohne")
|
||
RAUMFILTER_DEFAULT = "Pufferlayer"
|
||
|
||
|
||
class TabA(QWidget):
|
||
"""
|
||
UI-Klasse für Tab A (Daten) des Plan41-Plugins.
|
||
|
||
Zuständig für:
|
||
- Anzeige und Auswahl von Verfahrens-DB, Linklisten und Layern
|
||
- Steuerung der Pipeline über "Fachdaten laden"
|
||
- Persistierung von UI-States via Projektvariablen
|
||
|
||
Services (Pruefmanager, DataGrabber) werden zur Laufzeit vom DockWidget injiziert.
|
||
Alle fachlichen Prüfungen laufen über den zentralen Pruefmanager.
|
||
"""
|
||
|
||
tab_title = "Daten" #: 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[TabALogic] = None
|
||
|
||
# UI-State
|
||
self.verfahrens_db: Optional[str] = None
|
||
self.lokale_linkliste: Optional[str] = None
|
||
self._pufferlayer = None
|
||
self._attributes_list = []
|
||
|
||
# UI-Referenzen
|
||
self._raumfilter_combo: Optional[QComboBox] = None
|
||
|
||
# VLN-API
|
||
self.vln_logic: Optional[VlnApiLogic] = None
|
||
self._vln_restoring: bool = False
|
||
|
||
self._build_ui()
|
||
self._restore_state()
|
||
|
||
def set_services(self, pruefmanager: Pruefmanager, data_grabber: DataGrabber) -> None:
|
||
"""
|
||
Injiziert Services vom übergeordneten DockWidget.
|
||
|
||
:param pruefmanager: Zentrale Prüfmanager-Instanz
|
||
:param data_grabber: DataGrabber für Quellenprüfung/Abruf
|
||
"""
|
||
self.pruefmanager = pruefmanager
|
||
self.data_grabber = data_grabber
|
||
self.logic = TabALogic(
|
||
pruefmanager=self.pruefmanager,
|
||
link_pruefer=Linkpruefer(),
|
||
stil_pruefer=Stilpruefer(),
|
||
)
|
||
self.logic.data_grabber = self.data_grabber
|
||
|
||
# VLN-API-Logik initialisieren
|
||
self.vln_logic = VlnApiLogic(self.pruefmanager)
|
||
self._update_vln_ui_state()
|
||
self._restore_vln_state()
|
||
|
||
def _build_ui(self) -> None:
|
||
"""Erstellt die komplette UI-Hierarchie mit allen Gruppen."""
|
||
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)
|
||
|
||
# === RAUMFILTER ===
|
||
main_layout.addWidget(QLabel("Raumfilter"))
|
||
self._raumfilter_combo = QComboBox(self)
|
||
self._raumfilter_combo.setToolTip("Wählt die räumliche Bezugsfläche für die Datenextraktion.")
|
||
self._raumfilter_combo.addItems(RAUMFILTER_OPTIONS)
|
||
self._raumfilter_combo.currentTextChanged.connect(self._on_raumfilter_changed)
|
||
main_layout.addWidget(self._raumfilter_combo)
|
||
|
||
# === PIPELINE-STEUERUNG ===
|
||
self.btn_pipeline = QPushButton("Fachdaten laden")
|
||
self.btn_pipeline.setToolTip("Starte Pipeline: Linkliste → DataGrabber → Datenschreiber → Log")
|
||
self.btn_pipeline.clicked.connect(self._on_load_fachdaten)
|
||
main_layout.addWidget(self.btn_pipeline)
|
||
|
||
# === VLN API / PLAN 41 ===
|
||
self._vln_group_button = QToolButton()
|
||
self._vln_group_button.setText("VLN API / Plan 41")
|
||
self._vln_group_button.setCheckable(True)
|
||
self._vln_group_button.setChecked(False)
|
||
self._vln_group_button.setToolButtonStyle(ToolButtonTextBesideIcon)
|
||
self._vln_group_button.setArrowType(ArrowRight)
|
||
self._vln_group_button.setStyleSheet("font-weight: bold; margin-top: 8px;")
|
||
self._vln_group_button.toggled.connect(self._toggle_vln_group)
|
||
main_layout.addWidget(self._vln_group_button)
|
||
|
||
self._vln_group_content = QWidget()
|
||
self._vln_group_content.setSizePolicy(SizePolicyPreferred, SizePolicyMaximum)
|
||
vln_layout = QVBoxLayout()
|
||
vln_layout.setSpacing(4)
|
||
vln_layout.setContentsMargins(10, 4, 4, 8)
|
||
|
||
# Status
|
||
self._vln_status_label = QLabel("Nicht angemeldet")
|
||
self._vln_status_label.setStyleSheet("color: gray; font-style: italic;")
|
||
vln_layout.addWidget(self._vln_status_label)
|
||
|
||
# E-Mail und Passwort
|
||
vln_layout.addWidget(QLabel("E-Mail:"))
|
||
self._vln_mail_edit = QLineEdit()
|
||
self._vln_mail_edit.setPlaceholderText("mail@beispiel.de")
|
||
vln_layout.addWidget(self._vln_mail_edit)
|
||
|
||
vln_layout.addWidget(QLabel("Passwort:"))
|
||
self._vln_pass_edit = QLineEdit()
|
||
try:
|
||
self._vln_pass_edit.setEchoMode(QLineEdit.EchoMode.Password)
|
||
except AttributeError:
|
||
self._vln_pass_edit.setEchoMode(QLineEdit.Password)
|
||
vln_layout.addWidget(self._vln_pass_edit)
|
||
|
||
# Login / Logout Buttons
|
||
btn_row = QHBoxLayout()
|
||
self._btn_vln_login = QPushButton("Anmelden")
|
||
self._btn_vln_login.clicked.connect(self._on_vln_login)
|
||
self._btn_vln_logout = QPushButton("Abmelden")
|
||
self._btn_vln_logout.clicked.connect(self._on_vln_logout)
|
||
btn_row.addWidget(self._btn_vln_login)
|
||
btn_row.addWidget(self._btn_vln_logout)
|
||
vln_layout.addLayout(btn_row)
|
||
|
||
# Verfahren
|
||
vln_layout.addWidget(QLabel("Verfahren:"))
|
||
self._vln_verfahren_combo = QComboBox()
|
||
self._vln_verfahren_combo.setToolTip("Verfahren (Teilnehmergemeinschaft) wählen")
|
||
self._vln_verfahren_combo.setEnabled(False)
|
||
self._vln_verfahren_combo.currentIndexChanged.connect(
|
||
self._on_vln_verfahren_changed
|
||
)
|
||
vln_layout.addWidget(self._vln_verfahren_combo)
|
||
|
||
# Plan 41 laden
|
||
self._btn_p41_laden = QPushButton("Plan 41 (Wege- und Gewässerplan) laden")
|
||
self._btn_p41_laden.setToolTip(
|
||
"Lädt Flächen- und Linienlayer für das gewählte Verfahren vom Server"
|
||
)
|
||
self._btn_p41_laden.setEnabled(False)
|
||
self._btn_p41_laden.clicked.connect(self._on_p41_laden)
|
||
vln_layout.addWidget(self._btn_p41_laden)
|
||
|
||
# Upload
|
||
self._btn_upload = QPushButton("Aktiven Layer hochladen")
|
||
self._btn_upload.setToolTip(
|
||
"Lädt alle Plan-41-Layer des aktiven Verfahrens zum Server hoch"
|
||
)
|
||
self._btn_upload.setEnabled(False)
|
||
self._btn_upload.clicked.connect(self._on_upload_active)
|
||
vln_layout.addWidget(self._btn_upload)
|
||
|
||
self._vln_group_content.setLayout(vln_layout)
|
||
self._vln_group_content.setVisible(False)
|
||
main_layout.addWidget(self._vln_group_content)
|
||
|
||
main_layout.addStretch(1)
|
||
self.setLayout(main_layout)
|
||
|
||
def _restore_state(self) -> None:
|
||
"""Stellt UI-State aus Projektvariablen/Persistenz wieder her."""
|
||
# Verfahrens-DB
|
||
try:
|
||
db = get_variable("tab_a_verfahrens_db", scope="project")
|
||
if db and self.file_widget:
|
||
self.file_widget.setFilePath(db)
|
||
self.verfahrens_db = db
|
||
self._update_group_color()
|
||
except Exception:
|
||
pass
|
||
|
||
# Linkliste
|
||
try:
|
||
link = get_variable("tab_a_linkliste", scope="project")
|
||
if link and self.linkliste_widget:
|
||
self.linkliste_widget.setFilePath(link)
|
||
self.lokale_linkliste = link
|
||
except Exception:
|
||
pass
|
||
# Raumfilter (schon im _build_ui behandelt)
|
||
|
||
def _restore_vln_state(self) -> None:
|
||
"""Stellt die zuletzt gewählte VKZ aus der Projektdatei wieder her."""
|
||
if self.vln_logic is None or not self.vln_logic.is_authenticated:
|
||
return
|
||
try:
|
||
self._populate_verfahren_combo(restore_vkz=True)
|
||
except Exception:
|
||
pass
|
||
|
||
# === UI CALLBACKS ===
|
||
|
||
def _toggle_vln_group(self, checked: bool) -> None:
|
||
self._vln_group_button.setArrowType(ArrowDown if checked else ArrowRight)
|
||
self._vln_group_content.setVisible(checked)
|
||
|
||
def _update_vln_ui_state(self) -> None:
|
||
"""Passt alle VLN-Controls an den aktuellen Authentifizierungsstatus an."""
|
||
if self.vln_logic is None:
|
||
authenticated = False
|
||
available = False
|
||
else:
|
||
authenticated = self.vln_logic.is_authenticated
|
||
available = self.vln_logic.is_available()
|
||
|
||
if not available:
|
||
self._vln_status_label.setText(
|
||
"Plugin 'vln_karten' nicht installiert"
|
||
)
|
||
self._vln_status_label.setStyleSheet("color: red; font-style: italic;")
|
||
self._btn_vln_login.setEnabled(False)
|
||
elif authenticated:
|
||
mail = (self.vln_logic.mail or "API-Key") if self.vln_logic else ""
|
||
self._vln_status_label.setText("Angemeldet: %s" % mail)
|
||
self._vln_status_label.setStyleSheet(
|
||
"color: green; font-style: italic;"
|
||
)
|
||
self._btn_vln_login.setEnabled(False)
|
||
else:
|
||
self._vln_status_label.setText("Nicht angemeldet")
|
||
self._vln_status_label.setStyleSheet("color: gray; font-style: italic;")
|
||
self._btn_vln_login.setEnabled(True)
|
||
|
||
self._btn_vln_logout.setEnabled(authenticated)
|
||
self._vln_verfahren_combo.setEnabled(authenticated)
|
||
vkz_chosen = (
|
||
authenticated
|
||
and self._vln_verfahren_combo.currentData() is not None
|
||
)
|
||
self._btn_p41_laden.setEnabled(vkz_chosen)
|
||
self._btn_upload.setEnabled(authenticated)
|
||
|
||
def _populate_verfahren_combo(self, restore_vkz: bool = False) -> None:
|
||
"""Füllt die Verfahren-Combo und wählt ggf. die gespeicherte VKZ."""
|
||
if self.vln_logic is None:
|
||
return
|
||
verfahren = self.vln_logic.get_verfahren()
|
||
self._vln_restoring = True
|
||
self._vln_verfahren_combo.clear()
|
||
self._vln_verfahren_combo.addItem("— Verfahren wählen —", None)
|
||
for v in verfahren:
|
||
label = (
|
||
"%s — %s" % (v["vkz"], v["name"])
|
||
if v["name"]
|
||
else v["vkz"]
|
||
)
|
||
self._vln_verfahren_combo.addItem(label, v["vkz"])
|
||
self._vln_restoring = False
|
||
|
||
if restore_vkz:
|
||
stored_vkz = self.vln_logic.load_stored_vkz()
|
||
if stored_vkz:
|
||
idx = self._vln_verfahren_combo.findData(stored_vkz)
|
||
if idx >= 0:
|
||
self._vln_verfahren_combo.setCurrentIndex(idx)
|
||
|
||
self._vln_verfahren_combo.setEnabled(True)
|
||
self._update_vln_ui_state()
|
||
|
||
def _on_vln_login(self) -> None:
|
||
"""Führt den API-Login durch."""
|
||
if self.vln_logic is None:
|
||
return
|
||
mail = self._vln_mail_edit.text().strip()
|
||
password = self._vln_pass_edit.text()
|
||
if not mail or not password:
|
||
QMessageBox.warning(
|
||
self,
|
||
"Anmeldung",
|
||
"Bitte E-Mail-Adresse und Passwort eingeben.",
|
||
)
|
||
return
|
||
try:
|
||
self.vln_logic.login(mail, password)
|
||
except Exception as exc:
|
||
QMessageBox.warning(self, "Anmeldung fehlgeschlagen", str(exc))
|
||
return
|
||
|
||
self._vln_pass_edit.clear()
|
||
try:
|
||
self._populate_verfahren_combo(restore_vkz=True)
|
||
except Exception as exc:
|
||
QMessageBox.warning(
|
||
self,
|
||
"Verfahrensliste",
|
||
"Anmeldung erfolgreich, aber Verfahrensliste konnte nicht "
|
||
"geladen werden: %s" % exc,
|
||
)
|
||
self._update_vln_ui_state()
|
||
|
||
def _on_vln_logout(self) -> None:
|
||
"""Meldet den Benutzer lokal ab."""
|
||
if self.vln_logic is None:
|
||
return
|
||
self.vln_logic.logout()
|
||
self._vln_restoring = True
|
||
self._vln_verfahren_combo.clear()
|
||
self._vln_verfahren_combo.setEnabled(False)
|
||
self._vln_restoring = False
|
||
self._update_vln_ui_state()
|
||
|
||
def _on_vln_verfahren_changed(self, _index: int) -> None:
|
||
"""Persistiert die gewählte VKZ."""
|
||
if self._vln_restoring or self.vln_logic is None:
|
||
return
|
||
vkz = self._vln_verfahren_combo.currentData()
|
||
self.vln_logic.save_vkz(vkz)
|
||
self._update_vln_ui_state()
|
||
|
||
def _on_p41_laden(self) -> None:
|
||
"""Lädt den Plan-41-Datensatz für die gewählte VKZ."""
|
||
if self.vln_logic is None:
|
||
return
|
||
vkz = self._vln_verfahren_combo.currentData()
|
||
if not vkz:
|
||
QMessageBox.warning(
|
||
self, "Plan 41 laden", "Bitte zuerst ein Verfahren wählen."
|
||
)
|
||
return
|
||
|
||
# Bereits geladene Layer prüfen
|
||
existing = self.vln_logic.get_p41_layers(vkz)
|
||
if existing:
|
||
try:
|
||
answer = QMessageBox.question(
|
||
self,
|
||
"Layer ersetzen",
|
||
"Plan 41 für VKZ %s ist bereits geladen.\n"
|
||
"Beim Neuladen werden die bestehenden Layer ersetzt. Fortfahren?"
|
||
% vkz,
|
||
)
|
||
# Qt6: StandardButton.Yes, Qt5: QMessageBox.Yes
|
||
yes = getattr(
|
||
getattr(QMessageBox, "StandardButton", QMessageBox),
|
||
"Yes",
|
||
QMessageBox.Yes if hasattr(QMessageBox, "Yes") else None,
|
||
)
|
||
if answer != yes:
|
||
return
|
||
except Exception:
|
||
pass
|
||
self.vln_logic.remove_p41_layers(vkz)
|
||
|
||
try:
|
||
layers = self.vln_logic.load_p41(vkz)
|
||
except Exception as exc:
|
||
# AuthError: Sitzung abgelaufen
|
||
try:
|
||
from sn_plan41.modules.vln_api_client import AuthError as _AuthError
|
||
if isinstance(exc, _AuthError):
|
||
self.vln_logic.handle_session_expired()
|
||
self._on_vln_logout()
|
||
QMessageBox.warning(
|
||
self,
|
||
"Sitzung abgelaufen",
|
||
"Der API-Key ist nicht mehr gültig — bitte neu anmelden.",
|
||
)
|
||
return
|
||
except ImportError:
|
||
pass
|
||
QMessageBox.warning(self, "Laden fehlgeschlagen", str(exc))
|
||
return
|
||
|
||
total = sum(l.featureCount() for l in layers)
|
||
detail = ", ".join(
|
||
"%s: %d" % (l.name(), l.featureCount()) for l in layers
|
||
)
|
||
if total == 0:
|
||
QMessageBox.warning(
|
||
self,
|
||
"Plan 41 laden",
|
||
"Keine Objekte vorhanden — ein leerer Layer wurde angelegt.",
|
||
)
|
||
else:
|
||
try:
|
||
from sn_basis.functions.message_wrapper import info
|
||
info(
|
||
"Plan 41 geladen",
|
||
"%d Layer geladen (%s)." % (len(layers), detail),
|
||
)
|
||
except Exception:
|
||
pass
|
||
|
||
def _on_upload_active(self) -> None:
|
||
"""Lädt den aktiven Layer (und Geschwister-Layer) zum Server hoch."""
|
||
if self.vln_logic is None:
|
||
return
|
||
|
||
# Zusammenfassung für Bestaetigungs-Dialog ermitteln
|
||
try:
|
||
from sn_basis.functions.qgisui_wrapper import iface as _iface
|
||
active_layer = _iface.activeLayer() if _iface else None
|
||
except Exception:
|
||
active_layer = None
|
||
|
||
summary = self.vln_logic.upload_summary(active_layer)
|
||
if summary is None:
|
||
QMessageBox.warning(
|
||
self,
|
||
"Hochladen nicht möglich",
|
||
"Der aktive Layer wurde nicht über 'vln_karten' geladen.",
|
||
)
|
||
return
|
||
|
||
try:
|
||
answer = QMessageBox.question(
|
||
self,
|
||
"Zum Server hochladen",
|
||
"%s für VKZ %s übertragen?\n\n%s\n\n"
|
||
"%d Objekte; der bisherige Bestand dieser VKZ wird ersetzt."
|
||
% (
|
||
summary["dataset_label"],
|
||
summary["vkz"],
|
||
summary["listing"],
|
||
summary["total"],
|
||
),
|
||
)
|
||
yes = getattr(
|
||
getattr(QMessageBox, "StandardButton", QMessageBox),
|
||
"Yes",
|
||
QMessageBox.Yes if hasattr(QMessageBox, "Yes") else None,
|
||
)
|
||
if answer != yes:
|
||
return
|
||
except Exception:
|
||
return
|
||
|
||
try:
|
||
success, message = self.vln_logic.upload_active_layer(active_layer)
|
||
except Exception as exc:
|
||
try:
|
||
from sn_plan41.modules.vln_api_client import AuthError as _AuthError
|
||
if isinstance(exc, _AuthError):
|
||
self.vln_logic.handle_session_expired()
|
||
self._on_vln_logout()
|
||
QMessageBox.warning(
|
||
self,
|
||
"Sitzung abgelaufen",
|
||
"Der API-Key ist nicht mehr gültig — bitte neu anmelden.",
|
||
)
|
||
return
|
||
except ImportError:
|
||
pass
|
||
QMessageBox.warning(self, "Hochladen fehlgeschlagen", str(exc))
|
||
return
|
||
|
||
if success:
|
||
try:
|
||
from sn_basis.functions.message_wrapper import info
|
||
info("Upload erfolgreich", message)
|
||
except Exception:
|
||
pass
|
||
else:
|
||
QMessageBox.warning(self, "Hochladen fehlgeschlagen", message)
|
||
def _toggle_group(self, checked: bool) -> None:
|
||
"""Zeigt/verbirgt Verfahrens-DB-Gruppe."""
|
||
self.group_button.setArrowType(ArrowDown if checked else ArrowRight)
|
||
self.group_content.setVisible(checked)
|
||
|
||
def _toggle_optional(self, checked: bool) -> None:
|
||
"""Zeigt/verbirgt optionale Linkliste."""
|
||
self.optional_button.setArrowType(ArrowDown if checked else ArrowRight)
|
||
self.optional_content.setVisible(checked)
|
||
|
||
def _on_verfahrens_db_changed(self, path: str) -> None:
|
||
"""Persistieret Verfahrens-DB-Pfad."""
|
||
self.verfahrens_db = path
|
||
set_variable("tab_a_verfahrens_db", path, scope="project")
|
||
self._update_group_color()
|
||
|
||
def _on_linkliste_changed(self, path: str) -> None:
|
||
"""Persistieret lokale Linkliste."""
|
||
self.lokale_linkliste = path
|
||
set_variable("tab_a_linkliste", path, scope="project")
|
||
|
||
|
||
def _on_raumfilter_changed(self, value: str) -> None:
|
||
"""Persistieret Raumfilter-Auswahl."""
|
||
set_variable(RAUMFILTER_VAR, value, scope="project")
|
||
|
||
def _create_new_gpkg(self) -> None:
|
||
"""Delegiert GPKG-Erstellung (Prüfungen über Services)."""
|
||
file_path, _ = QFileDialog.getSaveFileName(
|
||
self, "Neue Verfahrens-Datenbank", "", "Geopackage (*.gpkg)"
|
||
)
|
||
if file_path:
|
||
if not file_path.lower().endswith(".gpkg"):
|
||
file_path += ".gpkg"
|
||
self.verfahrens_db = file_path
|
||
self.file_widget.setFilePath(file_path)
|
||
set_variable("tab_a_verfahrens_db", file_path, scope="project")
|
||
self._update_group_color()
|
||
|
||
def _update_group_color(self) -> None:
|
||
"""Visuelles Feedback für Verfahrens-DB-Status."""
|
||
if self.verfahrens_db:
|
||
self.group_button.setStyleSheet("font-weight: bold; background-color: ##d7a8ff;")
|
||
else:
|
||
self.group_button.setStyleSheet("font-weight: bold;")
|
||
|
||
|
||
|
||
|
||
def _on_load_fachdaten(self) -> None:
|
||
"""Kompatibilitäts-Handler → neue Pipeline."""
|
||
source = self.file_widget.filePath()
|
||
raumfilter = self._raumfilter_combo.currentText()
|
||
linkliste = self.linkliste_widget.filePath()
|
||
if self.logic:
|
||
try:
|
||
self.logic._on_run_pipeline(source, linkliste, raumfilter)
|
||
except Exception as exc:
|
||
QMessageBox.warning(
|
||
self,
|
||
"Fehler beim Laden",
|
||
f"Fehler beim Ausführen der Pipeline: {exc}",
|
||
QMessageBox.StandardButton.Ok,
|
||
)
|