From e2d732e56418f57757f5e669fc3f50e30a80d2de Mon Sep 17 00:00:00 2001 From: Michael Otto Date: Thu, 9 Oct 2025 11:35:08 +0200 Subject: [PATCH] First commit --- .vscode/launch.json | 21 ++++++ __init__.py | 31 ++++++++ assets/20250908_134217_image.png | Bin 0 -> 2862 bytes assets/20250908_134247_image.png | Bin 0 -> 1330 bytes icons/icon.png | Bin 0 -> 607 bytes main.py | 81 +++++++++++++++++++++ metadata.txt | 21 ++++++ resources.py | 101 +++++++++++++++++++++++++++ resources.qrc | 5 ++ scripts/compile.bat | 11 +++ shared/__init__.py | 2 + shared/dockmanager.py | 60 ++++++++++++++++ shared/ui.py | 75 ++++++++++++++++++++ ui/__init__.py | 1 + ui/sn_verfahrensgebiet_dockwidget.py | 31 ++++++++ ui/tab_verfahrensgebiet.py | 12 ++++ ui/tab_verfahrensgebiet.ui | 32 +++++++++ 17 files changed, 484 insertions(+) create mode 100644 .vscode/launch.json create mode 100644 __init__.py create mode 100644 assets/20250908_134217_image.png create mode 100644 assets/20250908_134247_image.png create mode 100644 icons/icon.png create mode 100644 main.py create mode 100644 metadata.txt create mode 100644 resources.py create mode 100644 resources.qrc create mode 100644 scripts/compile.bat create mode 100644 shared/__init__.py create mode 100644 shared/dockmanager.py create mode 100644 shared/ui.py create mode 100644 ui/__init__.py create mode 100644 ui/sn_verfahrensgebiet_dockwidget.py create mode 100644 ui/tab_verfahrensgebiet.py create mode 100644 ui/tab_verfahrensgebiet.ui diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..2b792f5 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,21 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Python: Remote Attach to QGIS", + "type": "debugpy", + "request": "attach", + "connect": { + "host": "127.0.0.1", + "port": 5678 + }, + "pathMappings": [ + { + "localRoot": "${workspaceFolder}", + "remoteRoot": "${workspaceFolder}" + } + ], + "justMyCode": true + } + ] +} diff --git a/__init__.py b/__init__.py new file mode 100644 index 0000000..b1c14f9 --- /dev/null +++ b/__init__.py @@ -0,0 +1,31 @@ +# -*- coding: utf-8 -*- +# import debugpy + +# _debugger_started = False + +def classFactory(iface): + from .main import Verfahrensgebiet + # start_debugger() + return Verfahrensgebiet(iface) + +# def start_debugger(): +# global _debugger_started + +# if _debugger_started: +# return # Schon gestartet – nichts tun + +# try: +# debugpy.listen(5678) +# _debugger_started = True +# print("Debugger wartet auf Verbindung...") +# except RuntimeError: +# print("Debugger läuft bereits – Verbindung wird erwartet...") + +# if debugpy.is_client_connected(): +# print("Debugger verbunden – Plugin läuft") +# else: +# try: +# debugpy.wait_for_client() +# print("Debugger verbunden – Plugin läuft") +# except RuntimeError as e: +# print(f"Fehler beim Warten auf Debugger: {e}") diff --git a/assets/20250908_134217_image.png b/assets/20250908_134217_image.png new file mode 100644 index 0000000000000000000000000000000000000000..b921c4577540d0bf4eda1a9182272d7747451a94 GIT binary patch literal 2862 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 M07*qoM6N<$f>$q)N&o-= literal 0 HcmV?d00001 diff --git a/assets/20250908_134247_image.png b/assets/20250908_134247_image.png new file mode 100644 index 0000000000000000000000000000000000000000..076ca7e76006d7f93e3dc7fb089753195d05d314 GIT binary patch literal 1330 zcmV-21Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D1jk84K~#8N?U*@8 zD?u25x3aOZP!thFP!Mg@ChL7*AtHhxXd~z%S}E9Rp^aK(3vJX+R1g#-rm;{&EkrFf zN#ju{9(aKFZSz0=A-is7v&oB@yu^9)!-q5f&JprClbw-31Q#LE2@$_Dgh)<8h~y-M zNKQhCLaMg&(BXmlo291fr-eEj}JkV5h6K3 zh~$K*i%d>VhVt@qsHmu53XYkQl46>VSD1)=e}Dfmm6et7`1lB~udhtOF{`SoO!M(d zOo)7bem3R91;-R3eM5-+1uz%6v9SSPUtgxO6+$E%n23CPd(+VlsC3y16#4Y@WXikU zZkU~&g{!M8@_c!D8J3ooOzrUbr8HbPfdm;U_r_Lj_#Z>Vu`aZp!R=hI(^G)G7x*VoteRcI_*VI{J&vlE(|o8jW( z0uBxiNIO+k_2;-+3knLLr>6%pGc$!q)*{2*T91#9VP<9q^7HedtgH-1Mn+&@U;xt7 z)1kGs6}GpxNxRk6RoL3vg45GeC@d_DtVoXvvaEuK&c_f;MAB!tP{6Ixc#cF-EiEk& zA0H1nIXO^UTMI=+MWkL_TnuAlV?OtULZ9!6(%MoNF85vva+&ZXJ^OMpSeim7w=R+ z!aALg6ix*cr&f1@BFUh-{j~D~bCKG1N|&whC-VIKoLsNX&(D)OZnb%Nd9b&)XX+nO zk>tx%z^Ucw=f*m{nvLzfe^urC`L{4D+@Q))6d5W;k@&l|xw#30gM*NmmY*wD}bX=!PYk&yxQ_4VZ3XzYJ|eGRfK6OqO| zj)@}a`2ymygUz_AY<6&Ic`R#xjqU#?Z}ps>UuO{%$p&^8owtU$NbNSBE?Z#~iJ+Li zzCI$;Pa8a2;!BXz=_GHrxV>V1Wo3n2&qYk6q`;y#@3Pyx0;w;b7D$gv z*NyofNJN;63}-j{{uoKCq!K&Ud5G^l#oL|OK{Aj zq$JaPyb^Vh0yZ!ai5Jv@=psaNf)L3GLL?_J5vg5L3!+EZB5?pgY!H@6L2MByEJcd= oT_Hqr5<(;=Aw+T#LL?{g2mjXqRWIqf{{R3007*qoM6N<$f_&0yPyhe` literal 0 HcmV?d00001 diff --git a/icons/icon.png b/icons/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..a4cdc61a155d2de93f86604bef196853c131b7e5 GIT binary patch literal 607 zcmV-l0-*hgP)pF8FWQhbW?9;ba!ELWdL_~cP?peYja~^aAhuUa%Y?FJQ@H10qjXc zK~z|U?UqkVR8bhle~;W?T$Le=kmS^&b(>u0N+V(j+}frOAVCWuXj6-pE)t<_pkE*o zzkqI9BnfUL{~)0Wv&ozpGTs*V9Xed^_1+vECFX_8x%W5kx$kq%dCr+D;0I9RVxk@a zSAagC+2P_P;Cti`M`re`lhq|f06m>7nigFFmtTOSK1pvSRRdO*G$U#3gnoA<%}RQc zSEB)x%#5@PxDOccB47`lJxj@tfJxxMbM`ad+Y8i-EWs^rHv%@~?Pg-scY#m9H1N5= zyNU8ss1y|dyauiUkAY=i_tXL;jR2!SYn`72K6v2mQ%Or^Hs{YTfi*L$ODg9TZ$+vH zfLA~bI0AnAeJzE3$XMet1w4=`AV}QwQHAUqu#(m1Uj&?JLO-u>09yeo0RtgxC-Qc| zAhA!j16Bc)V5g2$6H4mwLiZf~lyuwghXXcbW^K>JF%NiQD|l7f@j%u#`~r*v6F?Q1 z0>1ih6TlTyh{F z)p(NLNis>s-($GH#UwQ)^@e@&{tFg>^#uC}tY+jd5>I6|o1dnOP%8%$bJI tMD6l_5p@N01^o8{S_e^G(nZv7`~mZ}gGN*%+aLe{002ovPDHLkV1n|g0h|B; literal 0 HcmV?d00001 diff --git a/main.py b/main.py new file mode 100644 index 0000000..89ddc7b --- /dev/null +++ b/main.py @@ -0,0 +1,81 @@ +# Import grundlegender Qt- und QGIS-Komponenten +from qgis.PyQt.QtCore import QSettings, QTranslator, QCoreApplication, Qt +from qgis.PyQt.QtGui import QIcon +from qgis.PyQt.QtWidgets import QAction, QMessageBox +from qgis.utils import plugins + +# Import der generierten Ressourcen (z. B. Icons) +from .resources import * + +# Import der gemeinsamen UI-Klasse für Menü und Symbolleiste +from .shared import UI +from .shared import DockManager + +# Import des Dockwidgets, das beim Ausführen des Plugins angezeigt wird +from .ui.sn_verfahrensgebiet_dockwidget import VerfahrensgebietDockWidget +import os.path + +class Verfahrensgebiet: + """ + Hauptklasse des Plugins. Verwaltet die Initialisierung, GUI-Integration und das Dockwidget. + """ + + def __init__(self, iface): + # iface: QGIS-Schnittstelle zur Interaktion mit der Anwendung + self.iface = iface + self.plugin_dir = os.path.dirname(__file__) # Pfad zum Plugin-Verzeichnis + + self.actions = [] # Platzhalter für spätere Aktionsverwaltung (optional) + self.pluginIsActive = False # Statusflag, ob das Plugin aktiv ist + self.dockwidget = None # Referenz auf das Dockwidget + + def initGui(self): + """ + Wird beim Laden des Plugins aufgerufen. Fügt Menüeintrag und Symbolleistenaktion hinzu. + """ + self.action_text = "Verfahrensgebiet" # Einheitlicher Text für Menü und Toolbar + icon = QIcon(":/sn_plugin1/icons/icon.png") # Icon aus Ressourcen laden + self.ui = UI() # Gemeinsame UI-Instanz für Menü und Toolbar + self.ui.add_action(self.action_text, self.run, icon, tooltip="Öffnet Verfahrensgebiet") + + def onClosePlugin(self): + """ + Wird aufgerufen, wenn das Dockwidget geschlossen wird. Setzt den Aktivitätsstatus zurück. + """ + self.dockwidget.closingPlugin.disconnect(self.onClosePlugin) + self.pluginIsActive = False + + def unload(self): + """ + Wird beim Deaktivieren des Plugins aufgerufen. Entfernt Menü- und Toolbar-Eintrag. + """ + self.ui.remove_action(self.action_text) + + def run(self): + """ + Wird beim Klick auf Menüeintrag oder Symbolleistenaktion ausgeführt. + Zeigt das Dockwidget an. + """ + if 'sn_basis' not in plugins: + QMessageBox.warning(None, "Abhängigkeit fehlt", + "Das Plugin 'LNO Sachsen | Basisfunktionen' ist nicht installiert oder nicht aktiviert.\nBitte installieren und aktivieren, um fortzufahren.") + return # Plugin nicht starten + + # Prüfen, ob das eigene Dockwidget existiert und aktuell sichtbar ist + dock_visible = self.dockwidget is not None and self.dockwidget.isVisible() + + if not dock_visible: + # Pluginstatus setzen, damit z. B. beim Schließen korrekt zurückgesetzt werden kann + self.pluginIsActive = True + + # Falls noch kein Dockwidget existiert, wird es jetzt erzeugt + if self.dockwidget is None: + self.dockwidget = VerfahrensgebietDockWidget() + self.dockwidget.closingPlugin.connect(self.onClosePlugin) + + # Dock anzeigen und ggf. andere Docks schließen + from .shared.dockmanager import DockManager + DockManager.show(self.dockwidget) + else: + # Falls das eigene Dock bereits sichtbar ist, wird keine Aktion ausgeführt + pass diff --git a/metadata.txt b/metadata.txt new file mode 100644 index 0000000..0a4eaf2 --- /dev/null +++ b/metadata.txt @@ -0,0 +1,21 @@ +[general] +name=LNO Sachsen | Verfahrensgebiet +qgisMinimumVersion=3.0 +description=Dieses Plugin ist ein Test +version=25.10.1 +author=Michael Otto +email=michael.otto@landkreis-mittelsachsen.de + +about=Provide a brief description of the plugin and its purpose. + +hasProcessingProvider=no +tags=python + +category=Plugins +icon=icon.png +experimental=True + +deprecated=False + +server=False + diff --git a/resources.py b/resources.py new file mode 100644 index 0000000..5a9d74d --- /dev/null +++ b/resources.py @@ -0,0 +1,101 @@ +# -*- coding: utf-8 -*- + +# Resource object code +# +# Created by: The Resource Compiler for PyQt5 (Qt v5.15.2) +# +# WARNING! All changes made in this file will be lost! + +from PyQt5 import QtCore + +qt_resource_data = b"\ +\x00\x00\x02\x5f\ +\x89\ +\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\ +\x00\x00\x20\x00\x00\x00\x20\x08\x06\x00\x00\x00\x73\x7a\x7a\xf4\ +\x00\x00\x00\x09\x70\x48\x59\x73\x00\x00\x0e\xc3\x00\x00\x0e\xc3\ +\x01\xc7\x6f\xa8\x64\x00\x00\x00\x19\x74\x45\x58\x74\x53\x6f\x66\ +\x74\x77\x61\x72\x65\x00\x77\x77\x77\x2e\x69\x6e\x6b\x73\x63\x61\ +\x70\x65\x2e\x6f\x72\x67\x9b\xee\x3c\x1a\x00\x00\x01\xec\x49\x44\ +\x41\x54\x58\x85\xed\x96\x4f\x4b\x54\x51\x18\xc6\x7f\x8f\xdc\x60\ +\x5c\x95\x21\x8c\x90\xe4\xd4\xa2\x75\x9b\x5c\xe7\x4a\x23\x62\x08\ +\xdc\xda\xa6\x0f\x20\x41\x0b\x21\x68\x53\x8b\x96\x2e\x12\xa1\x6d\ +\xa0\x5f\x20\x12\xbf\x80\x6e\x5a\x24\x09\x6e\x24\xff\x20\xa1\x09\ +\xb3\xc9\x9c\x19\x32\xde\x16\xf7\x1d\x3a\x5c\xef\xf5\xde\x1c\x1d\ +\x25\xe6\x85\xcb\xb9\xf7\x37\xef\xb9\xef\x73\xce\x79\xce\x99\x2b\ +\xe0\x07\x50\xe2\x62\xa2\x1e\x01\x57\x80\x3e\xa0\xd9\xe1\xe2\x25\ +\xe0\x7b\xe4\x0f\x47\x66\xf6\xab\x93\xd5\x25\x45\x00\x3d\x9d\x2c\ +\x9a\x16\x5d\x01\x97\x5f\x80\xa4\x3e\x49\x6f\x25\x55\x03\x56\x96\ +\x34\x23\x69\xec\x84\x7e\x77\x24\xcd\x4a\x7a\x93\x57\xa3\x01\x94\ +\xcc\x8c\xb4\x0b\xb8\x0f\x18\xf0\x22\x60\x0f\x9d\x3d\x4b\xc9\x8f\ +\x80\x49\xe0\xc0\x73\xf6\x33\xde\xdb\x0b\xd4\x8b\x2c\xc1\x2d\x6f\ +\x37\x02\x36\xe4\xed\x66\x62\xd4\x77\x81\x4f\xc0\x34\xf0\xb9\xc0\ +\xbb\x89\xf2\x53\xa8\x14\x15\x00\xbc\x06\xae\x02\x8f\x81\x65\x60\ +\xf7\xd4\x02\x24\x8d\x00\xa3\x40\x6b\x9d\x9f\x04\x3e\x78\xe0\xed\ +\x53\x49\x4b\x66\x36\xe7\xcf\x2f\x81\x35\x33\xab\x4b\x2a\xe7\x15\ +\x6f\x45\xaa\x07\x80\x57\x40\x0d\x38\x02\x7e\xfb\x7d\x2d\x85\x7d\ +\xc8\x58\xe3\x32\x05\x3c\x90\x29\x20\x48\xdc\xf4\x51\x85\xec\x1b\ +\xb0\x92\xd5\xe7\x5f\x04\x9c\x68\x42\x3f\xaf\x6f\x00\x5b\x01\x2b\ +\x01\x03\x21\x6b\x27\xf2\x76\xc1\x20\xb1\x4f\xb6\x03\x56\x01\x94\ +\x60\xa7\x8e\x54\x13\x4a\xea\xf1\x42\xf7\x1c\xfd\x94\x74\xdb\xef\ +\x87\x03\x36\x64\x66\x6d\xcf\xc4\x31\x0f\x78\x61\x2b\x78\x55\xda\ +\xf1\x40\xd6\x36\xfc\x02\x8c\x03\x13\x40\x15\x98\x02\xbe\xfa\x6f\ +\x13\xc0\x23\xe0\x39\xb1\x41\x77\xce\x7c\x06\x02\x95\xef\x7d\x14\ +\x03\x01\x9b\x77\x76\xfd\xdc\x77\x01\xf1\x89\xd7\x04\xf6\x12\xec\ +\xc0\xcc\x6a\xed\x8e\x1c\xf2\x77\xc1\x4d\x60\xdb\x5c\x72\x20\x20\ +\xd5\x78\x92\xde\x49\x32\x49\xc6\xdf\x63\xb8\xbf\xc5\x24\x35\x25\ +\xf5\x86\x7d\xf2\xfe\x0b\x16\x80\xf5\x04\xfb\x08\xac\x66\xe4\x2f\ +\x12\x4f\x7b\x56\x1c\x92\xf8\xf8\x15\xb1\x07\xae\x99\x59\x23\x47\ +\xcc\x99\x86\xcf\x44\xed\xf2\x7f\x11\x75\x05\x74\x05\xfc\xf7\x02\ +\x5a\x07\x51\x5d\xd2\x45\xd4\x6f\xfc\x01\xf3\xb6\x83\x46\x54\x23\ +\xdb\x20\x00\x00\x00\x00\x49\x45\x4e\x44\xae\x42\x60\x82\ +" + +qt_resource_name = b"\ +\x00\x0a\ +\x07\x34\x98\xd1\ +\x00\x73\ +\x00\x6e\x00\x5f\x00\x70\x00\x6c\x00\x75\x00\x67\x00\x69\x00\x6e\x00\x31\ +\x00\x05\ +\x00\x6f\xa6\x53\ +\x00\x69\ +\x00\x63\x00\x6f\x00\x6e\x00\x73\ +\x00\x08\ +\x0a\x61\x5a\xa7\ +\x00\x69\ +\x00\x63\x00\x6f\x00\x6e\x00\x2e\x00\x70\x00\x6e\x00\x67\ +" + +qt_resource_struct_v1 = b"\ +\x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x01\ +\x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x02\ +\x00\x00\x00\x1a\x00\x02\x00\x00\x00\x01\x00\x00\x00\x03\ +\x00\x00\x00\x2a\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\ +" + +qt_resource_struct_v2 = b"\ +\x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x01\ +\x00\x00\x00\x00\x00\x00\x00\x00\ +\x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x02\ +\x00\x00\x00\x00\x00\x00\x00\x00\ +\x00\x00\x00\x1a\x00\x02\x00\x00\x00\x01\x00\x00\x00\x03\ +\x00\x00\x00\x00\x00\x00\x00\x00\ +\x00\x00\x00\x2a\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\ +\x00\x00\x01\x99\x28\x6e\x23\x10\ +" + +qt_version = [int(v) for v in QtCore.qVersion().split('.')] +if qt_version < [5, 8, 0]: + rcc_version = 1 + qt_resource_struct = qt_resource_struct_v1 +else: + rcc_version = 2 + qt_resource_struct = qt_resource_struct_v2 + +def qInitResources(): + QtCore.qRegisterResourceData(rcc_version, qt_resource_struct, qt_resource_name, qt_resource_data) + +def qCleanupResources(): + QtCore.qUnregisterResourceData(rcc_version, qt_resource_struct, qt_resource_name, qt_resource_data) + +qInitResources() diff --git a/resources.qrc b/resources.qrc new file mode 100644 index 0000000..ea9d1ea --- /dev/null +++ b/resources.qrc @@ -0,0 +1,5 @@ + + + icons/icon.png + + diff --git a/scripts/compile.bat b/scripts/compile.bat new file mode 100644 index 0000000..c6f2bb6 --- /dev/null +++ b/scripts/compile.bat @@ -0,0 +1,11 @@ +@echo off +REM Wechsle ins Plugin-Hauptverzeichnis (eine Ebene über /scripts) +cd /d %~dp0\.. + +call "C:\Program Files\QGIS 3.34.5\bin\o4w_env.bat" + +REM Kompiliere die Ressourcen-Datei +pyrcc5 resources.qrc -o resources.py + +@echo on +echo Ressourcen wurden erfolgreich kompiliert. diff --git a/shared/__init__.py b/shared/__init__.py new file mode 100644 index 0000000..3ba489b --- /dev/null +++ b/shared/__init__.py @@ -0,0 +1,2 @@ +from .ui import UI +from .dockmanager import DockManager diff --git a/shared/dockmanager.py b/shared/dockmanager.py new file mode 100644 index 0000000..04812be --- /dev/null +++ b/shared/dockmanager.py @@ -0,0 +1,60 @@ +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 + + @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) + + # Dock-Features setzen: schließbar und verschiebbar + dock_widget.setFeatures(QDockWidget.DockWidgetClosable | QDockWidget.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) + + # 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/shared/ui.py b/shared/ui.py new file mode 100644 index 0000000..a839fbc --- /dev/null +++ b/shared/ui.py @@ -0,0 +1,75 @@ +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 + +class UI: + TITLE = "LNO Sachsen" + + def __init__(self): + self.menu = self._get_or_create_menu() + self.toolbar = self._get_or_create_toolbar() + + def _get_or_create_menu(self): + global _shared_menu + if _shared_menu: + return _shared_menu + + menubar = iface.mainWindow().menuBar() + for action in menubar.actions(): + if action.menu() and action.text() == self.TITLE: + _shared_menu = action.menu() + return _shared_menu + + menu = QMenu(self.TITLE, iface.mainWindow()) + menu.setObjectName(self.TITLE) + menubar.addMenu(menu) + _shared_menu = menu + return menu + + 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) + 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) + 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/__init__.py b/ui/__init__.py new file mode 100644 index 0000000..d1f4eb2 --- /dev/null +++ b/ui/__init__.py @@ -0,0 +1 @@ +from .tab_verfahrensgebiet import TabVerfahrensgebietWidget \ No newline at end of file diff --git a/ui/sn_verfahrensgebiet_dockwidget.py b/ui/sn_verfahrensgebiet_dockwidget.py new file mode 100644 index 0000000..3f1cc61 --- /dev/null +++ b/ui/sn_verfahrensgebiet_dockwidget.py @@ -0,0 +1,31 @@ +from qgis.PyQt.QtWidgets import QDockWidget, QTabWidget, QVBoxLayout, QWidget +from qgis.PyQt.QtCore import pyqtSignal + +from sn_basis.ui.tab_projekt import TabProjektWidget + +from ..ui import TabVerfahrensgebietWidget + +class VerfahrensgebietDockWidget(QDockWidget): + + closingPlugin = pyqtSignal() + + def __init__(self, parent=None): + super().__init__(parent) + + self.setWindowTitle("LNO Sachsen | Verfahrensgebiet") + + container = QWidget() + layout = QVBoxLayout(container) + + self.tabWidget = QTabWidget() + layout.addWidget(self.tabWidget) + + self.setWidget(container) + + # Tabs hinzufügen + self.tabWidget.addTab(TabVerfahrensgebietWidget(self), "Verfahrensgebiet") + self.tabWidget.addTab(TabProjektWidget(self), "Projekt") + + def closeEvent(self, event): + self.closingPlugin.emit() + event.accept() \ No newline at end of file diff --git a/ui/tab_verfahrensgebiet.py b/ui/tab_verfahrensgebiet.py new file mode 100644 index 0000000..ea4718c --- /dev/null +++ b/ui/tab_verfahrensgebiet.py @@ -0,0 +1,12 @@ +# 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_verfahrensgebiet.ui')) + +class TabVerfahrensgebietWidget(QWidget, FORM_CLASS): + def __init__(self, parent=None): + super().__init__(parent) + self.setupUi(self) diff --git a/ui/tab_verfahrensgebiet.ui b/ui/tab_verfahrensgebiet.ui new file mode 100644 index 0000000..0e9f56a --- /dev/null +++ b/ui/tab_verfahrensgebiet.ui @@ -0,0 +1,32 @@ + + + Form + + + + 0 + 0 + 538 + 295 + + + + Form + + + + + 40 + 50 + 47 + 13 + + + + Tab 2 + + + + + +