commit a93c9a520fb2ad6fce0e408b85a4cc1318461b35 Author: Patrick Haßel Date: Sat Sep 27 09:53:40 2025 +0200 halfway working (verknüpfte checkboxen) diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..abf9723 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +/.venv/ +/basemap/ +/resources.py \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..f6a74dd --- /dev/null +++ b/Makefile @@ -0,0 +1,244 @@ +#/*************************************************************************** +# Pegelonline +# +# BlaBlaBla +# ------------------- +# begin : 2025-09-26 +# git sha : $Format:%H$ +# copyright : (C) 2025 by Katrin Haßel +# email : s6kathom@uni-trier.de +# ***************************************************************************/ +# +#/*************************************************************************** +# * * +# * This program is free software; you can redistribute it and/or modify * +# * it under the terms of the GNU General Public License as published by * +# * the Free Software Foundation; either version 2 of the License, or * +# * (at your option) any later version. * +# * * +# ***************************************************************************/ + +################################################# +# Edit the following to match your sources lists +################################################# + + +#Add iso code for any locales you want to support here (space separated) +# default is no locales +# LOCALES = af +LOCALES = + +# If locales are enabled, set the name of the lrelease binary on your system. If +# you have trouble compiling the translations, you may have to specify the full path to +# lrelease +#LRELEASE = lrelease +#LRELEASE = lrelease-qt4 + + +# translation +SOURCES = \ + __init__.py \ + pegelonline.py pegelonline_dockwidget.py + +PLUGINNAME = pegelonline + +PY_FILES = \ + __init__.py \ + pegelonline.py pegelonline_dockwidget.py + +UI_FILES = pegelonline_dockwidget_base.ui + +EXTRAS = metadata.txt icon.png + +EXTRA_DIRS = + +COMPILED_RESOURCE_FILES = resources.py + +PEP8EXCLUDE=pydev,resources.py,conf.py,third_party,ui + +# QGISDIR points to the location where your plugin should be installed. +# This varies by platform, relative to your HOME directory: +# * Linux: +# .local/share/QGIS/QGIS3/profiles/default/python/plugins/ +# * Mac OS X: +# Library/Application Support/QGIS/QGIS3/profiles/default/python/plugins +# * Windows: +# AppData\Roaming\QGIS\QGIS3\profiles\default\python\plugins' + +QGISDIR=/home/patrick/.local/share/QGIS/QGIS3/profiles/default/python/plugins/ + +################################################# +# Normally you would not need to edit below here +################################################# + +HELP = help/build/html + +PLUGIN_UPLOAD = $(c)/plugin_upload.py + +RESOURCE_SRC=$(shell grep '^ *@@g;s/.*>//g' | tr '\n' ' ') + +.PHONY: default +default: + @echo While you can use make to build and deploy your plugin, pb_tool + @echo is a much better solution. + @echo A Python script, pb_tool provides platform independent management of + @echo your plugins and runs anywhere. + @echo You can install pb_tool using: pip install pb_tool + @echo See https://g-sherman.github.io/plugin_build_tool/ for info. + +compile: $(COMPILED_RESOURCE_FILES) + +%.py : %.qrc $(RESOURCES_SRC) + pyrcc5 -o $*.py $< + +%.qm : %.ts + $(LRELEASE) $< + +test: compile transcompile + @echo + @echo "----------------------" + @echo "Regression Test Suite" + @echo "----------------------" + + @# Preceding dash means that make will continue in case of errors + @-export PYTHONPATH=`pwd`:$(PYTHONPATH); \ + export QGIS_DEBUG=0; \ + export QGIS_LOG_FILE=/dev/null; \ + nosetests -v --with-id --with-coverage --cover-package=. \ + 3>&1 1>&2 2>&3 3>&- || true + @echo "----------------------" + @echo "If you get a 'no module named qgis.core error, try sourcing" + @echo "the helper script we have provided first then run make test." + @echo "e.g. source run-env-linux.sh ; make test" + @echo "----------------------" + +deploy: compile doc transcompile + @echo + @echo "------------------------------------------" + @echo "Deploying plugin to your .qgis2 directory." + @echo "------------------------------------------" + # The deploy target only works on unix like operating system where + # the Python plugin directory is located at: + # $HOME/$(QGISDIR)/python/plugins + mkdir -p $(HOME)/$(QGISDIR)/python/plugins/$(PLUGINNAME) + cp -vf $(PY_FILES) $(HOME)/$(QGISDIR)/python/plugins/$(PLUGINNAME) + cp -vf $(UI_FILES) $(HOME)/$(QGISDIR)/python/plugins/$(PLUGINNAME) + cp -vf $(COMPILED_RESOURCE_FILES) $(HOME)/$(QGISDIR)/python/plugins/$(PLUGINNAME) + cp -vf $(EXTRAS) $(HOME)/$(QGISDIR)/python/plugins/$(PLUGINNAME) + cp -vfr i18n $(HOME)/$(QGISDIR)/python/plugins/$(PLUGINNAME) + cp -vfr $(HELP) $(HOME)/$(QGISDIR)/python/plugins/$(PLUGINNAME)/help + # Copy extra directories if any + (foreach EXTRA_DIR,(EXTRA_DIRS), cp -R (EXTRA_DIR) (HOME)/(QGISDIR)/python/plugins/(PLUGINNAME)/;) + + +# The dclean target removes compiled python files from plugin directory +# also deletes any .git entry +dclean: + @echo + @echo "-----------------------------------" + @echo "Removing any compiled python files." + @echo "-----------------------------------" + find $(HOME)/$(QGISDIR)/python/plugins/$(PLUGINNAME) -iname "*.pyc" -delete + find $(HOME)/$(QGISDIR)/python/plugins/$(PLUGINNAME) -iname ".git" -prune -exec rm -Rf {} \; + + +derase: + @echo + @echo "-------------------------" + @echo "Removing deployed plugin." + @echo "-------------------------" + rm -Rf $(HOME)/$(QGISDIR)/python/plugins/$(PLUGINNAME) + +zip: deploy dclean + @echo + @echo "---------------------------" + @echo "Creating plugin zip bundle." + @echo "---------------------------" + # The zip target deploys the plugin and creates a zip file with the deployed + # content. You can then upload the zip file on http://plugins.qgis.org + rm -f $(PLUGINNAME).zip + cd $(HOME)/$(QGISDIR)/python/plugins; zip -9r $(CURDIR)/$(PLUGINNAME).zip $(PLUGINNAME) + +package: compile + # Create a zip package of the plugin named $(PLUGINNAME).zip. + # This requires use of git (your plugin development directory must be a + # git repository). + # To use, pass a valid commit or tag as follows: + # make package VERSION=Version_0.3.2 + @echo + @echo "------------------------------------" + @echo "Exporting plugin to zip package. " + @echo "------------------------------------" + rm -f $(PLUGINNAME).zip + git archive --prefix=$(PLUGINNAME)/ -o $(PLUGINNAME).zip $(VERSION) + echo "Created package: $(PLUGINNAME).zip" + +upload: zip + @echo + @echo "-------------------------------------" + @echo "Uploading plugin to QGIS Plugin repo." + @echo "-------------------------------------" + $(PLUGIN_UPLOAD) $(PLUGINNAME).zip + +transup: + @echo + @echo "------------------------------------------------" + @echo "Updating translation files with any new strings." + @echo "------------------------------------------------" + @chmod +x scripts/update-strings.sh + @scripts/update-strings.sh $(LOCALES) + +transcompile: + @echo + @echo "----------------------------------------" + @echo "Compiled translation files to .qm files." + @echo "----------------------------------------" + @chmod +x scripts/compile-strings.sh + @scripts/compile-strings.sh $(LRELEASE) $(LOCALES) + +transclean: + @echo + @echo "------------------------------------" + @echo "Removing compiled translation files." + @echo "------------------------------------" + rm -f i18n/*.qm + +clean: + @echo + @echo "------------------------------------" + @echo "Removing uic and rcc generated files" + @echo "------------------------------------" + rm $(COMPILED_UI_FILES) $(COMPILED_RESOURCE_FILES) + +doc: + @echo + @echo "------------------------------------" + @echo "Building documentation using sphinx." + @echo "------------------------------------" + cd help; make html + +pylint: + @echo + @echo "-----------------" + @echo "Pylint violations" + @echo "-----------------" + @pylint --reports=n --rcfile=pylintrc . || true + @echo + @echo "----------------------" + @echo "If you get a 'no module named qgis.core' error, try sourcing" + @echo "the helper script we have provided first then run make pylint." + @echo "e.g. source run-env-linux.sh ; make pylint" + @echo "----------------------" + + +# Run pep8 style checking +#http://pypi.python.org/pypi/pep8 +pep8: + @echo + @echo "-----------" + @echo "PEP8 issues" + @echo "-----------" + @pep8 --repeat --ignore=E203,E121,E122,E123,E124,E125,E126,E127,E128 --exclude $(PEP8EXCLUDE) . || true + @echo "-----------" + @echo "Ignored in PEP8 check:" + @echo $(PEP8EXCLUDE) diff --git a/README.html b/README.html new file mode 100644 index 0000000..0a89331 --- /dev/null +++ b/README.html @@ -0,0 +1,42 @@ + + +

