[qgis] 01/01: Imported Upstream version 2.18.4+dfsg

Bas Couwenberg sebastic at debian.org
Fri Feb 24 15:47:46 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 1647035692b30671fa6600a26f7204ec4506570f
Author: Bas Couwenberg <sebastic at xs4all.nl>
Date:   Fri Feb 24 16:41:19 2017 +0100

    Imported Upstream version 2.18.4+dfsg
---
 CMakeLists.txt                                     |   6 +-
 ChangeLog                                          | 448 ++++++++++++++
 debian/changelog                                   |  10 +-
 i18n/qgis_de.ts                                    |  94 +--
 i18n/qgis_it.ts                                    |   2 +-
 python/analysis/analysis.sip                       |   1 -
 python/analysis/network/networkanalysis.sip        |   1 -
 python/core/conversions.sip                        |   6 +-
 python/core/core.sip                               |   1 -
 python/core/dxf/qgsdxfexport.sip                   |   6 +
 python/core/geometry/qgscurvev2.sip                |   3 +-
 python/core/qgscoordinatetransform.sip             |   3 +-
 python/core/qgsfeature.sip                         |   2 +-
 python/core/qgspallabeling.sip                     |   2 +-
 python/core/qgsvectorlayerfeatureiterator.sip      |   3 +-
 python/core/raster/qgsrasterprojector.sip          |   2 +-
 python/gui/editorwidgets/qgsdatetimeedit.sip       |   3 +-
 python/gui/editorwidgets/qgsdoublespinbox.sip      |   1 +
 python/gui/editorwidgets/qgsspinbox.sip            |   2 +-
 python/gui/gui.sip                                 |   1 -
 python/gui/qgslonglongvalidator.sip                |   4 +-
 python/plugins/db_manager/db_manager_plugin.py     |   6 +-
 python/plugins/processing/algs/gdal/polygonize.py  |   5 +-
 python/plugins/processing/algs/gdal/warp.py        |   6 +-
 .../processing/algs/grass/GrassAlgorithm.py        |   4 +-
 python/plugins/processing/algs/grass/GrassUtils.py |   2 +-
 .../processing/algs/grass7/Grass7Algorithm.py      |   8 +-
 .../processing/algs/grass7/description/m.cogo.txt  |   4 +-
 .../algs/grass7/description/r.circle.txt           |   2 +-
 .../algs/grass7/description/r.cost.coordinates.txt |   4 +-
 .../processing/algs/grass7/description/r.drain.txt |   2 +-
 .../algs/grass7/description/r.horizon.height.txt   |   4 +-
 .../algs/grass7/description/r.lake.coords.txt      |   2 +-
 .../algs/grass7/description/r.spreadpath.txt       |   2 +-
 .../algs/grass7/description/r.viewshed.txt         |   2 +-
 .../algs/grass7/description/r.what.coords.txt      |   2 +-
 .../algs/grass7/description/v.surf.rst.cvdev.txt   |   2 +-
 .../algs/grass7/description/v.surf.rst.line.txt    |   2 +-
 .../algs/grass7/description/v.surf.rst.txt         |   2 +-
 python/plugins/processing/algs/help/qgis.yaml      |   2 +-
 .../algs/lidar/fusion/FusionAlgorithm.py           |   2 +-
 python/plugins/processing/algs/qgis/Merge.py       |   5 +-
 .../processing/algs/qgis/SaveSelectedFeatures.py   |   6 +-
 python/plugins/processing/algs/qgis/Union.py       |  71 +--
 python/plugins/processing/algs/saga/SagaUtils.py   |   2 +-
 .../plugins/processing/algs/taudem/TauDEMUtils.py  |   1 +
 python/plugins/processing/core/GeoAlgorithm.py     |   7 +-
 python/plugins/processing/core/ProcessingConfig.py |   7 +-
 python/plugins/processing/gui/BatchPanel.py        |   2 +-
 python/plugins/processing/gui/ConfigDialog.py      |   8 +-
 .../plugins/processing/modeler/ModelerAlgorithm.py |   9 +
 .../plugins/processing/script/ScriptAlgorithm.py   |   6 +-
 .../tests/testdata/custom/union1_a.geojson         |  10 +
 .../tests/testdata/custom/union1_b.geojson         |  10 +
 .../processing/tests/testdata/expected/union1.gml  |  90 +++
 .../processing/tests/testdata/expected/union1.xsd  |  37 ++
 .../tests/testdata/qgis_algorithm_tests.yaml       |  19 +
 python/plugins/processing/tools/system.py          |  12 +
 python/server/qgswmsconfigparser.sip               |   2 +-
 python/server/qgswmsprojectparser.sip              |   2 +-
 python/server/server.sip                           |   1 -
 scripts/release.pl                                 |  18 +-
 src/app/CMakeLists.txt                             |   2 +-
 src/app/qgisapp.cpp                                |   3 +
 src/app/qgsdxfexportdialog.cpp                     |   5 +
 src/app/qgsdxfexportdialog.h                       |   1 +
 src/app/qgsfieldsproperties.cpp                    |  10 +-
 src/browser/CMakeLists.txt                         |   2 +-
 src/core/CMakeLists.txt                            |   2 +-
 src/core/dxf/qgsdxfexport.cpp                      | 128 ++--
 src/core/dxf/qgsdxfexport.h                        |   9 +-
 src/core/geometry/qgscircularstringv2.cpp          |  75 ++-
 src/core/geometry/qgscompoundcurvev2.cpp           |  31 +-
 src/core/geometry/qgscurvepolygonv2.cpp            |  26 +-
 src/core/geometry/qgscurvev2.h                     |   3 +-
 src/core/geometry/qgslinestringv2.cpp              |  14 +-
 src/core/geometry/qgsmultilinestringv2.cpp         |   2 +-
 src/core/layertree/qgslayertreemodellegendnode.cpp |   2 +-
 src/core/qgsapplication.cpp                        |   2 +-
 src/core/qgscoordinatereferencesystem_p.h          |   6 +-
 src/core/qgsdatasourceuri.cpp                      |   2 +-
 src/core/qgsexpression.cpp                         |   5 +
 src/core/qgsexpression.h                           |   2 +-
 src/core/qgsgml.cpp                                |  22 +-
 src/core/qgsgml.h                                  |   2 +
 src/core/qgsjsonutils.h                            |   6 +-
 src/core/qgsmaprenderercustompainterjob.cpp        |   2 +-
 src/core/qgsofflineediting.cpp                     |  40 +-
 src/core/qgsofflineediting.h                       |   4 +
 src/core/qgsogcutils.cpp                           |  10 +
 src/core/qgsvectorfilewriter.cpp                   |  21 +-
 src/core/qgsvectorfilewriter.h                     |   1 -
 src/core/qgsvectorlayer.cpp                        |  74 +--
 src/core/symbology-ng/qgssymbollayerv2utils.cpp    |  22 +-
 src/helpviewer/CMakeLists.txt                      |   2 +-
 .../ui/qgsgeometrycheckerresulttab.cpp             |   7 +
 src/providers/wfs/qgswfscapabilities.cpp           |  34 +-
 src/providers/wfs/qgswfsprovider.cpp               |  19 +-
 src/providers/wfs/qgswfstransactionrequest.cpp     |   1 +
 src/providers/wms/qgswmssourceselect.cpp           |   6 +-
 src/server/qgsserver.cpp                           |  10 +-
 src/server/qgswfsserver.cpp                        |  23 +-
 src/server/qgswmsconfigparser.cpp                  |   1 +
 tests/bench/CMakeLists.txt                         |   2 +-
 tests/src/core/testqgsgeometry.cpp                 |  45 +-
 tests/src/core/testqgsgml.cpp                      |  48 ++
 tests/src/gui/CMakeLists.txt                       |   2 +-
 tests/src/providers/CMakeLists.txt                 |   2 +-
 tests/src/python/CMakeLists.txt                    |   1 +
 tests/src/python/test_provider_wfs.py              | 136 ++++
 tests/src/python/test_qgsgeometry.py               |  14 +-
 tests/src/python/test_qgsserver.py                 | 317 ++++++++++
 tests/src/python/test_qgssymbollayerv2_readsld.py  | 117 ++++
 .../WMS_GetMap_Background.png                      | Bin 0 -> 29454 bytes
 .../WMS_GetMap_Background_Hex.png                  | Bin 0 -> 29454 bytes
 .../WMS_GetMap_Basic/WMS_GetMap_Basic.png          | Bin 0 -> 31254 bytes
 .../WMS_GetMap_Filter/WMS_GetMap_Filter.png        | Bin 0 -> 32826 bytes
 .../WMS_GetMap_LayerOrder.png                      | Bin 0 -> 42641 bytes
 .../WMS_GetMap_Opacities/WMS_GetMap_Opacities.png  | Bin 0 -> 59841 bytes
 .../qgis_server/WMS_GetMap_SRS/WMS_GetMap_SRS.png  | Bin 0 -> 47895 bytes
 .../WMS_GetMap_Selection/WMS_GetMap_Selection.png  | Bin 0 -> 53116 bytes
 .../WMS_GetMap_StyleCustom.png                     | Bin 0 -> 41270 bytes
 .../WMS_GetMap_StyleCustom_mask.png                | Bin 0 -> 34176 bytes
 .../WMS_GetMap_StyleDefault.png                    | Bin 0 -> 32958 bytes
 .../WMS_GetMap_StyleDefault_mask.png               | Bin 0 -> 6982 bytes
 .../WMS_GetMap_Transparent.png                     | Bin 0 -> 33000 bytes
 .../WMS_GetMap_Transparent_mask.png                | Bin 0 -> 864 bytes
 .../WMS_GetPrint_Basic/WMS_GetPrint_Basic.png      | Bin 0 -> 270757 bytes
 .../WMS_GetPrint_Basic/WMS_GetPrint_Basic_mask.png | Bin 0 -> 105668 bytes
 .../WMS_GetPrint_Grid/WMS_GetPrint_Grid.png        | Bin 0 -> 306229 bytes
 .../WMS_GetPrint_Grid/WMS_GetPrint_Grid_mask.png   | Bin 0 -> 105668 bytes
 .../WMS_GetPrint_Rotation.png                      | Bin 0 -> 338694 bytes
 .../WMS_GetPrint_Rotation_mask.png                 | Bin 0 -> 105668 bytes
 .../WMS_GetPrint_SRS/WMS_GetPrint_SRS.png          | Bin 0 -> 235542 bytes
 .../WMS_GetPrint_SRS/WMS_GetPrint_SRS_mask.png     | Bin 0 -> 105668 bytes
 .../WMS_GetPrint_Scale/WMS_GetPrint_Scale.png      | Bin 0 -> 206573 bytes
 .../WMS_GetPrint_Scale/WMS_GetPrint_Scale_mask.png | Bin 0 -> 105668 bytes
 .../WMS_GetPrint_Selection.png                     | Bin 0 -> 270757 bytes
 .../WMS_GetPrint_Selection_mask.png                | Bin 0 -> 105668 bytes
 tests/testdata/geom_data.csv                       |   1 +
 .../testdata/qgis_server/wfs_getfeature_limit2.txt |  12 +-
 .../testdata/qgis_server/wfs_getfeature_nobbox.txt |  18 +-
 .../qgis_server/wfs_getfeature_start1_limit1.txt   |   6 +-
 .../qgis_server/wfs_getfeature_startindex2.txt     |   6 +-
 .../testdata/qgis_server_accesscontrol/project.qgs | 685 ++++++++++++++++++++-
 .../symbol_layer/external_sld/simple_streams.sld   |  30 +
 .../testSimpleMarkerRotation-directValue.sld       |  30 +
 .../testSimpleMarkerRotation-ogcLiteral.sld        |  31 +
 148 files changed, 2678 insertions(+), 455 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 3936521..2c9c9fd 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 "3")
+SET(CPACK_PACKAGE_VERSION_PATCH "4")
 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+
@@ -288,6 +288,10 @@ ELSE()
   MESSAGE(STATUS "Found Qt version: ${QTVERSION}")
 ENDIF()
 
+IF(WITH_QTWEBKIT)
+    SET(OPTIONAL_QTWEBKIT ${QT_QTWEBKIT_LIBRARY})
+ENDIF(WITH_QTWEBKIT)
+
 IF (WITH_QTMOBILITY)
     FIND_PACKAGE(QtMobility 1.1.0)
 ENDIF (WITH_QTMOBILITY)
