diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 9bdd91c..c962195 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -14,6 +14,7 @@ jobs: quarto-publish: name: Publish with Quarto runs-on: ubuntu-latest + permissions: pages steps: # Circumvent this problem: https://github.com/actions/checkout/issues/165 - name: Checkout code with LFS cache diff --git a/docs/install.qmd b/docs/install.qmd index b12a6b9..5fb8cb5 100644 --- a/docs/install.qmd +++ b/docs/install.qmd @@ -8,7 +8,7 @@ QGIS-Tim therfore consists of three steps: ## 1. Install QGIS -Download and install a recent version of QGIS (>=3.40, <4.0) from the official +Download and install a recent version of QGIS (>=3.40) from the official QGIS website: {target="_blank"} diff --git a/docs/tutorial_Rijsenhout.qmd b/docs/tutorial_Rijsenhout.qmd index a4b43b1..cc17f4a 100644 --- a/docs/tutorial_Rijsenhout.qmd +++ b/docs/tutorial_Rijsenhout.qmd @@ -3,7 +3,7 @@ title: "Building Pit Rijsenhout" --- ## Requirements -- Be sure QGIS version 3.40 or later is installed, but not version 4.0. +- Be sure QGIS version 3.40 or later is installed - Be sure the ``gistim`` Python package is installed (see [installation](install.qmd) for instructions). - Download the tutorial material. [Follow this link.](https://deltares.thegood.cloud/s/zryWnfjT43Ryoea) - Internet connections is optional during this Tutorial. It is only required for installation of additional plugins and the use of an online topographic background map. diff --git a/docs/tutorial_TheHague.qmd b/docs/tutorial_TheHague.qmd index 161d29f..3932b9a 100644 --- a/docs/tutorial_TheHague.qmd +++ b/docs/tutorial_TheHague.qmd @@ -46,7 +46,7 @@ title: "Building Pit The Hague " --- ## Requirements -- Be sure QGIS version 3.40 or later is installed, but not version 4.0. +- Be sure QGIS version 3.40 or later is installed - Be sure the ``gistim`` Python package is installed (see [installation](install.qmd) for instructions). - Download the tutorial material. Follow this link. - Installation of the QGIS-Tim plugin and the MOD plugin is part of this Tutorial. The necessary ZIP files are included in the tutorial material. diff --git a/docs/tutorial_particle_tracking.qmd b/docs/tutorial_particle_tracking.qmd index 47d84a3..44d502d 100644 --- a/docs/tutorial_particle_tracking.qmd +++ b/docs/tutorial_particle_tracking.qmd @@ -4,7 +4,7 @@ title: "Particle Tracking" ## Requirements -- Be sure QGIS version 3.40 or later is installed, but not version 4.0. +- Be sure QGIS version 3.40 or later is installed - Be sure the ``gistim`` Python package is installed (see [installation](install.qmd) for instructions). ## Description diff --git a/gistim/__init__.py b/gistim/__init__.py index a0387e4..d512abd 100644 --- a/gistim/__init__.py +++ b/gistim/__init__.py @@ -1,3 +1,3 @@ import gistim.compute # noqa: F401 -__version__ = "0.7.0.dev1" +__version__ = "0.7.0.dev2" diff --git a/pixi.toml b/pixi.toml index 4d75921..a5ccd20 100644 --- a/pixi.toml +++ b/pixi.toml @@ -1,6 +1,6 @@ [workspace] name = "gistim" -version = "0.7.0.dev1" +version = "0.7.0.dev2" description = "Connects timflow Analytic Element modeling to QGIS" authors = ["Huite Bootsma"] channels = ["conda-forge"] @@ -40,10 +40,10 @@ qgis-stubs = "*" qgis-plugin-manager = ">=1.7.5, <2" [feature.dev.target.win-64.dependencies] -qgis = ">=3.40,<4" +qgis = ">=3.40, <5" [feature.dev.target.linux-64.dependencies] -qgis = ">=3.40,<4" +qgis = ">=3.40, <5" [feature.dev.tasks] diff --git a/plugin/qgistim/core/elements/aquifer.py b/plugin/qgistim/core/elements/aquifer.py index 62ab3db..3c4c13a 100644 --- a/plugin/qgistim/core/elements/aquifer.py +++ b/plugin/qgistim/core/elements/aquifer.py @@ -1,5 +1,5 @@ -from PyQt5.QtCore import QVariant from qgis.core import QgsDefaultValue, QgsField, QgsVectorLayerUtils +from qgis.PyQt.QtCore import QVariant from qgistim.core import geopackage from qgistim.core.elements.default_values import DefaultValues diff --git a/plugin/qgistim/core/elements/building_pit.py b/plugin/qgistim/core/elements/building_pit.py index c819918..d1deb74 100644 --- a/plugin/qgistim/core/elements/building_pit.py +++ b/plugin/qgistim/core/elements/building_pit.py @@ -1,7 +1,7 @@ from typing import Any, Dict -from PyQt5.QtCore import QVariant from qgis.core import QgsDefaultValue, QgsField, QgsSingleSymbolRenderer +from qgis.PyQt.QtCore import QVariant from qgistim.core.elements.colors import RED, TRANSPARENT_RED from qgistim.core.elements.default_values import DefaultValues diff --git a/plugin/qgistim/core/elements/circular_area_sink.py b/plugin/qgistim/core/elements/circular_area_sink.py index aff6f02..596a4ec 100644 --- a/plugin/qgistim/core/elements/circular_area_sink.py +++ b/plugin/qgistim/core/elements/circular_area_sink.py @@ -1,7 +1,7 @@ from typing import Any, Dict -from PyQt5.QtCore import QVariant from qgis.core import QgsField +from qgis.PyQt.QtCore import QVariant from qgistim.core.elements.colors import GREEN, TRANSPARENT_GREEN from qgistim.core.elements.element import TransientElement diff --git a/plugin/qgistim/core/elements/constant.py b/plugin/qgistim/core/elements/constant.py index 2b13526..a8d3587 100644 --- a/plugin/qgistim/core/elements/constant.py +++ b/plugin/qgistim/core/elements/constant.py @@ -1,5 +1,5 @@ -from PyQt5.QtCore import QVariant from qgis.core import QgsField, QgsSingleSymbolRenderer +from qgis.PyQt.QtCore import QVariant from qgistim.core.elements.colors import RED from qgistim.core.elements.element import Element diff --git a/plugin/qgistim/core/elements/discharge_observation.py b/plugin/qgistim/core/elements/discharge_observation.py index 7f6610d..29b6b46 100644 --- a/plugin/qgistim/core/elements/discharge_observation.py +++ b/plugin/qgistim/core/elements/discharge_observation.py @@ -1,5 +1,5 @@ -from PyQt5.QtCore import QVariant from qgis.core import QgsDefaultValue, QgsField, QgsSingleSymbolRenderer +from qgis.PyQt.QtCore import QVariant from qgistim.core.elements.colors import LIGHT_BLUE from qgistim.core.elements.element import Element diff --git a/plugin/qgistim/core/elements/domain.py b/plugin/qgistim/core/elements/domain.py index 329f930..658b582 100644 --- a/plugin/qgistim/core/elements/domain.py +++ b/plugin/qgistim/core/elements/domain.py @@ -1,6 +1,5 @@ from typing import Any, Tuple -from PyQt5.QtCore import QVariant from qgis.core import ( QgsFeature, QgsField, @@ -8,6 +7,7 @@ QgsPointXY, QgsSingleSymbolRenderer, ) +from qgis.PyQt.QtCore import QVariant from qgistim.core.elements.colors import BLACK from qgistim.core.elements.element import ElementExtraction, TransientElement diff --git a/plugin/qgistim/core/elements/element.py b/plugin/qgistim/core/elements/element.py index b69bc23..2623bca 100644 --- a/plugin/qgistim/core/elements/element.py +++ b/plugin/qgistim/core/elements/element.py @@ -56,14 +56,6 @@ from copy import deepcopy from typing import Any, Dict, List, NamedTuple, Optional, Set, Tuple, Union -from PyQt5.QtWidgets import ( - QDialog, - QHBoxLayout, - QLabel, - QLineEdit, - QPushButton, - QVBoxLayout, -) from qgis.core import ( QgsFillSymbol, QgsLineSymbol, @@ -71,6 +63,14 @@ QgsSingleSymbolRenderer, QgsVectorLayer, ) +from qgis.PyQt.QtWidgets import ( + QDialog, + QHBoxLayout, + QLabel, + QLineEdit, + QPushButton, + QVBoxLayout, +) from qgistim.core import geopackage from qgistim.core.extractor import ExtractorMixin @@ -141,7 +141,7 @@ def __init__(self, path: str, name: str): def dialog(cls, path: str, crs: Any, iface: Any, names: List[str]): dialog = NameDialog() dialog.show() - ok = dialog.exec_() + ok = dialog.exec() if not ok: return diff --git a/plugin/qgistim/core/elements/head_line_sink.py b/plugin/qgistim/core/elements/head_line_sink.py index 503e2d2..8e52251 100644 --- a/plugin/qgistim/core/elements/head_line_sink.py +++ b/plugin/qgistim/core/elements/head_line_sink.py @@ -1,5 +1,5 @@ -from PyQt5.QtCore import QVariant from qgis.core import QgsDefaultValue, QgsField, QgsSingleSymbolRenderer +from qgis.PyQt.QtCore import QVariant from qgistim.core.elements.colors import BLUE from qgistim.core.elements.default_values import DefaultValues diff --git a/plugin/qgistim/core/elements/headwell.py b/plugin/qgistim/core/elements/headwell.py index 6fb02b4..a82f18d 100644 --- a/plugin/qgistim/core/elements/headwell.py +++ b/plugin/qgistim/core/elements/headwell.py @@ -1,7 +1,5 @@ from typing import Any, Dict -from PyQt5.QtCore import QVariant -from PyQt5.QtGui import QColor from qgis.core import ( QgsArrowSymbolLayer, QgsDefaultValue, @@ -9,6 +7,8 @@ QgsLineSymbol, QgsSingleSymbolRenderer, ) +from qgis.PyQt.QtCore import QVariant +from qgis.PyQt.QtGui import QColor from qgistim.core.elements.colors import BLUE from qgistim.core.elements.element import TransientElement diff --git a/plugin/qgistim/core/elements/impermeable_line_doublet.py b/plugin/qgistim/core/elements/impermeable_line_doublet.py index 7618fd5..682dcd2 100644 --- a/plugin/qgistim/core/elements/impermeable_line_doublet.py +++ b/plugin/qgistim/core/elements/impermeable_line_doublet.py @@ -1,5 +1,5 @@ -from PyQt5.QtCore import QVariant from qgis.core import QgsDefaultValue, QgsField, QgsSingleSymbolRenderer +from qgis.PyQt.QtCore import QVariant from qgistim.core.elements.colors import RED from qgistim.core.elements.default_values import DefaultValues diff --git a/plugin/qgistim/core/elements/leaky_building_pit.py b/plugin/qgistim/core/elements/leaky_building_pit.py index a4eddaa..22b68a9 100644 --- a/plugin/qgistim/core/elements/leaky_building_pit.py +++ b/plugin/qgistim/core/elements/leaky_building_pit.py @@ -1,7 +1,7 @@ from typing import Any, Dict -from PyQt5.QtCore import QVariant from qgis.core import QgsDefaultValue, QgsField, QgsSingleSymbolRenderer +from qgis.PyQt.QtCore import QVariant from qgistim.core.elements.colors import RED, TRANSPARENT_RED from qgistim.core.elements.default_values import DefaultValues diff --git a/plugin/qgistim/core/elements/leaky_line_doublet.py b/plugin/qgistim/core/elements/leaky_line_doublet.py index 6bc179b..c9d2034 100644 --- a/plugin/qgistim/core/elements/leaky_line_doublet.py +++ b/plugin/qgistim/core/elements/leaky_line_doublet.py @@ -1,5 +1,5 @@ -from PyQt5.QtCore import QVariant from qgis.core import QgsDefaultValue, QgsField, QgsSingleSymbolRenderer +from qgis.PyQt.QtCore import QVariant from qgistim.core.elements.colors import RED from qgistim.core.elements.default_values import DefaultValues diff --git a/plugin/qgistim/core/elements/line_sink_ditch.py b/plugin/qgistim/core/elements/line_sink_ditch.py index 5ee6f0c..f878ce9 100644 --- a/plugin/qgistim/core/elements/line_sink_ditch.py +++ b/plugin/qgistim/core/elements/line_sink_ditch.py @@ -1,5 +1,5 @@ -from PyQt5.QtCore import QVariant from qgis.core import QgsDefaultValue, QgsField, QgsSingleSymbolRenderer +from qgis.PyQt.QtCore import QVariant from qgistim.core.elements.colors import GREEN from qgistim.core.elements.default_values import DefaultValues diff --git a/plugin/qgistim/core/elements/observation.py b/plugin/qgistim/core/elements/observation.py index d7c7352..f0abc39 100644 --- a/plugin/qgistim/core/elements/observation.py +++ b/plugin/qgistim/core/elements/observation.py @@ -1,5 +1,5 @@ -from PyQt5.QtCore import QVariant from qgis.core import QgsDefaultValue, QgsField, QgsSingleSymbolRenderer +from qgis.PyQt.QtCore import QVariant from qgistim.core.elements.colors import LIGHT_BLUE from qgistim.core.elements.element import TransientElement diff --git a/plugin/qgistim/core/elements/particle.py b/plugin/qgistim/core/elements/particle.py index 1dd0d4a..5cf259b 100644 --- a/plugin/qgistim/core/elements/particle.py +++ b/plugin/qgistim/core/elements/particle.py @@ -1,12 +1,12 @@ import abc from typing import Any, Dict -from PyQt5.QtCore import QVariant from qgis.core import ( QgsDefaultValue, QgsField, QgsSingleSymbolRenderer, ) +from qgis.PyQt.QtCore import QVariant from qgistim.core.elements.colors import GREY, LIGHT_GREY from qgistim.core.elements.default_values import DefaultValues diff --git a/plugin/qgistim/core/elements/polygon_area_sink.py b/plugin/qgistim/core/elements/polygon_area_sink.py index 21c02ae..919d0c3 100644 --- a/plugin/qgistim/core/elements/polygon_area_sink.py +++ b/plugin/qgistim/core/elements/polygon_area_sink.py @@ -1,7 +1,7 @@ from copy import deepcopy -from PyQt5.QtCore import QVariant from qgis.core import QgsDefaultValue, QgsField, QgsSingleSymbolRenderer +from qgis.PyQt.QtCore import QVariant from qgistim.core.elements.colors import GREEN, TRANSPARENT_GREEN from qgistim.core.elements.default_values import DefaultValues diff --git a/plugin/qgistim/core/elements/polygon_inhomogeneity.py b/plugin/qgistim/core/elements/polygon_inhomogeneity.py index d8d349a..6f62025 100644 --- a/plugin/qgistim/core/elements/polygon_inhomogeneity.py +++ b/plugin/qgistim/core/elements/polygon_inhomogeneity.py @@ -1,7 +1,7 @@ from typing import Any, Dict -from PyQt5.QtCore import QVariant from qgis.core import QgsDefaultValue, QgsField, QgsSingleSymbolRenderer +from qgis.PyQt.QtCore import QVariant from qgistim.core.elements.colors import GREY, TRANSPARENT_GREY from qgistim.core.elements.default_values import DefaultValues diff --git a/plugin/qgistim/core/elements/polygon_semi_confined_top.py b/plugin/qgistim/core/elements/polygon_semi_confined_top.py index 7d79485..7b2040b 100644 --- a/plugin/qgistim/core/elements/polygon_semi_confined_top.py +++ b/plugin/qgistim/core/elements/polygon_semi_confined_top.py @@ -1,7 +1,7 @@ from copy import deepcopy -from PyQt5.QtCore import QVariant from qgis.core import QgsDefaultValue, QgsField, QgsSingleSymbolRenderer +from qgis.PyQt.QtCore import QVariant from qgistim.core.elements.colors import BLUE, TRANSPARENT_BLUE from qgistim.core.elements.default_values import DefaultValues diff --git a/plugin/qgistim/core/elements/uniform_flow.py b/plugin/qgistim/core/elements/uniform_flow.py index 13957be..8a95937 100644 --- a/plugin/qgistim/core/elements/uniform_flow.py +++ b/plugin/qgistim/core/elements/uniform_flow.py @@ -1,5 +1,5 @@ -from PyQt5.QtCore import QVariant from qgis.core import QgsField +from qgis.PyQt.QtCore import QVariant from qgistim.core.elements.element import Element from qgistim.core.elements.schemata import SingleRowSchema diff --git a/plugin/qgistim/core/elements/well.py b/plugin/qgistim/core/elements/well.py index 132649d..7dd4dd9 100644 --- a/plugin/qgistim/core/elements/well.py +++ b/plugin/qgistim/core/elements/well.py @@ -1,7 +1,7 @@ from typing import Any, Dict -from PyQt5.QtCore import QVariant from qgis.core import QgsDefaultValue, QgsField, QgsSingleSymbolRenderer +from qgis.PyQt.QtCore import QVariant from qgistim.core.elements.colors import GREEN from qgistim.core.elements.element import TransientElement diff --git a/plugin/qgistim/core/geopackage.py b/plugin/qgistim/core/geopackage.py index 3b77e29..6705af3 100644 --- a/plugin/qgistim/core/geopackage.py +++ b/plugin/qgistim/core/geopackage.py @@ -14,7 +14,7 @@ from typing import List from qgis import processing -from qgis.core import QgsVectorFileWriter, QgsVectorLayer +from qgis.core import QgsProject, QgsVectorFileWriter, QgsVectorLayer @contextmanager @@ -74,11 +74,23 @@ def write_layer( options.driverName = "gpkg" options.layerName = layername if not newfile: - options.actionOnExistingFile = QgsVectorFileWriter.CreateOrOverwriteLayer - write_result, error_message = QgsVectorFileWriter.writeAsVectorFormat( - layer, path, options - ) - if write_result != QgsVectorFileWriter.NoError: + options.actionOnExistingFile = ( + QgsVectorFileWriter.ActionOnExistingFile.CreateOrOverwriteLayer + ) + if hasattr(QgsVectorFileWriter, "writeAsVectorFormatV3"): + result = QgsVectorFileWriter.writeAsVectorFormatV3( + layer, + path, + QgsProject.instance().transformContext(), + options, + ) + write_result = result[0] + error_message = result[-1] if len(result) > 1 else "" + else: + write_result, error_message = QgsVectorFileWriter.writeAsVectorFormat( + layer, path, options + ) + if write_result != QgsVectorFileWriter.WriterError.NoError: raise RuntimeError( f"Layer {layername} could not be written to geopackage: {path}" f" with error: {error_message}" diff --git a/plugin/qgistim/core/layer_styling.py b/plugin/qgistim/core/layer_styling.py index ecf33ec..bb397eb 100644 --- a/plugin/qgistim/core/layer_styling.py +++ b/plugin/qgistim/core/layer_styling.py @@ -8,7 +8,6 @@ from typing import List -from PyQt5.QtGui import QColor from qgis.core import ( QgsColorRampShader, QgsLineSymbol, @@ -22,6 +21,7 @@ QgsTextFormat, QgsVectorLayerSimpleLabeling, ) +from qgis.PyQt.QtGui import QColor def color_ramp_items( @@ -71,7 +71,7 @@ def pseudocolor_renderer( ------- renderer: QgsSingleBandPseudoColorRenderer """ - stats = layer.dataProvider().bandStatistics(band, QgsRasterBandStats.All) + stats = layer.dataProvider().bandStatistics(band, QgsRasterBandStats.Stats.All) minimum = stats.minimumValue maximum = stats.maximumValue @@ -80,8 +80,10 @@ def pseudocolor_renderer( shader_function.setMinimumValue(minimum) shader_function.setMaximumValue(maximum) shader_function.setSourceColorRamp(ramp) - shader_function.setColorRampType(QgsColorRampShader.Interpolated) - shader_function.setClassificationMode(QgsColorRampShader.EqualInterval) + shader_function.setColorRampType(QgsColorRampShader.Type.Interpolated) + shader_function.setClassificationMode( + QgsColorRampShader.ClassificationMode.EqualInterval + ) shader_function.setColorRampItemList(ramp_items) raster_shader = QgsRasterShader() @@ -104,7 +106,7 @@ def number_labels(field: str) -> QgsVectorLayerSimpleLabeling: pal_layer = QgsPalLayerSettings() pal_layer.fieldName = field pal_layer.enabled = True - pal_layer.placement = QgsPalLayerSettings.Line + pal_layer.placement = QgsPalLayerSettings.Placement.Line pal_layer.formatNumbers = True pal_layer.decimals = 2 diff --git a/plugin/qgistim/core/processing.py b/plugin/qgistim/core/processing.py index 6e6096e..6af5068 100644 --- a/plugin/qgistim/core/processing.py +++ b/plugin/qgistim/core/processing.py @@ -11,7 +11,6 @@ import numpy as np import processing -from PyQt5.QtCore import QDateTime, QVariant from qgis.analysis import QgsMeshContours from qgis.core import ( QgsFeature, @@ -24,6 +23,7 @@ QgsVectorLayer, QgsVectorLayerTemporalProperties, ) +from qgis.PyQt.QtCore import QDateTime, QVariant from qgistim.core import geopackage @@ -101,7 +101,7 @@ def steady_contours( geom = contourer.exportLines( qgs_index, value, - QgsMeshRendererScalarSettings.NeighbourAverage, + QgsMeshRendererScalarSettings.DataResamplingMethod.NeighbourAverage, ) if not geom.isNull(): feature_data.append(SteadyContourData(geom, value)) @@ -164,7 +164,7 @@ def transient_contours( geom = contourer.exportLines( qgs_index, value, - QgsMeshRendererScalarSettings.NeighbourAverage, + QgsMeshRendererScalarSettings.DataResamplingMethod.NeighbourAverage, ) if not geom.isNull(): mdal_time = layer.datasetMetadata( @@ -210,7 +210,7 @@ def set_temporal_properties(layer: QgsVectorLayer) -> None: temporal_properties.setStartField("datetime_start") temporal_properties.setEndField("datetime_end") temporal_properties.setMode( - QgsVectorLayerTemporalProperties.ModeFeatureDateTimeStartAndEndFromFields + QgsVectorLayerTemporalProperties.TemporalMode.ModeFeatureDateTimeStartAndEndFromFields ) temporal_properties.setIsActive(True) return diff --git a/plugin/qgistim/core/task.py b/plugin/qgistim/core/task.py index 58e2ca3..2c43762 100644 --- a/plugin/qgistim/core/task.py +++ b/plugin/qgistim/core/task.py @@ -5,7 +5,7 @@ class BaseServerTask(QgsTask): def __init__(self, parent, data, message_bar): - super().__init__(self.task_description, QgsTask.CanCancel) + super().__init__(self.task_description, QgsTask.Flag.CanCancel) self.parent = parent self.data = data self.message_bar = message_bar @@ -35,7 +35,7 @@ def push_success_message(self) -> None: self.message_bar.pushMessage( title="Info", text=self.success_message(), - level=Qgis.Info, + level=Qgis.MessageLevel.Info, ) return @@ -50,7 +50,7 @@ def push_failure_message(self) -> None: self.message_bar.pushMessage( title="Error", text=f"Failed {self.task_description}. Server error:\n{message}", - level=Qgis.Critical, + level=Qgis.MessageLevel.Critical, ) return diff --git a/plugin/qgistim/metadata.txt b/plugin/qgistim/metadata.txt index 8025e46..59bd0ed 100644 --- a/plugin/qgistim/metadata.txt +++ b/plugin/qgistim/metadata.txt @@ -5,8 +5,9 @@ [general] name=Qgis-Tim qgisMinimumVersion=3.40 +qgisMaximumVersion=4.99 description=QGIS plugin to setup Timflow multi-layer analytic elements -version=0.7.0.dev1 +version=0.7.0.dev2 author=Deltares email=huitebootsma@gmail.com @@ -21,6 +22,7 @@ repository=https://github.com/Deltares/QGIS-Tim hasProcessingProvider=no # Uncomment the following line and add your changelog: changelog=

