4 Commits

9 changed files with 391 additions and 3 deletions

View File

@@ -1,4 +1,4 @@
from .logic.variable_utils import get_variable from .functions.variable_utils import get_variable
def classFactory(iface): def classFactory(iface):
from .main import BasisPlugin from .main import BasisPlugin

44
functions/messages.py Normal file
View File

@@ -0,0 +1,44 @@
# sn_basis/functions/messages.py
from typing import Optional
from qgis.core import Qgis
from qgis.PyQt.QtWidgets import QWidget
from qgis.utils import iface
def push_message(
level: Qgis.MessageLevel,
title: str,
text: str,
duration: Optional[int] = 5,
parent: Optional[QWidget] = None,
):
"""
Zeigt eine Meldung in der QGIS-MessageBar.
- level: Qgis.Success | Qgis.Info | Qgis.Warning | Qgis.Critical
- title: Überschrift links (kurz halten)
- text: eigentliche Nachricht
- duration: Sekunden bis Auto-Ausblendung; None => bleibt sichtbar (mit Close-Button)
- parent: optionales Eltern-Widget (für Kontext), normalerweise nicht nötig
Rückgabe: MessageBarItem-Widget (kann später geschlossen/entfernt werden).
"""
bar = iface.messageBar()
# QGIS akzeptiert None als "sticky" Meldung
return bar.pushMessage(title, text, level=level, duration=duration)
def success(title: str, text: str, duration: int = 5):
return push_message(Qgis.Success, title, text, duration)
def info(title: str, text: str, duration: int = 5):
return push_message(Qgis.Info, title, text, duration)
def warning(title: str, text: str, duration: int = 5):
return push_message(Qgis.Warning, title, text, duration)
def error(title: str, text: str, duration: Optional[int] = 5):
# Fehler evtl. länger sichtbar lassen; setze duration=None falls gewünscht
return push_message(Qgis.Critical, title, text, duration)

28
functions/styles.py Normal file
View File

@@ -0,0 +1,28 @@
# sn_basis/functions/styles.py
import os
from qgis.core import QgsVectorLayer
def apply_style(layer: QgsVectorLayer, style_name: str) -> bool:
"""
Lädt einen QML-Style aus dem styles-Ordner des Plugins und wendet ihn auf den Layer an.
style_name: Dateiname ohne Pfad, z.B. 'verfahrensgebiet.qml'
Rückgabe: True bei Erfolg, False sonst
"""
if not layer or not layer.isValid():
return False
# Basis-Pfad: sn_basis/styles
base_dir = os.path.dirname(os.path.dirname(__file__)) # geht von functions/ eins hoch
style_path = os.path.join(base_dir, "styles", style_name)
if not os.path.exists(style_path):
print(f"Style-Datei nicht gefunden: {style_path}")
return False
ok, error_msg = layer.loadNamedStyle(style_path)
if not ok:
print(f"Style konnte nicht geladen werden: {error_msg}")
return False
layer.triggerRepaint()
return True

View File

@@ -2,7 +2,7 @@
name=LNO Sachsen | Basisfunktionen name=LNO Sachsen | Basisfunktionen
qgisMinimumVersion=3.0 qgisMinimumVersion=3.0
description=Plugin mit Basisfunktionen description=Plugin mit Basisfunktionen
version=25.11.3 version=25.11.4
author=Michael Otto author=Michael Otto
email=michael.otto@landkreis-mittelsachsen.de email=michael.otto@landkreis-mittelsachsen.de
about=Plugin mit Basisfunktionen about=Plugin mit Basisfunktionen

316
styles/verfahrensgebiet.qml Normal file
View File

