diff --git a/Dockerfile b/Dockerfile
index f9d68291f19..4623f87fb25 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,4 +1,7 @@
+# CACHE_TAG is provided by Docker cloud
+# see https://docs.docker.com/docker-cloud/builds/advanced/
+# using ARG in FROM requires min v17.05.0-ce
ARG CACHE_TAG=latest
FROM qgis/qgis3-build-deps:${CACHE_TAG}
diff --git a/README.md b/README.md
index 416dea14fbd..9cde4ff40be 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,7 @@
# About QGIS
[](https://travis-ci.org/qgis/QGIS)
+[](https://cloud.docker.com/app/qgis/repository/docker/qgis/qgis/general)
QGIS is an Open Source Geographic Information System. The project was born in
May of 2002 and was established as a project on SourceForge in June of the same
@@ -63,7 +64,7 @@ an email address where we can request additional information.
## Support
You can get support in the following ways:
- - Using the QGIS community site at http://qgis.org
+ - Using the QGIS community site at http://qgis.org
- Joining the [qgis-users mailing list](https://lists.osgeo.org/mailman/listinfo/qgis-user)
- Using IRC by joining the [#qgis](http://webchat.freenode.net/?channels=#qgis) channel on irc.freenode.net. Please wait around for a response to your question as many folks on the channel are doing other things and it may take a while for them to notice your question.
- Join the [Gitter](https://gitter.im/qgis/QGIS?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) chat.
diff --git a/debian/libqgis-dev.install.in b/debian/libqgis-dev.install.in
index effa246be06..f28dcc3e0aa 100644
--- a/debian/libqgis-dev.install.in
+++ b/debian/libqgis-dev.install.in
@@ -3,7 +3,8 @@ usr/lib/libqgis_app.so
usr/lib/libqgis_core.so
usr/lib/libqgis_gui.so
usr/lib/libqgis_analysis.so
-#server#usr/lib/libqgis_server.so
+usr/lib/libqgis_native.so
+usr/lib/libqgis_server.so
usr/lib/libqgisgrass{GRASSVER}.so
usr/lib/libqgispython.so
usr/share/qgis/FindQGIS.cmake
diff --git a/debian/qgis-common.install b/debian/qgis-common.install
index bd60a4ac005..c4e0539735d 100644
--- a/debian/qgis-common.install
+++ b/debian/qgis-common.install
@@ -12,6 +12,7 @@ usr/share/qgis/doc/images
usr/share/qgis/doc/index.html
usr/share/qgis/doc/news
usr/share/qgis/doc/news.html
+usr/share/qgis/doc/nohelp.html
usr/share/qgis/doc/style.css
usr/share/qgis/i18n/*
usr/share/qgis/images/*
diff --git a/debian/qgis.install b/debian/qgis.install
index 3c2521bc80a..b45db9e3fcd 100644
--- a/debian/qgis.install
+++ b/debian/qgis.install
@@ -6,7 +6,6 @@ usr/lib/qgis/plugins/libspatialqueryplugin.so
usr/lib/qgis/plugins/libofflineeditingplugin.so
usr/lib/qgis/plugins/libtopolplugin.so
usr/lib/qgis/plugins/libgeometrycheckerplugin.so
-usr/lib/qgis/qgis_help
usr/share/pixmaps/
usr/share/applications/
usr/share/mime/packages/
diff --git a/debian/qgis.lintian-overrides b/debian/qgis.lintian-overrides
deleted file mode 100644
index 72759f00cb8..00000000000
--- a/debian/qgis.lintian-overrides
+++ /dev/null
@@ -1,4 +0,0 @@
-# Build uses -D_FORTIFY_SOURCE=2, but hardening-check reports:
-# Fortify Source functions: no, only unprotected functions found!
-# unprotected: fgets
-qgis: hardening-no-fortify-functions usr/lib/qgis/qgis_help
diff --git a/doc/api_break.dox b/doc/api_break.dox
index 000f40309da..17e5773d269 100644
--- a/doc/api_break.dox
+++ b/doc/api_break.dox
@@ -269,6 +269,7 @@ should now call QgsCoordinateReferenceSystem::invalidateCache() and QgsCoordinat
- QgsFileNameWidgetWrapper was removed. Use QgsExternalResourceWidgetWrapper instead.
- QgsFileDropEdit was removed. Use QgsFileWidget instead.
- QgsFormAnnotationItem. Use QgsFormAnnotation instead.
+- QgsGeometryAnalyzer. Use the equivalent Processing algorithms instead.
- QgsHtmlAnnotationItem. Use QgsHtmlAnnotation instead.
- QgsHttpTransaction. This class was outdated and code should be ported to native Qt or Python implementations.
- QgsGenericProjectionSelector. Use QgsProjectionSelectionTreeWidget instead.
@@ -287,6 +288,7 @@ should now call QgsCoordinateReferenceSystem::invalidateCache() and QgsCoordinat
- QgsMapRenderer. It has been replaced by QgsMapRendererJob with subclasses and QgsMapSettings.
- QgsMapToolTouch. The touch navigation functionality is now built into the standard QgsMapToolPan tool.
- QgsPhotoWidgetWrapper was removed. Use QgsExternalResourceWidgetWrapper instead.
+- QgsPointSample. Use the Processing "Random Points in Polygon" algorithm instead.
- QgsPseudoColorShader. This shader has been broken for some time and was replaced by QgsSingleBandPseudoColorRenderer.
- QgsProjectBadLayerGuiHandler was removed. It was unused in QGIS code and barely useful. Implement your own QgsProjectBadLayerHandler subclass if needed.
- QgsRendererV2DataDefinedMenus was removed. Use QgsPropertyOverrideButton instead.
diff --git a/ms-windows/osgeo4w/package.cmd b/ms-windows/osgeo4w/package.cmd
index add5b0242b8..b26db6dcef4 100644
--- a/ms-windows/osgeo4w/package.cmd
+++ b/ms-windows/osgeo4w/package.cmd
@@ -384,7 +384,6 @@ tar -C %OSGEO4W_ROOT% -cjf %ARCH%/release/qgis/%PACKAGENAME%/%PACKAGENAME%-%VERS
"apps/%PACKAGENAME%/plugins/spatialqueryplugin.dll" ^
"apps/%PACKAGENAME%/plugins/topolplugin.dll" ^
"apps/%PACKAGENAME%/plugins/geometrycheckerplugin.dll" ^
- "apps/%PACKAGENAME%/qgis_help.exe" ^
"apps/%PACKAGENAME%/qtplugins/sqldrivers/qsqlspatialite.dll" ^
"apps/%PACKAGENAME%/qtplugins/designer/" ^
"apps/%PACKAGENAME%/python/" ^
diff --git a/python/analysis/analysis_auto.sip b/python/analysis/analysis_auto.sip
index 898598b2041..4966059b096 100644
--- a/python/analysis/analysis_auto.sip
+++ b/python/analysis/analysis_auto.sip
@@ -12,9 +12,6 @@
%Include raster/qgsrastermatrix.sip
%Include raster/qgsrastercalcnode.sip
%Include raster/qgstotalcurvaturefilter.sip
-%Include vector/qgsgeometryanalyzer.sip
-%Include vector/qgsoverlayanalyzer.sip
-%Include vector/qgspointsample.sip
%Include vector/qgstransectsample.sip
%Include vector/qgszonalstatistics.sip
%Include interpolation/qgsinterpolator.sip
diff --git a/python/analysis/vector/qgsgeometryanalyzer.sip b/python/analysis/vector/qgsgeometryanalyzer.sip
deleted file mode 100644
index 47f4a4a493e..00000000000
--- a/python/analysis/vector/qgsgeometryanalyzer.sip
+++ /dev/null
@@ -1,143 +0,0 @@
-/************************************************************************
- * This file has been generated automatically from *
- * *
- * src/analysis/vector/qgsgeometryanalyzer.h *
- * *
- * Do not edit manually ! Edit header and run scripts/sipify.pl again *
- ************************************************************************/
-
-
-
-
-
-
-class QgsGeometryAnalyzer
-{
-%Docstring
- The QGis class provides vector geometry analysis functions
-%End
-
-%TypeHeaderCode
-#include "qgsgeometryanalyzer.h"
-%End
- public:
-
- bool simplify( QgsVectorLayer *layer, const QString &shapefileName, double tolerance,
- bool onlySelectedFeatures = false, QProgressDialog *p = 0 );
-%Docstring
- Simplify vector layer using (a modified) Douglas-Peucker algorithm
- and write it to a new shape file
- \param layer input vector layer
- \param shapefileName path to the output shp
- \param tolerance (level of simplification)
- \param onlySelectedFeatures if true, only selected features are considered, else all the features
- \param p progress dialog (or 0 if no progress dialog is to be shown)
- :rtype: bool
-%End
-
- bool centroids( QgsVectorLayer *layer, const QString &shapefileName,
- bool onlySelectedFeatures = false, QProgressDialog *p = 0 );
-%Docstring
- Calculate the true centroids, or 'center of mass' for a vector layer and
- write it to a new shape file
- \param layer input vector layer
- \param shapefileName path to the output shp
- \param onlySelectedFeatures if true, only selected features are considered, else all the features
- \param p progress dialog (or 0 if no progress dialog is to be shown)
- :rtype: bool
-%End
-
- bool extent( QgsVectorLayer *layer, const QString &shapefileName, bool onlySelectedFeatures = false, QProgressDialog *p = 0 );
-%Docstring
- Create a polygon based on the extent of all (selected) features and write it to a new shape file
- \param layer input vector layer
- \param shapefileName path to the output shp
- \param onlySelectedFeatures if true, only selected features are considered, else all the features
- \param p progress dialog (or 0 if no progress dialog is to be shown)
- :rtype: bool
-%End
-
- bool buffer( QgsVectorLayer *layer, const QString &shapefileName, double bufferDistance,
- bool onlySelectedFeatures = false, bool dissolve = false, int bufferDistanceField = -1, QProgressDialog *p = 0 );
-%Docstring
- Create buffers for a vector layer and write it to a new shape file
- \param layer input vector layer
- \param shapefileName path to the output shp
- \param bufferDistance distance for buffering (if no buffer field is specified)
- \param onlySelectedFeatures if true, only selected features are considered, else all the features
- \param dissolve if true, merge all the buffers to a big multipolygon
- \param bufferDistanceField index of the attribute field that contains the buffer distance (or -1 if all features have the same buffer distance)
- \param p progress dialog (or 0 if no progress dialog is to be shown)
- :rtype: bool
-%End
-
- bool convexHull( QgsVectorLayer *layer, const QString &shapefileName, bool onlySelectedFeatures = false,
- int uniqueIdField = -1, QProgressDialog *p = 0 );
-%Docstring
- Create convex hull(s) of a vector layer and write it to a new shape file
- \param layer input vector layer
- \param shapefileName path to the output shp
- \param onlySelectedFeatures if true, only selected features are considered, else all the features
- \param uniqueIdField index of the attribute field that contains the unique convex hull id (or -1 if
- all features have the same buffer distance)
- \param p progress dialog (or 0 if no progress dialog is to be shown)
- :rtype: bool
-%End
-
- bool dissolve( QgsVectorLayer *layer, const QString &shapefileName, bool onlySelectedFeatures = false,
- int uniqueIdField = -1, QProgressDialog *p = 0 );
-%Docstring
- Dissolve a vector layer and write it to a new shape file
- \param layer input vector layer
- \param shapefileName path to the output shp
- \param onlySelectedFeatures if true, only selected features are considered, else all the features
- \param uniqueIdField index of the attribute field that contains the unique id to dissolve on (or -1 if
- all features should be dissolved together)
- \param p progress dialog (or 0 if no progress dialog is to be shown)
- :rtype: bool
-%End
-
- bool eventLayer( QgsVectorLayer *lineLayer, QgsVectorLayer *eventLayer, int lineField, int eventField, QgsFeatureIds &unlocatedFeatureIds /Out/, const QString &outputLayer,
- const QString &outputFormat, int locationField1, int locationField2 = -1, int offsetField = -1, double offsetScale = 1.0,
- bool forceSingleGeometry = false, QgsVectorDataProvider *memoryProvider = 0, QProgressDialog *p = 0 );
-%Docstring
- Creates an event layer (multipoint or multiline) by locating features from a (non-spatial) event table along the features of a line layer.
- Note that currently (until QgsGeometry supports m-values) the z-coordinate of the line layer is used for linear referencing
- \param lineLayer layer with the line geometry
- \param eventLayer layer with features and location field
- \param lineField join index in line layer
- \param eventField join index in event layer
- \param outputLayer name of output file (can be empty if a memory layer is used)
- \param outputFormat name of output format (can be empty if a memory provider is used to store the results)
- \param unlocatedFeatureIds out: ids of event features where linear referencing was not successful
- \param locationField1 attribute index of location field in event layer
- \param locationField2 attribute index of location end field (or -1 for point layer)
- \param offsetField attribute index for offset field. Negative offset value = offset to left side, positive value = offset to right side
- \param offsetScale factor to scale offset
- \param forceSingleGeometry force layer to single point/line type. Feature attributes are copied in case of multiple matches
- \param memoryProvider memory provider to write output to (can be 0 if output is written to a file)
- \param p progress dialog or 0 if no progress dialog should be shown
- :rtype: bool
-%End
-
- QgsGeometry locateBetweenMeasures( double fromMeasure, double toMeasure, const QgsGeometry &lineGeom );
-%Docstring
-Returns linear reference geometry as a multiline (or 0 if no match). Currently, the z-coordinates are considered to be the measures (no support for m-values in QGIS)
- :rtype: QgsGeometry
-%End
-
- QgsGeometry locateAlongMeasure( double measure, const QgsGeometry &lineGeom );
-%Docstring
- Returns linear reference geometry. Unlike the PostGIS function, this method always returns multipoint or 0 if no match (not geometry collection).
- Currently, the z-coordinates are considered to be the measures (no support for m-values in QGIS)
- :rtype: QgsGeometry
-%End
-
-};
-/************************************************************************
- * This file has been generated automatically from *
- * *
- * src/analysis/vector/qgsgeometryanalyzer.h *
- * *
- * Do not edit manually ! Edit header and run scripts/sipify.pl again *
- ************************************************************************/
diff --git a/python/analysis/vector/qgsoverlayanalyzer.sip b/python/analysis/vector/qgsoverlayanalyzer.sip
deleted file mode 100644
index fd550e1bca7..00000000000
--- a/python/analysis/vector/qgsoverlayanalyzer.sip
+++ /dev/null
@@ -1,46 +0,0 @@
-/************************************************************************
- * This file has been generated automatically from *
- * *
- * src/analysis/vector/qgsoverlayanalyzer.h *
- * *
- * Do not edit manually ! Edit header and run scripts/sipify.pl again *
- ************************************************************************/
-
-
-
-
-
-
-class QgsOverlayAnalyzer
-{
-%Docstring
- The QGis class provides vector overlay analysis functions
-%End
-
-%TypeHeaderCode
-#include "qgsoverlayanalyzer.h"
-%End
- public:
-
- bool intersection( QgsVectorLayer *layerA, QgsVectorLayer *layerB,
- const QString &shapefileName, bool onlySelectedFeatures = false,
- QProgressDialog *p = 0 );
-%Docstring
- Perform an intersection on two input vector layers and write output to a new shape file
-\param layerA input vector layer
-\param layerB input vector layer
-\param shapefileName path to the output shp
-\param onlySelectedFeatures if true, only selected features are considered, else all the features
-\param p progress dialog (or 0 if no progress dialog is to be shown)
- :rtype: bool
-%End
-
-};
-
-/************************************************************************
- * This file has been generated automatically from *
- * *
- * src/analysis/vector/qgsoverlayanalyzer.h *
- * *
- * Do not edit manually ! Edit header and run scripts/sipify.pl again *
- ************************************************************************/
diff --git a/python/analysis/vector/qgspointsample.sip b/python/analysis/vector/qgspointsample.sip
deleted file mode 100644
index f685510b82b..00000000000
--- a/python/analysis/vector/qgspointsample.sip
+++ /dev/null
@@ -1,38 +0,0 @@
-/************************************************************************
- * This file has been generated automatically from *
- * *
- * src/analysis/vector/qgspointsample.h *
- * *
- * Do not edit manually ! Edit header and run scripts/sipify.pl again *
- ************************************************************************/
-
-
-
-class QgsPointSample
-{
-%Docstring
- Creates random points in polygons / multipolygons*
-%End
-
-%TypeHeaderCode
-#include "qgspointsample.h"
-%End
- public:
- QgsPointSample( QgsVectorLayer *inputLayer, const QString &outputLayer, const QString &nPointsAttribute, const QString &minDistAttribute = QString() );
-
- int createRandomPoints( QProgressDialog *pd );
-%Docstring
- Starts calculation of random points
-:return: 0 in case of success*
- :rtype: int
-%End
-
-};
-
-/************************************************************************
- * This file has been generated automatically from *
- * *
- * src/analysis/vector/qgspointsample.h *
- * *
- * Do not edit manually ! Edit header and run scripts/sipify.pl again *
- ************************************************************************/
diff --git a/python/core/qgsapplication.sip b/python/core/qgsapplication.sip
index a6d1825cd78..8f051af9ceb 100644
--- a/python/core/qgsapplication.sip
+++ b/python/core/qgsapplication.sip
@@ -223,12 +223,6 @@ Returns the path to the licence file.
:rtype: str
%End
- static QString helpAppPath();
-%Docstring
-Returns the path to the help application.
- :rtype: str
-%End
-
static QString i18nPath();
%Docstring
Returns the path to the translation directory.
diff --git a/python/plugins/processing/algs/gdal/GdalAlgorithmProvider.py b/python/plugins/processing/algs/gdal/GdalAlgorithmProvider.py
index 2785aab2b93..28fa0e391c2 100644
--- a/python/plugins/processing/algs/gdal/GdalAlgorithmProvider.py
+++ b/python/plugins/processing/algs/gdal/GdalAlgorithmProvider.py
@@ -35,6 +35,7 @@ from .GdalUtils import GdalUtils
from .AssignProjection import AssignProjection
from .aspect import aspect
+from .buildvrt import buildvrt
from .ColorRelief import ColorRelief
from .tri import tri
from .warp import warp
@@ -44,7 +45,6 @@ from .nearblack import nearblack
# from .translate import translate
# from .pct2rgb import pct2rgb
# from .merge import merge
-# from .buildvrt import buildvrt
# from .polygonize import polygonize
# from .gdaladdo import gdaladdo
# from .ClipByExtent import ClipByExtent
@@ -144,6 +144,7 @@ class GdalAlgorithmProvider(QgsProcessingProvider):
# information(),
AssignProjection(),
aspect(),
+ buildvrt(),
ColorRelief(),
tri(),
warp(),
@@ -151,7 +152,6 @@ class GdalAlgorithmProvider(QgsProcessingProvider):
# rgb2pct(),
# pct2rgb(),
# merge(),
- # buildvrt(),
# polygonize(),
# gdaladdo(),
# ClipByExtent(),
diff --git a/python/plugins/processing/algs/gdal/buildvrt.py b/python/plugins/processing/algs/gdal/buildvrt.py
index 71fbc272db2..07d9afe2fd3 100644
--- a/python/plugins/processing/algs/gdal/buildvrt.py
+++ b/python/plugins/processing/algs/gdal/buildvrt.py
@@ -29,14 +29,16 @@ import os
from qgis.PyQt.QtGui import QIcon
-from qgis.core import QgsProcessingUtils
+from qgis.core import (QgsProcessing,
+ QgsProperty,
+ QgsProcessingParameterMultipleLayers,
+ QgsProcessingParameterEnum,
+ QgsProcessingParameterBoolean,
+ QgsProcessingParameterRasterDestination,
+ QgsProcessingOutputLayerDefinition,
+ QgsProcessingUtils)
from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm
-from processing.core.outputs import OutputRaster
-from processing.core.parameters import ParameterBoolean
-from processing.core.parameters import ParameterMultipleInput
-from processing.core.parameters import ParameterSelection
from processing.algs.gdal.GdalUtils import GdalUtils
-from processing.tools import dataobjects
pluginPath = os.path.split(os.path.split(os.path.dirname(__file__))[0])[0]
@@ -55,15 +57,27 @@ class buildvrt(GdalAlgorithm):
super().__init__()
def initAlgorithm(self, config=None):
- self.addParameter(ParameterMultipleInput(self.INPUT,
- self.tr('Input layers'), dataobjects.TYPE_RASTER))
- self.addParameter(ParameterSelection(self.RESOLUTION,
- self.tr('Resolution'), self.RESOLUTION_OPTIONS, 0))
- self.addParameter(ParameterBoolean(self.SEPARATE,
- self.tr('Layer stack'), True))
- self.addParameter(ParameterBoolean(self.PROJ_DIFFERENCE,
- self.tr('Allow projection difference'), False))
- self.addOutput(OutputRaster(buildvrt.OUTPUT, self.tr('Virtual')))
+
+ class ParameterVrtDestination(QgsProcessingParameterRasterDestination):
+
+ def __init__(self, name, description):
+ super().__init__(name, description)
+
+ def type(self):
+ return 'vrt_destination'
+
+ def defaultFileExtension(self):
+ return 'vrt'
+
+ self.addParameter(QgsProcessingParameterMultipleLayers(self.INPUT,
+ self.tr('Input layers'), QgsProcessing.TypeRaster))
+ self.addParameter(QgsProcessingParameterEnum(self.RESOLUTION,
+ self.tr('Resolution'), options=self.RESOLUTION_OPTIONS, defaultValue=0))
+ self.addParameter(QgsProcessingParameterBoolean(self.SEPARATE,
+ self.tr('Layer stack'), defaultValue=True))
+ self.addParameter(QgsProcessingParameterBoolean(self.PROJ_DIFFERENCE,
+ self.tr('Allow projection difference'), defaultValue=False))
+ self.addParameter(ParameterVrtDestination(self.OUTPUT, self.tr('Virtual')))
def name(self):
return 'buildvirtualraster'
@@ -80,25 +94,34 @@ class buildvrt(GdalAlgorithm):
def getConsoleCommands(self, parameters, context, feedback):
arguments = []
arguments.append('-resolution')
- arguments.append(self.RESOLUTION_OPTIONS[self.getParameterValue(self.RESOLUTION)])
- if self.getParameterValue(buildvrt.SEPARATE):
+ arguments.append(self.RESOLUTION_OPTIONS[self.parameterAsEnum(parameters, self.RESOLUTION, context)])
+ if self.parameterAsBool(parameters, buildvrt.SEPARATE, context):
arguments.append('-separate')
- if self.getParameterValue(buildvrt.PROJ_DIFFERENCE):
+ if self.parameterAsBool(parameters, buildvrt.PROJ_DIFFERENCE, context):
arguments.append('-allow_projection_difference')
# Always write input files to a text file in case there are many of them and the
# length of the command will be longer then allowed in command prompt
listFile = os.path.join(QgsProcessingUtils.tempFolder(), 'buildvrtInputFiles.txt')
with open(listFile, 'w') as f:
- f.write(self.getParameterValue(buildvrt.INPUT).replace(';', '\n'))
+ layers = []
+ for l in self.parameterAsLayerList(parameters, self.INPUT, context):
+ layers.append(l.source())
+ f.write('\n'.join(layers))
arguments.append('-input_file_list')
arguments.append(listFile)
- out = self.getOutputValue(buildvrt.OUTPUT)
+
+ out = self.parameterAsOutputLayer(parameters, self.OUTPUT, context)
# Ideally the file extensions should be limited to just .vrt but I'm not sure how
# to do it simply so instead a check is performed.
_, ext = os.path.splitext(out)
if not ext.lower() == '.vrt':
- out = out.replace(ext, '.vrt')
- self.setOutputValue(self.OUTPUT, out)
+ out = out[:-len(ext)] + '.vrt'
+ if isinstance(parameters[self.OUTPUT], QgsProcessingOutputLayerDefinition):
+ output_def = QgsProcessingOutputLayerDefinition(parameters[self.OUTPUT])
+ output_def.sink = QgsProperty.fromValue(out)
+ self.setOutputValue(self.OUTPUT, output_def)
+ else:
+ self.setOutputValue(self.OUTPUT, out)
arguments.append(out)
return ['gdalbuildvrt', GdalUtils.escapeAndJoin(arguments)]
diff --git a/python/plugins/processing/gui/MultipleInputDialog.py b/python/plugins/processing/gui/MultipleInputDialog.py
index a8fd860f02d..222f9e556fe 100644
--- a/python/plugins/processing/gui/MultipleInputDialog.py
+++ b/python/plugins/processing/gui/MultipleInputDialog.py
@@ -29,12 +29,17 @@ __revision__ = '$Format:%H$'
import os
-from qgis.core import QgsSettings
+from qgis.core import (QgsSettings,
+ QgsProcessing,
+ QgsVectorFileWriter,
+ QgsProviderRegistry,
+ QgsProcessingModelChildParameterSource)
from qgis.PyQt import uic
from qgis.PyQt.QtCore import Qt
from qgis.PyQt.QtCore import QByteArray
-from qgis.PyQt.QtWidgets import QDialog, QAbstractItemView, QPushButton, QDialogButtonBox
+from qgis.PyQt.QtWidgets import QDialog, QAbstractItemView, QPushButton, QDialogButtonBox, QFileDialog
from qgis.PyQt.QtGui import QStandardItemModel, QStandardItem
+from processing.tools import dataobjects
pluginPath = os.path.split(os.path.dirname(__file__))[0]
WIDGET, BASE = uic.loadUiType(
@@ -43,9 +48,11 @@ WIDGET, BASE = uic.loadUiType(
class MultipleInputDialog(BASE, WIDGET):
- def __init__(self, options, selectedoptions=None):
+ def __init__(self, options, selectedoptions=None, datatype=None):
super(MultipleInputDialog, self).__init__(None)
self.setupUi(self)
+ self.datatype = datatype
+ self.model = None
self.lstLayers.setSelectionMode(QAbstractItemView.NoSelection)
@@ -68,6 +75,11 @@ class MultipleInputDialog(BASE, WIDGET):
self.btnToggleSelection = QPushButton(self.tr('Toggle selection'))
self.buttonBox.addButton(self.btnToggleSelection,
QDialogButtonBox.ActionRole)
+ if self.datatype is not None:
+ btnAddFile = QPushButton(self.tr('Add file(s)…'))
+ btnAddFile.clicked.connect(self.addFiles)
+ self.buttonBox.addButton(btnAddFile,
+ QDialogButtonBox.ActionRole)
self.btnSelectAll.clicked.connect(lambda: self.selectAll(True))
self.btnClearSelection.clicked.connect(lambda: self.selectAll(False))
@@ -76,6 +88,7 @@ class MultipleInputDialog(BASE, WIDGET):
self.settings = QgsSettings()
self.restoreGeometry(self.settings.value("/Processing/multipleInputDialogGeometry", QByteArray()))
+ self.lstLayers.setSelectionMode(QAbstractItemView.ExtendedSelection)
self.populateList()
self.finished.connect(self.saveWindowGeometry)
@@ -83,15 +96,26 @@ class MultipleInputDialog(BASE, WIDGET):
self.settings.setValue("/Processing/multipleInputDialogGeometry", self.saveGeometry())
def populateList(self):
- model = QStandardItemModel()
+ self.model = QStandardItemModel()
for value, text in self.options:
item = QStandardItem(text)
item.setData(value, Qt.UserRole)
item.setCheckState(Qt.Checked if value in self.selectedoptions else Qt.Unchecked)
item.setCheckable(True)
- model.appendRow(item)
+ self.model.appendRow(item)
- self.lstLayers.setModel(model)
+ # add extra options (e.g. manually added layers)
+ for t in [o for o in self.selectedoptions if not isinstance(o, int)]:
+ if isinstance(t, QgsProcessingModelChildParameterSource):
+ item = QStandardItem(t.staticValue())
+ else:
+ item = QStandardItem(t)
+ item.setData(item.text(), Qt.UserRole)
+ item.setCheckState(Qt.Checked)
+ item.setCheckable(True)
+ self.model.appendRow(item)
+
+ self.lstLayers.setModel(self.model)
def accept(self):
self.selectedoptions = []
@@ -106,15 +130,56 @@ class MultipleInputDialog(BASE, WIDGET):
self.selectedoptions = None
QDialog.reject(self)
+ def getItemsToModify(self):
+ items = []
+ if len(self.lstLayers.selectedIndexes()) > 1:
+ for i in self.lstLayers.selectedIndexes():
+ items.append(self.model.itemFromIndex(i))
+ else:
+ for i in range(self.model.rowCount()):
+ items.append(self.model.item(i))
+ return items
+
def selectAll(self, value):
- model = self.lstLayers.model()
- for i in range(model.rowCount()):
- item = model.item(i)
+ for item in self.getItemsToModify():
item.setCheckState(Qt.Checked if value else Qt.Unchecked)
def toggleSelection(self):
- model = self.lstLayers.model()
- for i in range(model.rowCount()):
- item = model.item(i)
+ for item in self.getItemsToModify():
checked = item.checkState() == Qt.Checked
item.setCheckState(Qt.Unchecked if checked else Qt.Checked)
+
+ def getFileFilter(self, datatype):
+ """
+ Returns a suitable file filter pattern for the specified parameter definition
+ :param param:
+ :return:
+ """
+ if datatype == QgsProcessing.TypeRaster:
+ return QgsProviderRegistry.instance().fileRasterFilters()
+ elif datatype == QgsProcessing.TypeFile:
+ return self.tr('All files (*.*)')
+ else:
+ exts = QgsVectorFileWriter.supportedFormatExtensions()
+ for i in range(len(exts)):
+ exts[i] = self.tr('{0} files (*.{1})').format(exts[i].upper(), exts[i].lower())
+ return self.tr('All files (*.*)') + ';;' + ';;'.join(exts)
+
+ def addFiles(self):
+ filter = self.getFileFilter(self.datatype)
+
+ settings = QgsSettings()
+ path = str(settings.value('/Processing/LastInputPath'))
+
+ ret, selected_filter = QFileDialog.getOpenFileNames(self, self.tr('Select file(s)'),
+ path, filter)
+ if ret:
+ files = list(ret)
+ settings.setValue('/Processing/LastInputPath',
+ os.path.dirname(str(files[0])))
+ for filename in files:
+ item = QStandardItem(filename)
+ item.setData(filename, Qt.UserRole)
+ item.setCheckState(Qt.Checked)
+ item.setCheckable(True)
+ self.model.appendRow(item)
diff --git a/python/plugins/processing/gui/MultipleInputPanel.py b/python/plugins/processing/gui/MultipleInputPanel.py
index c33a6a6535f..7ac7e85274f 100644
--- a/python/plugins/processing/gui/MultipleInputPanel.py
+++ b/python/plugins/processing/gui/MultipleInputPanel.py
@@ -28,9 +28,10 @@ __revision__ = '$Format:%H$'
import os
+from qgis.core import QgsProcessing
from qgis.PyQt import uic
from qgis.PyQt.QtCore import pyqtSignal
-
+''
from processing.gui.MultipleInputDialog import MultipleInputDialog
from processing.gui.MultipleFileInputDialog import MultipleFileInputDialog
@@ -63,10 +64,10 @@ class MultipleInputPanel(BASE, WIDGET):
self.tr('{0} elements selected').format(len(self.selectedoptions)))
def showSelectionDialog(self):
- if self.datatype is None:
- dlg = MultipleInputDialog(self.options, self.selectedoptions)
- else:
+ if self.datatype == QgsProcessing.TypeFile:
dlg = MultipleFileInputDialog(self.selectedoptions)
+ else:
+ dlg = MultipleInputDialog(self.options, self.selectedoptions, datatype=self.datatype)
dlg.exec_()
if dlg.selectedoptions is not None:
self.selectedoptions = dlg.selectedoptions
@@ -76,12 +77,15 @@ class MultipleInputPanel(BASE, WIDGET):
def updateForOptions(self, options):
selectedoptions = []
- selected = [self.options[i] for i in self.selectedoptions]
+ selected = [self.options[i] if isinstance(i, int) else i for i in self.selectedoptions]
for sel in selected:
- try:
- idx = options.index(sel)
- selectedoptions.append(idx)
- except ValueError:
- pass
+ if isinstance(sel, int):
+ try:
+ idx = options.index(sel)
+ selectedoptions.append(idx)
+ except ValueError:
+ pass
+ else:
+ selectedoptions.append(sel)
self.options = options
self.setSelectedItems(selectedoptions)
diff --git a/python/plugins/processing/gui/wrappers.py b/python/plugins/processing/gui/wrappers.py
index 9f8eecc13f9..db431077aca 100644
--- a/python/plugins/processing/gui/wrappers.py
+++ b/python/plugins/processing/gui/wrappers.py
@@ -69,6 +69,7 @@ from qgis.core import (
QgsProcessingOutputVectorLayer,
QgsProcessingOutputString,
QgsProcessingOutputNumber,
+ QgsProcessingModelChildParameterSource,
QgsProcessingModelAlgorithm)
from qgis.PyQt.QtWidgets import (
@@ -524,20 +525,20 @@ class MultipleInputWidgetWrapper(WidgetWrapper):
def _getOptions(self):
if self.param.layerType() == QgsProcessing.TypeVectorAny:
- options = self.dialog.getAvailableValuesOfType(QgsProcessingParameterFeatureSource, QgsProcessingOutputVectorLayer)
+ options = self.dialog.getAvailableValuesOfType((QgsProcessingParameterFeatureSource, QgsProcessingParameterVectorLayer, QgsProcessingParameterMultipleLayers), QgsProcessingOutputVectorLayer)
elif self.param.layerType() == QgsProcessing.TypeVectorPoint:
- options = self.dialog.getAvailableValuesOfType(QgsProcessingParameterFeatureSource, QgsProcessingOutputVectorLayer,
+ options = self.dialog.getAvailableValuesOfType((QgsProcessingParameterFeatureSource, QgsProcessingParameterVectorLayer, QgsProcessingParameterMultipleLayers), QgsProcessingOutputVectorLayer,
[QgsProcessing.TypeVectorPoint, QgsProcessing.TypeVectorAny])
elif self.param.layerType() == QgsProcessing.TypeVectorLine:
- options = self.dialog.getAvailableValuesOfType(QgsProcessingParameterFeatureSource, QgsProcessingOutputVectorLayer,
+ options = self.dialog.getAvailableValuesOfType((QgsProcessingParameterFeatureSource, QgsProcessingParameterVectorLayer, QgsProcessingParameterMultipleLayers), QgsProcessingOutputVectorLayer,
[QgsProcessing.TypeVectorLine, QgsProcessing.TypeVectorAny])
elif self.param.layerType() == QgsProcessing.TypeVectorPolygon:
- options = self.dialog.getAvailableValuesOfType(QgsProcessingParameterFeatureSource, QgsProcessingOutputVectorLayer,
+ options = self.dialog.getAvailableValuesOfType((QgsProcessingParameterFeatureSource, QgsProcessingParameterVectorLayer, QgsProcessingParameterMultipleLayers), QgsProcessingOutputVectorLayer,
[QgsProcessing.TypeVectorPolygon, QgsProcessing.TypeVectorAny])
elif self.param.layerType() == QgsProcessing.TypeRaster:
- options = self.dialog.getAvailableValuesOfType(QgsProcessingParameterRasterLayer, QgsProcessingOutputRasterLayer)
+ options = self.dialog.getAvailableValuesOfType((QgsProcessingParameterRasterLayer, QgsProcessingParameterMultipleLayers), QgsProcessingOutputRasterLayer)
elif self.param.layerType() == QgsProcessing.TypeTable:
- options = self.dialog.getAvailableValuesOfType(QgsProcessingParameterVectorLayer, OutputTable)
+ options = self.dialog.getAvailableValuesOfType((QgsProcessingParameterFeatureSource, QgsProcessingParameterVectorLayer, QgsProcessingParameterMultipleLayers), OutputTable)
else:
options = self.dialog.getAvailableValuesOfType(QgsProcessingParameterFile, OutputFile)
options = sorted(options, key=lambda opt: self.dialog.resolveValueDescription(opt))
@@ -546,7 +547,7 @@ class MultipleInputWidgetWrapper(WidgetWrapper):
def createWidget(self):
if self.dialogType == DIALOG_STANDARD:
if self.param.layerType() == QgsProcessing.TypeFile:
- return MultipleInputPanel(datatype=dataobjects.TYPE_FILE)
+ return MultipleInputPanel(datatype=QgsProcessing.TypeFile)
else:
if self.param.layerType() == QgsProcessing.TypeRaster:
options = QgsProcessingUtils.compatibleRasterLayers(QgsProject.instance(), False)
@@ -555,14 +556,14 @@ class MultipleInputWidgetWrapper(WidgetWrapper):
else:
options = QgsProcessingUtils.compatibleVectorLayers(QgsProject.instance(), [self.param.layerType()], False)
opts = [getExtendedLayerName(opt) for opt in options]
- return MultipleInputPanel(opts)
+ return MultipleInputPanel(opts, datatype=self.param.layerType())
elif self.dialogType == DIALOG_BATCH:
widget = BatchInputSelectionPanel(self.param, self.row, self.col, self.dialog)
widget.valueChanged.connect(lambda: self.widgetValueHasChanged.emit(self))
return widget
else:
options = [self.dialog.resolveValueDescription(opt) for opt in self._getOptions()]
- return MultipleInputPanel(options)
+ return MultipleInputPanel(options, datatype=self.param.layerType())
def refresh(self):
if self.param.layerType() != QgsProcessing.TypeFile:
@@ -582,11 +583,20 @@ class MultipleInputWidgetWrapper(WidgetWrapper):
return self.widget.setText(value)
else:
options = self._getOptions()
- selected = []
- for i, opt in enumerate(options):
- if opt in value:
- selected.append(i)
- self.widget.setSelectedItems(selected)
+
+ if not isinstance(value, (tuple, list)):
+ value = [value]
+
+ selected_options = []
+ for sel in value:
+ if sel in options:
+ selected_options.append(options.index(sel))
+ elif isinstance(sel, QgsProcessingModelChildParameterSource):
+ selected_options.append(sel.staticValue())
+ else:
+ selected_options.append(sel)
+
+ self.widget.setSelectedItems(selected_options)
def value(self):
if self.dialogType == DIALOG_STANDARD:
@@ -599,12 +609,12 @@ class MultipleInputWidgetWrapper(WidgetWrapper):
options = QgsProcessingUtils.compatibleVectorLayers(QgsProject.instance(), [], False)
else:
options = QgsProcessingUtils.compatibleVectorLayers(QgsProject.instance(), [self.param.layerType()], False)
- return [options[i] for i in self.widget.selectedoptions]
+ return [options[i] if isinstance(i, int) else i for i in self.widget.selectedoptions]
elif self.dialogType == DIALOG_BATCH:
return self.widget.getText()
else:
options = self._getOptions()
- values = [options[i] for i in self.widget.selectedoptions]
+ values = [options[i] if isinstance(i, int) else QgsProcessingModelChildParameterSource.fromStaticValue(i) for i in self.widget.selectedoptions]
if len(values) == 0 and not self.param.flags() & QgsProcessing.FlagOptional:
raise InvalidParameterValue()
return values
diff --git a/python/plugins/processing/modeler/ModelerParametersDialog.py b/python/plugins/processing/modeler/ModelerParametersDialog.py
index 08d29209b43..536b20ac79c 100644
--- a/python/plugins/processing/modeler/ModelerParametersDialog.py
+++ b/python/plugins/processing/modeler/ModelerParametersDialog.py
@@ -44,6 +44,7 @@ from qgis.core import (QgsProcessingParameterDefinition,
QgsProcessingModelChildAlgorithm,
QgsProcessingModelChildParameterSource,
QgsProcessingParameterFeatureSink,
+ QgsProcessingParameterMultipleLayers,
QgsProcessingParameterRasterDestination,
QgsProcessingParameterFileDestination,
QgsProcessingParameterFolderDestination,
@@ -236,11 +237,11 @@ class ModelerParametersDialog(QDialog):
# upgrade paramType to list
if paramType is None:
paramType = []
- elif not isinstance(paramType, list):
+ elif not isinstance(paramType, (tuple, list)):
paramType = [paramType]
if outTypes is None:
outTypes = []
- elif not isinstance(outTypes, list):
+ elif not isinstance(outTypes, (tuple, list)):
outTypes = [outTypes]
return self.model.availableSourcesForChild(self.childId, [p.typeName() for p in paramType if issubclass(p, QgsProcessingParameterDefinition)],
diff --git a/src/analysis/CMakeLists.txt b/src/analysis/CMakeLists.txt
index 6aa593fbae8..072f6f3dd3c 100644
--- a/src/analysis/CMakeLists.txt
+++ b/src/analysis/CMakeLists.txt
@@ -35,12 +35,9 @@ SET(QGIS_ANALYSIS_SRCS
raster/qgsrastercalculator.cpp
raster/qgsrastermatrix.cpp
vector/mersenne-twister.cpp
- vector/qgsgeometryanalyzer.cpp
vector/qgsgeometrysnapper.cpp
- vector/qgspointsample.cpp
vector/qgstransectsample.cpp
vector/qgszonalstatistics.cpp
- vector/qgsoverlayanalyzer.cpp
openstreetmap/qgsosmbase.cpp
openstreetmap/qgsosmdatabase.cpp
@@ -116,9 +113,6 @@ SET(QGIS_ANALYSIS_HDRS
raster/qgsrastercalcnode.h
raster/qgstotalcurvaturefilter.h
- vector/qgsgeometryanalyzer.h
- vector/qgsoverlayanalyzer.h
- vector/qgspointsample.h
vector/qgstransectsample.h
vector/qgszonalstatistics.h
diff --git a/src/analysis/vector/qgsgeometryanalyzer.cpp b/src/analysis/vector/qgsgeometryanalyzer.cpp
deleted file mode 100644
index ddfcb087ef9..00000000000
--- a/src/analysis/vector/qgsgeometryanalyzer.cpp
+++ /dev/null
@@ -1,1493 +0,0 @@
-/***************************************************************************
- qgsgeometryanalyzer.cpp - QGIS Tools for vector geometry analysis
- -------------------
- begin : 19 March 2009
- copyright : (C) Carson Farmer
- email : carson.farmer@gmail.com
- ***************************************************************************/
-
-/***************************************************************************
- * *
- * 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. *
- * *
- ***************************************************************************/
-
-#include "qgsgeometryanalyzer.h"
-
-#include "qgsapplication.h"
-#include "qgsfields.h"
-#include "qgsfeature.h"
-#include "qgsfeatureiterator.h"
-#include "qgslogger.h"
-#include "qgscoordinatereferencesystem.h"
-#include "qgsvectorfilewriter.h"
-#include "qgsvectordataprovider.h"
-#include "qgsdistancearea.h"
-#include "qgis.h"
-#include "qgsvectorlayer.h"
-
-#include
-
-bool QgsGeometryAnalyzer::simplify( QgsVectorLayer *layer,
- const QString &shapefileName,
- double tolerance,
- bool onlySelectedFeatures,
- QProgressDialog *p )
-{
- if ( !layer )
- {
- return false;
- }
-
- QgsVectorDataProvider *dp = layer->dataProvider();
- if ( !dp )
- {
- return false;
- }
-
- QgsWkbTypes::Type outputType = dp->wkbType();
- QgsCoordinateReferenceSystem crs = layer->crs();
-
- QgsVectorFileWriter vWriter( shapefileName, dp->encoding(), layer->fields(), outputType, crs );
- QgsFeature currentFeature;
-
- //take only selection
- if ( onlySelectedFeatures )
- {
- //use QgsVectorLayer::featureAtId
- const QgsFeatureIds selection = layer->selectedFeatureIds();
- if ( p )
- {
- p->setMaximum( selection.size() );
- }
-
- int processedFeatures = 0;
- QgsFeatureIds::const_iterator it = selection.constBegin();
- for ( ; it != selection.constEnd(); ++it )
- {
- if ( p )
- {
- p->setValue( processedFeatures );
- }
-
- if ( p && p->wasCanceled() )
- {
- break;
- }
- if ( !layer->getFeatures( QgsFeatureRequest().setFilterFid( *it ) ).nextFeature( currentFeature ) )
- {
- continue;
- }
- simplifyFeature( currentFeature, &vWriter, tolerance );
- ++processedFeatures;
- }
-
- if ( p )
- {
- p->setValue( selection.size() );
- }
- }
- //take all features
- else
- {
- QgsFeatureIterator fit = layer->getFeatures();
-
- int featureCount = layer->featureCount();
- if ( p )
- {
- p->setMaximum( featureCount );
- }
- int processedFeatures = 0;
-
- while ( fit.nextFeature( currentFeature ) )
- {
- if ( p )
- {
- p->setValue( processedFeatures );
- }
- if ( p && p->wasCanceled() )
- {
- break;
- }
- simplifyFeature( currentFeature, &vWriter, tolerance );
- ++processedFeatures;
- }
- if ( p )
- {
- p->setValue( featureCount );
- }
- }
-
- return true;
-}
-
-void QgsGeometryAnalyzer::simplifyFeature( QgsFeature &f, QgsVectorFileWriter *vfw, double tolerance )
-{
- if ( !f.hasGeometry() )
- {
- return;
- }
-
- QgsGeometry featureGeometry = f.geometry();
-
- // simplify feature
- QgsGeometry tmpGeometry = featureGeometry.simplify( tolerance );
-
- QgsFeature newFeature;
- newFeature.setGeometry( tmpGeometry );
- newFeature.setAttributes( f.attributes() );
-
- //add it to vector file writer
- if ( vfw )
- {
- vfw->addFeature( newFeature );
- }
-}
-
-bool QgsGeometryAnalyzer::centroids( QgsVectorLayer *layer, const QString &shapefileName,
- bool onlySelectedFeatures, QProgressDialog *p )
-{
- if ( !layer )
- {
- QgsDebugMsg( "No layer passed to centroids" );
- return false;
- }
-
- QgsVectorDataProvider *dp = layer->dataProvider();
- if ( !dp )
- {
- QgsDebugMsg( "No data provider for layer passed to centroids" );
- return false;
- }
-
- QgsWkbTypes::Type outputType = QgsWkbTypes::Point;
- QgsCoordinateReferenceSystem crs = layer->crs();
-
- QgsVectorFileWriter vWriter( shapefileName, dp->encoding(), layer->fields(), outputType, crs );
- QgsFeature currentFeature;
-
- //take only selection
- if ( onlySelectedFeatures )
- {
- //use QgsVectorLayer::featureAtId
- const QgsFeatureIds selection = layer->selectedFeatureIds();
- if ( p )
- {
- p->setMaximum( selection.size() );
- }
-
- int processedFeatures = 0;
- QgsFeatureIds::const_iterator it = selection.constBegin();
- for ( ; it != selection.constEnd(); ++it )
- {
- if ( p )
- {
- p->setValue( processedFeatures );
- }
-
- if ( p && p->wasCanceled() )
- {
- break;
- }
- if ( !layer->getFeatures( QgsFeatureRequest().setFilterFid( *it ) ).nextFeature( currentFeature ) )
- {
- continue;
- }
- centroidFeature( currentFeature, &vWriter );
- ++processedFeatures;
- }
-
- if ( p )
- {
- p->setValue( selection.size() );
- }
- }
- //take all features
- else
- {
- QgsFeatureIterator fit = layer->getFeatures( QgsFeatureRequest().setSubsetOfAttributes( QgsAttributeList() ) );
-
- int featureCount = layer->featureCount();
- if ( p )
- {
- p->setMaximum( featureCount );
- }
- int processedFeatures = 0;
-
- while ( fit.nextFeature( currentFeature ) )
- {
- if ( p )
- {
- p->setValue( processedFeatures );
- }
- if ( p && p->wasCanceled() )
- {
- break;
- }
- centroidFeature( currentFeature, &vWriter );
- ++processedFeatures;
- }
- if ( p )
- {
- p->setValue( featureCount );
- }
- }
-
- return true;
-}
-
-
-void QgsGeometryAnalyzer::centroidFeature( QgsFeature &f, QgsVectorFileWriter *vfw )
-{
- if ( !f.hasGeometry() )
- {
- return;
- }
-
- QgsGeometry featureGeometry = f.geometry();
- QgsFeature newFeature;
- newFeature.setGeometry( featureGeometry.centroid() );
- newFeature.setAttributes( f.attributes() );
-
- //add it to vector file writer
- if ( vfw )
- {
- vfw->addFeature( newFeature );
- }
-}
-
-bool QgsGeometryAnalyzer::extent( QgsVectorLayer *layer,
- const QString &shapefileName,
- bool onlySelectedFeatures,
- QProgressDialog * )
-{
- if ( !layer )
- {
- return false;
- }
-
- QgsVectorDataProvider *dp = layer->dataProvider();
- if ( !dp )
- {
- return false;
- }
-
- QgsWkbTypes::Type outputType = QgsWkbTypes::Polygon;
- QgsCoordinateReferenceSystem crs = layer->crs();
-
- QgsFields fields;
- fields.append( QgsField( QStringLiteral( "MINX" ), QVariant::Double ) );
- fields.append( QgsField( QStringLiteral( "MINY" ), QVariant::Double ) );
- fields.append( QgsField( QStringLiteral( "MAXX" ), QVariant::Double ) );
- fields.append( QgsField( QStringLiteral( "MAXY" ), QVariant::Double ) );
- fields.append( QgsField( QStringLiteral( "CNTX" ), QVariant::Double ) );
- fields.append( QgsField( QStringLiteral( "CNTY" ), QVariant::Double ) );
- fields.append( QgsField( QStringLiteral( "AREA" ), QVariant::Double ) );
- fields.append( QgsField( QStringLiteral( "PERIM" ), QVariant::Double ) );
- fields.append( QgsField( QStringLiteral( "HEIGHT" ), QVariant::Double ) );
- fields.append( QgsField( QStringLiteral( "WIDTH" ), QVariant::Double ) );
-
- QgsVectorFileWriter vWriter( shapefileName, dp->encoding(), fields, outputType, crs );
-
- QgsRectangle rect;
- if ( onlySelectedFeatures ) // take only selection
- {
- rect = layer->boundingBoxOfSelected();
- }
- else
- {
- rect = layer->extent();
- }
-
- double minx = rect.xMinimum();
- double miny = rect.yMinimum();
- double maxx = rect.xMaximum();
- double maxy = rect.yMaximum();
- double height = rect.height();
- double width = rect.width();
- double cntx = minx + ( width / 2.0 );
- double cnty = miny + ( height / 2.0 );
- double area = width * height;
- double perim = ( 2 * width ) + ( 2 * height );
-
- QgsFeature feat;
- QgsAttributes attrs( 10 );
- attrs[0] = QVariant( minx );
- attrs[1] = QVariant( miny );
- attrs[2] = QVariant( maxx );
- attrs[3] = QVariant( maxy );
- attrs[4] = QVariant( cntx );
- attrs[5] = QVariant( cnty );
- attrs[6] = QVariant( area );
- attrs[7] = QVariant( perim );
- attrs[8] = QVariant( height );
- attrs[9] = QVariant( width );
- feat.setAttributes( attrs );
- feat.setGeometry( QgsGeometry::fromRect( rect ) );
- vWriter.addFeature( feat );
- return true;
-}
-
-QList QgsGeometryAnalyzer::simpleMeasure( QgsGeometry &mpGeometry )
-{
- QList list;
- double perim;
- if ( mpGeometry.wkbType() == QgsWkbTypes::Point )
- {
- QgsPointXY pt = mpGeometry.asPoint();
- list.append( pt.x() );
- list.append( pt.y() );
- }
- else
- {
- QgsDistanceArea measure;
- list.append( measure.measureArea( mpGeometry ) );
- if ( mpGeometry.type() == QgsWkbTypes::PolygonGeometry )
- {
- perim = perimeterMeasure( mpGeometry, measure );
- list.append( perim );
- }
- }
- return list;
-}
-
-double QgsGeometryAnalyzer::perimeterMeasure( const QgsGeometry &geometry, QgsDistanceArea &measure )
-{
- return measure.measurePerimeter( geometry );
-}
-
-bool QgsGeometryAnalyzer::convexHull( QgsVectorLayer *layer, const QString &shapefileName,
- bool onlySelectedFeatures, int uniqueIdField, QProgressDialog *p )
-{
- if ( !layer )
- {
- return false;
- }
- QgsVectorDataProvider *dp = layer->dataProvider();
- if ( !dp )
- {
- return false;
- }
- bool useField = false;
- if ( uniqueIdField == -1 )
- {
- uniqueIdField = 0;
- }
- else
- {
- useField = true;
- }
- QgsFields fields;
- fields.append( QgsField( QStringLiteral( "UID" ), QVariant::String ) );
- fields.append( QgsField( QStringLiteral( "AREA" ), QVariant::Double ) );
- fields.append( QgsField( QStringLiteral( "PERIM" ), QVariant::Double ) );
-
- QgsWkbTypes::Type outputType = QgsWkbTypes::Polygon;
- QgsCoordinateReferenceSystem crs = layer->crs();
-
- QgsVectorFileWriter vWriter( shapefileName, dp->encoding(), fields, outputType, crs );
- QgsFeature currentFeature;
- QgsGeometry dissolveGeometry; //dissolve geometry
- QMultiMap map;
-
- if ( onlySelectedFeatures )
- {
- //use QgsVectorLayer::featureAtId
- const QgsFeatureIds selection = layer->selectedFeatureIds();
- QgsFeatureIds::const_iterator it = selection.constBegin();
- for ( ; it != selection.constEnd(); ++it )
- {
-#if 0
- if ( p )
- {
- p->setValue( processedFeatures );
- }
- if ( p && p->wasCanceled() )
- {
- // break; // it may be better to do something else here?
- return false;
- }
-#endif
- if ( !layer->getFeatures( QgsFeatureRequest().setFilterFid( *it ) ).nextFeature( currentFeature ) )
- {
- continue;
- }
- map.insert( currentFeature.attribute( uniqueIdField ).toString(), currentFeature.id() );
- }
- }
- else
- {
- QgsFeatureIterator fit = layer->getFeatures();
- while ( fit.nextFeature( currentFeature ) )
- {
-#if 0
- if ( p )
- {
- p->setValue( processedFeatures );
- }
- if ( p && p->wasCanceled() )
- {
- // break; // it may be better to do something else here?
- return false;
- }
-#endif
- map.insert( currentFeature.attribute( uniqueIdField ).toString(), currentFeature.id() );
- }
- }
-
- QMultiMap::const_iterator jt = map.constBegin();
- while ( jt != map.constEnd() )
- {
- QString currentKey = jt.key();
- int processedFeatures = 0;
- //take only selection
- if ( onlySelectedFeatures )
- {
- //use QgsVectorLayer::featureAtId
- const QgsFeatureIds selection = layer->selectedFeatureIds();
- if ( p )
- {
- p->setMaximum( selection.size() );
- }
- processedFeatures = 0;
- while ( jt != map.constEnd() && ( jt.key() == currentKey || !useField ) )
- {
- if ( p && p->wasCanceled() )
- {
- break;
- }
- if ( selection.contains( jt.value() ) )
- {
- if ( p )
- {
- p->setValue( processedFeatures );
- }
- if ( !layer->getFeatures( QgsFeatureRequest().setFilterFid( jt.value() ) ).nextFeature( currentFeature ) )
- {
- continue;
- }
- convexFeature( currentFeature, processedFeatures, dissolveGeometry );
- ++processedFeatures;
- }
- ++jt;
- }
- QList values;
- if ( dissolveGeometry.isNull() )
- {
- QgsDebugMsg( "no dissolved geometry - should not happen" );
- return false;
- }
- dissolveGeometry = dissolveGeometry.convexHull();
- values = simpleMeasure( dissolveGeometry );
- QgsAttributes attributes( 3 );
- attributes[0] = QVariant( currentKey );
- attributes[1] = values.at( 0 );
- attributes[2] = values.at( 1 );
- QgsFeature dissolveFeature;
- dissolveFeature.setAttributes( attributes );
- dissolveFeature.setGeometry( dissolveGeometry );
- vWriter.addFeature( dissolveFeature );
- }
- //take all features
- else
- {
- int featureCount = layer->featureCount();
- if ( p )
- {
- p->setMaximum( featureCount );
- }
- processedFeatures = 0;
- while ( jt != map.constEnd() && ( jt.key() == currentKey || !useField ) )
- {
- if ( p )
- {
- p->setValue( processedFeatures );
- }
-
- if ( p && p->wasCanceled() )
- {
- break;
- }
- if ( !layer->getFeatures( QgsFeatureRequest().setFilterFid( jt.value() ) ).nextFeature( currentFeature ) )
- {
- continue;
- }
- convexFeature( currentFeature, processedFeatures, dissolveGeometry );
- ++processedFeatures;
- ++jt;
- }
- QList values;
- if ( dissolveGeometry.isNull() )
- {
- QgsDebugMsg( "no dissolved geometry - should not happen" );
- return false;
- }
- dissolveGeometry = dissolveGeometry.convexHull();
- // values = simpleMeasure( tmpGeometry );
- values = simpleMeasure( dissolveGeometry );
- QgsAttributes attributes;
- attributes[0] = QVariant( currentKey );
- attributes[1] = QVariant( values[ 0 ] );
- attributes[2] = QVariant( values[ 1 ] );
- QgsFeature dissolveFeature;
- dissolveFeature.setAttributes( attributes );
- dissolveFeature.setGeometry( dissolveGeometry );
- vWriter.addFeature( dissolveFeature );
- }
- }
- return true;
-}
-
-
-void QgsGeometryAnalyzer::convexFeature( QgsFeature &f, int nProcessedFeatures, QgsGeometry &dissolveGeometry )
-{
- if ( !f.hasGeometry() )
- {
- return;
- }
-
- QgsGeometry featureGeometry = f.geometry();
- QgsGeometry convexGeometry = featureGeometry.convexHull();
-
- if ( nProcessedFeatures == 0 )
- {
- dissolveGeometry = convexGeometry;
- }
- else
- {
- dissolveGeometry = dissolveGeometry.combine( convexGeometry );
- }
-}
-
-bool QgsGeometryAnalyzer::dissolve( QgsVectorLayer *layer, const QString &shapefileName,
- bool onlySelectedFeatures, int uniqueIdField, QProgressDialog *p )
-{
- if ( !layer )
- {
- return false;
- }
- QgsVectorDataProvider *dp = layer->dataProvider();
- if ( !dp )
- {
- return false;
- }
- bool useField = false;
- if ( uniqueIdField == -1 )
- {
- uniqueIdField = 0;
- }
- else
- {
- useField = true;
- }
-
- QgsWkbTypes::Type outputType = dp->wkbType();
- QgsCoordinateReferenceSystem crs = layer->crs();
-
- QgsVectorFileWriter vWriter( shapefileName, dp->encoding(), layer->fields(), outputType, crs );
- QgsFeature currentFeature;
- QMultiMap map;
-
- if ( onlySelectedFeatures )
- {
- //use QgsVectorLayer::featureAtId
- const QgsFeatureIds selection = layer->selectedFeatureIds();
- QgsFeatureIds::const_iterator it = selection.constBegin();
- for ( ; it != selection.constEnd(); ++it )
- {
- if ( !layer->getFeatures( QgsFeatureRequest().setFilterFid( *it ) ).nextFeature( currentFeature ) )
- {
- continue;
- }
- map.insert( currentFeature.attribute( uniqueIdField ).toString(), currentFeature.id() );
- }
- }
- else
- {
- QgsFeatureIterator fit = layer->getFeatures();
- while ( fit.nextFeature( currentFeature ) )
- {
- map.insert( currentFeature.attribute( uniqueIdField ).toString(), currentFeature.id() );
- }
- }
-
- QgsGeometry dissolveGeometry; //dissolve geometry
- QMultiMap::const_iterator jt = map.constBegin();
- QgsFeature outputFeature;
- while ( jt != map.constEnd() )
- {
- QString currentKey = jt.key();
- int processedFeatures = 0;
- bool first = true;
- //take only selection
- if ( onlySelectedFeatures )
- {
- //use QgsVectorLayer::featureAtId
- const QgsFeatureIds selection = layer->selectedFeatureIds();
- if ( p )
- {
- p->setMaximum( selection.size() );
- }
- while ( jt != map.constEnd() && ( jt.key() == currentKey || !useField ) )
- {
- if ( p && p->wasCanceled() )
- {
- break;
- }
- if ( selection.contains( jt.value() ) )
- {
- if ( p )
- {
- p->setValue( processedFeatures );
- }
- if ( !layer->getFeatures( QgsFeatureRequest().setFilterFid( jt.value() ) ).nextFeature( currentFeature ) )
- {
- continue;
- }
- if ( first )
- {
- outputFeature.setAttributes( currentFeature.attributes() );
- first = false;
- }
- dissolveGeometry = dissolveFeature( currentFeature, dissolveGeometry );
- ++processedFeatures;
- }
- ++jt;
- }
- }
- //take all features
- else
- {
- int featureCount = layer->featureCount();
- if ( p )
- {
- p->setMaximum( featureCount );
- }
- while ( jt != map.constEnd() && ( jt.key() == currentKey || !useField ) )
- {
- if ( p )
- {
- p->setValue( processedFeatures );
- }
-
- if ( p && p->wasCanceled() )
- {
- break;
- }
- if ( !layer->getFeatures( QgsFeatureRequest().setFilterFid( jt.value() ) ).nextFeature( currentFeature ) )
- {
- continue;
- }
- {
- outputFeature.setAttributes( currentFeature.attributes() );
- first = false;
- }
- dissolveGeometry = dissolveFeature( currentFeature, dissolveGeometry );
- ++processedFeatures;
- ++jt;
- }
- }
- outputFeature.setGeometry( dissolveGeometry );
- vWriter.addFeature( outputFeature );
- }
- return true;
-}
-
-QgsGeometry QgsGeometryAnalyzer::dissolveFeature( const QgsFeature &f, const QgsGeometry &dissolveInto )
-{
- if ( !f.hasGeometry() )
- {
- return dissolveInto;
- }
-
- QgsGeometry featureGeometry = f.geometry();
-
- if ( dissolveInto.isNull() )
- {
- return featureGeometry;
- }
- else
- {
- return dissolveInto.combine( featureGeometry );
- }
-}
-
-bool QgsGeometryAnalyzer::buffer( QgsVectorLayer *layer, const QString &shapefileName, double bufferDistance,
- bool onlySelectedFeatures, bool dissolve, int bufferDistanceField, QProgressDialog *p )
-{
- if ( !layer )
- {
- return false;
- }
-
- QgsVectorDataProvider *dp = layer->dataProvider();
- if ( !dp )
- {
- return false;
- }
-
- QgsWkbTypes::Type outputType = QgsWkbTypes::Polygon;
- if ( dissolve )
- {
- outputType = QgsWkbTypes::MultiPolygon;
- }
- QgsCoordinateReferenceSystem crs = layer->crs();
-
- QgsVectorFileWriter vWriter( shapefileName, dp->encoding(), layer->fields(), outputType, crs );
- QgsFeature currentFeature;
- QgsGeometry dissolveGeometry; //dissolve geometry (if dissolve enabled)
-
- //take only selection
- if ( onlySelectedFeatures )
- {
- //use QgsVectorLayer::featureAtId
- const QgsFeatureIds selection = layer->selectedFeatureIds();
- if ( p )
- {
- p->setMaximum( selection.size() );
- }
-
- int processedFeatures = 0;
- QgsFeatureIds::const_iterator it = selection.constBegin();
- for ( ; it != selection.constEnd(); ++it )
- {
- if ( p )
- {
- p->setValue( processedFeatures );
- }
-
- if ( p && p->wasCanceled() )
- {
- break;
- }
- if ( !layer->getFeatures( QgsFeatureRequest().setFilterFid( *it ) ).nextFeature( currentFeature ) )
- {
- continue;
- }
- bufferFeature( currentFeature, processedFeatures, &vWriter, dissolve, dissolveGeometry, bufferDistance, bufferDistanceField );
- ++processedFeatures;
- }
-
- if ( p )
- {
- p->setValue( selection.size() );
- }
- }
- //take all features
- else
- {
- QgsFeatureIterator fit = layer->getFeatures();
-
- int featureCount = layer->featureCount();
- if ( p )
- {
- p->setMaximum( featureCount );
- }
- int processedFeatures = 0;
-
- while ( fit.nextFeature( currentFeature ) )
- {
- if ( p )
- {
- p->setValue( processedFeatures );
- }
- if ( p && p->wasCanceled() )
- {
- break;
- }
- bufferFeature( currentFeature, processedFeatures, &vWriter, dissolve, dissolveGeometry, bufferDistance, bufferDistanceField );
- ++processedFeatures;
- }
- if ( p )
- {
- p->setValue( featureCount );
- }
- }
-
- if ( dissolve )
- {
- QgsFeature dissolveFeature;
- if ( dissolveGeometry.isNull() )
- {
- QgsDebugMsg( "no dissolved geometry - should not happen" );
- return false;
- }
- dissolveFeature.setGeometry( dissolveGeometry );
- vWriter.addFeature( dissolveFeature );
- }
- return true;
-}
-
-void QgsGeometryAnalyzer::bufferFeature( QgsFeature &f, int nProcessedFeatures, QgsVectorFileWriter *vfw, bool dissolve,
- QgsGeometry &dissolveGeometry, double bufferDistance, int bufferDistanceField )
-{
- if ( !f.hasGeometry() )
- {
- return;
- }
-
- double currentBufferDistance;
- QgsGeometry featureGeometry = f.geometry();
- QgsGeometry bufferGeometry;
-
- //create buffer
- if ( bufferDistanceField == -1 )
- {
- currentBufferDistance = bufferDistance;
- }
- else
- {
- currentBufferDistance = f.attribute( bufferDistanceField ).toDouble();
- }
- bufferGeometry = featureGeometry.buffer( currentBufferDistance, 5 );
-
- if ( dissolve )
- {
- if ( nProcessedFeatures == 0 )
- {
- dissolveGeometry = bufferGeometry;
- }
- else
- {
- dissolveGeometry = dissolveGeometry.combine( bufferGeometry );
- }
- }
- else //dissolve
- {
- QgsFeature newFeature;
- newFeature.setGeometry( bufferGeometry );
- newFeature.setAttributes( f.attributes() );
-
- //add it to vector file writer
- if ( vfw )
- {
- vfw->addFeature( newFeature );
- }
- }
-}
-
-bool QgsGeometryAnalyzer::eventLayer( QgsVectorLayer *lineLayer, QgsVectorLayer *eventLayer, int lineField, int eventField, QgsFeatureIds &unlocatedFeatureIds, const QString &outputLayer,
- const QString &outputFormat, int locationField1, int locationField2, int offsetField, double offsetScale,
- bool forceSingleGeometry, QgsVectorDataProvider *memoryProvider, QProgressDialog *p )
-{
- if ( !lineLayer || !eventLayer || !lineLayer->isValid() || !eventLayer->isValid() )
- {
- return false;
- }
-
- //create line field / id map for line layer
- QMultiHash< QString, QgsFeature > lineLayerIdMap; //1:n possible (e.g. several linear reference geometries for one feature in the event layer)
- QgsFeatureIterator fit = lineLayer->getFeatures( QgsFeatureRequest().setSubsetOfAttributes( QgsAttributeList() << lineField ) );
- QgsFeature fet;
- while ( fit.nextFeature( fet ) )
- {
- lineLayerIdMap.insert( fet.attribute( lineField ).toString(), fet );
- }
-
- //create output datasource or attributes in memory provider
- QgsVectorFileWriter *fileWriter = nullptr;
- QgsFeatureList memoryProviderFeatures;
- if ( !memoryProvider )
- {
- QgsWkbTypes::Type memoryProviderType = QgsWkbTypes::MultiLineString;
- if ( locationField2 == -1 )
- {
- memoryProviderType = forceSingleGeometry ? QgsWkbTypes::Point : QgsWkbTypes::MultiPoint;
- }
- else
- {
- memoryProviderType = forceSingleGeometry ? QgsWkbTypes::LineString : QgsWkbTypes::MultiLineString;
- }
- fileWriter = new QgsVectorFileWriter( outputLayer,
- eventLayer->dataProvider()->encoding(),
- eventLayer->fields(),
- memoryProviderType,
- lineLayer->crs(),
- outputFormat );
- }
- else
- {
- memoryProvider->addAttributes( eventLayer->fields().toList() );
- }
-
- //iterate over eventLayer and write new features to output file or layer
- fit = eventLayer->getFeatures( QgsFeatureRequest().setFlags( QgsFeatureRequest::NoGeometry ) );
- QgsGeometry lrsGeom;
- double measure1, measure2 = 0.0;
-
- int nEventFeatures = eventLayer->featureCount();
- int featureCounter = 0;
- int nOutputFeatures = 0; //number of output features for the current event feature
- if ( p )
- {
- p->setWindowModality( Qt::WindowModal );
- p->setMinimum( 0 );
- p->setMaximum( nEventFeatures );
- p->show();
- }
-
- while ( fit.nextFeature( fet ) )
- {
- nOutputFeatures = 0;
-
- //update progress dialog
- if ( p )
- {
- if ( p->wasCanceled() )
- {
- break;
- }
- p->setValue( featureCounter );
- ++featureCounter;
- }
-
- measure1 = fet.attribute( locationField1 ).toDouble();
- if ( locationField2 != -1 )
- {
- measure2 = fet.attribute( locationField2 ).toDouble();
- if ( qgsDoubleNear( ( measure2 - measure1 ), 0.0 ) )
- {
- continue;
- }
- }
-
- QList featureIdList = lineLayerIdMap.values( fet.attribute( eventField ).toString() );
- QList::iterator featureIdIt = featureIdList.begin();
- for ( ; featureIdIt != featureIdList.end(); ++featureIdIt )
- {
- if ( locationField2 == -1 )
- {
- lrsGeom = locateAlongMeasure( measure1, featureIdIt->geometry() );
- }
- else
- {
- lrsGeom = locateBetweenMeasures( measure1, measure2, featureIdIt->geometry() );
- }
-
- if ( !lrsGeom.isNull() )
- {
- ++nOutputFeatures;
- addEventLayerFeature( fet, lrsGeom, featureIdIt->geometry(), fileWriter, memoryProviderFeatures, offsetField, offsetScale, forceSingleGeometry );
- }
- }
- if ( nOutputFeatures < 1 )
- {
- unlocatedFeatureIds.insert( fet.id() );
- }
- }
-
- if ( p )
- {
- p->setValue( nEventFeatures );
- }
-
- if ( memoryProvider )
- {
- memoryProvider->addFeatures( memoryProviderFeatures );
- }
- delete fileWriter;
- return true;
-}
-
-void QgsGeometryAnalyzer::addEventLayerFeature( QgsFeature &feature, const QgsGeometry &geom, const QgsGeometry &lineGeom, QgsVectorFileWriter *fileWriter, QgsFeatureList &memoryFeatures,
- int offsetField, double offsetScale, bool forceSingleType )
-{
- if ( geom.isNull() )
- {
- return;
- }
-
- QList geomList;
- if ( forceSingleType )
- {
- geomList = geom.asGeometryCollection();
- }
- else
- {
- geomList.push_back( geom );
- }
-
- QList::iterator geomIt = geomList.begin();
- for ( ; geomIt != geomList.end(); ++geomIt )
- {
- //consider offset
- QgsGeometry newGeom = *geomIt;
- if ( offsetField >= 0 )
- {
- double offsetVal = feature.attribute( offsetField ).toDouble();
- offsetVal *= offsetScale;
- newGeom = createOffsetGeometry( *geomIt, lineGeom, offsetVal );
- if ( newGeom.isNull() )
- {
- continue;
- }
- }
-
- feature.setGeometry( newGeom );
- if ( fileWriter )
- {
- fileWriter->addFeature( feature );
- }
- else
- {
- memoryFeatures << feature;
- }
- }
-}
-
-QgsGeometry QgsGeometryAnalyzer::createOffsetGeometry( const QgsGeometry &geom, const QgsGeometry &lineGeom, double offset )
-{
- if ( !geom || lineGeom.isNull() )
- {
- return QgsGeometry();
- }
-
- QList inputGeomList;
-
- if ( geom.isMultipart() )
- {
- inputGeomList = geom.asGeometryCollection();
- }
- else
- {
- inputGeomList.push_back( geom );
- }
-
- QList outputGeomList;
- QList::const_iterator inputGeomIt = inputGeomList.constBegin();
- GEOSContextHandle_t geosctxt = QgsGeometry::getGEOSHandler();
- for ( ; inputGeomIt != inputGeomList.constEnd(); ++inputGeomIt )
- {
- if ( geom.type() == QgsWkbTypes::LineGeometry )
- {
- GEOSGeometry *inputGeomItGeos = inputGeomIt->exportToGeos();
- GEOSGeometry *offsetGeom = GEOSOffsetCurve_r( geosctxt, inputGeomItGeos, -offset, 8 /*quadSegments*/, 0 /*joinStyle*/, 5.0 /*miterLimit*/ );
- GEOSGeom_destroy_r( geosctxt, inputGeomItGeos );
- if ( !offsetGeom || !GEOSisValid_r( geosctxt, offsetGeom ) )
- {
- return QgsGeometry();
- }
- if ( !GEOSisValid_r( geosctxt, offsetGeom ) || GEOSGeomTypeId_r( geosctxt, offsetGeom ) != GEOS_LINESTRING || GEOSGeomGetNumPoints_r( geosctxt, offsetGeom ) < 1 )
- {
- GEOSGeom_destroy_r( geosctxt, offsetGeom );
- return QgsGeometry();
- }
- outputGeomList.push_back( offsetGeom );
- }
- else if ( geom.type() == QgsWkbTypes::PointGeometry )
- {
- QgsPointXY p = ( *inputGeomIt ).asPoint();
- p = createPointOffset( p.x(), p.y(), offset, lineGeom );
- GEOSCoordSequence *ptSeq = GEOSCoordSeq_create_r( geosctxt, 1, 2 );
- GEOSCoordSeq_setX_r( geosctxt, ptSeq, 0, p.x() );
- GEOSCoordSeq_setY_r( geosctxt, ptSeq, 0, p.y() );
- GEOSGeometry *geosPt = GEOSGeom_createPoint_r( geosctxt, ptSeq );
- outputGeomList.push_back( geosPt );
- }
- }
-
- QgsGeometry outGeometry;
- if ( !geom.isMultipart() )
- {
- GEOSGeometry *outputGeom = outputGeomList.at( 0 );
- if ( outputGeom )
- {
- outGeometry.fromGeos( outputGeom );
- }
- }
- else
- {
- GEOSGeometry **geomArray = new GEOSGeometry*[outputGeomList.size()];
- for ( int i = 0; i < outputGeomList.size(); ++i )
- {
- geomArray[i] = outputGeomList.at( i );
- }
- GEOSGeometry *collection = nullptr;
- if ( geom.type() == QgsWkbTypes::PointGeometry )
- {
- collection = GEOSGeom_createCollection_r( geosctxt, GEOS_MULTIPOINT, geomArray, outputGeomList.size() );
- }
- else if ( geom.type() == QgsWkbTypes::LineGeometry )
- {
- collection = GEOSGeom_createCollection_r( geosctxt, GEOS_MULTILINESTRING, geomArray, outputGeomList.size() );
- }
- outGeometry.fromGeos( collection );
- delete[] geomArray;
- }
- return outGeometry;
-}
-
-QgsPointXY QgsGeometryAnalyzer::createPointOffset( double x, double y, double dist, const QgsGeometry &lineGeom ) const
-{
- QgsPointXY p( x, y );
- QgsPointXY minDistPoint;
- int afterVertexNr;
- lineGeom.closestSegmentWithContext( p, minDistPoint, afterVertexNr );
-
- int beforeVertexNr = afterVertexNr - 1;
- QgsPointXY beforeVertex = lineGeom.vertexAt( beforeVertexNr );
- QgsPointXY afterVertex = lineGeom.vertexAt( afterVertexNr );
-
- //get normal vector
- double dx = afterVertex.x() - beforeVertex.x();
- double dy = afterVertex.y() - beforeVertex.y();
- double normalX = -dy;
- double normalY = dx; //#spellok
- double normalLength = sqrt( normalX * normalX + normalY * normalY ); //#spellok
- normalX *= ( dist / normalLength );
- normalY *= ( dist / normalLength ); //#spellok
-
- double debugLength = sqrt( normalX * normalX + normalY * normalY ); //control //#spellok
- Q_UNUSED( debugLength );
- return QgsPointXY( x - normalX, y - normalY ); //negative values -> left side, positive values -> right side //#spellok
-}
-
-QgsGeometry QgsGeometryAnalyzer::locateBetweenMeasures( double fromMeasure, double toMeasure, const QgsGeometry &lineGeom )
-{
- if ( lineGeom.isNull() )
- {
- return QgsGeometry();
- }
-
- QgsMultiPolyline resultGeom;
-
- //need to go with WKB and z coordinate until QgsGeometry supports M values
- QByteArray wkb( lineGeom.exportToWkb() );
- QgsConstWkbPtr wkbPtr( wkb );
- wkbPtr.readHeader();
-
- QgsWkbTypes::Type wkbType = lineGeom.wkbType();
- if ( wkbType != QgsWkbTypes::LineString25D && wkbType != QgsWkbTypes::MultiLineString25D )
- {
- return QgsGeometry();
- }
-
- if ( wkbType == QgsWkbTypes::LineString25D )
- {
- locateBetweenWkbString( wkbPtr, resultGeom, fromMeasure, toMeasure );
- }
- else if ( wkbType == QgsWkbTypes::MultiLineString25D )
- {
- int nLines;
- wkbPtr >> nLines;
- for ( int i = 0; i < nLines; ++i )
- {
- wkbPtr.readHeader();
- wkbPtr = locateBetweenWkbString( wkbPtr, resultGeom, fromMeasure, toMeasure );
- }
- }
-
- if ( resultGeom.size() < 1 )
- {
- return QgsGeometry();
- }
- return QgsGeometry::fromMultiPolyline( resultGeom );
-}
-
-QgsGeometry QgsGeometryAnalyzer::locateAlongMeasure( double measure, const QgsGeometry &lineGeom )
-{
- if ( lineGeom.isNull() )
- {
- return QgsGeometry();
- }
-
- QgsMultiPoint resultGeom;
-
- //need to go with WKB and z coordinate until QgsGeometry supports M values
- QByteArray wkb( lineGeom.exportToWkb() );
- QgsConstWkbPtr wkbPtr( wkb );
- QgsWkbTypes::Type wkbType = lineGeom.wkbType();
-
- if ( wkbType != QgsWkbTypes::LineString25D && wkbType != QgsWkbTypes::MultiLineString25D )
- {
- return QgsGeometry();
- }
-
- if ( wkbType == QgsWkbTypes::LineString25D )
- {
- locateAlongWkbString( wkbPtr, resultGeom, measure );
- }
- else if ( wkbType == QgsWkbTypes::MultiLineString25D )
- {
- int nLines;
- wkbPtr >> nLines;
- for ( int i = 0; i < nLines; ++i )
- {
- wkbPtr.readHeader();
- wkbPtr = locateAlongWkbString( wkbPtr, resultGeom, measure );
- }
- }
-
- if ( resultGeom.size() < 1 )
- {
- return QgsGeometry();
- }
-
- return QgsGeometry::fromMultiPoint( resultGeom );
-}
-
-QgsConstWkbPtr QgsGeometryAnalyzer::locateBetweenWkbString( QgsConstWkbPtr wkbPtr, QgsMultiPolyline &result, double fromMeasure, double toMeasure )
-{
- int nPoints;
- wkbPtr >> nPoints;
-
- QgsPolyline currentLine;
- double prevx = 0.0, prevy = 0.0, prevz = 0.0;
- for ( int i = 0; i < nPoints; ++i )
- {
- double x, y, z;
- wkbPtr >> x >> y >> z;
-
- if ( i > 0 )
- {
- QgsPointXY pt1, pt2;
- bool secondPointClipped; //true if second point is != segment endpoint
- bool measureInSegment = clipSegmentByRange( prevx, prevy, prevz, x, y, z, fromMeasure, toMeasure, pt1, pt2, secondPointClipped );
- if ( measureInSegment )
- {
- if ( currentLine.size() < 1 ) //no points collected yet, so the first point needs to be added to the line
- {
- currentLine.append( pt1 );
- }
-
- if ( pt1 != pt2 ) //avoid duplicated entry if measure value equals m-value of vertex
- {
- currentLine.append( pt2 );
- }
-
- if ( secondPointClipped || i == nPoints - 1 ) //close current segment
- {
- if ( currentLine.size() > 1 )
- {
- result.append( currentLine );
- }
- currentLine.clear();
- }
- }
- }
- prevx = x;
- prevy = y;
- prevz = z;
- }
-
- return wkbPtr;
-}
-
-QgsConstWkbPtr QgsGeometryAnalyzer::locateAlongWkbString( QgsConstWkbPtr wkbPtr, QgsMultiPoint &result, double measure )
-{
- int nPoints;
- wkbPtr >> nPoints;
-
- double x, y, z;
- double prevx = 0.0, prevy = 0.0, prevz = 0.0;
- for ( int i = 0; i < nPoints; ++i )
- {
- wkbPtr >> x >> y >> z;
-
- if ( i > 0 )
- {
- QgsPointXY pt1, pt2;
- bool pt1Ok, pt2Ok;
- locateAlongSegment( prevx, prevy, prevz, x, y, z, measure, pt1Ok, pt1, pt2Ok, pt2 );
- if ( pt1Ok )
- {
- result.append( pt1 );
- }
- if ( pt2Ok && i == nPoints - 1 )
- {
- result.append( pt2 );
- }
- }
- prevx = x;
- prevy = y;
- prevz = z;
- }
-
- return wkbPtr;
-}
-
-bool QgsGeometryAnalyzer::clipSegmentByRange( double x1, double y1, double m1, double x2, double y2, double m2, double range1, double range2, QgsPointXY &pt1,
- QgsPointXY &pt2, bool &secondPointClipped )
-{
- bool reversed = m1 > m2;
- double tmp;
-
- //reverse m1, m2 if necessary (and consequently also x1,x2 / y1, y2)
- if ( reversed )
- {
- tmp = m1;
- m1 = m2;
- m2 = tmp;
-
- tmp = x1;
- x1 = x2;
- x2 = tmp;
-
- tmp = y1;
- y1 = y2;
- y2 = tmp;
- }
-
- //reverse range1, range2 if necessary
- if ( range1 > range2 )
- {
- tmp = range1;
- range1 = range2;
- range2 = tmp;
- }
-
- //segment completely outside of range
- if ( m2 < range1 || m1 > range2 )
- {
- return false;
- }
-
- //segment completely inside of range
- if ( m2 <= range2 && m1 >= range1 )
- {
- if ( reversed )
- {
- pt1.setX( x2 );
- pt1.setY( y2 );
- pt2.setX( x1 );
- pt2.setY( y1 );
- }
- else
- {
- pt1.setX( x1 );
- pt1.setY( y1 );
- pt2.setX( x2 );
- pt2.setY( y2 );
- }
- secondPointClipped = false;
- return true;
- }
-
- //m1 inside and m2 not
- if ( m1 >= range1 && m1 <= range2 )
- {
- pt1.setX( x1 );
- pt1.setY( y1 );
- double dist = ( range2 - m1 ) / ( m2 - m1 );
- pt2.setX( x1 + ( x2 - x1 ) * dist );
- pt2.setY( y1 + ( y2 - y1 ) * dist );
- secondPointClipped = !reversed;
- }
-
- //m2 inside and m1 not
- if ( m2 >= range1 && m2 <= range2 )
- {
- pt2.setX( x2 );
- pt2.setY( y2 );
- double dist = ( m2 - range1 ) / ( m2 - m1 );
- pt1.setX( x2 - ( x2 - x1 ) * dist );
- pt1.setY( y2 - ( y2 - y1 ) * dist );
- secondPointClipped = reversed;
- }
-
- //range1 and range 2 both inside the segment
- if ( range1 >= m1 && range2 <= m2 )
- {
- double dist1 = ( range1 - m1 ) / ( m2 - m1 );
- double dist2 = ( range2 - m1 ) / ( m2 - m1 );
- pt1.setX( x1 + ( x2 - x1 ) * dist1 );
- pt1.setY( y1 + ( y2 - y1 ) * dist1 );
- pt2.setX( x1 + ( x2 - x1 ) * dist2 );
- pt2.setY( y1 + ( y2 - y1 ) * dist2 );
- secondPointClipped = true;
- }
-
- if ( reversed ) //switch p1 and p2
- {
- QgsPointXY tmpPt = pt1;
- pt1 = pt2;
- pt2 = tmpPt;
- }
-
- return true;
-}
-
-void QgsGeometryAnalyzer::locateAlongSegment( double x1, double y1, double m1, double x2, double y2, double m2, double measure, bool &pt1Ok, QgsPointXY &pt1, bool &pt2Ok, QgsPointXY &pt2 )
-{
- bool reversed = false;
- pt1Ok = false;
- pt2Ok = false;
- double tolerance = 0.000001; //work with a small tolerance to catch e.g. locations at endpoints
-
- if ( m1 > m2 )
- {
- double tmp = m1;
- m1 = m2;
- m2 = tmp;
- reversed = true;
- }
-
- //segment does not match
- if ( ( m1 - measure ) > tolerance || ( measure - m2 ) > tolerance )
- {
- pt1Ok = false;
- pt2Ok = false;
- return;
- }
-
- //match with vertex1
- if ( qgsDoubleNear( m1, measure, tolerance ) )
- {
- if ( reversed )
- {
- pt2Ok = true;
- pt2.setX( x2 );
- pt2.setY( y2 );
- }
- else
- {
- pt1Ok = true;
- pt1.setX( x1 );
- pt1.setY( y1 );
- }
- }
-
- //match with vertex2
- if ( qgsDoubleNear( m2, measure, tolerance ) )
- {
- if ( reversed )
- {
- pt1Ok = true;
- pt1.setX( x1 );
- pt1.setY( y1 );
- }
- else
- {
- pt2Ok = true;
- pt2.setX( x2 );
- pt2.setY( y2 );
- }
- }
-
-
- if ( pt1Ok || pt2Ok )
- {
- return;
- }
-
- //match between the vertices
- if ( qgsDoubleNear( m1, m2 ) )
- {
- pt1.setX( x1 );
- pt1.setY( y1 );
- pt1Ok = true;
- return;
- }
- double dist = ( measure - m1 ) / ( m2 - m1 );
- if ( reversed )
- {
- dist = 1 - dist;
- }
-
- pt1.setX( x1 + dist * ( x2 - x1 ) );
- pt1.setY( y1 + dist * ( y2 - y1 ) );
- pt1Ok = true;
-}
diff --git a/src/analysis/vector/qgsgeometryanalyzer.h b/src/analysis/vector/qgsgeometryanalyzer.h
deleted file mode 100644
index c7111f53aa8..00000000000
--- a/src/analysis/vector/qgsgeometryanalyzer.h
+++ /dev/null
@@ -1,161 +0,0 @@
-/***************************************************************************
- qgsgeometryanalyzer.h - QGIS Tools for vector geometry analysis
- -------------------
- begin : 19 March 2009
- copyright : (C) Carson Farmer
- email : carson.farmer@gmail.com
- ***************************************************************************/
-
-/***************************************************************************
- * *
- * 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. *
- * *
- ***************************************************************************/
-
-#ifndef QGSGEOMETRYANALYZERH
-#define QGSGEOMETRYANALYZERH
-
-#include "qgsfeature.h"
-#include "qgsgeometry.h"
-#include "qgis_analysis.h"
-
-class QgsVectorFileWriter;
-class QProgressDialog;
-class QgsVectorDataProvider;
-class QgsDistanceArea;
-
-/** \ingroup analysis
- * The QGis class provides vector geometry analysis functions
- */
-
-class ANALYSIS_EXPORT QgsGeometryAnalyzer
-{
- public:
-
- /** Simplify vector layer using (a modified) Douglas-Peucker algorithm
- * and write it to a new shape file
- * \param layer input vector layer
- * \param shapefileName path to the output shp
- * \param tolerance (level of simplification)
- * \param onlySelectedFeatures if true, only selected features are considered, else all the features
- * \param p progress dialog (or 0 if no progress dialog is to be shown)
- */
- bool simplify( QgsVectorLayer *layer, const QString &shapefileName, double tolerance,
- bool onlySelectedFeatures = false, QProgressDialog *p = nullptr );
-
- /** Calculate the true centroids, or 'center of mass' for a vector layer and
- * write it to a new shape file
- * \param layer input vector layer
- * \param shapefileName path to the output shp
- * \param onlySelectedFeatures if true, only selected features are considered, else all the features
- * \param p progress dialog (or 0 if no progress dialog is to be shown)
- */
- bool centroids( QgsVectorLayer *layer, const QString &shapefileName,
- bool onlySelectedFeatures = false, QProgressDialog *p = nullptr );
-
- /** Create a polygon based on the extent of all (selected) features and write it to a new shape file
- * \param layer input vector layer
- * \param shapefileName path to the output shp
- * \param onlySelectedFeatures if true, only selected features are considered, else all the features
- * \param p progress dialog (or 0 if no progress dialog is to be shown)
- */
- bool extent( QgsVectorLayer *layer, const QString &shapefileName, bool onlySelectedFeatures = false, QProgressDialog *p = 0 );
-
- /** Create buffers for a vector layer and write it to a new shape file
- * \param layer input vector layer
- * \param shapefileName path to the output shp
- * \param bufferDistance distance for buffering (if no buffer field is specified)
- * \param onlySelectedFeatures if true, only selected features are considered, else all the features
- * \param dissolve if true, merge all the buffers to a big multipolygon
- * \param bufferDistanceField index of the attribute field that contains the buffer distance (or -1 if all features have the same buffer distance)
- * \param p progress dialog (or 0 if no progress dialog is to be shown)
- */
- bool buffer( QgsVectorLayer *layer, const QString &shapefileName, double bufferDistance,
- bool onlySelectedFeatures = false, bool dissolve = false, int bufferDistanceField = -1, QProgressDialog *p = nullptr );
-
- /** Create convex hull(s) of a vector layer and write it to a new shape file
- * \param layer input vector layer
- * \param shapefileName path to the output shp
- * \param onlySelectedFeatures if true, only selected features are considered, else all the features
- * \param uniqueIdField index of the attribute field that contains the unique convex hull id (or -1 if
- * all features have the same buffer distance)
- * \param p progress dialog (or 0 if no progress dialog is to be shown)
- */
- bool convexHull( QgsVectorLayer *layer, const QString &shapefileName, bool onlySelectedFeatures = false,
- int uniqueIdField = -1, QProgressDialog *p = nullptr );
-
- /** Dissolve a vector layer and write it to a new shape file
- * \param layer input vector layer
- * \param shapefileName path to the output shp
- * \param onlySelectedFeatures if true, only selected features are considered, else all the features
- * \param uniqueIdField index of the attribute field that contains the unique id to dissolve on (or -1 if
- * all features should be dissolved together)
- * \param p progress dialog (or 0 if no progress dialog is to be shown)
- */
- bool dissolve( QgsVectorLayer *layer, const QString &shapefileName, bool onlySelectedFeatures = false,
- int uniqueIdField = -1, QProgressDialog *p = nullptr );
-
- /** Creates an event layer (multipoint or multiline) by locating features from a (non-spatial) event table along the features of a line layer.
- * Note that currently (until QgsGeometry supports m-values) the z-coordinate of the line layer is used for linear referencing
- * \param lineLayer layer with the line geometry
- * \param eventLayer layer with features and location field
- * \param lineField join index in line layer
- * \param eventField join index in event layer
- * \param outputLayer name of output file (can be empty if a memory layer is used)
- * \param outputFormat name of output format (can be empty if a memory provider is used to store the results)
- * \param unlocatedFeatureIds out: ids of event features where linear referencing was not successful
- * \param locationField1 attribute index of location field in event layer
- * \param locationField2 attribute index of location end field (or -1 for point layer)
- * \param offsetField attribute index for offset field. Negative offset value = offset to left side, positive value = offset to right side
- * \param offsetScale factor to scale offset
- * \param forceSingleGeometry force layer to single point/line type. Feature attributes are copied in case of multiple matches
- * \param memoryProvider memory provider to write output to (can be 0 if output is written to a file)
- * \param p progress dialog or 0 if no progress dialog should be shown
- */
- bool eventLayer( QgsVectorLayer *lineLayer, QgsVectorLayer *eventLayer, int lineField, int eventField, QgsFeatureIds &unlocatedFeatureIds SIP_OUT, const QString &outputLayer,
- const QString &outputFormat, int locationField1, int locationField2 = -1, int offsetField = -1, double offsetScale = 1.0,
- bool forceSingleGeometry = false, QgsVectorDataProvider *memoryProvider = nullptr, QProgressDialog *p = nullptr );
-
- //! Returns linear reference geometry as a multiline (or 0 if no match). Currently, the z-coordinates are considered to be the measures (no support for m-values in QGIS)
- QgsGeometry locateBetweenMeasures( double fromMeasure, double toMeasure, const QgsGeometry &lineGeom );
-
- /** Returns linear reference geometry. Unlike the PostGIS function, this method always returns multipoint or 0 if no match (not geometry collection).
- * Currently, the z-coordinates are considered to be the measures (no support for m-values in QGIS)
- */
- QgsGeometry locateAlongMeasure( double measure, const QgsGeometry &lineGeom );
-
- private:
-
- QList simpleMeasure( QgsGeometry &geometry );
- double perimeterMeasure( const QgsGeometry &geometry, QgsDistanceArea &measure );
- //! Helper function to simplify an individual feature
- void simplifyFeature( QgsFeature &f, QgsVectorFileWriter *vfw, double tolerance );
- //! Helper function to get the cetroid of an individual feature
- void centroidFeature( QgsFeature &f, QgsVectorFileWriter *vfw );
- //! Helper function to buffer an individual feature
- void bufferFeature( QgsFeature &f, int nProcessedFeatures, QgsVectorFileWriter *vfw, bool dissolve, QgsGeometry &dissolveGeometry,
- double bufferDistance, int bufferDistanceField );
- //! Helper function to get the convex hull of feature(s)
- void convexFeature( QgsFeature &f, int nProcessedFeatures, QgsGeometry &dissolveGeometry );
- //! Helper function to dissolve feature(s)
- QgsGeometry dissolveFeature( const QgsFeature &f, const QgsGeometry &dissolveInto );
-
- //helper functions for event layer
- void addEventLayerFeature( QgsFeature &feature, const QgsGeometry &geom, const QgsGeometry &lineGeom, QgsVectorFileWriter *fileWriter, QgsFeatureList &memoryFeatures, int offsetField = -1, double offsetScale = 1.0,
- bool forceSingleType = false );
-
- /** Create geometry offset relative to line geometry.
- \param geom the geometry to modify
- \param lineGeom the line geometry to which the feature is referenced
- \param offset the offset value in layer unit. Negative values mean offset towards left, positive values offset to the right side*/
- QgsGeometry createOffsetGeometry( const QgsGeometry &geom, const QgsGeometry &lineGeom, double offset );
- QgsPointXY createPointOffset( double x, double y, double dist, const QgsGeometry &lineGeom ) const;
- QgsConstWkbPtr locateBetweenWkbString( QgsConstWkbPtr ptr, QgsMultiPolyline &result, double fromMeasure, double toMeasure );
- QgsConstWkbPtr locateAlongWkbString( QgsConstWkbPtr ptr, QgsMultiPoint &result, double measure );
- static bool clipSegmentByRange( double x1, double y1, double m1, double x2, double y2, double m2, double range1, double range2, QgsPointXY &pt1, QgsPointXY &pt2, bool &secondPointClipped );
- static void locateAlongSegment( double x1, double y1, double m1, double x2, double y2, double m2, double measure, bool &pt1Ok, QgsPointXY &pt1, bool &pt2Ok, QgsPointXY &pt2 );
-};
-#endif //QGSVECTORANALYZER
diff --git a/src/analysis/vector/qgsoverlayanalyzer.cpp b/src/analysis/vector/qgsoverlayanalyzer.cpp
deleted file mode 100644
index 39049e7176c..00000000000
--- a/src/analysis/vector/qgsoverlayanalyzer.cpp
+++ /dev/null
@@ -1,195 +0,0 @@
-/***************************************************************************
- qgsoverlayanalyzer.cpp - QGIS Tools for vector geometry analysis
- -------------------
- begin : 8 Nov 2009
- copyright : (C) Carson J. Q. Farmer
- email : carson.farmer@gmail.com
- ***************************************************************************/
-
-/***************************************************************************
- * *
- * 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. *
- * *
- ***************************************************************************/
-
-#include "qgsoverlayanalyzer.h"
-
-#include "qgsapplication.h"
-#include "qgsfeatureiterator.h"
-#include "qgsfields.h"
-#include "qgsfeature.h"
-#include "qgsgeometry.h"
-#include "qgslogger.h"
-#include "qgscoordinatereferencesystem.h"
-#include "qgsspatialindex.h"
-#include "qgsvectorfilewriter.h"
-#include "qgsvectordataprovider.h"
-#include "qgsdistancearea.h"
-#include
-
-bool QgsOverlayAnalyzer::intersection( QgsVectorLayer *layerA, QgsVectorLayer *layerB,
- const QString &shapefileName, bool onlySelectedFeatures,
- QProgressDialog *p )
-{
- if ( !layerA || !layerB )
- {
- return false;
- }
-
- QgsVectorDataProvider *dpA = layerA->dataProvider();
- QgsVectorDataProvider *dpB = layerB->dataProvider();
- if ( !dpA || !dpB )
- {
- return false;
- }
-
- QgsWkbTypes::Type outputType = dpA->wkbType();
- QgsCoordinateReferenceSystem crs = layerA->crs();
- QgsFields fieldsA = layerA->fields();
- QgsFields fieldsB = layerB->fields();
- combineFieldLists( fieldsA, fieldsB );
-
- QgsVectorFileWriter vWriter( shapefileName, dpA->encoding(), fieldsA, outputType, crs );
- QgsFeature currentFeature;
-
- //take only selection
- if ( onlySelectedFeatures )
- {
- QgsFeatureIds selectionB = layerB->selectedFeatureIds();
- QgsFeatureRequest req = QgsFeatureRequest().setFilterFids( selectionB ).setSubsetOfAttributes( QgsAttributeList() );
- QgsSpatialIndex index = QgsSpatialIndex( layerB->getFeatures( req ) );
-
- //use QgsVectorLayer::featureAtId
- const QgsFeatureIds selectionA = layerA->selectedFeatureIds();
- if ( p )
- {
- p->setMaximum( selectionA.size() );
- }
- req = QgsFeatureRequest().setFilterFids( selectionA );
- QgsFeatureIterator selectionAIt = layerA->getFeatures( req );
- QgsFeature currentFeature;
- int processedFeatures = 0;
- while ( selectionAIt.nextFeature( currentFeature ) )
- {
- if ( p )
- {
- p->setValue( processedFeatures );
- }
-
- if ( p && p->wasCanceled() )
- {
- break;
- }
-
- intersectFeature( currentFeature, &vWriter, layerB, &index );
- ++processedFeatures;
- }
-
- if ( p )
- {
- p->setValue( selectionA.size() );
- }
- }
- //take all features
- else
- {
- QgsFeatureRequest req = QgsFeatureRequest().setSubsetOfAttributes( QgsAttributeList() );
- QgsSpatialIndex index = QgsSpatialIndex( layerB->getFeatures( req ) );
-
- int featureCount = layerA->featureCount();
- if ( p )
- {
- p->setMaximum( featureCount );
- }
- int processedFeatures = 0;
-
- QgsFeatureIterator fit = layerA->getFeatures();
-
- QgsFeature currentFeature;
- while ( fit.nextFeature( currentFeature ) )
- {
- if ( p )
- {
- p->setValue( processedFeatures );
- }
- if ( p && p->wasCanceled() )
- {
- break;
- }
- intersectFeature( currentFeature, &vWriter, layerB, &index );
- ++processedFeatures;
- }
- if ( p )
- {
- p->setValue( featureCount );
- }
- }
- return true;
-}
-
-void QgsOverlayAnalyzer::intersectFeature( QgsFeature &f, QgsVectorFileWriter *vfw,
- QgsVectorLayer *vl, QgsSpatialIndex *index )
-{
- if ( !f.hasGeometry() )
- {
- return;
- }
-
- QgsGeometry featureGeometry = f.geometry();
- QgsGeometry intersectGeometry;
- QgsFeature overlayFeature;
-
- QList intersects = index->intersects( featureGeometry.boundingBox() );
- QgsFeatureRequest req = QgsFeatureRequest().setFilterFids( intersects.toSet() );
- QgsFeatureIterator intersectIt = vl->getFeatures( req );
- QgsFeature outFeature;
- while ( intersectIt.nextFeature( overlayFeature ) )
- {
- if ( featureGeometry.intersects( overlayFeature.geometry() ) )
- {
- intersectGeometry = featureGeometry.intersection( overlayFeature.geometry() );
-
- outFeature.setGeometry( intersectGeometry );
- QgsAttributes attributesA = f.attributes();
- QgsAttributes attributesB = overlayFeature.attributes();
- combineAttributeMaps( attributesA, attributesB );
- outFeature.setAttributes( attributesA );
-
- //add it to vector file writer
- if ( vfw )
- {
- vfw->addFeature( outFeature );
- }
- }
- }
-}
-
-void QgsOverlayAnalyzer::combineFieldLists( QgsFields &fieldListA, const QgsFields &fieldListB )
-{
- QList names;
- Q_FOREACH ( const QgsField &field, fieldListA )
- names.append( field.name() );
-
- for ( int idx = 0; idx < fieldListB.count(); ++idx )
- {
- QgsField field = fieldListB.at( idx );
- int count = 0;
- while ( names.contains( field.name() ) )
- {
- QString name = QStringLiteral( "%1_%2" ).arg( field.name() ).arg( count );
- field = QgsField( name, field.type() );
- ++count;
- }
- fieldListA.append( field );
- names.append( field.name() );
- }
-}
-
-void QgsOverlayAnalyzer::combineAttributeMaps( QgsAttributes &attributesA, const QgsAttributes &attributesB )
-{
- attributesA += attributesB;
-}
-
diff --git a/src/analysis/vector/qgsoverlayanalyzer.h b/src/analysis/vector/qgsoverlayanalyzer.h
deleted file mode 100644
index 0fd9ada8a49..00000000000
--- a/src/analysis/vector/qgsoverlayanalyzer.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/***************************************************************************
- qgsoverlayanalyzer.h - QGIS Tools for vector geometry analysis
- -------------------
- begin : 19 March 2009
- copyright : (C) Carson Farmer
- email : carson.farmer@gmail.com
- ***************************************************************************/
-
-/***************************************************************************
- * *
- * 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. *
- * *
- ***************************************************************************/
-
-#ifndef QGSOVERLAYANALYZERH
-#define QGSOVERLAYANALYZERH
-
-#include "qgsvectorlayer.h"
-#include "qgis_analysis.h"
-
-class QgsVectorFileWriter;
-class QProgressDialog;
-class QgsSpatialIndex;
-
-/** \ingroup analysis
- * The QGis class provides vector overlay analysis functions
- */
-
-class ANALYSIS_EXPORT QgsOverlayAnalyzer
-{
- public:
-
- /** Perform an intersection on two input vector layers and write output to a new shape file
- \param layerA input vector layer
- \param layerB input vector layer
- \param shapefileName path to the output shp
- \param onlySelectedFeatures if true, only selected features are considered, else all the features
- \param p progress dialog (or 0 if no progress dialog is to be shown)
- */
- bool intersection( QgsVectorLayer *layerA, QgsVectorLayer *layerB,
- const QString &shapefileName, bool onlySelectedFeatures = false,
- QProgressDialog *p = nullptr );
-
- private:
-
- void combineFieldLists( QgsFields &fieldListA, const QgsFields &fieldListB );
- void intersectFeature( QgsFeature &f, QgsVectorFileWriter *vfw, QgsVectorLayer *dp, QgsSpatialIndex *index );
- void combineAttributeMaps( QgsAttributes &attributesA, const QgsAttributes &attributesB );
-};
-
-#endif //QGSVECTORANALYZER
diff --git a/src/analysis/vector/qgspointsample.cpp b/src/analysis/vector/qgspointsample.cpp
deleted file mode 100644
index 528ecbca227..00000000000
--- a/src/analysis/vector/qgspointsample.cpp
+++ /dev/null
@@ -1,170 +0,0 @@
-/***************************************************************************
- qgspointsample.cpp
- ---------------------
- begin : July 2013
- copyright : (C) 2013 by Marco Hugentobler
- email : marco dot hugentobler at sourcepole dot ch
- ***************************************************************************
- * *
- * 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. *
- * *
- ***************************************************************************/
-#include "qgspointsample.h"
-#include "qgsfeatureiterator.h"
-#include "qgsgeometry.h"
-#include "qgsspatialindex.h"
-#include "qgsvectorfilewriter.h"
-#include "qgsvectorlayer.h"
-#include
-#include "mersenne-twister.h"
-
-
-QgsPointSample::QgsPointSample( QgsVectorLayer *inputLayer, const QString &outputLayer, const QString &nPointsAttribute, const QString &minDistAttribute ): mInputLayer( inputLayer ),
- mOutputLayer( outputLayer ), mNumberOfPointsAttribute( nPointsAttribute ), mMinDistanceAttribute( minDistAttribute ), mNCreatedPoints( 0 )
-{
-}
-
-QgsPointSample::QgsPointSample()
- : mInputLayer( nullptr )
- , mNCreatedPoints( 0 )
-{
-}
-
-int QgsPointSample::createRandomPoints( QProgressDialog *pd )
-{
- Q_UNUSED( pd );
-
- //create input layer from id (test if polygon, valid)
- if ( !mInputLayer )
- {
- return 1;
- }
-
- if ( mInputLayer->geometryType() != QgsWkbTypes::PolygonGeometry )
- {
- return 2;
- }
-
- //delete output file if it already exists
- if ( QFile::exists( mOutputLayer ) )
- {
- QgsVectorFileWriter::deleteShapeFile( mOutputLayer );
- }
-
- //create vector file writer
- QgsFields outputFields;
- outputFields.append( QgsField( QStringLiteral( "id" ), QVariant::Int ) );
- outputFields.append( QgsField( QStringLiteral( "station_id" ), QVariant::Int ) );
- outputFields.append( QgsField( QStringLiteral( "stratum_id" ), QVariant::Int ) );
- QgsVectorFileWriter writer( mOutputLayer, QStringLiteral( "UTF-8" ),
- outputFields,
- QgsWkbTypes::Point,
- mInputLayer->crs() );
-
- //check if creation of output layer successful
- if ( writer.hasError() != QgsVectorFileWriter::NoError )
- {
- return 3;
- }
-
- //init random number generator
- mt_srand( QTime::currentTime().msec() );
- QgsFeature fet;
- int nPoints = 0;
- double minDistance = 0;
- mNCreatedPoints = 0;
-
- QgsFeatureIterator fIt = mInputLayer->getFeatures( QgsFeatureRequest().setSubsetOfAttributes(
- QStringList() << mNumberOfPointsAttribute << mMinDistanceAttribute, mInputLayer->fields() ) );
- while ( fIt.nextFeature( fet ) )
- {
- nPoints = fet.attribute( mNumberOfPointsAttribute ).toInt();
- if ( !mMinDistanceAttribute.isEmpty() )
- {
- minDistance = fet.attribute( mMinDistanceAttribute ).toDouble();
- }
- addSamplePoints( fet, writer, nPoints, minDistance );
- }
-
- return 0;
-}
-
-void QgsPointSample::addSamplePoints( QgsFeature &inputFeature, QgsVectorFileWriter &writer, int nPoints, double minDistance )
-{
- if ( !inputFeature.hasGeometry() )
- return;
-
- QgsGeometry geom = inputFeature.geometry();
- QgsRectangle geomRect = geom.boundingBox();
- if ( geomRect.isEmpty() )
- {
- return;
- }
-
- QgsSpatialIndex sIndex; //to check minimum distance
- QMap< QgsFeatureId, QgsPointXY > pointMapForFeature;
-
- int nIterations = 0;
- int maxIterations = nPoints * 200;
- int points = 0;
-
- double randX = 0;
- double randY = 0;
-
- while ( nIterations < maxIterations && points < nPoints )
- {
- randX = ( ( double )mt_rand() / MD_RAND_MAX ) * geomRect.width() + geomRect.xMinimum();
- randY = ( ( double )mt_rand() / MD_RAND_MAX ) * geomRect.height() + geomRect.yMinimum();
- QgsPointXY randPoint( randX, randY );
- QgsGeometry ptGeom = QgsGeometry::fromPoint( randPoint );
- if ( ptGeom.within( geom ) && checkMinDistance( randPoint, sIndex, minDistance, pointMapForFeature ) )
- {
- //add feature to writer
- QgsFeature f( mNCreatedPoints );
- f.setAttribute( QStringLiteral( "id" ), mNCreatedPoints + 1 );
- f.setAttribute( QStringLiteral( "station_id" ), points + 1 );
- f.setAttribute( QStringLiteral( "stratum_id" ), inputFeature.id() );
- f.setGeometry( ptGeom );
- writer.addFeature( f );
- sIndex.insertFeature( f );
- pointMapForFeature.insert( mNCreatedPoints, randPoint );
- ++points;
- ++mNCreatedPoints;
- }
- ++nIterations;
- }
-}
-
-bool QgsPointSample::checkMinDistance( QgsPointXY &pt, QgsSpatialIndex &index, double minDistance, QMap< QgsFeatureId, QgsPointXY > &pointMap )
-{
- if ( minDistance <= 0 )
- {
- return true;
- }
-
- QList neighborList = index.nearestNeighbor( pt, 1 );
- if ( neighborList.isEmpty() )
- {
- return true;
- }
-
- QMap< QgsFeatureId, QgsPointXY >::const_iterator it = pointMap.find( neighborList[0] );
- if ( it == pointMap.constEnd() ) //should not happen
- {
- return true;
- }
-
- QgsPointXY neighborPt = it.value();
- if ( neighborPt.sqrDist( pt ) < ( minDistance * minDistance ) )
- {
- return false;
- }
- return true;
-}
-
-
-
-
diff --git a/src/analysis/vector/qgspointsample.h b/src/analysis/vector/qgspointsample.h
deleted file mode 100644
index 098838c9f3e..00000000000
--- a/src/analysis/vector/qgspointsample.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/***************************************************************************
- qgspointsample.h
- ---------------------
- begin : July 2013
- copyright : (C) 2013 by Marco Hugentobler
- email : marco dot hugentobler at sourcepole dot ch
- ***************************************************************************
- * *
- * 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. *
- * *
- ***************************************************************************/
-#ifndef QGSPOINTSAMPLE_H
-#define QGSPOINTSAMPLE_H
-
-#include "qgsfeature.h"
-#include
-#include "qgis_analysis.h"
-
-class QgsFeature;
-class QgsPointXY;
-class QgsSpatialIndex;
-class QgsVectorFileWriter;
-class QgsVectorLayer;
-class QProgressDialog;
-
-/** \ingroup analysis
- * Creates random points in polygons / multipolygons*/
-class ANALYSIS_EXPORT QgsPointSample
-{
- public:
- QgsPointSample( QgsVectorLayer *inputLayer, const QString &outputLayer, const QString &nPointsAttribute, const QString &minDistAttribute = QString() );
-
- /** Starts calculation of random points
- \returns 0 in case of success*/
- int createRandomPoints( QProgressDialog *pd );
-
- private:
-
- QgsPointSample(); //default constructor is forbidden
- void addSamplePoints( QgsFeature &inputFeature, QgsVectorFileWriter &writer, int nPoints, double minDistance );
- bool checkMinDistance( QgsPointXY &pt, QgsSpatialIndex &index, double minDistance, QMap< QgsFeatureId, QgsPointXY > &pointMap );
-
- //! Layer id of input polygon/multipolygon layer
- QgsVectorLayer *mInputLayer = nullptr;
- //! Output path of result layer
- QString mOutputLayer;
- //! Attribute containing number of points per feature
- QString mNumberOfPointsAttribute;
- //! Attribute containing minimum distance between sample points (or -1 if no min. distance constraint)
- QString mMinDistanceAttribute;
- QgsFeatureId mNCreatedPoints; //helper to find free ids
-};
-
-#endif // QGSPOINTSAMPLE_H
diff --git a/src/app/CMakeLists.txt b/src/app/CMakeLists.txt
index 0cd83cafed0..dd2f575e3b2 100755
--- a/src/app/CMakeLists.txt
+++ b/src/app/CMakeLists.txt
@@ -124,8 +124,6 @@ SET(QGIS_APP_SRCS
qgstextannotationdialog.cpp
qgssvgannotationdialog.cpp
qgsundowidget.cpp
- qgstipgui.cpp
- qgstipfactory.cpp
qgsvectorlayerproperties.cpp
qgsmapthemes.cpp
qgshandlebadlayers.cpp
@@ -342,8 +340,6 @@ SET (QGIS_APP_MOC_HDRS
qgsstatisticalsummarydockwidget.h
qgssvgannotationdialog.h
qgstextannotationdialog.h
- qgstipgui.h
- qgstipfactory.h
qgsundowidget.h
qgsvectorlayerproperties.h
qgsmapthemes.h
diff --git a/src/app/qgisapp.cpp b/src/app/qgisapp.cpp
index c6917bf7c5d..834f39f65f2 100644
--- a/src/app/qgisapp.cpp
+++ b/src/app/qgisapp.cpp
@@ -261,7 +261,6 @@ Q_GUI_EXPORT extern int qt_defaultDpiX();
#include "qgstaskmanagerwidget.h"
#include "qgssymbolselectordialog.h"
#include "qgstextannotation.h"
-#include "qgstipgui.h"
#include "qgsundowidget.h"
#include "qgsuserinputdockwidget.h"
#include "qgsvectordataprovider.h"
@@ -1181,18 +1180,6 @@ QgisApp::QgisApp( QSplashScreen *splash, bool restorePlugins, bool skipVersionCh
toggleSnapping->setProperty( "Icon", QgsApplication::getThemeIcon( "/mIconSnapping.svg" ) );
connect( toggleSnapping, &QShortcut::activated, mSnappingUtils, &QgsSnappingUtils::toggleEnabled );
- // Show a nice tip of the day
- if ( settings.value( QStringLiteral( "qgis/showTips%1" ).arg( Qgis::QGIS_VERSION_INT / 100 ), true ).toBool() )
- {
- mSplash->hide();
- QgsTipGui myTip( this );
- myTip.exec();
- }
- else
- {
- QgsDebugMsg( "Tips are disabled" );
- }
-
if ( ! QTouchDevice::devices().isEmpty() )
{
//add reacting to long click in touch
diff --git a/src/app/qgsoptions.cpp b/src/app/qgsoptions.cpp
index 19e5f9db503..5f76ac7af2c 100644
--- a/src/app/qgsoptions.cpp
+++ b/src/app/qgsoptions.cpp
@@ -628,7 +628,6 @@ QgsOptions::QgsOptions( QWidget *parent, Qt::WindowFlags fl, const QListsetChecked( mSettings->value( QStringLiteral( "/qgis/legendLayersBold" ), true ).toBool() );
mLegendGroupsBoldChkBx->setChecked( mSettings->value( QStringLiteral( "/qgis/legendGroupsBold" ), false ).toBool() );
cbxHideSplash->setChecked( mSettings->value( QStringLiteral( "/qgis/hideSplash" ), false ).toBool() );
- cbxShowTips->setChecked( mSettings->value( QStringLiteral( "/qgis/showTips%1" ).arg( Qgis::QGIS_VERSION_INT / 100 ), true ).toBool() );
mDataSourceManagerNonModal->setChecked( mSettings->value( "/qgis/dataSourceManagerNonModal", false ).toBool() );
cbxCheckVersion->setChecked( mSettings->value( QStringLiteral( "/qgis/checkVersion" ), true ).toBool() );
cbxAttributeTableDocked->setChecked( mSettings->value( QStringLiteral( "/qgis/dockAttributeTable" ), false ).toBool() );
@@ -1209,7 +1208,6 @@ void QgsOptions::saveOptions()
bool legendGroupsBold = mSettings->value( QStringLiteral( "/qgis/legendGroupsBold" ), false ).toBool();
mSettings->setValue( QStringLiteral( "/qgis/legendGroupsBold" ), mLegendGroupsBoldChkBx->isChecked() );
mSettings->setValue( QStringLiteral( "/qgis/hideSplash" ), cbxHideSplash->isChecked() );
- mSettings->setValue( QStringLiteral( "/qgis/showTips%1" ).arg( Qgis::QGIS_VERSION_INT / 100 ), cbxShowTips->isChecked() );
mSettings->setValue( QStringLiteral( "/qgis/dataSourceManagerNonModal" ), mDataSourceManagerNonModal->isChecked() );
mSettings->setValue( QStringLiteral( "/qgis/checkVersion" ), cbxCheckVersion->isChecked() );
mSettings->setValue( QStringLiteral( "/qgis/dockAttributeTable" ), cbxAttributeTableDocked->isChecked() );
diff --git a/src/app/qgstip.h b/src/app/qgstip.h
deleted file mode 100644
index 7fcd57ce1b3..00000000000
--- a/src/app/qgstip.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/***************************************************************************
- qgstip.h
- ---------------------
- begin : February 2011
- copyright : (C) 2011 by Tim Sutton
- email : tim at linfiniti dot com
- ***************************************************************************
- * *
- * 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. *
- * *
- ***************************************************************************/
-#ifndef QGSTIP
-#define QGSTIP
-
-#include
-#include
-#include "qgis_app.h"
-
-/** \ingroup app
-* \brief An QgsTip represents a tip generated by the
-* QgsTipFactory factory class to serve up tips to the user.
-* Tips can be generic, in which case they make no mention of
-* gui dialogs etc, or gui-specific in which case they may allude
-* to features of the graphical user interface.
-* \see also QgsTipOfTheDay, QgsTipFactory
-*/
-
-class APP_EXPORT QgsTip
-{
- public:
- //! Constructor
- QgsTip() {}
- //! Destructor
- ~QgsTip() {}
- //
- // Accessors
- //
- //! Get the tip title
- QString title() {return mTitle;}
- //! Get the tip content
- QString content() {return mContent;}
-
- //
- // Mutators
- //
- //! Set the tip title
- void setTitle( const QString &title ) {mTitle = title;}
- //! Set the tip content
- void setContent( const QString &content ) {mContent = content;}
- private:
- QString mTitle;
- QString mContent;
-};
-
-#endif //QGSTIP
-
diff --git a/src/app/qgstipfactory.cpp b/src/app/qgstipfactory.cpp
deleted file mode 100644
index 660e7f8e39f..00000000000
--- a/src/app/qgstipfactory.cpp
+++ /dev/null
@@ -1,362 +0,0 @@
-/***************************************************************************
- qgstipfactory.cpp
- ---------------------
- begin : February 2011
- copyright : (C) 2007 by Tim Sutton
- email : tim at linfiniti dot com
- ***************************************************************************
- * *
- * 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. *
- * *
- ***************************************************************************/
-
-#include "qgstipfactory.h"
-#include
-//for rand & srand
-#include
-
-
-QgsTipFactory::QgsTipFactory() : QObject()
-{
- // I'm just doing this in a simple way so
- // its easy for translators...later
- // it its worth the time I'll move this data
- // into a sqlite database...
- QgsTip myTip;
- myTip.setTitle( tr( "QGIS is open source" ) );
- myTip.setContent( tr( "QGIS is open source software."
- " This means that the software source code can be freely viewed"
- " and modified. The GPL places a restriction that any modifications"
- " you make must be made available in source form to whoever you give"
- " modified versions to, and that you can not create a new version of"
- " QGIS under a 'closed source' license. Visit"
- " the QGIS home page"
- " for more information."
- ) );
- addGenericTip( myTip );
- //
- myTip.setTitle( tr( "QGIS Publications" ) );
- myTip.setContent( tr( "If you write a scientific paper or any other article"
- " that refers to QGIS we would love to include your work"
- " in the case studies section of"
- " the QGIS home page."
- ) );
- addGenericTip( myTip );
- myTip.setTitle( tr( "Become a QGIS translator" ) );
- myTip.setContent( tr( "Would you like to see QGIS"
- " in your native language? We are looking for more translators"
- " and would appreciate your help! The translation process is"
- " fairly straight forward - instructions are available in the"
- " QGIS wiki"
- " translator's page."
- ) );
- addGuiTip( myTip );
- myTip.setTitle( tr( "Getting Help With QGIS" ) );
- myTip.setContent( tr( "If you need help using QGIS"
- " there is a 'users' mailing list where users help each other with issues"
- " related to using QGIS. We also have a 'developers' mailing list"
- " for those wanting help and discuss things relating to the QGIS code base."
- " Details on different means to get help are described in the"
- " community section of the QGIS home page."
- ) );
- addGuiTip( myTip );
- myTip.setTitle( tr( "Is it 'QGIS' or 'Quantum GIS'?" ) );
- myTip.setContent( tr( "Both used to be correct, but we recently decided to just use 'QGIS'. For articles we suggest you write 'QGIS is ....'"
- ) );
- addGenericTip( myTip );
- myTip.setTitle( tr( "How do I refer to QGIS?" ) );
- myTip.setContent( tr( "QGIS is spelled in all caps."
- " We have various subprojects of the QGIS project"
- " and it will help to avoid confusion if you refer to each by"
- " its name:"
- ""
- "- QGIS Library - this is the C++ library that contains"
- " the core logic that is used to build the QGIS user interface and other applications.
"
- "- QGIS Desktop - this is the desktop application that you know and love so much :-).
"
- "- QGIS Server - this is a server-side application based on the QGIS Library"
- " that will serve up your .qgs projects using OGC standard protocols.
"
- "
"
- ) );
- addGenericTip( myTip );
- // This tip contributed by Andreas Neumann
- myTip.setTitle( tr( "Add the current date to a map layout" ) );
- myTip.setContent( tr( "You can add a current date variable to your map"
- " layout. Create a regular text label and add the string"
- " $CURRENT_DATE(yyyy-MM-dd) to the text box. See the"
- " "
- "QDate::toString format documentation for the possible date formats."
- ) );
- addGuiTip( myTip );
- myTip.setTitle( tr( "Moving Elements and Maps in the Print Composer" ) );
- myTip.setContent( tr( "In the print composer toolbar you can find two buttons for moving"
- " elements. The first one (
)"
- " selects and moves elements in the layout. After selecting the element"
- " with this tool you can also move them around with the arrow keys."
- " For accurate positioning use the %1 section,"
- " which can be found in the tab %2."
- " The other move tool (
)"
- " allows you to move the map content within a map frame." )
- .arg( tr( "Position and Size" ) )
- .arg( tr( "Item Properties" ) )
- );
- addGuiTip( myTip );
- addGuiTip( myTip );
- // This tip contributed by Andreas Neumann
- myTip.setTitle( tr( "Lock an item in the layout view" ) );
- myTip.setContent( tr( "Locking an element in the layout view prevents you to select or accidentally"
- " move it with the mouse. Locking an item is done by checking its"
- "
state in the"
- " %1 tab. While in a locked state, you can still get it"
- " selected from the %1 tab, and configure any of its"
- " properties in the %2 tab, including precisely setting"
- " its position and size." )
- .arg( tr( "Items" ) )
- .arg( tr( "Item Properties" ) )
- );
- addGuiTip( myTip );
- // This tip contributed by Andreas Neumann
- myTip.setTitle( tr( "Rotating a map and linking a north arrow" ) );
- myTip.setContent( tr( "In the Print Composer you can rotate a map by setting its rotation value"
- " in the tab Item Properties -> Map -> Main properties section."
- " To place a north arrow in your layout you can use the"
- " %1 tool. After the selection and"
- " placement of the north arrow in the layout you can link it"
- " with a specific map frame by activating the %2"
- " checkbox and selecting a map frame. Whenever you change the rotation"
- " value of a linked map, the north arrow will now automatically adjust"
- " its rotation." )
- .arg( tr( "Add Image" ) )
- .arg( tr( "Sync with map" ) )
- );
- addGuiTip( myTip );
- addGuiTip( myTip );
- // This tip contributed by Andreas Neumann
- myTip.setTitle( tr( "Numeric scale value in map layout linked to map frame" ) );
- myTip.setContent( tr( "If you want to place a text label as a placeholder for the"
- " current scale, linked to a map frame, you need to place a scalebar and"
- " set the style to 'Numeric'. You also need to select the map frame, if there"
- " is more than one."
- ) );
- addGuiTip( myTip );
- // by Tim
- myTip.setTitle( tr( "Using the mouse scroll wheel" ) );
- myTip.setContent( tr( "You can use the scroll wheel on your mouse to zoom in,"
- " out and pan the map. Scroll forwards to zoom in, scroll backwards to"
- " zoom out and press and hold the scroll wheel down to pan the map. You"
- " can configure the zoom scale factor in the %1 -> %2 panel." )
- .arg( tr( "Options" ) )
- .arg( tr( "Map tools" ) )
- );
- addGuiTip( myTip );
- addGuiTip( myTip );
- // by Tim
- myTip.setTitle( tr( "Disabling rendering" ) );
- myTip.setContent( tr( "Sometimes you have a very large dataset which takes ages"
- " to draw. If you are going to be performing several"
- " actions (e.g. modifying symbology options) and wish to temporarily"
- " disable map rendering while you do so, you can uncheck the 'Render'"
- " checkbox in the bottom right of the status bar. Don't forget to check"
- " it on again when you are ready to have the map draw itself again!"
- ) );
- addGuiTip( myTip );
- // Tip contributed by Alister Hood
- myTip.setTitle( tr( "Join intersected polylines when rendering" ) );
- myTip.setContent( tr( "When applying layered styles to a polyline layer, you can join"
- " intersecting lines together simply by enabling symbol levels."
- " The image below shows a before (left) and after (right) view of"
- " an intersection when symbol levels are enabled." ) +
- QStringLiteral( "
" )
- );
- addGuiTip( myTip );
- // by Tim
- myTip.setTitle( tr( "Auto-enable on the fly projection" ) );
- myTip.setContent( tr( "In the options dialog, under the CRS tab, you can set QGIS so that"
- " whenever you create a new project, 'on the fly projection' is enabled"
- " automatically and a pre-selected Coordinate Reference System of your"
- " choice is used."
- ) );
- addGuiTip( myTip );
- // by Tim
- myTip.setTitle( tr( "Sponsor QGIS" ) );
- myTip.setContent( tr( "If QGIS is saving you money or you like our work and"
- " have the financial ability to help, please consider sponsoring the"
- " development of QGIS. We use money from sponsors to pay for"
- " travel and costs related to our regular hackfest meetings, and to generally"
- " support the goals of our project. Please see the QGIS Sponsorship Web"
- " Page for more details."
- ) );
- addGenericTip( myTip );
- // by gsherman
- myTip.setTitle( tr( "QGIS has Plugins!" ) );
- myTip.setContent( tr( "QGIS has plugins that extend its functionality."
- " QGIS ships with some core plugins you can explore from the"
- " %1 -> %2 menu. In addition there"
- " are a lot of Python plugins "
- " contributed by the user community that can be"
- " installed via this same menu. Don't miss out on all QGIS has to offer!"
- " Check out the plugins and see what they can do for you." )
- .arg( tr( "Plugins" ) )
- .arg( tr( "Manage and Install Plugins..." ) )
- );
- addGuiTip( myTip );
- addGenericTip( myTip );
- // by yjacolin
- myTip.setTitle( tr( "Add an action to layer" ) );
- myTip.setContent( tr( "Action in a layer allows user to trigger action when clicking on a geometry"
- " with 'Run Feature Action' tools."
- "For example, you can open a HTML page using the field value of the geometry "
- "as a parameter. Look at the documentation."
- ) );
- addGuiTip( myTip );
- // by yjacolin
- myTip.setTitle( tr( "Copy, paste and cut in QGIS" ) );
- myTip.setContent( tr( "Copy, paste, and cut work as in another applications in QGIS. Select a "
- "feature (a geometry or an attribute row in the attribute table) and use "
- "one of these shortcuts: Ctrl+C to copy, Ctrl+X to cut, and Ctrl+V to paste."
- ) );
- addGuiTip( myTip );
- // by yjacolin
- myTip.setTitle( tr( "Right click with identify tools" ) );
- myTip.setContent( tr( "Right click with the identify tool to show a context menu from which you can "
- "choose the layer in which to identify a feature. A sub-menu will list features "
- "identified and a third sub-menu will show the action link setup for the layer. "
- "If one of this sub-menu doesn't contain any information, the next sub-menu "
- "will appear instead. For example, if you have just one layer, and click "
- "somewhere with several features, the first menu will list the features "
- "instead of layer list."
- ) );
- addGuiTip( myTip );
- // by Alister Hood
- myTip.setTitle( tr( "Use VRT files" ) );
- myTip.setContent( tr( "If you have a number of aerial photos spread across a wide area, instead of "
- "loading each file as a separate layer you can treat them all as a single layer "
- "by using a .vrt file. "
- "To create a .vrt, go to %1 -> %2 -> %3." )
- .arg( tr( "Raster" ) )
- .arg( tr( "Miscellaneous" ) )
- .arg( tr( "Build Virtual Raster (Catalog)" ) )
- );
- addGuiTip( myTip );
- // by Harrissou Sant-anna
- myTip.setTitle( tr( "Switch quickly between different styles of the layer" ) );
- myTip.setContent( tr( "From the Layer properties dialog, use the Styles -> Add combobox"
- " to create as many combinations of layer properties settings (symbology, labeling,"
- " diagram, fields form, actions...) as you want. Then, simply switch between styles"
- " from the context menu of the layer in %1 to automatically"
- " get different custom representations of your data." )
- .arg( tr( "Layers Panel" ) )
- );
- addGuiTip( myTip );
- // by Harrissou Sant-anna
- myTip.setTitle( tr( "Live update rendering" ) );
- myTip.setContent( tr( "Press F7 to activate the %1 panel from which you can"
- " easily and quickly configure the layer rendering. Check the %2"
- " option to automatically apply to the map canvas each of your modifications." )
- .arg( tr( "Layer Styling" ) )
- .arg( tr( "Live update" ) )
- );
- addGuiTip( myTip );
- // by Harrissou Sant-anna
- myTip.setTitle( tr( "Print or export a specific feature from an atlas composition" ) );
- myTip.setContent( tr( "If you want to print or export the composition of only one feature of the atlas,"
- " start the atlas preview, select the desired feature in the drop-down list"
- " and click on Composer -> Print menu (or use Composer ->"
- " Export... to any supported file format)."
- ) );
- addGuiTip( myTip );
- // by Harrissou Sant-anna
- myTip.setTitle( tr( "Start QGIS from command line" ) );
- myTip.setContent( tr( "QGIS can be launched from command line and supports a number of options. This can be"
- " handy if you need to use QGIS with particular configurations such as custom"
- " user profile or, without plugins... To get the list of the options,"
- " enter qgis --help on the command line."
- ) );
- addGuiTip( myTip );
- // by Harrissou Sant-anna
- myTip.setTitle( tr( "Set your own shortcuts for your actions" ) );
- myTip.setContent( tr( "QGIS provides you with a list of predefined shortcuts you can use to speed"
- " your workflow. These are available under %1 -> %2 "
- " menu and can be extended and customized for any dialog or tool." )
- .arg( tr( "Settings" ) )
- .arg( tr( "Keyboard Shortcuts" ) )
- );
- addGuiTip( myTip );
-
- /* Template for adding more tips
- myTip.setTitle(tr(""));
- myTip.setContent(tr(""
- ));
- addGuiTip(myTip);
- */
-}
-
-QgsTipFactory::~QgsTipFactory()
-{
-
-}
-//private helper method
-void QgsTipFactory::addGuiTip( const QgsTip &tip )
-{
- mGuiTips << tip;
- mAllTips << tip;
-}
-//private helper method
-void QgsTipFactory::addGenericTip( const QgsTip &tip )
-{
- mGenericTips << tip;
- mAllTips << tip;
-}
-QgsTip QgsTipFactory::getTip()
-{
- int myRand = qrand();
- int myValue = static_cast( myRand % mAllTips.count() ); //range [0,(count-1)]
- QgsTip myTip = mAllTips.at( myValue );
- return myTip;
-}
-QgsTip QgsTipFactory::getTip( int position )
-{
- QgsTip myTip = mAllTips.at( position );
- return myTip;
-}
-QgsTip QgsTipFactory::getGenericTip()
-{
- int myRand = qrand();
- int myValue = static_cast( myRand % mGenericTips.count() ); //range [0,(count-1)]
- QgsTip myTip = mGenericTips.at( myValue );
- return myTip;
-}
-QgsTip QgsTipFactory::getGuiTip()
-{
- int myRand = qrand();
- int myValue = static_cast( myRand % mGuiTips.count() ); //range [0,(count-1)]
- QgsTip myTip = mGuiTips.at( myValue );
- return myTip;
-}
-
-int QgsTipFactory::randomNumber( int max )
-{
- Q_UNUSED( max );
- return 0;
-}
-
-int QgsTipFactory::position( QgsTip tip )
-{
- for ( int i = 0; i < mAllTips.count(); ++i )
- {
- QgsTip myTip = mAllTips.at( i );
- if ( myTip.title() == tip.title() )
- {
- return i;
- }
- }
- return -1;
-}
-
-int QgsTipFactory::count()
-{
- return mAllTips.count();
-}
diff --git a/src/app/qgstipfactory.h b/src/app/qgstipfactory.h
deleted file mode 100644
index 9c66aa80090..00000000000
--- a/src/app/qgstipfactory.h
+++ /dev/null
@@ -1,77 +0,0 @@
-/***************************************************************************
- qgstipfactory.h
- ---------------------
- begin : February 2011
- copyright : (C) 2011 by Tim Sutton
- email : tim at linfiniti dot com
- ***************************************************************************
- * *
- * 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. *
- * *
- ***************************************************************************/
-
-#ifndef QGSTIPFACTORY
-#define QGSTIPFACTORY
-
-#include "qgstip.h"
-#include
-#include "qgis_app.h"
-
-/** \ingroup app
-* \brief A factory class to serve up tips to the user.
-* Tips can be generic, in which case they make no mention of
-* gui dialogs etc, or gui-specific in which case they may allude
-* to features of the graphical user interface.
-* \see also QgsTipOfTheDay, QgsTip
-*/
-
-class APP_EXPORT QgsTipFactory : public QObject
-{
- Q_OBJECT //used for tr() so we don't need to do QObject::tr()
- public:
- //! Constructor
- QgsTipFactory();
-
- ~QgsTipFactory();
-
- /** Get a random tip (generic or gui-centric)
- * \returns An QgsTip containing the tip
- */
- QgsTip getTip();
-
- /** Get a specific tip (generic or gui-centric).
- * \param position The tip returned will be based on the
- * number passed in as position. If the
- * position is invalid, an empty string will be
- * returned.
- * \returns An QgsTip containing the tip
- */
- QgsTip getTip( int position );
-
- /** Get a random generic tip
- * \returns An QgsTip containing the tip
- */
- QgsTip getGenericTip();
-
- /** Get a random gui-centric tip
- * \returns An QgsTip containing the tip
- */
- QgsTip getGuiTip();
-
- int position( QgsTip );
- int count();
-
- private:
- void addGenericTip( const QgsTip & );
- void addGuiTip( const QgsTip & );
- int randomNumber( int max );
- //@TODO move tipts into a sqlite db
- QList mGenericTips;
- QList mGuiTips;
- QList mAllTips;
-};
-#endif //QGSTIPFACTORY
-
diff --git a/src/app/qgstipgui.cpp b/src/app/qgstipgui.cpp
deleted file mode 100644
index bd511c0d20e..00000000000
--- a/src/app/qgstipgui.cpp
+++ /dev/null
@@ -1,108 +0,0 @@
-/***************************************************************************
- qgstipgui.cpp - description
- -------------------
- begin : Sat Aug 10 2002
- copyright : (C) 2002 by Gary E.Sherman
- email : sherman at mrcc.com
- ***************************************************************************/
-
-/***************************************************************************
- * *
- * 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. *
- * *
- ***************************************************************************/
-
-#include
-
-#include "qgstipgui.h"
-#include "qgssettings.h"
-#include "qgsapplication.h"
-#include "qgstip.h"
-#include "qgstipfactory.h"
-
-#ifdef Q_OS_MACX
-QgsTipGui::QgsTipGui( QWidget *parent )
- : QDialog( parent, Qt::WindowSystemMenuHint ) // Dialog with close button only
-#else
-QgsTipGui::QgsTipGui( QWidget * parent )
- : QDialog( parent ) // Normal dialog in non Mac-OS
-#endif
-{
- setupUi( this );
- init();
-}
-
-QgsTipGui::~QgsTipGui()
-{
-}
-
-void QgsTipGui::init()
-{
-
- QgsTipFactory myFactory;
- QgsTip myTip = myFactory.getTip();
- mTipPosition = myFactory.position( myTip );
-
- showTip( myTip );
-
- QPushButton *pb = nullptr;
- pb = new QPushButton( tr( "&Previous" ) );
- connect( pb, &QAbstractButton::clicked, this, &QgsTipGui::prevClicked );
- buttonBox->addButton( pb, QDialogButtonBox::ActionRole );
-
- pb = new QPushButton( tr( "&Next" ) );
- connect( pb, &QAbstractButton::clicked, this, &QgsTipGui::nextClicked );
- buttonBox->addButton( pb, QDialogButtonBox::ActionRole );
-}
-
-void QgsTipGui::showTip( QgsTip myTip )
-{
- // TODO - This html construction can be simplified using QStringBuilder
- // once Qt 4.6 is the minimum required version for building QGIS.
- //
- QString content = "
"
- + ""
- + myTip.title()
- + "
"
- + myTip.content();
-
- txtTip->setHtml( content );
-}
-
-void QgsTipGui::on_cbxDisableTips_toggled( bool flag )
-{
- QgsSettings settings;
- //note the ! below as when the cbx is checked (true) we want to
- //change the setting to false
- settings.setValue( QStringLiteral( "/qgis/showTips%1" ).arg( Qgis::QGIS_VERSION_INT / 100 ), !flag );
- hide();
-}
-
-void QgsTipGui::nextClicked()
-{
- mTipPosition += 1;
- QgsTipFactory myFactory;
- if ( mTipPosition >= myFactory.count() )
- {
- mTipPosition = 0;
- }
- QgsTip myTip = myFactory.getTip( mTipPosition );
- showTip( myTip );
-}
-
-void QgsTipGui::prevClicked()
-{
- mTipPosition -= 1;
- QgsTipFactory myFactory;
- if ( mTipPosition < 0 )
- {
- mTipPosition = myFactory.count() - 1;
- }
- QgsTip myTip = myFactory.getTip( mTipPosition );
- showTip( myTip );
-}
diff --git a/src/app/qgstipgui.h b/src/app/qgstipgui.h
deleted file mode 100644
index fd62ea2e9ae..00000000000
--- a/src/app/qgstipgui.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/***************************************************************************
- qgstipgui.h - description
- -------------------
- begin : Fri 18 Feb 2011
- copyright : (C) 2011 by Tim Sutton
- email : tim@linfiniti.com
- ***************************************************************************/
-
-/***************************************************************************
- * *
- * 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. *
- * *
- ***************************************************************************/
-#ifndef QGSTIPGUI_H
-#define QGSTIPGUI_H
-
-#include "ui_qgstipguibase.h"
-#include "qgis_app.h"
-class QgsTip;
-
-class APP_EXPORT QgsTipGui : public QDialog, private Ui::QgsTipGuiBase
-{
- Q_OBJECT
- public:
- QgsTipGui( QWidget *parent = nullptr );
- ~QgsTipGui();
-
- private:
- void init();
- void showTip( QgsTip );
-
- int mTipPosition;
-
- private slots:
- void on_cbxDisableTips_toggled( bool flag );
- void prevClicked();
- void nextClicked();
-};
-
-#endif
diff --git a/src/core/processing/qgsprocessingparameters.cpp b/src/core/processing/qgsprocessingparameters.cpp
index db83a397888..af1d1271667 100644
--- a/src/core/processing/qgsprocessingparameters.cpp
+++ b/src/core/processing/qgsprocessingparameters.cpp
@@ -22,6 +22,7 @@
#include "qgsprocessingoutputs.h"
#include "qgssettings.h"
#include "qgsvectorfilewriter.h"
+#include
bool QgsProcessingParameters::isDynamic( const QVariantMap ¶meters, const QString &name )
{
@@ -596,33 +597,38 @@ QList QgsProcessingParameters::parameterAsLayerList( const QgsPro
QStringList resultStringList;
- if ( val.canConvert() )
- resultStringList << val.value< QgsProperty >().valueAsString( context.expressionContext(), definition->defaultValue().toString() );
- else if ( val.type() == QVariant::List )
+ std::function< void( const QVariant &var ) > processVariant;
+ processVariant = [ &resultStringList, &layers, &context, &definition, &processVariant ]( const QVariant & var )
{
- Q_FOREACH ( const QVariant &var, val.toList() )
+ if ( var.type() == QVariant::List )
{
- if ( QgsMapLayer *layer = qobject_cast< QgsMapLayer * >( qvariant_cast( var ) ) )
+ Q_FOREACH ( const QVariant &listVar, var.toList() )
{
- layers << layer;
- }
- else
- {
- resultStringList << var.toString();
+ processVariant( listVar );
}
}
- }
- else if ( val.type() == QVariant::StringList )
- {
- Q_FOREACH ( const QString &s, val.toStringList() )
+ else if ( var.type() == QVariant::StringList )
{
- resultStringList << s;
+ Q_FOREACH ( const QString &s, var.toStringList() )
+ {
+ resultStringList << s;
+ }
}
- }
- else
- resultStringList << val.toString();
+ else if ( var.canConvert() )
+ resultStringList << var.value< QgsProperty >().valueAsString( context.expressionContext(), definition->defaultValue().toString() );
+ else if ( QgsMapLayer *layer = qobject_cast< QgsMapLayer * >( qvariant_cast( var ) ) )
+ {
+ layers << layer;
+ }
+ else
+ {
+ resultStringList << var.toString();
+ }
+ };
- if ( ( resultStringList.isEmpty() || resultStringList.at( 0 ).isEmpty() ) )
+ processVariant( val );
+
+ if ( layers.isEmpty() && ( resultStringList.isEmpty() || resultStringList.at( 0 ).isEmpty() ) )
{
resultStringList.clear();
// check default
diff --git a/src/core/qgsapplication.cpp b/src/core/qgsapplication.cpp
index 9228571278d..455ff6adfe3 100644
--- a/src/core/qgsapplication.cpp
+++ b/src/core/qgsapplication.cpp
@@ -614,21 +614,6 @@ QString QgsApplication::licenceFilePath()
return ABISYM( mPkgDataPath ) + QStringLiteral( "/doc/LICENSE" );
}
-QString QgsApplication::helpAppPath()
-{
- QString helpAppPath;
-#ifdef Q_OS_MACX
- helpAppPath = applicationDirPath() + "/bin/qgis_help.app/Contents/MacOS";
-#else
- helpAppPath = libexecPath();
-#endif
- helpAppPath += QLatin1String( "/qgis_help" );
-#ifdef Q_OS_WIN
- helpAppPath += ".exe";
-#endif
- return helpAppPath;
-}
-
QString QgsApplication::i18nPath()
{
if ( ABISYM( mRunningFromBuildDir ) )
diff --git a/src/core/qgsapplication.h b/src/core/qgsapplication.h
index f9219ba39da..694e7b0a85a 100644
--- a/src/core/qgsapplication.h
+++ b/src/core/qgsapplication.h
@@ -234,9 +234,6 @@ class CORE_EXPORT QgsApplication : public QApplication
*/
static QString licenceFilePath();
- //! Returns the path to the help application.
- static QString helpAppPath();
-
//! Returns the path to the translation directory.
static QString i18nPath();
diff --git a/src/providers/ogr/qgsgeopackagedataitems.cpp b/src/providers/ogr/qgsgeopackagedataitems.cpp
index a51531334ad..7806067f0d5 100644
--- a/src/providers/ogr/qgsgeopackagedataitems.cpp
+++ b/src/providers/ogr/qgsgeopackagedataitems.cpp
@@ -20,13 +20,18 @@
#include "qgsproject.h"
#include "qgsvectorlayer.h"
#include "qgsrasterlayer.h"
+#include "qgsogrprovider.h"
#include "qgsnewgeopackagelayerdialog.h"
+#include "qgsmessageoutput.h"
+#include "qgsvectorlayerexporter.h"
#include
#include
#include
#include
+QGISEXTERN bool deleteLayer( const QString &uri, const QString &errCause );
+
QgsDataItem *QgsGeoPackageDataItemProvider::createDataItem( const QString &path, QgsDataItem *parentItem )
{
QgsDebugMsg( "path = " + path );
@@ -268,6 +273,115 @@ QList QgsGeoPackageConnectionItem::actions()
}
#endif
+
+
+bool QgsGeoPackageConnectionItem::handleDrop( const QMimeData *data, Qt::DropAction )
+{
+
+ if ( !QgsMimeDataUtils::isUriList( data ) )
+ return false;
+
+ // TODO: probably should show a GUI with settings etc
+ QString uri;
+
+ QStringList importResults;
+ bool hasError = false;
+
+ QgsMimeDataUtils::UriList lst = QgsMimeDataUtils::decodeUriList( data );
+ Q_FOREACH ( const QgsMimeDataUtils::Uri &u, lst )
+ {
+ if ( u.layerType == QStringLiteral( "vector" ) )
+ {
+ // open the source layer
+ bool owner;
+ QString error;
+ QgsVectorLayer *srcLayer = u.vectorLayer( owner, error );
+ if ( !srcLayer )
+ {
+ importResults.append( tr( "%1: %2" ).arg( u.name ).arg( error ) );
+ hasError = true;
+ continue;
+ }
+
+ if ( srcLayer->isValid() )
+ {
+ uri = mPath;
+ QgsDebugMsgLevel( "URI " + uri, 3 );
+
+ // check if the destination layer already exists
+ bool exists = false;
+ // Q_FOREACH won't detach ...
+ for ( const auto child : children() )
+ {
+ if ( child->name() == u.name )
+ {
+ exists = true;
+ }
+ }
+ if ( ! exists || QMessageBox::question( nullptr, tr( "Overwrite Layer" ),
+ tr( "Destination layer %1 already exists. Do you want to overwrite it?" ).arg( u.name ), QMessageBox::Yes | QMessageBox::No ) == QMessageBox::Yes )
+ {
+
+ std::unique_ptr< QMap > options( new QMap );
+ options->insert( QStringLiteral( "driverName" ), QStringLiteral( "GPKG" ) );
+ options->insert( QStringLiteral( "update" ), true );
+ options->insert( QStringLiteral( "overwrite" ), true );
+ options->insert( QStringLiteral( "layerName" ), u.name );
+
+ std::unique_ptr< QgsVectorLayerExporterTask > exportTask( new QgsVectorLayerExporterTask( srcLayer, uri, QStringLiteral( "ogr" ), srcLayer->crs(), options.get(), owner ) );
+
+ // when export is successful:
+ connect( exportTask.get(), &QgsVectorLayerExporterTask::exportComplete, this, [ = ]()
+ {
+ // this is gross - TODO - find a way to get access to messageBar from data items
+ QMessageBox::information( nullptr, tr( "Import to GeoPackage database" ), tr( "Import was successful." ) );
+ refreshConnections();
+ } );
+
+ // when an error occurs:
+ connect( exportTask.get(), &QgsVectorLayerExporterTask::errorOccurred, this, [ = ]( int error, const QString & errorMessage )
+ {
+ if ( error != QgsVectorLayerExporter::ErrUserCanceled )
+ {
+ QgsMessageOutput *output = QgsMessageOutput::createMessageOutput();
+ output->setTitle( tr( "Import to GeoPackage database" ) );
+ output->setMessage( tr( "Failed to import some layers!\n\n" ) + errorMessage, QgsMessageOutput::MessageText );
+ output->showMessage();
+ }
+ } );
+
+ QgsApplication::taskManager()->addTask( exportTask.release() );
+ }
+ }
+ else
+ {
+ importResults.append( tr( "%1: Not a valid layer!" ).arg( u.name ) );
+ hasError = true;
+ }
+ }
+ else
+ {
+ // TODO: implemnent raster import
+ QgsMessageOutput *output = QgsMessageOutput::createMessageOutput();
+ output->setTitle( tr( "Import to GeoPackage database faile" ) );
+ output->setMessage( tr( "Failed to import some layers!\n\n" ) + QStringLiteral( "Raster import is not yet implemented!\n" ), QgsMessageOutput::MessageText );
+ output->showMessage();
+ }
+
+ }
+
+ if ( hasError )
+ {
+ QgsMessageOutput *output = QgsMessageOutput::createMessageOutput();
+ output->setTitle( tr( "Import to GeoPackage database" ) );
+ output->setMessage( tr( "Failed to import some layers!\n\n" ) + importResults.join( QStringLiteral( "\n" ) ), QgsMessageOutput::MessageText );
+ output->showMessage();
+ }
+
+ return true;
+}
+
+
QgsLayerItem::LayerType QgsGeoPackageConnectionItem::layerTypeFromDb( const QString &geometryType )
{
if ( geometryType.contains( QStringLiteral( "Point" ), Qt::CaseInsensitive ) )
@@ -327,7 +441,6 @@ void QgsGeoPackageConnectionItem::addTable()
QList QgsGeoPackageAbstractLayerItem::actions()
{
QList lst;
-
// TODO: delete layer when the provider supports it (not currently implemented)
return lst;
}
@@ -352,3 +465,55 @@ QgsGeoPackageRasterLayerItem::QgsGeoPackageRasterLayerItem( QgsDataItem *parent,
{
}
+
+
+#ifdef HAVE_GUI
+QList QgsGeoPackageVectorLayerItem::actions()
+{
+ QList lst = QgsGeoPackageAbstractLayerItem::actions();
+ QAction *actionDeleteLayer = new QAction( tr( "Delete layer '%1'..." ).arg( mName ), this );
+ connect( actionDeleteLayer, &QAction::triggered, this, &QgsGeoPackageVectorLayerItem::deleteLayer );
+ lst.append( actionDeleteLayer );
+ return lst;
+}
+
+
+void QgsGeoPackageVectorLayerItem::deleteLayer()
+{
+ // Check if the layer is in the registry
+ const QgsMapLayer *projectLayer = nullptr;
+ Q_FOREACH ( const QgsMapLayer *layer, QgsProject::instance()->mapLayers() )
+ {
+ if ( layer->publicSource() == mUri )
+ {
+ projectLayer = layer;
+ }
+ }
+ if ( ! projectLayer )
+ {
+ if ( QMessageBox::question( nullptr, QObject::tr( "Delete Layer" ),
+ QObject::tr( "Are you sure you want to delete layer '%1' from GeoPackage?" ).arg( mName ),
+ QMessageBox::Yes | QMessageBox::No, QMessageBox::No ) != QMessageBox::Yes )
+ return;
+
+ QString errCause;
+ bool res = ::deleteLayer( mUri, errCause );
+ if ( !res )
+ {
+ QMessageBox::warning( nullptr, tr( "Delete Layer" ), errCause );
+ }
+ else
+ {
+ QMessageBox::information( nullptr, tr( "Delete Layer" ), tr( "Layer deleted successfully." ) );
+ if ( mParent )
+ mParent->refresh();
+ }
+ }
+ else
+ {
+ QMessageBox::warning( nullptr, QObject::tr( "Delete Layer" ), QObject::tr( "The layer '%1' cannot be deleted because it is in the current project as '%2',"
+ " remove it from the project and retry." ).arg( mName, projectLayer->name() ) );
+ }
+}
+#endif
+
diff --git a/src/providers/ogr/qgsgeopackagedataitems.h b/src/providers/ogr/qgsgeopackagedataitems.h
index 3d47d4da921..d736cb4dded 100644
--- a/src/providers/ogr/qgsgeopackagedataitems.h
+++ b/src/providers/ogr/qgsgeopackagedataitems.h
@@ -49,7 +49,11 @@ class QgsGeoPackageVectorLayerItem : public QgsGeoPackageAbstractLayerItem
Q_OBJECT
public:
QgsGeoPackageVectorLayerItem( QgsDataItem *parent, QString name, QString path, QString uri, LayerType layerType );
-
+#ifdef HAVE_GUI
+ QList actions() override;
+ public slots:
+ void deleteLayer();
+#endif
};
@@ -67,7 +71,7 @@ class QgsGeoPackageConnectionItem : public QgsDataCollectionItem
#endif
virtual bool acceptDrop() override { return true; }
- //virtual bool handleDrop( const QMimeData *data, Qt::DropAction action ) override;
+ virtual bool handleDrop( const QMimeData *data, Qt::DropAction action ) override;
//! Return the layer type from \a geometryType
static QgsLayerItem::LayerType layerTypeFromDb( const QString &geometryType );
diff --git a/src/providers/ogr/qgsogrdataitems.cpp b/src/providers/ogr/qgsogrdataitems.cpp
index 2f92da08872..6aef581b5c6 100644
--- a/src/providers/ogr/qgsogrdataitems.cpp
+++ b/src/providers/ogr/qgsogrdataitems.cpp
@@ -18,10 +18,12 @@
#include "qgslogger.h"
#include "qgsmessagelog.h"
#include "qgssettings.h"
+#include "qgsproject.h"
#include
#include
#include
+#include
#include
#include
@@ -31,11 +33,14 @@
QGISEXTERN QStringList fileExtensions();
QGISEXTERN QStringList wildcards();
+QGISEXTERN bool deleteLayer( const QString &uri, const QString &errCause );
+
QgsOgrLayerItem::QgsOgrLayerItem( QgsDataItem *parent,
- QString name, QString path, QString uri, LayerType layerType )
+ QString name, QString path, QString uri, LayerType layerType, bool isSubLayer )
: QgsLayerItem( parent, name, path, uri, layerType, QStringLiteral( "ogr" ) )
{
+ mIsSubLayer = isSubLayer;
mToolTip = uri;
setState( Populated ); // children are not expected
@@ -56,6 +61,7 @@ QgsOgrLayerItem::QgsOgrLayerItem( QgsDataItem *parent,
}
}
+
bool QgsOgrLayerItem::setCrs( const QgsCoordinateReferenceSystem &crs )
{
if ( !( mCapabilities & SetCrs ) )
@@ -110,9 +116,71 @@ QString QgsOgrLayerItem::layerName() const
return info.completeBaseName();
}
+#ifdef HAVE_GUI
+QList QgsOgrLayerItem::actions()
+{
+ QList lst;
+ // Messages are different for files and tables
+ QString message = mIsSubLayer ? QObject::tr( "Delete layer '%1'..." ).arg( mName ) : QObject::tr( "Delete file '%1'..." ).arg( mUri );
+ QAction *actionDeleteLayer = new QAction( message, this );
+ connect( actionDeleteLayer, &QAction::triggered, this, &QgsOgrLayerItem::deleteLayer );
+ lst.append( actionDeleteLayer );
+ return lst;
+}
+
+void QgsOgrLayerItem::deleteLayer()
+{
+ // Messages are different for files and tables
+ QString title = mIsSubLayer ? QObject::tr( "Delete Layer" ) : QObject::tr( "Delete File" );
+ // Check if the layer is in the registry
+ const QgsMapLayer *projectLayer = nullptr;
+ Q_FOREACH ( const QgsMapLayer *layer, QgsProject::instance()->mapLayers() )
+ {
+ if ( layer->publicSource() == mUri )
+ {
+ projectLayer = layer;
+ }
+ }
+ if ( ! projectLayer )
+ {
+ QString confirmMessage;
+ if ( mIsSubLayer )
+ {
+ confirmMessage = QObject::tr( "Are you sure you want to delete layer '%1' from datasource?" ).arg( mName );
+ }
+ else
+ {
+ confirmMessage = QObject::tr( "Are you sure you want to delete file '%1'?" ).arg( mUri );
+ }
+ if ( QMessageBox::question( nullptr, title,
+ confirmMessage,
+ QMessageBox::Yes | QMessageBox::No, QMessageBox::No ) != QMessageBox::Yes )
+ return;
+
+ QString errCause;
+ bool res = ::deleteLayer( mUri, errCause );
+ if ( !res )
+ {
+ QMessageBox::warning( nullptr, title, errCause );
+ }
+ else
+ {
+ QMessageBox::information( nullptr, title, mIsSubLayer ? tr( "Layer deleted successfully." ) : tr( "File deleted successfully." ) );
+ if ( mParent )
+ mParent->refresh();
+ }
+ }
+ else
+ {
+ QMessageBox::warning( nullptr, title, QObject::tr( "The layer '%1' cannot be deleted because it is in the current project as '%2',"
+ " remove it from the project and retry." ).arg( mName, projectLayer->name() ) );
+ }
+}
+#endif
+
// -------
-static QgsOgrLayerItem *dataItemForLayer( QgsDataItem *parentItem, QString name, QString path, OGRDataSourceH hDataSource, int layerId )
+static QgsOgrLayerItem *dataItemForLayer( QgsDataItem *parentItem, QString name, QString path, OGRDataSourceH hDataSource, int layerId, bool isSubLayer = false )
{
OGRLayerH hLayer = OGR_DS_GetLayer( hDataSource, layerId );
OGRFeatureDefnH hDef = OGR_L_GetLayerDefn( hLayer );
@@ -166,7 +234,7 @@ static QgsOgrLayerItem *dataItemForLayer( QgsDataItem *parentItem, QString name,
QgsDebugMsgLevel( "OGR layer uri : " + layerUri, 2 );
- return new QgsOgrLayerItem( parentItem, name, path, layerUri, layerType );
+ return new QgsOgrLayerItem( parentItem, name, path, layerUri, layerType, isSubLayer );
}
// ----
@@ -189,7 +257,7 @@ QVector QgsOgrDataCollectionItem::createChildren()
children.reserve( numLayers );
for ( int i = 0; i < numLayers; ++i )
{
- QgsOgrLayerItem *item = dataItemForLayer( this, QString(), mPath, hDataSource, i );
+ QgsOgrLayerItem *item = dataItemForLayer( this, QString(), mPath, hDataSource, i, true );
children.append( item );
}
diff --git a/src/providers/ogr/qgsogrdataitems.h b/src/providers/ogr/qgsogrdataitems.h
index a81ff1ba58d..5edf1bdb0ea 100644
--- a/src/providers/ogr/qgsogrdataitems.h
+++ b/src/providers/ogr/qgsogrdataitems.h
@@ -24,11 +24,19 @@ class QgsOgrLayerItem : public QgsLayerItem
{
Q_OBJECT
public:
- QgsOgrLayerItem( QgsDataItem *parent, QString name, QString path, QString uri, LayerType layerType );
+ QgsOgrLayerItem( QgsDataItem *parent, QString name, QString path, QString uri, LayerType layerType, bool isSubLayer = false );
bool setCrs( const QgsCoordinateReferenceSystem &crs ) override;
QString layerName() const override;
+
+#ifdef HAVE_GUI
+ QList actions() override;
+ public slots:
+ void deleteLayer();
+#endif
+ private:
+ bool mIsSubLayer;
};
diff --git a/src/providers/ogr/qgsogrprovider.cpp b/src/providers/ogr/qgsogrprovider.cpp
index e7dbdf088c1..c9f83520b7c 100644
--- a/src/providers/ogr/qgsogrprovider.cpp
+++ b/src/providers/ogr/qgsogrprovider.cpp
@@ -4297,3 +4297,76 @@ QGISEXTERN void cleanupProvider()
// NOTE: QgsApplication takes care of
// calling OGRCleanupAll();
}
+
+
+
+QGISEXTERN bool deleteLayer( const QString &uri, QString &errCause )
+{
+ bool isSubLayer;
+ int layerIndex;
+ QString layerName;
+ QString subsetString;
+ OGRwkbGeometryType ogrGeometryType;
+ QString filePath = AnalyzeURI( uri,
+ isSubLayer,
+ layerIndex,
+ layerName,
+ subsetString,
+ ogrGeometryType );
+
+ OGRDataSourceH hDS = GDALOpenEx( filePath.toLocal8Bit().data(), GDAL_OF_RASTER | GDAL_OF_VECTOR | GDAL_OF_UPDATE, NULL, NULL, NULL );
+ if ( hDS && ( ! layerName.isEmpty() || layerIndex != -1 ) )
+ {
+ if ( layerIndex == -1 )
+ {
+ for ( int i = 0; i < GDALDatasetGetLayerCount( hDS ); i++ )
+ {
+ OGRLayerH hL = GDALDatasetGetLayer( hDS, i );
+ if ( layerName == QString( OGR_L_GetName( hL ) ) )
+ {
+ layerIndex = i;
+ }
+ }
+ }
+ OGRErr error = GDALDatasetDeleteLayer( hDS, layerIndex );
+ switch ( error )
+ {
+ case OGRERR_NOT_ENOUGH_DATA:
+ errCause = QObject::tr( "Not enough data to deserialize" );
+ break;
+ case OGRERR_NOT_ENOUGH_MEMORY:
+ errCause = QObject::tr( "Not enough memory" );
+ break;
+ case OGRERR_UNSUPPORTED_GEOMETRY_TYPE:
+ errCause = QObject::tr( "Unsupported geometry type" );
+ break;
+ case OGRERR_UNSUPPORTED_OPERATION:
+ errCause = QObject::tr( "Unsupported operation" );
+ break;
+ case OGRERR_CORRUPT_DATA:
+ errCause = QObject::tr( "Corrupt data" );
+ break;
+ case OGRERR_FAILURE:
+ errCause = QObject::tr( "Failure" );
+ break;
+ case OGRERR_UNSUPPORTED_SRS:
+ errCause = QObject::tr( "Unsupported SRS" );
+ break;
+ case OGRERR_INVALID_HANDLE:
+ errCause = QObject::tr( "Invalid handle" );
+ break;
+ case OGRERR_NON_EXISTING_FEATURE:
+ errCause = QObject::tr( "Non existing feature" );
+ break;
+ default:
+ case OGRERR_NONE:
+ errCause = QObject::tr( "Success" );
+ break;
+ }
+ errCause = QObject::tr( "GDAL result code: %s" ).arg( errCause );
+ return error == OGRERR_NONE;
+ }
+ // This should never happen:
+ errCause = QObject::tr( "Layer not found: %s" ).arg( uri );
+ return false;
+}
diff --git a/src/ui/qgsoptionsbase.ui b/src/ui/qgsoptionsbase.ui
index 4d1bf4b5a8c..c37595786e9 100755
--- a/src/ui/qgsoptionsbase.ui
+++ b/src/ui/qgsoptionsbase.ui
@@ -602,8 +602,32 @@
-
-
-
-
+
+
+ 0
+
+
-
+
+
+ Modeless data source manager dialog
+
+
+
+ -
+
+
+ QGIS-styled group boxes
+
+
+
+ -
+
+
+ Check QGIS version at startup
+
+
+
+ -
@@ -616,82 +640,14 @@
- -
-
-
-
- 12
- 0
-
-
-
- Qt::Vertical
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- Show tips at start up
-
-
-
- -
-
-
-
- 12
- 0
-
-
-
- Qt::Vertical
-
-
-
- -
-
-
- Check QGIS version at startup
-
-
-
-
-
- -
-
-
-
-
-
- Modeless data source manager dialog
-
-
-
- -
-
-
- QGIS-styled group boxes
-
-
-
-
-
- -
-
-
-
+
-
Use native color chooser dialogs
- -
+
-
Use live-updating color chooser dialogs
@@ -5543,12 +5499,6 @@ The bigger the number, the faster zooming with the mouse wheel will be.
mFontFamilyComboBox
spinFontSize
mMessageTimeoutSpnBx
- cbxHideSplash
- cbxShowTips
- cbxCheckVersion
- mCustomGroupBoxChkBx
- mNativeColorDialogsChkBx
- mLiveColorDialogsChkBx
groupBox_11
mProjectOnLaunchCmbBx
mProjectOnLaunchLineEdit
diff --git a/tests/src/analysis/CMakeLists.txt b/tests/src/analysis/CMakeLists.txt
index e79255854bd..21835c35c4f 100644
--- a/tests/src/analysis/CMakeLists.txt
+++ b/tests/src/analysis/CMakeLists.txt
@@ -63,7 +63,6 @@ ENDMACRO (ADD_QGIS_TEST)
#############################################################
# Tests:
SET(TESTS
- testqgsvectoranalyzer.cpp
testqgsgeometrysnapper.cpp
testopenstreetmap.cpp
testqgszonalstatistics.cpp
diff --git a/tests/src/analysis/testqgsvectoranalyzer.cpp b/tests/src/analysis/testqgsvectoranalyzer.cpp
deleted file mode 100644
index 057b210121b..00000000000
--- a/tests/src/analysis/testqgsvectoranalyzer.cpp
+++ /dev/null
@@ -1,145 +0,0 @@
-/***************************************************************************
- testqgsvectoranalyzer.cpp
- --------------------------------------
-Date : Sun Sep 16 12:22:49 AKDT 2007
-Copyright : (C) 2007 by Gary E. Sherman
-Email : sherman at mrcc dot com
- ***************************************************************************
- * *
- * 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. *
- * *
- ***************************************************************************/
-#include "qgstest.h"
-
-//header for class being tested
-#include
-#include
-#include
-#include "qgsvectorlayer.h"
-
-class TestQgsVectorAnalyzer : public QObject
-{
- Q_OBJECT
-
- public:
- TestQgsVectorAnalyzer()
- : mpLineLayer( 0 )
- , mpPolyLayer( 0 )
- , mpPointLayer( 0 )
- {}
-
- private slots:
- void initTestCase();// will be called before the first testfunction is executed.
- void cleanupTestCase();// will be called after the last testfunction was executed.
- void init() ;// will be called before each testfunction is executed.
- void cleanup() ;// will be called after every testfunction.
- //! Our tests proper begin here
- void singleToMulti();
- void multiToSingle();
- void extractNodes();
- void polygonsToLines();
- void exportGeometryInfo();
- void simplifyGeometry();
- void polygonCentroids();
- void layerExtent();
- private:
- QgsGeometryAnalyzer mAnalyzer;
- QgsVectorLayer *mpLineLayer = nullptr;
- QgsVectorLayer *mpPolyLayer = nullptr;
- QgsVectorLayer *mpPointLayer = nullptr;
-
-};
-
-void TestQgsVectorAnalyzer::initTestCase()
-{
- //
- // Runs once before any tests are run
- //
- // init QGIS's paths - true means that all path will be inited from prefix
- QgsApplication::init();
- QgsApplication::initQgis();
- QgsApplication::showSettings();
-
- //create some objects that will be used in all tests...
- //create a map layer that will be used in all tests...
- QString myBaseFileName( TEST_DATA_DIR ); //defined in CmakeLists.txt
- QString myEndName = QStringLiteral( "lines.shp" );
- QString myFileName = myBaseFileName + '/' + myEndName;
- qDebug() << myFileName;
- QFileInfo myLineInfo( myFileName );
- mpLineLayer = new QgsVectorLayer( myLineInfo.filePath(),
- myLineInfo.completeBaseName(), QStringLiteral( "ogr" ) );
-
- myEndName = QStringLiteral( "polys.shp" );
- myFileName = myBaseFileName + '/' + myEndName;
- QFileInfo myPolyInfo( myFileName );
- mpPolyLayer = new QgsVectorLayer( myPolyInfo.filePath(),
- myPolyInfo.completeBaseName(), QStringLiteral( "ogr" ) );
-
- myEndName = QStringLiteral( "points.shp" );
- myFileName = myBaseFileName + '/' + myEndName;
- QFileInfo myPointInfo( myFileName );
- mpPointLayer = new QgsVectorLayer( myPointInfo.filePath(),
- myPointInfo.completeBaseName(), QStringLiteral( "ogr" ) );
-}
-void TestQgsVectorAnalyzer::cleanupTestCase()
-{
- delete mpLineLayer;
- delete mpPolyLayer;
- delete mpPointLayer;
- QgsApplication::exitQgis();
-}
-void TestQgsVectorAnalyzer::init()
-{
-
-}
-void TestQgsVectorAnalyzer::cleanup()
-{
-
-}
-void TestQgsVectorAnalyzer::singleToMulti()
-{
-
-}
-void TestQgsVectorAnalyzer::multiToSingle()
-{
-
-}
-void TestQgsVectorAnalyzer::extractNodes()
-{
-
-}
-void TestQgsVectorAnalyzer::polygonsToLines()
-{
-
-}
-void TestQgsVectorAnalyzer::exportGeometryInfo()
-{
-}
-
-void TestQgsVectorAnalyzer::simplifyGeometry()
-{
- QString myTmpDir = QDir::tempPath() + '/';
- QString myFileName = myTmpDir + "simplify_layer.shp";
- QVERIFY( mAnalyzer.simplify( mpLineLayer, myFileName, 1.0 ) );
-}
-
-void TestQgsVectorAnalyzer::polygonCentroids()
-{
- QString myTmpDir = QDir::tempPath() + '/';
- QString myFileName = myTmpDir + "centroid_layer.shp";
- QVERIFY( mAnalyzer.centroids( mpPolyLayer, myFileName ) );
-}
-
-void TestQgsVectorAnalyzer::layerExtent()
-{
- QString myTmpDir = QDir::tempPath() + '/';
- QString myFileName = myTmpDir + "extent_layer.shp";
- QVERIFY( mAnalyzer.extent( mpPointLayer, myFileName ) );
-}
-
-QGSTEST_MAIN( TestQgsVectorAnalyzer )
-#include "testqgsvectoranalyzer.moc"
diff --git a/tests/src/core/testqgsprocessing.cpp b/tests/src/core/testqgsprocessing.cpp
index 10915eaf1a1..87ff8bcb6b0 100644
--- a/tests/src/core/testqgsprocessing.cpp
+++ b/tests/src/core/testqgsprocessing.cpp
@@ -2183,7 +2183,8 @@ void TestQgsProcessing::parameterLayerList()
QFileInfo fi1( raster1 );
QgsRasterLayer *r1 = new QgsRasterLayer( fi1.filePath(), "R1" );
QgsVectorLayer *v1 = new QgsVectorLayer( "Polygon?crs=EPSG:3111", "V4", "memory" );
- p.addMapLayers( QList() << v1 << r1 );
+ QgsVectorLayer *v2 = new QgsVectorLayer( "Polygon?crs=EPSG:3111", "V5", "memory" );
+ p.addMapLayers( QList() << v1 << v2 << r1 );
QgsProcessingContext context;
context.setProject( &p );
@@ -2225,6 +2226,14 @@ void TestQgsProcessing::parameterLayerList()
params.insert( "non_optional", QVariantList() << QVariant::fromValue( v1 ) << QVariant::fromValue( r1 ) );
QCOMPARE( QgsProcessingParameters::parameterAsLayerList( def.get(), params, context ), QList< QgsMapLayer *>() << v1 << r1 );
+ // mix of list and single layers (happens from models)
+ params.insert( "non_optional", QVariantList() << QVariant( QVariantList() << QVariant::fromValue( v1 ) << QVariant::fromValue( v2 ) ) << QVariant::fromValue( r1 ) );
+ QCOMPARE( QgsProcessingParameters::parameterAsLayerList( def.get(), params, context ), QList< QgsMapLayer *>() << v1 << v2 << r1 );
+
+ // mix of two lists (happens from models)
+ params.insert( "non_optional", QVariantList() << QVariant( QVariantList() << QVariant::fromValue( v1 ) << QVariant::fromValue( v2 ) ) << QVariant( QVariantList() << QVariant::fromValue( r1 ) ) );
+ QCOMPARE( QgsProcessingParameters::parameterAsLayerList( def.get(), params, context ), QList< QgsMapLayer *>() << v1 << v2 << r1 );
+
// mix of existing layers and non project layer string
params.insert( "non_optional", QVariantList() << v1->id() << raster2 );
QList< QgsMapLayer *> layers = QgsProcessingParameters::parameterAsLayerList( def.get(), params, context );
@@ -2310,6 +2319,9 @@ void TestQgsProcessing::parameterLayerList()
params.insert( "optional", QVariant() );
QCOMPARE( QgsProcessingParameters::parameterAsLayerList( def.get(), params, context ), QList< QgsMapLayer *>() << v1 );
+ params.insert( "optional", QVariantList() << QVariant::fromValue( r1 ) );
+ QCOMPARE( QgsProcessingParameters::parameterAsLayerList( def.get(), params, context ), QList< QgsMapLayer *>() << r1 );
+
code = def->asScriptCode();
QCOMPARE( code, QStringLiteral( "##optional=optional multiple vector " ) + v1->id() );
fromCode.reset( dynamic_cast< QgsProcessingParameterMultipleLayers * >( QgsProcessingParameters::parameterFromScriptCode( code ) ) );