0.7.0 + - Support QGIS 4.0 - Added particle tracking for steady-state simulations. - Use Timflow as computational core instead of TimML and TTim. - Clearer names for elements: diff --git a/plugin/qgistim/qgistim.py b/plugin/qgistim/qgistim.py index cd077a9..46ec48d 100644 --- a/plugin/qgistim/qgistim.py +++ b/plugin/qgistim/qgistim.py @@ -49,7 +49,9 @@ def toggle_tim(self): self.tim_widget = TimDockWidget("QGIS-Tim") self.tim_widget.setObjectName("QgisTimDock") - self.iface.addDockWidget(Qt.RightDockWidgetArea, self.tim_widget) + self.iface.addDockWidget( + Qt.DockWidgetArea.RightDockWidgetArea, self.tim_widget + ) widget = QgisTimWidget(self.tim_widget, self.iface) self.tim_widget.setWidget(widget) self.tim_widget.hide() diff --git a/plugin/qgistim/resources.py b/plugin/qgistim/resources.py index 7f04b7f..9261da0 100644 --- a/plugin/qgistim/resources.py +++ b/plugin/qgistim/resources.py @@ -6,7 +6,7 @@ # # WARNING! All changes made in this file will be lost! -from PyQt5 import QtCore +from qgis.PyQt import QtCore qt_resource_data = b"\ \x00\x00\x42\xa9\ diff --git a/plugin/qgistim/widgets/compute_widget.py b/plugin/qgistim/widgets/compute_widget.py index 055ae28..db565b8 100644 --- a/plugin/qgistim/widgets/compute_widget.py +++ b/plugin/qgistim/widgets/compute_widget.py @@ -2,30 +2,31 @@ from pathlib import Path from typing import NamedTuple, Tuple, Union -from PyQt5.QtCore import Qt -from PyQt5.QtWidgets import ( - QCheckBox, - QDoubleSpinBox, - QFileDialog, - QGroupBox, - QHBoxLayout, - QLabel, - QLineEdit, - QPushButton, - QVBoxLayout, - QWidget, -) from qgis.core import ( QgsApplication, QgsMapLayerProxyModel, QgsMeshDatasetIndex, QgsMeshLayer, + QgsMeshRendererScalarSettings, QgsProject, QgsRasterLayer, QgsTask, QgsVectorLayer, ) from qgis.gui import QgsMapLayerComboBox +from qgis.PyQt.QtCore import Qt +from qgis.PyQt.QtWidgets import ( + QCheckBox, + QDoubleSpinBox, + QFileDialog, + QGroupBox, + QHBoxLayout, + QLabel, + QLineEdit, + QPushButton, + QVBoxLayout, + QWidget, +) from qgistim.core import geopackage, layer_styling from qgistim.core.elements import ELEMENTS, parse_name @@ -130,7 +131,8 @@ def __init__(self, parent=None): self.contour_button.clicked.connect(self.redraw_contours) self.contour_layer = QgsMapLayerComboBox() self.contour_layer.setFilters( - QgsMapLayerProxyModel.MeshLayer | QgsMapLayerProxyModel.RasterLayer + QgsMapLayerProxyModel.Filter.MeshLayer + | QgsMapLayerProxyModel.Filter.RasterLayer ) self.contour_min_box = QDoubleSpinBox() self.contour_max_box = QDoubleSpinBox() @@ -183,9 +185,13 @@ def __init__(self, parent=None): contour_row1 = QHBoxLayout() to_label = QLabel("to") - to_label.setAlignment(Qt.AlignCenter | Qt.AlignVCenter) + to_label.setAlignment( + Qt.AlignmentFlag.AlignCenter | Qt.AlignmentFlag.AlignVCenter + ) step_label = QLabel("Step") - step_label.setAlignment(Qt.AlignRight | Qt.AlignVCenter) + step_label.setAlignment( + Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignVCenter + ) contour_row1.addWidget(self.contour_min_box) contour_row1.addWidget(to_label) contour_row1.addWidget(self.contour_max_box) @@ -392,7 +398,7 @@ def compute(self) -> None: self.start_task = self.parent.start_interpreter_task() if self.start_task is not None: self.compute_task.addSubTask( - self.start_task, [], QgsTask.ParentDependsOnSubTask + self.start_task, [], QgsTask.SubTaskDependency.ParentDependsOnSubTask ) self.set_interpreter_interaction(False) QgsApplication.taskManager().addTask(self.compute_task) @@ -439,7 +445,10 @@ def load_mesh_result(self, path: Union[Path, str], load_contours: bool) -> None: renderer.setActiveScalarDatasetGroup(index) scalar_settings = renderer.scalarSettings(index) - scalar_settings.setDataResamplingMethod(0) + no_resampling = ( + QgsMeshRendererScalarSettings.DataResamplingMethod.NoResampling + ) + scalar_settings.setDataResamplingMethod(no_resampling) renderer.setScalarSettings(index, scalar_settings) index_layer.setRendererSettings(renderer) diff --git a/plugin/qgistim/widgets/dataset_widget.py b/plugin/qgistim/widgets/dataset_widget.py index 9633666..023cefd 100644 --- a/plugin/qgistim/widgets/dataset_widget.py +++ b/plugin/qgistim/widgets/dataset_widget.py @@ -16,8 +16,9 @@ from shutil import copy from typing import Any, Dict, List, NamedTuple, Set, Tuple -from PyQt5.QtCore import Qt -from PyQt5.QtWidgets import ( +from qgis.core import Qgis, QgsEditFormConfig, QgsProject, QgsUnitTypes +from qgis.PyQt.QtCore import Qt +from qgis.PyQt.QtWidgets import ( QAbstractItemView, QCheckBox, QComboBox, @@ -34,7 +35,6 @@ QVBoxLayout, QWidget, ) -from qgis.core import Qgis, QgsProject, QgsUnitTypes from qgistim.core.elements import Aquifer, Domain, load_elements_from_geopackage from qgistim.core.formatting import data_to_json, data_to_script @@ -67,15 +67,15 @@ class Extraction(NamedTuple): class DatasetTreeWidget(QTreeWidget): def __init__(self, parent=None): super().__init__(parent) - self.setSelectionMode(QAbstractItemView.ExtendedSelection) + self.setSelectionMode(QAbstractItemView.SelectionMode.ExtendedSelection) self.setHeaderHidden(True) self.setSortingEnabled(True) - self.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Preferred) + self.setSizePolicy(QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Preferred) self.setHeaderLabels(["", "steady-state", "transient"]) self.setHeaderHidden(False) header = self.header() - header.setSectionResizeMode(1, QHeaderView.Stretch) - header.setSectionResizeMode(2, QHeaderView.Stretch) + header.setSectionResizeMode(1, QHeaderView.ResizeMode.Stretch) + header.setSectionResizeMode(2, QHeaderView.ResizeMode.Stretch) header.setSectionsMovable(False) self.setColumnCount(3) self.setColumnWidth(0, 1) @@ -165,10 +165,10 @@ def remove_geopackage_layers(self) -> None: self, "Deleting from Geopackage", f"Deleting:\n{message}", - QMessageBox.Yes | QMessageBox.No, - QMessageBox.No, + QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No, + QMessageBox.StandardButton.No, ) - if reply == QMessageBox.No: + if reply == QMessageBox.StandardButton.No: return # Start deleting @@ -282,7 +282,9 @@ def __init__(self, parent): self.dataset_tree = DatasetTreeWidget() self.model_crs = None self.start_task = None - self.dataset_tree.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Expanding) + self.dataset_tree.setSizePolicy( + QSizePolicy.Policy.Preferred, QSizePolicy.Policy.Expanding + ) self.dataset_line_edit = QLineEdit() self.dataset_line_edit.setEnabled(False) # Just used as a viewing port self.open_geopackage_button = QPushButton("Open") @@ -431,11 +433,13 @@ def new_geopackage(self) -> None: """ crs = self.parent.iface.mapCanvas().mapSettings().destinationCrs() if crs.mapUnits() not in ( - QgsUnitTypes.DistanceMeters, - QgsUnitTypes.DistanceFeet, + QgsUnitTypes.DistanceUnit.DistanceMeters, + QgsUnitTypes.DistanceUnit.DistanceFeet, ): msg = "Project Coordinate Reference System map units are not meters or feet" - self.parent.message_bar.pushMessage("Error", msg, level=Qgis.Critical) + self.parent.message_bar.pushMessage( + "Error", msg, level=Qgis.MessageLevel.Critical + ) return path, _ = QFileDialog.getSaveFileName(self, "Select file", "", "*.gpkg") @@ -462,7 +466,9 @@ def open_geopackage(self) -> None: self.load_geopackage() except: # noqa: E722 msg = f"GeoPackage is not valid QGIS-Tim model input: {path}" - self.parent.message_bar.pushMessage("Error", msg, level=Qgis.Critical) + self.parent.message_bar.pushMessage( + "Error", msg, level=Qgis.MessageLevel.Critical + ) self.dataset_line_edit.setText("") return @@ -493,7 +499,7 @@ def restore_geopackage(self) -> None: self.parent.message_bar.pushMessage( title="Error", text="Could not find a QGIS-Tim GeoPackage in this QGIS Project.", - level=Qgis.Critical, + level=Qgis.MessageLevel.Critical, ) return @@ -501,7 +507,7 @@ def restore_geopackage(self) -> None: self.parent.message_bar.pushMessage( title="Error", text=f"QGIS-Tim Geopackage {geopackage_path} does not exist.", - level=Qgis.Critical, + level=Qgis.MessageLevel.Critical, ) input_group_name, _ = qgs_project.readEntry("qgistim", "input_group") @@ -510,10 +516,10 @@ def restore_geopackage(self) -> None: self, "Restore Model from Project", f"Re-create Layers Panel group: {input_group_name}?", - QMessageBox.Yes | QMessageBox.No, - QMessageBox.No, + QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No, + QMessageBox.StandardButton.No, ) - if reply == QMessageBox.No: + if reply == QMessageBox.StandardButton.No: return self.dataset_line_edit.setText(geopackage_path) @@ -544,7 +550,11 @@ def suppress_popup_changed(self): layer = item.element.steady_layer if layer is not None: config = layer.editFormConfig() - config.setSuppress(suppress) + config.setSuppress( + QgsEditFormConfig.FeatureFormSuppress.SuppressOn + if suppress + else QgsEditFormConfig.FeatureFormSuppress.SuppressDefault + ) layer.setEditFormConfig(config) return @@ -614,7 +624,7 @@ def save_as_python(self) -> None: self.parent.message_bar.pushMessage( title="Info", text=f"Converted geopackage to Python script: {outpath}", - level=Qgis.Info, + level=Qgis.MessageLevel.Info, ) return @@ -661,7 +671,7 @@ def convert_to_json( self.parent.message_bar.pushMessage( title="Info", text=f"Converted geopackage to JSON: {path}", - level=Qgis.Info, + level=Qgis.MessageLevel.Info, ) return False diff --git a/plugin/qgistim/widgets/elements_widget.py b/plugin/qgistim/widgets/elements_widget.py index 1d8f04b..5f6ea6d 100644 --- a/plugin/qgistim/widgets/elements_widget.py +++ b/plugin/qgistim/widgets/elements_widget.py @@ -1,7 +1,7 @@ from functools import partial -from PyQt5.QtWidgets import QGridLayout, QPushButton, QVBoxLayout, QWidget from qgis.core import Qgis +from qgis.PyQt.QtWidgets import QGridLayout, QPushButton, QVBoxLayout, QWidget from qgistim.core.elements import ELEMENTS @@ -66,7 +66,9 @@ def tim_element(self, element_type: str) -> None: element = klass.dialog(self.parent.path, crs, self.parent.iface, names) except ValueError as e: msg = str(e) - self.parent.message_bar.pushMessage("Error", msg, level=Qgis.Critical) + self.parent.message_bar.pushMessage( + "Error", msg, level=Qgis.MessageLevel.Critical + ) return if element is None: # dialog cancelled diff --git a/plugin/qgistim/widgets/error_window.py b/plugin/qgistim/widgets/error_window.py index fc7be20..b3adc76 100644 --- a/plugin/qgistim/widgets/error_window.py +++ b/plugin/qgistim/widgets/error_window.py @@ -1,6 +1,12 @@ from typing import Any, Dict -from PyQt5.QtWidgets import QDialog, QHBoxLayout, QPushButton, QTextBrowser, QVBoxLayout +from qgis.PyQt.QtWidgets import ( + QDialog, + QHBoxLayout, + QPushButton, + QTextBrowser, + QVBoxLayout, +) def format_list(errors: Dict[str, Any]): diff --git a/plugin/qgistim/widgets/install_dialog.py b/plugin/qgistim/widgets/install_dialog.py index 4862156..b59862f 100644 --- a/plugin/qgistim/widgets/install_dialog.py +++ b/plugin/qgistim/widgets/install_dialog.py @@ -1,5 +1,6 @@ -from PyQt5.QtCore import Qt -from PyQt5.QtWidgets import ( +from qgis.core import Qgis, QgsApplication, QgsTask +from qgis.PyQt.QtCore import Qt +from qgis.PyQt.QtWidgets import ( QDialog, QFileDialog, QGridLayout, @@ -11,7 +12,6 @@ QPushButton, QVBoxLayout, ) -from qgis.core import Qgis, QgsApplication, QgsTask from qgistim.core.install_backend import install_from_github, install_from_zip @@ -25,7 +25,7 @@ def finished(self, result) -> None: self.message_bar.pushMessage( title="Info", text="Successfully installed timflow server", - level=Qgis.Info, + level=Qgis.MessageLevel.Info, ) else: if self.exception is not None: @@ -36,7 +36,7 @@ def finished(self, result) -> None: self.message_bar.pushMessage( title="Error", text=f"Failed to install timflow server. {message}", - level=Qgis.Critical, + level=Qgis.MessageLevel.Critical, ) return @@ -48,7 +48,7 @@ def cancel(self) -> None: class InstallZipTask(InstallTask): def __init__(self, parent, path: str, message_bar): - super().__init__("Install from ZIP file", QgsTask.CanCancel) + super().__init__("Install from ZIP file", QgsTask.Flag.CanCancel) self.parent = parent self.path = path self.message_bar = message_bar @@ -65,7 +65,7 @@ def run(self) -> bool: class InstallGithubTask(InstallTask): def __init__(self, parent, message_bar): - super().__init__("Install from GitHub", QgsTask.CanCancel) + super().__init__("Install from GitHub", QgsTask.Flag.CanCancel) self.parent = parent self.message_bar = message_bar self.exception = None @@ -126,7 +126,9 @@ def __init__(self, parent=None): layout.addWidget(version_group) layout.addWidget(github_group) layout.addWidget(zip_group) - layout.addWidget(self.close_button, stretch=0, alignment=Qt.AlignRight) + layout.addWidget( + self.close_button, stretch=0, alignment=Qt.AlignmentFlag.AlignRight + ) layout.addStretch() self.setLayout(layout) @@ -168,10 +170,10 @@ def install_from_zip(self) -> None: self, "Install from ZIP?", "This will install from the selected ZIP file. Continue?", - QMessageBox.Yes | QMessageBox.No, - QMessageBox.No, + QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No, + QMessageBox.StandardButton.No, ) - if reply == QMessageBox.No: + if reply == QMessageBox.StandardButton.No: return self.install_task = InstallZipTask( self, path=path, message_bar=self.parent.message_bar @@ -182,12 +184,12 @@ def install_from_zip(self) -> None: def install_from_github(self) -> None: reply = QMessageBox.question( self, - "Install from Github?", + "Install from GitHub?", "This will download and install the latest release from GitHub. Continue?", - QMessageBox.Yes | QMessageBox.No, - QMessageBox.No, + QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No, + QMessageBox.StandardButton.No, ) - if reply == QMessageBox.No: + if reply == QMessageBox.StandardButton.No: return self.install_task = InstallGithubTask(self, message_bar=self.parent.message_bar) self.enable_install_buttons(False) diff --git a/plugin/qgistim/widgets/tim_widget.py b/plugin/qgistim/widgets/tim_widget.py index a5d858d..2290cd5 100644 --- a/plugin/qgistim/widgets/tim_widget.py +++ b/plugin/qgistim/widgets/tim_widget.py @@ -8,15 +8,15 @@ from typing import Any, Dict, Union -from PyQt5.QtCore import Qt -from PyQt5.QtWidgets import ( +from qgis.core import QgsApplication, QgsEditFormConfig, QgsMapLayer, QgsProject +from qgis.PyQt.QtCore import Qt +from qgis.PyQt.QtWidgets import ( QPushButton, QTabWidget, QTreeWidgetItem, QVBoxLayout, QWidget, ) -from qgis.core import QgsApplication, QgsEditFormConfig, QgsMapLayer, QgsProject from qgistim.core.server_handler import ServerHandler from qgistim.core.task import BaseServerTask @@ -148,9 +148,9 @@ def add_layer( if suppress is not None: config = maplayer.editFormConfig() config.setSuppress( - QgsEditFormConfig.SuppressOn + QgsEditFormConfig.FeatureFormSuppress.SuppressOn if suppress - else QgsEditFormConfig.SuppressDefault + else QgsEditFormConfig.FeatureFormSuppress.SuppressDefault ) if renderer is not None: maplayer.setRenderer(renderer) @@ -219,7 +219,9 @@ def __init__(self, parent, iface): self.tabwidget.addTab(self.dataset_widget, "Model Manager") self.tabwidget.addTab(self.elements_widget, "Elements") self.tabwidget.addTab(self.compute_widget, "Results") - self.layout.addWidget(self.config_button, stretch=0, alignment=Qt.AlignRight) + self.layout.addWidget( + self.config_button, stretch=0, alignment=Qt.AlignmentFlag.AlignRight + ) self.setLayout(self.layout) # Default to the GeoPackage tab diff --git a/pyproject.toml b/pyproject.toml index d00201c..32300c4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,7 +6,7 @@ build-backend = "setuptools.build_meta" name = "gistim" description = "Connects timflow Analytic Element modeling to QGIS" readme = "README.md" -version = "0.7.0.dev1" +version = "0.7.0.dev2" maintainers = [{ name = "Huite Bootsma", email = "huite.bootsma@deltares.nl" }] requires-python = ">=3.11" dependencies = ['pandas', 'timflow>=0.2.0', 'xarray', 'numpy']