From 15e48f58af81f753917c4ba82b80365d15092d69 Mon Sep 17 00:00:00 2001 From: daniel Date: Fri, 19 Jun 2026 11:47:36 +0200 Subject: [PATCH 1/4] VLN-API integriert --- functions/dialog_wrapper.py | 2 +- functions/ly_style_wrapper.py | 19 ++++++++ functions/qgiscore_wrapper.py | 89 +++++++++++++++++++++++++++++++++++ functions/qt_wrapper.py | 34 ++++++++++++- 4 files changed, 141 insertions(+), 3 deletions(-) diff --git a/functions/dialog_wrapper.py b/functions/dialog_wrapper.py index 4bd1996..57bd248 100644 --- a/functions/dialog_wrapper.py +++ b/functions/dialog_wrapper.py @@ -200,7 +200,7 @@ def ask_detailpruefung_oder_vg_laden( Eltern-Widget oder None. title : str Dialog-Titel. - message : str + message : str Hauptmeldung mit Flächen-Informationen. Returns diff --git a/functions/ly_style_wrapper.py b/functions/ly_style_wrapper.py index ad0221a..a3b9a6c 100644 --- a/functions/ly_style_wrapper.py +++ b/functions/ly_style_wrapper.py @@ -5,6 +5,25 @@ from sn_basis.functions.sys_wrapper import get_plugin_root, join_path from sn_basis.modules.stilpruefer import Stilpruefer from typing import Optional +def apply_style_from_path(layer, style_path: str) -> bool: + """ + Wendet einen Layerstil anhand eines vollständigen Pfades an. + + Im Gegensatz zu :func:`apply_style` wird der Pfad extern bereitgestellt; + es findet keine eigene Stilprüfung statt. + """ + if not layer_exists(layer): + return False + try: + ok, _ = layer.loadNamedStyle(str(style_path)) + if ok: + getattr(layer, "triggerRepaint", lambda: None)() + return True + except Exception: + pass + return False + + def apply_style(layer, style_name: str) -> bool: """ Wendet einen Layerstil an, sofern er gültig ist. diff --git a/functions/qgiscore_wrapper.py b/functions/qgiscore_wrapper.py index 8387381..91cc267 100644 --- a/functions/qgiscore_wrapper.py +++ b/functions/qgiscore_wrapper.py @@ -38,6 +38,12 @@ QgsLayoutPoint: Type[Any] QgsLayoutSize: Type[Any] QgsUnitTypes: Type[Any] QgsLayoutItem: Type[Any] +QgsBlockingNetworkRequest: Type[Any] +QgsJsonExporter: Type[Any] +QgsJsonUtils: Type[Any] +GEOM_POINT: Any = None +GEOM_LINE: Any = None +GEOM_POLYGON: Any = None MAP_GRID_STYLE_MARKERS: Any = None MAP_GRID_STYLE_FRAME_ANNOTATIONS: Any = None @@ -91,6 +97,9 @@ try: QgsLayoutSize as _QgsLayoutSize, QgsUnitTypes as _QgsUnitTypes, QgsLayoutItem as _QgsLayoutItem, + QgsBlockingNetworkRequest as _QgsBlockingNetworkRequest, + QgsJsonExporter as _QgsJsonExporter, + QgsJsonUtils as _QgsJsonUtils, ) QgsProject = _QgsProject @@ -118,6 +127,32 @@ try: QgsLayoutSize = _QgsLayoutSize QgsUnitTypes = _QgsUnitTypes QgsLayoutItem = _QgsLayoutItem + QgsBlockingNetworkRequest = _QgsBlockingNetworkRequest + QgsJsonExporter = _QgsJsonExporter + QgsJsonUtils = _QgsJsonUtils + + # Geometrietyp-Konstanten (QGIS 4 / QGIS 3.30+ vs. ältere QGIS-3) + def _resolve_geom_type(*paths): + for obj, *attrs in paths: + val = obj + for attr in attrs: + val = getattr(val, attr, None) + if val is None: + break + else: + if val is not None: + return val + return None + + GEOM_POINT = _resolve_geom_type( + (_Qgis, "GeometryType", "Point"), + ) or getattr(__import__("qgis.core", fromlist=["QgsWkbTypes"]), "QgsWkbTypes", type("_", (), {"PointGeometry": 0})).PointGeometry + GEOM_LINE = _resolve_geom_type( + (_Qgis, "GeometryType", "Line"), + ) or getattr(__import__("qgis.core", fromlist=["QgsWkbTypes"]), "QgsWkbTypes", type("_", (), {"LineGeometry": 1})).LineGeometry + GEOM_POLYGON = _resolve_geom_type( + (_Qgis, "GeometryType", "Polygon"), + ) or getattr(__import__("qgis.core", fromlist=["QgsWkbTypes"]), "QgsWkbTypes", type("_", (), {"PolygonGeometry": 2})).PolygonGeometry def _resolve_qgis_enum(*paths: tuple[Any, ...]) -> Any: for path in paths: @@ -777,6 +812,60 @@ except Exception: QgsVectorFileWriter = _MockQgsVectorFileWriter + # Geometrietyp-Konstanten (Mock-Werte entsprechen QgsWkbTypes) + GEOM_POINT = 0 + GEOM_LINE = 1 + GEOM_POLYGON = 2 + + class _MockQgsBlockingNetworkRequest: + NoError = 0 + + def __init__(self): + self._reply = None + + def get(self, request: Any) -> int: + return self.NoError + + def post(self, request: Any, data: bytes) -> int: + return self.NoError + + def put(self, request: Any, data: bytes) -> int: + return self.NoError + + def reply(self) -> Any: + return self._reply + + def errorMessage(self) -> str: + return "" + + QgsBlockingNetworkRequest = _MockQgsBlockingNetworkRequest + + class _MockQgsJsonUtils: + @staticmethod + def stringToFields(text: str) -> Any: + return type("_Fields", (), {"toList": lambda self: []})() + + @staticmethod + def stringToFeatureList(text: str, fields: Any) -> list: + return [] + + QgsJsonUtils = _MockQgsJsonUtils + + class _MockQgsJsonExporter: + def __init__(self, layer: Any = None): + self._layer = layer + + def setSourceCrs(self, crs: Any) -> None: + pass + + def setTransformGeometries(self, transform: bool) -> None: + pass + + def exportFeatures(self, features: list) -> str: + return '{"type":"FeatureCollection","features":[]}' + + QgsJsonExporter = _MockQgsJsonExporter + # --------------------------------------------------------- # Netzwerk # --------------------------------------------------------- diff --git a/functions/qt_wrapper.py b/functions/qt_wrapper.py index 7dcb007..250aa2c 100644 --- a/functions/qt_wrapper.py +++ b/functions/qt_wrapper.py @@ -45,6 +45,7 @@ QComboBox: Type[Any] = object QCheckBox: Type[Any] = object QHBoxLayout: Type[Any] = object QFont: Type[Any] = object +QSettings: Type[Any] = object def exec_dialog(dialog: Any) -> Any: @@ -99,7 +100,8 @@ try: QUrl as _QUrl, QCoreApplication as _QCoreApplication, Qt as _Qt, - QVariant as _QVariant + QVariant as _QVariant, + QSettings as _QSettings, ) from qgis.PyQt.QtNetwork import ( QNetworkRequest as _QNetworkRequest, @@ -140,6 +142,7 @@ try: QVariant = _QVariant QHBoxLayout = _QHBoxLayout QFont = _QFont + QSettings = _QSettings # ✅ QT6 ENUMS YES = QMessageBox.StandardButton.Yes NO = QMessageBox.StandardButton.No @@ -199,7 +202,8 @@ except (ImportError, AttributeError): QUrl as _QUrl, QCoreApplication as _QCoreApplication, Qt as _Qt, - QVariant as _QVariant + QVariant as _QVariant, + QSettings as _QSettings, ) from PyQt5.QtNetwork import ( QNetworkRequest as _QNetworkRequest, @@ -238,6 +242,7 @@ except (ImportError, AttributeError): QVariant = _QVariant QHBoxLayout= _QHBoxLayout QFont = _QFont + QSettings = _QSettings # ✅ PYQT5 ENUMS YES = QMessageBox.Yes @@ -560,6 +565,31 @@ except (ImportError, AttributeError): pass QHBoxLayout = _MockQHBoxLayout + class _MockQSettings: + def __init__(self, *args, **kwargs): + self._data: dict = {} + self._group = "" + + def beginGroup(self, group: str) -> None: + self._group = group + + def endGroup(self) -> None: + self._group = "" + + def setValue(self, key: str, value: Any) -> None: + full = "%s/%s" % (self._group, key) if self._group else key + self._data[full] = value + + def value(self, key: str, default: Any = "") -> Any: + full = "%s/%s" % (self._group, key) if self._group else key + return self._data.get(full, default) + + def remove(self, key: str) -> None: + full = "%s/%s" % (self._group, key) if self._group else key + self._data.pop(full, None) + + QSettings = _MockQSettings + class _MockQCheckBox: def __init__(self, text: str = "", *args, **kwargs): self._text = text -- 2.54.0 From 970343cd98a9d16d409eb414e289f71b13ffda16 Mon Sep 17 00:00:00 2001 From: Daniel Helbig Date: Fri, 19 Jun 2026 11:52:15 +0200 Subject: [PATCH 2/4] changelog.txt aktualisiert --- changelog.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/changelog.txt b/changelog.txt index f3c3d0d..3f4088e 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,3 +1,4 @@ +- VLN-API zum Laden der Plan41-Maßnahmen integriert --- Version 26.5.2-testing: --- -- 2.54.0 From 319d425670accc7887f8378e4dc865b967dabdaf Mon Sep 17 00:00:00 2001 From: release-bot Date: Fri, 19 Jun 2026 09:53:11 +0000 Subject: [PATCH 3/4] Release 26.6.1-unstable --- changelog.txt | 2 ++ metadata.txt | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/changelog.txt b/changelog.txt index 3f4088e..7abd248 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,3 +1,5 @@ +--- +Version 26.6.1-unstable: - VLN-API zum Laden der Plan41-Maßnahmen integriert --- Version 26.5.2-testing: diff --git a/metadata.txt b/metadata.txt index 1a37a40..af70ba5 100644 --- a/metadata.txt +++ b/metadata.txt @@ -1,11 +1,11 @@ [general] -version=26.5.2-testing +version=26.6.1-unstable name=LNO Sachsen | Plugin Basisfunktionen description=Plugin mit Basisfunktionen author=Daniel Helbig, Michael Otto homepage=https://entwicklung.flurneuordnung-sachsen.de/AG_QGIS/Plugin_SN_Basis tracker=https://entwicklung.flurneuordnung-sachsen.de/AG_QGIS/Plugin_SN_Basis/issues -repository=https://entwicklung.flurneuordnung-sachsen.de/AG_QGIS/Plugin_SN_Basis/src/branch/testing/ +repository=https://entwicklung.flurneuordnung-sachsen.de/AG_QGIS/Plugin_SN_Basis/src/branch/unstable/ QGISMaximumVersion=4.99 qgisMinimumVersion=3.40 experimental=true -- 2.54.0 From 9dc15b5b92202b032068e958dbb51a3678f0c6f0 Mon Sep 17 00:00:00 2001 From: Michael Otto Date: Thu, 2 Jul 2026 11:02:04 +0200 Subject: [PATCH 4/4] auf neuen Release-Workflow umgestellt --- metadata.txt => .gitea/templates/metadata.template | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename metadata.txt => .gitea/templates/metadata.template (95%) diff --git a/metadata.txt b/.gitea/templates/metadata.template similarity index 95% rename from metadata.txt rename to .gitea/templates/metadata.template index af70ba5..2546b3e 100644 --- a/metadata.txt +++ b/.gitea/templates/metadata.template @@ -1,5 +1,5 @@ [general] -version=26.6.1-unstable +version= name=LNO Sachsen | Plugin Basisfunktionen description=Plugin mit Basisfunktionen author=Daniel Helbig, Michael Otto -- 2.54.0