diff --git a/ChangeLog b/ChangeLog
index bf81f44..dfea69c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,451 @@
+Andreas Sturmlechner <andreas.sturmlechner at gmail.com>	2017-02-19
+
+    Fix QtWebKit automagic
+
+Marco Hugentobler <marco.hugentobler at sourcepole.ch>	2017-02-22
+
+    Fix test xml indentention
+
+Marco Hugentobler <marco.hugentobler at sourcepole.ch>	2017-02-22
+
+    Port GML3 improvements to 2.18 branch
+
+Marco Hugentobler <marco.hugentobler at sourcepole.ch>	2017-02-22
+
+    Segmentize circular strings the same way in both directions, avoiding problems with tiny gaps/overlaps
+
+Matthias Kuhn <matthias at opengis.ch>	2017-02-22
+
+    Fix relations in offline editing
+
+Juergen E. Fischer <jef at norbit.de>	2017-02-20
+
+    release.pl: allow tagging branches as ltr on point releases and
+    bypass pre-commit hooks
+
+Merge: db91e4049d 339fc10137
+Alessandro Pasotti <elpaso at itopen.it>	2017-02-16
+
+    Merge pull request #4153 from boundlessgeo/release-2_18-SldRotationFix
+
+    fixed forgot merge conflict message
+
+Luigi Pirelli <luipir at gmail.com>	2017-02-16
+
+    fixed forgot merge conflict message
+
+Merge: 02c46888e0 e4d3da2eca
+Matthias Kuhn <matthias at opengis.ch>	2017-02-16
+
+    Merge pull request #4050 from boundlessgeo/release-2_18-SldRotationFix
+
+    Tests and fix to read sld:Rotation when does not have ogc sub tags
+
+Juergen E. Fischer <jef at norbit.de>	2017-02-15
+
+    german translation fixes (fixes #16194)
+
+Merge: 9ce1fb4776 c75b5c740f
+Alexander Bruy <alexander.bruy at gmail.com>	2017-02-14
+
+    Merge pull request #4143 from NaturalGIS/fix_grass7_v_surf_rst
+
+    [processing] fix GRASS7 v.surf.rst modules
+
+Merge: 119e1815f3 e9cfd0b276
+Alexander Bruy <alexander.bruy at gmail.com>	2017-02-14
+
+    Merge pull request #4142 from radosuav/fix_gdal_warp
+
+    [processing] fix spatial subseting with GDAL warp
+
+Giovanni Manghi <giovanni.manghi at naturalgis.pt>	2017-02-14
+
+    fix GRASS7 v_surf_rst modules in qgis 2_18
+
+radosuav <radoslaw.guzinski at esa.int>	2017-02-13
+
+    [Processing] Fix spatial subseting with GDAL warp.
+
+Nyall Dawson <nyall.dawson at gmail.com>	2017-02-13
+
+    Fix large memory leak in vector file writer (fix #16003)
+
+    (cherry-picked from 826a86)
+
+Nyall Dawson <nyall.dawson at gmail.com>	2017-02-13
+
+    Fix leak in QgsCoordinateReferenceSystem
+
+    (cherry-picked from aad7c5)
+
+Nyall Dawson <nyall.dawson at gmail.com>	2017-02-13
+
+    Fix expressions leaking internal data
+
+    (cherry-picked from 15dcb6)
+
+Nyall Dawson <nyall.dawson at gmail.com>	2017-02-13
+
+    Fix leak in QgsSymbolLegendNode
+
+    (cherry-picked from f94512)
+
+Nyall Dawson <nyall.dawson at gmail.com>	2017-02-13
+
+    Fix leak in expressions
+
+    (cherry-picked from 586631)
+
+Juergen E. Fischer <jef at norbit.de>	2017-02-12
+
+    dxf export: consider layer styles (fixes #15946; backported from 92091c5)
+
+Juergen E. Fischer <jef at norbit.de>	2017-02-11
+
+    adapt bindings to sip 4.19 (fixes #16071)
+
+Merge: fe2b34d833 78396dc832
+Alexander Bruy <alexander.bruy at gmail.com>	2017-02-10
+
+    Merge pull request #4037 from wonder-sk/union-fixes
+
+    [processing] Union: fix output of features that do not instersect layer A
+
+rldhont <rldhont at gmail.com>	2017-02-10
+
+    [Server] The RFC 7946 GeoJSON specification recommends limiting coordinate precision to 6
+
+Merge: 84bef5f3ba 539ee16f07
+Alexander Bruy <alexander.bruy at gmail.com>	2017-02-09
+
+    Merge pull request #4123 from radosuav/fix_grass6_provider
+
+    [processing] small fix in GRASS 6 provider
+
+radosuav <radoslaw.guzinski at esa.int>	2017-02-09
+
+    [Processing] Small fix in GRASS 6 provider
+
+volaya <volayaf at gmail.com>	2017-02-08
+
+    [processing] added missing import
+
+Luigi Pirelli <luipir at gmail.com>	2017-02-08
+
+    moved node value parsing to ogc filter parsing
+
+Merge: 73e0811a16 c0516a46e5
+Nyall Dawson <nyall.dawson at gmail.com>	2017-02-04
+
+    Merge pull request #4104 from nyalldawson/area
+
+    Forward port curvepolygon area fixes to 2.18
+
+Nyall Dawson <nyall.dawson at gmail.com>	2017-02-04
+
+    Adjust test result
+
+Marco Hugentobler <marco.hugentobler at sourcepole.ch>	2017-01-04
+
+    Adapt numbers in test for QgsLineStringV2::sumUpArea
+
+    (forward port from df0f97)
+
+Marco Hugentobler <marco.hugentobler at sourcepole.ch>	2017-01-04
+
+    Add unit test that makes sure that the area of a closed compound curve ring is the same as a closed linestring with the same number of vertices
+
+    (forward port from be71066)
+
+Marco Hugentobler <marco.hugentobler at sourcepole.ch>	2017-01-05
+
+    Exclude degenerated rings from polygon area calculation
+
+    (forward port from 64b0b1)
+
+Marco Hugentobler <marco.hugentobler at sourcepole.ch>	2017-01-05
+
+    Change comment for QgsCurveV2::sumUpArea
+
+    (forward port from 1c02dc7)
+
+Marco Hugentobler <marco.hugentobler at sourcepole.ch>	2017-01-03
+
+    Fix area calculation of compoundcurve rings if they contain a 2-vertex linestring
+
+    (forward port from 30d7423)
+
+Nyall Dawson <nyall.dawson at gmail.com>	2017-02-04
+
+    Add additional curvepolygon with compound curve to reference geometry tests
+
+rldhont <rldhont at gmail.com>	2017-02-02
+
+    [BUGFIX][DB Manager] Detect query layer like providers do
+
+    In postgres provider, a query layer is detected as a table starting with `(` and ending with `)`.
+
+Matthias Kuhn <matthias at opengis.ch>	2017-02-02
+
+    Offline editing: support for flattening Z and M layers.
+
+Tudor Bărăscu <tudor.barascu at qtibia.ro>	2017-02-01
+
+    backport sorted field list issues
+
+    If the field list is sorted by name, the touched functions
+    should take into consideration the sorted list IDs instead of the unsorted one.
+
+Alexander Bruy <alexander.bruy at gmail.com>	2017-01-27
+
+    [processing] fix parameter value retrieval
+
+rldhont <rldhont at gmail.com>	2017-01-26
+
+    [BUGFIX][Processing] Script: get output file extension
+
+Alexander Bruy <alexander.bruy at gmail.com>	2017-01-25
+
+    [processing] make additional Fusion parameters optional
+
+    (cherry picked from commit 49e7b94a633254c99309b439db20f06d196d2fac)
+
+luipir <luipir at gmail.com>	2017-01-25
+
+    typo
+
+Juergen E. Fischer <jef at norbit.de>	2017-01-24
+
+    fix typo (followup 84d1a65)
+
+Alexander Bruy <alexander.bruy at gmail.com>	2016-12-16
+
+    [processing] use point parameter in GRASS algs where possible (addresses #15983)
+
+    (cherry picked from commit 5dc39e0a41c6e67bd5b8b0b92a8562f1c8d6b690)
+
+Anita Graser <anitagraser at gmx.at>	2016-12-20
+
+    updated help for qgis:mergevectorlayers (#3883)
+
+    "two" => "multiple"
+    (cherry picked from commit 5e061b1c632b6701df09d293b53af028d1685847)
+
+nirvn <nirvn.asia at gmail.com>	2016-12-20
+
+    [processing] support non-ogr layers in merge vector layers alg
+
+    (cherry picked from commit e338a90c80dd8b58ed41cb932c8a166b3172db2a)
+
+nirvn <nirvn.asia at gmail.com>	2017-01-03
+
+    [processing] fix app freeze when closing options dialog (fixes #15550)
+
+    (cherry picked from commit 3dcf4874859f777050f06c9fde54233e5df73b2c)
+
+Etienne Trimaille <gustrimaille at yahoo.fr>	2017-01-03
+
+    skip if the SAGA folder is not defined
+
+    (cherry picked from commit d9d5bf7c2859701966ff4f8728684685ff4c2814)
+
+Mathieu Pellerin <nirvn.asia at gmail.com>	2017-01-04
+
+    [processing] fix modeler output values in case algorithm(s)
+
+    execution modifies those (fixes #16021)
+    (cherry picked from commit 9908d9cf8117741f4614f21595018e97cf829333)
+
+Alexander Bruy <alexander.bruy at gmail.com>	2017-01-13
+
+    [processing] allow other output formats than shapefile in GDAL
+    polygonize
+
+    (cherry picked from commit 8f291a92df1667e718d49a4108e6f44721357f40)
+
+Merge: 685e4a2be0 3525d035fe
+volaya <volayaf at gmail.com>	2017-01-24
+
+    Merge pull request #4046 from volaya/quote_GRASS
+
+    [processing] quote GRASS layer inputs
+
+volaya <volayaf at gmail.com>	2017-01-23
+
+    [processing] quote GRASS layer inputs
+
+Luigi Pirelli <luipir at gmail.com>	2017-01-17
+
+    Tests and fix to read sld:Rotation when does not have ogc sub tags
+
+Merge: 1746b32a08 6071b40d54
+Borys Jurgiel <info at borysjurgiel.pl>	2017-01-23
+
+    Merge pull request #4041 from borysiasty/release-2_18
+
+    [Processing] Yet another fix for error message encoding errors. Fixes #16102
+
+Borys Jurgiel <info at borysjurgiel.pl>	2017-01-23
+
+    [Processing] Follow up 2f65d3cc0cd665
+
+Borys Jurgiel <info at borysjurgiel.pl>	2017-01-23
+
+    [Processing] Yet another fix for error message encoding errors. Fixes #16102
+
+Merge: 5cfbfbd2c3 dfdec0fcaa
+rldhont <rldhont at gmail.com>	2017-01-23
+
+    Merge pull request #4034 from rldhont/sld-backport-release-2_18-parsing
+
+    SLD parsing: handling ogc:Literal within CssParameter - backport 2.18
+
+Martin Dobias <wonder.sk at gmail.com>	2017-01-23
+
+    [processing] Union: fix output of features that do not instersect layer A
+
+    Union algorithm had incorrect logic for output of geometries in layer B
+    that are partially intersected by layer A or not intersected at all.
+
+    Added processing unit test that should cover all cases.
+
+    I have added some TODOs to the code as the outputs may still misbehave
+    if intersection or difference operations return unexpected geometry types.
+
+Jorge Gustavo Rocha <jgr at geomaster.pt>	2017-01-18
+
+    DDL update: saving layer styles on databases
+    Fix #11421
+
+Jorge Gustavo Rocha <jgr at geomaster.pt>	2017-01-17
+
+    SLD parsing: handling ogc:Literal within CssParameter
+
+Jorge Gustavo Rocha <jgr at geomaster.pt>	2017-01-15
+
+    SLD parsing: handling ogc:Literal within CssParameter
+
+Merge: e23a3d0402 8e268da21e
+rldhont <rldhont at gmail.com>	2017-01-22
+
+    Merge pull request #4028 from rldhont/server-backport-release-2_18-tests
+
+    [Server] Backport tests for 2.18
+
+Jorge Gustavo Rocha <jgr at geomaster.pt>	2017-01-15
+
+    SLD parsing: handling ogc:Literal within CssParameter
+
+rldhont <rldhont at gmail.com>	2017-01-19
+
+    [Server] Backport tests
+
+rldhont <rldhont at gmail.com>	2017-01-20
+
+    [BUFIX][Server] Regression in GetPrint GRID parameters
+
+Alessandro Pasotti <apasotti at boundlessgeo.com>	2017-01-19
+
+    Replace broken WMS demo URLs with working URLs
+
+    I'd liked to add a UMN MapServer Demo too but
+    I couldn't find a working one.
+
+    Backported from master.
+
+volaya <volayaf at gmail.com>	2017-01-19
+
+    [processing] always use only selected features in 'save selected features'
+
+Matthias Kuhn <matthias at opengis.ch>	2017-01-19
+
+    Save readOnly state and default values to style
+
+    They should be handled equal to the edit form config.
+    Fix #15931
+
+Merge: 3ebe15b3f1 f2a7f0a445
+volaya <volayaf at gmail.com>	2017-01-19
+
+    Merge pull request #4007 from radosuav/numeric_setting_fix
+
+    [Processing] Fix exception when setting a numeric value in Processing options.
+
+Juergen E. Fischer <jef at norbit.de>	2017-01-18
+
+    italian translation fix
+
+radosuav <radoslaw.guzinski at esa.int>	2017-01-17
+
+    [Processing] Fix exception when setting a numeric value in Processing options.
+
+Alessandro Pasotti <apasotti at boundlessgeo.com>	2017-01-17
+
+    [bugfix] Fixes WFS HTTP auth basic username/password
+
+    Fixes #15360 and #15597
+
+Juergen E. Fischer <jef at norbit.de>	2017-01-16
+
+    fix msvc build (followup acf74a6)
+
+Sandro Mani <manisandro at gmail.com>	2016-07-14
+
+    [Geometry checker] Fix result table corruption when adding newly found errors
+
+Juergen E. Fischer <jef at norbit.de>	2017-01-16
+
+    fix 68387ce
+
+Merge: 77ff0f8330 68387ce7f2
+Nyall Dawson <nyall.dawson at gmail.com>	2017-01-16
+
+    Merge pull request #3994 from cjmayo/appicon
+
+    Fix application icon disappearance after removal of easter egg
+
+Even Rouault <even.rouault at spatialys.com>	2017-01-15
+
+    GML parser: do not use layer extent as feature geometry if the feature has no geometry
+
+Juergen E. Fischer <jef at norbit.de>	2017-01-15
+
+    fix build
+
+Even Rouault <even.rouault at spatialys.com>	2017-01-14
+
+    GML parser: fix parsing of typenames and geometry names with non-ASCII character (#16009)
+
+Merge: 77b8c3d67b 502a8da403
+Alessandro Pasotti <elpaso at itopen.it>	2017-01-14
+
+    Merge pull request #3989 from elpaso/wfst-200-fix-15597
+
+    [bugfix] WFS-T fixes #15597 #16043 geoserver compatibility
+
+Chris Mayo <aklhfex at gmail.com>	2017-01-14
+
+    Fix application icon disappearance after removal of easter egg
+
+    Commit 1eb3bfc1 changed return value to be a filename not the full path
+
+Alessandro Pasotti <apasotti at boundlessgeo.com>	2017-01-13
+
+    [bugfix] WFS-T Fixes #15597 #16043
+
+    Tested on GeoServer and QGIS Server
+
+    Needs forward port to master
+
+Juergen E. Fischer <jef at norbit.de>	2017-01-13
+
+    fix 2c43568
+
+Juergen E. Fischer <jef at norbit.de>	2017-01-13
+
+    Release of 2.18.3
+
 Juergen E. Fischer <jef at norbit.de>	2017-01-13
 
     german translation update
diff --git a/debian/changelog b/debian/changelog
index 8cec620..ec8f830 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,8 +1,14 @@
-qgis (2.18.3) UNRELEASED; urgency=medium
+qgis (2.18.4) UNRELEASED; urgency=medium
+
+  * Release of 2.18.4
+
+ -- Jürgen E. Fischer <jef at norbit.de>  Fri, 24 Feb 2017 13:00:06 +0100
+
+qgis (2.18.3) unstable; urgency=medium
 
   * Release of 2.18.3
 
- -- Jürgen E. Fischer <jef at norbit.de>  Fri, 13 Jan 2017 13:00:04 +0100
+ -- Jürgen E. Fischer <jef at norbit.de>  Fri, 24 Feb 2017 13:00:06 +0100
 
 qgis (2.18.2) unstable; urgency=medium
 
diff --git a/i18n/qgis_de.ts b/i18n/qgis_de.ts
index 26f023a..ad16029 100644
--- a/i18n/qgis_de.ts
+++ b/i18n/qgis_de.ts
@@ -23486,37 +23486,37 @@ Soll das Schema inkl. dieser Objekte wirklich gelöscht werden?</translation>
     <message>
         <location filename="../src/gui/auth/qgsauthguiutils.cpp" line="85"/>
         <source>Master password already set</source>
-        <translation>Hauptpaßwort bereits gesetzt</translation>
+        <translation>Hauptpasswort bereits gesetzt</translation>
     </message>
     <message>
         <location filename="../src/gui/auth/qgsauthguiutils.cpp" line="97"/>
         <source>Master password not cleared because it is not set</source>
-        <translation>Hauptpaßwort nicht geleert, weil es nicht gesetzt ist</translation>
+        <translation>Hauptpasswort nicht geleert, weil es nicht gesetzt ist</translation>
     </message>
     <message>
         <location filename="../src/gui/auth/qgsauthguiutils.cpp" line="103"/>
         <source>Master password cleared (NOTE: network connections may be cached)</source>
-        <translation>Hauptpaßwort geleert (Hinweis: Netzwerkverbindungen können gecached sein)</translation>
+        <translation>Hauptpasswort geleert (Hinweis: Netzwerkverbindungen können gecached sein)</translation>
     </message>
     <message>
         <location filename="../src/gui/auth/qgsauthguiutils.cpp" line="106"/>
         <source>Master password FAILED to be cleared</source>
-        <translation>Hauptpaßwort KONNTE nicht geleert werden</translation>
+        <translation>Hauptpasswort KONNTE nicht geleert werden</translation>
     </message>
     <message>
         <location filename="../src/gui/auth/qgsauthguiutils.cpp" line="119"/>
         <source>Master password reset</source>
-        <translation>Hauptpaßwort zurückgesetzt</translation>
+        <translation>Hauptpasswort zurückgesetzt</translation>
     </message>
     <message>
         <location filename="../src/gui/auth/qgsauthguiutils.cpp" line="125"/>
         <source>Master password reset: NO current password hash in database</source>
-        <translation>Hauptpaßwortrücksetzung: KEIN aktueller Paßworthash in Datenbank</translation>
+        <translation>Hauptpasswortrücksetzung: KEIN aktueller Passworthash in Datenbank</translation>
     </message>
     <message>
         <location filename="../src/gui/auth/qgsauthguiutils.cpp" line="145"/>
         <source>Master password FAILED to be reset</source>
-        <translation>Hauptpaßwort KONNTE nicht zurückgesetzt werden</translation>
+        <translation>Hauptpasswort KONNTE nicht zurückgesetzt werden</translation>
     </message>
     <message>
         <location filename="../src/gui/auth/qgsauthguiutils.cpp" line="151"/>
@@ -30018,7 +30018,7 @@ Autoritäten/Aussteller: %1%2</translation>
         <location filename="../src/ui/auth/qgsauthimportidentitydialog.ui" line="162"/>
         <location filename="../src/ui/auth/qgsauthimportidentitydialog.ui" line="300"/>
         <source>Optional passphrase</source>
-        <translation>Optionaler Paßwortsatz</translation>
+        <translation>Optionaler Passwortsatz</translation>
     </message>
     <message>
         <location filename="../src/ui/auth/qgsauthimportidentitydialog.ui" line="175"/>
@@ -30117,7 +30117,7 @@ Autoritäten/Aussteller: %1%2</translation>
     <message>
         <location filename="../src/gui/auth/qgsauthimportidentitydialog.cpp" line="333"/>
         <source>Private key password may not match</source>
-        <translation>Paßwort zur privatem Schlüssel paßt nicht</translation>
+        <translation>Passwort zur privatem Schlüssel paßt nicht</translation>
     </message>
     <message>
         <location filename="../src/gui/auth/qgsauthimportidentitydialog.cpp" line="368"/>
@@ -30132,12 +30132,12 @@ Autoritäten/Aussteller: %1%2</translation>
     <message>
         <location filename="../src/gui/auth/qgsauthimportidentitydialog.cpp" line="391"/>
         <source>Incorrect bundle password</source>
-        <translation>Ungültiges Bündelpaßwort</translation>
+        <translation>Ungültiges Bündelpasswort</translation>
     </message>
     <message>
         <location filename="../src/gui/auth/qgsauthimportidentitydialog.cpp" line="397"/>
         <source>Failed to decode (try entering password)</source>
-        <translation>Dekodieren gescheitert (Paßworteingabe versuchen)</translation>
+        <translation>Dekodieren gescheitert (Passworteingabe versuchen)</translation>
     </message>
     <message>
         <location filename="../src/gui/auth/qgsauthimportidentitydialog.cpp" line="403"/>
@@ -30213,74 +30213,74 @@ Autoritäten/Aussteller: %1%2</translation>
     <message>
         <location filename="../src/core/auth/qgsauthmanager.cpp" line="464"/>
         <source>Master password set: FAILED to verify, reset to previous</source>
-        <translation>Hauptpaßwort KONNTE nicht überprüft werden, auf vorheriges zurückgesetzt</translation>
+        <translation>Hauptpasswort KONNTE nicht überprüft werden, auf vorheriges zurückgesetzt</translation>
     </message>
     <message>
         <location filename="../src/core/auth/qgsauthmanager.cpp" line="482"/>
         <location filename="../src/core/auth/qgsauthmanager.cpp" line="2894"/>
         <source>Master password: FAILED to access database</source>
-        <translation>Hauptpaßwort: Datenbankzugriff gescheitert</translation>
+        <translation>Hauptpasswort: Datenbankzugriff gescheitert</translation>
     </message>
     <message>
         <location filename="../src/core/auth/qgsauthmanager.cpp" line="494"/>
         <source>Master password: FAILED to find just one master password record in database</source>
-        <translation>Hauptpaßwort: Es konnte nicht nur ein Hauptpaßwortdatensatz in der Datenbank gefunden werden</translation>
+        <translation>Hauptpasswort: Es konnte nicht nur ein Hauptpasswortdatensatz in der Datenbank gefunden werden</translation>
     </message>
     <message>
         <location filename="../src/core/auth/qgsauthmanager.cpp" line="507"/>
         <location filename="../src/core/auth/qgsauthmanager.cpp" line="550"/>
         <source>Master password: FAILED to verify against hash in database</source>
-        <translation>Hauptpaßwort: Vergleich mit Hash in Datenbank gescheitert</translation>
+        <translation>Hauptpasswort: Vergleich mit Hash in Datenbank gescheitert</translation>
     </message>
     <message>
         <location filename="../src/core/auth/qgsauthmanager.cpp" line="519"/>
         <source>Master password: failed 5 times authentication system DISABLED</source>
-        <translation>Hauptpaßwort fünfmal falsch eingegeben. Authentifizierungssystem ABGESCHALTET</translation>
+        <translation>Hauptpasswort fünfmal falsch eingegeben. Authentifizierungssystem ABGESCHALTET</translation>
     </message>
     <message>
         <location filename="../src/core/auth/qgsauthmanager.cpp" line="536"/>
         <source>Master password: hash FAILED to be stored in database</source>
-        <translation>Hauptpaßwort: Hash konnte nicht in Datenbank gespeichert werden</translation>
+        <translation>Hauptpasswort: Hash konnte nicht in Datenbank gespeichert werden</translation>
     </message>
     <message>
         <location filename="../src/core/auth/qgsauthmanager.cpp" line="609"/>
         <source>Master password reset FAILED: could not clear current password from database</source>
-        <translation>Hauptpaßwortrücksetzung gescheitert: konnte aktuelles Paßwort nicht in Datenbank zurücksetzen</translation>
+        <translation>Hauptpasswortrücksetzung gescheitert: konnte aktuelles Passwort nicht in Datenbank zurücksetzen</translation>
     </message>
     <message>
         <location filename="../src/core/auth/qgsauthmanager.cpp" line="625"/>
         <source>Master password reset FAILED: could not store new password in database</source>
-        <translation>Hauptpaßwortrücksetzung gescheitert: Konnte neues Paßwort nicht in Datenbank speichern</translation>
+        <translation>Hauptpasswortrücksetzung gescheitert: Konnte neues Passwort nicht in Datenbank speichern</translation>
     </message>
     <message>
         <location filename="../src/core/auth/qgsauthmanager.cpp" line="638"/>
         <source>Master password reset FAILED: could not verify new password in database</source>
-        <translation>Hauptpaßwortrücksetzung gescheitert: konnte neues Paßwort nicht in Datenbank überprüfen</translation>
+        <translation>Hauptpasswortrücksetzung gescheitert: konnte neues Passwort nicht in Datenbank überprüfen</translation>
     </message>
     <message>
         <location filename="../src/core/auth/qgsauthmanager.cpp" line="647"/>
         <source>Master password reset FAILED: could not re-encrypt configs in database</source>
-        <translation>Hauptpaßwortrücksetzung gescheitert: Konnte Konfigurationen in Datenbank nicht neu verschlüsseln</translation>
+        <translation>Hauptpasswortrücksetzung gescheitert: Konnte Konfigurationen in Datenbank nicht neu verschlüsseln</translation>
     </message>
     <message>
         <location filename="../src/core/auth/qgsauthmanager.cpp" line="660"/>
         <source>Master password reset FAILED: could not verify password can decrypt re-encrypted configs</source>
-        <translation>Hauptpaßwortrücksetzung gescheitert: konnte nicht verfizieren, dass das Paßwort die Konfiguationen ent- und wieder verschlüsseln kann</translation>
+        <translation>Hauptpasswortrücksetzung gescheitert: konnte nicht verfizieren, dass das Passwort die Konfiguationen ent- und wieder verschlüsseln kann</translation>
     </message>
     <message>
         <location filename="../src/core/auth/qgsauthmanager.cpp" line="668"/>
         <source>Master password reset FAILED: could not re-encrypt settings in database</source>
-        <translation>Hauptpaßwortrücksetzung gescheitert: Konnte Einstellungen in Datenbank nicht neu verschlüsseln</translation>
+        <translation>Hauptpasswortrücksetzung gescheitert: Konnte Einstellungen in Datenbank nicht neu verschlüsseln</translation>
     </message>
     <message>
         <location filename="../src/core/auth/qgsauthmanager.cpp" line="676"/>
         <source>Master password reset FAILED: could not re-encrypt identities in database</source>
-        <translation>Hauptpaßwortrücksetzung gescheitert: Konnte Identitäten in Datenbank nicht neu verschlüsseln</translation>
+        <translation>Hauptpasswortrücksetzung gescheitert: Konnte Identitäten in Datenbank nicht neu verschlüsseln</translation>
     </message>
     <message>
         <location filename="../src/core/auth/qgsauthmanager.cpp" line="707"/>
         <source>Master password reset: could not remove old database backup</source>
-        <translation>Hauptpaßwortrücksetzung gescheitert: Konnte alte Datenbanksicherung nicht löschen</translation>
+        <translation>Hauptpasswortrücksetzung gescheitert: Konnte alte Datenbanksicherung nicht löschen</translation>
     </message>
     <message>
         <location filename="../src/core/auth/qgsauthmanager.cpp" line="811"/>
@@ -30475,7 +30475,7 @@ Zertifikatsvertrauensregeln</translation>
     <message>
         <location filename="../src/auth/pkipkcs12/qgsauthpkcs12edit.ui" line="34"/>
         <source>Optional passphrase</source>
-        <translation>Optionaler Paßwortsatz</translation>
+        <translation>Optionaler Passwortsatz</translation>
     </message>
     <message>
         <location filename="../src/auth/pkipkcs12/qgsauthpkcs12edit.ui" line="47"/>
@@ -30520,12 +30520,12 @@ Zertifikatsvertrauensregeln</translation>
     <message>
         <location filename="../src/auth/pkipkcs12/qgsauthpkcs12edit.cpp" line="79"/>
         <source>Incorrect bundle password</source>
-        <translation>Ungültiges Bündelpaßwort</translation>
+        <translation>Ungültiges Bündelpasswort</translation>
     </message>
     <message>
         <location filename="../src/auth/pkipkcs12/qgsauthpkcs12edit.cpp" line="85"/>
         <source>Failed to decode (try entering password)</source>
-        <translation>Dekodieren gescheitert (Paßworteingabe versuchen)</translation>
+        <translation>Dekodieren gescheitert (Passworteingabe versuchen)</translation>
     </message>
     <message>
         <location filename="../src/auth/pkipkcs12/qgsauthpkcs12edit.cpp" line="91"/>
@@ -30588,7 +30588,7 @@ Zertifikatsvertrauensregeln</translation>
     <message>
         <location filename="../src/auth/pkipaths/qgsauthpkipathsedit.ui" line="103"/>
         <source>Optional passphrase</source>
-        <translation>Optionaler Paßwortsatz</translation>
+        <translation>Optionaler Passwortsatz</translation>
     </message>
     <message>
         <location filename="../src/auth/pkipaths/qgsauthpkipathsedit.ui" line="116"/>
@@ -39852,7 +39852,7 @@ und aktuelle Datei ist [%3]</translation>
     <message>
         <location filename="../src/ui/qgscredentialdialog.ui" line="151"/>
         <source>Verify password</source>
-        <translation>Paßwort überprüfen</translation>
+        <translation>Passwort überprüfen</translation>
     </message>
     <message>
         <location filename="../src/ui/qgscredentialdialog.ui" line="166"/>
@@ -39867,7 +39867,7 @@ und aktuelle Datei ist [%3]</translation>
     <message>
         <location filename="../src/ui/qgscredentialdialog.ui" line="192"/>
         <source>Password attempts: #</source>
-        <translation>Paßwortversuche: #</translation>
+        <translation>Passwortversuche: #</translation>
     </message>
     <message>
         <location filename="../src/ui/qgscredentialdialog.ui" line="210"/>
@@ -39893,17 +39893,17 @@ und aktuelle Datei ist [%3]</translation>
     <message>
         <location filename="../src/gui/qgscredentialdialog.cpp" line="125"/>
         <source>Enter CURRENT master authentication password</source>
-        <translation>Aktuelles Hauptpaßwort für Authentifikation eingeben</translation>
+        <translation>Aktuelles Hauptpasswort für Authentifikation eingeben</translation>
     </message>
     <message>
         <location filename="../src/gui/qgscredentialdialog.cpp" line="125"/>
         <source>Set NEW master authentication password</source>
-        <translation>Neues Hauptpaßwort für Authentifikation setzen</translation>
+        <translation>Neues Hauptpasswort für Authentifikation setzen</translation>
     </message>
     <message>
         <location filename="../src/gui/qgscredentialdialog.cpp" line="142"/>
         <source>Password attempts: %1</source>
-        <translation>Paßwortversuche: %1</translation>
+        <translation>Passwortversuche: %1</translation>
     </message>
 </context>
 <context>
@@ -40881,13 +40881,13 @@ und aktuelle Datei ist [%3]</translation>
     <message>
         <location filename="../src/providers/db2/qgsdb2newconnection.cpp" line="92"/>
         <source>Saving passwords</source>
-        <translation>Paßworte speichern</translation>
+        <translation>Passworte speichern</translation>
     </message>
     <message>
         <location filename="../src/providers/db2/qgsdb2newconnection.cpp" line="93"/>
         <source>WARNING: You have opted to save your password. It will be stored in plain text in your project files and in your home directory on Unix-like systems, or in your user profile on Windows. If you do not want this to happen, please press the Cancel button.
 </source>
-        <translation>WARNUNG: Sie haben zugestimmt Ihr Paßwort zu speichern.  Es wird im Klartext in Ihren Projektdateien, auf Unixsystemen in Ihrem Heimatverzeichnis und unter Windows in Ihrem Benutzerprofil gespeichert.  Wenn Sie dies nicht wünschen, brechen Sie den Vorgang bitte ab.</translation>
+        <translation>WARNUNG: Sie haben zugestimmt Ihr Passwort zu speichern.  Es wird im Klartext in Ihren Projektdateien, auf Unixsystemen in Ihrem Heimatverzeichnis und unter Windows in Ihrem Benutzerprofil gespeichert.  Wenn Sie dies nicht wünschen, brechen Sie den Vorgang bitte ab.</translation>
     </message>
     <message>
         <location filename="../src/providers/db2/qgsdb2newconnection.cpp" line="104"/>
@@ -62322,12 +62322,12 @@ Die könnte auf ein Netzwerkproblem oder ein Problem des WMS-Server hindeuten.</
     <message>
         <location filename="../src/ui/auth/qgsauthmasterpassresetdialog.ui" line="14"/>
         <source>Reset Master Password</source>
-        <translation>Hauptpaßwort zurücksetzen</translation>
+        <translation>Hauptpasswort zurücksetzen</translation>
     </message>
     <message>
         <location filename="../src/ui/auth/qgsauthmasterpassresetdialog.ui" line="27"/>
         <source>Enter CURRENT master authentication password</source>
-        <translation>Aktuelles Authentifikations-Hauptpaßwort eingeben</translation>
+        <translation>Aktuelles Authentifikations-Hauptpasswort eingeben</translation>
     </message>
     <message>
         <location filename="../src/ui/auth/qgsauthmasterpassresetdialog.ui" line="42"/>
@@ -62344,7 +62344,7 @@ Die könnte auf ein Netzwerkproblem oder ein Problem des WMS-Server hindeuten.</
     <message>
         <location filename="../src/ui/auth/qgsauthmasterpassresetdialog.ui" line="71"/>
         <source>Enter NEW master authentication password</source>
-        <translation>Neues Authentifikations-Hauptpaßwort eingeben</translation>
+        <translation>Neues Authentifikations-Hauptpasswort eingeben</translation>
     </message>
     <message>
         <location filename="../src/ui/auth/qgsauthmasterpassresetdialog.ui" line="123"/>
@@ -62355,7 +62355,7 @@ Die könnte auf ein Netzwerkproblem oder ein Problem des WMS-Server hindeuten.</
         <location filename="../src/ui/auth/qgsauthmasterpassresetdialog.ui" line="140"/>
         <source>Your authentication database will be duplicated
 and re-encrypted using new password</source>
-        <translation>Authentifizierungdatenbank wird kopiert und mit dem neuen Paßwort neuverschlüsselt</translation>
+        <translation>Authentifizierungdatenbank wird kopiert und mit dem neuen Passwort neuverschlüsselt</translation>
     </message>
 </context>
 <context>
@@ -62812,7 +62812,7 @@ and re-encrypted using new password</source>
         <source>HEADS UP: You have opted to save your password. It will be stored in plain text in your project files and in your home directory on Unix-like systems, or in your user profile on Windows
 
 Untick save if you don't wish to be the case.</source>
-        <translation>WARNUNG: Sie haben zugestimmt Ihr Paßwort zu speichern.  Es wird im Klartext in Ihren Projektdateien, auf Unixsystemen in Ihrem Heimatverzeichnis und unter Windows in Ihrem Benutzerprofil gespeichert.  Wenn Sie dies nicht wünschen, brechen Sie den Vorgang bitte ab.</translation>
+        <translation>WARNUNG: Sie haben zugestimmt Ihr Passwort zu speichern.  Es wird im Klartext in Ihren Projektdateien, auf Unixsystemen in Ihrem Heimatverzeichnis und unter Windows in Ihrem Benutzerprofil gespeichert.  Wenn Sie dies nicht wünschen, brechen Sie den Vorgang bitte ab.</translation>
     </message>
     <message>
         <location filename="../src/ui/qgsmssqlnewconnectionbase.ui" line="205"/>
@@ -63845,13 +63845,13 @@ verbesserung</translation>
     <message>
         <location filename="../src/gui/qgsnewhttpconnection.cpp" line="221"/>
         <source>Saving passwords</source>
-        <translation>Paßworte speichern</translation>
+        <translation>Passworte speichern</translation>
     </message>
     <message>
         <location filename="../src/gui/qgsnewhttpconnection.cpp" line="222"/>
         <source>WARNING: You have entered a password. It will be stored in plain text in your project files and in your home directory on Unix-like systems, or in your user profile on Windows. If you do not want this to happen, please press the Cancel button.
 Note: giving the password is optional. It will be requested interactivly, when needed.</source>
-        <translation>WARNUNG: Sie haben ein Paßwort eingegeben.  Es wird im Klartext in Ihren Projektdateien, auf Unixsystemen in Ihrem Heimatverzeichnis und unter Windows in Ihrem Benutzerprofil gespeichert.  Wenn Sie dies nicht wünschen, brechen Sie den Vorgang bitte ab.</translation>
+        <translation>WARNUNG: Sie haben ein Passwort eingegeben.  Es wird im Klartext in Ihren Projektdateien, auf Unixsystemen in Ihrem Heimatverzeichnis und unter Windows in Ihrem Benutzerprofil gespeichert.  Wenn Sie dies nicht wünschen, brechen Sie den Vorgang bitte ab.</translation>
     </message>
 </context>
 <context>
@@ -68200,13 +68200,13 @@ Fehler:%2
     <message>
         <location filename="../src/providers/oracle/qgsoraclenewconnection.cpp" line="93"/>
         <source>Saving passwords</source>
-        <translation>Paßworte speichern</translation>
+        <translation>Passworte speichern</translation>
     </message>
     <message>
         <location filename="../src/providers/oracle/qgsoraclenewconnection.cpp" line="94"/>
         <source>WARNING: You have opted to save your password. It will be stored in plain text in your project files and in your home directory on Unix-like systems, or in your user profile on Windows. If you do not want this to happen, please press the Cancel button.
 </source>
-        <translation>WARNUNG: Sie haben zugestimmt Ihr Paßwort zu speichern.  Es wird im Klartext in Ihren Projektdateien, auf Unixsystemen in Ihrem Heimatverzeichnis und unter Windows in Ihrem Benutzerprofil gespeichert.  Wenn Sie dies nicht wünschen, brechen Sie den Vorgang bitte ab.</translation>
+        <translation>WARNUNG: Sie haben zugestimmt Ihr Passwort zu speichern.  Es wird im Klartext in Ihren Projektdateien, auf Unixsystemen in Ihrem Heimatverzeichnis und unter Windows in Ihrem Benutzerprofil gespeichert.  Wenn Sie dies nicht wünschen, brechen Sie den Vorgang bitte ab.</translation>
     </message>
     <message>
         <location filename="../src/providers/oracle/qgsoraclenewconnection.cpp" line="105"/>
@@ -69736,13 +69736,13 @@ Fehler: %2</translation>
     <message>
         <location filename="../src/providers/postgres/qgspgnewconnection.cpp" line="117"/>
         <source>Saving passwords</source>
-        <translation>Paßworte speichern</translation>
+        <translation>Passworte speichern</translation>
     </message>
     <message>
         <location filename="../src/providers/postgres/qgspgnewconnection.cpp" line="118"/>
         <source>WARNING: You have opted to save your password. It will be stored in plain text in your project files and in your home directory on Unix-like systems, or in your user profile on Windows. If you do not want this to happen, please press the Cancel button.
 </source>
-        <translation>WARNUNG: Sie haben zugestimmt Ihr Paßwort zu speichern.  Es wird im Klartext in Ihren Projektdateien, auf Unixsystemen in Ihrem Heimatverzeichnis und unter Windows in Ihrem Benutzerprofil gespeichert.  Wenn Sie dies nicht wünschen, brechen Sie den Vorgang bitte ab.</translation>
+        <translation>WARNUNG: Sie haben zugestimmt Ihr Passwort zu speichern.  Es wird im Klartext in Ihren Projektdateien, auf Unixsystemen in Ihrem Heimatverzeichnis und unter Windows in Ihrem Benutzerprofil gespeichert.  Wenn Sie dies nicht wünschen, brechen Sie den Vorgang bitte ab.</translation>
     </message>
     <message>
         <location filename="../src/providers/postgres/qgspgnewconnection.cpp" line="129"/>
diff --git a/i18n/qgis_it.ts b/i18n/qgis_it.ts
index 52dc8a8..3142def 100644
--- a/i18n/qgis_it.ts
+++ b/i18n/qgis_it.ts
@@ -732,7 +732,7 @@ Apri il visualizzatore risultati per vederlo.</translation>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="145"/>
         <source>Interquartile Range (IQR): {}</source>
-        <translation>Scarto interquartile (IQR): {</translation>
+        <translation>Scarto interquartile (IQR): {}</translation>
     </message>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="117"/>
diff --git a/python/analysis/analysis.sip b/python/analysis/analysis.sip
index ceb5056..bd90e10 100644
--- a/python/analysis/analysis.sip
+++ b/python/analysis/analysis.sip
@@ -1,5 +1,4 @@
 %Module(name=qgis._analysis,
-        version=0,
         keyword_arguments="Optional")
 
 %Import QtCore/QtCoremod.sip
diff --git a/python/analysis/network/networkanalysis.sip b/python/analysis/network/networkanalysis.sip
index fb446d1..d2c192b 100644
--- a/python/analysis/network/networkanalysis.sip
+++ b/python/analysis/network/networkanalysis.sip
@@ -1,5 +1,4 @@
 %Module(name=qgis._networkanalysis,
-        version=0,
         keyword_arguments="Optional")
 
 %Import QtCore/QtCoremod.sip
diff --git a/python/core/conversions.sip b/python/core/conversions.sip
index 564d4de..f07d3ab 100644
--- a/python/core/conversions.sip
+++ b/python/core/conversions.sip
@@ -747,7 +747,7 @@ template<TYPE>
 
 // QMap<qint64, TYPE> is implemented as a Python dictionary.
 template<TYPE>
-%MappedType QMap<qint64, TYPE> /DocType="dict-of-qint64-TYPE"/
+%MappedType QMap<qint64, TYPE>
 {
 %TypeHeaderCode
 #include <qmap.h>
@@ -1873,7 +1873,7 @@ template <TYPE>
 };
 
 // QList<QgsField> is implemented as a Python list of QgsField.
-%MappedType QList<QgsField> /DocType="list-of-qgsfield"/
+%MappedType QList<QgsField>
 {
 %TypeHeaderCode
 #include <qgsfield.h>
@@ -1978,7 +1978,7 @@ template <TYPE>
 
 %If (QVECTORINT_CONVERSION)
 // QVector<int> is implemented as a Python list of integers.
-%MappedType QVector<int> /DocType="list-of-int"/
+%MappedType QVector<int>
 {
 %TypeHeaderCode
 #include <qvector.h>
diff --git a/python/core/core.sip b/python/core/core.sip
index 577c4c1..8f0b6af 100644
--- a/python/core/core.sip
+++ b/python/core/core.sip
@@ -1,5 +1,4 @@
 %Module(name=qgis._core,
-        version=0,
         keyword_arguments="Optional")
 
 %Feature QT5_SUPPORT
diff --git a/python/core/dxf/qgsdxfexport.sip b/python/core/dxf/qgsdxfexport.sip
index f1f220c..c43b075 100644
--- a/python/core/dxf/qgsdxfexport.sip
+++ b/python/core/dxf/qgsdxfexport.sip
@@ -32,6 +32,12 @@ class QgsDxfExport
     ~QgsDxfExport();
 
     /**
+     * Set map settings and assign layer name attributes
+     * @param settings map settings to apply
+     */
+    void setMapSettings( const QgsMapSettings &settings );
+
+    /**
      * Add layers to export
      * @param layers list of layers and corresponding attribute indexes that determine the layer name (-1 for original layer name or title)
      * @see setLayerTitleAsName
diff --git a/python/core/geometry/qgscurvev2.sip b/python/core/geometry/qgscurvev2.sip
index 6cca0df..16cdcb6 100644
--- a/python/core/geometry/qgscurvev2.sip
+++ b/python/core/geometry/qgscurvev2.sip
@@ -54,8 +54,7 @@ class QgsCurveV2: public QgsAbstractGeometryV2
      */
     virtual int numPoints() const = 0;
 
-    /** Calculates the area of the curve. Derived classes should override this
-     * to return the correct area of the curve.
+    /** Sums up the area of the curve by iterating over the vertices (shoelace formula).
      */
     virtual void sumUpArea( double& sum ) const = 0;
 
diff --git a/python/core/qgscoordinatetransform.sip b/python/core/qgscoordinatetransform.sip
index c14ba53..f9b7854 100644
--- a/python/core/qgscoordinatetransform.sip
+++ b/python/core/qgscoordinatetransform.sip
@@ -15,6 +15,7 @@
 class QgsCoordinateTransform : QObject
 {
 %TypeHeaderCode
+extern PyObject *sipExportedExceptions__core[2];  // workaround: sipExportedExceptions__core is only defined in the first sip part
 #include <qgscoordinatetransform.h>
 %End
 
@@ -215,5 +216,5 @@ class QgsCoordinateTransform : QObject
 
   signals:
     /** Signal when an invalid pj_transform() has occurred */
-    void  invalidTransformInput() const;
+    void invalidTransformInput() const;
 };
diff --git a/python/core/qgsfeature.sip b/python/core/qgsfeature.sip
index 596f8a8..4009b50 100644
--- a/python/core/qgsfeature.sip
+++ b/python/core/qgsfeature.sip
@@ -4,7 +4,7 @@ typedef QMap<int, QVariant> QgsAttributeMap;
 typedef QVector<QVariant> QgsAttributes;
 
 // QgsAttributes is implemented as a Python list of Python objects.
-%MappedType QgsAttributes /DocType="list-of-attributes"/
+%MappedType QgsAttributes
 {
 %TypeHeaderCode
 #include <qgsfeature.h>
diff --git a/python/core/qgspallabeling.sip b/python/core/qgspallabeling.sip
index 488b58b..3d99555 100644
--- a/python/core/qgspallabeling.sip
+++ b/python/core/qgspallabeling.sip
@@ -1,5 +1,5 @@
 // QMap<QgsPalLayerSettings::DataDefinedProperties, QgsDataDefined*> is implemented as a Python dictionary.
-%MappedType QMap<QgsPalLayerSettings::DataDefinedProperties, QgsDataDefined*> /DocType="dict-of-QgsPalLayerSettings.DataDefinedProperties-QgsDataDefined*"/
+%MappedType QMap<QgsPalLayerSettings::DataDefinedProperties, QgsDataDefined*>
 {
 %TypeHeaderCode
 #include <qmap.h>
diff --git a/python/core/qgsvectorlayerfeatureiterator.sip b/python/core/qgsvectorlayerfeatureiterator.sip
index 0685e20..ad3431c 100644
--- a/python/core/qgsvectorlayerfeatureiterator.sip
+++ b/python/core/qgsvectorlayerfeatureiterator.sip
@@ -70,5 +70,6 @@ class QgsVectorLayerFeatureIterator : QgsAbstractFeatureIterator
     //void updateFeatureGeometry( QgsFeature& f );
 
   private:
-    QgsVectorLayerFeatureIterator();
+    QgsVectorLayerFeatureIterator( const QgsVectorLayerFeatureIterator &rhs );
+
 };
diff --git a/python/core/raster/qgsrasterprojector.sip b/python/core/raster/qgsrasterprojector.sip
index 47bb697..40b9a10 100644
--- a/python/core/raster/qgsrasterprojector.sip
+++ b/python/core/raster/qgsrasterprojector.sip
@@ -55,7 +55,7 @@ class QgsRasterProjector : QgsRasterInterface
 
     int bandCount() const;
 
-    int dataType( int bandNo ) const;
+    QGis::DataType dataType( int bandNo ) const;
 
     /** \brief set source and destination CRS */
     void setCRS( const QgsCoordinateReferenceSystem & theSrcCRS, const QgsCoordinateReferenceSystem & theDestCRS,
diff --git a/python/gui/editorwidgets/qgsdatetimeedit.sip b/python/gui/editorwidgets/qgsdatetimeedit.sip
index deda76d..be658a1 100644
--- a/python/gui/editorwidgets/qgsdatetimeedit.sip
+++ b/python/gui/editorwidgets/qgsdatetimeedit.sip
@@ -37,6 +37,7 @@ class QgsDateTimeEdit : QDateTimeEdit
 
   protected:
     virtual void resizeEvent( QResizeEvent* event );
-
     void mousePressEvent( QMouseEvent*event );
+    virtual void fixup(QString & input) const;
+    virtual QValidator::State validate(QString &text, int &pos) const;
 };
diff --git a/python/gui/editorwidgets/qgsdoublespinbox.sip b/python/gui/editorwidgets/qgsdoublespinbox.sip
index 1666a02..58f589d 100644
--- a/python/gui/editorwidgets/qgsdoublespinbox.sip
+++ b/python/gui/editorwidgets/qgsdoublespinbox.sip
@@ -80,4 +80,5 @@ class QgsDoubleSpinBox : QDoubleSpinBox
   protected:
     virtual void changeEvent( QEvent* event );
     virtual void paintEvent( QPaintEvent* event );
+    virtual void fixup(QString & input) const;
 };
diff --git a/python/gui/editorwidgets/qgsspinbox.sip b/python/gui/editorwidgets/qgsspinbox.sip
index d560641..c953470 100644
--- a/python/gui/editorwidgets/qgsspinbox.sip
+++ b/python/gui/editorwidgets/qgsspinbox.sip
@@ -78,7 +78,7 @@ class QgsSpinBox : QSpinBox
     virtual QValidator::State validate( QString & input, int & pos ) const;
 
   protected:
-
     virtual void changeEvent( QEvent* event );
     virtual void paintEvent( QPaintEvent* event );
+    virtual void fixup(QString &input) const;
 };
diff --git a/python/gui/gui.sip b/python/gui/gui.sip
index 240c636..727ac70 100644
--- a/python/gui/gui.sip
+++ b/python/gui/gui.sip
@@ -1,5 +1,4 @@
 %Module(name=qgis._gui,
-        version=0,
         keyword_arguments="Optional")
 
 %Feature HAVE_QSCI_SIP
diff --git a/python/gui/qgslonglongvalidator.sip b/python/gui/qgslonglongvalidator.sip
index 9def830..7500357 100644
--- a/python/gui/qgslonglongvalidator.sip
+++ b/python/gui/qgslonglongvalidator.sip
@@ -8,7 +8,7 @@ class QgsLongLongValidator : QValidator
     QgsLongLongValidator( qint64 bottom, qint64 top, QObject *parent );
     ~QgsLongLongValidator();
 
-    QValidator::State validate( QString &input, int& ) const;
+    virtual QValidator::State validate( QString &input, int& ) const;
 
     void setBottom( qint64 bottom );
     void setTop( qint64 top );
@@ -17,4 +17,6 @@ class QgsLongLongValidator : QValidator
 
     qint64 bottom() const;
     qint64 top() const;
+
+    virtual void fixup(QString &input) const;
 };
diff --git a/python/plugins/db_manager/db_manager_plugin.py b/python/plugins/db_manager/db_manager_plugin.py
index dca2cbe..aa982aa 100644
--- a/python/plugins/db_manager/db_manager_plugin.py
+++ b/python/plugins/db_manager/db_manager_plugin.py
@@ -80,7 +80,8 @@ class DBManagerPlugin:
     def onLayerWasAdded(self, aMapLayer):
         if hasattr(aMapLayer, 'dataProvider') and aMapLayer.dataProvider().name() in ['postgres', 'spatialite', 'oracle']:
             uri = QgsDataSourceURI(aMapLayer.source())
-            if re.search('^\(SELECT .+ FROM .+\)$', uri.table(), re.S):
+            table = uri.table()
+            if table.startswith('(') and table.endswith(')'):
                 self.iface.legendInterface().addLegendLayerActionForLayer(self.layerAction, aMapLayer)
         # virtual has QUrl source
         # url = QUrl(QUrl.fromPercentEncoding(l.source()))
@@ -92,7 +93,8 @@ class DBManagerPlugin:
         l = self.iface.legendInterface().currentLayer()
         if l.dataProvider().name() in ['postgres', 'spatialite', 'oracle']:
             uri = QgsDataSourceURI(l.source())
-            if re.search('^\(SELECT .+ FROM .+\)$', uri.table(), re.S):
+            table = uri.table()
+            if table.startswith('(') and table.endswith(')'):
                 self.run()
                 self.dlg.runSqlLayerWindow(l)
         # virtual has QUrl source
diff --git a/python/plugins/processing/algs/gdal/polygonize.py b/python/plugins/processing/algs/gdal/polygonize.py
index 92510c6..4e80d4f 100644
--- a/python/plugins/processing/algs/gdal/polygonize.py
+++ b/python/plugins/processing/algs/gdal/polygonize.py
@@ -62,11 +62,12 @@ class polygonize(GdalAlgorithm):
         self.addOutput(OutputVector(polygonize.OUTPUT, self.tr('Vectorized')))
 
     def getConsoleCommands(self):
+        output = self.getOutputValue(polygonize.OUTPUT)
+
         arguments = []
         arguments.append(self.getParameterValue(polygonize.INPUT))
         arguments.append('-f')
-        arguments.append('ESRI Shapefile')
-        output = self.getOutputValue(polygonize.OUTPUT)
+        arguments.append(GdalUtils.getVectorDriverFromFileName(output))
         arguments.append(output)
         arguments.append(QFileInfo(output).baseName())
         arguments.append(self.getParameterValue(polygonize.FIELD))
diff --git a/python/plugins/processing/algs/gdal/warp.py b/python/plugins/processing/algs/gdal/warp.py
index 84e0fdf..d32f036 100644
--- a/python/plugins/processing/algs/gdal/warp.py
+++ b/python/plugins/processing/algs/gdal/warp.py
@@ -141,10 +141,10 @@ class warp(GdalAlgorithm):
         arguments = []
         arguments.append('-ot')
         arguments.append(self.TYPE[self.getParameterValue(self.RTYPE)])
-        if len(srccrs) > 0:
+        if srccrs:
             arguments.append('-s_srs')
             arguments.append(srccrs)
-        if len(dstcrs) > 0:
+        if dstcrs:
             arguments.append('-t_srs')
             arguments.append(dstcrs)
         if noData and len(noData) > 0:
@@ -177,7 +177,7 @@ class warp(GdalAlgorithm):
             arguments.extend(rastext)
 
         if GdalUtils.version() >= 2000000:
-            if rastext and rastext_crs is not None:
+            if rastext and rastext_crs:
                 arguments.append('-te_srs')
                 arguments.append(rastext_crs)
 
diff --git a/python/plugins/processing/algs/grass/GrassAlgorithm.py b/python/plugins/processing/algs/grass/GrassAlgorithm.py
index 5f41f68..fb778b4 100644
--- a/python/plugins/processing/algs/grass/GrassAlgorithm.py
+++ b/python/plugins/processing/algs/grass/GrassAlgorithm.py
@@ -31,7 +31,7 @@ import uuid
 import importlib
 import re
 
-from qgis.PyQt.QtCore import QCoreApplication
+from qgis.PyQt.QtCore import QCoreApplication, QUrl
 from qgis.PyQt.QtGui import QIcon
 
 from qgis.core import QgsRasterLayer
@@ -104,7 +104,7 @@ class GrassAlgorithm(GeoAlgorithm):
         if os.path.exists(helpPath):
             return False, QUrl.fromLocalFile(os.path.join(helpPath, '{}.html'.format(self.grassName))).toString()
         else:
-            return False, helpPath + '{}.html'.format(self.grass7Name)
+            return False, '{}{}.html'.format(helpPath, self.grassName)
 
     def getParameterDescriptions(self):
         descs = {}
diff --git a/python/plugins/processing/algs/grass/GrassUtils.py b/python/plugins/processing/algs/grass/GrassUtils.py
index 4962afe..bc9620e 100644
--- a/python/plugins/processing/algs/grass/GrassUtils.py
+++ b/python/plugins/processing/algs/grass/GrassUtils.py
@@ -420,7 +420,7 @@ class GrassUtils:
 
         if helpPath is None:
             if isWindows():
-                localPath = os.path.join(Grass7Utils.grassPath(), 'docs/html')
+                localPath = os.path.join(GrassUtils.grassPath(), 'docs/html')
                 if os.path.exists(localPath):
                     helpPath = os.path.abspath(localPath)
             elif isMac():
diff --git a/python/plugins/processing/algs/grass7/Grass7Algorithm.py b/python/plugins/processing/algs/grass7/Grass7Algorithm.py
index fd51f56..a6777af 100644
--- a/python/plugins/processing/algs/grass7/Grass7Algorithm.py
+++ b/python/plugins/processing/algs/grass7/Grass7Algorithm.py
@@ -395,16 +395,16 @@ class Grass7Algorithm(GeoAlgorithm):
             if isinstance(param, (ParameterRaster, ParameterVector)):
                 value = param.value
                 if value in self.exportedLayers.keys():
-                    command += ' ' + param.name + '=' \
-                        + self.exportedLayers[value]
+                    command += ' ' + param.name + '="' \
+                        + self.exportedLayers[value] + '"'
                 else:
-                    command += ' ' + param.name + '=' + value
+                    command += ' ' + param.name + '="' + value + '"'
             elif isinstance(param, ParameterMultipleInput):
                 s = param.value
                 for layer in self.exportedLayers.keys():
                     s = s.replace(layer, self.exportedLayers[layer])
                 s = s.replace(';', ',')
-                command += ' ' + param.name + '=' + s
+                command += ' ' + param.name + '="' + s + '"'
             elif isinstance(param, ParameterBoolean):
                 if param.value:
                     command += ' ' + param.name
diff --git a/python/plugins/processing/algs/grass7/description/m.cogo.txt b/python/plugins/processing/algs/grass7/description/m.cogo.txt
index 4e89a5c..05f4267 100644
--- a/python/plugins/processing/algs/grass7/description/m.cogo.txt
+++ b/python/plugins/processing/algs/grass7/description/m.cogo.txt
@@ -1,9 +1,9 @@
 m.cogo
-A simple utility for converting bearing and distance measurements to coordinates and vice versa. It assumes a cartesian coordinate system 
+A simple utility for converting bearing and distance measurements to coordinates and vice versa. It assumes a cartesian coordinate system
 Miscellaneous (m.*)
 ParameterFile|input|Name of input file|False
 OutputFile|output|Output text file
-ParameterString|coordinates|Starting coordinate pair (default 0.0, 0.0)|0.0,0.0
+ParameterPoint|coordinates|Starting coordinate pair|0.0,0.0
 *ParameterBoolean|-l|Lines are labelled|False
 *ParameterBoolean|-q|Suppress warnings|False
 *ParameterBoolean|-r|Convert from coordinates to bearing and distance|False
diff --git a/python/plugins/processing/algs/grass7/description/r.circle.txt b/python/plugins/processing/algs/grass7/description/r.circle.txt
index 2fe6a16..d7bbfc8 100644
--- a/python/plugins/processing/algs/grass7/description/r.circle.txt
+++ b/python/plugins/processing/algs/grass7/description/r.circle.txt
@@ -1,7 +1,7 @@
 r.circle
 Creates a raster map containing concentric rings around a given point.
 Raster (r.*)
-ParameterString|coordinates|The coordinate of the center (east,north)|0,0
+ParameterPoint|coordinates|The coordinate of the center (east,north)|0,0
 ParameterNumber|min|Minimum radius for ring/circle map (in meters)|None|None|10
 ParameterNumber|max|Maximum radius for ring/circle map (in meters)|None|None|20
 ParameterString|multiplier|Data value multiplier|1
diff --git a/python/plugins/processing/algs/grass7/description/r.cost.coordinates.txt b/python/plugins/processing/algs/grass7/description/r.cost.coordinates.txt
index ae0cc5c..7bbcaaa 100644
--- a/python/plugins/processing/algs/grass7/description/r.cost.coordinates.txt
+++ b/python/plugins/processing/algs/grass7/description/r.cost.coordinates.txt
@@ -2,8 +2,8 @@ r.cost
 r.cost.coordinates - Creates a raster layer of cumulative cost of moving across a raster layer whose cell values represent cost.
 Raster (r.*)
 ParameterRaster|input|Unit cost layer|False
-ParameterString|start_coordinates|Coordinates of starting point(s) (E,N)|0,0
-ParameterString|stop_coordinates|Coordinates of stopping point(s) (E,N)|
+ParameterPoint|start_coordinates|Coordinates of starting point(s) (E,N)|0,0
+ParameterPoint|stop_coordinates|Coordinates of stopping point(s) (E,N)|0,0
 ParameterBoolean|-k|Use the 'Knight's move'; slower, but more accurate|False
 ParameterBoolean|-n|Keep null values in output raster layer|True
 ParameterNumber|max_cost|Maximum cumulative cost|0|None|0
diff --git a/python/plugins/processing/algs/grass7/description/r.drain.txt b/python/plugins/processing/algs/grass7/description/r.drain.txt
index 9616474..09b60c4 100644
--- a/python/plugins/processing/algs/grass7/description/r.drain.txt
+++ b/python/plugins/processing/algs/grass7/description/r.drain.txt
@@ -3,7 +3,7 @@ Traces a flow through an elevation model on a raster map.
 Raster (r.*)
 ParameterRaster|input|Elevation|False
 ParameterRaster|direction|Name of input movement direction map associated with the cost surface|True
-ParameterString|start_coordinates|Map coordinates of starting point(s) (E,N)|0.0,0.0|False|True
+ParameterPoint|start_coordinates|Map coordinates of starting point(s) (E,N)|0.0,0.0|True
 ParameterVector|start_points|Vector layer containing starting point(s)|0|True
 ParameterBoolean|-c|Copy input cell values on output|False
 ParameterBoolean|-a|Accumulate input values along the path|False
diff --git a/python/plugins/processing/algs/grass7/description/r.horizon.height.txt b/python/plugins/processing/algs/grass7/description/r.horizon.height.txt
index accbf9d..da3065d 100644
--- a/python/plugins/processing/algs/grass7/description/r.horizon.height.txt
+++ b/python/plugins/processing/algs/grass7/description/r.horizon.height.txt
@@ -2,7 +2,7 @@ r.horizon
 r.horizon.height - Horizon angle computation from a digital elevation model.
 Raster (r.*)
 ParameterRaster|elevation|Name of input elevation raster map|False
-ParameterString|coordinates|Coordinate for which you want to calculate the horizon|0,0
+ParameterPoint|coordinates|Coordinate for which you want to calculate the horizon|0,0
 ParameterNumber|direction|Direction in which you want to calculate the horizon height|0|360|0.0
 ParameterNumber|step|Angle step size for multidirectional horizon [degrees]|0|360|0.0
 ParameterNumber|start|Start angle for multidirectional horizon [degrees]|0|360|0
@@ -10,4 +10,4 @@ ParameterNumber|end|End angle for multidirectional horizon [degrees]|0|360|360
 ParameterNumber|maxdistance|The maximum distance to consider when finding the horizon height|0|None|10000
 ParameterString|distance|Sampling distance step coefficient (0.5-1.5)|1.0
 ParameterBoolean|-d|Write output in degrees (default is radians)|False
-OutputHTML|html|Horizon
\ No newline at end of file
+OutputHTML|html|Horizon
diff --git a/python/plugins/processing/algs/grass7/description/r.lake.coords.txt b/python/plugins/processing/algs/grass7/description/r.lake.coords.txt
index 00dbcba..1760630 100644
--- a/python/plugins/processing/algs/grass7/description/r.lake.coords.txt
+++ b/python/plugins/processing/algs/grass7/description/r.lake.coords.txt
@@ -3,6 +3,6 @@ r.lake.coords - Fills lake at given point to given level.
 Raster (r.*)
 ParameterRaster|elevation|Elevation|False
 ParameterNumber|water_level|Water level|None|None|1000.0
-ParameterString|coordinates|Seed point coordinates|0,0
+ParameterPoint|coordinates|Seed point coordinates|0,0
 ParameterBoolean|-n|Use negative depth values for lake raster layer|False
 OutputRaster|lake|Lake
diff --git a/python/plugins/processing/algs/grass7/description/r.spreadpath.txt b/python/plugins/processing/algs/grass7/description/r.spreadpath.txt
index 8311dfc..7093395 100644
--- a/python/plugins/processing/algs/grass7/description/r.spreadpath.txt
+++ b/python/plugins/processing/algs/grass7/description/r.spreadpath.txt
@@ -3,5 +3,5 @@ Recursively traces the least cost path backwards to cells from which the cumulat
 Raster (r.*)
 ParameterRaster|x_input|x_input|False
 ParameterRaster|y_input|y_input|False
-ParameterString|coordinates|coordinate|0,0
+ParameterPoint|coordinates|coordinate|0,0
 OutputRaster|output|Backward least cost
diff --git a/python/plugins/processing/algs/grass7/description/r.viewshed.txt b/python/plugins/processing/algs/grass7/description/r.viewshed.txt
index 8fd1137..982fdce 100644
--- a/python/plugins/processing/algs/grass7/description/r.viewshed.txt
+++ b/python/plugins/processing/algs/grass7/description/r.viewshed.txt
@@ -2,7 +2,7 @@ r.viewshed
 Computes the viewshed of a point on an elevation raster map.
 Raster (r.*)
 ParameterRaster|input|Elevation|False
-ParameterString|coordinates|Coordinate identifying the viewing position|0,0|False|False
+ParameterPoint|coordinates|Coordinate identifying the viewing position|0.0,0.0
 ParameterString|observer_elevation|Viewing elevation above the ground|1.75|False|False
 ParameterString|target_elevation|Offset for target elevation above the ground|0.0|False|False
 ParameterString|max_distance|Maximum distance from the viewing point (meters)|-1|False|False
diff --git a/python/plugins/processing/algs/grass7/description/r.what.coords.txt b/python/plugins/processing/algs/grass7/description/r.what.coords.txt
index 4fc1557..8878e0d 100644
--- a/python/plugins/processing/algs/grass7/description/r.what.coords.txt
+++ b/python/plugins/processing/algs/grass7/description/r.what.coords.txt
@@ -2,7 +2,7 @@ r.what
 r.what.coords - Queries raster maps on their category values and category labels on a point.
 Raster (r.*)
 ParameterRaster|map|Name of raster map|False
-ParameterString|coordinates|Coordinates for query (east, north)|None|False|False
+ParameterPoint|coordinates|Coordinates for query (east, north)
 ParameterString|null_value|String representing NULL value|*|False|True
 ParameterString|separator|Field separator. Special characters: pipe, comma, space, tab, newlineString representing NULL value|pipe|False|True
 ParameterNumber|cache|Size of point cache|0|None|500|True
diff --git a/python/plugins/processing/algs/grass7/description/v.surf.rst.cvdev.txt b/python/plugins/processing/algs/grass7/description/v.surf.rst.cvdev.txt
index 8b081ce..20feb31 100644
--- a/python/plugins/processing/algs/grass7/description/v.surf.rst.cvdev.txt
+++ b/python/plugins/processing/algs/grass7/description/v.surf.rst.cvdev.txt
@@ -2,7 +2,7 @@ v.surf.rst
 v.surf.rst.cvdev - Spatial approximation and topographic analysis using regularized spline with tension.
 Vector (v.*)
 ParameterVector|input|Input vector layer|0|False
-ParameterString|where|WHERE conditions of SQL statement without 'where' keyword|
+*ParameterString|where|WHERE conditions of SQL statement without 'where' keyword|None|False|True
 ParameterRaster|mask|Name of the raster map used as mask|True
 ParameterTableField|zcolumn|Name of the attribute column with values to be used for approximation|input|-1|False
 ParameterNumber|tension|Tension parameter|None|None|40
diff --git a/python/plugins/processing/algs/grass7/description/v.surf.rst.line.txt b/python/plugins/processing/algs/grass7/description/v.surf.rst.line.txt
index 919576b..8848efa 100644
--- a/python/plugins/processing/algs/grass7/description/v.surf.rst.line.txt
+++ b/python/plugins/processing/algs/grass7/description/v.surf.rst.line.txt
@@ -2,7 +2,7 @@ v.surf.rst
 v.surf.rst.line - Spatial approximation and topographic analysis using regularized spline with tension.
 Vector (v.*)
 ParameterVector|input|Input lines layer|1|False
-ParameterString|where|WHERE conditions of SQL statement without 'where' keyword|
+*ParameterString|where|WHERE conditions of SQL statement without 'where' keyword|None|False|True
 ParameterRaster|mask|Name of the raster map used as mask|True
 ParameterTableField|zcolumn|Name of the attribute column with values to be used for approximation|input|-1|False
 ParameterNumber|tension|Tension parameter|None|None|40
diff --git a/python/plugins/processing/algs/grass7/description/v.surf.rst.txt b/python/plugins/processing/algs/grass7/description/v.surf.rst.txt
index ce4381d..969558a 100644
--- a/python/plugins/processing/algs/grass7/description/v.surf.rst.txt
+++ b/python/plugins/processing/algs/grass7/description/v.surf.rst.txt
@@ -2,7 +2,7 @@ v.surf.rst
 Spatial approximation and topographic analysis using regularized spline with tension.
 Vector (v.*)
 ParameterVector|input|Input points layer|0|False
-ParameterString|where|WHERE conditions of SQL statement without 'where' keyword|
+*ParameterString|where|WHERE conditions of SQL statement without 'where' keyword|None|False|True
 ParameterRaster|mask|Name of the raster map used as mask|True
 ParameterTableField|zcolumn|Name of the attribute column with values to be used for approximation|input|-1|False
 ParameterNumber|tension|Tension parameter|None|None|40
diff --git a/python/plugins/processing/algs/help/qgis.yaml b/python/plugins/processing/algs/help/qgis.yaml
index b491311..29f167d 100644
--- a/python/plugins/processing/algs/help/qgis.yaml
+++ b/python/plugins/processing/algs/help/qgis.yaml
@@ -237,7 +237,7 @@ qgis:mergelines: >
   If any parts of the input MultiLineString geometries are not connected, the resultant geometry will be a MultiLineString containing any lines which could be merged and any non-connected line parts.
 
 qgis:mergevectorlayers: >
-  This algorithm combines two vector layer of the same geometry type into a single one.
+  This algorithm combines multiple vector layers of the same geometry type into a single one.
 
   If attributes tables are different, the attribute table of the resulting layer will contain the attributes from both input layers
 
diff --git a/python/plugins/processing/algs/lidar/fusion/FusionAlgorithm.py b/python/plugins/processing/algs/lidar/fusion/FusionAlgorithm.py
index 49b3fc1..95e6ea2 100644
--- a/python/plugins/processing/algs/lidar/fusion/FusionAlgorithm.py
+++ b/python/plugins/processing/algs/lidar/fusion/FusionAlgorithm.py
@@ -48,7 +48,7 @@ class FusionAlgorithm(GeoAlgorithm):
 
     def addAdvancedModifiers(self):
         param = ParameterString(
-            self.ADVANCED_MODIFIERS, self.tr('Additional modifiers'), '')
+            self.ADVANCED_MODIFIERS, self.tr('Additional modifiers'), '', optional=True)
         param.isAdvanced = True
         self.addParameter(param)
 
diff --git a/python/plugins/processing/algs/qgis/Merge.py b/python/plugins/processing/algs/qgis/Merge.py
index 760b59a..ba16d93 100644
--- a/python/plugins/processing/algs/qgis/Merge.py
+++ b/python/plugins/processing/algs/qgis/Merge.py
@@ -57,13 +57,12 @@ class Merge(GeoAlgorithm):
 
     def processAlgorithm(self, progress):
         inLayers = self.getParameterValue(self.LAYERS)
-        paths = inLayers.split(';')
 
         layers = []
         fields = QgsFields()
         totalFeatureCount = 0
-        for x in xrange(len(paths)):
-            layer = QgsVectorLayer(paths[x], unicode(x), 'ogr')
+        for layerSource in inLayers.split(';'):
+            layer = dataobjects.getObjectFromUri(layerSource)
 
             if (len(layers) > 0):
                 if (layer.wkbType() != layers[0].wkbType()):
diff --git a/python/plugins/processing/algs/qgis/SaveSelectedFeatures.py b/python/plugins/processing/algs/qgis/SaveSelectedFeatures.py
index 77a8a58..17011a4 100644
--- a/python/plugins/processing/algs/qgis/SaveSelectedFeatures.py
+++ b/python/plugins/processing/algs/qgis/SaveSelectedFeatures.py
@@ -28,7 +28,7 @@ __revision__ = '$Format:%H$'
 from processing.core.GeoAlgorithm import GeoAlgorithm
 from processing.core.parameters import ParameterVector
 from processing.core.outputs import OutputVector
-from processing.tools import dataobjects, vector
+from processing.tools import dataobjects
 
 
 class SaveSelectedFeatures(GeoAlgorithm):
@@ -55,8 +55,8 @@ class SaveSelectedFeatures(GeoAlgorithm):
         writer = output.getVectorWriter(vectorLayer.fields(),
                                         vectorLayer.wkbType(), vectorLayer.crs())
 
-        features = vector.features(vectorLayer)
-        total = 100.0 / len(features)
+        features = vectorLayer.selectedFeaturesIterator()
+        total = 100.0 / int(vectorLayer.selectedFeatureCount())
         for current, feat in enumerate(features):
             writer.addFeature(feat)
             progress.setPercentage(int(current * total))
diff --git a/python/plugins/processing/algs/qgis/Union.py b/python/plugins/processing/algs/qgis/Union.py
index abca9c8..ecfe881 100644
--- a/python/plugins/processing/algs/qgis/Union.py
+++ b/python/plugins/processing/algs/qgis/Union.py
@@ -123,6 +123,11 @@ class Union(GeoAlgorithm):
                         else:
                             int_geom = QgsGeometry(int_geom)
 
+                        # TODO: the result may have a different dimension (e.g. intersection of two polygons may result in a single point)
+                        # or the result may be a collection of geometries (e.g. intersection of two polygons results in three polygons and one linestring).
+                        # We need to filter out all acceptable geometries into a single (possibly multi-part) geometry - and we need
+                        # to do it consistently also in the code further below
+
                         if int_geom.wkbType() == QGis.WKBUnknown or QgsWKBTypes.flatType(int_geom.geometry().wkbType()) == QgsWKBTypes.GeometryCollection:
                             # Intersection produced different geomety types
                             temp_list = int_geom.asGeometryCollection()
@@ -160,6 +165,7 @@ class Union(GeoAlgorithm):
                         ProcessingLog.addToLog(ProcessingLog.LOG_ERROR,
                                                self.tr('GEOS geoprocessing error: One or more input features have invalid geometry.'))
 
+                # TODO: correctly handly different output geometry types (see todo above)
                 if diff_geom.wkbType() == 0 or QgsWKBTypes.flatType(diff_geom.geometry().wkbType()) == QgsWKBTypes.GeometryCollection:
                     temp_list = diff_geom.asGeometryCollection()
                     for i in temp_list:
@@ -182,51 +188,38 @@ class Union(GeoAlgorithm):
             progress.setPercentage(nElement / float(nFeat) * 100)
             add = False
             geom = QgsGeometry(inFeatA.geometry())
-            diff_geom = QgsGeometry(geom)
             atMap = [None] * length
             atMap.extend(inFeatA.attributes())
             intersects = indexB.intersects(geom.boundingBox())
+            lstIntersectingA = []
 
-            if len(intersects) < 1:
-                try:
-                    outFeat.setGeometry(geom)
-                    outFeat.setAttributes(atMap)
-                    writer.addFeature(outFeat)
-                except:
-                    ProcessingLog.addToLog(ProcessingLog.LOG_INFO,
-                                           self.tr('Feature geometry error: One or more output features ignored due to invalid geometry.'))
-            else:
-                for id in intersects:
-                    request = QgsFeatureRequest().setFilterFid(id)
-                    inFeatB = vlayerA.getFeatures(request).next()
-                    atMapB = inFeatB.attributes()
-                    tmpGeom = QgsGeometry(inFeatB.geometry())
+            for id in intersects:
+                request = QgsFeatureRequest().setFilterFid(id)
+                inFeatB = vlayerA.getFeatures(request).next()
+                atMapB = inFeatB.attributes()
+                tmpGeom = QgsGeometry(inFeatB.geometry())
 
-                    if diff_geom.intersects(tmpGeom):
-                        add = True
-                        diff_geom = QgsGeometry(diff_geom.difference(tmpGeom))
-                        if diff_geom.isGeosEmpty() or not diff_geom.isGeosValid():
-                            ProcessingLog.addToLog(ProcessingLog.LOG_ERROR,
-                                                   self.tr('GEOS geoprocessing error: One or more input features have invalid geometry.'))
-                    else:
-                        try:
-                            # Ihis only happends if the bounding box
-                            # intersects, but the geometry doesn't
-                            outFeat.setGeometry(diff_geom)
-                            outFeat.setAttributes(atMap)
-                            writer.addFeature(outFeat)
-                        except:
-                            ProcessingLog.addToLog(ProcessingLog.LOG_INFO,
-                                                   self.tr('Feature geometry error: One or more output features ignored due to invalid geometry.'))
+                if geom.intersects(tmpGeom):
+                    lstIntersectingA.append(tmpGeom)
 
-            if add:
-                try:
-                    outFeat.setGeometry(diff_geom)
-                    outFeat.setAttributes(atMap)
-                    writer.addFeature(outFeat)
-                except:
-                    ProcessingLog.addToLog(ProcessingLog.LOG_INFO,
-                                           self.tr('Feature geometry error: One or more output features ignored due to invalid geometry.'))
+            if len(lstIntersectingA) == 0:
+                res_geom = geom
+            else:
+                intA = QgsGeometry.unaryUnion(lstIntersectingA)
+                res_geom = geom.difference(intA)
+                if res_geom.isGeosEmpty() or not res_geom.isGeosValid():
+                    ProcessingLog.addToLog(ProcessingLog.LOG_ERROR,
+                                           self.tr('GEOS geoprocessing error: One or more input features have invalid geometry.'))
+
+            # TODO: correctly handly different output geometry types (see todo above)
+
+            try:
+                outFeat.setGeometry(res_geom)
+                outFeat.setAttributes(atMap)
+                writer.addFeature(outFeat)
+            except:
+                ProcessingLog.addToLog(ProcessingLog.LOG_INFO,
+                                       self.tr('Feature geometry error: One or more output features ignored due to invalid geometry.'))
             nElement += 1
 
         del writer
diff --git a/python/plugins/processing/algs/saga/SagaUtils.py b/python/plugins/processing/algs/saga/SagaUtils.py
index 1e2a67d..ee13c78 100644
--- a/python/plugins/processing/algs/saga/SagaUtils.py
+++ b/python/plugins/processing/algs/saga/SagaUtils.py
@@ -72,7 +72,7 @@ def findSagaFolder():
 
 def sagaPath():
     folder = ProcessingConfig.getSetting(SAGA_FOLDER)
-    if not os.path.isdir(folder):
+    if folder and not os.path.isdir(folder):
         folder = None
         ProcessingLog.addToLog(ProcessingLog.LOG_WARNING,
                                'Specified SAGA folder does not exist. Will try to find built-in binaries.')
diff --git a/python/plugins/processing/algs/taudem/TauDEMUtils.py b/python/plugins/processing/algs/taudem/TauDEMUtils.py
index c249eee..41567a2 100644
--- a/python/plugins/processing/algs/taudem/TauDEMUtils.py
+++ b/python/plugins/processing/algs/taudem/TauDEMUtils.py
@@ -102,6 +102,7 @@ class TauDEMUtils:
     def executeTauDEM(command, progress):
         loglines = []
         loglines.append(TauDEMUtils.tr('TauDEM execution console output'))
+        command = escapeAndJoin(command)
         fused_command = ''.join(['"%s" ' % c for c in command])
         progress.setInfo(TauDEMUtils.tr('TauDEM command:'))
         progress.setCommand(fused_command.replace('" "', ' ').strip('"'))
diff --git a/python/plugins/processing/core/GeoAlgorithm.py b/python/plugins/processing/core/GeoAlgorithm.py
index ca56a2e..70c3555 100644
--- a/python/plugins/processing/core/GeoAlgorithm.py
+++ b/python/plugins/processing/core/GeoAlgorithm.py
@@ -215,8 +215,13 @@ class GeoAlgorithm:
             lines = [self.tr('Uncaught error while executing algorithm')]
             lines.append(traceback.format_exc())
             ProcessingLog.addToLog(ProcessingLog.LOG_ERROR, lines)
+            try:
+                message = unicode(e)
+            except UnicodeDecodeError:
+                # Try with the 'replace' mode (requires e.message instead of e!)
+                message = unicode(e.message, 'utf-8', 'replace')
             raise GeoAlgorithmExecutionException(
-                unicode(e.message, errors='replace') + self.tr('\nSee log for more details'), lines, e)
+                message + self.tr(' \nSee log for more details'), lines, e)
 
     def _checkParameterValuesBeforeExecuting(self):
         for param in self.parameters:
diff --git a/python/plugins/processing/core/ProcessingConfig.py b/python/plugins/processing/core/ProcessingConfig.py
index b9f51d9..2bb9c1c 100644
--- a/python/plugins/processing/core/ProcessingConfig.py
+++ b/python/plugins/processing/core/ProcessingConfig.py
@@ -293,16 +293,15 @@ class Setting:
         self.validator(value)
         self.value = value
 
-    def read(self):
-        qsettings = QSettings()
+    def read(self, qsettings=QSettings()):
         value = qsettings.value(self.qname, None)
         if value is not None:
             if isinstance(self.value, bool):
                 value = unicode(value).lower() == unicode(True).lower()
             self.value = value
 
-    def save(self):
-        QSettings().setValue(self.qname, self.value)
+    def save(self, qsettings=QSettings()):
+        qsettings.setValue(self.qname, self.value)
 
     def __str__(self):
         return self.name + '=' + unicode(self.value)
diff --git a/python/plugins/processing/gui/BatchPanel.py b/python/plugins/processing/gui/BatchPanel.py
index 9effc5d..090f20e 100644
--- a/python/plugins/processing/gui/BatchPanel.py
+++ b/python/plugins/processing/gui/BatchPanel.py
@@ -267,7 +267,7 @@ class BatchPanel(BASE, WIDGET):
                         self.parent.lblProgress.setText(
                             self.tr('<b>Missing parameter value: %s (row %d)</b>') % (param.description, row + 1))
                         return
-                    algParams[param.name] = unicode(param.value())
+                    algParams[param.name] = unicode(param.value)
                 col += 1
             for out in alg.outputs:
                 if out.hidden:
diff --git a/python/plugins/processing/gui/ConfigDialog.py b/python/plugins/processing/gui/ConfigDialog.py
index 527694a..85d8641 100644
--- a/python/plugins/processing/gui/ConfigDialog.py
+++ b/python/plugins/processing/gui/ConfigDialog.py
@@ -28,8 +28,7 @@ __revision__ = '$Format:%H$'
 import os
 
 from qgis.PyQt import uic
-from qgis.PyQt.QtCore import (Qt,
-                              QEvent)
+from qgis.PyQt.QtCore import Qt, QEvent, QSettings
 from qgis.PyQt.QtWidgets import (QFileDialog,
                                  QDialog,
                                  QStyle,
@@ -264,6 +263,7 @@ class ConfigDialog(BASE, WIDGET):
 
     def accept(self):
         QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
+        qsettings = QSettings()
         for setting in self.items.keys():
             if setting.group != menusSettingsGroup or self.saveMenus:
                 if isinstance(setting.value, bool):
@@ -275,7 +275,7 @@ class ConfigDialog(BASE, WIDGET):
                         QMessageBox.warning(self, self.tr('Wrong value'),
                                             self.tr('Wrong value for parameter "%s":\n\n%s' % (setting.description, unicode(e))))
                         return
-                setting.save()
+                setting.save(qsettings)
         Processing.updateAlgsList()
         settingsWatcher.settingsChanged.emit()
         updateMenus()
@@ -345,6 +345,8 @@ class SettingDelegate(QStyledItemDelegate):
         setting = index.model().data(index, Qt.UserRole)
         if setting.valuetype == Setting.SELECTION:
             editor.setCurrentIndex(editor.findText(value))
+        elif setting.valuetype == Setting.INT or setting.valuetype == Setting.FLOAT:
+            editor.setValue(value)
         else:
             editor.setText(value)
 
diff --git a/python/plugins/processing/modeler/ModelerAlgorithm.py b/python/plugins/processing/modeler/ModelerAlgorithm.py
index 7afea74..0f4a594 100644
--- a/python/plugins/processing/modeler/ModelerAlgorithm.py
+++ b/python/plugins/processing/modeler/ModelerAlgorithm.py
@@ -507,6 +507,15 @@ class ModelerAlgorithm(GeoAlgorithm):
                             t0 = time.time()
                             alg.algorithm.execute(progress, self)
                             dt = time.time() - t0
+
+                            # copy algorithm output value(s) back to model in case the algorithm modified those
+                            for out in alg.algorithm.outputs:
+                                if not out.hidden:
+                                    if out.name in alg.outputs:
+                                        modelOut = self.getOutputFromName(self.getSafeNameForOutput(alg.name, out.name))
+                                        if modelOut:
+                                            modelOut.value = out.value
+
                             executed.append(alg.name)
                             progress.setDebugInfo(
                                 self.tr('OK. Execution took %0.3f ms (%i outputs).', 'ModelerAlgorithm') % (dt, len(alg.algorithm.outputs)))
diff --git a/python/plugins/processing/script/ScriptAlgorithm.py b/python/plugins/processing/script/ScriptAlgorithm.py
index 9b9c171..aeaee13 100644
--- a/python/plugins/processing/script/ScriptAlgorithm.py
+++ b/python/plugins/processing/script/ScriptAlgorithm.py
@@ -321,9 +321,9 @@ class ScriptAlgorithm(GeoAlgorithm):
             out = OutputHTML()
         elif token.lower().strip().startswith('file'):
             out = OutputFile()
-            subtokens = token.split(' ')
-            if len(subtokens) > 2:
-                out.ext = subtokens[2]
+            ext = token.strip()[len('file') + 1:]
+            if ext:
+                out.ext = ext
         elif token.lower().strip().startswith('directory'):
             out = OutputDirectory()
         elif token.lower().strip().startswith('number'):
diff --git a/python/plugins/processing/tests/testdata/custom/union1_a.geojson b/python/plugins/processing/tests/testdata/custom/union1_a.geojson
new file mode 100644
index 0000000..5ac00b9
--- /dev/null
+++ b/python/plugins/processing/tests/testdata/custom/union1_a.geojson
@@ -0,0 +1,10 @@
+{
+"type": "FeatureCollection",
+"crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:EPSG::3857" } },
+"features": [
+{ "type": "Feature", "properties": { "id_a": "A1" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 1.0, 3.0 ], [ 2.0, 3.0 ], [ 2.0, 10.0 ], [ 8.0, 10.0 ], [ 8.0, 11.0 ], [ 1.0, 11.0 ], [ 1.0, 3.0 ] ] ] } },
+{ "type": "Feature", "properties": { "id_a": "A4" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 3.0, 3.0 ], [ 3.0, 4.0 ], [ 4.0, 4.0 ], [ 4.0, 3.0 ], [ 3.0, 3.0 ] ] ] } },
+{ "type": "Feature", "properties": { "id_a": "A2" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 3.0, 5.0 ], [ 6.0, 5.0 ], [ 6.0, 6.0 ], [ 3.0, 6.0 ], [ 3.0, 5.0 ] ] ] } },
+{ "type": "Feature", "properties": { "id_a": "A3" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 5.0, 7.0 ], [ 9.0, 7.0 ], [ 9.0, 8.0 ], [ 5.0, 8.0 ], [ 5.0, 7.0 ] ] ] } }
+]
+}
diff --git a/python/plugins/processing/tests/testdata/custom/union1_b.geojson b/python/plugins/processing/tests/testdata/custom/union1_b.geojson
new file mode 100644
index 0000000..5d684fb
--- /dev/null
+++ b/python/plugins/processing/tests/testdata/custom/union1_b.geojson
@@ -0,0 +1,10 @@
+{
+"type": "FeatureCollection",
+"crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:EPSG::3857" } },
+"features": [
+{ "type": "Feature", "properties": { "id_b": "B1" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 1.0, 1.0 ], [ 8.0, 1.0 ], [ 8.0, 9.0 ], [ 7.0, 9.0 ], [ 7.0, 2.0 ], [ 1.0, 2.0 ], [ 1.0, 1.0 ] ] ] } },
+{ "type": "Feature", "properties": { "id_b": "B4" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 5.0, 3.0 ], [ 6.0, 3.0 ], [ 6.0, 4.0 ], [ 5.0, 4.0 ], [ 5.0, 3.0 ] ] ] } },
+{ "type": "Feature", "properties": { "id_b": "B2" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 0.0, 5.0 ], [ 4.0, 5.0 ], [ 4.0, 6.0 ], [ 0.0, 6.0 ], [ 0.0, 5.0 ] ] ] } },
+{ "type": "Feature", "properties": { "id_b": "B3" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 3.0, 7.0 ], [ 6.0, 7.0 ], [ 6.0, 8.0 ], [ 3.0, 8.0 ], [ 3.0, 7.0 ] ] ] } }
+]
+}
diff --git a/python/plugins/processing/tests/testdata/expected/union1.gml b/python/plugins/processing/tests/testdata/expected/union1.gml
new file mode 100644
index 0000000..36fadf2
--- /dev/null
+++ b/python/plugins/processing/tests/testdata/expected/union1.gml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<ogr:FeatureCollection
+     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+     xsi:schemaLocation="http://ogr.maptools.org/ union1.xsd"
+     xmlns:ogr="http://ogr.maptools.org/"
+     xmlns:gml="http://www.opengis.net/gml">
+  <gml:boundedBy>
+    <gml:Box>
+      <gml:coord><gml:X>0</gml:X><gml:Y>1</gml:Y></gml:coord>
+      <gml:coord><gml:X>9</gml:X><gml:Y>11</gml:Y></gml:coord>
+    </gml:Box>
+  </gml:boundedBy>
+                                                                                                                                                               
+  <gml:featureMember>
+    <ogr:union1 fid="union1.0">
+      <ogr:geometryProperty><gml:Polygon srsName="EPSG:3857"><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>2,6 2,5 1,5 1,6 2,6</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></ogr:geometryProperty>
+      <ogr:id_a>A1</ogr:id_a>
+      <ogr:id_b>B2</ogr:id_b>
+    </ogr:union1>
+  </gml:featureMember>
+  <gml:featureMember>
+    <ogr:union1 fid="union1.1">
+      <ogr:geometryProperty><gml:MultiPolygon srsName="EPSG:3857"><gml:polygonMember><gml:Polygon><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>2,5 2,3 1,3 1,5 2,5</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></gml:polygonMember><gml:polygonMember><gml:Polygon><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>1,6 1,11 8,11 8,10 2,10 2,6 1,6</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></gml:polygonMember></gml:MultiPolygon></o [...]
+      <ogr:id_a>A1</ogr:id_a>
+    </ogr:union1>
+  </gml:featureMember>
+  <gml:featureMember>
+    <ogr:union1 fid="union1.2">
+      <ogr:geometryProperty><gml:Polygon srsName="EPSG:3857"><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>3,3 3,4 4,4 4,3 3,3</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></ogr:geometryProperty>
+      <ogr:id_a>A4</ogr:id_a>
+    </ogr:union1>
+  </gml:featureMember>
+  <gml:featureMember>
+    <ogr:union1 fid="union1.3">
+      <ogr:geometryProperty><gml:Polygon srsName="EPSG:3857"><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>4,5 3,5 3,6 4,6 4,5</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></ogr:geometryProperty>
+      <ogr:id_a>A2</ogr:id_a>
+      <ogr:id_b>B2</ogr:id_b>
+    </ogr:union1>
+  </gml:featureMember>
+  <gml:featureMember>
+    <ogr:union1 fid="union1.4">
+      <ogr:geometryProperty><gml:Polygon srsName="EPSG:3857"><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>4,6 6,6 6,5 4,5 4,6</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></ogr:geometryProperty>
+      <ogr:id_a>A2</ogr:id_a>
+    </ogr:union1>
+  </gml:featureMember>
+  <gml:featureMember>
+    <ogr:union1 fid="union1.5">
+      <ogr:geometryProperty><gml:Polygon srsName="EPSG:3857"><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>8,7 7,7 7,8 8,8 8,7</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></ogr:geometryProperty>
+      <ogr:id_a>A3</ogr:id_a>
+      <ogr:id_b>B1</ogr:id_b>
+    </ogr:union1>
+  </gml:featureMember>
+  <gml:featureMember>
+    <ogr:union1 fid="union1.6">
+      <ogr:geometryProperty><gml:Polygon srsName="EPSG:3857"><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>6,7 5,7 5,8 6,8 6,7</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></ogr:geometryProperty>
+      <ogr:id_a>A3</ogr:id_a>
+      <ogr:id_b>B3</ogr:id_b>
+    </ogr:union1>
+  </gml:featureMember>
+  <gml:featureMember>
+    <ogr:union1 fid="union1.7">
+      <ogr:geometryProperty><gml:MultiPolygon srsName="EPSG:3857"><gml:polygonMember><gml:Polygon><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>7,7 6,7 6,8 7,8 7,7</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></gml:polygonMember><gml:polygonMember><gml:Polygon><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>8,8 9,8 9,7 8,7 8,8</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></gml:polygonMember></gml:MultiPolygon></ogr:geometryP [...]
+      <ogr:id_a>A3</ogr:id_a>
+    </ogr:union1>
+  </gml:featureMember>
+  <gml:featureMember>
+    <ogr:union1 fid="union1.8">
+      <ogr:geometryProperty><gml:MultiPolygon srsName="EPSG:3857"><gml:polygonMember><gml:Polygon><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>8,7 8,1 1,1 1,2 7,2 7,7 8,7</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></gml:polygonMember><gml:polygonMember><gml:Polygon><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>7,8 7,9 8,9 8,8 7,8</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></gml:polygonMember></gml:MultiPolygon></ogr:g [...]
+      <ogr:id_b>B1</ogr:id_b>
+    </ogr:union1>
+  </gml:featureMember>
+  <gml:featureMember>
+    <ogr:union1 fid="union1.9">
+      <ogr:geometryProperty><gml:Polygon srsName="EPSG:3857"><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>5,3 6,3 6,4 5,4 5,3</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></ogr:geometryProperty>
+      <ogr:id_b>B4</ogr:id_b>
+    </ogr:union1>
+  </gml:featureMember>
+  <gml:featureMember>
+    <ogr:union1 fid="union1.10">
+      <ogr:geometryProperty><gml:MultiPolygon srsName="EPSG:3857"><gml:polygonMember><gml:Polygon><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>1,5 0,5 0,6 1,6 1,5</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></gml:polygonMember><gml:polygonMember><gml:Polygon><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>3,5 2,5 2,6 3,6 3,5</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></gml:polygonMember></gml:MultiPolygon></ogr:geometryP [...]
+      <ogr:id_b>B2</ogr:id_b>
+    </ogr:union1>
+  </gml:featureMember>
+  <gml:featureMember>
+    <ogr:union1 fid="union1.11">
+      <ogr:geometryProperty><gml:Polygon srsName="EPSG:3857"><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>5,7 3,7 3,8 5,8 5,7</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></ogr:geometryProperty>
+      <ogr:id_b>B3</ogr:id_b>
+    </ogr:union1>
+  </gml:featureMember>
+</ogr:FeatureCollection>
diff --git a/python/plugins/processing/tests/testdata/expected/union1.xsd b/python/plugins/processing/tests/testdata/expected/union1.xsd
new file mode 100644
index 0000000..8860ddf
--- /dev/null
+++ b/python/plugins/processing/tests/testdata/expected/union1.xsd
@@ -0,0 +1,37 @@
+<?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="union1" type="ogr:union1_Type" substitutionGroup="gml:_Feature"/>
+<xs:complexType name="union1_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="id_a" 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="id_b" nillable="true" minOccurs="0" maxOccurs="1">
+          <xs:simpleType>
+            <xs:restriction base="xs:string">
+              <xs:maxLength value="255"/>
+            </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 07b594e..b039827 100644
--- a/python/plugins/processing/tests/testdata/qgis_algorithm_tests.yaml
+++ b/python/plugins/processing/tests/testdata/qgis_algorithm_tests.yaml
@@ -583,3 +583,22 @@ tests:
       OUTPUT_LAYER:
         name: expected/point_on_line.gml
         type: vector