Plugin Builder Results

+ +Congratulations! You just built a plugin for QGIS!

+ +
+Your plugin Pegelonline was created in:
+  /home/patrick/PycharmProjects/pegelonline +

+Your QGIS plugin directory is located at:
+  /home/patrick/.local/share/QGIS/QGIS3/profiles/default/python/plugins +

+

What's Next

+
    +
  1. In your plugin directory, compile the resources file using pyrcc5 (simply run make if you have automake or use pb_tool) +
  2. Test the generated sources using make test (or run tests from your IDE) +
  3. Copy the entire directory containing your new plugin to the QGIS plugin directory (see Notes below) +
  4. Test the plugin by enabling it in the QGIS plugin manager +
  5. Customize it by editing the implementation file pegelonline.py +
  6. Create your own custom icon, replacing the default icon.png +
  7. Modify your user interface by opening pegelonline_dockwidget_base.ui in Qt Designer +
+Notes: +
    +
  • You can use the Makefile to compile and deploy when you + make changes. This requires GNU make (gmake). The Makefile is ready to use, however you + will have to edit it to add addional Python source files, dialogs, and translations. +
  • You can also use pb_tool to compile and deploy your plugin. Tweak the pb_tool.cfg file included with your plugin as you add files. Install pb_tool using + pip or easy_install. See http://loc8.cc/pb_tool for more information. +
+
+
+

+For information on writing PyQGIS code, see http://loc8.cc/pyqgis_resources for a list of resources. +

+
+

+©2011-2018 GeoApt LLC - geoapt.com +

