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

Bas Couwenberg sebastic at debian.org
Fri Aug 26 14:34:30 UTC 2016


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

sebastic pushed a commit to branch upstream
in repository qgis.

commit 81e727419a90712c45799d2d2b8d832158b75974
Author: Bas Couwenberg <sebastic at xs4all.nl>
Date:   Fri Aug 26 16:30:08 2016 +0200

    Imported Upstream version 2.16.2+dfsg
---
 .gitignore                                         |   2 +
 CMakeLists.txt                                     |   2 +-
 ChangeLog                                          | 266 +++++++++++++++++++++
 cmake_templates/qgsconfig.h.in                     |   4 +-
 debian/changelog                                   |  14 +-
 debian/compat.in                                   |   4 +-
 debian/control.in                                  |  50 ++--
 .../libqgis-analysis{QGIS_ABI}.lintian-overrides   |   1 +
 debian/libqgis-core{QGIS_ABI}.lintian-overrides    |   2 +
 debian/libqgis-customwidgets.lintian-overrides     |   1 -
 debian/libqgis-customwidgets.lintian-overrides.in  |   2 +
 debian/python-qgis.install.in                      |   4 +-
 debian/python-qgis.lintian-overrides.in            |   1 +
 debian/qgis-common.install                         |   5 +
 debian/qgis-plugin-globe-common.install            |   1 +
 debian/qgis-plugin-globe.install                   |   1 +
 debian/qgis-plugin-grass.lintian-overrides         |   2 -
 debian/qgis-provider.lintian-overrides             |   1 +
 debian/qgis-providers.install.in                   |   4 +-
 debian/qgis-providers.lintian-overrides            |   2 +
 debian/qgis.install                                |   6 +-
 debian/qgis.lintian-overrides                      |   6 +-
 debian/rules                                       |  15 +-
 i18n/qgis_de.ts                                    |   4 +-
 python/core/qgsvectorlayer.sip                     |  26 +-
 .../processing/algs/gdal/ogr2ogronesidebuffer.py   |  26 +-
 .../plugins/processing/algs/qgis/AddTableField.py  |   5 +-
 .../processing/algs/qgis/AutoincrementalField.py   |   5 +-
 python/plugins/processing/algs/qgis/Centroids.py   |   2 +-
 .../plugins/processing/algs/qgis/CheckValidity.py  |   9 +-
 python/plugins/processing/algs/qgis/ConcaveHull.py |   2 +-
 python/plugins/processing/algs/qgis/ConvexHull.py  |   2 +-
 .../processing/algs/qgis/DensifyGeometries.py      |   5 +-
 python/plugins/processing/algs/qgis/Difference.py  |   4 +-
 python/plugins/processing/algs/qgis/Dissolve.py    |   5 +-
 python/plugins/processing/algs/qgis/Eliminate.py   |   5 +-
 .../processing/algs/qgis/EquivalentNumField.py     |   5 +-
 python/plugins/processing/algs/qgis/Explode.py     |   3 +-
 .../processing/algs/qgis/ExportGeometryInfo.py     |   2 +-
 .../processing/algs/qgis/ExtractByLocation.py      |   2 +-
 .../plugins/processing/algs/qgis/FieldPyculator.py |   7 +-
 .../processing/algs/qgis/FieldsCalculator.py       |   5 +-
 .../plugins/processing/algs/qgis/FieldsMapper.py   |   3 +-
 .../plugins/processing/algs/qgis/Intersection.py   |   5 +-
 .../plugins/processing/algs/qgis/JoinAttributes.py |   3 +-
 python/plugins/processing/algs/qgis/Merge.py       |  10 +-
 .../processing/algs/qgis/MultipartToSingleparts.py |  20 +-
 .../algs/qgis/OrientedMinimumBoundingBox.py        |   5 +-
 .../processing/algs/qgis/PointsDisplacement.py     |   5 +-
 .../processing/algs/qgis/PointsInPolygon.py        |   7 +-
 .../processing/algs/qgis/PointsInPolygonUnique.py  |   5 +-
 .../algs/qgis/PointsInPolygonWeighted.py           |   7 +-
 .../processing/algs/qgis/PointsLayerFromTable.py   |   3 +-
 .../plugins/processing/algs/qgis/PointsToPaths.py  |   2 +-
 python/plugins/processing/algs/qgis/Polygonize.py  |   3 +-
 .../processing/algs/qgis/RandomPointsAlongLines.py |   2 +-
 .../processing/algs/qgis/RandomPointsLayer.py      |   2 +-
 .../algs/qgis/RandomPointsPolygonsFixed.py         |   2 +-
 .../algs/qgis/RandomPointsPolygonsVariable.py      |   2 +-
 .../processing/algs/qgis/ReverseLineDirection.py   |   3 +-
 .../processing/algs/qgis/SaveSelectedFeatures.py   |   5 +-
 .../algs/qgis/SinglePartsToMultiparts.py           |   2 +-
 python/plugins/processing/algs/qgis/Smooth.py      |   3 +-
 python/plugins/processing/algs/qgis/SpatialJoin.py |   9 +-
 python/plugins/processing/algs/qgis/SumLines.py    |   6 +-
 .../processing/algs/qgis/SymmetricalDifference.py  |  13 +-
 python/plugins/processing/algs/qgis/Union.py       |   6 +-
 python/plugins/processing/algs/qgis/VectorSplit.py |   2 +-
 .../processing/algs/qgis/ZonalStatistics.py        |   2 +-
 python/plugins/processing/core/SilentProgress.py   |   8 +-
 .../plugins/processing/gui/AlgorithmDialogBase.py  |   3 +
 .../plugins/processing/gui/GetScriptsAndModels.py  |  11 +-
 .../processing/gui/ListMultiselectWidget.py        |  10 +-
 .../plugins/processing/gui/ScriptEditorDialog.py   |   8 +-
 .../processing/modeler/AddModelFromFileAction.py   |   2 +-
 python/plugins/processing/modeler/ModelerDialog.py |   4 +-
 .../processing/script/AddScriptFromFileAction.py   |   2 +-
 python/testing/__init__.py                         |   5 +-
 src/app/qgisapp.cpp                                |   6 +-
 src/app/qgsbookmarks.cpp                           |   2 +
 src/app/qgsdxfexportdialog.cpp                     |   8 +-
 src/core/pal/feature.cpp                           |  80 ++++---
 src/core/pal/feature.h                             |   6 +-
 src/core/pal/geomfunction.cpp                      |  53 ++++
 src/core/pal/geomfunction.h                        |  12 +
 src/core/pal/layer.cpp                             |   2 +-
 src/core/pal/layer.h                               |  16 --
 src/core/pal/pointset.cpp                          |  45 +---
 src/core/qgslabelfeature.cpp                       |  24 ++
 src/core/qgslabelfeature.h                         |  34 +++
 src/core/qgslabelingenginev2.cpp                   |   3 -
 src/core/qgslabelingenginev2.h                     |   1 -
 src/core/qgspallabeling.cpp                        |  15 ++
 src/core/qgsvectorfilewriter.cpp                   |   9 +-
 src/core/qgsvectorlayer.cpp                        |  77 +++++-
 src/core/qgsvectorlayer.h                          |  26 +-
 src/core/qgsvectorlayerlabelprovider.cpp           |   1 -
 src/core/raster/qgscolorrampshader.cpp             |   3 +
 src/gui/CMakeLists.txt                             |  19 ++
 src/gui/attributetable/qgsattributetablemodel.cpp  |   2 +-
 src/gui/attributetable/qgsfeaturelistview.cpp      |   3 +-
 .../editorwidgets/core/qgseditorwidgetwrapper.cpp  |   2 +-
 .../editorwidgets/core/qgssearchwidgetwrapper.cpp  |   2 +-
 src/gui/qgsattributeform.cpp                       |  32 ++-
 src/gui/qgsattributeform.h                         |  14 +-
 .../qgssinglebandpseudocolorrendererwidget.cpp     |   3 +
 src/helpviewer/qgshelpviewer.cpp                   |   2 +-
 .../dxf2shp_converter/dxflib/src/dl_dxf.cpp        |   2 +-
 src/providers/grass/qgis.g.info.c                  |   2 +-
 src/providers/ogr/qgsogrfeatureiterator.cpp        |  49 +++-
 src/providers/ogr/qgsogrfeatureiterator.h          |   9 +-
 src/providers/ogr/qgsogrprovider.cpp               |  23 +-
 src/providers/wfs/qgswfscapabilities.cpp           |   2 +-
 src/providers/wfs/qgswfsconstants.cpp              |   2 +
 src/providers/wfs/qgswfsconstants.h                |   4 +
 src/providers/wfs/qgswfsdatasourceuri.cpp          |  58 ++++-
 src/providers/wfs/qgswfsdatasourceuri.h            |   5 +-
 src/providers/wfs/qgswfsprovider.cpp               |  41 ++--
 tests/src/gui/testqgsdualview.cpp                  |  27 +++
 tests/src/python/CMakeLists.txt                    |   1 +
 tests/src/python/providertestbase.py               |  26 ++
 tests/src/python/test_provider_tabfile.py          |  18 +-
 tests/src/python/test_provider_wfs.py              |  88 +++++++
 tests/src/python/test_qgsattributetablemodel.py    |  31 ++-
 tests/src/python/test_qgsfeatureiterator.py        |   9 +-
 tests/src/python/test_qgspallabeling_placement.py  |   1 +
 tests/src/python/test_qgsrastercolorrampshader.py  |  37 +++
 tests/src/python/test_qgsvectorfilewriter.py       |  46 ++++
 128 files changed, 1286 insertions(+), 407 deletions(-)

diff --git a/.gitignore b/.gitignore
index c06bd6e..a5dc157 100644
--- a/.gitignore
+++ b/.gitignore
@@ -61,4 +61,6 @@ tests/testdata/raster/band1_float32_noct_epsg4326.tif.aux.xml
 tests/testdata/raster/band1_int16_noct_epsg4326.tif.aux.xml
 tests/testdata/raster/band3_float32_noct_epsg4326.tif.aux.xml
 tests/testdata/raster/band3_int16_noct_epsg4326.tif.aux.xml
+python/plugins/processing/tests/testdata/custom/grass7/float_raster.tif.aux.xml
+python/plugins/processing/tests/testdata/custom/grass7/raster_1class.tif.aux.xml
 Thumb.db
diff --git a/CMakeLists.txt b/CMakeLists.txt
index e57efa3..5f703bd 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,6 +1,6 @@
 SET(CPACK_PACKAGE_VERSION_MAJOR "2")
 SET(CPACK_PACKAGE_VERSION_MINOR "16")
-SET(CPACK_PACKAGE_VERSION_PATCH "1")
+SET(CPACK_PACKAGE_VERSION_PATCH "2")
 SET(COMPLETE_VERSION ${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH})
 SET(RELEASE_NAME "Nødebo")
 IF (POLICY CMP0048) # in CMake 3.0.0+