+
+  - algorithm: qgis:union
+    name: Test Union (basic)
+    params:
+      INPUT:
+        name: custom/union1_a.geojson
+        type: vector
+      INPUT2:
+        name: custom/union1_b.geojson
+        type: vector
+    results:
+      OUTPUT:
+        name: expected/union1.gml
+        type: vector
+        # TODO: may need improvements to comparison
+        # - unordered comparison
+        #   (features could be written in different order and still being correct output)
+        # - geometry equality comparison instead of WKT string comparison
+        #   (geometries could different order of coordinate but still being correct output)
diff --git a/python/plugins/processing/tools/system.py b/python/plugins/processing/tools/system.py
index fa77d82..913b195 100644
--- a/python/plugins/processing/tools/system.py
+++ b/python/plugins/processing/tools/system.py
@@ -136,3 +136,15 @@ def mkdir(newdir):
             mkdir(head)
         if tail:
             os.mkdir(newdir)
+
+
+def escapeAndJoin(strList):
+    joined = ''
+    for s in strList:
+        if s[0] != '-' and ' ' in s:
+            escaped = '"' + s.replace('\\', '\\\\').replace('"', '\\"') \
+                + '"'
+        else:
+            escaped = s
+        joined += escaped + ' '
+    return joined.strip()
diff --git a/python/server/qgswmsconfigparser.sip b/python/server/qgswmsconfigparser.sip
index f05752c..d231637 100644
--- a/python/server/qgswmsconfigparser.sip
+++ b/python/server/qgswmsconfigparser.sip
@@ -115,7 +115,7 @@ class QgsWMSConfigParser
     virtual void setScaleDenominator( double denom ) = 0;
     virtual void addExternalGMLData( const QString& layerName, QDomDocument* gmlDoc ) = 0;
 
-    virtual QList< QPair< QString, QgsLayerCoordinateTransform > > layerCoordinateTransforms() const = 0;
+    // virtual QList< QPair< QString, QgsLayerCoordinateTransform > > layerCoordinateTransforms() const = 0;
 
     virtual int nLayers() const = 0;
 
diff --git a/python/server/qgswmsprojectparser.sip b/python/server/qgswmsprojectparser.sip
index f6dd579..13fea73 100644
--- a/python/server/qgswmsprojectparser.sip
+++ b/python/server/qgswmsprojectparser.sip
@@ -63,7 +63,7 @@ class QgsWMSProjectParser : public QgsWMSConfigParser
     void setScaleDenominator( double )  /*override*/;
     void addExternalGMLData( const QString&, QDomDocument* )  /*override*/ ;
 
-    QList< QPair< QString, QgsLayerCoordinateTransform > > layerCoordinateTransforms() const  /*override*/ ;
+    // QList< QPair< QString, QgsLayerCoordinateTransform > > layerCoordinateTransforms() const  /*override*/ ;
 
     /** 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*/
     int layersAndStyles( QStringList& layers, QStringList& styles ) const  /*override*/ ;
diff --git a/python/server/server.sip b/python/server/server.sip
index 537cd0b..355d3fa 100644
--- a/python/server/server.sip
+++ b/python/server/server.sip
@@ -1,5 +1,4 @@
 %Module(name=qgis._server,
-        version=0,
         keyword_arguments="Optional")
 
 
diff --git a/scripts/release.pl b/scripts/release.pl
index 7853935..5b5ce63 100755
--- a/scripts/release.pl
+++ b/scripts/release.pl
@@ -76,7 +76,6 @@ $i++ if defined $dominor;
 $i++ if defined $dopoint;
 pod2usage("Exactly one of -major, -minor or -point expected") if $i!=1;
 pod2usage("Release name for major and minor releases expected") if !$dopoint && !defined $newreleasename;
-pod2usage("Long term releases only for major and minor releases") if $doltr && $dopoint;
 pod2usage("Pre-major releases can only be minor releases") if $dopremajor && !$dominor;
 pod2usage("No CMakeLists.txt in current directory") unless -r "CMakeLists.txt";
 
@@ -155,7 +154,7 @@ unless( $dopoint ) {
 		print "Pulling transifex translations...\n";
 		run( "scripts/pull_ts.sh", "pull_ts.sh failed" );
 		run( "git add i18n/*.ts", "adding translations failed" );
-		run( "git commit -a -m \"translation update for $release from transifex\"", "could not commit translation updates" );
+		run( "git commit -n -a -m \"translation update for $release from transifex\"", "could not commit translation updates" );
 	} else {
 		print "TRANSIFEX UPDATE SKIPPED!\n";
 	}
@@ -167,7 +166,7 @@ run( "scripts/create_changelog.sh", "create_changelog.sh failed" );
 unless( $dopoint ) {
 	run( "scripts/update-news.pl $newmajor $newminor '$newreleasename'", "could not update news" ) if $major>2 || ($major==2 && $minor>14);
 
-	run( "git commit -a -m \"changelog and news update for $release\"", "could not commit changelog and news update" );
+	run( "git commit -n -a -m \"changelog and news update for $release\"", "could not commit changelog and news update" );
 
 	print "Creating and checking out branch...\n";
 	run( "git checkout -b $relbranch", "git checkout release branch failed" );
@@ -190,14 +189,15 @@ unless( $dopoint ) {
 		print "WARNING: NO images/splash/splash-release.xcf.bz2\n";
 	}
 
-	run( "git commit -a -m 'Release of $release ($newreleasename)'", "release commit failed" );
+	run( "git commit -n -a -m 'Release of $release ($newreleasename)'", "release commit failed" );
 	run( "git tag $reltag -m 'Version $release'", "release tag failed" );
-	run( "git tag $ltrtag -m 'Long term release $release'", "ltr tag failed" ) if $doltr;
 } else {
-	run( "git commit -a -m 'Release of $version'", "release commit failed" );
+	run( "git commit -n -a -m 'Release of $version'", "release commit failed" );
 	run( "git tag $reltag -m 'Version $version'", "tag failed" );
 }
 
+run( "git tag $ltrtag -m 'Long term release $release'", "ltr tag failed" ) if $doltr;
+
 print "Producing archive...\n";
 run( "git archive --format tar --prefix=qgis-$version/ $reltag | bzip2 -c >qgis-$version.tar.bz2", "git archive failed" );
 run( "md5sum qgis-$version.tar.bz2 >qgis-$version.tar.bz2.md5", "md5sum failed" );