+ + diff --git a/README.txt b/README.txt new file mode 100644 index 0000000..5a74931 --- /dev/null +++ b/README.txt @@ -0,0 +1,32 @@ +Plugin Builder Results + +Your plugin Pegelonline was created in: + /home/patrick/PycharmProjects/pegelonline + +Your QGIS plugin directory is located at: + /home/patrick/.local/share/QGIS/QGIS3/profiles/default/python/plugins + +What's Next: + + * Copy the entire directory containing your new plugin to the QGIS plugin + directory + + * Compile the resources file using pyrcc5 + + * Run the tests (``make test``) + + * Test the plugin by enabling it in the QGIS plugin manager + + * Customize it by editing the implementation file: ``pegelonline.py`` + + * Create your own custom icon, replacing the default icon.png + + * Modify your user interface by opening Pegelonline_dockwidget_base.ui in Qt Designer + + * You can use the Makefile to compile your Ui and resource files when + you make changes. This requires GNU make (gmake) + +For more information, see the PyQGIS Developer Cookbook at: +http://www.qgis.org/pyqgis-cookbook/index.html + +(C) 2011-2018 GeoApt LLC - geoapt.com diff --git a/__init__.py b/__init__.py new file mode 100644 index 0000000..bd13529 --- /dev/null +++ b/__init__.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- +""" +/*************************************************************************** + Pegelonline + A QGIS plugin + Lädt Daten von Pegelonline, bereitet sie für QGIS auf und stellt sie grafisch dar. + Generated by Plugin Builder: http://g-sherman.github.io/Qgis-Plugin-Builder/ + ------------------- + begin : 2025-09-26 + copyright : (C) 2025 by Katrin Haßel + email : s6kathom@uni-trier.de + git sha : $Format:%H$ + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + This script initializes the plugin, making it known to QGIS. +""" + + +# noinspection PyPep8Naming +def classFactory(iface): # pylint: disable=invalid-name + """Load Pegelonline class from file Pegelonline. + + :param iface: A QGIS interface instance. + :type iface: QgsInterface + """ + # + from .pegelonline import Pegelonline + return Pegelonline(iface) diff --git a/icon.png b/icon.png new file mode 100644 index 0000000..f696c00 Binary files /dev/null and b/icon.png differ diff --git a/metadata.txt b/metadata.txt new file mode 100644 index 0000000..a50bd40 --- /dev/null +++ b/metadata.txt @@ -0,0 +1,47 @@ +# This file contains metadata for your plugin. + +# This file should be included when you package your plugin.# Mandatory items: + +[general] +name=Pegelonline +qgisMinimumVersion=3.0 +description=Lädt Daten von Pegelonline, bereitet sie für QGIS auf und stellt sie grafisch dar. +version=0.1 +author=Katrin Haßel +email=s6kathom@uni-trier.de + +about=Lädt Daten von Pegelonline, bereitet sie für QGIS auf und stellt sie grafisch dar. + +tracker=http://bugs +repository=http://repo +# End of mandatory metadata + +# Recommended items: + +hasProcessingProvider=no +# Uncomment the following line and add your changelog: +# changelog= + +# Tags are comma separated with spaces allowed +tags=python + +homepage=http://homepage +category=Plugins +icon=icon.png +# experimental flag +experimental=False + +# deprecated flag (applies to the whole plugin, not just a single version) +deprecated=False + +# Since QGIS 3.8, a comma separated list of plugins to be installed +# (or upgraded) can be specified. +# Check the documentation for more information. +# plugin_dependencies= + +Category of the plugin: Raster, Vector, Database or Web +# category= + +# If the plugin can run on QGIS Server. +server=False + diff --git a/pb_tool.cfg b/pb_tool.cfg new file mode 100644 index 0000000..fb8f230 --- /dev/null +++ b/pb_tool.cfg @@ -0,0 +1,80 @@ +#/*************************************************************************** +# Pegelonline +# +# Configuration file for plugin builder tool (pb_tool) +# Generated by Plugin Builder: http://g-sherman.github.io/Qgis-Plugin-Builder/ +# ------------------- +# begin : 2025-09-26 +# copyright : (C) 2025 by Katrin Haßel +# email : s6kathom@uni-trier.de +# ***************************************************************************/ +# +#/*************************************************************************** +# * * +# * This program is free software; you can redistribute it and/or modify * +# * it under the terms of the GNU General Public License as published by * +# * the Free Software Foundation; either version 2 of the License, or * +# * (at your option) any later version. * +# * * +# ***************************************************************************/ +# +# +# You can install pb_tool using: +# pip install http://geoapt.net/files/pb_tool.zip +# +# Consider doing your development (and install of pb_tool) in a virtualenv. +# +# For details on setting up and using pb_tool, see: +# http://g-sherman.github.io/plugin_build_tool/ +# +# Issues and pull requests here: +# https://github.com/g-sherman/plugin_build_tool: +# +# Sane defaults for your plugin generated by the Plugin Builder are +# already set below. +# +# As you add Python source files and UI files to your plugin, add +# them to the appropriate [files] section below. + +[plugin] +# Name of the plugin. This is the name of the directory that will +# be created in .qgis2/python/plugins +name: pegelonline + +# Full path to where you want your plugin directory copied. If empty, +# the QGIS default path will be used. Don't include the plugin name in +# the path. +plugin_path:/home/patrick/.local/share/QGIS/QGIS3/profiles/default/python/plugins + +[files] +# Python files that should be deployed with the plugin +python_files: __init__.py pegelonline.py pegelonline_dockwidget.py po_runner.py poGraph2.py + +# The main dialog file that is loaded (not compiled) +main_dialog: pegelonline_dockwidget_base.ui + +# Other ui files for dialogs you create (these will be compiled) +compiled_ui_files: + +# Resource file(s) that will be compiled +resource_files: resources.qrc + +# Other files required for the plugin +extras: metadata.txt icon.png + +# Other directories to be deployed with the plugin. +# These must be subdirectories under the plugin directory +extra_dirs: pomodules basemap + +# ISO code(s) for any locales (translations), separated by spaces. +# Corresponding .ts files must exist in the i18n directory +locales: + +[help] +# the built help directory that should be deployed with the plugin +dir: help/build/html +# the name of the directory to target in the deployed plugin +target: help + + + diff --git a/pegelonline.py b/pegelonline.py new file mode 100644 index 0000000..fd843b3 --- /dev/null +++ b/pegelonline.py @@ -0,0 +1,225 @@ +# -*- coding: utf-8 -*- +""" +/*************************************************************************** + Pegelonline + A QGIS plugin + Lädt Daten von Pegelonline, bereitet sie für QGIS auf und stellt sie grafisch dar. + Generated by Plugin Builder: http://g-sherman.github.io/Qgis-Plugin-Builder/ + ------------------- + begin : 2025-09-26 + git sha : $Format:%H$ + copyright : (C) 2025 by Katrin Haßel + email : s6kathom@uni-trier.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ +""" +import os.path + +from qgis.PyQt.QtCore import QSettings, QTranslator, QCoreApplication, Qt +from qgis.PyQt.QtGui import QIcon +from qgis.PyQt.QtWidgets import QAction + +from .pegelonline_dockwidget import PegelonlineDockWidget +from .po_runner import PoRunner + + +class Pegelonline: + """QGIS Plugin Implementation.""" + + def __init__(self, iface): + """Constructor. + + :param iface: An interface instance that will be passed to this class + which provides the hook by which you can manipulate the QGIS + application at run time. + :type iface: QgsInterface + """ + # Save reference to the QGIS interface + self.iface = iface + + # initialize plugin directory + self.plugin_dir = os.path.dirname(__file__) + + # initialize locale + locale = QSettings().value('locale/userLocale')[0:2] + locale_path = os.path.join( + self.plugin_dir, + 'i18n', + 'Pegelonline_{}.qm'.format(locale)) + + if os.path.exists(locale_path): + self.translator = QTranslator() + self.translator.load(locale_path) + QCoreApplication.installTranslator(self.translator) + + # Declare instance attributes + self.actions = [] + self.menu = self.tr(u'&Pegelonline') + # TODO: We are going to let the user set this up in a future iteration + self.toolbar = self.iface.addToolBar(u'Pegelonline') + self.toolbar.setObjectName(u'Pegelonline') + + # print "** INITIALIZING Pegelonline" + + self.pluginIsActive = False + self.dockwidget = None + + # noinspection PyMethodMayBeStatic + def tr(self, message): + """Get the translation for a string using Qt translation API. + + We implement this ourselves since we do not inherit QObject. + + :param message: String for translation. + :type message: str, QString + + :returns: Translated version of message. + :rtype: QString + """ + # noinspection PyTypeChecker,PyArgumentList,PyCallByClass + return QCoreApplication.translate('Pegelonline', message) + + def add_action( + self, + icon_path, + text, + callback, + enabled_flag=True, + add_to_menu=True, + add_to_toolbar=True, + status_tip=None, + whats_this=None, + parent=None): + """Add a toolbar icon to the toolbar. + + :param icon_path: Path to the icon for this action. Can be a resource + path (e.g. ':/plugins/foo/bar.png') or a normal file system path. + :type icon_path: str + + :param text: Text that should be shown in menu items for this action. + :type text: str + + :param callback: Function to be called when the action is triggered. + :type callback: function + + :param enabled_flag: A flag indicating if the action should be enabled + by default. Defaults to True. + :type enabled_flag: bool + + :param add_to_menu: Flag indicating whether the action should also + be added to the menu. Defaults to True. + :type add_to_menu: bool + + :param add_to_toolbar: Flag indicating whether the action should also + be added to the toolbar. Defaults to True. + :type add_to_toolbar: bool + + :param status_tip: Optional text to show in a popup when mouse pointer + hovers over the action. + :type status_tip: str + + :param parent: Parent widget for the new action. Defaults None. + :type parent: QWidget + + :param whats_this: Optional text to show in the status bar when the + mouse pointer hovers over the action. + + :returns: The action that was created. Note that the action is also + added to self.actions list. + :rtype: QAction + """ + + icon = QIcon(icon_path) + action = QAction(icon, text, parent) + action.triggered.connect(callback) + action.setEnabled(enabled_flag) + + if status_tip is not None: + action.setStatusTip(status_tip) + + if whats_this is not None: + action.setWhatsThis(whats_this) + + if add_to_toolbar: + self.toolbar.addAction(action) + + if add_to_menu: + self.iface.addPluginToMenu( + self.menu, + action) + + self.actions.append(action) + + return action + + def initGui(self): + """Create the menu entries and toolbar icons inside the QGIS GUI.""" + + icon_path = ':/plugins/pegelonline/icon.png' + self.add_action( + icon_path, + text=self.tr(u'Pegelonline'), + callback=self.run, + parent=self.iface.mainWindow()) + + # -------------------------------------------------------------------------- + + def onClosePlugin(self): + """Cleanup necessary items here when plugin dockwidget is closed""" + + # print "** CLOSING Pegelonline" + + # disconnects + self.dockwidget.closingPlugin.disconnect(self.onClosePlugin) + + # remove this statement if dockwidget is to remain + # for reuse if plugin is reopened + # Commented next statement since it causes QGIS crashe + # when closing the docked window: + # self.dockwidget = None + + self.pluginIsActive = False + + def unload(self): + """Removes the plugin menu item and icon from QGIS GUI.""" + + # print "** UNLOAD Pegelonline" + + for action in self.actions: + self.iface.removePluginMenu( + self.tr(u'&Pegelonline'), + action) + self.iface.removeToolBarIcon(action) + # remove the toolbar + del self.toolbar + + # -------------------------------------------------------------------------- + + def run(self): + """Run method that loads and starts the plugin""" + + if not self.pluginIsActive: + self.pluginIsActive = True + + print("** STARTING Pegelonline") + + if self.dockwidget == None: + # Create the dockwidget (after translation) and keep reference + self.dockwidget = PegelonlineDockWidget() + self.runner = PoRunner(self.dockwidget, self.iface) + + # connect to provide cleanup on closing of dockwidget + self.dockwidget.closingPlugin.connect(self.onClosePlugin) + + # show the dockwidget + # TODO: fix to allow choice of dock location + self.iface.addDockWidget(Qt.LeftDockWidgetArea, self.dockwidget) + self.dockwidget.show() diff --git a/pegelonline_dockwidget.py b/pegelonline_dockwidget.py new file mode 100644 index 0000000..36aa795 --- /dev/null +++ b/pegelonline_dockwidget.py @@ -0,0 +1,48 @@ +# -*- coding: utf-8 -*- +""" +/*************************************************************************** + PegelonlineDockWidget + A QGIS plugin + Lädt Daten von Pegelonline, bereitet sie für QGIS auf und stellt sie grafisch dar. + Generated by Plugin Builder: http://g-sherman.github.io/Qgis-Plugin-Builder/ + ------------------- + begin : 2025-09-26 + git sha : $Format:%H$ + copyright : (C) 2025 by Katrin Haßel + email : s6kathom@uni-trier.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ +""" + +import os + +from qgis.PyQt import QtWidgets, uic +from qgis.PyQt.QtCore import pyqtSignal + +FORM_CLASS, _ = uic.loadUiType(os.path.join(os.path.dirname(__file__), 'pegelonline_dockwidget_base.ui')) + + +class PegelonlineDockWidget(QtWidgets.QDockWidget, FORM_CLASS): + closingPlugin = pyqtSignal() + + def __init__(self, parent=None): + """Constructor.""" + super(PegelonlineDockWidget, self).__init__(parent) + # Set up the user interface from Designer. + # After setupUI you can access any designer object by doing + # self., and you can use autoconnect slots - see + # http://doc.qt.io/qt-5/designer-using-a-ui-file.html + # #widgets-and-dialogs-with-auto-connect + self.setupUi(self) + + def closeEvent(self, event): + self.closingPlugin.emit() + event.accept() diff --git a/pegelonline_dockwidget_base.ui b/pegelonline_dockwidget_base.ui new file mode 100644 index 0000000..c77aefd --- /dev/null +++ b/pegelonline_dockwidget_base.ui @@ -0,0 +1,107 @@ + + + PegelOnlineDockWidgetBase + + + + 0 + 0 + 395 + 365 + + + + + 524287 + 524287 + + + + Pegelonline + + + + + + + Wasserstandinformationen anzeigen: + + + + + + Stationen anzeigen + + + + + + + Wasserstände anzeigen + + + + + + + Basiskarte Flüsse anzeigen + + + + + + + Basiskarte Flächen anzeigen + + + + + + + Beschriftungen + + + + + + + Trend + + + rbValue + + + + + + + Absolutwerte (in cm) + + + rbValue + + + + + + + + + + + + + + + PoGraphDisplay + QWidget +
pegelonline.poGraph2
+ 1 +
+
+ + + + + +
diff --git a/poGraph2.py b/poGraph2.py new file mode 100644 index 0000000..65034ff --- /dev/null +++ b/poGraph2.py @@ -0,0 +1,117 @@ +import ctypes +from urllib.parse import quote + +from PyQt5 import QtCore, QtGui +from PyQt5 import QtWidgets + +from .pomodules import poBaseURL +from .pomodules.urlreader import UrlReader + + +class PoGraphDisplay(QtWidgets.QWidget): + + def __init__(self, parent=None): + QtWidgets.QWidget.__init__(self, parent) + self.setupUi(self) + + # Layer + self.layer = None + + def setupUi(self, poGraphDisplay): + """Definition der Benutzeroberflaeche des Wasserstanddiagramms mit den dazugehoerigen Funktionen.""" + + # uebergeordnetes Layout + self.verticalLayout = QtWidgets.QVBoxLayout(poGraphDisplay) + + # Erste Zeile --- + + self.horizontalLayout = QtWidgets.QHBoxLayout() + + # Label Station + self.lbStation = QtWidgets.QLabel() + self.lbStation.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignTrailing | QtCore.Qt.AlignVCenter) + self.horizontalLayout.addWidget(self.lbStation) + self.lbStation.setText("Geben Sie hier eine Station ein:") + + # ComboBox Stations + self.comboBox = QtWidgets.QComboBox() + self.comboBox.setEditable(True) + self.horizontalLayout.addWidget(self.comboBox) + + # Label Tage + self.lbTage = QtWidgets.QLabel() + self.lbTage.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignTrailing | QtCore.Qt.AlignVCenter) + self.lbTage.setText("Tage") + self.horizontalLayout.addWidget(self.lbTage) + + # SpinBox Tage + self.sbTage = QtWidgets.QSpinBox() + self.sbTage.setMinimum(5) + self.sbTage.setMaximum(30) + self.sbTage.setProperty("value", 14) + self.horizontalLayout.addWidget(self.sbTage) + + # PushButton Laden + self.pbLaden = QtWidgets.QPushButton() + self.pbLaden.setObjectName("pbLaden") + self.pbLaden.setText("Laden") + self.horizontalLayout.addWidget(self.pbLaden) + + # Signal Slots + self.pbLaden.clicked.connect(self.doPbLaden) + self.verticalLayout.addLayout(self.horizontalLayout) + + # Zweite Zeile --- + + # Label fuer den Graphen + self.lbGraph = QtWidgets.QLabel() + self.lbGraph.setText("") + self.lbGraph.setObjectName("lbGraph") + self.verticalLayout.addWidget(self.lbGraph) + + # Quellenhinweis + self.lbDatenquelle = QtWidgets.QLabel() + self.lbDatenquelle.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignLeading | QtCore.Qt.AlignVCenter) + self.lbDatenquelle.setText("Die Daten werden von 'pegelonline.wsv.de' zur Verfügung gestellt.") + self.verticalLayout.addWidget(self.lbDatenquelle) + + # Dritte Zeile --- + + spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + self.verticalLayout.addItem(spacerItem) + + def doLoadGraph(self): + """Laedt die Stationsdaten anhand der vom Nutzer eingegebenen Daten.""" + + # Anzahl der Tage in der SpinBox + days = self.getCurrentDays() + + # Stationsname aus der ComboBox + station = quote(self.getCurrentStation()) + url = poBaseURL + "/stations/%s/W/measurements.png?start=P%dD" % (station, days) + ur = UrlReader(url) + self.img_data = ur.getDataResponse() + + if ur.code > 299: + AlertBox = ctypes.windll.user32.MessageBoxW + AlertBox(None, "Beim Laden der Daten ist ein Fehler aufgetreten.", "Fehler", 0) + + else: + # Grafik einsetzen + pixmap = QtGui.QPixmap() + pixmap.loadFromData(self.img_data) + self.lbGraph.clear() + self.lbGraph.setPixmap(pixmap) + self.lbGraph.resize(pixmap.width(), pixmap.height()) + + def doPbLaden(self): + """Laedt den Graphen der ausgewaehlten Station.""" + + if self.layer is None: + self.doLoadGraph() + + def getCurrentDays(self): + return self.sbTage.value() + + def getCurrentStation(self): + return self.comboBox.currentText() diff --git a/po_runner.py b/po_runner.py new file mode 100644 index 0000000..247cc81 --- /dev/null +++ b/po_runner.py @@ -0,0 +1,201 @@ +import os.path +from typing import Callable + +from qgis._core import QgsVectorLayer, QgsProject, QgsLayerTreeLayer + +from .pegelonline_dockwidget import PegelonlineDockWidget +from .pomodules.poqgscurrentw import PoQgsCurrentW +from .pomodules.poqgsstations import PoQgsStations + + +# noinspection PyMethodMayBeStatic +class PoRunner(object): + + def __init__(self, ui: PegelonlineDockWidget, iface): + self.ui: PegelonlineDockWidget = ui + self.iface = iface + self.local_dir = os.path.dirname(os.path.realpath(__file__)) + + # Layer Variablen + self.layer_stations = None + self.layer_waterlevels = None + self.basemap_lines = None + self.basemap_areas = None + + # connect ui signals + self.ui.cbStationsVisible.toggled.connect(self.cbStationsVisibleToggled) + self.ui.cbWaterlevelsVisible.toggled.connect(self.cbWaterlevelsVisibleToggled) + self.ui.cbBasemapLinesVisible.toggled.connect(self.cbBasemapLinesVisibleToggled) + self.ui.cbBasemapAreasVisible.toggled.connect(self.cbBasemapAreasVisibleToggled) + self.ui.cbWaterlevelsLabelsVisible.toggled.connect(self.cbWaterlevelsLabelsVisibleToggled) + self.ui.rbValue.buttonClicked.connect(self.rbValueChanged) + + def loadStations(self): + print("loadStations") + reader = PoQgsStations() + self.layer_stations = self._layerFromReader(reader.fields, reader.crs, reader.getStationsFeatures(), "Stationen") + self._layerShow(self.layer_stations, "styles/label_stations.qml", self.disconnectStations) + + def loadWaterlevels(self): + print("loadWaterlevels") + reader = PoQgsCurrentW() + self.layer_waterlevels = self._layerFromReader(reader.fields, reader.crs, reader.getCurrentWFeatures(), "Wasserstandinformationen") + self._layerShow(self.layer_waterlevels, "styles/label_currentw.qml", self.disconnectWaterlevels) + + def _layerFromReader(self, fields, crs, features, title) -> None | QgsVectorLayer: + print("_layerFromReader") + if features is None: + return None + + layer_path = "Point?crs=%s" % (crs.authid(),) + print("layer_path: " + layer_path) + + layer = QgsVectorLayer(layer_path, title, "memory") + layer.updateFields() + layer.updateExtents() + layer.commitChanges() + + provider = layer.dataProvider() + provider.addAttributes(fields) + provider.addFeatures(features) + + if layer.isValid(): + return layer + + return None + + def _layerShow(self, layer: QgsVectorLayer, styles_path: str, disconnect: Callable[[], None]): + print("_layerShow") + if layer is None: + print("_layerShow: Übergebener Layer ist None") + return + + # Styles laden + layer.loadNamedStyle(os.path.join(self.local_dir, styles_path)) + + # disconnect setzen + layer.willBeDeleted.connect(disconnect) + + # zur Instanz hinzufügen + QgsProject.instance().addMapLayer(layer, False) + + # zum LayerTree hinzufügen + layer_tree = self.iface.layerTreeCanvasBridge().rootGroup() + layer_tree.insertChildNode(0, QgsLayerTreeLayer(layer)) + + self._layerSetVisible(layer, True) + self._layerRefresh(layer) + + def _layerRefresh(self, layer): + print("_layerRefresh") + if self.iface.mapCanvas().isCachingEnabled(): + layer.triggerRepaint() + else: + self.iface.mapCanvas().refresh() + + def cbBasemapLinesVisibleToggled(self): + checked = self.ui.cbBasemapLinesVisible.isChecked() + print("cbBasemapLinesVisibleToggled: %s" % (checked,)) + + if self.basemap_lines is None and checked: + self.basemap_lines = self._basemapCreate("waters.gpkg|layername=water_l", "Flüsse", self.disconnectBasemapLines) + + if self.basemap_lines is not None: + self._layerSetVisible(self.basemap_lines, checked) + + def cbBasemapAreasVisibleToggled(self): + checked = self.ui.cbBasemapAreasVisible.isChecked() + print("cbBasemapAreasVisibleToggled: %s" % (checked,)) + + if self.basemap_areas is None and checked: + self.basemap_areas = self._basemapCreate("waters.gpkg|layername=water_f", "Flächen", self.disconnectBasemapAreas) + + if self.basemap_areas is not None: + self._layerSetVisible(self.basemap_areas, checked) + + def _basemapCreate(self, path, name, disconnect: Callable[[], None]) -> None | QgsVectorLayer: + print("_basemapCreate: %s" % (name,)) + path = os.path.join(self.local_dir, "basemap", path) + basemap = QgsVectorLayer(path, name, "ogr") + + if not basemap.isValid(): + print("_basemapCreate: QgsVectorLayer nicht gültig: path=%s, name=%s" % (path, name)) + return None + + # disconnect setzen + basemap.willBeDeleted.connect(disconnect) + + # zur Instanz hinzufügen + QgsProject.instance().addMapLayer(basemap, False) + + # zum LayerTree hinzufügen + layer_tree = self.iface.layerTreeCanvasBridge().rootGroup() + layer_tree.insertChildNode(-1, QgsLayerTreeLayer(basemap)) + + return basemap + + def _layerSetVisible(self, basemap: QgsVectorLayer, visible): + print("_layerSetVisible: %s => %s" % (basemap.name, visible)) + layer_tree = QgsProject.instance().layerTreeRoot().findLayer(basemap.id()) + layer_tree.setItemVisibilityChecked(visible) + self._layerRefresh(basemap) + + def cbStationsVisibleToggled(self): + visible = self.ui.cbStationsVisible.isChecked() + print("cbStationsVisibleToggled: %s" % (visible,)) + + if self.layer_stations is None and visible: + self.loadStations() + + if self.layer_stations is not None: + self.layer_stations.setLabelsEnabled(visible) + self._layerSetVisible(self.layer_stations, visible) + self._layerRefresh(self.layer_stations) + + def cbWaterlevelsVisibleToggled(self): + visible = self.ui.cbWaterlevelsVisible.isChecked() + print("cbWaterlevelsVisibleToggled: %s" % (visible,)) + + if self.layer_waterlevels is None: + self.loadWaterlevels() + + if self.layer_waterlevels is not None: + self.layer_waterlevels.setLabelsEnabled(visible) + self._layerSetVisible(self.layer_waterlevels, visible) + self._layerRefresh(self.layer_waterlevels) + + def cbWaterlevelsLabelsVisibleToggled(self): + print("cbWaterlevelsLabelsVisibleToggled: %s" % (self.ui.cbWaterlevelsVisible.isChecked(),)) + # TODO + + def rbValueChanged(self, button): + print("rbValueChanged") + if self.layer_waterlevels is None: + self.loadWaterlevels() + + if button.objectName() == "rbShowTrend": + self.layer_waterlevels.loadNamedStyle(os.path.join(self.local_dir, "styles/label_currentw_trend.qml")) + elif button.objectName() == "rbShowAbsValues": + self.layer_waterlevels.loadNamedStyle(os.path.join(self.local_dir, "styles/label_currentw_absvalue.qml")) + + self.cbWaterlevelsVisibleToggled() + + def disconnectStations(self): + print("disconnectStations") + self.layer_stations = None + self.ui.cbStationsVisible.setChecked(False) + + def disconnectWaterlevels(self): + print("disconnectWaterlevels") + self.layer_waterlevels = None + self.ui.cbWaterlevelsVisible.setChecked(False) + + def disconnectBasemapLines(self): + print("disconnectBasemapLines") + self.basemap_lines = None + self.ui.cbBasemapLinesVisible.setChecked(False) + + def disconnectBasemapAreas(self): + print("disconnectBasemapAreas") + self.basemap_areas = None + self.ui.cbBasemapAreasVisible.setChecked(False) diff --git a/pomodules/__init__.py b/pomodules/__init__.py new file mode 100644 index 0000000..2d164e9 --- /dev/null +++ b/pomodules/__init__.py @@ -0,0 +1 @@ +poBaseURL = 'https://www.pegelonline.wsv.de/webservices/rest-api/v2/' diff --git a/pomodules/pocurrentw.py b/pomodules/pocurrentw.py new file mode 100644 index 0000000..ae343dd --- /dev/null +++ b/pomodules/pocurrentw.py @@ -0,0 +1,45 @@ +from . import poBaseURL +from .urlreader import UrlReader + + +class PoCurrentW(object): + + def __init__(self): + self.url = poBaseURL + 'stations.json?timeseries=W&includeTimeseries=true&includeCurrentMeasurement=true' + + def getCurrentW(self): + print("getCurrentW: Getting data...") + + reader = UrlReader(self.url) + stations_json = reader.getJsonResponse() + if stations_json is None: + print("getCurrentW: FEHLER: Keine Stationen erhalten") + return None + + print("getCurrentW: %d Stationen erhalten" % (len(stations_json),)) + + stations = [] + for station_json in stations_json: + if 'longitude' not in station_json or 'latitude' not in station_json or 'km' not in station_json: + print("getCurrentW: WARN: Station hat fehlende Attribute: %s" % (station_json['longname'],)) + continue + + stations.append( + { + 'geometry': { + 'longitude': station_json['longitude'], + 'latitude': station_json['latitude'], + }, + 'attributes': { + 'uuid': station_json['uuid'], + 'shortname': station_json['shortname'], + 'timestamp': station_json['timeseries'][0]['currentMeasurement']['timestamp'], + 'value': station_json['timeseries'][0]['currentMeasurement']['value'], + 'stateMnwMhw': station_json['timeseries'][0]['currentMeasurement']['stateMnwMhw'], + 'stateNswHsw': station_json['timeseries'][0]['currentMeasurement']['stateNswHsw'], + }, + } + ) + + print("getCurrentW: %d / %d Stationen überführt" % (len(stations), len(stations_json))) + return stations diff --git a/pomodules/poqgscurrentw.py b/pomodules/poqgscurrentw.py new file mode 100644 index 0000000..deacde0 --- /dev/null +++ b/pomodules/poqgscurrentw.py @@ -0,0 +1,44 @@ +from PyQt5.QtCore import QVariant +from qgis._core import QgsCoordinateReferenceSystem, QgsGeometry, QgsPointXY +from qgis.core import QgsFields, QgsFeature, QgsField + +from .pocurrentw import PoCurrentW + + +class PoQgsCurrentW(PoCurrentW): + + def __init__(self): + super().__init__() + self.crs = QgsCoordinateReferenceSystem(4326, QgsCoordinateReferenceSystem.EpsgCrsId) + + self.fields = QgsFields() + self.fields.append(QgsField('timestamp', QVariant.DateTime)) + self.fields.append(QgsField('value', QVariant.Double)) + self.fields.append(QgsField('stateMnwMhw', QVariant.String)) + self.fields.append(QgsField('stateNswHsw', QVariant.String)) + + def getCurrentWFeatures(self): + print("getCurrentWFeatures: Erzeuge Features...") + + features = [] + for station in self.getCurrentW(): + feature = self._getFeatureForStation(station) + features.append(feature) + + print("getCurrentWFeatures: %d Features erzeugt" % (len(features),)) + return features + + def _getFeatureForStation(self, station): + feature = QgsFeature() + + longitude = station['geometry']['longitude'] + latitude = station['geometry']['latitude'] + feature.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(longitude, latitude))) + + feature.setFields(self.fields) + feature.setAttribute('timestamp', station['attributes']['timestamp']) + feature.setAttribute('value', station['attributes']['value']) + feature.setAttribute('stateMnwMhw', station['attributes']['stateMnwMhw']) + feature.setAttribute('stateNswHsw', station['attributes']['stateNswHsw']) + + return feature diff --git a/pomodules/poqgsstations.py b/pomodules/poqgsstations.py new file mode 100644 index 0000000..271c179 --- /dev/null +++ b/pomodules/poqgsstations.py @@ -0,0 +1,50 @@ +from PyQt5.QtCore import QVariant +from qgis._core import QgsCoordinateReferenceSystem, QgsGeometry, QgsPointXY +from qgis.core import QgsFields, QgsFeature, QgsField + +from .postations import PoStations + + +class PoQgsStations(PoStations): + + def __init__(self): + PoStations.__init__(self) + self.crs = QgsCoordinateReferenceSystem(4326, QgsCoordinateReferenceSystem.EpsgCrsId) + + self.fields = QgsFields() + self.fields.append(QgsField('uuid', QVariant.String)) + self.fields.append(QgsField('number', QVariant.Int)) + self.fields.append(QgsField('shortname', QVariant.String)) + self.fields.append(QgsField('longname', QVariant.String)) + self.fields.append(QgsField('km', QVariant.Double)) + self.fields.append(QgsField('agency', QVariant.String)) + self.fields.append(QgsField('water', QVariant.String)) + + def getStationsFeatures(self): + print("getStationsFeatures: Erzeuge Features...") + + features = [] + for station in self.getStations(): + feature = self._getFeatureForStation(station) + features.append(feature) + + print("getStationsFeatures: %d Features erzeugt" % (len(features),)) + return features + + def _getFeatureForStation(self, station) -> QgsFeature: + feature = QgsFeature() + + longitude = station['geometry']['longitude'] + latitude = station['geometry']['latitude'] + feature.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(longitude, latitude))) + + feature.setFields(self.fields) + feature.setAttribute('uuid', station['attributes']['uuid']) + feature.setAttribute('number', station['attributes']['number']) + feature.setAttribute('shortname', station['attributes']['shortname']) + feature.setAttribute('longname', station['attributes']['longname']) + feature.setAttribute('km', station['attributes']['km']) + feature.setAttribute('agency', station['attributes']['agency']) + feature.setAttribute('water', station['attributes']['water']) + + return feature diff --git a/pomodules/postations.py b/pomodules/postations.py new file mode 100644 index 0000000..52c1bd3 --- /dev/null +++ b/pomodules/postations.py @@ -0,0 +1,46 @@ +from . import poBaseURL +from .urlreader import UrlReader + + +class PoStations(object): + + def __init__(self): + self.url = poBaseURL + 'stations.json' + + def getStations(self): + print("getStations: Getting data...") + + reader = UrlReader(self.url) + stations_json = reader.getJsonResponse() + if stations_json is None: + print("getStations: Keine Stationen erhalten") + return None + + print("getStations: %d Stationen erhalten" % (len(stations_json),)) + + stations = [] + for station_json in stations_json: + if 'longitude' not in station_json or 'latitude' not in station_json or 'km' not in station_json: + print("getStations: Station hat fehlende Attribute: %s" % (station_json['longname'],)) + continue + + stations.append( + { + 'geometry': { + 'longitude':station_json['longitude'], + 'latitude':station_json['latitude'], + }, + 'attributes': { + 'uuid': station_json['uuid'], + 'number': station_json['number'], + 'shortname': station_json['shortname'], + 'longname': station_json['longname'], + 'km': station_json['km'], + 'agency': station_json['agency'], + 'water': station_json['water']['longname'], + }, + } + ) + + print("getStations: %d / %d Stationen überführt" % (len(stations), len(stations_json))) + return stations diff --git a/pomodules/urlreader.py b/pomodules/urlreader.py new file mode 100644 index 0000000..70d441b --- /dev/null +++ b/pomodules/urlreader.py @@ -0,0 +1,123 @@ +import json +from gzip import GzipFile +from os.path import basename, join +from urllib.error import URLError +from urllib.parse import urlparse +from urllib.request import Request, urlopen + + +class UrlReader(object): + + def __init__(self, _url): + self.url = _url + + def openUrl(self): + """ + Öffnet eine URL-Verbindung, fragt GZIP-Kompression an und gibt das Response-Objekt zurück + :return: Response-Objekt oder None im Fehlerfall + """ + print("openURL: url: \"%s\"" % (self.url,)) + try: + request = Request(self.url) + request.add_header('Accept-Encoding', 'gzip') + response = urlopen(request) + print("openURL: Verbindung hergestellt") + return response + except URLError as e: # auch HTTPError + print("openURL: FEHLER: " + str(e)) + + return None # Fehler + + def getDataResponse(self): + """ + Benutzt openUrl und gibt die (entpackten) Daten zurück. + :return: (entpackte) Daten oder None im Fehlerfall + """ + print("getDataResponse: url: \"%s\"" % (self.url,)) + response = self.openUrl() + if response is None: + print("getDataResponse: FEHLER: Kein Response-Objekt erhalten") + return None + + try: + if response.headers['Content-Encoding'] == 'gzip': + print("getDataResponse: Empfange GZIP Daten...") + daten = GzipFile(fileobj=response).read() + else: + print("getDataResponse: Empfange unkomprimierte Daten...") + daten = response.read() + + print("getDataResponse: Daten empfangen") + return daten + + except OSError as e: + print("getDataResponse: FEHLER: " + str(e)) + + return None # Kein Erfolg + + def getJsonResponse(self): + """ + Benutzt getDataResponse zum Herunterladen, interpretiert die Daten als JSON und gibt das Ergebnis zurück. + :return: Geparste JSON Daten oder None im Fehlerfall + """ + print("getJsonResponse: url=" + self.url) + daten = self.getDataResponse() + if daten is None: + print("getJsonResponse: FEHLER: Keine Daten erhalten") + return None + + try: + print("getJsonResponse: Lese JSON...") + parsed = json.loads(daten) + print("getJsonResponse: JSON gelesen") + return parsed + + except ValueError as e: # JSONDecodeError + print("getJsonResponse: ValueError: " + str(e)) + + except TypeError as e: # JSONDecodeError + print("getJsonResponse: TypeError: " + str(e)) + + return None # Kein Erfolg + + def _dateiname_von_url(self): + result = urlparse(self.url) + dateiname = basename(result.path) + return dateiname + + def getFileResponse(self, pfad): + """ + Benutzt getDataResponse zum Herunterladen, schreibt die Daten in eine Datei und gibt ihren Pfad zurück (gegebenes Verzeichnis + basename des URL-Pfades). + :param pfad: Verzeichnis in dem die Datei gespeichert werden soll. + :return: Pfad der erzeugten Datei oder None im Fehlerfall + """ + print("getFileResponse: url: \"%s\"" % (self.url,)) + print("getFileResponse: pfad: \"%s\"" % (pfad,)) + + daten = self.getDataResponse() + if daten is None: + print("getFileResponse: FEHLER: Keine Daten erhalten") + return None + + dateiname = self._dateiname_von_url() + print("getFileResponse: dateiname: \"%s\"" % (dateiname,)) + + dateipfad = join(pfad, dateiname) + print("getFileResponse: dateipfad: \"%s\"" % (dateipfad,)) + + try: + print("getFileResponse: Schreibe Datei...") + with open(dateipfad, 'wb') as datei: + datei.write(daten) + print("getFileResponse: Datei geschrieben") + return dateipfad + + except OSError as e: + print("getFilesResponse: FEHLER: " + str(e)) + + return None + + +if __name__ == '__main__': + url = "https://ia800302.us.archive.org/8/items/BennyGoodmanQuartetAndTrio/BodySoul-BennyGoodmanGeneKrupaTeddyWilsoncarnegieHall1938_64kb.mp3" + print(UrlReader(url).getFileResponse("")) diff --git a/resources.qrc b/resources.qrc new file mode 100644 index 0000000..ae450c5 --- /dev/null +++ b/resources.qrc @@ -0,0 +1,5 @@ + + + icon.png + + diff --git a/styles/beschriftungen_currentw.qml b/styles/beschriftungen_currentw.qml new file mode 100644 index 0000000..8137671 --- /dev/null +++ b/styles/beschriftungen_currentw.qml @@ -0,0 +1,243 @@ + + + + 1 + 1 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + 0 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + 0 + generatedlayout + + + + + + + + + + + + + + + + + + + + uuid + + 0 + diff --git a/styles/label_currentw.qml b/styles/label_currentw.qml new file mode 100644 index 0000000..2778c13 --- /dev/null +++ b/styles/label_currentw.qml @@ -0,0 +1,243 @@ + + + + 1 + 1 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + 0 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + 0 + generatedlayout + + + + + + + + + + + + + + + + + + + + uuid + + 0 + diff --git a/styles/label_currentw_absvalue.qml b/styles/label_currentw_absvalue.qml new file mode 100644 index 0000000..2755990 --- /dev/null +++ b/styles/label_currentw_absvalue.qml @@ -0,0 +1,411 @@ + + + + 1 + 1 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + uuid + + + + + + 0 + 0 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + 0 + generatedlayout + + + + + + + + + + + + + + + + + + + + uuid + + 0 + diff --git a/styles/label_currentw_trend.qml b/styles/label_currentw_trend.qml new file mode 100644 index 0000000..4fe7d8b --- /dev/null +++ b/styles/label_currentw_trend.qml @@ -0,0 +1,345 @@ + + + + 1 + 1 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + 0 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + 0 + generatedlayout + + + + + + + + + + + + + + + + + + + + uuid + + 0 + diff --git a/styles/label_stations.qml b/styles/label_stations.qml new file mode 100644 index 0000000..5383489 --- /dev/null +++ b/styles/label_stations.qml @@ -0,0 +1,243 @@ + + + + 1 + 1 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + 0 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + 0 + generatedlayout + + + + + + + + + + + + + + + + + + + + uuid + + 0 + diff --git a/styles/lyr_style.py b/styles/lyr_style.py new file mode 100644 index 0000000..15d500a --- /dev/null +++ b/styles/lyr_style.py @@ -0,0 +1,8 @@ +import os +local_dir = r"J:\gp190225\Home\.qgis3\profiles\default\python\plugins\pegelonline" +lyr = iface.activeLayer() +lyr.loadNamedStyle(os.path.join(local_dir, "styles/trend.qml")) +if iface.mapCanvas().isCachingEnabled(): + lyr.triggerRepaint() +else: + iface.mapCanvas().refresh() \ No newline at end of file