@@ -0,0 +1,316 @@
<!DOCTYPE qgis PUBLIC 'http://mrcc.com/qgis.dtd' 'SYSTEM'>
<qgis maxScale="0" simplifyDrawingHints="1" simplifyDrawingTol="1" styleCategories="AllStyleCategories" version="3.10.8-A Coruña" simplifyMaxScale="1" simplifyLocal="1" readOnly="0" hasScaleBasedVisibilityFlag="0" minScale="1e+08" simplifyAlgorithm="0" labelsEnabled="1">
<flags>
<Identifiable>1</Identifiable>
<Removable>1</Removable>
<Searchable>1</Searchable>
</flags>
<renderer-v2 type="singleSymbol" forceraster="0" symbollevels="0" enableorderby="0">
<symbols>
<symbol alpha="1" type="fill" clip_to_extent="1" name="0" force_rhr="0">
<layer class="SimpleFill" locked="0" pass="0" enabled="1">
<prop k="border_width_map_unit_scale" v="3x:0,0,0,0,0,0"/>
<prop k="color" v="255,255,153,173"/>
<prop k="joinstyle" v="miter"/>
<prop k="offset" v="0,0"/>
<prop k="offset_map_unit_scale" v="3x:0,0,0,0,0,0"/>
<prop k="offset_unit" v="MM"/>
<prop k="outline_color" v="161,2,213,255"/>
<prop k="outline_style" v="solid"/>
<prop k="outline_width" v="1"/>
<prop k="outline_width_unit" v="MM"/>
<prop k="style" v="solid"/>
<data_defined_properties>
<Option type="Map">
<Option type="QString" value="" name="name"/>
<Option name="properties"/>
<Option type="QString" value="collection" name="type"/>
</Option>
</data_defined_properties>
</layer>
</symbol>
</symbols>
<rotation/>
<sizescale/>
</renderer-v2>
<labeling type="simple">
<settings calloutType="simple">
<text-style fontFamily="MS Shell Dlg 2" fontSize="8.25" previewBkgrdColor="255,255,255,255" textOrientation="horizontal" fieldName="Name" textColor="0,0,0,255" fontItalic="0" fontUnderline="0" fontSizeUnit="Point" fontCapitals="0" isExpression="0" fontStrikeout="0" fontWeight="50" fontLetterSpacing="0" fontSizeMapUnitScale="3x:0,0,0,0,0,0" fontWordSpacing="0" textOpacity="1" useSubstitutions="0" fontKerning="1" blendMode="0" namedStyle="Standard" multilineHeight="1">
<text-buffer bufferSizeMapUnitScale="3x:0,0,0,0,0,0" bufferJoinStyle="128" bufferSizeUnits="MM" bufferSize="1" bufferDraw="0" bufferColor="255,255,255,255" bufferNoFill="0" bufferBlendMode="0" bufferOpacity="1"/>
<background shapeRadiiMapUnitScale="3x:0,0,0,0,0,0" shapeRotation="0" shapeSizeType="0" shapeOffsetX="0" shapeBlendMode="0" shapeFillColor="255,255,255,255" shapeBorderColor="128,128,128,255" shapeRadiiX="0" shapeRadiiUnit="MM" shapeDraw="0" shapeJoinStyle="64" shapeOffsetUnit="MM" shapeBorderWidthUnit="MM" shapeSizeX="0" shapeSizeUnit="MM" shapeSizeY="0" shapeRadiiY="0" shapeOpacity="1" shapeOffsetY="0" shapeSVGFile="" shapeType="0" shapeBorderWidth="0" shapeRotationType="0" shapeOffsetMapUnitScale="3x:0,0,0,0,0,0" shapeBorderWidthMapUnitScale="3x:0,0,0,0,0,0" shapeSizeMapUnitScale="3x:0,0,0,0,0,0">
<symbol alpha="1" type="marker" clip_to_extent="1" name="markerSymbol" force_rhr="0">
<layer class="SimpleMarker" locked="0" pass="0" enabled="1">
<prop k="angle" v="0"/>
<prop k="color" v="213,180,60,255"/>
<prop k="horizontal_anchor_point" v="1"/>
<prop k="joinstyle" v="bevel"/>
<prop k="name" v="circle"/>
<prop k="offset" v="0,0"/>
<prop k="offset_map_unit_scale" v="3x:0,0,0,0,0,0"/>
<prop k="offset_unit" v="MM"/>
<prop k="outline_color" v="35,35,35,255"/>
<prop k="outline_style" v="solid"/>
<prop k="outline_width" v="0"/>
<prop k="outline_width_map_unit_scale" v="3x:0,0,0,0,0,0"/>
<prop k="outline_width_unit" v="MM"/>
<prop k="scale_method" v="diameter"/>
<prop k="size" v="2"/>
<prop k="size_map_unit_scale" v="3x:0,0,0,0,0,0"/>
<prop k="size_unit" v="MM"/>
<prop k="vertical_anchor_point" v="1"/>
<data_defined_properties>
<Option type="Map">
<Option type="QString" value="" name="name"/>
<Option name="properties"/>
<Option type="QString" value="collection" name="type"/>
</Option>
</data_defined_properties>
</layer>
</symbol>
</background>
<shadow shadowUnder="0" shadowOffsetUnit="MM" shadowScale="100" shadowColor="0,0,0,255" shadowBlendMode="6" shadowOffsetAngle="135" shadowOffsetDist="1" shadowRadiusUnit="MM" shadowOffsetMapUnitScale="3x:0,0,0,0,0,0" shadowRadiusMapUnitScale="3x:0,0,0,0,0,0" shadowOpacity="0.7" shadowDraw="0" shadowRadiusAlphaOnly="0" shadowOffsetGlobal="1" shadowRadius="1.5"/>
<dd_properties>
<Option type="Map">
<Option type="QString" value="" name="name"/>
<Option name="properties"/>
<Option type="QString" value="collection" name="type"/>
</Option>
</dd_properties>
<substitutions/>
</text-style>
<text-format autoWrapLength="0" placeDirectionSymbol="0" leftDirectionSymbol="&lt;" rightDirectionSymbol=">" decimals="3" wrapChar="" useMaxLineLengthForAutoWrap="1" plussign="0" formatNumbers="0" addDirectionSymbol="0" reverseDirectionSymbol="0" multilineAlign="4294967295"/>
<placement xOffset="0" distMapUnitScale="3x:0,0,0,0,0,0" dist="0" repeatDistanceUnits="MM" predefinedPositionOrder="TR,TL,BR,BL,R,L,TSR,BSR" centroidWhole="0" rotationAngle="0" overrunDistanceUnit="MM" placement="1" repeatDistance="0" geometryGeneratorEnabled="0" layerType="PolygonGeometry" offsetUnits="MapUnit" centroidInside="0" offsetType="0" yOffset="0" labelOffsetMapUnitScale="3x:0,0,0,0,0,0" overrunDistance="0" geometryGenerator="" geometryGeneratorType="PointGeometry" placementFlags="10" preserveRotation="1" distUnits="MM" fitInPolygonOnly="0" maxCurvedCharAngleOut="-25" repeatDistanceMapUnitScale="3x:0,0,0,0,0,0" quadOffset="4" maxCurvedCharAngleIn="25" priority="5" overrunDistanceMapUnitScale="3x:0,0,0,0,0,0"/>
<rendering fontLimitPixelSize="0" upsidedownLabels="0" zIndex="0" drawLabels="1" fontMinPixelSize="3" displayAll="0" scaleMax="10000000" labelPerPart="0" fontMaxPixelSize="10000" mergeLines="0" obstacle="1" minFeatureSize="0" obstacleType="0" obstacleFactor="1" scaleMin="1" limitNumLabels="0" scaleVisibility="0" maxNumLabels="2000"/>
<dd_properties>
<Option type="Map">
<Option type="QString" value="" name="name"/>
<Option name="properties"/>
<Option type="QString" value="collection" name="type"/>
</Option>
</dd_properties>
<callout type="simple">
<Option type="Map">
<Option type="QString" value="pole_of_inaccessibility" name="anchorPoint"/>
<Option type="Map" name="ddProperties">
<Option type="QString" value="" name="name"/>
<Option name="properties"/>
<Option type="QString" value="collection" name="type"/>
</Option>
<Option type="bool" value="false" name="drawToAllParts"/>
<Option type="QString" value="0" name="enabled"/>
<Option type="QString" value="&lt;symbol alpha=&quot;1&quot; type=&quot;line&quot; clip_to_extent=&quot;1&quot; name=&quot;symbol&quot; force_rhr=&quot;0&quot;>&lt;layer class=&quot;SimpleLine&quot; locked=&quot;0&quot; pass=&quot;0&quot; enabled=&quot;1&quot;>&lt;prop k=&quot;capstyle&quot; v=&quot;square&quot;/>&lt;prop k=&quot;customdash&quot; v=&quot;5;2&quot;/>&lt;prop k=&quot;customdash_map_unit_scale&quot; v=&quot;3x:0,0,0,0,0,0&quot;/>&lt;prop k=&quot;customdash_unit&quot; v=&quot;MM&quot;/>&lt;prop k=&quot;draw_inside_polygon&quot; v=&quot;0&quot;/>&lt;prop k=&quot;joinstyle&quot; v=&quot;bevel&quot;/>&lt;prop k=&quot;line_color&quot; v=&quot;60,60,60,255&quot;/>&lt;prop k=&quot;line_style&quot; v=&quot;solid&quot;/>&lt;prop k=&quot;line_width&quot; v=&quot;0.3&quot;/>&lt;prop k=&quot;line_width_unit&quot; v=&quot;MM&quot;/>&lt;prop k=&quot;offset&quot; v=&quot;0&quot;/>&lt;prop k=&quot;offset_map_unit_scale&quot; v=&quot;3x:0,0,0,0,0,0&quot;/>&lt;prop k=&quot;offset_unit&quot; v=&quot;MM&quot;/>&lt;prop k=&quot;ring_filter&quot; v=&quot;0&quot;/>&lt;prop k=&quot;use_custom_dash&quot; v=&quot;0&quot;/>&lt;prop k=&quot;width_map_unit_scale&quot; v=&quot;3x:0,0,0,0,0,0&quot;/>&lt;data_defined_properties>&lt;Option type=&quot;Map&quot;>&lt;Option type=&quot;QString&quot; value=&quot;&quot; name=&quot;name&quot;/>&lt;Option name=&quot;properties&quot;/>&lt;Option type=&quot;QString&quot; value=&quot;collection&quot; name=&quot;type&quot;/>&lt;/Option>&lt;/data_defined_properties>&lt;/layer>&lt;/symbol>" name="lineSymbol"/>
<Option type="double" value="0" name="minLength"/>
<Option type="QString" value="3x:0,0,0,0,0,0" name="minLengthMapUnitScale"/>
<Option type="QString" value="MM" name="minLengthUnit"/>
<Option type="double" value="0" name="offsetFromAnchor"/>
<Option type="QString" value="3x:0,0,0,0,0,0" name="offsetFromAnchorMapUnitScale"/>
<Option type="QString" value="MM" name="offsetFromAnchorUnit"/>
<Option type="double" value="0" name="offsetFromLabel"/>
<Option type="QString" value="3x:0,0,0,0,0,0" name="offsetFromLabelMapUnitScale"/>
<Option type="QString" value="MM" name="offsetFromLabelUnit"/>
</Option>
</callout>
</settings>
</labeling>
<customproperties>
<property value="0" key="embeddedWidgets/count"/>
<property key="variableNames"/>
<property key="variableValues"/>
</customproperties>
<blendMode>0</blendMode>
<featureBlendMode>0</featureBlendMode>
<layerOpacity>1</layerOpacity>
<SingleCategoryDiagramRenderer attributeLegend="1" diagramType="Histogram">
<DiagramCategory minimumSize="0" enabled="0" scaleBasedVisibility="0" labelPlacementMethod="XHeight" rotationOffset="270" backgroundColor="#ffffff" width="15" backgroundAlpha="255" sizeType="MM" penWidth="0" penColor="#000000" lineSizeScale="3x:0,0,0,0,0,0" maxScaleDenominator="1e+08" sizeScale="3x:0,0,0,0,0,0" scaleDependency="Area" barWidth="5" lineSizeType="MM" minScaleDenominator="0" height="15" opacity="1" diagramOrientation="Up" penAlpha="255">
<fontProperties description="MS Shell Dlg 2,8.25,-1,5,50,0,0,0,0,0" style=""/>
</DiagramCategory>
</SingleCategoryDiagramRenderer>
<DiagramLayerSettings placement="1" showAll="1" priority="0" zIndex="0" obstacle="0" linePlacementFlags="18" dist="0">
<properties>
<Option type="Map">
<Option type="QString" value="" name="name"/>
<Option name="properties"/>
<Option type="QString" value="collection" name="type"/>
</Option>
</properties>
</DiagramLayerSettings>
<geometryOptions removeDuplicateNodes="0" geometryPrecision="0">
<activeChecks/>
<checkConfiguration type="Map">
<Option type="Map" name="QgsGeometryGapCheck">
<Option type="double" value="0" name="allowedGapsBuffer"/>
<Option type="bool" value="false" name="allowedGapsEnabled"/>
<Option type="QString" value="" name="allowedGapsLayer"/>
</Option>
</checkConfiguration>
</geometryOptions>
<fieldConfiguration>
<field name="id">
<editWidget type="TextEdit">
<config>
<Option/>
</config>
</editWidget>
</field>
<field name="Name">
<editWidget type="TextEdit">
<config>
<Option/>
</config>
</editWidget>
</field>
<field name="Nummer">
<editWidget type="Range">
<config>
<Option/>
</config>
</editWidget>
</field>
<field name="Referat">
<editWidget type="TextEdit">
<config>
<Option/>
</config>
</editWidget>
</field>
<field name="Ansprechpartner">
<editWidget type="TextEdit">
<config>
<Option/>
</config>
</editWidget>
</field>
<field name="Telefon">
<editWidget type="TextEdit">
<config>
<Option/>
</config>
</editWidget>
</field>
<field name="E-Mail">
<editWidget type="TextEdit">
<config>
<Option/>
</config>
</editWidget>
</field>
<field name="Letzte Änderung">
<editWidget type="DateTime">
<config>
<Option/>
</config>
</editWidget>
</field>
</fieldConfiguration>
<aliases>
<alias index="0" name="" field="id"/>
<alias index="1" name="" field="Name"/>
<alias index="2" name="" field="Nummer"/>
<alias index="3" name="" field="Referat"/>
<alias index="4" name="" field="Ansprechpartner"/>
<alias index="5" name="" field="Telefon"/>
<alias index="6" name="" field="E-Mail"/>
<alias index="7" name="" field="Letzte Änderung"/>
</aliases>
<excludeAttributesWMS/>
<excludeAttributesWFS/>
<defaults>
<default expression="" applyOnUpdate="0" field="id"/>
<default expression="" applyOnUpdate="0" field="Name"/>
<default expression="" applyOnUpdate="0" field="Nummer"/>
<default expression="" applyOnUpdate="0" field="Referat"/>
<default expression="" applyOnUpdate="0" field="Ansprechpartner"/>
<default expression="" applyOnUpdate="0" field="Telefon"/>
<default expression="" applyOnUpdate="0" field="E-Mail"/>
<default expression="" applyOnUpdate="0" field="Letzte Änderung"/>
</defaults>
<constraints>
<constraint exp_strength="0" notnull_strength="1" unique_strength="1" field="id" constraints="3"/>
<constraint exp_strength="0" notnull_strength="0" unique_strength="0" field="Name" constraints="0"/>
<constraint exp_strength="0" notnull_strength="0" unique_strength="0" field="Nummer" constraints="0"/>
<constraint exp_strength="0" notnull_strength="0" unique_strength="0" field="Referat" constraints="0"/>
<constraint exp_strength="0" notnull_strength="0" unique_strength="0" field="Ansprechpartner" constraints="0"/>
<constraint exp_strength="0" notnull_strength="0" unique_strength="0" field="Telefon" constraints="0"/>
<constraint exp_strength="0" notnull_strength="0" unique_strength="0" field="E-Mail" constraints="0"/>
<constraint exp_strength="0" notnull_strength="0" unique_strength="0" field="Letzte Änderung" constraints="0"/>
</constraints>
<constraintExpressions>
<constraint desc="" exp="" field="id"/>
<constraint desc="" exp="" field="Name"/>
<constraint desc="" exp="" field="Nummer"/>
<constraint desc="" exp="" field="Referat"/>
<constraint desc="" exp="" field="Ansprechpartner"/>
<constraint desc="" exp="" field="Telefon"/>
<constraint desc="" exp="" field="E-Mail"/>
<constraint desc="" exp="" field="Letzte Änderung"/>
</constraintExpressions>
<expressionfields/>
<attributeactions>
<defaultAction value="{00000000-0000-0000-0000-000000000000}" key="Canvas"/>
</attributeactions>
<attributetableconfig sortOrder="0" actionWidgetStyle="dropDown" sortExpression="">
<columns>
<column type="actions" hidden="1" width="-1"/>
<column type="field" hidden="0" width="-1" name="Nummer"/>
<column type="field" hidden="0" width="-1" name="Name"/>
<column type="field" hidden="0" width="-1" name="E-Mail"/>
<column type="field" hidden="0" width="-1" name="Letzte Änderung"/>
<column type="field" hidden="0" width="-1" name="id"/>
<column type="field" hidden="0" width="-1" name="Referat"/>
<column type="field" hidden="0" width="-1" name="Ansprechpartner"/>
<column type="field" hidden="0" width="-1" name="Telefon"/>
</columns>
</attributetableconfig>
<conditionalstyles>
<rowstyles/>
<fieldstyles/>
</conditionalstyles>
<storedexpressions/>
<editform tolerant="1">.</editform>
<editforminit/>
<editforminitcodesource>0</editforminitcodesource>
<editforminitfilepath>.</editforminitfilepath>
<editforminitcode><![CDATA[# -*- coding: utf-8 -*-
"""
QGIS forms can have a Python function that is called when the form is
opened.
Use this function to add extra logic to your forms.
Enter the name of the function in the "Python Init function"
field.
An example follows:
"""
from qgis.PyQt.QtWidgets import QWidget
def my_form_open(dialog, layer, feature):
geom = feature.geometry()
control = dialog.findChild(QWidget, "MyLineEdit")
]]></editforminitcode>
<featformsuppress>0</featformsuppress>
<editorlayout>generatedlayout</editorlayout>
<editable>
<field name="Ansprechpartner" editable="1"/>
<field name="E-Mail" editable="1"/>
<field name="Letzte Änderung" editable="1"/>
<field name="Name" editable="1"/>
<field name="Nummer" editable="1"/>
<field name="Referat" editable="1"/>
<field name="Telefon" editable="1"/>
<field name="id" editable="1"/>
</editable>
<labelOnTop>
<field labelOnTop="0" name="Ansprechpartner"/>
<field labelOnTop="0" name="E-Mail"/>
<field labelOnTop="0" name="Letzte Änderung"/>
<field labelOnTop="0" name="Name"/>
<field labelOnTop="0" name="Nummer"/>
<field labelOnTop="0" name="Referat"/>
<field labelOnTop="0" name="Telefon"/>
<field labelOnTop="0" name="id"/>
</labelOnTop>
<widgets/>
<previewExpression>COALESCE( "name", '&lt;NULL>' )</previewExpression>
<mapTip></mapTip>
<layerGeometryType>2</layerGeometryType>
</qgis>

View File

@@ -2,7 +2,7 @@ from qgis.PyQt.QtWidgets import (
QWidget, QGridLayout, QLabel, QLineEdit, QWidget, QGridLayout, QLabel, QLineEdit,
QGroupBox, QVBoxLayout, QPushButton QGroupBox, QVBoxLayout, QPushButton
) )
from sn_basis.logic.settings_logic import SettingsLogic from sn_basis.functions.settings_logic import SettingsLogic
class SettingsTab(QWidget): class SettingsTab(QWidget):