[qgis] 01/01: New upstream version 2.18.13+dfsg

Bas Couwenberg sebastic at debian.org
Sat Sep 16 23:42:32 UTC 2017


This is an automated email from the git hooks/post-receive script.

sebastic pushed a commit to branch upstream
in repository qgis.

commit 7ebe32a582257857ed65f134ea3f5d87764641fc
Author: Bas Couwenberg <sebastic at xs4all.nl>
Date:   Sun Sep 17 01:38:40 2017 +0200

    New upstream version 2.18.13+dfsg
---
 CMakeLists.txt                                     |   2 +-
 ChangeLog                                          | 319 ++++++++++
 debian/changelog                                   |  10 +-
 doc/TRANSLATORS                                    |  76 +--
 i18n/qgis_de.ts                                    | 660 ++++++++++++---------
 python/core/__init__.py                            |   2 +-
 python/core/composer/qgscomposermodel.sip          |   1 -
 python/core/dxf/qgsdxfexport.sip                   |  14 +
 python/core/qgscoordinatetransform.sip             |   2 +
 python/core/symbology-ng/qgssymbollayerv2utils.sip |   8 +
 .../algs/grass7/description/v.in.dxf.txt           |   4 +-
 .../plugins/processing/algs/qgis/AddTableField.py  |   2 +-
 .../processing/algs/qgis/AutoincrementalField.py   |   2 +-
 .../processing/algs/qgis/BasicStatisticsNumbers.py |   2 +-
 .../processing/algs/qgis/BasicStatisticsStrings.py |   2 +-
 python/plugins/processing/algs/qgis/Boundary.py    |   2 +-
 python/plugins/processing/algs/qgis/BoundingBox.py |   2 +-
 python/plugins/processing/algs/qgis/Buffer.py      |   2 +-
 python/plugins/processing/algs/qgis/Centroids.py   |   2 +-
 .../plugins/processing/algs/qgis/CheckValidity.py  |   2 +-
 python/plugins/processing/algs/qgis/Clip.py        |   2 +-
 python/plugins/processing/algs/qgis/ConcaveHull.py |  13 +-
 python/plugins/processing/algs/qgis/ConvexHull.py  |   4 +-
 .../processing/algs/qgis/Datasources2Vrt.py        |   2 +-
 python/plugins/processing/algs/qgis/Delaunay.py    |   4 +-
 .../plugins/processing/algs/qgis/DeleteColumn.py   |   2 +-
 .../algs/qgis/DeleteDuplicateGeometries.py         |   4 +-
 python/plugins/processing/algs/qgis/DeleteHoles.py |   2 +-
 .../processing/algs/qgis/DensifyGeometries.py      |   2 +-
 .../algs/qgis/DensifyGeometriesInterval.py         |   2 +-
 python/plugins/processing/algs/qgis/Difference.py  |   2 +-
 python/plugins/processing/algs/qgis/Dissolve.py    |   4 +-
 .../processing/algs/qgis/EquivalentNumField.py     |   2 +-
 python/plugins/processing/algs/qgis/ExecuteSQL.py  |   2 +-
 python/plugins/processing/algs/qgis/Explode.py     |   2 +-
 .../processing/algs/qgis/ExportGeometryInfo.py     |   2 +-
 .../processing/algs/qgis/ExtentFromLayer.py        |   2 +-
 .../processing/algs/qgis/ExtractByExpression.py    |  78 +++
 .../processing/algs/qgis/ExtractByLocation.py      |   2 +-
 .../plugins/processing/algs/qgis/ExtractNodes.py   |   2 +-
 .../plugins/processing/algs/qgis/FieldPyculator.py |   2 +-
 .../processing/algs/qgis/FieldsCalculator.py       |   2 +-
 .../plugins/processing/algs/qgis/FieldsMapper.py   |   2 +-
 .../processing/algs/qgis/GeometryConvert.py        |   2 +-
 python/plugins/processing/algs/qgis/Gridify.py     |   2 +-
 python/plugins/processing/algs/qgis/HubDistance.py |   2 +-
 python/plugins/processing/algs/qgis/HubLines.py    |   2 +-
 .../processing/algs/qgis/HypsometricCurves.py      |   2 +-
 .../plugins/processing/algs/qgis/Intersection.py   |   2 +-
 .../plugins/processing/algs/qgis/JoinAttributes.py |   4 +-
 .../processing/algs/qgis/LinesIntersection.py      |   2 +-
 .../processing/algs/qgis/LinesToPolygons.py        |   2 +-
 python/plugins/processing/algs/qgis/MeanCoords.py  |  20 +-
 python/plugins/processing/algs/qgis/Merge.py       |   2 +-
 python/plugins/processing/algs/qgis/MergeLines.py  |   2 +-
 .../processing/algs/qgis/MultipartToSingleparts.py |   2 +-
 .../algs/qgis/NearestNeighbourAnalysis.py          |   2 +-
 .../algs/qgis/OrientedMinimumBoundingBox.py        |   4 +-
 .../plugins/processing/algs/qgis/PointDistance.py  |   4 +-
 .../plugins/processing/algs/qgis/PointOnSurface.py |   2 +-
 .../processing/algs/qgis/PointsDisplacement.py     |   4 +-
 .../processing/algs/qgis/PointsFromLines.py        |   2 +-
 .../processing/algs/qgis/PointsFromPolygons.py     |   2 +-
 .../processing/algs/qgis/PointsInPolygon.py        |   2 +-
 .../processing/algs/qgis/PointsInPolygonUnique.py  |   2 +-
 .../algs/qgis/PointsInPolygonWeighted.py           |   2 +-
 .../processing/algs/qgis/PointsLayerFromTable.py   |   2 +-
 .../plugins/processing/algs/qgis/PointsToPaths.py  |   4 +-
 python/plugins/processing/algs/qgis/Polygonize.py  |   4 +-
 .../processing/algs/qgis/PolygonsToLines.py        |   2 +-
 .../processing/algs/qgis/QGISAlgorithmProvider.py  |   3 +-
 .../plugins/processing/algs/qgis/RandomExtract.py  |   2 +-
 .../algs/qgis/RandomExtractWithinSubsets.py        |   4 +-
 .../processing/algs/qgis/RandomPointsAlongLines.py |   2 +-
 .../processing/algs/qgis/RandomPointsExtent.py     |   2 +-
 .../processing/algs/qgis/RandomPointsLayer.py      |   2 +-
 .../algs/qgis/RandomPointsPolygonsFixed.py         |   2 +-
 .../algs/qgis/RandomPointsPolygonsVariable.py      |   2 +-
 .../algs/qgis/RandomSelectionWithinSubsets.py      |   2 +-
 .../algs/qgis/RectanglesOvalsDiamondsFixed.py      |   2 +-
 .../algs/qgis/RectanglesOvalsDiamondsVariable.py   |   2 +-
 .../processing/algs/qgis/RemoveNullGeometry.py     |   2 +-
 .../plugins/processing/algs/qgis/ReprojectLayer.py |   2 +-
 .../processing/algs/qgis/ReverseLineDirection.py   |   2 +-
 .../processing/algs/qgis/SaveSelectedFeatures.py   |   2 +-
 .../processing/algs/qgis/SelectByLocation.py       |   2 +-
 .../processing/algs/qgis/SimplifyGeometries.py     |   2 +-
 .../algs/qgis/SinglePartsToMultiparts.py           |   2 +-
 python/plugins/processing/algs/qgis/Smooth.py      |   2 +-
 python/plugins/processing/algs/qgis/SpatialJoin.py |   2 +-
 .../processing/algs/qgis/SplitLinesWithLines.py    |   2 +-
 .../processing/algs/qgis/StatisticsByCategories.py |   2 +-
 python/plugins/processing/algs/qgis/SumLines.py    |   2 +-
 .../processing/algs/qgis/SymmetricalDifference.py  |   2 +-
 python/plugins/processing/algs/qgis/TextToFloat.py |   2 +-
 python/plugins/processing/algs/qgis/Union.py       |   4 +-
 python/plugins/processing/algs/qgis/VectorSplit.py |   2 +-
 .../processing/algs/qgis/VoronoiPolygons.py        |   2 +-
 .../processing/algs/qgis/ZonalStatistics.py        |   2 +-
 .../plugins/processing/algs/saga/SagaAlgorithm.py  |  31 +-
 .../algs/saga/description/GridCalculator.txt       |   1 +
 .../algs/saga/description/ReclassifyGridValues.txt |   1 +
 .../saga/description/VectorisingGridClasses.txt    |   2 +-
 .../processing/algs/taudem/TauDEMAlgorithm.py      |   2 +-
 .../processing/gui/RenderingStyleFilePanel.py      |   2 +-
 python/plugins/processing/tests/ToolsTest.py       |  79 +--
 .../tests/testdata/expected/extract_expression.gml |  30 +
 .../tests/testdata/expected/extract_expression.xsd |  45 ++
 .../tests/testdata/qgis_algorithm_tests.yaml       |  12 +
 python/plugins/processing/tools/vector.py          |  24 +-
 python/server/qgswmsconfigparser.sip               |   4 +
 src/analysis/raster/qgsderivativefilter.cpp        |   4 +-
 src/app/composer/qgscomposerscalebarwidget.cpp     |   8 +-
 src/app/composer/qgscomposerscalebarwidget.h       |   6 +-
 src/app/qgisapp.cpp                                |   1 +
 src/app/qgsdxfexportdialog.cpp                     |   6 +-
 src/app/qgsdxfexportdialog.h                       |   1 +
 src/core/composer/qgscomposermodel.cpp             |  19 +-
 src/core/composer/qgscomposermodel.h               |   3 +-
 src/core/composer/qgscomposernodesitem.cpp         |   5 +
 src/core/composer/qgscomposerscalebar.cpp          |   4 +-
 src/core/dxf/qgsdxfexport.cpp                      |   7 +-
 src/core/dxf/qgsdxfexport.h                        |  15 +
 src/core/qgsvectorfilewriter.cpp                   |  12 +-
 src/core/symbology-ng/qgsellipsesymbollayerv2.cpp  |   5 +
 src/core/symbology-ng/qgsfillsymbollayerv2.cpp     |  16 +
 src/core/symbology-ng/qgslinesymbollayerv2.cpp     |  10 +
 src/core/symbology-ng/qgsmarkersymbollayerv2.cpp   |  16 +
 src/core/symbology-ng/qgssymbollayerv2utils.cpp    |  20 +
 src/core/symbology-ng/qgssymbollayerv2utils.h      |   8 +
 .../editorwidgets/qgsrelationreferencewidget.cpp   | 144 +++--
 src/gui/editorwidgets/qgsrelationreferencewidget.h |   3 +
 src/gui/qgsadvanceddigitizingcanvasitem.cpp        |   3 +-
 src/gui/qgsadvanceddigitizingdockwidget.cpp        |   4 +-
 src/gui/qgscomposeritemcombobox.cpp                |   1 -
 src/gui/qgsmapcanvastracer.cpp                     |  15 +-
 src/gui/qgsmapcanvastracer.h                       |   4 +-
 src/providers/ogr/qgsogrfeatureiterator.cpp        |  41 +-
 src/providers/ogr/qgsogrfeatureiterator.h          |   1 +
 src/providers/ogr/qgsogrprovider.cpp               |  49 +-
 src/providers/ogr/qgsogrprovider.h                 |   2 +-
 src/server/qgswmsconfigparser.cpp                  |  87 ++-
 src/server/qgswmsconfigparser.h                    |   4 +
 src/server/qgswmsserver.cpp                        |  83 +--
 src/server/qgswmsserver.h                          |   4 -
 src/ui/composer/qgscomposerscalebarwidgetbase.ui   |   6 +-
 src/ui/qgsdxfexportdialogbase.ui                   |  25 +-
 tests/src/gui/CMakeLists.txt                       |   2 +
 tests/src/gui/testqgsrelationreferencewidget.cpp   | 224 +++++++
 tests/src/python/test_provider_ogr_gpkg.py         |  62 ++
 tests/src/python/test_provider_ogr_sqlite.py       |  59 ++
 tests/src/python/test_qgsexpression.py             |  23 +
 tests/src/python/test_qgssymbollayerv2_readsld.py  | 304 +++++++++-
 .../symbol_layer/QgsMarkerLineSymbolLayerV2.sld    |   2 +
 .../symbol_layer/QgsSimpleMarkerSymbolLayerV2.sld  |   4 +
 ...erV2.sld => QgsSvgMarkerSymbolLayerUomFoot.sld} |  19 +-
 ...rV2.sld => QgsSvgMarkerSymbolLayerUomMetre.sld} |  19 +-
 ...rV2.sld => QgsSvgMarkerSymbolLayerUomPixel.sld} |  19 +-
 158 files changed, 2281 insertions(+), 735 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 6249a5d..c6dfe97 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,6 +1,6 @@
 SET(CPACK_PACKAGE_VERSION_MAJOR "2")
 SET(CPACK_PACKAGE_VERSION_MINOR "18")
-SET(CPACK_PACKAGE_VERSION_PATCH "12")
+SET(CPACK_PACKAGE_VERSION_PATCH "13")
 SET(COMPLETE_VERSION ${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH})
 SET(RELEASE_NAME "Las Palmas")
 IF (POLICY CMP0048) # in CMake 3.0.0+
diff --git a/ChangeLog b/ChangeLog
index 907cb06..0b61e3f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,314 @@
+Merge: c10c6aeb34 b8c6295f42
+Alexander Bruy <alexander.bruy at gmail.com>	2017-09-15
+
+    Merge pull request #5197 from NaturalGIS/fix_saga_vectorizng_grid_classes
+
+    [processing] fix SAGA LTR vectorizing grid classes tool
+
+Giovanni Manghi <giovanni.manghi at naturalgis.pt>	2017-09-14
+
+    fix SAGA LTR vectorizing grid classes tool
+
+rldhont <rldhont at gmail.com>	2017-09-12
+
+    [BUFIX][Server] GetFeatureInfo on Raster Layer, fix valid identify
+
+    Needs to be manually apply to QGIS 3
+
+    Funded by Ifremer
+
+Matthias Kuhn <matthias at opengis.ch>	2017-09-13
+
+    Fix tracing
+
+Merge: b3a8d6f853 439477a3fe
+Alessandro Pasotti <elpaso at itopen.it>	2017-09-13
+
+    Merge pull request #5144 from boundlessgeo/Backport_Fix_uom_reading
+
+    [bugfix] backport from 3.0 Fix unit of sizes when reading a SLD file (fixes #8978)
+
+Merge: b0357049c5 54653e4a5b
+Sandro Mani <manisandro at gmail.com>	2017-09-12
+
+    Merge pull request #5182 from manisandro/ogr_subsetsetring
+
+    [OGR] Ensure subset string is set when reopening dataset
+
+Sandro Mani <manisandro at gmail.com>	2017-09-12
+
+    [OGR] Ensure subset string is set when reopening dataset
+
+    QgsOgrProvider::reloadData calls close() and open(), which in turn called setSubsetString with mSubsetString.
+    Since setSubsetString does nothing if the passed sql string is equal to mSubsetString, this resulted in the
+    substring not being set on re-open. This commit clears mSubsetString before calling setSubsetString, and
+    blocks signals when calling setSubsetString to avoid an endless recursion of emit dataChanged -> reload.
+    Fixes #17122.
+
+Merge: 70cd0e4d45 9d12581fc5
+rldhont <rldhont at gmail.com>	2017-09-12
+
+    Merge pull request #5168 from rldhont/release-2_18-server-getprint-group-order
+
+    [BUGFIX][Server] GetPrint request renders layers from group in wrong order
+
+Merge: 592151f0b7 8c46e4be74
+Alexander Bruy <alexander.bruy at gmail.com>	2017-09-12
+
+    Merge pull request #5177 from alexbruy/fix-zero-division
+
+    [processing] prevent float division by zero in QGIS algorithms
+
+Luigi Pirelli <luipir at gmail.com>	2017-09-06
+
+    set uom as const
+
+Luigi Pirelli <luipir at gmail.com>	2017-06-14
+
+    aligned test to 3.x version
+
+Luigi Pirelli <luipir at gmail.com>	2017-06-14
+
+    fixed indentation
+
+Luigi Pirelli <luipir at gmail.com>	2017-06-12
+
+    [bugfix] backport from 3.0 Fix unit of sizes when reading a SLD file (fixes #8978)
+
+Merge: a45913b254 a090d7d9cd
+Alexander Bruy <alexander.bruy at gmail.com>	2017-09-12
+
+    Merge pull request #5176 from alexbruy/fix-test
+
+    [processing] attempt to fix failing test
+
+Alexander Bruy <alexander.bruy at gmail.com>	2017-09-12
+
+    attempt to fix failing test
+
+Mathieu Pellerin <nirvn.asia at gmail.com>	2017-09-12
+
+    [ogr provider] insure connection pool updated when subset sql added/changed (#5174)
+
+Alexander Bruy <alexander.bruy at gmail.com>	2017-09-12
+
+    [processing] prevent float division by zero in QGIS algorithms
+
+Martin Dobias <wonder.sk at gmail.com>	2017-09-11
+
+    CAD dock: fix a typo -> enable new snapping option
+
+    When X or Y is locked and user has mouse on top of a segment, CAD dock widget
+    will snap at the intersection of the segment and the axis.
+
+Martin Dobias <wonder.sk at gmail.com>	2017-09-11
+
+    Only update CAD canvas item geometry when necessary
+
+    The call to setRect() in paint() handler was triggering canvas redraws
+    all the time, keeping one CPU core busy nearly all the time when
+    CAD dock was active.
+
+Merge: 88dc61503c c8aceb22ba
+Alexander Bruy <alexander.bruy at gmail.com>	2017-09-12
+
+    Merge pull request #5167 from alexbruy/extract-by-expression
+
+     [processing] add Extract by expression algorithm to QGIS 2.18
+
+rldhont <rldhont at gmail.com>	2017-09-11
+
+    [BUGFIX][Server] GetPrint request renders layers from group in wrong order
+
+    Fixed #16769
+
+Alexander Bruy <alexander.bruy at gmail.com>	2017-09-11
+
+    [processing] add Extract by expression algorithm as combination
+    of "Select by expression" and "Save selected features" does not
+    work in modeler
+
+Juergen E. Fischer <jef at norbit.de>	2017-09-05
+
+    Fix build with GDAL<2
+
+Merge: fa8e1a71f6 8eaeaaa0c0
+Sandro Mani <manisandro at gmail.com>	2017-09-04
+
+    Merge pull request #5125 from manisandro/ogr_orig_fid
+
+    [2.18][OGR] Attempt to use actual ogr_fid also if subset string is set
+
+Sandro Mani <manisandro at gmail.com>	2017-09-02
+
+    [OGR] Attempt to use actual ogr_fid also if subset string is set
+
+    If a subset string is set on an OGR layer, the feature iterator returns features with ids taken from a sequence starting from 0, regardless of the original feature id.
+
+    This causes a mismatch in the data shown by the identify results table and the attribute widget.
+
+Juergen E. Fischer <jef at norbit.de>	2017-09-04
+
+    german translation update
+
+Juergen E. Fischer <jef at norbit.de>	2017-09-04
+
+    translation string fix
+
+Juergen E. Fischer <jef at norbit.de>	2017-08-30
+
+    dxf export: allow forcing to 2d to support polyline width (fixes #17049)
+
+    (backported from commit 12e69d09914d443adb2ca48f8c89416fc762cd64)
+
+Merge: 474f39a777 89c38ed24a
+Nyall Dawson <nyall.dawson at gmail.com>	2017-09-02
+
+    Merge pull request #5108 from nyalldawson/fix_17086
+
+    [composer] Fix node based items (line/polygon) ignore exclude from export setting
+
+Merge: aec8cd338e f64f8e2bfa
+Nyall Dawson <nyall.dawson at gmail.com>	2017-09-02
+
+    Merge pull request #5107 from nyalldawson/scalebar_height
+
+    [composer] Allow finer setting of scalebar height and widths
+
+Nyall Dawson <nyall.dawson at gmail.com>	2017-09-02
+
+    [composer] Fix node based items (line/polygon) ignore exclude
+    from export setting
+
+    Fixes #17086
+
+Nyall Dawson <nyall.dawson at gmail.com>	2017-09-02
+
+    [composer] Allow finer setting of scalebar height and widths
+
+    While the settings are stored as double, they were being
+    rounded off in the UI to the nearest mm
+
+    (cherry-picked from 7ca0b3d)
+
+Merge: 4514c69925 02c095b699
+Nyall Dawson <nyall.dawson at gmail.com>	2017-08-31
+
+    Merge pull request #5097 from nyalldawson/fix_16924
+
+    Fix missing entries from composer map combo boxes (fixes #16924)
+
+Nyall Dawson <nyall.dawson at gmail.com>	2017-08-31
+
+    Fix missing entries from composer map combo boxes (fixes #16924)
+
+    Followup cb33c0d40
+
+Alexander Bruy <alexander.bruy at gmail.com>	2017-08-30
+
+    [processing] fix TauDEM descriptions parsing
+
+Eric Brelsford <ebrelsford at gmail.com>	2017-08-28
+
+    Only pass progress to runalg if it's SilentProgress
+
+    Otherwise allow each algorithm to have its own progress
+
+Eric Brelsford <ebrelsford at gmail.com>	2017-08-26
+
+    Use progress in ConcaveHull when using runalg
+
+    Use the progress parameter when using runalg on other algorithms.
+    Otherwise those algorithms may try to report progress and cause a crash,
+    for example if ConcaveHull is called from a plugin from a thread other
+    than the UI thread.
+
+Etienne Trimaille <gustrimaille at yahoo.fr>	2017-08-22
+
+    enable custom help in python expressions
+
+Mathieu Pellerin <nirvn.asia at gmail.com>	2017-08-25
+
+    [analysis] fix derivative filter z factor handling (#5073)
+
+volaya <volayaf at gmail.com>	2017-08-22
+
+    [processing] only show cml file in selecting rendering styles
+
+    Fixes #16896
+
+volaya <volayaf at gmail.com>	2017-08-22
+
+    [processing] correctly handle null gems in meancoords alg
+
+    Fixes #17026
+
+volaya <volayaf at gmail.com>	2017-08-18
+
+    [processing] fixes in SAGA algorithm after latest changes
+
+volaya <volayaf at gmail.com>	2017-08-17
+
+    [processing] syntax fix
+
+volaya <volayaf at gmail.com>	2017-08-17
+
+    [processing] correctly use TYPE_VECTOR constants from corresponding module
+
+volaya <volayaf at gmail.com>	2017-08-17
+
+    [processing] add resampling method option for all albs that use raster layers
+
+Juergen E. Fischer <jef at norbit.de>	2017-08-22
+
+    bring back sip workaround, but only for the affected versions (followup 7e4345a9d)
+
+Juergen E. Fischer <jef at norbit.de>	2017-08-22
+
+    Fix windows build again (followup d2315e450)
+
+Merge: 7e4345a9db d2315e450e
+Hugo Mercier <hugo.mercier at oslandia.com>	2017-08-21
+
+    Merge pull request #5045 from pblottiere/bugfix_refrel_218
+
+    Fixes relation reference widget by refreshing filter lists. Fixes #16400 (backport)
+
+Blottiere Paul <blottiere.paul at gmail.com>	2017-08-21
+
+    Add unit tests
+
+Blottiere Paul <blottiere.paul at gmail.com>	2017-08-21
+
+    Fixes relation reference widget by refreshing filter lists. Fixes #16400
+
+Juergen E. Fischer <jef at norbit.de>	2017-08-20
+
+    remove sip workaround (fixes #17038, refs #16071)
+
+Juergen E. Fischer <jef at norbit.de>	2017-08-20
+
+    Fix windows build (followup b5bdafe4d)
+
+Giovanni Manghi <giovanni.manghi at naturalgis.pt>	2017-08-18
+
+    improves grass7 v.in.dxf making a couple of parameters optional/mandatory
+
+Even Rouault <even.rouault at spatialys.com>	2017-08-18
+
+    [OGR provider] Avoid 'database locked' issues when editing several layers of the same GeoPackage (fixes #17034)
+
+Merge: a6c461bfec b5bdafe4d3
+Hugo Mercier <hugo.mercier at oslandia.com>	2017-08-18
+
+    Merge pull request #4933 from pblottiere/bugfix_chainfilter_218
+
+    Fixes relation reference widget when chain filter option is activated, fixes #16903 (backport)
+
+Juergen E. Fischer <jef at norbit.de>	2017-08-18
+
+    Release of 2.18.12
+
 Juergen E. Fischer <jef at norbit.de>	2017-08-18
 
     Fix trusty build (QStringLiteral is Qt5; followup b6254513d64)
@@ -13,6 +324,14 @@ Luigi Pirelli <luipir at gmail.com>	2017-08-17
 
     fixed unnecessary deepcopy and use the correct api
 
+Blottiere Paul <blottiere.paul at gmail.com>	2017-07-21
+
+    Add tests
+
+Blottiere Paul <blottiere.paul at gmail.com>	2017-07-21
+
+    Fix relation reference widget when 'Chain Filters' is activated. Fixes #16903
+
 Luigi Pirelli <luipir at gmail.com>	2017-08-06
 
     From Clipboard Cut&Paste fix when attached special field values. Fiexies #16870
diff --git a/debian/changelog b/debian/changelog
index 971ce36..cb75902 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,8 +1,14 @@
-qgis (2.18.12) UNRELEASED; urgency=medium
+qgis (2.18.13) UNRELEASED; urgency=medium
+
+  * Release of 2.18.13
+
+ -- Jürgen E. Fischer <jef at norbit.de>  Fri, 15 Sep 2017 15:08:52 +0200
+
+qgis (2.18.12) unstable; urgency=medium
 
   * Release of 2.18.12
 
- -- Jürgen E. Fischer <jef at norbit.de>  Fri, 18 Aug 2017 14:31:22 +0200
+ -- Jürgen E. Fischer <jef at norbit.de>  Fri, 15 Sep 2017 15:08:52 +0200
 
 qgis (2.18.11) unstable; urgency=medium
 
diff --git a/doc/TRANSLATORS b/doc/TRANSLATORS
index 8b7a4e6..268700e 100644
--- a/doc/TRANSLATORS
+++ b/doc/TRANSLATORS
@@ -1,40 +1,40 @@
 <style>table {font-size:80%;}th {text-align:left; }.bartodo{ background-color:red;width:100px;height:20px;}.bardone{ background-color:green;width:80px;height:20px;font-size:80%;text-align:center;padding-top:4px;height:16px;color:white;}</style><table><tr><th colspan="2" style="width:250px;">Language</th><th>Finished %</th><th>Translators</th></tr>
 
-<tr><td><img src="qrc:/images/flags/de.png"></td><td>German</td><td><div title="finished:18607 unfinished:0 untranslated:0" class="bartodo"><div class="bardone" style="width:100px">100.0</div></div></td><td>Jürgen E. Fischer, Stephan Holl, Otto Dassau, Werner Macho</td></tr>
-<tr><td><img src="qrc:/images/flags/sv.png"></td><td>Swedish</td><td><div title="finished:18089 unfinished:211 untranslated:307" class="bartodo"><div class="bardone" style="width:97px">97.8</div></div></td><td>Victor Axbom, Lars Luthman, Magnus Homann, Klas Karlsson, Isabelle J Wigren, Daniel Rosander, Anders Ekwall, Magnus Nilsson, Jonas Svensson, Christian Brinkenberg</td></tr>
-<tr><td><img src="qrc:/images/flags/eu.png"></td><td>Basque</td><td><div title="finished:18089 unfinished:207 untranslated:311" class="bartodo"><div class="bardone" style="width:97px">97.8</div></div></td><td>Asier Sarasua Garmendia, Irantzu Alvarez</td></tr>
-<tr><td><img src="qrc:/images/flags/gl.png"></td><td>Galician</td><td><div title="finished:18088 unfinished:204 untranslated:315" class="bartodo"><div class="bardone" style="width:97px">97.8</div></div></td><td>Xan Vieiro</td></tr>
-<tr><td><img src="qrc:/images/flags/nl.png"></td><td>Dutch</td><td><div title="finished:18084 unfinished:211 untranslated:312" class="bartodo"><div class="bardone" style="width:97px">97.8</div></div></td><td>Richard Duivenvoorde, Raymond Nijssen, Carlo van Rijswijk, Diethard Jansen, Willem Hoffmans, Dick Groskamp</td></tr>
-<tr><td><img src="qrc:/images/flags/ro.png"></td><td>Romanian</td><td><div title="finished:18089 unfinished:197 untranslated:321" class="bartodo"><div class="bardone" style="width:97px">97.7</div></div></td><td>Sorin Călinică, Tudor Bărăscu, Georgiana Ioanovici, Alex Bădescu, Lonut Losifescu-Enescu, Bogdan Pacurar</td></tr>
-<tr><td><img src="qrc:/images/flags/pt_BR.png"></td><td>Portuguese (Brazil)</td><td><div title="finished:18089 unfinished:195 untranslated:323" class="bartodo"><div class="bardone" style="width:97px">97.7</div></div></td><td>Sidney Schaberle Goveia, Arthur Nanni, Marcelo Soares Souza, Narcélio de Sá Pereira Filho, Leônidas Descovi Filho, Felipe Sodré Barros </td></tr>
-<tr><td><img src="qrc:/images/flags/fr.png"></td><td>French</td><td><div title="finished:18065 unfinished:203 untranslated:339" class="bartodo"><div class="bardone" style="width:97px">97.6</div></div></td><td>Arnaud Morvan, Augustin Roche, DelazJ, Didier Vanden Berghe, Dofabien, etrimaille, Jean-Roc Morreale, Jérémy Garniaux, Loïc Buscoz, Lsam, Marc-André Saia, Marie Silvestre, Mathieu Bossaert, Mathieu Lattes, Mayeul Kauffmann, Médéric Ribreux, Mehdi Semchaoui, Michael Douchin, Nicolas  [...]
-<tr><td><img src="qrc:/images/flags/bs.png"></td><td>Bosnian</td><td><div title="finished:17944 unfinished:213 untranslated:450" class="bartodo"><div class="bardone" style="width:97px">97.0</div></div></td><td>Almir Karabegovic</td></tr>
-<tr><td><img src="qrc:/images/flags/da.png"></td><td>Danish</td><td><div title="finished:17746 unfinished:166 untranslated:695" class="bartodo"><div class="bardone" style="width:95px">95.8</div></div></td><td>Jacob Overgaard Madsen, Bo Victor Thomsen</td></tr>
-<tr><td><img src="qrc:/images/flags/es.png"></td><td>Spanish</td><td><div title="finished:17639 unfinished:134 untranslated:834" class="bartodo"><div class="bardone" style="width:95px">95.2</div></div></td><td>Carlos Dávila, Javier César Aldariz, Gabriela Awad, Edwin Amado, Mayeul Kauffmann, Diana Galindo</td></tr>
-<tr><td><img src="qrc:/images/flags/ja.png"></td><td>Japanese</td><td><div title="finished:17226 unfinished:210 untranslated:1171" class="bartodo"><div class="bardone" style="width:93px">93.1</div></div></td><td>BABA Yoshihiko, Yoichi Kayama, Minoru Akagi, Takayuki Nuimura, Takayuki Mizutani, Norihiro Yamate</td></tr>
-<tr><td><img src="qrc:/images/flags/hu.png"></td><td>Hungarian</td><td><div title="finished:16518 unfinished:146 untranslated:1943" class="bartodo"><div class="bardone" style="width:89px">89.2</div></div></td><td>Zoltan Siki</td></tr>
-<tr><td><img src="qrc:/images/flags/vi.png"></td><td>Vietnamese</td><td><div title="finished:16489 unfinished:97 untranslated:2021" class="bartodo"><div class="bardone" style="width:88px">88.9</div></div></td><td>Phùng Văn Doanh, Bùi Hữu Mạnh, Nguyễn Văn Thanh, Nguyễn Hữu Phúc, Cao Minh Tu</td></tr>
-<tr><td><img src="qrc:/images/flags/zh.png"></td><td>Chinese simplified</td><td><div title="finished:16091 unfinished:104 untranslated:2412" class="bartodo"><div class="bardone" style="width:86px">86.8</div></div></td><td>Calvin Ngei, Lisashen</td></tr>
-<tr><td><img src="qrc:/images/flags/pt_PT.png"></td><td>Portuguese (Portugal)</td><td><div title="finished:15508 unfinished:93 untranslated:3006" class="bartodo"><div class="bardone" style="width:83px">83.6</div></div></td><td>Giovanni Manghi, Joana Simões, Duarte Carreira, Alexandre Neto, Pedro Pereira, Pedro Palheiro, Nelson Silva, Ricardo Sena, Leandro Infantini, João Gaspar</td></tr>
-<tr><td><img src="qrc:/images/flags/ru.png"></td><td>Russian</td><td><div title="finished:15435 unfinished:158 untranslated:3014" class="bartodo"><div class="bardone" style="width:83px">83.4</div></div></td><td>Alexander Bruy, Artem Popov</td></tr>
-<tr><td><img src="qrc:/images/flags/pl.png"></td><td>Polish</td><td><div title="finished:14714 unfinished:96 untranslated:3797" class="bartodo"><div class="bardone" style="width:79px">79.3</div></div></td><td>Robert Szczepanek, Milena Nowotarska, Borys Jurgiel, Mateusz Łoskot, Tomasz Paul, Andrzej Świąder, Radosław Pasiok, Michał Kułach, Ewelina Krawczak, Michał Smoczyk, Jakub Bobrowski</td></tr>
-<tr><td><img src="qrc:/images/flags/cs.png"></td><td>Czech</td><td><div title="finished:14644 unfinished:134 untranslated:3829" class="bartodo"><div class="bardone" style="width:79px">79.1</div></div></td><td>Jan Helebrant, Martin Landa, Peter Antolik, Martin Dzurov, Stanislav Horáček</td></tr>
-<tr><td><img src="qrc:/images/flags/nb.png"></td><td>Norwegian Bokmal</td><td><div title="finished:14547 unfinished:135 untranslated:3925" class="bartodo"><div class="bardone" style="width:78px">78.5</div></div></td><td>James Stott, Maléne Peterson</td></tr>
-<tr><td><img src="qrc:/images/flags/fi.png"></td><td>Finnish</td><td><div title="finished:14031 unfinished:351 untranslated:4225" class="bartodo"><div class="bardone" style="width:76px">76.4</div></div></td><td>Kari Mikkonen, Matti Mäntynen</td></tr>
-<tr><td><img src="qrc:/images/flags/zh.png"></td><td>Chinese traditional</td><td><div title="finished:14052 unfinished:159 untranslated:4396" class="bartodo"><div class="bardone" style="width:75px">75.9</div></div></td><td>Calvin Ngei, Zhang Jun, Richard Xie</td></tr>
-<tr><td><img src="qrc:/images/flags/it.png"></td><td>Italian</td><td><div title="finished:13994 unfinished:145 untranslated:4468" class="bartodo"><div class="bardone" style="width:75px">75.6</div></div></td><td>Roberto Angeletti, Michele Beneventi, Marco Braida, Stefano Campus, Luca Casagrande, Paolo Cavallini, Giuliano Curti, Luca Delucchi, Alessandro Fanna, Michele Ferretti, Matteo Ghetta, Anne Gishla, Maurizio Napolitano, Flavio Rigolon</td></tr>
-<tr><td><img src="qrc:/images/flags/et.png"></td><td>Estonian</td><td><div title="finished:13143 unfinished:168 untranslated:5296" class="bartodo"><div class="bardone" style="width:71px">71.1</div></div></td><td>Veiko Viil</td></tr>
-<tr><td><img src="qrc:/images/flags/ca.png"></td><td>Catalan</td><td><div title="finished:12877 unfinished:147 untranslated:5583" class="bartodo"><div class="bardone" style="width:69px">69.6</div></div></td><td>Albert F, Pau Reguant Ridó, Xavier Roijals</td></tr>
-<tr><td><img src="qrc:/images/flags/hi.png"></td><td>Hindi</td><td><div title="finished:12446 unfinished:194 untranslated:5967" class="bartodo"><div class="bardone" style="width:67px">67.4</div></div></td><td>Harish Kumar Solanki</td></tr>
-<tr><td><img src="qrc:/images/flags/bg.png"></td><td>Bulgarian</td><td><div title="finished:12359 unfinished:163 untranslated:6085" class="bartodo"><div class="bardone" style="width:66px">66.9</div></div></td><td>Захари Савов, Jordan Tzvetkov</td></tr>
-<tr><td><img src="qrc:/images/flags/ko.png"></td><td>Korean</td><td><div title="finished:11741 unfinished:185 untranslated:6681" class="bartodo"><div class="bardone" style="width:63px">63.6</div></div></td><td>OSGeo Korean Chapter</td></tr>
-<tr><td><img src="qrc:/images/flags/lt.png"></td><td>Lithuanian</td><td><div title="finished:11314 unfinished:197 untranslated:7096" class="bartodo"><div class="bardone" style="width:61px">61.3</div></div></td><td>Paulius Litvinas, Tomas Straupis, Kestas M</td></tr>
-<tr><td><img src="qrc:/images/flags/tr.png"></td><td>Turkish</td><td><div title="finished:10847 unfinished:158 untranslated:7602" class="bartodo"><div class="bardone" style="width:58px">58.7</div></div></td><td>Osman Yalçın YILMAZ, Omur Saygin</td></tr>
-<tr><td><img src="qrc:/images/flags/id.png"></td><td>Indonesian</td><td><div title="finished:10705 unfinished:331 untranslated:7571" class="bartodo"><div class="bardone" style="width:58px">58.4</div></div></td><td>Emir Hartato, Muhammad Iqnaul Haq Siregar, Trias Aditya, Januar V. Simarmata, I Made Anombawa</td></tr>
-<tr><td><img src="qrc:/images/flags/el.png"></td><td>Modern Greek (1453-)</td><td><div title="finished:10719 unfinished:125 untranslated:7763" class="bartodo"><div class="bardone" style="width:57px">57.9</div></div></td><td>Theodoros Vakkas, Ioannis Tsimpiris, Evripidis Argyropoulos, Mike Pegnigiannis, Nikos Ves</td></tr>
-<tr><td><img src="qrc:/images/flags/sl.png"></td><td>Slovenian</td><td><div title="finished:9504 unfinished:187 untranslated:8916" class="bartodo"><div class="bardone" style="width:51px">51.6</div></div></td><td>Jože Detečnik, Dejan Gregor, Jaka Kranjc</td></tr>
-<tr><td><img src="qrc:/images/flags/km.png"></td><td>Central Khmer</td><td><div title="finished:9326 unfinished:189 untranslated:9092" class="bartodo"><div class="bardone" style="width:50px">50.6</div></div></td><td>Khoem Sokhem</td></tr>
-<tr><td><img src="qrc:/images/flags/ar.png"></td><td>Arabic</td><td><div title="finished:9286 unfinished:188 untranslated:9133" class="bartodo"><div class="bardone" style="width:50px">50.4</div></div></td><td>Ichaouia Amine, Hosham Munier</td></tr>
-<tr><td><img src="qrc:/images/flags/lv.png"></td><td>Latvian</td><td><div title="finished:9158 unfinished:274 untranslated:9175" class="bartodo"><div class="bardone" style="width:49px">50.0</div></div></td><td>Maris Nartiss, Pēteris Brūns</td></tr>
-<tr><td><img src="qrc:/images/flags/sk.png"></td><td>Slovak</td><td><div title="finished:7754 unfinished:869 untranslated:9984" class="bartodo"><div class="bardone" style="width:44px">44.0</div></div></td><td>Lubos Balazovic, Jana Kormanikova, Ivan Mincik</td></tr>
-<tr><td><img src="qrc:/images/flags/hr.png"></td><td>Croatian</td><td><div title="finished:7284 unfinished:193 untranslated:11130" class="bartodo"><div class="bardone" style="width:39px">39.7</div></div></td><td>Zoran Jankovic</td></tr></table>
+<tr><td><img src="qrc:/images/flags/de.png"></td><td>German</td><td><div title="finished:18331 unfinished:4 untranslated:20" class="bartodo"><div class="bardone" style="width:99px">99.9</div></div></td><td>Jürgen E. Fischer, Stephan Holl, Otto Dassau, Werner Macho</td></tr>
+<tr><td><img src="qrc:/images/flags/sv.png"></td><td>Swedish</td><td><div title="finished:17813 unfinished:215 untranslated:327" class="bartodo"><div class="bardone" style="width:97px">97.6</div></div></td><td>Victor Axbom, Lars Luthman, Magnus Homann, Klas Karlsson, Isabelle J Wigren, Daniel Rosander, Anders Ekwall, Magnus Nilsson, Jonas Svensson, Christian Brinkenberg</td></tr>
+<tr><td><img src="qrc:/images/flags/eu.png"></td><td>Basque</td><td><div title="finished:17813 unfinished:211 untranslated:331" class="bartodo"><div class="bardone" style="width:97px">97.6</div></div></td><td>Asier Sarasua Garmendia, Irantzu Alvarez</td></tr>
+<tr><td><img src="qrc:/images/flags/gl.png"></td><td>Galician</td><td><div title="finished:17812 unfinished:208 untranslated:335" class="bartodo"><div class="bardone" style="width:97px">97.6</div></div></td><td>Xan Vieiro</td></tr>
+<tr><td><img src="qrc:/images/flags/nl.png"></td><td>Dutch</td><td><div title="finished:17808 unfinished:215 untranslated:332" class="bartodo"><div class="bardone" style="width:97px">97.6</div></div></td><td>Richard Duivenvoorde, Raymond Nijssen, Carlo van Rijswijk, Diethard Jansen, Willem Hoffmans, Dick Groskamp</td></tr>
+<tr><td><img src="qrc:/images/flags/ro.png"></td><td>Romanian</td><td><div title="finished:17813 unfinished:201 untranslated:341" class="bartodo"><div class="bardone" style="width:97px">97.6</div></div></td><td>Sorin Călinică, Tudor Bărăscu, Georgiana Ioanovici, Alex Bădescu, Lonut Losifescu-Enescu, Bogdan Pacurar</td></tr>
+<tr><td><img src="qrc:/images/flags/pt_BR.png"></td><td>Portuguese (Brazil)</td><td><div title="finished:17813 unfinished:199 untranslated:343" class="bartodo"><div class="bardone" style="width:97px">97.6</div></div></td><td>Sidney Schaberle Goveia, Arthur Nanni, Marcelo Soares Souza, Narcélio de Sá Pereira Filho, Leônidas Descovi Filho, Felipe Sodré Barros </td></tr>
+<tr><td><img src="qrc:/images/flags/fr.png"></td><td>French</td><td><div title="finished:17789 unfinished:207 untranslated:359" class="bartodo"><div class="bardone" style="width:97px">97.5</div></div></td><td>Arnaud Morvan, Augustin Roche, DelazJ, Didier Vanden Berghe, Dofabien, etrimaille, Jean-Roc Morreale, Jérémy Garniaux, Loïc Buscoz, Lsam, Marc-André Saia, Marie Silvestre, Mathieu Bossaert, Mathieu Lattes, Mayeul Kauffmann, Médéric Ribreux, Mehdi Semchaoui, Michael Douchin, Nicolas  [...]
+<tr><td><img src="qrc:/images/flags/bs.png"></td><td>Bosnian</td><td><div title="finished:17668 unfinished:217 untranslated:470" class="bartodo"><div class="bardone" style="width:96px">96.8</div></div></td><td>Almir Karabegovic</td></tr>
+<tr><td><img src="qrc:/images/flags/da.png"></td><td>Danish</td><td><div title="finished:17509 unfinished:170 untranslated:676" class="bartodo"><div class="bardone" style="width:95px">95.9</div></div></td><td>Jacob Overgaard Madsen, Bo Victor Thomsen</td></tr>
+<tr><td><img src="qrc:/images/flags/es.png"></td><td>Spanish</td><td><div title="finished:17370 unfinished:138 untranslated:847" class="bartodo"><div class="bardone" style="width:95px">95.0</div></div></td><td>Carlos Dávila, Javier César Aldariz, Gabriela Awad, Edwin Amado, Mayeul Kauffmann, Diana Galindo</td></tr>
+<tr><td><img src="qrc:/images/flags/ja.png"></td><td>Japanese</td><td><div title="finished:17130 unfinished:214 untranslated:1011" class="bartodo"><div class="bardone" style="width:93px">93.9</div></div></td><td>BABA Yoshihiko, Yoichi Kayama, Minoru Akagi, Takayuki Nuimura, Takayuki Mizutani, Norihiro Yamate</td></tr>
+<tr><td><img src="qrc:/images/flags/hu.png"></td><td>Hungarian</td><td><div title="finished:16386 unfinished:149 untranslated:1820" class="bartodo"><div class="bardone" style="width:89px">89.7</div></div></td><td>Zoltan Siki</td></tr>
+<tr><td><img src="qrc:/images/flags/vi.png"></td><td>Vietnamese</td><td><div title="finished:16229 unfinished:101 untranslated:2025" class="bartodo"><div class="bardone" style="width:88px">88.7</div></div></td><td>Phùng Văn Doanh, Bùi Hữu Mạnh, Nguyễn Văn Thanh, Nguyễn Hữu Phúc, Cao Minh Tu</td></tr>
+<tr><td><img src="qrc:/images/flags/zh.png"></td><td>Chinese simplified</td><td><div title="finished:15943 unfinished:108 untranslated:2304" class="bartodo"><div class="bardone" style="width:87px">87.2</div></div></td><td>Calvin Ngei, Lisashen</td></tr>
+<tr><td><img src="qrc:/images/flags/pt_PT.png"></td><td>Portuguese (Portugal)</td><td><div title="finished:15358 unfinished:97 untranslated:2900" class="bartodo"><div class="bardone" style="width:83px">83.9</div></div></td><td>Giovanni Manghi, Joana Simões, Duarte Carreira, Alexandre Neto, Pedro Pereira, Pedro Palheiro, Nelson Silva, Ricardo Sena, Leandro Infantini, João Gaspar</td></tr>
+<tr><td><img src="qrc:/images/flags/ru.png"></td><td>Russian</td><td><div title="finished:15314 unfinished:160 untranslated:2881" class="bartodo"><div class="bardone" style="width:83px">83.9</div></div></td><td>Alexander Bruy, Artem Popov</td></tr>
+<tr><td><img src="qrc:/images/flags/pl.png"></td><td>Polish</td><td><div title="finished:14688 unfinished:100 untranslated:3567" class="bartodo"><div class="bardone" style="width:80px">80.3</div></div></td><td>Robert Szczepanek, Milena Nowotarska, Borys Jurgiel, Mateusz Łoskot, Tomasz Paul, Andrzej Świąder, Radosław Pasiok, Michał Kułach, Ewelina Krawczak, Michał Smoczyk, Jakub Bobrowski</td></tr>
+<tr><td><img src="qrc:/images/flags/nb.png"></td><td>Norwegian Bokmal</td><td><div title="finished:14525 unfinished:139 untranslated:3691" class="bartodo"><div class="bardone" style="width:79px">79.5</div></div></td><td>James Stott, Maléne Peterson</td></tr>
+<tr><td><img src="qrc:/images/flags/cs.png"></td><td>Czech</td><td><div title="finished:14493 unfinished:137 untranslated:3725" class="bartodo"><div class="bardone" style="width:79px">79.3</div></div></td><td>Jan Helebrant, Martin Landa, Peter Antolik, Martin Dzurov, Stanislav Horáček</td></tr>
+<tr><td><img src="qrc:/images/flags/zh.png"></td><td>Chinese traditional</td><td><div title="finished:13975 unfinished:163 untranslated:4217" class="bartodo"><div class="bardone" style="width:76px">76.6</div></div></td><td>Calvin Ngei, Zhang Jun, Richard Xie</td></tr>
+<tr><td><img src="qrc:/images/flags/fi.png"></td><td>Finnish</td><td><div title="finished:13878 unfinished:353 untranslated:4124" class="bartodo"><div class="bardone" style="width:76px">76.6</div></div></td><td>Kari Mikkonen, Matti Mäntynen</td></tr>
+<tr><td><img src="qrc:/images/flags/it.png"></td><td>Italian</td><td><div title="finished:13964 unfinished:149 untranslated:4242" class="bartodo"><div class="bardone" style="width:76px">76.5</div></div></td><td>Roberto Angeletti, Michele Beneventi, Marco Braida, Stefano Campus, Luca Casagrande, Paolo Cavallini, Giuliano Curti, Luca Delucchi, Alessandro Fanna, Michele Ferretti, Matteo Ghetta, Anne Gishla, Maurizio Napolitano, Flavio Rigolon</td></tr>
+<tr><td><img src="qrc:/images/flags/et.png"></td><td>Estonian</td><td><div title="finished:13131 unfinished:168 untranslated:5056" class="bartodo"><div class="bardone" style="width:71px">72.0</div></div></td><td>Veiko Viil</td></tr>
+<tr><td><img src="qrc:/images/flags/ca.png"></td><td>Catalan</td><td><div title="finished:12806 unfinished:148 untranslated:5401" class="bartodo"><div class="bardone" style="width:70px">70.2</div></div></td><td>Albert F, Pau Reguant Ridó, Xavier Roijals</td></tr>
+<tr><td><img src="qrc:/images/flags/hi.png"></td><td>Hindi</td><td><div title="finished:12436 unfinished:194 untranslated:5725" class="bartodo"><div class="bardone" style="width:68px">68.3</div></div></td><td>Harish Kumar Solanki</td></tr>
+<tr><td><img src="qrc:/images/flags/bg.png"></td><td>Bulgarian</td><td><div title="finished:12336 unfinished:167 untranslated:5852" class="bartodo"><div class="bardone" style="width:67px">67.7</div></div></td><td>Захари Савов, Jordan Tzvetkov</td></tr>
+<tr><td><img src="qrc:/images/flags/ko.png"></td><td>Korean</td><td><div title="finished:11729 unfinished:185 untranslated:6441" class="bartodo"><div class="bardone" style="width:64px">64.4</div></div></td><td>OSGeo Korean Chapter</td></tr>
+<tr><td><img src="qrc:/images/flags/lt.png"></td><td>Lithuanian</td><td><div title="finished:11285 unfinished:199 untranslated:6871" class="bartodo"><div class="bardone" style="width:62px">62.0</div></div></td><td>Paulius Litvinas, Tomas Straupis, Kestas M</td></tr>
+<tr><td><img src="qrc:/images/flags/tr.png"></td><td>Turkish</td><td><div title="finished:10787 unfinished:159 untranslated:7409" class="bartodo"><div class="bardone" style="width:59px">59.2</div></div></td><td>Osman Yalçın YILMAZ, Omur Saygin</td></tr>
+<tr><td><img src="qrc:/images/flags/id.png"></td><td>Indonesian</td><td><div title="finished:10696 unfinished:330 untranslated:7329" class="bartodo"><div class="bardone" style="width:59px">59.2</div></div></td><td>Emir Hartato, Muhammad Iqnaul Haq Siregar, Trias Aditya, Januar V. Simarmata, I Made Anombawa</td></tr>
+<tr><td><img src="qrc:/images/flags/el.png"></td><td>Modern Greek (1453-)</td><td><div title="finished:10702 unfinished:126 untranslated:7527" class="bartodo"><div class="bardone" style="width:58px">58.6</div></div></td><td>Theodoros Vakkas, Ioannis Tsimpiris, Evripidis Argyropoulos, Mike Pegnigiannis, Nikos Ves</td></tr>
+<tr><td><img src="qrc:/images/flags/sl.png"></td><td>Slovenian</td><td><div title="finished:9492 unfinished:188 untranslated:8675" class="bartodo"><div class="bardone" style="width:52px">52.2</div></div></td><td>Jože Detečnik, Dejan Gregor, Jaka Kranjc</td></tr>
+<tr><td><img src="qrc:/images/flags/km.png"></td><td>Central Khmer</td><td><div title="finished:9317 unfinished:189 untranslated:8849" class="bartodo"><div class="bardone" style="width:51px">51.3</div></div></td><td>Khoem Sokhem</td></tr>
+<tr><td><img src="qrc:/images/flags/ar.png"></td><td>Arabic</td><td><div title="finished:9278 unfinished:188 untranslated:8889" class="bartodo"><div class="bardone" style="width:51px">51.1</div></div></td><td>Ichaouia Amine, Hosham Munier</td></tr>
+<tr><td><img src="qrc:/images/flags/lv.png"></td><td>Latvian</td><td><div title="finished:9151 unfinished:273 untranslated:8931" class="bartodo"><div class="bardone" style="width:50px">50.6</div></div></td><td>Maris Nartiss, Pēteris Brūns</td></tr>
+<tr><td><img src="qrc:/images/flags/sk.png"></td><td>Slovak</td><td><div title="finished:7745 unfinished:868 untranslated:9742" class="bartodo"><div class="bardone" style="width:44px">44.6</div></div></td><td>Lubos Balazovic, Jana Kormanikova, Ivan Mincik</td></tr>
+<tr><td><img src="qrc:/images/flags/hr.png"></td><td>Croatian</td><td><div title="finished:7277 unfinished:193 untranslated:10885" class="bartodo"><div class="bardone" style="width:40px">40.2</div></div></td><td>Zoran Jankovic</td></tr></table>
diff --git a/i18n/qgis_de.ts b/i18n/qgis_de.ts
index be5018e..0af6782 100644
--- a/i18n/qgis_de.ts
+++ b/i18n/qgis_de.ts
@@ -8636,6 +8636,10 @@ Bitte vor der Ausführung von GRASS-Algorithmen konfigurieren.</translation>
         <source>v.surf.rst.cvdev - Spatial approximation and topographic analysis using regularized spline with tension.</source>
         <translation>v.surf.rst.cvdev - Räumliche Approximation und topographische Analyse mit einer regularisierten Spline-Funktion mit Spannung.</translation>
     </message>
+    <message>
+        <source>v.voronoi.skeleton - Extract skeletons for input areas.</source>
+        <translation>v.voronoi.skeleton - Skelette aus den Eingabebereichen extrahieren.</translation>
+    </message>
 </context>
 <context>
     <name>GrassAlgorithmProvider</name>
@@ -12579,7 +12583,7 @@ Mehr Informationen.im Protokoll.</translation>
     <name>OTBAlgorithmProvider</name>
     <message>
         <source>Problem with OTB installation: OTB was not found or is not correctly installed</source>
-        <translation>Problem mit OTB-Installation: OTB wurde nicht gefunden oder ist nicht richtig installiert</translation>
+        <translation type="obsolete">Problem mit OTB-Installation: OTB wurde nicht gefunden oder ist nicht richtig installiert</translation>
     </message>
     <message>
         <source>Problem with OTB installation: installed OTB version (%s) is not supported</source>
@@ -15622,7 +15626,7 @@ Nur %1 von %2 Objekten geschrieben.</translation>
     </message>
     <message>
         <source>Override the type of shapefile created. Can be one of NULL for a simple .dbf file with no .shp file, POINT, ARC, POLYGON or MULTIPOINT for 2D, or POINTZ, ARCZ, POLYGONZ or MULTIPOINTZ for 3D. Shapefiles with measure values are not supported, nor are MULTIPATCH files.</source>
-        <translation>Typ der Shapedatei ändern. Kann NULL für eine einfache DBF-Datei ohne .shp-Datei sein, POINT, ARC, POLYGON oder MULTIPOINT für 2D oder POINTZ, ARCZ, POLYGONZ oder MULTIPOINTZ für 3D.  Shapedateien mit Maßwerten oder MULTIPATCH-Dateien werden nicht unterstützt.</translation>
+        <translation type="obsolete">Typ der Shapedatei ändern. Kann NULL für eine einfache DBF-Datei ohne .shp-Datei sein, POINT, ARC, POLYGON oder MULTIPOINT für 2D oder POINTZ, ARCZ, POLYGONZ oder MULTIPOINTZ für 3D.  Shapedateien mit Maßwerten oder MULTIPATCH-Dateien werden nicht unterstützt.</translation>
     </message>
     <message>
         <source>set the encoding value in the DBF file. The default value is LDID/87. It is not clear what other values may be appropriate.</source>
@@ -15938,11 +15942,11 @@ Nur %1 von %2 Objekten geschrieben.</translation>
     </message>
     <message>
         <source>If the database is of the SpatiaLite flavour, and if OGR is linked against libspatialite, this option can be used to control if a spatial index must be created.</source>
-        <translation>Wenn es sich um eine SpatiaLite-Datenbank handelt und OGR gegen libspatialite gelinkt ist, kann diese Option verwendet werden, um zu steuern ob ein räumlicher Index erzeugt werden muß.</translation>
+        <translation type="obsolete">Wenn es sich um eine SpatiaLite-Datenbank handelt und OGR gegen libspatialite gelinkt ist, kann diese Option verwendet werden, um zu steuern ob ein räumlicher Index erzeugt werden muß.</translation>
     </message>
     <message>
         <source>If the format of the geometry BLOB is of the SpatiaLite flavour, this option can be used to control if the compressed format for geometries (LINESTRINGs, POLYGONs) must be used</source>
-        <translation>Wenn das Geometrieformat SpatiaLite ist, kann diese Option verwendet werden, um das Kompressionsformat für Geometrien (LINESTRINGs, POLYGONe) zu steuern</translation>
+        <translation type="obsolete">Wenn das Geometrieformat SpatiaLite ist, kann diese Option verwendet werden, um das Kompressionsformat für Geometrien (LINESTRINGs, POLYGONe) zu steuern</translation>
     </message>
     <message>
         <source>Used to force the SRID number of the SRS associated with the layer. When this option isn't specified and that a SRS is associated with the layer, a search is made in the spatial_ref_sys to find a match for the SRS, and, if there is no match, a new entry is inserted for the SRS in the spatial_ref_sys table. When the SRID option is specified, this search (and the eventual insertion of a new entry) will not be done: the specified SRID is used as such.</source>
@@ -19004,6 +19008,54 @@ Fehler: %2</translation>
         <source>Layer %2 of %1 exists and overwrite flag is false.</source>
         <translation>Layer %2 von %1 bereits vorhanden und Überschreiben nicht aktiv.</translation>
     </message>
+    <message>
+        <source>Override the type of shapefile created. Can be one of NULL for a simple .dbf file with no .shp file, POINT, ARC, POLYGON or MULTIPOINT for 2D, or POINTZ, ARCZ, POLYGONZ or MULTIPOINTZ for 3D;</source>
+        <translation>Typ der Shapedatei ändern. Kann NULL für eine einfache DBF-Datei ohne .shp-Datei sein, POINT, ARC, POLYGON oder MULTIPOINT für 2D oder POINTZ, ARCZ, POLYGONZ oder MULTIPOINTZ für 3D;</translation>
+    </message>
+    <message>
+        <source> Shapefiles with measure values are not supported, nor are MULTIPATCH files.</source>
+        <translation> Shapedateien mit Maßwerten oder MULTIPATCH-Dateien werden nicht unterstützt.</translation>
+    </message>
+    <message>
+        <source> POINTM, ARCM, POLYGONM or MULTIPOINTM for measured geometries and POINTZM, ARCZM, POLYGONZM or MULTIPOINTZM for 3D measured geometries.</source>
+        <translation> POINTM, ARCM, POLYGONM oder MULTIPOINTM für gemessene Geometrien und POINTZM, ARCZM, POLYGONZM oder MULTIPOINTZM für 3D gemessene Geometrien.</translation>
+    </message>
+    <message>
+        <source> MULTIPATCH files are supported since GDAL 2.2.</source>
+        <translation> MULTIPATCH-Dateien werden seit GDAL 2.2 unterstützt.</translation>
+    </message>
+    <message>
+        <source>The DOCUMENT_ID datasource creation option can be used to specified the id of the root <Document> node. The default value is root_doc.</source>
+        <translation>Die Datenquellenerzeugungsoption DOCUMENT_ID kann verwendet werden um den Wurzelknoten des <Document>s anzugeben. Der Vorgabewert ist root_doc.</translation>
+    </message>
+    <message>
+        <source>(multiples of 512): Block size for .map files. Defaults to 512. MapInfo 15.2 and above creates .tab files with a blocksize of 16384 bytes. Any MapInfo version should be able to handle block sizes from 512 to 32256.</source>
+        <translation>(Mehrfaches von 512):  Blockgröße für Map-Dateien (Vorgabe 512). MapInfo 15.2 und höher erzeugt Tab-Dateien mit einer Blockgröße von 16384 Bytes. Jede MapInfo-Version sollte in der Lage sein Blockgrößen zwischen 512 und 32256 zu verarbeiten.</translation>
+    </message>
+    <message>
+        <source>xmin,ymin,xmax,ymax: Define custom layer bounds to increase the accuracy of the coordinates. Note: the geometry of written features must be within the defined box.</source>
+        <translation>xmin,ymin,xmax,ymax: Layergrenzen festlegen umd die Genauigkeit der Koordinaten zu erhöhen.  Hinweis: Die Geometrie der geschriebenen Objekt muß innerhalb des definierten Rahmens liegen.</translation>
+    </message>
+    <message>
+        <source>If the database is of the SpatiaLite flavor, and if OGR is linked against libspatialite, this option can be used to control if a spatial index must be created.</source>
+        <translation>Wenn es sich um eine SpatiaLite-Datenbank handelt und OGR gegen libspatialite gelinkt ist, kann diese Option verwendet werden, um zu steuern ob ein räumlicher Index erzeugt werden muß.</translation>
+    </message>
+    <message>
+        <source>If the format of the geometry BLOB is of the SpatiaLite flavor, this option can be used to control if the compressed format for geometries (LINESTRINGs, POLYGONs) must be used</source>
+        <translation>Wenn das Geometrieformat SpatiaLite ist, kann diese Option verwendet werden, um das Kompressionsformat für Geometrien (LINESTRINGs, POLYGONe) zu steuern</translation>
+    </message>
+    <message>
+        <source>defines the feature to be created. The TYPE corresponds to one of the Name found in the GCT file for a type section. The SUBTYPE corresponds to one of the Name found in the GCT file for a sub-type section within the previous type section.</source>
+        <translation>Definiert das zu erzeugende Objekt. Der TYPE korrespondiert mit einem der in der GCT zu findenden Namen für einen Typabschnitt.  Der SUBTYPE korrespondiert mit einem der Namen eines Untertypabschnitts dieses Typabschnitts.</translation>
+    </message>
+    <message>
+        <source>By default, the driver will read the first lines of each sheet to detect if the first line might be the name of columns. If set to FORCE, the driver will consider the first default</source>
+        <translation type="obsolete">Gemäß Vorgabe ließ der Treiber die ersten Zeilen der Tabelle, um festzustellen, ob es sich um Spaltennamen handelt.  Wenn FORCE gesetzt ist, betrachte der Treiber die erste Vorgabe.</translation>
+    </message>
+    <message>
+        <source>By default, the driver will read the first lines of each sheet to detect if the first line might be the name of columns. If set to FORCE, the driver will consider the first line will be taken as the header line. If set to DISABLE, it will be considered as the first feature. Otherwise auto-detection will occur.</source>
+        <translation>Gemäß Vorgabe liest der Treiber die ersten Zeilen der Tabelle, um festzustellen, ob es sich um Spaltennamen handelt.  Wenn FORCE gesetzt ist, betrachtet der Treiber die erste immer als Kopfzeile.  Wenn DISABLE gesetzt ist, wird sie immer als erstes Objekt betrachtet.  Ansonsten erfolgt eine automatische Erkennung.</translation>
+    </message>
 </context>
 <context>
     <name>QSpatiaLiteDriver</name>
@@ -24943,6 +24995,13 @@ Sollen die vorhandenen Klassen vor der Klassifizierung gelöscht werden?</transl
     </message>
 </context>
 <context>
+    <name>QgsClipboard</name>
+    <message>
+        <source>Datum transformation for copied features</source>
+        <translation>Datum transformation für kopierte Objekte</translation>
+    </message>
+</context>
+<context>
     <name>QgsCodeEditorCSS</name>
     <message>
         <source>CSS Editor</source>
@@ -34102,6 +34161,10 @@ Parser-Fehler:
         <source>CRS</source>
         <translation>KBS</translation>
     </message>
+    <message>
+        <source>Force 2d output (eg. to support polyline width)</source>
+        <translation>2D-Ausgabe erzwingen (z.B. um Polylinienbreiten zu unterstützen)</translation>
+    </message>
 </context>
 <context>
     <name>QgsEditorWidgetRegistry</name>
@@ -65778,6 +65841,14 @@ Fehler war:%2</translation>
         <translation>
 Datenanbieterfehler:</translation>
     </message>
+    <message numerus="yes">
+        <source>ERROR: %n feature(s) not added - geometry type is not compatible with the current layer.</source>
+        <comment>not added features count</comment>
+        <translation>
+            <numerusform>FEHLER: Ein Objekt nicht hinzugefügt - Geometrietyp paßt nicht zum aktuellen Layer.</numerusform>
+            <numerusform>FEHLER: %n Objekte nicht hinzugefügt - Geometrietyp paßt nicht zum aktuellen Layer.</numerusform>
+        </translation>
+    </message>
 </context>
 <context>
     <name>QgsVectorLayerProperties</name>
@@ -69563,7 +69634,11 @@ Maximalzahl der Versuche überschritten.</translation>
     </message>
     <message>
         <source>QGIS Layer Style File (*.qml *.QML)</source>
-        <translation>QGIS Layerstildatei (*.qml *.QML)</translation>
+        <translation type="obsolete">QGIS Layerstildatei (*.qml *.QML)</translation>
+    </message>
+    <message>
+        <source>QGIS Layer Style File (*.qml *.QML);;</source>
+        <translation>QGIS-Layerstildatei (*.qml *.QML);;</translation>
     </message>
 </context>
 <context>
@@ -69843,1047 +69918,1047 @@ Maximalzahl der Versuche überschritten.</translation>
     <name>SAGAAlgorithm</name>
     <message>
         <source>Slope Length</source>
-        <translation>Hanglänge</translation>
+        <translation type="obsolete">Hanglänge</translation>
     </message>
     <message>
         <source>Shapes Buffer (Attribute distance)|Shapes Buffer</source>
-        <translation>Shapepuffer (Attributabstand)|Shapepuffer</translation>
+        <translation type="obsolete">Shapepuffer (Attributabstand)|Shapepuffer</translation>
     </message>
     <message>
         <source>Representativeness|Representativeness (Grid)</source>
-        <translation>Repräsentativität|Repräsentativität (Raster)</translation>
+        <translation type="obsolete">Repräsentativität|Repräsentativität (Raster)</translation>
     </message>
     <message>
         <source>Gaussian Filter</source>
-        <translation>Gauss'scher Filter</translation>
+        <translation type="obsolete">Gauss'scher Filter</translation>
     </message>
     <message>
         <source>Flow Accumulation (Top-Down)</source>
-        <translation>Flußdichte (Oben-Unten)</translation>
+        <translation type="obsolete">Flußdichte (Oben-Unten)</translation>
     </message>
     <message>
         <source>Convex Hull</source>
-        <translation>Konvexe Hülle</translation>
+        <translation type="obsolete">Konvexe Hülle</translation>
     </message>
     <message>
         <source>Flow Accumulation (Recursive)</source>
-        <translation>Flußdichte (Rekursiv)</translation>
+        <translation type="obsolete">Flußdichte (Rekursiv)</translation>
     </message>
     <message>
         <source>Polygon Centroids</source>
-        <translation>Polygonschwerpunkt</translation>
+        <translation type="obsolete">Polygonschwerpunkt</translation>
     </message>
     <message>
         <source>Flow Accumulation (Flow Tracing)</source>
-        <translation>Flußdichte (Flußverfolgung)</translation>
+        <translation type="obsolete">Flußdichte (Flußverfolgung)</translation>
     </message>
     <message>
         <source>Point Statistics for Polygons</source>
-        <translation>Polygon-Punktstatistik</translation>
+        <translation type="obsolete">Polygon-Punktstatistik</translation>
     </message>
     <message>
         <source>Grid Values to Points (randomly)</source>
-        <translation>Gitterwerte zu Punkten (zufällig)</translation>
+        <translation type="obsolete">Gitterwerte zu Punkten (zufällig)</translation>
     </message>
     <message>
         <source>Clip Points with Polygons</source>
-        <translation>Punkte auf Polygon zuschneiden</translation>
+        <translation type="obsolete">Punkte auf Polygon zuschneiden</translation>
     </message>
     <message>
         <source>Gradient Vectors from Direction and Length</source>
-        <translation>Gradientenvektor aus Richtung und Länge</translation>
+        <translation type="obsolete">Gradientenvektor aus Richtung und Länge</translation>
     </message>
     <message>
         <source>Grid Statistics for Polygons</source>
-        <translation>Gitterstatistik für Polygone</translation>
+        <translation type="obsolete">Gitterstatistik für Polygone</translation>
     </message>
     <message>
         <source>Layer of extreme value</source>
-        <translation>Extrema-Layer</translation>
+        <translation type="obsolete">Extrema-Layer</translation>
     </message>
     <message>
         <source>Create Graticule</source>
-        <translation>Gradnetz erzeugen</translation>
+        <translation type="obsolete">Gradnetz erzeugen</translation>
     </message>
     <message>
         <source>Difference</source>
-        <translation>Differenz</translation>
+        <translation type="obsolete">Differenz</translation>
     </message>
     <message>
         <source>Clip Grid with Polygon</source>
-        <translation>Punkte auf Polygon zuschneiden</translation>
+        <translation type="obsolete">Punkte auf Polygon zuschneiden</translation>
     </message>
     <message>
         <source>Crop to Data</source>
-        <translation>Auf Daten zuschneiden</translation>
+        <translation type="obsolete">Auf Daten zuschneiden</translation>
     </message>
     <message>
         <source>Close Gaps</source>
-        <translation>Lücken schließen</translation>
+        <translation type="obsolete">Lücken schließen</translation>
     </message>
     <message>
         <source>Polygon Clipping</source>
-        <translation>Polygonclipping</translation>
+        <translation type="obsolete">Polygonclipping</translation>
     </message>
     <message>
         <source>Multiresolution Index of Valley Bottom Flatness (MRVBF)</source>
-        <translation>Mehrauflösung-Talbodenebenheitsindex (MRVBF)</translation>
+        <translation type="obsolete">Mehrauflösung-Talbodenebenheitsindex (MRVBF)</translation>
     </message>
     <message>
         <source>Flatten Polygon Layer</source>
-        <translation>Polygonlayer glätten</translation>
+        <translation type="obsolete">Polygonlayer glätten</translation>
     </message>
     <message>
         <source>Shared Polygon Edges</source>
-        <translation>Gemeinsame Polygonkanten</translation>
+        <translation type="obsolete">Gemeinsame Polygonkanten</translation>
     </message>
     <message>
         <source>Add Point Attributes to Polygons</source>
-        <translation>Punktattribute zu Polygonen hinzufügen</translation>
+        <translation type="obsolete">Punktattribute zu Polygonen hinzufügen</translation>
     </message>
     <message>
         <source>Polygon Self-Intersection</source>
-        <translation>Polygonselbstüberschneidungen</translation>
+        <translation type="obsolete">Polygonselbstüberschneidungen</translation>
     </message>
     <message>
         <source>Gradient Vectors from Surface</source>
-        <translation>Gradientenvektor aus Oberfläche</translation>
+        <translation type="obsolete">Gradientenvektor aus Oberfläche</translation>
     </message>
     <message>
         <source>GWR for Multiple Predictor Grids</source>
-        <translation>GWR für mehrere Vorsagegitter</translation>
+        <translation type="obsolete">GWR für mehrere Vorsagegitter</translation>
     </message>
     <message>
         <source>Multiple Regression Analysis (Points/Grids)</source>
-        <translation>Mehrfach-Regressionsanalyse (Punkt/Raster)</translation>
+        <translation type="obsolete">Mehrfach-Regressionsanalyse (Punkt/Raster)</translation>
     </message>
     <message>
         <source>Hypsometry</source>
-        <translation>Hypsometrie</translation>
+        <translation type="obsolete">Hypsometrie</translation>
     </message>
     <message>
         <source>Aggregation Index</source>
-        <translation>Aggregationsindex</translation>
+        <translation type="obsolete">Aggregationsindex</translation>
     </message>
     <message>
         <source>Identity</source>
-        <translation>Identität</translation>
+        <translation type="obsolete">Identität</translation>
     </message>
     <message>
         <source>LS Factor</source>
-        <translation>LS-Faktor</translation>
+        <translation type="obsolete">LS-Faktor</translation>
     </message>
     <message>
         <source>DTM Filter (slope-based)</source>
-        <translation>DTM-Filter (Hangbasiert)</translation>
+        <translation type="obsolete">DTM-Filter (Hangbasiert)</translation>
     </message>
     <message>
         <source>Effective Air Flow Heights</source>
-        <translation>Effektive Luftflußhöhen</translation>
+        <translation type="obsolete">Effektive Luftflußhöhen</translation>
     </message>
     <message>
         <source>Add Grid Values to Points</source>
-        <translation>Gitterwerte zu Punkten</translation>
+        <translation type="obsolete">Gitterwerte zu Punkten</translation>
     </message>
     <message>
         <source>Kernel Density Estimation</source>
-        <translation>Kerndichtenschätzung</translation>
+        <translation type="obsolete">Kerndichtenschätzung</translation>
     </message>
     <message>
         <source>Grid Cell Index</source>
-        <translation>Gitterzellenindex</translation>
+        <translation type="obsolete">Gitterzellenindex</translation>
     </message>
     <message>
         <source>Mass Balance Index</source>
-        <translation>Gleichgewichtsindex</translation>
+        <translation type="obsolete">Gleichgewichtsindex</translation>
     </message>
     <message>
         <source>Transform Shapes</source>
-        <translation>Shapes transformieren</translation>
+        <translation type="obsolete">Shapes transformieren</translation>
     </message>
     <message>
         <source>Regression analysis|Regression Analysis (Points/Grid)</source>
-        <translation>Regressionanalyse|Regressionsanalyse (Punkte/Raster)</translation>
+        <translation type="obsolete">Regressionanalyse|Regressionsanalyse (Punkte/Raster)</translation>
     </message>
     <message>
         <source>Polygon Properties</source>
-        <translation>Polygoneigenschaften</translation>
+        <translation type="obsolete">Polygoneigenschaften</translation>
     </message>
     <message>
         <source>Geographically Weighted Multiple Regression</source>
-        <translation>Geografischgewichtete Mehrfach-Regression</translation>
+        <translation type="obsolete">Geografischgewichtete Mehrfach-Regression</translation>
     </message>
     <message>
         <source>GWR for Multiple Predictors (Gridded Model Output)</source>
-        <translation>GWR für mehrere Vorsagegitter (Gerasterte Modellausgabe)</translation>
+        <translation type="obsolete">GWR für mehrere Vorsagegitter (Gerasterte Modellausgabe)</translation>
     </message>
     <message>
         <source>Directional Statistics for Single Grid</source>
-        <translation>Richtungsstatistik für Einzelraster</translation>
+        <translation type="obsolete">Richtungsstatistik für Einzelraster</translation>
     </message>
     <message>
         <source>Fill Sinks|Fill Sinks (Planchon/Darboux, 2001)</source>
-        <translation>Senken füllen|Senken füllen (Planchon/Darboux, 2001)</translation>
+        <translation type="obsolete">Senken füllen|Senken füllen (Planchon/Darboux, 2001)</translation>
     </message>
     <message>
         <source>Grids Product</source>
-        <translation>Rasterprodukte</translation>
+        <translation type="obsolete">Rasterprodukte</translation>
     </message>
     <message>
         <source>Fill Gaps in Records</source>
-        <translation>Datensatzlücken füllen</translation>
+        <translation type="obsolete">Datensatzlücken füllen</translation>
     </message>
     <message>
         <source>Topographic Correction</source>
-        <translation>Topographische Korrektur</translation>
+        <translation type="obsolete">Topographische Korrektur</translation>
     </message>
     <message>
         <source>Grid Buffer</source>
-        <translation>Gitterpuffer</translation>
+        <translation type="obsolete">Gitterpuffer</translation>
     </message>
     <message>
         <source>Catchment Area (Flow Tracing)</source>
-        <translation>Einzugsbereich (Flußverfolgung)</translation>
+        <translation type="obsolete">Einzugsbereich (Flußverfolgung)</translation>
     </message>
     <message>
         <source>User Defined Filter</source>
-        <translation>Benutzerdefinierter Filter</translation>
+        <translation type="obsolete">Benutzerdefinierter Filter</translation>
     </message>
     <message>
         <source>Watershed Segmentation</source>
-        <translation>Niederschlagssegmentierung</translation>
+        <translation type="obsolete">Niederschlagssegmentierung</translation>
     </message>
     <message>
         <source>Line Simplification</source>
-        <translation>Linienvereinfachung</translation>
+        <translation type="obsolete">Linienvereinfachung</translation>
     </message>
     <message>
         <source>Convergence Index (Search Radius)</source>
-        <translation>Konvergenzindex (Suchradius)</translation>
+        <translation type="obsolete">Konvergenzindex (Suchradius)</translation>
     </message>
     <message>
         <source>Topographic Wetness Index (TWI)</source>
-        <translation>Topographischer Niederschlagsindex (TWI)</translation>
+        <translation type="obsolete">Topographischer Niederschlagsindex (TWI)</translation>
     </message>
     <message>
         <source>Upslope Area|4</source>
-        <translation>Anstieg Areal4</translation>
+        <translation type="obsolete">Anstieg Areal4</translation>
     </message>
     <message>
         <source>Laplacian Filter</source>
-        <translation>Laplace-Filter</translation>
+        <translation type="obsolete">Laplace-Filter</translation>
     </message>
     <message>
         <source>Grid Proximity Buffer</source>
-        <translation>Gitterannährungspuffer</translation>
+        <translation type="obsolete">Gitterannährungspuffer</translation>
     </message>
     <message>
         <source>Aggregate Point Observations</source>
-        <translation>Punktbeobachtung sammeln</translation>
+        <translation type="obsolete">Punktbeobachtung sammeln</translation>
     </message>
     <message>
         <source>Transpose Grids</source>
-        <translation>Gitter transponieren</translation>
+        <translation type="obsolete">Gitter transponieren</translation>
     </message>
     <message>
         <source>Topographic Position Index (TPI)</source>
-        <translation>Topographische Position (TPI)</translation>
+        <translation type="obsolete">Topographische Position (TPI)</translation>
     </message>
     <message>
         <source>Grid Masking</source>
-        <translation>Gittermaskierung</translation>
+        <translation type="obsolete">Gittermaskierung</translation>
     </message>
     <message>
         <source>Channel Network and Drainage Basins</source>
-        <translation>Kanalnetzwerk und Drainagebecken</translation>
+        <translation type="obsolete">Kanalnetzwerk und Drainagebecken</translation>
     </message>
     <message>
         <source>Real Surface Area</source>
-        <translation>Echte Oberfläche</translation>
+        <translation type="obsolete">Echte Oberfläche</translation>
     </message>
     <message>
         <source>Threshold Buffer</source>
-        <translation>Schwellenpuffer</translation>
+        <translation type="obsolete">Schwellenpuffer</translation>
     </message>
     <message>
         <source>Add Grid Values to Shapes</source>
-        <translation>Gitterwerte zu Shapes hinzufügen</translation>
+        <translation type="obsolete">Gitterwerte zu Shapes hinzufügen</translation>
     </message>
     <message>
         <source>QuadTree Structure to Shapes</source>
-        <translation>Quad-Tree-Struktur zu Shapes</translation>
+        <translation type="obsolete">Quad-Tree-Struktur zu Shapes</translation>
     </message>
     <message>
         <source>Analytical Hillshading</source>
-        <translation>Analytische Schummerung</translation>
+        <translation type="obsolete">Analytische Schummerung</translation>
     </message>
     <message>
         <source>Surface Specific Points</source>
-        <translation>Oberflächen spezifische Punkte</translation>
+        <translation type="obsolete">Oberflächen spezifische Punkte</translation>
     </message>
     <message>
         <source>Transect through polygon shapefile</source>
-        <translation>Durch Polygonshapedateien schneiden</translation>
+        <translation type="obsolete">Durch Polygonshapedateien schneiden</translation>
     </message>
     <message>
         <source>Convert Lines to Polygons</source>
-        <translation>Linien in Polygone umwandeln</translation>
+        <translation type="obsolete">Linien in Polygone umwandeln</translation>
     </message>
     <message>
         <source>Local Minima and Maxima</source>
-        <translation>Lokale Minima und Maxima</translation>
+        <translation type="obsolete">Lokale Minima und Maxima</translation>
     </message>
     <message>
         <source>Accumulated Cost (Isotropic)</source>
-        <translation>Aufgelaufenen Kosten (isotropisch)</translation>
+        <translation type="obsolete">Aufgelaufenen Kosten (isotropisch)</translation>
     </message>
     <message>
         <source>Line Dissolve</source>
-        <translation>Linien auflösen</translation>
+        <translation type="obsolete">Linien auflösen</translation>
     </message>
     <message>
         <source>Resampling</source>
-        <translation>Abtastung</translation>
+        <translation type="obsolete">Abtastung</translation>
     </message>
     <message>
         <source>Fuzzy Union (OR)</source>
-        <translation>Fuzzy-Vereinigung (ODER)</translation>
+        <translation type="obsolete">Fuzzy-Vereinigung (ODER)</translation>
     </message>
     <message>
         <source>Natural Neighbour</source>
-        <translation>Natürlicher Nachbar</translation>
+        <translation type="obsolete">Natürlicher Nachbar</translation>
     </message>
     <message>
         <source>Convert Lines to Points</source>
-        <translation>Linien in Punkten umwandeln</translation>
+        <translation type="obsolete">Linien in Punkten umwandeln</translation>
     </message>
     <message>
         <source>Thin Plate Spline (Global)</source>
-        <translation>Thin Plate Spline (global)</translation>
+        <translation type="obsolete">Thin Plate Spline (global)</translation>
     </message>
     <message>
         <source>Polygon dissolve (by attribute)|Polygon Dissolve</source>
-        <translation>Polygon auflösen (nach Attribut)|Polygon auflösen</translation>
+        <translation type="obsolete">Polygon auflösen (nach Attribut)|Polygon auflösen</translation>
     </message>
     <message>
         <source>Stream Power Index</source>
-        <translation>Stromstärkeindex</translation>
+        <translation type="obsolete">Stromstärkeindex</translation>
     </message>
     <message>
         <source>Global Moran's I for Grids</source>
-        <translation>Global Moran I für Raster</translation>
+        <translation type="obsolete">Global Moran I für Raster</translation>
     </message>
     <message>
         <source>Polynomial Regression</source>
-        <translation>Polynominalregression</translation>
+        <translation type="obsolete">Polynominalregression</translation>
     </message>
     <message>
         <source>Multiple Regression Analysis (Grid/Grids)</source>
-        <translation>Mehrfach-Regressionsanalyse (Gitter)</translation>
+        <translation type="obsolete">Mehrfach-Regressionsanalyse (Gitter)</translation>
     </message>
     <message>
         <source>Nearest Neighbour</source>
-        <translation>Nächster Nachbar</translation>
+        <translation type="obsolete">Nächster Nachbar</translation>
     </message>
     <message>
         <source>Water Retention Capacity</source>
-        <translation>Bodenwasserspannungskapazität</translation>
+        <translation type="obsolete">Bodenwasserspannungskapazität</translation>
     </message>
     <message>
         <source>Gradient Vectors from Directional Components</source>
-        <translation>Gradientenvektoren aus gerichteten Komponenten</translation>
+        <translation type="obsolete">Gradientenvektoren aus gerichteten Komponenten</translation>
     </message>
     <message>
         <source>Majority Filter</source>
-        <translation>Mehrheitsfilter</translation>
+        <translation type="obsolete">Mehrheitsfilter</translation>
     </message>
     <message>
         <source>Flow Path Length</source>
-        <translation>Fließweglänge</translation>
+        <translation type="obsolete">Fließweglänge</translation>
     </message>
     <message>
         <source>Simple Region Growing</source>
-        <translation>Einfaches Region-Growing</translation>
+        <translation type="obsolete">Einfaches Region-Growing</translation>
     </message>
     <message>
         <source>Simulation</source>
-        <translation>Simulation</translation>
+        <translation type="obsolete">Simulation</translation>
     </message>
     <message>
         <source>Get Shapes Extents</source>
-        <translation>Shapeausmaße bestimmen</translation>
+        <translation type="obsolete">Shapeausmaße bestimmen</translation>
     </message>
     <message>
         <source>Union</source>
-        <translation>Vereinigungen</translation>
+        <translation type="obsolete">Vereinigungen</translation>
     </message>
     <message>
         <source>Fill Sinks XXL (Wang & Liu)</source>
-        <translation>Senken füllen XXL (Wang & Liu)</translation>
+        <translation type="obsolete">Senken füllen XXL (Wang & Liu)</translation>
     </message>
     <message>
         <source>B-Spline Approximation</source>
-        <translation>B-Spline-Approximation</translation>
+        <translation type="obsolete">B-Spline-Approximation</translation>
     </message>
     <message>
         <source>Polygon Parts to Separate Polygons</source>
-        <translation>Polygonteile in Einzelpolygone umwandeln</translation>
+        <translation type="obsolete">Polygonteile in Einzelpolygone umwandeln</translation>
     </message>
     <message>
         <source>Points Thinning</source>
-        <translation>Punkte ausdünnen</translation>
+        <translation type="obsolete">Punkte ausdünnen</translation>
     </message>
     <message>
         <source>Change Date Format</source>
-        <translation>Datumsformat ändern</translation>
+        <translation type="obsolete">Datumsformat ändern</translation>
     </message>
     <message>
         <source>Gradient Vector from Cartesian to Polar Coordinates</source>
-        <translation>Gradientenvektor aus kartesischen in Polar-Koordinaten</translation>
+        <translation type="obsolete">Gradientenvektor aus kartesischen in Polar-Koordinaten</translation>
     </message>
     <message>
         <source>Fragmentation Classes from Density and Connectivity</source>
-        <translation>Fragmentierungsklassen aus Dichte und Verbindungen</translation>
+        <translation type="obsolete">Fragmentierungsklassen aus Dichte und Verbindungen</translation>
     </message>
     <message>
         <source>Ordinary Kriging</source>
-        <translation>Normales Krigen</translation>
+        <translation type="obsolete">Normales Krigen</translation>
     </message>
     <message>
         <source>Grid Volume</source>
-        <translation>Rastervolumen</translation>
+        <translation type="obsolete">Rastervolumen</translation>
     </message>
     <message>
         <source>Patching</source>
-        <translation>Zusammenflicken</translation>
+        <translation type="obsolete">Zusammenflicken</translation>
     </message>
     <message>
         <source>Ordered Weighted Averaging|Ordered Weighted Averaging (OWA)</source>
-        <translation>Sortiertes gewichtetes Mitteln|Sortiertes gewichtetes Mitteln (OWA)</translation>
+        <translation type="obsolete">Sortiertes gewichtetes Mitteln|Sortiertes gewichtetes Mitteln (OWA)</translation>
     </message>
     <message>
         <source>Thin Plate Spline (TIN)</source>
-        <translation>Thin-Plate-Spline (TIN)</translation>
+        <translation type="obsolete">Thin-Plate-Spline (TIN)</translation>
     </message>
     <message>
         <source>SAGA Wetness Index</source>
-        <translation>SAGA Feuchtigkeitsindex</translation>
+        <translation type="obsolete">SAGA Feuchtigkeitsindex</translation>
     </message>
     <message>
         <source>Histogram Surface</source>
-        <translation>Histogramm-Oberfläche</translation>
+        <translation type="obsolete">Histogramm-Oberfläche</translation>
     </message>
     <message>
         <source>Merge Layers</source>
-        <translation>Layer zusammenführen</translation>
+        <translation type="obsolete">Layer zusammenführen</translation>
     </message>
     <message>
         <source>Grid Skeletonization</source>
-        <translation>Rasterskelettierung</translation>
+        <translation type="obsolete">Rasterskelettierung</translation>
     </message>
     <message>
         <source>Catchment Area|Catchment Area (Parallel)</source>
-        <translation>Einzugsgebiet|Einzugsgebiet (Parallel)</translation>
+        <translation type="obsolete">Einzugsgebiet|Einzugsgebiet (Parallel)</translation>
     </message>
     <message>
         <source>Geometric Figures</source>
-        <translation>Geometrische Figuren</translation>
+        <translation type="obsolete">Geometrische Figuren</translation>
     </message>
     <message>
         <source>Spatial Point Pattern Analysis</source>
-        <translation>Räumliche Punktmusteranalyse</translation>
+        <translation type="obsolete">Räumliche Punktmusteranalyse</translation>
     </message>
     <message>
         <source>Update</source>
-        <translation>Aktualisieren</translation>
+        <translation type="obsolete">Aktualisieren</translation>
     </message>
     <message>
         <source>Sink Removal</source>
-        <translation>Ablauf entfernen</translation>
+        <translation type="obsolete">Ablauf entfernen</translation>
     </message>
     <message>
         <source>Convert Points to Line(s)</source>
-        <translation>Punkte in Linien umwandeln</translation>
+        <translation type="obsolete">Punkte in Linien umwandeln</translation>
     </message>
     <message>
         <source>Change Grid Values</source>
-        <translation>Gitterwert ändern</translation>
+        <translation type="obsolete">Gitterwert ändern</translation>
     </message>
     <message>
         <source>Line Properties</source>
-        <translation>Linieneigenschaften</translation>
+        <translation type="obsolete">Linieneigenschaften</translation>
     </message>
     <message>
         <source>Convert Multipoints to Points</source>
-        <translation>Multipunkt zu Punkt umwandeln</translation>
+        <translation type="obsolete">Multipunkt zu Punkt umwandeln</translation>
     </message>
     <message>
         <source>Cell Balance</source>
-        <translation>Zellengleichgewicht</translation>
+        <translation type="obsolete">Zellengleichgewicht</translation>
     </message>
     <message>
         <source>Fill Sinks (Wang & Liu)</source>
-        <translation>Senken füllen (Wang & Liu)</translation>
+        <translation type="obsolete">Senken füllen (Wang & Liu)</translation>
     </message>
     <message>
         <source>Convert Data Storage Type</source>
-        <translation>Datenspeichertyp umwandeln</translation>
+        <translation type="obsolete">Datenspeichertyp umwandeln</translation>
     </message>
     <message>
         <source>Rank Filter</source>
-        <translation>Rangfilter</translation>
+        <translation type="obsolete">Rangfilter</translation>
     </message>
     <message>
         <source>Change Detection</source>
-        <translation>Erkennung ändern</translation>
+        <translation type="obsolete">Erkennung ändern</translation>
     </message>
     <message>
         <source>Strahler Order</source>
-        <translation>Strahler-Reihenfolge</translation>
+        <translation type="obsolete">Strahler-Reihenfolge</translation>
     </message>
     <message>
         <source>Inverse Distance Weighted</source>
-        <translation>gewichtete inverse Distanz (IDW)</translation>
+        <translation type="obsolete">gewichtete inverse Distanz (IDW)</translation>
     </message>
     <message>
         <source>Multilevel B-Spline Interpolation (from Grid)</source>
-        <translation>Mehrstufen-B-Spline-Interpolation (aus Gitter)</translation>
+        <translation type="obsolete">Mehrstufen-B-Spline-Interpolation (aus Gitter)</translation>
     </message>
     <message>
         <source>Geographically Weighted Multiple Regression (Points/Grids)</source>
-        <translation>Geografischgewichtete Mehrfach-Regression (Punkt/Gitter)</translation>
+        <translation type="obsolete">Geografischgewichtete Mehrfach-Regression (Punkt/Gitter)</translation>
     </message>
     <message>
         <source>Fast Region Growing Algorithm</source>
-        <translation>Schneller Regionswachstumalgorithmus</translation>
+        <translation type="obsolete">Schneller Regionswachstumalgorithmus</translation>
     </message>
     <message>
         <source>Terrain Ruggedness Index (TRI)</source>
-        <translation>Oberflächenrauhigkeit (TRI)</translation>
+        <translation type="obsolete">Oberflächenrauhigkeit (TRI)</translation>
     </message>
     <message>
         <source>GWR for Single Predictor Grid</source>
-        <translation>GWR für einzelnes Vorsagegitter</translation>
+        <translation type="obsolete">GWR für einzelnes Vorsagegitter</translation>
     </message>
     <message>
         <source>Points Filter</source>
-        <translation>Punktfilter</translation>
+        <translation type="obsolete">Punktfilter</translation>
     </message>
     <message>
         <source>Radius of Variance (Grid)</source>
-        <translation>Radius der Varianz (Gitter)</translation>
+        <translation type="obsolete">Radius der Varianz (Gitter)</translation>
     </message>
     <message>
         <source>Geographically Weighted Multiple Regression (Points)</source>
-        <translation>Geografischgewichtete Mehrfach-Regression (Punkte)</translation>
+        <translation type="obsolete">Geografischgewichtete Mehrfach-Regression (Punkte)</translation>
     </message>
     <message>
         <source>Sink Drainage Route Detection</source>
-        <translation>Ablaufdrainageweg bestimmen</translation>
+        <translation type="obsolete">Ablaufdrainageweg bestimmen</translation>
     </message>
     <message>
         <source>GWR for Single Predictor (Gridded Model Output)</source>
-        <translation>GWR für einzelnes Vorsagegitter (Gerasterte Modellausgabe)</translation>
+        <translation type="obsolete">GWR für einzelnes Vorsagegitter (Gerasterte Modellausgabe)</translation>
     </message>
     <message>
         <source>Cubic Spline Approximation</source>
-        <translation>Kubische Spline-Nährung</translation>
+        <translation type="obsolete">Kubische Spline-Nährung</translation>
     </message>
     <message>
         <source>Overland Flow Distance to Channel Network</source>
-        <translation>Überlandflußabstand zu Kanalnetzwerken</translation>
+        <translation type="obsolete">Überlandflußabstand zu Kanalnetzwerken</translation>
     </message>
     <message>
         <source>Shapes Buffer (Fixed distance)|Shapes Buffer</source>
-        <translation>Shapepuffer (fester Abstand)|Shapepuffer</translation>
+        <translation type="obsolete">Shapepuffer (fester Abstand)|Shapepuffer</translation>
     </message>
     <message>
         <source>Line-Polygon Intersection</source>
-        <translation>Linien-Polygon-Verschneidung</translation>
+        <translation type="obsolete">Linien-Polygon-Verschneidung</translation>
     </message>
     <message>
         <source>Accumulated Cost (Anisotropic)</source>
-        <translation>Aufgelaufenen Kosten (Anisotropisch)</translation>
+        <translation type="obsolete">Aufgelaufenen Kosten (Anisotropisch)</translation>
     </message>
     <message>
         <source>Fragmentation (Alternative)</source>
-        <translation>Fragmentierung (Alternative)</translation>
+        <translation type="obsolete">Fragmentierung (Alternative)</translation>
     </message>
     <message>
         <source>Principle Components Analysis</source>
-        <translation>Hauptkomponentenanalyse</translation>
+        <translation type="obsolete">Hauptkomponentenanalyse</translation>
     </message>
     <message>
         <source>Ordinary Kriging (Global)</source>
-        <translation>Normales Krigen (Global)</translation>
+        <translation type="obsolete">Normales Krigen (Global)</translation>
     </message>
     <message>
         <source>Multi-Band Variation</source>
-        <translation>Mehrkanalvariation</translation>
+        <translation type="obsolete">Mehrkanalvariation</translation>
     </message>
     <message>
         <source>Universal Kriging (Global)</source>
-        <translation>Universeles Krigen (Global)</translation>
+        <translation type="obsolete">Universeles Krigen (Global)</translation>
     </message>
     <message>
         <source>Analytical Hierarchy Process</source>
-        <translation>Analytischer Hierachieprozeß</translation>
+        <translation type="obsolete">Analytischer Hierachieprozeß</translation>
     </message>
     <message>
         <source>Diurnal Anisotropic Heating</source>
-        <translation>Anisotrope Erwärmung über Tag</translation>
+        <translation type="obsolete">Anisotrope Erwärmung über Tag</translation>
     </message>
     <message>
         <source>Variogram Surface</source>
-        <translation>Variogramm-Oberfläche</translation>
+        <translation type="obsolete">Variogramm-Oberfläche</translation>
     </message>
     <message>
         <source>Multi Direction Lee Filter</source>
-        <translation>Mehrrichtung-Lee-Filter</translation>
+        <translation type="obsolete">Mehrrichtung-Lee-Filter</translation>
     </message>
     <message>
         <source>Watershed Basins</source>
-        <translation>Einzugsgebietsbecken</translation>
+        <translation type="obsolete">Einzugsgebietsbecken</translation>
     </message>
     <message>
         <source>Supervised Classification</source>
-        <translation>Überwachte Klassifizierung</translation>
+        <translation type="obsolete">Überwachte Klassifizierung</translation>
     </message>
     <message>
         <source>Soil Texture Classification</source>
-        <translation>Bodentexturklassifizierung</translation>
+        <translation type="obsolete">Bodentexturklassifizierung</translation>
     </message>
     <message>
         <source>Vectorising Grid Classes</source>
-        <translation>Vektorisierende Gitter-Klassen</translation>
+        <translation type="obsolete">Vektorisierende Gitter-Klassen</translation>
     </message>
     <message>
         <source>Modified Quadratic Shepard</source>
-        <translation>Modifizierte quadratische Shepard-Methode</translation>
+        <translation type="obsolete">Modifizierte quadratische Shepard-Methode</translation>
     </message>
     <message>
         <source>Variogram Cloud</source>
-        <translation>Variogramm Wolke</translation>
+        <translation type="obsolete">Variogramm Wolke</translation>
     </message>
     <message>
         <source>Vectorising Raster Classes</source>
-        <translation>Vektorisierene Rasterklassen</translation>
+        <translation type="obsolete">Vektorisierene Rasterklassen</translation>
     </message>
     <message>
         <source>Morphometric Protection Index</source>
-        <translation>Morphometrischer Schutzindex</translation>
+        <translation type="obsolete">Morphometrischer Schutzindex</translation>
     </message>
     <message>
         <source>Universal Kriging</source>
-        <translation>Universeles Krigen</translation>
+        <translation type="obsolete">Universeles Krigen</translation>
     </message>
     <message>
         <source>Raster calculator|Grid Calculator</source>
-        <translation>Rasterrechner|Rasterrechner</translation>
+        <translation type="obsolete">Rasterrechner|Rasterrechner</translation>
     </message>
     <message>
         <source>Grid Orientation</source>
-        <translation>Gitterrichtung</translation>
+        <translation type="obsolete">Gitterrichtung</translation>
     </message>
     <message>
         <source>Convergence Index</source>
-        <translation>Konvergenzindex</translation>
+        <translation type="obsolete">Konvergenzindex</translation>
     </message>
     <message>
         <source>Shapes to Grid</source>
-        <translation>Shapes in Gitter</translation>
+        <translation type="obsolete">Shapes in Gitter</translation>
     </message>
     <message>
         <source>Land Surface Temperature</source>
-        <translation>Landoberflächentemperatur</translation>
+        <translation type="obsolete">Landoberflächentemperatur</translation>
     </message>
     <message>
         <source>Polygon dissolve (all polygons)|Polygon Dissolve</source>
-        <translation>Polygon auflösen (alle Polygone)|Polygon auflösen</translation>
+        <translation type="obsolete">Polygon auflösen (alle Polygone)|Polygon auflösen</translation>
     </message>
     <message>
         <source>Flow Width and Specific Catchment Area</source>
-        <translation>Flußbreite und spezifisches Einzugsgebiet</translation>
+        <translation type="obsolete">Flußbreite und spezifisches Einzugsgebiet</translation>
     </message>
     <message>
         <source>Random Terrain Generation</source>
-        <translation>Zufälliges Gelände erzeugen</translation>
+        <translation type="obsolete">Zufälliges Gelände erzeugen</translation>
     </message>
     <message>
         <source>Convert Polygons to Lines</source>
-        <translation>Polygon in Linien umwandeln</translation>
+        <translation type="obsolete">Polygon in Linien umwandeln</translation>
     </message>
     <message>
         <source>Fuzzy Intersection (AND)</source>
-        <translation>Fuzzy-Schnittmenge (UND)</translation>
+        <translation type="obsolete">Fuzzy-Schnittmenge (UND)</translation>
     </message>
     <message>
         <source>Polygon Shape Indices</source>
-        <translation>Polygonshapeindizes</translation>
+        <translation type="obsolete">Polygonshapeindizes</translation>
     </message>
     <message>
         <source>Cluster Analysis for Grids</source>
-        <translation>Häufungsanalyse für Gitter</translation>
+        <translation type="obsolete">Häufungsanalyse für Gitter</translation>
     </message>
     <message>
         <source>Burn Stream Network into DEM</source>
-        <translation>Stromnetzwerk in DEM brennen</translation>
+        <translation type="obsolete">Stromnetzwerk in DEM brennen</translation>
     </message>
     <message>
         <source>Relative Heights and Slope Positions</source>
-        <translation>Relative Höhen und Hangpositionen</translation>
+        <translation type="obsolete">Relative Höhen und Hangpositionen</translation>
     </message>
     <message>
         <source>Regression Kriging</source>
-        <translation>Regressionskrigen</translation>
+        <translation type="obsolete">Regressionskrigen</translation>
     </message>
     <message>
         <source>Simple Kriging</source>
-        <translation>Einfaches Krigen</translation>
+        <translation type="obsolete">Einfaches Krigen</translation>
     </message>
     <message>
         <source>Fuzzify</source>
-        <translation>Fuzzifizieren</translation>
+        <translation type="obsolete">Fuzzifizieren</translation>
     </message>
     <message>
         <source>Catchment Area (Recursive)</source>
-        <translation>Einzugsbereich (Rekursiv)</translation>
+        <translation type="obsolete">Einzugsbereich (Rekursiv)</translation>
     </message>
     <message>
         <source>Convert Polygon/Line Vertices to Points</source>
-        <translation>Polygon-/Linienstützpunkte in Punkte umwandeln</translation>
+        <translation type="obsolete">Polygon-/Linienstützpunkte in Punkte umwandeln</translation>
     </message>
     <message>
         <source>Least Cost Paths</source>
-        <translation>Pfad geringster Kosten</translation>
+        <translation type="obsolete">Pfad geringster Kosten</translation>
     </message>
     <message>
         <source>Split Shapes Layer Randomly</source>
-        <translation>Shapelayer zufällig aufteilen</translation>
+        <translation type="obsolete">Shapelayer zufällig aufteilen</translation>
     </message>
     <message>
         <source>Grid Standardisation</source>
-        <translation>Gitterstandardisierung</translation>
+        <translation type="obsolete">Gitterstandardisierung</translation>
     </message>
     <message>
         <source>Proximity Grid</source>
-        <translation>Näheraster</translation>
+        <translation type="obsolete">Näheraster</translation>
     </message>
     <message>
         <source>Contour Lines from Grid</source>
-        <translation>Umrandungslinien aus Raster</translation>
+        <translation type="obsolete">Umrandungslinien aus Raster</translation>
     </message>
     <message>
         <source>Fragmentation (Standard)</source>
-        <translation>Fragmentierung (Standard)</translation>
+        <translation type="obsolete">Fragmentierung (Standard)</translation>
     </message>
     <message>
         <source>Invert Data/No-Data</source>
-        <translation>Daten/Leerdaten invertieren</translation>
+        <translation type="obsolete">Daten/Leerdaten invertieren</translation>
     </message>
     <message>
         <source>Vegetation Index (Slope Based)</source>
-        <translation>Vegetationsindex (hangbasiert)</translation>
+        <translation type="obsolete">Vegetationsindex (hangbasiert)</translation>
     </message>
     <message>
         <source>Statistics for Grids</source>
-        <translation>Statistik für Gitter</translation>
+        <translation type="obsolete">Statistik für Gitter</translation>
     </message>
     <message>
         <source>Grids Sum</source>
-        <translation>Gittersumme</translation>
+        <translation type="obsolete">Gittersumme</translation>
     </message>
     <message>
         <source>Triangulation</source>
-        <translation>Triangulation</translation>
+        <translation type="obsolete">Triangulation</translation>
     </message>
     <message>
         <source>Grid Values to Points</source>
-        <translation>Gitterwerte in Punkte</translation>
+        <translation type="obsolete">Gitterwerte in Punkte</translation>
     </message>
     <message>
         <source>Add Coordinates to points</source>
-        <translation>Koordinaten zu Punkten hinzufügen</translation>
+        <translation type="obsolete">Koordinaten zu Punkten hinzufügen</translation>
     </message>
     <message>
         <source>Symmetrical Difference</source>
-        <translation>Symmetrische Differenz</translation>
+        <translation type="obsolete">Symmetrische Differenz</translation>
     </message>
     <message>
         <source>Flat Detection</source>
-        <translation>Flacherkennung</translation>
+        <translation type="obsolete">Flacherkennung</translation>
     </message>
     <message>
         <source>Aggregate</source>
-        <translation>Aggregieren</translation>
+        <translation type="obsolete">Aggregieren</translation>
     </message>
     <message>
         <source>Sky View Factor</source>
-        <translation>Himmelsichtfaktor</translation>
+        <translation type="obsolete">Himmelsichtfaktor</translation>
     </message>
     <message>
         <source>Grid Difference</source>
-        <translation>Gitterdifferenz</translation>
+        <translation type="obsolete">Gitterdifferenz</translation>
     </message>
     <message>
         <source>Vertical Distance to Channel Network</source>
-        <translation>Vertikale Distanz in Kanalnetzwerk</translation>
+        <translation type="obsolete">Vertikale Distanz in Kanalnetzwerk</translation>
     </message>
     <message>
         <source>Random Field</source>
-        <translation>Zufälliges Feld</translation>
+        <translation type="obsolete">Zufälliges Feld</translation>
     </message>
     <message>
         <source>Simple Filter</source>
-        <translation>Einfacher Filter</translation>
+        <translation type="obsolete">Einfacher Filter</translation>
     </message>
     <message>
         <source>Minimum Distance Analysis</source>
-        <translation>Minimumdistanzanalyse</translation>
+        <translation type="obsolete">Minimumdistanzanalyse</translation>
     </message>
     <message>
         <source>Shrink and Expand</source>
-        <translation>Verkleinern und Vergrößern</translation>
+        <translation type="obsolete">Verkleinern und Vergrößern</translation>
     </message>
     <message>
         <source>Cut Shapes Layer</source>
-        <translation>Shapelayer schneiden</translation>
+        <translation type="obsolete">Shapelayer schneiden</translation>
     </message>
     <message>
         <source>TPI Based Landform Classification</source>
-        <translation>TPI basierte Landformklassifikation</translation>
+        <translation type="obsolete">TPI basierte Landformklassifikation</translation>
     </message>
     <message>
         <source>Intersect</source>
-        <translation>Schnittmengen</translation>
+        <translation type="obsolete">Schnittmengen</translation>
     </message>
     <message>
         <source>Profile from points table|Profile from points</source>
-        <translation>Profile aus Punkttabelle|Profil aus Punkten</translation>
+        <translation type="obsolete">Profile aus Punkttabelle|Profil aus Punkten</translation>
     </message>
     <message>
         <source>Downslope Distance Gradient</source>
-        <translation>Abwärtsabstandsgrendiente</translation>
+        <translation type="obsolete">Abwärtsabstandsgrendiente</translation>
     </message>
     <message>
         <source>Channel Network</source>
-        <translation>Kanalnetzwerk</translation>
+        <translation type="obsolete">Kanalnetzwerk</translation>
     </message>
     <message>
         <source>Pattern Analysis</source>
-        <translation>Musteranalyse</translation>
+        <translation type="obsolete">Musteranalyse</translation>
     </message>
     <message>
         <source>Fit N Points to shape</source>
-        <translation>N-Punkte in Shape einpassen</translation>
+        <translation type="obsolete">N-Punkte in Shape einpassen</translation>
     </message>
     <message>
         <source>Remove Duplicate Points</source>
-        <translation>Doppelte Punkte entfernen</translation>
+        <translation type="obsolete">Doppelte Punkte entfernen</translation>
     </message>
     <message>
         <source>Reclassify Grid Values</source>
-        <translation>Gitterwert neuklassifizieren</translation>
+        <translation type="obsolete">Gitterwert neuklassifizieren</translation>
     </message>
     <message>
         <source>Geographically Weighted Regression (Points/Grid)</source>
-        <translation>Geografischgewichtete Regression (Punkt/Gitter)</translation>
+        <translation type="obsolete">Geografischgewichtete Regression (Punkt/Gitter)</translation>
     </message>
     <message>
         <source>Close One Cell Gaps</source>
-        <translation>Einzellenlücken schließen</translation>
+        <translation type="obsolete">Einzellenlücken schließen</translation>
     </message>
     <message>
         <source>Slope, Aspect, Curvature</source>
-        <translation>Neigung, Exposition, Wölbung</translation>
+        <translation type="obsolete">Neigung, Exposition, Wölbung</translation>
     </message>
     <message>
         <source>Function</source>
-        <translation>Funktion</translation>
+        <translation type="obsolete">Funktion</translation>
     </message>
     <message>
         <source>GWR for Multiple Predictors</source>
-        <translation>GWR für mehrere Vorhersagen</translation>
+        <translation type="obsolete">GWR für mehrere Vorhersagen</translation>
     </message>
     <message>
         <source>Wind effect|Wind Effect (Windward / Leeward Index)</source>
-        <translation>Windeffekt|Wind Effekt (Windwärts / Leeindex)</translation>
+        <translation type="obsolete">Windeffekt|Wind Effekt (Windwärts / Leeindex)</translation>
     </message>
     <message>
         <source>Close Gaps with Spline</source>
-        <translation>Lücken mit Spline schließen</translation>
+        <translation type="obsolete">Lücken mit Spline schließen</translation>
     </message>
     <message>
         <source>Fill Sinks (QM of ESP)</source>
-        <translation>Senken füllen (QM von ESP)</translation>
+        <translation type="obsolete">Senken füllen (QM von ESP)</translation>
     </message>
     <message>
         <source>Diversity of Categories</source>
-        <translation>Kategorienvielfalt</translation>
+        <translation type="obsolete">Kategorienvielfalt</translation>
     </message>
     <message>
         <source>Create Polygons Graticule|Create Graticule</source>
-        <translation>Gradnetz als Polygone erzeugen|Gradnetz erzeugen</translation>
+        <translation type="obsolete">Gradnetz als Polygone erzeugen|Gradnetz erzeugen</translation>
     </message>
     <message>
         <source>Change Time Format</source>
-        <translation>Zeitformat ändern</translation>
+        <translation type="obsolete">Zeitformat ändern</translation>
     </message>
     <message>
         <source>Confusion Matrix (Polygons / Grid)</source>
-        <translation>Wahrheitsmatrix (Polygone / Gitter)</translation>
+        <translation type="obsolete">Wahrheitsmatrix (Polygone / Gitter)</translation>
     </message>
     <message>
         <source>Successive Flow Routing</source>
-        <translation>Aufeinanderfolgende Flußlenkung</translation>
+        <translation type="obsolete">Aufeinanderfolgende Flußlenkung</translation>
     </message>
     <message>
         <source>Thin Plate Spline (Local)</source>
-        <translation>Thin Plate Spline (Lokal)</translation>
+        <translation type="obsolete">Thin Plate Spline (Lokal)</translation>
     </message>
     <message>
         <source>Multilevel B-Spline Interpolation for Categories</source>
-        <translation>Mehrstufen-B-Spline-Interpolation für Kategorien</translation>
+        <translation type="obsolete">Mehrstufen-B-Spline-Interpolation für Kategorien</translation>
     </message>
     <message>
         <source>Diffusive Hillslope Evolution (FTCS)</source>
-        <translation>Diffusive Hillslope Evolution (FTCS)</translation>
+        <translation type="obsolete">Diffusive Hillslope Evolution (FTCS)</translation>
     </message>
     <message>
         <source>Diffusive Hillslope Evolution (ADI)</source>
-        <translation>Diffusive Hillslope Evolution (ADI)</translation>
+        <translation type="obsolete">Diffusive Hillslope Evolution (ADI)</translation>
     </message>
     <message>
         <source>Create Lines Graticule|Create Graticule</source>
-        <translation>Gradnetz als Linien erzeugen|Gradnetz erzeugen</translation>
+        <translation type="obsolete">Gradnetz als Linien erzeugen|Gradnetz erzeugen</translation>
     </message>
     <message>
         <source>Flow Accumulation (QM of ESP)</source>
-        <translation>Flußdichte (QM von ESP)</translation>
+        <translation type="obsolete">Flußdichte (QM von ESP)</translation>
     </message>
     <message>
         <source>Grid Normalisation</source>
-        <translation>Gitternormalisierung</translation>
+        <translation type="obsolete">Gitternormalisierung</translation>
     </message>
     <message>
         <source>Thin Plate Spline</source>
-        <translation>Thin Plate Spline</translation>
+        <translation type="obsolete">Thin Plate Spline</translation>
     </message>
     <message>
         <source>Seed Generation</source>
-        <translation>Saaterzeugung</translation>
+        <translation type="obsolete">Saaterzeugung</translation>
     </message>
     <message>
         <source>Polygon-Line Intersection</source>
-        <translation>Polygon-Linien-Verschneidung</translation>
+        <translation type="obsolete">Polygon-Linien-Verschneidung</translation>
     </message>
     <message>
         <source>Running Average</source>
-        <translation>Beweglicher Mittelwert</translation>
+        <translation type="obsolete">Beweglicher Mittelwert</translation>
     </message>
     <message>
         <source>Cross-Classification and Tabulation</source>
-        <translation>Kreuzklassifizierung und Tabellierung</translation>
+        <translation type="obsolete">Kreuzklassifizierung und Tabellierung</translation>
     </message>
     <message>
         <source>Gradient Vector from Polar to Cartesian Coordinates</source>
-        <translation>Gradientenvektor aus Polar- zu kartesischen Koordinaten</translation>
+        <translation type="obsolete">Gradientenvektor aus Polar- zu kartesischen Koordinaten</translation>
     </message>
     <message>
         <source>Metric Conversions</source>
-        <translation>Metrische Umwandlungen</translation>
+        <translation type="obsolete">Metrische Umwandlungen</translation>
     </message>
     <message>
         <source>RGB Composite</source>
-        <translation>RGB-Composite</translation>
+        <translation type="obsolete">RGB-Composite</translation>
     </message>
     <message>
         <source>Edge Contamination</source>
-        <translation>Kantenverunreinigung</translation>
+        <translation type="obsolete">Kantenverunreinigung</translation>
     </message>
     <message>
         <source>Curvature Classification</source>
-        <translation>Wölbungsklassifizierung</translation>
+        <translation type="obsolete">Wölbungsklassifizierung</translation>
     </message>
     <message>
         <source>Filter Clumps</source>
-        <translation>Klumpen filtern</translation>
+        <translation type="obsolete">Klumpen filtern</translation>
     </message>
     <message>
         <source>Overland Flow - Kinematic Wave D8</source>
-        <translation>Überlandfluß - Kinematische Welle D8</translation>
+        <translation type="obsolete">Überlandfluß - Kinematische Welle D8</translation>
     </message>
     <message>
         <source>Profiles from Lines</source>
-        <translation>Profile aus Linien</translation>
+        <translation type="obsolete">Profile aus Linien</translation>
     </message>
     <message>
         <source>Distance Matrix</source>
-        <translation>Distanzmatrix</translation>
+        <translation type="obsolete">Distanzmatrix</translation>
     </message>
     <message>
         <source>Residual analysis|Residual Analysis (Grid)</source>
-        <translation>Restanalyse|Restanalyse (Raster)</translation>
+        <translation type="obsolete">Restanalyse|Restanalyse (Raster)</translation>
     </message>
     <message>
         <source>Zonal Grid Statistics</source>
-        <translation>Zonengitterstatistik</translation>
+        <translation type="obsolete">Zonengitterstatistik</translation>
     </message>
     <message>
         <source>Grid Division</source>
-        <translation>Gitterteilung</translation>
+        <translation type="obsolete">Gitterteilung</translation>
     </message>
     <message>
         <source>Lake Flood</source>
-        <translation>Seeflut</translation>
+        <translation type="obsolete">Seeflut</translation>
     </message>
     <message>
         <source>Add Polygon Attributes to Points</source>
-        <translation>Polygonattribute zu Punkten hinzufügen</translation>
+        <translation type="obsolete">Polygonattribute zu Punkten hinzufügen</translation>
     </message>
     <message>
         <source>Multilevel B-Spline Interpolation</source>
-        <translation>Mehrstufen-B-Spline-Interpolation</translation>
+        <translation type="obsolete">Mehrstufen-B-Spline-Interpolation</translation>
     </message>
     <message>
         <source>Cross Profiles</source>
-        <translation>Kreuzprofile</translation>
+        <translation type="obsolete">Kreuzprofile</translation>
     </message>
     <message>
         <source>Polar to Cartesian Coordinates</source>
-        <translation>Polar- zu kartesischen Koordinaten</translation>
+        <translation type="obsolete">Polar- zu kartesischen Koordinaten</translation>
     </message>
     <message>
         <source>Mosaick raster layers|Mosaicking</source>
-        <translation>Stitching von Rasterlayern|Stitching</translation>
+        <translation type="obsolete">Stitching von Rasterlayern|Stitching</translation>
     </message>
     <message>
         <source>Fire Risk Analysis</source>
-        <translation>Feuerriskikoanalyse</translation>
+        <translation type="obsolete">Feuerriskikoanalyse</translation>
     </message>
     <message>
         <source>Geographically Weighted Regression</source>
-        <translation>Geografischgewichtete Regression</translation>
+        <translation type="obsolete">Geografischgewichtete Regression</translation>
     </message>
     <message>
         <source>Separate points by direction</source>
-        <translation>Punkte nach Richtung aufteilen</translation>
+        <translation type="obsolete">Punkte nach Richtung aufteilen</translation>
     </message>
     <message>
         <source>Polygons to Edges and Nodes</source>
-        <translation>Polygone zu Kanten und Knoten</translation>
+        <translation type="obsolete">Polygone zu Kanten und Knoten</translation>
     </message>
     <message>
         <source>Morphological Filter</source>
-        <translation>Morphologischer Filter</translation>
+        <translation type="obsolete">Morphologischer Filter</translation>
     </message>
     <message>
         <source>Vector Ruggedness Measure (VRM)</source>
-        <translation>Vektorrauhigkeitsmaß (VRM)</translation>
+        <translation type="obsolete">Vektorrauhigkeitsmaß (VRM)</translation>
     </message>
     <message>
         <source>Fast Representativeness</source>
-        <translation>Schnelle Repräsentativität</translation>
+        <translation type="obsolete">Schnelle Repräsentativität</translation>
     </message>
 </context>
 <context>
@@ -70902,7 +70977,7 @@ Maximalzahl der Versuche überschritten.</translation>
     </message>
 </context>
 <context>
-    <name>SagaAlgorithm212</name>
+    <name>SagaAlgorithm</name>
     <message>
         <source>Unsupported file format</source>
         <translation>Nicht unterstütztes Dateiformat</translation>
@@ -70923,21 +70998,42 @@ Mehrkanallayer werden von SAGA nicht unterstützt</translation>
     </message>
 </context>
 <context>
+    <name>SagaAlgorithm212</name>
+    <message>
+        <source>Unsupported file format</source>
+        <translation type="obsolete">Nicht unterstütztes Dateiformat</translation>
+    </message>
+    <message>
+        <source>SAGA execution commands</source>
+        <translation type="obsolete">SAGA-Befehlsausführung</translation>
+    </message>
+    <message>
+        <source>Input layer %s has more than one band.
+Multiband layers are not supported by SAGA</source>
+        <translation type="obsolete">Eingabelayer %s hat mehr als einen Kanal.
+Mehrkanallayer werden von SAGA nicht unterstützt</translation>
+    </message>
+    <message>
+        <source>Input layers do not have the same grid extent.</source>
+        <translation type="obsolete">Eingabelayer haben nicht die gleichen Gitterabmessungen.</translation>
+    </message>
+</context>
+<context>
     <name>SagaAlgorithm213</name>
     <message>
         <source>Unsupported file format</source>
-        <translation>Nicht unterstütztes Dateiformat</translation>
+        <translation type="obsolete">Nicht unterstütztes Dateiformat</translation>
     </message>
     <message>
         <source>SAGA execution commands</source>
-        <translation>SAGA-Befehlsausführung</translation>
+        <translation type="obsolete">SAGA-Befehlsausführung</translation>
     </message>
 </context>
 <context>
     <name>SagaAlgorithmProvider</name>
     <message>
         <source>SAGA folder</source>
-        <translation>SAGA-Verzeichnis</translation>
+        <translation type="obsolete">SAGA-Verzeichnis</translation>
     </message>
     <message>
         <source>Enable SAGA Import/Export optimizations</source>
@@ -70961,18 +71057,32 @@ Mehrkanallayer werden von SAGA nicht unterstützt</translation>
     </message>
     <message>
         <source>Problem with SAGA installation: installed SAGA version (%s) is not supported</source>
-        <translation>Problem mit SAGA-Installation: Installierte SAGA-Version (%s) ist nicht unterstützt</translation>
+        <translation type="obsolete">Problem mit SAGA-Installation: Installierte SAGA-Version (%s) ist nicht unterstützt</translation>
     </message>
     <message>
         <source>Could not open SAGA algorithm: %s</source>
-        <translation>Konnte SAGA-Algorithmus nicht öffnen: %s</translation>
+        <translation type="obsolete">Konnte SAGA-Algorithmus nicht öffnen: %s</translation>
     </message>
     <message>
         <source>Could not open SAGA algorithm: %s
 %s</source>
-        <translation>Konnte SAGA-Algorithmus nicht öffnen: %s
+        <translation type="obsolete">Konnte SAGA-Algorithmus nicht öffnen: %s
 %s</translation>
     </message>
+    <message>
+        <source>Problem with SAGA installation: unsupported SAGA version found.</source>
+        <translation>Problem mit SAGA-Installation: Nicht unterstützte SAGA-Version gefunden.</translation>
+    </message>
+    <message>
+        <source>Could not open SAGA algorithm: {}</source>
+        <translation>Konnte SAGA-Algorithmus nicht öffnen: {}</translation>
+    </message>
+    <message>
+        <source>Could not open SAGA algorithm: {}
+{}</source>
+        <translation>Konnte SAGA-Algorithmus nicht öffnen: {}
+{}</translation>
+    </message>
 </context>
 <context>
     <name>SagaUtils</name>
@@ -83152,6 +83262,10 @@ Base Path (i.e. keep only filename from attribute)</source>
         <source>Merged</source>
         <translation>Zusammengeführt</translation>
     </message>
+    <message>
+        <source>Assign a specified nodata value to output bands</source>
+        <translation>Legt den Leerwert des Ausgabekanals fest</translation>
+    </message>
 </context>
 <context>
     <name>nearblack</name>
diff --git a/python/core/__init__.py b/python/core/__init__.py
index d0a6daf..9d78d57 100644
--- a/python/core/__init__.py
+++ b/python/core/__init__.py
@@ -78,7 +78,7 @@ def register_function(function, arg_count, group, usesgeometry=False, referenced
 
     helptemplate = string.Template("""<h3>$name function</h3><br>$doc""")
     name = kwargs.get('name', function.__name__)
-    helptext = function.__doc__ or ''
+    helptext = kwargs.get('help_text') or function.__doc__ or ''
     helptext = helptext.strip()
     expandargs = False
 
diff --git a/python/core/composer/qgscomposermodel.sip b/python/core/composer/qgscomposermodel.sip
index a70fe8a..89dc14f 100644
--- a/python/core/composer/qgscomposermodel.sip
+++ b/python/core/composer/qgscomposermodel.sip
@@ -283,7 +283,6 @@ class QgsComposerProxyModel: QSortFilterProxyModel
 
   protected:
     bool filterAcceptsRow( int source_row, const QModelIndex & source_parent ) const;
-    bool lessThan( const QModelIndex &left, const QModelIndex &right ) const;
 
 };
 
diff --git a/python/core/dxf/qgsdxfexport.sip b/python/core/dxf/qgsdxfexport.sip
index c43b075..c18c88d 100644
--- a/python/core/dxf/qgsdxfexport.sip
+++ b/python/core/dxf/qgsdxfexport.sip
@@ -130,6 +130,20 @@ class QgsDxfExport
     bool layerTitleAsName();
 
     /**
+     * Force 2d output (eg. to support linewidth in polylines)
+     * \param force2d flag
+     * \see force2d
+     */
+    void setForce2d( bool force2d );
+
+    /**
+     * Retrieve whether the output should be forced to 2d
+     * \returns flag
+     * \see setForce2d
+     */
+    bool force2d();
+
+    /**
      * Get DXF palette index of nearest entry for given color
      * @param color
      */
diff --git a/python/core/qgscoordinatetransform.sip b/python/core/qgscoordinatetransform.sip
index f9b7854..900967d 100644
--- a/python/core/qgscoordinatetransform.sip
+++ b/python/core/qgscoordinatetransform.sip
@@ -15,7 +15,9 @@
 class QgsCoordinateTransform : QObject
 {
 %TypeHeaderCode
+#if (SIP_VERSION >= 0x041300 && SIP_VERSION < 0x041303)
 extern PyObject *sipExportedExceptions__core[2];  // workaround: sipExportedExceptions__core is only defined in the first sip part
+#endif
 #include <qgscoordinatetransform.h>
 %End
 
diff --git a/python/core/symbology-ng/qgssymbollayerv2utils.sip b/python/core/symbology-ng/qgssymbollayerv2utils.sip
index 3f88173..3838626 100644
--- a/python/core/symbology-ng/qgssymbollayerv2utils.sip
+++ b/python/core/symbology-ng/qgssymbollayerv2utils.sip
@@ -57,6 +57,14 @@ class QgsSymbolLayerV2Utils
     static QString encodeSldUom( QgsSymbolV2::OutputUnit unit, double *scaleFactor );
     static QgsSymbolV2::OutputUnit decodeSldUom( const QString& str, double *scaleFactor );
 
+    /** Returns the size scaled in pixels according to the uom attribute.
+     * \param uom The uom attribute from SLD 1.1 version
+     * \param size The original size
+     * \returns the size in pixels
+     * \since QGIS 3.0
+     */
+    static double sizeInPixelsFromSldUom( const QString &uom, double size );
+
     static QString encodeScaleMethod( QgsSymbolV2::ScaleMethod scaleMethod );
     static QgsSymbolV2::ScaleMethod decodeScaleMethod( const QString& str );
 
diff --git a/python/plugins/processing/algs/grass7/description/v.in.dxf.txt b/python/plugins/processing/algs/grass7/description/v.in.dxf.txt
index 0e9641e..3b9e62a 100644
--- a/python/plugins/processing/algs/grass7/description/v.in.dxf.txt
+++ b/python/plugins/processing/algs/grass7/description/v.in.dxf.txt
@@ -1,8 +1,8 @@
 v.in.dxf
 Converts files in DXF format to GRASS vector map format.
 Vector (v.*)
-ParameterFile|input|Name of input DXF file|False
-ParameterString|layers|List of layers to import|
+ParameterFile|input|Name of input DXF file|False|False
+ParameterString|layers|List of layers to import||False|True
 ParameterBoolean|-e|Ignore the map extent of DXF file|True
 ParameterBoolean|-t|Do not create attribute tables|False
 ParameterBoolean|-f|Import polyface meshes as 3D wire frame|True
diff --git a/python/plugins/processing/algs/qgis/AddTableField.py b/python/plugins/processing/algs/qgis/AddTableField.py
index d722eef..15e9ddb 100644
--- a/python/plugins/processing/algs/qgis/AddTableField.py
+++ b/python/plugins/processing/algs/qgis/AddTableField.py
@@ -85,7 +85,7 @@ class AddTableField(GeoAlgorithm):
                                         layer.crs())
         outFeat = QgsFeature()
         features = vector.features(layer)
-        total = 100.0 / len(features)
+        total = 100.0 / len(features) if len(features) > 0 else 1
         for current, feat in enumerate(features):
             progress.setPercentage(int(current * total))
             geom = feat.geometry()
diff --git a/python/plugins/processing/algs/qgis/AutoincrementalField.py b/python/plugins/processing/algs/qgis/AutoincrementalField.py
index 8ec34a1..49f6393 100644
--- a/python/plugins/processing/algs/qgis/AutoincrementalField.py
+++ b/python/plugins/processing/algs/qgis/AutoincrementalField.py
@@ -55,7 +55,7 @@ class AutoincrementalField(GeoAlgorithm):
                                         vlayer.crs())
         outFeat = QgsFeature()
         features = vector.features(vlayer)
-        total = 100.0 / len(features)
+        total = 100.0 / len(features) if len(features) > 0 else 1
         for current, feat in enumerate(features):
             progress.setPercentage(int(current * total))
             geom = feat.geometry()
diff --git a/python/plugins/processing/algs/qgis/BasicStatisticsNumbers.py b/python/plugins/processing/algs/qgis/BasicStatisticsNumbers.py
index c20a778..15ea32a 100644
--- a/python/plugins/processing/algs/qgis/BasicStatisticsNumbers.py
+++ b/python/plugins/processing/algs/qgis/BasicStatisticsNumbers.py
@@ -124,7 +124,7 @@ class BasicStatisticsNumbers(GeoAlgorithm):
 
         features = vector.features(layer)
         count = len(features)
-        total = 100.0 / float(count)
+        total = 100.0 / count if count > 0 else 1
         for current, ft in enumerate(features):
             value = ft[fieldName]
             if value or value == 0:
diff --git a/python/plugins/processing/algs/qgis/BasicStatisticsStrings.py b/python/plugins/processing/algs/qgis/BasicStatisticsStrings.py
index 07cb31f..a205925 100644
--- a/python/plugins/processing/algs/qgis/BasicStatisticsStrings.py
+++ b/python/plugins/processing/algs/qgis/BasicStatisticsStrings.py
@@ -100,7 +100,7 @@ class BasicStatisticsStrings(GeoAlgorithm):
 
         features = vector.features(layer)
         count = len(features)
-        total = 100.0 / count
+        total = 100.0 / count if count > 0 else 1
         for current, ft in enumerate(features):
             value = ft[fieldName]
             if value:
diff --git a/python/plugins/processing/algs/qgis/Boundary.py b/python/plugins/processing/algs/qgis/Boundary.py
index 079cacd..f66f88f 100644
--- a/python/plugins/processing/algs/qgis/Boundary.py
+++ b/python/plugins/processing/algs/qgis/Boundary.py
@@ -73,7 +73,7 @@ class Boundary(GeoAlgorithm):
                 layer.crs())
 
         features = vector.features(layer)
-        total = 100.0 / len(features)
+        total = 100.0 / len(features) if len(features) > 0 else 1
 
         for current, input_feature in enumerate(features):
             output_feature = input_feature
diff --git a/python/plugins/processing/algs/qgis/BoundingBox.py b/python/plugins/processing/algs/qgis/BoundingBox.py
index e5a0ce1..e5f18ae 100644
--- a/python/plugins/processing/algs/qgis/BoundingBox.py
+++ b/python/plugins/processing/algs/qgis/BoundingBox.py
@@ -67,7 +67,7 @@ class BoundingBox(GeoAlgorithm):
                 layer.crs())
 
         features = vector.features(layer)
-        total = 100.0 / len(features)
+        total = 100.0 / len(features) if len(features) > 0 else 1
 
         for current, input_feature in enumerate(features):
             output_feature = input_feature
diff --git a/python/plugins/processing/algs/qgis/Buffer.py b/python/plugins/processing/algs/qgis/Buffer.py
index 433ae2f..28074b8 100644
--- a/python/plugins/processing/algs/qgis/Buffer.py
+++ b/python/plugins/processing/algs/qgis/Buffer.py
@@ -44,7 +44,7 @@ def buffering(progress, writer, distance, field, useField, layer, dissolve,
 
     current = 0
     features = vector.features(layer)
-    total = 100.0 / float(len(features))
+    total = 100.0 / len(features) if len(features) > 0 else 1
 
     # With dissolve
     if dissolve:
diff --git a/python/plugins/processing/algs/qgis/Centroids.py b/python/plugins/processing/algs/qgis/Centroids.py
index 505f39c..235e958 100644
--- a/python/plugins/processing/algs/qgis/Centroids.py
+++ b/python/plugins/processing/algs/qgis/Centroids.py
@@ -70,7 +70,7 @@ class Centroids(GeoAlgorithm):
         outFeat = QgsFeature()
 
         features = vector.features(layer)
-        total = 100.0 / len(features)
+        total = 100.0 / len(features) if len(features) > 0 else 1
         for current, feat in enumerate(features):
             inGeom = feat.geometry()
             attrs = feat.attributes()
diff --git a/python/plugins/processing/algs/qgis/CheckValidity.py b/python/plugins/processing/algs/qgis/CheckValidity.py
index 1ac8061..33f7adf 100644
--- a/python/plugins/processing/algs/qgis/CheckValidity.py
+++ b/python/plugins/processing/algs/qgis/CheckValidity.py
@@ -132,7 +132,7 @@ class CheckValidity(GeoAlgorithm):
         error_count = 0
 
         features = vector.features(layer)
-        total = 100.0 / len(features)
+        total = 100.0 / len(features) if len(features) > 0 else 1
         for current, inFeat in enumerate(features):
             geom = QgsGeometry(inFeat.geometry())
             attrs = inFeat.attributes()
diff --git a/python/plugins/processing/algs/qgis/Clip.py b/python/plugins/processing/algs/qgis/Clip.py
index b9f13f0..e5f8f99 100644
--- a/python/plugins/processing/algs/qgis/Clip.py
+++ b/python/plugins/processing/algs/qgis/Clip.py
@@ -96,7 +96,7 @@ class Clip(GeoAlgorithm):
                 continue
 
             if single_clip_feature:
-                total = 100.0 / len(input_features)
+                total = 100.0 / len(features) if len(features) > 0 else 1
             else:
                 total = 0
 
diff --git a/python/plugins/processing/algs/qgis/ConcaveHull.py b/python/plugins/processing/algs/qgis/ConcaveHull.py
index 73be49f..8ed1789 100644
--- a/python/plugins/processing/algs/qgis/ConcaveHull.py
+++ b/python/plugins/processing/algs/qgis/ConcaveHull.py
@@ -27,6 +27,7 @@ __revision__ = '$Format:%H$'
 
 from qgis.core import QGis, QgsFeatureRequest, QgsFeature, QgsGeometry
 from processing.core.GeoAlgorithm import GeoAlgorithm
+from processing.core.SilentProgress import SilentProgress
 from processing.core.parameters import ParameterVector
 from processing.core.parameters import ParameterNumber
 from processing.core.parameters import ParameterBoolean
@@ -63,16 +64,20 @@ class ConcaveHull(GeoAlgorithm):
         alpha = self.getParameterValue(self.ALPHA)
         holes = self.getParameterValue(self.HOLES)
         no_multigeom = self.getParameterValue(self.NO_MULTIGEOMETRY)
+        runalg_kwargs = {}
+        if isinstance(progress, SilentProgress):
+            runalg_kwargs['progress'] = progress
 
         # Delaunay triangulation from input point layer
         progress.setText(self.tr('Creating Delaunay triangles...'))
-        delone_triangles = processing.runalg("qgis:delaunaytriangulation", layer, None)['OUTPUT']
+        delone_triangles = processing.runalg("qgis:delaunaytriangulation",
+                                             layer, None, **runalg_kwargs)['OUTPUT']
         delaunay_layer = processing.getObject(delone_triangles)
 
         # Get max edge length from Delaunay triangles
         progress.setText(self.tr('Computing edges max length...'))
         features = delaunay_layer.getFeatures()
-        counter = 50. / delaunay_layer.featureCount()
+        counter = 50. / delaunay_layer.featureCount() if delaunay_layer.featureCount() > 0 else 1
         lengths = []
         edges = {}
         for feat in features:
@@ -85,7 +90,7 @@ class ConcaveHull(GeoAlgorithm):
 
         # Get features with longest edge longer than alpha*max_length
         progress.setText(self.tr('Removing features...'))
-        counter = 50. / len(edges)
+        counter = 50. / len(edges) if len(edges) > 0 else 1
         i = 0
         ids = []
         for id, max_len in edges.iteritems():
@@ -103,7 +108,7 @@ class ConcaveHull(GeoAlgorithm):
         # Dissolve all Delaunay triangles
         progress.setText(self.tr('Dissolving Delaunay triangles...'))
         dissolved = processing.runalg("qgis:dissolve", delaunay_layer,
-                                      True, None, None)['OUTPUT']
+                                      True, None, None, **runalg_kwargs)['OUTPUT']
         dissolved_layer = processing.getObject(dissolved)
 
         # Save result
diff --git a/python/plugins/processing/algs/qgis/ConvexHull.py b/python/plugins/processing/algs/qgis/ConvexHull.py
index 9627f2d..43f7f0f 100644
--- a/python/plugins/processing/algs/qgis/ConvexHull.py
+++ b/python/plugins/processing/algs/qgis/ConvexHull.py
@@ -109,7 +109,7 @@ class ConvexHull(GeoAlgorithm):
         if useField:
             unique = layer.uniqueValues(index)
             current = 0
-            total = 100.0 / (len(features) * len(unique))
+            total = 100.0 / (len(features) * len(unique)) if len(features) * len(unique) > 0 else 1
             for i in unique:
                 first = True
                 hull = []
@@ -141,7 +141,7 @@ class ConvexHull(GeoAlgorithm):
                 fid += 1
         else:
             hull = []
-            total = 100.0 / layer.featureCount()
+            total = 100.0 / layer.featureCount() if layer.featureCount() > 0 else 1
             features = vector.features(layer)
             for current, f in enumerate(features):
                 inGeom = QgsGeometry(f.geometry())
diff --git a/python/plugins/processing/algs/qgis/Datasources2Vrt.py b/python/plugins/processing/algs/qgis/Datasources2Vrt.py
index 177991e..811dc46 100644
--- a/python/plugins/processing/algs/qgis/Datasources2Vrt.py
+++ b/python/plugins/processing/algs/qgis/Datasources2Vrt.py
@@ -93,7 +93,7 @@ class Datasources2Vrt(GeoAlgorithm):
         if union:
             vrt += '<OGRVRTUnionLayer name="UnionedLayer">'
 
-        total = 100.0 / len(dataSources)
+        total = 100.0 / len(dataSources) if len(dataSources) > 0 else 1
         for current, inFile in enumerate(dataSources):
             progress.setPercentage(int(current * total))
 
diff --git a/python/plugins/processing/algs/qgis/Delaunay.py b/python/plugins/processing/algs/qgis/Delaunay.py
index 63acd97..d4d3c6b 100644
--- a/python/plugins/processing/algs/qgis/Delaunay.py
+++ b/python/plugins/processing/algs/qgis/Delaunay.py
@@ -76,7 +76,7 @@ class Delaunay(GeoAlgorithm):
         ptNdx = -1
         c = voronoi.Context()
         features = vector.features(layer)
-        total = 100.0 / len(features)
+        total = 100.0 / len(features) if len(features) > 0 else 1
         for current, inFeat in enumerate(features):
             geom = QgsGeometry(inFeat.geometry())
             point = geom.asPoint()
@@ -100,7 +100,7 @@ class Delaunay(GeoAlgorithm):
         triangles = c.triangles
         feat = QgsFeature()
 
-        total = 100.0 / len(triangles)
+        total = 100.0 / len(triangles) if len(triangles) > 0 else 1
         for current, triangle in enumerate(triangles):
             indicies = list(triangle)
             indicies.append(indicies[0])
diff --git a/python/plugins/processing/algs/qgis/DeleteColumn.py b/python/plugins/processing/algs/qgis/DeleteColumn.py
index 96aea8b..7d72b6c 100644
--- a/python/plugins/processing/algs/qgis/DeleteColumn.py
+++ b/python/plugins/processing/algs/qgis/DeleteColumn.py
@@ -61,7 +61,7 @@ class DeleteColumn(GeoAlgorithm):
                                                                      layer.wkbType(), layer.crs())
 
         features = vector.features(layer)
-        total = 100.0 / len(features)
+        total = 100.0 / len(features) if len(features) > 0 else 1
 
         feat = QgsFeature()
         for current, f in enumerate(features):
diff --git a/python/plugins/processing/algs/qgis/DeleteDuplicateGeometries.py b/python/plugins/processing/algs/qgis/DeleteDuplicateGeometries.py
index 6731e42..ef044be 100644
--- a/python/plugins/processing/algs/qgis/DeleteDuplicateGeometries.py
+++ b/python/plugins/processing/algs/qgis/DeleteDuplicateGeometries.py
@@ -56,7 +56,7 @@ class DeleteDuplicateGeometries(GeoAlgorithm):
 
         features = vector.features(layer)
 
-        total = 100.0 / len(features)
+        total = 100.0 / len(features) if len(features) > 0 else 1
         geoms = dict()
         for current, f in enumerate(features):
             geoms[f.id()] = QgsGeometry(f.geometry())
@@ -71,7 +71,7 @@ class DeleteDuplicateGeometries(GeoAlgorithm):
                 if g.isGeosEqual(cleaned[j]):
                     del cleaned[j]
 
-        total = 100.0 / len(cleaned)
+        total = 100.0 / len(cleaned) if len(cleaned) > 0 else 1
         request = QgsFeatureRequest().setFilterFids(cleaned.keys())
         for current, f in enumerate(layer.getFeatures(request)):
             writer.addFeature(f)
diff --git a/python/plugins/processing/algs/qgis/DeleteHoles.py b/python/plugins/processing/algs/qgis/DeleteHoles.py
index b32b8c5..c64a06b 100644
--- a/python/plugins/processing/algs/qgis/DeleteHoles.py
+++ b/python/plugins/processing/algs/qgis/DeleteHoles.py
@@ -54,7 +54,7 @@ class DeleteHoles(GeoAlgorithm):
             layer.crs())
 
         features = vector.features(layer)
-        total = 100.0 / len(features)
+        total = 100.0 / len(features) if len(features) > 0 else 1
 
         feat = QgsFeature()
         for current, f in enumerate(features):
diff --git a/python/plugins/processing/algs/qgis/DensifyGeometries.py b/python/plugins/processing/algs/qgis/DensifyGeometries.py
index f19ade8..79d66ff 100644
--- a/python/plugins/processing/algs/qgis/DensifyGeometries.py
+++ b/python/plugins/processing/algs/qgis/DensifyGeometries.py
@@ -69,7 +69,7 @@ class DensifyGeometries(GeoAlgorithm):
                                          layer.wkbType(), layer.crs())
 
         features = vector.features(layer)
-        total = 100.0 / len(features)
+        total = 100.0 / len(features) if len(features) > 0 else 1
         for current, f in enumerate(features):
             featGeometry = QgsGeometry(f.geometry())
             attrs = f.attributes()
diff --git a/python/plugins/processing/algs/qgis/DensifyGeometriesInterval.py b/python/plugins/processing/algs/qgis/DensifyGeometriesInterval.py
index 99e8b6c..b4c6697 100644
--- a/python/plugins/processing/algs/qgis/DensifyGeometriesInterval.py
+++ b/python/plugins/processing/algs/qgis/DensifyGeometriesInterval.py
@@ -66,7 +66,7 @@ class DensifyGeometriesInterval(GeoAlgorithm):
                                          layer.wkbType(), layer.crs())
 
         features = vector.features(layer)
-        total = 100.0 / len(features)
+        total = 100.0 / len(features) if len(features) > 0 else 1
         for current, f in enumerate(features):
             featGeometry = QgsGeometry(f.geometry())
             attrs = f.attributes()
diff --git a/python/plugins/processing/algs/qgis/Difference.py b/python/plugins/processing/algs/qgis/Difference.py
index c36af09..39f45eb 100644
--- a/python/plugins/processing/algs/qgis/Difference.py
+++ b/python/plugins/processing/algs/qgis/Difference.py
@@ -77,7 +77,7 @@ class Difference(GeoAlgorithm):
         outFeat = QgsFeature()
         index = vector.spatialindex(layerB)
         selectionA = vector.features(layerA)
-        total = 100.0 / len(selectionA)
+        total = 100.0 / len(selectionA) if len(selectionA) > 0 else 1
         for current, inFeatA in enumerate(selectionA):
             add = True
             geom = QgsGeometry(inFeatA.geometry())
diff --git a/python/plugins/processing/algs/qgis/Dissolve.py b/python/plugins/processing/algs/qgis/Dissolve.py
index 449244a..91b8664 100644
--- a/python/plugins/processing/algs/qgis/Dissolve.py
+++ b/python/plugins/processing/algs/qgis/Dissolve.py
@@ -78,7 +78,7 @@ class Dissolve(GeoAlgorithm):
                                              vlayerA.crs())
         outFeat = QgsFeature()
         features = vector.features(vlayerA)
-        total = 100.0 / len(features)
+        total = 100.0 / len(features) if len(features) > 0 else 1
 
         if not useField:
             first = True
@@ -154,7 +154,7 @@ class Dissolve(GeoAlgorithm):
 
                 geometry_dict[index_attrs].append(tmpInGeom)
 
-            nFeat = len(attribute_dict)
+            nFeat = len(attribute_dict) if len(attribute_dict) > 0 else 1
 
             nElement = 0
             for key, value in geometry_dict.items():
diff --git a/python/plugins/processing/algs/qgis/EquivalentNumField.py b/python/plugins/processing/algs/qgis/EquivalentNumField.py
index 0468b34..f43a1cf 100644
--- a/python/plugins/processing/algs/qgis/EquivalentNumField.py
+++ b/python/plugins/processing/algs/qgis/EquivalentNumField.py
@@ -63,7 +63,7 @@ class EquivalentNumField(GeoAlgorithm):
         classes = {}
 
         features = vector.features(vlayer)
-        total = 100.0 / len(features)
+        total = 100.0 / len(features) if len(features) > 0 else 1
         for current, feature in enumerate(features):
             progress.setPercentage(int(current * total))
             inGeom = feature.geometry()
diff --git a/python/plugins/processing/algs/qgis/ExecuteSQL.py b/python/plugins/processing/algs/qgis/ExecuteSQL.py
index d7cb68b..7ac7fc5 100644
--- a/python/plugins/processing/algs/qgis/ExecuteSQL.py
+++ b/python/plugins/processing/algs/qgis/ExecuteSQL.py
@@ -137,7 +137,7 @@ class ExecuteSQL(GeoAlgorithm):
             vLayer.crs())
 
         features = vector.features(vLayer)
-        total = 100.0 / len(features)
+        total = 100.0 / len(features) if len(features) > 0 else 1
         outFeat = QgsFeature()
         for current, inFeat in enumerate(features):
             outFeat.setAttributes(inFeat.attributes())
diff --git a/python/plugins/processing/algs/qgis/Explode.py b/python/plugins/processing/algs/qgis/Explode.py
index daa35ba..50f2a20 100644
--- a/python/plugins/processing/algs/qgis/Explode.py
+++ b/python/plugins/processing/algs/qgis/Explode.py
@@ -53,7 +53,7 @@ class Explode(GeoAlgorithm):
                                         vlayer.crs())
         outFeat = QgsFeature()
         features = vector.features(vlayer)
-        total = 100.0 / len(features)
+        total = 100.0 / len(features) if len(features) > 0 else 1
         for current, feature in enumerate(features):
             progress.setPercentage(int(current * total))
             inGeom = feature.geometry()
diff --git a/python/plugins/processing/algs/qgis/ExportGeometryInfo.py b/python/plugins/processing/algs/qgis/ExportGeometryInfo.py
index ddd21c6..c3c7d4e 100644
--- a/python/plugins/processing/algs/qgis/ExportGeometryInfo.py
+++ b/python/plugins/processing/algs/qgis/ExportGeometryInfo.py
@@ -116,7 +116,7 @@ class ExportGeometryInfo(GeoAlgorithm):
         outFeat.setFields(fields)
 
         features = vector.features(layer)
-        total = 100.0 / len(features)
+        total = 100.0 / len(features) if len(features) > 0 else 1
         for current, f in enumerate(features):
             inGeom = f.geometry()
 
diff --git a/python/plugins/processing/algs/qgis/ExtentFromLayer.py b/python/plugins/processing/algs/qgis/ExtentFromLayer.py
index 1835213..de95fb2 100644
--- a/python/plugins/processing/algs/qgis/ExtentFromLayer.py
+++ b/python/plugins/processing/algs/qgis/ExtentFromLayer.py
@@ -125,7 +125,7 @@ class ExtentFromLayer(GeoAlgorithm):
 
     def featureExtent(self, layer, writer, progress):
         features = vector.features(layer)
-        total = 100.0 / len(features)
+        total = 100.0 / len(features) if len(features) > 0 else 1
         feat = QgsFeature()
         for current, f in enumerate(features):
             rect = f.geometry().boundingBox()
diff --git a/python/plugins/processing/algs/qgis/ExtractByExpression.py b/python/plugins/processing/algs/qgis/ExtractByExpression.py
new file mode 100644
index 0000000..2d6a64a
--- /dev/null
+++ b/python/plugins/processing/algs/qgis/ExtractByExpression.py
@@ -0,0 +1,78 @@
+# -*- coding: utf-8 -*-
+
+"""
+***************************************************************************
+    ExtractByExpression.py
+    ---------------------
+    Date                 : September 2017
+    Copyright            : (C) 2017 by Alexander Bruy
+    Email                : alexander dot bruy at gmail 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.                                   *
+*                                                                         *
+***************************************************************************
+"""
+
+__author__ = 'Alexander Bruy'
+__date__ = 'September 2017'
+__copyright__ = '(C) 2017, Alexander Bruy'
+
+# This will get replaced with a git SHA1 when you do a git archive
+
+__revision__ = '$Format:%H$'
+
+from qgis.core import QgsExpression, QgsExpressionContext, QgsExpressionContextUtils, QgsFeatureRequest
+from processing.core.GeoAlgorithm import GeoAlgorithm
+from processing.core.GeoAlgorithmExecutionException import GeoAlgorithmExecutionException
+from processing.core.parameters import ParameterVector
+from processing.core.parameters import ParameterString
+from processing.core.outputs import OutputVector
+from processing.tools import dataobjects
+
+
+class ExtractByExpression(GeoAlgorithm):
+
+    INPUT = 'INPUT'
+    EXPRESSION = 'EXPRESSION'
+    OUTPUT = 'OUTPUT'
+
+    def defineCharacteristics(self):
+        self.name, self.i18n_name = self.trAlgorithm('Extract by expression')
+        self.group, self.i18n_group = self.trAlgorithm('Vector selection tools')
+
+        self.addParameter(ParameterVector(self.INPUT,
+                                          self.tr('Input Layer'), [ParameterVector.VECTOR_TYPE_ANY]))
+        self.addParameter(ParameterString(self.EXPRESSION,
+                                          self.tr("Expression")))
+        self.addOutput(OutputVector(self.OUTPUT, self.tr('Extracted (expression)')))
+
+    def processAlgorithm(self, progress):
+        layer = layer = dataobjects.getObjectFromUri(self.getParameterValue(self.INPUT))
+
+        expression = self.getParameterValue(self.EXPRESSION)
+        qExp = QgsExpression(expression)
+        if qExp.hasParserError():
+            raise GeoAlgorithmExecutionException(qExp.parserErrorString())
+
+        writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(
+            layer.fields(), layer.wkbType(), layer.crs())
+
+        context = QgsExpressionContext()
+        context.appendScope(QgsExpressionContextUtils.globalScope())
+        context.appendScope(QgsExpressionContextUtils.projectScope())
+        context.appendScope(QgsExpressionContextUtils.layerScope(layer))
+
+        count = layer.featureCount()
+        step = 100.0 / count if count else 1
+
+        request = QgsFeatureRequest(qExp, context)
+
+        for current, f in enumerate(layer.getFeatures(request)):
+            writer.addFeature(f)
+            progress.setPercentage(int(current * step))
+
+        del writer
diff --git a/python/plugins/processing/algs/qgis/ExtractByLocation.py b/python/plugins/processing/algs/qgis/ExtractByLocation.py
index 5df9981..c85ebdb 100644
--- a/python/plugins/processing/algs/qgis/ExtractByLocation.py
+++ b/python/plugins/processing/algs/qgis/ExtractByLocation.py
@@ -80,7 +80,7 @@ class ExtractByLocation(GeoAlgorithm):
 
         selectedSet = []
         features = vector.features(selectLayer)
-        total = 100.0 / len(features)
+        total = 100.0 / len(features) if len(features) > 0 else 1
         for current, f in enumerate(features):
             geom = vector.snapToPrecision(f.geometry(), precision)
             bbox = vector.bufferedBoundingBox(geom.boundingBox(), 0.51 * precision)
diff --git a/python/plugins/processing/algs/qgis/ExtractNodes.py b/python/plugins/processing/algs/qgis/ExtractNodes.py
index 73d92c9..3c8fcd6 100644
--- a/python/plugins/processing/algs/qgis/ExtractNodes.py
+++ b/python/plugins/processing/algs/qgis/ExtractNodes.py
@@ -69,7 +69,7 @@ class ExtractNodes(GeoAlgorithm):
         outGeom = QgsGeometry()
 
         features = vector.features(layer)
-        total = 100.0 / len(features)
+        total = 100.0 / len(features) if len(features) > 0 else 1
         for current, f in enumerate(features):
             inGeom = f.geometry()
             attrs = f.attributes()
diff --git a/python/plugins/processing/algs/qgis/FieldPyculator.py b/python/plugins/processing/algs/qgis/FieldPyculator.py
index 0f517fc..ba1ad0c 100644
--- a/python/plugins/processing/algs/qgis/FieldPyculator.py
+++ b/python/plugins/processing/algs/qgis/FieldPyculator.py
@@ -130,7 +130,7 @@ class FieldsPyculator(GeoAlgorithm):
 
         # Run
         features = vector.features(layer)
-        total = 100.0 / len(features)
+        total = 100.0 / len(features) if len(features) > 0 else 1
         for current, feat in enumerate(features):
             progress.setPercentage(int(current * total))
             attrs = feat.attributes()
diff --git a/python/plugins/processing/algs/qgis/FieldsCalculator.py b/python/plugins/processing/algs/qgis/FieldsCalculator.py
index f769566..ae09952 100644
--- a/python/plugins/processing/algs/qgis/FieldsCalculator.py
+++ b/python/plugins/processing/algs/qgis/FieldsCalculator.py
@@ -130,7 +130,7 @@ class FieldsCalculator(GeoAlgorithm):
         calculationSuccess = True
 
         features = vector.features(layer)
-        total = 100.0 / len(features)
+        total = 100.0 / len(features) if len(features) > 0 else 1
 
         rownum = 1
         for current, f in enumerate(features):
diff --git a/python/plugins/processing/algs/qgis/FieldsMapper.py b/python/plugins/processing/algs/qgis/FieldsMapper.py
index dfb7d39..bfd7e5d 100644
--- a/python/plugins/processing/algs/qgis/FieldsMapper.py
+++ b/python/plugins/processing/algs/qgis/FieldsMapper.py
@@ -118,7 +118,7 @@ class FieldsMapper(GeoAlgorithm):
         outFeat = QgsFeature()
         features = vector.features(layer)
         if len(features):
-            total = 100.0 / len(features)
+            total = 100.0 / len(features) if len(features) > 0 else 1
             for current, inFeat in enumerate(features):
                 rownum = current + 1
 
diff --git a/python/plugins/processing/algs/qgis/GeometryConvert.py b/python/plugins/processing/algs/qgis/GeometryConvert.py
index 9e977ca..09d78fd 100644
--- a/python/plugins/processing/algs/qgis/GeometryConvert.py
+++ b/python/plugins/processing/algs/qgis/GeometryConvert.py
@@ -81,7 +81,7 @@ class GeometryConvert(GeoAlgorithm):
             layer.pendingFields(), newType, layer.crs())
 
         features = vector.features(layer)
-        total = 100.0 / len(features)
+        total = 100.0 / len(features) if len(features) > 0 else 1
 
         for current, f in enumerate(features):
             geom = f.geometry()
diff --git a/python/plugins/processing/algs/qgis/Gridify.py b/python/plugins/processing/algs/qgis/Gridify.py
index 1f94db8..3a4291f 100644
--- a/python/plugins/processing/algs/qgis/Gridify.py
+++ b/python/plugins/processing/algs/qgis/Gridify.py
@@ -68,7 +68,7 @@ class Gridify(GeoAlgorithm):
             layer.pendingFields(), layer.wkbType(), layer.crs())
 
         features = vector.features(layer)
-        total = 100.0 / len(features)
+        total = 100.0 / len(features) if len(features) > 0 else 1
 
         for current, f in enumerate(features):
             geom = f.geometry()
diff --git a/python/plugins/processing/algs/qgis/HubDistance.py b/python/plugins/processing/algs/qgis/HubDistance.py
index d590c5d..c503fec 100644
--- a/python/plugins/processing/algs/qgis/HubDistance.py
+++ b/python/plugins/processing/algs/qgis/HubDistance.py
@@ -117,7 +117,7 @@ class HubDistance(GeoAlgorithm):
 
         # Scan source points, find nearest hub, and write to output file
         features = vector.features(layerPoints)
-        total = 100.0 / len(features)
+        total = 100.0 / len(features) if len(features) > 0 else 1
         for current, f in enumerate(features):
             src = f.geometry().boundingBox().center()
 
diff --git a/python/plugins/processing/algs/qgis/HubLines.py b/python/plugins/processing/algs/qgis/HubLines.py
index f552040..436ff15 100644
--- a/python/plugins/processing/algs/qgis/HubLines.py
+++ b/python/plugins/processing/algs/qgis/HubLines.py
@@ -75,7 +75,7 @@ class HubLines(GeoAlgorithm):
 
         spokes = vector.features(layerSpoke)
         hubs = vector.features(layerHub)
-        total = 100.0 / len(spokes)
+        total = 100.0 / len(spokes) if len(spokes) > 0 else 1
 
         for current, spokepoint in enumerate(spokes):
             p = spokepoint.geometry().boundingBox().center()
diff --git a/python/plugins/processing/algs/qgis/HypsometricCurves.py b/python/plugins/processing/algs/qgis/HypsometricCurves.py
index d7de346..c0f21df 100644
--- a/python/plugins/processing/algs/qgis/HypsometricCurves.py
+++ b/python/plugins/processing/algs/qgis/HypsometricCurves.py
@@ -100,7 +100,7 @@ class HypsometricCurves(GeoAlgorithm):
         memRasterDriver = gdal.GetDriverByName('MEM')
 
         features = vector.features(layer)
-        total = 100.0 / len(features)
+        total = 100.0 / len(features) if len(features) > 0 else 1
 
         for current, f in enumerate(features):
             geom = f.geometry()
diff --git a/python/plugins/processing/algs/qgis/Intersection.py b/python/plugins/processing/algs/qgis/Intersection.py
index cdff563..a30b60e 100644
--- a/python/plugins/processing/algs/qgis/Intersection.py
+++ b/python/plugins/processing/algs/qgis/Intersection.py
@@ -86,7 +86,7 @@ class Intersection(GeoAlgorithm):
         outFeat = QgsFeature()
         index = vector.spatialindex(vlayerB)
         selectionA = vector.features(vlayerA)
-        total = 100.0 / len(selectionA)
+        total = 100.0 / len(selectionA) if len(selectionA) > 0 else 1
         for current, inFeatA in enumerate(selectionA):
             progress.setPercentage(int(current * total))
             geom = inFeatA.geometry()
diff --git a/python/plugins/processing/algs/qgis/JoinAttributes.py b/python/plugins/processing/algs/qgis/JoinAttributes.py
index e1422d7..f8de077 100644
--- a/python/plugins/processing/algs/qgis/JoinAttributes.py
+++ b/python/plugins/processing/algs/qgis/JoinAttributes.py
@@ -81,7 +81,7 @@ class JoinAttributes(GeoAlgorithm):
         # Cache attributes of Layer 2
         cache = {}
         features = vector.features(layer2)
-        total = 100.0 / len(features)
+        total = 100.0 / len(features) if len(features) > 0 else 1
         for current, feat in enumerate(features):
             attrs = feat.attributes()
             joinValue2 = unicode(attrs[joinField2Index])
@@ -92,7 +92,7 @@ class JoinAttributes(GeoAlgorithm):
         # Create output vector layer with additional attribute
         outFeat = QgsFeature()
         features = vector.features(layer)
-        total = 100.0 / len(features)
+        total = 100.0 / len(features) if len(features) > 0 else 1
         for current, feat in enumerate(features):
             outFeat.setGeometry(feat.geometry())
             attrs = feat.attributes()
diff --git a/python/plugins/processing/algs/qgis/LinesIntersection.py b/python/plugins/processing/algs/qgis/LinesIntersection.py
index 6ff11ed..b9c9b94 100644
--- a/python/plugins/processing/algs/qgis/LinesIntersection.py
+++ b/python/plugins/processing/algs/qgis/LinesIntersection.py
@@ -92,7 +92,7 @@ class LinesIntersection(GeoAlgorithm):
 
         outFeat = QgsFeature()
         features = vector.features(layerA)
-        total = 100.0 / len(features)
+        total = 100.0 / len(features) if len(features) > 0 else 1
         hasIntersections = False
 
         for current, inFeatA in enumerate(features):
diff --git a/python/plugins/processing/algs/qgis/LinesToPolygons.py b/python/plugins/processing/algs/qgis/LinesToPolygons.py
index 065935d..cb30ad9 100644
--- a/python/plugins/processing/algs/qgis/LinesToPolygons.py
+++ b/python/plugins/processing/algs/qgis/LinesToPolygons.py
@@ -64,7 +64,7 @@ class LinesToPolygons(GeoAlgorithm):
 
         outFeat = QgsFeature()
         features = vector.features(layer)
-        total = 100.0 / len(features)
+        total = 100.0 / len(features) if len(features) > 0 else 1
         for current, f in enumerate(features):
             outGeomList = []
             if f.geometry().isMultipart():
diff --git a/python/plugins/processing/algs/qgis/MeanCoords.py b/python/plugins/processing/algs/qgis/MeanCoords.py
index 605caad..dc4febb 100644
--- a/python/plugins/processing/algs/qgis/MeanCoords.py
+++ b/python/plugins/processing/algs/qgis/MeanCoords.py
@@ -94,7 +94,7 @@ class MeanCoords(GeoAlgorithm):
         )
 
         features = vector.features(layer)
-        total = 100.0 / len(features)
+        total = 100.0 / len(features) if len(features) > 0 else 1
         means = {}
         for current, feat in enumerate(features):
             progress.setPercentage(int(current * total))
@@ -122,16 +122,16 @@ class MeanCoords(GeoAlgorithm):
             means[clazz] = (cx, cy, totalweight)
 
         current = 0
-        total = 100.0 / len(means)
+        total = 100.0 / len(means) if len(means) > 0 else 1
         for (clazz, values) in means.iteritems():
-            outFeat = QgsFeature()
-            cx = values[0] / values[2]
-            cy = values[1] / values[2]
-            meanPoint = QgsPoint(cx, cy)
-
-            outFeat.setGeometry(QgsGeometry.fromPoint(meanPoint))
-            outFeat.setAttributes([cx, cy, clazz])
-            writer.addFeature(outFeat)
+            if values[2]:
+                outFeat = QgsFeature()
+                cx = values[0] / values[2]
+                cy = values[1] / values[2]
+                meanPoint = QgsPoint(cx, cy)
+                outFeat.setGeometry(QgsGeometry.fromPoint(meanPoint))
+                outFeat.setAttributes([cx, cy, clazz])
+                writer.addFeature(outFeat)
             current += 1
             progress.setPercentage(int(current * total))
 
diff --git a/python/plugins/processing/algs/qgis/Merge.py b/python/plugins/processing/algs/qgis/Merge.py
index 6eec00d..fc679a2 100644
--- a/python/plugins/processing/algs/qgis/Merge.py
+++ b/python/plugins/processing/algs/qgis/Merge.py
@@ -86,7 +86,7 @@ class Merge(GeoAlgorithm):
                 if not found:
                     fields.append(sfield)
 
-        total = 100.0 / totalFeatureCount
+        total = 100.0 / totalFeatureCount if totalFeatureCount > 0 else 1
         writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(
             fields.toList(), layers[0].wkbType(),
             layers[0].crs())
diff --git a/python/plugins/processing/algs/qgis/MergeLines.py b/python/plugins/processing/algs/qgis/MergeLines.py
index fe1c08a..b9ee356 100644
--- a/python/plugins/processing/algs/qgis/MergeLines.py
+++ b/python/plugins/processing/algs/qgis/MergeLines.py
@@ -67,7 +67,7 @@ class MergeLines(GeoAlgorithm):
                 layer.crs())
 
         features = vector.features(layer)
-        total = 100.0 / len(features)
+        total = 100.0 / len(features) if len(features) > 0 else 1
 
         for current, inFeat in enumerate(features):
             outFeat = QgsFeature()
diff --git a/python/plugins/processing/algs/qgis/MultipartToSingleparts.py b/python/plugins/processing/algs/qgis/MultipartToSingleparts.py
index a95b577..cc78251 100644
--- a/python/plugins/processing/algs/qgis/MultipartToSingleparts.py
+++ b/python/plugins/processing/algs/qgis/MultipartToSingleparts.py
@@ -64,7 +64,7 @@ class MultipartToSingleparts(GeoAlgorithm):
             layer.pendingFields().toList(), geomType, layer.crs())
 
         features = vector.features(layer)
-        total = 100.0 / len(features)
+        total = 100.0 / len(features) if len(features) > 0 else 1
         for current, f in enumerate(features):
             outFeat = QgsFeature()
             attrs = f.attributes()
diff --git a/python/plugins/processing/algs/qgis/NearestNeighbourAnalysis.py b/python/plugins/processing/algs/qgis/NearestNeighbourAnalysis.py
index c6aa673..db76e41 100644
--- a/python/plugins/processing/algs/qgis/NearestNeighbourAnalysis.py
+++ b/python/plugins/processing/algs/qgis/NearestNeighbourAnalysis.py
@@ -89,7 +89,7 @@ class NearestNeighbourAnalysis(GeoAlgorithm):
 
         features = vector.features(layer)
         count = len(features)
-        total = 100.0 / count
+        total = 100.0 / count if count > 0 else 1
         for current, feat in enumerate(features):
             neighbourID = spatialIndex.nearestNeighbor(
                 feat.geometry().asPoint(), 2)[1]
diff --git a/python/plugins/processing/algs/qgis/OrientedMinimumBoundingBox.py b/python/plugins/processing/algs/qgis/OrientedMinimumBoundingBox.py
index 72e5900..3c8aa5b 100644
--- a/python/plugins/processing/algs/qgis/OrientedMinimumBoundingBox.py
+++ b/python/plugins/processing/algs/qgis/OrientedMinimumBoundingBox.py
@@ -85,7 +85,7 @@ class OrientedMinimumBoundingBox(GeoAlgorithm):
 
         fit = layer.getFeatures()
         inFeat = QgsFeature()
-        total = 100.0 / layer.featureCount()
+        total = 100.0 / layer.featureCount() if layer.featureCount() > 0 else 1
         newgeometry = QgsGeometry()
         first = True
         while fit.nextFeature(inFeat):
@@ -112,7 +112,7 @@ class OrientedMinimumBoundingBox(GeoAlgorithm):
 
     def featureOmbb(self, layer, writer, progress):
         features = vector.features(layer)
-        total = 100.0 / len(features)
+        total = 100.0 / len(features) if len(features) > 0 else 1
         outFeat = QgsFeature()
         for current, inFeat in enumerate(features):
             geometry, area, perim, angle, width, height = self.OMBBox(
diff --git a/python/plugins/processing/algs/qgis/PointDistance.py b/python/plugins/processing/algs/qgis/PointDistance.py
index 3bb0dbf..d2e5e0e 100644
--- a/python/plugins/processing/algs/qgis/PointDistance.py
+++ b/python/plugins/processing/algs/qgis/PointDistance.py
@@ -126,7 +126,7 @@ class PointDistance(GeoAlgorithm):
         distArea = QgsDistanceArea()
 
         features = vector.features(inLayer)
-        total = 100.0 / len(features)
+        total = 100.0 / len(features) if len(features) > 0 else 1
         for current, inFeat in enumerate(features):
             inGeom = inFeat.geometry()
             inID = unicode(inFeat.attributes()[inIdx])
@@ -166,7 +166,7 @@ class PointDistance(GeoAlgorithm):
 
         first = True
         features = vector.features(inLayer)
-        total = 100.0 / len(features)
+        total = 100.0 / len(features) if len(features) > 0 else 1
         for current, inFeat in enumerate(features):
             inGeom = inFeat.geometry()
             inID = unicode(inFeat.attributes()[inIdx])
diff --git a/python/plugins/processing/algs/qgis/PointOnSurface.py b/python/plugins/processing/algs/qgis/PointOnSurface.py
index 096273f..3fa8e7c 100644
--- a/python/plugins/processing/algs/qgis/PointOnSurface.py
+++ b/python/plugins/processing/algs/qgis/PointOnSurface.py
@@ -64,7 +64,7 @@ class PointOnSurface(GeoAlgorithm):
                 layer.crs())
 
         features = vector.features(layer)
-        total = 100.0 / len(features)
+        total = 100.0 / len(features) if len(features) > 0 else 1
 
         for current, input_feature in enumerate(features):
             output_feature = input_feature
diff --git a/python/plugins/processing/algs/qgis/PointsDisplacement.py b/python/plugins/processing/algs/qgis/PointsDisplacement.py
index c61d480..2075cfc 100644
--- a/python/plugins/processing/algs/qgis/PointsDisplacement.py
+++ b/python/plugins/processing/algs/qgis/PointsDisplacement.py
@@ -67,7 +67,7 @@ class PointsDisplacement(GeoAlgorithm):
 
         features = vector.features(layer)
 
-        total = 100.0 / len(features)
+        total = 100.0 / len(features) if len(features) > 0 else 1
 
         duplicates = dict()
         for current, f in enumerate(features):
@@ -80,7 +80,7 @@ class PointsDisplacement(GeoAlgorithm):
             progress.setPercentage(int(current * total))
 
         current = 0
-        total = 100.0 / len(duplicates)
+        total = 100.0 / len(duplicates) if len(duplicates) > 0 else 1
         progress.setPercentage(0)
 
         fullPerimeter = 2 * math.pi
diff --git a/python/plugins/processing/algs/qgis/PointsFromLines.py b/python/plugins/processing/algs/qgis/PointsFromLines.py
index 649c813..ea4d0bf 100644
--- a/python/plugins/processing/algs/qgis/PointsFromLines.py
+++ b/python/plugins/processing/algs/qgis/PointsFromLines.py
@@ -77,7 +77,7 @@ class PointsFromLines(GeoAlgorithm):
         self.pointId = 0
 
         features = vector.features(layer)
-        total = 100.0 / len(features)
+        total = 100.0 / len(features) if len(features) > 0 else 1
         for current, f in enumerate(features):
             geom = f.geometry()
             if geom.isMultipart():
diff --git a/python/plugins/processing/algs/qgis/PointsFromPolygons.py b/python/plugins/processing/algs/qgis/PointsFromPolygons.py
index 02d04b7..3c88afc 100644
--- a/python/plugins/processing/algs/qgis/PointsFromPolygons.py
+++ b/python/plugins/processing/algs/qgis/PointsFromPolygons.py
@@ -78,7 +78,7 @@ class PointsFromPolygons(GeoAlgorithm):
         pointId = 0
 
         features = vector.features(layer)
-        total = 100.0 / len(features)
+        total = 100.0 / len(features) if len(features) > 0 else 1
         for current, f in enumerate(features):
             geom = f.geometry()
             bbox = geom.boundingBox()
diff --git a/python/plugins/processing/algs/qgis/PointsInPolygon.py b/python/plugins/processing/algs/qgis/PointsInPolygon.py
index d457e9d..1988ca8 100644
--- a/python/plugins/processing/algs/qgis/PointsInPolygon.py
+++ b/python/plugins/processing/algs/qgis/PointsInPolygon.py
@@ -85,7 +85,7 @@ class PointsInPolygon(GeoAlgorithm):
         geom = QgsGeometry()
 
         features = vector.features(polyLayer)
-        total = 100.0 / len(features)
+        total = 100.0 / len(features) if len(features) > 0 else 1
         for current, ftPoly in enumerate(features):
             geom = ftPoly.geometry()
             engine = QgsGeometry.createGeometryEngine(geom.geometry())
diff --git a/python/plugins/processing/algs/qgis/PointsInPolygonUnique.py b/python/plugins/processing/algs/qgis/PointsInPolygonUnique.py
index d0dc350..7ad12f8 100644
--- a/python/plugins/processing/algs/qgis/PointsInPolygonUnique.py
+++ b/python/plugins/processing/algs/qgis/PointsInPolygonUnique.py
@@ -79,7 +79,7 @@ class PointsInPolygonUnique(GeoAlgorithm):
         geom = QgsGeometry()
 
         features = vector.features(polyLayer)
-        total = 100.0 / len(features)
+        total = 100.0 / len(features) if len(features) > 0 else 1
         for current, ftPoly in enumerate(features):
             geom = ftPoly.geometry()
             engine = QgsGeometry.createGeometryEngine(geom.geometry())
diff --git a/python/plugins/processing/algs/qgis/PointsInPolygonWeighted.py b/python/plugins/processing/algs/qgis/PointsInPolygonWeighted.py
index 13ae723..a2bf336 100644
--- a/python/plugins/processing/algs/qgis/PointsInPolygonWeighted.py
+++ b/python/plugins/processing/algs/qgis/PointsInPolygonWeighted.py
@@ -85,7 +85,7 @@ class PointsInPolygonWeighted(GeoAlgorithm):
         geom = QgsGeometry()
 
         features = vector.features(polyLayer)
-        total = 100.0 / len(features)
+        total = 100.0 / len(features) if len(features) > 0 else 1
         for current, ftPoly in enumerate(features):
             geom = ftPoly.geometry()
             engine = QgsGeometry.createGeometryEngine(geom.geometry())
diff --git a/python/plugins/processing/algs/qgis/PointsLayerFromTable.py b/python/plugins/processing/algs/qgis/PointsLayerFromTable.py
index 4929870..67104ca 100644
--- a/python/plugins/processing/algs/qgis/PointsLayerFromTable.py
+++ b/python/plugins/processing/algs/qgis/PointsLayerFromTable.py
@@ -75,7 +75,7 @@ class PointsLayerFromTable(GeoAlgorithm):
 
         outFeat = QgsFeature()
         features = vector.features(vlayer)
-        total = 100.0 / len(features)
+        total = 100.0 / len(features) if len(features) > 0 else 1
         for current, feature in enumerate(features):
             progress.setPercentage(int(current * total))
             attrs = feature.attributes()
diff --git a/python/plugins/processing/algs/qgis/PointsToPaths.py b/python/plugins/processing/algs/qgis/PointsToPaths.py
index 8407916..44fdd72 100644
--- a/python/plugins/processing/algs/qgis/PointsToPaths.py
+++ b/python/plugins/processing/algs/qgis/PointsToPaths.py
@@ -85,7 +85,7 @@ class PointsToPaths(GeoAlgorithm):
 
         points = dict()
         features = vector.features(layer)
-        total = 100.0 / len(features)
+        total = 100.0 / len(features) if len(features) > 0 else 1
         for current, f in enumerate(features):
             point = f.geometry().asPoint()
             group = f[groupField]
@@ -104,7 +104,7 @@ class PointsToPaths(GeoAlgorithm):
         da = QgsDistanceArea()
 
         current = 0
-        total = 100.0 / len(points)
+        total = 100.0 / len(points) if len(points) > 0 else 1
         for group, vertices in points.iteritems():
             vertices.sort()
             f = QgsFeature()
diff --git a/python/plugins/processing/algs/qgis/Polygonize.py b/python/plugins/processing/algs/qgis/Polygonize.py
index 18a6900..febc6c2 100644
--- a/python/plugins/processing/algs/qgis/Polygonize.py
+++ b/python/plugins/processing/algs/qgis/Polygonize.py
@@ -72,7 +72,7 @@ class Polygonize(GeoAlgorithm):
         allLinesList = []
         features = vector.features(vlayer)
         progress.setInfo(self.tr('Processing lines...'))
-        total = 40.0 / len(features)
+        total = 40.0 / len(features) if len(features) > 0 else 1
         for current, inFeat in enumerate(features):
             inGeom = inFeat.geometry()
             if inGeom.isMultipart():
@@ -97,7 +97,7 @@ class Polygonize(GeoAlgorithm):
         progress.setInfo('Saving polygons...')
         writer = output.getVectorWriter(fields, QGis.WKBPolygon, vlayer.crs())
         outFeat = QgsFeature()
-        total = 50.0 / len(polygons)
+        total = 50.0 / len(polygons) if len(polygons) > 0 else 1
         for current, polygon in enumerate(polygons):
             outFeat.setGeometry(QgsGeometry.fromWkt(polygon.wkt))
             if self.getParameterValue(self.GEOMETRY):
diff --git a/python/plugins/processing/algs/qgis/PolygonsToLines.py b/python/plugins/processing/algs/qgis/PolygonsToLines.py
index 387b3ec..4d2a637 100644
--- a/python/plugins/processing/algs/qgis/PolygonsToLines.py
+++ b/python/plugins/processing/algs/qgis/PolygonsToLines.py
@@ -67,7 +67,7 @@ class PolygonsToLines(GeoAlgorithm):
         outGeom = QgsGeometry()
 
         features = vector.features(layer)
-        total = 100.0 / len(features)
+        total = 100.0 / len(features) if len(features) > 0 else 1
         for current, f in enumerate(features):
             inGeom = f.geometry()
             attrs = f.attributes()
diff --git a/python/plugins/processing/algs/qgis/QGISAlgorithmProvider.py b/python/plugins/processing/algs/qgis/QGISAlgorithmProvider.py
index 095f45e..a4d3c09 100644
--- a/python/plugins/processing/algs/qgis/QGISAlgorithmProvider.py
+++ b/python/plugins/processing/algs/qgis/QGISAlgorithmProvider.py
@@ -55,6 +55,7 @@ from .VectorGrid import VectorGrid
 from .RandomExtract import RandomExtract
 from .RandomExtractWithinSubsets import RandomExtractWithinSubsets
 from .ExtractByLocation import ExtractByLocation
+from .ExtractByExpression import ExtractByExpression
 from .PointsInPolygon import PointsInPolygon
 from .PointsInPolygonUnique import PointsInPolygonUnique
 from .PointsInPolygonWeighted import PointsInPolygonWeighted
@@ -192,7 +193,7 @@ class QGISAlgorithmProvider(AlgorithmProvider):
                         ZonalStatistics(), PointsFromPolygons(),
                         PointsFromLines(), RandomPointsExtent(),
                         RandomPointsLayer(), RandomPointsPolygonsFixed(),
-                        RandomPointsPolygonsVariable(),
+                        RandomPointsPolygonsVariable(), ExtractByExpression(),
                         RandomPointsAlongLines(), PointsToPaths(),
                         PostGISExecuteSQL(), ImportIntoPostGIS(),
                         SetVectorStyle(), SetRasterStyle(),
diff --git a/python/plugins/processing/algs/qgis/RandomExtract.py b/python/plugins/processing/algs/qgis/RandomExtract.py
index 80839de..599031e 100644
--- a/python/plugins/processing/algs/qgis/RandomExtract.py
+++ b/python/plugins/processing/algs/qgis/RandomExtract.py
@@ -85,7 +85,7 @@ class RandomExtract(GeoAlgorithm):
         writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(
             layer.pendingFields().toList(), layer.wkbType(), layer.crs())
 
-        total = 100.0 / featureCount
+        total = 100.0 / featureCount if featureCount > 0 else 1
         for i, feat in enumerate(features):
             if i in selran:
                 writer.addFeature(feat)
diff --git a/python/plugins/processing/algs/qgis/RandomExtractWithinSubsets.py b/python/plugins/processing/algs/qgis/RandomExtractWithinSubsets.py
index b66db4b..f0e3a85 100644
--- a/python/plugins/processing/algs/qgis/RandomExtractWithinSubsets.py
+++ b/python/plugins/processing/algs/qgis/RandomExtractWithinSubsets.py
@@ -93,7 +93,7 @@ class RandomExtractWithinSubsets(GeoAlgorithm):
 
         selran = []
         current = 0
-        total = 100.0 / (featureCount * len(unique))
+        total = 100.0 / (featureCount * len(unique)) if featureCount * len(unique) > 0 else 1
         features = vector.features(layer)
 
         if not len(unique) == featureCount:
@@ -121,7 +121,7 @@ class RandomExtractWithinSubsets(GeoAlgorithm):
             selran = range(featureCount)
 
         features = vector.features(layer)
-        total = 100.0 / len(features)
+        total = 100.0 / len(features) if len(features) > 0 else 1
         for (i, feat) in enumerate(features):
             if i in selran:
                 writer.addFeature(feat)
diff --git a/python/plugins/processing/algs/qgis/RandomPointsAlongLines.py b/python/plugins/processing/algs/qgis/RandomPointsAlongLines.py
index 6dcfb90..d9206e7 100644
--- a/python/plugins/processing/algs/qgis/RandomPointsAlongLines.py
+++ b/python/plugins/processing/algs/qgis/RandomPointsAlongLines.py
@@ -74,7 +74,7 @@ class RandomPointsAlongLines(GeoAlgorithm):
         nIterations = 0
         maxIterations = pointCount * 200
         featureCount = layer.featureCount()
-        total = 100.0 / pointCount
+        total = 100.0 / pointCount if pointCount > 0 else 1
 
         index = QgsSpatialIndex()
         points = dict()
diff --git a/python/plugins/processing/algs/qgis/RandomPointsExtent.py b/python/plugins/processing/algs/qgis/RandomPointsExtent.py
index 721337a..23a6523 100644
--- a/python/plugins/processing/algs/qgis/RandomPointsExtent.py
+++ b/python/plugins/processing/algs/qgis/RandomPointsExtent.py
@@ -87,7 +87,7 @@ class RandomPointsExtent(GeoAlgorithm):
         nPoints = 0
         nIterations = 0
         maxIterations = pointCount * 200
-        total = 100.0 / pointCount
+        total = 100.0 / pointCount if pointCount > 0 else 1
 
         index = QgsSpatialIndex()
         points = dict()
diff --git a/python/plugins/processing/algs/qgis/RandomPointsLayer.py b/python/plugins/processing/algs/qgis/RandomPointsLayer.py
index e661358..3854a1f 100644
--- a/python/plugins/processing/algs/qgis/RandomPointsLayer.py
+++ b/python/plugins/processing/algs/qgis/RandomPointsLayer.py
@@ -82,7 +82,7 @@ class RandomPointsLayer(GeoAlgorithm):
         nPoints = 0
         nIterations = 0
         maxIterations = pointCount * 200
-        total = 100.0 / pointCount
+        total = 100.0 / pointCount if pointCount > 0 else 1
 
         index = QgsSpatialIndex()
         points = dict()
diff --git a/python/plugins/processing/algs/qgis/RandomPointsPolygonsFixed.py b/python/plugins/processing/algs/qgis/RandomPointsPolygonsFixed.py
index afe334c..c12eb2f 100644
--- a/python/plugins/processing/algs/qgis/RandomPointsPolygonsFixed.py
+++ b/python/plugins/processing/algs/qgis/RandomPointsPolygonsFixed.py
@@ -102,7 +102,7 @@ class RandomPointsPolygonsFixed(GeoAlgorithm):
             nPoints = 0
             nIterations = 0
             maxIterations = pointCount * 200
-            total = 100.0 / pointCount
+            total = 100.0 / pointCount if pointCount > 0 else 1
 
             random.seed()
 
diff --git a/python/plugins/processing/algs/qgis/RandomPointsPolygonsVariable.py b/python/plugins/processing/algs/qgis/RandomPointsPolygonsVariable.py
index 454c4a1..034fbc5 100644
--- a/python/plugins/processing/algs/qgis/RandomPointsPolygonsVariable.py
+++ b/python/plugins/processing/algs/qgis/RandomPointsPolygonsVariable.py
@@ -109,7 +109,7 @@ class RandomPointsPolygonsVariable(GeoAlgorithm):
             nPoints = 0
             nIterations = 0
             maxIterations = pointCount * 200
-            total = 100.0 / pointCount
+            total = 100.0 / pointCount if pointCount > 0 else 1
 
             random.seed()
 
diff --git a/python/plugins/processing/algs/qgis/RandomSelectionWithinSubsets.py b/python/plugins/processing/algs/qgis/RandomSelectionWithinSubsets.py
index 4465da2..d8645ae 100644
--- a/python/plugins/processing/algs/qgis/RandomSelectionWithinSubsets.py
+++ b/python/plugins/processing/algs/qgis/RandomSelectionWithinSubsets.py
@@ -104,7 +104,7 @@ class RandomSelectionWithinSubsets(GeoAlgorithm):
         inFeat = QgsFeature()
 
         current = 0
-        total = 100.0 / (featureCount * len(unique))
+        total = 100.0 / (featureCount * len(unique)) if featureCount * len(unique) > 0 else 1
 
         if not len(unique) == featureCount:
             for i in unique:
diff --git a/python/plugins/processing/algs/qgis/RectanglesOvalsDiamondsFixed.py b/python/plugins/processing/algs/qgis/RectanglesOvalsDiamondsFixed.py
index 368dbe4..d775856 100644
--- a/python/plugins/processing/algs/qgis/RectanglesOvalsDiamondsFixed.py
+++ b/python/plugins/processing/algs/qgis/RectanglesOvalsDiamondsFixed.py
@@ -96,7 +96,7 @@ class RectanglesOvalsDiamondsFixed(GeoAlgorithm):
         outFeat = QgsFeature()
 
         features = vector.features(layer)
-        total = 100.0 / len(features)
+        total = 100.0 / len(features) if len(features) > 0 else 1
 
         if shape == 0:
             self.rectangles(writer, features, width, height, rotation)
diff --git a/python/plugins/processing/algs/qgis/RectanglesOvalsDiamondsVariable.py b/python/plugins/processing/algs/qgis/RectanglesOvalsDiamondsVariable.py
index 1353ad6..67ac6e4 100644
--- a/python/plugins/processing/algs/qgis/RectanglesOvalsDiamondsVariable.py
+++ b/python/plugins/processing/algs/qgis/RectanglesOvalsDiamondsVariable.py
@@ -104,7 +104,7 @@ class RectanglesOvalsDiamondsVariable(GeoAlgorithm):
         outFeat = QgsFeature()
 
         features = vector.features(layer)
-        total = 100.0 / len(features)
+        total = 100.0 / len(features) if len(features) > 0 else 1
 
         if shape == 0:
             self.rectangles(writer, features, width, height, rotation)
diff --git a/python/plugins/processing/algs/qgis/RemoveNullGeometry.py b/python/plugins/processing/algs/qgis/RemoveNullGeometry.py
index 15b1dc9..627699f 100644
--- a/python/plugins/processing/algs/qgis/RemoveNullGeometry.py
+++ b/python/plugins/processing/algs/qgis/RemoveNullGeometry.py
@@ -54,7 +54,7 @@ class RemoveNullGeometry(GeoAlgorithm):
                 layer.crs())
 
         features = vector.features(layer)
-        total = 100.0 / len(features)
+        total = 100.0 / len(features) if len(features) > 0 else 1
 
         for current, input_feature in enumerate(features):
             if input_feature.constGeometry():
diff --git a/python/plugins/processing/algs/qgis/ReprojectLayer.py b/python/plugins/processing/algs/qgis/ReprojectLayer.py
index d5104e9..66e0c39 100644
--- a/python/plugins/processing/algs/qgis/ReprojectLayer.py
+++ b/python/plugins/processing/algs/qgis/ReprojectLayer.py
@@ -64,7 +64,7 @@ class ReprojectLayer(GeoAlgorithm):
 
         outFeat = QgsFeature()
         features = vector.features(layer)
-        total = 100.0 / len(features)
+        total = 100.0 / len(features) if len(features) > 0 else 1
         for current, f in enumerate(features):
             geom = f.geometry()
             geom.transform(crsTransform)
diff --git a/python/plugins/processing/algs/qgis/ReverseLineDirection.py b/python/plugins/processing/algs/qgis/ReverseLineDirection.py
index c5bf196..2f7be8b 100644
--- a/python/plugins/processing/algs/qgis/ReverseLineDirection.py
+++ b/python/plugins/processing/algs/qgis/ReverseLineDirection.py
@@ -59,7 +59,7 @@ class ReverseLineDirection(GeoAlgorithm):
         outFeat = QgsFeature()
 
         features = vector.features(layer)
-        total = 100.0 / len(features)
+        total = 100.0 / len(features) if len(features) > 0 else 1
         for current, inFeat in enumerate(features):
             inGeom = inFeat.constGeometry()
             attrs = inFeat.attributes()
diff --git a/python/plugins/processing/algs/qgis/SaveSelectedFeatures.py b/python/plugins/processing/algs/qgis/SaveSelectedFeatures.py
index 3372b82..7450c02 100644
--- a/python/plugins/processing/algs/qgis/SaveSelectedFeatures.py
+++ b/python/plugins/processing/algs/qgis/SaveSelectedFeatures.py
@@ -60,7 +60,7 @@ class SaveSelectedFeatures(GeoAlgorithm):
         if vectorLayer.selectedFeatureCount() == 0:
             raise GeoAlgorithmExecutionException(self.tr('There are no selected features in the input layer.'))
 
-        total = 100.0 / int(vectorLayer.selectedFeatureCount())
+        total = 100.0 / vectorLayer.selectedFeatureCount() if vectorLayer.selectedFeatureCount() > 0 else 1
         for current, feat in enumerate(features):
             writer.addFeature(feat)
             progress.setPercentage(int(current * total))
diff --git a/python/plugins/processing/algs/qgis/SelectByLocation.py b/python/plugins/processing/algs/qgis/SelectByLocation.py
index a67a0ce..ce14bc2 100644
--- a/python/plugins/processing/algs/qgis/SelectByLocation.py
+++ b/python/plugins/processing/algs/qgis/SelectByLocation.py
@@ -100,7 +100,7 @@ class SelectByLocation(GeoAlgorithm):
         geom = QgsGeometry()
         selectedSet = []
         features = vector.features(selectLayer)
-        total = 100.0 / len(features)
+        total = 100.0 / len(features) if len(features) > 0 else 1
         for current, f in enumerate(features):
             geom = vector.snapToPrecision(f.geometry(), precision)
             bbox = vector.bufferedBoundingBox(geom.boundingBox(), 0.51 * precision)
diff --git a/python/plugins/processing/algs/qgis/SimplifyGeometries.py b/python/plugins/processing/algs/qgis/SimplifyGeometries.py
index a6992c6..ae6c836 100644
--- a/python/plugins/processing/algs/qgis/SimplifyGeometries.py
+++ b/python/plugins/processing/algs/qgis/SimplifyGeometries.py
@@ -73,7 +73,7 @@ class SimplifyGeometries(GeoAlgorithm):
             layer.pendingFields().toList(), QGis.flatType(layer.wkbType()), layer.crs())
 
         features = vector.features(layer)
-        total = 100.0 / len(features)
+        total = 100.0 / len(features) if len(features) > 0 else 1
         for current, f in enumerate(features):
             featGeometry = f.geometry()
             if featGeometry is not None:
diff --git a/python/plugins/processing/algs/qgis/SinglePartsToMultiparts.py b/python/plugins/processing/algs/qgis/SinglePartsToMultiparts.py
index 9d75b7f..d8ba575 100644
--- a/python/plugins/processing/algs/qgis/SinglePartsToMultiparts.py
+++ b/python/plugins/processing/algs/qgis/SinglePartsToMultiparts.py
@@ -79,7 +79,7 @@ class SinglePartsToMultiparts(GeoAlgorithm):
 
         current = 0
         features = vector.features(layer)
-        total = 100.0 / (len(features) * len(unique))
+        total = 100.0 / (len(features) * len(unique)) if len(features) * len(unique) > 0 else 1
 
         nullFeatures = []
         if not len(unique) == layer.featureCount():
diff --git a/python/plugins/processing/algs/qgis/Smooth.py b/python/plugins/processing/algs/qgis/Smooth.py
index 45bea2b..e80cd20 100644
--- a/python/plugins/processing/algs/qgis/Smooth.py
+++ b/python/plugins/processing/algs/qgis/Smooth.py
@@ -67,7 +67,7 @@ class Smooth(GeoAlgorithm):
         outFeat = QgsFeature()
 
         features = vector.features(layer)
-        total = 100.0 / len(features)
+        total = 100.0 / len(features) if len(features) > 0 else 1
 
         for current, inFeat in enumerate(features):
             inGeom = inFeat.constGeometry()
diff --git a/python/plugins/processing/algs/qgis/SpatialJoin.py b/python/plugins/processing/algs/qgis/SpatialJoin.py
index 056fce6..9ee4e84 100644
--- a/python/plugins/processing/algs/qgis/SpatialJoin.py
+++ b/python/plugins/processing/algs/qgis/SpatialJoin.py
@@ -152,7 +152,7 @@ class SpatialJoin(GeoAlgorithm):
             mapP2[f.id()] = QgsFeature(f)
 
         features = vector.features(target)
-        total = 100.0 / len(features)
+        total = 100.0 / len(features) if len(features) > 0 else 1
         for c, f in enumerate(features):
             atMap1 = f.attributes()
             outFeat.setGeometry(f.geometry())
diff --git a/python/plugins/processing/algs/qgis/SplitLinesWithLines.py b/python/plugins/processing/algs/qgis/SplitLinesWithLines.py
index 168060b..b234670 100644
--- a/python/plugins/processing/algs/qgis/SplitLinesWithLines.py
+++ b/python/plugins/processing/algs/qgis/SplitLinesWithLines.py
@@ -66,7 +66,7 @@ class SplitLinesWithLines(GeoAlgorithm):
 
         outFeat = QgsFeature()
         features = vector.features(layerA)
-        total = 100.0 / float(len(features))
+        total = 100.0 / len(features) if len(features) > 0 else 1
 
         for current, inFeatA in enumerate(features):
             inGeom = QgsGeometry(inFeatA.geometry())
diff --git a/python/plugins/processing/algs/qgis/StatisticsByCategories.py b/python/plugins/processing/algs/qgis/StatisticsByCategories.py
index 6b327ed..3ab7c6a 100644
--- a/python/plugins/processing/algs/qgis/StatisticsByCategories.py
+++ b/python/plugins/processing/algs/qgis/StatisticsByCategories.py
@@ -65,7 +65,7 @@ class StatisticsByCategories(GeoAlgorithm):
         categoriesField = layer.fieldNameIndex(categoriesFieldName)
 
         features = vector.features(layer)
-        total = 100.0 / len(features)
+        total = 100.0 / len(features) if len(features) > 0 else 1
         values = {}
         for current, feat in enumerate(features):
             progress.setPercentage(int(current * total))
diff --git a/python/plugins/processing/algs/qgis/SumLines.py b/python/plugins/processing/algs/qgis/SumLines.py
index e26cbb5..296486c 100644
--- a/python/plugins/processing/algs/qgis/SumLines.py
+++ b/python/plugins/processing/algs/qgis/SumLines.py
@@ -90,7 +90,7 @@ class SumLines(GeoAlgorithm):
         distArea = QgsDistanceArea()
 
         features = vector.features(polyLayer)
-        total = 100.0 / len(features)
+        total = 100.0 / len(features) if len(features) > 0 else 1
         hasIntersections = False
         for current, ftPoly in enumerate(features):
             inGeom = QgsGeometry(ftPoly.geometry())
diff --git a/python/plugins/processing/algs/qgis/SymmetricalDifference.py b/python/plugins/processing/algs/qgis/SymmetricalDifference.py
index b17935a..8e20124 100644
--- a/python/plugins/processing/algs/qgis/SymmetricalDifference.py
+++ b/python/plugins/processing/algs/qgis/SymmetricalDifference.py
@@ -79,7 +79,7 @@ class SymmetricalDifference(GeoAlgorithm):
         featuresA = vector.features(layerA)
         featuresB = vector.features(layerB)
 
-        total = 100.0 / (len(featuresA) * len(featuresB))
+        total = 100.0 / (len(featuresA) * len(featuresB)) if len(featuresA) * len(featuresB) > 0 else 1
         count = 0
 
         for featA in featuresA:
diff --git a/python/plugins/processing/algs/qgis/TextToFloat.py b/python/plugins/processing/algs/qgis/TextToFloat.py
index 45da82c..9216cd1 100644
--- a/python/plugins/processing/algs/qgis/TextToFloat.py
+++ b/python/plugins/processing/algs/qgis/TextToFloat.py
@@ -63,7 +63,7 @@ class TextToFloat(GeoAlgorithm):
 
         features = vector.features(layer)
 
-        total = 100.0 / len(features)
+        total = 100.0 / len(features) if len(features) > 0 else 1
         for current, f in enumerate(features):
             value = f[idx]
             try:
diff --git a/python/plugins/processing/algs/qgis/Union.py b/python/plugins/processing/algs/qgis/Union.py
index f04ae4e..76966e7 100644
--- a/python/plugins/processing/algs/qgis/Union.py
+++ b/python/plugins/processing/algs/qgis/Union.py
@@ -86,7 +86,7 @@ class Union(GeoAlgorithm):
         count = 0
         nElement = 0
         featuresA = vector.features(vlayerA)
-        nFeat = len(featuresA)
+        nFeat = len(featuresA) if len(featuresA) > 0 else 1
         for inFeatA in featuresA:
             progress.setPercentage(nElement / float(nFeat) * 50)
             nElement += 1
@@ -188,7 +188,7 @@ class Union(GeoAlgorithm):
         atMapA = [None] * length
 
         featuresA = vector.features(vlayerB)
-        nFeat = len(featuresA)
+        nFeat = len(featuresA) if len(featuresA) else 1
         for inFeatA in featuresA:
             progress.setPercentage(nElement / float(nFeat) * 100)
             add = False
diff --git a/python/plugins/processing/algs/qgis/VectorSplit.py b/python/plugins/processing/algs/qgis/VectorSplit.py
index 7659808..ec4fb39 100644
--- a/python/plugins/processing/algs/qgis/VectorSplit.py
+++ b/python/plugins/processing/algs/qgis/VectorSplit.py
@@ -74,7 +74,7 @@ class VectorSplit(GeoAlgorithm):
         crs = layer.crs()
         geomType = layer.wkbType()
 
-        total = 100.0 / len(uniqueValues)
+        total = 100.0 / len(uniqueValues) if len(uniqueValues) > 0 else 1
 
         for current, i in enumerate(uniqueValues):
             fName = u'{0}_{1}.shp'.format(baseName, unicode(i).strip())
diff --git a/python/plugins/processing/algs/qgis/VoronoiPolygons.py b/python/plugins/processing/algs/qgis/VoronoiPolygons.py
index 6a2a48f..8c7f1fd 100644
--- a/python/plugins/processing/algs/qgis/VoronoiPolygons.py
+++ b/python/plugins/processing/algs/qgis/VoronoiPolygons.py
@@ -83,7 +83,7 @@ class VoronoiPolygons(GeoAlgorithm):
         ptNdx = -1
 
         features = vector.features(layer)
-        total = 100.0 / len(features)
+        total = 100.0 / len(features) if len(features) > 0 else 1
         for current, inFeat in enumerate(features):
             geom = QgsGeometry(inFeat.geometry())
             point = geom.asPoint()
diff --git a/python/plugins/processing/algs/qgis/ZonalStatistics.py b/python/plugins/processing/algs/qgis/ZonalStatistics.py
index 3d612fd..2d3c61f 100644
--- a/python/plugins/processing/algs/qgis/ZonalStatistics.py
+++ b/python/plugins/processing/algs/qgis/ZonalStatistics.py
@@ -172,7 +172,7 @@ class ZonalStatistics(GeoAlgorithm):
         outFeat.setFields(fields)
 
         features = vector.features(layer)
-        total = 100.0 / len(features)
+        total = 100.0 / len(features) if len(features) > 0 else 1
         for current, f in enumerate(features):
             geom = f.geometry()
 
diff --git a/python/plugins/processing/algs/saga/SagaAlgorithm.py b/python/plugins/processing/algs/saga/SagaAlgorithm.py
index 69c5db9..0a5d5f4 100644
--- a/python/plugins/processing/algs/saga/SagaAlgorithm.py
+++ b/python/plugins/processing/algs/saga/SagaAlgorithm.py
@@ -65,11 +65,13 @@ sessionExportedLayers = {}
 class SagaAlgorithm(GeoAlgorithm):
 
     OUTPUT_EXTENT = 'OUTPUT_EXTENT'
+    RESAMPLING = "_RESAMPLING"
 
     def __init__(self, descriptionfile):
         GeoAlgorithm.__init__(self)
         self.hardcodedStrings = []
         self.allowUnmatchingGridExtents = False
+        self.noResamplingChoice = False
         self.descriptionFile = descriptionfile
         self.defineCharacteristicsFromFile()
         self._icon = None
@@ -115,6 +117,8 @@ class SagaAlgorithm(GeoAlgorithm):
                     self.addParameter(getParameterFromString(line))
                 elif line.startswith('AllowUnmatching'):
                     self.allowUnmatchingGridExtents = True
+                elif line.startswith('NoResamplingChoice'):
+                    self.noResamplingChoice = True
                 elif line.startswith('Extent'):
                     # An extent parameter that wraps 4 SAGA numerical parameters
                     self.extentParamNames = line[6:].strip().split(' ')
@@ -123,6 +127,19 @@ class SagaAlgorithm(GeoAlgorithm):
                 else:
                     self.addOutput(getOutputFromString(line))
                 line = lines.readline().strip('\n').strip()
+            hasRaster = False
+            for param in self.parameters:
+                if (isinstance(param, ParameterRaster) or 
+                    (isinstance(param, ParameterMultipleInput) 
+                        and param.type == ParameterMultipleInput.TYPE_RASTER)):
+                    hasRaster = True
+                    break;
+
+            if (not self.noResamplingChoice and hasRaster):
+                param = ParameterSelection(self.RESAMPLING, "Resampling method", ["Nearest Neighbour", "Bilinear Interpolation", "Bicubic Spline Interpolation", "B-Spline Interpolation"], 3)
+                param.isAdvanced = True
+                self.addParameter(param)
+
 
     def processAlgorithm(self, progress):
         commands = list()
@@ -178,10 +195,10 @@ class SagaAlgorithm(GeoAlgorithm):
                             if exportCommand is not None:
                                 commands.append(exportCommand)
                         param.value = ";".join(layers)
-                elif param.datatype in [dataobjects.TYPE_VECTOR_ANY,
-                                        dataobjects.TYPE_VECTOR_LINE,
-                                        dataobjects.TYPE_VECTOR_POLYGON,
-                                        dataobjects.TYPE_VECTOR_POINT]:
+                elif param.datatype in [ParameterMultipleInput.TYPE_VECTOR_ANY,
+                                        ParameterMultipleInput.TYPE_VECTOR_LINE,
+                                        ParameterMultipleInput.TYPE_VECTOR_POLYGON,
+                                        ParameterMultipleInput.TYPE_VECTOR_POINT]:
                     for layerfile in layers:
                         layer = dataobjects.getObjectFromUri(layerfile, False)
                         if layer:
@@ -196,7 +213,7 @@ class SagaAlgorithm(GeoAlgorithm):
         command += ' ' + ' '.join(self.hardcodedStrings)
 
         for param in self.parameters:
-            if param.value is None:
+            if param.value is None or param.name == self.RESAMPLING:
                 continue
             if isinstance(param, (ParameterRaster, ParameterVector, ParameterTable)):
                 value = param.value
@@ -327,7 +344,9 @@ class SagaAlgorithm(GeoAlgorithm):
         destFilename = getTempFilenameInTempFolder(filename + '.sgrd')
         self.exportedLayers[source] = destFilename
         sessionExportedLayers[source] = destFilename
-        return 'io_gdal 0 -TRANSFORM 1 -RESAMPLING 3 -GRIDS "' + destFilename + '" -FILES "' + source + '"'
+        resampling = self.getParameterValue(self.RESAMPLING)
+        resampling = str(resampling) if resampling is not None else "0"
+        return 'io_gdal 0 -TRANSFORM 1 -RESAMPLING ' + resampling + ' -GRIDS "' + destFilename + '" -FILES "' + source + '"'
 
     def checkParameterValuesBeforeExecuting(self):
         """
diff --git a/python/plugins/processing/algs/saga/description/GridCalculator.txt b/python/plugins/processing/algs/saga/description/GridCalculator.txt
index 38bda55..9ca8283 100644
--- a/python/plugins/processing/algs/saga/description/GridCalculator.txt
+++ b/python/plugins/processing/algs/saga/description/GridCalculator.txt
@@ -1,6 +1,7 @@
 Raster calculator|Grid Calculator
 grid_calculus
 AllowUnmatching
+NoResamplingChoice
 ParameterRaster|GRIDS|Main input layer|False
 ParameterMultipleInput|XGRIDS|Additional layers|3|True
 ParameterString|FORMULA|Formula|
diff --git a/python/plugins/processing/algs/saga/description/ReclassifyGridValues.txt b/python/plugins/processing/algs/saga/description/ReclassifyGridValues.txt
index d76e5a5..36c2654 100644
--- a/python/plugins/processing/algs/saga/description/ReclassifyGridValues.txt
+++ b/python/plugins/processing/algs/saga/description/ReclassifyGridValues.txt
@@ -1,5 +1,6 @@
 Reclassify Grid Values
 grid_tools
+NoResamplingChoice
 ParameterRaster|INPUT|Grid|False
 ParameterSelection|METHOD|Method|[0] single;[1] range;[2] simple table
 ParameterNumber|OLD|old value (for single value change)|None|None|0.0
diff --git a/python/plugins/processing/algs/saga/description/VectorisingGridClasses.txt b/python/plugins/processing/algs/saga/description/VectorisingGridClasses.txt
index d3e37cd..0057f58 100644
--- a/python/plugins/processing/algs/saga/description/VectorisingGridClasses.txt
+++ b/python/plugins/processing/algs/saga/description/VectorisingGridClasses.txt
@@ -1,4 +1,4 @@
-Vectorising Raster Classes
+Vectorising Grid Classes
 shapes_grid
 ParameterRaster|GRID|Grid|False
 ParameterSelection|CLASS_ALL|Class Selection|[0] one single class specified by class identifier;[1] all classes|1
diff --git a/python/plugins/processing/algs/taudem/TauDEMAlgorithm.py b/python/plugins/processing/algs/taudem/TauDEMAlgorithm.py
index ce8459d..33181b6 100644
--- a/python/plugins/processing/algs/taudem/TauDEMAlgorithm.py
+++ b/python/plugins/processing/algs/taudem/TauDEMAlgorithm.py
@@ -112,7 +112,7 @@ class TauDEMAlgorithm(GeoAlgorithm):
                 commands.append(param.name)
                 commands.append(param.value)
             elif isinstance(param, ParameterBoolean):
-                if not param.value:
+                if param.value:
                     commands.append(param.name)
             elif isinstance(param, ParameterString):
                 commands.append(param.name)
diff --git a/python/plugins/processing/gui/RenderingStyleFilePanel.py b/python/plugins/processing/gui/RenderingStyleFilePanel.py
index f645c02..3ef555f 100644
--- a/python/plugins/processing/gui/RenderingStyleFilePanel.py
+++ b/python/plugins/processing/gui/RenderingStyleFilePanel.py
@@ -48,7 +48,7 @@ class RenderingStyleFilePanel(BASE, WIDGET):
     def showSelectionDialog(self):
         filename = QFileDialog.getOpenFileName(self,
                                                self.tr('Select style file'), '',
-                                               self.tr('QGIS Layer Style File (*.qml *.QML)'))
+                                               self.tr('QGIS Layer Style File (*.qml *.QML);;'))
         if filename:
             self.leText.setText(filename)
 
diff --git a/python/plugins/processing/tests/ToolsTest.py b/python/plugins/processing/tests/ToolsTest.py
index d07e2b5..aa83e83 100644
--- a/python/plugins/processing/tests/ToolsTest.py
+++ b/python/plugins/processing/tests/ToolsTest.py
@@ -25,28 +25,17 @@ __copyright__ = '(C) 2016, Nyall Dawson'
 
 __revision__ = '$Format:%H$'
 
+import os
+import shutil
+import tempfile
+
 from qgis.testing import start_app, unittest
 from processing.tests.TestData import points2
 from processing.tools import vector
 from qgis.core import (QgsVectorLayer, QgsFeatureRequest)
 from processing.core.ProcessingConfig import ProcessingConfig
 
-import os.path
-import errno
-import shutil
-
-dataFolder = os.path.join(os.path.dirname(__file__), '../../../../tests/testdata/')
-tmpBaseFolder = os.path.join(os.sep, 'tmp', 'qgis_test', str(os.getpid()))
-
-
-def mkDirP(path):
-    try:
-        os.makedirs(path)
-    except OSError as exc:
-        if exc.errno == errno.EEXIST and os.path.isdir(path):
-            pass
-        else:
-            raise
+testDataPath = os.path.join(os.path.dirname(__file__), 'testdata')
 
 start_app()
 
@@ -55,54 +44,50 @@ class VectorTest(unittest.TestCase):
 
     @classmethod
     def setUpClass(cls):
-        mkDirP(tmpBaseFolder)
+        cls.cleanup_paths = []
 
     @classmethod
     def tearDownClass(cls):
-        shutil.rmtree(tmpBaseFolder)
-        pass
+        for path in cls.cleanup_paths:
+            shutil.rmtree(path)
 
-    # See http://hub.qgis.org/issues/15698
-    def test_ogrLayerName(self):
-        tmpdir = os.path.join(tmpBaseFolder, 'ogrLayerName')
-        os.mkdir(tmpdir)
+    def testOgrLayerNameExtraction(self):
+        outdir = tempfile.mkdtemp()
+        self.cleanup_paths.append(outdir)
 
-        def linkTestfile(f, t):
-            os.link(os.path.join(dataFolder, f), os.path.join(tmpdir, t))
+        def _copyFile(dst):
+            shutil.copyfile(os.path.join(testDataPath, 'custom', 'grass7', 'weighted.csv'), dst)
 
-        # URI from OGR provider
-        linkTestfile('geom_data.csv', 'a.csv')
-        name = vector.ogrLayerName(tmpdir)
+        # OGR provider - single layer
+        _copyFile(os.path.join(outdir, 'a.csv'))
+        name = vector.ogrLayerName(outdir)
         self.assertEqual(name, 'a')
 
-        # URI from OGR provider
-        linkTestfile('wkt_data.csv', 'b.csv')
-        name = vector.ogrLayerName(tmpdir + '|layerid=0')
-        self.assertEqual(name, 'a')
-        name = vector.ogrLayerName(tmpdir + '|layerid=1')
+        # OGR provider - multiple layers
+        _copyFile(os.path.join(outdir, 'b.csv'))
+        name = vector.ogrLayerName(outdir + '|layerid=0')
         self.assertEqual(name, 'b')
+        name = vector.ogrLayerName(outdir + '|layerid=1')
+        self.assertEqual(name, 'a')
 
-        # URI from OGR provider
-        name = vector.ogrLayerName(tmpdir + '|layerid=2')
-        self.assertEqual(name, 'invalid-layerid')
+        name = vector.ogrLayerName(outdir + '|layerid=2')
+        self.assertIsNone(name)
 
-        # URI from OGR provider
-        name = vector.ogrLayerName(tmpdir + '|layername=f')
-        self.assertEqual(name, 'f') # layername takes precedence
+        # OGR provider - layername takes precedence
+        name = vector.ogrLayerName(outdir + '|layername=f')
+        self.assertEqual(name, 'f')
 
-        # URI from OGR provider
-        name = vector.ogrLayerName(tmpdir + '|layerid=0|layername=f2')
-        self.assertEqual(name, 'f2') # layername takes precedence
+        name = vector.ogrLayerName(outdir + '|layerid=0|layername=f')
+        self.assertEqual(name, 'f')
 
-        # URI from OGR provider
-        name = vector.ogrLayerName(tmpdir + '|layername=f2|layerid=0')
-        self.assertEqual(name, 'f2') # layername takes precedence
+        name = vector.ogrLayerName(outdir + '|layername=f|layerid=0')
+        self.assertEqual(name, 'f')
 
-        # URI from Sqlite provider
+        # SQLiite provider
         name = vector.ogrLayerName('dbname=\'/tmp/x.sqlite\' table="t" (geometry) sql=')
         self.assertEqual(name, 't')
 
-        # URI from PostgreSQL provider
+        # PostgreSQL provider
         name = vector.ogrLayerName('port=5493 sslmode=disable key=\'edge_id\' srid=0 type=LineString table="city_data"."edge" (geom) sql=')
         self.assertEqual(name, 'city_data.edge')
 
diff --git a/python/plugins/processing/tests/testdata/expected/extract_expression.gml b/python/plugins/processing/tests/testdata/expected/extract_expression.gml
new file mode 100644
index 0000000..57e5f57
--- /dev/null
+++ b/python/plugins/processing/tests/testdata/expected/extract_expression.gml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<ogr:FeatureCollection
+     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+     xsi:schemaLocation="http://ogr.maptools.org/ extract_expression.xsd"
+     xmlns:ogr="http://ogr.maptools.org/"
+     xmlns:gml="http://www.opengis.net/gml">
+  <gml:boundedBy>
+    <gml:Box>
+      <gml:coord><gml:X>4</gml:X><gml:Y>-3</gml:Y></gml:coord>
+      <gml:coord><gml:X>10</gml:X><gml:Y>5</gml:Y></gml:coord>
+    </gml:Box>
+  </gml:boundedBy>
+                                                                                                                                                              
+  <gml:featureMember>
+    <ogr:extract_expression fid="polys.1">
+      <ogr:geometryProperty><gml:Polygon srsName="EPSG:4326"><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>5,5 6,4 4,4 5,5</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></ogr:geometryProperty>
+      <ogr:name>Aaaaa</ogr:name>
+      <ogr:intval>-33</ogr:intval>
+      <ogr:floatval>0.00000</ogr:floatval>
+    </ogr:extract_expression>
+  </gml:featureMember>
+  <gml:featureMember>
+    <ogr:extract_expression fid="polys.3">
+      <ogr:geometryProperty><gml:Polygon srsName="EPSG:4326"><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>6,1 10,1 10,-3 6,-3 6,1</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs><gml:innerBoundaryIs><gml:LinearRing><gml:coordinates>7,0 7,-2 9,-2 9,0 7,0</gml:coordinates></gml:LinearRing></gml:innerBoundaryIs></gml:Polygon></ogr:geometryProperty>
+      <ogr:name>ASDF</ogr:name>
+      <ogr:intval>0</ogr:intval>
+      <ogr:floatval xsi:nil="true"/>
+    </ogr:extract_expression>
+  </gml:featureMember>
+</ogr:FeatureCollection>
diff --git a/python/plugins/processing/tests/testdata/expected/extract_expression.xsd b/python/plugins/processing/tests/testdata/expected/extract_expression.xsd
new file mode 100644
index 0000000..e95c088
--- /dev/null
+++ b/python/plugins/processing/tests/testdata/expected/extract_expression.xsd
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xs:schema targetNamespace="http://ogr.maptools.org/" xmlns:ogr="http://ogr.maptools.org/" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:gml="http://www.opengis.net/gml" elementFormDefault="qualified" version="1.0">
+<xs:import namespace="http://www.opengis.net/gml" schemaLocation="http://schemas.opengis.net/gml/2.1.2/feature.xsd"/>
+<xs:element name="FeatureCollection" type="ogr:FeatureCollectionType" substitutionGroup="gml:_FeatureCollection"/>
+<xs:complexType name="FeatureCollectionType">
+  <xs:complexContent>
+    <xs:extension base="gml:AbstractFeatureCollectionType">
+      <xs:attribute name="lockId" type="xs:string" use="optional"/>
+      <xs:attribute name="scope" type="xs:string" use="optional"/>
+    </xs:extension>
+  </xs:complexContent>
+</xs:complexType>
+<xs:element name="extract_expression" type="ogr:extract_expression_Type" substitutionGroup="gml:_Feature"/>
+<xs:complexType name="extract_expression_Type">
+  <xs:complexContent>
+    <xs:extension base="gml:AbstractFeatureType">
+      <xs:sequence>
+        <xs:element name="geometryProperty" type="gml:PolygonPropertyType" nillable="true" minOccurs="0" maxOccurs="1"/>
+        <xs:element name="name" nillable="true" minOccurs="0" maxOccurs="1">
+          <xs:simpleType>
+            <xs:restriction base="xs:string">
+              <xs:maxLength value="255"/>
+            </xs:restriction>
+          </xs:simpleType>
+        </xs:element>
+        <xs:element name="intval" nillable="true" minOccurs="0" maxOccurs="1">
+          <xs:simpleType>
+            <xs:restriction base="xs:integer">
+              <xs:totalDigits value="10"/>
+            </xs:restriction>
+          </xs:simpleType>
+        </xs:element>
+        <xs:element name="floatval" nillable="true" minOccurs="0" maxOccurs="1">
+          <xs:simpleType>
+            <xs:restriction base="xs:decimal">
+              <xs:totalDigits value="21"/>
+              <xs:fractionDigits value="5"/>
+            </xs:restriction>
+          </xs:simpleType>
+        </xs:element>
+      </xs:sequence>
+    </xs:extension>
+  </xs:complexContent>
+</xs:complexType>
+</xs:schema>
diff --git a/python/plugins/processing/tests/testdata/qgis_algorithm_tests.yaml b/python/plugins/processing/tests/testdata/qgis_algorithm_tests.yaml
index 7d7809c..e1e456a 100644
--- a/python/plugins/processing/tests/testdata/qgis_algorithm_tests.yaml
+++ b/python/plugins/processing/tests/testdata/qgis_algorithm_tests.yaml
@@ -614,3 +614,15 @@ tests:
       OUTPUT:
         name: expected/single_to_multi.gml
         type: vector
+
+  - algorithm: qgis:extractbyexpression
+    name: Test (qgis:extractbyexpression)
+    params:
+      EXPRESSION: left("Name", 1) = 'A'
+      INPUT:
+        name: polys.gml
+        type: vector
+    results:
+      OUTPUT:
+        name: expected/extract_expression.gml
+        type: vector
diff --git a/python/plugins/processing/tools/vector.py b/python/plugins/processing/tools/vector.py
index 32e1102..bb58383 100644
--- a/python/plugins/processing/tools/vector.py
+++ b/python/plugins/processing/tools/vector.py
@@ -525,26 +525,6 @@ def ogrConnectionString(uri):
     return '"' + ogrstr + '"'
 
 
-#
-# The uri parameter is an URI from any QGIS provider,
-# so could have different formats.
-# Example formats:
-#
-# -- PostgreSQL provider
-# port=5493 sslmode=disable key='edge_id' srid=0 type=LineString table="city_data"."edge" (geom) sql=
-#
-# -- Spatialite provider
-# dbname='/tmp/x.sqlite' table="t" (geometry) sql='
-#
-# -- OGR provider (single-layer directory)
-# /tmp/x.gdb
-#
-# -- OGR provider (multi-layer directory)
-# /tmp/x.gdb|layerid=1
-#
-# -- OGR provider (multi-layer directory)
-# /tmp/x.gdb|layername=thelayer
-#
 def ogrLayerName(uri):
 
     # handle URIs of database providers
@@ -580,10 +560,10 @@ def ogrLayerName(uri):
             # take precedence
     ds = ogr.Open(ogruri)
     if not ds:
-        return "invalid-uri"
+        return None
     ly = ds.GetLayer(layerid)
     if not ly:
-        return "invalid-layerid"
+        return None
     name = ly.GetName()
     return name
 
diff --git a/python/server/qgswmsconfigparser.sip b/python/server/qgswmsconfigparser.sip
index efd3eb8..29c3e26 100644
--- a/python/server/qgswmsconfigparser.sip
+++ b/python/server/qgswmsconfigparser.sip
@@ -35,6 +35,10 @@ class QgsWMSConfigParser
     /** Fills a layer and a style list. The two list have the same number of entries and the style and the layer at a position belong together (similar to the HTTP parameters 'Layers' and 'Styles'. Returns 0 in case of success*/
     virtual int layersAndStyles( QStringList& layers, QStringList& styles ) const = 0;
 
+    /** Creates a layer set and returns a stringlist with layer ids that can be passed to a QgsMapRenderer. Usually used in conjunction with readLayersAndStyles
+       @param scaleDenominator Filter out layer if scale based visibility does not match (or use -1 if no scale restriction)*/
+    QStringList layerSet( const QStringList& layersList, const QStringList& stylesList, const QgsCoordinateReferenceSystem& destCRS, double scaleDenominator = -1 ) const;
+
     /** Returns the xml fragment of a style*/
     virtual QDomDocument getStyle( const QString& styleName, const QString& layerName ) const = 0;
 
diff --git a/src/analysis/raster/qgsderivativefilter.cpp b/src/analysis/raster/qgsderivativefilter.cpp
index 656ebec..a25302a 100644
--- a/src/analysis/raster/qgsderivativefilter.cpp
+++ b/src/analysis/raster/qgsderivativefilter.cpp
@@ -92,7 +92,7 @@ float QgsDerivativeFilter::calcFirstDerX( float* x11, float* x21, float* x31, fl
     return mOutputNodataValue;
   }
 
-  return sum / ( weight * mCellSizeX * mZFactor );
+  return sum / ( weight * mCellSizeX ) * mZFactor;
 }
 
 float QgsDerivativeFilter::calcFirstDerY( float* x11, float* x21, float* x31, float* x12, float* x22, float* x32, float* x13, float* x23, float* x33 )
@@ -159,7 +159,7 @@ float QgsDerivativeFilter::calcFirstDerY( float* x11, float* x21, float* x31, fl
     return mOutputNodataValue;
   }
 
-  return sum / ( weight * mCellSizeY * mZFactor );
+  return sum / ( weight * mCellSizeY ) * mZFactor;
 }
 
 
diff --git a/src/app/composer/qgscomposerscalebarwidget.cpp b/src/app/composer/qgscomposerscalebarwidget.cpp
index d598da7..c8e61c1 100644
--- a/src/app/composer/qgscomposerscalebarwidget.cpp
+++ b/src/app/composer/qgscomposerscalebarwidget.cpp
@@ -219,7 +219,7 @@ void QgsComposerScaleBarWidget::on_mNumberOfSegmentsSpinBox_valueChanged( int i
   mComposerScaleBar->endCommand();
 }
 
-void QgsComposerScaleBarWidget::on_mHeightSpinBox_valueChanged( int i )
+void QgsComposerScaleBarWidget::on_mHeightSpinBox_valueChanged( double d )
 {
   if ( !mComposerScaleBar )
   {
@@ -227,7 +227,7 @@ void QgsComposerScaleBarWidget::on_mHeightSpinBox_valueChanged( int i )
   }
   mComposerScaleBar->beginCommand( tr( "Scalebar height changed" ), QgsComposerMergeCommand::ScaleBarHeight );
   disconnectUpdateSignal();
-  mComposerScaleBar->setHeight( i );
+  mComposerScaleBar->setHeight( d );
   mComposerScaleBar->update();
   connectUpdateSignal();
   mComposerScaleBar->endCommand();
@@ -647,7 +647,7 @@ void QgsComposerScaleBarWidget::composerMapChanged( QgsComposerItem* item )
   mComposerScaleBar->endCommand();
 }
 
-void QgsComposerScaleBarWidget::on_mMinWidthSpinBox_valueChanged( int )
+void QgsComposerScaleBarWidget::on_mMinWidthSpinBox_valueChanged( double )
 {
   if ( !mComposerScaleBar )
   {
@@ -662,7 +662,7 @@ void QgsComposerScaleBarWidget::on_mMinWidthSpinBox_valueChanged( int )
   mComposerScaleBar->endCommand();
 }
 
-void QgsComposerScaleBarWidget::on_mMaxWidthSpinBox_valueChanged( int )
+void QgsComposerScaleBarWidget::on_mMaxWidthSpinBox_valueChanged( double )
 {
   if ( !mComposerScaleBar )
   {
diff --git a/src/app/composer/qgscomposerscalebarwidget.h b/src/app/composer/qgscomposerscalebarwidget.h
index 7a2872d..0965b55 100644
--- a/src/app/composer/qgscomposerscalebarwidget.h
+++ b/src/app/composer/qgscomposerscalebarwidget.h
@@ -35,7 +35,7 @@ class QgsComposerScaleBarWidget: public QgsComposerItemBaseWidget, private Ui::Q
 
   public slots:
 
-    void on_mHeightSpinBox_valueChanged( int i );
+    void on_mHeightSpinBox_valueChanged( double d );
     void on_mLineWidthSpinBox_valueChanged( double d );
     void on_mSegmentSizeSpinBox_valueChanged( double d );
     void on_mSegmentsLeftSpinBox_valueChanged( int i );
@@ -54,8 +54,8 @@ class QgsComposerScaleBarWidget: public QgsComposerItemBaseWidget, private Ui::Q
     void on_mUnitsComboBox_currentIndexChanged( int index );
     void on_mLineJoinStyleCombo_currentIndexChanged( int index );
     void on_mLineCapStyleCombo_currentIndexChanged( int index );
-    void on_mMinWidthSpinBox_valueChanged( int i );
-    void on_mMaxWidthSpinBox_valueChanged( int i );
+    void on_mMinWidthSpinBox_valueChanged( double d );
+    void on_mMaxWidthSpinBox_valueChanged( double d );
 
   private slots:
     void setGuiElements();
diff --git a/src/app/qgisapp.cpp b/src/app/qgisapp.cpp
index 9633f54..d2826c1 100644
--- a/src/app/qgisapp.cpp
+++ b/src/app/qgisapp.cpp
@@ -5116,6 +5116,7 @@ void QgisApp::dxfExport()
     dxfExport.setSymbologyExport( d.symbologyMode() );
     dxfExport.setLayerTitleAsName( d.layerTitleAsName() );
     dxfExport.setDestinationCrs( d.crs() );
+    dxfExport.setForce2d( d.force2d() );
     if ( mapCanvas() )
     {
       dxfExport.setMapUnits( mapCanvas()->mapUnits() );
diff --git a/src/app/qgsdxfexportdialog.cpp b/src/app/qgsdxfexportdialog.cpp
index 4f6a873..4e434a3 100644
--- a/src/app/qgsdxfexportdialog.cpp
+++ b/src/app/qgsdxfexportdialog.cpp
@@ -52,7 +52,6 @@ QWidget *FieldSelectorDelegate::createEditor( QWidget *parent, const QStyleOptio
   if ( !vl )
     return nullptr;
 
-
   QgsFieldComboBox *w = new QgsFieldComboBox( parent );
   w->setLayer( vl );
   return w;
@@ -603,6 +602,11 @@ bool QgsDxfExportDialog::layerTitleAsName() const
   return mLayerTitleAsName->isChecked();
 }
 
+bool QgsDxfExportDialog::force2d() const
+{
+  return mForce2d->isChecked();
+}
+
 void QgsDxfExportDialog::saveSettings()
 {
   QSettings s;
diff --git a/src/app/qgsdxfexportdialog.h b/src/app/qgsdxfexportdialog.h
index 2b46677..a62838b 100644
--- a/src/app/qgsdxfexportdialog.h
+++ b/src/app/qgsdxfexportdialog.h
@@ -87,6 +87,7 @@ class QgsDxfExportDialog : public QDialog, private Ui::QgsDxfExportDialogBase
     QString saveFile() const;
     bool exportMapExtent() const;
     bool layerTitleAsName() const;
+    bool force2d() const;
     QString mapTheme() const;
     QString encoding() const;
     long crs() const;
diff --git a/src/core/composer/qgscomposermodel.cpp b/src/core/composer/qgscomposermodel.cpp
index 58ee49e..175dc38 100644
--- a/src/core/composer/qgscomposermodel.cpp
+++ b/src/core/composer/qgscomposermodel.cpp
@@ -961,29 +961,16 @@ QgsComposerProxyModel::QgsComposerProxyModel( QgsComposition *composition, QObje
   // WARNING: the below code triggers a Qt bug (tested on Qt 4.8, can't reproduce on Qt5) whenever the QgsComposerModel source model
   // calls beginInsertRows - since it's non functional anyway it's now disabled
   // PLEASE verify that the Qt issue is fixed before reenabling
+
+  setDynamicSortFilter( true );
 #if 0
   // TODO doesn't seem to work correctly - not updated when item changes
-  setDynamicSortFilter( true );
   setSortLocaleAware( true );
   sort( QgsComposerModel::ItemId );
 #endif
 }
 
-bool QgsComposerProxyModel::lessThan( const QModelIndex &left, const QModelIndex &right ) const
-{
-  //sort by item id
-  const QgsComposerItem* item1 = itemFromSourceIndex( left );
-  const QgsComposerItem* item2 = itemFromSourceIndex( right );
-  if ( !item1 )
-    return false;
-
-  if ( !item2 )
-    return true;
-
-  return QString::localeAwareCompare( item1->displayName(), item2->displayName() ) < 0;
-}
-
-QgsComposerItem* QgsComposerProxyModel::itemFromSourceIndex( const QModelIndex &sourceIndex ) const
+QgsComposerItem *QgsComposerProxyModel::itemFromSourceIndex( const QModelIndex &sourceIndex ) const
 {
   if ( !mComposition )
     return nullptr;
diff --git a/src/core/composer/qgscomposermodel.h b/src/core/composer/qgscomposermodel.h
index 9ead21d..42999b8 100644
--- a/src/core/composer/qgscomposermodel.h
+++ b/src/core/composer/qgscomposermodel.h
@@ -347,8 +347,7 @@ class CORE_EXPORT QgsComposerProxyModel: public QSortFilterProxyModel
     QgsComposerItem* itemFromSourceIndex( const QModelIndex& sourceIndex ) const;
 
   protected:
-    bool filterAcceptsRow( int source_row, const QModelIndex & source_parent ) const override;
-    bool lessThan( const QModelIndex &left, const QModelIndex &right ) const override;
+    bool filterAcceptsRow( int source_row, const QModelIndex &source_parent ) const override;
 
   private:
     QgsComposition* mComposition;
diff --git a/src/core/composer/qgscomposernodesitem.cpp b/src/core/composer/qgscomposernodesitem.cpp
index d303951..5d64a8b 100644
--- a/src/core/composer/qgscomposernodesitem.cpp
+++ b/src/core/composer/qgscomposernodesitem.cpp
@@ -202,6 +202,11 @@ void QgsComposerNodesItem::paint( QPainter* painter,
   if ( !painter )
     return;
 
+  if ( !shouldDrawItem() )
+  {
+    return;
+  }
+
   painter->save();
   painter->setPen( Qt::NoPen );
   painter->setBrush( Qt::NoBrush );
diff --git a/src/core/composer/qgscomposerscalebar.cpp b/src/core/composer/qgscomposerscalebar.cpp
index 10e180e..44b9252 100644
--- a/src/core/composer/qgscomposerscalebar.cpp
+++ b/src/core/composer/qgscomposerscalebar.cpp
@@ -757,8 +757,8 @@ bool QgsComposerScaleBar::readXML( const QDomElement& itemElem, const QDomDocume
   mNumSegmentsLeft = itemElem.attribute( "numSegmentsLeft", "0" ).toInt();
   mNumUnitsPerSegment = itemElem.attribute( "numUnitsPerSegment", "1.0" ).toDouble();
   mSegmentSizeMode = static_cast<SegmentSizeMode>( itemElem.attribute( "segmentSizeMode", "0" ).toInt() );
-  mMinBarWidth = itemElem.attribute( "minBarWidth", "50" ).toInt();
-  mMaxBarWidth = itemElem.attribute( "maxBarWidth", "150" ).toInt();
+  mMinBarWidth = itemElem.attribute( "minBarWidth", "50" ).toDouble();
+  mMaxBarWidth = itemElem.attribute( "maxBarWidth", "150" ).toDouble();
   mSegmentMillimeters = itemElem.attribute( "segmentMillimeters", "0.0" ).toDouble();
   mNumMapUnitsPerScaleBarUnit = itemElem.attribute( "numMapUnitsPerScaleBarUnit", "1.0" ).toDouble();
   mPen.setWidthF( itemElem.attribute( "outlineWidth", "0.3" ).toDouble() );
diff --git a/src/core/dxf/qgsdxfexport.cpp b/src/core/dxf/qgsdxfexport.cpp
index 8cfa66f..3d5d336 100644
--- a/src/core/dxf/qgsdxfexport.cpp
+++ b/src/core/dxf/qgsdxfexport.cpp
@@ -373,6 +373,7 @@ QgsDxfExport::QgsDxfExport()
     , mNextHandleId( DXF_HANDSEED )
     , mBlockCounter( 0 )
     , mCrs( -1 )
+    , mForce2d( false )
 {
 }
 
@@ -444,7 +445,7 @@ void QgsDxfExport::writeGroup( int code, const QgsPoint &p, double z, bool skipz
 {
   writeGroup( code + 10, p.x() );
   writeGroup( code + 20, p.y() );
-  if ( !skipz )
+  if ( !mForce2d && !skipz )
     writeGroup( code + 30, z );
 }
 
@@ -452,7 +453,7 @@ void QgsDxfExport::writeGroup( int code, const QgsPointV2 &p )
 {
   writeGroup( code + 10, p.x() );
   writeGroup( code + 20, p.y() );
-  if ( p.is3D() && qIsFinite( p.z() ) )
+  if ( !mForce2d && p.is3D() && qIsFinite( p.z() ) )
     writeGroup( code + 30, p.z() );
 }
 
@@ -3472,7 +3473,7 @@ void QgsDxfExport::writePolyline( const QgsPointSequenceV2 &line, const QString&
     return;
   }
 
-  if ( !line.at( 0 ).is3D() )
+  if ( mForce2d || !line.at( 0 ).is3D() )
   {
     writeGroup( 0, "LWPOLYLINE" );
     writeHandle();
diff --git a/src/core/dxf/qgsdxfexport.h b/src/core/dxf/qgsdxfexport.h
index 1811edf..3a212f7 100644
--- a/src/core/dxf/qgsdxfexport.h
+++ b/src/core/dxf/qgsdxfexport.h
@@ -154,6 +154,20 @@ class CORE_EXPORT QgsDxfExport
     bool layerTitleAsName() { return mLayerTitleAsName; }
 
     /**
+     * Force 2d output (eg. to support linewidth in polylines)
+     * \param force2d flag
+     * \see force2d
+     */
+    void setForce2d( bool force2d ) { mForce2d = force2d; }
+
+    /**
+     * Retrieve whether the output should be forced to 2d
+     * \returns flag
+     * \see setForce2d
+     */
+    bool force2d() { return mForce2d; }
+
+    /**
      * Get DXF palette index of nearest entry for given color
      * @param color
      */
@@ -465,6 +479,7 @@ class CORE_EXPORT QgsDxfExport
     QgsMapSettings mMapSettings;
     QHash<QString, int> mLayerNameAttribute;
     double mFactor;
+    bool mForce2d;
 };
 
 #endif // QGSDXFEXPORT_H
diff --git a/src/core/qgsvectorfilewriter.cpp b/src/core/qgsvectorfilewriter.cpp
index 1539a0b..6d4f866 100644
--- a/src/core/qgsvectorfilewriter.cpp
+++ b/src/core/qgsvectorfilewriter.cpp
@@ -1856,8 +1856,10 @@ QMap<QString, QgsVectorFileWriter::MetaData> QgsVectorFileWriter::initMetaData()
 
   layerOptions.insert( "OGR_XLSX_HEADERS", new SetOption(
                          QObject::tr( "By default, the driver will read the first lines of each sheet to detect "
-                                      "if the first line might be the name of columns. If set to FORCE, the "
-                                      "driver will consider the first default" ),
+                                      "if the first line might be the name of columns. If set to FORCE, the driver "
+                                      "will consider the first line will be taken as the header line. If set to "
+                                      "DISABLE, it will be considered as the first feature. Otherwise "
+                                      "auto-detection will occur." ),
                          QStringList()
                          << "FORCE"
                          << "DISABLE"
@@ -1894,8 +1896,10 @@ QMap<QString, QgsVectorFileWriter::MetaData> QgsVectorFileWriter::initMetaData()
 
   layerOptions.insert( "OGR_ODS_HEADERS", new SetOption(
                          QObject::tr( "By default, the driver will read the first lines of each sheet to detect "
-                                      "if the first line might be the name of columns. If set to FORCE, the "
-                                      "driver will consider the first default" ),
+                                      "if the first line might be the name of columns. If set to FORCE, the driver "
+                                      "will consider the first line will be taken as the header line. If set to "
+                                      "DISABLE, it will be considered as the first feature. Otherwise "
+                                      "auto-detection will occur." ),
                          QStringList()
                          << "FORCE"
                          << "DISABLE"
diff --git a/src/core/symbology-ng/qgsellipsesymbollayerv2.cpp b/src/core/symbology-ng/qgsellipsesymbollayerv2.cpp
index 70328d3..7e11e5a 100644
--- a/src/core/symbology-ng/qgsellipsesymbollayerv2.cpp
+++ b/src/core/symbology-ng/qgsellipsesymbollayerv2.cpp
@@ -490,6 +490,10 @@ QgsSymbolLayerV2* QgsEllipseSymbolLayerV2::createFromSld( QDomElement &element )
   if ( !QgsSymbolLayerV2Utils::wellKnownMarkerFromSld( graphicElem, name, fillColor, borderColor, borderStyle, borderWidth, size ) )
     return nullptr;
 
+  const QString uom = element.attribute( QString( "uom" ), "" );
+  size = QgsSymbolLayerV2Utils::sizeInPixelsFromSldUom( uom, size );
+  borderWidth = QgsSymbolLayerV2Utils::sizeInPixelsFromSldUom( uom, borderWidth );
+
   double angle = 0.0;
   QString angleFunc;
   if ( QgsSymbolLayerV2Utils::rotationFromSldElement( graphicElem, angleFunc ) )
@@ -501,6 +505,7 @@ QgsSymbolLayerV2* QgsEllipseSymbolLayerV2::createFromSld( QDomElement &element )
   }
 
   QgsEllipseSymbolLayerV2 *m = new QgsEllipseSymbolLayerV2();
+  m->setOutputUnit( QgsSymbolV2::Pixel );
   m->setSymbolName( name );
   m->setFillColor( fillColor );
   m->setOutlineColor( borderColor );
diff --git a/src/core/symbology-ng/qgsfillsymbollayerv2.cpp b/src/core/symbology-ng/qgsfillsymbollayerv2.cpp
index 7d9da12..5fd0745 100644
--- a/src/core/symbology-ng/qgsfillsymbollayerv2.cpp
+++ b/src/core/symbology-ng/qgsfillsymbollayerv2.cpp
@@ -390,7 +390,13 @@ QgsSymbolLayerV2* QgsSimpleFillSymbolLayerV2::createFromSld( QDomElement &elemen
   QPointF offset;
   QgsSymbolLayerV2Utils::displacementFromSldElement( element, offset );
 
+  QString uom = element.attribute( QString( "uom" ), "" );
+  offset.setX( QgsSymbolLayerV2Utils::sizeInPixelsFromSldUom( uom, offset.x() ) );
+  offset.setY( QgsSymbolLayerV2Utils::sizeInPixelsFromSldUom( uom, offset.y() ) );
+  borderWidth = QgsSymbolLayerV2Utils::sizeInPixelsFromSldUom( uom, borderWidth );
+
   QgsSimpleFillSymbolLayerV2* sl = new QgsSimpleFillSymbolLayerV2( color, fillStyle, borderColor, borderStyle, borderWidth );
+  sl->setOutputUnit( QgsSymbolV2::Pixel );
   sl->setOffset( offset );
   return sl;
 }
@@ -2159,6 +2165,10 @@ QgsSymbolLayerV2* QgsSVGFillSymbolLayer::createFromSld( QDomElement &element )
 
   QgsSymbolLayerV2Utils::lineFromSld( graphicElem, penStyle, borderColor, borderWidth );
 
+  QString uom = element.attribute( QString( "uom" ), "" );
+  size = QgsSymbolLayerV2Utils::sizeInPixelsFromSldUom( uom, size );
+  borderWidth = QgsSymbolLayerV2Utils::sizeInPixelsFromSldUom( uom, borderWidth );
+
   double angle = 0.0;
   QString angleFunc;
   if ( QgsSymbolLayerV2Utils::rotationFromSldElement( graphicElem, angleFunc ) )
@@ -2170,6 +2180,7 @@ QgsSymbolLayerV2* QgsSVGFillSymbolLayer::createFromSld( QDomElement &element )
   }
 
   QgsSVGFillSymbolLayer* sl = new QgsSVGFillSymbolLayer( path, size, angle );
+  sl->setOutputUnit( QgsSymbolV2::Pixel );
   sl->setSvgFillColor( fillColor );
   sl->setSvgOutlineColor( borderColor );
   sl->setSvgOutlineWidth( borderWidth );
@@ -3018,7 +3029,12 @@ QgsSymbolLayerV2* QgsLinePatternFillSymbolLayer::createFromSld( QDomElement &ele
     offset = sqrt( pow( vectOffset.x(), 2 ) + pow( vectOffset.y(), 2 ) );
   }
 
+  QString uom = element.attribute( QString( "uom" ), "" );
+  size = QgsSymbolLayerV2Utils::sizeInPixelsFromSldUom( uom, size );
+  lineWidth = QgsSymbolLayerV2Utils::sizeInPixelsFromSldUom( uom, lineWidth );
+
   QgsLinePatternFillSymbolLayer* sl = new QgsLinePatternFillSymbolLayer();
+  sl->setOutputUnit( QgsSymbolV2::Pixel );
   sl->setColor( lineColor );
   sl->setLineWidth( lineWidth );
   sl->setLineAngle( angle );
diff --git a/src/core/symbology-ng/qgslinesymbollayerv2.cpp b/src/core/symbology-ng/qgslinesymbollayerv2.cpp
index 0f56fd0..65bb09e 100644
--- a/src/core/symbology-ng/qgslinesymbollayerv2.cpp
+++ b/src/core/symbology-ng/qgslinesymbollayerv2.cpp
@@ -471,7 +471,12 @@ QgsSymbolLayerV2* QgsSimpleLineSymbolLayerV2::createFromSld( QDomElement &elemen
       offset = d;
   }
 
+  QString uom = element.attribute( QString( "uom" ), "" );
+  width = QgsSymbolLayerV2Utils::sizeInPixelsFromSldUom( uom, width );
+  offset = QgsSymbolLayerV2Utils::sizeInPixelsFromSldUom( uom, offset );
+
   QgsSimpleLineSymbolLayerV2* l = new QgsSimpleLineSymbolLayerV2( color, width, penStyle );
+  l->setOutputUnit( QgsSymbolV2::Pixel );
   l->setOffset( offset );
   l->setPenJoinStyle( penJoinStyle );
   l->setPenCapStyle( penCapStyle );
@@ -1551,7 +1556,12 @@ QgsSymbolLayerV2* QgsMarkerLineSymbolLayerV2::createFromSld( QDomElement &elemen
       offset = d;
   }
 
+  QString uom = element.attribute( QString( "uom" ), "" );
+  interval = QgsSymbolLayerV2Utils::sizeInPixelsFromSldUom( uom, interval );
+  offset = QgsSymbolLayerV2Utils::sizeInPixelsFromSldUom( uom, offset );
+
   QgsMarkerLineSymbolLayerV2* x = new QgsMarkerLineSymbolLayerV2( rotateMarker );
+  x->setOutputUnit( QgsSymbolV2::Pixel );
   x->setPlacement( placement );
   x->setInterval( interval );
   x->setSubSymbol( marker );
diff --git a/src/core/symbology-ng/qgsmarkersymbollayerv2.cpp b/src/core/symbology-ng/qgsmarkersymbollayerv2.cpp
index dc8b9bd..6dceec6 100644
--- a/src/core/symbology-ng/qgsmarkersymbollayerv2.cpp
+++ b/src/core/symbology-ng/qgsmarkersymbollayerv2.cpp
@@ -1239,7 +1239,13 @@ QgsSymbolLayerV2* QgsSimpleMarkerSymbolLayerV2::createFromSld( QDomElement &elem
 
   Shape shape = decodeShape( name );
 
+  QString uom = element.attribute( QString( "uom" ), "" );
+  size = QgsSymbolLayerV2Utils::sizeInPixelsFromSldUom( uom, size );
+  offset.setX( QgsSymbolLayerV2Utils::sizeInPixelsFromSldUom( uom, offset.x() ) );
+  offset.setY( QgsSymbolLayerV2Utils::sizeInPixelsFromSldUom( uom, offset.y() ) );
+
   QgsSimpleMarkerSymbolLayerV2 *m = new QgsSimpleMarkerSymbolLayerV2( shape, size );
+  m->setOutputUnit( QgsSymbolV2::Pixel );
   m->setColor( color );
   m->setBorderColor( borderColor );
   m->setAngle( angle );
@@ -2266,6 +2272,9 @@ QgsSymbolLayerV2* QgsSvgMarkerSymbolLayerV2::createFromSld( QDomElement &element
   if ( !QgsSymbolLayerV2Utils::externalGraphicFromSld( graphicElem, path, mimeType, fillColor, size ) )
     return nullptr;
 
+  QString uom = element.attribute( QString( "uom" ), "" );
+  size = QgsSymbolLayerV2Utils::sizeInPixelsFromSldUom( uom, size );
+
   if ( mimeType != "image/svg+xml" )
     return nullptr;
 
@@ -2283,6 +2292,7 @@ QgsSymbolLayerV2* QgsSvgMarkerSymbolLayerV2::createFromSld( QDomElement &element
   QgsSymbolLayerV2Utils::displacementFromSldElement( graphicElem, offset );
 
   QgsSvgMarkerSymbolLayerV2* m = new QgsSvgMarkerSymbolLayerV2( path, size );
+  m->setOutputUnit( QgsSymbolV2::Pixel );
   m->setFillColor( fillColor );
   //m->setOutlineColor( outlineColor );
   //m->setOutlineWidth( outlineWidth );
@@ -2945,7 +2955,13 @@ QgsSymbolLayerV2* QgsFontMarkerSymbolLayerV2::createFromSld( QDomElement &elemen
   QPointF offset;
   QgsSymbolLayerV2Utils::displacementFromSldElement( graphicElem, offset );
 
+  QString uom = element.attribute( QString( "uom" ), "" );
+  offset.setX( QgsSymbolLayerV2Utils::sizeInPixelsFromSldUom( uom, offset.x() ) );
+  offset.setY( QgsSymbolLayerV2Utils::sizeInPixelsFromSldUom( uom, offset.y() ) );
+  size = QgsSymbolLayerV2Utils::sizeInPixelsFromSldUom( uom, size );
+
   QgsMarkerSymbolLayerV2 *m = new QgsFontMarkerSymbolLayerV2( fontFamily, chr, size, color );
+  m->setOutputUnit( QgsSymbolV2::Pixel );
   m->setAngle( angle );
   m->setOffset( offset );
   return m;
diff --git a/src/core/symbology-ng/qgssymbollayerv2utils.cpp b/src/core/symbology-ng/qgssymbollayerv2utils.cpp
index 31b8d84..a2a4972 100644
--- a/src/core/symbology-ng/qgssymbollayerv2utils.cpp
+++ b/src/core/symbology-ng/qgssymbollayerv2utils.cpp
@@ -4231,3 +4231,23 @@ void QgsSymbolLayerV2Utils::mergeScaleDependencies( int mScaleMinDenom, int mSca
       props[ "scaleMaxDenom" ] = QString::number( qMin( parentScaleMaxDenom, mScaleMaxDenom ) );
   }
 }
+
+double QgsSymbolLayerV2Utils::sizeInPixelsFromSldUom( const QString &uom, double size )
+{
+  double scale = 1.0;
+
+  if ( uom == QLatin1String( "http://www.opengeospatial.org/se/units/metre" ) )
+  {
+    scale = 1.0 / 0.00028; // from meters to pixels
+  }
+  else if ( uom == QLatin1String( "http://www.opengeospatial.org/se/units/foot" ) )
+  {
+    scale = 304.8 / 0.28; // from feet to pixels
+  }
+  else
+  {
+    scale = 1.0; // from pixels to pixels (default unit)
+  }
+
+  return size * scale;
+}
diff --git a/src/core/symbology-ng/qgssymbollayerv2utils.h b/src/core/symbology-ng/qgssymbollayerv2utils.h
index e9e48cb..259a030 100644
--- a/src/core/symbology-ng/qgssymbollayerv2utils.h
+++ b/src/core/symbology-ng/qgssymbollayerv2utils.h
@@ -103,6 +103,14 @@ class CORE_EXPORT QgsSymbolLayerV2Utils
     static QString encodeScaleMethod( QgsSymbolV2::ScaleMethod scaleMethod );
     static QgsSymbolV2::ScaleMethod decodeScaleMethod( const QString& str );
 
+    /** Returns the size scaled in pixels according to the uom attribute.
+     * @param uom The uom attribute from SLD 1.1 version
+     * @param size The original size
+     * @returns the size in pixels
+     * @note added in QGIS 2.18 and 3.0
+     */
+    static double sizeInPixelsFromSldUom( const QString &uom, double size );
+
     static QPainter::CompositionMode decodeBlendMode( const QString& s );
 
     static QIcon symbolPreviewIcon( QgsSymbolV2* symbol, QSize size );
diff --git a/src/gui/editorwidgets/qgsrelationreferencewidget.cpp b/src/gui/editorwidgets/qgsrelationreferencewidget.cpp
index 0d91c98..8b3d3d9 100644
--- a/src/gui/editorwidgets/qgsrelationreferencewidget.cpp
+++ b/src/gui/editorwidgets/qgsrelationreferencewidget.cpp
@@ -191,10 +191,10 @@ void QgsRelationReferenceWidget::setRelation( const QgsRelation& relation, bool
     mReferencedFieldIdx = mReferencedLayer->fieldNameIndex( relation.fieldPairs().at( 0 ).second );
     mReferencingFieldIdx = mReferencingLayer->fieldNameIndex( relation.fieldPairs().at( 0 ).first );
 
-    QgsAttributeEditorContext context( mEditorContext, relation, QgsAttributeEditorContext::Single, QgsAttributeEditorContext::Embed );
 
     if ( mEmbedForm )
     {
+      QgsAttributeEditorContext context( mEditorContext, relation, QgsAttributeEditorContext::Single, QgsAttributeEditorContext::Embed );
       mAttributeEditorFrame->setTitle( mReferencedLayer->name() );
       mReferencedAttributeForm = new QgsAttributeForm( relation.referencedLayer(), QgsFeature(), context, this );
       mAttributeEditorLayout->addWidget( mReferencedAttributeForm );
@@ -276,6 +276,20 @@ void QgsRelationReferenceWidget::setForeignKey( const QVariant& value )
   }
   else
   {
+    QString nullValue = QSettings().value( "qgis/nullValue", "NULL" ).toString();
+
+    if ( mChainFilters && mFeature.isValid() && mFilterComboBoxes.count() >= mFilterFields.count() )
+    {
+      QgsFeature feature = mFeature;
+
+      for ( int i = 0; i < mFilterFields.size(); i++ )
+      {
+        QVariant v = feature.attribute( mFilterFields[i] );
+        QString f = v.isNull() ? nullValue : v.toString();
+        mFilterComboBoxes.at( i )->setCurrentIndex( mFilterComboBoxes.at( i )->findText( f ) );
+      }
+    }
+
     int i = mComboBox->findData( mFeature.id(), QgsAttributeTableModel::FeatureIdRole );
     if ( i == -1 && mAllowNull )
     {
@@ -464,6 +478,10 @@ void QgsRelationReferenceWidget::init()
       {
         QVariantList uniqueValues;
         int idx = mReferencedLayer->fieldNameIndex( fieldName );
+
+        if ( idx == -1 )
+          continue;
+
         QComboBox* cb = new QComboBox();
         cb->setProperty( "Field", fieldName );
         cb->setProperty( "FieldAlias", mReferencedLayer->attributeDisplayName( idx ) );
@@ -785,13 +803,41 @@ void QgsRelationReferenceWidget::filterChanged()
 {
   QVariant nullValue = QSettings().value( "qgis/nullValue", "NULL" );
 
-  QStringList filters;
+  QMap<QString, QString> filters;
   QgsAttributeList attrs;
 
   QComboBox* scb = qobject_cast<QComboBox*>( sender() );
 
   Q_ASSERT( scb );
 
+  QgsFeature f;
+  QgsFeatureIds featureIds;
+  QString filterExpression;
+
+  // comboboxes have to be disabled before building filters
+  if ( mChainFilters )
+    disableChainedComboBoxes( scb );
+
+  // build filters
+  Q_FOREACH ( QComboBox *cb, mFilterComboBoxes )
+  {
+    if ( cb->currentIndex() != 0 )
+    {
+      const QString fieldName = cb->property( "Field" ).toString();
+
+      if ( cb->currentText() == nullValue.toString() )
+      {
+        filters[fieldName] = QString( "\"%1\" IS NULL" ).arg( fieldName );
+      }
+      else
+      {
+        filters[fieldName] = QgsExpression::createFieldEqualityExpression( fieldName, cb->currentText() );
+      }
+      attrs << mReferencedLayer->fieldNameIndex( fieldName );
+    }
+  }
+
+  bool filtered = false;
   if ( mChainFilters )
   {
     QComboBox* ccb = nullptr;
@@ -805,13 +851,11 @@ void QgsRelationReferenceWidget::filterChanged()
         continue;
       }
 
-      if ( ccb->currentIndex() == 0 )
-      {
-        cb->setCurrentIndex( 0 );
-        cb->setEnabled( false );
-      }
-      else
+      if ( ccb->currentIndex() != 0 )
       {
+        const QString fieldName = cb->property( "Field" ).toString();
+        filtered = true;
+
         cb->blockSignals( true );
         cb->clear();
         cb->addItem( cb->property( "FieldAlias" ).toString() );
@@ -821,8 +865,30 @@ void QgsRelationReferenceWidget::filterChanged()
         QStringList texts;
         Q_FOREACH ( const QString& txt, mFilterCache[ccb->property( "Field" ).toString()][ccb->currentText()] )
         {
-          texts << txt;
+          QMap<QString, QString> filtersAttrs = filters;
+          filtersAttrs[fieldName] = QgsExpression::createFieldEqualityExpression( fieldName, txt );
+          QStringList vals = filtersAttrs.values();
+          QString expression = vals.join( QString( " AND " ) );
+
+          QgsAttributeList subset = attrs;
+          subset << mReferencedLayer->fieldNameIndex( fieldName );
+
+          QgsFeatureIterator it( mMasterModel->layerCache()->getFeatures( QgsFeatureRequest().setFilterExpression( expression ).setSubsetOfAttributes( subset ) ) );
+
+          bool found = false;
+          while ( it.nextFeature( f ) )
+          {
+            if ( !featureIds.contains( f.id() ) )
+              featureIds << f.id();
+
+            found = true;
+          }
+
+          // item is only provided if at least 1 feature exists
+          if ( found )
+            texts << txt;
         }
+
         texts.sort();
         cb->addItems( texts );
 
@@ -834,34 +900,21 @@ void QgsRelationReferenceWidget::filterChanged()
     }
   }
 
-  Q_FOREACH ( QComboBox* cb, mFilterComboBoxes )
+  if ( !mChainFilters || ( mChainFilters && !filtered ) )
   {
-    if ( cb->currentIndex() != 0 )
-    {
-      const QString fieldName = cb->property( "Field" ).toString();
+    QStringList vals = filters.values();
+    filterExpression = vals.join( QString( " AND " ) );
 
-      if ( cb->currentText() == nullValue.toString() )
-      {
-        filters << QString( "\"%1\" IS NULL" ).arg( fieldName );
-      }
-      else
-      {
-        filters << QgsExpression::createFieldEqualityExpression( fieldName, cb->currentText() );
-      }
-      attrs << mReferencedLayer->fieldNameIndex( fieldName );
-    }
-  }
-
-  QString filterExpression = filters.join( " AND " );
+    QgsFeatureRequest req = QgsFeatureRequest().setSubsetOfAttributes( attrs );
+    if ( !filterExpression.isEmpty() )
+      req.setFilterExpression( filterExpression );
 
-  QgsFeatureIterator it( mMasterModel->layerCache()->getFeatures( QgsFeatureRequest().setFilterExpression( filterExpression ).setSubsetOfAttributes( attrs ) ) );
-
-  QgsFeature f;
-  QgsFeatureIds featureIds;
+    QgsFeatureIterator it( mMasterModel->layerCache()->getFeatures( req ) );
 
-  while ( it.nextFeature( f ) )
-  {
-    featureIds << f.id();
+    while ( it.nextFeature( f ) )
+    {
+      featureIds << f.id();
+    }
   }
 
   mFilterModel->setFilteredFeatures( featureIds );
@@ -896,3 +949,28 @@ void QgsRelationReferenceWidget::updateAddEntryButton()
   mAddEntryButton->setVisible( mAllowAddFeatures );
   mAddEntryButton->setEnabled( mReferencedLayer && mReferencedLayer->isEditable() );
 }
+
+void QgsRelationReferenceWidget::disableChainedComboBoxes( const QComboBox *scb )
+{
+  QComboBox *ccb = nullptr;
+  Q_FOREACH ( QComboBox *cb, mFilterComboBoxes )
+  {
+    if ( !ccb )
+    {
+      if ( cb == scb )
+      {
+        ccb = cb;
+      }
+
+      continue;
+    }
+
+    cb->setCurrentIndex( 0 );
+    if ( ccb->currentIndex() == 0 )
+    {
+      cb->setEnabled( false );
+    }
+
+    ccb = cb;
+  }
+}
diff --git a/src/gui/editorwidgets/qgsrelationreferencewidget.h b/src/gui/editorwidgets/qgsrelationreferencewidget.h
index 4031c6d..0579612 100644
--- a/src/gui/editorwidgets/qgsrelationreferencewidget.h
+++ b/src/gui/editorwidgets/qgsrelationreferencewidget.h
@@ -162,6 +162,7 @@ class GUI_EXPORT QgsRelationReferenceWidget : public QWidget
   private:
     void highlightFeature( QgsFeature f = QgsFeature(), CanvasExtent canvasExtent = Fixed );
     void updateAttributeEditorFrame( const QgsFeature& feature );
+    void disableChainedComboBoxes( const QComboBox *scb );
 
     // initialized
     QgsAttributeEditorContext mEditorContext;
@@ -218,6 +219,8 @@ class GUI_EXPORT QgsRelationReferenceWidget : public QWidget
     QVBoxLayout* mAttributeEditorLayout;
     QLineEdit* mLineEdit;
     QLabel* mInvalidLabel;
+
+    friend class TestQgsRelationReferenceWidget;
 };
 
 #endif // QGSRELATIONREFERENCEWIDGET_H
diff --git a/src/gui/qgsadvanceddigitizingcanvasitem.cpp b/src/gui/qgsadvanceddigitizingcanvasitem.cpp
index c69b190..727fec9 100644
--- a/src/gui/qgsadvanceddigitizingcanvasitem.cpp
+++ b/src/gui/qgsadvanceddigitizingcanvasitem.cpp
@@ -42,7 +42,8 @@ void QgsAdvancedDigitizingCanvasItem::paint( QPainter* painter )
     return;
 
   QgsRectangle mapRect = mMapCanvas->extent();
-  setRect( mapRect );
+  if ( rect() != mapRect )
+    setRect( mapRect );
 
   int nPoints = mAdvancedDigitizingDockWidget->pointsCount();
   if ( !nPoints )
diff --git a/src/gui/qgsadvanceddigitizingdockwidget.cpp b/src/gui/qgsadvanceddigitizingdockwidget.cpp
index db0b986..fe3eef3 100644
--- a/src/gui/qgsadvanceddigitizingdockwidget.cpp
+++ b/src/gui/qgsadvanceddigitizingdockwidget.cpp
@@ -578,7 +578,7 @@ bool QgsAdvancedDigitizingDockWidget::applyConstraints( QgsMapMouseEvent* e )
     {
       point.setX( previousPt.x() + mXConstraint->value() );
     }
-    if ( !mSnappedSegment.isEmpty() && !mXConstraint->isLocked() )
+    if ( !mSnappedSegment.isEmpty() && !mYConstraint->isLocked() )
     {
       // intersect with snapped segment line at X ccordinate
       const double dx = mSnappedSegment.at( 1 ).x() - mSnappedSegment.at( 0 ).x();
@@ -605,7 +605,7 @@ bool QgsAdvancedDigitizingDockWidget::applyConstraints( QgsMapMouseEvent* e )
     {
       point.setY( previousPt.y() + mYConstraint->value() );
     }
-    if ( !mSnappedSegment.isEmpty() && !mYConstraint->isLocked() )
+    if ( !mSnappedSegment.isEmpty() && !mXConstraint->isLocked() )
     {
       // intersect with snapped segment line at Y ccordinate
       const double dy = mSnappedSegment.at( 1 ).y() - mSnappedSegment.at( 0 ).y();
diff --git a/src/gui/qgscomposeritemcombobox.cpp b/src/gui/qgscomposeritemcombobox.cpp
index b7c4acb..c28c849 100644
--- a/src/gui/qgscomposeritemcombobox.cpp
+++ b/src/gui/qgscomposeritemcombobox.cpp
@@ -36,7 +36,6 @@ void QgsComposerItemComboBox::setComposition( QgsComposition *composition )
   connect( mProxyModel, SIGNAL( rowsRemoved( QModelIndex, int, int ) ), this, SLOT( rowsChanged() ) );
   setModel( mProxyModel );
   setModelColumn( QgsComposerModel::ItemId );
-  mProxyModel->sort( 0, Qt::AscendingOrder );
 }
 
 void QgsComposerItemComboBox::setItem( const QgsComposerItem* item )
diff --git a/src/gui/qgsmapcanvastracer.cpp b/src/gui/qgsmapcanvastracer.cpp
index c4d5b3b..3469a58 100644
--- a/src/gui/qgsmapcanvastracer.cpp
+++ b/src/gui/qgsmapcanvastracer.cpp
@@ -24,16 +24,13 @@
 
 #include <QAction>
 
-QHash<QgsMapCanvas*, QgsMapCanvasTracer*> QgsMapCanvasTracer::sTracers;
-
-
 QgsMapCanvasTracer::QgsMapCanvasTracer( QgsMapCanvas* canvas, QgsMessageBar* messageBar )
     : mCanvas( canvas )
     , mMessageBar( messageBar )
     , mLastMessage( nullptr )
     , mActionEnableTracing( nullptr )
 {
-  sTracers.insert( canvas, this );
+  tracers().insert( mCanvas, this );
 
   // when things change we just invalidate the graph - and set up new parameters again only when necessary
   connect( canvas, SIGNAL( destinationCrsChanged() ), this, SLOT( invalidateGraph() ) );
@@ -49,12 +46,12 @@ QgsMapCanvasTracer::QgsMapCanvasTracer( QgsMapCanvas* canvas, QgsMessageBar* mes
 
 QgsMapCanvasTracer::~QgsMapCanvasTracer()
 {
-  sTracers.remove( mCanvas );
+  tracers().remove( mCanvas );
 }
 
 QgsMapCanvasTracer* QgsMapCanvasTracer::tracerForCanvas( QgsMapCanvas* canvas )
 {
-  return sTracers.value( canvas, 0 );
+  return tracers().value( canvas );
 }
 
 void QgsMapCanvasTracer::reportError( QgsTracer::PathError err, bool addingVertex )
@@ -137,3 +134,9 @@ void QgsMapCanvasTracer::onCurrentLayerChanged()
   if ( mCanvas->snappingUtils()->snapToMapMode() == QgsSnappingUtils::SnapCurrentLayer )
     invalidateGraph();
 }
+
+QHash<QgsMapCanvas*, QgsMapCanvasTracer*> &QgsMapCanvasTracer::tracers()
+{
+  static QHash<QgsMapCanvas*, QgsMapCanvasTracer*> sTracers;
+  return sTracers;
+}
diff --git a/src/gui/qgsmapcanvastracer.h b/src/gui/qgsmapcanvastracer.h
index 32f6d65..0d6fbae 100644
--- a/src/gui/qgsmapcanvastracer.h
+++ b/src/gui/qgsmapcanvastracer.h
@@ -67,13 +67,13 @@ class GUI_EXPORT QgsMapCanvasTracer : public QgsTracer
     void onCurrentLayerChanged();
 
   private:
+    static QHash<QgsMapCanvas*, QgsMapCanvasTracer*>& tracers();
+
     QgsMapCanvas* mCanvas;
     QgsMessageBar* mMessageBar;
     QgsMessageBarItem* mLastMessage;
 
     QAction* mActionEnableTracing;
-
-    static QHash<QgsMapCanvas*, QgsMapCanvasTracer*> sTracers;
 };
 
 #endif // QGSMAPCANVASTRACER_H
diff --git a/src/providers/ogr/qgsogrfeatureiterator.cpp b/src/providers/ogr/qgsogrfeatureiterator.cpp
index 754fe10..d4849bd 100644
--- a/src/providers/ogr/qgsogrfeatureiterator.cpp
+++ b/src/providers/ogr/qgsogrfeatureiterator.cpp
@@ -41,6 +41,7 @@ QgsOgrFeatureIterator::QgsOgrFeatureIterator( QgsOgrFeatureSource* source, bool
     , mConn( nullptr )
     , ogrLayer( nullptr )
     , mSubsetStringSet( false )
+    , mOrigFidAdded( false )
     , mFetchGeometry( false )
     , mExpressionCompiled( false )
     , mFilterFids( mRequest.filterFids() )
@@ -67,7 +68,7 @@ QgsOgrFeatureIterator::QgsOgrFeatureIterator( QgsOgrFeatureSource* source, bool
 
   if ( !mSource->mSubsetString.isEmpty() )
   {
-    ogrLayer = QgsOgrProviderUtils::setSubsetString( ogrLayer, mConn->ds, mSource->mEncoding, mSource->mSubsetString );
+    ogrLayer = QgsOgrProviderUtils::setSubsetString( ogrLayer, mConn->ds, mSource->mEncoding, mSource->mSubsetString, mOrigFidAdded );
     if ( !ogrLayer )
     {
       return;
@@ -171,7 +172,30 @@ bool QgsOgrFeatureIterator::nextFeatureFilterExpression( QgsFeature& f )
 bool QgsOgrFeatureIterator::fetchFeatureWithId( QgsFeatureId id, QgsFeature& feature ) const
 {
   feature.setValid( false );
-  OGRFeatureH fet = OGR_L_GetFeature( ogrLayer, FID_TO_NUMBER( id ) );
+  OGRFeatureH fet;
+  if ( mOrigFidAdded )
+  {
+    OGR_L_ResetReading( ogrLayer );
+    while (( fet = OGR_L_GetNextFeature( ogrLayer ) ) )
+    {
+      if (
+#if defined(GDAL_VERSION_NUM) && GDAL_VERSION_NUM >= 2000000
+        OGR_F_GetFieldAsInteger64
+#else
+        OGR_F_GetFieldAsInteger
+#endif
+        ( fet, 0 ) == FID_TO_NUMBER( id ) )
+      {
+        break;
+      }
+      OGR_F_Destroy( fet );
+    }
+  }
+  else
+  {
+    fet = OGR_L_GetFeature( ogrLayer, FID_TO_NUMBER( id ) );
+  }
+
   if ( !fet )
   {
     return false;
@@ -296,7 +320,18 @@ void QgsOgrFeatureIterator::getFeatureAttribute( OGRFeatureH ogrFet, QgsFeature
 
 bool QgsOgrFeatureIterator::readFeature( OGRFeatureH fet, QgsFeature& feature ) const
 {
-  feature.setFeatureId( OGR_F_GetFID( fet ) );
+  if ( mOrigFidAdded )
+  {
+#if defined(GDAL_VERSION_NUM) && GDAL_VERSION_NUM >= 2000000
+    feature.setFeatureId( OGR_F_GetFieldAsInteger64( fet, 0 ) );
+#else
+    feature.setFeatureId( OGR_F_GetFieldAsInteger( fet, 0 ) );
+#endif
+  }
+  else
+  {
+    feature.setFeatureId( OGR_F_GetFID( fet ) );
+  }
   feature.initAttributes( mSource->mFields.count() );
   feature.setFields( mSource->mFields ); // allow name-based attribute lookups
 
diff --git a/src/providers/ogr/qgsogrfeatureiterator.h b/src/providers/ogr/qgsogrfeatureiterator.h
index b06848b..606712a 100644
--- a/src/providers/ogr/qgsogrfeatureiterator.h
+++ b/src/providers/ogr/qgsogrfeatureiterator.h
@@ -78,6 +78,7 @@ class QgsOgrFeatureIterator : public QgsAbstractFeatureIteratorFromSource<QgsOgr
     OGRLayerH ogrLayer;
 
     bool mSubsetStringSet;
+    bool mOrigFidAdded;
 
     //! Set to true, if geometry is in the requested columns
     bool mFetchGeometry;
diff --git a/src/providers/ogr/qgsogrprovider.cpp b/src/providers/ogr/qgsogrprovider.cpp
index a09f1d6..f6c53b7 100644
--- a/src/providers/ogr/qgsogrprovider.cpp
+++ b/src/providers/ogr/qgsogrprovider.cpp
@@ -555,7 +555,12 @@ bool QgsOgrProvider::setSubsetString( const QString& theSQL, bool updateFeatureC
     uri += QString( "|geometrytype=%1" ).arg( ogrWkbGeometryTypeName( mOgrGeometryTypeFilter ) );
   }
 
-  setDataSourceUri( uri );
+  if ( uri != dataSourceUri() )
+  {
+    QgsOgrConnPool::instance()->unref( dataSourceUri() );
+    setDataSourceUri( uri );
+    QgsOgrConnPool::instance()->ref( dataSourceUri() );
+  }
 
   OGR_L_ResetReading( ogrLayer );
 
@@ -1661,6 +1666,7 @@ bool QgsOgrProvider::changeAttributeValues( const QgsChangedAttributesMap &attr_
       pushError( tr( "Feature %1 for attribute update not found." ).arg( fid ) );
       continue;
     }
+    OGR_L_ResetReading( ogrLayer ); // needed for SQLite-based to clear iterator
 
     QgsLocaleNumC l;
 
@@ -1803,6 +1809,7 @@ bool QgsOgrProvider::changeGeometryValues( const QgsGeometryMap &geometry_map )
       pushError( tr( "OGR error changing geometry: feature %1 not found" ).arg( it.key() ) );
       continue;
     }
+    OGR_L_ResetReading( ogrLayer ); // needed for SQLite-based to clear iterator
 
     OGRGeometryH theNewGeometry = nullptr;
     // We might receive null geometries. It is ok, but don't go through the
@@ -3414,14 +3421,17 @@ OGRwkbGeometryType QgsOgrProvider::ogrWkbSingleFlatten( OGRwkbGeometryType type
 
 OGRLayerH QgsOgrProvider::setSubsetString( OGRLayerH layer, OGRDataSourceH ds )
 {
-  return QgsOgrProviderUtils::setSubsetString( layer, ds, mEncoding, mSubsetString );
+  bool origFidAdded = false;
+  return QgsOgrProviderUtils::setSubsetString( layer, ds, mEncoding, mSubsetString, origFidAdded );
 }
 
-OGRLayerH QgsOgrProviderUtils::setSubsetString( OGRLayerH layer, OGRDataSourceH ds, QTextCodec* encoding, const QString& subsetString )
+OGRLayerH QgsOgrProviderUtils::setSubsetString( OGRLayerH layer, OGRDataSourceH ds, QTextCodec* encoding, const QString& subsetString, bool &origFidAdded )
 {
   QByteArray layerName = OGR_FD_GetName( OGR_L_GetLayerDefn( layer ) );
   OGRSFDriverH ogrDriver = OGR_DS_GetDriver( ds );
   QString ogrDriverName = OGR_Dr_GetName( ogrDriver );
+  bool origFidAddAttempted = false;
+  origFidAdded = false;
 
   if ( ogrDriverName == "ODBC" ) //the odbc driver does not like schema names for subset
   {
@@ -3438,12 +3448,33 @@ OGRLayerH QgsOgrProviderUtils::setSubsetString( OGRLayerH layer, OGRDataSourceH
     sql = encoding->fromUnicode( subsetString );
   else
   {
-    sql = "SELECT * FROM " + quotedIdentifier( layerName, ogrDriverName );
+    QByteArray fidColumn = OGR_L_GetFIDColumn( layer );
+
+    sql = QByteArray( "SELECT " );
+    if ( !fidColumn.isEmpty() )
+    {
+      sql += fidColumn + " as orig_ogc_fid, ";
+      origFidAddAttempted = true;
+    }
+    sql += "* FROM " + quotedIdentifier( layerName, ogrDriverName );
     sql += " WHERE " + encoding->fromUnicode( subsetString );
   }
 
   QgsDebugMsg( QString( "SQL: %1" ).arg( encoding->toUnicode( sql ) ) );
-  return OGR_DS_ExecuteSQL( ds, sql.constData(), nullptr, nullptr );
+  OGRLayerH subsetLayer = OGR_DS_ExecuteSQL( ds, sql.constData(), nullptr, nullptr );
+
+  // Check if first column is orig_ogc_fid
+  if ( origFidAddAttempted && subsetLayer )
+  {
+    OGRFeatureDefnH fdef = OGR_L_GetLayerDefn( subsetLayer );
+    if ( OGR_FD_GetFieldCount( fdef ) > 0 )
+    {
+      OGRFieldDefnH fldDef = OGR_FD_GetFieldDefn( fdef, 0 );
+      origFidAdded = qstrcmp( OGR_Fld_GetNameRef( fldDef ), "orig_ogc_fid" ) == 0;
+    }
+  }
+
+  return subsetLayer;
 }
 
 void QgsOgrProvider::open( OpenMode mode )
@@ -3543,7 +3574,13 @@ void QgsOgrProvider::open( OpenMode mode )
       // check that the initial encoding setting is fit for this layer
       setEncoding( encoding() );
 
-      mValid = setSubsetString( mSubsetString );
+      // Ensure subset is set (setSubsetString does nothing if the passed sql subset string is equal to mSubsetString, which is the case when reloading the dataset)
+      QString origSubsetString = mSubsetString;
+      mSubsetString = "";
+      // Block signals to avoid endless recusion reloadData -> emit dataChanged -> reloadData
+      blockSignals( true );
+      mValid = setSubsetString( origSubsetString );
+      blockSignals( false );
       if ( mValid )
       {
         if ( mode == OpenModeInitial )
diff --git a/src/providers/ogr/qgsogrprovider.h b/src/providers/ogr/qgsogrprovider.h
index ca99c4e..3c01afa 100644
--- a/src/providers/ogr/qgsogrprovider.h
+++ b/src/providers/ogr/qgsogrprovider.h
@@ -400,7 +400,7 @@ class QgsOgrProviderUtils
 {
   public:
     static void setRelevantFields( OGRLayerH ogrLayer, int fieldCount, bool fetchGeometry, const QgsAttributeList &fetchAttributes, bool firstAttrIsFid );
-    static OGRLayerH setSubsetString( OGRLayerH layer, OGRDataSourceH ds, QTextCodec* encoding, const QString& subsetString );
+    static OGRLayerH setSubsetString( OGRLayerH layer, OGRDataSourceH ds, QTextCodec* encoding, const QString& subsetString, bool &origFidAdded );
     static QByteArray quotedIdentifier( QByteArray field, const QString& ogrDriverName );
 
     /** Quote a value for placement in a SQL string.
diff --git a/src/server/qgswmsconfigparser.cpp b/src/server/qgswmsconfigparser.cpp
index 275588a..342f593 100644
--- a/src/server/qgswmsconfigparser.cpp
+++ b/src/server/qgswmsconfigparser.cpp
@@ -19,6 +19,8 @@
 #include "qgsmaplayer.h"
 #include "qgsmaplayerregistry.h"
 #include "qgsmapserviceexception.h"
+#include "qgslogger.h"
+#include "qgsmessagelog.h"
 
 #include "qgscomposerlabel.h"
 #include "qgscomposerlegend.h"
@@ -45,6 +47,73 @@ QgsWMSConfigParser::~QgsWMSConfigParser()
 
 }
 
+QStringList QgsWMSConfigParser::layerSet( const QStringList &layersList,
+    const QStringList &stylesList,
+    const QgsCoordinateReferenceSystem &destCRS, double scaleDenominator ) const
+{
+  Q_UNUSED( destCRS );
+  QStringList layerKeys;
+  QStringList::const_iterator llstIt;
+  QStringList::const_iterator slstIt;
+  QgsMapLayer* theMapLayer = nullptr;
+  QgsMessageLog::logMessage( QString( "Calculating layerset using %1 layers, %2 styles and CRS %3" ).arg( layersList.count() ).arg( stylesList.count() ).arg( destCRS.description() ) );
+  for ( llstIt = layersList.begin(), slstIt = stylesList.begin(); llstIt != layersList.end(); ++llstIt )
+  {
+    QString styleName;
+    if ( slstIt != stylesList.end() )
+    {
+      styleName = *slstIt;
+    }
+    QgsMessageLog::logMessage( "Trying to get layer " + *llstIt + "//" + styleName );
+
+    //does the layer name appear several times in the layer list?
+    //if yes, layer caching must be disabled because several named layers could have
+    //several user styles
+    bool allowCaching = true;
+    if ( layersList.count( *llstIt ) > 1 )
+    {
+      allowCaching = false;
+    }
+
+    QList<QgsMapLayer*> layerList = mapLayerFromStyle( *llstIt, styleName, allowCaching );
+    int listIndex;
+
+    for ( listIndex = layerList.size() - 1; listIndex >= 0; listIndex-- )
+    {
+      theMapLayer = layerList.at( listIndex );
+      if ( theMapLayer )
+      {
+        QString lName =  theMapLayer->name();
+        if ( useLayerIDs() )
+          lName = theMapLayer->id();
+        else if ( !theMapLayer->shortName().isEmpty() )
+          lName = theMapLayer->shortName();
+        QgsMessageLog::logMessage( QString( "Checking layer: %1" ).arg( lName ) );
+        //test if layer is visible in requested scale
+        bool useScaleConstraint = ( scaleDenominator > 0 && theMapLayer->hasScaleBasedVisibility() );
+        if ( !useScaleConstraint ||
+             ( theMapLayer->minimumScale() <= scaleDenominator && theMapLayer->maximumScale() >= scaleDenominator ) )
+        {
+          layerKeys.push_front( theMapLayer->id() );
+          QgsMapLayerRegistry::instance()->addMapLayers(
+            QList<QgsMapLayer *>() << theMapLayer, false, false );
+        }
+      }
+      else
+      {
+        QgsMessageLog::logMessage( "Layer or style not defined, aborting" );
+        throw QgsMapServiceException( "LayerNotDefined", "Layer '" + *llstIt + "' and/or style '" + styleName + "' not defined" );
+      }
+    }
+
+    if ( slstIt != stylesList.end() )
+    {
+      ++slstIt;
+    }
+  }
+  return layerKeys;
+}
+
 QgsComposition* QgsWMSConfigParser::createPrintComposition( const QString& composerTemplate, QgsMapRenderer* mapRenderer, const QMap< QString, QString >& parameterMap ) const
 {
   QStringList highlightLayers;
@@ -144,10 +213,11 @@ QgsComposition* QgsWMSConfigParser::createPrintComposition( const QString& compo
     }
 
     //layers / styles
-    QStringList layerSet;
+    QgsCoordinateReferenceSystem dummyCRS;
+    QStringList mapLayerSet;
     if ( currentMap->keepLayerSet() )
     {
-      layerSet = currentMap->layerSet();
+      mapLayerSet = currentMap->layerSet();
     }
     else
     {
@@ -169,6 +239,8 @@ QgsComposition* QgsWMSConfigParser::createPrintComposition( const QString& compo
         wmsStyleList = styles.split( "," );
       }
 
+      mapLayerSet = layerSet( wmsLayerList, wmsStyleList, dummyCRS );
+      /*
       for ( int i = 0; i < wmsLayerList.size(); ++i )
       {
         QString styleName;
@@ -185,15 +257,16 @@ QgsComposition* QgsWMSConfigParser::createPrintComposition( const QString& compo
           }
         }
       }
+      * */
     }
 
     //save layer list prior to adding highlight layers
-    QStringList bkLayerSet = layerSet;
+    QStringList bkLayerSet = mapLayerSet;
 
     //add highlight layers
-    highlightLayers.append( addHighlightLayers( parameterMap, layerSet, mapId + ":" ) );
+    highlightLayers.append( addHighlightLayers( parameterMap, mapLayerSet, mapId + ":" ) );
 
-    currentMap->setLayerSet( layerSet );
+    currentMap->setLayerSet( mapLayerSet );
     currentMap->setKeepLayerSet( true );
 
     //remove highlight layers from the composer legends
@@ -233,8 +306,8 @@ QgsComposition* QgsWMSConfigParser::createPrintComposition( const QString& compo
 
       // get model and layer tree root of the legend
       QgsLegendModelV2* model = currentLegend->modelV2();
-      QStringList layerSet = map->layerSet();
-      setLayerIdsToLegendModel( model, layerSet, map->scale() );
+      QStringList mapLayerSet = map->layerSet();
+      setLayerIdsToLegendModel( model, mapLayerSet, map->scale() );
     }
   }
 
diff --git a/src/server/qgswmsconfigparser.h b/src/server/qgswmsconfigparser.h
index 6846cce..e83bd09 100644
--- a/src/server/qgswmsconfigparser.h
+++ b/src/server/qgswmsconfigparser.h
@@ -46,6 +46,10 @@ class SERVER_EXPORT QgsWMSConfigParser
     /** Fills a layer and a style list. The two list have the same number of entries and the style and the layer at a position belong together (similar to the HTTP parameters 'Layers' and 'Styles'. Returns 0 in case of success*/
     virtual int layersAndStyles( QStringList& layers, QStringList& styles ) const = 0;
 
+    /** Creates a layer set and returns a stringlist with layer ids that can be passed to a QgsMapRenderer. Usually used in conjunction with readLayersAndStyles
+       @param scaleDenominator Filter out layer if scale based visibility does not match (or use -1 if no scale restriction)*/
+    QStringList layerSet( const QStringList& layersList, const QStringList& stylesList, const QgsCoordinateReferenceSystem& destCRS, double scaleDenominator = -1 ) const;
+
     /** Returns the xml fragment of a style*/
     virtual QDomDocument getStyle( const QString& styleName, const QString& layerName ) const = 0;
 
diff --git a/src/server/qgswmsserver.cpp b/src/server/qgswmsserver.cpp
index 1c5c8ca..2dc9194 100644
--- a/src/server/qgswmsserver.cpp
+++ b/src/server/qgswmsserver.cpp
@@ -779,7 +779,7 @@ QImage* QgsWMSServer::getLegendGraphics()
   }
 
   QgsCoordinateReferenceSystem dummyCRS;
-  QStringList layerIds = layerSet( layersList, stylesList, dummyCRS, scaleDenominator );
+  QStringList layerIds = mConfigParser->layerSet( layersList, stylesList, dummyCRS, scaleDenominator );
   if ( layerIds.size() < 1 )
   {
     return nullptr;
@@ -1690,7 +1690,7 @@ int QgsWMSServer::getFeatureInfo( QDomDocument& result, const QString& version )
   }
 
   //get the layer registered in QgsMapLayerRegistry and apply possible filters
-  ( void )layerSet( layersList, stylesList, mMapRenderer->destinationCrs() );
+  ( void )mConfigParser->layerSet( layersList, stylesList, mMapRenderer->destinationCrs() );
 
   //scoped pointer to restore all original layer filters (subsetStrings) when pointer goes out of scope
   //there's LOTS of potential exit paths here, so we avoid having to restore the filters manually
@@ -1967,7 +1967,7 @@ QImage* QgsWMSServer::initializeRendering( QStringList& layersList, QStringList&
   QgsRectangle mapExtent = mMapRenderer->extent();
   mConfigParser->setScaleDenominator( scaleCalc.calculate( mapExtent, theImage->width() ) );
 
-  layerIdList = layerSet( layersList, stylesList, mMapRenderer->destinationCrs() );
+  layerIdList = mConfigParser->layerSet( layersList, stylesList, mMapRenderer->destinationCrs() );
 #ifdef QGISDEBUG
   QgsMessageLog::logMessage( QString( "Number of layers to be rendered. %1" ).arg( layerIdList.count() ) );
 #endif
@@ -2547,19 +2547,23 @@ int QgsWMSServer::featureInfoFromRasterLayer( QgsRasterLayer* layer,
   {
     return 1;
   }
-  QMap<int, QVariant> attributes;
+  QgsRasterIdentifyResult identifyResult;
   // use context extent, width height (comes with request) to use WCS cache
   // We can only use context if raster is not reprojected, otherwise it is difficult
   // to guess correct source resolution
   if ( mMapRenderer->hasCrsTransformEnabled() && layer->dataProvider()->crs() != mMapRenderer->destinationCrs() )
   {
-    attributes = layer->dataProvider()->identify( *infoPoint, QgsRaster::IdentifyFormatValue ).results();
+    identifyResult = layer->dataProvider()->identify( *infoPoint, QgsRaster::IdentifyFormatValue );
   }
   else
   {
-    attributes = layer->dataProvider()->identify( *infoPoint, QgsRaster::IdentifyFormatValue, mMapRenderer->extent(), mMapRenderer->outputSize().width(), mMapRenderer->outputSize().height() ).results();
+    identifyResult = layer->dataProvider()->identify( *infoPoint, QgsRaster::IdentifyFormatValue, mMapRenderer->extent(), mMapRenderer->outputSize().width(), mMapRenderer->outputSize().height() );
   }
 
+  if ( !identifyResult.isValid() )
+    return 1;
+
+  QMap<int, QVariant> attributes = identifyResult.results();
   if ( infoFormat == "application/vnd.ogc.gml" )
   {
     QgsFeature feature;
@@ -2597,73 +2601,6 @@ int QgsWMSServer::featureInfoFromRasterLayer( QgsRasterLayer* layer,
   return 0;
 }
 
-QStringList QgsWMSServer::layerSet( const QStringList &layersList,
-                                    const QStringList &stylesList,
-                                    const QgsCoordinateReferenceSystem &destCRS, double scaleDenominator ) const
-{
-  Q_UNUSED( destCRS );
-  QStringList layerKeys;
-  QStringList::const_iterator llstIt;
-  QStringList::const_iterator slstIt;
-  QgsMapLayer* theMapLayer = nullptr;
-  QgsMessageLog::logMessage( QString( "Calculating layerset using %1 layers, %2 styles and CRS %3" ).arg( layersList.count() ).arg( stylesList.count() ).arg( destCRS.description() ) );
-  for ( llstIt = layersList.begin(), slstIt = stylesList.begin(); llstIt != layersList.end(); ++llstIt )
-  {
-    QString styleName;
-    if ( slstIt != stylesList.end() )
-    {
-      styleName = *slstIt;
-    }
-    QgsMessageLog::logMessage( "Trying to get layer " + *llstIt + "//" + styleName );
-
-    //does the layer name appear several times in the layer list?
-    //if yes, layer caching must be disabled because several named layers could have
-    //several user styles
-    bool allowCaching = true;
-    if ( layersList.count( *llstIt ) > 1 )
-    {
-      allowCaching = false;
-    }
-
-    QList<QgsMapLayer*> layerList = mConfigParser->mapLayerFromStyle( *llstIt, styleName, allowCaching );
-    int listIndex;
-
-    for ( listIndex = layerList.size() - 1; listIndex >= 0; listIndex-- )
-    {
-      theMapLayer = layerList.at( listIndex );
-      if ( theMapLayer )
-      {
-        QString lName =  theMapLayer->name();
-        if ( mConfigParser && mConfigParser->useLayerIDs() )
-          lName = theMapLayer->id();
-        else if ( !theMapLayer->shortName().isEmpty() )
-          lName = theMapLayer->shortName();
-        QgsMessageLog::logMessage( QString( "Checking layer: %1" ).arg( lName ) );
-        //test if layer is visible in requested scale
-        bool useScaleConstraint = ( scaleDenominator > 0 && theMapLayer->hasScaleBasedVisibility() );
-        if ( !useScaleConstraint ||
-             ( theMapLayer->minimumScale() <= scaleDenominator && theMapLayer->maximumScale() >= scaleDenominator ) )
-        {
-          layerKeys.push_front( theMapLayer->id() );
-          QgsMapLayerRegistry::instance()->addMapLayers(
-            QList<QgsMapLayer *>() << theMapLayer, false, false );
-        }
-      }
-      else
-      {
-        QgsMessageLog::logMessage( "Layer or style not defined, aborting" );
-        throw QgsMapServiceException( "LayerNotDefined", "Layer '" + *llstIt + "' and/or style '" + styleName + "' not defined" );
-      }
-    }
-
-    if ( slstIt != stylesList.end() )
-    {
-      ++slstIt;
-    }
-  }
-  return layerKeys;
-}
-
 
 void QgsWMSServer::applyRequestedLayerFilters( const QStringList& layerList , QHash<QgsMapLayer*, QString>& originalFilters ) const
 {
diff --git a/src/server/qgswmsserver.h b/src/server/qgswmsserver.h
index edc580b..62e909a 100644
--- a/src/server/qgswmsserver.h
+++ b/src/server/qgswmsserver.h
@@ -171,10 +171,6 @@ class QgsWMSServer: public QgsOWSServer
                                     const QString& version,
                                     const QString& infoFormat ) const;
 
-    /** Creates a layer set and returns a stringlist with layer ids that can be passed to a QgsMapRenderer. Usually used in conjunction with readLayersAndStyles
-       @param scaleDenominator Filter out layer if scale based visibility does not match (or use -1 if no scale restriction)*/
-    QStringList layerSet( const QStringList& layersList, const QStringList& stylesList, const QgsCoordinateReferenceSystem& destCRS, double scaleDenominator = -1 ) const;
-
     /** Record which symbols would be used if the map was in the current configuration of mMapRenderer. This is useful for content-based legend*/
     void runHitTest( QPainter* painter, HitTest& hitTest );
     /** Record which symbols within one layer would be rendered with the given renderer context*/
diff --git a/src/ui/composer/qgscomposerscalebarwidgetbase.ui b/src/ui/composer/qgscomposerscalebarwidgetbase.ui
index 2a44102..100f696 100644
--- a/src/ui/composer/qgscomposerscalebarwidgetbase.ui
+++ b/src/ui/composer/qgscomposerscalebarwidgetbase.ui
@@ -262,7 +262,7 @@
            </widget>
           </item>
           <item row="4" column="2">
-           <widget class="QgsSpinBox" name="mMaxWidthSpinBox">
+           <widget class="QgsDoubleSpinBox" name="mMaxWidthSpinBox">
             <property name="enabled">
              <bool>false</bool>
             </property>
@@ -288,7 +288,7 @@
            </widget>
           </item>
           <item row="3" column="2">
-           <widget class="QgsSpinBox" name="mMinWidthSpinBox">
+           <widget class="QgsDoubleSpinBox" name="mMinWidthSpinBox">
             <property name="enabled">
              <bool>false</bool>
             </property>
@@ -304,7 +304,7 @@
            </widget>
           </item>
           <item row="5" column="2">
-           <widget class="QgsSpinBox" name="mHeightSpinBox">
+           <widget class="QgsDoubleSpinBox" name="mHeightSpinBox">
             <property name="suffix">
              <string> mm</string>
             </property>
diff --git a/src/ui/qgsdxfexportdialogbase.ui b/src/ui/qgsdxfexportdialogbase.ui
index 119ffa1..1dbdd8e 100644
--- a/src/ui/qgsdxfexportdialogbase.ui
+++ b/src/ui/qgsdxfexportdialogbase.ui
@@ -14,6 +14,13 @@
    <string>DXF export</string>
   </property>
   <layout class="QGridLayout" name="gridLayout_2">
+   <item row="2" column="0">
+    <widget class="QLabel" name="mSymbologyScaleLabel">
+     <property name="text">
+      <string>Symbology scale</string>
+     </property>
+    </widget>
+   </item>
    <item row="0" column="2">
     <widget class="QToolButton" name="mFileSelectionButton">
      <property name="text">
@@ -54,13 +61,6 @@
      </property>
     </widget>
    </item>
-   <item row="2" column="0">
-    <widget class="QLabel" name="mSymbologyScaleLabel">
-     <property name="text">
-      <string>Symbology scale</string>
-     </property>
-    </widget>
-   </item>
    <item row="7" column="0" colspan="3">
     <widget class="QgsLayerTreeView" name="mTreeView">
      <property name="selectionMode">
@@ -122,7 +122,7 @@
      </property>
     </widget>
    </item>
-   <item row="12" column="0" colspan="3">
+   <item row="13" column="0" colspan="3">
     <widget class="QDialogButtonBox" name="buttonBox">
      <property name="orientation">
       <enum>Qt::Horizontal</enum>
@@ -170,6 +170,13 @@
      </property>
     </widget>
    </item>
+   <item row="12" column="0" colspan="3">
+    <widget class="QCheckBox" name="mForce2d">
+     <property name="text">
+      <string>Force 2d output (eg. to support polyline width)</string>
+     </property>
+    </widget>
+   </item>
   </layout>
  </widget>
  <customwidgets>
@@ -195,12 +202,14 @@
   <tabstop>mFileSelectionButton</tabstop>
   <tabstop>mSymbologyModeComboBox</tabstop>
   <tabstop>mEncoding</tabstop>
+  <tabstop>mScaleWidget</tabstop>
   <tabstop>mVisibilityPresets</tabstop>
   <tabstop>mTreeView</tabstop>
   <tabstop>mSelectAllButton</tabstop>
   <tabstop>mUnSelectAllButton</tabstop>
   <tabstop>mLayerTitleAsName</tabstop>
   <tabstop>mMapExtentCheckBox</tabstop>
+  <tabstop>mForce2d</tabstop>
   <tabstop>buttonBox</tabstop>
  </tabstops>
  <resources/>
diff --git a/tests/src/gui/CMakeLists.txt b/tests/src/gui/CMakeLists.txt
index 9e5ac2f..bcaf2c7 100644
--- a/tests/src/gui/CMakeLists.txt
+++ b/tests/src/gui/CMakeLists.txt
@@ -14,6 +14,7 @@ INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}
   ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/gui/editorwidgets/core
   ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/gui/symbology-ng
   ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/gui/raster
+  ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/gui/attributetable
   ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/core
   ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/core/auth
   ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/core/composer
@@ -145,3 +146,4 @@ ADD_QGIS_TEST(sqlcomposerdialog testqgssqlcomposerdialog.cpp)
 ADD_QGIS_TEST(filedownloader testqgsfiledownloader.cpp)
 ADD_QGIS_TEST(composergui testqgscomposergui.cpp)
 ADD_QGIS_TEST(valuerelationwidgetwrapper testqgsvaluerelationwidgetwrapper.cpp)
+ADD_QGIS_TEST(relationreferencewidget testqgsrelationreferencewidget.cpp)
diff --git a/tests/src/gui/testqgsrelationreferencewidget.cpp b/tests/src/gui/testqgsrelationreferencewidget.cpp
new file mode 100644
index 0000000..9404e00
--- /dev/null
+++ b/tests/src/gui/testqgsrelationreferencewidget.cpp
@@ -0,0 +1,224 @@
+/***************************************************************************
+    testqgsrelationreferencewidget.cpp
+     --------------------------------------
+    Date                 : 21 07 2017
+    Copyright            : (C) 2017 Paul Blottiere
+    Email                : paul dot blottiere at oslandia 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 <QtTest/QtTest>
+#include <editorwidgets/core/qgseditorwidgetregistry.h>
+#include <qgsapplication.h>
+#include "qgseditorwidgetwrapper.h"
+#include <qgsmaplayerregistry.h>
+#include <editorwidgets/qgsrelationreferencewidget.h>
+#include <qgsproject.h>
+#include <qgsattributeform.h>
+#include <qgsrelationmanager.h>
+#include <attributetable/qgsattributetablefiltermodel.h>
+
+class TestQgsRelationReferenceWidget : public QObject
+{
+    Q_OBJECT
+  public:
+    TestQgsRelationReferenceWidget() {}
+
+  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.
+
+    void testChainFilter();
+    void testChainFilterRefreshed();
+
+  private:
+    QgsVectorLayer* mLayer1;
+    QgsVectorLayer* mLayer2;
+    std::unique_ptr<QgsRelation> mRelation;
+};
+
+void TestQgsRelationReferenceWidget::initTestCase()
+{
+  QgsApplication::init();
+  QgsApplication::initQgis();
+  QgsEditorWidgetRegistry::initEditors();
+}
+
+void TestQgsRelationReferenceWidget::cleanupTestCase()
+{
+  QgsApplication::exitQgis();
+}
+
+void TestQgsRelationReferenceWidget::init()
+{
+  // create layer
+  mLayer1 = new QgsVectorLayer( QString( "LineString?crs=epsg:3111&field=pk:int&field=fk:int" ), QString( "vl1" ), QString( "memory" ) );
+  QgsMapLayerRegistry::instance()->addMapLayer( mLayer1 );
+
+  mLayer2 = new QgsVectorLayer( QString( "LineString?field=pk:int&field=material:string&field=diameter:int&field=raccord:string" ), QString( "vl2" ), QString( "memory" ) );
+  QgsMapLayerRegistry::instance()->addMapLayer( mLayer2 );
+
+  // create relation
+  mRelation.reset( new QgsRelation() );
+  mRelation->setRelationId( QString( "vl1.vl2" ) );
+  mRelation->setRelationName( QString( "vl1.vl2" ) );
+  mRelation->setReferencingLayer( mLayer1->id() );
+  mRelation->setReferencedLayer( mLayer2->id() );
+  mRelation->addFieldPair( "fk", "pk" );
+  QVERIFY( mRelation->isValid() );
+  QgsProject::instance()->relationManager()->addRelation( *mRelation.get() );
+
+  // add features
+  QgsFeature ft0( mLayer1->fields() );
+  ft0.setAttribute( QString( "pk" ), 0 );
+  ft0.setAttribute( QString( "fk" ), 0 );
+  mLayer1->startEditing();
+  mLayer1->addFeature( ft0 );
+  mLayer1->commitChanges();
+
+  QgsFeature ft1( mLayer1->fields() );
+  ft1.setAttribute( QString( "pk" ), 1 );
+  ft1.setAttribute( QString( "fk" ), 1 );
+  mLayer1->startEditing();
+  mLayer1->addFeature( ft1 );
+  mLayer1->commitChanges();
+
+  QgsFeature ft2( mLayer2->fields() );
+  ft2.setAttribute( QString( "pk" ), 10 );
+  ft2.setAttribute( QString( "material" ), "iron" );
+  ft2.setAttribute( QString( "diameter" ), 120 );
+  ft2.setAttribute( QString( "raccord" ), "brides" );
+  mLayer2->startEditing();
+  mLayer2->addFeature( ft2 );
+  mLayer2->commitChanges();
+
+  QgsFeature ft3( mLayer2->fields() );
+  ft3.setAttribute( QString( "pk" ), 11 );
+  ft3.setAttribute( QString( "material" ), "iron" );
+  ft3.setAttribute( QString( "diameter" ), 120 );
+  ft3.setAttribute( QString( "raccord" ), "sleeve" );
+  mLayer2->startEditing();
+  mLayer2->addFeature( ft3 );
+  mLayer2->commitChanges();
+
+  QgsFeature ft4( mLayer2->fields() );
+  ft4.setAttribute( QString( "pk" ), 12 );
+  ft4.setAttribute( QString( "material" ), "steel" );
+  ft4.setAttribute( QString( "diameter" ), 120 );
+  ft4.setAttribute( QString( "raccord" ), "collar" );
+  mLayer2->startEditing();
+  mLayer2->addFeature( ft4 );
+  mLayer2->commitChanges();
+}
+
+void TestQgsRelationReferenceWidget::cleanup()
+{
+}
+
+void TestQgsRelationReferenceWidget::testChainFilter()
+{
+  // init a relation reference widget
+  QStringList filterFields = QStringList() << "material" << "diameter" << "raccord";
+
+  QgsRelationReferenceWidget w( new QWidget() );
+  w.setChainFilters( true );
+  w.setFilterFields( filterFields );
+  w.setRelation( *mRelation, true );
+  w.init();
+
+  // check default status for comboboxes
+  QList<QComboBox *> cbs = w.mFilterComboBoxes;
+  QCOMPARE( cbs.count(), 3 );
+  Q_FOREACH ( const QComboBox *cb, cbs )
+  {
+    if ( cb->currentText() == "raccord" )
+      QCOMPARE( cb->count(), 5 );
+    else if ( cb->currentText() == "material" )
+      QCOMPARE( cb->count(), 4 );
+    else if ( cb->currentText() == "diameter" )
+      QCOMPARE( cb->count(), 3 );
+  }
+
+  // set first filter
+  cbs[0]->setCurrentIndex( cbs[0]->findText( "iron" ) );
+  cbs[1]->setCurrentIndex( cbs[1]->findText( "120" ) );
+
+  Q_FOREACH ( const QComboBox *cb, cbs )
+  {
+    if ( cb->itemText( 0 ) == "material" )
+      QCOMPARE( cb->count(), 4 );
+    else if ( cb->itemText( 0 ) == "diameter" )
+      QCOMPARE( cb->count(), 2 );
+    else if ( cb->itemText( 0 ) == "raccord" )
+    {
+      QStringList items;
+      for ( int i = 0; i < cb->count(); i++ )
+        items << cb->itemText( i );
+
+      QCOMPARE( cb->count(), 3 );
+      QCOMPARE(( bool )items.contains( "collar" ), false );
+      // collar should not be available in combobox as there's no existing
+      // feature with the filter expression:
+      // "material" ==  'iron' AND "diameter" == '120' AND "raccord" = 'collar'
+    }
+  }
+
+  // set the filter for "raccord" and then reset filter for "diameter". As
+  // chain filter is activated, the filter on "raccord" field should be reset
+  cbs[2]->setCurrentIndex( cbs[2]->findText( "brides" ) );
+  cbs[1]->setCurrentIndex( cbs[1]->findText( "diameter" ) );
+
+  // combobox should propose NULL, 10 and 11 because the filter is now:
+  // "material" == 'iron'
+  QCOMPARE( w.mComboBox->count(), 3 );
+
+  // if there's no filter at all, all features' id should be proposed
+  cbs[0]->setCurrentIndex( cbs[0]->findText( "material" ) );
+  QCOMPARE( w.mComboBox->count(), 4 );
+}
+
+void TestQgsRelationReferenceWidget::testChainFilterRefreshed()
+{
+  // init a relation reference widget
+  QStringList filterFields = QStringList() << "material" << "diameter" << "raccord";
+
+  QgsRelationReferenceWidget w( new QWidget() );
+  w.setChainFilters( true );
+  w.setFilterFields( filterFields );
+  w.setRelation( *mRelation, true );
+  w.init();
+
+  // check default status for comboboxes
+  QList<QComboBox *> cbs = w.mFilterComboBoxes;
+  QCOMPARE( cbs.count(), 3 );
+  QCOMPARE( cbs[0]->currentText(), QString( "material" ) );
+  QCOMPARE( cbs[1]->currentText(), QString( "diameter" ) );
+  QCOMPARE( cbs[2]->currentText(), QString( "raccord" ) );
+
+  // update foreign key
+  w.setForeignKey( QVariant( 12 ) );
+  QCOMPARE( cbs[0]->currentText(), QString( "steel" ) );
+  QCOMPARE( cbs[1]->currentText(), QString( "120" ) );
+  QCOMPARE( cbs[2]->currentText(), QString( "collar" ) );
+
+  w.setForeignKey( QVariant( 10 ) );
+  QCOMPARE( cbs[0]->currentText(), QString( "iron" ) );
+  QCOMPARE( cbs[1]->currentText(), QString( "120" ) );
+  QCOMPARE( cbs[2]->currentText(), QString( "brides" ) );
+
+  w.setForeignKey( QVariant( 11 ) );
+  QCOMPARE( cbs[0]->currentText(), QString( "iron" ) );
+  QCOMPARE( cbs[1]->currentText(), QString( "120" ) );
+  QCOMPARE( cbs[2]->currentText(), QString( "sleeve" ) );
+}
+
+QTEST_MAIN( TestQgsRelationReferenceWidget )
+#include "testqgsrelationreferencewidget.moc"
diff --git a/tests/src/python/test_provider_ogr_gpkg.py b/tests/src/python/test_provider_ogr_gpkg.py
index a45fa6f..04e8d84 100644
--- a/tests/src/python/test_provider_ogr_gpkg.py
+++ b/tests/src/python/test_provider_ogr_gpkg.py
@@ -324,6 +324,68 @@ class TestPyQgsOGRProviderGpkg(unittest.TestCase):
         self.assertEqual(f['f1'], 3)
         features = None
 
+    def testGeopackageTwoLayerEdition(self):
+        ''' test https://issues.qgis.org/issues/17034 '''
+        tmpfile = os.path.join(self.basetestpath, 'testGeopackageTwoLayerEdition.gpkg')
+        ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile)
+        lyr = ds.CreateLayer('layer1', geom_type=ogr.wkbPoint)
+        lyr.CreateField(ogr.FieldDefn('attr', ogr.OFTInteger))
+        f = ogr.Feature(lyr.GetLayerDefn())
+        f.SetGeometry(ogr.CreateGeometryFromWkt('POINT(0 0)'))
+        lyr.CreateFeature(f)
+        f = None
+        lyr = ds.CreateLayer('layer2', geom_type=ogr.wkbPoint)
+        lyr.CreateField(ogr.FieldDefn('attr', ogr.OFTInteger))
+        f = ogr.Feature(lyr.GetLayerDefn())
+        f.SetGeometry(ogr.CreateGeometryFromWkt('POINT(1 1)'))
+        lyr.CreateFeature(f)
+        f = None
+        ds = None
+
+        vl1 = QgsVectorLayer(u'{}'.format(tmpfile) + "|layername=layer1", u'layer1', u'ogr')
+        vl2 = QgsVectorLayer(u'{}'.format(tmpfile) + "|layername=layer2", u'layer2', u'ogr')
+
+        # Edit vl1, vl2 multiple times
+        self.assertTrue(vl1.startEditing())
+        self.assertTrue(vl2.startEditing())
+        self.assertTrue(vl1.changeGeometry(1, QgsGeometry.fromWkt('Point (2 2)')))
+        self.assertTrue(vl2.changeGeometry(1, QgsGeometry.fromWkt('Point (3 3)')))
+        self.assertTrue(vl1.commitChanges())
+        self.assertTrue(vl2.commitChanges())
+
+        self.assertTrue(vl1.startEditing())
+        self.assertTrue(vl2.startEditing())
+        self.assertTrue(vl1.changeAttributeValue(1, 1, 100))
+        self.assertTrue(vl2.changeAttributeValue(1, 1, 101))
+        self.assertTrue(vl1.commitChanges())
+        self.assertTrue(vl2.commitChanges())
+
+        self.assertTrue(vl1.startEditing())
+        self.assertTrue(vl2.startEditing())
+        self.assertTrue(vl1.changeGeometry(1, QgsGeometry.fromWkt('Point (4 4)')))
+        self.assertTrue(vl2.changeGeometry(1, QgsGeometry.fromWkt('Point (5 5)')))
+        self.assertTrue(vl1.commitChanges())
+        self.assertTrue(vl2.commitChanges())
+
+        vl1 = None
+        vl2 = None
+
+        # Check everything is as expected after re-opening
+        vl1 = QgsVectorLayer(u'{}'.format(tmpfile) + "|layername=layer1", u'layer1', u'ogr')
+        vl2 = QgsVectorLayer(u'{}'.format(tmpfile) + "|layername=layer2", u'layer2', u'ogr')
+
+        got = [feat for feat in vl1.getFeatures()][0]
+        got_geom = got.geometry()
+        self.assertEqual(got['attr'], 100)
+        reference = QgsGeometry.fromWkt('Point (4 4)')
+        self.assertEqual(got_geom.asWkb(), reference.asWkb(), 'Expected {}, got {}'.format(reference.exportToWkt(), got_geom.exportToWkt()))
+
+        got = [feat for feat in vl2.getFeatures()][0]
+        got_geom = got.geometry()
+        self.assertEqual(got['attr'], 101)
+        reference = QgsGeometry.fromWkt('Point (5 5)')
+        self.assertEqual(got_geom.asWkb(), reference.asWkb(), 'Expected {}, got {}'.format(reference.exportToWkt(), got_geom.exportToWkt()))
+
 
 if __name__ == '__main__':
     unittest.main()
diff --git a/tests/src/python/test_provider_ogr_sqlite.py b/tests/src/python/test_provider_ogr_sqlite.py
index b87225d..47e80ee 100644
--- a/tests/src/python/test_provider_ogr_sqlite.py
+++ b/tests/src/python/test_provider_ogr_sqlite.py
@@ -129,6 +129,65 @@ class TestPyQgsOGRProviderSqlite(unittest.TestCase):
         got = [(f.attribute('fid'), f.attribute('intfield')) for f in vl.dataProvider().getFeatures(QgsFeatureRequest().setFilterExpression("fid = 12"))]
         self.assertEqual(got, [(12, 123)])
 
+    def testSubsetStringFids(self):
+        """
+          - tests that feature ids are stable even if a subset string is set
+          - tests that the subset string is correctly set on the ogr layer event when reloading the data source (issue #17122)
+        """
+
+        tmpfile = os.path.join(self.basetestpath, 'subsetStringFids.sqlite')
+        ds = ogr.GetDriverByName('SQLite').CreateDataSource(tmpfile)
+        lyr = ds.CreateLayer('test', geom_type=ogr.wkbPoint, options=['FID=fid'])
+        lyr.CreateField(ogr.FieldDefn('type', ogr.OFTInteger))
+        lyr.CreateField(ogr.FieldDefn('value', ogr.OFTInteger))
+        f = ogr.Feature(lyr.GetLayerDefn())
+        f.SetFID(0)
+        f.SetField(0, 1)
+        f.SetField(1, 11)
+        lyr.CreateFeature(f)
+        f = ogr.Feature(lyr.GetLayerDefn())
+        f.SetFID(1)
+        f.SetField(0, 1)
+        f.SetField(1, 12)
+        lyr.CreateFeature(f)
+        f = ogr.Feature(lyr.GetLayerDefn())
+        f.SetFID(2)
+        f.SetField(0, 1)
+        f.SetField(1, 13)
+        lyr.CreateFeature(f)
+        f = ogr.Feature(lyr.GetLayerDefn())
+        f.SetFID(3)
+        f.SetField(0, 2)
+        f.SetField(1, 14)
+        lyr.CreateFeature(f)
+        f = ogr.Feature(lyr.GetLayerDefn())
+        f.SetFID(4)
+        f.SetField(0, 2)
+        f.SetField(1, 15)
+        lyr.CreateFeature(f)
+        f = ogr.Feature(lyr.GetLayerDefn())
+        f.SetFID(5)
+        f.SetField(0, 2)
+        f.SetField(1, 16)
+        lyr.CreateFeature(f)
+        f = None
+        ds = None
+
+        vl = QgsVectorLayer(tmpfile + "|subset=type=2", 'test', 'ogr')
+        self.assertTrue(vl.isValid())
+        self.assertTrue(vl.fields().at(0).name() == "orig_ogc_fid")
+
+        req = QgsFeatureRequest()
+        req.setFilterExpression("value=16")
+        it = vl.getFeatures(req)
+        f = QgsFeature()
+        self.assertTrue(it.nextFeature(f))
+        self.assertTrue(f.id() == 5)
+
+        # Check that subset string is correctly set on reload
+        vl.reload()
+        self.assertTrue(vl.fields().at(0).name() == "orig_ogc_fid")
+
 
 if __name__ == '__main__':
     unittest.main()
diff --git a/tests/src/python/test_qgsexpression.py b/tests/src/python/test_qgsexpression.py
index 7cb662f..69d2e1f 100644
--- a/tests/src/python/test_qgsexpression.py
+++ b/tests/src/python/test_qgsexpression.py
@@ -42,6 +42,18 @@ class TestQgsExpressionCustomFunctions(unittest.TestCase):
     def sqrt(values, feature, parent):
         pass
 
+    @qgsfunction(1, 'testing', register=False)
+    def help_with_docstring(values, feature, parent):
+        """The help comes from the python docstring."""
+        pass
+
+    help_text = 'The help comes from a variable.'
+
+    @qgsfunction(1, 'testing', register=False, help_text=help_text)
+    def help_with_variable(values, feature, parent):
+        """This docstring is not used for the help."""
+        pass
+
     @qgsfunction(1, 'testing', register=False, usesgeometry=True)
     def geomtest(values, feature, parent):
         pass
@@ -67,6 +79,17 @@ class TestQgsExpressionCustomFunctions(unittest.TestCase):
         args = function.params()
         self.assertEqual(args, 3)
 
+    def testHelp(self):
+        QgsExpression.registerFunction(self.help_with_variable)
+        html = ('<h3>help_with_variable function</h3><br>'
+                'The help comes from a variable.')
+        self.assertEqual(self.help_with_variable.helptext(), html)
+
+        QgsExpression.registerFunction(self.help_with_docstring)
+        html = ('<h3>help_with_docstring function</h3><br>'
+                'The help comes from the python docstring.')
+        self.assertEqual(self.help_with_docstring.helptext(), html)
+
     def testAutoArgsAreExpanded(self):
         function = self.expandargs
         args = function.params()
diff --git a/tests/src/python/test_qgssymbollayerv2_readsld.py b/tests/src/python/test_qgssymbollayerv2_readsld.py
index 201ceef..deea842 100644
--- a/tests/src/python/test_qgssymbollayerv2_readsld.py
+++ b/tests/src/python/test_qgssymbollayerv2_readsld.py
@@ -26,11 +26,24 @@ __revision__ = '$Format:%H$'
 import qgis  # NOQA
 
 import os
+from qgis.PyQt.QtXml import QDomDocument
 from qgis.testing import start_app, unittest
 from qgis.core import (QgsVectorLayer,
                        QgsFeature,
                        QgsGeometry,
-                       QgsPoint
+                       QgsPoint,
+                       QgsUnitTypes,
+                       QgsPoint,
+                       QgsSvgMarkerSymbolLayerV2,
+                       QgsEllipseSymbolLayerV2,
+                       QgsSimpleFillSymbolLayerV2,
+                       QgsSVGFillSymbolLayer,
+                       QgsLinePatternFillSymbolLayer,
+                       QgsSimpleLineSymbolLayerV2,
+                       QgsMarkerLineSymbolLayerV2,
+                       QgsSimpleMarkerSymbolLayerV2,
+                       QgsFontMarkerSymbolLayerV2,
+                       QgsSymbolV2
                        )
 from qgis.testing import unittest
 from qgis.testing.mocked import get_iface
@@ -52,6 +65,28 @@ def createLayerWithOneLine():
     return linelayer
 
 
+def createLayerWithOnePoint():
+    layer = QgsVectorLayer("Point?field=fldtxt:string&field=fldint:integer",
+                           "addfeat", "memory")
+    pr = layer.dataProvider()
+    f = QgsFeature()
+    f.setAttributes(["test", 123])
+    f.setGeometry(QgsGeometry.fromPoint(QgsPoint(100, 200)))
+    assert pr.addFeatures([f])
+    assert layer.pendingFeatureCount() == 1
+    return layer
+
+
+def createLayerWithOnePolygon():
+    layer = QgsVectorLayer("Polygon?crs=epsg:3111&field=pk:int", "vl", "memory")
+    assert layer.isValid()
+    f1 = QgsFeature(layer.dataProvider().fields(), 1)
+    f1.setAttribute("pk", 1)
+    f1.setGeometry(QgsGeometry.fromPolygon([[QgsPoint(2484588, 2425722), QgsPoint(2482767, 2398853), QgsPoint(2520109, 2397715), QgsPoint(2520792, 2425494), QgsPoint(2484588, 2425722)]]))
+    assert layer.dataProvider().addFeatures([f1])
+    return layer
+
+
 class TestQgsSymbolLayerReadSld(unittest.TestCase):
 
     """
@@ -70,17 +105,17 @@ class TestQgsSymbolLayerReadSld(unittest.TestCase):
         props = layer.rendererV2().symbol().symbolLayers()[0].properties()
 
         def testLineColor():
-            # stroke CSSParameter within ogc:Literal
+            # border CSSParameter within ogc:Literal
             # expected color is #003EBA, RGB 0,62,186
             self.assertEqual(layer.rendererV2().symbol().symbolLayers()[0].color().name(), '#003eba')
 
         def testLineWidth():
-            # stroke-width CSSParameter within ogc:Literal
+            # border-width CSSParameter within ogc:Literal
             self.assertEqual(props['line_width'], '2')
 
         def testLineOpacity():
-            # stroke-opacity CSSParameter NOT within ogc:Literal
-            # stroke-opacity=0.1
+            # border-opacity CSSParameter NOT within ogc:Literal
+            # border-opacity=0.1
             self.assertEqual(props['line_color'], '0,62,186,25')
 
         testLineColor()
@@ -112,6 +147,265 @@ class TestQgsSymbolLayerReadSld(unittest.TestCase):
         props = layer.rendererV2().symbol().symbolLayers()[0].properties()
         self.assertEqual(props['angle'], '50')
 
+    def testSymbolSizeUom(self):
+        # create a layer
+        layer = createLayerWithOnePoint()
+
+        # load a sld with marker size without uom attribute (pixels)
+        sld = 'symbol_layer/QgsSvgMarkerSymbolLayerV2.sld'
+        mFilePath = os.path.join(TEST_DATA_DIR, sld)
+        layer.loadSldStyle(mFilePath)
+
+        sld_size_px = 12
+
+        sl = layer.rendererV2().symbol().symbolLayers()[0]
+        size = sl.size()
+        unit = sl.outputUnit()
+        self.assertEqual(unit, QgsSymbolV2.Pixel)
+        self.assertEqual(size, sld_size_px)
+
+        # load a sld with marker size with uom attribute in pixel
+        sld = 'symbol_layer/QgsSvgMarkerSymbolLayerUomPixel.sld'
+        mFilePath = os.path.join(TEST_DATA_DIR, sld)
+        layer.loadSldStyle(mFilePath)
+
+        sld_size_px = 12
+
+        sl = layer.rendererV2().symbol().symbolLayers()[0]
+        size = sl.size()
+        unit = sl.outputUnit()
+        self.assertEqual(unit, QgsSymbolV2.Pixel)
+        self.assertEqual(size, sld_size_px)
+
+        # load a sld with marker size with uom attribute in meter
+        sld = 'symbol_layer/QgsSvgMarkerSymbolLayerUomMetre.sld'
+        mFilePath = os.path.join(TEST_DATA_DIR, sld)
+        layer.loadSldStyle(mFilePath)
+
+        sld_size_px = 12 / (0.28 * 0.001)
+
+        sl = layer.rendererV2().symbol().symbolLayers()[0]
+        size = sl.size()
+        unit = sl.outputUnit()
+        self.assertEqual(unit, QgsSymbolV2.Pixel)
+        self.assertAlmostEqual(size, sld_size_px, delta=0.1)
+
+        # load a sld with marker size with uom attribute in foot
+        sld = 'symbol_layer/QgsSvgMarkerSymbolLayerUomFoot.sld'
+        mFilePath = os.path.join(TEST_DATA_DIR, sld)
+        layer.loadSldStyle(mFilePath)
+
+        sld_size_px = 12 * (304.8 / 0.28)
+
+        sl = layer.rendererV2().symbol().symbolLayers()[0]
+        size = sl.size()
+        unit = sl.outputUnit()
+        self.assertEqual(unit, QgsSymbolV2.Pixel)
+        self.assertAlmostEqual(size, sld_size_px, delta=0.1)
+
+    def testSymbolSize(self):
+        # create a layers
+        layer = createLayerWithOnePoint()
+        player = createLayerWithOnePolygon()
+
+        # size test for QgsEllipseSymbolLayer
+        sld = 'symbol_layer/QgsEllipseSymbolLayerV2.sld'
+        mFilePath = os.path.join(TEST_DATA_DIR, sld)
+        layer.loadSldStyle(mFilePath)
+
+        sld_size_px = 7
+        sld_border_width_px = 1
+
+        sl = layer.rendererV2().symbol().symbolLayers()[0]
+        size = sl.symbolWidth()
+        border_width = sl.outlineWidth()
+        unit = sl.outputUnit()
+        self.assertTrue(isinstance(sl, QgsEllipseSymbolLayerV2))
+        self.assertEqual(unit, QgsSymbolV2.Pixel)
+        self.assertEqual(size, sld_size_px)
+        self.assertEqual(border_width, sld_border_width_px)
+
+        # size test for QgsVectorFieldSymbolLayer
+        # createFromSld not implemented
+
+        # size test for QgsSimpleFillSymbolLayer
+        sld = 'symbol_layer/QgsSimpleFillSymbolLayerV2.sld'
+        mFilePath = os.path.join(TEST_DATA_DIR, sld)
+        player.loadSldStyle(mFilePath)
+
+        sld_border_width_px = 0.26
+
+        sl = player.rendererV2().symbol().symbolLayers()[0]
+        border_width = sl.borderWidth()
+        unit = sl.outputUnit()
+        self.assertTrue(isinstance(sl, QgsSimpleFillSymbolLayerV2))
+        self.assertEqual(unit, QgsSymbolV2.Pixel)
+        self.assertEqual(border_width, sld_border_width_px)
+
+        # size test for QgsSVGFillSymbolLayer
+        sld = 'symbol_layer/QgsSVGFillSymbolLayer.sld'
+        mFilePath = os.path.join(TEST_DATA_DIR, sld)
+        player.loadSldStyle(mFilePath)
+
+        sld_size_px = 6
+        sld_border_width_px = 3
+
+        sl = player.rendererV2().symbol().symbolLayers()[0]
+        size = sl.patternWidth()
+        border_width = sl.svgOutlineWidth()
+        unit = sl.outputUnit()
+        self.assertTrue(isinstance(sl, QgsSVGFillSymbolLayer))
+        self.assertEqual(unit, QgsSymbolV2.Pixel)
+        self.assertEqual(size, sld_size_px)
+        self.assertEqual(border_width, sld_border_width_px)
+
+        # size test for QgsSvgMarkerSymbolLayer
+        sld = 'symbol_layer/QgsSvgMarkerSymbolLayerV2.sld'
+        mFilePath = os.path.join(TEST_DATA_DIR, sld)
+        layer.loadSldStyle(mFilePath)
+
+        sld_size_px = 12
+
+        sl = layer.rendererV2().symbol().symbolLayers()[0]
+        size = sl.size()
+        unit = sl.outputUnit()
+        self.assertTrue(isinstance(sl, QgsSvgMarkerSymbolLayerV2))
+        self.assertEqual(unit, QgsSymbolV2.Pixel)
+        self.assertEqual(size, sld_size_px)
+
+        # size test for QgsPointPatternFillSymbolLayer
+        # createFromSld not implemented
+
+        # size test for QgsLinePatternFillSymbolLayer
+        sld = 'symbol_layer/QgsLinePatternFillSymbolLayer.sld'
+        mFilePath = os.path.join(TEST_DATA_DIR, sld)
+        player.loadSldStyle(mFilePath)
+
+        sld_size_px = 4
+        sld_border_width_px = 1.5
+
+        sl = player.rendererV2().symbol().symbolLayers()[0]
+        size = sl.distance()
+        border_width = sl.lineWidth()
+        unit = sl.outputUnit()
+        self.assertTrue(isinstance(sl, QgsLinePatternFillSymbolLayer))
+        self.assertEqual(unit, QgsSymbolV2.Pixel)
+        self.assertEqual(size, sld_size_px)
+        self.assertEqual(border_width, sld_border_width_px)
+
+        # test size for QgsSimpleLineSymbolLayer
+        sld = 'symbol_layer/QgsSimpleLineSymbolLayerV2.sld'
+        mFilePath = os.path.join(TEST_DATA_DIR, sld)
+        player.loadSldStyle(mFilePath)
+
+        sld_border_width_px = 1.26
+
+        sl = player.rendererV2().symbol().symbolLayers()[0]
+        border_width = sl.width()
+        unit = sl.outputUnit()
+        self.assertTrue(isinstance(sl, QgsSimpleLineSymbolLayerV2))
+        self.assertEqual(unit, QgsSymbolV2.Pixel)
+        self.assertEqual(border_width, sld_border_width_px)
+
+        # test size for QgsMarkerLineSymbolLayer
+        sld = 'symbol_layer/QgsMarkerLineSymbolLayerV2.sld'
+        mFilePath = os.path.join(TEST_DATA_DIR, sld)
+        player.loadSldStyle(mFilePath)
+
+        sld_interval_px = 3.3
+        sld_offset_px = 6.6
+
+        sl = player.rendererV2().symbol().symbolLayers()[0]
+        interval = sl.interval()
+        offset = sl.offset()
+        unit = sl.outputUnit()
+        self.assertTrue(isinstance(sl, QgsMarkerLineSymbolLayerV2))
+        self.assertEqual(unit, QgsSymbolV2.Pixel)
+        self.assertEqual(interval, sld_interval_px)
+        self.assertEqual(offset, sld_offset_px)
+
+        # test size for QgsSimpleMarkerSymbolLayer
+        sld = 'symbol_layer/QgsSimpleMarkerSymbolLayerV2.sld'
+        mFilePath = os.path.join(TEST_DATA_DIR, sld)
+        layer.loadSldStyle(mFilePath)
+
+        sld_size_px = 6
+
+        sld_displacement_x_px = 3.3
+        sld_displacement_y_px = 6.6
+
+        sl = layer.rendererV2().symbol().symbolLayers()[0]
+        size = sl.size()
+        offset = sl.offset()
+        unit = sl.outputUnit()
+        self.assertTrue(isinstance(sl, QgsSimpleMarkerSymbolLayerV2))
+        self.assertEqual(unit, QgsSymbolV2.Pixel)
+        self.assertEqual(size, sld_size_px)
+        self.assertEqual(offset.x(), sld_displacement_x_px)
+        self.assertEqual(offset.y(), sld_displacement_y_px)
+
+        # test size for QgsSVGMarkerSymbolLayer
+        sld = 'symbol_layer/QgsSvgMarkerSymbolLayerV2.sld'
+        mFilePath = os.path.join(TEST_DATA_DIR, sld)
+        layer.loadSldStyle(mFilePath)
+
+        sld_size_px = 12
+
+        sl = layer.rendererV2().symbol().symbolLayers()[0]
+        size = sl.size()
+        self.assertTrue(isinstance(sl, QgsSvgMarkerSymbolLayerV2))
+        self.assertEqual(unit, QgsSymbolV2.Pixel)
+        self.assertEqual(size, sld_size_px)
+
+        # test size for QgsFontMarkerSymbolLayer
+        sld = 'symbol_layer/QgsFontMarkerSymbolLayerV2.sld'
+        mFilePath = os.path.join(TEST_DATA_DIR, sld)
+        layer.loadSldStyle(mFilePath)
+
+        sld_size_px = 6.23
+
+        sl = layer.rendererV2().symbol().symbolLayers()[0]
+        size = sl.size()
+        self.assertTrue(isinstance(sl, QgsFontMarkerSymbolLayerV2))
+        self.assertEqual(unit, QgsSymbolV2.Pixel)
+        self.assertEqual(size, sld_size_px)
+
+    def testSymbolSizeAfterReload(self):
+        # create a layer
+        layer = createLayerWithOnePoint()
+
+        # load a sld with marker size
+        sld = 'symbol_layer/QgsSvgMarkerSymbolLayerV2.sld'
+        mFilePath = os.path.join(TEST_DATA_DIR, sld)
+        layer.loadSldStyle(mFilePath)
+
+        # get the size and unit of the symbol
+        sl = layer.rendererV2().symbol().symbolLayers()[0]
+        first_size = sl.size()
+        first_unit = sl.outputUnit()  # in pixels
+
+        # export sld into a qdomdocument with namespace processing activated
+        doc = QDomDocument()
+        msg = ""
+        layer.exportSldStyle(doc, msg)
+        doc.setContent(doc.toString(), True)
+        self.assertTrue(msg == "")
+
+        # reload the same sld
+        root = doc.firstChildElement("StyledLayerDescriptor")
+        el = root.firstChildElement("NamedLayer")
+        layer.readSld(el, msg)
+
+        # extract the size and unit of symbol
+        sl = layer.rendererV2().symbol().symbolLayers()[0]
+        second_size = sl.size()
+        second_unit = sl.outputUnit()
+
+        # size and unit should be the same after export and reload the same
+        # sld description
+        self.assertEqual(first_size, second_size)
+        self.assertEqual(first_unit, second_unit)
+
 
 if __name__ == '__main__':
     unittest.main()
diff --git a/tests/testdata/symbol_layer/QgsMarkerLineSymbolLayerV2.sld b/tests/testdata/symbol_layer/QgsMarkerLineSymbolLayerV2.sld
index f06603d..d313a17 100644
--- a/tests/testdata/symbol_layer/QgsMarkerLineSymbolLayerV2.sld
+++ b/tests/testdata/symbol_layer/QgsMarkerLineSymbolLayerV2.sld
@@ -11,6 +11,8 @@
             <VendorOption name="placement">centralPoint</VendorOption>
             <se:Stroke>
               <se:GraphicStroke>
+                <se:Gap>3.3</se:Gap>
+                <se:PerpendicularOffset>6.6</se:PerpendicularOffset>
                 <se:Graphic>
                   <se:Mark>
                     <se:WellKnownName>circle</se:WellKnownName>
diff --git a/tests/testdata/symbol_layer/QgsSimpleMarkerSymbolLayerV2.sld b/tests/testdata/symbol_layer/QgsSimpleMarkerSymbolLayerV2.sld
index 3079773..add169b 100644
--- a/tests/testdata/symbol_layer/QgsSimpleMarkerSymbolLayerV2.sld
+++ b/tests/testdata/symbol_layer/QgsSimpleMarkerSymbolLayerV2.sld
@@ -9,6 +9,10 @@
           <se:Name>Single symbol</se:Name>
           <se:PointSymbolizer>
             <se:Graphic>
+              <se:Displacement>
+                <se:DisplacementX>3.3</se:DisplacementX>
+                <se:DisplacementY>6.6</se:DisplacementY>
+              </se:Displacement>
               <se:Mark>
                 <se:WellKnownName>pentagon</se:WellKnownName>
                 <se:Fill>
diff --git a/tests/testdata/symbol_layer/QgsSimpleMarkerSymbolLayerV2.sld b/tests/testdata/symbol_layer/QgsSvgMarkerSymbolLayerUomFoot.sld
similarity index 63%
copy from tests/testdata/symbol_layer/QgsSimpleMarkerSymbolLayerV2.sld
copy to tests/testdata/symbol_layer/QgsSvgMarkerSymbolLayerUomFoot.sld
index 3079773..0c47fe1 100644
--- a/tests/testdata/symbol_layer/QgsSimpleMarkerSymbolLayerV2.sld
+++ b/tests/testdata/symbol_layer/QgsSvgMarkerSymbolLayerUomFoot.sld
@@ -7,20 +7,15 @@
       <se:FeatureTypeStyle>
         <se:Rule>
           <se:Name>Single symbol</se:Name>
-          <se:PointSymbolizer>
+          <se:PointSymbolizer uom="http://www.opengeospatial.org/se/units/foot">
             <se:Graphic>
-              <se:Mark>
-                <se:WellKnownName>pentagon</se:WellKnownName>
-                <se:Fill>
-                  <se:SvgParameter name="fill">#68a0f4</se:SvgParameter>
-                </se:Fill>
-                <se:Stroke>
-                  <se:SvgParameter name="stroke">#5500ff</se:SvgParameter>
-                </se:Stroke>
-              </se:Mark>
-              <se:Size>6</se:Size>
+              <se:ExternalGraphic>
+                <OnlineResource xlink:type="simple" xlink:href="file:///gpsicons/skull.svg"/>
+                <Format>image/svg+xml</Format>
+              </se:ExternalGraphic>
+              <se:Size>12</se:Size>
               <se:Rotation>
-                <ogc:Literal>10</ogc:Literal>
+                <ogc:Literal>45</ogc:Literal>
               </se:Rotation>
             </se:Graphic>
           </se:PointSymbolizer>
diff --git a/tests/testdata/symbol_layer/QgsSimpleMarkerSymbolLayerV2.sld b/tests/testdata/symbol_layer/QgsSvgMarkerSymbolLayerUomMetre.sld
similarity index 63%
copy from tests/testdata/symbol_layer/QgsSimpleMarkerSymbolLayerV2.sld
copy to tests/testdata/symbol_layer/QgsSvgMarkerSymbolLayerUomMetre.sld
index 3079773..15b3b57 100644
--- a/tests/testdata/symbol_layer/QgsSimpleMarkerSymbolLayerV2.sld
+++ b/tests/testdata/symbol_layer/QgsSvgMarkerSymbolLayerUomMetre.sld
@@ -7,20 +7,15 @@
       <se:FeatureTypeStyle>
         <se:Rule>
           <se:Name>Single symbol</se:Name>
-          <se:PointSymbolizer>
+          <se:PointSymbolizer uom="http://www.opengeospatial.org/se/units/metre">
             <se:Graphic>
-              <se:Mark>
-                <se:WellKnownName>pentagon</se:WellKnownName>
-                <se:Fill>
-                  <se:SvgParameter name="fill">#68a0f4</se:SvgParameter>
-                </se:Fill>
-                <se:Stroke>
-                  <se:SvgParameter name="stroke">#5500ff</se:SvgParameter>
-                </se:Stroke>
-              </se:Mark>
-              <se:Size>6</se:Size>
+              <se:ExternalGraphic>
+                <OnlineResource xlink:type="simple" xlink:href="file:///gpsicons/skull.svg"/>
+                <Format>image/svg+xml</Format>
+              </se:ExternalGraphic>
+              <se:Size>12</se:Size>
               <se:Rotation>
-                <ogc:Literal>10</ogc:Literal>
+                <ogc:Literal>45</ogc:Literal>
               </se:Rotation>
             </se:Graphic>
           </se:PointSymbolizer>
diff --git a/tests/testdata/symbol_layer/QgsSimpleMarkerSymbolLayerV2.sld b/tests/testdata/symbol_layer/QgsSvgMarkerSymbolLayerUomPixel.sld
similarity index 63%
copy from tests/testdata/symbol_layer/QgsSimpleMarkerSymbolLayerV2.sld
copy to tests/testdata/symbol_layer/QgsSvgMarkerSymbolLayerUomPixel.sld
index 3079773..1160acc 100644
--- a/tests/testdata/symbol_layer/QgsSimpleMarkerSymbolLayerV2.sld
+++ b/tests/testdata/symbol_layer/QgsSvgMarkerSymbolLayerUomPixel.sld
@@ -7,20 +7,15 @@
       <se:FeatureTypeStyle>
         <se:Rule>
           <se:Name>Single symbol</se:Name>
-          <se:PointSymbolizer>
+          <se:PointSymbolizer uom="http://www.opengeospatial.org/se/units/pixel">
             <se:Graphic>
-              <se:Mark>
-                <se:WellKnownName>pentagon</se:WellKnownName>
-                <se:Fill>
-                  <se:SvgParameter name="fill">#68a0f4</se:SvgParameter>
-                </se:Fill>
-                <se:Stroke>
-                  <se:SvgParameter name="stroke">#5500ff</se:SvgParameter>
-                </se:Stroke>
-              </se:Mark>
-              <se:Size>6</se:Size>
+              <se:ExternalGraphic>
+                <OnlineResource xlink:type="simple" xlink:href="file:///gpsicons/skull.svg"/>
+                <Format>image/svg+xml</Format>
+              </se:ExternalGraphic>
+              <se:Size>12</se:Size>
               <se:Rotation>
-                <ogc:Literal>10</ogc:Literal>
+                <ogc:Literal>45</ogc:Literal>
               </se:Rotation>
             </se:Graphic>
           </se:PointSymbolizer>

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-grass/qgis.git



More information about the Pkg-grass-devel mailing list