diff --git a/functions/ly_existence_wrapper.py b/functions/ly_existence_wrapper.py index d39e000..08ded40 100644 --- a/functions/ly_existence_wrapper.py +++ b/functions/ly_existence_wrapper.py @@ -1,20 +1,31 @@ # sn_basis/functions/ly_existence_wrapper.py def layer_exists(layer) -> bool: + """ + Prüft, ob ein Layer-Objekt existiert (nicht None). + """ + return layer is not None + + +def layer_is_valid(layer) -> bool: + """ + Prüft, ob ein Layer gültig ist (QGIS-konform). + """ if layer is None: return False - is_valid_flag = getattr(layer, "is_valid", None) - if is_valid_flag is not None: + is_valid = getattr(layer, "isValid", None) + if callable(is_valid): try: - return bool(is_valid_flag) + return bool(is_valid()) except Exception: return False - try: - is_valid = getattr(layer, "isValid", None) - if callable(is_valid): - return bool(is_valid()) - return True - except Exception: - return False + return False + + +def layer_is_usable(layer) -> bool: + """ + Prüft, ob ein Layer existiert und gültig ist. + """ + return layer_exists(layer) and layer_is_valid(layer) diff --git a/functions/ly_geometry_wrapper.py b/functions/ly_geometry_wrapper.py index 97c2b6a..03a33de 100644 --- a/functions/ly_geometry_wrapper.py +++ b/functions/ly_geometry_wrapper.py @@ -1,48 +1,57 @@ # sn_basis/functions/ly_geometry_wrapper.py -def get_layer_geometry_type(layer) -> str: - if layer is None: - return "None" +from typing import Optional - geometry_type = getattr(layer, "geometry_type", None) - if geometry_type is not None: - return str(geometry_type) + +GEOM_NONE = None +GEOM_POINT = "Point" +GEOM_LINE = "LineString" +GEOM_POLYGON = "Polygon" + + +def get_layer_geometry_type(layer) -> Optional[str]: + """ + Gibt den Geometrietyp eines Layers zurück. + + Rückgabewerte: + - "Point" + - "LineString" + - "Polygon" + - None (nicht räumlich / ungültig / unbekannt) + """ + if layer is None: + return None try: - if callable(getattr(layer, "isSpatial", None)) and not layer.isSpatial(): - return "None" + is_spatial = getattr(layer, "isSpatial", None) + if callable(is_spatial) and not is_spatial(): + return None gtype = getattr(layer, "geometryType", None) if callable(gtype): value = gtype() - if not isinstance(value, int): - return "None" - - return { - 0: "Point", - 1: "LineString", - 2: "Polygon", - }.get(value, "None") + if value == 0: + return GEOM_POINT + if value == 1: + return GEOM_LINE + if value == 2: + return GEOM_POLYGON except Exception: pass - return "None" - - + return None def get_layer_feature_count(layer) -> int: + """ + Gibt die Anzahl der Features eines Layers zurück. + """ if layer is None: return 0 - count = getattr(layer, "feature_count", None) - if count is not None: - if isinstance(count, int): - return count - return 0 - try: - if callable(getattr(layer, "isSpatial", None)) and not layer.isSpatial(): + is_spatial = getattr(layer, "isSpatial", None) + if callable(is_spatial) and not is_spatial(): return 0 fc = getattr(layer, "featureCount", None) @@ -54,4 +63,3 @@ def get_layer_feature_count(layer) -> int: pass return 0 - diff --git a/functions/ly_metadata_wrapper.py b/functions/ly_metadata_wrapper.py index 48c4d19..dde7a9c 100644 --- a/functions/ly_metadata_wrapper.py +++ b/functions/ly_metadata_wrapper.py @@ -1,35 +1,44 @@ -# layer/metadata.py +# sn_basis/functions/ly_metadata_wrapper.py -def get_layer_type(layer) -> str: +from typing import Optional, List + + +LAYER_TYPE_VECTOR = "vector" +LAYER_TYPE_TABLE = "table" + + +def get_layer_type(layer) -> Optional[str]: + """ + Gibt den Layer-Typ zurück. + + Rückgabewerte: + - "vector" + - "table" + - None (unbekannt / nicht bestimmbar) + """ if layer is None: - return "unknown" - - layer_type = getattr(layer, "layer_type", None) - if layer_type is not None: - return str(layer_type) + return None try: - if callable(getattr(layer, "isSpatial", None)): - return "vector" if layer.isSpatial() else "table" + is_spatial = getattr(layer, "isSpatial", None) + if callable(is_spatial): + return LAYER_TYPE_VECTOR if is_spatial() else LAYER_TYPE_TABLE except Exception: pass - return "unknown" + return None -def get_layer_crs(layer) -> str: +def get_layer_crs(layer) -> Optional[str]: + """ + Gibt das CRS als AuthID zurück (z. B. 'EPSG:25833'). + """ if layer is None: - return "None" - - crs = getattr(layer, "crs", None) - if crs is not None and not callable(crs): - if isinstance(crs, str): - return crs - return "None" + return None try: - crs_obj = layer.crs() - authid = getattr(crs_obj, "authid", None) + crs = layer.crs() + authid = getattr(crs, "authid", None) if callable(authid): value = authid() if isinstance(value, str): @@ -37,49 +46,47 @@ def get_layer_crs(layer) -> str: except Exception: pass - return "None" + return None - -def get_layer_fields(layer) -> list[str]: +def get_layer_fields(layer) -> List[str]: + """ + Gibt die Feldnamen eines Layers zurück. + """ if layer is None: return [] - fields = getattr(layer, "fields", None) - if fields is not None and not callable(fields): - return list(fields) - try: - f = layer.fields() - if callable(getattr(f, "names", None)): - return list(f.names()) - return list(f) + return list(layer.fields().names()) except Exception: return [] -def get_layer_source(layer) -> str: - if layer is None: - return "None" - source = getattr(layer, "source", None) - if source is not None and not callable(source): - return str(source) +def get_layer_source(layer) -> Optional[str]: + """ + Gibt die Datenquelle eines Layers zurück. + """ + if layer is None: + return None try: - return layer.source() or "None" + value = layer.source() + if isinstance(value, str) and value: + return value except Exception: - return "None" + pass + + return None def is_layer_editable(layer) -> bool: + """ + Prüft, ob ein Layer editierbar ist. + """ if layer is None: return False - editable = getattr(layer, "editable", None) - if editable is not None: - return bool(editable) - try: is_editable = getattr(layer, "isEditable", None) if callable(is_editable): diff --git a/functions/ly_style_wrapper.py b/functions/ly_style_wrapper.py index 71d48e6..3145532 100644 --- a/functions/ly_style_wrapper.py +++ b/functions/ly_style_wrapper.py @@ -1,4 +1,4 @@ -# layer/style.py +# sn_basis/functions/ly_style_wrapper.py from sn_basis.functions.ly_existence_wrapper import layer_exists from sn_basis.functions.sys_wrapper import ( diff --git a/functions/ly_visibility_wrapper.py b/functions/ly_visibility_wrapper.py index b37a4ce..ba375bc 100644 --- a/functions/ly_visibility_wrapper.py +++ b/functions/ly_visibility_wrapper.py @@ -1,17 +1,19 @@ # sn_basis/functions/ly_visibility_wrapper.py def is_layer_visible(layer) -> bool: + """ + Prüft, ob ein Layer im Layer-Tree sichtbar ist. + """ if layer is None: return False - visible = getattr(layer, "visible", None) - if visible is not None: - return bool(visible) - try: - is_visible = getattr(layer, "isVisible", None) - if callable(is_visible): - return bool(is_visible()) + node = getattr(layer, "treeLayer", None) + if callable(node): + tree_node = node() + is_visible = getattr(tree_node, "isVisible", None) + if callable(is_visible): + return bool(is_visible()) except Exception: pass @@ -19,21 +21,20 @@ def is_layer_visible(layer) -> bool: def set_layer_visible(layer, visible: bool) -> bool: + """ + Setzt die Sichtbarkeit eines Layers im Layer-Tree. + """ if layer is None: return False try: - if hasattr(layer, "visible"): - layer.visible = bool(visible) - return True - except Exception: - pass - - try: - node = getattr(layer, "treeLayer", lambda: None)() - if node and callable(getattr(node, "setItemVisibilityChecked", None)): - node.setItemVisibilityChecked(bool(visible)) - return True + node = getattr(layer, "treeLayer", None) + if callable(node): + tree_node = node() + setter = getattr(tree_node, "setItemVisibilityChecked", None) + if callable(setter): + setter(bool(visible)) + return True except Exception: pass diff --git a/functions/qgiscore_wrapper.py b/functions/qgiscore_wrapper.py index 77e8ae3..a554e88 100644 --- a/functions/qgiscore_wrapper.py +++ b/functions/qgiscore_wrapper.py @@ -18,6 +18,7 @@ QgsProject: Type[Any] QgsVectorLayer: Type[Any] QgsNetworkAccessManager: Type[Any] Qgis: Type[Any] +QgsMapLayerProxyModel: Type[Any] QGIS_AVAILABLE = False @@ -31,12 +32,14 @@ try: QgsVectorLayer as _QgsVectorLayer, QgsNetworkAccessManager as _QgsNetworkAccessManager, Qgis as _Qgis, + QgsMapLayerProxyModel as _QgsMaplLayerProxyModel ) QgsProject = _QgsProject QgsVectorLayer = _QgsVectorLayer QgsNetworkAccessManager = _QgsNetworkAccessManager Qgis = _Qgis + QgsMapLayerProxyModel=_QgsMaplLayerProxyModel QGIS_AVAILABLE = True @@ -94,6 +97,20 @@ except Exception: Qgis = _MockQgis + class _MockQgsMapLayerProxyModel: + # Layer-Typen (entsprechen QGIS-Konstanten) + NoLayer = 0 + VectorLayer = 1 + RasterLayer = 2 + PluginLayer = 3 + MeshLayer = 4 + VectorTileLayer = 5 + PointCloudLayer = 6 + + def __init__(self, *args, **kwargs): + pass + + QgsMapLayerProxyModel = _MockQgsMapLayerProxyModel # --------------------------------------------------------- # Netzwerk diff --git a/functions/qgisui_wrapper.py b/functions/qgisui_wrapper.py index 56e5775..77b945d 100644 --- a/functions/qgisui_wrapper.py +++ b/functions/qgisui_wrapper.py @@ -2,7 +2,10 @@ sn_basis/functions/qgisui_wrapper.py – zentrale QGIS-UI-Abstraktion """ -from typing import Any, List +from __future__ import annotations + +from typing import Any, List, Type + from sn_basis.functions.qt_wrapper import QDockWidget @@ -10,18 +13,39 @@ from sn_basis.functions.qt_wrapper import QDockWidget iface: Any QGIS_UI_AVAILABLE = False +QgsFileWidget: Type[Any] +QgsMapLayerComboBox: Type[Any] + # --------------------------------------------------------- -# iface initialisieren (QGIS oder Mock) +# iface + QGIS-Widgets initialisieren (QGIS oder Mock) # --------------------------------------------------------- try: from qgis.utils import iface as _iface + from qgis.gui import ( + QgsFileWidget as _QgsFileWidget, + QgsMapLayerComboBox as _QgsMapLayerComboBox, + ) + iface = _iface + QgsFileWidget = _QgsFileWidget + QgsMapLayerComboBox = _QgsMapLayerComboBox QGIS_UI_AVAILABLE = True except Exception: - + QGIS_UI_AVAILABLE = False + + class _MockSignal: + def __init__(self): + self._callbacks: list[Any] = [] + + def connect(self, callback): + self._callbacks.append(callback) + + def emit(self, *args, **kwargs): + for cb in list(self._callbacks): + cb(*args, **kwargs) class _MockMessageBar: def pushMessage(self, title, text, level=0, duration=5): @@ -53,6 +77,48 @@ except Exception: iface = _MockIface() + class _MockQgsFileWidget: + GetFile = 0 + + def __init__(self, *args, **kwargs): + self._path = "" + self.fileChanged = _MockSignal() + + def setStorageMode(self, *args, **kwargs): + pass + + def setFilter(self, *args, **kwargs): + pass + + def setFilePath(self, path: str): + self._path = path + self.fileChanged.emit(path) + + def filePath(self) -> str: + return self._path + + class _MockQgsMapLayerComboBox: + def __init__(self, *args, **kwargs): + self.layerChanged = _MockSignal() + self._layer = None + self._count = 0 + + def setFilters(self, *args, **kwargs): + pass + + def setLayer(self, layer): + self._layer = layer + self.layerChanged.emit(layer) + + def count(self) -> int: + return self._count + + def setCurrentIndex(self, idx: int): + pass + + QgsFileWidget = _MockQgsFileWidget + QgsMapLayerComboBox = _MockQgsMapLayerComboBox + # --------------------------------------------------------- # Main Window @@ -108,8 +174,6 @@ def add_menu(menu): main_window.menuBar().addMenu(menu) - - def remove_menu(menu): main_window = iface.mainWindow() if not main_window: @@ -119,9 +183,6 @@ def remove_menu(menu): main_window.menuBar().removeAction(menu.menuAction()) - - - # --------------------------------------------------------- # Toolbar-Handling # --------------------------------------------------------- diff --git a/functions/qt_wrapper.py b/functions/qt_wrapper.py index 08de053..9e116dc 100644 --- a/functions/qt_wrapper.py +++ b/functions/qt_wrapper.py @@ -29,8 +29,9 @@ QMenu: Type[Any] QToolBar: Type[Any] QActionGroup: Type[Any] QTabWidget: type - - +QToolButton: Type[Any] +QSizePolicy: Type[Any] +Qt: Type[Any] YES: Optional[Any] = None NO: Optional[Any] = None @@ -65,6 +66,9 @@ try: QActionGroup as _QActionGroup,# type: ignore QDockWidget as _QDockWidget,# type: ignore QTabWidget as _QTabWidget,# type: ignore + QToolButton as _QToolButton,#type:ignore + QSizePolicy as _QSizePolicy,#type:ignore + ) @@ -73,6 +77,7 @@ try: QEventLoop as _QEventLoop,# type: ignore QUrl as _QUrl,# type: ignore QCoreApplication as _QCoreApplication,# type: ignore + Qt as _Qt#type:ignore ) from qgis.PyQt.QtNetwork import ( # type: ignore QNetworkRequest as _QNetworkRequest,# type: ignore @@ -86,6 +91,7 @@ try: QNetworkRequest = _QNetworkRequest QNetworkReply = _QNetworkReply QCoreApplication = _QCoreApplication + Qt=_Qt QDockWidget = _QDockWidget QWidget = _QWidget QGridLayout = _QGridLayout @@ -99,13 +105,37 @@ try: QToolBar = _QToolBar QActionGroup = _QActionGroup QTabWidget = _QTabWidget - - + QToolButton=_QToolButton + QSizePolicy=_QSizePolicy YES = QMessageBox.StandardButton.Yes NO = QMessageBox.StandardButton.No CANCEL = QMessageBox.StandardButton.Cancel ICON_QUESTION = QMessageBox.Icon.Question + # --------------------------------------------------------- + # Qt6 Enum-Aliase (vereinheitlicht) + # --------------------------------------------------------- + + ToolButtonTextBesideIcon = Qt.ToolButtonStyle.ToolButtonTextBesideIcon + ArrowDown = Qt.ArrowType.DownArrow + ArrowRight = Qt.ArrowType.RightArrow + # QSizePolicy Enum-Aliase (Qt6) + SizePolicyPreferred = QSizePolicy.Policy.Preferred + SizePolicyMaximum = QSizePolicy.Policy.Maximum + # --------------------------------------------------------- + # QDockWidget Feature-Aliase (Qt6) + # --------------------------------------------------------- + + DockWidgetMovable = QDockWidget.DockWidgetFeature.DockWidgetMovable + DockWidgetFloatable = QDockWidget.DockWidgetFeature.DockWidgetFloatable + DockWidgetClosable = QDockWidget.DockWidgetFeature.DockWidgetClosable + # --------------------------------------------------------- + # Dock-Area-Aliase (Qt6) + # --------------------------------------------------------- + + DockAreaLeft = Qt.DockWidgetArea.LeftDockWidgetArea + DockAreaRight = Qt.DockWidgetArea.RightDockWidgetArea + @@ -134,12 +164,14 @@ except Exception: QActionGroup as _QActionGroup, QDockWidget as _QDockWidget, QTabWidget as _QTabWidget, - + QToolButton as _QToolButton, + QSizePolicy as _QSizePolicy, ) from PyQt5.QtCore import ( QEventLoop as _QEventLoop, QUrl as _QUrl, QCoreApplication as _QCoreApplication, + Qt as _Qt, ) from PyQt5.QtNetwork import ( QNetworkRequest as _QNetworkRequest, @@ -153,6 +185,7 @@ except Exception: QNetworkRequest = _QNetworkRequest QNetworkReply = _QNetworkReply QCoreApplication = _QCoreApplication + Qt=_Qt QDockWidget = _QDockWidget @@ -168,8 +201,8 @@ except Exception: QToolBar = _QToolBar QActionGroup = _QActionGroup QTabWidget = _QTabWidget - - + QToolButton=_QToolButton + QSizePolicy=_QSizePolicy YES = QMessageBox.Yes NO = QMessageBox.No @@ -177,6 +210,30 @@ except Exception: ICON_QUESTION = QMessageBox.Question QT_VERSION = 5 + # --------------------------------------------------------- + # Qt5 Enum-Aliase (vereinheitlicht) + # --------------------------------------------------------- + + ToolButtonTextBesideIcon = Qt.ToolButtonTextBesideIcon + ArrowDown = Qt.DownArrow + ArrowRight = Qt.RightArrow + # QSizePolicy Enum-Aliase (Qt5) + SizePolicyPreferred = QSizePolicy.Preferred + SizePolicyMaximum = QSizePolicy.Maximum + # --------------------------------------------------------- + # QDockWidget Feature-Aliase (Qt5) + # --------------------------------------------------------- + + DockWidgetMovable = QDockWidget.DockWidgetMovable + DockWidgetFloatable = QDockWidget.DockWidgetFloatable + DockWidgetClosable = QDockWidget.DockWidgetClosable + # --------------------------------------------------------- + # Dock-Area-Aliase (Qt5) + # --------------------------------------------------------- + + DockAreaLeft = Qt.LeftDockWidgetArea + DockAreaRight = Qt.RightDockWidgetArea + def exec_dialog(dialog: Any) -> Any: return dialog.exec_() @@ -257,15 +314,26 @@ except Exception: pass class _MockLayout: - def addWidget(self, *args, **kwargs): - pass + def __init__(self, *args, **kwargs): + self._widgets = [] - def addLayout(self, *args, **kwargs): + def addWidget(self, widget): + self._widgets.append(widget) + + def addLayout(self, layout): pass def addStretch(self, *args, **kwargs): pass + def setSpacing(self, *args, **kwargs): + pass + + def setContentsMargins(self, *args, **kwargs): + pass + + + class _MockLabel: def __init__(self, text: str = ""): self._text = text @@ -296,7 +364,18 @@ except Exception: pass QCoreApplication = _MockQCoreApplication + class _MockQt: + # ToolButtonStyle + ToolButtonTextBesideIcon = 0 + # ArrowType + ArrowDown = 1 + ArrowRight = 2 + + Qt=_MockQt + ToolButtonTextBesideIcon = Qt.ToolButtonTextBesideIcon + ArrowDown = Qt.ArrowDown + ArrowRight = Qt.ArrowRight class _MockQDockWidget(_MockWidget): def __init__(self, *args, **kwargs): @@ -380,6 +459,54 @@ except Exception: QToolBar = _MockToolBar QActionGroup = _MockActionGroup + class _MockToolButton(_MockWidget): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self._checked = False + self.toggled = lambda *a, **k: None + + def setText(self, text: str) -> None: + pass + + def setCheckable(self, value: bool) -> None: + pass + + def setChecked(self, value: bool) -> None: + self._checked = value + + def setToolButtonStyle(self, *args, **kwargs): + pass + + def setArrowType(self, *args, **kwargs): + pass + + def setStyleSheet(self, *args, **kwargs): + pass + + QToolButton=_MockToolButton + + class _MockQSizePolicy: + # horizontale Policies + Fixed = 0 + Minimum = 1 + Maximum = 2 + Preferred = 3 + Expanding = 4 + MinimumExpanding = 5 + Ignored = 6 + + # vertikale Policies (Qt nutzt dieselben Werte) + def __init__(self, horizontal=None, vertical=None): + self.horizontal = horizontal + self.vertical = vertical + QSizePolicy=_MockQSizePolicy + SizePolicyPreferred = QSizePolicy.Preferred + SizePolicyMaximum = QSizePolicy.Maximum + DockWidgetMovable = 1 + DockWidgetFloatable = 2 + DockWidgetClosable = 4 + DockAreaLeft = 1 + DockAreaRight = 2 def exec_dialog(dialog: Any) -> Any: return YES diff --git a/functions/variable_wrapper.py b/functions/variable_wrapper.py index 416e864..d3f8a2d 100644 --- a/functions/variable_wrapper.py +++ b/functions/variable_wrapper.py @@ -1,5 +1,5 @@ """ -variable_wrapper.py – QGIS-Variablen-Abstraktion +sn_basis/functions/variable_wrapper.py – QGIS-Variablen-Abstraktion """ from typing import Any diff --git a/modules/Dateipruefer.py b/modules/Dateipruefer.py index 5564654..cb4e6af 100644 --- a/modules/Dateipruefer.py +++ b/modules/Dateipruefer.py @@ -5,7 +5,7 @@ Verwendet sys_wrapper und gibt pruef_ergebnis an den Pruefmanager zurück. from pathlib import Path -from sn_basis.functions import ( +from sn_basis.functions.sys_wrapper import ( join_path, file_exists, ) diff --git a/pyrightconfig.json b/pyrightconfig.json new file mode 100644 index 0000000..17b70df --- /dev/null +++ b/pyrightconfig.json @@ -0,0 +1,3 @@ +{ + "extraPaths": ["."] +} diff --git a/test/__init__.py b/tests/__init__.py similarity index 100% rename from test/__init__.py rename to tests/__init__.py diff --git a/test/run_tests.py b/tests/run_tests.py similarity index 100% rename from test/run_tests.py rename to tests/run_tests.py diff --git a/test/start_osgeo4w_qgis.bat b/tests/start_osgeo4w_qgis.bat similarity index 100% rename from test/start_osgeo4w_qgis.bat rename to tests/start_osgeo4w_qgis.bat diff --git a/test/test_bootstrap.py b/tests/test_bootstrap.py similarity index 100% rename from test/test_bootstrap.py rename to tests/test_bootstrap.py diff --git a/test/test_dateipruefer.py b/tests/test_dateipruefer.py similarity index 100% rename from test/test_dateipruefer.py rename to tests/test_dateipruefer.py diff --git a/test/test_layerpruefer.py b/tests/test_layerpruefer.py similarity index 100% rename from test/test_layerpruefer.py rename to tests/test_layerpruefer.py diff --git a/test/test_linkpruefer.py b/tests/test_linkpruefer.py similarity index 100% rename from test/test_linkpruefer.py rename to tests/test_linkpruefer.py diff --git a/test/test_pruefmanager.py b/tests/test_pruefmanager.py similarity index 100% rename from test/test_pruefmanager.py rename to tests/test_pruefmanager.py diff --git a/test/test_qgis.bat b/tests/test_qgis.bat similarity index 100% rename from test/test_qgis.bat rename to tests/test_qgis.bat diff --git a/test/test_settings_logic.py b/tests/test_settings_logic.py similarity index 100% rename from test/test_settings_logic.py rename to tests/test_settings_logic.py diff --git a/test/test_stilpruefer.py b/tests/test_stilpruefer.py similarity index 100% rename from test/test_stilpruefer.py rename to tests/test_stilpruefer.py diff --git a/ui/base_dockwidget.py b/ui/base_dockwidget.py index e0ce1f6..ededcc9 100644 --- a/ui/base_dockwidget.py +++ b/ui/base_dockwidget.py @@ -6,6 +6,17 @@ Basis-Dockwidget für alle LNO-Module. from sn_basis.functions.qt_wrapper import QDockWidget, QTabWidget from sn_basis.functions.message_wrapper import warning, error +from sn_basis.functions.qt_wrapper import ( + QDockWidget, + QTabWidget, + Qt, + DockWidgetMovable, + DockWidgetFloatable, + DockWidgetClosable, + DockAreaLeft, + DockAreaRight, +) + class BaseDockWidget(QDockWidget): @@ -23,6 +34,19 @@ class BaseDockWidget(QDockWidget): def __init__(self, parent=None, subtitle=""): super().__init__(parent) + # ----------------------------------------------------- + # Dock-Konfiguration (WICHTIG) + # ----------------------------------------------------- + self.setFeatures( + DockWidgetMovable + | DockWidgetFloatable + | DockWidgetClosable + ) + + self.setAllowedAreas( + DockAreaLeft + | DockAreaRight + ) # ----------------------------------------------------- # Titel setzen diff --git a/ui/dockmanager.py b/ui/dockmanager.py index e8f0393..bcd92fb 100644 --- a/ui/dockmanager.py +++ b/ui/dockmanager.py @@ -5,7 +5,7 @@ Verwaltet das Anzeigen und Ersetzen von DockWidgets. Stellt sicher, dass immer nur ein sn_basis-Dock gleichzeitig sichtbar ist. """ -from typing import Any +from typing import Any, Optional from sn_basis.functions import ( add_dock_widget, @@ -14,6 +14,9 @@ from sn_basis.functions import ( warning, error, ) +from sn_basis.functions.qt_wrapper import ( + DockAreaRight, +) class DockManager: @@ -24,22 +27,34 @@ class DockManager: dock_prefix = "sn_dock_" @classmethod - def show(cls, dock_widget: Any, area=None) -> None: + def show(cls, dock_widget: Any, area: Optional[Any] = None) -> None: """ Zeigt ein DockWidget an und entfernt vorher alle anderen sn_basis-Docks (erkennbar am Prefix 'sn_dock_'). """ + # ----------------------------------------------------- + # Default-Dock-Area (wrapper-konform) + # ----------------------------------------------------- + if area is None: + area = DockAreaRight + if dock_widget is None: error("Dock konnte nicht angezeigt werden", "Dock-Widget ist None.") return try: + # ------------------------------------------------- # Sicherstellen, dass das Dock einen Namen hat + # ------------------------------------------------- if not dock_widget.objectName(): - dock_widget.setObjectName(f"{cls.dock_prefix}{id(dock_widget)}") + dock_widget.setObjectName( + f"{cls.dock_prefix}{id(dock_widget)}" + ) + # ------------------------------------------------- # Vorhandene Plugin-Docks entfernen + # ------------------------------------------------- try: for widget in find_dock_widgets(): if ( @@ -54,7 +69,9 @@ class DockManager: str(e), ) + # ------------------------------------------------- # Neues Dock anzeigen + # ------------------------------------------------- try: add_dock_widget(area, dock_widget) dock_widget.show() @@ -66,4 +83,3 @@ class DockManager: except Exception as e: error("DockManager-Fehler", str(e)) - diff --git a/ui/navigation.py b/ui/navigation.py index c621b7c..d1d9a05 100644 --- a/ui/navigation.py +++ b/ui/navigation.py @@ -47,7 +47,8 @@ class Navigation: test_action = QAction("TEST ACTION", main_window) self.menu.addAction(test_action) self.toolbar.addAction(test_action) - + self.plugin_group = QActionGroup(main_window) + self.plugin_group.setExclusive(True) # ----------------------------------------------------- diff --git a/ui/tabs/settings_tab.py b/ui/tabs/settings_tab.py index e0ce1f6..83a1571 100644 --- a/ui/tabs/settings_tab.py +++ b/ui/tabs/settings_tab.py @@ -8,7 +8,7 @@ from sn_basis.functions.qt_wrapper import QDockWidget, QTabWidget from sn_basis.functions.message_wrapper import warning, error -class BaseDockWidget(QDockWidget): +class SettingsTab(QDockWidget): """ Basis-Dockwidget für alle LNO-Module.