From a302ce2228f8026c551a4ff932705adc7ff28be6 Mon Sep 17 00:00:00 2001 From: Michael Otto Date: Mon, 17 Nov 2025 10:05:42 +0100 Subject: [PATCH] Refactoring Aufgrund Fehler beim Beenden. --- __init__.py | 4 +- logic/__init__.py | 0 logic/settings_logic.py | 40 ++++++ main.py | 29 +++-- metadata.txt | 24 ++-- ui/__init__.py | 3 - ui/dockmanager.py | 56 +-------- ui/navigation.py | 92 ++++---------- ui/tab_projekt.py | 20 --- ui/tab_projekt.ui | 264 ---------------------------------------- ui/tabs/__init__.py | 0 ui/tabs/settings_tab.py | 84 +++++++++++++ 12 files changed, 179 insertions(+), 437 deletions(-) create mode 100644 logic/__init__.py create mode 100644 logic/settings_logic.py delete mode 100644 ui/tab_projekt.py delete mode 100644 ui/tab_projekt.ui create mode 100644 ui/tabs/__init__.py create mode 100644 ui/tabs/settings_tab.py diff --git a/__init__.py b/__init__.py index 2fb6498..854d63e 100644 --- a/__init__.py +++ b/__init__.py @@ -1,3 +1,3 @@ def classFactory(iface): - from .main import lnoSachsenBasis - return lnoSachsenBasis(iface) + from .main import BasisPlugin + return BasisPlugin(iface) diff --git a/logic/__init__.py b/logic/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/logic/settings_logic.py b/logic/settings_logic.py new file mode 100644 index 0000000..ab0dbce --- /dev/null +++ b/logic/settings_logic.py @@ -0,0 +1,40 @@ +from qgis.core import QgsProject, QgsExpressionContextUtils + + +class SettingsLogic: + def __init__(self): + self.project = QgsProject.instance() + + def save(self, fields: dict): + """Speichert Felder als globale und projektbezogene Ausdrucksvariablen.""" + + # 🟦 Globale Ausdrucksvariablen (nutzerspezifisch, Sitzungsspeicher) + QgsExpressionContextUtils.setGlobalVariable("sn_amt", fields["amt"]) + QgsExpressionContextUtils.setGlobalVariable("sn_behoerde", fields["behoerde"]) + QgsExpressionContextUtils.setGlobalVariable("sn_landkreis_user", fields["landkreis_user"]) + QgsExpressionContextUtils.setGlobalVariable("sn_sachgebiet", fields["sachgebiet"]) + + # 🟨 Projektvariablen (sichtbar in Projekt → Eigenschaften → Variablen) + QgsExpressionContextUtils.setProjectVariable(self.project, "sn_bezeichnung", fields["bezeichnung"]) + QgsExpressionContextUtils.setProjectVariable(self.project, "sn_verfahrensnummer", fields["verfahrensnummer"]) + QgsExpressionContextUtils.setProjectVariable(self.project, "sn_gemeinden", fields["gemeinden"]) + QgsExpressionContextUtils.setProjectVariable(self.project, "sn_landkreise_proj", fields["landkreise_proj"]) + + print("✅ Ausdrucksvariablen gespeichert.") + + def load(self) -> dict: + """Lädt Werte ausschließlich aus Ausdrucksvariablen (global + projektbezogen).""" + + return { + # Globale Variablen (nutzerspezifisch) + "amt": QgsExpressionContextUtils.globalScope().variable("sn_amt") or "", + "behoerde": QgsExpressionContextUtils.globalScope().variable("sn_behoerde") or "", + "landkreis_user": QgsExpressionContextUtils.globalScope().variable("sn_landkreis_user") or "", + "sachgebiet": QgsExpressionContextUtils.globalScope().variable("sn_sachgebiet") or "", + + # Projektvariablen + "bezeichnung": QgsExpressionContextUtils.projectScope(self.project).variable("sn_bezeichnung") or "", + "verfahrensnummer": QgsExpressionContextUtils.projectScope(self.project).variable("sn_verfahrensnummer") or "", + "gemeinden": QgsExpressionContextUtils.projectScope(self.project).variable("sn_gemeinden") or "", + "landkreise_proj": QgsExpressionContextUtils.projectScope(self.project).variable("sn_landkreise_proj") or "" + } diff --git a/main.py b/main.py index ccc4c2d..b4f32da 100644 --- a/main.py +++ b/main.py @@ -1,22 +1,21 @@ -import os - -class lnoSachsenBasis: - """ - Plugin-Klasse für Basisfunktionen. Stellt Funktionen und Klassen für andere Plugins bereit. - """ +from qgis.PyQt.QtCore import QCoreApplication +from qgis.PyQt.QtGui import QIcon +from sn_basis.ui.navigation import Navigation +from sn_basis.ui.dockmanager import DockManager +class BasisPlugin: def __init__(self, iface): self.iface = iface - self.plugin_dir = os.path.dirname(__file__) + self.ui = None + self.quitting = False + QCoreApplication.instance().aboutToQuit.connect(self._on_quit) + + def _on_quit(self): + self.quitting = True def initGui(self): - """ - Keine GUI-Integration nötig. - """ - pass + self.ui = Navigation(self.iface) def unload(self): - """ - Keine GUI-Elemente zu entfernen. - """ - pass \ No newline at end of file + if not self.quitting and self.ui: + self.ui.remove_all() diff --git a/metadata.txt b/metadata.txt index ec392aa..292ec53 100644 --- a/metadata.txt +++ b/metadata.txt @@ -1,23 +1,13 @@ [general] name=LNO Sachsen | Basisfunktionen qgisMinimumVersion=3.0 -description=Dieses Plugin ist ein Test -version=25.10.3 +description=Plugin mit Basisfunktionen +version=25.11.1 author=Michael Otto email=michael.otto@landkreis-mittelsachsen.de - -about=Provide a brief description of the plugin and its purpose. - -supportsQt6=True - -hasProcessingProvider=no -tags=python - +about=Plugin mit Basisfunktionen category=Plugins -icon=icon.png -experimental=True - -deprecated=False - -server=False - +homepage=https://entwicklung.vln-sn.de/AG_QGIS/Plugin_SN_Basis +repository=https://entwicklung.vln-sn.de/AG_QGIS/Repository +supportsQt6=true +experimental=true \ No newline at end of file diff --git a/ui/__init__.py b/ui/__init__.py index 55a1077..e69de29 100644 --- a/ui/__init__.py +++ b/ui/__init__.py @@ -1,3 +0,0 @@ -from .tab_projekt import TabProjektWidget -from .dockmanager import DockManager -from .navigation import Navigation \ No newline at end of file diff --git a/ui/dockmanager.py b/ui/dockmanager.py index d867a30..7b956fd 100644 --- a/ui/dockmanager.py +++ b/ui/dockmanager.py @@ -1,67 +1,21 @@ from qgis.PyQt.QtCore import Qt from qgis.PyQt.QtWidgets import QDockWidget from qgis.utils import iface -import inspect class DockManager: - """ - Zeigt ein Dockwidget an und schließt alle anderen mit dem Namensschema 'sn_dock_'. - Der Dockname wird automatisch aus dem Pluginmodul abgeleitet. - """ - - # Standard-Dockbereich: Rechts (wie die Verarbeitungswerkzeuge) - # default_area = Qt.RightDockWidgetArea #Qt6 default_area = Qt.DockWidgetArea.RightDockWidgetArea @classmethod def show(cls, dock_widget, area=None): - # Falls kein Bereich übergeben wurde, verwende den Standardwert if area is None: area = cls.default_area - # Pluginname automatisch aus dem Modulpfad ableiten (z. B. 'sn_plugin1' → 'plugin1') - caller_module = inspect.getmodule(inspect.stack()[1][0]) - full_module_name = caller_module.__name__ # z. B. 'sn_plugin1.main' - plugin_name = full_module_name.split('.')[0] # → 'sn_plugin1' - dock_name = f"sn_dock_{plugin_name.replace('sn_', '')}" # → 'sn_dock_plugin1' - - # Objektname für das Dock setzen, damit es eindeutig identifizierbar ist - dock_widget.setObjectName(dock_name) - - # Nur rechts andocken erlauben, wie bei der Toolbox - # dock_widget.setAllowedAreas(Qt.RightDockWidgetArea) #Qt6 - dock_widget.setAllowedAreas(Qt.DockWidgetArea.RightDockWidgetArea) - - # Dock-Features setzen: schließbar und verschiebbar - #dock_widget.setFeatures(QDockWidget.DockWidgetClosable | QDockWidget.DockWidgetMovable) #Qt6 - dock_widget.setFeatures( - QDockWidget.DockWidgetFeature.DockWidgetClosable | - QDockWidget.DockWidgetFeature.DockWidgetMovable - ) - - - # Alle vorhandenen Dockwidgets im Hauptfenster durchsuchen - # und solche mit dem Namensschema 'sn_dock_' schließen – außer dem aktuellen - all_docks = iface.mainWindow().findChildren(QDockWidget) - for widget in all_docks: - if widget.objectName().startswith("sn_dock_") and widget != dock_widget: - try: - iface.removeDockWidget(widget) - widget.close() - except Exception: - pass # Fehler beim Schließen ignorieren (z. B. falls bereits entfernt) + # Alle vorhandenen Plugin-Docks schließen + for widget in iface.mainWindow().findChildren(QDockWidget): + if widget != dock_widget and widget.objectName().startswith("sn_dock_"): + iface.removeDockWidget(widget) + widget.deleteLater() # Neues Dock anzeigen iface.addDockWidget(area, dock_widget) - - # Tabifizierung verhindern – andere Docks im selben Bereich entfernen - for widget in iface.mainWindow().findChildren(QDockWidget): - if widget != dock_widget and iface.mainWindow().dockWidgetArea(widget) == area: - iface.mainWindow().removeDockWidget(widget) - - # Breite setzen wie bei der Toolbox (optional, anpassbar) - dock_widget.setMinimumWidth(300) - dock_widget.setMaximumWidth(400) - - # Höhe nicht erzwingen – Qt passt sie automatisch an dock_widget.show() diff --git a/ui/navigation.py b/ui/navigation.py index 6fc80f6..bc14769 100644 --- a/ui/navigation.py +++ b/ui/navigation.py @@ -1,75 +1,37 @@ -from qgis.PyQt.QtWidgets import QMenu, QToolBar, QAction -from qgis.PyQt.QtGui import QIcon -from qgis.utils import iface - -_shared_toolbar = None # globale Toolbar-Instanz -_shared_menu = None # globale Menü-Instanz +from qgis.PyQt.QtWidgets import QAction, QMenu, QToolBar class Navigation: - TITLE = "LNO Sachsen" + def __init__(self, iface): + self.iface = iface + self.actions = [] - def __init__(self): - self.menu = self._get_or_create_menu() - self.toolbar = self._get_or_create_toolbar() + # Menü und Toolbar einmalig anlegen + self.menu = QMenu("LNO Sachsen", iface.mainWindow()) + iface.mainWindow().menuBar().addMenu(self.menu) - def _get_or_create_menu(self): - global _shared_menu - if _shared_menu: - return _shared_menu + self.toolbar = QToolBar("LNO Sachsen") + iface.addToolBar(self.toolbar) - menubar = iface.mainWindow().menuBar() - for action in menubar.actions(): - if action.menu() and action.text() == self.TITLE: - _shared_menu = action.menu() - return _shared_menu + def add_action(self, text, callback, tooltip="", priority=100, icon=None): + action = QAction(icon, text, self.iface.mainWindow()) if icon else QAction(text, self.iface.mainWindow()) + if tooltip: + action.setToolTip(tooltip) + action.triggered.connect(callback) - menu = QMenu(self.TITLE, iface.mainWindow()) - menu.setObjectName(self.TITLE) - menubar.addMenu(menu) - _shared_menu = menu - return menu + # Action mit Priority speichern + self.actions.append((priority, action)) + return action + + def finalize_menu_and_toolbar(self): + # Sortieren nach Priority + self.actions.sort(key=lambda x: x[0]) - def _get_or_create_toolbar(self): - global _shared_toolbar - if _shared_toolbar: - return _shared_toolbar - - main_window = iface.mainWindow() - toolbar = main_window.findChild(QToolBar, self.TITLE) - if not toolbar: - toolbar = QToolBar(self.TITLE, main_window) - toolbar.setObjectName(self.TITLE) - main_window.addToolBar(toolbar) - - _shared_toolbar = toolbar - return toolbar - - def add_action(self, text, callback, icon=None, tooltip=None): - # Menüeintrag - if not any(a.text() == text for a in self.menu.actions()): - action = QAction(icon, text, iface.mainWindow()) if icon else QAction(text, iface.mainWindow()) - if tooltip: - action.setToolTip(tooltip) - action.triggered.connect(callback) + # Menüeinträge + self.menu.clear() + for _, action in self.actions: self.menu.addAction(action) - # Symbolleistenaktion - if not any(a.text() == text for a in self.toolbar.actions()): - action = QAction(icon, text, iface.mainWindow()) if icon else QAction(text, iface.mainWindow()) - if tooltip: - action.setToolTip(tooltip) - action.triggered.connect(callback) + # Toolbar-Einträge + self.toolbar.clear() + for _, action in self.actions: self.toolbar.addAction(action) - - def remove_action(self, text): - # Menüeintrag entfernen - for act in self.menu.actions(): - if act.text() == text: - self.menu.removeAction(act) - break - - # Symbolleistenaktion entfernen - for act in self.toolbar.actions(): - if act.text() == text: - self.toolbar.removeAction(act) - break diff --git a/ui/tab_projekt.py b/ui/tab_projekt.py deleted file mode 100644 index fa9ba26..0000000 --- a/ui/tab_projekt.py +++ /dev/null @@ -1,20 +0,0 @@ -# tab_info.py -from qgis.PyQt import uic -from qgis.PyQt.QtWidgets import QWidget -import os - -FORM_CLASS, _ = uic.loadUiType(os.path.join( - os.path.dirname(__file__), 'tab_projekt.ui')) - -class TabProjektWidget(QWidget, FORM_CLASS): - def __init__(self, parent=None): - super().__init__(parent) - self.setupUi(self) - - # Zugriff auf den Button - self.btn_save.setText("Sichern") # Text ändern - self.btn_save.setEnabled(True) # Aktivieren - self.btn_save.clicked.connect(self.speichern) # Klick-Event verbinden - - def speichern(self): - print("Speichern wurde geklickt!") \ No newline at end of file diff --git a/ui/tab_projekt.ui b/ui/tab_projekt.ui deleted file mode 100644 index 8f954e6..0000000 --- a/ui/tab_projekt.ui +++ /dev/null @@ -1,264 +0,0 @@ - - - Form - - - - 0 - 0 - 604 - 939 - - - - - 60 - 0 - - - - Form - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - - - 50 - false - - - - Benutzerspezifische Festlegungen___ - - - - - - - - - - - 100 - 0 - - - - Amt - - - - - - - - - - - - - - - 100 - 0 - - - - Behörde - - - - - - - - - - - - - - - 100 - 0 - - - - Landkreis - - - - - - - - - - - - - - - 100 - 0 - - - - Sachgebiet - - - - - - - - - - - - - - - - - Projektspezifische Festlegungen - - - - - - - - - - - 100 - 0 - - - - Bezeichnung - - - - - - - - - - - - - - - 100 - 0 - - - - Verfahrensnummer - - - - - - - - - - - - - - - 100 - 0 - - - - Gemeinde(n) - - - - - - - - - - - - - - - 100 - 0 - - - - Landkreis(e) - - - - - - - - - - - - - - - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Speichern - - - - - - - - - - - - diff --git a/ui/tabs/__init__.py b/ui/tabs/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/ui/tabs/settings_tab.py b/ui/tabs/settings_tab.py new file mode 100644 index 0000000..cedf049 --- /dev/null +++ b/ui/tabs/settings_tab.py @@ -0,0 +1,84 @@ +from qgis.PyQt.QtWidgets import ( + QWidget, QGridLayout, QLabel, QLineEdit, + QGroupBox, QVBoxLayout, QPushButton +) +from sn_basis.logic.settings_logic import SettingsLogic + + +class SettingsTab(QWidget): + def __init__(self, parent=None): + super().__init__(parent) + self.logic = SettingsLogic() + + main_layout = QVBoxLayout() + + # 🟦 Benutzerspezifische Festlegungen + user_group = QGroupBox("Benutzerspezifische Festlegungen") + user_layout = QGridLayout() + self.amt = QLineEdit() + self.behoerde = QLineEdit() + self.landkreis_user = QLineEdit() + self.sachgebiet = QLineEdit() + user_layout.addWidget(QLabel("Amt:"), 0, 0) + user_layout.addWidget(self.amt, 0, 1) + user_layout.addWidget(QLabel("Behörde:"), 1, 0) + user_layout.addWidget(self.behoerde, 1, 1) + user_layout.addWidget(QLabel("Landkreis:"), 2, 0) + user_layout.addWidget(self.landkreis_user, 2, 1) + user_layout.addWidget(QLabel("Sachgebiet:"), 3, 0) + user_layout.addWidget(self.sachgebiet, 3, 1) + user_group.setLayout(user_layout) + + # 🟨 Projektspezifische Festlegungen + project_group = QGroupBox("Projektspezifische Festlegungen") + project_layout = QGridLayout() + self.bezeichnung = QLineEdit() + self.verfahrensnummer = QLineEdit() + self.gemeinden = QLineEdit() + self.landkreise_proj = QLineEdit() + project_layout.addWidget(QLabel("Bezeichnung:"), 0, 0) + project_layout.addWidget(self.bezeichnung, 0, 1) + project_layout.addWidget(QLabel("Verfahrensnummer:"), 1, 0) + project_layout.addWidget(self.verfahrensnummer, 1, 1) + project_layout.addWidget(QLabel("Gemeinde(n):"), 2, 0) + project_layout.addWidget(self.gemeinden, 2, 1) + project_layout.addWidget(QLabel("Landkreis(e):"), 3, 0) + project_layout.addWidget(self.landkreise_proj, 3, 1) + project_group.setLayout(project_layout) + + # 🟩 Speichern-Button + save_button = QPushButton("Speichern") + save_button.clicked.connect(self.save_data) + + # Layout zusammenfügen + main_layout.addWidget(user_group) + main_layout.addWidget(project_group) + main_layout.addStretch() + main_layout.addWidget(save_button) + + self.setLayout(main_layout) + self.load_data() + + def save_data(self): + fields = { + "amt": self.amt.text(), + "behoerde": self.behoerde.text(), + "landkreis_user": self.landkreis_user.text(), + "sachgebiet": self.sachgebiet.text(), + "bezeichnung": self.bezeichnung.text(), + "verfahrensnummer": self.verfahrensnummer.text(), + "gemeinden": self.gemeinden.text(), + "landkreise_proj": self.landkreise_proj.text() + } + self.logic.save(fields) + + def load_data(self): + data = self.logic.load() + self.amt.setText(data["amt"]) + self.behoerde.setText(data["behoerde"]) + self.landkreis_user.setText(data["landkreis_user"]) + self.sachgebiet.setText(data["sachgebiet"]) + self.bezeichnung.setText(data["bezeichnung"]) + self.verfahrensnummer.setText(data["verfahrensnummer"]) + self.gemeinden.setText(data["gemeinden"]) + self.landkreise_proj.setText(data["landkreise_proj"])