From f19fe71bfaf98ae5052530104f48dd99fd7e9243 Mon Sep 17 00:00:00 2001 From: daniel Date: Fri, 20 Mar 2026 14:01:57 +0100 Subject: [PATCH] =?UTF-8?q?Erg=C3=A4nzungen=20in=20de=20Wrappern/=20Pr?= =?UTF-8?q?=C3=BCfmanager=20=20f=C3=BCr=20Layouts?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- functions/dialog_wrapper.py | 32 +++++++- functions/qgiscore_wrapper.py | 136 ++++++++++++++++++++++++++++++++++ functions/qgisui_wrapper.py | 10 +++ functions/qt_wrapper.py | 27 ++++++- modules/Pruefmanager.py | 7 ++ 5 files changed, 210 insertions(+), 2 deletions(-) diff --git a/functions/dialog_wrapper.py b/functions/dialog_wrapper.py index 6a5ddc7..c8f2879 100644 --- a/functions/dialog_wrapper.py +++ b/functions/dialog_wrapper.py @@ -5,7 +5,7 @@ from typing import Any from typing import Literal, Optional from sn_basis.functions.qt_wrapper import ( QMessageBox, YES, NO, CANCEL, QT_VERSION, exec_dialog, ICON_QUESTION, - QProgressDialog, QCoreApplication, Qt, + QProgressDialog, QCoreApplication, Qt, QInputDialog, QLineEdit, ) def ask_yes_no( @@ -53,6 +53,36 @@ def show_info_dialog(title: str, message: str, parent: Any = None) -> None: print(f"⚠️ show_info_dialog Fehler: {e}") +def ask_text( + title: str, + label: str, + default_text: str = "", + parent: Any = None, +) -> tuple[str, bool]: + """Zeigt einen modalen Texteingabe-Dialog und gibt Text + OK-Status zurück.""" + try: + if QT_VERSION == 0: # Mock-Modus + print(f"Mock-Modus: ask_text('{title}') -> '{default_text}'") + return default_text, True + # PyQt6: QLineEdit.EchoMode.Normal / PyQt5: QLineEdit.Normal + echo_mode = ( + getattr(QLineEdit, "Normal", None) + or getattr(getattr(QLineEdit, "EchoMode", None), "Normal", None) + or 0 + ) + text, accepted = QInputDialog.getText( + parent, + title, + label, + echo_mode, + default_text, + ) + return str(text or ""), bool(accepted) + except Exception as e: + print(f"⚠️ ask_text Fehler: {e}") + return default_text, False + + OverwriteDecision = Optional[Literal["overwrite", "append", "cancel"]] diff --git a/functions/qgiscore_wrapper.py b/functions/qgiscore_wrapper.py index de4b063..d769e30 100644 --- a/functions/qgiscore_wrapper.py +++ b/functions/qgiscore_wrapper.py @@ -26,6 +26,13 @@ QgsGeometry: Type[Any] QgsFeatureRequest: Type[Any] QgsCoordinateTransform: Type[Any] QgsCoordinateReferenceSystem: Type[Any] +QgsPrintLayout: Type[Any] +QgsLayoutItemMap: Type[Any] +QgsLayoutItemLabel: Type[Any] +QgsLayoutPoint: Type[Any] +QgsLayoutSize: Type[Any] +QgsUnitTypes: Type[Any] +QgsLayoutItem: Type[Any] QGIS_AVAILABLE = False @@ -48,6 +55,13 @@ try: QgsFeatureRequest as _QgsFeatureRequest, QgsCoordinateTransform as _QgsCoordinateTransform, QgsCoordinateReferenceSystem as _QgsCoordinateReferenceSystem, + QgsPrintLayout as _QgsPrintLayout, + QgsLayoutItemMap as _QgsLayoutItemMap, + QgsLayoutItemLabel as _QgsLayoutItemLabel, + QgsLayoutPoint as _QgsLayoutPoint, + QgsLayoutSize as _QgsLayoutSize, + QgsUnitTypes as _QgsUnitTypes, + QgsLayoutItem as _QgsLayoutItem, ) QgsProject = _QgsProject @@ -63,6 +77,13 @@ try: QgsFeatureRequest = _QgsFeatureRequest QgsCoordinateTransform = _QgsCoordinateTransform QgsCoordinateReferenceSystem = _QgsCoordinateReferenceSystem + QgsPrintLayout = _QgsPrintLayout + QgsLayoutItemMap = _QgsLayoutItemMap + QgsLayoutItemLabel = _QgsLayoutItemLabel + QgsLayoutPoint = _QgsLayoutPoint + QgsLayoutSize = _QgsLayoutSize + QgsUnitTypes = _QgsUnitTypes + QgsLayoutItem = _QgsLayoutItem QGIS_AVAILABLE = True @@ -73,9 +94,17 @@ try: except Exception: QGIS_AVAILABLE = False + class _MockLayoutManager: + def layoutByName(self, name: str): + return None + + def addLayout(self, layout: Any) -> bool: + return True + class _MockQgsProject: def __init__(self): self._variables = {} + self._layout_manager = _MockLayoutManager() @staticmethod def instance() -> "_MockQgsProject": @@ -84,6 +113,9 @@ except Exception: def read(self) -> bool: return True + def layoutManager(self): + return self._layout_manager + QgsProject = _MockQgsProject class _MockQgsVectorLayer: @@ -134,6 +166,110 @@ except Exception: QgsRasterLayer = _MockQgsRasterLayer + class _MockQgsPrintLayout: + def __init__(self, project: Any): + self.project = project + self._name = "" + self._page = _MockQgsLayoutPage() + + def initializeDefaults(self) -> None: + pass + + def setName(self, name: str) -> None: + self._name = name + + def pageCollection(self): + return self + + def page(self, index: int): + return self._page + + def addLayoutItem(self, item: Any) -> None: + pass + + class _MockQgsLayoutPage: + def setPageSize(self, size: Any) -> None: + self.size = size + + class _MockQgsLayoutItem: + class ReferencePoint: + LowerLeft = 0 + + class _MockQgsLayoutItemMap: + def __init__(self, layout: Any): + self.layout = layout + + def setId(self, item_id: str) -> None: + pass + + def setExtent(self, extent: Any) -> None: + pass + + def setScale(self, scale: float) -> None: + pass + + def attemptMove(self, point: Any) -> None: + pass + + def attemptResize(self, size: Any) -> None: + pass + + def setFollowVisibilityPreset(self, active: bool) -> None: + pass + + def setFollowVisibilityPresetName(self, name: str) -> None: + pass + + class _MockQgsLayoutItemLabel: + ModeHtml = 1 + + def __init__(self, layout: Any): + self.layout = layout + + def setId(self, item_id: str) -> None: + pass + + def setText(self, text: str) -> None: + pass + + def setMode(self, mode: Any) -> None: + pass + + def setFont(self, font: Any) -> None: + pass + + def setReferencePoint(self, point: Any) -> None: + pass + + def attemptMove(self, point: Any) -> None: + pass + + def attemptResize(self, size: Any) -> None: + pass + + class _MockQgsLayoutPoint: + def __init__(self, x: float, y: float, unit: Any): + self.x = x + self.y = y + self.unit = unit + + class _MockQgsLayoutSize: + def __init__(self, width: float, height: float, unit: Any): + self.width = width + self.height = height + self.unit = unit + + class _MockQgsUnitTypes: + LayoutMillimeters = 0 + + QgsPrintLayout = _MockQgsPrintLayout + QgsLayoutItemMap = _MockQgsLayoutItemMap + QgsLayoutItemLabel = _MockQgsLayoutItemLabel + QgsLayoutPoint = _MockQgsLayoutPoint + QgsLayoutSize = _MockQgsLayoutSize + QgsUnitTypes = _MockQgsUnitTypes + QgsLayoutItem = _MockQgsLayoutItem + class _MockQgsFeatureRequest: def __init__(self): self._filter_rect = None diff --git a/functions/qgisui_wrapper.py b/functions/qgisui_wrapper.py index 7156afa..5ca92f8 100644 --- a/functions/qgisui_wrapper.py +++ b/functions/qgisui_wrapper.py @@ -76,6 +76,9 @@ except Exception: def removeToolBar(self, *args, **kwargs): pass + def openLayoutDesigner(self, layout): + return layout + iface = _MockIface() class _MockQgsFileWidget: @@ -132,6 +135,13 @@ def get_main_window(): return None +def open_layout_designer(layout: Any) -> Any: + try: + return iface.openLayoutDesigner(layout) + except Exception: + return None + + # --------------------------------------------------------- # Dock-Handling # --------------------------------------------------------- diff --git a/functions/qt_wrapper.py b/functions/qt_wrapper.py index aa2a5d0..7dcb007 100644 --- a/functions/qt_wrapper.py +++ b/functions/qt_wrapper.py @@ -29,6 +29,7 @@ QWidget: Type[Any] = object QGridLayout: Type[Any] = object QLabel: Type[Any] = object QLineEdit: Type[Any] = object +QInputDialog: Type[Any] = object QGroupBox: Type[Any] = object QVBoxLayout: Type[Any] = object QPushButton: Type[Any] = object @@ -43,6 +44,7 @@ Qt: Type[Any] = object QComboBox: Type[Any] = object QCheckBox: Type[Any] = object QHBoxLayout: Type[Any] = object +QFont: Type[Any] = object def exec_dialog(dialog: Any) -> Any: @@ -74,6 +76,7 @@ try: QGridLayout as _QGridLayout, QLabel as _QLabel, QLineEdit as _QLineEdit, + QInputDialog as _QInputDialog, QGroupBox as _QGroupBox, QVBoxLayout as _QVBoxLayout, QPushButton as _QPushButton, @@ -89,6 +92,7 @@ try: QCheckBox as _QCheckBox, QHBoxLayout as _QHBoxLayout, ) + from qgis.PyQt.QtGui import QFont as _QFont from qgis.PyQt.QtCore import ( QEventLoop as _QEventLoop, QTimer as _QTimer, @@ -120,6 +124,7 @@ try: QGridLayout = _QGridLayout QLabel = _QLabel QLineEdit = _QLineEdit + QInputDialog = _QInputDialog QGroupBox = _QGroupBox QVBoxLayout = _QVBoxLayout QPushButton = _QPushButton @@ -134,6 +139,7 @@ try: QCheckBox = _QCheckBox QVariant = _QVariant QHBoxLayout = _QHBoxLayout + QFont = _QFont # ✅ QT6 ENUMS YES = QMessageBox.StandardButton.Yes NO = QMessageBox.StandardButton.No @@ -170,6 +176,7 @@ except (ImportError, AttributeError): QGridLayout as _QGridLayout, QLabel as _QLabel, QLineEdit as _QLineEdit, + QInputDialog as _QInputDialog, QGroupBox as _QGroupBox, QVBoxLayout as _QVBoxLayout, QPushButton as _QPushButton, @@ -185,6 +192,7 @@ except (ImportError, AttributeError): QCheckBox as _QCheckBox, QHBoxLayout as _QHBoxLayout, ) + from PyQt5.QtGui import QFont as _QFont from PyQt5.QtCore import ( QEventLoop as _QEventLoop, QTimer as _QTimer, @@ -214,6 +222,7 @@ except (ImportError, AttributeError): QGridLayout = _QGridLayout QLabel = _QLabel QLineEdit = _QLineEdit + QInputDialog = _QInputDialog QGroupBox = _QGroupBox QVBoxLayout = _QVBoxLayout QPushButton = _QPushButton @@ -228,6 +237,7 @@ except (ImportError, AttributeError): QCheckBox = _QCheckBox QVariant = _QVariant QHBoxLayout= _QHBoxLayout + QFont = _QFont # ✅ PYQT5 ENUMS YES = QMessageBox.Yes @@ -299,6 +309,13 @@ except (ImportError, AttributeError): QFileDialog = _MockQFileDialog + class _MockQInputDialog: + @staticmethod + def getText(parent, title, label, mode=None, text=""): + return text, True + + QInputDialog = _MockQInputDialog + class _MockQEventLoop: def exec(self) -> int: return 0 def quit(self) -> None: pass @@ -346,11 +363,18 @@ except (ImportError, AttributeError): class _MockLabel: def __init__(self, text: str = ""): self._text = text class _MockLineEdit: + Normal = 0 + def __init__(self, *args, **kwargs): self._text = "" def text(self) -> str: return self._text def setText(self, value: str) -> None: self._text = value - class _MockButton: + class _MockFont: + def __init__(self, family: str = "", pointSize: int = 10): + self.family = family + self.pointSize = pointSize + + class _MockButton: def __init__(self, *args, **kwargs): self.clicked = lambda *a, **k: None QWidget = _MockWidget @@ -360,6 +384,7 @@ except (ImportError, AttributeError): QGroupBox = _MockWidget QVBoxLayout = _MockLayout QPushButton = _MockButton + QFont = _MockFont QCoreApplication = object() class _MockQt: diff --git a/modules/Pruefmanager.py b/modules/Pruefmanager.py index c1c124e..1bb131f 100644 --- a/modules/Pruefmanager.py +++ b/modules/Pruefmanager.py @@ -70,6 +70,13 @@ class Pruefmanager: return default return ask_yes_no(titel, meldung, default=default, parent=self.parent) + def frage_text(self, titel: str, meldung: str, default_text: str = "") -> tuple[str, bool]: + """Fragt einen Textwert ab und gibt Text + OK-Status zurück.""" + from sn_basis.functions.dialog_wrapper import ask_text + if self.ui_modus != "qgis": + return default_text, True + return ask_text(titel, meldung, default_text=default_text, parent=self.parent) + # ------------------------------------------------------------------ # VERFAHRENS-DB-spezifische Entscheidungen # ------------------------------------------------------------------