@@ -216,7 +216,7 @@ unless( $dopoint ) {
 		run( "cp /tmp/changelog debian", "restore changelog failed" );
 		run( "dch -r ''", "dch failed" );
 		run( "dch --newversion $newmajor.$newminor.0 'New development version $newmajor.$newminor after branch of $release'", "dch failed" );
-		run( "git commit -a -m 'New development branch for interim $newmajor.x releases'", "bump version failed" );
+		run( "git commit -n -a -m 'New development branch for interim $newmajor.x releases'", "bump version failed" );
 
 		push @topush, "master_$newmajor";
 
@@ -228,7 +228,7 @@ unless( $dopoint ) {
 	run( "cp /tmp/changelog debian", "restore changelog failed" );
 	run( "dch -r ''", "dch failed" );
 	run( "dch --newversion $newmajor.$newminor.0 'New development version $newmajor.$newminor after branch of $release'", "dch failed" );
-	run( "git commit -a -m 'Bump version to $newmajor.$newminor'", "bump version failed" );
+	run( "git commit -n -a -m 'Bump version to $newmajor.$newminor'", "bump version failed" );
 
 	push @topush, $branch;
 }
@@ -238,7 +238,7 @@ my $topush = join(" ", @topush);
 
 print "Push dry-run...\n";
 run( "git push -n --follow-tags origin $topush", "push dry run failed" );
-print "Now manually push and upload the tarballs :\n\tgit push --follow-tags origin $topush\n\trsync qgis-$version.tar.bz2* qgis.org:/var/www/downloads/\n\n";
+print "Now manually push and upload the tar balls:\n\tgit push --follow-tags origin $topush\n\trsync qgis-$version.tar.bz2* ssh.qgis.org:/var/www/downloads/\n\n";
 print "WARNING: TRANSIFEX UPDATE SKIPPED!\n" if $skipts;
 
 
diff --git a/src/app/CMakeLists.txt b/src/app/CMakeLists.txt
index 15579de..b6ef545 100644
--- a/src/app/CMakeLists.txt
+++ b/src/app/CMakeLists.txt
@@ -609,7 +609,7 @@ TARGET_LINK_LIBRARIES(qgis_app
   ${QWT_LIBRARY}
   ${QT_QTSQL_LIBRARY}
   ${QT_QTUITOOLS_LIBRARY}
-  ${QT_QTWEBKIT_LIBRARY}
+  ${OPTIONAL_QTWEBKIT}
   #should only be needed for win
   ${QT_QTMAIN_LIBRARY}
   ${QWTPOLAR_LIBRARY}
diff --git a/src/app/qgisapp.cpp b/src/app/qgisapp.cpp
index 400a664..bcd7a46 100644
--- a/src/app/qgisapp.cpp
+++ b/src/app/qgisapp.cpp
@@ -5105,6 +5105,9 @@ void QgisApp::dxfExport()
   if ( d.exec() == QDialog::Accepted )
   {
     QgsDxfExport dxfExport;
+    QgsMapSettings settings( mapCanvas()->mapSettings() );
+    settings.setLayerStyleOverrides( QgsProject::instance()->visibilityPresetCollection()->presetStyleOverrides( d.mapTheme() ) );
+    dxfExport.setMapSettings( settings );
     dxfExport.addLayers( d.layers() );
     dxfExport.setSymbologyScaleDenominator( d.symbologyScale() );
     dxfExport.setSymbologyExport( d.symbologyMode() );
diff --git a/src/app/qgsdxfexportdialog.cpp b/src/app/qgsdxfexportdialog.cpp
index 64da1cf..4f6a873 100644
--- a/src/app/qgsdxfexportdialog.cpp
+++ b/src/app/qgsdxfexportdialog.cpp
@@ -639,3 +639,8 @@ long QgsDxfExportDialog::crs() const
 {
   return mCRS;
 }
+
+QString QgsDxfExportDialog::mapTheme() const
+{
+  return mVisibilityPresets->currentText();
+}
diff --git a/src/app/qgsdxfexportdialog.h b/src/app/qgsdxfexportdialog.h
index b795cfc..2b46677 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;
+    QString mapTheme() const;
     QString encoding() const;
     long crs() const;
 
diff --git a/src/app/qgsfieldsproperties.cpp b/src/app/qgsfieldsproperties.cpp
index b5bd2b2..24440da 100644
--- a/src/app/qgsfieldsproperties.cpp
+++ b/src/app/qgsfieldsproperties.cpp
@@ -987,11 +987,11 @@ void QgsFieldsProperties::apply()
     int idx = mFieldsList->item( i, attrIdCol )->text().toInt();
     FieldConfig cfg = configForRow( i );
 
-    mLayer->editFormConfig()->setReadOnly( i, !cfg.mEditable );
-    mLayer->editFormConfig()->setLabelOnTop( i, cfg.mLabelOnTop );
-    mLayer->editFormConfig()->setNotNull( i, cfg.mNotNull );
-    mLayer->editFormConfig()->setExpressionDescription( i, cfg.mConstraintDescription );
-    mLayer->editFormConfig()->setExpression( i, cfg.mConstraint );
+    mLayer->editFormConfig()->setReadOnly( idx, !cfg.mEditable );
+    mLayer->editFormConfig()->setLabelOnTop( idx, cfg.mLabelOnTop );
+    mLayer->editFormConfig()->setNotNull( idx, cfg.mNotNull );
+    mLayer->editFormConfig()->setExpressionDescription( idx, cfg.mConstraintDescription );
+    mLayer->editFormConfig()->setExpression( idx, cfg.mConstraint );
 
     mLayer->editFormConfig()->setWidgetType( idx, cfg.mEditorWidgetV2Type );
     mLayer->editFormConfig()->setWidgetConfig( idx, cfg.mEditorWidgetV2Config );
diff --git a/src/browser/CMakeLists.txt b/src/browser/CMakeLists.txt
index e53c1de..1a72070 100644
--- a/src/browser/CMakeLists.txt
+++ b/src/browser/CMakeLists.txt
@@ -80,7 +80,7 @@ TARGET_LINK_LIBRARIES(qbrowser
   ${QT_QTNETWORK_LIBRARY}
   ${QT_QTSVG_LIBRARY}
   ${QT_QTXML_LIBRARY}
-  ${QT_QTWEBKIT_LIBRARY}
+  ${OPTIONAL_QTWEBKIT}
   ${QT_QTMAIN_LIBRARY}
   ${SQLITE3_LIBRARY}
 )
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index e2d9ae8..cd8e305 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -981,7 +981,7 @@ TARGET_LINK_LIBRARIES(qgis_core
   ${QT_QTGUI_LIBRARY}
   ${QT_QTNETWORK_LIBRARY}
   ${QT_QTSVG_LIBRARY}
-  ${QT_QTWEBKIT_LIBRARY}
+  ${OPTIONAL_QTWEBKIT}
   ${QT_QTSQL_LIBRARY}
   ${QCA_LIBRARY}
 
diff --git a/src/core/dxf/qgsdxfexport.cpp b/src/core/dxf/qgsdxfexport.cpp
index 85aeba0..8cfa66f 100644
--- a/src/core/dxf/qgsdxfexport.cpp
+++ b/src/core/dxf/qgsdxfexport.cpp
@@ -36,6 +36,7 @@
 #include "qgslinesymbollayerv2.h"
 #include "qgsvectorlayer.h"
 #include "qgsmaplayerregistry.h"
+#include "qgsmaplayerstylemanager.h"
 #include "qgsunittypes.h"
 #include "qgstextlabelfeature.h"
 #include "qgscrscache.h"
@@ -380,9 +381,10 @@ QgsDxfExport::QgsDxfExport( const QgsDxfExport& dxfExport )
   *this = dxfExport;
 }
 
-QgsDxfExport& QgsDxfExport::operator=( const QgsDxfExport & dxfExport )
+QgsDxfExport &QgsDxfExport::operator=( const QgsDxfExport & dxfExport )
 {
-  mLayers = dxfExport.mLayers;
+  mMapSettings = dxfExport.mMapSettings;
+  mLayerNameAttribute = dxfExport.mLayerNameAttribute;
   mSymbologyScaleDenominator = dxfExport.mSymbologyScaleDenominator;
   mSymbologyExport = dxfExport.mSymbologyExport;
   mMapUnits = dxfExport.mMapUnits;
@@ -398,9 +400,26 @@ QgsDxfExport::~QgsDxfExport()
 {
 }
 
+void QgsDxfExport::setMapSettings( const QgsMapSettings &settings )
+{
+  mMapSettings = settings;
+}
+
 void QgsDxfExport::addLayers( const QList< QPair< QgsVectorLayer *, int > > &layers )
 {
-  mLayers = layers;
+  QStringList layerList;
+
+  mLayerNameAttribute.clear();
+
+  QList< QPair< QgsVectorLayer*, int > >::const_iterator layerIt = layers.constBegin();
+  for ( ; layerIt != layers.constEnd(); ++layerIt )
+  {
+    layerList << layerIt->first->id();
+    if ( layerIt->second >= 0 )
+      mLayerNameAttribute.insert( layerIt->first->id(), layerIt->second );
+  }
+
+  mMapSettings.setLayers( layerList );
 }
 
 void QgsDxfExport::writeGroup( int code, int i )
@@ -506,22 +525,22 @@ int QgsDxfExport::writeToFile( QIODevice* d, const QString& encoding )
 
   if ( mExtent.isEmpty() )
   {
-    QList< QPair<QgsVectorLayer*, int> >::const_iterator layerIt = mLayers.constBegin();
-    for ( ; layerIt != mLayers.constEnd(); ++layerIt )
+    Q_FOREACH ( QString id, mMapSettings.layers() )
     {
-      if ( layerIt->first )
-      {
-        QgsRectangle layerExtent = layerIt->first->extent();
-        layerExtent = mMapSettings.layerToMapCoordinates( layerIt->first, layerExtent );
+      QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( QgsMapLayerRegistry::instance()->mapLayer( id ) );
+      if ( !vl )
+        continue;
 
-        if ( mExtent.isEmpty() )
-        {
-          mExtent = layerExtent;
-        }
-        else
-        {
-          mExtent.combineExtentWith( layerExtent );
-        }
+      QgsRectangle layerExtent = vl->extent();
+      layerExtent = mMapSettings.layerToMapCoordinates( vl, layerExtent );
+
+      if ( mExtent.isEmpty() )
+      {
+        mExtent = layerExtent;
+      }
+      else
+      {
+        mExtent.combineExtentWith( layerExtent );
       }
     }
   }
@@ -756,27 +775,25 @@ void QgsDxfExport::writeTables()
   writeGroup( 70, 0 );
   writeGroup( 0, "ENDTAB" );
 
-  QList< QPair<QgsVectorLayer*, int> >::const_iterator layerIt = mLayers.constBegin();
   QSet<QString> layerNames;
-  for ( ; layerIt != mLayers.constEnd(); ++layerIt )
+  Q_FOREACH ( QString id, mMapSettings.layers() )
   {
-    if ( !layerIsScaleBasedVisible( layerIt->first ) )
+    QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( QgsMapLayerRegistry::instance()->mapLayer( id ) );
+    if ( !vl || !layerIsScaleBasedVisible( vl ) )
       continue;
 
-    if ( layerIt->first )
+    int attrIdx = mLayerNameAttribute.value( vl->id(), -1 );
+    if ( attrIdx < 0 )
     {
-      if ( layerIt->second < 0 )
-      {
-        layerNames << dxfLayerName( layerName( layerIt->first ) );
-      }
-      else
+      layerNames << dxfLayerName( layerName( vl ) );
+    }
+    else
+    {
+      QList<QVariant> values;
+      vl->uniqueValues( attrIdx, values );
+      Q_FOREACH ( const QVariant& v, values )
       {
-        QList<QVariant> values;
-        layerIt->first->uniqueValues( layerIt->second, values );
-        Q_FOREACH ( const QVariant& v, values )
-        {
-          layerNames << dxfLayerName( v.toString() );
-        }
+        layerNames << dxfLayerName( v.toString() );
       }
     }
   }
@@ -954,27 +971,40 @@ void QgsDxfExport::writeEntities()
   engine.setMapSettings( mMapSettings );
 
   // iterate through the maplayers
-  QList< QPair< QgsVectorLayer*, int > >::const_iterator layerIt = mLayers.constBegin();
-  for ( ; layerIt != mLayers.constEnd(); ++layerIt )
+  Q_FOREACH ( QString id, mMapSettings.layers() )
   {
-    QgsVectorLayer* vl = layerIt->first;
+    QgsVectorLayer* vl = qobject_cast<QgsVectorLayer *>( QgsMapLayerRegistry::instance()->mapLayer( id ) );
     if ( !vl || !layerIsScaleBasedVisible( vl ) )
     {
       continue;
     }
 
+    bool hasStyleOverride = mMapSettings.layerStyleOverrides().contains( vl->id() );
+    if ( hasStyleOverride )
+    {
+      QgsDebugMsg( QString( "%1: apply override style" ).arg( vl->id() ) );
+      vl->styleManager()->setOverrideStyle( mMapSettings.layerStyleOverrides().value( vl->id() ) );
+    }
+    else
+    {
+      QgsDebugMsg( QString( "%1: not override style" ).arg( vl->id() ) );
+    }
+
     QgsSymbolV2RenderContext sctx( ctx, QgsSymbolV2::MM, 1.0, false, 0, nullptr );
     QgsFeatureRendererV2* renderer = vl->rendererV2();
     if ( !renderer )
     {
+      if ( hasStyleOverride )
+        vl->styleManager()->restoreOverrideStyle();
       continue;
     }
     renderer->startRender( ctx, vl->fields() );
 
     QStringList attributes = renderer->usedAttributes();
-    if ( vl->fields().exists( layerIt->second ) )
+    int attrIdx = mLayerNameAttribute.value( vl->id(), 1 );
+    if ( vl->fields().exists( attrIdx ) )
     {
-      QString layerAttr = vl->fields().at( layerIt->second ).name();
+      QString layerAttr = vl->fields().at( attrIdx ).name();
       if ( !attributes.contains( layerAttr ) )
         attributes << layerAttr;
     }
@@ -1012,6 +1042,10 @@ void QgsDxfExport::writeEntities()
     {
       writeEntitiesSymbolLevels( vl );
       renderer->stopRender( ctx );
+
+      if ( hasStyleOverride )
+        vl->styleManager()->restoreOverrideStyle();
+
       continue;
     }
 
@@ -1026,7 +1060,7 @@ void QgsDxfExport::writeEntities()
     while ( featureIt.nextFeature( fet ) )
     {
       ctx.expressionContext().setFeature( fet );
-      QString lName( dxfLayerName( layerIt->second == -1 ? layerName( vl ) : fet.attribute( layerIt->second ).toString() ) );
+      QString lName( dxfLayerName( attrIdx < 0 ? layerName( vl ) : fet.attribute( attrIdx ).toString() ) );
 
       sctx.setFeature( &fet );
       if ( mSymbologyExport == NoSymbology )
@@ -1076,6 +1110,9 @@ void QgsDxfExport::writeEntities()
     }
 
     renderer->stopRender( ctx );
+
+    if ( hasStyleOverride )
+      vl->styleManager()->restoreOverrideStyle();
   }
 
   engine.run( ctx );
@@ -4014,11 +4051,9 @@ QList< QPair< QgsSymbolLayerV2*, QgsSymbolV2* > > QgsDxfExport::symbolLayers( Qg
 {
   QList< QPair< QgsSymbolLayerV2*, QgsSymbolV2* > > symbolLayers;
 
-  QList< QPair< QgsVectorLayer*, int> >::const_iterator lIt = mLayers.constBegin();
-  for ( ; lIt != mLayers.constEnd(); ++lIt )
+  Q_FOREACH ( QString id, mMapSettings.layers() )
   {
-    // cast to vector layer
-    QgsVectorLayer* vl = lIt->first;
+    QgsVectorLayer* vl = qobject_cast<QgsVectorLayer *>( QgsMapLayerRegistry::instance()->mapLayer( id ) );
     if ( !vl )
     {
       continue;
@@ -4271,12 +4306,13 @@ bool QgsDxfExport::layerIsScaleBasedVisible( const QgsMapLayer* layer ) const
 
 QString QgsDxfExport::layerName( const QString &id, const QgsFeature &f ) const
 {
-  QList< QPair<QgsVectorLayer*, int> >::const_iterator layerIt = mLayers.constBegin();
-  for ( ; layerIt != mLayers.constEnd(); ++layerIt )
+  Q_FOREACH ( QString lid, mMapSettings.layers() )
   {
-    if ( layerIt->first && layerIt->first->id() == id )
+    QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( QgsMapLayerRegistry::instance()->mapLayer( lid ) );
+    if ( vl && vl->id() == id )
     {
-      return dxfLayerName( layerIt->second < 0 ? layerName( layerIt->first ) : f.attribute( layerIt->second ).toString() );
+      int attrIdx = mLayerNameAttribute.value( vl->id(), -1 );
+      return dxfLayerName( attrIdx < 0 ? layerName( vl ) : f.attribute( attrIdx ).toString() );
     }
   }
 
diff --git a/src/core/dxf/qgsdxfexport.h b/src/core/dxf/qgsdxfexport.h
index fcfd81b..1811edf 100644
--- a/src/core/dxf/qgsdxfexport.h
+++ b/src/core/dxf/qgsdxfexport.h
@@ -56,6 +56,12 @@ class CORE_EXPORT QgsDxfExport
     QgsDxfExport &operator=( const QgsDxfExport &dxfExport );
 
     /**
+     * Set map settings and assign layer name attributes
+     * @param settings map settings to apply
+     */
+    void setMapSettings( const QgsMapSettings &settings );
+
+    /**
      * Add layers to export
      * @param layers list of layers and corresponding attribute indexes that determine the layer name (-1 for original layer name or title)
      * @see setLayerTitleAsName
@@ -391,8 +397,6 @@ class CORE_EXPORT QgsDxfExport
     void registerDxfLayer( QString layerId, QgsFeatureId fid, QString layer );
 
   private:
-    QList< QPair<QgsVectorLayer*, int> > mLayers;
-
     /** Extent for export, only intersecting features are exported. If the extent is an empty rectangle, all features are exported*/
     QgsRectangle mExtent;
     /** Scale for symbology export (used if symbols units are mm)*/
@@ -459,6 +463,7 @@ class CORE_EXPORT QgsDxfExport
     QMap< QString, QMap<QgsFeatureId, QString> > mDxfLayerNames;
     long mCrs;
     QgsMapSettings mMapSettings;
+    QHash<QString, int> mLayerNameAttribute;
     double mFactor;
 };
 
diff --git a/src/core/geometry/qgscircularstringv2.cpp b/src/core/geometry/qgscircularstringv2.cpp
index 2c55584..0357715 100644
--- a/src/core/geometry/qgscircularstringv2.cpp
+++ b/src/core/geometry/qgscircularstringv2.cpp
@@ -475,14 +475,25 @@ void QgsCircularStringV2::setPoints( const QgsPointSequenceV2 &points )
 
 void QgsCircularStringV2::segmentize( const QgsPointV2& p1, const QgsPointV2& p2, const QgsPointV2& p3, QgsPointSequenceV2 &points, double tolerance, SegmentationToleranceType toleranceType ) const
 {
+  bool clockwise = false;
+  int segSide = segmentSide( p1, p3, p2 );
+  if ( segSide == -1 )
+  {
+    clockwise = true;
+  }
+
+  QgsPointV2 circlePoint1 = clockwise ? p3 : p1;
+  QgsPointV2 circlePoint2 = p2;
+  QgsPointV2 circlePoint3 = clockwise ? p1 : p3 ;
+
   //adapted code from postgis
   double radius = 0;
   double centerX = 0;
   double centerY = 0;
-  QgsGeometryUtils::circleCenterRadius( p1, p2, p3, radius, centerX, centerY );
-  int segSide = segmentSide( p1, p3, p2 );
+  QgsGeometryUtils::circleCenterRadius( circlePoint1, circlePoint2, circlePoint3, radius, centerX, centerY );
 
-  if ( p1 != p3 && ( radius < 0 || qgsDoubleNear( segSide, 0.0 ) ) ) //points are colinear
+
+  if ( circlePoint1 != circlePoint3 && ( radius < 0 || qgsDoubleNear( segSide, 0.0 ) ) ) //points are colinear
   {
     points.append( p1 );
     points.append( p2 );
@@ -490,12 +501,6 @@ void QgsCircularStringV2::segmentize( const QgsPointV2& p1, const QgsPointV2& p2
     return;
   }
 
-  bool clockwise = false;
-  if ( segSide == -1 )
-  {
-    clockwise = true;
-  }
-
   double increment = tolerance; //one segment per degree
   if ( toleranceType == QgsAbstractGeometryV2::MaximumDifference )
   {
@@ -504,27 +509,15 @@ void QgsCircularStringV2::segmentize( const QgsPointV2& p1, const QgsPointV2& p2
   }
 
   //angles of pt1, pt2, pt3
-  double a1 = atan2( p1.y() - centerY, p1.x() - centerX );
-  double a2 = atan2( p2.y() - centerY, p2.x() - centerX );
-  double a3 = atan2( p3.y() - centerY, p3.x() - centerX );
+  double a1 = atan2( circlePoint1.y() - centerY, circlePoint1.x() - centerX );
+  double a2 = atan2( circlePoint2.y() - centerY, circlePoint2.x() - centerX );
+  double a3 = atan2( circlePoint3.y() - centerY, circlePoint3.x() - centerX );
 
-  if ( clockwise )
-  {
-    increment *= -1;
-    /* Adjust a3 down so we can decrement from a1 to a3 cleanly */
-    if ( a3 >= a1 )
-      a3 -= 2.0 * M_PI;
-    if ( a2 > a1 )
-      a2 -= 2.0 * M_PI;
-  }
-  else
-  {
-    /* Adjust a3 up so we can increment from a1 to a3 cleanly */
-    if ( a3 <= a1 )
-      a3 += 2.0 * M_PI;
-    if ( a2 < a1 )
-      a2 += 2.0 * M_PI;
-  }
+  /* Adjust a3 up so we can increment from a1 to a3 cleanly */
+  if ( a3 <= a1 )
+    a3 += 2.0 * M_PI;
+  if ( a2 < a1 )
+    a2 += 2.0 * M_PI;
 
   bool hasZ = is3D();
   bool hasM = isMeasure();
@@ -533,8 +526,9 @@ void QgsCircularStringV2::segmentize( const QgsPointV2& p1, const QgsPointV2& p2
   double z = 0;
   double m = 0;
 
-  points.append( p1 );
-  if ( p2 != p3 && p1 != p2 ) //draw straight line segment if two points have the same position
+  QList<QgsPointV2> stringPoints;
+  stringPoints.insert( clockwise ? 0 : stringPoints.size(), circlePoint1 );
+  if ( circlePoint2 != circlePoint3 && circlePoint1 != circlePoint2 ) //draw straight line segment if two points have the same position
   {
     QgsWKBTypes::Type pointWkbType = QgsWKBTypes::Point;
     if ( hasZ )
@@ -544,16 +538,16 @@ void QgsCircularStringV2::segmentize( const QgsPointV2& p1, const QgsPointV2& p2
 
     //make sure the curve point p2 is part of the segmentized vertices. But only if p1 != p3
     bool addP2 = true;
-    if ( qgsDoubleNear( p1.x(), p3.x() ) && qgsDoubleNear( p1.y(), p3.y() ) )
+    if ( qgsDoubleNear( circlePoint1.x(), circlePoint3.x() ) && qgsDoubleNear( circlePoint1.y(), circlePoint3.y() ) )
     {
       addP2 = false;
     }
 
-    for ( double angle = a1 + increment; clockwise ? angle > a3 : angle < a3; angle += increment )
+    for ( double angle = a1 + increment; angle < a3; angle += increment )
     {
-      if (( addP2 && clockwise && angle < a2 ) || ( addP2 && !clockwise && angle > a2 ) )
+      if (( addP2 && angle > a2 ) )
       {
-        points.append( p2 );
+        stringPoints.insert( clockwise ? 0 : stringPoints.size(), circlePoint2 );
         addP2 = false;
       }
 
@@ -562,23 +556,24 @@ void QgsCircularStringV2::segmentize( const QgsPointV2& p1, const QgsPointV2& p2
 
       if ( !hasZ && !hasM )
       {
-        points.append( QgsPointV2( x, y ) );
+        stringPoints.insert( clockwise ? 0 : stringPoints.size(), QgsPointV2( x, y ) );
         continue;
       }
 
       if ( hasZ )
       {
-        z = interpolateArc( angle, a1, a2, a3, p1.z(), p2.z(), p3.z() );
+        z = interpolateArc( angle, a1, a2, a3, circlePoint1.z(), circlePoint2.z(), circlePoint3.z() );
       }
       if ( hasM )
       {
-        m = interpolateArc( angle, a1, a2, a3, p1.m(), p2.m(), p3.m() );
+        m = interpolateArc( angle, a1, a2, a3, circlePoint1.m(), circlePoint2.m(), circlePoint3.m() );
       }
 
-      points.append( QgsPointV2( pointWkbType, x, y, z, m ) );
+      stringPoints.insert( clockwise ? 0 : stringPoints.size(), QgsPointV2( pointWkbType, x, y, z, m ) );
     }
   }
-  points.append( p3 );
+  stringPoints.insert( clockwise ? 0 : stringPoints.size(), circlePoint3 );
+  points.append( stringPoints );
 }
 
 int QgsCircularStringV2::segmentSide( const QgsPointV2& pt1, const QgsPointV2& pt3, const QgsPointV2& pt2 ) const
diff --git a/src/core/geometry/qgscompoundcurvev2.cpp b/src/core/geometry/qgscompoundcurvev2.cpp
index 98395f4..8415f5e 100644
--- a/src/core/geometry/qgscompoundcurvev2.cpp
+++ b/src/core/geometry/qgscompoundcurvev2.cpp
@@ -256,33 +256,16 @@ QDomElement QgsCompoundCurveV2::asGML2( QDomDocument& doc, int precision, const
 
 QDomElement QgsCompoundCurveV2::asGML3( QDomDocument& doc, int precision, const QString& ns ) const
 {
-  QDomElement elemCurve = doc.createElementNS( ns, "Curve" );
-
-  QDomElement elemSegments = doc.createElementNS( ns, "segments" );
-
+  QDomElement compoundCurveElem = doc.createElementNS( ns, "CompositeCurve" );
   Q_FOREACH ( const QgsCurveV2* curve, mCurves )
   {
-    if ( dynamic_cast<const QgsLineStringV2*>( curve ) )
-    {
-      QgsPointSequenceV2 pts;
-      curve->points( pts );
-
-      QDomElement elemLineStringSegment = doc.createElementNS( ns, "LineStringSegment" );
-      elemLineStringSegment.appendChild( QgsGeometryUtils::pointsToGML3( pts, doc, precision, ns, is3D() ) );
-      elemSegments.appendChild( elemLineStringSegment );
-    }
-    else if ( dynamic_cast<const QgsCircularStringV2*>( curve ) )
-    {
-      QgsPointSequenceV2 pts;
-      curve->points( pts );
-
-      QDomElement elemArcString = doc.createElementNS( ns, "ArcString" );
-      elemArcString.appendChild( QgsGeometryUtils::pointsToGML3( pts, doc, precision, ns, is3D() ) );
-      elemSegments.appendChild( elemArcString );
-    }
+    QDomElement curveMemberElem = doc.createElementNS( ns, "curveMember" );
+    QDomElement curveElem = curve->asGML3( doc, precision, ns );
+    curveMemberElem.appendChild( curveElem );
+    compoundCurveElem.appendChild( curveMemberElem );
   }
-  elemCurve.appendChild( elemSegments );
-  return elemCurve;
+
+  return compoundCurveElem;
 }
 
 QString QgsCompoundCurveV2::asJSON( int precision ) const
diff --git a/src/core/geometry/qgscurvepolygonv2.cpp b/src/core/geometry/qgscurvepolygonv2.cpp
index dc57188..ba74cc0 100644
--- a/src/core/geometry/qgscurvepolygonv2.cpp
+++ b/src/core/geometry/qgscurvepolygonv2.cpp
@@ -320,18 +320,26 @@ QDomElement QgsCurvePolygonV2::asGML3( QDomDocument& doc, int precision, const Q
 {
   QDomElement elemCurvePolygon = doc.createElementNS( ns, "Polygon" );
   QDomElement elemExterior = doc.createElementNS( ns, "exterior" );
-  QDomElement outerRing = exteriorRing()->asGML2( doc, precision, ns );
-  outerRing.toElement().setTagName( "LinearRing" );
-  elemExterior.appendChild( outerRing );
+  QDomElement curveElem = exteriorRing()->asGML3( doc, precision, ns );
+  if ( curveElem.tagName() == "LineString" )
+  {
+    curveElem.setTagName( "LinearRing" );
+  }
+  elemExterior.appendChild( curveElem );
+  elemCurvePolygon.appendChild( elemExterior );
+
   elemCurvePolygon.appendChild( elemExterior );
-  QDomElement elemInterior = doc.createElementNS( ns, "interior" );
   for ( int i = 0, n = numInteriorRings(); i < n; ++i )
   {
-    QDomElement innerRing = interiorRing( i )->asGML2( doc, precision, ns );
-    innerRing.toElement().setTagName( "LinearRing" );
+    QDomElement elemInterior = doc.createElementNS( ns, "interior" );
+    QDomElement innerRing = interiorRing( i )->asGML3( doc, precision, ns );
+    if ( innerRing.tagName() == "LineString" )
+    {
+      innerRing.setTagName( "LinearRing" );
+    }
     elemInterior.appendChild( innerRing );
+    elemCurvePolygon.appendChild( elemInterior );
   }
-  elemCurvePolygon.appendChild( elemInterior );
   return elemCurvePolygon;
 }
 
@@ -371,7 +379,7 @@ double QgsCurvePolygonV2::area() const
 
   double totalArea = 0.0;
 
-  if ( mExteriorRing->isClosed() )
+  if ( mExteriorRing->isRing() )
   {
     double area = 0.0;
     mExteriorRing->sumUpArea( area );
@@ -382,7 +390,7 @@ double QgsCurvePolygonV2::area() const
   for ( ; ringIt != mInteriorRings.constEnd(); ++ringIt )
   {
     double area = 0.0;
-    if (( *ringIt )->isClosed() )
+    if (( *ringIt )->isRing() )
     {
       ( *ringIt )->sumUpArea( area );
       totalArea -= qAbs( area );
diff --git a/src/core/geometry/qgscurvev2.h b/src/core/geometry/qgscurvev2.h
index cb2d416..10c868b 100644
--- a/src/core/geometry/qgscurvev2.h
+++ b/src/core/geometry/qgscurvev2.h
@@ -81,8 +81,7 @@ class CORE_EXPORT QgsCurveV2: public QgsAbstractGeometryV2
      */
     virtual int numPoints() const = 0;
 
-    /** Calculates the area of the curve. Derived classes should override this
-     * to return the correct area of the curve.
+    /** Sums up the area of the curve by iterating over the vertices (shoelace formula).
      */
     virtual void sumUpArea( double& sum ) const = 0;
 
diff --git a/src/core/geometry/qgslinestringv2.cpp b/src/core/geometry/qgslinestringv2.cpp
index 8b25f3d..96984aa 100644
--- a/src/core/geometry/qgslinestringv2.cpp
+++ b/src/core/geometry/qgslinestringv2.cpp
@@ -209,14 +209,9 @@ QDomElement QgsLineStringV2::asGML3( QDomDocument& doc, int precision, const QSt
   QgsPointSequenceV2 pts;
   points( pts );
 
-  QDomElement elemCurve = doc.createElementNS( ns, "Curve" );
-  QDomElement elemSegments = doc.createElementNS( ns, "segments" );
-  QDomElement elemArcString = doc.createElementNS( ns, "LineStringSegment" );
-  elemArcString.appendChild( QgsGeometryUtils::pointsToGML3( pts, doc, precision, ns, is3D() ) );
-  elemSegments.appendChild( elemArcString );
-  elemCurve.appendChild( elemSegments );
-
-  return elemCurve;
+  QDomElement elemLineString = doc.createElementNS( ns, "LineString" );
+  elemLineString.appendChild( QgsGeometryUtils::pointsToGML3( pts, doc, precision, ns, is3D() ) );
+  return elemLineString;
 }
 
 QString QgsLineStringV2::asJSON( int precision ) const
@@ -840,9 +835,6 @@ QgsPointV2 QgsLineStringV2::centroid() const
 void QgsLineStringV2::sumUpArea( double& sum ) const
 {
   int maxIndex = numPoints() - 1;
-  if ( maxIndex == 1 )
-    return; //no area, just a single line
-
   for ( int i = 0; i < maxIndex; ++i )
   {
     sum += 0.5 * ( mX.at( i ) * mY.at( i + 1 ) - mY.at( i ) * mX.at( i + 1 ) );
diff --git a/src/core/geometry/qgsmultilinestringv2.cpp b/src/core/geometry/qgsmultilinestringv2.cpp
index b705cc3..7edb39d 100644
--- a/src/core/geometry/qgsmultilinestringv2.cpp
+++ b/src/core/geometry/qgsmultilinestringv2.cpp
@@ -60,7 +60,7 @@ QDomElement QgsMultiLineStringV2::asGML2( QDomDocument& doc, int precision, cons
 
 QDomElement QgsMultiLineStringV2::asGML3( QDomDocument& doc, int precision, const QString& ns ) const
 {
-  QDomElement elemMultiCurve = doc.createElementNS( ns, "MultiLineString" );
+  QDomElement elemMultiCurve = doc.createElementNS( ns, "MultiCurve" );
   Q_FOREACH ( const QgsAbstractGeometryV2 *geom, mGeometries )
   {
     if ( dynamic_cast<const QgsLineStringV2*>( geom ) )
diff --git a/src/core/layertree/qgslayertreemodellegendnode.cpp b/src/core/layertree/qgslayertreemodellegendnode.cpp
index d88d501..84314e3 100644
--- a/src/core/layertree/qgslayertreemodellegendnode.cpp
+++ b/src/core/layertree/qgslayertreemodellegendnode.cpp
@@ -200,7 +200,7 @@ void QgsSymbolV2LegendNode::setSymbol( QgsSymbolV2* symbol )
     return;
 
   mItem.setSymbol( symbol );
-  vlayer->rendererV2()->setLegendSymbolItem( mItem.ruleKey(), symbol->clone() );
+  vlayer->rendererV2()->setLegendSymbolItem( mItem.ruleKey(), symbol );
 
   mPixmap = QPixmap();
 
diff --git a/src/core/qgsapplication.cpp b/src/core/qgsapplication.cpp
index 4cdb07e..7936bca 100644
--- a/src/core/qgsapplication.cpp
+++ b/src/core/qgsapplication.cpp
@@ -396,7 +396,7 @@ QString QgsApplication::activeThemePath()
 
 QString QgsApplication::appIconPath()
 {
-  return QString( "qgis-icon-60x60.png" );
+  return iconsPath() + "qgis-icon-60x60.png";
 }
 
 QString QgsApplication::iconPath( const QString& iconFile )
diff --git a/src/core/qgscoordinatereferencesystem_p.h b/src/core/qgscoordinatereferencesystem_p.h
index f824f5b..861a354 100644
--- a/src/core/qgscoordinatereferencesystem_p.h
+++ b/src/core/qgscoordinatereferencesystem_p.h
@@ -65,7 +65,7 @@ class QgsCoordinateReferenceSystemPrivate : public QSharedData
         , mSRID( other.mSRID )
         , mAuthId( other.mAuthId )
         , mIsValid( other.mIsValid )
-        , mCRS( OSRNewSpatialReference( nullptr ) )
+        , mCRS( nullptr )
         , mValidationHint( other.mValidationHint )
         , mWkt( other.mWkt )
         , mProj4( other.mProj4 )
@@ -76,6 +76,10 @@ class QgsCoordinateReferenceSystemPrivate : public QSharedData
       {
         mCRS = OSRClone( other.mCRS );
       }
+      else
+      {
+        mCRS = OSRNewSpatialReference( nullptr );
+      }
     }
 
     ~QgsCoordinateReferenceSystemPrivate()
diff --git a/src/core/qgsdatasourceuri.cpp b/src/core/qgsdatasourceuri.cpp
index a920ff6..048d542 100644
--- a/src/core/qgsdatasourceuri.cpp
+++ b/src/core/qgsdatasourceuri.cpp
@@ -153,7 +153,7 @@ QgsDataSourceURI::QgsDataSourceURI( QString uri )
       {
         mAuthConfigId = pval;
       }
-      else if ( pname == "user" )
+      else if ( pname == "user" || pname == "username" ) // Also accepts username as used in new WFS provider
       {
         mUsername = pval;
       }
diff --git a/src/core/qgsexpression.cpp b/src/core/qgsexpression.cpp
index 5d340fe..8c23f31 100644
--- a/src/core/qgsexpression.cpp
+++ b/src/core/qgsexpression.cpp
@@ -3697,6 +3697,11 @@ QgsExpression::QgsExpression( const QgsExpression& other )
 
 QgsExpression& QgsExpression::operator=( const QgsExpression & other )
 {
+  if ( !d->ref.deref() )
+  {
+    delete d;
+  }
+
   d = other.d;
   d->ref.ref();
   return *this;
diff --git a/src/core/qgsexpression.h b/src/core/qgsexpression.h
index 9bd8beb..8608ce9 100644
--- a/src/core/qgsexpression.h
+++ b/src/core/qgsexpression.h
@@ -1052,7 +1052,7 @@ class CORE_EXPORT QgsExpression
         /** Adds a named node. Takes ownership of the provided node.
          * @note added in QGIS 2.16
         */
-        void append( NamedNode* node ) { mList.append( node->node ); mNameList.append( node->name.toLower() ); mHasNamedNodes = true; }
+        void append( NamedNode* node ) { mList.append( node->node ); mNameList.append( node->name.toLower() ); mHasNamedNodes = true; delete node; }
 
         /** Returns the number of nodes in the list.
          */
diff --git a/src/core/qgsgml.cpp b/src/core/qgsgml.cpp
index 4238f5e..6f7f543 100644
--- a/src/core/qgsgml.cpp
+++ b/src/core/qgsgml.cpp
@@ -282,10 +282,12 @@ QgsGmlStreamingParser::QgsGmlStreamingParser( const QString& typeName,
     : mTypeName( typeName )
     , mTypeNameBA( mTypeName.toUtf8() )
     , mTypeNamePtr( mTypeNameBA.constData() )
+    , mTypeNameUTF8Len( strlen( mTypeNamePtr ) )
     , mWkbType( QGis::WKBUnknown )
     , mGeometryAttribute( geometryAttribute )
     , mGeometryAttributeBA( geometryAttribute.toUtf8() )
     , mGeometryAttributePtr( mGeometryAttributeBA.constData() )
+    , mGeometryAttributeUTF8Len( strlen( mGeometryAttributePtr ) )
     , mFields( fields )
     , mIsException( false )
     , mTruncatedResponse( false )
@@ -320,6 +322,7 @@ QgsGmlStreamingParser::QgsGmlStreamingParser( const QString& typeName,
     mTypeName = mTypeName.mid( index + 1 );
     mTypeNameBA = mTypeName.toUtf8();
     mTypeNamePtr = mTypeNameBA.constData();
+    mTypeNameUTF8Len = strlen( mTypeNamePtr );
   }
 
   mParser = XML_ParserCreateNS( nullptr, NS_SEPARATOR );
@@ -345,8 +348,10 @@ QgsGmlStreamingParser::QgsGmlStreamingParser( const QList<LayerProperties>& laye
     bool invertAxisOrientation )
     : mLayerProperties( layerProperties )
     , mTypeNamePtr( nullptr )
+    , mTypeNameUTF8Len( 0 )
     , mWkbType( QGis::WKBUnknown )
     , mGeometryAttributePtr( nullptr )
+    , mGeometryAttributeUTF8Len( 0 )
     , mFields( fields )
     , mIsException( false )
     , mTruncatedResponse( false )
@@ -402,6 +407,7 @@ QgsGmlStreamingParser::QgsGmlStreamingParser( const QList<LayerProperties>& laye
     mGeometryAttribute = mLayerProperties[0].mGeometryAttribute;
     mGeometryAttributeBA = mGeometryAttribute.toUtf8();
     mGeometryAttributePtr = mGeometryAttributeBA.constData();
+    mGeometryAttributeUTF8Len = strlen( mGeometryAttributePtr );
     int index = mTypeName.indexOf( ':' );
     if ( index != -1 && index < mTypeName.length() )
     {
@@ -409,6 +415,7 @@ QgsGmlStreamingParser::QgsGmlStreamingParser( const QList<LayerProperties>& laye
     }
     mTypeNameBA = mTypeName.toUtf8();
     mTypeNamePtr = mTypeNameBA.constData();
+    mTypeNameUTF8Len = strlen( mTypeNamePtr );
   }
 
   mEndian = QgsApplication::endian();
@@ -547,7 +554,7 @@ void QgsGmlStreamingParser::startElement( const XML_Char* el, const XML_Char** a
       }
     }
   }
-  else if ( localNameLen == mGeometryAttribute.size() &&
+  else if ( localNameLen == static_cast<int>( mGeometryAttributeUTF8Len ) &&
             memcmp( pszLocalName, mGeometryAttributePtr, localNameLen ) == 0 )
   {
     mParseModeStack.push( QgsGmlStreamingParser::geometry );
@@ -611,6 +618,7 @@ void QgsGmlStreamingParser::startElement( const XML_Char* el, const XML_Char** a
       }
       mGeometryAttributeBA = mGeometryAttribute.toUtf8();
       mGeometryAttributePtr = mGeometryAttributeBA.constData();
+      mGeometryAttributeUTF8Len = strlen( mGeometryAttributePtr );
       mParseModeStack.push( QgsGmlStreamingParser::featureTuple );
       QString id;
       if ( mGMLNameSpaceURI.isEmpty() )
@@ -639,7 +647,8 @@ void QgsGmlStreamingParser::startElement( const XML_Char* el, const XML_Char** a
     }
   }
   else if ( theParseMode == none &&
-            localNameLen == mTypeName.size() && memcmp( pszLocalName, mTypeNamePtr, mTypeName.size() ) == 0 )
+            localNameLen == static_cast<int>( mTypeNameUTF8Len ) &&
+            memcmp( pszLocalName, mTypeNamePtr, mTypeNameUTF8Len ) == 0 )
   {
     Q_ASSERT( !mCurrentFeature );
     mCurrentFeature = new QgsFeature( mFeatureCount );
@@ -862,7 +871,8 @@ void QgsGmlStreamingParser::endElement( const XML_Char* el )
 
     setAttribute( mAttributeName, mStringCash );
   }
-  else if ( theParseMode == geometry && localNameLen == mGeometryAttribute.size() &&
+  else if ( theParseMode == geometry &&
+            localNameLen == static_cast<int>( mGeometryAttributeUTF8Len ) &&
             memcmp( pszLocalName, mGeometryAttributePtr, localNameLen ) == 0 )
   {
     mParseModeStack.pop();
@@ -903,6 +913,7 @@ void QgsGmlStreamingParser::endElement( const XML_Char* el )
          mCurrentFeature == nullptr && mFeatureCount == 0 )
     {
       mLayerExtent = mCurrentExtent;
+      mCurrentExtent = QgsRectangle();
     }
 
     mParseModeStack.pop();
@@ -944,8 +955,9 @@ void QgsGmlStreamingParser::endElement( const XML_Char* el )
   }
   else if (( theParseMode == tuple && !mTypeNamePtr &&
              LOCALNAME_EQUALS( "Tuple" ) ) ||
-           ( theParseMode == feature && localNameLen == mTypeName.size() &&
-             memcmp( pszLocalName, mTypeNamePtr, mTypeName.size() ) == 0 ) )
+           ( theParseMode == feature &&
+             localNameLen == static_cast<int>( mTypeNameUTF8Len ) &&
+             memcmp( pszLocalName, mTypeNamePtr, mTypeNameUTF8Len ) == 0 ) )
   {
     Q_ASSERT( mCurrentFeature );
     if ( !mCurrentFeature->geometry() )
diff --git a/src/core/qgsgml.h b/src/core/qgsgml.h
index 1a439ab..2b5008a 100644
--- a/src/core/qgsgml.h
+++ b/src/core/qgsgml.h
@@ -244,6 +244,7 @@ class CORE_EXPORT QgsGmlStreamingParser
     QString mTypeName;
     QByteArray mTypeNameBA;
     const char* mTypeNamePtr;
+    size_t mTypeNameUTF8Len;
 
     QGis::WkbType mWkbType;
 
@@ -253,6 +254,7 @@ class CORE_EXPORT QgsGmlStreamingParser
     QString mGeometryAttribute;
     QByteArray mGeometryAttributeBA;
     const char* mGeometryAttributePtr;
+    size_t mGeometryAttributeUTF8Len;
 
     QgsFields mFields;
     QMap<QString, QPair<int, QgsField> > mThematicAttributes;
diff --git a/src/core/qgsjsonutils.h b/src/core/qgsjsonutils.h
index 478b2a8..46c6c5a 100644
--- a/src/core/qgsjsonutils.h
+++ b/src/core/qgsjsonutils.h
@@ -38,11 +38,13 @@ class CORE_EXPORT QgsJSONExporter
 
     /** Constructor for QgsJSONExporter.
      * @param vectorLayer associated vector layer (required for related attribute export)
-     * @param precision maximum number of decimal places to use for geometry coordinates
+     * @param precision maximum number of decimal places to use for geometry coordinates,
+     *  the RFC 7946 GeoJSON specification recommends limiting coordinate precision to 6
      */
-    QgsJSONExporter( const QgsVectorLayer* vectorLayer = nullptr, int precision = 17 );
+    QgsJSONExporter( const QgsVectorLayer* vectorLayer = nullptr, int precision = 6 );
 
     /** Sets the maximum number of decimal places to use in geometry coordinates.
+     * The RFC 7946 GeoJSON specification recommends limiting coordinate precision to 6
      * @param precision number of decimal places
      * @see precision()
      */
diff --git a/src/core/qgsmaprenderercustompainterjob.cpp b/src/core/qgsmaprenderercustompainterjob.cpp
index 2e2dce5..8385188 100644
--- a/src/core/qgsmaprenderercustompainterjob.cpp
+++ b/src/core/qgsmaprenderercustompainterjob.cpp
@@ -75,7 +75,7 @@ void QgsMapRendererCustomPainterJob::start()
 #ifndef QT_NO_DEBUG
   QPaintDevice* thePaintDevice = mPainter->device();
   QString errMsg = QString( "pre-set DPI not equal to painter's DPI (%1 vs %2)" ).arg( thePaintDevice->logicalDpiX() ).arg( mSettings.outputDpi() );
-  Q_ASSERT_X( thePaintDevice->logicalDpiX() == round( mSettings.outputDpi() ), "Job::startRender()", errMsg.toAscii().data() );
+  Q_ASSERT_X( thePaintDevice->logicalDpiX() == qgsRound( mSettings.outputDpi() ), "Job::startRender()", errMsg.toAscii().data() );
 #endif
 
   delete mLabelingEngine;
diff --git a/src/core/qgsofflineediting.cpp b/src/core/qgsofflineediting.cpp
index 7e29461..3bfc7d6 100644
--- a/src/core/qgsofflineediting.cpp
+++ b/src/core/qgsofflineediting.cpp
@@ -256,6 +256,7 @@ void QgsOfflineEditing::synchronize()
 
       // copy style
       copySymbology( offlineLayer, remoteLayer );
+      updateRelations( offlineLayer, remoteLayer );
 
       // apply layer edit log
       QString qgisLayerId = layer->id();
@@ -525,7 +526,7 @@ QgsVectorLayer* QgsOfflineEditing::copyVectorLayer( QgsVectorLayer* layer, sqlit
   if ( layer->hasGeometryType() )
   {
     QString geomType = "";
-    switch ( layer->wkbType() )
+    switch ( QGis::flatType( layer->wkbType() ) )
     {
       case QGis::WKBPoint:
         geomType = "POINT";
@@ -549,6 +550,10 @@ QgsVectorLayer* QgsOfflineEditing::copyVectorLayer( QgsVectorLayer* layer, sqlit
         showWarning( tr( "QGIS wkbType %1 not supported" ).arg( layer->wkbType() ) );
         break;
     };
+
+    if ( QGis::flatType( layer->wkbType() ) != layer->wkbType() )
+      showWarning( tr( "Will drop Z and M values from layer %1 in offline copy." ).arg( layer->name() ) );
+
     QString sqlAddGeom = QString( "SELECT AddGeometryColumn('%1', 'Geometry', %2, '%3', 2)" )
                          .arg( tableName )
                          .arg( layer->crs().authid().startsWith( "EPSG:", Qt::CaseInsensitive ) ? layer->crs().authid().mid( 5 ).toLong() : 0 )
@@ -626,6 +631,7 @@ QgsVectorLayer* QgsOfflineEditing::copyVectorLayer( QgsVectorLayer* layer, sqlit
         copySymbology( layer, newLayer );
       }
 
+      updateRelations( layer, newLayer );
       // copy features
       newLayer->startEditing();
       QgsFeature f;
@@ -670,6 +676,15 @@ QgsVectorLayer* QgsOfflineEditing::copyVectorLayer( QgsVectorLayer* layer, sqlit
         }
         f.setAttributes( newAttrs );
 
+        // The spatialite provider doesn't properly handle Z and M values
+        if ( f.geometry() && f.geometry()->geometry() )
+        {
+          QgsAbstractGeometryV2* geom = f.geometry()->geometry()->clone();
+          geom->dropZValue();
+          geom->dropMValue();
+          f.geometry()->setGeometry( geom );
+        }
+
         newLayer->addFeature( f, false );
 
         emit progressUpdated( featureCount++ );
@@ -932,6 +947,29 @@ void QgsOfflineEditing::copySymbology( QgsVectorLayer* sourceLayer, QgsVectorLay
   }
 }
 
+void QgsOfflineEditing::updateRelations( QgsVectorLayer* sourceLayer, QgsVectorLayer* targetLayer )
+{
+  QgsRelationManager* relationManager = QgsProject::instance()->relationManager();
+  QList<QgsRelation> relations;
+  relations = relationManager->referencedRelations( sourceLayer );
+
+  Q_FOREACH ( QgsRelation relation, relations )
+  {
+    relationManager->removeRelation( relation );
+    relation.setReferencedLayer( targetLayer->id() );
+    relationManager->addRelation( relation );
+  }
+
+  relations = relationManager->referencingRelations( sourceLayer );
+
+  Q_FOREACH ( QgsRelation relation, relations )
+  {
+    relationManager->removeRelation( relation );
+    relation.setReferencingLayer( targetLayer->id() );
+    relationManager->addRelation( relation );
+  }
+}
+
 // NOTE: use this to map column indices in case the remote geometry column is not last
 QMap<int, int> QgsOfflineEditing::attributeLookup( QgsVectorLayer* offlineLayer, QgsVectorLayer* remoteLayer )
 {
diff --git a/src/core/qgsofflineediting.h b/src/core/qgsofflineediting.h
index 0d088cb..0923156 100644
--- a/src/core/qgsofflineediting.h
+++ b/src/core/qgsofflineediting.h
@@ -108,6 +108,10 @@ class CORE_EXPORT QgsOfflineEditing : public QObject
     void applyGeometryChanges( QgsVectorLayer* remoteLayer, sqlite3* db, int layerId, int commitNo );
     void updateFidLookup( QgsVectorLayer* remoteLayer, sqlite3* db, int layerId );
     void copySymbology( QgsVectorLayer* sourceLayer, QgsVectorLayer* targetLayer );
+    /**
+     * Updates all relations that reference or are referenced by the source layer to the targetLayer.
+     */
+    void updateRelations( QgsVectorLayer* sourceLayer, QgsVectorLayer* targetLayer );
     QMap<int, int> attributeLookup( QgsVectorLayer* offlineLayer, QgsVectorLayer* remoteLayer );
 
     void showWarning( const QString& message );
diff --git a/src/core/qgsogcutils.cpp b/src/core/qgsogcutils.cpp
index fce0bc9..06ad0cc 100644
--- a/src/core/qgsogcutils.cpp
+++ b/src/core/qgsogcutils.cpp
@@ -1599,6 +1599,16 @@ QgsExpression* QgsOgcUtils::expressionFromOgcFilter( const QDomElement& element
   if ( element.isNull() || !element.hasChildNodes() )
     return nullptr;
 
+  // check if it is a single string value => no DomElement
+  if ( element.firstChild().nodeType() == QDomNode::TextNode )
+  {
+    QgsExpression *expr = new QgsExpression( element.firstChild().nodeValue() );
+    expr->d->mParserErrorString = QString();
+    return expr;
+  }
+
+  // now parse OGC operators. OGC operator does not have a only text value
+  // but only sub element operators
   QgsExpression *expr = new QgsExpression();
 
   QDomElement childElem = element.firstChildElement();
diff --git a/src/core/qgsvectorfilewriter.cpp b/src/core/qgsvectorfilewriter.cpp
index 1ba1b3c..600c0be 100644
--- a/src/core/qgsvectorfilewriter.cpp
+++ b/src/core/qgsvectorfilewriter.cpp
@@ -86,7 +86,6 @@ QgsVectorFileWriter::QgsVectorFileWriter(
     : mDS( nullptr )
     , mLayer( nullptr )
     , mOgrRef( nullptr )
-    , mGeom( nullptr )
     , mError( NoError )
     , mCodec( nullptr )
     , mWkbType( QGis::fromOldWkbType( geometryType ) )
@@ -103,7 +102,6 @@ QgsVectorFileWriter::QgsVectorFileWriter( const QString& vectorFileName, const Q
     : mDS( nullptr )
     , mLayer( nullptr )
     , mOgrRef( nullptr )
-    , mGeom( nullptr )
     , mError( NoError )
     , mCodec( nullptr )
     , mWkbType( geometryType )
@@ -132,7 +130,6 @@ QgsVectorFileWriter::QgsVectorFileWriter( const QString& vectorFileName,
     : mDS( nullptr )
     , mLayer( nullptr )
     , mOgrRef( nullptr )
-    , mGeom( nullptr )
     , mError( NoError )
     , mCodec( nullptr )
     , mWkbType( geometryType )
@@ -692,11 +689,6 @@ void QgsVectorFileWriter::init( QString vectorFileName,
   QgsDebugMsg( "Done creating fields" );
 
   mWkbType = geometryType;
-  if ( mWkbType != QgsWKBTypes::NoGeometry )
-  {
-    // create geometry which will be used for import
-    mGeom = createEmptyGeometry( mWkbType );
-  }
 
   if ( newFilename )
     *newFilename = vectorFileName;
@@ -2133,7 +2125,9 @@ OGRFeatureH QgsVectorFileWriter::createFeature( QgsFeature& feature )
       }
       else // wkb type matches
       {
-        OGRErr err = OGR_G_ImportFromWkb( mGeom, const_cast<unsigned char *>( geom->asWkb() ), static_cast< int >( geom->wkbSize() ) );
+        OGRGeometryH ogrGeom = createEmptyGeometry( mWkbType );
+        OGRErr err = OGR_G_ImportFromWkb( ogrGeom, const_cast<unsigned char *>( geom->asWkb() ), static_cast< int >( geom->wkbSize() ) );
+
         if ( err != OGRERR_NONE )
         {
           mErrorMessage = QObject::tr( "Feature geometry not imported (OGR error: %1)" )
@@ -2144,8 +2138,8 @@ OGRFeatureH QgsVectorFileWriter::createFeature( QgsFeature& feature )
           return nullptr;
         }
 
-        // set geometry (ownership is not passed to OGR)
-        OGR_F_SetGeometry( poFeature, mGeom );
+        // set geometry (ownership is passed to OGR)
+        OGR_F_SetGeometryDirectly( poFeature, ogrGeom );
       }
     }
     else
@@ -2182,11 +2176,6 @@ bool QgsVectorFileWriter::writeFeature( OGRLayerH layer, OGRFeatureH feature )
 
 QgsVectorFileWriter::~QgsVectorFileWriter()
 {
-  if ( mGeom )
-  {
-    OGR_G_DestroyGeometry( mGeom );
-  }
-
   if ( mDS )
   {
     OGR_DS_Destroy( mDS );
diff --git a/src/core/qgsvectorfilewriter.h b/src/core/qgsvectorfilewriter.h
index 96a8a17..e5cfcb7 100644
--- a/src/core/qgsvectorfilewriter.h
+++ b/src/core/qgsvectorfilewriter.h
@@ -517,7 +517,6 @@ class CORE_EXPORT QgsVectorFileWriter
     OGRDataSourceH mDS;
     OGRLayerH mLayer;
     OGRSpatialReferenceH mOgrRef;
-    OGRGeometryH mGeom;
 
     QgsFields mFields;
 
diff --git a/src/core/qgsvectorlayer.cpp b/src/core/qgsvectorlayer.cpp
index def0bf1..68282fd 100644
--- a/src/core/qgsvectorlayer.cpp
+++ b/src/core/qgsvectorlayer.cpp
@@ -1630,10 +1630,6 @@ bool QgsVectorLayer::readXml( const QDomNode& layer_node )
     return false;
   }
 
-  QDomElement mapLayerNode = layer_node.toElement();
-  if ( mapLayerNode.attribute( "readOnly", "0" ).toInt() == 1 )
-    mReadOnly = true;
-
   QDomElement pkeyElem = pkeyNode.toElement();
   if ( !pkeyElem.isNull() )
   {
@@ -1679,24 +1675,6 @@ bool QgsVectorLayer::readXml( const QDomNode& layer_node )
 
   readStyleManager( layer_node );
 
-  // default expressions
-  mDefaultExpressionMap.clear();
-  QDomNode defaultsNode = layer_node.namedItem( "defaults" );
-  if ( !defaultsNode.isNull() )
-  {
-    QDomNodeList defaultNodeList = defaultsNode.toElement().elementsByTagName( "default" );
-    for ( int i = 0; i < defaultNodeList.size(); ++i )
-    {
-      QDomElement defaultElem = defaultNodeList.at( i ).toElement();
-
-      QString field = defaultElem.attribute( "field", QString() );
-      QString expression = defaultElem.attribute( "expression", QString() );
-      if ( field.isEmpty() || expression.isEmpty() )
-        continue;
-
-      mDefaultExpressionMap.insert( field, expression );
-    }
-  }
   updateFields();
 
   setLegend( QgsMapLayerLegend::defaultVectorLegend( this ) );
@@ -1874,9 +1852,6 @@ bool QgsVectorLayer::writeXml( QDomNode & layer_node,
     layer_node.appendChild( provider );
   }
 
-  // save readonly state
-  mapLayerNode.setAttribute( "readOnly", mReadOnly );
-
   // save preview expression
   QDomElement prevExpElem = document.createElement( "previewExpression" );
   QDomText prevExpText = document.createTextNode( mDisplayExpression );
@@ -1899,17 +1874,6 @@ bool QgsVectorLayer::writeXml( QDomNode & layer_node,
   // save expression fields
   mExpressionFieldBuffer->writeXml( layer_node, document );
 
-  //default expressions
-  QDomElement defaultsElem = document.createElement( "defaults" );
-  Q_FOREACH ( const QgsField& field, mUpdatedFields )
-  {
-    QDomElement defaultElem = document.createElement( "default" );
-    defaultElem.setAttribute( "field", field.name() );
-    defaultElem.setAttribute( "expression", field.defaultValueExpression() );
-    defaultsElem.appendChild( defaultElem );
-  }
-  layer_node.appendChild( defaultsElem );
-
   writeStyleManager( layer_node, document );
 
   // renderer specific settings
@@ -1963,6 +1927,24 @@ bool QgsVectorLayer::readSymbology( const QDomNode& node, QString& errorMessage
       mAttributeAliasMap.insert( field, aliasElem.attribute( "name" ) );
     }
   }
+  // default expressions
+  mDefaultExpressionMap.clear();
+  QDomNode defaultsNode = node.namedItem( "defaults" );
+  if ( !defaultsNode.isNull() )
+  {
+    QDomNodeList defaultNodeList = defaultsNode.toElement().elementsByTagName( "default" );
+    for ( int i = 0; i < defaultNodeList.size(); ++i )
+    {
+      QDomElement defaultElem = defaultNodeList.at( i ).toElement();
+
+      QString field = defaultElem.attribute( "field", QString() );
+      QString expression = defaultElem.attribute( "expression", QString() );
+      if ( field.isEmpty() || expression.isEmpty() )
+        continue;
+
+      mDefaultExpressionMap.insert( field, expression );
+    }
+  }
   updateFields();
 
   //Attributes excluded from WMS and WFS
@@ -1996,6 +1978,11 @@ bool QgsVectorLayer::readSymbology( const QDomNode& node, QString& errorMessage
 
   readCustomProperties( node, "variable" );
 
+  QDomElement mapLayerNode = node.toElement();
+  if ( mapLayerNode.attribute( "readOnly", "0" ).toInt() == 1 )
+    mReadOnly = true;
+
+
   return true;
 }
 
@@ -2101,7 +2088,6 @@ bool QgsVectorLayer::readStyle( const QDomNode &node, QString &errorMessage )
 
     if ( !labelattributesnode.isNull() && mLabel )
     {
-      QgsDebugMsg( "calling readXML" );
       mLabel->readXML( labelattributesnode );
     }
 
@@ -2193,6 +2179,20 @@ bool QgsVectorLayer::writeSymbology( QDomNode& node, QDomDocument& doc, QString&
   mEditFormConfig->writeXml( node );
   mConditionalStyles->writeXml( node, doc );
 
+  // save readonly state
+  node.toElement().setAttribute( "readOnly", mReadOnly );
+
+  //default expressions
+  QDomElement defaultsElem = node.ownerDocument().createElement( "defaults" );
+  Q_FOREACH ( const QgsField& field, mUpdatedFields )
+  {
+    QDomElement defaultElem = doc.createElement( "default" );
+    defaultElem.setAttribute( "field", field.name() );
+    defaultElem.setAttribute( "expression", field.defaultValueExpression() );
+    defaultsElem.appendChild( defaultElem );
+  }
+  node.appendChild( defaultsElem );
+
   return true;
 }
 
diff --git a/src/core/symbology-ng/qgssymbollayerv2utils.cpp b/src/core/symbology-ng/qgssymbollayerv2utils.cpp
index 3c12908..31b8d84 100644
--- a/src/core/symbology-ng/qgssymbollayerv2utils.cpp
+++ b/src/core/symbology-ng/qgssymbollayerv2utils.cpp
@@ -2577,6 +2577,7 @@ bool QgsSymbolLayerV2Utils::createFunctionElement( QDomDocument &doc, QDomElemen
 
 bool QgsSymbolLayerV2Utils::functionFromSldElement( QDomElement &element, QString &function )
 {
+  // check if ogc:Filter or containe ogc:Filters
   QDomElement elem = element;
   if ( element.tagName() != "Filter" )
   {
@@ -2592,7 +2593,7 @@ bool QgsSymbolLayerV2Utils::functionFromSldElement( QDomElement &element, QStrin
     return false;
   }
 
-
+  // parse ogc:Filter
   QgsExpression *expr = QgsOgcUtils::expressionFromOgcFilter( elem );
   if ( !expr )
     return false;
@@ -2656,6 +2657,7 @@ QDomElement QgsSymbolLayerV2Utils::createSvgParameterElement( QDomDocument &doc,
 QgsStringMap QgsSymbolLayerV2Utils::getSvgParameterList( QDomElement &element )
 {
   QgsStringMap params;
+  QString value;
 
   QDomElement paramElem = element.firstChildElement();
   while ( !paramElem.isNull() )
@@ -2663,7 +2665,23 @@ QgsStringMap QgsSymbolLayerV2Utils::getSvgParameterList( QDomElement &element )
     if ( paramElem.localName() == "SvgParameter" || paramElem.localName() == "CssParameter" )
     {
       QString name = paramElem.attribute( "name" );
-      QString value = paramElem.firstChild().nodeValue();
+      if ( paramElem.firstChild().nodeType() == QDomNode::TextNode )
+      {
+        value = paramElem.firstChild().nodeValue();
+      }
+      else
+      {
+        if ( paramElem.firstChild().nodeType() == QDomNode::ElementNode &&
+             paramElem.firstChild().localName() == "Literal" )
+        {
+          QgsDebugMsg( paramElem.firstChild().localName() );
+          value = paramElem.firstChild().firstChild().nodeValue();
+        }
+        else
+        {
+          QgsDebugMsg( QString( "unexpected child of %1" ).arg( paramElem.localName() ) );
+        }
+      }
 
       if ( !name.isEmpty() && !value.isEmpty() )
         params[ name ] = value;
diff --git a/src/helpviewer/CMakeLists.txt b/src/helpviewer/CMakeLists.txt
index cec5ad1..ffd0966 100644
--- a/src/helpviewer/CMakeLists.txt
+++ b/src/helpviewer/CMakeLists.txt
@@ -68,7 +68,7 @@ TARGET_LINK_LIBRARIES(qgis_help
   ${QT_QTNETWORK_LIBRARY}
   ${QT_QTSVG_LIBRARY}
   ${QT_QTXML_LIBRARY}
-  ${QT_QTWEBKIT_LIBRARY}
+  ${OPTIONAL_QTWEBKIT}
   ${QT_QTMAIN_LIBRARY}
   ${SQLITE3_LIBRARY}
 )
diff --git a/src/plugins/geometry_checker/ui/qgsgeometrycheckerresulttab.cpp b/src/plugins/geometry_checker/ui/qgsgeometrycheckerresulttab.cpp
index bca51ad..964471c 100644
--- a/src/plugins/geometry_checker/ui/qgsgeometrycheckerresulttab.cpp
+++ b/src/plugins/geometry_checker/ui/qgsgeometrycheckerresulttab.cpp
@@ -110,6 +110,10 @@ void QgsGeometryCheckerResultTab::finalize()
 
 void QgsGeometryCheckerResultTab::addError( QgsGeometryCheckError *error )
 {
+  bool sortingWasEnabled = ui.tableWidgetErrors->isSortingEnabled();
+  if ( sortingWasEnabled )
+    ui.tableWidgetErrors->setSortingEnabled( false );
+
   int row = ui.tableWidgetErrors->rowCount();
   int prec = 7 - std::floor( qMax( 0., std::log10( qMax( error->location().x(), error->location().y() ) ) ) );
   QString posStr = QString( "%1, %2" ).arg( error->location().x(), 0, 'f', prec ).arg( error->location().y(), 0, 'f', prec );
@@ -142,6 +146,9 @@ void QgsGeometryCheckerResultTab::addError( QgsGeometryCheckError *error )
   ui.labelErrorCount->setText( tr( "Total errors: %1, fixed errors: %2" ).arg( mErrorCount ).arg( mFixedCount ) );
   mStatistics.newErrors.insert( error );
   mErrorMap.insert( error, QPersistentModelIndex( ui.tableWidgetErrors->model()->index( row, 0 ) ) );
+
+  if ( sortingWasEnabled )
+    ui.tableWidgetErrors->setSortingEnabled( true );
 }
 
 void QgsGeometryCheckerResultTab::updateError( QgsGeometryCheckError *error, bool statusChanged )
diff --git a/src/providers/wfs/qgswfscapabilities.cpp b/src/providers/wfs/qgswfscapabilities.cpp
index 4934226..9a96433 100644
--- a/src/providers/wfs/qgswfscapabilities.cpp
+++ b/src/providers/wfs/qgswfscapabilities.cpp
@@ -247,11 +247,31 @@ void QgsWFSCapabilities::capabilitiesReplyFinished()
   }
 
   // Parse operations supported for all feature types
-  bool insertCap, updateCap, deleteCap;
-  parseSupportedOperations( featureTypeListElem.firstChildElement( "Operations" ),
-                            insertCap,
-                            updateCap,
-                            deleteCap );
+  bool insertCap = false;
+  bool updateCap = false;
+  bool deleteCap = false;
+  // WFS < 2
+  if ( mCaps.version.startsWith( "1" ) )
+  {
+    parseSupportedOperations( featureTypeListElem.firstChildElement( "Operations" ),
+                              insertCap,
+                              updateCap,
+                              deleteCap );
+  }
+  else // WFS 2.0.0 tested on GeoServer
+  {
+    QDomNodeList operationNodes = doc.elementsByTagName( "Operation" );
+    for ( int i = 0; i < operationNodes.count(); i++ )
+    {
+      QDomElement operationElement = operationNodes.at( i ).toElement( );
+      if ( operationElement.isElement( ) && "Transaction" == operationElement.attribute( "name" ) )
+      {
+        insertCap = true;
+        updateCap = true;
+        deleteCap = true;
+      }
+    }
+  }
 
   // get the <FeatureType> elements
   QDomNodeList featureTypeList = featureTypeListElem.elementsByTagName( "FeatureType" );
@@ -475,10 +495,6 @@ void QgsWFSCapabilities::parseSupportedOperations( const QDomElement& operations
   updateCap = false;
   deleteCap = false;
 
-  // TODO: remove me when WFS-T 1.1 or 2.0 is done
-  if ( !mCaps.version.startsWith( "1.0" ) )
-    return;
-
   if ( operationsElem.isNull() )
   {
     return;
diff --git a/src/providers/wfs/qgswfsprovider.cpp b/src/providers/wfs/qgswfsprovider.cpp
index 0bc9f07..2e988cd 100644
--- a/src/providers/wfs/qgswfsprovider.cpp
+++ b/src/providers/wfs/qgswfsprovider.cpp
@@ -849,6 +849,18 @@ bool QgsWFSProvider::addFeatures( QgsFeatureList &flist )
   {
     //transaction successful. Add the features to the cache
     QStringList idList = insertedFeatureIds( serverResponse );
+
+    /* Fix issue with GeoServer and shapefile feature stores when no real
+       feature id are returned but new0 returned instead of the featureId*/
+    Q_FOREACH ( const QString &v, idList )
+    {
+      if ( v.startsWith( "new" ) )
+      {
+        reloadData();
+        return true;
+      }
+    }
+
     QStringList::const_iterator idIt = idList.constBegin();
     featureIt = flist.begin();
 
@@ -1344,7 +1356,10 @@ bool QgsWFSProvider::sendTransactionDocument( const QDomDocument& doc, QDomDocum
 QDomElement QgsWFSProvider::createTransactionElement( QDomDocument& doc ) const
 {
   QDomElement transactionElem = doc.createElementNS( QgsWFSConstants::WFS_NAMESPACE, "Transaction" );
-  transactionElem.setAttribute( "version", "1.0.0" );
+  // QString WfsVersion = mShared->mWFSVersion;
+  // For now: hardcoded to 1.0.0
+  QString WfsVersion = "1.0.0";
+  transactionElem.setAttribute( "version", WfsVersion );
   transactionElem.setAttribute( "service", "WFS" );
   transactionElem.setAttribute( "xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance" );
 
@@ -1353,7 +1368,7 @@ QDomElement QgsWFSProvider::createTransactionElement( QDomDocument& doc ) const
   if ( mShared->mURI.baseURL().toString().contains( "fake_qgis_http_endpoint" ) )
     describeFeatureTypeURL = QUrl( "http://fake_qgis_http_endpoint" );
   describeFeatureTypeURL.addQueryItem( "REQUEST", "DescribeFeatureType" );
-  describeFeatureTypeURL.addQueryItem( "VERSION", "1.0.0" );
+  describeFeatureTypeURL.addQueryItem( "VERSION", WfsVersion );
   describeFeatureTypeURL.addQueryItem( "TYPENAME", mShared->mURI.typeName() );
 
   transactionElem.setAttribute( "xsi:schemaLocation", mApplicationNamespace + ' '
diff --git a/src/providers/wfs/qgswfstransactionrequest.cpp b/src/providers/wfs/qgswfstransactionrequest.cpp
index 2fb1da8..b37c542 100644
--- a/src/providers/wfs/qgswfstransactionrequest.cpp
+++ b/src/providers/wfs/qgswfstransactionrequest.cpp
@@ -36,6 +36,7 @@ bool QgsWFSTransactionRequest::send( const QDomDocument& doc, QDomDocument& serv
       QgsDebugMsg( errorMsg );
       return false;
     }
+    QgsDebugMsg( mResponse );
     return true;
   }
   return false;
diff --git a/src/providers/wms/qgswmssourceselect.cpp b/src/providers/wms/qgswmssourceselect.cpp
index 456b101..465a5c3 100644
--- a/src/providers/wms/qgswmssourceselect.cpp
+++ b/src/providers/wms/qgswmssourceselect.cpp
@@ -1095,10 +1095,8 @@ QString QgsWMSSourceSelect::descriptionForAuthId( const QString& authId )
 void QgsWMSSourceSelect::addDefaultServers()
 {
   QMap<QString, QString> exampleServers;
-  exampleServers["DM Solutions GMap"] = "http://www2.dmsolutions.ca/cgi-bin/mswms_gmap";
-  exampleServers["Lizardtech server"] =  "http://wms.lizardtech.com/lizardtech/iserv/ows";
-  // Nice to have the qgis users map, but I'm not sure of the URL at the moment.
-  //  exampleServers["Qgis users map"] = "http://qgis.org/wms.cgi";
+  exampleServers["QGIS Server Demo - Alaska"] = "http://demo.qgis.org/cgi-bin/qgis_mapserv.fcgi?map=/web/demos/alaska/alaska_map.qgs";
+  exampleServers["GeoServer Demo - World"] = "http://tiles.boundlessgeo.com/";
 
   QSettings settings;
   settings.beginGroup( "/Qgis/connections-wms" );
diff --git a/src/server/qgsserver.cpp b/src/server/qgsserver.cpp
index 6758f03..4f51aa0 100644
--- a/src/server/qgsserver.cpp
+++ b/src/server/qgsserver.cpp
@@ -202,18 +202,18 @@ void QgsServer::printRequestParameters( const QMap< QString, QString>& parameter
  */
 void QgsServer::printRequestInfos()
 {
-  QgsMessageLog::logMessage( QStringLiteral( "******************** New request ***************" ), QStringLiteral( "Server" ), QgsMessageLog::INFO );
+  QgsMessageLog::logMessage( "******************** New request ***************", "Server", QgsMessageLog::INFO );
   if ( getenv( "REMOTE_ADDR" ) )
   {
-    QgsMessageLog::logMessage( "REMOTE_ADDR: " + QString( getenv( "REMOTE_ADDR" ) ), QStringLiteral( "Server" ), QgsMessageLog::INFO );
+    QgsMessageLog::logMessage( "REMOTE_ADDR: " + QString( getenv( "REMOTE_ADDR" ) ), "Server", QgsMessageLog::INFO );
   }
   if ( getenv( "REMOTE_HOST" ) )
   {
-    QgsMessageLog::logMessage( "REMOTE_HOST: " + QString( getenv( "REMOTE_HOST" ) ), QStringLiteral( "Server" ), QgsMessageLog::INFO );
+    QgsMessageLog::logMessage( "REMOTE_HOST: " + QString( getenv( "REMOTE_HOST" ) ), "Server", QgsMessageLog::INFO );
   }
   if ( getenv( "REMOTE_USER" ) )
   {
-    QgsMessageLog::logMessage( "REMOTE_USER: " + QString( getenv( "REMOTE_USER" ) ), QStringLiteral( "Server" ), QgsMessageLog::INFO );
+    QgsMessageLog::logMessage( "REMOTE_USER: " + QString( getenv( "REMOTE_USER" ) ), "Server", QgsMessageLog::INFO );
   }
   if ( getenv( "REMOTE_IDENT" ) )
   {
@@ -245,7 +245,7 @@ void QgsServer::printRequestInfos()
   }
   if ( getenv( "HTTP_AUTHORIZATION" ) )
   {
-    QgsMessageLog::logMessage( "HTTP_AUTHORIZATION: " + QString( getenv( "HTTP_AUTHORIZATION" ) ), QStringLiteral( "Server" ), QgsMessageLog::INFO );
+    QgsMessageLog::logMessage( "HTTP_AUTHORIZATION: " + QString( getenv( "HTTP_AUTHORIZATION" ) ), "Server", QgsMessageLog::INFO );
   }
 }
 
diff --git a/src/server/qgswfsserver.cpp b/src/server/qgswfsserver.cpp
index 9ccbc6d..1544407 100644
--- a/src/server/qgswfsserver.cpp
+++ b/src/server/qgswfsserver.cpp
@@ -1913,7 +1913,10 @@ QString QgsWFSServer::createFeatureGeoJSON( QgsFeature* feat, int prec, QgsCoord
 
   QgsJSONExporter exporter;
   exporter.setSourceCrs( crs );
-  exporter.setPrecision( prec );
+  //QgsJSONExporter force transform geometry to ESPG:4326
+  //and the RFC 7946 GeoJSON specification recommends limiting coordinate precision to 6
+  Q_UNUSED( prec );
+  //exporter.setPrecision( prec );
 
   //copy feature so we can modify its geometry as required
   QgsFeature f( *feat );
@@ -1990,7 +1993,14 @@ QDomElement QgsWFSServer::createFeatureGML2( QgsFeature* feat, QDomDocument& doc
       delete centroid;
     }
     else
-      gmlElem = QgsOgcUtils::geometryToGML( geom, doc, prec );
+    {
+      QgsAbstractGeometryV2* abstractGeom = geom->geometry();
+      if ( abstractGeom )
+      {
+        gmlElem = abstractGeom->asGML2( doc, prec, "http://www.opengis.net/gml" );
+      }
+    }
+
     if ( !gmlElem.isNull() )
     {
       QgsRectangle box = geom->boundingBox();
@@ -2067,7 +2077,14 @@ QDomElement QgsWFSServer::createFeatureGML3( QgsFeature* feat, QDomDocument& doc
       delete centroid;
     }
     else
-      gmlElem = QgsOgcUtils::geometryToGML( geom, doc, "GML3", prec );
+    {
+      QgsAbstractGeometryV2* abstractGeom = geom->geometry();
+      if ( abstractGeom )
+      {
+        gmlElem = abstractGeom->asGML3( doc, prec, "http://www.opengis.net/gml" );
+      }
+    }
+
     if ( !gmlElem.isNull() )
     {
       QgsRectangle box = geom->boundingBox();
diff --git a/src/server/qgswmsconfigparser.cpp b/src/server/qgswmsconfigparser.cpp
index e844809..275588a 100644
--- a/src/server/qgswmsconfigparser.cpp
+++ b/src/server/qgswmsconfigparser.cpp
@@ -209,6 +209,7 @@ QgsComposition* QgsWMSConfigParser::createPrintComposition( const QString& compo
     //grid space x / y
     currentMap->grid()->setIntervalX( parameterMap.value( mapId + ":GRID_INTERVAL_X" ).toDouble() );
     currentMap->grid()->setIntervalY( parameterMap.value( mapId + ":GRID_INTERVAL_Y" ).toDouble() );
+    currentMap->grid()->setEnabled( currentMap->grid()->intervalX() != 0.0 && currentMap->grid()->intervalY() != 0.0 );
   }
 //update legend
 // if it has an auto-update model
diff --git a/tests/bench/CMakeLists.txt b/tests/bench/CMakeLists.txt
index b605a6a..aa45a27 100644
--- a/tests/bench/CMakeLists.txt
+++ b/tests/bench/CMakeLists.txt
@@ -35,7 +35,7 @@ TARGET_LINK_LIBRARIES(qgis_bench
   ${QT_QTNETWORK_LIBRARY}
   ${QT_QTSVG_LIBRARY}
   ${QT_QTXML_LIBRARY}
-  ${QT_QTWEBKIT_LIBRARY}
+  ${OPTIONAL_QTWEBKIT}
   ${QT_QTMAIN_LIBRARY}
   ${QT_QTTEST_LIBRARY}
 )
diff --git a/tests/src/core/testqgsgeometry.cpp b/tests/src/core/testqgsgeometry.cpp
index 2fe4646..530af24 100644
--- a/tests/src/core/testqgsgeometry.cpp
+++ b/tests/src/core/testqgsgeometry.cpp
@@ -27,6 +27,7 @@
 
 //qgis includes...
 #include <qgsapplication.h>
+#include "qgscompoundcurvev2.h"
 #include <qgsgeometry.h>
 #include "qgsgeometryutils.h"
 #include <qgspoint.h>
@@ -67,6 +68,7 @@ class TestQgsGeometry : public QObject
     // geometry types
     void pointV2(); //test QgsPointV2
     void lineStringV2(); //test QgsLineStringV2
+    void compoundCurveV2(); //test QgsCompoundCurveV2
     void polygonV2(); //test QgsPolygonV2
     void multiPoint();
     void multiLineString();
@@ -1426,9 +1428,9 @@ void TestQgsGeometry::lineStringV2()
   QCOMPARE( elemToString( exportLineFloat.asGML2( doc, 3 ) ), expectedGML2prec3 );
 
   //asGML3
-  QString expectedGML3( "<Curve xmlns=\"gml\"><segments xmlns=\"gml\"><LineStringSegment xmlns=\"gml\"><posList xmlns=\"gml\" srsDimension=\"2\">31 32 41 42 51 52</posList></LineStringSegment></segments></Curve>" );
+  QString expectedGML3( "<LineString xmlns=\"gml\"><posList xmlns=\"gml\" srsDimension=\"2\">31 32 41 42 51 52</posList></LineString>" );
   QCOMPARE( elemToString( exportLine.asGML3( doc ) ), expectedGML3 );
-  QString expectedGML3prec3( "<Curve xmlns=\"gml\"><segments xmlns=\"gml\"><LineStringSegment xmlns=\"gml\"><posList xmlns=\"gml\" srsDimension=\"2\">0.333 0.667 1.333 1.667 2.333 2.667</posList></LineStringSegment></segments></Curve>" );
+  QString expectedGML3prec3( "<LineString xmlns=\"gml\"><posList xmlns=\"gml\" srsDimension=\"2\">0.333 0.667 1.333 1.667 2.333 2.667</posList></LineString>" );
   QCOMPARE( elemToString( exportLineFloat.asGML3( doc, 3 ) ), expectedGML3prec3 );
 
   //asJSON
@@ -2077,13 +2079,13 @@ void TestQgsGeometry::lineStringV2()
   QCOMPARE( area, 1.0 );
   l36.setPoints( QgsPointSequenceV2() << QgsPointV2( 5, 10 ) << QgsPointV2( 10, 10 ) );
   l36.sumUpArea( area );
-  QCOMPARE( area, 1.0 );
+  QVERIFY( qgsDoubleNear( area, -24 ) );
   l36.setPoints( QgsPointSequenceV2() << QgsPointV2( 0, 0 ) << QgsPointV2( 2, 0 ) << QgsPointV2( 2, 2 ) );
   l36.sumUpArea( area );
-  QVERIFY( qgsDoubleNear( area, 3.0 ) );
+  QVERIFY( qgsDoubleNear( area, -22 ) );
   l36.setPoints( QgsPointSequenceV2() << QgsPointV2( 0, 0 ) << QgsPointV2( 2, 0 ) << QgsPointV2( 2, 2 ) << QgsPointV2( 0, 2 ) );
   l36.sumUpArea( area );
-  QVERIFY( qgsDoubleNear( area, 7.0 ) );
+  QVERIFY( qgsDoubleNear( area, -18 ) );
 
   //boundingBox - test that bounding box is updated after every modification to the line string
   QgsLineStringV2 l37;
@@ -2200,6 +2202,31 @@ void TestQgsGeometry::lineStringV2()
   QCOMPARE( static_cast< QgsPointV2*>( mpBoundary->geometryN( 1 ) )->z(), 20.0 );
 }
 
+void TestQgsGeometry::compoundCurveV2()
+{
+  //test that area of a compound curve ring is equal to a closed linestring with the same vertices
+  QgsCompoundCurveV2 cc;
+  QgsLineStringV2* l1 = new QgsLineStringV2();
+  l1->setPoints( QgsPointSequenceV2() << QgsPointV2( 1, 1 ) << QgsPointV2( 0, 2 ) );
+  cc.addCurve( l1 );
+  QgsLineStringV2* l2 = new QgsLineStringV2();
+  l2->setPoints( QgsPointSequenceV2() << QgsPointV2( 0, 2 ) << QgsPointV2( -1, 0 ) << QgsPointV2( 0, -1 ) );
+  cc.addCurve( l2 );
+  QgsLineStringV2* l3 = new QgsLineStringV2();
+  l3->setPoints( QgsPointSequenceV2() << QgsPointV2( 0, -1 ) << QgsPointV2( 1, 1 ) );
+  cc.addCurve( l3 );
+
+  double ccArea = 0.0;
+  cc.sumUpArea( ccArea );
+
+  QgsLineStringV2 ls;
+  ls.setPoints( QgsPointSequenceV2() << QgsPointV2( 1, 1 ) << QgsPointV2( 0, 2 ) <<  QgsPointV2( -1, 0 ) << QgsPointV2( 0, -1 )
+                << QgsPointV2( 1, 1 ) );
+  double lsArea = 0.0;
+  ls.sumUpArea( lsArea );
+  QVERIFY( qgsDoubleNear( ccArea, lsArea ) );
+}
+
 void TestQgsGeometry::polygonV2()
 {
   //test constructor
@@ -2907,11 +2934,11 @@ void TestQgsGeometry::polygonV2()
   QCOMPARE( elemToString( exportPolygonFloat.asGML2( doc, 3 ) ), expectedGML2prec3 );
 
   //as GML3
-  QString expectedGML3( "<Polygon xmlns=\"gml\"><exterior xmlns=\"gml\"><LinearRing xmlns=\"gml\"><coordinates xmlns=\"gml\">0,0 0,10 10,10 10,0 0,0</coordinates></LinearRing></exterior>" );
-  expectedGML3 += QString( "<interior xmlns=\"gml\"><LinearRing xmlns=\"gml\"><coordinates xmlns=\"gml\">1,1 1,9 9,9 9,1 1,1</coordinates></LinearRing></interior></Polygon>" );
+  QString expectedGML3( "<Polygon xmlns=\"gml\"><exterior xmlns=\"gml\"><LinearRing xmlns=\"gml\"><posList xmlns=\"gml\" srsDimension=\"2\">0 0 0 10 10 10 10 0 0 0</posList></LinearRing></exterior>" );
+  expectedGML3 += QString( "<interior xmlns=\"gml\"><LinearRing xmlns=\"gml\"><posList xmlns=\"gml\" srsDimension=\"2\">1 1 1 9 9 9 9 1 1 1</posList></LinearRing></interior></Polygon>" );
   QCOMPARE( elemToString( exportPolygon.asGML3( doc ) ), expectedGML3 );
-  QString expectedGML3prec3( "<Polygon xmlns=\"gml\"><exterior xmlns=\"gml\"><LinearRing xmlns=\"gml\"><coordinates xmlns=\"gml\">1.111,1.111 1.111,11.111 11.111,11.111 11.111,1.111 1.111,1.111</coordinates></LinearRing></exterior>" );
-  expectedGML3prec3 += QString( "<interior xmlns=\"gml\"><LinearRing xmlns=\"gml\"><coordinates xmlns=\"gml\">0.667,0.667 0.667,1.333 1.333,1.333 1.333,0.667 0.667,0.667</coordinates></LinearRing></interior></Polygon>" );
+  QString expectedGML3prec3( "<Polygon xmlns=\"gml\"><exterior xmlns=\"gml\"><LinearRing xmlns=\"gml\"><posList xmlns=\"gml\" srsDimension=\"2\">1.111 1.111 1.111 11.111 11.111 11.111 11.111 1.111 1.111 1.111</posList></LinearRing></exterior>" );
+  expectedGML3prec3 += QString( "<interior xmlns=\"gml\"><LinearRing xmlns=\"gml\"><posList xmlns=\"gml\" srsDimension=\"2\">0.667 0.667 0.667 1.333 1.333 1.333 1.333 0.667 0.667 0.667</posList></LinearRing></interior></Polygon>" );
   QCOMPARE( elemToString( exportPolygonFloat.asGML3( doc, 3 ) ), expectedGML3prec3 );
 
   //removing the fourth to last vertex removes the whole ring
diff --git a/tests/src/core/testqgsgml.cpp b/tests/src/core/testqgsgml.cpp
index 3d73858..7e1ea6b 100644
--- a/tests/src/core/testqgsgml.cpp
+++ b/tests/src/core/testqgsgml.cpp
@@ -75,6 +75,7 @@ class TestQgsGML : public QObject
     void testPartialFeature();
     void testThroughOGRGeometry();
     void testThroughOGRGeometry_urn_EPSG_4326();
+    void testAccents();
 };
 
 const QString data1( "<myns:FeatureCollection "
@@ -1101,6 +1102,53 @@ void TestQgsGML::testThroughOGRGeometry_urn_EPSG_4326()
   QCOMPARE( multi[0][0][0], QgsPoint( 2, 49 ) );
   delete features[0].first;
 }
+void TestQgsGML::testAccents()
+{
+  QgsFields fields;
+  QgsGmlStreamingParser gmlParser( QString::fromUtf8( QByteArray( "my\xc3\xa9typename" ) ),
+                                   QString::fromUtf8( QByteArray( "my\xc3\xa9geom" ) ),
+                                   fields );
+  QCOMPARE( gmlParser.processData( QByteArray( "<myns:FeatureCollection "
+                                   "xmlns:myns='http://myns' "
+                                   "xmlns:gml='http://www.opengis.net/gml'>"
+                                   "<gml:featureMember>"
+                                   "<myns:my\xc3\xa9typename fid='mytypename.1'>"
+                                   "<myns:my\xc3\xa9geom>"
+                                   "<gml:MultiSurface srsName='EPSG:27700'>"
+                                   "<gml:surfaceMember>"
+                                   "<gml:Polygon srsName='EPSG:27700'>"
+                                   "<gml:exterior>"
+                                   "<gml:LinearRing>"
+                                   "<gml:posList>0 0 0 10 10 10 10 0 0 0</gml:posList>"
+                                   "</gml:LinearRing>"
+                                   "</gml:exterior>"
+                                   "</gml:Polygon>"
+                                   "</gml:surfaceMember>"
+                                   "<gml:surfaceMember>"
+                                   "<gml:Polygon srsName='EPSG:27700'>"
+                                   "<gml:exterior>"
+                                   "<gml:LinearRing>"
+                                   "<gml:posList>0 0 0 10 10 10 10 0 0 0</gml:posList>"
+                                   "</gml:LinearRing>"
+                                   "</gml:exterior>"
+                                   "</gml:Polygon>"
+                                   "</gml:surfaceMember>"
+                                   "</gml:MultiSurface>"
+                                   "</myns:my\xc3\xa9geom>"
+                                   "</myns:my\xc3\xa9typename>"
+                                   "</gml:featureMember>"
+                                   "</myns:FeatureCollection>" ), true ), true );
+  QCOMPARE( gmlParser.wkbType(), QGis::WKBMultiPolygon );
+  QVector<QgsGmlStreamingParser::QgsGmlFeaturePtrGmlIdPair> features = gmlParser.getAndStealReadyFeatures();
+  QCOMPARE( features.size(), 1 );
+  QVERIFY( features[0].first->constGeometry() != nullptr );
+  QCOMPARE( features[0].first->constGeometry()->wkbType(), QGis::WKBMultiPolygon );
+  QgsMultiPolygon multi = features[0].first->constGeometry()->asMultiPolygon();
+  QCOMPARE( multi.size(), 2 );
+  QCOMPARE( multi[0].size(), 1 );
+  QCOMPARE( multi[0][0].size(), 5 );
+  delete features[0].first;
+}
 
 QTEST_MAIN( TestQgsGML )
 #include "testqgsgml.moc"
diff --git a/tests/src/gui/CMakeLists.txt b/tests/src/gui/CMakeLists.txt
index f1c823a..94d8692 100644
--- a/tests/src/gui/CMakeLists.txt
+++ b/tests/src/gui/CMakeLists.txt
@@ -102,7 +102,7 @@ MACRO (ADD_QGIS_TEST testname testsrc)
     ${QT_QTSVG_LIBRARY}
     ${QT_QTTEST_LIBRARY}
     ${QT_QTNETWORK_LIBRARY}
-    ${QT_QTWEBKIT_LIBRARY}
+    ${OPTIONAL_QTWEBKIT}
     ${QT_QTMAIN_LIBRARY}
     ${PROJ_LIBRARY}
     ${GEOS_LIBRARY}
diff --git a/tests/src/providers/CMakeLists.txt b/tests/src/providers/CMakeLists.txt
index 7e8b2e9..0388150 100644
--- a/tests/src/providers/CMakeLists.txt
+++ b/tests/src/providers/CMakeLists.txt
@@ -124,7 +124,7 @@ IF(UNIX AND NOT ANDROID AND CMAKE_BUILD_TYPE MATCHES Debug)
     ${QT_QTNETWORK_LIBRARY}
     ${QT_QTSVG_LIBRARY}
     ${QT_QTXML_LIBRARY}
-    ${QT_QTWEBKIT_LIBRARY}
+    ${OPTIONAL_QTWEBKIT}
     ${QT_QTMAIN_LIBRARY}
     ${QT_QTSCRIPT_LIBRARY}
     qgis_core
diff --git a/tests/src/python/CMakeLists.txt b/tests/src/python/CMakeLists.txt
index 0ab0ad7..ada22f6 100644
--- a/tests/src/python/CMakeLists.txt
+++ b/tests/src/python/CMakeLists.txt
@@ -95,6 +95,7 @@ ADD_PYTHON_TEST(PyQgsSQLStatement test_qgssqlstatement.py)
 ADD_PYTHON_TEST(PyQgsStringStatisticalSummary test_qgsstringstatisticalsummary.py)
 ADD_PYTHON_TEST(PyQgsSymbolLayerV2 test_qgssymbollayerv2.py)
 ADD_PYTHON_TEST(PyQgsSymbolLayerV2CreateSld test_qgssymbollayerv2_createsld.py)
+ADD_PYTHON_TEST(PyQgsSymbolLayerReadSld test_qgssymbollayerv2_readsld.py)
 ADD_PYTHON_TEST(PyQgsArrowSymbolLayer test_qgsarrowsymbollayer.py)
 ADD_PYTHON_TEST(PyQgsSymbolExpressionVariables test_qgssymbolexpressionvariables.py)
 ADD_PYTHON_TEST(PyQgsSyntacticSugar test_syntactic_sugar.py)
diff --git a/tests/src/python/test_provider_wfs.py b/tests/src/python/test_provider_wfs.py
index 1f8c72f..2a916df 100644
--- a/tests/src/python/test_provider_wfs.py
+++ b/tests/src/python/test_provider_wfs.py
@@ -2225,6 +2225,142 @@ class TestPyQgsWFSProvider(unittest.TestCase, ProviderTestCase):
         got = got_f[0].geometry().geometry()
         self.assertEqual((got.x(), got.y()), (2.0, 49.0))
 
+    def testWFS20TransactionsDisabled(self):
+        """Test WFS 2.0 Transaction disabled"""
+
+        endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_WFS_2.0_transaction'
+
+        with open(sanitize(endpoint, '?SERVICE=WFS?REQUEST=GetCapabilities?ACCEPTVERSIONS=2.0.0,1.1.0,1.0.0'), 'wb') as f:
+            f.write("""
+<wfs:WFS_Capabilities version="2.0.0" xmlns="http://www.opengis.net/wfs/2.0" xmlns:wfs="http://www.opengis.net/wfs/2.0" xmlns:ows="http://www.opengis.net/ows/1.1" xmlns:gml="http://schemas.opengis.net/gml/3.2" xmlns:fes="http://www.opengis.net/fes/2.0">
+  <ows:OperationsMetadata>
+    <ows:Operation name="GetFeature">
+      <ows:Constraint name="CountDefault">
+        <ows:NoValues/>
+        <ows:DefaultValue>1</ows:DefaultValue>
+      </ows:Constraint>
+    </ows:Operation>
+    <ows:Constraint name="ImplementsTransactionalWFS">
+      <ows:NoValues/>
+      <ows:DefaultValue>TRUE</ows:DefaultValue>
+    </ows:Constraint>
+  </ows:OperationsMetadata>
+  <FeatureTypeList>
+    <FeatureType>
+      <Name>my:typename</Name>
+      <Title>Title</Title>
+      <Abstract>Abstract</Abstract>
+      <DefaultCRS>urn:ogc:def:crs:EPSG::4326</DefaultCRS>
+      <ows:WGS84BoundingBox>
+        <ows:LowerCorner>-71.123 66.33</ows:LowerCorner>
+        <ows:UpperCorner>-65.32 78.3</ows:UpperCorner>
+      </ows:WGS84BoundingBox>
+    </FeatureType>
+  </FeatureTypeList>
+</wfs:WFS_Capabilities>""".encode('UTF-8'))
+
+        with open(sanitize(endpoint, '?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAME=my:typename'), 'wb') as f:
+            f.write("""
+<xsd:schema xmlns:my="http://my" xmlns:gml="http://www.opengis.net/gml/3.2" xmlns:xsd="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" targetNamespace="http://my">
+  <xsd:import namespace="http://www.opengis.net/gml/3.2"/>
+  <xsd:complexType name="typenameType">
+    <xsd:complexContent>
+      <xsd:extension base="gml:AbstractFeatureType">
+        <xsd:sequence>
+          <xsd:element maxOccurs="1" minOccurs="0" name="geometryProperty" nillable="true" type="gml:PointPropertyType"/>
+        </xsd:sequence>
+      </xsd:extension>
+    </xsd:complexContent>
+  </xsd:complexType>
+  <xsd:element name="typename" substitutionGroup="gml:_Feature" type="my:typenameType"/>
+</xsd:schema>
+""".encode('UTF-8'))
+
+        # Create test layer
+        vl = QgsVectorLayer(u"url='http://" + endpoint + u"' typename='my:typename'", u'test', u'WFS')
+        assert vl.isValid()
+        self.assertEqual(vl.dataProvider().capabilities() & vl.dataProvider().EditingCapabilities, 0)
+        self.assertEqual(vl.wkbType(), QgsWKBTypes.Point)
+
+    def testWFS20TransactionsEnabled(self):
+        """Test WFS 2.0 Transaction enabled"""
+
+        endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_WFS_2.0_transaction'
+
+        with open(sanitize(endpoint, '?SERVICE=WFS?REQUEST=GetCapabilities?ACCEPTVERSIONS=2.0.0,1.1.0,1.0.0'), 'wb') as f:
+            f.write("""
+<wfs:WFS_Capabilities version="2.0.0" xmlns="http://www.opengis.net/wfs/2.0" xmlns:wfs="http://www.opengis.net/wfs/2.0" xmlns:ows="http://www.opengis.net/ows/1.1" xmlns:gml="http://schemas.opengis.net/gml/3.2" xmlns:fes="http://www.opengis.net/fes/2.0">
+  <ows:OperationsMetadata>
+    <ows:Operation name="GetFeature">
+      <ows:Constraint name="CountDefault">
+        <ows:NoValues/>
+        <ows:DefaultValue>1</ows:DefaultValue>
+      </ows:Constraint>
+    </ows:Operation>
+    <ows:Constraint name="ImplementsTransactionalWFS">
+      <ows:NoValues/>
+      <ows:DefaultValue>TRUE</ows:DefaultValue>
+    </ows:Constraint>
+    <ows:Operation name="Transaction">
+      <ows:DCP>
+        <ows:HTTP>
+          <ows:Get xlink:href="http://{endpoint}"/>
+          <ows:Post xlink:href="{endpoint}"/>
+        </ows:HTTP>
+      </ows:DCP>
+      <ows:Parameter name="inputFormat">
+        <ows:AllowedValues>
+          <ows:Value>text/xml; subtype=gml/3.2</ows:Value>
+        </ows:AllowedValues>
+      </ows:Parameter>
+      <ows:Parameter name="releaseAction">
+        <ows:AllowedValues>
+          <ows:Value>ALL</ows:Value>
+          <ows:Value>SOME</ows:Value>
+        </ows:AllowedValues>
+      </ows:Parameter>
+    </ows:Operation>
+  </ows:OperationsMetadata>
+  <FeatureTypeList>
+    <FeatureType>
+      <Name>my:typename</Name>
+      <Title>Title</Title>
+      <Abstract>Abstract</Abstract>
+      <DefaultCRS>urn:ogc:def:crs:EPSG::4326</DefaultCRS>
+      <ows:WGS84BoundingBox>
+        <ows:LowerCorner>-71.123 66.33</ows:LowerCorner>
+        <ows:UpperCorner>-65.32 78.3</ows:UpperCorner>
+      </ows:WGS84BoundingBox>
+    </FeatureType>
+  </FeatureTypeList>
+</wfs:WFS_Capabilities>""".format(endpoint=endpoint).encode('UTF-8'))
+
+        with open(sanitize(endpoint, '?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAME=my:typename'), 'wb') as f:
+            f.write("""
+<xsd:schema xmlns:my="http://my" xmlns:gml="http://www.opengis.net/gml/3.2" xmlns:xsd="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" targetNamespace="http://my">
+  <xsd:import namespace="http://www.opengis.net/gml/3.2"/>
+  <xsd:complexType name="typenameType">
+    <xsd:complexContent>
+      <xsd:extension base="gml:AbstractFeatureType">
+        <xsd:sequence>
+          <xsd:element maxOccurs="1" minOccurs="0" name="intfield" nillable="true" type="xsd:int"/>
+          <xsd:element maxOccurs="1" minOccurs="0" name="longfield" nillable="true" type="xsd:long"/>
+          <xsd:element maxOccurs="1" minOccurs="0" name="stringfield" nillable="true" type="xsd:string"/>
+          <xsd:element maxOccurs="1" minOccurs="0" name="datetimefield" nillable="true" type="xsd:dateTime"/>
+          <xsd:element maxOccurs="1" minOccurs="0" name="geomfield" nillable="true" type="gml:PointPropertyType"/>
+        </xsd:sequence>
+      </xsd:extension>
+    </xsd:complexContent>
+  </xsd:complexType>
+  <xsd:element name="typename" substitutionGroup="gml:_Feature" type="my:typenameType"/>
+</xsd:schema>
+""".encode('UTF-8'))
+
+        # Create test layer
+        vl = QgsVectorLayer(u"url='http://" + endpoint + u"' typename='my:typename'", u'test', u'WFS')
+        assert vl.isValid()
+        self.assertNotEqual(vl.dataProvider().capabilities() & vl.dataProvider().EditingCapabilities, 0)
+        self.assertEqual(vl.wkbType(), QgsWKBTypes.Point)
 
 if __name__ == '__main__':
     unittest.main()
diff --git a/tests/src/python/test_qgsgeometry.py b/tests/src/python/test_qgsgeometry.py
index d805fb9..04d9502 100644
--- a/tests/src/python/test_qgsgeometry.py
+++ b/tests/src/python/test_qgsgeometry.py
@@ -180,31 +180,31 @@ class TestQgsGeometry(unittest.TestCase):
                 bbox = geom.geometry().boundingBox()
                 exp = float(row['x_min'])
                 result = bbox.xMinimum()
-                assert doubleNear(result, exp), "Min X {}: mismatch Expected:\n{}\nGot:\n{}\n".format(i + 1, exp, result)
+                self.assertAlmostEqual(result, exp, 5, "Min X {}: mismatch Expected:\n{}\nGot:\n{}\n".format(i + 1, exp, result))
                 exp = float(row['y_min'])
                 result = bbox.yMinimum()
-                assert doubleNear(result, exp), "Min Y {}: mismatch Expected:\n{}\nGot:\n{}\n".format(i + 1, exp, result)
+                self.assertAlmostEqual(result, exp, 5, "Min Y {}: mismatch Expected:\n{}\nGot:\n{}\n".format(i + 1, exp, result))
                 exp = float(row['x_max'])
                 result = bbox.xMaximum()
-                assert doubleNear(result, exp), "Max X {}: mismatch Expected:\n{}\nGot:\n{}\n".format(i + 1, exp, result)
+                self.assertAlmostEqual(result, exp, 5, "Max X {}: mismatch Expected:\n{}\nGot:\n{}\n".format(i + 1, exp, result))
                 exp = float(row['y_max'])
                 result = bbox.yMaximum()
-                assert doubleNear(result, exp), "Max Y {}: mismatch Expected:\n{}\nGot:\n{}\n".format(i + 1, exp, result)
+                self.assertAlmostEqual(result, exp, 5, "Max Y {}: mismatch Expected:\n{}\nGot:\n{}\n".format(i + 1, exp, result))
 
                 # test area calculation
                 exp = float(row['area'])
                 result = geom.geometry().area()
-                assert doubleNear(result, exp), "Area {}: mismatch Expected:\n{}\nGot:\n{}\n".format(i + 1, exp, result)
+                self.assertAlmostEqual(result, exp, 5, "Area {}: mismatch Expected:\n{}\nGot:\n{}\n".format(i + 1, exp, result))
 
                 # test length calculation
                 exp = float(row['length'])
                 result = geom.geometry().length()
-                assert doubleNear(result, exp, 0.00001), "Length {}: mismatch Expected:\n{}\nGot:\n{}\n".format(i + 1, exp, result)
+                self.assertAlmostEqual(result, exp, 5, "Length {}: mismatch Expected:\n{}\nGot:\n{}\n".format(i + 1, exp, result))
 
                 # test perimeter calculation
                 exp = float(row['perimeter'])
                 result = geom.geometry().perimeter()
-                assert doubleNear(result, exp, 0.00001), "Perimeter {}: mismatch Expected:\n{}\nGot:\n{}\n".format(i + 1, exp, result)
+                self.assertAlmostEqual(result, exp, 5, "Perimeter {}: mismatch Expected:\n{}\nGot:\n{}\n".format(i + 1, exp, result))
 
     def testIntersection(self):
         myLine = QgsGeometry.fromPolyline([
diff --git a/tests/src/python/test_qgsserver.py b/tests/src/python/test_qgsserver.py
index 454fd0b..6028683 100644
--- a/tests/src/python/test_qgsserver.py
+++ b/tests/src/python/test_qgsserver.py
@@ -378,6 +378,323 @@ class TestQgsServer(unittest.TestCase):
         for id, req in tests:
             self.wfs_getfeature_post_compare(id, req)
 
+    def test_wms_getmap_basic(self):
+        qs = "&".join(["%s=%s" % i for i in list({
+            "MAP": urllib.quote(self.projectPath),
+            "SERVICE": "WMS",
+            "VERSION": "1.1.1",
+            "REQUEST": "GetMap",
+            "LAYERS": "Country",
+            "STYLES": "",
+            "FORMAT": "image/png",
+            "BBOX": "-16817707,-4710778,5696513,14587125",
+            "HEIGHT": "500",
+            "WIDTH": "500",
+            "CRS": "EPSG:3857"
+        }.items())])
+
+        r, h = self._result(self.server.handleRequest(qs))
+        self._img_diff_error(r, h, "WMS_GetMap_Basic")
+
+    def test_wms_getmap_transparent(self):
+        qs = "&".join(["%s=%s" % i for i in list({
+            "MAP": urllib.quote(self.projectPath),
+            "SERVICE": "WMS",
+            "VERSION": "1.1.1",
+            "REQUEST": "GetMap",
+            "LAYERS": "Country",
+            "STYLES": "",
+            "FORMAT": "image/png",
+            "BBOX": "-16817707,-4710778,5696513,14587125",
+            "HEIGHT": "500",
+            "WIDTH": "500",
+            "CRS": "EPSG:3857",
+            "TRANSPARENT": "TRUE"
+        }.items())])
+
+        r, h = self._result(self.server.handleRequest(qs))
+        self._img_diff_error(r, h, "WMS_GetMap_Transparent")
+
+    def test_wms_getmap_background(self):
+        qs = "&".join(["%s=%s" % i for i in list({
+            "MAP": urllib.quote(self.projectPath),
+            "SERVICE": "WMS",
+            "VERSION": "1.1.1",
+            "REQUEST": "GetMap",
+            "LAYERS": "Country",
+            "STYLES": "",
+            "FORMAT": "image/png",
+            "BBOX": "-16817707,-4710778,5696513,14587125",
+            "HEIGHT": "500",
+            "WIDTH": "500",
+            "CRS": "EPSG:3857",
+            "BGCOLOR": "green"
+        }.items())])
+
+        r, h = self._result(self.server.handleRequest(qs))
+        self._img_diff_error(r, h, "WMS_GetMap_Background")
+
+        qs = "&".join(["%s=%s" % i for i in list({
+            "MAP": urllib.quote(self.projectPath),
+            "SERVICE": "WMS",
+            "VERSION": "1.1.1",
+            "REQUEST": "GetMap",
+            "LAYERS": "Country",
+            "STYLES": "",
+            "FORMAT": "image/png",
+            "BBOX": "-16817707,-4710778,5696513,14587125",
+            "HEIGHT": "500",
+            "WIDTH": "500",
+            "CRS": "EPSG:3857",
+            "BGCOLOR": "0x008000"
+        }.items())])
+
+        r, h = self._result(self.server.handleRequest(qs))
+        self._img_diff_error(r, h, "WMS_GetMap_Background_Hex")
+
+    def test_wms_getmap_order(self):
+        qs = "&".join(["%s=%s" % i for i in list({
+            "MAP": urllib.quote(self.projectPath),
+            "SERVICE": "WMS",
+            "VERSION": "1.1.1",
+            "REQUEST": "GetMap",
+            "LAYERS": "Hello,Country",
+            "STYLES": "",
+            "FORMAT": "image/png",
+            "BBOX": "-16817707,-4710778,5696513,14587125",
+            "HEIGHT": "500",
+            "WIDTH": "500",
+            "CRS": "EPSG:3857"
+        }.items())])
+
+        r, h = self._result(self.server.handleRequest(qs))
+        self._img_diff_error(r, h, "WMS_GetMap_LayerOrder")
+
+    def test_wms_getmap_srs(self):
+        qs = "&".join(["%s=%s" % i for i in list({
+            "MAP": urllib.quote(self.projectPath),
+            "SERVICE": "WMS",
+            "VERSION": "1.1.1",
+            "REQUEST": "GetMap",
+            "LAYERS": "Country,Hello",
+            "STYLES": "",
+            "FORMAT": "image/png",
+            "BBOX": "-151.7,-38.9,51.0,78.0",
+            "HEIGHT": "500",
+            "WIDTH": "500",
+            "CRS": "EPSG:4326"
+        }.items())])
+
+        r, h = self._result(self.server.handleRequest(qs))
+        self._img_diff_error(r, h, "WMS_GetMap_SRS")
+
+    def test_wms_getmap_style(self):
+      # default style
+        qs = "&".join(["%s=%s" % i for i in list({
+            "MAP": urllib.quote(self.projectPath),
+            "SERVICE": "WMS",
+            "VERSION": "1.1.1",
+            "REQUEST": "GetMap",
+            "LAYERS": "Country_Labels",
+            "STYLES": "",
+            "FORMAT": "image/png",
+            "BBOX": "-16817707,-4710778,5696513,14587125",
+            "HEIGHT": "500",
+            "WIDTH": "500",
+            "CRS": "EPSG:3857"
+        }.items())])
+
+        r, h = self._result(self.server.handleRequest(qs))
+        self._img_diff_error(r, h, "WMS_GetMap_StyleDefault")
+
+      # custom style
+        qs = "&".join(["%s=%s" % i for i in list({
+            "MAP": urllib.quote(self.projectPath),
+            "SERVICE": "WMS",
+            "VERSION": "1.1.1",
+            "REQUEST": "GetMap",
+            "LAYERS": "Country_Labels",
+            "STYLES": "custom",
+            "FORMAT": "image/png",
+            "BBOX": "-16817707,-4710778,5696513,14587125",
+            "HEIGHT": "500",
+            "WIDTH": "500",
+            "CRS": "EPSG:3857"
+        }.items())])
+
+        r, h = self._result(self.server.handleRequest(qs))
+        self._img_diff_error(r, h, "WMS_GetMap_StyleCustom")
+
+    def test_wms_getmap_filter(self):
+        qs = "&".join(["%s=%s" % i for i in list({
+            "MAP": urllib.quote(self.projectPath),
+            "SERVICE": "WMS",
+            "VERSION": "1.1.1",
+            "REQUEST": "GetMap",
+            "LAYERS": "Country,Hello",
+            "STYLES": "",
+            "FORMAT": "image/png",
+            "BBOX": "-16817707,-4710778,5696513,14587125",
+            "HEIGHT": "500",
+            "WIDTH": "500",
+            "CRS": "EPSG:3857",
+            "FILTER": "Country:\"name\" = 'eurasia'"
+        }.items())])
+
+        r, h = self._result(self.server.handleRequest(qs))
+        self._img_diff_error(r, h, "WMS_GetMap_Filter")
+
+    def test_wms_getmap_selection(self):
+        qs = "&".join(["%s=%s" % i for i in list({
+            "MAP": urllib.quote(self.projectPath),
+            "SERVICE": "WMS",
+            "VERSION": "1.1.1",
+            "REQUEST": "GetMap",
+            "LAYERS": "Country,Hello",
+            "STYLES": "",
+            "FORMAT": "image/png",
+            "BBOX": "-16817707,-4710778,5696513,14587125",
+            "HEIGHT": "500",
+            "WIDTH": "500",
+            "SRS": "EPSG:3857",
+            "SELECTION": "Country: 4"
+        }.items())])
+
+        r, h = self._result(self.server.handleRequest(qs))
+        self._img_diff_error(r, h, "WMS_GetMap_Selection")
+
+    def test_wms_getmap_opacities(self):
+        qs = "&".join(["%s=%s" % i for i in list({
+            "MAP": urllib.quote(self.projectPath),
+            "SERVICE": "WMS",
+            "VERSION": "1.1.1",
+            "REQUEST": "GetMap",
+            "LAYERS": "Country,Hello",
+            "STYLES": "",
+            "FORMAT": "image/png",
+            "BBOX": "-16817707,-4710778,5696513,14587125",
+            "HEIGHT": "500",
+            "WIDTH": "500",
+            "CRS": "EPSG:3857",
+            "OPACITIES": "125, 50"
+        }.items())])
+
+        r, h = self._result(self.server.handleRequest(qs))
+        self._img_diff_error(r, h, "WMS_GetMap_Opacities")
+
+    def test_wms_getprint_basic(self):
+        qs = "&".join(["%s=%s" % i for i in list({
+            "MAP": urllib.quote(self.projectPath),
+            "SERVICE": "WMS",
+            "VERSION": "1.1.1",
+            "REQUEST": "GetPrint",
+            "TEMPLATE": "layoutA4",
+            "FORMAT": "png",
+            "map0:EXTENT": "-33626185.498,-13032965.185,33978427.737,16020257.031",
+            "map0:LAYERS": "Country,Hello",
+            "HEIGHT": "500",
+            "WIDTH": "500",
+            "CRS": "EPSG:3857"
+        }.items())])
+
+        r, h = self._result(self.server.handleRequest(qs))
+        self._img_diff_error(r, h, "WMS_GetPrint_Basic")
+
+    def test_wms_getprint_srs(self):
+        qs = "&".join(["%s=%s" % i for i in list({
+            "MAP": urllib.quote(self.projectPath),
+            "SERVICE": "WMS",
+            "VERSION": "1.1.1",
+            "REQUEST": "GetPrint",
+            "TEMPLATE": "layoutA4",
+            "FORMAT": "png",
+            "map0:EXTENT": "-309.015,-133.011,312.179,133.949",
+            "map0:LAYERS": "Country,Hello",
+            "HEIGHT": "500",
+            "WIDTH": "500",
+            "CRS": "EPSG:4326"
+        }.items())])
+
+        r, h = self._result(self.server.handleRequest(qs))
+        self._img_diff_error(r, h, "WMS_GetPrint_SRS")
+
+    def test_wms_getprint_scale(self):
+        qs = "&".join(["%s=%s" % i for i in list({
+            "MAP": urllib.quote(self.projectPath),
+            "SERVICE": "WMS",
+            "VERSION": "1.1.1",
+            "REQUEST": "GetPrint",
+            "TEMPLATE": "layoutA4",
+            "FORMAT": "png",
+            "map0:EXTENT": "-33626185.498,-13032965.185,33978427.737,16020257.031",
+            "map0:LAYERS": "Country,Hello",
+            "map0:SCALE": "36293562",
+            "HEIGHT": "500",
+            "WIDTH": "500",
+            "CRS": "EPSG:3857"
+        }.items())])
+
+        r, h = self._result(self.server.handleRequest(qs))
+        self._img_diff_error(r, h, "WMS_GetPrint_Scale")
+
+    def test_wms_getprint_grid(self):
+        qs = "&".join(["%s=%s" % i for i in list({
+            "MAP": urllib.quote(self.projectPath),
+            "SERVICE": "WMS",
+            "VERSION": "1.1.1",
+            "REQUEST": "GetPrint",
+            "TEMPLATE": "layoutA4",
+            "FORMAT": "png",
+            "map0:EXTENT": "-33626185.498,-13032965.185,33978427.737,16020257.031",
+            "map0:LAYERS": "Country,Hello",
+            "map0:GRID_INTERVAL_X": "1000000",
+            "map0:GRID_INTERVAL_Y": "2000000",
+            "HEIGHT": "500",
+            "WIDTH": "500",
+            "CRS": "EPSG:3857"
+        }.items())])
+
+        r, h = self._result(self.server.handleRequest(qs))
+        self._img_diff_error(r, h, "WMS_GetPrint_Grid")
+
+    def test_wms_getprint_rotation(self):
+        qs = "&".join(["%s=%s" % i for i in list({
+            "MAP": urllib.quote(self.projectPath),
+            "SERVICE": "WMS",
+            "VERSION": "1.1.1",
+            "REQUEST": "GetPrint",
+            "TEMPLATE": "layoutA4",
+            "FORMAT": "png",
+            "map0:EXTENT": "-33626185.498,-13032965.185,33978427.737,16020257.031",
+            "map0:LAYERS": "Country,Hello",
+            "map0:ROTATION": "45",
+            "HEIGHT": "500",
+            "WIDTH": "500",
+            "CRS": "EPSG:3857"
+        }.items())])
+
+        r, h = self._result(self.server.handleRequest(qs))
+        self._img_diff_error(r, h, "WMS_GetPrint_Rotation")
+
+    def test_wms_getprint_selection(self):
+        qs = "&".join(["%s=%s" % i for i in list({
+            "MAP": urllib.quote(self.projectPath),
+            "SERVICE": "WMS",
+            "VERSION": "1.1.1",
+            "REQUEST": "GetPrint",
+            "TEMPLATE": "layoutA4",
+            "FORMAT": "png",
+            "map0:EXTENT": "-33626185.498,-13032965.185,33978427.737,16020257.031",
+            "map0:LAYERS": "Country,Hello",
+            "HEIGHT": "500",
+            "WIDTH": "500",
+            "CRS": "EPSG:3857",
+            "SELECTION": "Country: 4"
+        }.items())])
+
+        r, h = self._result(self.server.handleRequest(qs))
+        self._img_diff_error(r, h, "WMS_GetPrint_Selection")
+
     def test_getLegendGraphics(self):
         """Test that does not return an exception but an image"""
         parms = {
diff --git a/tests/src/python/test_qgssymbollayerv2_readsld.py b/tests/src/python/test_qgssymbollayerv2_readsld.py
new file mode 100644
index 0000000..201ceef
--- /dev/null
+++ b/tests/src/python/test_qgssymbollayerv2_readsld.py
@@ -0,0 +1,117 @@
+# -*- coding: utf-8 -*-
+
+"""
+***************************************************************************
+    test_qgssymbollayerv2_readsld.py
+    ---------------------
+    Date                 : January 2017
+    Copyright            : (C) 2017, Jorge Gustavo Rocha
+    Email                : jgr at di dot uminho dot pt
+***************************************************************************
+*                                                                         *
+*   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__ = 'Jorge Gustavo Rocha'
+__date__ = 'January 2017'
+__copyright__ = '(C) 2017, Jorge Gustavo Rocha'
+# This will get replaced with a git SHA1 when you do a git archive
+__revision__ = '$Format:%H$'
+
+import qgis  # NOQA
+
+import os
+from qgis.testing import start_app, unittest
+from qgis.core import (QgsVectorLayer,
+                       QgsFeature,
+                       QgsGeometry,
+                       QgsPoint
+                       )
+from qgis.testing import unittest
+from qgis.testing.mocked import get_iface
+from utilities import unitTestDataPath
+
+start_app()
+
+TEST_DATA_DIR = unitTestDataPath()
+
+
+def createLayerWithOneLine():
+    # create a temporary layer
+    # linelayer = iface.addVectorLayer("LineString?crs=epsg:4326&field=gid:int&field=name:string", "simple_line", "memory")
+    linelayer = QgsVectorLayer("LineString?crs=epsg:4326&field=gid:int&field=name:string", "simple_line", "memory")
+    one = QgsFeature(linelayer.dataProvider().fields(), 0)
+    one.setAttributes([1, 'one'])
+    one.setGeometry(QgsGeometry.fromPolyline([QgsPoint(-7, 38), QgsPoint(-8, 42)]))
+    linelayer.dataProvider().addFeatures([one])
+    return linelayer
+
+
+class TestQgsSymbolLayerReadSld(unittest.TestCase):
+
+    """
+    This class checks if SLD styles are properly applied
+    """
+
+    def setUp(self):
+        self.iface = get_iface()
+
+    # test <CSSParameter>VALUE<CSSParameter/>
+    # test <CSSParameter><ogc:Literal>VALUE<ogc:Literal/><CSSParameter/>
+    def test_Literal_within_CSSParameter(self):
+        layer = createLayerWithOneLine()
+        mFilePath = os.path.join(TEST_DATA_DIR, 'symbol_layer/external_sld/simple_streams.sld')
+        layer.loadSldStyle(mFilePath)
+        props = layer.rendererV2().symbol().symbolLayers()[0].properties()
+
+        def testLineColor():
+            # stroke 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
+            self.assertEqual(props['line_width'], '2')
+
+        def testLineOpacity():
+            # stroke-opacity CSSParameter NOT within ogc:Literal
+            # stroke-opacity=0.1
+            self.assertEqual(props['line_color'], '0,62,186,25')
+
+        testLineColor()
+        testLineWidth()
+        testLineOpacity()
+
+    def testSimpleMarkerRotation(self):
+        """
+        Test if pointMarker property sld:Rotation value can be read if format is:
+        <sld:Rotation>50.0</sld:Rotation>
+        or
+        <se:Rotation><ogc:Literal>50</ogc:Literal></se:Rotation>
+        """
+        # technically it's not necessary to use a real shape, but a empty memory
+        # layer. In case these tests will upgrate to a rendering where to
+        # compare also rendering not only properties
+        #myShpFile = os.path.join(unitTestDataPath(), 'points.shp')
+        #layer = QgsVectorLayer(myShpFile, 'points', 'ogr')
+        layer = QgsVectorLayer("Point", "addfeat", "memory")
+        assert(layer.isValid())
+        # test if able to read <sld:Rotation>50.0</sld:Rotation>
+        mFilePath = os.path.join(unitTestDataPath(), 'symbol_layer/external_sld/testSimpleMarkerRotation-directValue.sld')
+        layer.loadSldStyle(mFilePath)
+        props = layer.rendererV2().symbol().symbolLayers()[0].properties()
+        self.assertEqual(props['angle'], '50')
+        # test if able to read <se:Rotation><ogc:Literal>50</ogc:Literal></se:Rotation>
+        mFilePath = os.path.join(unitTestDataPath(), 'symbol_layer/external_sld/testSimpleMarkerRotation-ogcLiteral.sld')
+        layer.loadSldStyle(mFilePath)
+        props = layer.rendererV2().symbol().symbolLayers()[0].properties()
+        self.assertEqual(props['angle'], '50')
+
+
+if __name__ == '__main__':
+    unittest.main()
diff --git a/tests/testdata/control_images/qgis_server/WMS_GetMap_Background/WMS_GetMap_Background.png b/tests/testdata/control_images/qgis_server/WMS_GetMap_Background/WMS_GetMap_Background.png
new file mode 100644
index 0000000..3692284
Binary files /dev/null and b/tests/testdata/control_images/qgis_server/WMS_GetMap_Background/WMS_GetMap_Background.png differ
diff --git a/tests/testdata/control_images/qgis_server/WMS_GetMap_Background_Hex/WMS_GetMap_Background_Hex.png b/tests/testdata/control_images/qgis_server/WMS_GetMap_Background_Hex/WMS_GetMap_Background_Hex.png
new file mode 100644
index 0000000..3692284
Binary files /dev/null and b/tests/testdata/control_images/qgis_server/WMS_GetMap_Background_Hex/WMS_GetMap_Background_Hex.png differ
diff --git a/tests/testdata/control_images/qgis_server/WMS_GetMap_Basic/WMS_GetMap_Basic.png b/tests/testdata/control_images/qgis_server/WMS_GetMap_Basic/WMS_GetMap_Basic.png
new file mode 100644
index 0000000..085c529
Binary files /dev/null and b/tests/testdata/control_images/qgis_server/WMS_GetMap_Basic/WMS_GetMap_Basic.png differ
diff --git a/tests/testdata/control_images/qgis_server/WMS_GetMap_Filter/WMS_GetMap_Filter.png b/tests/testdata/control_images/qgis_server/WMS_GetMap_Filter/WMS_GetMap_Filter.png
new file mode 100644
index 0000000..58bcd9e
Binary files /dev/null and b/tests/testdata/control_images/qgis_server/WMS_GetMap_Filter/WMS_GetMap_Filter.png differ
diff --git a/tests/testdata/control_images/qgis_server/WMS_GetMap_LayerOrder/WMS_GetMap_LayerOrder.png b/tests/testdata/control_images/qgis_server/WMS_GetMap_LayerOrder/WMS_GetMap_LayerOrder.png
new file mode 100644
index 0000000..b6c9277
Binary files /dev/null and b/tests/testdata/control_images/qgis_server/WMS_GetMap_LayerOrder/WMS_GetMap_LayerOrder.png differ
diff --git a/tests/testdata/control_images/qgis_server/WMS_GetMap_Opacities/WMS_GetMap_Opacities.png b/tests/testdata/control_images/qgis_server/WMS_GetMap_Opacities/WMS_GetMap_Opacities.png
new file mode 100644
index 0000000..b02aee9
Binary files /dev/null and b/tests/testdata/control_images/qgis_server/WMS_GetMap_Opacities/WMS_GetMap_Opacities.png differ
diff --git a/tests/testdata/control_images/qgis_server/WMS_GetMap_SRS/WMS_GetMap_SRS.png b/tests/testdata/control_images/qgis_server/WMS_GetMap_SRS/WMS_GetMap_SRS.png
new file mode 100644
index 0000000..1dd0cb9
Binary files /dev/null and b/tests/testdata/control_images/qgis_server/WMS_GetMap_SRS/WMS_GetMap_SRS.png differ
diff --git a/tests/testdata/control_images/qgis_server/WMS_GetMap_Selection/WMS_GetMap_Selection.png b/tests/testdata/control_images/qgis_server/WMS_GetMap_Selection/WMS_GetMap_Selection.png
new file mode 100644
index 0000000..54fe431
Binary files /dev/null and b/tests/testdata/control_images/qgis_server/WMS_GetMap_Selection/WMS_GetMap_Selection.png differ
diff --git a/tests/testdata/control_images/qgis_server/WMS_GetMap_StyleCustom/WMS_GetMap_StyleCustom.png b/tests/testdata/control_images/qgis_server/WMS_GetMap_StyleCustom/WMS_GetMap_StyleCustom.png
new file mode 100644
index 0000000..00e00a5
Binary files /dev/null and b/tests/testdata/control_images/qgis_server/WMS_GetMap_StyleCustom/WMS_GetMap_StyleCustom.png differ
diff --git a/tests/testdata/control_images/qgis_server/WMS_GetMap_StyleCustom/WMS_GetMap_StyleCustom_mask.png b/tests/testdata/control_images/qgis_server/WMS_GetMap_StyleCustom/WMS_GetMap_StyleCustom_mask.png
new file mode 100644
index 0000000..5a61972
Binary files /dev/null and b/tests/testdata/control_images/qgis_server/WMS_GetMap_StyleCustom/WMS_GetMap_StyleCustom_mask.png differ
diff --git a/tests/testdata/control_images/qgis_server/WMS_GetMap_StyleDefault/WMS_GetMap_StyleDefault.png b/tests/testdata/control_images/qgis_server/WMS_GetMap_StyleDefault/WMS_GetMap_StyleDefault.png
new file mode 100644
index 0000000..2dd85da
Binary files /dev/null and b/tests/testdata/control_images/qgis_server/WMS_GetMap_StyleDefault/WMS_GetMap_StyleDefault.png differ
diff --git a/tests/testdata/control_images/qgis_server/WMS_GetMap_StyleDefault/WMS_GetMap_StyleDefault_mask.png b/tests/testdata/control_images/qgis_server/WMS_GetMap_StyleDefault/WMS_GetMap_StyleDefault_mask.png
new file mode 100644
index 0000000..ff4ebc2
Binary files /dev/null and b/tests/testdata/control_images/qgis_server/WMS_GetMap_StyleDefault/WMS_GetMap_StyleDefault_mask.png differ
diff --git a/tests/testdata/control_images/qgis_server/WMS_GetMap_Transparent/WMS_GetMap_Transparent.png b/tests/testdata/control_images/qgis_server/WMS_GetMap_Transparent/WMS_GetMap_Transparent.png
new file mode 100644
index 0000000..6526eb5
Binary files /dev/null and b/tests/testdata/control_images/qgis_server/WMS_GetMap_Transparent/WMS_GetMap_Transparent.png differ
diff --git a/tests/testdata/control_images/qgis_server/WMS_GetMap_Transparent/WMS_GetMap_Transparent_mask.png b/tests/testdata/control_images/qgis_server/WMS_GetMap_Transparent/WMS_GetMap_Transparent_mask.png
new file mode 100644
index 0000000..bfc13a0
Binary files /dev/null and b/tests/testdata/control_images/qgis_server/WMS_GetMap_Transparent/WMS_GetMap_Transparent_mask.png differ
diff --git a/tests/testdata/control_images/qgis_server/WMS_GetPrint_Basic/WMS_GetPrint_Basic.png b/tests/testdata/control_images/qgis_server/WMS_GetPrint_Basic/WMS_GetPrint_Basic.png
new file mode 100644
index 0000000..fa16ea4
Binary files /dev/null and b/tests/testdata/control_images/qgis_server/WMS_GetPrint_Basic/WMS_GetPrint_Basic.png differ
diff --git a/tests/testdata/control_images/qgis_server/WMS_GetPrint_Basic/WMS_GetPrint_Basic_mask.png b/tests/testdata/control_images/qgis_server/WMS_GetPrint_Basic/WMS_GetPrint_Basic_mask.png
new file mode 100644
index 0000000..4d13a81
Binary files /dev/null and b/tests/testdata/control_images/qgis_server/WMS_GetPrint_Basic/WMS_GetPrint_Basic_mask.png differ
diff --git a/tests/testdata/control_images/qgis_server/WMS_GetPrint_Grid/WMS_GetPrint_Grid.png b/tests/testdata/control_images/qgis_server/WMS_GetPrint_Grid/WMS_GetPrint_Grid.png
new file mode 100644
index 0000000..5e67c3e
Binary files /dev/null and b/tests/testdata/control_images/qgis_server/WMS_GetPrint_Grid/WMS_GetPrint_Grid.png differ
diff --git a/tests/testdata/control_images/qgis_server/WMS_GetPrint_Grid/WMS_GetPrint_Grid_mask.png b/tests/testdata/control_images/qgis_server/WMS_GetPrint_Grid/WMS_GetPrint_Grid_mask.png
new file mode 100644
index 0000000..4d13a81
Binary files /dev/null and b/tests/testdata/control_images/qgis_server/WMS_GetPrint_Grid/WMS_GetPrint_Grid_mask.png differ
diff --git a/tests/testdata/control_images/qgis_server/WMS_GetPrint_Rotation/WMS_GetPrint_Rotation.png b/tests/testdata/control_images/qgis_server/WMS_GetPrint_Rotation/WMS_GetPrint_Rotation.png
new file mode 100644
index 0000000..45be394
Binary files /dev/null and b/tests/testdata/control_images/qgis_server/WMS_GetPrint_Rotation/WMS_GetPrint_Rotation.png differ
diff --git a/tests/testdata/control_images/qgis_server/WMS_GetPrint_Rotation/WMS_GetPrint_Rotation_mask.png b/tests/testdata/control_images/qgis_server/WMS_GetPrint_Rotation/WMS_GetPrint_Rotation_mask.png
new file mode 100644
index 0000000..4d13a81
Binary files /dev/null and b/tests/testdata/control_images/qgis_server/WMS_GetPrint_Rotation/WMS_GetPrint_Rotation_mask.png differ
diff --git a/tests/testdata/control_images/qgis_server/WMS_GetPrint_SRS/WMS_GetPrint_SRS.png b/tests/testdata/control_images/qgis_server/WMS_GetPrint_SRS/WMS_GetPrint_SRS.png
new file mode 100644
index 0000000..0c10133
Binary files /dev/null and b/tests/testdata/control_images/qgis_server/WMS_GetPrint_SRS/WMS_GetPrint_SRS.png differ
diff --git a/tests/testdata/control_images/qgis_server/WMS_GetPrint_SRS/WMS_GetPrint_SRS_mask.png b/tests/testdata/control_images/qgis_server/WMS_GetPrint_SRS/WMS_GetPrint_SRS_mask.png
new file mode 100644
index 0000000..4d13a81
Binary files /dev/null and b/tests/testdata/control_images/qgis_server/WMS_GetPrint_SRS/WMS_GetPrint_SRS_mask.png differ
diff --git a/tests/testdata/control_images/qgis_server/WMS_GetPrint_Scale/WMS_GetPrint_Scale.png b/tests/testdata/control_images/qgis_server/WMS_GetPrint_Scale/WMS_GetPrint_Scale.png
new file mode 100644
index 0000000..f2736c0
Binary files /dev/null and b/tests/testdata/control_images/qgis_server/WMS_GetPrint_Scale/WMS_GetPrint_Scale.png differ
diff --git a/tests/testdata/control_images/qgis_server/WMS_GetPrint_Scale/WMS_GetPrint_Scale_mask.png b/tests/testdata/control_images/qgis_server/WMS_GetPrint_Scale/WMS_GetPrint_Scale_mask.png
new file mode 100644
index 0000000..4d13a81
Binary files /dev/null and b/tests/testdata/control_images/qgis_server/WMS_GetPrint_Scale/WMS_GetPrint_Scale_mask.png differ
diff --git a/tests/testdata/control_images/qgis_server/WMS_GetPrint_Selection/WMS_GetPrint_Selection.png b/tests/testdata/control_images/qgis_server/WMS_GetPrint_Selection/WMS_GetPrint_Selection.png
new file mode 100644
index 0000000..fa16ea4
Binary files /dev/null and b/tests/testdata/control_images/qgis_server/WMS_GetPrint_Selection/WMS_GetPrint_Selection.png differ
diff --git a/tests/testdata/control_images/qgis_server/WMS_GetPrint_Selection/WMS_GetPrint_Selection_mask.png b/tests/testdata/control_images/qgis_server/WMS_GetPrint_Selection/WMS_GetPrint_Selection_mask.png
new file mode 100644
index 0000000..4d13a81
Binary files /dev/null and b/tests/testdata/control_images/qgis_server/WMS_GetPrint_Selection/WMS_GetPrint_Selection_mask.png differ
diff --git a/tests/testdata/geom_data.csv b/tests/testdata/geom_data.csv
index 2ac5ea2..a7e146f 100644
--- a/tests/testdata/geom_data.csv
+++ b/tests/testdata/geom_data.csv
@@ -120,3 +120,4 @@ Polygon,,,,,,,,,,,,,,Malformed WKT
 "PolygonM ((0 0 1, 10 0 1, 10 10 1, 0 10 1, 0 0 1),(5 5 1, 7 5 1, 7 7 1, 5 7 1, 5 5 1),(1 1 1,2 1 1, 2 2 1, 1 2 1, 1 1 1))","POLYGON M ((0 0 1,10 0 1,10 10 1,0 10 1,0 0 1),(5 5 1,7 5 1,7 7 1,5 7 1,5 5 1),(1 1 1,2 1 1,2 2 1,1 2 1,1 1 1))",15,0,95,52,1,2,0,POINT(4.99473684210526 4.99473684210526),0,0,10,10,
 "PolygonZ ((0 0 1 , 10 0 1, 10 10 1, 0 10 1, 0 0 1))","POLYGON Z ((0 0 1,10 0 1,10 10 1,0 10 1,0 0 1))",5,0,100,40,1,0,0,POINT(5 5),0,0,10,10,
 "PolygonZ ((0 0 1, 10 0 1, 10 10 1, 0 10 1, 0 0 1),(5 5 1, 7 5 1, 7 7 1 , 5 7 1, 5 5 1))","POLYGON Z ((0 0 1,10 0 1,10 10 1,0 10 1,0 0 1),(5 5 1,7 5 1,7 7 1,5 7 1,5 5 1))",10,0,96,48,1,1,0,POINT(4.95833333333333 4.95833333333333),0,0,10,10,
+"CurvePolygon (CompoundCurve ((2678124.57778842002153397 1225804.43286111624911427, 2678251.0684670670889318 1225964.66278979112394154, 2678201.75901959836483002 1226077.95337014575488865, 2678199.27904875669628382 1226083.94340024818666279, 2678198.13904719380661845 1226083.5034040967002511, 2678188.08903313148766756 1226079.56343783461488783, 2678164.688993189483881 1226068.85351158352568746, 2678152.65896565327420831 1226061.85354482522234321, 2678133.63892276119440794 1226050.9235978 [...]
diff --git a/tests/testdata/qgis_server/wfs_getfeature_limit2.txt b/tests/testdata/qgis_server/wfs_getfeature_limit2.txt
index bcb35f5..bfe1e94 100644
--- a/tests/testdata/qgis_server/wfs_getfeature_limit2.txt
+++ b/tests/testdata/qgis_server/wfs_getfeature_limit2.txt
@@ -13,9 +13,9 @@ Content-Type: text/xml; charset=utf-8
    </gml:Box>
   </gml:boundedBy>
   <qgs:geometry>
-   <gml:Point srsName="EPSG:4326">
-    <gml:coordinates cs="," ts=" ">8.20349634,44.90148253</gml:coordinates>
-   </gml:Point>
+   <Point xmlns="http://www.opengis.net/gml" srsName="EPSG:4326">
+    <coordinates xmlns="http://www.opengis.net/gml">8.20349634,44.90148253</coordinates>
+   </Point>
   </qgs:geometry>
   <qgs:id>1</qgs:id>
   <qgs:name>one</qgs:name>
@@ -30,9 +30,9 @@ Content-Type: text/xml; charset=utf-8
    </gml:Box>
   </gml:boundedBy>
   <qgs:geometry>
-   <gml:Point srsName="EPSG:4326">
-    <gml:coordinates cs="," ts=" ">8.20354699,44.90143568</gml:coordinates>
-   </gml:Point>
+   <Point xmlns="http://www.opengis.net/gml" srsName="EPSG:4326">
+    <coordinates xmlns="http://www.opengis.net/gml">8.20354699,44.90143568</coordinates>
+   </Point>
   </qgs:geometry>
   <qgs:id>2</qgs:id>
   <qgs:name>two</qgs:name>
diff --git a/tests/testdata/qgis_server/wfs_getfeature_nobbox.txt b/tests/testdata/qgis_server/wfs_getfeature_nobbox.txt
index d13aefc..8b95180 100644
--- a/tests/testdata/qgis_server/wfs_getfeature_nobbox.txt
+++ b/tests/testdata/qgis_server/wfs_getfeature_nobbox.txt
@@ -13,9 +13,9 @@ Content-Type: text/xml; charset=utf-8
    </gml:Box>
   </gml:boundedBy>
   <qgs:geometry>
-   <gml:Point srsName="EPSG:4326">
-    <gml:coordinates cs="," ts=" ">8.20349634,44.90148253</gml:coordinates>
-   </gml:Point>
+   <Point xmlns="http://www.opengis.net/gml" srsName="EPSG:4326">
+    <coordinates xmlns="http://www.opengis.net/gml">8.20349634,44.90148253</coordinates>
+   </Point>
   </qgs:geometry>
   <qgs:id>1</qgs:id>
   <qgs:name>one</qgs:name>
@@ -30,9 +30,9 @@ Content-Type: text/xml; charset=utf-8
    </gml:Box>
   </gml:boundedBy>
   <qgs:geometry>
-   <gml:Point srsName="EPSG:4326">
-    <gml:coordinates cs="," ts=" ">8.20354699,44.90143568</gml:coordinates>
-   </gml:Point>
+   <Point xmlns="http://www.opengis.net/gml" srsName="EPSG:4326">
+    <coordinates xmlns="http://www.opengis.net/gml">8.20354699,44.90143568</coordinates>
+   </Point>
   </qgs:geometry>
   <qgs:id>2</qgs:id>
   <qgs:name>two</qgs:name>
@@ -47,9 +47,9 @@ Content-Type: text/xml; charset=utf-8
    </gml:Box>
   </gml:boundedBy>
   <qgs:geometry>
-   <gml:Point srsName="EPSG:4326">
-    <gml:coordinates cs="," ts=" ">8.20345931,44.90139484</gml:coordinates>
-   </gml:Point>
+   <Point xmlns="http://www.opengis.net/gml" srsName="EPSG:4326">
+    <coordinates xmlns="http://www.opengis.net/gml">8.20345931,44.90139484</coordinates>
+   </Point>
   </qgs:geometry>
   <qgs:id>3</qgs:id>
   <qgs:name>three</qgs:name>
diff --git a/tests/testdata/qgis_server/wfs_getfeature_start1_limit1.txt b/tests/testdata/qgis_server/wfs_getfeature_start1_limit1.txt
index 9408334..cc3fb49 100644
--- a/tests/testdata/qgis_server/wfs_getfeature_start1_limit1.txt
+++ b/tests/testdata/qgis_server/wfs_getfeature_start1_limit1.txt
@@ -13,9 +13,9 @@ Content-Type: text/xml; charset=utf-8
    </gml:Box>
   </gml:boundedBy>
   <qgs:geometry>
-   <gml:Point srsName="EPSG:4326">
-    <gml:coordinates cs="," ts=" ">8.20354699,44.90143568</gml:coordinates>
-   </gml:Point>
+   <Point xmlns="http://www.opengis.net/gml" srsName="EPSG:4326">
+    <coordinates xmlns="http://www.opengis.net/gml">8.20354699,44.90143568</coordinates>
+   </Point>
   </qgs:geometry>
   <qgs:id>2</qgs:id>
   <qgs:name>two</qgs:name>
diff --git a/tests/testdata/qgis_server/wfs_getfeature_startindex2.txt b/tests/testdata/qgis_server/wfs_getfeature_startindex2.txt
index 534f7a1..937ef3a 100644
--- a/tests/testdata/qgis_server/wfs_getfeature_startindex2.txt
+++ b/tests/testdata/qgis_server/wfs_getfeature_startindex2.txt
@@ -13,9 +13,9 @@ Content-Type: text/xml; charset=utf-8
    </gml:Box>
   </gml:boundedBy>
   <qgs:geometry>
-   <gml:Point srsName="EPSG:4326">
-    <gml:coordinates cs="," ts=" ">8.20345931,44.90139484</gml:coordinates>
-   </gml:Point>
+   <Point xmlns="http://www.opengis.net/gml" srsName="EPSG:4326">
+    <coordinates xmlns="http://www.opengis.net/gml">8.20345931,44.90139484</coordinates>
+   </Point>
   </qgs:geometry>
   <qgs:id>3</qgs:id>
   <qgs:name>three</qgs:name>
diff --git a/tests/testdata/qgis_server_accesscontrol/project.qgs b/tests/testdata/qgis_server_accesscontrol/project.qgs
index 7e1d322..4f1292e 100644
--- a/tests/testdata/qgis_server_accesscontrol/project.qgs
+++ b/tests/testdata/qgis_server_accesscontrol/project.qgs
@@ -24,6 +24,9 @@
     <layer-tree-layer expanded="1" checked="Qt::Checked" id="country20131022151106556" name="Country">
       <customproperties/>
     </layer-tree-layer>
+    <layer-tree-layer name="Country_Labels" id="Country_copy20161127151800736" checked="Qt::Unchecked" expanded="1">
+      <customproperties/>
+    </layer-tree-layer>
   </layer-tree-group>
   <relations/>
   <mapcanvas>
@@ -53,6 +56,7 @@
       <layer_coordinate_transform destAuthId="EPSG:3857" srcAuthId="EPSG:3857" srcDatumTransform="-1" destDatumTransform="-1" layerid="Hello_SubsetString_copy20160222085231770"/>
       <layer_coordinate_transform destAuthId="EPSG:3857" srcAuthId="EPSG:3857" srcDatumTransform="-1" destDatumTransform="-1" layerid="Hello_copy20150804164427541"/>
       <layer_coordinate_transform destAuthId="EPSG:3857" srcAuthId="EPSG:3857" srcDatumTransform="-1" destDatumTransform="-1" layerid="country20131022151106556"/>
+      <layer_coordinate_transform destAuthId="EPSG:3857" srcAuthId="EPSG:3857" srcDatumTransform="-1" destDatumTransform="-1" layerid="Country_copy20161127151800736"/>
       <layer_coordinate_transform destAuthId="EPSG:3857" srcAuthId="EPSG:4326" srcDatumTransform="-1" destDatumTransform="-1" layerid="dem20150730091219559"/>
       <layer_coordinate_transform destAuthId="EPSG:3857" srcAuthId="EPSG:3857" srcDatumTransform="-1" destDatumTransform="-1" layerid="hello20131022151106574"/>
       <layer_coordinate_transform destAuthId="EPSG:3857" srcAuthId="EPSG:3857" srcDatumTransform="-1" destDatumTransform="-1" layerid="points20150803121107046"/>
@@ -70,6 +74,7 @@
       <item>Hello_copy20150804164427541</item>
       <item>Hello_SubsetString_copy20160222085231770</item>
       <item>Hello_Project_SubsetString_copy20160223113949592</item>
+      <item>Country_copy20161127151800736</item>
     </custom-order>
   </layer-tree-canvas>
   <legend updateDrawingOrder="true">
@@ -108,6 +113,11 @@
         <legendlayerfile isInOverview="0" layerid="country20131022151106556" visible="1"/>
       </filegroup>
     </legendlayer>
+    <legendlayer name="Country_Labels" showFeatureCount="0" checked="Qt::Unchecked" open="true" drawingOrder="-1">
+      <filegroup open="true" hidden="false">
+        <legendlayerfile isInOverview="0" layerid="Country_copy20161127151800736" visible="0"/>
+      </filegroup>
+    </legendlayer>
   </legend>
   <Composer title="layoutA4" visible="0">
     <Composition resizeToContentsMarginLeft="0" snapping="0" showPages="1" guidesVisible="1" resizeToContentsMarginTop="0" alignmentSnap="1" printResolution="300" paperWidth="297" gridVisible="0" snapGridOffsetX="0" smartGuides="1" snapGridOffsetY="0" resizeToContentsMarginRight="0" snapTolerancePixels="10" printAsRaster="0" generateWorldFile="0" paperHeight="210" numPages="1" snapGridResolution="0" resizeToContentsMarginBottom="0">
@@ -215,6 +225,665 @@
     </Composition>
   </Composer>
   <projectlayers>
+    <maplayer simplifyLocal="1" maximumScale="1e+08" simplifyDrawingTol="1" minimumScale="0" simplifyDrawingHints="1" geometry="Polygon" simplifyAlgorithm="0" simplifyMaxScale="1" type="vector" readOnly="0" hasScaleBasedVisibilityFlag="0">
+      <extent>
+        <xmin>-19619892.68012013286352158</xmin>
+        <ymin>-10327100.34232237376272678</ymin>
+        <xmax>19972134.91854240000247955</xmax>
+        <ymax>18415866.31293442100286484</ymax>
+      </extent>
+      <id>Country_copy20161127151800736</id>
+      <datasource>dbname='./helloworld.db' table="country" (geom) sql=</datasource>
+      <keywordList>
+        <value></value>
+      </keywordList>
+      <layername>Country_Labels</layername>
+      <srs>
+        <spatialrefsys>
+          <proj4>+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +wktext  +no_defs</proj4>
+          <srsid>3857</srsid>
+          <srid>3857</srid>
+          <authid>EPSG:3857</authid>
+          <description>WGS 84 / Pseudo Mercator</description>
+          <projectionacronym>merc</projectionacronym>
+          <ellipsoidacronym>WGS84</ellipsoidacronym>
+          <geographicflag>false</geographicflag>
+        </spatialrefsys>
+      </srs>
+      <provider encoding="UTF-8">spatialite</provider>
+      <vectorjoins/>
+      <layerDependencies/>
+      <defaults>
+        <default expression="" field="pk"/>
+        <default expression="" field="name"/>
+      </defaults>
+      <constraints>
+        <constraint notnull_strength="1" unique_strength="1" exp_strength="0" field="pk" constraints="3"/>
+        <constraint notnull_strength="0" unique_strength="0" exp_strength="0" field="name" constraints="0"/>
+      </constraints>
+      <constraintExpressions>
+        <constraint exp="" desc="" field="pk"/>
+        <constraint exp="" desc="" field="name"/>
+      </constraintExpressions>
+      <dataDependencies/>
+      <expressionfields/>
+      <map-layer-style-manager current="">
+        <map-layer-style name=""/>
+        <map-layer-style name="custom">
+          <qgis simplifyLocal="1" simplifyDrawingTol="1" maximumScale="1e+08" simplifyDrawingHints="1" minimumScale="0" simplifyAlgorithm="0" simplifyMaxScale="1" readOnly="0" hasScaleBasedVisibilityFlag="0" version="2.99.0-Master">
+            <edittypes>
+              <edittype name="pk" widgetv2type="TextEdit">
+                <widgetv2config labelOnTop="0" UseHtml="0" IsMultiline="0" fieldEditable="1"/>
+              </edittype>
+              <edittype name="name" widgetv2type="TextEdit">
+                <widgetv2config labelOnTop="0" UseHtml="0" IsMultiline="0" fieldEditable="1"/>
+              </edittype>
+            </edittypes>
+            <renderer-v2 forceraster="0" symbollevels="0" type="singleSymbol" enableorderby="0">
+              <symbols>
+                <symbol alpha="1" name="0" clip_to_extent="1" type="fill">
+                  <layer enabled="1" locked="0" pass="0" class="SimpleFill">
+                    <prop v="0,0,0,0,0,0" k="border_width_map_unit_scale"/>
+                    <prop v="145,149,158,255" k="color"/>
+                    <prop v="bevel" k="joinstyle"/>
+                    <prop v="0.80000000000000004,0.80000000000000004" k="offset"/>
+                    <prop v="0,0,0,0,0,0" k="offset_map_unit_scale"/>
+                    <prop v="MM" k="offset_unit"/>
+                    <prop v="157,157,157,255" k="outline_color"/>
+                    <prop v="solid" k="outline_style"/>
+                    <prop v="0.26" k="outline_width"/>
+                    <prop v="MM" k="outline_width_unit"/>
+                    <prop v="solid" k="style"/>
+                  </layer>
+                  <layer enabled="1" locked="0" pass="0" class="SimpleFill">
+                    <prop v="0,0,0,0,0,0" k="border_width_map_unit_scale"/>
+                    <prop v="0,0,255,255" k="color"/>
+                    <prop v="bevel" k="joinstyle"/>
+                    <prop v="0,0" k="offset"/>
+                    <prop v="0,0,0,0,0,0" k="offset_map_unit_scale"/>
+                    <prop v="MM" k="offset_unit"/>
+                    <prop v="0,0,0,255" k="outline_color"/>
+                    <prop v="solid" k="outline_style"/>
+                    <prop v="0.26" k="outline_width"/>
+                    <prop v="MM" k="outline_width_unit"/>
+                    <prop v="solid" k="style"/>
+                  </layer>
+                </symbol>
+              </symbols>
+              <rotation/>
+              <sizescale/>
+            </renderer-v2>
+            <labeling type="simple"/>
+            <customproperties>
+              <property value="0" key="embeddedWidgets/count"/>
+              <property value="pal" key="labeling"/>
+              <property value="false" key="labeling/addDirectionSymbol"/>
+              <property value="0" key="labeling/angleOffset"/>
+              <property value="0" key="labeling/blendMode"/>
+              <property value="0" key="labeling/bufferBlendMode"/>
+              <property value="255" key="labeling/bufferColorA"/>
+              <property value="255" key="labeling/bufferColorB"/>
+              <property value="255" key="labeling/bufferColorG"/>
+              <property value="255" key="labeling/bufferColorR"/>
+              <property value="false" key="labeling/bufferDraw"/>
+              <property value="64" key="labeling/bufferJoinStyle"/>
+              <property value="false" key="labeling/bufferNoFill"/>
+              <property value="1" key="labeling/bufferOpacity"/>
+              <property value="1" key="labeling/bufferSize"/>
+              <property value="false" key="labeling/bufferSizeInMapUnits"/>
+              <property value="0" key="labeling/bufferSizeMapUnitMaxScale"/>
+              <property value="0" key="labeling/bufferSizeMapUnitMinScale"/>
+              <property value="0,0,0,0,0,0" key="labeling/bufferSizeMapUnitScale"/>
+              <property value="MM" key="labeling/bufferSizeUnits"/>
+              <property value="0" key="labeling/bufferTransp"/>
+              <property value="false" key="labeling/centroidInside"/>
+              <property value="false" key="labeling/centroidWhole"/>
+              <property value="3" key="labeling/decimals"/>
+              <property value="false" key="labeling/displayAll"/>
+              <property value="0" key="labeling/dist"/>
+              <property value="false" key="labeling/distInMapUnits"/>
+              <property value="0" key="labeling/distMapUnitMaxScale"/>
+              <property value="0" key="labeling/distMapUnitMinScale"/>
+              <property value="0,0,0,0,0,0" key="labeling/distMapUnitScale"/>
+              <property value="true" key="labeling/drawLabels"/>
+              <property value="true" key="labeling/enabled"/>
+              <property value="name" key="labeling/fieldName"/>
+              <property value="false" key="labeling/fitInPolygonOnly"/>
+              <property value="false" key="labeling/fontBold"/>
+              <property value="0" key="labeling/fontCapitals"/>
+              <property value="Sans Serif" key="labeling/fontFamily"/>
+              <property value="true" key="labeling/fontItalic"/>
+              <property value="0" key="labeling/fontLetterSpacing"/>
+              <property value="false" key="labeling/fontLimitPixelSize"/>
+              <property value="10000" key="labeling/fontMaxPixelSize"/>
+              <property value="3" key="labeling/fontMinPixelSize"/>
+              <property value="40" key="labeling/fontSize"/>
+              <property value="false" key="labeling/fontSizeInMapUnits"/>
+              <property value="0" key="labeling/fontSizeMapUnitMaxScale"/>
+              <property value="0" key="labeling/fontSizeMapUnitMinScale"/>
+              <property value="0,0,0,0,0,0" key="labeling/fontSizeMapUnitScale"/>
+              <property value="Point" key="labeling/fontSizeUnit"/>
+              <property value="false" key="labeling/fontStrikeout"/>
+              <property value="true" key="labeling/fontUnderline"/>
+              <property value="50" key="labeling/fontWeight"/>
+              <property value="0" key="labeling/fontWordSpacing"/>
+              <property value="false" key="labeling/formatNumbers"/>
+              <property value="false" key="labeling/isExpression"/>
+              <property value="true" key="labeling/labelOffsetInMapUnits"/>
+              <property value="0" key="labeling/labelOffsetMapUnitMaxScale"/>
+              <property value="0" key="labeling/labelOffsetMapUnitMinScale"/>
+              <property value="0,0,0,0,0,0" key="labeling/labelOffsetMapUnitScale"/>
+              <property value="false" key="labeling/labelPerPart"/>
+              <property value="<" key="labeling/leftDirectionSymbol"/>
+              <property value="false" key="labeling/limitNumLabels"/>
+              <property value="20" key="labeling/maxCurvedCharAngleIn"/>
+              <property value="-20" key="labeling/maxCurvedCharAngleOut"/>
+              <property value="2000" key="labeling/maxNumLabels"/>
+              <property value="false" key="labeling/mergeLines"/>
+              <property value="0" key="labeling/minFeatureSize"/>
+              <property value="0" key="labeling/multilineAlign"/>
+              <property value="1" key="labeling/multilineHeight"/>
+              <property value="Italic" key="labeling/namedStyle"/>
+              <property value="true" key="labeling/obstacle"/>
+              <property value="1" key="labeling/obstacleFactor"/>
+              <property value="0" key="labeling/obstacleType"/>
+              <property value="0" key="labeling/offsetType"/>
+              <property value="0" key="labeling/placeDirectionSymbol"/>
+              <property value="0" key="labeling/placement"/>
+              <property value="0" key="labeling/placementFlags"/>
+              <property value="false" key="labeling/plussign"/>
+              <property value="TR,TL,BR,BL,R,L,TSR,BSR" key="labeling/predefinedPositionOrder"/>
+              <property value="true" key="labeling/preserveRotation"/>
+              <property value="#ffffff" key="labeling/previewBkgrdColor"/>
+              <property value="5" key="labeling/priority"/>
+              <property value="4" key="labeling/quadOffset"/>
+              <property value="0" key="labeling/repeatDistance"/>
+              <property value="0" key="labeling/repeatDistanceMapUnitMaxScale"/>
+              <property value="0" key="labeling/repeatDistanceMapUnitMinScale"/>
+              <property value="0,0,0,0,0,0" key="labeling/repeatDistanceMapUnitScale"/>
+              <property value="1" key="labeling/repeatDistanceUnit"/>
+              <property value="false" key="labeling/reverseDirectionSymbol"/>
+              <property value=">" key="labeling/rightDirectionSymbol"/>
+              <property value="10000000" key="labeling/scaleMax"/>
+              <property value="1" key="labeling/scaleMin"/>
+              <property value="false" key="labeling/scaleVisibility"/>
+              <property value="6" key="labeling/shadowBlendMode"/>
+              <property value="0" key="labeling/shadowColorB"/>
+              <property value="0" key="labeling/shadowColorG"/>
+              <property value="0" key="labeling/shadowColorR"/>
+              <property value="false" key="labeling/shadowDraw"/>
+              <property value="135" key="labeling/shadowOffsetAngle"/>
+              <property value="1" key="labeling/shadowOffsetDist"/>
+              <property value="true" key="labeling/shadowOffsetGlobal"/>
+              <property value="0" key="labeling/shadowOffsetMapUnitMaxScale"/>
+              <property value="0" key="labeling/shadowOffsetMapUnitMinScale"/>
+              <property value="0,0,0,0,0,0" key="labeling/shadowOffsetMapUnitScale"/>
+              <property value="MapUnit" key="labeling/shadowOffsetUnit"/>
+              <property value="1" key="labeling/shadowOffsetUnits"/>
+              <property value="0.69999999999999996" key="labeling/shadowOpacity"/>
+              <property value="1.5" key="labeling/shadowRadius"/>
+              <property value="false" key="labeling/shadowRadiusAlphaOnly"/>
+              <property value="0" key="labeling/shadowRadiusMapUnitMaxScale"/>
+              <property value="0" key="labeling/shadowRadiusMapUnitMinScale"/>
+              <property value="0,0,0,0,0,0" key="labeling/shadowRadiusMapUnitScale"/>
+              <property value="MapUnit" key="labeling/shadowRadiusUnit"/>
+              <property value="1" key="labeling/shadowRadiusUnits"/>
+              <property value="100" key="labeling/shadowScale"/>
+              <property value="30" key="labeling/shadowTransparency"/>
+              <property value="0" key="labeling/shadowUnder"/>
+              <property value="0" key="labeling/shapeBlendMode"/>
+              <property value="255" key="labeling/shapeBorderColorA"/>
+              <property value="128" key="labeling/shapeBorderColorB"/>
+              <property value="128" key="labeling/shapeBorderColorG"/>
+              <property value="128" key="labeling/shapeBorderColorR"/>
+              <property value="0" key="labeling/shapeBorderWidth"/>
+              <property value="0" key="labeling/shapeBorderWidthMapUnitMaxScale"/>
+              <property value="0" key="labeling/shapeBorderWidthMapUnitMinScale"/>
+              <property value="0,0,0,0,0,0" key="labeling/shapeBorderWidthMapUnitScale"/>
+              <property value="MapUnit" key="labeling/shapeBorderWidthUnit"/>
+              <property value="1" key="labeling/shapeBorderWidthUnits"/>
+              <property value="false" key="labeling/shapeDraw"/>
+              <property value="255" key="labeling/shapeFillColorA"/>
+              <property value="255" key="labeling/shapeFillColorB"/>
+              <property value="255" key="labeling/shapeFillColorG"/>
+              <property value="255" key="labeling/shapeFillColorR"/>
+              <property value="64" key="labeling/shapeJoinStyle"/>
+              <property value="0" key="labeling/shapeOffsetMapUnitMaxScale"/>
+              <property value="0" key="labeling/shapeOffsetMapUnitMinScale"/>
+              <property value="0,0,0,0,0,0" key="labeling/shapeOffsetMapUnitScale"/>
+              <property value="MapUnit" key="labeling/shapeOffsetUnit"/>
+              <property value="1" key="labeling/shapeOffsetUnits"/>
+              <property value="0" key="labeling/shapeOffsetX"/>
+              <property value="0" key="labeling/shapeOffsetY"/>
+              <property value="1" key="labeling/shapeOpacity"/>
+              <property value="0" key="labeling/shapeRadiiMapUnitMaxScale"/>
+              <property value="0" key="labeling/shapeRadiiMapUnitMinScale"/>
+              <property value="0,0,0,0,0,0" key="labeling/shapeRadiiMapUnitScale"/>
+              <property value="MapUnit" key="labeling/shapeRadiiUnit"/>
+              <property value="1" key="labeling/shapeRadiiUnits"/>
+              <property value="0" key="labeling/shapeRadiiX"/>
+              <property value="0" key="labeling/shapeRadiiY"/>
+              <property value="0" key="labeling/shapeRotation"/>
+              <property value="0" key="labeling/shapeRotationType"/>
+              <property value="" key="labeling/shapeSVGFile"/>
+              <property value="0" key="labeling/shapeSizeMapUnitMaxScale"/>
+              <property value="0" key="labeling/shapeSizeMapUnitMinScale"/>
+              <property value="0,0,0,0,0,0" key="labeling/shapeSizeMapUnitScale"/>
+              <property value="0" key="labeling/shapeSizeType"/>
+              <property value="MapUnit" key="labeling/shapeSizeUnit"/>
+              <property value="1" key="labeling/shapeSizeUnits"/>
+              <property value="0" key="labeling/shapeSizeX"/>
+              <property value="0" key="labeling/shapeSizeY"/>
+              <property value="0" key="labeling/shapeTransparency"/>
+              <property value="0" key="labeling/shapeType"/>
+              <property value="<substitutions/>" key="labeling/substitutions"/>
+              <property value="255" key="labeling/textColorA"/>
+              <property value="1" key="labeling/textColorB"/>
+              <property value="1" key="labeling/textColorG"/>
+              <property value="255" key="labeling/textColorR"/>
+              <property value="1" key="labeling/textOpacity"/>
+              <property value="0" key="labeling/textTransp"/>
+              <property value="0" key="labeling/upsidedownLabels"/>
+              <property value="false" key="labeling/useSubstitutions"/>
+              <property value="" key="labeling/wrapChar"/>
+              <property value="0" key="labeling/xOffset"/>
+              <property value="0" key="labeling/yOffset"/>
+              <property value="0" key="labeling/zIndex"/>
+              <property key="variableNames"/>
+              <property key="variableValues"/>
+            </customproperties>
+            <blendMode>0</blendMode>
+            <featureBlendMode>0</featureBlendMode>
+            <layerTransparency>0</layerTransparency>
+            <SingleCategoryDiagramRenderer sizeLegend="0" attributeLegend="1" diagramType="Pie">
+              <DiagramCategory enabled="0" maxScaleDenominator="1e+08" minimumSize="0" penWidth="0" lineSizeType="MM" scaleDependency="Area" diagramOrientation="Up" barWidth="5" angleOffset="1440" penAlpha="255" sizeType="MM" sizeScale="0,0,0,0,0,0" scaleBasedVisibility="0" transparency="0" penColor="#000000" backgroundColor="#ffffff" height="15" lineSizeScale="0,0,0,0,0,0" width="15" labelPlacementMethod="XHeight" minScaleDenominator="0" backgroundAlpha="255">
+                <fontProperties description="DejaVu Sans,11,-1,5,50,0,0,0,0,0" style=""/>
+                <attribute label="" color="#000000" field=""/>
+              </DiagramCategory>
+              <symbol alpha="1" name="sizeSymbol" clip_to_extent="1" type="marker">
+                <layer enabled="1" locked="0" pass="0" class="SimpleMarker">
+                  <prop v="0" k="angle"/>
+                  <prop v="255,0,0,255" k="color"/>
+                  <prop v="1" k="horizontal_anchor_point"/>
+                  <prop v="bevel" k="joinstyle"/>
+                  <prop v="circle" k="name"/>
+                  <prop v="0,0" k="offset"/>
+                  <prop v="0,0,0,0,0,0" k="offset_map_unit_scale"/>
+                  <prop v="MM" k="offset_unit"/>
+                  <prop v="0,0,0,255" k="outline_color"/>
+                  <prop v="solid" k="outline_style"/>
+                  <prop v="0" k="outline_width"/>
+                  <prop v="0,0,0,0,0,0" k="outline_width_map_unit_scale"/>
+                  <prop v="MM" k="outline_width_unit"/>
+                  <prop v="diameter" k="scale_method"/>
+                  <prop v="2" k="size"/>
+                  <prop v="0,0,0,0,0,0" k="size_map_unit_scale"/>
+                  <prop v="MM" k="size_unit"/>
+                  <prop v="1" k="vertical_anchor_point"/>
+                </layer>
+              </symbol>
+            </SingleCategoryDiagramRenderer>
+            <DiagramLayerSettings priority="0" obstacle="0" yPosColumn="-1" showColumn="0" zIndex="0" placement="0" xPosColumn="-1" dist="0" linePlacementFlags="10" showAll="1"/>
+            <annotationform>.</annotationform>
+            <aliases>
+              <alias name="" index="0" field="pk"/>
+              <alias name="" index="1" field="name"/>
+            </aliases>
+            <excludeAttributesWMS/>
+            <excludeAttributesWFS/>
+            <attributeactions>
+              <defaultAction value="{00000000-0000-0000-0000-000000000000}" key="Canvas"/>
+            </attributeactions>
+            <attributetableconfig actionWidgetStyle="dropDown" sortExpression="" sortOrder="0">
+              <columns>
+                <column name="pk" width="-1" hidden="0" type="field"/>
+                <column name="name" width="-1" hidden="0" type="field"/>
+                <column width="-1" hidden="1" type="actions"/>
+              </columns>
+            </attributetableconfig>
+            <editform>.</editform>
+            <editforminit/>
+            <editforminitcodesource>0</editforminitcodesource>
+            <editforminitfilepath/>
+            <editforminitcode><![CDATA[# -*- coding: utf-8 -*-
+"""
+QGIS forms can have a Python function that is called when the form is
+opened.
+
+Use this function to add extra logic to your forms.
+
+Enter the name of the function in the "Python Init function"
+field.
+An example follows:
+"""
+from qgis.PyQt.QtWidgets import QWidget
+
+def my_form_open(dialog, layer, feature):
+    geom = feature.geometry()
+    control = dialog.findChild(QWidget, "MyLineEdit")
+]]></editforminitcode>
+            <featformsuppress>0</featformsuppress>
+            <editorlayout>generatedlayout</editorlayout>
+            <attributeEditorForm>
+              <attributeEditorContainer groupBox="0" name="ttt" visibilityExpressionEnabled="0" showLabel="1" visibilityExpression="" columnCount="0"/>
+            </attributeEditorForm>
+            <widgets/>
+            <conditionalstyles>
+              <rowstyles/>
+              <fieldstyles/>
+            </conditionalstyles>
+            <expressionfields/>
+            <previewExpression>name</previewExpression>
+            <mapTip/>
+            <layerGeometryType>2</layerGeometryType>
+          </qgis>
+        </map-layer-style>
+      </map-layer-style-manager>
+      <edittypes>
+        <edittype name="pk" widgetv2type="TextEdit">
+          <widgetv2config labelOnTop="0" UseHtml="0" IsMultiline="0" fieldEditable="1"/>
+        </edittype>
+        <edittype name="name" widgetv2type="TextEdit">
+          <widgetv2config labelOnTop="0" UseHtml="0" IsMultiline="0" fieldEditable="1"/>
+        </edittype>
+      </edittypes>
+      <renderer-v2 forceraster="0" symbollevels="0" type="singleSymbol" enableorderby="0">
+        <symbols>
+          <symbol name="0" alpha="1" clip_to_extent="1" type="fill">
+            <layer enabled="1" locked="0" pass="0" class="SimpleFill">
+              <prop v="0,0,0,0,0,0" k="border_width_map_unit_scale"/>
+              <prop v="145,149,158,255" k="color"/>
+              <prop v="bevel" k="joinstyle"/>
+              <prop v="0.80000000000000004,0.80000000000000004" k="offset"/>
+              <prop v="0,0,0,0,0,0" k="offset_map_unit_scale"/>
+              <prop v="MM" k="offset_unit"/>
+              <prop v="157,157,157,255" k="outline_color"/>
+              <prop v="solid" k="outline_style"/>
+              <prop v="0.26" k="outline_width"/>
+              <prop v="MM" k="outline_width_unit"/>
+              <prop v="solid" k="style"/>
+            </layer>
+            <layer enabled="1" locked="0" pass="0" class="SimpleFill">
+              <prop v="0,0,0,0,0,0" k="border_width_map_unit_scale"/>
+              <prop v="0,0,255,255" k="color"/>
+              <prop v="bevel" k="joinstyle"/>
+              <prop v="0,0" k="offset"/>
+              <prop v="0,0,0,0,0,0" k="offset_map_unit_scale"/>
+              <prop v="MM" k="offset_unit"/>
+              <prop v="0,0,0,255" k="outline_color"/>
+              <prop v="solid" k="outline_style"/>
+              <prop v="0.26" k="outline_width"/>
+              <prop v="MM" k="outline_width_unit"/>
+              <prop v="solid" k="style"/>
+            </layer>
+          </symbol>
+        </symbols>
+        <rotation/>
+        <sizescale/>
+      </renderer-v2>
+      <labeling type="simple"/>
+      <customproperties>
+        <property value="0" key="embeddedWidgets/count"/>
+        <property value="pal" key="labeling"/>
+        <property value="false" key="labeling/addDirectionSymbol"/>
+        <property value="0" key="labeling/angleOffset"/>
+        <property value="0" key="labeling/blendMode"/>
+        <property value="0" key="labeling/bufferBlendMode"/>
+        <property value="255" key="labeling/bufferColorA"/>
+        <property value="255" key="labeling/bufferColorB"/>
+        <property value="255" key="labeling/bufferColorG"/>
+        <property value="255" key="labeling/bufferColorR"/>
+        <property value="false" key="labeling/bufferDraw"/>
+        <property value="64" key="labeling/bufferJoinStyle"/>
+        <property value="false" key="labeling/bufferNoFill"/>
+        <property value="1" key="labeling/bufferOpacity"/>
+        <property value="1" key="labeling/bufferSize"/>
+        <property value="false" key="labeling/bufferSizeInMapUnits"/>
+        <property value="0" key="labeling/bufferSizeMapUnitMaxScale"/>
+        <property value="0" key="labeling/bufferSizeMapUnitMinScale"/>
+        <property value="0,0,0,0,0,0" key="labeling/bufferSizeMapUnitScale"/>
+        <property value="MM" key="labeling/bufferSizeUnits"/>
+        <property value="0" key="labeling/bufferTransp"/>
+        <property value="false" key="labeling/centroidInside"/>
+        <property value="false" key="labeling/centroidWhole"/>
+        <property value="3" key="labeling/decimals"/>
+        <property value="false" key="labeling/displayAll"/>
+        <property value="0" key="labeling/dist"/>
+        <property value="false" key="labeling/distInMapUnits"/>
+        <property value="0" key="labeling/distMapUnitMaxScale"/>
+        <property value="0" key="labeling/distMapUnitMinScale"/>
+        <property value="0,0,0,0,0,0" key="labeling/distMapUnitScale"/>
+        <property value="true" key="labeling/drawLabels"/>
+        <property value="true" key="labeling/enabled"/>
+        <property value="name" key="labeling/fieldName"/>
+        <property value="false" key="labeling/fitInPolygonOnly"/>
+        <property value="false" key="labeling/fontBold"/>
+        <property value="0" key="labeling/fontCapitals"/>
+        <property value="Sans Serif" key="labeling/fontFamily"/>
+        <property value="false" key="labeling/fontItalic"/>
+        <property value="0" key="labeling/fontLetterSpacing"/>
+        <property value="false" key="labeling/fontLimitPixelSize"/>
+        <property value="10000" key="labeling/fontMaxPixelSize"/>
+        <property value="3" key="labeling/fontMinPixelSize"/>
+        <property value="9" key="labeling/fontSize"/>
+        <property value="false" key="labeling/fontSizeInMapUnits"/>
+        <property value="0" key="labeling/fontSizeMapUnitMaxScale"/>
+        <property value="0" key="labeling/fontSizeMapUnitMinScale"/>
+        <property value="0,0,0,0,0,0" key="labeling/fontSizeMapUnitScale"/>
+        <property value="Point" key="labeling/fontSizeUnit"/>
+        <property value="false" key="labeling/fontStrikeout"/>
+        <property value="false" key="labeling/fontUnderline"/>
+        <property value="50" key="labeling/fontWeight"/>
+        <property value="0" key="labeling/fontWordSpacing"/>
+        <property value="false" key="labeling/formatNumbers"/>
+        <property value="false" key="labeling/isExpression"/>
+        <property value="true" key="labeling/labelOffsetInMapUnits"/>
+        <property value="0" key="labeling/labelOffsetMapUnitMaxScale"/>
+        <property value="0" key="labeling/labelOffsetMapUnitMinScale"/>
+        <property value="0,0,0,0,0,0" key="labeling/labelOffsetMapUnitScale"/>
+        <property value="false" key="labeling/labelPerPart"/>
+        <property value="<" key="labeling/leftDirectionSymbol"/>
+        <property value="false" key="labeling/limitNumLabels"/>
+        <property value="20" key="labeling/maxCurvedCharAngleIn"/>
+        <property value="-20" key="labeling/maxCurvedCharAngleOut"/>
+        <property value="2000" key="labeling/maxNumLabels"/>
+        <property value="false" key="labeling/mergeLines"/>
+        <property value="0" key="labeling/minFeatureSize"/>
+        <property value="0" key="labeling/multilineAlign"/>
+        <property value="1" key="labeling/multilineHeight"/>
+        <property value="Normal" key="labeling/namedStyle"/>
+        <property value="true" key="labeling/obstacle"/>
+        <property value="1" key="labeling/obstacleFactor"/>
+        <property value="0" key="labeling/obstacleType"/>
+        <property value="0" key="labeling/offsetType"/>
+        <property value="0" key="labeling/placeDirectionSymbol"/>
+        <property value="0" key="labeling/placement"/>
+        <property value="0" key="labeling/placementFlags"/>
+        <property value="false" key="labeling/plussign"/>
+        <property value="TR,TL,BR,BL,R,L,TSR,BSR" key="labeling/predefinedPositionOrder"/>
+        <property value="true" key="labeling/preserveRotation"/>
+        <property value="#ffffff" key="labeling/previewBkgrdColor"/>
+        <property value="5" key="labeling/priority"/>
+        <property value="4" key="labeling/quadOffset"/>
+        <property value="0" key="labeling/repeatDistance"/>
+        <property value="0" key="labeling/repeatDistanceMapUnitMaxScale"/>
+        <property value="0" key="labeling/repeatDistanceMapUnitMinScale"/>
+        <property value="0,0,0,0,0,0" key="labeling/repeatDistanceMapUnitScale"/>
+        <property value="1" key="labeling/repeatDistanceUnit"/>
+        <property value="false" key="labeling/reverseDirectionSymbol"/>
+        <property value=">" key="labeling/rightDirectionSymbol"/>
+        <property value="10000000" key="labeling/scaleMax"/>
+        <property value="1" key="labeling/scaleMin"/>
+        <property value="false" key="labeling/scaleVisibility"/>
+        <property value="6" key="labeling/shadowBlendMode"/>
+        <property value="0" key="labeling/shadowColorB"/>
+        <property value="0" key="labeling/shadowColorG"/>
+        <property value="0" key="labeling/shadowColorR"/>
+        <property value="false" key="labeling/shadowDraw"/>
+        <property value="135" key="labeling/shadowOffsetAngle"/>
+        <property value="1" key="labeling/shadowOffsetDist"/>
+        <property value="true" key="labeling/shadowOffsetGlobal"/>
+        <property value="0" key="labeling/shadowOffsetMapUnitMaxScale"/>
+        <property value="0" key="labeling/shadowOffsetMapUnitMinScale"/>
+        <property value="0,0,0,0,0,0" key="labeling/shadowOffsetMapUnitScale"/>
+        <property value="MapUnit" key="labeling/shadowOffsetUnit"/>
+        <property value="1" key="labeling/shadowOffsetUnits"/>
+        <property value="0.69999999999999996" key="labeling/shadowOpacity"/>
+        <property value="1.5" key="labeling/shadowRadius"/>
+        <property value="false" key="labeling/shadowRadiusAlphaOnly"/>
+        <property value="0" key="labeling/shadowRadiusMapUnitMaxScale"/>
+        <property value="0" key="labeling/shadowRadiusMapUnitMinScale"/>
+        <property value="0,0,0,0,0,0" key="labeling/shadowRadiusMapUnitScale"/>
+        <property value="MapUnit" key="labeling/shadowRadiusUnit"/>
+        <property value="1" key="labeling/shadowRadiusUnits"/>
+        <property value="100" key="labeling/shadowScale"/>
+        <property value="30" key="labeling/shadowTransparency"/>
+        <property value="0" key="labeling/shadowUnder"/>
+        <property value="0" key="labeling/shapeBlendMode"/>
+        <property value="255" key="labeling/shapeBorderColorA"/>
+        <property value="128" key="labeling/shapeBorderColorB"/>
+        <property value="128" key="labeling/shapeBorderColorG"/>
+        <property value="128" key="labeling/shapeBorderColorR"/>
+        <property value="0" key="labeling/shapeBorderWidth"/>
+        <property value="0" key="labeling/shapeBorderWidthMapUnitMaxScale"/>
+        <property value="0" key="labeling/shapeBorderWidthMapUnitMinScale"/>
+        <property value="0,0,0,0,0,0" key="labeling/shapeBorderWidthMapUnitScale"/>
+        <property value="MapUnit" key="labeling/shapeBorderWidthUnit"/>
+        <property value="1" key="labeling/shapeBorderWidthUnits"/>
+        <property value="false" key="labeling/shapeDraw"/>
+        <property value="255" key="labeling/shapeFillColorA"/>
+        <property value="255" key="labeling/shapeFillColorB"/>
+        <property value="255" key="labeling/shapeFillColorG"/>
+        <property value="255" key="labeling/shapeFillColorR"/>
+        <property value="64" key="labeling/shapeJoinStyle"/>
+        <property value="0" key="labeling/shapeOffsetMapUnitMaxScale"/>
+        <property value="0" key="labeling/shapeOffsetMapUnitMinScale"/>
+        <property value="0,0,0,0,0,0" key="labeling/shapeOffsetMapUnitScale"/>
+        <property value="MapUnit" key="labeling/shapeOffsetUnit"/>
+        <property value="1" key="labeling/shapeOffsetUnits"/>
+        <property value="0" key="labeling/shapeOffsetX"/>
+        <property value="0" key="labeling/shapeOffsetY"/>
+        <property value="1" key="labeling/shapeOpacity"/>
+        <property value="0" key="labeling/shapeRadiiMapUnitMaxScale"/>
+        <property value="0" key="labeling/shapeRadiiMapUnitMinScale"/>
+        <property value="0,0,0,0,0,0" key="labeling/shapeRadiiMapUnitScale"/>
+        <property value="MapUnit" key="labeling/shapeRadiiUnit"/>
+        <property value="1" key="labeling/shapeRadiiUnits"/>
+        <property value="0" key="labeling/shapeRadiiX"/>
+        <property value="0" key="labeling/shapeRadiiY"/>
+        <property value="0" key="labeling/shapeRotation"/>
+        <property value="0" key="labeling/shapeRotationType"/>
+        <property value="" key="labeling/shapeSVGFile"/>
+        <property value="0" key="labeling/shapeSizeMapUnitMaxScale"/>
+        <property value="0" key="labeling/shapeSizeMapUnitMinScale"/>
+        <property value="0,0,0,0,0,0" key="labeling/shapeSizeMapUnitScale"/>
+        <property value="0" key="labeling/shapeSizeType"/>
+        <property value="MapUnit" key="labeling/shapeSizeUnit"/>
+        <property value="1" key="labeling/shapeSizeUnits"/>
+        <property value="0" key="labeling/shapeSizeX"/>
+        <property value="0" key="labeling/shapeSizeY"/>
+        <property value="0" key="labeling/shapeTransparency"/>
+        <property value="0" key="labeling/shapeType"/>
+        <property value="<substitutions/>" key="labeling/substitutions"/>
+        <property value="255" key="labeling/textColorA"/>
+        <property value="0" key="labeling/textColorB"/>
+        <property value="0" key="labeling/textColorG"/>
+        <property value="0" key="labeling/textColorR"/>
+        <property value="1" key="labeling/textOpacity"/>
+        <property value="0" key="labeling/textTransp"/>
+        <property value="0" key="labeling/upsidedownLabels"/>
+        <property value="false" key="labeling/useSubstitutions"/>
+        <property value="" key="labeling/wrapChar"/>
+        <property value="0" key="labeling/xOffset"/>
+        <property value="0" key="labeling/yOffset"/>
+        <property value="0" key="labeling/zIndex"/>
+        <property key="variableNames"/>
+        <property key="variableValues"/>
+      </customproperties>
+      <blendMode>0</blendMode>
+      <featureBlendMode>0</featureBlendMode>
+      <layerTransparency>0</layerTransparency>
+      <SingleCategoryDiagramRenderer sizeLegend="0" attributeLegend="1" diagramType="Pie">
+        <DiagramCategory enabled="0" maxScaleDenominator="1e+08" penWidth="0" minimumSize="0" lineSizeType="MM" scaleDependency="Area" diagramOrientation="Up" barWidth="5" angleOffset="1440" penAlpha="255" sizeType="MM" sizeScale="0,0,0,0,0,0" scaleBasedVisibility="0" transparency="0" penColor="#000000" backgroundColor="#ffffff" height="15" lineSizeScale="0,0,0,0,0,0" width="15" labelPlacementMethod="XHeight" minScaleDenominator="0" backgroundAlpha="255">
+          <fontProperties description="DejaVu Sans,11,-1,5,50,0,0,0,0,0" style=""/>
+          <attribute label="" color="#000000" field=""/>
+        </DiagramCategory>
+        <symbol name="sizeSymbol" alpha="1" clip_to_extent="1" type="marker">
+          <layer enabled="1" locked="0" pass="0" class="SimpleMarker">
+            <prop v="0" k="angle"/>
+            <prop v="255,0,0,255" k="color"/>
+            <prop v="1" k="horizontal_anchor_point"/>
+            <prop v="bevel" k="joinstyle"/>
+            <prop v="circle" k="name"/>
+            <prop v="0,0" k="offset"/>
+            <prop v="0,0,0,0,0,0" k="offset_map_unit_scale"/>
+            <prop v="MM" k="offset_unit"/>
+            <prop v="0,0,0,255" k="outline_color"/>
+            <prop v="solid" k="outline_style"/>
+            <prop v="0" k="outline_width"/>
+            <prop v="0,0,0,0,0,0" k="outline_width_map_unit_scale"/>
+            <prop v="MM" k="outline_width_unit"/>
+            <prop v="diameter" k="scale_method"/>
+            <prop v="2" k="size"/>
+            <prop v="0,0,0,0,0,0" k="size_map_unit_scale"/>
+            <prop v="MM" k="size_unit"/>
+            <prop v="1" k="vertical_anchor_point"/>
+          </layer>
+        </symbol>
+      </SingleCategoryDiagramRenderer>
+      <DiagramLayerSettings priority="0" obstacle="0" yPosColumn="-1" showColumn="0" zIndex="0" placement="0" dist="0" xPosColumn="-1" linePlacementFlags="10" showAll="1"/>
+      <annotationform>.</annotationform>
+      <aliases>
+        <alias name="" index="0" field="pk"/>
+        <alias name="" index="1" field="name"/>
+      </aliases>
+      <excludeAttributesWMS/>
+      <excludeAttributesWFS/>
+      <attributeactions>
+        <defaultAction value="{00000000-0000-0000-0000-000000000000}" key="Canvas"/>
+      </attributeactions>
+      <attributetableconfig actionWidgetStyle="dropDown" sortExpression="" sortOrder="0">
+        <columns>
+          <column name="pk" width="-1" hidden="0" type="field"/>
+          <column name="name" width="-1" hidden="0" type="field"/>
+          <column width="-1" hidden="1" type="actions"/>
+        </columns>
+      </attributetableconfig>
+      <editform>.</editform>
+      <editforminit/>
+      <editforminitcodesource>0</editforminitcodesource>
+      <editforminitfilepath></editforminitfilepath>
+      <editforminitcode><![CDATA[# -*- coding: utf-8 -*-
+"""
+QGIS forms can have a Python function that is called when the form is
+opened.
+
+Use this function to add extra logic to your forms.
+
+Enter the name of the function in the "Python Init function"
+field.
+An example follows:
+"""
+from qgis.PyQt.QtWidgets import QWidget
+
+def my_form_open(dialog, layer, feature):
+    geom = feature.geometry()
+    control = dialog.findChild(QWidget, "MyLineEdit")
+]]></editforminitcode>
+      <featformsuppress>0</featformsuppress>
+      <editorlayout>generatedlayout</editorlayout>
+      <attributeEditorForm>
+        <attributeEditorContainer groupBox="0" name="ttt" visibilityExpressionEnabled="0" showLabel="1" visibilityExpression="" columnCount="0"/>
+      </attributeEditorForm>
+      <widgets/>
+      <conditionalstyles>
+        <rowstyles/>
+        <fieldstyles/>
+      </conditionalstyles>
+      <expressionfields/>
+      <previewExpression>name</previewExpression>
+      <mapTip></mapTip>
+    </maplayer>
     <maplayer minimumScale="0" maximumScale="1e+08" simplifyDrawingHints="1" minLabelScale="1" maxLabelScale="1e+08" simplifyDrawingTol="1" geometry="Polygon" simplifyMaxScale="1" type="vector" hasScaleBasedVisibilityFlag="0" simplifyLocal="1" scaleBasedLabelVisibilityFlag="0">
       <id>Hello_Project_SubsetString_copy20160223113949592</id>
       <datasource>dbname='./helloworld.db' table="hello" (geom) sql=</datasource>
@@ -500,8 +1169,8 @@ An example follows:
 from PyQt4.QtGui import QWidget
 
 def my_form_open(dialog, layer, feature):
-	geom = feature.geometry()
-	control = dialog.findChild(QWidget, "MyLineEdit")
+    geom = feature.geometry()
+    control = dialog.findChild(QWidget, "MyLineEdit")
 ]]></editforminitcode>
       <featformsuppress>0</featformsuppress>
       <editorlayout>generatedlayout</editorlayout>
@@ -817,8 +1486,8 @@ An example follows:
 from PyQt4.QtGui import QWidget
 
 def my_form_open(dialog, layer, feature):
-	geom = feature.geometry()
-	control = dialog.findChild(QWidget, "MyLineEdit")
+    geom = feature.geometry()
+    control = dialog.findChild(QWidget, "MyLineEdit")
 ]]></editforminitcode>
       <featformsuppress>0</featformsuppress>
       <editorlayout>generatedlayout</editorlayout>
@@ -1134,8 +1803,8 @@ An example follows:
 from PyQt4.QtGui import QWidget
 
 def my_form_open(dialog, layer, feature):
-	geom = feature.geometry()
-	control = dialog.findChild(QWidget, "MyLineEdit")
+    geom = feature.geometry()
+    control = dialog.findChild(QWidget, "MyLineEdit")
 ]]></editforminitcode>
       <featformsuppress>0</featformsuppress>
       <editorlayout>generatedlayout</editorlayout>
@@ -2591,9 +3260,7 @@ def my_form_open(dialog, layer, feature):
       <hello20131022151106574 type="int">0</hello20131022151106574>
       <points20150803121107046 type="int">1</points20150803121107046>
     </WFSLayersPrecision>
-    <WMSRestrictedComposers type="QStringList">
-      <value>layoutA4</value>
-    </WMSRestrictedComposers>
+    <WMSRestrictedComposers type="QStringList"/>
     <WMSServiceTitle type="QString">QGIS Server test</WMSServiceTitle>
     <WMSContactPhone type="QString"></WMSContactPhone>
     <WFSTLayers>
diff --git a/tests/testdata/symbol_layer/external_sld/simple_streams.sld b/tests/testdata/symbol_layer/external_sld/simple_streams.sld
new file mode 100644
index 0000000..30c2f7f
--- /dev/null
+++ b/tests/testdata/symbol_layer/external_sld/simple_streams.sld
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<StyledLayerDescriptor version="1.0.0" xmlns="http://www.opengis.net/sld" xmlns:ogc="http://www.opengis.net/ogc"
+  xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://www.opengis.net/sld http://schemas.opengis.net/sld/1.0.0/StyledLayerDescriptor.xsd">
+  <NamedLayer>
+    <Name>Simple Streams</Name>
+    <UserStyle>
+
+      <Title>Default Styler for streams segments</Title>
+      <Abstract>Blue lines, 2px wide</Abstract>
+      <FeatureTypeStyle>
+        <FeatureTypeName>Feature</FeatureTypeName>
+        <Rule>
+          <Title>Streams</Title>
+          <LineSymbolizer>
+            <Stroke>
+              <CssParameter name="stroke">
+                <ogc:Literal>#003EBA</ogc:Literal>
+              </CssParameter>
+              <CssParameter name="stroke-width">
+                <ogc:Literal>2</ogc:Literal>
+              </CssParameter>
+              <CssParameter name="stroke-opacity">0.1</CssParameter>
+            </Stroke>
+          </LineSymbolizer>
+        </Rule>
+      </FeatureTypeStyle>
+    </UserStyle>
+  </NamedLayer>
+</StyledLayerDescriptor>
\ No newline at end of file
diff --git a/tests/testdata/symbol_layer/external_sld/testSimpleMarkerRotation-directValue.sld b/tests/testdata/symbol_layer/external_sld/testSimpleMarkerRotation-directValue.sld
new file mode 100644
index 0000000..ee82a9c
--- /dev/null
+++ b/tests/testdata/symbol_layer/external_sld/testSimpleMarkerRotation-directValue.sld
@@ -0,0 +1,30 @@
+<?xml version="1.0" ?>
+<sld:StyledLayerDescriptor version="1.0.0" xmlns="http://www.opengis.net/sld" xmlns:gml="http://www.opengis.net/gml" xmlns:ogc="http://www.opengis.net/ogc" xmlns:sld="http://www.opengis.net/sld">
+	<sld:NamedLayer>
+		<sld:Name>testSimpleMarkerRotation</sld:Name>
+		<sld:UserStyle>
+			<sld:Name>testSimpleMarkerRotation</sld:Name>
+			<sld:FeatureTypeStyle>
+				<sld:Name>name</sld:Name>
+				<sld:Rule>
+					<sld:Name>Single symbol</sld:Name>
+					<sld:PointSymbolizer>
+						<sld:Graphic>
+							<sld:Mark>
+								<sld:WellKnownName>star</sld:WellKnownName>
+								<sld:Fill>
+									<sld:CssParameter name="fill">#ff0000</sld:CssParameter>
+								</sld:Fill>
+								<sld:Stroke>
+									<sld:CssParameter name="stroke">#00ff00</sld:CssParameter>
+								</sld:Stroke>
+							</sld:Mark>
+							<sld:Size>36</sld:Size>
+							<sld:Rotation>50.0</sld:Rotation>
+						</sld:Graphic>
+					</sld:PointSymbolizer>
+				</sld:Rule>
+			</sld:FeatureTypeStyle>
+		</sld:UserStyle>
+	</sld:NamedLayer>
+</sld:StyledLayerDescriptor>
diff --git a/tests/testdata/symbol_layer/external_sld/testSimpleMarkerRotation-ogcLiteral.sld b/tests/testdata/symbol_layer/external_sld/testSimpleMarkerRotation-ogcLiteral.sld
new file mode 100644
index 0000000..d3139fb
--- /dev/null
+++ b/tests/testdata/symbol_layer/external_sld/testSimpleMarkerRotation-ogcLiteral.sld
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<StyledLayerDescriptor xmlns="http://www.opengis.net/sld" xmlns:ogc="http://www.opengis.net/ogc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.1.0" xmlns:xlink="http://www.w3.org/1999/xlink" xsi:schemaLocation="http://www.opengis.net/sld http://schemas.opengis.net/sld/1.1.0/StyledLayerDescriptor.xsd" xmlns:se="http://www.opengis.net/se">
+  <NamedLayer>
+    <se:Name>points</se:Name>
+    <UserStyle>
+      <se:Name>points</se:Name>
+      <se:FeatureTypeStyle>
+        <se:Rule>
+          <se:Name>Single symbol</se:Name>
+          <se:PointSymbolizer>
+            <se:Graphic>
+              <se:Mark>
+                <se:WellKnownName>regular_star</se:WellKnownName>
+                <se:Fill>
+                  <se:SvgParameter name="fill">#ff0000</se:SvgParameter>
+                </se:Fill>
+                <se:Stroke>
+                  <se:SvgParameter name="stroke">#00ff00</se:SvgParameter>
+                </se:Stroke>
+              </se:Mark>
+              <se:Size>10</se:Size>
+              <se:Rotation>
+                <ogc:Literal>50</ogc:Literal>
+              </se:Rotation>
+            </se:Graphic>
+          </se:PointSymbolizer>
+        </se:Rule>
+      </se:FeatureTypeStyle>
+    </UserStyle>
+  </NamedLayer>
+</StyledLayerDescriptor>

-- 
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