diff --git a/ChangeLog b/ChangeLog
index 3def048..d73e733 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,269 @@
+Alexander Bruy <alexander.bruy at gmail.com>	2016-08-23
+
+    fix typo
+
+Juergen E. Fischer <jef at norbit.de>	2016-08-23
+
+    fix switching of projects within unicode folders
+
+    (cherry picked from commit 3951f15b6481a85b551e2f33f26c2aeb6687a24a)
+
+Alexander Bruy <alexander.bruy at gmail.com>	2016-08-23
+
+    [processing] add missed error() method
+
+    (cherry picked from commit 6a7fa7dd5a199bfa0ced8e4768b910171c3b8e8e)
+
+Matthias Kuhn <matthias at opengis.ch>	2016-08-19
+
+    Improve wording
+
+    Fix #15456
+
+Matthias Kuhn <matthias at opengis.ch>	2016-08-19
+
+    Hide invalid constraints label when it's unused
+
+    Fix #15452
+
+Matthias Kuhn <matthias at opengis.ch>	2016-08-19
+
+    Widget constraints: use field alias where available
+
+    Fix #15455
+
+Juergen E. Fischer <jef at norbit.de>	2016-08-18
+
+    dxf export: avoid symbology scale 0 (fixes #14138)
+
+    (cherry picked from commit 0a07fee15297e18a73b63f194f5aeecffd76800c)
+
+Juergen E. Fischer <jef at norbit.de>	2016-08-18
+
+    debian packaging update
+
+    (cherry picked from commit 127fb683b226908c4f34a78a8fa1e43965a51dfa)
+
+Nyall Dawson <nyall.dawson at gmail.com>	2016-08-17
+
+    fix repeated labels on curved lines when label width > repeat distance
+
+    (cherry-picked from fb346ecf4fda53ccac7ef939bc6ec84a361a9d58)
+    o
+
+Nyall Dawson <nyall.dawson at gmail.com>	2016-08-17
+
+    Make QgsVectorLayer uniqueValues/min/maxValue consider edits
+
+    Previously these methods would inconsistently handle the
+    edit buffer, eg uniqueValues would consider changed attributes
+    but not added features. Now uniqueValues, minimumValue and
+    maximumValue all consider both added features and changed
+    attribute values when performing their calculation.
+
+    The most noticable effect of this fix is that the unique
+    values widget now correctly shows values for features which
+    have been added but not yet committed to the provider.
+
+    (cherry-picked from 50c35929d86ab01b22c29cd129fd7019a1bf624a)
+
+Nyall Dawson <nyall.dawson at gmail.com>	2016-08-17
+
+    Don't crash raster shader with nan or inf values (fix #15444)
+
+    (cherry-picked from 34ebe124ff62956095941b5bb76809c6ba4b1a0f)
+
+Nyall Dawson <nyall.dawson at gmail.com>	2016-08-17
+
+    Fix some missing autoupdates for raster psuedo color widget
+
+    (cherry-picked from b349eb8a982d762d399ad4c21e3214195e6cd778)
+
+Juergen E. Fischer <jef at norbit.de>	2016-08-15
+
+    exclude release name from version string (fixes #15258)
+
+    (cherry picked from commit 1391aad2f713a796b0ac3d0c22bec6c1c7ada3bb)
+
+Juergen E. Fischer <jef at norbit.de>	2016-08-15
+
+    debian packaging update
+
+    (cherry picked from commit 977b5f2b8c9d5ee93e166a7c95f1f70fc2e800ec)
+
+Anita Graser <anitagraser at gmx.at>	2016-08-10
+
+    fixed failure to insert only one point
+
+    Previously, if pointsNumber was 1, it wouldn't insert a new point in the middle.
+    (cherry picked from commit 754ccefabc5c5fb9ba4472b182f1f05cd2a0ebb2)
+
+Larry Shaffer <lshaffer at boundlessgeo.com>	2016-08-10
+
+    [auth] Add missing auth system ui headers for external C++ apps
+
+    (cherry-picked from f3e90f1d5a87b2a7c6c693aa8ba3eaad64161b1d)
+
+Matthias Kuhn <matthias at opengis.ch>	2016-08-10
+
+    Fix crash when clicking in empty relation editor
+
+Nyall Dawson <nyall.dawson at gmail.com>	2016-08-10
+
+    Reset layers for each pal placement test, avoids all tests failing
+    because of one
+
+    (cherry-picked from 95ecdaf4383a0337710fd98fe34c93323be8e0ad)
+
+Nyall Dawson <nyall.dawson at gmail.com>	2016-08-10
+
+    Fix "label only inside polygon" mode when used with perimeter placement
+
+    The option was not working with perimeter placements as perimeter placements alter
+    the label feature geometry to be a boundary linestring - hence no labels where
+    ever inside this boundary.
+
+    Accordingly this refactors how the force label inside polygon option functions.
+    Now QgsLabelFeatures can have a permissible zone geometry set, such that any
+    label candidates outside of this permissible zone are discarded.
+
+    This approach is more flexible as it could also be used for more labeling options
+    in future, eg discarding label candidates which are too far from a centroid or
+    something.
+
+    Sponsored by Andreas Neumann
+
+    (cherry-picked from c234d80e1e6c07813140df416b26ad5665b9ab99)
+
+Nyall Dawson <nyall.dawson at gmail.com>	2016-08-09
+
+    Make test layer comparison handle different order of features
+
+    (cherry-picked from f449bf236198ced18bbd7078144f12a9aab77cd0)
+
+Nyall Dawson <nyall.dawson at gmail.com>	2016-08-09
+
+    [processing] Fix broken multi field selection widget
+
+    (cherry-picked from fda93dfc574a152be2509d7f370af073abd3ba37)
+
+Nyall Dawson <nyall.dawson at gmail.com>	2016-08-09
+
+    [processing] Fix multipart to singlepart handling of null geometry
+
+    (cherry-picked from 0455b6600d2ab443ea8d691e3c007ee481a30910)
+
+Nyall Dawson <nyall.dawson at gmail.com>	2016-08-09
+
+    Add processing test .aux.xml to .gitignore
+
+    (cherry-picked from 0939dbf9df5d0cb6867a4d0b3ea6a543eea77366)
+
+Nyall Dawson <nyall.dawson at gmail.com>	2016-08-09
+
+    [processing] Use layer crs/fields instead of provider crs/fields
+
+    Since the layer has more complete knowledge of the crs (ie, when
+    provider could not determine crs and user has selected it from
+    the list), and also better knowledge of layer fields (virtual
+    fields, joined fields) we should use these rather than the
+    provider methods.
+
+    (cherry-picked from 06c4b07222f9410e1669387a6497897c61748a16)
+
+Merge: 005d467 f49bd5c
+Alessandro Pasotti <elpaso at itopen.it>	2016-08-09
+
+    Merge pull request #3368 from elpaso/wfs_fixes
+
+    Try to fix #15360
+
+Alessandro Pasotti <apasotti at boundlessgeo.com>	2016-08-08
+
+    [WFS] Fixes #15360 and other issues
+
+    - fixes authcfg params not passed to requests
+    - fixes backward URI compatibility
+    - fixes version parameter ignored in old style URI
+    - check for "user" in addition to "username" in WFS URI
+
+Nyall Dawson <nyall.dawson at gmail.com>	2016-08-09
+
+    Implement provider side FilterFids iterators for OGR provider
+
+    Makes some operations with OGR sources magnitudes faster, ie
+    zoom to 20 selected features in a 4 million point dataset:
+
+    before: 14 seconds of blocked gui
+    after: instant
+
+    (cherry-picked from 1f02fd491d62b2a79ee1bd98000f48cb4db1b442)
+
+Even Rouault <even.rouault at spatialys.com>	2016-08-08
+
+    [QgsVectorFileWriter + OGR provider] Create Integer64 fields as Real fields when output driver doesn't support Integer64
+
+    Fix #15405
+
+Even Rouault <even.rouault at spatialys.com>	2016-08-08
+
+    [WFS provider] Succesfully analyze DescribeFeatureType response with <complexType> as inline element of <element> (#15395)
+
+Juergen E. Fischer <jef at norbit.de>	2016-08-04
+
+    debian packaging update
+
+    (cherry picked from commit aef87037254729583590102e86a59ea51262cf78)
+
+Alexander Bruy <alexander.bruy at gmail.com>	2016-07-25
+
+    [processing] always use user-defined default folder for scripts/models
+
+    (cherry picked from commit 48cca3bc12e874d681669b47ce2ee24b96baa4de)
+
+    Conflicts:
+python/plugins/processing/modeler/AddModelFromFileAction.py
+python/plugins/processing/script/AddScriptFromFileAction.py
+
+Matthias Kuhn <matthias at opengis.ch>	2016-08-03
+
+    Don't show scrollbar in embedded drag and drop designer form
+
+Juergen E. Fischer <jef at norbit.de>	2016-07-31
+
+    debian packaging update
+
+    (cherry picked from commit 750e60fe19eb89489e5e0803717dbbfabfb75e0e)
+
+Juergen E. Fischer <jef at norbit.de>	2016-08-03
+
+    fix crash when QSQLITE is unavailable (fixes #15358)
+
+    (cherry picked from commit 285bcd053c353bd99f7e8e71003f5b4bd39bde57)
+
+Matthias Kuhn <matthias at opengis.ch>	2016-08-01
+
+    Sort attribute table by value for numerical columns
+
+    Fix #15318
+    Fix #15295
+
+Alexander Bruy <alexander.bruy at gmail.com>	2016-08-01
+
+    [processing] don't apply additional parameter if offset curve operation is used (fix #15342)
+
+    (cherry picked from commit 1d2b0b4ca7658ed57c4663d9f064ca4bbc55381e)
+
+Alexander Bruy <alexander.bruy at gmail.com>	2016-08-01
+
+    [processing] add missed import (fix #15359)
+
+    (cherry picked from commit 98a55274063fcfe8174b3c3d0369d72d5e2f7c73)
+
+Juergen E. Fischer <jef at norbit.de>	2016-07-29
+
+    Release of 2.16.1
+
 Nyall Dawson <nyall.dawson at gmail.com>	2016-07-29
 
     Fix map not refreshed after using pan to selected (fix #15324)
diff --git a/cmake_templates/qgsconfig.h.in b/cmake_templates/qgsconfig.h.in
index 629c69a..c1b9e75 100644
--- a/cmake_templates/qgsconfig.h.in
+++ b/cmake_templates/qgsconfig.h.in
@@ -5,10 +5,10 @@
 #define QGSCONFIG_H
 
 // Version must be specified according to
-// <int>.<int>.<int>-<any text>.
+// <int>.<int>.<int>"
 // or else upgrading old project file will not work
 // reliably.
-#define VERSION "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}-${RELEASE_NAME}"
+#define VERSION "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}"
 
 //used in vim src/core/qgis.cpp
 //The way below should work but it resolves to a number like 0110 which the compiler treats as octal I think
diff --git a/debian/changelog b/debian/changelog
index 9da69c1..c5e60a7 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,8 +1,18 @@
-qgis (2.16.1) UNRELEASED; urgency=medium
+qgis (2.16.2) UNRELEASED; urgency=medium
+
+  * Release of 2.16.2
+
+ -- Jürgen E. Fischer <jef at norbit.de>  Fri, 26 Aug 2016 13:58:37 +0200
+
+qgis (2.16.1) unstable; urgency=medium
 
   * Release of 2.16.1
+  * drop support for debian wheezy and ubuntu wily
+  * add python-requests dependency for metasearch plugin
+  * lintian fixes
+  * add version constraint to libqgis-customwidgets dependency.
 
- -- Jürgen E. Fischer <jef at norbit.de>  Fri, 29 Jul 2016 14:04:56 +0200
+ -- Jürgen E. Fischer <jef at norbit.de>  Fri, 26 Aug 2016 13:58:36 +0200
 
 qgis (2.16.0) unstable; urgency=medium
 
diff --git a/debian/compat.in b/debian/compat.in
index 286144b..d00268c 100644
--- a/debian/compat.in
+++ b/debian/compat.in
@@ -1,3 +1,3 @@
-#stretch sid jessie trusty wily xenial#9
-#wheezy jessie#8
+#stretch sid jessie trusty xenial#9
+#jessie#8
 #precise#7
diff --git a/debian/control.in b/debian/control.in
index 3bc7f4e..789102d 100644
--- a/debian/control.in
+++ b/debian/control.in
@@ -6,21 +6,19 @@ Priority: optional
 Build-Depends:
  bison,
  cmake (>= 2.8),
-#wily# cmake (<< 3.3.2),
-#sid stretch jessie wheezy trusty wily xenial# debhelper (>= 9),
-#sid stretch jessie trusty wily xenial# dh-python,
+#sid stretch jessie trusty xenial# debhelper (>= 9),
+#sid stretch jessie trusty xenial# dh-python,
 #precise# debhelper (>= 7),
  flex,
  grass-dev,
  libexpat1-dev,
  libfcgi-dev,
-#sid stretch jessie trusty wily xenial# libgdal-dev (>= 1.10.1-0~),
+#sid stretch jessie trusty xenial# libgdal-dev (>= 1.10.1-0~),
 #precise# libgdal-dev (>= 1.9.0) | libgdal1-dev (<< 1.9.0),
-#wheezy# libgdal1-dev,
  gdal-bin,
  python-gdal,
  libgeos-dev (>= 3.0.0),
-#jessie wheezy precise trusty wily# libgsl0-dev,
+#jessie precise trusty# libgsl0-dev,
 #sid stretch xenial# libgsl-dev,
  libpq-dev,
  libproj-dev,
@@ -28,10 +26,10 @@ Build-Depends:
  libqt4-opengl-dev,
  libqca2-dev,
  libqca2-plugin-ossl,
-#wheezy jessie precise trusty utopic vivid wily# libqtwebkit-dev,
-#stretch jessie wheezy# libqwt-dev,
-#precise trusty wily xenial sid# libqwt5-qt4-dev,
-#sid stretch jessie wheezy trusty wily xenial# libqjson-dev,
+#jessie precise trusty xenial# libqtwebkit-dev,
+#stretch jessie# libqwt-dev,
+#precise trusty xenial sid# libqwt5-qt4-dev,
+#sid stretch jessie trusty xenial# libqjson-dev,
  libspatialite-dev,
  libsqlite3-dev,
  libspatialindex-dev,
@@ -42,14 +40,13 @@ Build-Depends:
  python-qt4-dev,
  python-qt4-sql,
  python-yaml, python-mock,
-#stretch sid wily xenial# python-future,
-#precise wheezy# python,
+#stretch sid xenial# python-future,
+#precise# python,
 #precise# python-central (>= 0.5),
-#wheezy# python-dev,
-#sid stretch jessie trusty wily xenial# python-all (>= 2.6.6-3~), python-all-dev (>= 2.6.6-3~),
-#sid stretch jessie wily xenial# pyqt4.qsci-dev,
-#sid stretch jessie trusty wily xenial# python-pyspatialite,
-#sid wheezy jessie stretch trusty wily xenial# python-nose2,
+#sid stretch jessie trusty xenial# python-all (>= 2.6.6-3~), python-all-dev (>= 2.6.6-3~),
+#sid stretch jessie xenial# pyqt4.qsci-dev,
+#sid stretch jessie trusty xenial# python-pyspatialite,
+#sid jessie stretch trusty xenial# python-nose2,
  python-sip (>= 4.5.0),
  python-sip-dev (>= 4.5.0),
  libosgearth-dev,
@@ -67,11 +64,10 @@ Build-Depends:
  libqt4-sql-sqlite, python-psycopg2
 Build-Conflicts: libqgis-dev, qgis-dev
 #sid stretch xenial#Standards-Version: 3.9.7
-#jessie wily#Standards-Version: 3.9.6
-#wheezy#Standards-Version: 3.9.3
+#jessie#Standards-Version: 3.9.6
 #precise trusty#Standards-Version: 3.8.4
 #sid stretch jessie#X-Python-Version: >= 2.7, << 2.8
-#wheezy precise trusty wily xenial#XS-Python-Version: current
+#precise trusty xenial#XS-Python-Version: current
 Vcs-Browser: https://github.com/qgis/QGIS/
 Vcs-Git: https://github.com/qgis/QGIS.git
 Homepage: http://qgis.org/
@@ -244,11 +240,10 @@ Section: libdevel
 Depends:
  grass-dev,
  libexpat1-dev,
-#sid stretch jessie trusty wily xenial# libgdal-dev (>= 1.10.1-0~),
+#sid stretch jessie trusty xenial# libgdal-dev (>= 1.10.1-0~),
 #precise# libgdal-dev (>= 1.9.0) | libgdal1-dev (<< 1.9.0),
-#wheezy# libgdal1-dev,
  libgeos-dev (>= 3.0.0),
-#jessie wheezy precise trusty wily# libgsl0-dev,
+#jessie precise trusty# libgsl0-dev,
 #sid stretch xenial# libgsl-dev,
  libpq-dev,
  libproj-dev,
@@ -383,11 +378,12 @@ Depends:
  python-markupsafe,
  python-pygments,
  python-dateutil,
+ python-requests,
  python-tz,
  python-six,
  python-yaml,
-#stretch sid wily xenial# python-future,
-#sid stretch jessie trusty wily xenial# python-pyspatialite,
+#stretch sid xenial# python-future,
+#sid stretch jessie trusty xenial# python-pyspatialite,
  libqgispython{QGIS_ABI},
  ${shlibs:Depends},
  ${python:Depends},
@@ -395,7 +391,7 @@ Depends:
  ${sip:Depends}
 Provides: ${python:Provides}
 Recommends: liblwgeom-dev
-#wheezy precise#XB-Python-Version: ${python:Versions}
+#precise#XB-Python-Version: ${python:Versions}
 Description: Python bindings to QGIS
  QGIS is a Geographic Information System (GIS) which manages, analyzes and
  display databases of geographic information.
@@ -411,7 +407,7 @@ Depends:
  python-gdal,
  python-matplotlib,
  python-shapely,
- libqgis-customwidgets,
+ libqgis-customwidgets (>= ${source:Version}),
  ${misc:Depends}
 XB-Python-Version: ${python:Versions}
 Description: Python bindings to QGIS - architecture-independent files
diff --git a/debian/libqgis-analysis{QGIS_ABI}.lintian-overrides b/debian/libqgis-analysis{QGIS_ABI}.lintian-overrides
index ead8655..0df4bb6 100644
--- a/debian/libqgis-analysis{QGIS_ABI}.lintian-overrides
+++ b/debian/libqgis-analysis{QGIS_ABI}.lintian-overrides
@@ -1,2 +1,3 @@
 libqgis-analysis{QGIS_ABI}: no-symbols-control-file
 libqgis-analysis{QGIS_ABI}: shlib-calls-exit
+libqgis-analysis{QGIS_ABI}: spelling-error-in-binary usr/lib/libqgis_analysis.so.{QGIS_ABI} normalY normally
diff --git a/debian/libqgis-core{QGIS_ABI}.lintian-overrides b/debian/libqgis-core{QGIS_ABI}.lintian-overrides
index 5adeb61..60d9b9f 100644
--- a/debian/libqgis-core{QGIS_ABI}.lintian-overrides
+++ b/debian/libqgis-core{QGIS_ABI}.lintian-overrides
@@ -1,2 +1,4 @@
 libqgis-core{QGIS_ABI}: shlib-calls-exit usr/lib/libqgis_core.so.{QGIS_ABI}
 libqgis-core{QGIS_ABI}: no-symbols-control-file usr/lib/libqgis_core.so.{QGIS_ABI}
+libqgis-core{QGIS_ABI}: spelling-error-in-binary usr/lib/libqgis_core.so.{QGIS_ABI} naM name
+libqgis-core{QGIS_ABI}: spelling-error-in-binary usr/lib/libqgis_core.so.{QGIS_ABI} orderD ordered
diff --git a/debian/libqgis-customwidgets.lintian-overrides b/debian/libqgis-customwidgets.lintian-overrides
deleted file mode 100644
index 7e6ce08..0000000
--- a/debian/libqgis-customwidgets.lintian-overrides
+++ /dev/null
@@ -1 +0,0 @@
-libqgis-customwidgets: no-symbols-control-file
diff --git a/debian/libqgis-customwidgets.lintian-overrides.in b/debian/libqgis-customwidgets.lintian-overrides.in
new file mode 100644
index 0000000..863d93a
--- /dev/null
+++ b/debian/libqgis-customwidgets.lintian-overrides.in
@@ -0,0 +1,2 @@
+libqgis-customwidgets: no-symbols-control-file
+libqgis-customwidgets: spelling-error-in-binary {QT_PLUGIN_DIR}/designer/libqgis_customwidgets.so.{QGIS_ABI} YUr Your
diff --git a/debian/python-qgis.install.in b/debian/python-qgis.install.in
index 2a77bdd..f01f61c 100644
--- a/debian/python-qgis.install.in
+++ b/debian/python-qgis.install.in
@@ -7,5 +7,5 @@ usr/lib/python*/*-packages/qgis/networkanalysis/*
 usr/lib/python*/*-packages/qgis/PyQt/*
 usr/lib/python*/*-packages/qgis/server/*
 usr/lib/python*/*-packages/qgis/testing/*
-#wheezy precise#usr/lib/python*/*-packages/pyspatialite/*.py
-#wheezy precise#usr/lib/python*/*-packages/pyspatialite/*.so
+#precise#usr/lib/python*/*-packages/pyspatialite/*.py
+#precise#usr/lib/python*/*-packages/pyspatialite/*.so
diff --git a/debian/python-qgis.lintian-overrides.in b/debian/python-qgis.lintian-overrides.in
index df98f72..694dcdd 100644
--- a/debian/python-qgis.lintian-overrides.in
+++ b/debian/python-qgis.lintian-overrides.in
@@ -1 +1,2 @@
 python-qgis: hardening-no-fortify-functions
+python-qgis: spelling-error-in-binary usr/lib/python*/*-packages/qgis/*.so onself oneself
diff --git a/debian/qgis-common.install b/debian/qgis-common.install
index bd60a4a..25ff73b 100644
--- a/debian/qgis-common.install
+++ b/debian/qgis-common.install
@@ -12,8 +12,13 @@ usr/share/qgis/doc/images
 usr/share/qgis/doc/index.html
 usr/share/qgis/doc/news
 usr/share/qgis/doc/news.html
+usr/share/qgis/doc/release-sponsors.html
 usr/share/qgis/doc/style.css
 usr/share/qgis/i18n/*
 usr/share/qgis/images/*
 usr/share/qgis/resources/spatialite.db
 usr/share/qgis/resources/themes/*
+usr/share/pixmaps/
+usr/share/mime/packages/
+usr/share/mimelnk/
+usr/share/icons/hicolor/
diff --git a/debian/qgis-plugin-globe-common.install b/debian/qgis-plugin-globe-common.install
index 085c3bf..127ba65 100644
--- a/debian/qgis-plugin-globe-common.install
+++ b/debian/qgis-plugin-globe-common.install
@@ -1 +1,2 @@
 usr/share/qgis/globe
+usr/include/osgEarthDrivers/feature_qgis
diff --git a/debian/qgis-plugin-globe.install b/debian/qgis-plugin-globe.install
index 4f5797a..a137f9c 100644
--- a/debian/qgis-plugin-globe.install
+++ b/debian/qgis-plugin-globe.install
@@ -1 +1,2 @@
 usr/lib/qgis/plugins/libglobeplugin.so
+usr/lib/libosgdb_osgearth_feature_qgis.so
diff --git a/debian/qgis-plugin-grass.lintian-overrides b/debian/qgis-plugin-grass.lintian-overrides
deleted file mode 100644
index d830446..0000000
--- a/debian/qgis-plugin-grass.lintian-overrides
+++ /dev/null
@@ -1,2 +0,0 @@
-qgis-plugin-grass: package-name-doesnt-match-sonames
-qgis-plugin-grass: no-symbols-control-file
diff --git a/debian/qgis-provider.lintian-overrides b/debian/qgis-provider.lintian-overrides
new file mode 100644
index 0000000..89bd1bb
--- /dev/null
+++ b/debian/qgis-provider.lintian-overrides
@@ -0,0 +1 @@
+qgis: spelling-error-in-binary usr/lib/qgis/qgis_help YUr Your
diff --git a/debian/qgis-providers.install.in b/debian/qgis-providers.install.in
index 3d4d300..7e82c0f 100644
--- a/debian/qgis-providers.install.in
+++ b/debian/qgis-providers.install.in
@@ -17,6 +17,6 @@ usr/lib/qgis/plugins/libvirtuallayerprovider.so
 usr/lib/qgis/plugins/libwcsprovider.so
 usr/lib/qgis/plugins/libwfsprovider.so
 usr/lib/qgis/plugins/libwmsprovider.so
-#sid stretch jessie wheezy trusty wily xenial#usr/lib/qgis/plugins/libarcgismapserverprovider.so
-#sid stretch jessie wheezy trusty wily xenial#usr/lib/qgis/plugins/libarcgisfeatureserverprovider.so
+#sid stretch jessie trusty xenial#usr/lib/qgis/plugins/libarcgismapserverprovider.so
+#sid stretch jessie trusty xenial#usr/lib/qgis/plugins/libarcgisfeatureserverprovider.so
 {QT_PLUGIN_DIR}/sqldrivers/libqsqlspatialite.so
diff --git a/debian/qgis-providers.lintian-overrides b/debian/qgis-providers.lintian-overrides
new file mode 100644
index 0000000..5e600e1
--- /dev/null
+++ b/debian/qgis-providers.lintian-overrides
@@ -0,0 +1,2 @@
+qgis-providers: spelling-error-in-binary usr/lib/qgis/plugins/libdelimitedtextprovider.so AddD Add
+qgis-providers: spelling-error-in-binary usr/lib/qgis/plugins/libpostgresprovider.so theRes there's
diff --git a/debian/qgis.install b/debian/qgis.install
index b452705..9c2b7c4 100644
--- a/debian/qgis.install
+++ b/debian/qgis.install
@@ -15,8 +15,4 @@ usr/lib/qgis/plugins/libtopolplugin.so
 usr/lib/qgis/plugins/libgeometrycheckerplugin.so
 usr/lib/qgis/plugins/libgeometrysnapperplugin.so
 usr/lib/qgis/qgis_help
-usr/share/pixmaps/
-usr/share/applications/
-usr/share/mime/packages/
-usr/share/mimelnk/
-usr/share/icons/hicolor/
+usr/share/applications
diff --git a/debian/qgis.lintian-overrides b/debian/qgis.lintian-overrides
index 72759f0..deda0be 100644
--- a/debian/qgis.lintian-overrides
+++ b/debian/qgis.lintian-overrides
@@ -1,4 +1,2 @@
-# Build uses -D_FORTIFY_SOURCE=2, but hardening-check reports:
-#  Fortify Source functions: no, only unprotected functions found!
-#         unprotected: fgets
-qgis: hardening-no-fortify-functions usr/lib/qgis/qgis_help
+qgis: spelling-error-in-binary usr/bin/qgis.bin YUr Your
+qgis: spelling-error-in-binary usr/lib/qgis/qgis_help YUr Your
diff --git a/debian/rules b/debian/rules
index 560325a..9a2d786 100755
--- a/debian/rules
+++ b/debian/rules
@@ -34,7 +34,7 @@ ifneq (,$(findstring -oracle,$(DISTRIBUTION)))
 	WITH_ORACLE=1
 endif
 
-ifneq ($(DISTRIBUTION),$(findstring $(DISTRIBUTION),"wheezy jessie stretch precise trusty wily xenial"))
+ifneq ($(DISTRIBUTION),$(findstring $(DISTRIBUTION),"jessie stretch precise trusty xenial"))
 	DISTRIBUTION := sid
 endif
 
@@ -68,6 +68,7 @@ CMAKE_OPTS := \
 	-DQGIS_CGIBIN_SUBDIR=/usr/lib/cgi-bin \
 	-DWITH_APIDOC=TRUE \
 	-DGENERATE_QHP=TRUE \
+	-DSUPPRESS_SIP_WARNINGS=TRUE \
 	-DWITH_CUSTOM_WIDGETS=TRUE \
 	-DWITH_INTERNAL_HTTPLIB2=FALSE \
 	-DWITH_INTERNAL_JINJA2=FALSE \
@@ -106,7 +107,7 @@ else
 	CMAKE_OPTS += -DWITH_INTERNAL_NOSE2=FALSE -DWITH_INTERNAL_SIX=FALSE
 endif
 
-ifeq (,$(findstring $(DISTRIBUTION),"stretch sid wily xenial"))
+ifeq (,$(findstring $(DISTRIBUTION),"stretch sid xenial"))
 	CMAKE_OPTS += -DWITH_INTERNAL_FUTURE=TRUE
 else
 	CMAKE_OPTS += -DWITH_INTERNAL_FUTURE=FALSE
@@ -116,7 +117,7 @@ ifneq (,$(WITH_GLOBE))
 	CMAKE_OPTS += -DWITH_GLOBE=TRUE
 endif
 
-ifneq (,$(findstring $(DISTRIBUTION),"wheezy precise"))
+ifneq (,$(findstring $(DISTRIBUTION),"precise"))
 	CMAKE_OPTS += -DWITH_PYSPATIALITE=TRUE
 endif
 
@@ -132,7 +133,7 @@ ifneq (,$(findstring $(DISTRIBUTION),"sid"))
 	CMAKE_OPTS += -DGEOS_LIBRARY=/usr/lib/$(DEB_BUILD_MULTIARCH)/libgeos_c.so
 endif
 
-ifneq (,$(findstring $(DISTRIBUTION),"jessie stretch trusty wily xenial sid"))
+ifneq (,$(findstring $(DISTRIBUTION),"jessie stretch trusty xenial sid"))
 	CMAKE_OPTS += -DPYTHON_LIBRARY=/usr/lib/$(DEB_BUILD_MULTIARCH)/libpython2.7.so
 endif
 
@@ -152,6 +153,10 @@ endif
 		-DORACLE_INCLUDEDIR=$(ORACLE_INCLUDEDIR)
 endif
 
+ifneq (,$(findstring $(DISTRIBUTION),"sid stretch"))
+	CMAKE_OPTS += -DFCGI_LIBRARY=/usr/lib/$(DEB_BUILD_MULTIARCH)/libfcgi.so
+endif
+
 ifneq (,$(findstring $(DISTRIBUTION),"sid stretch jessie"))
 	CMAKE_OPTS += -DSPATIALINDEX_LIBRARY=/usr/lib/$(DEB_BUILD_MULTIARCH)/libspatialindex.so
 endif
@@ -170,7 +175,7 @@ else
 	CMAKE_OPTS += -DENABLE_TESTS=TRUE
 endif
 
-ifneq (,$(findstring $(DISTRIBUTION),"wheezy jessie stretch trusty sid"))
+ifneq (,$(findstring $(DISTRIBUTION),"jessie stretch trusty sid"))
 CPPFLAGS := $(shell dpkg-buildflags --get CPPFLAGS)
 CFLAGS   := $(shell dpkg-buildflags --get CFLAGS) $(CPPFLAGS)
 CXXFLAGS := $(shell dpkg-buildflags --get CXXFLAGS) $(CPPFLAGS)
diff --git a/i18n/qgis_de.ts b/i18n/qgis_de.ts
index e790861..8ec2a1c 100644
--- a/i18n/qgis_de.ts
+++ b/i18n/qgis_de.ts
@@ -20740,8 +20740,8 @@ Nur %1 von %2 Objekten geschrieben.</translation>
     </message>
     <message>
         <location filename="../src/gui/editorwidgets/core/qgssearchwidgetwrapper.cpp" line="73"/>
-        <source>Is not missing (null)</source>
-        <translation>Nicht belegt (NULL)</translation>
+        <source>Is not missing (not null)</source>
+        <translation>Nicht belegt (NOT NULL)</translation>
     </message>
     <message>
         <location filename="../src/gui/editorwidgets/core/qgssearchwidgetwrapper.cpp" line="75"/>
diff --git a/python/core/qgsvectorlayer.sip b/python/core/qgsvectorlayer.sip
index a1784ca..3a5fbbc 100644
--- a/python/core/qgsvectorlayer.sip
+++ b/python/core/qgsvectorlayer.sip
@@ -1317,17 +1317,35 @@ class QgsVectorLayer : QgsMapLayer
     /** Caches joined attributes if required (and not already done) */
     void createJoinCaches();
 
-    /** Returns unique values for column
+    /** Calculates a list of unique values contained within an attribute in the layer. Note that
+     * in some circumstances when unsaved changes are present for the layer then the returned list
+     * may contain outdated values (for instance when the attribute value in a saved feature has
+     * been changed inside the edit buffer then the previous saved value will be included in the
+     * returned list).
      * @param index column index for attribute
      * @param uniqueValues out: result list
-     * @param limit maximum number of values to return (-1 if unlimited)
+     * @param limit maximum number of values to return (or -1 if unlimited)
+     * @see minimumValue()
+     * @see maximumValue()
      */
     void uniqueValues( int index, QList<QVariant> &uniqueValues /Out/, int limit = -1 );
 
-    /** Returns minimum value for an attribute column or invalid variant in case of error */
+    /** Returns the minimum value for an attribute column or an invalid variant in case of error.
+     * Note that in some circumstances when unsaved changes are present for the layer then the
+     * returned value may be outdated (for instance when the attribute value in a saved feature has
+     * been changed inside the edit buffer then the previous saved value may be returned as the minimum).
+     * @see maximumValue()
+     * @see uniqueValues()
+     */
     QVariant minimumValue( int index );
 
-    /** Returns maximum value for an attribute column or invalid variant in case of error */
+    /** Returns the maximum value for an attribute column or an invalid variant in case of error.
+     * Note that in some circumstances when unsaved changes are present for the layer then the
+     * returned value may be outdated (for instance when the attribute value in a saved feature has
+     * been changed inside the edit buffer then the previous saved value may be returned as the maximum).
+     * @see minimumValue()
+     * @see uniqueValues()
+     */
     QVariant maximumValue( int index );
 
     /** Calculates an aggregated value from the layer's features.
diff --git a/python/plugins/processing/algs/gdal/ogr2ogronesidebuffer.py b/python/plugins/processing/algs/gdal/ogr2ogronesidebuffer.py
index de4e459..a16cb51 100644
--- a/python/plugins/processing/algs/gdal/ogr2ogronesidebuffer.py
+++ b/python/plugins/processing/algs/gdal/ogr2ogronesidebuffer.py
@@ -85,7 +85,7 @@ class Ogr2OgrOneSideBuffer(GdalAlgorithm):
         inLayer = self.getParameterValue(self.INPUT_LAYER)
         ogrLayer = ogrConnectionString(inLayer)[1:-1]
         layername = "'" + ogrLayerName(inLayer) + "'"
-        operation = self.OPERATIONLIST[self.getParameterValue(self.OPERATION)]
+        operation = self.getParameterValue(self.OPERATION)
         geometry = unicode(self.getParameterValue(self.GEOMETRY))
         distance = unicode(self.getParameterValue(self.RADIUS))
         leftright = self.LEFTRIGHTLIST[self.getParameterValue(self.LEFTRIGHT)]
@@ -104,12 +104,12 @@ class Ogr2OgrOneSideBuffer(GdalAlgorithm):
         arguments.append(ogrLayer)
         arguments.append(ogrLayerName(inLayer))
         if dissolveall or field != 'None':
-            if operation == 'Single Side Buffer':
+            if operation == 0:
                 arguments.append('-dialect sqlite -sql "SELECT ST_Union(ST_SingleSidedBuffer(')
             else:
                 arguments.append('-dialect sqlite -sql "SELECT ST_Union(ST_OffsetCurve(')
         else:
-            if operation == 'Single Side Buffer':
+            if operation == 0:
                 arguments.append('-dialect sqlite -sql "SELECT ST_SingleSidedBuffer(')
             else:
                 arguments.append('-dialect sqlite -sql "SELECT ST_OffsetCurve(')
@@ -118,14 +118,26 @@ class Ogr2OgrOneSideBuffer(GdalAlgorithm):
         arguments.append(distance)
         if dissolveall or field != 'None':
             if leftright == 'Left':
-                arguments.append(',0)),*')
+                if operation == 0:
+                    arguments.append(',0)),*')
+                else:
+                    arguments.append(')),*')
             else:
-                arguments.append(',1)),*')
+                if operation == 0:
+                    arguments.append(',1)),*')
+                else:
+                    arguments.append(')),*')
         else:
             if leftright == 'Left':
-                arguments.append(',0),*')
+                if operation == 0:
+                    arguments.append(',0),*')
+                else:
+                    arguments.append('),*')
             else:
-                arguments.append(',1),*')
+                if operation == 0:
+                    arguments.append(',1),*')
+                else:
+                    arguments.append('),*')
         arguments.append('FROM')
         arguments.append(layername)
         if field != 'None':
diff --git a/python/plugins/processing/algs/qgis/AddTableField.py b/python/plugins/processing/algs/qgis/AddTableField.py
index 93c7dad..d722eef 100644
--- a/python/plugins/processing/algs/qgis/AddTableField.py
+++ b/python/plugins/processing/algs/qgis/AddTableField.py
@@ -78,11 +78,10 @@ class AddTableField(GeoAlgorithm):
         layer = dataobjects.getObjectFromUri(
             self.getParameterValue(self.INPUT_LAYER))
 
-        provider = layer.dataProvider()
-        fields = provider.fields()
+        fields = layer.fields()
         fields.append(QgsField(fieldName, self.TYPES[fieldType], '',
                                fieldLength, fieldPrecision))
-        writer = output.getVectorWriter(fields, provider.geometryType(),
+        writer = output.getVectorWriter(fields, layer.wkbType(),
                                         layer.crs())
         outFeat = QgsFeature()
         features = vector.features(layer)
diff --git a/python/plugins/processing/algs/qgis/AutoincrementalField.py b/python/plugins/processing/algs/qgis/AutoincrementalField.py
index 4412d80..8ec34a1 100644
--- a/python/plugins/processing/algs/qgis/AutoincrementalField.py
+++ b/python/plugins/processing/algs/qgis/AutoincrementalField.py
@@ -49,10 +49,9 @@ class AutoincrementalField(GeoAlgorithm):
         output = self.getOutputFromName(self.OUTPUT)
         vlayer = \
             dataobjects.getObjectFromUri(self.getParameterValue(self.INPUT))
-        vprovider = vlayer.dataProvider()
-        fields = vprovider.fields()
+        fields = vlayer.fields()
         fields.append(QgsField('AUTO', QVariant.Int))
-        writer = output.getVectorWriter(fields, vprovider.geometryType(),
+        writer = output.getVectorWriter(fields, vlayer.wkbType(),
                                         vlayer.crs())
         outFeat = QgsFeature()
         features = vector.features(vlayer)
diff --git a/python/plugins/processing/algs/qgis/Centroids.py b/python/plugins/processing/algs/qgis/Centroids.py
index 8d5ee99..505f39c 100644
--- a/python/plugins/processing/algs/qgis/Centroids.py
+++ b/python/plugins/processing/algs/qgis/Centroids.py
@@ -63,7 +63,7 @@ class Centroids(GeoAlgorithm):
 
         writer = self.getOutputFromName(
             self.OUTPUT_LAYER).getVectorWriter(
-                layer.pendingFields().toList(),
+                layer.fields(),
                 QGis.WKBPoint,
                 layer.crs())
 
diff --git a/python/plugins/processing/algs/qgis/CheckValidity.py b/python/plugins/processing/algs/qgis/CheckValidity.py
index db5b5e5..1ac8061 100644
--- a/python/plugins/processing/algs/qgis/CheckValidity.py
+++ b/python/plugins/processing/algs/qgis/CheckValidity.py
@@ -97,27 +97,26 @@ class CheckValidity(GeoAlgorithm):
     def doCheck(self, progress):
         layer = dataobjects.getObjectFromUri(
             self.getParameterValue(self.INPUT_LAYER))
-        provider = layer.dataProvider()
 
         settings = QSettings()
         method = int(settings.value(settings_method_key, 1))
 
         valid_ouput = self.getOutputFromName(self.VALID_OUTPUT)
-        valid_fields = layer.pendingFields().toList()
+        valid_fields = layer.fields()
         valid_writer = valid_ouput.getVectorWriter(
             valid_fields,
-            provider.geometryType(),
+            layer.wkbType(),
             layer.crs())
         valid_count = 0
 
         invalid_ouput = self.getOutputFromName(self.INVALID_OUTPUT)
-        invalid_fields = layer.pendingFields().toList() + [
+        invalid_fields = layer.fields().toList() + [
             QgsField(name='_errors',
                      type=QVariant.String,
                      len=255)]
         invalid_writer = invalid_ouput.getVectorWriter(
             invalid_fields,
-            provider.geometryType(),
+            layer.wkbType(),
             layer.crs())
         invalid_count = 0
 
diff --git a/python/plugins/processing/algs/qgis/ConcaveHull.py b/python/plugins/processing/algs/qgis/ConcaveHull.py
index 5279ac1..36df1eb 100644
--- a/python/plugins/processing/algs/qgis/ConcaveHull.py
+++ b/python/plugins/processing/algs/qgis/ConcaveHull.py
@@ -111,7 +111,7 @@ class ConcaveHull(GeoAlgorithm):
         feat = QgsFeature()
         dissolved_layer.getFeatures(QgsFeatureRequest().setFilterFid(0)).nextFeature(feat)
         writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(
-            layer.pendingFields().toList(), QGis.WKBPolygon, layer.crs())
+            layer.fields().toList(), QGis.WKBPolygon, layer.crs())
         geom = feat.geometry()
         if no_multigeom and geom.isMultipart():
             # Only singlepart geometries are allowed
diff --git a/python/plugins/processing/algs/qgis/ConvexHull.py b/python/plugins/processing/algs/qgis/ConvexHull.py
index 0f1a1bc..9627f2d 100644
--- a/python/plugins/processing/algs/qgis/ConvexHull.py
+++ b/python/plugins/processing/algs/qgis/ConvexHull.py
@@ -97,7 +97,7 @@ class ConvexHull(GeoAlgorithm):
                   ]
 
         writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(
-            fields, QGis.WKBPolygon, layer.dataProvider().crs())
+            fields, QGis.WKBPolygon, layer.crs())
 
         outFeat = QgsFeature()
         inGeom = QgsGeometry()
diff --git a/python/plugins/processing/algs/qgis/DensifyGeometries.py b/python/plugins/processing/algs/qgis/DensifyGeometries.py
index bbc9fb4..f19ade8 100644
--- a/python/plugins/processing/algs/qgis/DensifyGeometries.py
+++ b/python/plugins/processing/algs/qgis/DensifyGeometries.py
@@ -112,10 +112,7 @@ class DensifyGeometries(GeoAlgorithm):
 
     def densify(self, polyline, pointsNumber):
         output = []
-        if pointsNumber != 1:
-            multiplier = 1.0 / float(pointsNumber + 1)
-        else:
-            multiplier = 1
+        multiplier = 1.0 / float(pointsNumber + 1)
         for i in xrange(len(polyline) - 1):
             p1 = polyline[i]
             p2 = polyline[i + 1]
diff --git a/python/plugins/processing/algs/qgis/Difference.py b/python/plugins/processing/algs/qgis/Difference.py
index 5ce7525..56f38a1 100644
--- a/python/plugins/processing/algs/qgis/Difference.py
+++ b/python/plugins/processing/algs/qgis/Difference.py
@@ -68,11 +68,11 @@ class Difference(GeoAlgorithm):
             self.getParameterValue(Difference.OVERLAY))
         ignoreInvalid = self.getParameterValue(Difference.IGNORE_INVALID)
 
-        geomType = layerA.dataProvider().geometryType()
+        geomType = layerA.wkbType()
         writer = self.getOutputFromName(
             Difference.OUTPUT).getVectorWriter(layerA.pendingFields(),
                                                geomType,
-                                               layerA.dataProvider().crs())
+                                               layerA.crs())
 
         outFeat = QgsFeature()
         index = vector.spatialindex(layerB)
diff --git a/python/plugins/processing/algs/qgis/Dissolve.py b/python/plugins/processing/algs/qgis/Dissolve.py
index 8154d08..c471553 100644
--- a/python/plugins/processing/algs/qgis/Dissolve.py
+++ b/python/plugins/processing/algs/qgis/Dissolve.py
@@ -70,12 +70,11 @@ class Dissolve(GeoAlgorithm):
         fieldname = self.getParameterValue(Dissolve.FIELD)
         vlayerA = dataobjects.getObjectFromUri(
             self.getParameterValue(Dissolve.INPUT))
-        vproviderA = vlayerA.dataProvider()
         fields = vlayerA.fields()
         writer = self.getOutputFromName(
             Dissolve.OUTPUT).getVectorWriter(fields,
-                                             vproviderA.geometryType(),
-                                             vproviderA.crs())
+                                             vlayerA.wkbType(),
+                                             vlayerA.crs())
         outFeat = QgsFeature()
         features = vector.features(vlayerA)
         total = 100.0 / len(features)
diff --git a/python/plugins/processing/algs/qgis/Eliminate.py b/python/plugins/processing/algs/qgis/Eliminate.py
index 5fa24e4..60e9601 100644
--- a/python/plugins/processing/algs/qgis/Eliminate.py
+++ b/python/plugins/processing/algs/qgis/Eliminate.py
@@ -315,10 +315,9 @@ class Eliminate(GeoAlgorithm):
         # End while
 
         # Create output
-        provider = processLayer.dataProvider()
         output = self.getOutputFromName(self.OUTPUT)
-        writer = output.getVectorWriter(provider.fields(),
-                                        provider.geometryType(), processLayer.crs())
+        writer = output.getVectorWriter(processLayer.fields(),
+                                        processLayer.wkbType(), processLayer.crs())
 
         # Write all features that are left over to output layer
         iterator = processLayer.getFeatures()
diff --git a/python/plugins/processing/algs/qgis/EquivalentNumField.py b/python/plugins/processing/algs/qgis/EquivalentNumField.py
index a60851e..0468b34 100644
--- a/python/plugins/processing/algs/qgis/EquivalentNumField.py
+++ b/python/plugins/processing/algs/qgis/EquivalentNumField.py
@@ -54,11 +54,10 @@ class EquivalentNumField(GeoAlgorithm):
         output = self.getOutputFromName(self.OUTPUT)
         vlayer = dataobjects.getObjectFromUri(
             self.getParameterValue(self.INPUT))
-        vprovider = vlayer.dataProvider()
         fieldindex = vlayer.fieldNameIndex(fieldname)
-        fields = vprovider.fields()
+        fields = vlayer.fields()
         fields.append(QgsField('NUM_FIELD', QVariant.Int))
-        writer = output.getVectorWriter(fields, vprovider.geometryType(),
+        writer = output.getVectorWriter(fields, vlayer.wkbType(),
                                         vlayer.crs())
         outFeat = QgsFeature()
         classes = {}
diff --git a/python/plugins/processing/algs/qgis/Explode.py b/python/plugins/processing/algs/qgis/Explode.py
index a541971..daa35ba 100644
--- a/python/plugins/processing/algs/qgis/Explode.py
+++ b/python/plugins/processing/algs/qgis/Explode.py
@@ -48,8 +48,7 @@ class Explode(GeoAlgorithm):
         vlayer = dataobjects.getObjectFromUri(
             self.getParameterValue(self.INPUT))
         output = self.getOutputFromName(self.OUTPUT)
-        vprovider = vlayer.dataProvider()
-        fields = vprovider.fields()
+        fields = vlayer.fields()
         writer = output.getVectorWriter(fields, QGis.WKBLineString,
                                         vlayer.crs())
         outFeat = QgsFeature()
diff --git a/python/plugins/processing/algs/qgis/ExportGeometryInfo.py b/python/plugins/processing/algs/qgis/ExportGeometryInfo.py
index f5eb74d..ddd21c6 100644
--- a/python/plugins/processing/algs/qgis/ExportGeometryInfo.py
+++ b/python/plugins/processing/algs/qgis/ExportGeometryInfo.py
@@ -89,7 +89,7 @@ class ExportGeometryInfo(GeoAlgorithm):
             fields.append(QgsField(yName, QVariant.Double))
 
         writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(
-            fields.toList(), layer.dataProvider().geometryType(), layer.crs())
+            fields.toList(), layer.wkbType(), layer.crs())
 
         ellips = None
         crs = None
diff --git a/python/plugins/processing/algs/qgis/ExtractByLocation.py b/python/plugins/processing/algs/qgis/ExtractByLocation.py
index 3477ba4..5df9981 100644
--- a/python/plugins/processing/algs/qgis/ExtractByLocation.py
+++ b/python/plugins/processing/algs/qgis/ExtractByLocation.py
@@ -71,7 +71,7 @@ class ExtractByLocation(GeoAlgorithm):
 
         output = self.getOutputFromName(self.OUTPUT)
         writer = output.getVectorWriter(layer.pendingFields(),
-                                        layer.dataProvider().geometryType(), layer.crs())
+                                        layer.wkbType(), layer.crs())
 
         if 'disjoint' in predicates:
             disjoinSet = []
diff --git a/python/plugins/processing/algs/qgis/FieldPyculator.py b/python/plugins/processing/algs/qgis/FieldPyculator.py
index a347759..0f517fc 100644
--- a/python/plugins/processing/algs/qgis/FieldPyculator.py
+++ b/python/plugins/processing/algs/qgis/FieldPyculator.py
@@ -88,11 +88,10 @@ class FieldsPyculator(GeoAlgorithm):
 
         layer = dataobjects.getObjectFromUri(
             self.getParameterValue(self.INPUT_LAYER))
-        provider = layer.dataProvider()
-        fields = provider.fields()
+        fields = layer.fields()
         fields.append(QgsField(fieldName, self.TYPES[fieldType], '',
                                fieldLength, fieldPrecision))
-        writer = output.getVectorWriter(fields, provider.geometryType(),
+        writer = output.getVectorWriter(fields, layer.wkbType(),
                                         layer.crs())
         outFeat = QgsFeature()
         new_ns = {}
@@ -107,7 +106,7 @@ class FieldsPyculator(GeoAlgorithm):
                     self.tr("FieldPyculator code execute error.Global code block can't be executed!\n%s\n%s") % (unicode(sys.exc_info()[0].__name__), unicode(sys.exc_info()[1])))
 
         # Replace all fields tags
-        fields = provider.fields()
+        fields = layer.fields()
         num = 0
         for field in fields:
             field_name = unicode(field.name())
diff --git a/python/plugins/processing/algs/qgis/FieldsCalculator.py b/python/plugins/processing/algs/qgis/FieldsCalculator.py
index 0bddcab..f769566 100644
--- a/python/plugins/processing/algs/qgis/FieldsCalculator.py
+++ b/python/plugins/processing/algs/qgis/FieldsCalculator.py
@@ -94,12 +94,11 @@ class FieldsCalculator(GeoAlgorithm):
             output.value = system.getTempFilenameInTempFolder(
                 output.name + '.' + ext)
 
-        provider = layer.dataProvider()
-        fields = layer.pendingFields()
+        fields = layer.fields()
         if newField:
             fields.append(QgsField(fieldName, fieldType, '', width, precision))
 
-        writer = output.getVectorWriter(fields, provider.geometryType(),
+        writer = output.getVectorWriter(fields, layer.wkbType(),
                                         layer.crs())
 
         exp = QgsExpression(formula)
diff --git a/python/plugins/processing/algs/qgis/FieldsMapper.py b/python/plugins/processing/algs/qgis/FieldsMapper.py
index f7eb85e..d8c9679 100644
--- a/python/plugins/processing/algs/qgis/FieldsMapper.py
+++ b/python/plugins/processing/algs/qgis/FieldsMapper.py
@@ -68,7 +68,6 @@ class FieldsMapper(GeoAlgorithm):
         output = self.getOutputFromName(self.OUTPUT_LAYER)
 
         layer = dataobjects.getObjectFromUri(layer)
-        provider = layer.dataProvider()
         fields = []
         expressions = []
 
@@ -109,7 +108,7 @@ class FieldsMapper(GeoAlgorithm):
             expressions.append(expression)
 
         writer = output.getVectorWriter(fields,
-                                        provider.geometryType(),
+                                        layer.wkbType(),
                                         layer.crs())
 
         # Create output vector layer with new attributes
diff --git a/python/plugins/processing/algs/qgis/Intersection.py b/python/plugins/processing/algs/qgis/Intersection.py
index 76395c3..f774c30 100644
--- a/python/plugins/processing/algs/qgis/Intersection.py
+++ b/python/plugins/processing/algs/qgis/Intersection.py
@@ -73,12 +73,11 @@ class Intersection(GeoAlgorithm):
             self.getParameterValue(self.INPUT))
         vlayerB = dataobjects.getObjectFromUri(
             self.getParameterValue(self.INPUT2))
-        vproviderA = vlayerA.dataProvider()
 
-        geomType = vproviderA.geometryType()
+        geomType = vlayerA.wkbType()
         fields = vector.combineVectorFields(vlayerA, vlayerB)
         writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(fields,
-                                                                     geomType, vproviderA.crs())
+                                                                     geomType, vlayerA.crs())
         outFeat = QgsFeature()
         index = vector.spatialindex(vlayerB)
         selectionA = vector.features(vlayerA)
diff --git a/python/plugins/processing/algs/qgis/JoinAttributes.py b/python/plugins/processing/algs/qgis/JoinAttributes.py
index cb48f1a..e1422d7 100644
--- a/python/plugins/processing/algs/qgis/JoinAttributes.py
+++ b/python/plugins/processing/algs/qgis/JoinAttributes.py
@@ -69,14 +69,13 @@ class JoinAttributes(GeoAlgorithm):
         field2 = self.getParameterValue(self.TABLE_FIELD_2)
 
         layer = dataobjects.getObjectFromUri(input)
-        provider = layer.dataProvider()
         joinField1Index = layer.fieldNameIndex(field)
 
         layer2 = dataobjects.getObjectFromUri(input2)
         joinField2Index = layer2.fieldNameIndex(field2)
 
         outFields = vector.combineVectorFields(layer, layer2)
-        writer = output.getVectorWriter(outFields, provider.geometryType(),
+        writer = output.getVectorWriter(outFields, layer.wkbType(),
                                         layer.crs())
 
         # Cache attributes of Layer 2
diff --git a/python/plugins/processing/algs/qgis/Merge.py b/python/plugins/processing/algs/qgis/Merge.py
index b348a57..760b59a 100644
--- a/python/plugins/processing/algs/qgis/Merge.py
+++ b/python/plugins/processing/algs/qgis/Merge.py
@@ -66,14 +66,14 @@ class Merge(GeoAlgorithm):
             layer = QgsVectorLayer(paths[x], unicode(x), 'ogr')
 
             if (len(layers) > 0):
-                if (layer.dataProvider().geometryType() != layers[0].dataProvider().geometryType()):
+                if (layer.wkbType() != layers[0].wkbType()):
                     raise GeoAlgorithmExecutionException(
                         self.tr('All layers must have same geometry type!'))
 
             layers.append(layer)
             totalFeatureCount += layer.featureCount()
 
-            for sindex, sfield in enumerate(layer.dataProvider().fields()):
+            for sindex, sfield in enumerate(layer.fields()):
                 found = None
                 for dfield in fields:
                     if (dfield.name().upper() == sfield.name().upper()):
@@ -88,12 +88,12 @@ class Merge(GeoAlgorithm):
 
         total = 100.0 / totalFeatureCount
         writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(
-            fields.toList(), layers[0].dataProvider().geometryType(),
+            fields.toList(), layers[0].wkbType(),
             layers[0].crs())
 
         featureCount = 0
         for layer in layers:
-            for feature in layer.dataProvider().getFeatures():
+            for feature in layer.getFeatures():
                 sattributes = feature.attributes()
                 dattributes = []
                 for dindex, dfield in enumerate(fields):
@@ -104,7 +104,7 @@ class Merge(GeoAlgorithm):
                     else:
                         dattribute = ''
 
-                    for sindex, sfield in enumerate(layer.dataProvider().fields()):
+                    for sindex, sfield in enumerate(layer.fields()):
                         if (sfield.name().upper() == dfield.name().upper()):
                             if (sfield.type() != dfield.type()):
                                 raise GeoAlgorithmExecutionException(
diff --git a/python/plugins/processing/algs/qgis/MultipartToSingleparts.py b/python/plugins/processing/algs/qgis/MultipartToSingleparts.py
index 67f19ab..a95b577 100644
--- a/python/plugins/processing/algs/qgis/MultipartToSingleparts.py
+++ b/python/plugins/processing/algs/qgis/MultipartToSingleparts.py
@@ -58,25 +58,27 @@ class MultipartToSingleparts(GeoAlgorithm):
     def processAlgorithm(self, progress):
         layer = dataobjects.getObjectFromUri(self.getParameterValue(self.INPUT))
 
-        geomType = self.multiToSingleGeom(layer.dataProvider().geometryType())
+        geomType = self.multiToSingleGeom(layer.wkbType())
 
         writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(
             layer.pendingFields().toList(), geomType, layer.crs())
 
-        outFeat = QgsFeature()
-        inGeom = QgsGeometry()
-
         features = vector.features(layer)
         total = 100.0 / len(features)
         for current, f in enumerate(features):
-            inGeom = f.geometry()
+            outFeat = QgsFeature()
             attrs = f.attributes()
-
-            geometries = self.extractAsSingle(inGeom)
             outFeat.setAttributes(attrs)
 
-            for g in geometries:
-                outFeat.setGeometry(g)
+            if f.constGeometry():
+                inGeom = QgsGeometry(f.constGeometry())
+                geometries = self.extractAsSingle(inGeom)
+
+                for g in geometries:
+                    outFeat.setGeometry(g)
+                    writer.addFeature(outFeat)
+            else:
+                #input feature with null geometry
                 writer.addFeature(outFeat)
 
             progress.setPercentage(int(current * total))
diff --git a/python/plugins/processing/algs/qgis/OrientedMinimumBoundingBox.py b/python/plugins/processing/algs/qgis/OrientedMinimumBoundingBox.py
index 4f702e2d6..72e5900 100644
--- a/python/plugins/processing/algs/qgis/OrientedMinimumBoundingBox.py
+++ b/python/plugins/processing/algs/qgis/OrientedMinimumBoundingBox.py
@@ -82,11 +82,10 @@ class OrientedMinimumBoundingBox(GeoAlgorithm):
 
     def layerOmmb(self, layer, writer, progress):
         current = 0
-        vprovider = layer.dataProvider()
 
-        fit = vprovider.getFeatures()
+        fit = layer.getFeatures()
         inFeat = QgsFeature()
-        total = 100.0 / vprovider.featureCount()
+        total = 100.0 / layer.featureCount()
         newgeometry = QgsGeometry()
         first = True
         while fit.nextFeature(inFeat):
diff --git a/python/plugins/processing/algs/qgis/PointsDisplacement.py b/python/plugins/processing/algs/qgis/PointsDisplacement.py
index bae5822..c61d480 100644
--- a/python/plugins/processing/algs/qgis/PointsDisplacement.py
+++ b/python/plugins/processing/algs/qgis/PointsDisplacement.py
@@ -62,9 +62,8 @@ class PointsDisplacement(GeoAlgorithm):
 
         layer = dataobjects.getObjectFromUri(self.getParameterValue(self.INPUT_LAYER))
 
-        provider = layer.dataProvider()
-        writer = output.getVectorWriter(provider.fields(),
-                                        provider.geometryType(), provider.crs())
+        writer = output.getVectorWriter(layer.fields(),
+                                        layer.wkbType(), layer.crs())
 
         features = vector.features(layer)
 
diff --git a/python/plugins/processing/algs/qgis/PointsInPolygon.py b/python/plugins/processing/algs/qgis/PointsInPolygon.py
index e11f6e6..d457e9d 100644
--- a/python/plugins/processing/algs/qgis/PointsInPolygon.py
+++ b/python/plugins/processing/algs/qgis/PointsInPolygon.py
@@ -68,15 +68,14 @@ class PointsInPolygon(GeoAlgorithm):
         pointLayer = dataobjects.getObjectFromUri(self.getParameterValue(self.POINTS))
         fieldName = self.getParameterValue(self.FIELD)
 
-        polyProvider = polyLayer.dataProvider()
-        fields = polyProvider.fields()
+        fields = polyLayer.fields()
         fields.append(QgsField(fieldName, QVariant.Int))
 
         (idxCount, fieldList) = vector.findOrCreateField(polyLayer,
-                                                         polyLayer.pendingFields(), fieldName)
+                                                         polyLayer.fields(), fieldName)
 
         writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(
-            fields.toList(), polyProvider.geometryType(), polyProvider.crs())
+            fields.toList(), polyLayer.wkbType(), polyLayer.crs())
 
         spatialIndex = vector.spatialindex(pointLayer)
 
diff --git a/python/plugins/processing/algs/qgis/PointsInPolygonUnique.py b/python/plugins/processing/algs/qgis/PointsInPolygonUnique.py
index 1da6ad0..d0dc350 100644
--- a/python/plugins/processing/algs/qgis/PointsInPolygonUnique.py
+++ b/python/plugins/processing/algs/qgis/PointsInPolygonUnique.py
@@ -62,8 +62,7 @@ class PointsInPolygonUnique(GeoAlgorithm):
         fieldName = self.getParameterValue(self.FIELD)
         classFieldName = self.getParameterValue(self.CLASSFIELD)
 
-        polyProvider = polyLayer.dataProvider()
-        fields = polyProvider.fields()
+        fields = polyLayer.fields()
         fields.append(QgsField(fieldName, QVariant.Int))
 
         classFieldIndex = pointLayer.fieldNameIndex(classFieldName)
@@ -71,7 +70,7 @@ class PointsInPolygonUnique(GeoAlgorithm):
                                                          polyLayer.pendingFields(), fieldName)
 
         writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(
-            fields.toList(), polyProvider.geometryType(), polyProvider.crs())
+            fields.toList(), polyLayer.wkbType(), polyLayer.crs())
 
         spatialIndex = vector.spatialindex(pointLayer)
 
diff --git a/python/plugins/processing/algs/qgis/PointsInPolygonWeighted.py b/python/plugins/processing/algs/qgis/PointsInPolygonWeighted.py
index cb19a22..13ae723 100644
--- a/python/plugins/processing/algs/qgis/PointsInPolygonWeighted.py
+++ b/python/plugins/processing/algs/qgis/PointsInPolygonWeighted.py
@@ -69,15 +69,14 @@ class PointsInPolygonWeighted(GeoAlgorithm):
         fieldName = self.getParameterValue(self.FIELD)
         fieldIdx = pointLayer.fieldNameIndex(self.getParameterValue(self.WEIGHT))
 
-        polyProvider = polyLayer.dataProvider()
-        fields = polyProvider.fields()
+        fields = polyLayer.fields()
         fields.append(QgsField(fieldName, QVariant.Int))
 
         (idxCount, fieldList) = vector.findOrCreateField(polyLayer,
-                                                         polyLayer.pendingFields(), fieldName)
+                                                         polyLayer.fields(), fieldName)
 
         writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(
-            fields.toList(), polyProvider.geometryType(), polyProvider.crs())
+            fields.toList(), polyLayer.wkbType(), polyLayer.crs())
 
         spatialIndex = vector.spatialindex(pointLayer)
 
diff --git a/python/plugins/processing/algs/qgis/PointsLayerFromTable.py b/python/plugins/processing/algs/qgis/PointsLayerFromTable.py
index 07d45e1..4929870 100644
--- a/python/plugins/processing/algs/qgis/PointsLayerFromTable.py
+++ b/python/plugins/processing/algs/qgis/PointsLayerFromTable.py
@@ -63,8 +63,7 @@ class PointsLayerFromTable(GeoAlgorithm):
         source = self.getParameterValue(self.INPUT)
         vlayer = dataobjects.getObjectFromUri(source)
         output = self.getOutputFromName(self.OUTPUT)
-        vprovider = vlayer.dataProvider()
-        fields = vprovider.fields()
+        fields = vlayer.fields()
         writer = output.getVectorWriter(fields, QGis.WKBPoint, self.crs)
         xfieldindex = vlayer.fieldNameIndex(self.getParameterValue(self.XFIELD))
         yfieldindex = vlayer.fieldNameIndex(self.getParameterValue(self.YFIELD))
diff --git a/python/plugins/processing/algs/qgis/PointsToPaths.py b/python/plugins/processing/algs/qgis/PointsToPaths.py
index aaa33cb..8407916 100644
--- a/python/plugins/processing/algs/qgis/PointsToPaths.py
+++ b/python/plugins/processing/algs/qgis/PointsToPaths.py
@@ -81,7 +81,7 @@ class PointsToPaths(GeoAlgorithm):
         fields.append(QgsField('begin', QVariant.String, '', 254, 0))
         fields.append(QgsField('end', QVariant.String, '', 254, 0))
         writer = self.getOutputFromName(self.OUTPUT_LINES).getVectorWriter(
-            fields, QGis.WKBLineString, layer.dataProvider().crs())
+            fields, QGis.WKBLineString, layer.crs())
 
         points = dict()
         features = vector.features(layer)
diff --git a/python/plugins/processing/algs/qgis/Polygonize.py b/python/plugins/processing/algs/qgis/Polygonize.py
index 8334804..18a6900 100644
--- a/python/plugins/processing/algs/qgis/Polygonize.py
+++ b/python/plugins/processing/algs/qgis/Polygonize.py
@@ -60,9 +60,8 @@ class Polygonize(GeoAlgorithm):
     def processAlgorithm(self, progress):
         vlayer = dataobjects.getObjectFromUri(self.getParameterValue(self.INPUT))
         output = self.getOutputFromName(self.OUTPUT)
-        vprovider = vlayer.dataProvider()
         if self.getParameterValue(self.FIELDS):
-            fields = vprovider.fields()
+            fields = vlayer.fields()
         else:
             fields = QgsFields()
         if self.getParameterValue(self.GEOMETRY):
diff --git a/python/plugins/processing/algs/qgis/RandomPointsAlongLines.py b/python/plugins/processing/algs/qgis/RandomPointsAlongLines.py
index f7df447..6dcfb90 100644
--- a/python/plugins/processing/algs/qgis/RandomPointsAlongLines.py
+++ b/python/plugins/processing/algs/qgis/RandomPointsAlongLines.py
@@ -68,7 +68,7 @@ class RandomPointsAlongLines(GeoAlgorithm):
         fields = QgsFields()
         fields.append(QgsField('id', QVariant.Int, '', 10, 0))
         writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(
-            fields, QGis.WKBPoint, layer.dataProvider().crs())
+            fields, QGis.WKBPoint, layer.crs())
 
         nPoints = 0
         nIterations = 0
diff --git a/python/plugins/processing/algs/qgis/RandomPointsLayer.py b/python/plugins/processing/algs/qgis/RandomPointsLayer.py
index 5042533..e661358 100644
--- a/python/plugins/processing/algs/qgis/RandomPointsLayer.py
+++ b/python/plugins/processing/algs/qgis/RandomPointsLayer.py
@@ -77,7 +77,7 @@ class RandomPointsLayer(GeoAlgorithm):
         fields = QgsFields()
         fields.append(QgsField('id', QVariant.Int, '', 10, 0))
         writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(
-            fields, QGis.WKBPoint, layer.dataProvider().crs())
+            fields, QGis.WKBPoint, layer.crs())
 
         nPoints = 0
         nIterations = 0
diff --git a/python/plugins/processing/algs/qgis/RandomPointsPolygonsFixed.py b/python/plugins/processing/algs/qgis/RandomPointsPolygonsFixed.py
index 073f5c2..afe334c 100644
--- a/python/plugins/processing/algs/qgis/RandomPointsPolygonsFixed.py
+++ b/python/plugins/processing/algs/qgis/RandomPointsPolygonsFixed.py
@@ -83,7 +83,7 @@ class RandomPointsPolygonsFixed(GeoAlgorithm):
         fields = QgsFields()
         fields.append(QgsField('id', QVariant.Int, '', 10, 0))
         writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(
-            fields, QGis.WKBPoint, layer.dataProvider().crs())
+            fields, QGis.WKBPoint, layer.crs())
 
         da = QgsDistanceArea()
 
diff --git a/python/plugins/processing/algs/qgis/RandomPointsPolygonsVariable.py b/python/plugins/processing/algs/qgis/RandomPointsPolygonsVariable.py
index d14898a..fe88b9f 100644
--- a/python/plugins/processing/algs/qgis/RandomPointsPolygonsVariable.py
+++ b/python/plugins/processing/algs/qgis/RandomPointsPolygonsVariable.py
@@ -84,7 +84,7 @@ class RandomPointsPolygonsVariable(GeoAlgorithm):
         fields = QgsFields()
         fields.append(QgsField('id', QVariant.Int, '', 10, 0))
         writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(
-            fields, QGis.WKBPoint, layer.dataProvider().crs())
+            fields, QGis.WKBPoint, layer.crs())
 
         da = QgsDistanceArea()
 
diff --git a/python/plugins/processing/algs/qgis/ReverseLineDirection.py b/python/plugins/processing/algs/qgis/ReverseLineDirection.py
index 9b5eefa..c5bf196 100644
--- a/python/plugins/processing/algs/qgis/ReverseLineDirection.py
+++ b/python/plugins/processing/algs/qgis/ReverseLineDirection.py
@@ -49,12 +49,11 @@ class ReverseLineDirection(GeoAlgorithm):
     def processAlgorithm(self, progress):
         layer = dataobjects.getObjectFromUri(
             self.getParameterValue(self.INPUT_LAYER))
-        provider = layer.dataProvider()
 
         writer = self.getOutputFromName(
             self.OUTPUT_LAYER).getVectorWriter(
                 layer.fields().toList(),
-                provider.geometryType(),
+                layer.wkbType(),
                 layer.crs())
 
         outFeat = QgsFeature()
diff --git a/python/plugins/processing/algs/qgis/SaveSelectedFeatures.py b/python/plugins/processing/algs/qgis/SaveSelectedFeatures.py
index 756e870..77a8a58 100644
--- a/python/plugins/processing/algs/qgis/SaveSelectedFeatures.py
+++ b/python/plugins/processing/algs/qgis/SaveSelectedFeatures.py
@@ -52,9 +52,8 @@ class SaveSelectedFeatures(GeoAlgorithm):
 
         vectorLayer = dataobjects.getObjectFromUri(inputFilename)
 
-        provider = vectorLayer.dataProvider()
-        writer = output.getVectorWriter(provider.fields(),
-                                        provider.geometryType(), vectorLayer.crs())
+        writer = output.getVectorWriter(vectorLayer.fields(),
+                                        vectorLayer.wkbType(), vectorLayer.crs())
 
         features = vector.features(vectorLayer)
         total = 100.0 / len(features)
diff --git a/python/plugins/processing/algs/qgis/SinglePartsToMultiparts.py b/python/plugins/processing/algs/qgis/SinglePartsToMultiparts.py
index 37d841d..e563201 100644
--- a/python/plugins/processing/algs/qgis/SinglePartsToMultiparts.py
+++ b/python/plugins/processing/algs/qgis/SinglePartsToMultiparts.py
@@ -64,7 +64,7 @@ class SinglePartsToMultiparts(GeoAlgorithm):
         layer = dataobjects.getObjectFromUri(self.getParameterValue(self.INPUT))
         fieldName = self.getParameterValue(self.FIELD)
 
-        geomType = self.singleToMultiGeom(layer.dataProvider().geometryType())
+        geomType = self.singleToMultiGeom(layer.wkbType())
 
         writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(
             layer.pendingFields().toList(), geomType, layer.crs())
diff --git a/python/plugins/processing/algs/qgis/Smooth.py b/python/plugins/processing/algs/qgis/Smooth.py
index bd9c8f4..45bea2b 100644
--- a/python/plugins/processing/algs/qgis/Smooth.py
+++ b/python/plugins/processing/algs/qgis/Smooth.py
@@ -55,14 +55,13 @@ class Smooth(GeoAlgorithm):
     def processAlgorithm(self, progress):
         layer = dataobjects.getObjectFromUri(
             self.getParameterValue(self.INPUT_LAYER))
-        provider = layer.dataProvider()
         iterations = self.getParameterValue(self.ITERATIONS)
         offset = self.getParameterValue(self.OFFSET)
 
         writer = self.getOutputFromName(
             self.OUTPUT_LAYER).getVectorWriter(
                 layer.fields().toList(),
-                provider.geometryType(),
+                layer.wkbType(),
                 layer.crs())
 
         outFeat = QgsFeature()
diff --git a/python/plugins/processing/algs/qgis/SpatialJoin.py b/python/plugins/processing/algs/qgis/SpatialJoin.py
index edf5d98..056fce6 100644
--- a/python/plugins/processing/algs/qgis/SpatialJoin.py
+++ b/python/plugins/processing/algs/qgis/SpatialJoin.py
@@ -108,11 +108,8 @@ class SpatialJoin(GeoAlgorithm):
 
         sumList = self.getParameterValue(self.STATS).lower().split(',')
 
-        targetProvider = target.dataProvider()
-        joinProvider = join.dataProvider()
-
-        targetFields = targetProvider.fields()
-        joinFields = joinProvider.fields()
+        targetFields = target.fields()
+        joinFields = join.fields()
 
         fieldList = QgsFields()
 
@@ -141,7 +138,7 @@ class SpatialJoin(GeoAlgorithm):
             fields.append(f)
 
         writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(
-            fields, targetProvider.geometryType(), targetProvider.crs())
+            fields, target.wkbType(), target.crs())
 
         outFeat = QgsFeature()
         inFeatB = QgsFeature()
diff --git a/python/plugins/processing/algs/qgis/SumLines.py b/python/plugins/processing/algs/qgis/SumLines.py
index 7048fe6..e26cbb5 100644
--- a/python/plugins/processing/algs/qgis/SumLines.py
+++ b/python/plugins/processing/algs/qgis/SumLines.py
@@ -72,15 +72,13 @@ class SumLines(GeoAlgorithm):
         lengthFieldName = self.getParameterValue(self.LEN_FIELD)
         countFieldName = self.getParameterValue(self.COUNT_FIELD)
 
-        polyProvider = polyLayer.dataProvider()
-
         (idxLength, fieldList) = vector.findOrCreateField(polyLayer,
-                                                          polyLayer.pendingFields(), lengthFieldName)
+                                                          polyLayer.fields(), lengthFieldName)
         (idxCount, fieldList) = vector.findOrCreateField(polyLayer, fieldList,
                                                          countFieldName)
 
         writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(
-            fieldList.toList(), polyProvider.geometryType(), polyProvider.crs())
+            fieldList.toList(), polyLayer.wkbType(), polyLayer.crs())
 
         spatialIndex = vector.spatialindex(lineLayer)
 
diff --git a/python/plugins/processing/algs/qgis/SymmetricalDifference.py b/python/plugins/processing/algs/qgis/SymmetricalDifference.py
index 79f5500..251b8cc 100644
--- a/python/plugins/processing/algs/qgis/SymmetricalDifference.py
+++ b/python/plugins/processing/algs/qgis/SymmetricalDifference.py
@@ -65,13 +65,10 @@ class SymmetricalDifference(GeoAlgorithm):
         layerB = dataobjects.getObjectFromUri(
             self.getParameterValue(self.OVERLAY))
 
-        providerA = layerA.dataProvider()
-        providerB = layerB.dataProvider()
-
-        geomType = providerA.geometryType()
+        geomType = layerA.wkbType()
         fields = vector.combineVectorFields(layerA, layerB)
         writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(
-            fields, geomType, providerA.crs())
+            fields, geomType, layerA.crs())
 
         featB = QgsFeature()
         outFeat = QgsFeature()
@@ -92,7 +89,7 @@ class SymmetricalDifference(GeoAlgorithm):
             attrs = featA.attributes()
             intersects = indexA.intersects(geom.boundingBox())
             for i in intersects:
-                providerB.getFeatures(QgsFeatureRequest().setFilterFid(i)).nextFeature(featB)
+                layerB.getFeatures(QgsFeatureRequest().setFilterFid(i)).nextFeature(featB)
                 tmpGeom = QgsGeometry(featB.geometry())
                 if diffGeom.intersects(tmpGeom):
                     diffGeom = QgsGeometry(diffGeom.difference(tmpGeom))
@@ -117,7 +114,7 @@ class SymmetricalDifference(GeoAlgorithm):
             count += 1
             progress.setPercentage(int(count * total))
 
-        length = len(providerA.fields())
+        length = len(layerA.fields())
 
         for featA in featuresB:
             add = True
@@ -127,7 +124,7 @@ class SymmetricalDifference(GeoAlgorithm):
             attrs = [NULL] * length + attrs
             intersects = indexB.intersects(geom.boundingBox())
             for i in intersects:
-                providerA.getFeatures(QgsFeatureRequest().setFilterFid(i)).nextFeature(featB)
+                layerA.getFeatures(QgsFeatureRequest().setFilterFid(i)).nextFeature(featB)
                 tmpGeom = QgsGeometry(featB.geometry())
                 if diffGeom.intersects(tmpGeom):
                     diffGeom = QgsGeometry(diffGeom.difference(tmpGeom))
diff --git a/python/plugins/processing/algs/qgis/Union.py b/python/plugins/processing/algs/qgis/Union.py
index 84efb35..1fff140 100644
--- a/python/plugins/processing/algs/qgis/Union.py
+++ b/python/plugins/processing/algs/qgis/Union.py
@@ -72,9 +72,7 @@ class Union(GeoAlgorithm):
         vlayerA = dataobjects.getObjectFromUri(self.getParameterValue(Union.INPUT))
         vlayerB = dataobjects.getObjectFromUri(self.getParameterValue(Union.INPUT2))
 
-        vproviderA = vlayerA.dataProvider()
-
-        geomType = vproviderA.geometryType()
+        geomType = vlayerA.wkbType()
         fields = vector.combineVectorFields(vlayerA, vlayerB)
         writer = self.getOutputFromName(Union.OUTPUT).getVectorWriter(fields,
                                                                       geomType, vproviderA.crs())
@@ -175,7 +173,7 @@ class Union(GeoAlgorithm):
                     ProcessingLog.addToLog(ProcessingLog.LOG_INFO,
                                            self.tr('Feature geometry error: One or more output features ignored due to invalid geometry.'))
 
-        length = len(vproviderA.fields())
+        length = len(vlayerA.fields())
         atMapA = [None] * length
 
         featuresA = vector.features(vlayerB)
diff --git a/python/plugins/processing/algs/qgis/VectorSplit.py b/python/plugins/processing/algs/qgis/VectorSplit.py
index 5c6cee7..7659808 100644
--- a/python/plugins/processing/algs/qgis/VectorSplit.py
+++ b/python/plugins/processing/algs/qgis/VectorSplit.py
@@ -71,7 +71,7 @@ class VectorSplit(GeoAlgorithm):
         baseName = os.path.join(directory, '{0}_{1}'.format(layer.name(), fieldName))
 
         fields = layer.pendingFields()
-        crs = layer.dataProvider().crs()
+        crs = layer.crs()
         geomType = layer.wkbType()
 
         total = 100.0 / len(uniqueValues)
diff --git a/python/plugins/processing/algs/qgis/ZonalStatistics.py b/python/plugins/processing/algs/qgis/ZonalStatistics.py
index 4d09e4c..510bae2 100644
--- a/python/plugins/processing/algs/qgis/ZonalStatistics.py
+++ b/python/plugins/processing/algs/qgis/ZonalStatistics.py
@@ -158,7 +158,7 @@ class ZonalStatistics(GeoAlgorithm):
                                                          columnPrefix + 'mode', 21, 6)
 
         writer = self.getOutputFromName(self.OUTPUT_LAYER).getVectorWriter(
-            fields.toList(), layer.dataProvider().geometryType(), layer.crs())
+            fields.toList(), layer.wkbType(), layer.crs())
 
         outFeat = QgsFeature()
 
diff --git a/python/plugins/processing/core/SilentProgress.py b/python/plugins/processing/core/SilentProgress.py
index cff916f..06e5605 100644
--- a/python/plugins/processing/core/SilentProgress.py
+++ b/python/plugins/processing/core/SilentProgress.py
@@ -37,16 +37,16 @@ class SilentProgress(object):
     def setPercentage(self, i):
         pass
 
-    def setInfo(self, _):
+    def setInfo(self, msg):
         pass
 
-    def setCommand(self, _):
+    def setCommand(self, msg):
         pass
 
-    def setDebugInfo(self, _):
+    def setDebugInfo(self, msg):
         pass
 
-    def setConsoleInfo(self, _):
+    def setConsoleInfo(self, msg):
         pass
 
     def close(self):
diff --git a/python/plugins/processing/gui/AlgorithmDialogBase.py b/python/plugins/processing/gui/AlgorithmDialogBase.py
index c4e02db..94775e8 100644
--- a/python/plugins/processing/gui/AlgorithmDialogBase.py
+++ b/python/plugins/processing/gui/AlgorithmDialogBase.py
@@ -171,6 +171,9 @@ class AlgorithmDialogBase(BASE, WIDGET):
         self.setInfo(text, False)
         QCoreApplication.processEvents()
 
+    def error(self, text):
+        self.setInfo(text, error=True)
+
     def setParamValues(self):
         pass
 
diff --git a/python/plugins/processing/gui/GetScriptsAndModels.py b/python/plugins/processing/gui/GetScriptsAndModels.py
index ab686e1..ccd4523 100644
--- a/python/plugins/processing/gui/GetScriptsAndModels.py
+++ b/python/plugins/processing/gui/GetScriptsAndModels.py
@@ -40,12 +40,13 @@ from qgis.utils import iface, show_message_log
 from qgis.core import QgsNetworkAccessManager, QgsMessageLog
 from qgis.gui import QgsMessageBar
 
+from processing.core.alglist import algList
 from processing.gui.ToolboxAction import ToolboxAction
+from processing.gui import Help2Html
+from processing.gui.Help2Html import getDescription, ALG_DESC, ALG_VERSION, ALG_CREATOR
 from processing.script.ScriptUtils import ScriptUtils
 from processing.algs.r.RUtils import RUtils
 from processing.modeler.ModelerUtils import ModelerUtils
-from processing.gui import Help2Html
-from processing.gui.Help2Html import getDescription, ALG_DESC, ALG_VERSION, ALG_CREATOR
 
 pluginPath = os.path.split(os.path.dirname(__file__))[0]
 WIDGET, BASE = uic.loadUiType(
@@ -128,15 +129,15 @@ class GetScriptsAndModelsDialog(BASE, WIDGET):
 
         self.resourceType = resourceType
         if self.resourceType == self.MODELS:
-            self.folder = ModelerUtils.defaultModelsFolder()
+            self.folder = ModelerUtils.modelsFolders()[0]
             self.urlBase = 'https://raw.githubusercontent.com/qgis/QGIS-Processing/master/models/'
             self.icon = QIcon(os.path.join(pluginPath, 'images', 'model.png'))
         elif self.resourceType == self.SCRIPTS:
-            self.folder = ScriptUtils.defaultScriptsFolder()
+            self.folder = ScriptUtils.scriptsFolders()[0]
             self.urlBase = 'https://raw.githubusercontent.com/qgis/QGIS-Processing/master/scripts/'
             self.icon = QIcon(os.path.join(pluginPath, 'images', 'script.png'))
         else:
-            self.folder = RUtils.defaultRScriptsFolder()
+            self.folder = RUtils.RScriptsFolders()[0]
             self.urlBase = 'https://raw.githubusercontent.com/qgis/QGIS-Processing/master/rscripts/'
             self.icon = QIcon(os.path.join(pluginPath, 'images', 'r.svg'))
 
diff --git a/python/plugins/processing/gui/ListMultiselectWidget.py b/python/plugins/processing/gui/ListMultiselectWidget.py
index 3283ee4..f7ca14b 100644
--- a/python/plugins/processing/gui/ListMultiselectWidget.py
+++ b/python/plugins/processing/gui/ListMultiselectWidget.py
@@ -23,7 +23,7 @@ from qgis.PyQt.QtWidgets import (QGroupBox,
                                  QListWidget,
                                  QAbstractItemView)
 from qgis.PyQt.QtGui import QFont
-from qgis.PyQt.QtCore import pyqtSignal
+from qgis.PyQt.QtCore import Qt, QSize, pyqtSignal
 
 
 class ListMultiSelectWidget(QGroupBox):
@@ -163,7 +163,7 @@ class ListMultiSelectWidget(QGroupBox):
         self._set_list_widget_defaults(self.unselected_widget)
         unselected_label = QLabel()
         unselected_label.setText('Unselected')
-        unselected_label.setAlignment(Qt.Qt.AlignCenter)
+        unselected_label.setAlignment(Qt.AlignCenter)
         unselected_label.setFont(italic_font)
         unselected_v_layout = QVBoxLayout()
         unselected_v_layout.addWidget(unselected_label)
@@ -174,7 +174,7 @@ class ListMultiSelectWidget(QGroupBox):
         self._set_list_widget_defaults(self.selected_widget)
         selected_label = QLabel()
         selected_label.setText('Selected')
-        selected_label.setAlignment(Qt.Qt.AlignCenter)
+        selected_label.setAlignment(Qt.AlignCenter)
         selected_label.setFont(italic_font)
         selected_v_layout = QVBoxLayout()
         selected_v_layout.addWidget(selected_label)
@@ -215,7 +215,7 @@ class ListMultiSelectWidget(QGroupBox):
         widget.setDragEnabled(True)
         widget.setDragDropMode(QAbstractItemView.DragDrop)
         widget.setDragDropOverwriteMode(False)
-        widget.setDefaultDropAction(QtCore.Qt.MoveAction)
+        widget.setDefaultDropAction(Qt.MoveAction)
         widget.setSelectionMode(QAbstractItemView.MultiSelection)
 
 
@@ -227,4 +227,4 @@ class SmallQPushButton(QPushButton):
         buttons_size_policy = QSizePolicy(
             QSizePolicy.Fixed, QSizePolicy.Fixed)
         self.setSizePolicy(buttons_size_policy)
-        self.setMaximumSize(QtCore.QSize(30, 30))
+        self.setMaximumSize(QSize(30, 30))
diff --git a/python/plugins/processing/gui/ScriptEditorDialog.py b/python/plugins/processing/gui/ScriptEditorDialog.py
index b178441..6f9fa24 100644
--- a/python/plugins/processing/gui/ScriptEditorDialog.py
+++ b/python/plugins/processing/gui/ScriptEditorDialog.py
@@ -193,10 +193,10 @@ class ScriptEditorDialog(BASE, WIDGET):
                 return
 
         if self.algType == self.SCRIPT_PYTHON:
-            scriptDir = ScriptUtils.defaultScriptsFolder()
+            scriptDir = ScriptUtils.scriptsFolders()[0]
             filterName = self.tr('Python scripts (*.py)')
         elif self.algType == self.SCRIPT_R:
-            scriptDir = RUtils.defaultRScriptsFolder()
+            scriptDir = RUtils.RScriptsFolders()[0]
             filterName = self.tr('Processing R script (*.rsx)')
 
         self.filename = QFileDialog.getOpenFileName(
@@ -224,10 +224,10 @@ class ScriptEditorDialog(BASE, WIDGET):
     def saveScript(self, saveAs):
         if self.filename is None or saveAs:
             if self.algType == self.SCRIPT_PYTHON:
-                scriptDir = ScriptUtils.defaultScriptsFolder()
+                scriptDir = ScriptUtils.scriptsFolders()[0]
                 filterName = self.tr('Python scripts (*.py)')
             elif self.algType == self.SCRIPT_R:
-                scriptDir = RUtils.defaultRScriptsFolder()
+                scriptDir = RUtils.RScriptsFolders()[0]
                 filterName = self.tr('Processing R script (*.rsx)')
 
             self.filename = unicode(QFileDialog.getSaveFileName(self,
diff --git a/python/plugins/processing/modeler/AddModelFromFileAction.py b/python/plugins/processing/modeler/AddModelFromFileAction.py
index 456fe6d..d95a716 100644
--- a/python/plugins/processing/modeler/AddModelFromFileAction.py
+++ b/python/plugins/processing/modeler/AddModelFromFileAction.py
@@ -71,6 +71,6 @@ class AddModelFromFileAction(ToolboxAction):
                                     self.tr('Error reading model', 'AddModelFromFileAction'),
                                     self.tr('Cannot read file', 'AddModelFromFileAction'))
                 return
-            destFilename = os.path.join(ModelerUtils.modelsFolder(), os.path.basename(filename))
+            destFilename = os.path.join(ModelerUtils.modelsFolders()[0], os.path.basename(filename))
             shutil.copyfile(filename, destFilename)
             algList.reloadProvider('model')
diff --git a/python/plugins/processing/modeler/ModelerDialog.py b/python/plugins/processing/modeler/ModelerDialog.py
index ca95279..696d437 100644
--- a/python/plugins/processing/modeler/ModelerDialog.py
+++ b/python/plugins/processing/modeler/ModelerDialog.py
@@ -310,7 +310,7 @@ class ModelerDialog(BASE, WIDGET):
         else:
             filename = unicode(QFileDialog.getSaveFileName(self,
                                                            self.tr('Save Model'),
-                                                           ModelerUtils.defaultModelsFolder(),
+                                                           ModelerUtils.modelsFolders()[0],
                                                            self.tr('Processing models (*.model)')))
             if filename:
                 if not filename.endswith('.model'):
@@ -341,7 +341,7 @@ class ModelerDialog(BASE, WIDGET):
 
     def openModel(self):
         filename = unicode(QFileDialog.getOpenFileName(self,
-                                                       self.tr('Open Model'), ModelerUtils.defaultModelsFolder(),
+                                                       self.tr('Open Model'), ModelerUtils.modelsFolders()[0],
                                                        self.tr('Processing models (*.model *.MODEL)')))
         if filename:
             try:
diff --git a/python/plugins/processing/script/AddScriptFromFileAction.py b/python/plugins/processing/script/AddScriptFromFileAction.py
index 75a9181..64a3123 100644
--- a/python/plugins/processing/script/AddScriptFromFileAction.py
+++ b/python/plugins/processing/script/AddScriptFromFileAction.py
@@ -65,7 +65,7 @@ class AddScriptFromFileAction(ToolboxAction):
                                     self.tr('Error reading script', 'AddScriptFromFileAction'),
                                     self.tr('The selected file does not contain a valid script', 'AddScriptFromFileAction'))
                 return
-            destFilename = os.path.join(ScriptUtils.scriptsFolder(), os.path.basename(filename))
+            destFilename = os.path.join(ScriptUtils.scriptsFolders()[0], os.path.basename(filename))
             with open(destFilename, 'w') as f:
                 f.write(script.script)
             algList.reloadProvider('script')
diff --git a/python/testing/__init__.py b/python/testing/__init__.py
index 1285e75..3e1984a 100644
--- a/python/testing/__init__.py
+++ b/python/testing/__init__.py
@@ -73,7 +73,10 @@ class TestCase(_TestCase):
         except KeyError:
             precision = 14
 
-        for feats in zip(layer_expected.getFeatures(request), layer_result.getFeatures(request)):
+        expected_features = sorted(layer_expected.getFeatures(request), key=lambda f: f.id())
+        result_features = sorted(layer_expected.getFeatures(request), key=lambda f: f.id())
+
+        for feats in zip(expected_features, result_features):
             if feats[0].geometry() is not None:
                 geom0 = feats[0].geometry().geometry().asWkt(precision)
             else:
diff --git a/src/app/qgisapp.cpp b/src/app/qgisapp.cpp
index 0a84300..94f4c2e 100644
--- a/src/app/qgisapp.cpp
+++ b/src/app/qgisapp.cpp
@@ -376,7 +376,7 @@ static void setTitleBarText_( QWidget & qgisApp )
 {
   QString caption = QgisApp::tr( "QGIS " );
 
-  if ( QGis::QGIS_VERSION.endsWith( "Master" ) )
+  if ( QGis::QGIS_RELEASE_NAME == "Master" )
   {
     caption += QString( "%1" ).arg( QGis::QGIS_DEV_VERSION );
   }
@@ -11258,13 +11258,13 @@ void QgisApp::projectChanged( const QDomDocument &doc )
   if ( !prevProjectDir.isNull() )
   {
     QString prev = prevProjectDir;
-    expr = QString( "sys.path.remove('%1'); " ).arg( prev.replace( '\'', "\\'" ) );
+    expr = QString( "sys.path.remove(u'%1'); " ).arg( prev.replace( '\'', "\\'" ) );
   }
 
   prevProjectDir = fi.canonicalPath();
 
   QString prev = prevProjectDir;
-  expr += QString( "sys.path.append('%1')" ).arg( prev.replace( '\'', "\\'" ) );
+  expr += QString( "sys.path.append(u'%1')" ).arg( prev.replace( '\'', "\\'" ) );
 
   QgsPythonRunner::run( expr );
 }
diff --git a/src/app/qgsbookmarks.cpp b/src/app/qgsbookmarks.cpp
index f288c8e..20a3eed 100644
--- a/src/app/qgsbookmarks.cpp
+++ b/src/app/qgsbookmarks.cpp
@@ -38,6 +38,8 @@
 
 QgsBookmarks::QgsBookmarks( QWidget *parent )
     : QgsDockWidget( parent )
+    , mQgisModel( nullptr )
+    , mProjectModel( nullptr )
 {
   setupUi( this );
   restorePosition();
diff --git a/src/app/qgsdxfexportdialog.cpp b/src/app/qgsdxfexportdialog.cpp
index 028fbbb..b67a6ac 100644
--- a/src/app/qgsdxfexportdialog.cpp
+++ b/src/app/qgsdxfexportdialog.cpp
@@ -528,11 +528,13 @@ QList< QPair<QgsVectorLayer *, int> > QgsDxfExportDialog::layers() const
 
 double QgsDxfExportDialog::symbologyScale() const
 {
-  double scale = 1 / mScaleWidget->scale();
+  if ( qgsDoubleNear( mScaleWidget->scale(), 0.0 ) )
+    return 1.0;
+
+  double scale = 1.0 / mScaleWidget->scale();
   if ( qgsDoubleNear( scale, 0.0 ) )
-  {
     return 1.0;
-  }
+
   return scale;
 }
 
diff --git a/src/core/pal/feature.cpp b/src/core/pal/feature.cpp
index 77bb9c2..8473231 100644
--- a/src/core/pal/feature.cpp
+++ b/src/core/pal/feature.cpp
@@ -227,7 +227,7 @@ LabelPosition::Quadrant FeaturePart::quadrantFromOffset() const
   }
 }
 
-int FeaturePart::createCandidatesOverPoint( double x, double y, QList< LabelPosition*>& lPos, double angle, PointSet *mapShape )
+int FeaturePart::createCandidatesOverPoint( double x, double y, QList< LabelPosition*>& lPos, double angle )
 {
   int nbp = 1;
 
@@ -294,9 +294,9 @@ int FeaturePart::createCandidatesOverPoint( double x, double y, QList< LabelPosi
   double lx = x + xdiff;
   double ly = y + ydiff;
 
-  if ( mapShape && type == GEOS_POLYGON && mLF->layer()->fitInPolygonOnly() )
+  if ( mLF->permissibleZonePrepared() )
   {
-    if ( !mapShape->containsLabelCandidate( lx, ly, labelW, labelH, angle ) )
+    if ( !GeomFunction::containsCandidate( mLF->permissibleZonePrepared(), lx, ly, labelW, labelH, angle ) )
     {
       return 0;
     }
@@ -419,10 +419,12 @@ int FeaturePart::createCandidatesAtOrderedPositionsOverPoint( double x, double y
     double labelX = referenceX + deltaX;
     double labelY = referenceY + deltaY;
 
-    lPos << new LabelPosition( i, labelX, labelY, labelWidth, labelHeight, angle, cost, this, false, quadrant );
-
-    //TODO - tweak
-    cost += 0.001;
+    if ( ! mLF->permissibleZonePrepared() || GeomFunction::containsCandidate( mLF->permissibleZonePrepared(), labelX, labelY, labelWidth, labelHeight, angle ) )
+    {
+      lPos << new LabelPosition( i, labelX, labelY, labelWidth, labelHeight, angle, cost, this, false, quadrant );
+      //TODO - tweak
+      cost += 0.001;
+    }
 
     ++i;
   }
@@ -430,7 +432,7 @@ int FeaturePart::createCandidatesAtOrderedPositionsOverPoint( double x, double y
   return lPos.count();
 }
 
-int FeaturePart::createCandidatesAroundPoint( double x, double y, QList< LabelPosition* >& lPos, double angle, PointSet *mapShape )
+int FeaturePart::createCandidatesAroundPoint( double x, double y, QList< LabelPosition* >& lPos, double angle )
 {
   double labelWidth = getLabelWidth();
   double labelHeight = getLabelHeight();
@@ -547,9 +549,9 @@ int FeaturePart::createCandidatesAroundPoint( double x, double y, QList< LabelPo
       cost = 0.0001 + 0.0020 * double( icost ) / double( numberCandidates - 1 );
 
 
-    if ( mapShape && type == GEOS_POLYGON && mLF->layer()->fitInPolygonOnly() )
+    if ( mLF->permissibleZonePrepared() )
     {
-      if ( !mapShape->containsLabelCandidate( labelX, labelY, labelWidth, labelHeight, angle ) )
+      if ( !GeomFunction::containsCandidate( mLF->permissibleZonePrepared(), labelX, labelY, labelWidth, labelHeight, angle ) )
       {
         continue;
       }
@@ -698,17 +700,17 @@ int FeaturePart::createCandidatesAlongLine( QList< LabelPosition* >& lPos, Point
 
       if ( aboveLine )
       {
-        if ( !mLF->layer()->fitInPolygonOnly() || mapShape->containsLabelCandidate( bx + cos( beta ) *distlabel, by + sin( beta ) *distlabel, xrm, yrm, alpha ) )
+        if ( !mLF->permissibleZonePrepared() || GeomFunction::containsCandidate( mLF->permissibleZonePrepared(), bx + cos( beta ) *distlabel, by + sin( beta ) *distlabel, xrm, yrm, alpha ) )
           positions.append( new LabelPosition( i, bx + cos( beta ) *distlabel, by + sin( beta ) *distlabel, xrm, yrm, alpha, cost, this, isRightToLeft ) ); // Line
       }
       if ( belowLine )
       {
-        if ( !mLF->layer()->fitInPolygonOnly() || mapShape->containsLabelCandidate( bx - cos( beta ) *( distlabel + yrm ), by - sin( beta ) *( distlabel + yrm ), xrm, yrm, alpha ) )
+        if ( !mLF->permissibleZonePrepared() || GeomFunction::containsCandidate( mLF->permissibleZonePrepared(), bx - cos( beta ) *( distlabel + yrm ), by - sin( beta ) *( distlabel + yrm ), xrm, yrm, alpha ) )
           positions.append( new LabelPosition( i, bx - cos( beta ) *( distlabel + yrm ), by - sin( beta ) *( distlabel + yrm ), xrm, yrm, alpha, cost, this, isRightToLeft ) );   // Line
       }
       if ( flags & FLAG_ON_LINE )
       {
-        if ( !mLF->layer()->fitInPolygonOnly() || mapShape->containsLabelCandidate( bx - yrm*cos( beta ) / 2, by - yrm*sin( beta ) / 2, xrm, yrm, alpha ) )
+        if ( !mLF->permissibleZonePrepared() || GeomFunction::containsCandidate( mLF->permissibleZonePrepared(), bx - yrm*cos( beta ) / 2, by - yrm*sin( beta ) / 2, xrm, yrm, alpha ) )
           positions.append( new LabelPosition( i, bx - yrm*cos( beta ) / 2, by - yrm*sin( beta ) / 2, xrm, yrm, alpha, cost, this, isRightToLeft ) ); // Line
       }
     }
@@ -879,6 +881,7 @@ LabelPosition* FeaturePart::curvedPlacementAtOffset( PointSet* path_positions, d
       delete slp;
       return nullptr;
     }
+
     // Shift the character downwards since the draw position is specified at the baseline
     // and we're calculating the mean line here
     double dist = 0.9 * li->label_height / 2;
@@ -1047,14 +1050,36 @@ int FeaturePart::createCurvedCandidatesAlongLine( QList< LabelPosition* >& lPos,
 
       // average angle is calculated with respect to periodicity of angles
       double angle_avg = atan2( sin_avg / li->char_num, cos_avg / li->char_num );
-      // displacement
-      if (( !reversed && ( flags & FLAG_ABOVE_LINE ) ) || ( reversed && ( flags & FLAG_BELOW_LINE ) ) )
-        positions.append( _createCurvedCandidate( slp, angle_avg, mLF->distLabel() + li->label_height / 2 ) );
-      if ( flags & FLAG_ON_LINE )
-        positions.append( _createCurvedCandidate( slp, angle_avg, 0 ) );
-      if (( !reversed && ( flags & FLAG_BELOW_LINE ) ) || ( reversed && ( flags & FLAG_ABOVE_LINE ) ) )
-        positions.append( _createCurvedCandidate( slp, angle_avg, -li->label_height / 2 - mLF->distLabel() ) );
+      // displacement - we loop through 3 times, generating above, online then below line placements successively
+      for ( int i = 0; i <= 2; ++i )
+      {
+        LabelPosition* p = nullptr;
+        if ( i == 0 && (( !reversed && ( flags & FLAG_ABOVE_LINE ) ) || ( reversed && ( flags & FLAG_BELOW_LINE ) ) ) )
+          p = _createCurvedCandidate( slp, angle_avg, mLF->distLabel() + li->label_height / 2 );
+        if ( i == 1 && flags & FLAG_ON_LINE )
+          p = _createCurvedCandidate( slp, angle_avg, 0 );
+        if ( i == 2 && (( !reversed && ( flags & FLAG_BELOW_LINE ) ) || ( reversed && ( flags & FLAG_ABOVE_LINE ) ) ) )
+          p = _createCurvedCandidate( slp, angle_avg, -li->label_height / 2 - mLF->distLabel() );
+
+        if ( p && mLF->permissibleZonePrepared() )
+        {
+          bool within = true;
+          LabelPosition* currentPos = p;
+          while ( within && currentPos )
+          {
+            within = GeomFunction::containsCandidate( mLF->permissibleZonePrepared(), currentPos->getX(), currentPos->getY(), currentPos->getWidth(), currentPos->getHeight(), currentPos->getAlpha() );
+            currentPos = currentPos->getNextPart();
+          }
+          if ( !within )
+          {
+            delete p;
+            p = nullptr;
+          }
+        }
 
+        if ( p )
+          positions.append( p );
+      }
       // delete original candidate
       delete slp;
     }
@@ -1144,7 +1169,7 @@ int FeaturePart::createCandidatesForPolygon( QList< LabelPosition*>& lPos, Point
 
     //fit in polygon only mode slows down calculation a lot, so if it's enabled
     //then use a smaller limit for number of iterations
-    int maxTry = mLF->layer()->fitInPolygonOnly() ? 7 : 10;
+    int maxTry = mLF->permissibleZonePrepared() ? 7 : 10;
 
     do
     {
@@ -1158,10 +1183,11 @@ int FeaturePart::createCandidatesForPolygon( QList< LabelPosition*>& lPos, Point
           continue;
         }
 
-        if ( mLF->layer()->arrangement() == QgsPalLayerSettings::Horizontal && mLF->layer()->fitInPolygonOnly() )
+        if ( mLF->layer()->arrangement() == QgsPalLayerSettings::Horizontal && mLF->permissibleZonePrepared() )
         {
           //check width/height of bbox is sufficient for label
-          if ( box->length < labelWidth || box->width < labelHeight )
+          if ( mLF->permissibleZone().boundingBox().width() < labelWidth ||
+               mLF->permissibleZone().boundingBox().height() < labelHeight )
           {
             //no way label can fit in this box, skip it
             continue;
@@ -1249,8 +1275,8 @@ int FeaturePart::createCandidatesForPolygon( QList< LabelPosition*>& lPos, Point
             rx += box->x[0];
             ry += box->y[0];
 
-            bool candidateAcceptable = ( mLF->layer()->fitInPolygonOnly()
-                                         ? mapShape->containsLabelCandidate( rx - dlx, ry - dly, labelWidth, labelHeight, alpha )
+            bool candidateAcceptable = ( mLF->permissibleZonePrepared()
+                                         ? GeomFunction::containsCandidate( mLF->permissibleZonePrepared(), rx - dlx, ry - dly, labelWidth, labelHeight, alpha )
                                          : mapShape->containsPoint( rx, ry ) );
             if ( candidateAcceptable )
             {
@@ -1337,9 +1363,9 @@ int FeaturePart::createCandidates( QList< LabelPosition*>& lPos,
             double cx, cy;
             mapShape->getCentroid( cx, cy, mLF->layer()->centroidInside() );
             if ( mLF->layer()->arrangement() == QgsPalLayerSettings::OverPoint )
-              createCandidatesOverPoint( cx, cy, lPos, angle, mapShape );
+              createCandidatesOverPoint( cx, cy, lPos, angle );
             else
-              createCandidatesAroundPoint( cx, cy, lPos, angle, mapShape );
+              createCandidatesAroundPoint( cx, cy, lPos, angle );
             break;
           case QgsPalLayerSettings::Line:
             createCandidatesAlongLine( lPos, mapShape );
diff --git a/src/core/pal/feature.h b/src/core/pal/feature.h
index eb2b3a6..05adb6f 100644
--- a/src/core/pal/feature.h
+++ b/src/core/pal/feature.h
@@ -132,20 +132,18 @@ namespace pal
        * @param y y coordinate of the point
        * @param lPos pointer to an array of candidates, will be filled by generated candidates
        * @param angle orientation of the label
-       * @param mapShape optional geometry of source polygon
        * @returns the number of generated candidates
        */
-      int createCandidatesAroundPoint( double x, double y, QList<LabelPosition *> &lPos, double angle, PointSet *mapShape = nullptr );
+      int createCandidatesAroundPoint( double x, double y, QList<LabelPosition *> &lPos, double angle );
 
       /** Generate one candidate over or offset the specified point.
        * @param x x coordinate of the point
        * @param y y coordinate of the point
        * @param lPos pointer to an array of candidates, will be filled by generated candidate
        * @param angle orientation of the label
-       * @param mapShape optional geometry of source polygon
        * @returns the number of generated candidates (always 1)
        */
-      int createCandidatesOverPoint( double x, double y, QList<LabelPosition *> &lPos, double angle, PointSet *mapShape = nullptr );
+      int createCandidatesOverPoint( double x, double y, QList<LabelPosition *> &lPos, double angle );
 
       /** Generates candidates following a prioritised list of predefined positions around a point.
        * @param x x coordinate of the point
diff --git a/src/core/pal/geomfunction.cpp b/src/core/pal/geomfunction.cpp
index bdf8c40..623e539 100644
--- a/src/core/pal/geomfunction.cpp
+++ b/src/core/pal/geomfunction.cpp
@@ -31,6 +31,8 @@
 #include "feature.h"
 #include "util.h"
 #include "qgis.h"
+#include "pal.h"
+#include "qgsmessagelog.h"
 
 using namespace pal;
 
@@ -315,6 +317,57 @@ int GeomFunction::reorderPolygon( int nbPoints, double *x, double *y )
   return 0;
 }
 
+bool GeomFunction::containsCandidate( const GEOSPreparedGeometry *geom, double x, double y, double width, double height, double alpha )
+{
+  if ( !geom )
+    return false;
+
+  GEOSContextHandle_t geosctxt = geosContext();
+  GEOSCoordSequence *coord = GEOSCoordSeq_create_r( geosctxt, 5, 2 );
+
+  GEOSCoordSeq_setX_r( geosctxt, coord, 0, x );
+  GEOSCoordSeq_setY_r( geosctxt, coord, 0, y );
+  if ( !qgsDoubleNear( alpha, 0.0 ) )
+  {
+    double beta = alpha + ( M_PI / 2 );
+    double dx1 = cos( alpha ) * width;
+    double dy1 = sin( alpha ) * width;
+    double dx2 = cos( beta ) * height;
+    double dy2 = sin( beta ) * height;
+    GEOSCoordSeq_setX_r( geosctxt, coord, 1, x  + dx1 );
+    GEOSCoordSeq_setY_r( geosctxt, coord, 1, y + dy1 );
+    GEOSCoordSeq_setX_r( geosctxt, coord, 2, x + dx1 + dx2 );
+    GEOSCoordSeq_setY_r( geosctxt, coord, 2, y + dy1 + dy2 );
+    GEOSCoordSeq_setX_r( geosctxt, coord, 3, x + dx2 );
+    GEOSCoordSeq_setY_r( geosctxt, coord, 3, y + dy2 );
+  }
+  else
+  {
+    GEOSCoordSeq_setX_r( geosctxt, coord, 1, x + width );
+    GEOSCoordSeq_setY_r( geosctxt, coord, 1, y );
+    GEOSCoordSeq_setX_r( geosctxt, coord, 2, x + width );
+    GEOSCoordSeq_setY_r( geosctxt, coord, 2, y + height );
+    GEOSCoordSeq_setX_r( geosctxt, coord, 3, x );
+    GEOSCoordSeq_setY_r( geosctxt, coord, 3, y + height );
+  }
+  //close ring
+  GEOSCoordSeq_setX_r( geosctxt, coord, 4, x );
+  GEOSCoordSeq_setY_r( geosctxt, coord, 4, y );
+
+  try
+  {
+    GEOSGeometry* bboxGeos = GEOSGeom_createLinearRing_r( geosctxt, coord );
+    bool result = ( GEOSPreparedContainsProperly_r( geosctxt, geom, bboxGeos ) == 1 );
+    GEOSGeom_destroy_r( geosctxt, bboxGeos );
+    return result;
+  }
+  catch ( GEOSException &e )
+  {
+    QgsMessageLog::logMessage( QObject::tr( "Exception: %1" ).arg( e.what() ), QObject::tr( "GEOS" ) );
+    return false;
+  }
+}
+
 void GeomFunction::findLineCircleIntersection( double cx, double cy, double radius,
     double x1, double y1, double x2, double y2,
     double& xRes, double& yRes )
diff --git a/src/core/pal/geomfunction.h b/src/core/pal/geomfunction.h
index 140ff75..2b745ca 100644
--- a/src/core/pal/geomfunction.h
+++ b/src/core/pal/geomfunction.h
@@ -31,6 +31,7 @@
 #define PAL_GEOM_FUNCTION
 
 #include "util.h"
+#include "qgsgeos.h"
 
 namespace pal
 {
@@ -99,6 +100,17 @@ namespace pal
       //! Reorder points to have cross prod ((x,y)[i], (x,y)[i+1), point) > 0 when point is outside
       static int reorderPolygon( int nbPoints, double *x, double *y );
 
+      /** Returns true if a GEOS prepared geometry totally contains a label candidate.
+       * @param geom GEOS prepared geometry
+       * @param x candidate x
+       * @param y candidate y
+       * @param width candidate width
+       * @param height candidate height
+       * @param alpha candidate angle
+       * @returns true if candidate is totally contained
+       */
+      static bool containsCandidate( const GEOSPreparedGeometry* geom, double x, double y, double width, double height, double alpha );
+
   };
 } //namespace
 
diff --git a/src/core/pal/layer.cpp b/src/core/pal/layer.cpp
index 604d2d1..e00b438 100644
--- a/src/core/pal/layer.cpp
+++ b/src/core/pal/layer.cpp
@@ -49,7 +49,6 @@ Layer::Layer( QgsAbstractLabelProvider* provider, const QString& name, QgsPalLay
     , mLabelLayer( toLabel )
     , mDisplayAll( displayAll )
     , mCentroidInside( false )
-    , mFitInPolygon( false )
     , mArrangement( arrangement )
     , mArrangementFlags( nullptr )
     , mMode( LabelPerFeature )
@@ -427,6 +426,7 @@ void Layer::chopFeaturesAtRepeatDistance()
     double chopInterval = fpart->repeatDistance();
     if ( chopInterval != 0. && GEOSGeomTypeId_r( geosctxt, geom ) == GEOS_LINESTRING )
     {
+      chopInterval *= ceil( fpart->getLabelWidth() / fpart->repeatDistance() );
 
       double bmin[2], bmax[2];
       fpart->getBoundingBox( bmin, bmax );
diff --git a/src/core/pal/layer.h b/src/core/pal/layer.h
index ba24fd4..e31c5d4 100644
--- a/src/core/pal/layer.h
+++ b/src/core/pal/layer.h
@@ -213,21 +213,6 @@ namespace pal
        */
       bool centroidInside() const { return mCentroidInside; }
 
-      /** Sets whether labels which do not fit completely within a polygon feature
-       * are discarded.
-       * @param fitInPolygon set to true to discard labels which do not fit within
-       * polygon features. Set to false to allow labels which partially fall outside
-       * the polygon.
-       * @see fitInPolygonOnly
-       */
-      void setFitInPolygonOnly( bool fitInPolygon ) { mFitInPolygon = fitInPolygon; }
-
-      /** Returns whether labels which do not fit completely within a polygon feature
-       * are discarded.
-       * @see setFitInPolygonOnly
-       */
-      bool fitInPolygonOnly() const { return mFitInPolygon; }
-
       /** Register a feature in the layer.
        *
        * Does not take ownership of the label feature (it is owned by its provider).
@@ -269,7 +254,6 @@ namespace pal
       bool mLabelLayer;
       bool mDisplayAll;
       bool mCentroidInside;
-      bool mFitInPolygon;
 
       /** Optional flags used for some placement methods */
       QgsPalLayerSettings::Placement mArrangement;
diff --git a/src/core/pal/pointset.cpp b/src/core/pal/pointset.cpp
index 2626c3d..a996d77 100644
--- a/src/core/pal/pointset.cpp
+++ b/src/core/pal/pointset.cpp
@@ -289,50 +289,7 @@ bool PointSet::containsPoint( double x, double y ) const
 
 bool PointSet::containsLabelCandidate( double x, double y, double width, double height, double alpha ) const
 {
-  GEOSContextHandle_t geosctxt = geosContext();
-  GEOSCoordSequence *coord = GEOSCoordSeq_create_r( geosctxt, 5, 2 );
-
-  GEOSCoordSeq_setX_r( geosctxt, coord, 0, x );
-  GEOSCoordSeq_setY_r( geosctxt, coord, 0, y );
-  if ( !qgsDoubleNear( alpha, 0.0 ) )
-  {
-    double beta = alpha + ( M_PI / 2 );
-    double dx1 = cos( alpha ) * width;
-    double dy1 = sin( alpha ) * width;
-    double dx2 = cos( beta ) * height;
-    double dy2 = sin( beta ) * height;
-    GEOSCoordSeq_setX_r( geosctxt, coord, 1, x  + dx1 );
-    GEOSCoordSeq_setY_r( geosctxt, coord, 1, y + dy1 );
-    GEOSCoordSeq_setX_r( geosctxt, coord, 2, x + dx1 + dx2 );
-    GEOSCoordSeq_setY_r( geosctxt, coord, 2, y + dy1 + dy2 );
-    GEOSCoordSeq_setX_r( geosctxt, coord, 3, x + dx2 );
-    GEOSCoordSeq_setY_r( geosctxt, coord, 3, y + dy2 );
-  }
-  else
-  {
-    GEOSCoordSeq_setX_r( geosctxt, coord, 1, x + width );
-    GEOSCoordSeq_setY_r( geosctxt, coord, 1, y );
-    GEOSCoordSeq_setX_r( geosctxt, coord, 2, x + width );
-    GEOSCoordSeq_setY_r( geosctxt, coord, 2, y + height );
-    GEOSCoordSeq_setX_r( geosctxt, coord, 3, x );
-    GEOSCoordSeq_setY_r( geosctxt, coord, 3, y + height );
-  }
-  //close ring
-  GEOSCoordSeq_setX_r( geosctxt, coord, 4, x );
-  GEOSCoordSeq_setY_r( geosctxt, coord, 4, y );
-
-  try
-  {
-    GEOSGeometry* bboxGeos = GEOSGeom_createLinearRing_r( geosctxt, coord );
-    bool result = ( GEOSPreparedContainsProperly_r( geosctxt, preparedGeom(), bboxGeos ) == 1 );
-    GEOSGeom_destroy_r( geosctxt, bboxGeos );
-    return result;
-  }
-  catch ( GEOSException &e )
-  {
-    QgsMessageLog::logMessage( QObject::tr( "Exception: %1" ).arg( e.what() ), QObject::tr( "GEOS" ) );
-    return false;
-  }
+  return GeomFunction::containsCandidate( preparedGeom(), x, y, width, height, alpha );
 }
 
 void PointSet::splitPolygons( QLinkedList<PointSet*> &shapes_toProcess,
diff --git a/src/core/qgslabelfeature.cpp b/src/core/qgslabelfeature.cpp
index 4ed75b7..d371b31 100644
--- a/src/core/qgslabelfeature.cpp
+++ b/src/core/qgslabelfeature.cpp
@@ -35,6 +35,7 @@ QgsLabelFeature::QgsLabelFeature( QgsFeatureId id, GEOSGeometry* geometry, QSize
     , mIsObstacle( false )
     , mObstacleFactor( 1 )
     , mInfo( nullptr )
+    , mPermissibleZoneGeosPrepared( nullptr )
 {
 }
 
@@ -46,6 +47,9 @@ QgsLabelFeature::~QgsLabelFeature()
   if ( mObstacleGeometry )
     GEOSGeom_destroy_r( QgsGeometry::getGEOSHandler(), mObstacleGeometry );
 
+  if ( mPermissibleZoneGeosPrepared )
+    GEOSPreparedGeom_destroy_r( QgsGeometry::getGEOSHandler(), mPermissibleZoneGeosPrepared );
+
   delete mInfo;
 }
 
@@ -56,3 +60,23 @@ void QgsLabelFeature::setObstacleGeometry( GEOSGeometry* obstacleGeom )
 
   mObstacleGeometry = obstacleGeom;
 }
+
+void QgsLabelFeature::setPermissibleZone( const QgsGeometry &geometry )
+{
+  mPermissibleZone = geometry;
+
+  if ( mPermissibleZoneGeosPrepared )
+  {
+    GEOSPreparedGeom_destroy_r( QgsGeometry::getGEOSHandler(), mPermissibleZoneGeosPrepared );
+    mPermissibleZoneGeosPrepared = nullptr;
+  }
+
+  if ( mPermissibleZone.isEmpty() )
+    return;
+
+  const GEOSGeometry* zoneGeos = mPermissibleZone.asGeos();
+  if ( !zoneGeos )
+    return;
+
+  mPermissibleZoneGeosPrepared = GEOSPrepare_r( QgsGeometry::getGEOSHandler(), zoneGeos );
+}
diff --git a/src/core/qgslabelfeature.h b/src/core/qgslabelfeature.h
index e2e0441..f99b67a 100644
--- a/src/core/qgslabelfeature.h
+++ b/src/core/qgslabelfeature.h
@@ -107,6 +107,32 @@ class CORE_EXPORT QgsLabelFeature
      */
     GEOSGeometry* obstacleGeometry() const { return mObstacleGeometry; }
 
+    /** Sets the label's permissible zone geometry. If set, the feature's label MUST be fully contained
+     * within this zone, and the feature will not be labeled if no candidates can be generated which
+     * are not contained within the zone.
+     * @param geometry permissible zone geometry. If an invalid QgsGeometry is passed then no zone limit
+     * will be applied to the label candidates (this is the default behaviour).
+     * @note added in QGIS 3.0
+     * @see permissibleZone()
+     */
+    void setPermissibleZone( const QgsGeometry& geometry );
+
+    /** Returns the label's permissible zone geometry. If a valid geometry is returned, the feature's label
+     * MUST be fully contained within this zone, and the feature will not be labeled if no candidates can be
+     * generated which are not contained within the zone.
+     * @note added in QGIS 3.0
+     * @see setPermissibleZone()
+     * @see permissibleZonePrepared()
+     */
+    QgsGeometry permissibleZone() const { return mPermissibleZone; }
+
+    /** Returns a GEOS prepared geometry representing the label's permissibleZone().
+     * @see permissibleZone()
+     * @note added in QGIS 3.0
+     */
+    //TODO - remove when QgsGeometry caches GEOS preparedness
+    const GEOSPreparedGeometry* permissibleZonePrepared() const { return mPermissibleZoneGeosPrepared; }
+
     //! Size of the label (in map units)
     QSizeF size() const { return mSize; }
 
@@ -316,6 +342,8 @@ class CORE_EXPORT QgsLabelFeature
     GEOSGeometry* mGeometry;
     //! Optional geometry to use for label obstacles, if different to mGeometry
     GEOSGeometry* mObstacleGeometry;
+    //! Optional geometry to use for label's permissible zone
+    QgsGeometry mPermissibleZone;
     //! Width and height of the label
     QSizeF mSize;
     //! Visual margin of label contents
@@ -358,6 +386,12 @@ class CORE_EXPORT QgsLabelFeature
     QString mLabelText;
     //! extra information for curved labels (may be null)
     pal::LabelInfo* mInfo;
+
+  private:
+
+    // TODO - not required when QgsGeometry caches geos preparedness
+    const GEOSPreparedGeometry* mPermissibleZoneGeosPrepared;
+
 };
 
 #endif // QGSLABELFEATURE_H
diff --git a/src/core/qgslabelingenginev2.cpp b/src/core/qgslabelingenginev2.cpp
index eaff8c1..5bc40b6 100644
--- a/src/core/qgslabelingenginev2.cpp
+++ b/src/core/qgslabelingenginev2.cpp
@@ -129,9 +129,6 @@ void QgsLabelingEngineV2::processProvider( QgsAbstractLabelProvider* provider, Q
   // set whether location of centroid must be inside of polygons
   l->setCentroidInside( flags.testFlag( QgsAbstractLabelProvider::CentroidMustBeInside ) );
 
-  // set whether labels must fall completely within the polygon
-  l->setFitInPolygonOnly( flags.testFlag( QgsAbstractLabelProvider::FitInPolygonOnly ) );
-
   // set how to show upside-down labels
   pal::Layer::UpsideDownLabels upsdnlabels;
   switch ( provider->upsidedownLabels() )
diff --git a/src/core/qgslabelingenginev2.h b/src/core/qgslabelingenginev2.h
index aadeded..2b1a369 100644
--- a/src/core/qgslabelingenginev2.h
+++ b/src/core/qgslabelingenginev2.h
@@ -57,7 +57,6 @@ class CORE_EXPORT QgsAbstractLabelProvider
       DrawAllLabels           = 1 << 2,  //!< whether all features will be labelled even though overlaps occur
       MergeConnectedLines     = 1 << 3,  //!< whether adjacent lines (with the same label text) should be merged
       CentroidMustBeInside    = 1 << 4,  //!< whether location of centroid must be inside of polygons
-      FitInPolygonOnly        = 1 << 5,  //!< whether labels must fall completely within the polygon
       LabelPerFeaturePart     = 1 << 6,  //!< whether to label each part of multi-part features separately
     };
     Q_DECLARE_FLAGS( Flags, Flag )
diff --git a/src/core/qgspallabeling.cpp b/src/core/qgspallabeling.cpp
index f6dd0e6..6aeba76 100644
--- a/src/core/qgspallabeling.cpp
+++ b/src/core/qgspallabeling.cpp
@@ -2455,6 +2455,20 @@ void QgsPalLayerSettings::registerFeature( QgsFeature& f, QgsRenderContext &cont
     doClip = true;
   }
 
+  // if using fitInPolygonOnly option, generate the permissible zone (must happen before geometry is modified - eg
+  // as a result of using perimeter based labeling and the geometry is converted to a boundary)
+  QgsGeometry permissibleZone;
+  if ( geom->type() == QGis::Polygon && fitInPolygonOnly )
+  {
+    permissibleZone = *geom;
+    if ( QgsPalLabeling::geometryRequiresPreparation( &permissibleZone, context, ct, doClip ? extentGeom : nullptr ) )
+    {
+      QgsGeometry* preparedZone = QgsPalLabeling::prepareGeometry( &permissibleZone, context, ct, doClip ? extentGeom : nullptr );
+      permissibleZone = *preparedZone;
+      delete preparedZone;
+    }
+  }
+
   const GEOSGeometry* geos_geom = nullptr;
   const QgsGeometry* preparedGeom = geom;
   QScopedPointer<QgsGeometry> scopedPreparedGeom;
@@ -2853,6 +2867,7 @@ void QgsPalLayerSettings::registerFeature( QgsFeature& f, QgsRenderContext &cont
   ( *labelFeature )->setAlwaysShow( alwaysShow );
   ( *labelFeature )->setRepeatDistance( repeatDist );
   ( *labelFeature )->setLabelText( labelText );
+  ( *labelFeature )->setPermissibleZone( permissibleZone );
   if ( geosObstacleGeomClone )
   {
     ( *labelFeature )->setObstacleGeometry( geosObstacleGeomClone );
diff --git a/src/core/qgsvectorfilewriter.cpp b/src/core/qgsvectorfilewriter.cpp
index 3f6542e..c44a14f 100644
--- a/src/core/qgsvectorfilewriter.cpp
+++ b/src/core/qgsvectorfilewriter.cpp
@@ -45,6 +45,7 @@
 #include <ogr_srs_api.h>
 #include <cpl_error.h>
 #include <cpl_conv.h>
+#include <gdal.h>
 
 #if defined(GDAL_VERSION_NUM) && GDAL_VERSION_NUM >= 1800
 #define TO8F(x)  (x).toUtf8().constData()
@@ -435,10 +436,16 @@ void QgsVectorFileWriter::init( QString vectorFileName,
         break;
 #else
       case QVariant::LongLong:
-        ogrType = OFTInteger64;
+      {
+        const char* pszDataTypes = GDALGetMetadataItem( poDriver, GDAL_DMD_CREATIONFIELDDATATYPES, NULL );
+        if ( pszDataTypes && strstr( pszDataTypes, "Integer64" ) )
+          ogrType = OFTInteger64;
+        else
+          ogrType = OFTReal;
         ogrWidth = ogrWidth > 0 && ogrWidth <= 20 ? ogrWidth : 20;
         ogrPrecision = 0;
         break;
+      }
 #endif
       case QVariant::String:
         ogrType = OFTString;
diff --git a/src/core/qgsvectorlayer.cpp b/src/core/qgsvectorlayer.cpp
index 6149e59..1071b65 100644
--- a/src/core/qgsvectorlayer.cpp
+++ b/src/core/qgsvectorlayer.cpp
@@ -3156,6 +3156,23 @@ void QgsVectorLayer::uniqueValues( int index, QList<QVariant> &uniqueValues, int
           vals << v.toString();
         }
 
+        QgsFeatureMap added = mEditBuffer->addedFeatures();
+        QMapIterator< QgsFeatureId, QgsFeature > addedIt( added );
+        while ( addedIt.hasNext() && ( limit < 0 || uniqueValues.count() < limit ) )
+        {
+          addedIt.next();
+          QVariant v = addedIt.value().attribute( index );
+          if ( v.isValid() )
+          {
+            QString vs = v.toString();
+            if ( !vals.contains( vs ) )
+            {
+              vals << vs;
+              uniqueValues << v;
+            }
+          }
+        }
+
         QMapIterator< QgsFeatureId, QgsAttributeMap > it( mEditBuffer->changedAttributeValues() );
         while ( it.hasNext() && ( limit < 0 || uniqueValues.count() < limit ) )
         {
@@ -3234,7 +3251,35 @@ QVariant QgsVectorLayer::minimumValue( int index )
       return QVariant();
 
     case QgsFields::OriginProvider: //a provider field
-      return mDataProvider->minimumValue( index );
+    {
+      QVariant min = mDataProvider->minimumValue( index );
+      if ( mEditBuffer )
+      {
+        QgsFeatureMap added = mEditBuffer->addedFeatures();
+        QMapIterator< QgsFeatureId, QgsFeature > addedIt( added );
+        while ( addedIt.hasNext() )
+        {
+          addedIt.next();
+          QVariant v = addedIt.value().attribute( index );
+          if ( v.isValid() && qgsVariantLessThan( v, min ) )
+          {
+            min = v;
+          }
+        }
+
+        QMapIterator< QgsFeatureId, QgsAttributeMap > it( mEditBuffer->changedAttributeValues() );
+        while ( it.hasNext() )
+        {
+          it.next();
+          QVariant v = it.value().value( index );
+          if ( v.isValid() && qgsVariantLessThan( v, min ) )
+          {
+            min = v;
+          }
+        }
+      }
+      return min;
+    }
 
     case QgsFields::OriginEdit:
     {
@@ -3293,7 +3338,35 @@ QVariant QgsVectorLayer::maximumValue( int index )
       return QVariant();
 
     case QgsFields::OriginProvider: //a provider field
-      return mDataProvider->maximumValue( index );
+    {
+      QVariant min = mDataProvider->maximumValue( index );
+      if ( mEditBuffer )
+      {
+        QgsFeatureMap added = mEditBuffer->addedFeatures();
+        QMapIterator< QgsFeatureId, QgsFeature > addedIt( added );
+        while ( addedIt.hasNext() )
+        {
+          addedIt.next();
+          QVariant v = addedIt.value().attribute( index );
+          if ( v.isValid() && qgsVariantGreaterThan( v, min ) )
+          {
+            min = v;
+          }
+        }
+
+        QMapIterator< QgsFeatureId, QgsAttributeMap > it( mEditBuffer->changedAttributeValues() );
+        while ( it.hasNext() )
+        {
+          it.next();
+          QVariant v = it.value().value( index );
+          if ( v.isValid() && qgsVariantGreaterThan( v, min ) )
+          {
+            min = v;
+          }
+        }
+      }
+      return min;
+    }
 
     case QgsFields::OriginEdit:
       // the layer is editable, but in certain cases it can still be avoided going through all features
diff --git a/src/core/qgsvectorlayer.h b/src/core/qgsvectorlayer.h
index 0d7c646..6bad318 100644
--- a/src/core/qgsvectorlayer.h
+++ b/src/core/qgsvectorlayer.h
@@ -1707,17 +1707,35 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer
     /** Caches joined attributes if required (and not already done) */
     void createJoinCaches();
 
-    /** Returns unique values for column
+    /** Calculates a list of unique values contained within an attribute in the layer. Note that
+     * in some circumstances when unsaved changes are present for the layer then the returned list
+     * may contain outdated values (for instance when the attribute value in a saved feature has
+     * been changed inside the edit buffer then the previous saved value will be included in the
+     * returned list).
      * @param index column index for attribute
      * @param uniqueValues out: result list
-     * @param limit maximum number of values to return (-1 if unlimited)
+     * @param limit maximum number of values to return (or -1 if unlimited)
+     * @see minimumValue()
+     * @see maximumValue()
      */
     void uniqueValues( int index, QList<QVariant> &uniqueValues, int limit = -1 );
 
-    /** Returns minimum value for an attribute column or invalid variant in case of error */
+    /** Returns the minimum value for an attribute column or an invalid variant in case of error.
+     * Note that in some circumstances when unsaved changes are present for the layer then the
+     * returned value may be outdated (for instance when the attribute value in a saved feature has
+     * been changed inside the edit buffer then the previous saved value may be returned as the minimum).
+     * @see maximumValue()
+     * @see uniqueValues()
+     */
     QVariant minimumValue( int index );
 
-    /** Returns maximum value for an attribute column or invalid variant in case of error */
+    /** Returns the maximum value for an attribute column or an invalid variant in case of error.
+     * Note that in some circumstances when unsaved changes are present for the layer then the
+     * returned value may be outdated (for instance when the attribute value in a saved feature has
+     * been changed inside the edit buffer then the previous saved value may be returned as the maximum).
+     * @see minimumValue()
+     * @see uniqueValues()
+     */
     QVariant maximumValue( int index );
 
     /** Calculates an aggregated value from the layer's features.
diff --git a/src/core/qgsvectorlayerlabelprovider.cpp b/src/core/qgsvectorlayerlabelprovider.cpp
index 810361a..f5535ad 100644
--- a/src/core/qgsvectorlayerlabelprovider.cpp
+++ b/src/core/qgsvectorlayerlabelprovider.cpp
@@ -101,7 +101,6 @@ void QgsVectorLayerLabelProvider::init()
   if ( mSettings.displayAll ) mFlags |= DrawAllLabels;
   if ( mSettings.mergeLines ) mFlags |= MergeConnectedLines;
   if ( mSettings.centroidInside ) mFlags |= CentroidMustBeInside;
-  if ( mSettings.fitInPolygonOnly ) mFlags |= FitInPolygonOnly;
   if ( mSettings.labelPerPart ) mFlags |= LabelPerFeaturePart;
   mPriority = 1 - mSettings.priority / 10.0; // convert 0..10 --> 1..0
 
diff --git a/src/core/raster/qgscolorrampshader.cpp b/src/core/raster/qgscolorrampshader.cpp
index c8a19fa..bbf996e 100644
--- a/src/core/raster/qgscolorrampshader.cpp
+++ b/src/core/raster/qgscolorrampshader.cpp
@@ -88,6 +88,9 @@ bool QgsColorRampShader::shade( double theValue, int* theReturnRedValue, int* th
   {
     return false;
   }
+  if ( qIsNaN( theValue ) || qIsInf( theValue ) )
+    return false;
+
   int colorRampItemListCount = mColorRampItemList.count();
   int idx;
   if ( !mLUTInitialized )
diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt
index fc352e4..470f1cb 100644
--- a/src/gui/CMakeLists.txt
+++ b/src/gui/CMakeLists.txt
@@ -708,6 +708,25 @@ IF (WITH_TOUCH)
 ENDIF (WITH_TOUCH)
 
 SET(QGIS_GUI_UI_HDRS
+  ${CMAKE_CURRENT_BINARY_DIR}/../ui/ui_qgsauthauthoritieseditor.h
+  ${CMAKE_CURRENT_BINARY_DIR}/../ui/ui_qgsauthcertificateinfo.h
+  ${CMAKE_CURRENT_BINARY_DIR}/../ui/ui_qgsauthcertificatemanager.h
+  ${CMAKE_CURRENT_BINARY_DIR}/../ui/ui_qgsauthconfigedit.h
+  ${CMAKE_CURRENT_BINARY_DIR}/../ui/ui_qgsauthconfigeditor.h
+  ${CMAKE_CURRENT_BINARY_DIR}/../ui/ui_qgsauthconfigidedit.h
+  ${CMAKE_CURRENT_BINARY_DIR}/../ui/ui_qgsauthconfigselect.h
+  ${CMAKE_CURRENT_BINARY_DIR}/../ui/ui_qgsauthconfiguriedit.h
+  ${CMAKE_CURRENT_BINARY_DIR}/../ui/ui_qgsautheditorwidgets.h
+  ${CMAKE_CURRENT_BINARY_DIR}/../ui/ui_qgsauthidentitieseditor.h
+  ${CMAKE_CURRENT_BINARY_DIR}/../ui/ui_qgsauthimportcertdialog.h
+  ${CMAKE_CURRENT_BINARY_DIR}/../ui/ui_qgsauthimportidentitydialog.h
+  ${CMAKE_CURRENT_BINARY_DIR}/../ui/ui_qgsauthmethodplugins.h
+  ${CMAKE_CURRENT_BINARY_DIR}/../ui/ui_qgsauthserverseditor.h
+  ${CMAKE_CURRENT_BINARY_DIR}/../ui/ui_qgsauthsslconfigwidget.h
+  ${CMAKE_CURRENT_BINARY_DIR}/../ui/ui_qgsauthsslerrorsdialog.h
+  ${CMAKE_CURRENT_BINARY_DIR}/../ui/ui_qgsauthsslimportdialog.h
+  ${CMAKE_CURRENT_BINARY_DIR}/../ui/ui_qgsauthsslimporterrors.h
+  ${CMAKE_CURRENT_BINARY_DIR}/../ui/ui_qgsauthtrustedcasdialog.h
   ${CMAKE_CURRENT_BINARY_DIR}/../ui/ui_qgscredentialdialog.h
   ${CMAKE_CURRENT_BINARY_DIR}/../ui/ui_qgsdetaileditemwidgetbase.h
   ${CMAKE_CURRENT_BINARY_DIR}/../ui/ui_qgsexpressionbuilderdialogbase.h
diff --git a/src/gui/attributetable/qgsattributetablemodel.cpp b/src/gui/attributetable/qgsattributetablemodel.cpp
index 78f8b15..454bf42 100644
--- a/src/gui/attributetable/qgsattributetablemodel.cpp
+++ b/src/gui/attributetable/qgsattributetablemodel.cpp
@@ -827,7 +827,7 @@ void QgsAttributeTableModel::prefetchSortData( const QString& expressionString )
     }
     else
     {
-      QVariant sortValue = widgetFactory->representValue( layer(), mSortFieldIndex, widgetConfig, widgetCache, f.attribute( mSortFieldIndex ) );
+      QVariant sortValue = widgetFactory->sortValue( layer(), mSortFieldIndex, widgetConfig, widgetCache, f.attribute( mSortFieldIndex ) );
       mSortCache.insert( f.id(), sortValue );
     }
   }
diff --git a/src/gui/attributetable/qgsfeaturelistview.cpp b/src/gui/attributetable/qgsfeaturelistview.cpp
index 56f185e..17e4f53 100644
--- a/src/gui/attributetable/qgsfeaturelistview.cpp
+++ b/src/gui/attributetable/qgsfeaturelistview.cpp
@@ -258,7 +258,8 @@ void QgsFeatureListView::mouseReleaseEvent( QMouseEvent *event )
   }
   else
   {
-    mFeatureSelectionModel->enableSync( true );
+    if ( mFeatureSelectionModel )
+      mFeatureSelectionModel->enableSync( true );
   }
 }
 
diff --git a/src/gui/editorwidgets/core/qgseditorwidgetwrapper.cpp b/src/gui/editorwidgets/core/qgseditorwidgetwrapper.cpp
index e7d0719..fdb7941 100644
--- a/src/gui/editorwidgets/core/qgseditorwidgetwrapper.cpp
+++ b/src/gui/editorwidgets/core/qgseditorwidgetwrapper.cpp
@@ -142,7 +142,7 @@ void QgsEditorWidgetWrapper::updateConstraint( const QgsFeature &ft )
   {
     if ( !expression.isEmpty() )
     {
-      QString fieldName = ft.fields()->field( mFieldIdx ).name();
+      QString fieldName = layer()->attributeDisplayName( mFieldIdx );
       expression = "( " + expression + " ) AND ( " + fieldName + " IS NOT NULL)";
       description = "( " + description + " ) AND NotNull";
     }
diff --git a/src/gui/editorwidgets/core/qgssearchwidgetwrapper.cpp b/src/gui/editorwidgets/core/qgssearchwidgetwrapper.cpp
index 11b2bbb..58d57f7 100644
--- a/src/gui/editorwidgets/core/qgssearchwidgetwrapper.cpp
+++ b/src/gui/editorwidgets/core/qgssearchwidgetwrapper.cpp
@@ -70,7 +70,7 @@ QString QgsSearchWidgetWrapper::toString( QgsSearchWidgetWrapper::FilterFlag fla
     case IsNull:
       return QObject::tr( "Is missing (null)" );
     case IsNotNull:
-      return QObject::tr( "Is not missing (null)" );
+      return QObject::tr( "Is not missing (not null)" );
     case IsNotBetween:
       return QObject::tr( "Is not between (inclusive)" );
 
diff --git a/src/gui/qgsattributeform.cpp b/src/gui/qgsattributeform.cpp
index aabbdfb..b123c37 100644
--- a/src/gui/qgsattributeform.cpp
+++ b/src/gui/qgsattributeform.cpp
@@ -780,12 +780,13 @@ bool QgsAttributeForm::currentFormFeature( QgsFeature &feature )
 
 void QgsAttributeForm::clearInvalidConstraintsMessage()
 {
+  mInvalidConstraintMessage->hide();
   mInvalidConstraintMessage->clear();
   mInvalidConstraintMessage->setStyleSheet( QString() );
 }
 
-void QgsAttributeForm::displayInvalidConstraintMessage( const QStringList &f,
-    const QStringList &d )
+void QgsAttributeForm::displayInvalidConstraintMessage( const QStringList& f,
+    const QStringList& d )
 {
   clearInvalidConstraintsMessage();
 
@@ -801,6 +802,7 @@ void QgsAttributeForm::displayInvalidConstraintMessage( const QStringList &f,
   QString title = QString( "<img src=\"%1\">     <b>%2:" ).arg( icPath ).arg( tr( "Invalid fields" ) );
   QString msg = QString( "%1</b><ul>%2</ul>" ).arg( title ).arg( descriptions ) ;
 
+  mInvalidConstraintMessage->show();
   mInvalidConstraintMessage->setText( msg );
   mInvalidConstraintMessage->setStyleSheet( "QLabel { background-color : #ffc800; }" );
 }
@@ -888,7 +890,7 @@ void QgsAttributeForm::onUpdatedFields()
 }
 
 void QgsAttributeForm::onConstraintStatusChanged( const QString& constraint,
-    const QString &description, const QString& err, bool ok )
+    const QString& description, const QString& err, bool ok )
 {
   QgsEditorWidgetWrapper* eww = qobject_cast<QgsEditorWidgetWrapper*>( sender() );
   Q_ASSERT( eww );
@@ -919,8 +921,8 @@ void QgsAttributeForm::onConstraintStatusChanged( const QString& constraint,
   }
 }
 
-void QgsAttributeForm::constraintDependencies( QgsEditorWidgetWrapper *w,
-    QList<QgsEditorWidgetWrapper*> &wDeps )
+void QgsAttributeForm::constraintDependencies( QgsEditorWidgetWrapper* w,
+    QList<QgsEditorWidgetWrapper*>& wDeps )
 {
   QString name =  w->field().name();
 
@@ -1048,6 +1050,7 @@ void QgsAttributeForm::init()
   vl->addWidget( mMessageBar );
 
   mInvalidConstraintMessage = new QLabel( this );
+  mInvalidConstraintMessage->hide();
   vl->addWidget( mInvalidConstraintMessage );
 
   setLayout( vl );
@@ -1548,15 +1551,22 @@ QgsAttributeForm::WidgetInfo QgsAttributeForm::createWidgetFromDef( const QgsAtt
       }
       else
       {
-        QScrollArea *scrollArea = new QScrollArea( parent );
+        myContainer = new QWidget();
 
-        myContainer = new QWidget( scrollArea );
+        if ( context.formMode() != QgsAttributeEditorContext::Embed )
+        {
+          QScrollArea *scrollArea = new QScrollArea( parent );
 
-        scrollArea->setWidget( myContainer );
-        scrollArea->setWidgetResizable( true );
-        scrollArea->setFrameShape( QFrame::NoFrame );
+          scrollArea->setWidget( myContainer );
+          scrollArea->setWidgetResizable( true );
+          scrollArea->setFrameShape( QFrame::NoFrame );
 
-        newWidgetInfo.widget = scrollArea;
+          newWidgetInfo.widget = scrollArea;
+        }
+        else
+        {
+          newWidgetInfo.widget = myContainer;
+        }
       }
 
       QGridLayout* gbLayout = new QGridLayout();
diff --git a/src/gui/qgsattributeform.h b/src/gui/qgsattributeform.h
index 23b5a1c..76f96b9 100644
--- a/src/gui/qgsattributeform.h
+++ b/src/gui/qgsattributeform.h
@@ -256,7 +256,7 @@ class GUI_EXPORT QgsAttributeForm : public QWidget
     void onAttributeDeleted( int idx );
     void onUpdatedFields();
     void onConstraintStatusChanged( const QString& constraint,
-                                    const QString &description, const QString& err, bool ok );
+                                    const QString& description, const QString& err, bool ok );
     void preventFeatureRefresh();
     void synchronizeEnabledState();
     void layerSelectionChanged();
@@ -321,13 +321,13 @@ class GUI_EXPORT QgsAttributeForm : public QWidget
 
     //! constraints management
     void updateAllConstaints();
-    void updateConstraints( QgsEditorWidgetWrapper *w );
-    bool currentFormFeature( QgsFeature &feature );
-    bool currentFormValidConstraints( QStringList &invalidFields, QStringList &descriptions );
-    void constraintDependencies( QgsEditorWidgetWrapper *w, QList<QgsEditorWidgetWrapper*> &wDeps );
+    void updateConstraints( QgsEditorWidgetWrapper* w );
+    bool currentFormFeature( QgsFeature& feature );
+    bool currentFormValidConstraints( QStringList& invalidFields, QStringList& descriptions );
+    void constraintDependencies( QgsEditorWidgetWrapper* w, QList<QgsEditorWidgetWrapper*>& wDeps );
     void clearInvalidConstraintsMessage();
-    void displayInvalidConstraintMessage( const QStringList &invalidFields,
-                                          const QStringList &description );
+    void displayInvalidConstraintMessage( const QStringList& invalidFields,
+                                          const QStringList& description );
 
     QgsVectorLayer* mLayer;
     QgsFeature mFeature;
diff --git a/src/gui/raster/qgssinglebandpseudocolorrendererwidget.cpp b/src/gui/raster/qgssinglebandpseudocolorrendererwidget.cpp
index 3064a7c..7466309 100644
--- a/src/gui/raster/qgssinglebandpseudocolorrendererwidget.cpp
+++ b/src/gui/raster/qgssinglebandpseudocolorrendererwidget.cpp
@@ -147,6 +147,7 @@ QgsSingleBandPseudoColorRendererWidget::QgsSingleBandPseudoColorRendererWidget(
   connect( mInvertCheckBox, SIGNAL( stateChanged( int ) ), this, SLOT( on_mClassifyButton_clicked() ) );
   connect( mNumberOfEntriesSpinBox, SIGNAL( valueChanged( int ) ), this, SLOT( on_mClassifyButton_clicked() ) );
   connect( mBandComboBox, SIGNAL( currentIndexChanged( int ) ), this, SLOT( on_mClassifyButton_clicked() ) );
+  connect( mClipCheckBox, SIGNAL( toggled( bool ) ), this, SIGNAL( widgetChanged() ) );
 }
 
 QgsSingleBandPseudoColorRendererWidget::~QgsSingleBandPseudoColorRendererWidget()
@@ -791,6 +792,7 @@ void QgsSingleBandPseudoColorRendererWidget::mColormapTreeWidget_itemEdited( QTr
   {
     mColormapTreeWidget->sortItems( ValueColumn, Qt::AscendingOrder );
     autoLabel();
+    emit widgetChanged();
   }
   else if ( column == LabelColumn )
   {
@@ -873,6 +875,7 @@ void QgsSingleBandPseudoColorRendererWidget::on_mColorInterpolationComboBox_curr
   header->setToolTip( ValueColumn, valueToolTip );
 
   autoLabel();
+  emit widgetChanged();
 }
 
 void QgsSingleBandPseudoColorRendererWidget::loadMinMax( int theBandNo, double theMin, double theMax, int theOrigin )
diff --git a/src/helpviewer/qgshelpviewer.cpp b/src/helpviewer/qgshelpviewer.cpp
index 176613f..e4d39c4 100644
--- a/src/helpviewer/qgshelpviewer.cpp
+++ b/src/helpviewer/qgshelpviewer.cpp
@@ -36,7 +36,7 @@ void QgsReaderThread::run()
   QString help;
 
   char buffer[1024];
-  while ( fgets( buffer, sizeof buffer, stdin ) )
+  while ( fgets( buffer, sizeof buffer - 1, stdin ) )
   {
     if ( strcmp( buffer, "EOH\n" ) == 0 )
     {
diff --git a/src/plugins/dxf2shp_converter/dxflib/src/dl_dxf.cpp b/src/plugins/dxf2shp_converter/dxflib/src/dl_dxf.cpp
index 549c1b1..43b71af 100644
--- a/src/plugins/dxf2shp_converter/dxflib/src/dl_dxf.cpp
+++ b/src/plugins/dxf2shp_converter/dxflib/src/dl_dxf.cpp
@@ -236,7 +236,7 @@ bool DL_Dxf::getStrippedLine(std::string& s, unsigned int size, FILE *fp) {
         // Only the useful part of the line
         char* line;
 
-        line = fgets(wholeLine, size, fp);
+        line = fgets(wholeLine, size-1, fp);
 
         if (line!=nullptr && line[0] != '\0') { // Evaluates to fgets() retval
             // line == wholeLine at this point.
diff --git a/src/providers/grass/qgis.g.info.c b/src/providers/grass/qgis.g.info.c
index d5687d6..088ad48 100644
--- a/src/providers/grass/qgis.g.info.c
+++ b/src/providers/grass/qgis.g.info.c
@@ -217,7 +217,7 @@ int main( int argc, char **argv )
       G_suppress_masking(); // must be after G_set_window()
       fd = G_open_cell_old( rast_opt->answer, "" );
       // wait for coords from stdin
-      while ( fgets( buff, 100, stdin ) != 0 )
+      while ( fgets( buff, sizeof buff - 1, stdin ) != 0 )
       {
         if ( sscanf( buff, "%lf%lf", &x, &y ) != 2 )
         {
diff --git a/src/providers/ogr/qgsogrfeatureiterator.cpp b/src/providers/ogr/qgsogrfeatureiterator.cpp
index 26e8ceb..04a0bc7 100644
--- a/src/providers/ogr/qgsogrfeatureiterator.cpp
+++ b/src/providers/ogr/qgsogrfeatureiterator.cpp
@@ -43,6 +43,8 @@ QgsOgrFeatureIterator::QgsOgrFeatureIterator( QgsOgrFeatureSource* source, bool
     , mSubsetStringSet( false )
     , mFetchGeometry( false )
     , mExpressionCompiled( false )
+    , mFilterFids( mRequest.filterFids() )
+    , mFilterFidsIt( mFilterFids.constBegin() )
 {
   mConn = QgsOgrConnPool::instance()->acquireConnection( mSource->mProvider->dataSourceUri() );
   if ( !mConn->ds )
@@ -166,6 +168,22 @@ bool QgsOgrFeatureIterator::nextFeatureFilterExpression( QgsFeature& f )
     return fetchFeature( f );
 }
 
+bool QgsOgrFeatureIterator::fetchFeatureWithId( QgsFeatureId id, QgsFeature& feature ) const
+{
+  feature.setValid( false );
+  OGRFeatureH fet = OGR_L_GetFeature( ogrLayer, FID_TO_NUMBER( id ) );
+  if ( !fet )
+  {
+    return false;
+  }
+
+  if ( readFeature( fet, feature ) )
+    OGR_F_Destroy( fet );
+
+  feature.setValid( true );
+  return true;
+}
+
 bool QgsOgrFeatureIterator::fetchFeature( QgsFeature& feature )
 {
   feature.setValid( false );
@@ -175,19 +193,22 @@ bool QgsOgrFeatureIterator::fetchFeature( QgsFeature& feature )
 
   if ( mRequest.filterType() == QgsFeatureRequest::FilterFid )
   {
-    OGRFeatureH fet = OGR_L_GetFeature( ogrLayer, FID_TO_NUMBER( mRequest.filterFid() ) );
-    if ( !fet )
+    bool result = fetchFeatureWithId( mRequest.filterFid(), feature );
+    close(); // the feature has been read or was not found: we have finished here
+    return result;
+  }
+  else if ( mRequest.filterType() == QgsFeatureRequest::FilterFids )
+  {
+    while ( mFilterFidsIt != mFilterFids.constEnd() )
     {
-      close();
-      return false;
-    }
-
-    if ( readFeature( fet, feature ) )
-      OGR_F_Destroy( fet );
+      QgsFeatureId nextId = *mFilterFidsIt;
+      mFilterFidsIt++;
 
-    feature.setValid( true );
-    close(); // the feature has been read: we have finished here
-    return true;
+      if ( fetchFeatureWithId( nextId, feature ) )
+        return true;
+    }
+    close();
+    return false;
   }
 
   OGRFeatureH fet;
@@ -220,6 +241,8 @@ bool QgsOgrFeatureIterator::rewind()
 
   OGR_L_ResetReading( ogrLayer );
 
+  mFilterFidsIt = mFilterFids.constBegin();
+
   return true;
 }
 
@@ -246,7 +269,7 @@ bool QgsOgrFeatureIterator::close()
 }
 
 
-void QgsOgrFeatureIterator::getFeatureAttribute( OGRFeatureH ogrFet, QgsFeature & f, int attindex )
+void QgsOgrFeatureIterator::getFeatureAttribute( OGRFeatureH ogrFet, QgsFeature & f, int attindex ) const
 {
   if ( mSource->mFirstFieldIsFid && attindex == 0 )
   {
@@ -264,7 +287,7 @@ void QgsOgrFeatureIterator::getFeatureAttribute( OGRFeatureH ogrFet, QgsFeature
 }
 
 
-bool QgsOgrFeatureIterator::readFeature( OGRFeatureH fet, QgsFeature& feature )
+bool QgsOgrFeatureIterator::readFeature( OGRFeatureH fet, QgsFeature& feature ) const
 {
   feature.setFeatureId( OGR_F_GetFID( fet ) );
   feature.initAttributes( mSource->mFields.count() );
diff --git a/src/providers/ogr/qgsogrfeatureiterator.h b/src/providers/ogr/qgsogrfeatureiterator.h
index 263a0f9..15bb5a7 100644
--- a/src/providers/ogr/qgsogrfeatureiterator.h
+++ b/src/providers/ogr/qgsogrfeatureiterator.h
@@ -68,10 +68,10 @@ class QgsOgrFeatureIterator : public QgsAbstractFeatureIteratorFromSource<QgsOgr
     //! fetch next feature filter expression
     bool nextFeatureFilterExpression( QgsFeature& f ) override;
 
-    bool readFeature( OGRFeatureH fet, QgsFeature& feature );
+    bool readFeature( OGRFeatureH fet, QgsFeature& feature ) const;
 
     //! Get an attribute associated with a feature
-    void getFeatureAttribute( OGRFeatureH ogrFet, QgsFeature & f, int attindex );
+    void getFeatureAttribute( OGRFeatureH ogrFet, QgsFeature & f, int attindex ) const;
 
     bool mFeatureFetched;
 
@@ -85,6 +85,11 @@ class QgsOgrFeatureIterator : public QgsAbstractFeatureIteratorFromSource<QgsOgr
 
   private:
     bool mExpressionCompiled;
+    QgsFeatureIds mFilterFids;
+    QgsFeatureIds::const_iterator mFilterFidsIt;
+
+    bool fetchFeatureWithId( QgsFeatureId id, QgsFeature& feature ) const;
+
 };
 
 #endif // QGSOGRFEATUREITERATOR_H
diff --git a/src/providers/ogr/qgsogrprovider.cpp b/src/providers/ogr/qgsogrprovider.cpp
index c826240..122a52d 100644
--- a/src/providers/ogr/qgsogrprovider.cpp
+++ b/src/providers/ogr/qgsogrprovider.cpp
@@ -1276,6 +1276,8 @@ bool QgsOgrProvider::addAttributes( const QList<QgsField> &attributes )
 
   bool returnvalue = true;
 
+  QMap< QString, QVariant::Type > mapFieldTypesToPatch;
+
   for ( QList<QgsField>::const_iterator iter = attributes.begin(); iter != attributes.end(); ++iter )
   {
     OGRFieldType type;
@@ -1287,8 +1289,17 @@ bool QgsOgrProvider::addAttributes( const QList<QgsField> &attributes )
         break;
 #if defined(GDAL_VERSION_NUM) && GDAL_VERSION_NUM >= 2000000
       case QVariant::LongLong:
-        type = OFTInteger64;
+      {
+        const char* pszDataTypes = GDALGetMetadataItem( ogrDriver, GDAL_DMD_CREATIONFIELDDATATYPES, NULL );
+        if ( pszDataTypes && strstr( pszDataTypes, "Integer64" ) )
+          type = OFTInteger64;
+        else
+        {
+          mapFieldTypesToPatch[ iter->name()] = iter->type();
+          type = OFTReal;
+        }
         break;
+      }
 #endif
       case QVariant::Double:
         type = OFTReal;
@@ -1326,6 +1337,16 @@ bool QgsOgrProvider::addAttributes( const QList<QgsField> &attributes )
     OGR_Fld_Destroy( fielddefn );
   }
   loadFields();
+
+  // Patch field type in case of Integer64->Real mapping so that QVariant::LongLong
+  // is still returned to the caller
+  for ( QMap< QString, QVariant::Type >::const_iterator it = mapFieldTypesToPatch.begin(); it != mapFieldTypesToPatch.end(); ++it )
+  {
+    int idx = mAttributeFields.fieldNameIndex( it.key() );
+    if ( idx >= 0 )
+      mAttributeFields[ idx ].setType( *it );
+  }
+
   return returnvalue;
 }
 
diff --git a/src/providers/wfs/qgswfscapabilities.cpp b/src/providers/wfs/qgswfscapabilities.cpp
index e3349d4..ec83cd2 100644
--- a/src/providers/wfs/qgswfscapabilities.cpp
+++ b/src/providers/wfs/qgswfscapabilities.cpp
@@ -26,7 +26,7 @@
 #include <QSettings>
 #include <QStringList>
 
-QgsWFSCapabilities::QgsWFSCapabilities( const QString& theUri )
+QgsWFSCapabilities::QgsWFSCapabilities( const QString &theUri )
     : QgsWFSRequest( theUri )
 {
   connect( this, SIGNAL( downloadFinished() ), this, SLOT( capabilitiesReplyFinished() ) );
diff --git a/src/providers/wfs/qgswfsconstants.cpp b/src/providers/wfs/qgswfsconstants.cpp
index 380e5f0..2aecf3e 100644
--- a/src/providers/wfs/qgswfsconstants.cpp
+++ b/src/providers/wfs/qgswfsconstants.cpp
@@ -23,11 +23,13 @@ const QString QgsWFSConstants::XMLSCHEMA_NAMESPACE( "http://www.w3.org/2001/XMLS
 
 const QString QgsWFSConstants::URI_PARAM_URL( "url" );
 const QString QgsWFSConstants::URI_PARAM_USERNAME( "username" );
+const QString QgsWFSConstants::URI_PARAM_USER( "user" );
 const QString QgsWFSConstants::URI_PARAM_PASSWORD( "password" );
 const QString QgsWFSConstants::URI_PARAM_AUTHCFG( "authcfg" );
 const QString QgsWFSConstants::URI_PARAM_VERSION( "version" );
 const QString QgsWFSConstants::URI_PARAM_TYPENAME( "typename" );
 const QString QgsWFSConstants::URI_PARAM_SRSNAME( "srsname" );
+const QString QgsWFSConstants::URI_PARAM_BBOX( "bbox" );
 const QString QgsWFSConstants::URI_PARAM_FILTER( "filter" );
 const QString QgsWFSConstants::URI_PARAM_RESTRICT_TO_REQUEST_BBOX( "retrictToRequestBBOX" );
 const QString QgsWFSConstants::URI_PARAM_MAXNUMFEATURES( "maxNumFeatures" );
diff --git a/src/providers/wfs/qgswfsconstants.h b/src/providers/wfs/qgswfsconstants.h
index 3011a34..23345ac 100644
--- a/src/providers/wfs/qgswfsconstants.h
+++ b/src/providers/wfs/qgswfsconstants.h
@@ -29,12 +29,16 @@ struct QgsWFSConstants
   // URI parameters
   static const QString URI_PARAM_URL;
   static const QString URI_PARAM_USERNAME;
+  // QgsDataSourceURI recognizes "user" instead of "username"
+  // we are going to check both
+  static const QString URI_PARAM_USER;
   static const QString URI_PARAM_PASSWORD;
   static const QString URI_PARAM_AUTHCFG;
   static const QString URI_PARAM_VERSION;
   static const QString URI_PARAM_TYPENAME;
   static const QString URI_PARAM_SRSNAME;
   static const QString URI_PARAM_FILTER;
+  static const QString URI_PARAM_BBOX;
   static const QString URI_PARAM_RESTRICT_TO_REQUEST_BBOX;
   static const QString URI_PARAM_MAXNUMFEATURES;
   static const QString URI_PARAM_IGNOREAXISORIENTATION;
diff --git a/src/providers/wfs/qgswfsdatasourceuri.cpp b/src/providers/wfs/qgswfsdatasourceuri.cpp
index 735051c..337563b 100644
--- a/src/providers/wfs/qgswfsdatasourceuri.cpp
+++ b/src/providers/wfs/qgswfsdatasourceuri.cpp
@@ -13,6 +13,8 @@
  *                                                                         *
  ***************************************************************************/
 
+#include "QtGlobal"
+
 #include "qgswfsconstants.h"
 #include "qgswfsdatasourceuri.h"
 #include "qgsmessagelog.h"
@@ -25,11 +27,26 @@ QgsWFSDataSourceURI::QgsWFSDataSourceURI( const QString& uri )
   if ( !mURI.hasParam( QgsWFSConstants::URI_PARAM_URL ) )
   {
     QUrl url( uri );
-    QString srsname = url.queryItemValue( "SRSNAME" );
-    QString bbox = url.queryItemValue( "BBOX" );
-    QString typeName = url.queryItemValue( "TYPENAME" );
-    QString filter = url.queryItemValue( "FILTER" );
+    // Transform all param keys to lowercase
+    typedef QPair<QString, QString> queryItem;
+    QList<queryItem> items( url.queryItems() );
+    foreach ( queryItem item, items )
+    {
+      url.removeQueryItem( item.first );
+      url.addQueryItem( item.first.toLower(), item.second );
+    }
+
+    QString srsname = url.queryItemValue( QgsWFSConstants::URI_PARAM_SRSNAME );
+    QString bbox = url.queryItemValue( QgsWFSConstants::URI_PARAM_BBOX );
+    QString typeName = url.queryItemValue( QgsWFSConstants::URI_PARAM_TYPENAME );
+    QString version = url.queryItemValue( QgsWFSConstants::URI_PARAM_VERSION );
+    QString filter = url.queryItemValue( QgsWFSConstants::URI_PARAM_FILTER );
     mAuth.mUserName = url.queryItemValue( QgsWFSConstants::URI_PARAM_USERNAME );
+    // In QgsDataSourceURI, the "username" param is named "user", check it
+    if ( mAuth.mUserName.isEmpty() )
+    {
+      mAuth.mUserName = url.queryItemValue( QgsWFSConstants::URI_PARAM_USER );
+    }
     mAuth.mPassword = url.queryItemValue( QgsWFSConstants::URI_PARAM_PASSWORD );
     mAuth.mAuthCfg = url.queryItemValue( QgsWFSConstants::URI_PARAM_AUTHCFG );
 
@@ -49,6 +66,7 @@ QgsWFSDataSourceURI::QgsWFSDataSourceURI( const QString& uri )
     mURI.setParam( QgsWFSConstants::URI_PARAM_URL, url.toEncoded() );
     setTypeName( typeName );
     setSRSName( srsname );
+    setVersion( version );
 
     //if the xml comes from the dialog, it needs to be a string to pass the validity test
     if ( filter.startsWith( '\'' ) && filter.endsWith( '\'' ) && filter.size() > 1 )
@@ -63,17 +81,32 @@ QgsWFSDataSourceURI::QgsWFSDataSourceURI( const QString& uri )
   }
   else
   {
-    mAuth.mUserName = mURI.param( QgsWFSConstants::URI_PARAM_USERNAME );
-    mAuth.mPassword = mURI.param( QgsWFSConstants::URI_PARAM_PASSWORD );
-    mAuth.mAuthCfg = mURI.param( QgsWFSConstants::URI_PARAM_AUTHCFG );
+    mAuth.mUserName = mURI.username();
+    mAuth.mPassword = mURI.password();
+    mAuth.mAuthCfg = mURI.authConfigId();
   }
 }
 
-QString QgsWFSDataSourceURI::uri()
+const QString QgsWFSDataSourceURI::uri( bool expandAuthConfig ) const
 {
-  return mURI.uri();
+  QgsDataSourceURI theURI( mURI );
+  // Add auth params back into the uri
+  if ( ! mAuth.mAuthCfg.isEmpty() )
+  {
+    theURI.setAuthConfigId( mAuth.mAuthCfg );
+  }
+  if ( ! mAuth.mUserName.isEmpty() )
+  {
+    theURI.setUsername( mAuth.mUserName );
+  }
+  if ( ! mAuth.mPassword.isEmpty() )
+  {
+    theURI.setPassword( mAuth.mPassword );
+  }
+  return theURI.uri( expandAuthConfig );
 }
 
+
 QUrl QgsWFSDataSourceURI::baseURL( bool bIncludeServiceWFS ) const
 {
   QUrl url( mURI.param( QgsWFSConstants::URI_PARAM_URL ) );
@@ -122,6 +155,13 @@ void QgsWFSDataSourceURI::setSRSName( const QString& crsString )
     mURI.setParam( QgsWFSConstants::URI_PARAM_SRSNAME, crsString );
 }
 
+void QgsWFSDataSourceURI::setVersion( const QString& versionString )
+{
+  mURI.removeParam( QgsWFSConstants::URI_PARAM_VERSION );
+  if ( !versionString.isEmpty() )
+    mURI.setParam( QgsWFSConstants::URI_PARAM_VERSION, versionString );
+}
+
 QString QgsWFSDataSourceURI::SRSName() const
 {
   return mURI.param( QgsWFSConstants::URI_PARAM_SRSNAME );
diff --git a/src/providers/wfs/qgswfsdatasourceuri.h b/src/providers/wfs/qgswfsdatasourceuri.h
index d995b1c..7375068 100644
--- a/src/providers/wfs/qgswfsdatasourceuri.h
+++ b/src/providers/wfs/qgswfsdatasourceuri.h
@@ -66,7 +66,7 @@ class QgsWFSDataSourceURI
     explicit QgsWFSDataSourceURI( const QString& uri );
 
     /** Return the URI */
-    QString uri();
+    const QString uri( bool expandAuthConfig = true ) const;
 
     /** Return base URL (with SERVICE=WFS parameter if bIncludeServiceWFS=true) */
     QUrl baseURL( bool bIncludeServiceWFS = true ) const;
@@ -92,6 +92,9 @@ class QgsWFSDataSourceURI
     /** Set SRS name (in the normalized form EPSG:xxxx) */
     void setSRSName( const QString& crsString );
 
+    /** Set version */
+    void setVersion( const QString& versionString );
+
     /** Get OGC filter xml or a QGIS expression */
     QString filter() const;
 
diff --git a/src/providers/wfs/qgswfsprovider.cpp b/src/providers/wfs/qgswfsprovider.cpp
index 41759c9..17617ac 100644
--- a/src/providers/wfs/qgswfsprovider.cpp
+++ b/src/providers/wfs/qgswfsprovider.cpp
@@ -1101,7 +1101,7 @@ bool QgsWFSProvider::describeFeatureType( QString& geometryAttribute, QgsFields&
 {
   fields.clear();
 
-  QgsWFSDescribeFeatureType describeFeatureType( mShared->mURI.uri() );
+  QgsWFSDescribeFeatureType describeFeatureType( mShared->mURI.uri( false ) );
   if ( !describeFeatureType.requestFeatureType( mShared->mWFSVersion,
        mShared->mURI.typeName() ) )
   {
@@ -1162,17 +1162,23 @@ bool QgsWFSProvider::readAttributesFromSchema( QDomDocument& schemaDoc,
   // collect the correspond type.
   QDomElement elementElement = schemaElement.firstChildElement( "element" );
   QString elementTypeString;
+  QDomElement complexTypeElement;
   while ( !elementElement.isNull() )
   {
     QString name = elementElement.attribute( "name" );
     if ( name == unprefixedTypename )
     {
       elementTypeString = elementElement.attribute( "type" );
+      if ( elementTypeString.isEmpty() )
+      {
+        // e.g http://afnemers.ruimtelijkeplannen.nl/afnemers2012/services?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAME=app:Bouwvlak
+        complexTypeElement = elementElement.firstChildElement( "complexType" );
+      }
       break;
     }
     elementElement = elementElement.nextSiblingElement( "element" );
   }
-  if ( elementTypeString.isEmpty() )
+  if ( elementTypeString.isEmpty() && complexTypeElement.isNull() )
   {
     // "http://demo.deegree.org/inspire-workspace/services/wfs?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAME=ad:Address"
     QDomElement iter = schemaElement.firstChildElement();
@@ -1207,21 +1213,24 @@ bool QgsWFSProvider::readAttributesFromSchema( QDomDocument& schemaDoc,
     elementTypeString = elementTypeString.section( ':', 1 );
   }
 
-  //the <complexType> element corresponding to the feature type
-  QDomElement complexTypeElement = schemaElement.firstChildElement( "complexType" );
-  while ( !complexTypeElement.isNull() )
+  if ( complexTypeElement.isNull() )
   {
-    QString name = complexTypeElement.attribute( "name" );
-    if ( name == elementTypeString )
+    //the <complexType> element corresponding to the feature type
+    complexTypeElement = schemaElement.firstChildElement( "complexType" );
+    while ( !complexTypeElement.isNull() )
     {
-      break;
+      QString name = complexTypeElement.attribute( "name" );
+      if ( name == elementTypeString )
+      {
+        break;
+      }
+      complexTypeElement = complexTypeElement.nextSiblingElement( "complexType" );
+    }
+    if ( complexTypeElement.isNull() )
+    {
+      errorMsg = tr( "Cannot find ComplexType element '%1'" ).arg( elementTypeString );
+      return false;
     }
-    complexTypeElement = complexTypeElement.nextSiblingElement( "complexType" );
-  }
-  if ( complexTypeElement.isNull() )
-  {
-    errorMsg = tr( "Cannot find ComplexType element '%1'" ).arg( elementTypeString );
-    return false;
   }
 
   //we have the relevant <complexType> element. Now find out the geometry and the thematic attributes
@@ -1321,7 +1330,7 @@ bool QgsWFSProvider::sendTransactionDocument( const QDomDocument& doc, QDomDocum
     return false;
   }
 
-  QgsWFSTransactionRequest request( mShared->mURI.uri() );
+  QgsWFSTransactionRequest request( mShared->mURI.uri( false ) );
   return request.send( doc, serverResponse );
 }
 
@@ -1424,7 +1433,7 @@ bool QgsWFSProvider::getCapabilities()
 
   if ( mShared->mCaps.version.isEmpty() )
   {
-    QgsWFSCapabilities getCapabilities( mShared->mURI.uri() );
+    QgsWFSCapabilities getCapabilities( mShared->mURI.uri( false ) );
     if ( !getCapabilities.requestCapabilities( true ) )
     {
       QgsMessageLog::logMessage( tr( "GetCapabilities failed for url %1: %2" ).
diff --git a/tests/src/gui/testqgsdualview.cpp b/tests/src/gui/testqgsdualview.cpp
index 4e2b017..0882a32 100644
--- a/tests/src/gui/testqgsdualview.cpp
+++ b/tests/src/gui/testqgsdualview.cpp
@@ -171,6 +171,33 @@ void TestQgsDualView::testSort()
     QModelIndex index = mDualView->tableView()->model()->index( i, 0 );
     QCOMPARE( mDualView->tableView()->model()->data( index ).toString(), classes.at( i ) );
   }
+
+  QStringList headings;
+  headings << "0"
+  <<  "0"
+  <<  "12"
+  <<  "34"
+  <<  "80"
+  <<  "85"
+  <<  "90"
+  <<  "90"
+  <<  "95"
+  <<  "100"
+  <<  "140"
+  <<  "160"
+  <<  "180"
+  <<  "240"
+  <<  "270"
+  <<  "300"
+  <<  "340";
+
+  mDualView->setSortExpression( "Heading" );
+
+  for ( int i = 0; i < headings.length(); ++i )
+  {
+    QModelIndex index = mDualView->tableView()->model()->index( i, 1 );
+    QCOMPARE( mDualView->tableView()->model()->data( index ).toString(), headings.at( i ) );
+  }
 }
 
 void TestQgsDualView::testAttributeFormSharedValueScanning()
diff --git a/tests/src/python/CMakeLists.txt b/tests/src/python/CMakeLists.txt
index 1fddd91..eb6d877 100644
--- a/tests/src/python/CMakeLists.txt
+++ b/tests/src/python/CMakeLists.txt
@@ -69,6 +69,7 @@ ADD_PYTHON_TEST(PyQgsPoint test_qgspoint.py)
 ADD_PYTHON_TEST(PyQgsRangeWidgets test_qgsrangewidgets.py)
 ADD_PYTHON_TEST(PyQgsRasterFileWriter test_qgsrasterfilewriter.py)
 ADD_PYTHON_TEST(PyQgsRasterLayer test_qgsrasterlayer.py)
+ADD_PYTHON_TEST(PyQgsRasterColorRampShader test_qgsrastercolorrampshader.py)
 ADD_PYTHON_TEST(PyQgsRectangle test_qgsrectangle.py)
 ADD_PYTHON_TEST(PyQgsRelation test_qgsrelation.py)
 ADD_PYTHON_TEST(PyQgsRelationManager test_qgsrelationmanager.py)
diff --git a/tests/src/python/providertestbase.py b/tests/src/python/providertestbase.py
index 5d19ffd..698e4d3 100644
--- a/tests/src/python/providertestbase.py
+++ b/tests/src/python/providertestbase.py
@@ -383,10 +383,36 @@ class ProviderTestCase(object):
         expected = set([fids[1], fids[3], fids[4]])
         assert result == expected, 'Expected {} and got {} when testing for feature IDs filter'.format(expected, result)
 
+        #providers should ignore non-existant fids
+        result = set([f.id() for f in self.provider.getFeatures(QgsFeatureRequest().setFilterFids([-101, fids[1], -102, fids[3], -103, fids[4], -104]))])
+        expected = set([fids[1], fids[3], fids[4]])
+        assert result == expected, 'Expected {} and got {} when testing for feature IDs filter'.format(expected, result)
+
         result = set([f.id() for f in self.provider.getFeatures(QgsFeatureRequest().setFilterFids([]))])
         expected = set([])
         assert result == expected, 'Expected {} and got {} when testing for feature IDs filter'.format(expected, result)
 
+        # Rewind mid-way
+        request = QgsFeatureRequest().setFilterFids([fids[1], fids[3], fids[4]])
+        feature_it = self.provider.getFeatures(request)
+        feature = QgsFeature()
+        feature.setValid(True)
+        self.assertTrue(feature_it.nextFeature(feature))
+        self.assertIn(feature.id(), [fids[1], fids[3], fids[4]])
+        first_feature = feature
+        self.assertTrue(feature.isValid())
+        # rewind
+        self.assertTrue(feature_it.rewind())
+        self.assertTrue(feature_it.nextFeature(feature))
+        self.assertEqual(feature.id(), first_feature.id())
+        self.assertTrue(feature.isValid())
+        # grab all features
+        self.assertTrue(feature_it.nextFeature(feature))
+        self.assertTrue(feature_it.nextFeature(feature))
+        # none left
+        self.assertFalse(feature_it.nextFeature(feature))
+        self.assertFalse(feature.isValid())
+
     def testGetFeaturesFilterRectTests(self):
         extent = QgsRectangle(-70, 67, -60, 80)
         request = QgsFeatureRequest().setFilterRect(extent)
diff --git a/tests/src/python/test_provider_tabfile.py b/tests/src/python/test_provider_tabfile.py
index ca86d22..3acaff6 100644
--- a/tests/src/python/test_provider_tabfile.py
+++ b/tests/src/python/test_provider_tabfile.py
@@ -14,8 +14,8 @@ __revision__ = '$Format:%H$'
 
 import os
 import tempfile
-from qgis.core import QgsVectorLayer, QgsFeatureRequest, QgsVectorDataProvider
-from qgis.PyQt.QtCore import QDate, QTime, QDateTime, QVariant
+from qgis.core import QgsVectorLayer, QgsFeatureRequest, QgsVectorDataProvider, QgsField
+from qgis.PyQt.QtCore import QDate, QTime, QDateTime, QVariant, QDir
 from qgis.testing import (
     start_app,
     unittest
@@ -90,6 +90,20 @@ class TestPyQgsTabfileProvider(unittest.TestCase):
         self.assertEquals(vl.dataProvider().property("_debug_open_mode"), "read-only")
         self.assertTrue(vl.dataProvider().isValid())
 
+    @unittest.expectedFailure(int(osgeo.gdal.VersionInfo()[:1]) < 2)
+    def testInteger64WriteTabfile(self):
+        """Check writing Integer64 fields to an MapInfo tabfile (which does not support that type)."""
+
+        base_dest_file_name = os.path.join(str(QDir.tempPath()), 'integer64')
+        dest_file_name = base_dest_file_name + '.tab'
+        shutil.copy(os.path.join(TEST_DATA_DIR, 'tab_file.tab'), base_dest_file_name + '.tab')
+        shutil.copy(os.path.join(TEST_DATA_DIR, 'tab_file.dat'), base_dest_file_name + '.dat')
+        shutil.copy(os.path.join(TEST_DATA_DIR, 'tab_file.map'), base_dest_file_name + '.map')
+        shutil.copy(os.path.join(TEST_DATA_DIR, 'tab_file.id'), base_dest_file_name + '.id')
+        vl = QgsVectorLayer(u'{}|layerid=0'.format(dest_file_name), u'test', u'ogr')
+        self.assertTrue(vl.isValid())
+        self.assertTrue(vl.dataProvider().addAttributes([QgsField("int8", QVariant.LongLong, "integer64")]))
+
 
 if __name__ == '__main__':
     unittest.main()
diff --git a/tests/src/python/test_provider_wfs.py b/tests/src/python/test_provider_wfs.py
index dcdb1cc..07da9ad 100644
--- a/tests/src/python/test_provider_wfs.py
+++ b/tests/src/python/test_provider_wfs.py
@@ -2111,6 +2111,94 @@ class TestPyQgsWFSProvider(unittest.TestCase, ProviderTestCase):
         got = got_f[0].geometry().geometry()
         self.assertEqual((got.x(), got.y()), (2.0, 49.0))
 
+    def testDescribeFeatureTypeWithInlineType(self):
+        """Test a DescribeFeatureType response with a inline ComplexType (#15395)."""
+
+        endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_testDescribeFeatureTypeWithInlineType'
+
+        with open(sanitize(endpoint, '?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=1.1.0'), 'wb') as f:
+            f.write("""
+<wfs:WFS_Capabilities version="1.1.0" xmlns="http://www.opengis.net/wfs" xmlns:wfs="http://www.opengis.net/wfs" xmlns:ogc="http://www.opengis.net/ogc" xmlns:ows="http://www.opengis.net/ows" xmlns:gml="http://schemas.opengis.net/gml">
+  <FeatureTypeList>
+    <FeatureType>
+      <Name>my:typename</Name>
+      <Title>Title</Title>
+      <Abstract>Abstract</Abstract>
+      <DefaultCRS>urn:ogc:def:crs:EPSG::4326</DefaultCRS>
+      <ows:WGS84BoundingBox>
+        <ows:LowerCorner>2 49</ows:LowerCorner>
+        <ows:UpperCorner>2 49</ows:UpperCorner>
+      </ows:WGS84BoundingBox>
+    </FeatureType>
+  </FeatureTypeList>
+</wfs:WFS_Capabilities>""".encode('UTF-8'))
+
+        with open(sanitize(endpoint, '?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=1.1.0&TYPENAME=my:typename'), 'wb') as f:
+            f.write("""
+<schema
+   targetNamespace="http://my"
+   xmlns:my="http://my"
+   xmlns:ogc="http://www.opengis.net/ogc"
+   xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+   xmlns="http://www.w3.org/2001/XMLSchema"
+   xmlns:gml="http://www.opengis.net/gml"
+   elementFormDefault="qualified" version="0.1" >
+  <import namespace="http://www.opengis.net/gml"
+          schemaLocation="http://schemas.opengis.net/gml/3.1.1/base/gml.xsd" />
+  <element name="typename"
+           substitutionGroup="gml:_Feature">
+    <complexType>
+      <complexContent>
+        <extension base="gml:AbstractFeatureType">
+          <sequence>
+            <element name="geometryProperty" type="gml:GeometryPropertyType" minOccurs="0" maxOccurs="1"/>
+          </sequence>
+        </extension>
+      </complexContent>
+    </complexType>
+  </element>
+</schema>
+""".encode('UTF-8'))
+
+        with open(sanitize(endpoint, """?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.1.0&TYPENAME=my:typename&SRSNAME=urn:ogc:def:crs:EPSG::4326"""), 'wb') as f:
+            f.write("""
+<wfs:FeatureCollection
+   xmlns:my="http://my"
+   xmlns:gml="http://www.opengis.net/gml"
+   xmlns:wfs="http://www.opengis.net/wfs"
+   xmlns:ogc="http://www.opengis.net/ogc">
+      <gml:boundedBy>
+        <gml:Envelope srsName="EPSG:4326">
+            <gml:lowerCorner>49.000000 2.000000</gml:lowerCorner>
+            <gml:upperCorner>49.000000 2.000000</gml:upperCorner>
+        </gml:Envelope>
+      </gml:boundedBy>
+    <gml:featureMember>
+      <my:typename gml:id="typename.1">
+        <gml:boundedBy>
+            <gml:Envelope srsName="EPSG:4326">
+                <gml:lowerCorner>49.000000 2.000000</gml:lowerCorner>
+                <gml:upperCorner>49.000000 2.000000</gml:upperCorner>
+            </gml:Envelope>
+        </gml:boundedBy>
+        <my:geometryProperty>
+          <gml:Point srsName="EPSG:4326">
+            <gml:pos>49.000000 2.000000</gml:pos>
+          </gml:Point>
+        </my:geometryProperty>
+      </my:typename>
+    </gml:featureMember>
+</wfs:FeatureCollection>
+
+""".encode('UTF-8'))
+
+        vl = QgsVectorLayer(u"url='http://" + endpoint + u"' typename='my:typename' version='1.1.0'", u'test', u'WFS')
+        assert vl.isValid()
+
+        got_f = [f for f in vl.getFeatures()]
+        got = got_f[0].geometry().geometry()
+        self.assertEqual((got.x(), got.y()), (2.0, 49.0))
+
 
 if __name__ == '__main__':
     unittest.main()
diff --git a/tests/src/python/test_qgsattributetablemodel.py b/tests/src/python/test_qgsattributetablemodel.py
index 5a01928..9fabaec 100644
--- a/tests/src/python/test_qgsattributetablemodel.py
+++ b/tests/src/python/test_qgsattributetablemodel.py
@@ -12,8 +12,17 @@ __copyright__ = 'Copyright 2015, The QGIS Project'
 # This will get replaced with a git SHA1 when you do a git archive
 __revision__ = '$Format:%H$'
 
-from qgis.gui import QgsAttributeTableModel, QgsEditorWidgetRegistry
-from qgis.core import QgsFeature, QgsGeometry, QgsPoint, QgsVectorLayer, QgsVectorLayerCache
+from qgis.gui import (
+    QgsAttributeTableModel,
+    QgsEditorWidgetRegistry
+)
+from qgis.core import (
+    QgsFeature,
+    QgsGeometry,
+    QgsPoint,
+    QgsVectorLayer,
+    QgsVectorLayerCache
+)
 
 from qgis.testing import (start_app,
                           unittest
@@ -51,20 +60,20 @@ class TestQgsAttributeTableModel(unittest.TestCase):
             f.setGeometry(QgsGeometry.fromPoint(QgsPoint(100 * i, 2 ^ i)))
             features.append(f)
 
-        assert pr.addFeatures(features)
+        self.assertTrue(pr.addFeatures(features))
         return layer
 
     def testLoad(self):
-        assert self.am.rowCount() == 10, self.am.rowCount()
-        assert self.am.columnCount() == 2, self.am.columnCount()
+        self.assertEquals(self.am.rowCount(), 10)
+        self.assertEquals(self.am.columnCount(), 2)
 
     def testRemove(self):
         self.layer.startEditing()
         self.layer.deleteFeature(5)
-        assert self.am.rowCount() == 9, self.am.rowCount()
+        self.assertEquals(self.am.rowCount(), 9)
         self.layer.setSelectedFeatures([1, 3, 6, 7])
         self.layer.deleteSelectedFeatures()
-        assert self.am.rowCount() == 5, self.am.rowCount()
+        self.assertEquals(self.am.rowCount(), 5)
 
     def testAdd(self):
         self.layer.startEditing()
@@ -74,14 +83,14 @@ class TestQgsAttributeTableModel(unittest.TestCase):
         f.setGeometry(QgsGeometry.fromPoint(QgsPoint(100, 200)))
         self.layer.addFeature(f)
 
-        assert self.am.rowCount() == 11, self.am.rowCount()
+        self.assertEquals(self.am.rowCount(), 11)
 
     def testRemoveColumns(self):
-        assert self.layer.startEditing()
+        self.assertTrue(self.layer.startEditing())
 
-        assert self.layer.deleteAttribute(1)
+        self.assertTrue(self.layer.deleteAttribute(1))
 
-        assert self.am.columnCount() == 1, self.am.columnCount()
+        self.assertEquals(self.am.columnCount(), 1)
 
 if __name__ == '__main__':
     unittest.main()
diff --git a/tests/src/python/test_qgsfeatureiterator.py b/tests/src/python/test_qgsfeatureiterator.py
index 9b29a61..d6ca9b9 100644
--- a/tests/src/python/test_qgsfeatureiterator.py
+++ b/tests/src/python/test_qgsfeatureiterator.py
@@ -79,23 +79,20 @@ class TestQgsFeatureIterator(unittest.TestCase):
 
         ids = [feat.id() for feat in pointLayer.getFeatures(QgsFeatureRequest().setFilterFids([7, 8, 12, 30]))]
         expectedIds = [7, 8, 12]
-        myMessage = '\nExpected: {0} features\nGot: {1} features'.format(repr(expectedIds), repr(ids))
-        assert ids == expectedIds, myMessage
+        self.assertEquals(set(ids), set(expectedIds))
 
         pointLayer.startEditing()
         self.addFeatures(pointLayer)
 
         ids = [feat.id() for feat in pointLayer.getFeatures(QgsFeatureRequest().setFilterFids([-4, 7, 8, 12, 30]))]
         expectedIds = [-4, 7, 8, 12]
-        myMessage = '\nExpected: {0} features\nGot: {1} features'.format(repr(expectedIds), repr(ids))
-        assert ids == expectedIds, myMessage
+        self.assertEquals(set(ids), set(expectedIds))
 
         pointLayer.rollBack()
 
         ids = [feat.id() for feat in pointLayer.getFeatures(QgsFeatureRequest().setFilterFids([-2, 7, 8, 12, 30]))]
         expectedIds = [7, 8, 12]
-        myMessage = '\nExpected: {0} features\nGot: {1} features'.format(repr(expectedIds), repr(ids))
-        assert ids == expectedIds, myMessage
+        self.assertEquals(set(ids), set(expectedIds))
 
     def addFeatures(self, vl):
         feat = QgsFeature()
diff --git a/tests/src/python/test_qgspallabeling_placement.py b/tests/src/python/test_qgspallabeling_placement.py
index e7c5c37..5b32792 100644
--- a/tests/src/python/test_qgspallabeling_placement.py
+++ b/tests/src/python/test_qgspallabeling_placement.py
@@ -48,6 +48,7 @@ class TestPlacementBase(TestQgsPalLabeling):
     def setUp(self):
         """Run before each test."""
         super(TestPlacementBase, self).setUp()
+        self.removeAllLayers()
         self.configTest('pal_placement', 'sp')
         self._TestImage = ''
         # ensure per test map settings stay encapsulated
diff --git a/tests/src/python/test_qgsrastercolorrampshader.py b/tests/src/python/test_qgsrastercolorrampshader.py
new file mode 100644
index 0000000..e32d734
--- /dev/null
+++ b/tests/src/python/test_qgsrastercolorrampshader.py
@@ -0,0 +1,37 @@
+# -*- coding: utf-8 -*-
+"""QGIS Unit tests for QgsColorRampShader.
+
+.. note:: 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__ = 'Nyall Dawson'
+__date__ = '17/08/2016'
+__copyright__ = 'Copyright 2016, The QGIS Project'
+# This will get replaced with a git SHA1 when you do a git archive
+__revision__ = '$Format:%H$'
+
+import qgis  # NOQA
+
+
+from qgis.PyQt.QtGui import QColor
+
+from qgis.core import (QgsColorRampShader)
+from qgis.testing import unittest
+
+
+class TestQgsRasterColorRampShader(unittest.TestCase):
+
+    def testNan(self):
+        shader = QgsColorRampShader()
+
+        item1 = QgsColorRampShader.ColorRampItem(1, QColor(0, 0, 0))
+        item2 = QgsColorRampShader.ColorRampItem(2, QColor(255, 255, 255))
+        shader.setColorRampItemList([item1, item2])
+        self.assertFalse(shader.shade(float('NaN'))[0])
+        self.assertFalse(shader.shade(float("inf"))[0])
+
+if __name__ == '__main__':
+    unittest.main()
diff --git a/tests/src/python/test_qgsvectorfilewriter.py b/tests/src/python/test_qgsvectorfilewriter.py
index 3b98e2e..f2d94f8 100644
--- a/tests/src/python/test_qgsvectorfilewriter.py
+++ b/tests/src/python/test_qgsvectorfilewriter.py
@@ -36,6 +36,10 @@ from utilities import writeShape, compareWkt
 start_app()
 
 
+def GDAL_COMPUTE_VERSION(maj, min, rev):
+    return ((maj) * 1000000 + (min) * 10000 + (rev) * 100)
+
+
 class TestFieldValueConverter(QgsVectorFileWriter.FieldValueConverter):
 
     def __init__(self, layer):
@@ -416,5 +420,47 @@ class TestQgsVectorLayer(unittest.TestCase):
         self.assertEqual(f['nonconv'], 1)
         self.assertEqual(f['conv_attr'], 'converted_val')
 
+    @unittest.expectedFailure(int(osgeo.gdal.VersionInfo('VERSION_NUM')) < GDAL_COMPUTE_VERSION(2, 0, 0))
+    def testInteger64WriteTabfile(self):
+        """Check writing Integer64 fields to an MapInfo tabfile (which does not support that type)."""
+        ml = QgsVectorLayer(
+            ('Point?crs=epsg:4326&field=int8:int8'),
+            'test',
+            'memory')
+
+        self.assertIsNotNone(ml, 'Provider not initialized')
+        self.assertTrue(ml.isValid(), 'Source layer not valid')
+        provider = ml.dataProvider()
+        self.assertIsNotNone(provider)
+
+        ft = QgsFeature()
+        ft.setAttributes([2123456789])
+        res, features = provider.addFeatures([ft])
+        self.assertTrue(res)
+        self.assertTrue(features)
+
+        dest_file_name = os.path.join(str(QDir.tempPath()), 'integer64.tab')
+        crs = QgsCoordinateReferenceSystem()
+        crs.createFromId(4326, QgsCoordinateReferenceSystem.EpsgCrsId)
+        write_result = QgsVectorFileWriter.writeAsVectorFormat(
+            ml,
+            dest_file_name,
+            'utf-8',
+            crs,
+            'MapInfo File')
+        self.assertEqual(write_result, QgsVectorFileWriter.NoError)
+
+        # Open result and check
+        created_layer = QgsVectorLayer(u'{}|layerid=0'.format(dest_file_name), u'test', u'ogr')
+
+        fields = created_layer.dataProvider().fields()
+        self.assertEqual(fields.at(fields.indexFromName('int8')).type(), QVariant.Double)
+
+        f = next(created_layer.getFeatures(QgsFeatureRequest()))
+
+        int8_idx = created_layer.fieldNameIndex('int8')
+        self.assertEqual(f.attributes()[int8_idx], 2123456789)
+
+
 if __name__ == '__main__':
     unittest.main()

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