[qgis] 01/06: Imported Upstream version 2.14.7+dfsg

Bas Couwenberg sebastic at debian.org
Sat Sep 24 07:45:57 UTC 2016


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

sebastic pushed a commit to branch master
in repository qgis.

commit 32a1925b38832177c5c92fdceb0c46a2e907ce41
Author: Bas Couwenberg <sebastic at xs4all.nl>
Date:   Sat Sep 24 08:44:41 2016 +0200

    Imported Upstream version 2.14.7+dfsg
---
 CMakeLists.txt                                     |   2 +-
 ChangeLog                                          | 826 ++++++++++++++-------
 debian/changelog                                   |  10 +-
 debian/python-qgis.install.in                      |   1 +
 debian/rules                                       |   4 +
 python/CMakeLists.txt                              |  12 +
 python/QtWebKit/QtWebKitmod.sip                    |  63 ++
 python/QtWebKit/__init__.py                        |   0
 python/QtWebKit/qgraphicswebview.sip               | 150 ++++
 python/QtWebKit/qwebdatabase.sip                   |  46 ++
 python/QtWebKit/qwebelement.sip                    | 144 ++++
 python/QtWebKit/qwebframe.sip                      | 244 ++++++
 python/QtWebKit/qwebhistory.sip                    | 104 +++
 python/QtWebKit/qwebhistoryinterface.sip           |  40 +
 python/QtWebKit/qwebinspector.sip                  |  48 ++
 python/QtWebKit/qwebkitglobal.sip                  |  37 +
 python/QtWebKit/qwebkitversion.sip                 |  37 +
 python/QtWebKit/qwebpage.sip                       | 522 +++++++++++++
 python/QtWebKit/qwebpluginfactory.sip              |  88 +++
 python/QtWebKit/qwebsecurityorigin.sip             |  56 ++
 python/QtWebKit/qwebsettings.sip                   | 237 ++++++
 python/QtWebKit/qwebview.sip                       | 167 +++++
 python/core/geometry/qgsabstractgeometryv2.sip     |   6 +
 python/core/geometry/qgslinestringv2.sip           |   4 +
 python/core/geometry/qgsmultilinestringv2.sip      |   4 +
 python/core/geometry/qgsmultipolygonv2.sip         |   4 +
 python/core/geometry/qgspolygonv2.sip              |   4 +
 python/core/qgsstringutils.sip                     |  19 +
 python/core/qgsvectordataprovider.sip              |   4 +
 python/gui/qgsmessagebar.sip                       |   4 +-
 python/plugins/processing/algs/qgis/ConcaveHull.py |   4 +-
 .../plugins/processing/algs/qgis/Intersection.py   |   6 +-
 python/plugins/processing/algs/qgis/MeanCoords.py  |  11 +-
 .../algs/qgis/SinglePartsToMultiparts.py           |   4 +-
 python/plugins/processing/core/parameters.py       |   2 +-
 .../plugins/processing/gui/AlgorithmDialogBase.py  |   3 -
 .../processing/ui/DlgGetScriptsAndModels.ui        |   5 -
 src/analysis/vector/qgsgeometryanalyzer.cpp        |  59 +-
 src/analysis/vector/qgsgeometryanalyzer.h          |  10 +-
 src/app/main.cpp                                   |  94 ++-
 src/app/qgsidentifyresultsdialog.cpp               |   2 +
 src/app/qgssnappingdialog.cpp                      |   2 +-
 src/core/auth/qgsauthmanager.cpp                   |   8 +-
 src/core/geometry/qgsabstractgeometryv2.h          |   6 +
 src/core/geometry/qgsgeometry.cpp                  |   5 +
 src/core/geometry/qgslinestringv2.cpp              |   8 +
 src/core/geometry/qgslinestringv2.h                |   3 +
 src/core/geometry/qgsmultilinestringv2.cpp         |  11 +
 src/core/geometry/qgsmultilinestringv2.h           |   3 +
 src/core/geometry/qgsmultipolygonv2.cpp            |  10 +
 src/core/geometry/qgsmultipolygonv2.h              |   3 +
 src/core/geometry/qgspolygonv2.cpp                 |  12 +
 src/core/geometry/qgspolygonv2.h                   |   3 +
 src/core/qgsexpression.cpp                         |  14 +-
 src/core/qgslegendrenderer.cpp                     |  46 +-
 src/core/qgspallabeling.cpp                        |  71 +-
 src/core/qgspointlocator.cpp                       |   1 +
 src/core/qgspointlocator.h                         |   2 +-
 src/core/qgsstringutils.cpp                        |  50 ++
 src/core/qgsstringutils.h                          |  18 +
 src/core/qgsvectordataprovider.cpp                 | 109 ++-
 src/core/qgsvectordataprovider.h                   |   4 +
 src/core/qgsvectorlayer.cpp                        |   7 +-
 src/core/qgsvectorlayerfeatureiterator.cpp         | 287 ++++---
 src/core/qgsvectorlayerfeatureiterator.h           |  29 +-
 src/core/qgsvectorlayerlabelprovider.h             |   2 +
 src/core/symbology-ng/qgsvectorcolorrampv2.cpp     |   5 +-
 src/gui/editorwidgets/qgswebviewwidgetwrapper.cpp  |   1 +
 .../qgsdelimitedtextfeatureiterator.cpp            |  10 +-
 .../delimitedtext/qgsdelimitedtextfile.cpp         |  10 +-
 src/providers/ogr/qgsogrconnpool.h                 |   3 +-
 src/providers/ogr/qgsogrfeatureiterator.cpp        |   7 +
 src/providers/ogr/qgsogrprovider.cpp               | 177 ++++-
 src/providers/ogr/qgsogrprovider.h                 |   8 +
 src/providers/postgres/qgspostgresdataitems.cpp    |   8 +-
 src/providers/postgres/qgspostgresprovider.cpp     |   7 +-
 .../spatialite/qgsspatialitesourceselect.cpp       |   4 +
 .../virtual/qgsvirtuallayerqueryparser.cpp         |   6 +-
 .../virtual/qgsvirtuallayersqlitemodule.cpp        |  19 +-
 tests/src/core/testqgsexpression.cpp               |   1 +
 tests/src/core/testqgslabelingenginev2.cpp         |  60 ++
 tests/src/core/testqgslegendrenderer.cpp           |  62 ++
 tests/src/python/test_provider_ogr_gpkg.py         | 164 ++++
 tests/src/python/test_provider_virtual.py          |  14 +
 tests/src/python/test_qgsfeatureiterator.py        |  88 ++-
 .../expected_legend_2_by_2.png                     | Bin 0 -> 4515 bytes
 .../expected_legend_2_by_2_mask.png                | Bin 0 -> 1198 bytes
 .../expected_legend_3_by_2.png                     | Bin 0 -> 5364 bytes
 .../expected_legend_3_by_2_mask.png                | Bin 0 -> 1491 bytes
 .../expected_legend_3_by_3.png                     | Bin 0 -> 5800 bytes
 .../expected_legend_3_by_3_mask.png                | Bin 0 -> 1526 bytes
 .../expected_legend_4_by_2.png                     | Bin 0 -> 5472 bytes
 .../expected_legend_4_by_2_mask.png                | Bin 0 -> 1676 bytes
 .../expected_legend_4_by_3.png                     | Bin 0 -> 6529 bytes
 .../expected_legend_4_by_3_mask.png                | Bin 0 -> 1855 bytes
 .../expected_legend_5_by_2.png                     | Bin 0 -> 6661 bytes
 .../expected_legend_5_by_2_mask.png                | Bin 0 -> 1964 bytes
 .../expected_legend_5_by_3.png                     | Bin 0 -> 6870 bytes
 .../expected_legend_5_by_3_mask.png                | Bin 0 -> 2045 bytes
 .../expected_legend_6_by_3.png                     | Bin 0 -> 7470 bytes
 .../expected_legend_6_by_3_mask.png                | Bin 0 -> 2226 bytes
 .../expected_legend_7_by_3.png                     | Bin 0 -> 8244 bytes
 .../expected_legend_7_by_3_mask.png                | Bin 0 -> 2539 bytes
 103 files changed, 3894 insertions(+), 561 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index f945b1a..612b0f3 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,6 +1,6 @@
 SET(CPACK_PACKAGE_VERSION_MAJOR "2")
 SET(CPACK_PACKAGE_VERSION_MINOR "14")
-SET(CPACK_PACKAGE_VERSION_PATCH "6")
+SET(CPACK_PACKAGE_VERSION_PATCH "7")
 SET(COMPLETE_VERSION ${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH})
 SET(RELEASE_NAME "Essen")
 IF (POLICY CMP0048) # in CMake 3.0.0+
diff --git a/ChangeLog b/ChangeLog
index 6d0f335..1d1f2bf 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,285 @@
+Even Rouault <even.rouault at spatialys.com>	2016-09-22
+
+    Fix database locking when editing GeoPackage
+
+    Concurrent read and write can lock a GeoPackage database given
+    the default journaling mode of SQLite (delete). Use WAL when
+    possible to avoid that.
+
+    Fixes #15351
+
+Martin Dobias <wonder.sk at gmail.com>	2016-09-21
+
+    [snapping] fix default advanced mode values for added layers
+
+    Backported from PR #3513
+
+    (cherry picked from commit be636c178cd527f4533f467292acd05bde4238c9)
+
+Juergen E. Fischer <jef at norbit.de>	2016-09-20
+
+    [processing] Just remove the url property from DlgGetScriptsAndModel.
+
+    (revert 7e24798, followup fad50ec)
+
+Juergen E. Fischer <jef at norbit.de>	2016-09-20
+
+    Fix fad50ec
+
+rldhont <rldhont at gmail.com>	2016-09-16
+
+    [Processing] bugfix: intersection QGIS algorithm
+
+    fixing this by testing int_com.
+    ```
+    Traceback (most recent call last):
+    File "C:/PROGRA~1/QGIS2~1.17/apps/qgis/./python/plugins\processing\core\GeoAlgorithm.py", line 203, in execute
+    self.processAlgorithm(progress)
+    File "C:/PROGRA~1/QGIS2~1.17/apps/qgis/./python/plugins\processing\algs\qgis\Intersection.py", line 100, in processAlgorithm
+    int_geom = QgsGeometry(int_com.difference(int_sym))
+    ```
+
+    AttributeError: 'NoneType' object has no attribute 'difference'
+    (cherry picked from commit 3661bc39dbee312b3a0887ca80287cbc7b2260ec)
+    (cherry picked from commit 5b573179f3d2fb94542714a4bd3fcdb28f4e3307)
+
+Juergen E. Fischer <jef at norbit.de>	2016-09-17
+
+    show command line help as message box on windows
+
+    (cherry picked from commit bd23bf1a2368fa68fe692d451f61bfe3095619bd)
+
+Alexander Bruy <alexander.bruy at gmail.com>	2016-09-16
+
+    [processing] allow all field types as unique ID field in Mean coords alg
+
+    (cherry picked from commit 75269d66b9d79c3b4a2b18bd9626c22840aa6713)
+
+arnaud.morvan at camptocamp.com <arnaud.morvan at camptocamp.com>	2016-09-08
+
+    Fix ParameterGeometryPredicate.getValueAsCommandLineParameter
+
+    (cherry picked from commit d85de7ccd8946ab3ded83abae674554d482dbcf5)
+
+Nyall Dawson <nyall.dawson at gmail.com>	2016-09-15
+
+    Catch exceptions in transform() expression function
+
+    (cherry-picked from 2a8333ef6be003b8c391a72dbed033a33373d677)
+
+Alexander Bruy <alexander.bruy at gmail.com>	2016-09-15
+
+    [processing] correct error message (fix #15511)
+
+    (cherry picked from commit d393734bd3d368f52271838414a3edbf1d4eb1a5)
+
+Juergen E. Fischer <jef at norbit.de>	2016-09-14
+
+    fix 058aa46
+
+Juergen E. Fischer <jef at norbit.de>	2016-09-14
+
+    Enable plugins (eg. to show PDFs) in webview widgets used on feature info in identify or in forms
+
+Nyall Dawson <nyall.dawson at gmail.com>	2016-09-10
+
+    Test masks
+
+    (cherry-picked from e3313fac95ea143988ea32bf162b01b4df8e6fa1)
+
+Nyall Dawson <nyall.dawson at gmail.com>	2016-09-10
+
+    Make sure items in legend always occupy the set number of columns
+
+    In some cases (eg a legend with 4 items and 3 columns) less
+    columns were being created
+
+    (cherry-picked from 52eef9006183a66d53926f33e73afa1dcd534e59)
+
+Nyall Dawson <nyall.dawson at gmail.com>	2016-09-10
+
+    Fix multi column legends with odd number of items would place
+    more items in rightmost columns instead of leftmost columns
+
+    Eg a 2 column legend with 3 items would put 1 item in
+    the first column and 2 in the second. This was ugly, and now
+    it places 2 in the first column and 1 in the second.
+
+    The legend column assigner was incorrectly adding padding above
+    the first item in a column during column size calculation
+    (padding which is not present when actually rendering the column)
+
+    (cherry-picked from a673fa8393146d9a8cd1a3bf6f0444bfa23352d7)
+
+Nyall Dawson <nyall.dawson at gmail.com>	2016-09-10
+
+    Add a bunch of tests for legend grouping into columns
+
+    (cherry-picked from 570e6936b655aef2877d2d63c9892f1df05df312)
+
+nirvn <nirvn.asia at gmail.com>	2016-09-13
+
+    [delimitertext] fix watcher check ignored and harmful watcher created for iterator
+    (fixes #15558)
+
+    (cherry-picked from b3e31087181732f7511d047b98352e97f08b0d04)
+
+Marco Bernasocchi <marco at bernawebdesign.ch>	2016-09-11
+
+    qgsmessagebar timeout is not respected in python
+
+    the default timeout is not respected in python
+
+    gui/qgsmessagebar.sip:51:    void pushMessage( const QString &text, MessageLevel level = INFO, int duration = 0 );
+
+    https://qgis.org/api/qgsmessagebar_8h_source.html#l00090
+    void pushMessage( const QString &text, MessageLevel level = INFO, int duration = 5 ) { return pushMessage( QString::null, text, level, duration ); }
+
+    (cherry-picked from bb4e6b8fb800b69d28407102a4f17494a4cd5ad9)
+
+Alexander Bruy <alexander.bruy at gmail.com>	2016-09-13
+
+    [processing] fix progress reporting (fix #15521)
+
+    (cherry picked from commit b14dfa65fe8c5db852bac0899f8aac64b91faada)
+
+    Conflicts:
+            python/plugins/processing/gui/AlgorithmDialogBase.py
+
+Merge: c151724 bb4d83f
+mhugent <marco.hugentobler at sourcepole.ch>	2016-09-13
+
+    Merge pull request #3482 from mhugent/joins_over_several_tables2
+
+    Joins over several tables2
+
+Marco Hugentobler <marco.hugentobler at sourcepole.ch>	2016-09-13
+
+    Fix imports in test_qgsfeatureiterator
+
+Marco Hugentobler <marco.hugentobler at sourcepole.ch>	2016-09-12
+
+    Fix joins over several tables
+
+Nyall Dawson <nyall.dawson at gmail.com>	2016-06-10
+
+    Correctly support joins using virtual fields
+
+Merge: 4aaa6d4 9290ee3
+mhugent <marco.hugentobler at sourcepole.ch>	2016-09-12
+
+    Merge pull request #3476 from mhugent/fix_event_layer
+
+    Fix for event layer functionality in 2.4
+
+Marco Hugentobler <marco.hugentobler at sourcepole.ch>	2016-09-09
+
+    Fix event layer to work with 25d, z and zm
+
+Juergen E. Fischer <jef at norbit.de>	2016-09-06
+
+    debian packaging update: add internal QtWebKit bindings
+
+    (backported from c2f363f)
+
+Marco Hugentobler <marco.hugentobler at sourcepole.ch>	2016-09-05
+
+    Fix warning
+
+Marco Hugentobler <marco.hugentobler at sourcepole.ch>	2016-09-05
+
+    Fix bindings
+
+Merge: a528eb9 b14255c
+mhugent <marco.hugentobler at sourcepole.ch>	2016-09-05
+
+    Merge pull request #3446 from mhugent/convert_geometry_provider
+
+    Port conversion of geometry to provider type to 2.14 branch
+
+Marco Hugentobler <marco.hugentobler at sourcepole.ch>	2016-09-02
+
+    Port conversion of geometry to provider type to 2.14 branch
+
+Larry Shaffer <lshaffer at boundlessgeo.com>	2016-09-01
+
+    [auth] Fix return value for plugins that do not support an expansion
+
+    Bug not evident until there were providers with multiple credential
+    expansions (now supported in OWS providers). Lack of support for an
+    expansion should only trigger a debug message, not a failure.
+
+    (cherry-picked from 194b5adb1ed81bcfe7edd78477dfea81cae77aed)
+
+Hugo Mercier <hugo.mercier at oslandia.com>	2016-09-01
+
+    Fix virtual layer queries with accents in layer name
+
+    (cherry-picked from af0d6b93a6)
+
+Matthias Kuhn <matthias at opengis.ch>	2016-09-01
+
+    Export main() when building for android
+
+Hugo Mercier <hugo.mercier at oslandia.com>	2016-07-21
+
+    Snapping: destroy index on dataChanged signal
+
+    Snapping caches on layers that have been changed by the provider or
+    by external sources are now invalidated.
+
+    (Cherry-picked from e6fd2e25)
+
+Nyall Dawson <nyall.dawson at gmail.com>	2016-08-30
+
+    Fix Capitalize First Letter fails with curved labels (fix #14875)
+
+    Instead of using QFont's inbuilt capitalization support, which
+    applies only on rendering and accordingly fails for curved
+    labels which are drawn one character at a time, we now manually
+    capitalize label text while registering features.
+
+    The capitalize first method from Qt was reimplemented in QgsStringUtils
+    (together with what I expect is better handling of unicode characters
+    over the Qt method).
+
+    This change also makes it possible to implement other capitalization
+    methods not directly supported by Qt
+
+    (cherry-picked from 15dd295)
+
+Tim Sutton <tim at kartoza.com>	2016-08-22
+
+    Spatialite error message fix (#3416)
+
+    * Fixed issue where opening an invalid spatialite db fails and gives and poor warning message
+
+Nyall Dawson <nyall.dawson at gmail.com>	2016-08-26
+
+    [browser] Correctly refresh postgres schemas when dropping tables
+
+    (cherry-picked from 5a41748b867505784a091a882a0eb1ca187c4ba8)
+
+Nyall Dawson <nyall.dawson at gmail.com>	2016-08-26
+
+    Make QgsVectorDataProvider defaults methods more efficient
+
+    (cherry-picked from a10b8fc3e5658290dd7e18df1001e543c3a75caa)
+
+Nyall Dawson <nyall.dawson at gmail.com>	2016-08-26
+
+    Fix limited random color ramp always returns 1 less color than set
+
+    (cherry-picked from 1d98b10904884d8223372fc9248c2825c85591e9)
+
+Nyall Dawson <nyall.dawson at gmail.com>	2016-08-25
+
+    Fix potential crash
+
+Juergen E. Fischer <jef at norbit.de>	2016-08-26
+
+    Release of 2.14.6
+
 rldhont <rldhont at gmail.com>	2016-08-25
 
     fix typo 1369794 @alexbruy [processing] add missed error() method
@@ -446,7 +728,7 @@ volaya <volayaf at gmail.com>	2016-06-01
     (cherry picked from commit 479ceb36b40407643764586fc5122333b7eb38eb)
 
     Conflicts:
-python/plugins/processing/tools/dataobjects.py
+            python/plugins/processing/tools/dataobjects.py
 
 Patrick Valsecchi <patrick.valsecchi at camptocamp.com>	2016-05-13
 
@@ -1443,7 +1725,7 @@ Alexander Bruy <alexander.bruy at gmail.com>	2016-06-22
     (cherry picked from commit e4c1d896e97952743ea1c0c2144e33983fa5706a)
 
     Conflicts:
-python/plugins/processing/algs/gdal/GdalUtils.py
+            python/plugins/processing/algs/gdal/GdalUtils.py
 
 Sandro Santilli <strk at kbt.io>	2016-06-22
 
@@ -1463,7 +1745,7 @@ Alexander Bruy <alexander.bruy at gmail.com>	2016-06-21
     (cherry picked from commit e0c9733f6482f184aeeff1339fafef210d1a0709)
 
     Conflicts:
-python/plugins/processing/algs/qgis/HubDistance.py
+            python/plugins/processing/algs/qgis/HubDistance.py
 
 Alexander Bruy <alexander.bruy at gmail.com>	2016-06-21
 
@@ -1580,11 +1862,11 @@ Alexander Bruy <alexander.bruy at gmail.com>	2016-06-13
     (cherry picked from commit 0553f7b33b4a3294f9a1cfb24e8c238f9211503d)
 
     Conflicts:
-python/plugins/processing/algs/qgis/Clip.py
-python/plugins/processing/algs/qgis/Difference.py
-python/plugins/processing/algs/qgis/Intersection.py
-python/plugins/processing/algs/qgis/SymmetricalDifference.py
-python/plugins/processing/algs/qgis/Union.py
+            python/plugins/processing/algs/qgis/Clip.py
+            python/plugins/processing/algs/qgis/Difference.py
+            python/plugins/processing/algs/qgis/Intersection.py
+            python/plugins/processing/algs/qgis/SymmetricalDifference.py
+            python/plugins/processing/algs/qgis/Union.py
 
 rldhont <rldhont at gmail.com>	2016-06-10
 
@@ -2146,8 +2428,8 @@ rldhont <rldhont at gmail.com>	2016-04-26
     (cherry picked from commit 793b712eb9dbd5d6d7589e7490c63d50d0038a69)
 
     Conflicts:
-python/plugins/processing/algs/gdal/rasterize.py
-python/plugins/processing/algs/gdal/warp.py
+            python/plugins/processing/algs/gdal/rasterize.py
+            python/plugins/processing/algs/gdal/warp.py
 
 volaya <volayaf at gmail.com>	2016-04-26
 
@@ -2170,7 +2452,7 @@ Alexander Bruy <alexander.bruy at gmail.com>	2016-04-11
     (cherry picked from commit e873540d14cb102ffe9318063b32c323c56e5bfb)
 
     Conflicts:
-python/plugins/processing/algs/otb/OTBUtils.py
+            python/plugins/processing/algs/otb/OTBUtils.py
 
 Nyall Dawson <nyall.dawson at gmail.com>	2016-04-26
 
@@ -8682,7 +8964,7 @@ Michael Kirk <michael.john.kirk at gmail.com>	2015-11-29
     - Test BooleanParameter
 
     Conflicts:
-python/plugins/processing/core/parameters.py
+            python/plugins/processing/core/parameters.py
 
 rldhont <rldhont at gmail.com>	2015-12-23
 
@@ -10791,7 +11073,7 @@ Giuseppe Sucameli <brush.tyler at gmail.com>	2015-11-30
         Merge branch 'gdaltools_buildvrt_asrs' of https://github.com/giohappy/QGIS into giohappy-gdaltools_buildvrt_asrs
 
         Conflicts:
-python/plugins/GdalTools/tools/doBuildVRT.py
+            python/plugins/GdalTools/tools/doBuildVRT.py
 
     commit 6d3df91f0226fa71356da45b9b5ef1c9f9796ebd
     Author: giohappy <giohappy at gmail.com>
@@ -13409,7 +13691,7 @@ Giuseppe Sucameli <brush.tyler at gmail.com>	2015-10-25
     Merge branch 'clipper' of https://github.com/PedroVenancio/Quantum-GIS into PedroVenancio-clipper
 
     Conflicts:
-python/plugins/processing/algs/gdal/ClipByMask.py
+            python/plugins/processing/algs/gdal/ClipByMask.py
 
 mdouchin <mdouchin at 3liz.com>	2015-10-25
 
@@ -13442,7 +13724,7 @@ volaya <volayaf at gmail.com>	2015-10-22
     [processing] fixed SAGA version handling
 
     Conflicts:
-python/plugins/processing/algs/saga/SagaAlgorithmProvider.py
+            python/plugins/processing/algs/saga/SagaAlgorithmProvider.py
 
 volaya <volayaf at gmail.com>	2015-10-22
 
@@ -18439,7 +18721,7 @@ Nathan Woodrow <madmanwoo at gmail.com>	2015-08-25
     Merge branch 'master' of https://github.com/qgis/QGIS
 
     Conflicts:
-src/gui/attributetable/qgsfieldconditionalformatwidget.cpp
+            src/gui/attributetable/qgsfieldconditionalformatwidget.cpp
 
 Nyall Dawson <nyall.dawson at gmail.com>	2015-08-25
 
@@ -18631,13 +18913,13 @@ Nathan Woodrow <madmanwoo at gmail.com>	2015-08-23
     Merge row style support for attribute table
 
     Conflicts:
-python/core/qgsconditionalstyle.sip
-python/core/qgsfielduiproperties.sip
-src/core/qgsfielduiproperties.cpp
-src/core/qgsfielduiproperties.h
-src/gui/attributetable/qgsattributetablemodel.cpp
-src/ui/qgsfieldconditionalformatwidget.ui
-tests/src/python/test_qgsconditionalstyle.py
+            python/core/qgsconditionalstyle.sip
+            python/core/qgsfielduiproperties.sip
+            src/core/qgsfielduiproperties.cpp
+            src/core/qgsfielduiproperties.h
+            src/gui/attributetable/qgsattributetablemodel.cpp
+            src/ui/qgsfieldconditionalformatwidget.ui
+            tests/src/python/test_qgsconditionalstyle.py
 
 Nathan Woodrow <madmanwoo at gmail.com>	2015-08-23
 
@@ -24131,7 +24413,7 @@ Alexander Bruy <alexander.bruy at gmail.com>	2015-05-27
     Merge branch 'master' of https://github.com/scubbx/QGIS into processing-r.stat
 
     Conflicts:
-python/plugins/processing/algs/grass7/Grass7Algorithm.py
+            python/plugins/processing/algs/grass7/Grass7Algorithm.py
 
 Nyall Dawson <nyall.dawson at gmail.com>	2015-05-27
 
@@ -26888,7 +27170,7 @@ Alexander Bruy <alexander.bruy at gmail.com>	2015-04-02
     Merge branch 'master' of https://github.com/gbd-consult/QGIS into ftools-enhancements
 
     Conflicts:
-python/plugins/fTools/tools/doPointsInPolygon.py
+            python/plugins/fTools/tools/doPointsInPolygon.py
 
 Anatoliy Golubev <darth.naihil at gmail.com>	2015-04-01
 
@@ -27922,7 +28204,7 @@ Alexander Bruy <alexander.bruy at gmail.com>	2015-02-24
     Merge branch 'processing_import_geomless_tables_in_postgresql_2' of https://github.com/gioman/QGIS into geometry-less-import
 
     Conflicts:
-python/plugins/processing/algs/gdal/GdalOgrAlgorithmProvider.py
+            python/plugins/processing/algs/gdal/GdalOgrAlgorithmProvider.py
 
 Merge: 8ab014d b4f2568
 Alexander Bruy <alexander.bruy at gmail.com>	2015-02-24
@@ -27953,7 +28235,7 @@ Alexander Bruy <alexander.bruy at gmail.com>	2015-02-24
     Merge branch 'processing_add_gdal_raster_calc' of https://github.com/gioman/QGIS into gdal_calc
 
     Conflicts:
-python/plugins/processing/algs/gdal/GdalOgrAlgorithmProvider.py
+            python/plugins/processing/algs/gdal/GdalOgrAlgorithmProvider.py
 
 Merge: 33c6051 bf08b7b
 alexbruy <alexander.bruy at gmail.com>	2015-02-24
@@ -29711,7 +29993,7 @@ Michael Kirk <michael.john.kirk at gmail.com>	2015-01-26
     Merge remote-tracking branch 'upstream/master' into feature/export-png-first-8493
 
     Conflicts:
-src/gui/qgisgui.h
+            src/gui/qgisgui.h
 
 Juergen E. Fischer <jef at norbit.de>	2015-01-27
 
@@ -33538,7 +33820,7 @@ Martin Dobias <wonder.sk at gmail.com>	2014-11-15
     Merge remote-tracking branch 'rldhont/filter_legend_displacement_point2'
 
     Conflicts:
-src/core/qgsmaphittest.cpp
+            src/core/qgsmaphittest.cpp
 
 Matthias Kuhn <matthias.kuhn at gmx.ch>	2014-11-14
 
@@ -34047,7 +34329,7 @@ elpaso <apasotti at gmail.com>	2014-10-09
       response headers and body
 
     Conflicts:
-src/mapserver/qgswmsserver.cpp
+            src/mapserver/qgswmsserver.cpp
 
     Funded by ItOpen - http://www.itopen.it
 
@@ -37678,9 +37960,9 @@ Martin Dobias <wonder.sk at gmail.com>	2014-09-13
     Merge remote-tracking branch 'rouault/use_geos_reentrant_api'
 
     Conflicts:
-src/core/pal/layer.cpp
-src/core/qgsgeometry.cpp
-src/core/qgspallabeling.cpp
+            src/core/pal/layer.cpp
+            src/core/qgsgeometry.cpp
+            src/core/qgspallabeling.cpp
 
 Martin Dobias <wonder.sk at gmail.com>	2014-09-13
 
@@ -38309,8 +38591,8 @@ Denis Rouzaud <denis.rouzaud at gmail.com>	2014-08-27
     [map layer actions] action for group of features, rename availability to target (flags), only emit signal for defined target"
 
     Conflicts:
-src/gui/qgsmaplayeractionregistry.cpp
-src/gui/qgsmaplayeractionregistry.h
+            src/gui/qgsmaplayeractionregistry.cpp
+            src/gui/qgsmaplayeractionregistry.h
 
 Nyall Dawson <nyall.dawson at gmail.com>	2014-09-01
 
@@ -41903,7 +42185,7 @@ Martin Dobias <wonder.sk at gmail.com>	2014-06-15
     Merge remote-tracking branch 'edigonzales/master'
 
     Conflicts:
-src/core/symbology-ng/qgslinesymbollayerv2.cpp
+            src/core/symbology-ng/qgslinesymbollayerv2.cpp
 
 Merge: 6c21262 7bec7c2
 Werner Macho <werner.macho at gmail.com>	2014-06-15
@@ -42545,11 +42827,11 @@ Martin Dobias <wonder.sk at gmail.com>	2014-06-10
     Fix #10355 (crash) and #10338 (overlapping polygons) in inverted polygon renderer
 
     Conflicts:
-python/core/symbology-ng/qgsinvertedpolygonrenderer.sip
-src/core/symbology-ng/qgsinvertedpolygonrenderer.cpp
-src/core/symbology-ng/qgsinvertedpolygonrenderer.h
-src/gui/symbology-ng/qgsinvertedpolygonrendererwidget.cpp
-src/gui/symbology-ng/qgsinvertedpolygonrendererwidget.h
+            python/core/symbology-ng/qgsinvertedpolygonrenderer.sip
+            src/core/symbology-ng/qgsinvertedpolygonrenderer.cpp
+            src/core/symbology-ng/qgsinvertedpolygonrenderer.h
+            src/gui/symbology-ng/qgsinvertedpolygonrendererwidget.cpp
+            src/gui/symbology-ng/qgsinvertedpolygonrendererwidget.h
 
 Martin Dobias <wonder.sk at gmail.com>	2014-06-10
 
@@ -43436,7 +43718,7 @@ Martin Dobias <wonder.sk at gmail.com>	2014-05-30
     Merge remote-tracking branch 'alvaro/Simplification_MTR'
 
     Conflicts:
-python/core/qgsmapsettings.sip
+            python/core/qgsmapsettings.sip
 
 Martin Dobias <wonder.sk at gmail.com>	2014-05-30
 
@@ -44364,7 +44646,7 @@ Martin Dobias <wonder.sk at gmail.com>	2014-05-21
     - controlling of map canvas: QgsLayerTreeCanvasBridge
 
     Conflicts:
-src/ui/qgisapp.ui
+            src/ui/qgisapp.ui
 
 Martin Dobias <wonder.sk at gmail.com>	2014-05-21
 
@@ -46926,7 +47208,7 @@ Marcel Dancak <marcel.dancak at gista.sk>	2014-04-07
     Merge remote-tracking branch 'origin/master'
 
     Conflicts:
-src/mapserver/qgswmsserver.cpp
+            src/mapserver/qgswmsserver.cpp
 
 Merge: 3e4b568 1399c6e
 mhugent <marco.hugentobler at sourcepole.ch>	2014-04-07
@@ -49009,13 +49291,13 @@ Martin Dobias <wonder.sk at gmail.com>	2014-02-23
     Merge remote-tracking branch 'origin/master' into threading-revival
 
     Conflicts:
-src/core/qgspallabeling.cpp
-src/core/qgsrenderchecker.h
-src/core/qgsvectorlayer.cpp
-src/core/symbology-ng/qgslinesymbollayerv2.cpp
-src/core/symbology-ng/qgssymbollayerv2.cpp
-src/providers/wms/qgswmsdataitems.cpp
-tests/src/core/testqgsblendmodes.cpp
+            src/core/qgspallabeling.cpp
+            src/core/qgsrenderchecker.h
+            src/core/qgsvectorlayer.cpp
+            src/core/symbology-ng/qgslinesymbollayerv2.cpp
+            src/core/symbology-ng/qgssymbollayerv2.cpp
+            src/providers/wms/qgswmsdataitems.cpp
+            tests/src/core/testqgsblendmodes.cpp
 
 Matthias Kuhn <matthias.kuhn at gmx.ch>	2014-02-23
 
@@ -49741,75 +50023,75 @@ Martin Dobias <wonder.sk at gmail.com>	2014-02-18
     Some features are still disabled - will be fixed later
 
     Conflicts:
-python/core/composer/qgscomposition.sip
-python/core/diagram/qgsdiagram.sip
-python/core/diagram/qgshistogramdiagram.sip
-python/core/diagram/qgspiediagram.sip
-python/core/diagram/qgstextdiagram.sip
-python/core/qgsdiagramrendererv2.sip
-python/core/qgsfield.sip
-python/core/qgslabelsearchtree.sip
-python/core/qgsmaprenderer.sip
-python/core/qgsrenderchecker.sip
-python/core/symbology-ng/qgssymbollayerv2.sip
-python/gui/qgsmapcanvas.sip
-src/app/composer/qgscomposerlegendwidget.cpp
-src/app/qgisapp.cpp
-src/core/composer/qgsatlascomposition.cpp
-src/core/composer/qgscomposerattributetable.cpp
-src/core/composer/qgscomposermap.cpp
-src/core/composer/qgscomposition.cpp
-src/core/composer/qgscomposition.h
-src/core/diagram/qgsdiagram.h
-src/core/diagram/qgshistogramdiagram.cpp
-src/core/diagram/qgshistogramdiagram.h
-src/core/diagram/qgspiediagram.cpp
-src/core/diagram/qgspiediagram.h
-src/core/diagram/qgstextdiagram.cpp
-src/core/diagram/qgstextdiagram.h
-src/core/qgsdiagramrendererv2.cpp
-src/core/qgsdiagramrendererv2.h
-src/core/qgsmaprenderer.cpp
-src/core/qgsmaprenderer.h
-src/core/qgsnetworkaccessmanager.h
-src/core/qgspallabeling.cpp
-src/core/qgsrenderchecker.h
-src/core/qgsvectorlayer.cpp
-src/core/qgsvectorlayer.h
-src/core/qgsvectorlayerfeatureiterator.cpp
-src/core/qgsvectorlayerfeatureiterator.h
-src/core/raster/qgsrasterlayer.cpp
-src/core/symbology-ng/qgscategorizedsymbolrendererv2.cpp
-src/core/symbology-ng/qgsgraduatedsymbolrendererv2.cpp
-src/core/symbology-ng/qgsmarkersymbollayerv2.cpp
-src/core/symbology-ng/qgssinglesymbolrendererv2.cpp
-src/core/symbology-ng/qgssymbollayerv2.cpp
-src/core/symbology-ng/qgssymbollayerv2.h
-src/core/symbology-ng/qgssymbolv2.cpp
-src/gui/qgshighlight.cpp
-src/gui/qgsmapcanvas.cpp
-src/gui/qgsmapcanvas.h
-src/gui/qgsmapcanvasitem.cpp
-src/gui/qgsmaptoolidentify.cpp
-src/plugins/georeferencer/qgsgeorefplugingui.cpp
-src/providers/memory/qgsmemoryfeatureiterator.cpp
-src/providers/ogr/qgsogrfeatureiterator.cpp
-src/providers/ogr/qgsogrfeatureiterator.h
-src/providers/ogr/qgsogrprovider.cpp
-src/providers/oracle/qgsoraclefeatureiterator.cpp
-src/providers/oracle/qgsoracleprovider.cpp
-src/providers/postgres/qgspostgresconn.cpp
-src/providers/postgres/qgspostgresfeatureiterator.cpp
-src/providers/postgres/qgspostgresfeatureiterator.h
-src/providers/wfs/qgswfsfeatureiterator.cpp
-src/providers/wms/qgswmsprovider.cpp
-src/providers/wms/qgswmsprovider.h
-src/ui/qgsoptionsbase.ui
-tests/src/core/CMakeLists.txt
-tests/src/core/testqgscomposereffects.cpp
-tests/src/core/testqgscomposerhtml.cpp
-tests/src/core/testqgscomposerscalebar.cpp
-tests/src/core/testqgscomposershapes.cpp
+            python/core/composer/qgscomposition.sip
+            python/core/diagram/qgsdiagram.sip
+            python/core/diagram/qgshistogramdiagram.sip
+            python/core/diagram/qgspiediagram.sip
+            python/core/diagram/qgstextdiagram.sip
+            python/core/qgsdiagramrendererv2.sip
+            python/core/qgsfield.sip
+            python/core/qgslabelsearchtree.sip
+            python/core/qgsmaprenderer.sip
+            python/core/qgsrenderchecker.sip
+            python/core/symbology-ng/qgssymbollayerv2.sip
+            python/gui/qgsmapcanvas.sip
+            src/app/composer/qgscomposerlegendwidget.cpp
+            src/app/qgisapp.cpp
+            src/core/composer/qgsatlascomposition.cpp
+            src/core/composer/qgscomposerattributetable.cpp
+            src/core/composer/qgscomposermap.cpp
+            src/core/composer/qgscomposition.cpp
+            src/core/composer/qgscomposition.h
+            src/core/diagram/qgsdiagram.h
+            src/core/diagram/qgshistogramdiagram.cpp
+            src/core/diagram/qgshistogramdiagram.h
+            src/core/diagram/qgspiediagram.cpp
+            src/core/diagram/qgspiediagram.h
+            src/core/diagram/qgstextdiagram.cpp
+            src/core/diagram/qgstextdiagram.h
+            src/core/qgsdiagramrendererv2.cpp
+            src/core/qgsdiagramrendererv2.h
+            src/core/qgsmaprenderer.cpp
+            src/core/qgsmaprenderer.h
+            src/core/qgsnetworkaccessmanager.h
+            src/core/qgspallabeling.cpp
+            src/core/qgsrenderchecker.h
+            src/core/qgsvectorlayer.cpp
+            src/core/qgsvectorlayer.h
+            src/core/qgsvectorlayerfeatureiterator.cpp
+            src/core/qgsvectorlayerfeatureiterator.h
+            src/core/raster/qgsrasterlayer.cpp
+            src/core/symbology-ng/qgscategorizedsymbolrendererv2.cpp
+            src/core/symbology-ng/qgsgraduatedsymbolrendererv2.cpp
+            src/core/symbology-ng/qgsmarkersymbollayerv2.cpp
+            src/core/symbology-ng/qgssinglesymbolrendererv2.cpp
+            src/core/symbology-ng/qgssymbollayerv2.cpp
+            src/core/symbology-ng/qgssymbollayerv2.h
+            src/core/symbology-ng/qgssymbolv2.cpp
+            src/gui/qgshighlight.cpp
+            src/gui/qgsmapcanvas.cpp
+            src/gui/qgsmapcanvas.h
+            src/gui/qgsmapcanvasitem.cpp
+            src/gui/qgsmaptoolidentify.cpp
+            src/plugins/georeferencer/qgsgeorefplugingui.cpp
+            src/providers/memory/qgsmemoryfeatureiterator.cpp
+            src/providers/ogr/qgsogrfeatureiterator.cpp
+            src/providers/ogr/qgsogrfeatureiterator.h
+            src/providers/ogr/qgsogrprovider.cpp
+            src/providers/oracle/qgsoraclefeatureiterator.cpp
+            src/providers/oracle/qgsoracleprovider.cpp
+            src/providers/postgres/qgspostgresconn.cpp
+            src/providers/postgres/qgspostgresfeatureiterator.cpp
+            src/providers/postgres/qgspostgresfeatureiterator.h
+            src/providers/wfs/qgswfsfeatureiterator.cpp
+            src/providers/wms/qgswmsprovider.cpp
+            src/providers/wms/qgswmsprovider.h
+            src/ui/qgsoptionsbase.ui
+            tests/src/core/CMakeLists.txt
+            tests/src/core/testqgscomposereffects.cpp
+            tests/src/core/testqgscomposerhtml.cpp
+            tests/src/core/testqgscomposerscalebar.cpp
+            tests/src/core/testqgscomposershapes.cpp
 
 Merge: 49fbfba f4f450f
 Martin Dobias <wonder.sk at gmail.com>	2014-02-18
@@ -53209,10 +53491,10 @@ Nathan Woodrow <nathan.woodrow at mapsolutions.com.au>	2014-01-03
 
     Update to new style side bar style for dialogs.
 
-- New blue-grey with white text style dialog
-- Side panel runs top to bottom
-- Icon size is read from settings
-- Option to disable in options dialog
+            - New blue-grey with white text style dialog
+            - Side panel runs top to bottom
+            - Icon size is read from settings
+            - Option to disable in options dialog
 
 elpaso <apasotti at gmail.com>	2014-01-06
 
@@ -53915,9 +54197,9 @@ Alvaro Huarte <ahuarte47 at yahoo.es>	2013-12-17
     Merge branch 'Issue_8725-OGR' of https://github.com/ahuarte47/QGIS into Issue_8725-OGR
 
     Conflicts:
-src/app/qgsoptions.cpp
-src/app/qgsoptions.h
-src/core/symbology-ng/qgssymbollayerv2.cpp
+            src/app/qgsoptions.cpp
+            src/app/qgsoptions.h
+            src/core/symbology-ng/qgssymbollayerv2.cpp
 
 ahuarte47 <ahuarte47 at yahoo.es>	2013-12-12
 
@@ -58292,7 +58574,7 @@ Marco Bernasocchi <marco at opengis.ch>	2013-05-18
 
 Marco Bernasocchi <marco at opengis.ch>	2013-05-03
 
-#7752 for android        sip generation issue fix
+    sip generation issue fix        #7752 for android
 
 Larry Shaffer <larrys at dakotacarto.com>	2013-09-09
 
@@ -61167,7 +61449,7 @@ Victor Olaya <volayaf at gmail.com>	2013-07-15
     This reverts commit 1c2e49ed249a89480c1195f50c96614dc72700d3.
 
     Conflicts:
-python/plugins/sextante/saga/SagaAlgorithm.py
+            python/plugins/sextante/saga/SagaAlgorithm.py
 
 pcav <cavallini at faunalia.it>	2013-07-18
 
@@ -62501,7 +62783,7 @@ yoichigmf <yoichi.kayama at gmail.com>	2013-07-02
     Merge branch 'master' of https://github.com/qgis/Quantum-GIS into make_pull_req_from_ja
 
     Conflicts:
-i18n/qgis_ja.ts
+            i18n/qgis_ja.ts
 
 Matthias Kuhn <matthias.kuhn at gmx.ch>	2013-07-02
 
@@ -64471,8 +64753,8 @@ Ivan Mincik <ivan.mincik at gmail.com>	2013-06-03
 Ivan Mincik <ivan.mincik at gmail.com>	2013-06-03
 
     First batch of Slovak translation for version 2.0.
-- translation
-- merge with 4b76600 (adding function_help, context_help)
+            - translation
+            - merge with 4b76600 (adding function_help, context_help)
 
 Merge: 21a884b d4945db
 Ivan Mincik <ivan.mincik at gmail.com>	2013-06-03
@@ -66648,7 +66930,7 @@ Emilio Loi <loi at faunalia.it>	2013-04-30
     Merge branch 'styles_to_db' of https://github.com/el1073/Quantum-GIS into styles_to_db
 
     Conflicts:
-src/core/qgsvectordataprovider.h
+            src/core/qgsvectordataprovider.h
 
 Emilio Loi <loi at faunalia.it>	2013-04-30
 
@@ -66660,9 +66942,9 @@ Emilio Loi <loi at faunalia.it>	2013-04-30
     Merge branch 'master' of https://github.com/qgis/Quantum-GIS into styles_to_db
 
     Conflicts:
-python/console/console_editor.py
-src/core/qgsvectordataprovider.h
-src/core/qgsvectorfilewriter.cpp
+            python/console/console_editor.py
+            src/core/qgsvectordataprovider.h
+            src/core/qgsvectorfilewriter.cpp
 
 Merge: c499df7 009ba1b
 Emilio Loi <loi at faunalia.it>	2013-04-30
@@ -66670,9 +66952,9 @@ Emilio Loi <loi at faunalia.it>	2013-04-30
     Merge branch 'master' of https://github.com/qgis/Quantum-GIS into styles_to_db
 
     Conflicts:
-python/console/console_editor.py
-src/core/qgsvectordataprovider.h
-src/core/qgsvectorfilewriter.cpp
+            python/console/console_editor.py
+            src/core/qgsvectordataprovider.h
+            src/core/qgsvectorfilewriter.cpp
 
 Merge: 7dc0e51 2f9cb93
 Matthias Kuhn <matthias.kuhn at gmx.ch>	2013-04-30
@@ -66738,42 +67020,42 @@ olivierdalang <olivier.dalang at gmail.com>	2013-04-24
     SVG : clean arrows
 
     Conflicts:
-images/svg/north_arrows/NorthArrow1.svg
-images/svg/north_arrows/NorthArrow10.svg
-images/svg/north_arrows/NorthArrow11.svg
-images/svg/north_arrows/NorthArrow12.svg
-images/svg/north_arrows/NorthArrow13.svg
-images/svg/north_arrows/NorthArrow14.svg
-images/svg/north_arrows/NorthArrow15.svg
-images/svg/north_arrows/NorthArrow16.svg
-images/svg/north_arrows/NorthArrow2.svg
-images/svg/north_arrows/NorthArrow4.svg
-images/svg/north_arrows/NorthArrow5.svg
-images/svg/north_arrows/NorthArrow6.svg
-images/svg/north_arrows/NorthArrow_blackgreenblack.svg
-images/svg/north_arrows/NorthArrow_blackwhiteblack.svg
-images/svg/north_arrows/NorthArrow_blackyellowblack.svg
-images/svg/north_arrows/NorthArrow_bluegreenblue.svg
-images/svg/north_arrows/NorthArrow_source.svg
-images/svg/north_arrows/default.svg
-images/svg/north_arrows/north-arrow_0_qgis_decoration.svg
-images/svg/north_arrows/north-arrow_10_with_map_layers.svg
-images/svg/north_arrows/north-arrow_11_simple_corner.svg
-images/svg/north_arrows/north-arrow_12_triangular_arrows_with_worldmap.svg
-images/svg/north_arrows/north-arrow_13_checkerboard_earth.svg
-images/svg/north_arrows/north-arrow_14_steering_wheel.svg
-images/svg/north_arrows/north-arrow_15_checkerboard_corner_arrows.svg
-images/svg/north_arrows/north-arrow_16_corner_arrows_unfilled_with_circle.svg
-images/svg/north_arrows/north-arrow_17_corner_n_e.svg
-images/svg/north_arrows/north-arrow_1_simple_half_arrow.svg
-images/svg/north_arrows/north-arrow_2_simple_half_arrow.svg
-images/svg/north_arrows/north-arrow_3_simple_symmetric_triangular.svg
-images/svg/north_arrows/north-arrow_4_double_arrow.svg
-images/svg/north_arrows/north-arrow_5_arrow_in_circle_small_n.svg
-images/svg/north_arrows/north-arrow_6_unfilled_big_arrow_symmetric.svg
-images/svg/north_arrows/north-arrow_7_big_circle_with_small_arrow_unfilled_n.svg
-images/svg/north_arrows/north-arrow_8_checkered.svg
-images/svg/north_arrows/north-arrow_9_half_arrow_unfilled.svg
+            images/svg/north_arrows/NorthArrow1.svg
+            images/svg/north_arrows/NorthArrow10.svg
+            images/svg/north_arrows/NorthArrow11.svg
+            images/svg/north_arrows/NorthArrow12.svg
+            images/svg/north_arrows/NorthArrow13.svg
+            images/svg/north_arrows/NorthArrow14.svg
+            images/svg/north_arrows/NorthArrow15.svg
+            images/svg/north_arrows/NorthArrow16.svg
+            images/svg/north_arrows/NorthArrow2.svg
+            images/svg/north_arrows/NorthArrow4.svg
+            images/svg/north_arrows/NorthArrow5.svg
+            images/svg/north_arrows/NorthArrow6.svg
+            images/svg/north_arrows/NorthArrow_blackgreenblack.svg
+            images/svg/north_arrows/NorthArrow_blackwhiteblack.svg
+            images/svg/north_arrows/NorthArrow_blackyellowblack.svg
+            images/svg/north_arrows/NorthArrow_bluegreenblue.svg
+            images/svg/north_arrows/NorthArrow_source.svg
+            images/svg/north_arrows/default.svg
+            images/svg/north_arrows/north-arrow_0_qgis_decoration.svg
+            images/svg/north_arrows/north-arrow_10_with_map_layers.svg
+            images/svg/north_arrows/north-arrow_11_simple_corner.svg
+            images/svg/north_arrows/north-arrow_12_triangular_arrows_with_worldmap.svg
+            images/svg/north_arrows/north-arrow_13_checkerboard_earth.svg
+            images/svg/north_arrows/north-arrow_14_steering_wheel.svg
+            images/svg/north_arrows/north-arrow_15_checkerboard_corner_arrows.svg
+            images/svg/north_arrows/north-arrow_16_corner_arrows_unfilled_with_circle.svg
+            images/svg/north_arrows/north-arrow_17_corner_n_e.svg
+            images/svg/north_arrows/north-arrow_1_simple_half_arrow.svg
+            images/svg/north_arrows/north-arrow_2_simple_half_arrow.svg
+            images/svg/north_arrows/north-arrow_3_simple_symmetric_triangular.svg
+            images/svg/north_arrows/north-arrow_4_double_arrow.svg
+            images/svg/north_arrows/north-arrow_5_arrow_in_circle_small_n.svg
+            images/svg/north_arrows/north-arrow_6_unfilled_big_arrow_symmetric.svg
+            images/svg/north_arrows/north-arrow_7_big_circle_with_small_arrow_unfilled_n.svg
+            images/svg/north_arrows/north-arrow_8_checkered.svg
+            images/svg/north_arrows/north-arrow_9_half_arrow_unfilled.svg
 
 olivierdalang <olivier.dalang at gmail.com>	2013-04-23
 
@@ -66853,7 +67135,7 @@ Emilio Loi <loi at faunalia.it>	2013-04-29
     Merge branch 'master' of https://github.com/qgis/Quantum-GIS into styles_to_db
 
     Conflicts:
-python/console/console_editor.py
+            python/console/console_editor.py
 
 Merge: 2232c3d 1959182
 Chris Crook <ccrook at linz.govt.nz>	2013-04-29
@@ -67007,9 +67289,9 @@ Emilio Loi <loi at faunalia.it>	2013-04-26
     Merge branch 'master' of https://github.com/qgis/Quantum-GIS into styles_to_db
 
     Conflicts:
-python/console/console_editor.py
-src/core/qgsvectordataprovider.h
-src/core/qgsvectorfilewriter.cpp
+            python/console/console_editor.py
+            src/core/qgsvectordataprovider.h
+            src/core/qgsvectorfilewriter.cpp
 
 Merge: 02fa729 f7cce9c
 Borys Jurgiel <info at borysjurgiel.pl>	2013-04-26
@@ -67142,7 +67424,7 @@ Nathan Woodrow <nathan.woodrow at mapsolutions.com.au>	2013-04-26
 
     Add workaround for loading forms with custom widgets from PyQt4
 
-More information: qt-project.org/forums/viewthread/27098/
+            More information: qt-project.org/forums/viewthread/27098/
 
 Matthias Kuhn <matthias.kuhn at gmx.ch>	2013-04-14
 
@@ -67330,7 +67612,7 @@ Emilio Loi <loi at faunalia.it>	2013-04-22
     Merge branch 'master' of git://github.com/qgis/Quantum-GIS into styles_to_db
 
     Conflicts:
-src/ui/qgsvectorlayerpropertiesbase.ui
+            src/ui/qgsvectorlayerpropertiesbase.ui
 
 Minoru Akagi <akaginch at gmail.com>	2013-04-22
 
@@ -69332,9 +69614,9 @@ Nathan Woodrow <woodrow.nathan at gmail.com>	2013-04-01
 
     Data defined symbol UI clean up
 
-- Reduce margins
-- Remove cell selection
-- Adjust first column width
+            - Reduce margins
+            - Remove cell selection
+            - Adjust first column width
 
 Merge: 6c3f418 7b6e322
 Tim Sutton <tim at linfiniti.com>	2013-04-01
@@ -69895,7 +70177,7 @@ vinayan <vinayan at vinayan-MS-7623.(none)>	2012-12-12
 
     Conflicts:
 
-src/plugins/CMakeLists.txt
+            src/plugins/CMakeLists.txt
 
     fixed issues in duplicate rule where zooming was not possible..renamed 'Test' to 'Rule'
 
@@ -72804,14 +73086,14 @@ Martin Dobias <wonder.sk at gmail.com>	2013-01-24
     Merge remote-tracking branch 'jef/oraclespatial-nva' into new_vector_api
 
     Conflicts:
-doc/TRANSLATORS
-i18n/qgis_de.ts
-src/app/qgisapp.cpp
-src/core/qgis.cpp
-src/core/qgsvectorlayerimport.cpp
-src/providers/oracle/CMakeLists.txt
-src/providers/oracle/qgsoracleprovider.cpp
-src/providers/oracle/qgsoracleprovider.h
+            doc/TRANSLATORS
+            i18n/qgis_de.ts
+            src/app/qgisapp.cpp
+            src/core/qgis.cpp
+            src/core/qgsvectorlayerimport.cpp
+            src/providers/oracle/CMakeLists.txt
+            src/providers/oracle/qgsoracleprovider.cpp
+            src/providers/oracle/qgsoracleprovider.h
 
 Merge: dda51c6 5f70a68
 Martin Dobias <wonder.sk at gmail.com>	2013-01-23
@@ -72819,16 +73101,16 @@ Martin Dobias <wonder.sk at gmail.com>	2013-01-23
     Merge remote-tracking branch 'origin/master' into new_vector_api
 
     Conflicts:
-python/core/qgsvectordataprovider.sip
-src/app/legend/qgslegendlayer.cpp
-src/app/qgisapp.cpp
-src/app/qgsmergeattributesdialog.cpp
-src/core/qgsvectordataprovider.cpp
-src/core/qgsvectordataprovider.h
-src/core/qgsvectorlayer.cpp
-src/gui/qgssearchquerybuilder.cpp
-src/providers/postgres/qgspostgresprovider.cpp
-src/providers/wfs/CMakeLists.txt
+            python/core/qgsvectordataprovider.sip
+            src/app/legend/qgslegendlayer.cpp
+            src/app/qgisapp.cpp
+            src/app/qgsmergeattributesdialog.cpp
+            src/core/qgsvectordataprovider.cpp
+            src/core/qgsvectordataprovider.h
+            src/core/qgsvectorlayer.cpp
+            src/gui/qgssearchquerybuilder.cpp
+            src/providers/postgres/qgspostgresprovider.cpp
+            src/providers/wfs/CMakeLists.txt
 
 Tim Sutton <tim at linfiniti.com>	2013-01-24
 
@@ -72979,9 +73261,9 @@ Victor Olaya <volayaf at gmail.com>	2013-01-21
     Merge branch 'master' of https://github.com/qgis/Quantum-GIS
 
     Conflicts:
-python/plugins/sextante/algs/ftools/Difference.py
-python/plugins/sextante/algs/ftools/Intersection.py
-python/plugins/sextante/outputs/OutputTable.py
+            python/plugins/sextante/algs/ftools/Difference.py
+            python/plugins/sextante/algs/ftools/Intersection.py
+            python/plugins/sextante/outputs/OutputTable.py
 
 Victor Olaya <volayaf at gmail.com>	2013-01-21
 
@@ -73678,27 +73960,27 @@ Martin Dobias <wonder.sk at gmail.com>	2012-12-18
     Fixed tests.
 
     Conflicts:
-src/app/legend/qgslegendlayer.cpp
-src/app/qgsattributedialog.cpp
-src/app/qgsattributedialog.h
-src/app/qgslabelpropertydialog.cpp
-src/app/qgsmaptoollabel.cpp
-src/app/qgsvectorlayerproperties.cpp
-src/core/CMakeLists.txt
-src/core/composer/qgsatlascomposition.cpp
-src/core/qgsexpression.cpp
-src/core/qgspallabeling.cpp
-src/core/qgsvectorlayer.cpp
-src/core/qgsvectorlayer.h
-src/core/qgsvectorlayerimport.cpp
-src/mapserver/qgsprojectparser.cpp
-src/mapserver/qgswfsserver.cpp
-src/mapserver/qgswfsserver.h
-src/mapserver/qgswmsserver.cpp
-src/providers/postgres/qgspostgresprovider.cpp
-src/providers/spatialite/qgsspatialiteprovider.h
-tests/src/core/testqgsexpression.cpp
-tests/src/python/test_qgsmemoryprovider.py
+            src/app/legend/qgslegendlayer.cpp
+            src/app/qgsattributedialog.cpp
+            src/app/qgsattributedialog.h
+            src/app/qgslabelpropertydialog.cpp
+            src/app/qgsmaptoollabel.cpp
+            src/app/qgsvectorlayerproperties.cpp
+            src/core/CMakeLists.txt
+            src/core/composer/qgsatlascomposition.cpp
+            src/core/qgsexpression.cpp
+            src/core/qgspallabeling.cpp
+            src/core/qgsvectorlayer.cpp
+            src/core/qgsvectorlayer.h
+            src/core/qgsvectorlayerimport.cpp
+            src/mapserver/qgsprojectparser.cpp
+            src/mapserver/qgswfsserver.cpp
+            src/mapserver/qgswfsserver.h
+            src/mapserver/qgswmsserver.cpp
+            src/providers/postgres/qgspostgresprovider.cpp
+            src/providers/spatialite/qgsspatialiteprovider.h
+            tests/src/core/testqgsexpression.cpp
+            tests/src/python/test_qgsmemoryprovider.py
 
 Martin Dobias <wonder.sk at gmail.com>	2012-12-17
 
@@ -74494,7 +74776,7 @@ Victor Olaya <volayaf at gmail.com>	2012-12-15
     Merge branch 'master' of https://github.com/qgis/Quantum-GIS
 
     Conflicts:
-python/plugins/sextante/grass/ext/CMakeLists.txt
+            python/plugins/sextante/grass/ext/CMakeLists.txt
 
 Victor Olaya <volayaf at gmail.com>	2012-12-15
 
@@ -74673,7 +74955,7 @@ Victor Olaya <volayaf at gmail.com>	2012-12-12
     Merge branch 'master' of https://github.com/qgis/Quantum-GIS
 
     Conflicts:
-python/plugins/sextante/grass/GrassAlgorithm.py
+            python/plugins/sextante/grass/GrassAlgorithm.py
 
 Victor Olaya <volayaf at gmail.com>	2012-12-12
 
@@ -74704,7 +74986,7 @@ Hugo Mercier <hugo.mercier at oslandia.com>	2012-12-11
     Merge branch 'master' of https://github.com/qgis/Quantum-GIS
 
     Conflicts:
-src/core/composer/qgsatlascomposition.cpp
+            src/core/composer/qgsatlascomposition.cpp
 
 Hugo Mercier <hugo.mercier at oslandia.com>	2012-12-11
 
@@ -78535,8 +78817,8 @@ Hugo Mercier <hugo.mercier at oslandia.com>	2012-10-04
     Merge branch 'atlas' into atlas2
 
     Conflicts:
-python/core/composer/qgscomposition.sip
-tests/src/python/CMakeLists.txt
+            python/core/composer/qgscomposition.sip
+            tests/src/python/CMakeLists.txt
 
 Hugo Mercier <hugo.mercier at oslandia.com>	2012-10-04
 
@@ -78946,7 +79228,7 @@ Hugo Mercier <hugo.mercier at oslandia.com>	2012-09-28
     Merge branch 'master' of https://github.com/qgis/Quantum-GIS into atlas
 
     Conflicts:
-src/core/composer/qgscomposition.cpp
+            src/core/composer/qgscomposition.cpp
 
 Hugo Mercier <hugo.mercier at oslandia.com>	2012-09-28
 
@@ -79130,7 +79412,7 @@ Hugo Mercier <hugo.mercier at oslandia.com>	2012-09-26
     Merge branch 'master' of https://github.com/qgis/Quantum-GIS into atlas
 
     Conflicts:
-python/core/qgsexpression.sip
+            python/core/qgsexpression.sip
 
     Add a missing function to QgsExpression
 
@@ -81123,7 +81405,7 @@ Matthias Kuhn <matthias.kuhn at gmx.ch>	2012-08-29
     Merge branch 'master' of https://github.com/matthias-kuhn/Quantum-GIS
 
     Conflicts:
-src/app/qgsdiagramproperties.cpp
+            src/app/qgsdiagramproperties.cpp
 
 Merge: c8a3321 b97f2fc
 Matthias Kuhn <matthias.kuhn at gmx.ch>	2012-08-29
@@ -81874,7 +82156,7 @@ Matthias Kuhn <matthias.kuhn at gmx.ch>	2012-08-16
     Merge diagram icons
 
     Conflicts:
-src/app/qgsdiagramproperties.cpp
+            src/app/qgsdiagramproperties.cpp
 
 Matthias Kuhn <matthias.kuhn at gmx.ch>	2012-08-16
 
@@ -81986,7 +82268,7 @@ Martin Dobias <wonder.sk at gmail.com>	2012-08-14
     Merge remote-tracking branch 'arun/gsoc'
 
     Conflicts:
-src/gui/symbology-ng/qgssymbolv2selectordialog.cpp
+            src/gui/symbology-ng/qgssymbolv2selectordialog.cpp
 
 Radim Blazek <radim.blazek at gmail.com>	2012-08-14
 
@@ -83383,7 +83665,7 @@ Hugo Mercier <hugo.mercier at oslandia.com>	2012-07-25
     Merge branch 'master' of git://github.com/qgis/Quantum-GIS
 
     Conflicts:
-src/core/symbology-ng/qgsrulebasedrendererv2.cpp
+            src/core/symbology-ng/qgsrulebasedrendererv2.cpp
 
 Merge: d039c3f 1bcd947
 Marco Hugentobler <marco.hugentobler at sourcepole.ch>	2012-07-25
@@ -91637,7 +91919,7 @@ Martin Dobias <wonder.sk at gmail.com>	2012-01-24
     [FEATURE] Merge branch 'rules' - new rule-based rendering
 
     Conflicts:
-src/gui/symbology-ng/qgsgraduatedsymbolrendererv2widget.cpp
+            src/gui/symbology-ng/qgsgraduatedsymbolrendererv2widget.cpp
 
 Martin Dobias <wonder.sk at gmail.com>	2012-01-24
 
@@ -92450,7 +92732,7 @@ Marco Bernasocchi <marco at bernawebdesign.ch>	2012-01-05
     Merge branch 'master' of https://github.com/qgis/Quantum-GIS into android
 
     Conflicts:
-src/ui/qgsnewspatialitelayerdialogbase.ui
+            src/ui/qgsnewspatialitelayerdialogbase.ui
 
 Marco Hugentobler <marco.hugentobler at sourcepole.ch>	2012-01-05
 
@@ -94671,8 +94953,8 @@ Nathan Woodrow <madmanwoo at gmail.com>	2011-10-18
     Merge remote-tracking branch 'upstream/master' into expression-labels
 
     Conflicts:
-src/core/qgsexpression.cpp
-src/gui/CMakeLists.txt
+            src/core/qgsexpression.cpp
+            src/gui/CMakeLists.txt
 
 Nathan Woodrow <madmanwoo at gmail.com>	2011-10-18
 
@@ -94903,7 +95185,7 @@ Giuseppe Sucameli <brush.tyler at gmail.com>	2011-10-07
     Merge remote-tracking branch 'brushtyler/master'
 
     Conflicts:
-src/providers/postgres/qgspostgresprovider.cpp
+            src/providers/postgres/qgspostgresprovider.cpp
 
 Giuseppe Sucameli <brush.tyler at gmail.com>	2011-10-07
 
@@ -94940,7 +95222,7 @@ Sergey Yakushevs <yakushevs at list.ru>	2011-10-04
     Merge remote branch 'pb/master'
 
     Conflicts:
-src/plugins/roadgraph/linevectorlayerdirector.cpp
+            src/plugins/roadgraph/linevectorlayerdirector.cpp
 
 Martin Dobias <wonder.sk at gmail.com>	2011-10-03
 
@@ -95081,13 +95363,13 @@ Sergey Yakushevs <yakushevs at list.ru>	2011-09-27
     Merge remote branch 'pb/master' into network-analysis
 
     Conflicts:
-python/CMakeLists.txt
-src/analysis/network/qgsgraphbuilder.h
-src/plugins/roadgraph/graphbuilder.h
-src/plugins/roadgraph/linevectorlayerdirector.cpp
-src/plugins/roadgraph/simplegraphbuilder.cpp
-src/plugins/roadgraph/utils.cpp
-src/plugins/roadgraph/utils.h
+            python/CMakeLists.txt
+            src/analysis/network/qgsgraphbuilder.h
+            src/plugins/roadgraph/graphbuilder.h
+            src/plugins/roadgraph/linevectorlayerdirector.cpp
+            src/plugins/roadgraph/simplegraphbuilder.cpp
+            src/plugins/roadgraph/utils.cpp
+            src/plugins/roadgraph/utils.h
 
 Nathan Woodrow <madmanwoo at gmail.com>	2011-09-26
 
@@ -95425,7 +95707,7 @@ Martin Dobias <wonder.sk at gmail.com>	2011-08-30
     Merge remote-tracking branch 'remotes/giuseppe/dataitems' into dataitems
 
     Conflicts:
-src/app/CMakeLists.txt
+            src/app/CMakeLists.txt
 
 Martin Dobias <wonder.sk at gmail.com>	2011-08-30
 
@@ -95892,9 +96174,9 @@ NathanW <woodrow.nathan at gmail.com>	2011-08-08
     Merge remote branch 'upstream/master' into expression-labels
 
     Conflicts:
-src/core/qgspallabeling.cpp
-src/gui/CMakeLists.txt
-src/ui/qgslabelingguibase.ui
+            src/core/qgspallabeling.cpp
+            src/gui/CMakeLists.txt
+            src/ui/qgslabelingguibase.ui
 
 marco <marco at marco-laptop.(none)>	2011-08-08
 
@@ -97099,7 +97381,7 @@ NathanW <woodrow.nathan at gmail.com>	2011-07-03
     Fixed merge conflict in pallabeling
 
     Conflicts:
-src/core/qgspallabeling.cpp
+            src/core/qgspallabeling.cpp
 
 Marco Hugentobler <marco.hugentobler at sourcepole.ch>	2011-07-02
 
@@ -97959,13 +98241,13 @@ Sergey Yakushevs <yakushevs at list.ru>	2011-05-31
     Merge remote branch 'pb/master' into network-analysis
 
     Conflicts:
-src/analysis/network/qgsdistanceedgeproperter.cpp
-src/analysis/network/qgsgraphbuilder.h
-src/plugins/roadgraph/graphbuilder.h
-src/plugins/roadgraph/linevectorlayerdirector.cpp
-src/plugins/roadgraph/roadgraphplugin.cpp
-src/plugins/roadgraph/shortestpathwidget.cpp
-src/plugins/roadgraph/simplegraphbuilder.cpp
+            src/analysis/network/qgsdistanceedgeproperter.cpp
+            src/analysis/network/qgsgraphbuilder.h
+            src/plugins/roadgraph/graphbuilder.h
+            src/plugins/roadgraph/linevectorlayerdirector.cpp
+            src/plugins/roadgraph/roadgraphplugin.cpp
+            src/plugins/roadgraph/shortestpathwidget.cpp
+            src/plugins/roadgraph/simplegraphbuilder.cpp
 
 Merge: 8bbdde6 c8dd587
 Sergey Yakushevs <yakushevs at list.ru>	2011-05-31
@@ -97973,7 +98255,7 @@ Sergey Yakushevs <yakushevs at list.ru>	2011-05-31
     Merge remote branch 'pb/master'
 
     Conflicts:
-src/plugins/roadgraph/linevectorlayerdirector.cpp
+            src/plugins/roadgraph/linevectorlayerdirector.cpp
 
 Marco Hugentobler <marco.hugentobler at sourcepole.ch>	2011-05-31
 
@@ -98424,12 +98706,12 @@ Martin Dobias <wonder.sk at gmail.com>	2011-05-13
     Merge branch 'master' into dbl
 
     Conflicts:
-images/splash/splash.png
-src/CMakeLists.txt
-src/app/main.cpp
-src/app/qgsvectorlayerproperties.cpp
-src/core/qgsvectorlayer.cpp
-src/providers/wms/qgswmssourceselect.cpp
+            images/splash/splash.png
+            src/CMakeLists.txt
+            src/app/main.cpp
+            src/app/qgsvectorlayerproperties.cpp
+            src/core/qgsvectorlayer.cpp
+            src/providers/wms/qgswmssourceselect.cpp
 
 Martin Dobias <wonder.sk at gmail.com>	2011-05-13
 
@@ -104210,7 +104492,7 @@ gsherman <gsherman at c8812cc2-4d05-0410-92ff-de0c093fc19c>	2010-12-11
     Merge branch 'master' of github.com:qgis/qgis
 
     Conflicts:
-README
+            README
 
     git-svn-id: http://svn.osgeo.org/qgis/trunk@14888 c8812cc2-4d05-0410-92ff-de0c093fc19c
 
@@ -173245,7 +173527,7 @@ gsherman <gsherman at c8812cc2-4d05-0410-92ff-de0c093fc19c>	2004-03-01
 
     1. Added bounds checking for selecting features.
     2. Created wkbPoint structure for building WKB (well known binary) representation
- of the point.
+             of the point.
     3. Implementation is not complete.
 
 
diff --git a/debian/changelog b/debian/changelog
index 4941a01..97463cb 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,8 +1,14 @@
-qgis (2.14.6) UNRELEASED; urgency=medium
+qgis (2.14.7) UNRELEASED; urgency=medium
+
+  * Release of 2.14.7
+
+ -- Jürgen E. Fischer <jef at norbit.de>  Fri, 23 Sep 2016 20:23:30 +0200
+
+qgis (2.14.6) unstable; urgency=medium
 
   * Release of 2.14.6
 
- -- Jürgen E. Fischer <jef at norbit.de>  Fri, 26 Aug 2016 13:57:14 +0200
+ -- Jürgen E. Fischer <jef at norbit.de>  Fri, 23 Sep 2016 20:23:29 +0200
 
 qgis (2.14.5) unstable; urgency=medium
 
diff --git a/debian/python-qgis.install.in b/debian/python-qgis.install.in
index 87920d8..a5d64e1 100644
--- a/debian/python-qgis.install.in
+++ b/debian/python-qgis.install.in
@@ -9,3 +9,4 @@ 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
+#sid stretch#usr/lib/python*/*-packages/PyQt4/*.so
diff --git a/debian/rules b/debian/rules
index 1d87840..508e06c 100755
--- a/debian/rules
+++ b/debian/rules
@@ -110,6 +110,10 @@ ifneq (,$(findstring $(DISTRIBUTION),"sid stretch"))
 	CMAKE_OPTS += -DPOSTGRES_LIBRARY=/usr/lib/$(DEB_BUILD_MULTIARCH)/libpq.so
 endif
 
+ifneq (,$(findstring $(DISTRIBUTION),"sid stretch"))
+	CMAKE_OPTS += -DWITH_INTERNAL_WEBKIT_BINDINGS=TRUE
+endif
+
 ifneq (,$(findstring $(DISTRIBUTION),"sid"))
 	CMAKE_OPTS += -DGEOS_LIBRARY=/usr/lib/$(DEB_BUILD_MULTIARCH)/libgeos_c.so
 endif
diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt
index 1d04545..df06f1d 100644
--- a/python/CMakeLists.txt
+++ b/python/CMakeLists.txt
@@ -307,3 +307,15 @@ FOREACH(module ${PY_MODULES})
   ENDFOREACH(pyfile)
   PY_COMPILE(py${module} "${QGIS_PYTHON_OUTPUT_DIRECTORY}/${module}")
 ENDFOREACH(module)
+
+SET (WITH_INTERNAL_WEBKIT_BINDINGS FALSE CACHE BOOL "Build internal QtWebKit bindings")
+IF(WITH_INTERNAL_WEBKIT_BINDINGS)
+  INCLUDE_DIRECTORIES(${QT_QTWEBKIT_INCLUDE_DIR})
+  FILE(GLOB_RECURSE sip_files_qtwebkit QtWebKit/*.sip)
+  SET(SIP_EXTRA_FILES_DEPEND ${sip_files_qtwebkit})
+  SET(SIP_EXTRA_OPTIONS ${PYQT_SIP_FLAGS} -o -a ${CMAKE_BINARY_DIR}/python/PyQt4.QtWebKit.api)
+
+  SET (CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PYTHON_OUTPUT_DIRECTORY}/PyQt4)
+  SET (CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PYTHON_OUTPUT_DIRECTORY}/PyQt4)
+  ADD_SIP_PYTHON_MODULE(PyQt4.QtWebKit QtWebKit/QtWebKitmod.sip QtWebKit QtCore QtGui QtNetwork)
+ENDIF(WITH_INTERNAL_WEBKIT_BINDINGS)
diff --git a/python/QtWebKit/QtWebKitmod.sip b/python/QtWebKit/QtWebKitmod.sip
new file mode 100644
index 0000000..dbb17f3
--- /dev/null
+++ b/python/QtWebKit/QtWebKitmod.sip
@@ -0,0 +1,63 @@
+// QtWebKitmod.sip generated by MetaSIP
+//
+// This file is part of the QtWebKit Python extension module.
+//
+// Copyright (c) 2015 Riverbank Computing Limited <info at riverbankcomputing.com>
+//
+// This file is part of PyQt4.
+//
+// This file may be used under the terms of the GNU General Public License
+// version 3.0 as published by the Free Software Foundation and appearing in
+// the file LICENSE included in the packaging of this file.  Please review the
+// following information to ensure the GNU General Public License version 3.0
+// requirements will be met: http://www.gnu.org/copyleft/gpl.html.
+//
+// If you do not wish to use this file under the terms of the GPL version 3.0
+// then you may purchase a commercial license.  For more information contact
+// info at riverbankcomputing.com.
+//
+// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+
+
+%Module(name=PyQt4.QtWebKit, keyword_arguments="Optional")
+
+%Import QtCore/QtCoremod.sip
+%Import QtGui/QtGuimod.sip
+%Import QtNetwork/QtNetworkmod.sip
+
+%Copying
+Copyright (c) 2015 Riverbank Computing Limited <info at riverbankcomputing.com>
+
+This file is part of PyQt4.
+
+This file may be used under the terms of the GNU General Public License
+version 3.0 as published by the Free Software Foundation and appearing in
+the file LICENSE included in the packaging of this file.  Please review the
+following information to ensure the GNU General Public License version 3.0
+requirements will be met: http://www.gnu.org/copyleft/gpl.html.
+
+If you do not wish to use this file under the terms of the GPL version 3.0
+then you may purchase a commercial license.  For more information contact
+info at riverbankcomputing.com.
+
+This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+%End
+
+%DefaultSupertype sip.simplewrapper
+
+%Include qgraphicswebview.sip
+%Include qwebdatabase.sip
+%Include qwebelement.sip
+%Include qwebframe.sip
+%Include qwebkitglobal.sip
+%Include qwebhistory.sip
+%Include qwebhistoryinterface.sip
+%Include qwebinspector.sip
+%Include qwebkitversion.sip
+%Include qwebpage.sip
+%Include qwebpluginfactory.sip
+%Include qwebsecurityorigin.sip
+%Include qwebsettings.sip
+%Include qwebview.sip
diff --git a/python/QtWebKit/__init__.py b/python/QtWebKit/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/python/QtWebKit/qgraphicswebview.sip b/python/QtWebKit/qgraphicswebview.sip
new file mode 100644
index 0000000..e006416
--- /dev/null
+++ b/python/QtWebKit/qgraphicswebview.sip
@@ -0,0 +1,150 @@
+// qgraphicswebview.sip generated by MetaSIP
+//
+// This file is part of the QtWebKit Python extension module.
+//
+// Copyright (c) 2015 Riverbank Computing Limited <info at riverbankcomputing.com>
+//
+// This file is part of PyQt4.
+//
+// This file may be used under the terms of the GNU General Public License
+// version 3.0 as published by the Free Software Foundation and appearing in
+// the file LICENSE included in the packaging of this file.  Please review the
+// following information to ensure the GNU General Public License version 3.0
+// requirements will be met: http://www.gnu.org/copyleft/gpl.html.
+//
+// If you do not wish to use this file under the terms of the GPL version 3.0
+// then you may purchase a commercial license.  For more information contact
+// info at riverbankcomputing.com.
+//
+// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+
+
+%If (Qt_4_6_0 -)
+
+class QGraphicsWebView : QGraphicsWidget
+{
+%TypeHeaderCode
+#include <qgraphicswebview.h>
+%End
+
+%ConvertToSubClassCode
+    sipType = 0;
+
+    // For some reason Qt doesn't allocate a new type for this so we have to test
+    // the numeric and QObject types.
+    if (sipCpp->type() == 11)
+    {
+        QGraphicsWidget *gw = static_cast<QGraphicsWidget *>(sipCpp);
+
+        if (gw->inherits("QGraphicsWebView"))
+        {
+            *sipCppRet = static_cast<QGraphicsWebView *>(gw);
+            sipType = sipType_QGraphicsWebView;
+        }
+    }
+%End
+
+public:
+    explicit QGraphicsWebView(QGraphicsItem *parent /TransferThis/ = 0);
+    virtual ~QGraphicsWebView();
+    QWebPage *page() const;
+    void setPage(QWebPage * /KeepReference/);
+    QUrl url() const;
+    void setUrl(const QUrl &);
+    QString title() const;
+    QIcon icon() const;
+    qreal zoomFactor() const;
+    void setZoomFactor(qreal);
+    bool isModified() const;
+    void load(const QUrl &url) /ReleaseGIL/;
+    void load(const QNetworkRequest &request, QNetworkAccessManager::Operation operation = QNetworkAccessManager::GetOperation, const QByteArray &body = QByteArray()) /ReleaseGIL/;
+    void setHtml(const QString &html, const QUrl &baseUrl = QUrl());
+    void setContent(const QByteArray &data, const QString &mimeType = QString(), const QUrl &baseUrl = QUrl());
+    QWebHistory *history() const;
+    QWebSettings *settings() const;
+    QAction *pageAction(QWebPage::WebAction action) const;
+    void triggerPageAction(QWebPage::WebAction action, bool checked = false);
+    bool findText(const QString &subString, QFlags<QWebPage::FindFlag> options = 0);
+    virtual void setGeometry(const QRectF &rect);
+    virtual void updateGeometry();
+    virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0);
+    virtual QVariant itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value);
+    virtual bool event(QEvent *);
+    virtual QSizeF sizeHint(Qt::SizeHint which, const QSizeF &constraint) const;
+    virtual QVariant inputMethodQuery(Qt::InputMethodQuery query) const;
+
+public slots:
+    void stop();
+    void back();
+    void forward();
+    void reload();
+
+signals:
+    void loadStarted();
+    void loadFinished(bool);
+    void loadProgress(int progress);
+    void urlChanged(const QUrl &);
+    void titleChanged(const QString &);
+    void iconChanged();
+    void statusBarMessage(const QString &message);
+    void linkClicked(const QUrl &);
+
+protected:
+    virtual void mousePressEvent(QGraphicsSceneMouseEvent *);
+    virtual void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *);
+    virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *);
+    virtual void mouseMoveEvent(QGraphicsSceneMouseEvent *);
+    virtual void hoverMoveEvent(QGraphicsSceneHoverEvent *);
+    virtual void hoverLeaveEvent(QGraphicsSceneHoverEvent *);
+    virtual void wheelEvent(QGraphicsSceneWheelEvent *);
+    virtual void keyPressEvent(QKeyEvent *);
+    virtual void keyReleaseEvent(QKeyEvent *);
+    virtual void contextMenuEvent(QGraphicsSceneContextMenuEvent *);
+    virtual void dragEnterEvent(QGraphicsSceneDragDropEvent *);
+    virtual void dragLeaveEvent(QGraphicsSceneDragDropEvent *);
+    virtual void dragMoveEvent(QGraphicsSceneDragDropEvent *);
+    virtual void dropEvent(QGraphicsSceneDragDropEvent *);
+    virtual void focusInEvent(QFocusEvent *);
+    virtual void focusOutEvent(QFocusEvent *);
+    virtual void inputMethodEvent(QInputMethodEvent *);
+    virtual bool focusNextPrevChild(bool next);
+    virtual bool sceneEvent(QEvent *);
+
+public:
+%If (Qt_4_7_0 -)
+    bool resizesToContents() const;
+%End
+%If (Qt_4_7_0 -)
+    void setResizesToContents(bool enabled);
+%End
+%If (Qt_4_7_0 -)
+    bool isTiledBackingStoreFrozen() const;
+%End
+%If (Qt_4_7_0 -)
+    void setTiledBackingStoreFrozen(bool frozen);
+%End
+%If (Qt_4_8_0 -)
+    QFlags<QPainter::RenderHint> renderHints() const;
+%End
+%If (Qt_4_8_0 -)
+    void setRenderHints(QFlags<QPainter::RenderHint> hints);
+%End
+%If (Qt_4_8_0 -)
+    void setRenderHint(QPainter::RenderHint hint, bool enabled = true);
+%End
+};
+
+%End
+
+%ModuleHeaderCode
+#if QT_VERSION >= 0x040600
+// This is needed by the %ConvertSubClassCode.
+#include <QGraphicsWebView>
+#endif
+
+// This is needed for Qt v5.0.0.
+#if defined(B0)
+#undef B0
+#endif
+%End
diff --git a/python/QtWebKit/qwebdatabase.sip b/python/QtWebKit/qwebdatabase.sip
new file mode 100644
index 0000000..5da7c2e
--- /dev/null
+++ b/python/QtWebKit/qwebdatabase.sip
@@ -0,0 +1,46 @@
+// qwebdatabase.sip generated by MetaSIP
+//
+// This file is part of the QtWebKit Python extension module.
+//
+// Copyright (c) 2015 Riverbank Computing Limited <info at riverbankcomputing.com>
+//
+// This file is part of PyQt4.
+//
+// This file may be used under the terms of the GNU General Public License
+// version 3.0 as published by the Free Software Foundation and appearing in
+// the file LICENSE included in the packaging of this file.  Please review the
+// following information to ensure the GNU General Public License version 3.0
+// requirements will be met: http://www.gnu.org/copyleft/gpl.html.
+//
+// If you do not wish to use this file under the terms of the GPL version 3.0
+// then you may purchase a commercial license.  For more information contact
+// info at riverbankcomputing.com.
+//
+// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+
+
+%If (Qt_4_5_0 -)
+
+class QWebDatabase
+{
+%TypeHeaderCode
+#include <qwebdatabase.h>
+%End
+
+public:
+    QWebDatabase(const QWebDatabase &other);
+    ~QWebDatabase();
+    QString name() const;
+    QString displayName() const;
+    qint64 expectedSize() const;
+    qint64 size() const;
+    QString fileName() const;
+    QWebSecurityOrigin origin() const;
+    static void removeDatabase(const QWebDatabase &db);
+%If (Qt_4_6_0 -)
+    static void removeAllDatabases();
+%End
+};
+
+%End
diff --git a/python/QtWebKit/qwebelement.sip b/python/QtWebKit/qwebelement.sip
new file mode 100644
index 0000000..bd158c5
--- /dev/null
+++ b/python/QtWebKit/qwebelement.sip
@@ -0,0 +1,144 @@
+// qwebelement.sip generated by MetaSIP
+//
+// This file is part of the QtWebKit Python extension module.
+//
+// Copyright (c) 2015 Riverbank Computing Limited <info at riverbankcomputing.com>
+//
+// This file is part of PyQt4.
+//
+// This file may be used under the terms of the GNU General Public License
+// version 3.0 as published by the Free Software Foundation and appearing in
+// the file LICENSE included in the packaging of this file.  Please review the
+// following information to ensure the GNU General Public License version 3.0
+// requirements will be met: http://www.gnu.org/copyleft/gpl.html.
+//
+// If you do not wish to use this file under the terms of the GPL version 3.0
+// then you may purchase a commercial license.  For more information contact
+// info at riverbankcomputing.com.
+//
+// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+
+
+%If (Qt_4_6_0 -)
+
+class QWebElement
+{
+%TypeHeaderCode
+#include <qwebelement.h>
+%End
+
+public:
+    QWebElement();
+    QWebElement(const QWebElement &);
+    ~QWebElement();
+    bool operator==(const QWebElement &o) const;
+    bool operator!=(const QWebElement &o) const;
+    bool isNull() const;
+    QWebElementCollection findAll(const QString &selectorQuery) const;
+    QWebElement findFirst(const QString &selectorQuery) const;
+    void setPlainText(const QString &text);
+    QString toPlainText() const;
+    void setOuterXml(const QString &markup);
+    QString toOuterXml() const;
+    void setInnerXml(const QString &markup);
+    QString toInnerXml() const;
+    void setAttribute(const QString &name, const QString &value);
+    void setAttributeNS(const QString &namespaceUri, const QString &name, const QString &value);
+    QString attribute(const QString &name, const QString &defaultValue = QString()) const;
+    QString attributeNS(const QString &namespaceUri, const QString &name, const QString &defaultValue = QString()) const;
+    bool hasAttribute(const QString &name) const;
+    bool hasAttributeNS(const QString &namespaceUri, const QString &name) const;
+    void removeAttribute(const QString &name);
+    void removeAttributeNS(const QString &namespaceUri, const QString &name);
+    bool hasAttributes() const;
+    QStringList attributeNames(const QString &namespaceUri = QString()) const;
+    QStringList classes() const;
+    bool hasClass(const QString &name) const;
+    void addClass(const QString &name);
+    void removeClass(const QString &name);
+    void toggleClass(const QString &name);
+    bool hasFocus() const;
+    void setFocus();
+    QRect geometry() const;
+    QString tagName() const;
+    QString prefix() const;
+    QString localName() const;
+    QString namespaceUri() const;
+    QWebElement parent() const;
+    QWebElement firstChild() const;
+    QWebElement lastChild() const;
+    QWebElement nextSibling() const;
+    QWebElement previousSibling() const;
+    QWebElement document() const;
+    QWebFrame *webFrame() const;
+    void appendInside(const QString &markup);
+    void appendInside(const QWebElement &element);
+    void prependInside(const QString &markup);
+    void prependInside(const QWebElement &element);
+    void appendOutside(const QString &markup);
+    void appendOutside(const QWebElement &element);
+    void prependOutside(const QString &markup);
+    void prependOutside(const QWebElement &element);
+    void encloseContentsWith(const QWebElement &element);
+    void encloseContentsWith(const QString &markup);
+    void encloseWith(const QString &markup);
+    void encloseWith(const QWebElement &element);
+    void replace(const QString &markup);
+    void replace(const QWebElement &element);
+    QWebElement clone() const;
+    QWebElement &takeFromDocument();
+    void removeFromDocument();
+    void removeAllChildren();
+    QVariant evaluateJavaScript(const QString &scriptSource);
+
+    enum StyleResolveStrategy
+    {
+        InlineStyle,
+        CascadedStyle,
+        ComputedStyle,
+    };
+
+    QString styleProperty(const QString &name, QWebElement::StyleResolveStrategy strategy) const;
+    void setStyleProperty(const QString &name, const QString &value);
+    void render(QPainter *painter);
+%If (Qt_4_8_0 -)
+    void render(QPainter *painter, const QRect &clip);
+%End
+};
+
+%End
+%If (Qt_4_6_0 -)
+
+class QWebElementCollection
+{
+%TypeHeaderCode
+#include <qwebelement.h>
+%End
+
+public:
+    QWebElementCollection();
+    QWebElementCollection(const QWebElement &contextElement, const QString &query);
+    QWebElementCollection(const QWebElementCollection &);
+    ~QWebElementCollection();
+    QWebElementCollection operator+(const QWebElementCollection &other) const;
+    QWebElementCollection &operator+=(const QWebElementCollection &other);
+    void append(const QWebElementCollection &collection);
+    int count() const /__len__/;
+    QWebElement at(int i) const;
+    QWebElement operator[](int i) const;
+%MethodCode
+        SIP_SSIZE_T idx = sipConvertFromSequenceIndex(a0, sipCpp->count());
+
+        if (idx < 0)
+            sipIsErr = 1;
+        else
+            sipRes = new QWebElement(sipCpp->operator[]((int)idx));
+%End
+
+    QWebElement first() const;
+    QWebElement last() const;
+    QList<QWebElement> toList() const;
+};
+
+%End
diff --git a/python/QtWebKit/qwebframe.sip b/python/QtWebKit/qwebframe.sip
new file mode 100644
index 0000000..30768a2
--- /dev/null
+++ b/python/QtWebKit/qwebframe.sip
@@ -0,0 +1,244 @@
+// qwebframe.sip generated by MetaSIP
+//
+// This file is part of the QtWebKit Python extension module.
+//
+// Copyright (c) 2015 Riverbank Computing Limited <info at riverbankcomputing.com>
+//
+// This file is part of PyQt4.
+//
+// This file may be used under the terms of the GNU General Public License
+// version 3.0 as published by the Free Software Foundation and appearing in
+// the file LICENSE included in the packaging of this file.  Please review the
+// following information to ensure the GNU General Public License version 3.0
+// requirements will be met: http://www.gnu.org/copyleft/gpl.html.
+//
+// If you do not wish to use this file under the terms of the GPL version 3.0
+// then you may purchase a commercial license.  For more information contact
+// info at riverbankcomputing.com.
+//
+// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+
+
+%If (Qt_4_4_0 -)
+%ModuleCode
+#include <qwebframe.h>
+%End
+%End
+
+%If (Qt_4_4_0 -)
+
+class QWebHitTestResult
+{
+%TypeHeaderCode
+#include <qwebframe.h>
+%End
+
+public:
+    QWebHitTestResult();
+    QWebHitTestResult(const QWebHitTestResult &other);
+    ~QWebHitTestResult();
+    bool isNull() const;
+    QPoint pos() const;
+    QString title() const;
+    QString linkText() const;
+    QUrl linkUrl() const;
+    QUrl linkTitle() const;
+    QWebFrame *linkTargetFrame() const;
+    QString alternateText() const;
+    QUrl imageUrl() const;
+    QPixmap pixmap() const;
+    bool isContentEditable() const;
+    bool isContentSelected() const;
+    QWebFrame *frame() const;
+%If (Qt_4_5_0 -)
+    QRect boundingRect() const;
+%End
+%If (Qt_4_6_0 -)
+    QWebElement enclosingBlockElement() const;
+%End
+%If (Qt_4_6_0 -)
+    QWebElement linkElement() const;
+%End
+%If (Qt_4_6_0 -)
+    QWebElement element() const;
+%End
+};
+
+%End
+%If (Qt_4_4_0 -)
+
+class QWebFrame : QObject /NoDefaultCtors/
+{
+%TypeHeaderCode
+#include <qwebframe.h>
+%End
+
+    virtual ~QWebFrame();
+
+public:
+    QWebPage *page() const;
+    void load(const QUrl &url);
+    void load(const QNetworkRequest &request, QNetworkAccessManager::Operation operation = QNetworkAccessManager::GetOperation, const QByteArray &body = QByteArray());
+    void setHtml(const QString &html, const QUrl &baseUrl = QUrl());
+    void setContent(const QByteArray &data, const QString &mimeType /DocValue="Py_v3:''"/ = QString(), const QUrl &baseUrl = QUrl());
+%If (Qt_5_0_0 -)
+
+    enum ValueOwnership
+    {
+        QtOwnership,
+        ScriptOwnership,
+        AutoOwnership,
+    };
+
+%End
+%If (Qt_5_0_0 -)
+    void addToJavaScriptWindowObject(const QString &name, QObject *object, QWebFrame::ValueOwnership ownership = QWebFrame::QtOwnership);
+%End
+%If (- Qt_5_0_0)
+    void addToJavaScriptWindowObject(const QString &name, QObject *object);
+%End
+    QString toHtml() const;
+    QString toPlainText() const;
+%If (- Qt_5_0_0)
+    QString renderTreeDump() const;
+%End
+    QString title() const;
+    void setUrl(const QUrl &url);
+    QUrl url() const;
+    QIcon icon() const;
+    QString frameName() const;
+    QWebFrame *parentFrame() const;
+    QList<QWebFrame*> childFrames() const;
+    Qt::ScrollBarPolicy scrollBarPolicy(Qt::Orientation orientation) const;
+    void setScrollBarPolicy(Qt::Orientation orientation, Qt::ScrollBarPolicy policy);
+    void setScrollBarValue(Qt::Orientation orientation, int value);
+    int scrollBarValue(Qt::Orientation orientation) const;
+    int scrollBarMinimum(Qt::Orientation orientation) const;
+    int scrollBarMaximum(Qt::Orientation orientation) const;
+%If (- Qt_5_0_0)
+    void render(QPainter *painter, const QRegion &clip);
+%End
+%If (- Qt_5_0_0)
+    void render(QPainter *painter);
+%End
+    void setTextSizeMultiplier(qreal factor);
+    qreal textSizeMultiplier() const;
+    QPoint pos() const;
+    QRect geometry() const;
+    QSize contentsSize() const;
+    QWebHitTestResult hitTestContent(const QPoint &pos) const;
+    virtual bool event(QEvent *);
+
+public slots:
+    QVariant evaluateJavaScript(const QString &scriptSource);
+%If (PyQt_Printer)
+    void print(QPrinter *printer) const /PyName=print_/;
+%End
+%If (Py_v3)
+%If (PyQt_Printer)
+    void print(QPrinter *printer) const;
+%End
+%End
+
+signals:
+    void javaScriptWindowObjectCleared();
+    void titleChanged(const QString &title);
+    void urlChanged(const QUrl &url);
+    void initialLayoutCompleted();
+    void iconChanged();
+
+public:
+%If (Qt_4_5_0 -)
+    QMultiMap<QString, QString> metaData() const;
+%End
+%If (Qt_4_5_0 -)
+    void scroll(int, int);
+%End
+%If (Qt_4_5_0 -)
+    QPoint scrollPosition() const;
+%End
+%If (Qt_4_5_0 -)
+    void setScrollPosition(const QPoint &pos);
+%End
+%If (Qt_4_5_0 -)
+    qreal zoomFactor() const;
+%End
+%If (Qt_4_5_0 -)
+    void setZoomFactor(qreal factor);
+%End
+%If (Qt_4_5_0 -)
+    QWebSecurityOrigin securityOrigin() const;
+%End
+%If (Qt_4_6_0 -)
+    QUrl requestedUrl() const;
+%End
+%If (Qt_4_6_0 -)
+    QUrl baseUrl() const;
+%End
+%If (Qt_4_6_0 -)
+    QRect scrollBarGeometry(Qt::Orientation orientation) const;
+%End
+%If (Qt_4_6_0 -)
+
+    enum RenderLayer
+    {
+        ContentsLayer,
+        ScrollBarLayer,
+        PanIconLayer,
+        AllLayers,
+    };
+
+%End
+%If (Qt_5_0_0 -)
+    typedef QFlags<QWebFrame::RenderLayer> RenderLayers;
+%End
+%If (Qt_4_6_0 - Qt_5_0_0)
+    void render(QPainter *, QWebFrame::RenderLayer layer, const QRegion &clip = QRegion());
+%End
+%If (Qt_5_0_0 -)
+    void render(QPainter *, const QRegion &clip = QRegion());
+%End
+%If (Qt_5_0_0 -)
+    void render(QPainter *, QFlags<QWebFrame::RenderLayer> layer, const QRegion &clip = QRegion());
+%End
+%If (Qt_4_6_0 -)
+    bool hasFocus() const;
+%End
+%If (Qt_4_6_0 -)
+    void setFocus();
+%End
+%If (Qt_4_6_0 -)
+    QWebElement documentElement() const;
+%End
+%If (Qt_4_6_0 -)
+    QWebElementCollection findAllElements(const QString &selectorQuery) const;
+%End
+%If (Qt_4_6_0 -)
+    QWebElement findFirstElement(const QString &selectorQuery) const;
+%End
+
+signals:
+%If (Qt_4_6_0 -)
+    void contentsSizeChanged(const QSize &size);
+%End
+%If (Qt_4_6_0 -)
+    void loadStarted();
+%End
+%If (Qt_4_6_0 -)
+    void loadFinished(bool ok);
+%End
+%If (Qt_4_7_0 -)
+    void pageChanged();
+%End
+
+public:
+%If (Qt_4_7_0 -)
+    void scrollToAnchor(const QString &anchor);
+%End
+};
+
+%End
+%If (Qt_5_0_0 -)
+QFlags<QWebFrame::RenderLayer> operator|(QWebFrame::RenderLayer f1, QFlags<QWebFrame::RenderLayer> f2);
+%End
diff --git a/python/QtWebKit/qwebhistory.sip b/python/QtWebKit/qwebhistory.sip
new file mode 100644
index 0000000..59ddb3a
--- /dev/null
+++ b/python/QtWebKit/qwebhistory.sip
@@ -0,0 +1,104 @@
+// qwebhistory.sip generated by MetaSIP
+//
+// This file is part of the QtWebKit Python extension module.
+//
+// Copyright (c) 2015 Riverbank Computing Limited <info at riverbankcomputing.com>
+//
+// This file is part of PyQt4.
+//
+// This file may be used under the terms of the GNU General Public License
+// version 3.0 as published by the Free Software Foundation and appearing in
+// the file LICENSE included in the packaging of this file.  Please review the
+// following information to ensure the GNU General Public License version 3.0
+// requirements will be met: http://www.gnu.org/copyleft/gpl.html.
+//
+// If you do not wish to use this file under the terms of the GPL version 3.0
+// then you may purchase a commercial license.  For more information contact
+// info at riverbankcomputing.com.
+//
+// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+
+
+%If (Qt_4_4_0 -)
+%ModuleCode
+#include <qwebhistory.h>
+%End
+%End
+
+%If (Qt_4_4_0 -)
+
+class QWebHistoryItem
+{
+%TypeHeaderCode
+#include <qwebhistory.h>
+%End
+
+public:
+    QWebHistoryItem(const QWebHistoryItem &other);
+    ~QWebHistoryItem();
+    QUrl originalUrl() const;
+    QUrl url() const;
+    QString title() const;
+    QDateTime lastVisited() const;
+    QIcon icon() const;
+%If (Qt_4_5_0 -)
+    QVariant userData() const;
+%End
+%If (Qt_4_5_0 -)
+    void setUserData(const QVariant &userData);
+%End
+%If (Qt_4_5_0 -)
+    bool isValid() const;
+%End
+};
+
+%End
+%If (Qt_4_4_0 -)
+
+class QWebHistory
+{
+%TypeHeaderCode
+#include <qwebhistory.h>
+%End
+
+public:
+    void clear();
+    QList<QWebHistoryItem> items() const;
+    QList<QWebHistoryItem> backItems(int maxItems) const;
+    QList<QWebHistoryItem> forwardItems(int maxItems) const;
+    bool canGoBack() const;
+    bool canGoForward() const;
+    void back();
+    void forward();
+    void goToItem(const QWebHistoryItem &item);
+    QWebHistoryItem backItem() const;
+    QWebHistoryItem currentItem() const;
+    QWebHistoryItem forwardItem() const;
+    QWebHistoryItem itemAt(int i) const;
+    int count() const /__len__/;
+
+private:
+    QWebHistory();
+    QWebHistory(const QWebHistory &);
+    ~QWebHistory();
+
+public:
+%If (Qt_4_5_0 -)
+    int currentItemIndex() const;
+%End
+%If (Qt_4_5_0 -)
+    int maximumItemCount() const;
+%End
+%If (Qt_4_5_0 -)
+    void setMaximumItemCount(int count);
+%End
+};
+
+%End
+%If (Qt_4_6_0 -)
+QDataStream &operator<<(QDataStream &, const QWebHistory & /Constrained/);
+%End
+%If (Qt_4_6_0 -)
+QDataStream &operator>>(QDataStream &, QWebHistory & /Constrained/);
+%End
diff --git a/python/QtWebKit/qwebhistoryinterface.sip b/python/QtWebKit/qwebhistoryinterface.sip
new file mode 100644
index 0000000..7493a10
--- /dev/null
+++ b/python/QtWebKit/qwebhistoryinterface.sip
@@ -0,0 +1,40 @@
+// qwebhistoryinterface.sip generated by MetaSIP
+//
+// This file is part of the QtWebKit Python extension module.
+//
+// Copyright (c) 2015 Riverbank Computing Limited <info at riverbankcomputing.com>
+//
+// This file is part of PyQt4.
+//
+// This file may be used under the terms of the GNU General Public License
+// version 3.0 as published by the Free Software Foundation and appearing in
+// the file LICENSE included in the packaging of this file.  Please review the
+// following information to ensure the GNU General Public License version 3.0
+// requirements will be met: http://www.gnu.org/copyleft/gpl.html.
+//
+// If you do not wish to use this file under the terms of the GPL version 3.0
+// then you may purchase a commercial license.  For more information contact
+// info at riverbankcomputing.com.
+//
+// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+
+
+%If (Qt_4_4_0 -)
+
+class QWebHistoryInterface : QObject
+{
+%TypeHeaderCode
+#include <qwebhistoryinterface.h>
+%End
+
+public:
+    QWebHistoryInterface(QObject *parent /TransferThis/ = 0);
+    virtual ~QWebHistoryInterface();
+    static void setDefaultInterface(QWebHistoryInterface *defaultInterface /KeepReference/);
+    static QWebHistoryInterface *defaultInterface();
+    virtual bool historyContains(const QString &url) const = 0;
+    virtual void addHistoryEntry(const QString &url) = 0;
+};
+
+%End
diff --git a/python/QtWebKit/qwebinspector.sip b/python/QtWebKit/qwebinspector.sip
new file mode 100644
index 0000000..50405ed
--- /dev/null
+++ b/python/QtWebKit/qwebinspector.sip
@@ -0,0 +1,48 @@
+// qwebinspector.sip generated by MetaSIP
+//
+// This file is part of the QtWebKit Python extension module.
+//
+// Copyright (c) 2015 Riverbank Computing Limited <info at riverbankcomputing.com>
+//
+// This file is part of PyQt4.
+//
+// This file may be used under the terms of the GNU General Public License
+// version 3.0 as published by the Free Software Foundation and appearing in
+// the file LICENSE included in the packaging of this file.  Please review the
+// following information to ensure the GNU General Public License version 3.0
+// requirements will be met: http://www.gnu.org/copyleft/gpl.html.
+//
+// If you do not wish to use this file under the terms of the GPL version 3.0
+// then you may purchase a commercial license.  For more information contact
+// info at riverbankcomputing.com.
+//
+// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+
+
+%If (Qt_4_6_0 -)
+
+class QWebInspector : QWidget
+{
+%TypeHeaderCode
+#include <qwebinspector.h>
+%End
+
+public:
+    QWebInspector(QWidget *parent /TransferThis/ = 0);
+    virtual ~QWebInspector();
+    void setPage(QWebPage *page /KeepReference/);
+    QWebPage *page() const;
+    virtual QSize sizeHint() const;
+    virtual bool event(QEvent *);
+
+protected:
+    virtual void resizeEvent(QResizeEvent *event);
+    virtual void showEvent(QShowEvent *event);
+    virtual void hideEvent(QHideEvent *event);
+%If (Qt_4_7_0 -)
+    virtual void closeEvent(QCloseEvent *event);
+%End
+};
+
+%End
diff --git a/python/QtWebKit/qwebkitglobal.sip b/python/QtWebKit/qwebkitglobal.sip
new file mode 100644
index 0000000..f7dad16
--- /dev/null
+++ b/python/QtWebKit/qwebkitglobal.sip
@@ -0,0 +1,37 @@
+// qwebkitglobal.sip generated by MetaSIP
+//
+// This file is part of the QtWebKit Python extension module.
+//
+// Copyright (c) 2015 Riverbank Computing Limited <info at riverbankcomputing.com>
+//
+// This file is part of PyQt4.
+//
+// This file may be used under the terms of the GNU General Public License
+// version 3.0 as published by the Free Software Foundation and appearing in
+// the file LICENSE included in the packaging of this file.  Please review the
+// following information to ensure the GNU General Public License version 3.0
+// requirements will be met: http://www.gnu.org/copyleft/gpl.html.
+//
+// If you do not wish to use this file under the terms of the GPL version 3.0
+// then you may purchase a commercial license.  For more information contact
+// info at riverbankcomputing.com.
+//
+// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+
+
+%If (Qt_5_0_0 -)
+%ModuleCode
+#include <qwebkitglobal.h>
+%End
+%End
+
+%If (Qt_5_0_0 -)
+QString qWebKitVersion();
+%End
+%If (Qt_5_0_0 -)
+int qWebKitMajorVersion();
+%End
+%If (Qt_5_0_0 -)
+int qWebKitMinorVersion();
+%End
diff --git a/python/QtWebKit/qwebkitversion.sip b/python/QtWebKit/qwebkitversion.sip
new file mode 100644
index 0000000..63729ba
--- /dev/null
+++ b/python/QtWebKit/qwebkitversion.sip
@@ -0,0 +1,37 @@
+// qwebkitversion.sip generated by MetaSIP
+//
+// This file is part of the QtWebKit Python extension module.
+//
+// Copyright (c) 2015 Riverbank Computing Limited <info at riverbankcomputing.com>
+//
+// This file is part of PyQt4.
+//
+// This file may be used under the terms of the GNU General Public License
+// version 3.0 as published by the Free Software Foundation and appearing in
+// the file LICENSE included in the packaging of this file.  Please review the
+// following information to ensure the GNU General Public License version 3.0
+// requirements will be met: http://www.gnu.org/copyleft/gpl.html.
+//
+// If you do not wish to use this file under the terms of the GPL version 3.0
+// then you may purchase a commercial license.  For more information contact
+// info at riverbankcomputing.com.
+//
+// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+
+
+%If (Qt_4_6_0 - Qt_5_0_0)
+%ModuleCode
+#include <qwebkitversion.h>
+%End
+%End
+
+%If (Qt_4_6_0 - Qt_5_0_0)
+QString qWebKitVersion();
+%End
+%If (Qt_4_6_0 - Qt_5_0_0)
+int qWebKitMajorVersion();
+%End
+%If (Qt_4_6_0 - Qt_5_0_0)
+int qWebKitMinorVersion();
+%End
diff --git a/python/QtWebKit/qwebpage.sip b/python/QtWebKit/qwebpage.sip
new file mode 100644
index 0000000..88ddfd1
--- /dev/null
+++ b/python/QtWebKit/qwebpage.sip
@@ -0,0 +1,522 @@
+// qwebpage.sip generated by MetaSIP
+//
+// This file is part of the QtWebKit Python extension module.
+//
+// Copyright (c) 2015 Riverbank Computing Limited <info at riverbankcomputing.com>
+//
+// This file is part of PyQt4.
+//
+// This file may be used under the terms of the GNU General Public License
+// version 3.0 as published by the Free Software Foundation and appearing in
+// the file LICENSE included in the packaging of this file.  Please review the
+// following information to ensure the GNU General Public License version 3.0
+// requirements will be met: http://www.gnu.org/copyleft/gpl.html.
+//
+// If you do not wish to use this file under the terms of the GPL version 3.0
+// then you may purchase a commercial license.  For more information contact
+// info at riverbankcomputing.com.
+//
+// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+
+
+%If (Qt_4_4_0 -)
+%ModuleCode
+#include <qwebpage.h>
+%End
+%End
+
+%If (Qt_4_4_0 -)
+
+class QWebPage : QObject
+{
+%TypeHeaderCode
+#include <qwebpage.h>
+%End
+
+public:
+    enum NavigationType
+    {
+        NavigationTypeLinkClicked,
+        NavigationTypeFormSubmitted,
+        NavigationTypeBackOrForward,
+        NavigationTypeReload,
+        NavigationTypeFormResubmitted,
+        NavigationTypeOther,
+    };
+
+    enum WebAction
+    {
+        NoWebAction,
+        OpenLink,
+        OpenLinkInNewWindow,
+        OpenFrameInNewWindow,
+        DownloadLinkToDisk,
+        CopyLinkToClipboard,
+        OpenImageInNewWindow,
+        DownloadImageToDisk,
+        CopyImageToClipboard,
+        Back,
+        Forward,
+        Stop,
+        Reload,
+        Cut,
+        Copy,
+        Paste,
+        Undo,
+        Redo,
+        MoveToNextChar,
+        MoveToPreviousChar,
+        MoveToNextWord,
+        MoveToPreviousWord,
+        MoveToNextLine,
+        MoveToPreviousLine,
+        MoveToStartOfLine,
+        MoveToEndOfLine,
+        MoveToStartOfBlock,
+        MoveToEndOfBlock,
+        MoveToStartOfDocument,
+        MoveToEndOfDocument,
+        SelectNextChar,
+        SelectPreviousChar,
+        SelectNextWord,
+        SelectPreviousWord,
+        SelectNextLine,
+        SelectPreviousLine,
+        SelectStartOfLine,
+        SelectEndOfLine,
+        SelectStartOfBlock,
+        SelectEndOfBlock,
+        SelectStartOfDocument,
+        SelectEndOfDocument,
+        DeleteStartOfWord,
+        DeleteEndOfWord,
+        SetTextDirectionDefault,
+        SetTextDirectionLeftToRight,
+        SetTextDirectionRightToLeft,
+        ToggleBold,
+        ToggleItalic,
+        ToggleUnderline,
+        InspectElement,
+%If (Qt_4_5_0 -)
+        InsertParagraphSeparator,
+%End
+%If (Qt_4_5_0 -)
+        InsertLineSeparator,
+%End
+%If (Qt_4_5_0 -)
+        SelectAll,
+%End
+%If (Qt_4_6_0 -)
+        ReloadAndBypassCache,
+%End
+%If (Qt_4_6_0 -)
+        PasteAndMatchStyle,
+%End
+%If (Qt_4_6_0 -)
+        RemoveFormat,
+%End
+%If (Qt_4_6_0 -)
+        ToggleStrikethrough,
+%End
+%If (Qt_4_6_0 -)
+        ToggleSubscript,
+%End
+%If (Qt_4_6_0 -)
+        ToggleSuperscript,
+%End
+%If (Qt_4_6_0 -)
+        InsertUnorderedList,
+%End
+%If (Qt_4_6_0 -)
+        InsertOrderedList,
+%End
+%If (Qt_4_6_0 -)
+        Indent,
+%End
+%If (Qt_4_6_0 -)
+        Outdent,
+%End
+%If (Qt_4_6_0 -)
+        AlignCenter,
+%End
+%If (Qt_4_6_0 -)
+        AlignJustified,
+%End
+%If (Qt_4_6_0 -)
+        AlignLeft,
+%End
+%If (Qt_4_6_0 -)
+        AlignRight,
+%End
+%If (Qt_4_7_0 -)
+        StopScheduledPageRefresh,
+%End
+%If (Qt_4_8_0 -)
+        CopyImageUrlToClipboard,
+%End
+%If (Qt_5_0_0 -)
+        OpenLinkInThisWindow,
+%End
+    };
+
+    enum FindFlag
+    {
+        FindBackward,
+        FindCaseSensitively,
+        FindWrapsAroundDocument,
+%If (Qt_4_6_0 -)
+        HighlightAllOccurrences,
+%End
+    };
+
+    typedef QFlags<QWebPage::FindFlag> FindFlags;
+
+    enum LinkDelegationPolicy
+    {
+        DontDelegateLinks,
+        DelegateExternalLinks,
+        DelegateAllLinks,
+    };
+
+    enum WebWindowType
+    {
+        WebBrowserWindow,
+        WebModalDialog,
+    };
+
+    explicit QWebPage(QObject *parent /TransferThis/ = 0);
+    virtual ~QWebPage();
+    QWebFrame *mainFrame() const;
+    QWebFrame *currentFrame() const;
+    QWebHistory *history() const;
+    QWebSettings *settings() const;
+    void setView(QWidget *view /KeepReference/);
+    QWidget *view() const;
+    bool isModified() const;
+    QUndoStack *undoStack() const;
+    void setNetworkAccessManager(QNetworkAccessManager *manager /KeepReference/);
+    QNetworkAccessManager *networkAccessManager() const;
+    void setPluginFactory(QWebPluginFactory *factory /KeepReference/);
+    QWebPluginFactory *pluginFactory() const;
+    quint64 totalBytes() const;
+    quint64 bytesReceived() const;
+    QString selectedText() const;
+    QAction *action(QWebPage::WebAction action) const;
+    virtual void triggerAction(QWebPage::WebAction action, bool checked = false);
+    QSize viewportSize() const;
+    void setViewportSize(const QSize &size) const;
+    virtual bool event(QEvent *);
+    bool focusNextPrevChild(bool next);
+    QVariant inputMethodQuery(Qt::InputMethodQuery property) const;
+    bool findText(const QString &subString, QFlags<QWebPage::FindFlag> options = 0);
+    void setForwardUnsupportedContent(bool forward);
+    bool forwardUnsupportedContent() const;
+    void setLinkDelegationPolicy(QWebPage::LinkDelegationPolicy policy);
+    QWebPage::LinkDelegationPolicy linkDelegationPolicy() const;
+    void setPalette(const QPalette &palette);
+    QPalette palette() const;
+    bool swallowContextMenuEvent(QContextMenuEvent *event);
+    void updatePositionDependentActions(const QPoint &pos);
+
+    enum Extension
+    {
+%If (Qt_4_5_0 -)
+        ChooseMultipleFilesExtension,
+%End
+%If (Qt_4_6_0 -)
+        ErrorPageExtension,
+%End
+    };
+
+    class ExtensionOption
+    {
+%TypeHeaderCode
+#include <qwebpage.h>
+%End
+    };
+
+    class ExtensionReturn
+    {
+%TypeHeaderCode
+#include <qwebpage.h>
+%End
+    };
+
+    virtual bool extension(QWebPage::Extension extension, const QWebPage::ExtensionOption *option = 0, QWebPage::ExtensionReturn *output = 0);
+%VirtualCatcherCode
+        const sipTypeDef *option_type = sipType_QWebPage_ExtensionOption;
+        const sipTypeDef *return_type = sipType_QWebPage_ExtensionReturn;
+
+        #if QT_VERSION >= 0x040500
+        if (a0 == QWebPage::ChooseMultipleFilesExtension)
+        {
+            option_type = sipType_QWebPage_ChooseMultipleFilesExtensionOption;
+            return_type = sipType_QWebPage_ChooseMultipleFilesExtensionReturn;
+        }
+        #if QT_VERSION >= 0x040600
+        else if (a0 == QWebPage::ErrorPageExtension)
+        {
+            option_type = sipType_QWebPage_ErrorPageExtensionOption;
+            return_type = sipType_QWebPage_ErrorPageExtensionReturn;
+        }
+        #endif
+        #endif
+
+        PyObject *res_obj = sipCallMethod(&sipIsErr, sipMethod, "FDD",
+                a0, sipType_QWebPage_Extension,
+                a1, option_type, NULL,
+                a2, return_type, NULL);
+
+        if (res_obj)
+        {
+            sipParseResult(&sipIsErr, sipMethod, res_obj, "b", &sipRes);
+            Py_DECREF(res_obj);
+        }
+        else
+        {
+            sipIsErr = 1;
+        }
+%End
+
+    virtual bool supportsExtension(QWebPage::Extension extension) const;
+
+signals:
+    void loadFinished(bool ok);
+    void loadProgress(int progress);
+    void loadStarted();
+    void linkHovered(const QString &link, const QString &title, const QString &textContent);
+    void statusBarMessage(const QString &text);
+    void selectionChanged();
+    void frameCreated(QWebFrame *frame);
+    void geometryChangeRequested(const QRect &geom);
+    void repaintRequested(const QRect &dirtyRect);
+    void scrollRequested(int dx, int dy, const QRect &scrollViewRect);
+    void windowCloseRequested();
+    void printRequested(QWebFrame *frame);
+    void linkClicked(const QUrl &url);
+    void toolBarVisibilityChangeRequested(bool visible);
+    void statusBarVisibilityChangeRequested(bool visible);
+    void menuBarVisibilityChangeRequested(bool visible);
+    void unsupportedContent(QNetworkReply *reply);
+    void downloadRequested(const QNetworkRequest &request);
+    void microFocusChanged();
+
+protected:
+    virtual QWebPage *createWindow(QWebPage::WebWindowType type);
+    virtual QObject *createPlugin(const QString &classid, const QUrl &url, const QStringList &paramNames, const QStringList &paramValues);
+    virtual bool acceptNavigationRequest(QWebFrame *frame, const QNetworkRequest &request, QWebPage::NavigationType type);
+    virtual QString chooseFile(QWebFrame *originatingFrame, const QString &oldFile);
+    virtual void javaScriptAlert(QWebFrame *originatingFrame, const QString &msg);
+    virtual bool javaScriptConfirm(QWebFrame *originatingFrame, const QString &msg);
+    virtual bool javaScriptPrompt(QWebFrame *originatingFrame, const QString &msg, const QString &defaultValue, QString *result /Out/) /API=QString:2 - /;
+    virtual bool javaScriptPrompt(QWebFrame *originatingFrame, const QString &msg, const QString &defaultValue, QString *result /Constrained/) /API=QString: - 2/;
+    virtual void javaScriptConsoleMessage(const QString &message, int lineNumber, const QString &sourceID);
+    virtual QString userAgentForUrl(const QUrl &url) const;
+
+public:
+%If (Qt_4_5_0 -)
+    void setContentEditable(bool editable);
+%End
+%If (Qt_4_5_0 -)
+    bool isContentEditable() const;
+%End
+%If (Qt_4_5_0 -)
+    QMenu *createStandardContextMenu() /Factory/;
+%End
+%If (Qt_4_5_0 -)
+
+    class ChooseMultipleFilesExtensionOption : QWebPage::ExtensionOption
+    {
+%TypeHeaderCode
+#include <qwebpage.h>
+%End
+
+    public:
+        QWebFrame *parentFrame;
+        QStringList suggestedFileNames;
+    };
+
+%End
+%If (Qt_4_5_0 -)
+
+    class ChooseMultipleFilesExtensionReturn : QWebPage::ExtensionReturn
+    {
+%TypeHeaderCode
+#include <qwebpage.h>
+%End
+
+    public:
+        QStringList fileNames;
+    };
+
+%End
+
+signals:
+%If (Qt_4_5_0 -)
+    void contentsChanged();
+%End
+%If (Qt_4_5_0 -)
+    void databaseQuotaExceeded(QWebFrame *frame, QString databaseName);
+%End
+%If (Qt_4_5_0 -)
+    void saveFrameStateRequested(QWebFrame *frame, QWebHistoryItem *item);
+%End
+%If (Qt_4_5_0 -)
+    void restoreFrameStateRequested(QWebFrame *frame);
+%End
+
+public:
+%If (Qt_4_6_0 -)
+    QWebFrame *frameAt(const QPoint &pos) const;
+%End
+%If (Qt_4_6_0 -)
+    QSize preferredContentsSize() const;
+%End
+%If (Qt_4_6_0 -)
+    void setPreferredContentsSize(const QSize &size) const;
+%End
+%If (Qt_4_6_0 -)
+
+    enum ErrorDomain
+    {
+        QtNetwork,
+        Http,
+        WebKit,
+    };
+
+%End
+%If (Qt_4_6_0 -)
+
+    class ErrorPageExtensionOption : QWebPage::ExtensionOption
+    {
+%TypeHeaderCode
+#include <qwebpage.h>
+%End
+
+    public:
+        QUrl url;
+        QWebFrame *frame;
+        QWebPage::ErrorDomain domain;
+        int error;
+        QString errorString;
+    };
+
+%End
+%If (Qt_4_6_0 -)
+
+    class ErrorPageExtensionReturn : QWebPage::ExtensionReturn
+    {
+%TypeHeaderCode
+#include <qwebpage.h>
+%End
+
+    public:
+        ErrorPageExtensionReturn();
+        QString contentType;
+        QString encoding;
+        QUrl baseUrl;
+        QByteArray content;
+    };
+
+%End
+%If (Qt_5_0_0 -)
+    virtual bool shouldInterruptJavaScript();
+%End
+
+public slots:
+%If (Qt_4_6_0 - Qt_5_0_0)
+    bool shouldInterruptJavaScript();
+%End
+
+public:
+%If (Qt_4_8_0 -)
+
+    enum PermissionPolicy
+    {
+        PermissionUnknown,
+        PermissionGrantedByUser,
+        PermissionDeniedByUser,
+    };
+
+%End
+%If (Qt_4_8_0 -)
+
+    enum Feature
+    {
+        Notifications,
+        Geolocation,
+    };
+
+%End
+%If (Qt_4_8_0 -)
+
+    class ViewportAttributes
+    {
+%TypeHeaderCode
+#include <qwebpage.h>
+%End
+
+    public:
+        ViewportAttributes();
+        ViewportAttributes(const QWebPage::ViewportAttributes &other);
+        ~ViewportAttributes();
+        qreal initialScaleFactor() const;
+        qreal minimumScaleFactor() const;
+        qreal maximumScaleFactor() const;
+        qreal devicePixelRatio() const;
+        bool isUserScalable() const;
+        bool isValid() const;
+%If (Qt_5_0_0 -)
+        QSizeF size() const;
+%End
+%If (- Qt_5_0_0)
+        QSize size() const;
+%End
+    };
+
+%End
+%If (Qt_4_8_0 -)
+    bool hasSelection() const;
+%End
+%If (Qt_4_8_0 -)
+    QString selectedHtml() const;
+%End
+%If (Qt_4_8_0 -)
+    QWebPage::ViewportAttributes viewportAttributesForSize(const QSize &availableSize) const;
+%End
+%If (Qt_4_8_0 -)
+    void setActualVisibleContentRect(const QRect &rect) const;
+%End
+%If (Qt_4_8_0 -)
+    void setFeaturePermission(QWebFrame *frame, QWebPage::Feature feature, QWebPage::PermissionPolicy policy);
+%End
+%If (Qt_4_8_0 -)
+    QStringList supportedContentTypes() const;
+%End
+%If (Qt_4_8_0 -)
+    bool supportsContentType(const QString &mimeType) const;
+%End
+
+signals:
+%If (Qt_5_0_0 -)
+    void applicationCacheQuotaExceeded(QWebSecurityOrigin *origin, quint64 defaultOriginQuota, quint64 totalSpaceNeeded);
+%End
+%If (Qt_4_8_0 - Qt_5_0_0)
+    void applicationCacheQuotaExceeded(QWebSecurityOrigin *origin, quint64 defaultOriginQuota);
+%End
+%If (Qt_4_8_0 -)
+    void viewportChangeRequested();
+%End
+%If (Qt_4_8_0 -)
+    void featurePermissionRequested(QWebFrame *frame, QWebPage::Feature feature);
+%End
+%If (Qt_4_8_0 -)
+    void featurePermissionRequestCanceled(QWebFrame *frame, QWebPage::Feature feature);
+%End
+};
+
+%End
+%If (Qt_4_4_0 -)
+QFlags<QWebPage::FindFlag> operator|(QWebPage::FindFlag f1, QFlags<QWebPage::FindFlag> f2);
+%End
diff --git a/python/QtWebKit/qwebpluginfactory.sip b/python/QtWebKit/qwebpluginfactory.sip
new file mode 100644
index 0000000..d6e9795
--- /dev/null
+++ b/python/QtWebKit/qwebpluginfactory.sip
@@ -0,0 +1,88 @@
+// qwebpluginfactory.sip generated by MetaSIP
+//
+// This file is part of the QtWebKit Python extension module.
+//
+// Copyright (c) 2015 Riverbank Computing Limited <info at riverbankcomputing.com>
+//
+// This file is part of PyQt4.
+//
+// This file may be used under the terms of the GNU General Public License
+// version 3.0 as published by the Free Software Foundation and appearing in
+// the file LICENSE included in the packaging of this file.  Please review the
+// following information to ensure the GNU General Public License version 3.0
+// requirements will be met: http://www.gnu.org/copyleft/gpl.html.
+//
+// If you do not wish to use this file under the terms of the GPL version 3.0
+// then you may purchase a commercial license.  For more information contact
+// info at riverbankcomputing.com.
+//
+// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+
+
+%If (Qt_4_4_0 -)
+
+class QWebPluginFactory : QObject
+{
+%TypeHeaderCode
+#include <qwebpluginfactory.h>
+%End
+
+public:
+    struct MimeType
+    {
+%TypeHeaderCode
+#include <qwebpluginfactory.h>
+%End
+
+        QString name;
+        QString description;
+        QStringList fileExtensions;
+%If (Qt_4_6_0 -)
+        bool operator==(const QWebPluginFactory::MimeType &other) const;
+%End
+%If (Qt_4_6_0 -)
+        bool operator!=(const QWebPluginFactory::MimeType &other) const;
+%End
+    };
+
+    struct Plugin
+    {
+%TypeHeaderCode
+#include <qwebpluginfactory.h>
+%End
+
+        QString name;
+        QString description;
+        QList<QWebPluginFactory::MimeType> mimeTypes;
+    };
+
+    explicit QWebPluginFactory(QObject *parent /TransferThis/ = 0);
+    virtual ~QWebPluginFactory();
+    virtual QList<QWebPluginFactory::Plugin> plugins() const = 0;
+    virtual void refreshPlugins();
+    virtual QObject *create(const QString &mimeType, const QUrl &url, const QStringList &argumentNames, const QStringList &argumentValues) const = 0 /Factory/;
+
+    enum Extension
+    {
+    };
+
+    class ExtensionOption
+    {
+%TypeHeaderCode
+#include <qwebpluginfactory.h>
+%End
+    };
+
+    class ExtensionReturn
+    {
+%TypeHeaderCode
+#include <qwebpluginfactory.h>
+%End
+    };
+
+    virtual bool extension(QWebPluginFactory::Extension extension, const QWebPluginFactory::ExtensionOption *option = 0, QWebPluginFactory::ExtensionReturn *output = 0);
+    virtual bool supportsExtension(QWebPluginFactory::Extension extension) const;
+};
+
+%End
diff --git a/python/QtWebKit/qwebsecurityorigin.sip b/python/QtWebKit/qwebsecurityorigin.sip
new file mode 100644
index 0000000..b5eca42
--- /dev/null
+++ b/python/QtWebKit/qwebsecurityorigin.sip
@@ -0,0 +1,56 @@
+// qwebsecurityorigin.sip generated by MetaSIP
+//
+// This file is part of the QtWebKit Python extension module.
+//
+// Copyright (c) 2015 Riverbank Computing Limited <info at riverbankcomputing.com>
+//
+// This file is part of PyQt4.
+//
+// This file may be used under the terms of the GNU General Public License
+// version 3.0 as published by the Free Software Foundation and appearing in
+// the file LICENSE included in the packaging of this file.  Please review the
+// following information to ensure the GNU General Public License version 3.0
+// requirements will be met: http://www.gnu.org/copyleft/gpl.html.
+//
+// If you do not wish to use this file under the terms of the GPL version 3.0
+// then you may purchase a commercial license.  For more information contact
+// info at riverbankcomputing.com.
+//
+// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+
+
+%If (Qt_4_5_0 -)
+
+class QWebSecurityOrigin
+{
+%TypeHeaderCode
+#include <qwebsecurityorigin.h>
+%End
+
+public:
+    QWebSecurityOrigin(const QWebSecurityOrigin &other);
+    ~QWebSecurityOrigin();
+    static QList<QWebSecurityOrigin> allOrigins();
+    QString scheme() const;
+    QString host() const;
+    int port() const;
+    qint64 databaseUsage() const;
+    qint64 databaseQuota() const;
+    void setDatabaseQuota(qint64 quota);
+    QList<QWebDatabase> databases() const;
+%If (Qt_4_6_0 -)
+    static void addLocalScheme(const QString &scheme);
+%End
+%If (Qt_4_6_0 -)
+    static void removeLocalScheme(const QString &scheme);
+%End
+%If (Qt_4_6_0 -)
+    static QStringList localSchemes();
+%End
+%If (Qt_4_8_0 -)
+    void setApplicationCacheQuota(qint64 quota);
+%End
+};
+
+%End
diff --git a/python/QtWebKit/qwebsettings.sip b/python/QtWebKit/qwebsettings.sip
new file mode 100644
index 0000000..1aa3e17
--- /dev/null
+++ b/python/QtWebKit/qwebsettings.sip
@@ -0,0 +1,237 @@
+// qwebsettings.sip generated by MetaSIP
+//
+// This file is part of the QtWebKit Python extension module.
+//
+// Copyright (c) 2015 Riverbank Computing Limited <info at riverbankcomputing.com>
+//
+// This file is part of PyQt4.
+//
+// This file may be used under the terms of the GNU General Public License
+// version 3.0 as published by the Free Software Foundation and appearing in
+// the file LICENSE included in the packaging of this file.  Please review the
+// following information to ensure the GNU General Public License version 3.0
+// requirements will be met: http://www.gnu.org/copyleft/gpl.html.
+//
+// If you do not wish to use this file under the terms of the GPL version 3.0
+// then you may purchase a commercial license.  For more information contact
+// info at riverbankcomputing.com.
+//
+// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+
+
+%If (Qt_4_4_0 -)
+
+class QWebSettings
+{
+%TypeHeaderCode
+#include <qwebsettings.h>
+%End
+
+public:
+    enum FontFamily
+    {
+        StandardFont,
+        FixedFont,
+        SerifFont,
+        SansSerifFont,
+        CursiveFont,
+        FantasyFont,
+    };
+
+    enum WebAttribute
+    {
+        AutoLoadImages,
+        JavascriptEnabled,
+        JavaEnabled,
+        PluginsEnabled,
+        PrivateBrowsingEnabled,
+        JavascriptCanOpenWindows,
+%If (Qt_4_8_0 -)
+        JavascriptCanCloseWindows,
+%End
+        JavascriptCanAccessClipboard,
+        DeveloperExtrasEnabled,
+        LinksIncludedInFocusChain,
+%If (Qt_4_5_0 -)
+        ZoomTextOnly,
+%End
+%If (Qt_4_5_0 -)
+        PrintElementBackgrounds,
+%End
+%If (Qt_4_5_0 -)
+        OfflineStorageDatabaseEnabled,
+%End
+%If (Qt_4_5_0 -)
+        OfflineWebApplicationCacheEnabled,
+%End
+%If (Qt_4_5_0 -)
+        LocalStorageDatabaseEnabled,
+%End
+%If (Qt_4_6_0 -)
+        LocalStorageEnabled,
+%End
+%If (Qt_4_6_0 -)
+        LocalContentCanAccessRemoteUrls,
+%End
+%If (Qt_4_6_0 -)
+        DnsPrefetchEnabled,
+%End
+%If (Qt_4_7_0 -)
+        XSSAuditingEnabled,
+%End
+%If (Qt_4_7_0 -)
+        AcceleratedCompositingEnabled,
+%End
+%If (Qt_4_7_0 -)
+        SpatialNavigationEnabled,
+%End
+%If (Qt_4_7_0 -)
+        LocalContentCanAccessFileUrls,
+%End
+%If (Qt_4_7_0 -)
+        TiledBackingStoreEnabled,
+%End
+%If (Qt_4_7_0 -)
+        FrameFlatteningEnabled,
+%End
+%If (Qt_4_7_0 -)
+        SiteSpecificQuirksEnabled,
+%End
+%If (Qt_4_8_0 -)
+        WebGLEnabled,
+%End
+%If (Qt_4_8_0 -)
+        HyperlinkAuditingEnabled,
+%End
+%If (Qt_5_0_0 -)
+        CSSRegionsEnabled,
+%End
+%If (Qt_5_0_0 -)
+        CSSGridLayoutEnabled,
+%End
+%If (Qt_5_0_0 -)
+        ScrollAnimatorEnabled,
+%End
+%If (Qt_5_0_0 -)
+        CaretBrowsingEnabled,
+%End
+%If (Qt_5_0_0 -)
+        NotificationsEnabled,
+%End
+    };
+
+    enum WebGraphic
+    {
+        MissingImageGraphic,
+        MissingPluginGraphic,
+        DefaultFrameIconGraphic,
+        TextAreaSizeGripCornerGraphic,
+%If (Qt_4_8_0 -)
+        InputSpeechButtonGraphic,
+%End
+%If (Qt_4_8_0 -)
+        SearchCancelButtonGraphic,
+%End
+%If (Qt_4_8_0 -)
+        SearchCancelButtonPressedGraphic,
+%End
+    };
+
+    enum FontSize
+    {
+        MinimumFontSize,
+        MinimumLogicalFontSize,
+        DefaultFontSize,
+        DefaultFixedFontSize,
+    };
+
+    static QWebSettings *globalSettings();
+    void setFontFamily(QWebSettings::FontFamily which, const QString &family);
+    QString fontFamily(QWebSettings::FontFamily which) const;
+    void resetFontFamily(QWebSettings::FontFamily which);
+    void setFontSize(QWebSettings::FontSize type, int size);
+    int fontSize(QWebSettings::FontSize type) const;
+    void resetFontSize(QWebSettings::FontSize type);
+    void setAttribute(QWebSettings::WebAttribute attr, bool on);
+    bool testAttribute(QWebSettings::WebAttribute attr) const;
+    void resetAttribute(QWebSettings::WebAttribute attr);
+    void setUserStyleSheetUrl(const QUrl &location);
+    QUrl userStyleSheetUrl() const;
+    static void setIconDatabasePath(const QString &location);
+    static QString iconDatabasePath();
+    static void clearIconDatabase();
+    static QIcon iconForUrl(const QUrl &url);
+    static void setWebGraphic(QWebSettings::WebGraphic type, const QPixmap &graphic);
+    static QPixmap webGraphic(QWebSettings::WebGraphic type);
+    static void setMaximumPagesInCache(int pages);
+    static int maximumPagesInCache();
+    static void setObjectCacheCapacities(int cacheMinDeadCapacity, int cacheMaxDead, int totalCapacity);
+
+private:
+    QWebSettings();
+    QWebSettings(const QWebSettings &);
+    ~QWebSettings();
+
+public:
+%If (Qt_4_5_0 -)
+    static void setOfflineStoragePath(const QString &path);
+%End
+%If (Qt_4_5_0 -)
+    static QString offlineStoragePath();
+%End
+%If (Qt_4_5_0 -)
+    static void setOfflineStorageDefaultQuota(qint64 maximumSize);
+%End
+%If (Qt_4_5_0 -)
+    static qint64 offlineStorageDefaultQuota();
+%End
+%If (Qt_4_6_0 -)
+    void setDefaultTextEncoding(const QString &encoding);
+%End
+%If (Qt_4_6_0 -)
+    QString defaultTextEncoding() const;
+%End
+%If (Qt_4_6_0 -)
+    static void setOfflineWebApplicationCachePath(const QString &path);
+%End
+%If (Qt_4_6_0 -)
+    static QString offlineWebApplicationCachePath();
+%End
+%If (Qt_4_6_0 -)
+    static void setOfflineWebApplicationCacheQuota(qint64 maximumSize);
+%End
+%If (Qt_4_6_0 -)
+    static qint64 offlineWebApplicationCacheQuota();
+%End
+%If (Qt_4_6_0 -)
+    void setLocalStoragePath(const QString &path);
+%End
+%If (Qt_4_6_0 -)
+    QString localStoragePath() const;
+%End
+%If (Qt_4_6_0 -)
+    static void clearMemoryCaches();
+%End
+%If (Qt_4_6_0 -)
+    static void enablePersistentStorage(const QString &path = QString());
+%End
+%If (Qt_5_0_0 -)
+
+    enum ThirdPartyCookiePolicy
+    {
+        AlwaysAllowThirdPartyCookies,
+        AlwaysBlockThirdPartyCookies,
+        AllowThirdPartyWithExistingCookies,
+    };
+
+%End
+%If (Qt_5_0_0 -)
+    void setThirdPartyCookiePolicy(QWebSettings::ThirdPartyCookiePolicy);
+%End
+%If (Qt_5_0_0 -)
+    QWebSettings::ThirdPartyCookiePolicy thirdPartyCookiePolicy() const;
+%End
+};
+
+%End
diff --git a/python/QtWebKit/qwebview.sip b/python/QtWebKit/qwebview.sip
new file mode 100644
index 0000000..80318d4
--- /dev/null
+++ b/python/QtWebKit/qwebview.sip
@@ -0,0 +1,167 @@
+// qwebview.sip generated by MetaSIP
+//
+// This file is part of the QtWebKit Python extension module.
+//
+// Copyright (c) 2015 Riverbank Computing Limited <info at riverbankcomputing.com>
+//
+// This file is part of PyQt4.
+//
+// This file may be used under the terms of the GNU General Public License
+// version 3.0 as published by the Free Software Foundation and appearing in
+// the file LICENSE included in the packaging of this file.  Please review the
+// following information to ensure the GNU General Public License version 3.0
+// requirements will be met: http://www.gnu.org/copyleft/gpl.html.
+//
+// If you do not wish to use this file under the terms of the GPL version 3.0
+// then you may purchase a commercial license.  For more information contact
+// info at riverbankcomputing.com.
+//
+// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+
+
+%If (Qt_4_4_0 -)
+
+class QWebView : QWidget
+{
+%TypeHeaderCode
+#include <qwebview.h>
+%End
+
+%ConvertToSubClassCode
+    static struct class_graph {
+            const char *name;
+            sipTypeDef **type;
+            int yes, no;
+        } graph[] = {
+            {sipName_QWebPluginFactory, &sipType_QWebPluginFactory, -1, 1},
+            {sipName_QWebFrame, &sipType_QWebFrame, -1, 2},
+            {sipName_QWebPage, &sipType_QWebPage, -1, 3},
+            {sipName_QWebHistoryInterface, &sipType_QWebHistoryInterface, -1, 4},
+            {sipName_QWebView, &sipType_QWebView, -1, 5},
+    #if QT_VERSION >= 0x040600
+            {sipName_QWebInspector, &sipType_QWebInspector, -1, 6},
+            {sipName_QGraphicsWebView, &sipType_QGraphicsWebView, -1, -1},
+    #else
+            {0, 0, -1, 6},
+            {0, 0, -1, -1},
+    #endif
+        };
+
+        int i = 0;
+
+        sipType = 0;
+
+        do
+        {
+            struct class_graph *cg = &graph[i];
+
+            if (cg->name != NULL && sipCpp->inherits(cg->name))
+            {
+                sipType = *cg->type;
+                i = cg->yes;
+            }
+            else
+                i = cg->no;
+        }
+        while (i >= 0);
+%End
+
+public:
+    explicit QWebView(QWidget *parent /TransferThis/ = 0);
+    virtual ~QWebView();
+    QWebPage *page() const;
+    void setPage(QWebPage *page /KeepReference/);
+    void load(const QUrl &url) /ReleaseGIL/;
+    void load(const QNetworkRequest &request, QNetworkAccessManager::Operation operation = QNetworkAccessManager::GetOperation, const QByteArray &body = QByteArray()) /ReleaseGIL/;
+    void setHtml(const QString &html, const QUrl &baseUrl = QUrl());
+    void setContent(const QByteArray &data, const QString &mimeType /DocValue="Py_v3:''"/ = QString(), const QUrl &baseUrl = QUrl());
+    QWebHistory *history() const;
+    QWebSettings *settings() const;
+    QString title() const;
+    void setUrl(const QUrl &url);
+    QUrl url() const;
+    QIcon icon() const;
+    QString selectedText() const;
+    QAction *pageAction(QWebPage::WebAction action) const;
+    void triggerPageAction(QWebPage::WebAction action, bool checked = false);
+    bool isModified() const;
+    virtual QVariant inputMethodQuery(Qt::InputMethodQuery property) const;
+    virtual QSize sizeHint() const;
+    void setTextSizeMultiplier(qreal factor);
+    qreal textSizeMultiplier() const;
+    bool findText(const QString &subString, QFlags<QWebPage::FindFlag> options = 0);
+    virtual bool event(QEvent *);
+
+public slots:
+    void stop();
+    void back();
+    void forward();
+    void reload();
+%If (PyQt_Printer)
+    void print(QPrinter *printer) const /PyName=print_/;
+%End
+%If (Py_v3)
+%If (PyQt_Printer)
+    void print(QPrinter *printer) const;
+%End
+%End
+
+signals:
+    void loadStarted();
+    void loadProgress(int progress);
+    void loadFinished(bool);
+    void titleChanged(const QString &title);
+    void statusBarMessage(const QString &text);
+    void linkClicked(const QUrl &url);
+    void selectionChanged();
+    void iconChanged();
+    void urlChanged(const QUrl &url);
+
+protected:
+    virtual QWebView *createWindow(QWebPage::WebWindowType type);
+    virtual void resizeEvent(QResizeEvent *e);
+    virtual void paintEvent(QPaintEvent *ev);
+    virtual void changeEvent(QEvent *);
+    virtual void mouseMoveEvent(QMouseEvent *);
+    virtual void mousePressEvent(QMouseEvent *);
+    virtual void mouseDoubleClickEvent(QMouseEvent *);
+    virtual void mouseReleaseEvent(QMouseEvent *);
+    virtual void contextMenuEvent(QContextMenuEvent *);
+    virtual void wheelEvent(QWheelEvent *);
+    virtual void keyPressEvent(QKeyEvent *);
+    virtual void keyReleaseEvent(QKeyEvent *);
+    virtual void dragEnterEvent(QDragEnterEvent *);
+    virtual void dragLeaveEvent(QDragLeaveEvent *);
+    virtual void dragMoveEvent(QDragMoveEvent *);
+    virtual void dropEvent(QDropEvent *);
+    virtual void focusInEvent(QFocusEvent *);
+    virtual void focusOutEvent(QFocusEvent *);
+    virtual void inputMethodEvent(QInputMethodEvent *);
+    virtual bool focusNextPrevChild(bool next);
+
+public:
+%If (Qt_4_5_0 -)
+    qreal zoomFactor() const;
+%End
+%If (Qt_4_5_0 -)
+    void setZoomFactor(qreal factor);
+%End
+%If (Qt_4_6_0 -)
+    QFlags<QPainter::RenderHint> renderHints() const;
+%End
+%If (Qt_4_6_0 -)
+    void setRenderHints(QFlags<QPainter::RenderHint> hints);
+%End
+%If (Qt_4_6_0 -)
+    void setRenderHint(QPainter::RenderHint hint, bool enabled = true);
+%End
+%If (Qt_4_8_0 -)
+    bool hasSelection() const;
+%End
+%If (Qt_4_8_0 -)
+    QString selectedHtml() const;
+%End
+};
+
+%End
diff --git a/python/core/geometry/qgsabstractgeometryv2.sip b/python/core/geometry/qgsabstractgeometryv2.sip
index 3cd3ab5..2264423 100644
--- a/python/core/geometry/qgsabstractgeometryv2.sip
+++ b/python/core/geometry/qgsabstractgeometryv2.sip
@@ -306,6 +306,12 @@ class QgsAbstractGeometryV2
      */
     virtual QgsAbstractGeometryV2* segmentize() const /Factory/;
 
+    /** Returns the geometry converted to the more generic curve type.
+        E.g. QgsLineString -> QgsCompoundCurve, QgsPolygonV2 -> QgsCurvePolygon,
+        QgsMultiLineString -> QgsMultiCurve, QgsMultiPolygonV2 -> QgsMultiSurface
+        @return the converted geometry. Caller takes ownership*/
+    virtual QgsAbstractGeometryV2* toCurveType() const /Factory/;
+
     /** Returns approximate angle at a vertex. This is usually the average angle between adjacent
      * segments, and can be pictured as the orientation of a line following the curvature of the
      * geometry at the specified vertex.
diff --git a/python/core/geometry/qgslinestringv2.sip b/python/core/geometry/qgslinestringv2.sip
index fad5fca..319a811 100644
--- a/python/core/geometry/qgslinestringv2.sip
+++ b/python/core/geometry/qgslinestringv2.sip
@@ -102,6 +102,10 @@ class QgsLineStringV2: public QgsCurveV2
     /** Closes the line string by appending the first point to the end of the line, if it is not already closed.*/
     void close();
 
+    /** Returns the geometry converted to the more generic curve type QgsCompoundCurve
+    @return the converted geometry. Caller takes ownership*/
+    QgsAbstractGeometryV2* toCurveType() const /Factory/;
+
     /** Returns a QPolygonF representing the line string.
      */
     QPolygonF asQPolygonF() const;
diff --git a/python/core/geometry/qgsmultilinestringv2.sip b/python/core/geometry/qgsmultilinestringv2.sip
index c1833e7..a3853cc 100644
--- a/python/core/geometry/qgsmultilinestringv2.sip
+++ b/python/core/geometry/qgsmultilinestringv2.sip
@@ -20,6 +20,10 @@ class QgsMultiLineStringV2: public QgsMultiCurveV2
     /** Adds a geometry and takes ownership. Returns true in case of success*/
     virtual bool addGeometry( QgsAbstractGeometryV2* g );
 
+    /** Returns the geometry converted to the more generic curve type QgsMultiCurve
+        @return the converted geometry. Caller takes ownership*/
+    QgsAbstractGeometryV2* toCurveType() const /Factory/;
+
   protected:
 
     virtual bool wktOmitChildType() const;
diff --git a/python/core/geometry/qgsmultipolygonv2.sip b/python/core/geometry/qgsmultipolygonv2.sip
index 26392e2..66d080f 100644
--- a/python/core/geometry/qgsmultipolygonv2.sip
+++ b/python/core/geometry/qgsmultipolygonv2.sip
@@ -20,6 +20,10 @@ class QgsMultiPolygonV2: public QgsMultiSurfaceV2
     /** Adds a geometry and takes ownership. Returns true in case of success*/
     virtual bool addGeometry( QgsAbstractGeometryV2* g );
 
+    /** Returns the geometry converted to the more generic curve type QgsMultiSurface
+        @return the converted geometry. Caller takes ownership*/
+    QgsAbstractGeometryV2* toCurveType() const /Factory/;
+
   protected:
 
     virtual bool wktOmitChildType() const;
diff --git a/python/core/geometry/qgspolygonv2.sip b/python/core/geometry/qgspolygonv2.sip
index f52273e..7416804 100644
--- a/python/core/geometry/qgspolygonv2.sip
+++ b/python/core/geometry/qgspolygonv2.sip
@@ -26,6 +26,10 @@ class QgsPolygonV2: public QgsCurvePolygonV2
 
     QgsPolygonV2* surfaceToPolygon() const;
 
+    /** Returns the geometry converted to the more generic curve type QgsCurvePolygon
+         @return the converted geometry. Caller takes ownership*/
+    QgsAbstractGeometryV2* toCurveType() const /Factory/;
+
     void addInteriorRing( QgsCurveV2* ring /Transfer/ );
     //overridden to handle LineString25D rings
     virtual void setExteriorRing( QgsCurveV2* ring /Transfer/ );
diff --git a/python/core/qgsstringutils.sip b/python/core/qgsstringutils.sip
index a030161..7c133c7 100644
--- a/python/core/qgsstringutils.sip
+++ b/python/core/qgsstringutils.sip
@@ -10,6 +10,25 @@ class QgsStringUtils
 #include <qgsstringutils.h>
 %End
   public:
+
+
+    //! Capitalization options
+    enum Capitalization
+    {
+      MixedCase, //!< Mixed case, ie no change
+      AllUppercase, //!< Convert all characters to uppercase
+      AllLowercase,  //!< Convert all characters to lowercase
+      ForceFirstLetterToCapital, //!< Convert just the first letter of each word to uppercase, leave the rest untouched
+    };
+
+    /** Converts a string by applying capitalization rules to the string.
+     * @param string input string
+     * @param capitalization capitalization type to apply
+     * @return capitalized string
+     * @note added in QGIS 3.0
+     */
+    static QString capitalize( const QString& string, Capitalization capitalization );
+
     /** Returns the Levenshtein edit distance between two strings. This equates to the minimum
      * number of character edits (insertions, deletions or substitutions) required to change
      * one string to another.
diff --git a/python/core/qgsvectordataprovider.sip b/python/core/qgsvectordataprovider.sip
index 3755723..d5ca5ac 100644
--- a/python/core/qgsvectordataprovider.sip
+++ b/python/core/qgsvectordataprovider.sip
@@ -361,4 +361,8 @@ class QgsVectorDataProvider : QgsDataProvider
     void fillMinMaxCache();
 
     void pushError( const QString& msg );
+
+    /** Converts the geometry to the provider type if possible / necessary
+    @return the converted geometry or nullptr if no conversion was necessary or possible*/
+    QgsGeometry* convertToProviderType( const QgsGeometry& geom ) const /Factory/;
 };
diff --git a/python/gui/qgsmessagebar.sip b/python/gui/qgsmessagebar.sip
index ad3ba32..0d74447 100644
--- a/python/gui/qgsmessagebar.sip
+++ b/python/gui/qgsmessagebar.sip
@@ -48,9 +48,9 @@ class QgsMessageBar: QFrame
     static QgsMessageBarItem* createMessage( QWidget *widget, QWidget *parent = 0 ) /Factory/;
 
     //! convenience method for pushing a message to the bar
-    void pushMessage( const QString &text, MessageLevel level = INFO, int duration = 0 );
+    void pushMessage( const QString &text, MessageLevel level = INFO, int duration = 5 );
     //! convenience method for pushing a message with title to the bar
-    void pushMessage( const QString &title, const QString &text, MessageLevel level = INFO, int duration = 0 );
+    void pushMessage( const QString &title, const QString &text, MessageLevel level = INFO, int duration = 5 );
 
     QgsMessageBarItem *currentItem();
 
diff --git a/python/plugins/processing/algs/qgis/ConcaveHull.py b/python/plugins/processing/algs/qgis/ConcaveHull.py
index 36df1eb..73be49f 100644
--- a/python/plugins/processing/algs/qgis/ConcaveHull.py
+++ b/python/plugins/processing/algs/qgis/ConcaveHull.py
@@ -66,7 +66,7 @@ class ConcaveHull(GeoAlgorithm):
 
         # Delaunay triangulation from input point layer
         progress.setText(self.tr('Creating Delaunay triangles...'))
-        delone_triangles = processing.runalg("qgis:delaunaytriangulation", layer, None, progress=None)['OUTPUT']
+        delone_triangles = processing.runalg("qgis:delaunaytriangulation", layer, None)['OUTPUT']
         delaunay_layer = processing.getObject(delone_triangles)
 
         # Get max edge length from Delaunay triangles
@@ -103,7 +103,7 @@ class ConcaveHull(GeoAlgorithm):
         # Dissolve all Delaunay triangles
         progress.setText(self.tr('Dissolving Delaunay triangles...'))
         dissolved = processing.runalg("qgis:dissolve", delaunay_layer,
-                                      True, None, None, progress=None)['OUTPUT']
+                                      True, None, None)['OUTPUT']
         dissolved_layer = processing.getObject(dissolved)
 
         # Save result
diff --git a/python/plugins/processing/algs/qgis/Intersection.py b/python/plugins/processing/algs/qgis/Intersection.py
index dc182e0..6310bca 100644
--- a/python/plugins/processing/algs/qgis/Intersection.py
+++ b/python/plugins/processing/algs/qgis/Intersection.py
@@ -87,8 +87,10 @@ class Intersection(GeoAlgorithm):
                     int_geom = QgsGeometry(geom.intersection(tmpGeom))
                     if int_geom.wkbType() == QGis.WKBUnknown or QgsWKBTypes.flatType(int_geom.geometry().wkbType()) == QgsWKBTypes.GeometryCollection:
                         int_com = geom.combine(tmpGeom)
-                        int_sym = geom.symDifference(tmpGeom)
-                        int_geom = QgsGeometry(int_com.difference(int_sym))
+                        int_geom = QgsGeometry()
+                        if int_com is not None:
+                            int_sym = geom.symDifference(tmpGeom)
+                            int_geom = QgsGeometry(int_com.difference(int_sym))
                     if int_geom.isGeosEmpty() or not int_geom.isGeosValid():
                         ProcessingLog.addToLog(ProcessingLog.LOG_ERROR,
                                                self.tr('GEOS geoprocessing error: One or '
diff --git a/python/plugins/processing/algs/qgis/MeanCoords.py b/python/plugins/processing/algs/qgis/MeanCoords.py
index 58fa89f..fe28b9f 100644
--- a/python/plugins/processing/algs/qgis/MeanCoords.py
+++ b/python/plugins/processing/algs/qgis/MeanCoords.py
@@ -49,11 +49,14 @@ class MeanCoords(GeoAlgorithm):
         self.addParameter(ParameterVector(self.POINTS,
                                           self.tr('Input layer'), [ParameterVector.VECTOR_TYPE_ANY]))
         self.addParameter(ParameterTableField(self.WEIGHT,
-                                              self.tr('Weight field'), MeanCoords.POINTS,
-                                              ParameterTableField.DATA_TYPE_NUMBER, optional=True))
+                                              self.tr('Weight field'),
+                                              MeanCoords.POINTS,
+                                              ParameterTableField.DATA_TYPE_NUMBER,
+                                              optional=True))
         self.addParameter(ParameterTableField(self.UID,
-                                              self.tr('Unique ID field'), MeanCoords.POINTS,
-                                              ParameterTableField.DATA_TYPE_NUMBER, optional=True))
+                                              self.tr('Unique ID field'),
+                                              MeanCoords.POINTS,
+                                              optional=True))
 
         self.addOutput(OutputVector(MeanCoords.OUTPUT, self.tr('Mean coordinates')))
 
diff --git a/python/plugins/processing/algs/qgis/SinglePartsToMultiparts.py b/python/plugins/processing/algs/qgis/SinglePartsToMultiparts.py
index 355b138..e28b263 100644
--- a/python/plugins/processing/algs/qgis/SinglePartsToMultiparts.py
+++ b/python/plugins/processing/algs/qgis/SinglePartsToMultiparts.py
@@ -98,7 +98,9 @@ class SinglePartsToMultiparts(GeoAlgorithm):
 
             del writer
         else:
-            raise GeoAlgorithmExecutionException(self.tr('Invalid unique ID field'))
+            raise GeoAlgorithmExecutionException(
+                self.tr('At least two features must have same attribute '
+                        'value! Please choose another field...'))
 
     def singleToMultiGeom(self, wkbType):
         try:
diff --git a/python/plugins/processing/core/parameters.py b/python/plugins/processing/core/parameters.py
index 75621a1..5126f66 100644
--- a/python/plugins/processing/core/parameters.py
+++ b/python/plugins/processing/core/parameters.py
@@ -885,7 +885,7 @@ class ParameterGeometryPredicate(Parameter):
             self.enabledPredicates = self.predicates
 
     def getValueAsCommandLineParameter(self):
-        return '"' + unicode(self.value) + '"'
+        return unicode(self.value)
 
     def setValue(self, value):
         if value is None:
diff --git a/python/plugins/processing/gui/AlgorithmDialogBase.py b/python/plugins/processing/gui/AlgorithmDialogBase.py
index 69c282d..4dd1ad5 100644
--- a/python/plugins/processing/gui/AlgorithmDialogBase.py
+++ b/python/plugins/processing/gui/AlgorithmDialogBase.py
@@ -172,9 +172,6 @@ class AlgorithmDialogBase(BASE, WIDGET):
         self.setInfo(text, False)
         QCoreApplication.processEvents()
 
-    def error(self, msg):
-        self.setInfo(msg, error=True)
-
     def setParamValues(self):
         pass
 
diff --git a/python/plugins/processing/ui/DlgGetScriptsAndModels.ui b/python/plugins/processing/ui/DlgGetScriptsAndModels.ui
index 62a0372..fec3be0 100644
--- a/python/plugins/processing/ui/DlgGetScriptsAndModels.ui
+++ b/python/plugins/processing/ui/DlgGetScriptsAndModels.ui
@@ -81,11 +81,6 @@
            <height>10000</height>
           </size>
          </property>
-         <property name="url">
-          <url>
-           <string>about:blank</string>
-          </url>
-         </property>
         </widget>
        </item>
       </layout>
diff --git a/src/analysis/vector/qgsgeometryanalyzer.cpp b/src/analysis/vector/qgsgeometryanalyzer.cpp
index 245efdf..10eee32 100644
--- a/src/analysis/vector/qgsgeometryanalyzer.cpp
+++ b/src/analysis/vector/qgsgeometryanalyzer.cpp
@@ -1178,29 +1178,32 @@ QgsGeometry* QgsGeometryAnalyzer::locateBetweenMeasures( double fromMeasure, dou
   }
 
   QgsMultiPolyline resultGeom;
+  QgsWKBTypes::Type wkbType = lineGeom->geometry()->wkbType();
 
-  //need to go with WKB and z coordinate until QgsGeometry supports M values
-  QgsConstWkbPtr wkbPtr( lineGeom->asWkb(), lineGeom->wkbSize() );
-  wkbPtr.readHeader();
-
-  QGis::WkbType wkbType = lineGeom->wkbType();
-  if ( wkbType != QGis::WKBLineString25D && wkbType != QGis::WKBMultiLineString25D )
+  //only linestring / multilinestring types supported at the moment
+  if ( QgsWKBTypes::singleType( QgsWKBTypes::flatType( wkbType ) ) != QgsWKBTypes::LineString || QgsWKBTypes::coordDimensions( wkbType ) < 3 )
   {
     return nullptr;
   }
 
-  if ( wkbType == QGis::WKBLineString25D )
+  bool hasZM = QgsWKBTypes::hasZ( wkbType ) && QgsWKBTypes::hasM( wkbType );
+
+
+  QgsConstWkbPtr wkbPtr( lineGeom->asWkb(), lineGeom->wkbSize() );
+  wkbPtr.readHeader();
+
+  if ( QgsWKBTypes::flatType( wkbType ) == QgsWKBTypes::LineString )
   {
-    locateBetweenWkbString( wkbPtr, resultGeom, fromMeasure, toMeasure );
+    locateBetweenWkbString( wkbPtr, resultGeom, fromMeasure, toMeasure, hasZM );
   }
-  else if ( wkbType == QGis::WKBMultiLineString25D )
+  else if ( QgsWKBTypes::flatType( wkbType ) == QgsWKBTypes::MultiLineString )
   {
     int nLines;
     wkbPtr >> nLines;
     for ( int i = 0; i < nLines; ++i )
     {
       wkbPtr.readHeader();
-      wkbPtr = locateBetweenWkbString( wkbPtr, resultGeom, fromMeasure, toMeasure );
+      wkbPtr = locateBetweenWkbString( wkbPtr, resultGeom, fromMeasure, toMeasure, hasZM );
     }
   }
 
@@ -1213,7 +1216,7 @@ QgsGeometry* QgsGeometryAnalyzer::locateBetweenMeasures( double fromMeasure, dou
 
 QgsGeometry* QgsGeometryAnalyzer::locateAlongMeasure( double measure, const QgsGeometry *lineGeom )
 {
-  if ( !lineGeom )
+  if ( !lineGeom || !lineGeom->geometry() )
   {
     return nullptr;
   }
@@ -1222,25 +1225,29 @@ QgsGeometry* QgsGeometryAnalyzer::locateAlongMeasure( double measure, const QgsG
 
   //need to go with WKB and z coordinate until QgsGeometry supports M values
   QgsConstWkbPtr wkbPtr( lineGeom->asWkb(), lineGeom->wkbSize() );
-  QGis::WkbType wkbType = lineGeom->wkbType();
+  wkbPtr.readHeader();
+  QgsWKBTypes::Type wkbType = lineGeom->geometry()->wkbType();
 
-  if ( wkbType != QGis::WKBLineString25D && wkbType != QGis::WKBMultiLineString25D )
+  //only linestring / multilinestring types supported at the moment
+  if ( QgsWKBTypes::singleType( QgsWKBTypes::flatType( wkbType ) ) != QgsWKBTypes::LineString || QgsWKBTypes::coordDimensions( wkbType ) < 3 )
   {
     return nullptr;
   }
 
-  if ( wkbType == QGis::WKBLineString25D )
+  bool hasZM = QgsWKBTypes::hasZ( wkbType ) && QgsWKBTypes::hasM( wkbType );
+
+  if ( QgsWKBTypes::flatType( wkbType ) == QgsWKBTypes::LineString )
   {
-    locateAlongWkbString( wkbPtr, resultGeom, measure );
+    locateAlongWkbString( wkbPtr, resultGeom, measure, hasZM );
   }
-  else if ( wkbType == QGis::WKBMultiLineString25D )
+  else if ( QgsWKBTypes::flatType( wkbType ) == QgsWKBTypes::MultiLineString )
   {
     int nLines;
     wkbPtr >> nLines;
     for ( int i = 0; i < nLines; ++i )
     {
       wkbPtr.readHeader();
-      wkbPtr = locateAlongWkbString( wkbPtr, resultGeom, measure );
+      wkbPtr = locateAlongWkbString( wkbPtr, resultGeom, measure, hasZM );
     }
   }
 
@@ -1252,7 +1259,7 @@ QgsGeometry* QgsGeometryAnalyzer::locateAlongMeasure( double measure, const QgsG
   return QgsGeometry::fromMultiPoint( resultGeom );
 }
 
-QgsConstWkbPtr QgsGeometryAnalyzer::locateBetweenWkbString( QgsConstWkbPtr wkbPtr, QgsMultiPolyline& result, double fromMeasure, double toMeasure )
+QgsConstWkbPtr QgsGeometryAnalyzer::locateBetweenWkbString( QgsConstWkbPtr wkbPtr, QgsMultiPolyline& result, double fromMeasure, double toMeasure, bool zm )
 {
   int nPoints;
   wkbPtr >> nPoints;
@@ -1262,7 +1269,12 @@ QgsConstWkbPtr QgsGeometryAnalyzer::locateBetweenWkbString( QgsConstWkbPtr wkbPt
   for ( int i = 0; i < nPoints; ++i )
   {
     double x, y, z;
-    wkbPtr >> x >> y >> z;
+    wkbPtr >> x >> y;
+    if ( zm )
+    {
+      wkbPtr += sizeof( double );
+    }
+    wkbPtr >> z;
 
     if ( i > 0 )
     {
@@ -1299,7 +1311,7 @@ QgsConstWkbPtr QgsGeometryAnalyzer::locateBetweenWkbString( QgsConstWkbPtr wkbPt
   return wkbPtr;
 }
 
-QgsConstWkbPtr QgsGeometryAnalyzer::locateAlongWkbString( QgsConstWkbPtr wkbPtr, QgsMultiPoint& result, double measure )
+QgsConstWkbPtr QgsGeometryAnalyzer::locateAlongWkbString( QgsConstWkbPtr wkbPtr, QgsMultiPoint& result, double measure, bool zm )
 {
   int nPoints;
   wkbPtr >> nPoints;
@@ -1308,7 +1320,12 @@ QgsConstWkbPtr QgsGeometryAnalyzer::locateAlongWkbString( QgsConstWkbPtr wkbPtr,
   double prevx = 0.0, prevy = 0.0, prevz = 0.0;
   for ( int i = 0; i < nPoints; ++i )
   {
-    wkbPtr >> x >> y >> z;
+    wkbPtr >> x >> y;
+    if ( zm )
+    {
+      wkbPtr += sizeof( double );
+    }
+    wkbPtr >> z;
 
     if ( i > 0 )
     {
diff --git a/src/analysis/vector/qgsgeometryanalyzer.h b/src/analysis/vector/qgsgeometryanalyzer.h
index cbd50e8..f886a47 100644
--- a/src/analysis/vector/qgsgeometryanalyzer.h
+++ b/src/analysis/vector/qgsgeometryanalyzer.h
@@ -100,7 +100,7 @@ class ANALYSIS_EXPORT QgsGeometryAnalyzer
                    int uniqueIdField = -1, QProgressDialog* p = nullptr );
 
     /** Creates an event layer (multipoint or multiline) by locating features from a (non-spatial) event table along the features of a line layer.
-     * Note that currently (until QgsGeometry supports m-values) the z-coordinate of the line layer is used for linear referencing
+     * Note that this function only supports linestring / multilinestring 25D/Z/M/ZM types as input
      * @param lineLayer layer with the line geometry
      * @param eventLayer layer with features and location field
      * @param lineField join index in line layer
@@ -120,10 +120,10 @@ class ANALYSIS_EXPORT QgsGeometryAnalyzer
                      const QString& outputFormat, int locationField1, int locationField2 = -1, int offsetField = -1, double offsetScale = 1.0,
                      bool forceSingleGeometry = false, QgsVectorDataProvider* memoryProvider = nullptr, QProgressDialog* p = nullptr );
 
-    /** Returns linear reference geometry as a multiline (or 0 if no match). Currently, the z-coordinates are considered to be the measures (no support for m-values in QGIS)*/
+    /** Returns linear reference geometry as a multiline (or 0 if no match). This function only supports linestring/multilinestring 25D/Z/M/ZM types*/
     QgsGeometry* locateBetweenMeasures( double fromMeasure, double toMeasure, const QgsGeometry *lineGeom );
     /** Returns linear reference geometry. Unlike the PostGIS function, this method always returns multipoint or 0 if no match (not geometry collection).
-     * Currently, the z-coordinates are considered to be the measures (no support for m-values in QGIS)
+     * Note that this function only supports linestring / multilinestring 25D/Z/M/ZM types as input
      */
     QgsGeometry* locateAlongMeasure( double measure, const QgsGeometry* lineGeom );
 
@@ -152,8 +152,8 @@ class ANALYSIS_EXPORT QgsGeometryAnalyzer
         @param offset the offset value in layer unit. Negative values mean offset towards left, positive values offset to the right side*/
     bool createOffsetGeometry( QgsGeometry* geom, QgsGeometry* lineGeom, double offset );
     QgsPoint createPointOffset( double x, double y, double dist, QgsGeometry* lineGeom ) const;
-    QgsConstWkbPtr locateBetweenWkbString( QgsConstWkbPtr ptr, QgsMultiPolyline& result, double fromMeasure, double toMeasure );
-    QgsConstWkbPtr locateAlongWkbString( QgsConstWkbPtr ptr, QgsMultiPoint& result, double measure );
+    QgsConstWkbPtr locateBetweenWkbString( QgsConstWkbPtr ptr, QgsMultiPolyline& result, double fromMeasure, double toMeasure, bool zm );
+    QgsConstWkbPtr locateAlongWkbString( QgsConstWkbPtr ptr, QgsMultiPoint& result, double measure, bool zm );
     static bool clipSegmentByRange( double x1, double y1, double m1, double x2, double y2, double m2, double range1, double range2, QgsPoint& pt1, QgsPoint& pt2, bool& secondPointClipped );
     static void locateAlongSegment( double x1, double y1, double m1, double x2, double y2, double m2, double measure, bool& pt1Ok, QgsPoint& pt1, bool& pt2Ok, QgsPoint& pt2 );
 };
diff --git a/src/app/main.cpp b/src/app/main.cpp
index 1882ecd..1bdd275 100644
--- a/src/app/main.cpp
+++ b/src/app/main.cpp
@@ -105,46 +105,57 @@ typedef SInt32 SRefCon;
 
 /** Print usage text
  */
-void usage( std::string const & appName )
+void usage( QString appName )
 {
-  std::cerr << "QGIS - " << VERSION << " '" << RELEASE_NAME << "' ("
-            << QGSVERSION << ")\n"
-            << "QGIS is a user friendly Open Source Geographic Information System.\n"
-            << "Usage: " << appName <<  " [OPTION] [FILE]\n"
-            << "  OPTION:\n"
-            << "\t[--snapshot filename]\temit snapshot of loaded datasets to given file\n"
-            << "\t[--width width]\twidth of snapshot to emit\n"
-            << "\t[--height height]\theight of snapshot to emit\n"
-            << "\t[--lang language]\tuse language for interface text\n"
-            << "\t[--project projectfile]\tload the given QGIS project\n"
-            << "\t[--extent xmin,ymin,xmax,ymax]\tset initial map extent\n"
-            << "\t[--nologo]\thide splash screen\n"
-            << "\t[--noversioncheck]\tdon't check for new version of QGIS at startup"
-            << "\t[--noplugins]\tdon't restore plugins on startup\n"
-            << "\t[--nocustomization]\tdon't apply GUI customization\n"
-            << "\t[--customizationfile]\tuse the given ini file as GUI customization\n"
-            << "\t[--optionspath path]\tuse the given QSettings path\n"
-            << "\t[--configpath path]\tuse the given path for all user configuration\n"
-            << "\t[--authdbdirectory path] use the given directory for authentication database\n"
-            << "\t[--code path]\trun the given python file on load\n"
-            << "\t[--defaultui]\tstart by resetting user ui settings to default\n"
-            << "\t[--dxf-export filename.dxf]\temit dxf output of loaded datasets to given file\n"
-            << "\t[--dxf-extent xmin,ymin,xmax,ymax]\tset extent to export to dxf\n"
-            << "\t[--dxf-symbology-mode none|symbollayer|feature]\tsymbology mode for dxf output\n"
-            << "\t[--dxf-scale-denom scale]\tscale for dxf output\n"
-            << "\t[--dxf-encoding encoding]\tencoding to use for dxf output\n"
-            << "\t[--dxf-preset visiblity-preset]\tlayer visibility preset to use for dxf output\n"
-            << "\t[--help]\t\tthis text\n"
-            << "\t[--]\t\ttreat all following arguments as FILEs\n\n"
-            << "  FILE:\n"
-            << "    Files specified on the command line can include rasters,\n"
-            << "    vectors, and QGIS project files (.qgs): \n"
-            << "     1. Rasters - supported formats include GeoTiff, DEM \n"
-            << "        and others supported by GDAL\n"
-            << "     2. Vectors - supported formats include ESRI Shapefiles\n"
-            << "        and others supported by OGR and PostgreSQL layers using\n"
-            << "        the PostGIS extension\n"  ; // OK
+  QStringList msg;
+
+  msg
+  << "QGIS - " << VERSION << " '" << RELEASE_NAME << "' ("
+  << QGSVERSION << ")\n"
+  << "QGIS is a user friendly Open Source Geographic Information System.\n"
+  << "Usage: " << appName <<  " [OPTION] [FILE]\n"
+  << "  OPTION:\n"
+  << "\t[--snapshot filename]\temit snapshot of loaded datasets to given file\n"
+  << "\t[--width width]\twidth of snapshot to emit\n"
+  << "\t[--height height]\theight of snapshot to emit\n"
+  << "\t[--lang language]\tuse language for interface text\n"
+  << "\t[--project projectfile]\tload the given QGIS project\n"
+  << "\t[--extent xmin,ymin,xmax,ymax]\tset initial map extent\n"
+  << "\t[--nologo]\thide splash screen\n"
+  << "\t[--noversioncheck]\tdon't check for new version of QGIS at startup\n"
+  << "\t[--noplugins]\tdon't restore plugins on startup\n"
+  << "\t[--nocustomization]\tdon't apply GUI customization\n"
+  << "\t[--customizationfile]\tuse the given ini file as GUI customization\n"
+  << "\t[--optionspath path]\tuse the given QSettings path\n"
+  << "\t[--configpath path]\tuse the given path for all user configuration\n"
+  << "\t[--authdbdirectory path] use the given directory for authentication database\n"
+  << "\t[--code path]\trun the given python file on load\n"
+  << "\t[--defaultui]\tstart by resetting user ui settings to default\n"
+  << "\t[--dxf-export filename.dxf]\temit dxf output of loaded datasets to given file\n"
+  << "\t[--dxf-extent xmin,ymin,xmax,ymax]\tset extent to export to dxf\n"
+  << "\t[--dxf-symbology-mode none|symbollayer|feature]\tsymbology mode for dxf output\n"
+  << "\t[--dxf-scale-denom scale]\tscale for dxf output\n"
+  << "\t[--dxf-encoding encoding]\tencoding to use for dxf output\n"
+  << "\t[--dxf-preset visiblity-preset]\tlayer visibility preset to use for dxf output\n"
+  << "\t[--help]\t\tthis text\n"
+  << "\t[--]\t\ttreat all following arguments as FILEs\n\n"
+  << "  FILE:\n"
+  << "    Files specified on the command line can include rasters,\n"
+  << "    vectors, and QGIS project files (.qgs): \n"
+  << "     1. Rasters - supported formats include GeoTiff, DEM \n"
+  << "        and others supported by GDAL\n"
+  << "     2. Vectors - supported formats include ESRI Shapefiles\n"
+  << "        and others supported by OGR and PostgreSQL layers using\n"
+  << "        the PostGIS extension\n"  ; // OK
 
+#ifdef Q_OS_WIN
+  MessageBox( nullptr,
+              msg.join( QString() ).toLocal8Bit().constData(),
+              "QGIS command line options",
+              MB_OK );
+#else
+  std::cerr << msg.join( QString() ).toLocal8Bit().constData();
+#endif
 
 } // usage()
 
@@ -400,6 +411,11 @@ void myMessageOutput( QtMsgType type, const char *msg )
   }
 }
 
+#if(ANDROID)
+// On Android, there there is a libqgis.so instead of a qgis executable.
+// The main method symbol of this library needs to be exported so it can be called by java
+APP_EXPORT
+#endif
 int main( int argc, char *argv[] )
 {
 #ifdef Q_OS_MACX
@@ -549,7 +565,7 @@ int main( int argc, char *argv[] )
 
       if ( arg == "--help" || arg == "-?" )
       {
-        usage( args[0].toStdString() );
+        usage( args[0] );
         return 2;
       }
       else if ( arg == "--nologo" || arg == "-n" )
diff --git a/src/app/qgsidentifyresultsdialog.cpp b/src/app/qgsidentifyresultsdialog.cpp
index d2416ae..fe0557a 100644
--- a/src/app/qgsidentifyresultsdialog.cpp
+++ b/src/app/qgsidentifyresultsdialog.cpp
@@ -69,6 +69,7 @@ QgsIdentifyResultsWebView::QgsIdentifyResultsWebView( QWidget *parent ) : QgsWeb
   page()->setLinkDelegationPolicy( QWebPage::DontDelegateLinks );
   settings()->setAttribute( QWebSettings::LocalContentCanAccessRemoteUrls, true );
   settings()->setAttribute( QWebSettings::JavascriptCanOpenWindows, true );
+  settings()->setAttribute( QWebSettings::PluginsEnabled, true );
 #ifdef QGISDEBUG
   settings()->setAttribute( QWebSettings::DeveloperExtrasEnabled, true );
 #endif
@@ -109,6 +110,7 @@ QgsWebView *QgsIdentifyResultsWebView::createWindow( QWebPage::WebWindowType typ
   wv->page()->setNetworkAccessManager( QgsNetworkAccessManager::instance() );
   wv->settings()->setAttribute( QWebSettings::LocalContentCanAccessRemoteUrls, true );
   wv->settings()->setAttribute( QWebSettings::JavascriptCanOpenWindows, true );
+  wv->settings()->setAttribute( QWebSettings::PluginsEnabled, true );
 #ifdef QGISDEBUG
   wv->settings()->setAttribute( QWebSettings::DeveloperExtrasEnabled, true );
 #endif
diff --git a/src/app/qgssnappingdialog.cpp b/src/app/qgssnappingdialog.cpp
index b288c2b..41d0b86 100644
--- a/src/app/qgssnappingdialog.cpp
+++ b/src/app/qgssnappingdialog.cpp
@@ -310,7 +310,7 @@ void QgsSnappingDialog::addLayer( QgsMapLayer *theMapLayer )
   bool myDockFlag = myQsettings.value( "/qgis/dockSnapping", false ).toBool();
   double defaultSnappingTolerance = myQsettings.value( "/qgis/digitizing/default_snapping_tolerance", 0 ).toDouble();
   int defaultSnappingUnit = myQsettings.value( "/qgis/digitizing/default_snapping_tolerance_unit", QgsTolerance::ProjectUnits ).toInt();
-  QString defaultSnappingString = myQsettings.value( "/qgis/digitizing/default_snap_mode", "to vertex" ).toString();
+  QString defaultSnappingString = myQsettings.value( "/qgis/digitizing/default_snap_mode", "off" ).toString();
 
   int defaultSnappingStringIdx = 0;
   if ( defaultSnappingString == "to vertex" )
diff --git a/src/core/auth/qgsauthmanager.cpp b/src/core/auth/qgsauthmanager.cpp
index cb7ec4b..7ee1cb3 100644
--- a/src/core/auth/qgsauthmanager.cpp
+++ b/src/core/auth/qgsauthmanager.cpp
@@ -1365,8 +1365,8 @@ bool QgsAuthManager::updateNetworkRequest( QNetworkRequest &request, const QStri
   {
     if ( !( authmethod->supportedExpansions() & QgsAuthMethod::NetworkRequest ) )
     {
-      QgsDebugMsg( QString( "Data source URI updating not supported by authcfg: %1" ).arg( authcfg ) );
-      return false;
+      QgsDebugMsg( QString( "Network request updating not supported by authcfg: %1" ).arg( authcfg ) );
+      return true;
     }
 
     if ( !authmethod->updateNetworkRequest( request, authcfg, dataprovider.toLower() ) )
@@ -1392,7 +1392,7 @@ bool QgsAuthManager::updateNetworkReply( QNetworkReply *reply, const QString& au
     if ( !( authmethod->supportedExpansions() & QgsAuthMethod::NetworkReply ) )
     {
       QgsDebugMsg( QString( "Network reply updating not supported by authcfg: %1" ).arg( authcfg ) );
-      return false;
+      return true;
     }
 
     if ( !authmethod->updateNetworkReply( reply, authcfg, dataprovider.toLower() ) )
@@ -1418,7 +1418,7 @@ bool QgsAuthManager::updateDataSourceUriItems( QStringList &connectionItems, con
     if ( !( authmethod->supportedExpansions() & QgsAuthMethod::DataSourceURI ) )
     {
       QgsDebugMsg( QString( "Data source URI updating not supported by authcfg: %1" ).arg( authcfg ) );
-      return false;
+      return true;
     }
 
     if ( !authmethod->updateDataSourceUriItems( connectionItems, authcfg, dataprovider.toLower() ) )
diff --git a/src/core/geometry/qgsabstractgeometryv2.h b/src/core/geometry/qgsabstractgeometryv2.h
index e6f72d6..f5493f9 100644
--- a/src/core/geometry/qgsabstractgeometryv2.h
+++ b/src/core/geometry/qgsabstractgeometryv2.h
@@ -292,6 +292,12 @@ class CORE_EXPORT QgsAbstractGeometryV2
      */
     virtual QgsAbstractGeometryV2* segmentize() const { return clone(); }
 
+    /** Returns the geometry converted to the more generic curve type.
+     *  E.g. QgsLineStringV2 -> QgsCompoundCurveV2, QgsPolygonV2 -> QgsCurvePolygonV2,
+     *  QgsMultiLineStringV2 -> QgsMultiCurveV2, QgsMultiPolygonV2 -> QgsMultiSurfaceV2
+     */
+    virtual QgsAbstractGeometryV2* toCurveType() const { return 0; }
+
     /** Returns approximate angle at a vertex. This is usually the average angle between adjacent
      * segments, and can be pictured as the orientation of a line following the curvature of the
      * geometry at the specified vertex.
diff --git a/src/core/geometry/qgsgeometry.cpp b/src/core/geometry/qgsgeometry.cpp
index cb4dcc6..8cf207b 100644
--- a/src/core/geometry/qgsgeometry.cpp
+++ b/src/core/geometry/qgsgeometry.cpp
@@ -132,6 +132,11 @@ QgsAbstractGeometryV2* QgsGeometry::geometry() const
 
 void QgsGeometry::setGeometry( QgsAbstractGeometryV2* geometry )
 {
+  if ( d->geometry == geometry )
+  {
+    return;
+  }
+
   detach( false );
   if ( d->geometry )
   {
diff --git a/src/core/geometry/qgslinestringv2.cpp b/src/core/geometry/qgslinestringv2.cpp
index a6d2cd1..13534a8 100644
--- a/src/core/geometry/qgslinestringv2.cpp
+++ b/src/core/geometry/qgslinestringv2.cpp
@@ -17,6 +17,7 @@
 
 #include "qgslinestringv2.h"
 #include "qgsapplication.h"
+#include "qgscompoundcurvev2.h"
 #include "qgscoordinatetransform.h"
 #include "qgsgeometryutils.h"
 #include "qgsmaptopixel.h"
@@ -583,6 +584,13 @@ QPolygonF QgsLineStringV2::asQPolygonF() const
   return points;
 }
 
+QgsAbstractGeometryV2* QgsLineStringV2::toCurveType() const
+{
+  QgsCompoundCurveV2* compoundCurve = new QgsCompoundCurveV2();
+  compoundCurve->addCurve( clone() );
+  return compoundCurve;
+}
+
 /***************************************************************************
  * This class is considered CRITICAL and any change MUST be accompanied with
  * full unit tests.
diff --git a/src/core/geometry/qgslinestringv2.h b/src/core/geometry/qgslinestringv2.h
index 3ebfff2..16677d5 100644
--- a/src/core/geometry/qgslinestringv2.h
+++ b/src/core/geometry/qgslinestringv2.h
@@ -132,6 +132,9 @@ class CORE_EXPORT QgsLineStringV2: public QgsCurveV2
      */
     QPolygonF asQPolygonF() const;
 
+    /** Returns the geometry converted to QgsCompoundCurveV2*/
+    QgsAbstractGeometryV2* toCurveType() const override;
+
     //reimplemented methods
 
     virtual QString geometryType() const override { return "LineString"; }
diff --git a/src/core/geometry/qgsmultilinestringv2.cpp b/src/core/geometry/qgsmultilinestringv2.cpp
index fc1a9e6..a83bdc6 100644
--- a/src/core/geometry/qgsmultilinestringv2.cpp
+++ b/src/core/geometry/qgsmultilinestringv2.cpp
@@ -20,6 +20,7 @@ email                : marco.hugentobler at sourcepole dot com
 #include "qgscompoundcurvev2.h"
 #include "qgsgeometryutils.h"
 #include "qgslinestringv2.h"
+#include "qgsmulticurvev2.h"
 
 QgsMultiLineStringV2* QgsMultiLineStringV2::clone() const
 {
@@ -101,3 +102,13 @@ bool QgsMultiLineStringV2::addGeometry( QgsAbstractGeometryV2* g )
   setZMTypeFromSubGeometry( g, QgsWKBTypes::MultiLineString );
   return QgsGeometryCollectionV2::addGeometry( g );
 }
+
+QgsAbstractGeometryV2* QgsMultiLineStringV2::toCurveType() const
+{
+  QgsMultiCurveV2* multiCurve = new QgsMultiCurveV2();
+  for ( int i = 0; i < mGeometries.size(); ++i )
+  {
+    multiCurve->addGeometry( mGeometries.at( i )->clone() );
+  }
+  return multiCurve;
+}
diff --git a/src/core/geometry/qgsmultilinestringv2.h b/src/core/geometry/qgsmultilinestringv2.h
index f3de420..6e28ad4 100644
--- a/src/core/geometry/qgsmultilinestringv2.h
+++ b/src/core/geometry/qgsmultilinestringv2.h
@@ -42,6 +42,9 @@ class CORE_EXPORT QgsMultiLineStringV2: public QgsMultiCurveV2
     /** Adds a geometry and takes ownership. Returns true in case of success*/
     virtual bool addGeometry( QgsAbstractGeometryV2* g ) override;
 
+    /** Returns the geometry converted to QgsMultiCurveV2*/
+    QgsAbstractGeometryV2* toCurveType() const override;
+
   protected:
 
     virtual bool wktOmitChildType() const override { return true; }
diff --git a/src/core/geometry/qgsmultipolygonv2.cpp b/src/core/geometry/qgsmultipolygonv2.cpp
index 80e9ca0..8277989 100644
--- a/src/core/geometry/qgsmultipolygonv2.cpp
+++ b/src/core/geometry/qgsmultipolygonv2.cpp
@@ -117,3 +117,13 @@ bool QgsMultiPolygonV2::addGeometry( QgsAbstractGeometryV2* g )
   setZMTypeFromSubGeometry( g, QgsWKBTypes::MultiPolygon );
   return QgsGeometryCollectionV2::addGeometry( g );
 }
+
+QgsAbstractGeometryV2* QgsMultiPolygonV2::toCurveType() const
+{
+  QgsMultiSurfaceV2* multiSurface = new QgsMultiSurfaceV2();
+  for ( int i = 0; i < mGeometries.size(); ++i )
+  {
+    multiSurface->addGeometry( mGeometries.at( i )->clone() );
+  }
+  return multiSurface;
+}
diff --git a/src/core/geometry/qgsmultipolygonv2.h b/src/core/geometry/qgsmultipolygonv2.h
index d59a71e..176dfd1 100644
--- a/src/core/geometry/qgsmultipolygonv2.h
+++ b/src/core/geometry/qgsmultipolygonv2.h
@@ -43,6 +43,9 @@ class CORE_EXPORT QgsMultiPolygonV2: public QgsMultiSurfaceV2
     /** Adds a geometry and takes ownership. Returns true in case of success*/
     virtual bool addGeometry( QgsAbstractGeometryV2* g ) override;
 
+    /** Returns the geometry converted to QgsMultiSurfaceV2*/
+    QgsAbstractGeometryV2* toCurveType() const override;
+
   protected:
 
     virtual bool wktOmitChildType() const override { return true; }
diff --git a/src/core/geometry/qgspolygonv2.cpp b/src/core/geometry/qgspolygonv2.cpp
index 3521df0..9fecf25 100644
--- a/src/core/geometry/qgspolygonv2.cpp
+++ b/src/core/geometry/qgspolygonv2.cpp
@@ -240,3 +240,15 @@ QgsPolygonV2* QgsPolygonV2::surfaceToPolygon() const
 {
   return clone();
 }
+
+QgsAbstractGeometryV2* QgsPolygonV2::toCurveType() const
+{
+  QgsCurvePolygonV2* curvePolygon = new QgsCurvePolygonV2();
+  curvePolygon->setExteriorRing( mExteriorRing->clone() );
+  int nInteriorRings = mInteriorRings.size();
+  for ( int i = 0; i < nInteriorRings; ++i )
+  {
+    curvePolygon->addInteriorRing( mInteriorRings.at( i )->clone() );
+  }
+  return curvePolygon;
+}
diff --git a/src/core/geometry/qgspolygonv2.h b/src/core/geometry/qgspolygonv2.h
index c645a8d..1f0c125 100644
--- a/src/core/geometry/qgspolygonv2.h
+++ b/src/core/geometry/qgspolygonv2.h
@@ -50,6 +50,9 @@ class CORE_EXPORT QgsPolygonV2: public QgsCurvePolygonV2
 
     QgsPolygonV2* surfaceToPolygon() const override;
 
+    /** Returns the geometry converted to QgsCurvePolygonV2*/
+    QgsAbstractGeometryV2* toCurveType() const override;
+
     void addInteriorRing( QgsCurveV2* ring ) override;
     //overridden to handle LineString25D rings
     virtual void setExteriorRing( QgsCurveV2* ring ) override;
diff --git a/src/core/qgsexpression.cpp b/src/core/qgsexpression.cpp
index 26853f1..6635efc 100644
--- a/src/core/qgsexpression.cpp
+++ b/src/core/qgsexpression.cpp
@@ -49,6 +49,8 @@
 #include "qgscurvepolygonv2.h"
 #include "qgsexpressionprivate.h"
 #include "qgsexpressionsorter.h"
+#include "qgsmessagelog.h"
+#include "qgscsexception.h"
 
 #if QT_VERSION < 0x050000
 #include <qtextdocument.h>
@@ -2634,8 +2636,16 @@ static QVariant fcnTransformGeometry( const QVariantList& values, const QgsExpre
     return QVariant::fromValue( fGeom );
 
   QgsCoordinateTransform t( s, d );
-  if ( fGeom.transform( t ) == 0 )
-    return QVariant::fromValue( fGeom );
+  try
+  {
+    if ( fGeom.transform( t ) == 0 )
+      return QVariant::fromValue( fGeom );
+  }
+  catch ( QgsCsException &cse )
+  {
+    QgsMessageLog::logMessage( QString( "Transform error caught in transform() function: %1" ).arg( cse.what() ) );
+    return QVariant();
+  }
   return QVariant();
 }
 
diff --git a/src/core/qgslegendrenderer.cpp b/src/core/qgslegendrenderer.cpp
index 74cbd35..8d49139 100644
--- a/src/core/qgslegendrenderer.cpp
+++ b/src/core/qgslegendrenderer.cpp
@@ -266,17 +266,12 @@ void QgsLegendRenderer::setColumns( QList<Atom>& atomList )
 
   // Divide atoms to columns
   double totalHeight = 0;
-  // bool first = true;
   qreal maxAtomHeight = 0;
   Q_FOREACH ( const Atom& atom, atomList )
   {
-    //if ( !first )
-    //{
     totalHeight += spaceAboveAtom( atom );
-    //}
     totalHeight += atom.size.height();
     maxAtomHeight = qMax( atom.size.height(), maxAtomHeight );
-    // first  = false;
   }
 
   // We know height of each atom and we have to split them into columns
@@ -284,31 +279,36 @@ void QgsLegendRenderer::setColumns( QList<Atom>& atomList )
   // We are using simple heuristic, brute fore appeared to be to slow,
   // the number of combinations is N = n!/(k!*(n-k)!) where n = atomsCount-1
   // and k = columnsCount-1
-
-  double avgColumnHeight = totalHeight / mSettings.columnCount();
+  double maxColumnHeight = 0;
   int currentColumn = 0;
   int currentColumnAtomCount = 0; // number of atoms in current column
   double currentColumnHeight = 0;
-  double maxColumnHeight = 0;
   double closedColumnsHeight = 0;
-  // first = true; // first in column
+
   for ( int i = 0; i < atomList.size(); i++ )
   {
-    Atom atom = atomList[i];
+    // Recalc average height for remaining columns including current
+    double avgColumnHeight = ( totalHeight - closedColumnsHeight ) / ( mSettings.columnCount() - currentColumn );
+
+    Atom atom = atomList.at( i );
     double currentHeight = currentColumnHeight;
-    //if ( !first )
-    //{
-    currentHeight += spaceAboveAtom( atom );
-    //}
+    if ( currentColumnAtomCount > 0 )
+      currentHeight += spaceAboveAtom( atom );
     currentHeight += atom.size.height();
 
-    // Recalc average height for remaining columns including current
-    avgColumnHeight = ( totalHeight - closedColumnsHeight ) / ( mSettings.columnCount() - currentColumn );
-    if (( currentHeight - avgColumnHeight ) > atom.size.height() / 2 // center of current atom is over average height
-        && currentColumnAtomCount > 0 // do not leave empty column
-        && currentHeight > maxAtomHeight  // no sense to make smaller columns than max atom height
-        && currentHeight > maxColumnHeight  // no sense to make smaller columns than max column already created
-        && currentColumn < mSettings.columnCount() - 1 ) // must not exceed max number of columns
+    bool canCreateNewColumn = ( currentColumnAtomCount > 0 )  // do not leave empty column
+                              && ( currentColumn < mSettings.columnCount() - 1 ); // must not exceed max number of columns
+
+    bool shouldCreateNewColumn = ( currentHeight - avgColumnHeight ) > atom.size.height() / 2  // center of current atom is over average height
+                                 && currentColumnAtomCount > 0 // do not leave empty column
+                                 && currentHeight > maxAtomHeight  // no sense to make smaller columns than max atom height
+                                 && currentHeight > maxColumnHeight; // no sense to make smaller columns than max column already created
+
+    // also should create a new column if the number of items left < number of columns left
+    // in this case we should spread the remaining items out over the remaining columns
+    shouldCreateNewColumn |= ( atomList.size() - i < mSettings.columnCount() - currentColumn );
+
+    if ( canCreateNewColumn && shouldCreateNewColumn )
     {
       // New column
       currentColumn++;
@@ -323,11 +323,9 @@ void QgsLegendRenderer::setColumns( QList<Atom>& atomList )
     atomList[i].column = currentColumn;
     currentColumnAtomCount++;
     maxColumnHeight = qMax( currentColumnHeight, maxColumnHeight );
-
-    // first  = false;
   }
 
-  // Alling labels of symbols for each layr/column to the same labelXOffset
+  // Align labels of symbols for each layr/column to the same labelXOffset
   QMap<QString, qreal> maxSymbolWidth;
   for ( int i = 0; i < atomList.size(); i++ )
   {
diff --git a/src/core/qgspallabeling.cpp b/src/core/qgspallabeling.cpp
index 92df90c..2439b47 100644
--- a/src/core/qgspallabeling.cpp
+++ b/src/core/qgspallabeling.cpp
@@ -18,6 +18,7 @@
 #include "qgspallabeling.h"
 #include "qgstextlabelfeature.h"
 #include "qgsunittypes.h"
+#include "qgsstringutils.h"
 
 #include <list>
 
@@ -2283,6 +2284,7 @@ void QgsPalLayerSettings::registerFeature( QgsFeature& f, QgsRenderContext &cont
 
   // calculate rest of font attributes and store any data defined values
   // this is done here for later use in making label backgrounds part of collision management (when implemented)
+  labelFont.setCapitalization( QFont::MixedCase ); // reset this - we don't use QFont's handling as it breaks with curved labels
   parseTextStyle( labelFont, fontunits, context );
   parseTextFormatting( context );
   parseTextBuffer( context );
@@ -2316,6 +2318,41 @@ void QgsPalLayerSettings::registerFeature( QgsFeature& f, QgsRenderContext &cont
     labelText = v.isNull() ? "" : v.toString();
   }
 
+  // apply capitalization
+  QgsStringUtils::Capitalization capitalization = QgsStringUtils::MixedCase;
+  // maintain API - capitalization may have been set in textFont
+  if ( textFont.capitalization() != QFont::MixedCase )
+  {
+    capitalization = static_cast< QgsStringUtils::Capitalization >( textFont.capitalization() );
+  }
+  // data defined font capitalization?
+  if ( dataDefinedEvaluate( QgsPalLayerSettings::FontCase, exprVal, &context.expressionContext() ) )
+  {
+    QString fcase = exprVal.toString().trimmed();
+    QgsDebugMsgLevel( QString( "exprVal FontCase:%1" ).arg( fcase ), 4 );
+
+    if ( !fcase.isEmpty() )
+    {
+      if ( fcase.compare( "NoChange", Qt::CaseInsensitive ) == 0 )
+      {
+        capitalization = QgsStringUtils::MixedCase;
+      }
+      else if ( fcase.compare( "Upper", Qt::CaseInsensitive ) == 0 )
+      {
+        capitalization = QgsStringUtils::AllUppercase;
+      }
+      else if ( fcase.compare( "Lower", Qt::CaseInsensitive ) == 0 )
+      {
+        capitalization = QgsStringUtils::AllLowercase;
+      }
+      else if ( fcase.compare( "Capitalize", Qt::CaseInsensitive ) == 0 )
+      {
+        capitalization = QgsStringUtils::ForceFirstLetterToCapital;
+      }
+    }
+  }
+  labelText = QgsStringUtils::capitalize( labelText, capitalization );
+
   // data defined format numbers?
   bool formatnum = formatNumbers;
   if ( dataDefinedEvaluate( QgsPalLayerSettings::NumFormat, exprVal, &context.expressionContext(), formatNumbers ) )
@@ -3315,7 +3352,6 @@ void QgsPalLayerSettings::parseTextStyle( QFont& labelFont,
     // copy over existing font settings
     //newFont = newFont.resolve( labelFont ); // should work, but let's be sure what's being copied
     newFont.setPixelSize( labelFont.pixelSize() );
-    newFont.setCapitalization( labelFont.capitalization() );
     newFont.setUnderline( labelFont.underline() );
     newFont.setStrikeOut( labelFont.strikeOut() );
     newFont.setWordSpacing( labelFont.wordSpacing() );
@@ -3352,39 +3388,6 @@ void QgsPalLayerSettings::parseTextStyle( QFont& labelFont,
   }
   labelFont.setLetterSpacing( QFont::AbsoluteSpacing, scaleToPixelContext( letterspace, context, fontunits, false, fontSizeMapUnitScale ) );
 
-  // data defined font capitalization?
-  QFont::Capitalization fontcaps = labelFont.capitalization();
-  if ( dataDefinedEvaluate( QgsPalLayerSettings::FontCase, exprVal, &context.expressionContext() ) )
-  {
-    QString fcase = exprVal.toString().trimmed();
-    QgsDebugMsgLevel( QString( "exprVal FontCase:%1" ).arg( fcase ), 4 );
-
-    if ( !fcase.isEmpty() )
-    {
-      if ( fcase.compare( "NoChange", Qt::CaseInsensitive ) == 0 )
-      {
-        fontcaps = QFont::MixedCase;
-      }
-      else if ( fcase.compare( "Upper", Qt::CaseInsensitive ) == 0 )
-      {
-        fontcaps = QFont::AllUppercase;
-      }
-      else if ( fcase.compare( "Lower", Qt::CaseInsensitive ) == 0 )
-      {
-        fontcaps = QFont::AllLowercase;
-      }
-      else if ( fcase.compare( "Capitalize", Qt::CaseInsensitive ) == 0 )
-      {
-        fontcaps = QFont::Capitalize;
-      }
-
-      if ( fontcaps != labelFont.capitalization() )
-      {
-        labelFont.setCapitalization( fontcaps );
-      }
-    }
-  }
-
   // data defined strikeout font style?
   if ( dataDefinedEvaluate( QgsPalLayerSettings::Strikeout, exprVal, &context.expressionContext(), labelFont.strikeOut() ) )
   {
diff --git a/src/core/qgspointlocator.cpp b/src/core/qgspointlocator.cpp
index f6c242f..66b2647 100644
--- a/src/core/qgspointlocator.cpp
+++ b/src/core/qgspointlocator.cpp
@@ -609,6 +609,7 @@ QgsPointLocator::QgsPointLocator( QgsVectorLayer* layer, const QgsCoordinateRefe
   connect( mLayer, SIGNAL( featureAdded( QgsFeatureId ) ), this, SLOT( onFeatureAdded( QgsFeatureId ) ) );
   connect( mLayer, SIGNAL( featureDeleted( QgsFeatureId ) ), this, SLOT( onFeatureDeleted( QgsFeatureId ) ) );
   connect( mLayer, SIGNAL( geometryChanged( QgsFeatureId, QgsGeometry& ) ), this, SLOT( onGeometryChanged( QgsFeatureId, QgsGeometry& ) ) );
+  connect( mLayer, SIGNAL( dataChanged() ), this, SLOT( destroyIndex() ) );
 }
 
 
diff --git a/src/core/qgspointlocator.h b/src/core/qgspointlocator.h
index 09aad1b..f2f7292 100644
--- a/src/core/qgspointlocator.h
+++ b/src/core/qgspointlocator.h
@@ -186,8 +186,8 @@ class CORE_EXPORT QgsPointLocator : public QObject
 
   protected:
     bool rebuildIndex( int maxFeaturesToIndex = -1 );
+  protected slots:
     void destroyIndex();
-
   private slots:
     void onFeatureAdded( QgsFeatureId fid );
     void onFeatureDeleted( QgsFeatureId fid );
diff --git a/src/core/qgsstringutils.cpp b/src/core/qgsstringutils.cpp
index 1d84445..0ed5e7c 100644
--- a/src/core/qgsstringutils.cpp
+++ b/src/core/qgsstringutils.cpp
@@ -15,6 +15,56 @@
 
 #include "qgsstringutils.h"
 #include <QVector>
+#include <QRegExp>
+#include <QStringList>
+#include <QTextBoundaryFinder>
+
+QString QgsStringUtils::capitalize( const QString& string, QgsStringUtils::Capitalization capitalization )
+{
+  if ( string.isEmpty() )
+    return QString();
+
+  switch ( capitalization )
+  {
+    case MixedCase:
+      return string;
+
+    case AllUppercase:
+      return string.toUpper();
+
+    case AllLowercase:
+      return string.toLower();
+
+    case ForceFirstLetterToCapital:
+    {
+      QString temp = string;
+
+      QTextBoundaryFinder wordSplitter( QTextBoundaryFinder::Word, string.constData(), string.length(), 0, 0 );
+      QTextBoundaryFinder letterSplitter( QTextBoundaryFinder::Grapheme, string.constData(), string.length(), 0, 0 );
+
+      wordSplitter.setPosition( 0 );
+      bool first = true;
+#if QT_VERSION >= 0x050000
+      while (( first && wordSplitter.boundaryReasons() & QTextBoundaryFinder::StartOfItem )
+             || wordSplitter.toNextBoundary() >= 0 )
+#else
+      while (( first && wordSplitter.boundaryReasons() & QTextBoundaryFinder::StartWord )
+             || wordSplitter.toNextBoundary() >= 0 )
+#endif
+      {
+        first = false;
+        letterSplitter.setPosition( wordSplitter.position() );
+        letterSplitter.toNextBoundary();
+        QString substr = string.mid( wordSplitter.position(), letterSplitter.position() - wordSplitter.position() );
+        temp.replace( wordSplitter.position(), substr.length(), substr.toUpper() );
+      }
+      return temp;
+    }
+
+  }
+  // no warnings
+  return string;
+}
 
 int QgsStringUtils::levenshteinDistance( const QString& string1, const QString& string2, bool caseSensitive )
 {
diff --git a/src/core/qgsstringutils.h b/src/core/qgsstringutils.h
index 4335870..5120aba 100644
--- a/src/core/qgsstringutils.h
+++ b/src/core/qgsstringutils.h
@@ -14,6 +14,7 @@
  ***************************************************************************/
 
 #include <QString>
+#include <QFont> // for enum values
 
 #ifndef QGSSTRINGUTILS_H
 #define QGSSTRINGUTILS_H
@@ -28,6 +29,23 @@ class CORE_EXPORT QgsStringUtils
 {
   public:
 
+    //! Capitalization options
+    enum Capitalization
+    {
+      MixedCase = QFont::MixedCase, //!< Mixed case, ie no change
+      AllUppercase = QFont::AllUppercase, //!< Convert all characters to uppercase
+      AllLowercase = QFont::AllLowercase,  //!< Convert all characters to lowercase
+      ForceFirstLetterToCapital = QFont::Capitalize, //!< Convert just the first letter of each word to uppercase, leave the rest untouched
+    };
+
+    /** Converts a string by applying capitalization rules to the string.
+     * @param string input string
+     * @param capitalization capitalization type to apply
+     * @return capitalized string
+     * @note added in QGIS 3.0
+     */
+    static QString capitalize( const QString& string, Capitalization capitalization );
+
     /** Returns the Levenshtein edit distance between two strings. This equates to the minimum
      * number of character edits (insertions, deletions or substitutions) required to change
      * one string to another.
diff --git a/src/core/qgsvectordataprovider.cpp b/src/core/qgsvectordataprovider.cpp
index 7a4cebd..b5f740d 100644
--- a/src/core/qgsvectordataprovider.cpp
+++ b/src/core/qgsvectordataprovider.cpp
@@ -21,10 +21,15 @@
 #include <limits>
 
 #include "qgsvectordataprovider.h"
+#include "qgscircularstringv2.h"
+#include "qgscompoundcurvev2.h"
 #include "qgsfeature.h"
 #include "qgsfeatureiterator.h"
 #include "qgsfeaturerequest.h"
 #include "qgsfield.h"
+#include "qgsgeometry.h"
+#include "qgsgeometrycollectionv2.h"
+#include "qgsgeometryfactory.h"
 #include "qgslogger.h"
 #include "qgsmessagelog.h"
 
@@ -367,7 +372,7 @@ void QgsVectorDataProvider::uniqueValues( int index, QList<QVariant> &values, in
   QgsFeature f;
   QgsAttributeList keys;
   keys.append( index );
-  QgsFeatureIterator fi = getFeatures( QgsFeatureRequest().setSubsetOfAttributes( keys ) );
+  QgsFeatureIterator fi = getFeatures( QgsFeatureRequest().setSubsetOfAttributes( keys ).setFlags( QgsFeatureRequest::NoGeometry ) );
 
   QSet<QString> set;
   values.clear();
@@ -422,7 +427,8 @@ void QgsVectorDataProvider::fillMinMaxCache()
 
   QgsFeature f;
   QgsAttributeList keys = mCacheMinValues.keys();
-  QgsFeatureIterator fi = getFeatures( QgsFeatureRequest().setSubsetOfAttributes( keys ) );
+  QgsFeatureIterator fi = getFeatures( QgsFeatureRequest().setSubsetOfAttributes( keys )
+                                       .setFlags( QgsFeatureRequest::NoGeometry ) );
 
   while ( fi.nextFeature( f ) )
   {
@@ -581,4 +587,103 @@ QSet<QString> QgsVectorDataProvider::layerDependencies() const
   return QSet<QString>();
 }
 
+QgsGeometry* QgsVectorDataProvider::convertToProviderType( const QgsGeometry& geom ) const
+{
+  if ( geom.isEmpty() )
+  {
+    return nullptr;
+  }
+
+  QgsAbstractGeometryV2* geometry = geom.geometry();
+  if ( !geometry )
+  {
+    return nullptr;
+  }
+
+  QgsWKBTypes::Type providerGeomType = QgsWKBTypes::Type( geometryType() );
+
+  //geom is already in the provider geometry type
+  if ( geometry->wkbType() == providerGeomType )
+  {
+    return nullptr;
+  }
+
+  QgsAbstractGeometryV2* outputGeom = nullptr;
+
+  //convert compoundcurve to circularstring (possible if compoundcurve consists of one circular string)
+  if ( QgsWKBTypes::flatType( providerGeomType ) == QgsWKBTypes::CircularString && QgsWKBTypes::flatType( geometry->wkbType() ) == QgsWKBTypes::CompoundCurve )
+  {
+    QgsCompoundCurveV2* compoundCurve = static_cast<QgsCompoundCurveV2*>( geometry );
+    if ( compoundCurve )
+    {
+      if ( compoundCurve->nCurves() == 1 )
+      {
+        const QgsCircularStringV2* circularString = dynamic_cast<const QgsCircularStringV2*>( compoundCurve->curveAt( 0 ) );
+        if ( circularString )
+        {
+          outputGeom = circularString->clone();
+        }
+      }
+    }
+  }
+
+  //convert to multitype if necessary
+  if ( QgsWKBTypes::isMultiType( providerGeomType ) && !QgsWKBTypes::isMultiType( geometry->wkbType() ) )
+  {
+    outputGeom = QgsGeometryFactory::geomFromWkbType( providerGeomType );
+    QgsGeometryCollectionV2* geomCollection = dynamic_cast<QgsGeometryCollectionV2*>( outputGeom );
+    if ( geomCollection )
+    {
+      geomCollection->addGeometry( geometry->clone() );
+    }
+  }
+
+  //convert to curved type if necessary
+  if ( !QgsWKBTypes::isCurvedType( geometry->wkbType() ) && QgsWKBTypes::isCurvedType( providerGeomType ) )
+  {
+    QgsAbstractGeometryV2* curveGeom = outputGeom ? outputGeom->toCurveType() : geometry->toCurveType();
+    if ( curveGeom )
+    {
+      delete outputGeom;
+      outputGeom = curveGeom;
+    }
+  }
+
+  //convert to linear type from curved type
+  if ( QgsWKBTypes::isCurvedType( geometry->wkbType() ) && !QgsWKBTypes::isCurvedType( providerGeomType ) )
+  {
+    QgsAbstractGeometryV2* segmentizedGeom = nullptr;
+    segmentizedGeom = outputGeom ? outputGeom->segmentize() : geometry->segmentize();
+    if ( segmentizedGeom )
+    {
+      delete outputGeom;
+      outputGeom = segmentizedGeom;
+    }
+  }
+
+  //set z/m types
+  if ( QgsWKBTypes::hasZ( providerGeomType ) )
+  {
+    if ( !outputGeom )
+    {
+      outputGeom = geometry->clone();
+    }
+    outputGeom->addZValue();
+  }
+  if ( QgsWKBTypes::hasM( providerGeomType ) )
+  {
+    if ( !outputGeom )
+    {
+      outputGeom = geometry->clone();
+    }
+    outputGeom->addMValue();
+  }
+
+  if ( outputGeom )
+  {
+    return new QgsGeometry( outputGeom );
+  }
+  return nullptr;
+}
+
 QStringList QgsVectorDataProvider::smEncodings;
diff --git a/src/core/qgsvectordataprovider.h b/src/core/qgsvectordataprovider.h
index a601287..0aea4ba 100644
--- a/src/core/qgsvectordataprovider.h
+++ b/src/core/qgsvectordataprovider.h
@@ -429,6 +429,10 @@ class CORE_EXPORT QgsVectorDataProvider : public QgsDataProvider
     /** Old-style mapping of index to name for QgsPalLabeling fix */
     QgsAttrPalIndexNameHash mAttrPalIndexName;
 
+    /** Converts the geometry to the provider type if possible / necessary
+    @return the converted geometry or nullptr if no conversion was necessary or possible*/
+    QgsGeometry* convertToProviderType( const QgsGeometry& geom ) const;
+
   private:
     /** Old notation **/
     QMap<QString, QVariant::Type> mOldTypeList;
diff --git a/src/core/qgsvectorlayer.cpp b/src/core/qgsvectorlayer.cpp
index ec50d7c..5535cb9 100644
--- a/src/core/qgsvectorlayer.cpp
+++ b/src/core/qgsvectorlayer.cpp
@@ -1923,8 +1923,11 @@ bool QgsVectorLayer::writeSymbology( QDomNode& node, QDomDocument& doc, QString&
 
   if ( hasGeometryType() )
   {
-    QDomElement rendererElement = mRendererV2->save( doc );
-    node.appendChild( rendererElement );
+    if ( mRendererV2 )
+    {
+      QDomElement rendererElement = mRendererV2->save( doc );
+      node.appendChild( rendererElement );
+    }
 
     if ( mLabeling )
     {
diff --git a/src/core/qgsvectorlayerfeatureiterator.cpp b/src/core/qgsvectorlayerfeatureiterator.cpp
index 7448ba9..1cce059 100644
--- a/src/core/qgsvectorlayerfeatureiterator.cpp
+++ b/src/core/qgsvectorlayerfeatureiterator.cpp
@@ -95,11 +95,7 @@ QgsVectorLayerFeatureIterator::QgsVectorLayerFeatureIterator( QgsVectorLayerFeat
     , mFetchedFid( false )
     , mEditGeometrySimplifier( nullptr )
 {
-  prepareExpressions();
-
-  // prepare joins: may add more attributes to fetch (in order to allow join)
-  if ( mSource->mJoinBuffer->containsJoins() )
-    prepareJoins();
+  prepareFields();
 
   mHasVirtualAttributes = !mFetchJoinInfo.isEmpty() || !mExpressionFieldInfo.isEmpty();
 
@@ -472,147 +468,214 @@ void QgsVectorLayerFeatureIterator::rewindEditBuffer()
   mFetchChangedGeomIt = mSource->mChangedGeometries.constBegin();
 }
 
+void QgsVectorLayerFeatureIterator::prepareJoin( int fieldIdx )
+{
+  if ( !mSource->mFields.exists( fieldIdx ) )
+    return;
 
+  if ( mSource->mFields.fieldOrigin( fieldIdx ) != QgsFields::OriginJoin )
+    return;
 
-void QgsVectorLayerFeatureIterator::prepareJoins()
-{
-  QgsAttributeList fetchAttributes = ( mRequest.flags() & QgsFeatureRequest::SubsetOfAttributes ) ? mRequest.subsetOfAttributes() : mSource->mFields.allAttributesList();
-  QgsAttributeList sourceJoinFields; // attributes that also need to be fetched from this layer in order to have joins working
+  int sourceLayerIndex;
+  const QgsVectorJoinInfo* joinInfo = mSource->mJoinBuffer->joinForFieldIndex( fieldIdx, mSource->mFields, sourceLayerIndex );
+  Q_ASSERT( joinInfo );
 
-  mFetchJoinInfo.clear();
+  QgsVectorLayer* joinLayer = qobject_cast<QgsVectorLayer*>( QgsMapLayerRegistry::instance()->mapLayer( joinInfo->joinLayerId ) );
+  Q_ASSERT( joinLayer );
 
-  for ( QgsAttributeList::const_iterator attIt = fetchAttributes.constBegin(); attIt != fetchAttributes.constEnd(); ++attIt )
+  if ( !mFetchJoinInfo.contains( joinInfo ) )
   {
-    if ( !mSource->mFields.exists( *attIt ) )
-      continue;
+    FetchJoinInfo info;
+    info.joinInfo = joinInfo;
+    info.joinLayer = joinLayer;
+    info.indexOffset = mSource->mJoinBuffer->joinedFieldsOffset( joinInfo, mSource->mFields );
 
-    if ( mSource->mFields.fieldOrigin( *attIt ) != QgsFields::OriginJoin )
-      continue;
+    if ( joinInfo->targetFieldName.isEmpty() )
+      info.targetField = joinInfo->targetFieldIndex;    //for compatibility with 1.x
+    else
+      info.targetField = mSource->mFields.indexFromName( joinInfo->targetFieldName );
+
+    if ( joinInfo->joinFieldName.isEmpty() )
+      info.joinField = joinInfo->joinFieldIndex;      //for compatibility with 1.x
+    else
+      info.joinField = joinLayer->fields().indexFromName( joinInfo->joinFieldName );
+
+    // for joined fields, we always need to request the targetField from the provider too
+    if ( !mPreparedFields.contains( info.targetField ) && !mFieldsToPrepare.contains( info.targetField ) )
+      mFieldsToPrepare << info.targetField;
+
+    if ( mRequest.flags() & QgsFeatureRequest::SubsetOfAttributes && !mRequest.subsetOfAttributes().contains( info.targetField ) )
+      mRequest.setSubsetOfAttributes( mRequest.subsetOfAttributes() << info.targetField );
+
+    mFetchJoinInfo.insert( joinInfo, info );
+  }
+
+  // store field source index - we'll need it when fetching from provider
+  mFetchJoinInfo[ joinInfo ].attributes.push_back( sourceLayerIndex );
+}
+
+void QgsVectorLayerFeatureIterator::prepareExpression( int fieldIdx )
+{
+  const QList<QgsExpressionFieldBuffer::ExpressionField>& exps = mSource->mExpressionFieldBuffer->expressions();
+
+  int oi = mSource->mFields.fieldOriginIndex( fieldIdx );
+  QgsExpression* exp = new QgsExpression( exps[oi].cachedExpression );
 
-    int sourceLayerIndex;
-    const QgsVectorJoinInfo* joinInfo = mSource->mJoinBuffer->joinForFieldIndex( *attIt, mSource->mFields, sourceLayerIndex );
-    Q_ASSERT( joinInfo );
+  QgsDistanceArea da;
+  da.setSourceCrs( mSource->mCrsId );
+  da.setEllipsoidalMode( true );
+  da.setEllipsoid( QgsProject::instance()->readEntry( "Measure", "/Ellipsoid", GEO_NONE ) );
+  exp->setGeomCalculator( da );
+  exp->setDistanceUnits( QgsProject::instance()->distanceUnits() );
+  exp->setAreaUnits( QgsProject::instance()->areaUnits() );
 
-    QgsVectorLayer* joinLayer = qobject_cast<QgsVectorLayer*>( QgsMapLayerRegistry::instance()->mapLayer( joinInfo->joinLayerId ) );
-    Q_ASSERT( joinLayer );
+  exp->prepare( mExpressionContext.data() );
+  mExpressionFieldInfo.insert( fieldIdx, exp );
 
-    if ( !mFetchJoinInfo.contains( joinInfo ) )
+  Q_FOREACH ( const QString& col, exp->referencedColumns() )
+  {
+    int dependantFieldIdx = mSource->mFields.fieldNameIndex( col );
+    if ( mRequest.flags() & QgsFeatureRequest::SubsetOfAttributes )
     {
-      FetchJoinInfo info;
-      info.joinInfo = joinInfo;
-      info.joinLayer = joinLayer;
-      info.indexOffset = mSource->mJoinBuffer->joinedFieldsOffset( joinInfo, mSource->mFields );
-
-      if ( joinInfo->targetFieldName.isEmpty() )
-        info.targetField = joinInfo->targetFieldIndex;    //for compatibility with 1.x
-      else
-        info.targetField = mSource->mFields.indexFromName( joinInfo->targetFieldName );
-
-      if ( joinInfo->joinFieldName.isEmpty() )
-        info.joinField = joinInfo->joinFieldIndex;      //for compatibility with 1.x
-      else
-        info.joinField = joinLayer->fields().indexFromName( joinInfo->joinFieldName );
-
-      // for joined fields, we always need to request the targetField from the provider too
-      if ( !fetchAttributes.contains( info.targetField ) )
-        sourceJoinFields << info.targetField;
-
-      mFetchJoinInfo.insert( joinInfo, info );
+      mRequest.setSubsetOfAttributes( mRequest.subsetOfAttributes() << dependantFieldIdx );
     }
-
-    // store field source index - we'll need it when fetching from provider
-    mFetchJoinInfo[ joinInfo ].attributes.push_back( sourceLayerIndex );
+    // also need to fetch this dependant field
+    if ( !mPreparedFields.contains( dependantFieldIdx ) && !mFieldsToPrepare.contains( dependantFieldIdx ) )
+      mFieldsToPrepare << dependantFieldIdx;
   }
 
-  // add sourceJoinFields if we're using a subset
-  if ( mRequest.flags() & QgsFeatureRequest::SubsetOfAttributes )
-    mRequest.setSubsetOfAttributes( mRequest.subsetOfAttributes() + sourceJoinFields );
+  if ( exp->needsGeometry() )
+  {
+    mRequest.setFlags( mRequest.flags() & ~QgsFeatureRequest::NoGeometry );
+  }
 }
 
-void QgsVectorLayerFeatureIterator::prepareExpressions()
+void QgsVectorLayerFeatureIterator::prepareFields()
 {
-  const QList<QgsExpressionFieldBuffer::ExpressionField> exps = mSource->mExpressionFieldBuffer->expressions();
+  mPreparedFields.clear();
+  mFieldsToPrepare.clear();
+  mFetchJoinInfo.clear();
+  mOrderedJoinInfoList.clear();
 
   mExpressionContext.reset( new QgsExpressionContext() );
   mExpressionContext->appendScope( QgsExpressionContextUtils::globalScope() );
   mExpressionContext->appendScope( QgsExpressionContextUtils::projectScope() );
   mExpressionContext->setFields( mSource->mFields );
 
-  QList< int > virtualFieldsToFetch;
-  for ( int i = 0; i < mSource->mFields.count(); i++ )
+  mFieldsToPrepare = ( mRequest.flags() & QgsFeatureRequest::SubsetOfAttributes ) ? mRequest.subsetOfAttributes() : mSource->mFields.allAttributesList();
+
+  while ( !mFieldsToPrepare.isEmpty() )
   {
-    if ( mSource->mFields.fieldOrigin( i ) == QgsFields::OriginExpression )
-    {
-      // Only prepare if there is no subset defined or the subset contains this field
-      if ( !( mRequest.flags() & QgsFeatureRequest::SubsetOfAttributes )
-           || mRequest.subsetOfAttributes().contains( i ) )
-      {
-        virtualFieldsToFetch << i;
-      }
-    }
+    int fieldIdx = mFieldsToPrepare.takeFirst();
+    if ( mPreparedFields.contains( fieldIdx ) )
+      continue;
+
+    mPreparedFields << fieldIdx;
+    prepareField( fieldIdx );
   }
 
-  QList< int > virtualFieldsProcessed;
-  while ( !virtualFieldsToFetch.isEmpty() )
+  //sort joins by dependency
+  if ( mFetchJoinInfo.size() > 0 )
   {
-    int fieldIdx = virtualFieldsToFetch.takeFirst();
-    if ( virtualFieldsProcessed.contains( fieldIdx ) )
-      continue;
+    createOrderedJoinList();
+  }
+}
 
-    virtualFieldsProcessed << fieldIdx;
+void QgsVectorLayerFeatureIterator::createOrderedJoinList()
+{
+  mOrderedJoinInfoList = mFetchJoinInfo.values();
+  if ( mOrderedJoinInfoList.size() < 2 )
+  {
+    return;
+  }
 
+  QSet<int> resolvedFields; //todo: get provider / virtual fields without joins
 
-    int oi = mSource->mFields.fieldOriginIndex( fieldIdx );
-    QgsExpression* exp = new QgsExpression( exps[oi].cachedExpression );
+  //add all provider fields without joins as resolved fields
+  QList< int >::const_iterator prepFieldIt = mPreparedFields.constBegin();
+  for ( ; prepFieldIt != mPreparedFields.constEnd(); ++prepFieldIt )
+  {
+    if ( mSource->mFields.fieldOrigin( *prepFieldIt ) != QgsFields::OriginJoin )
+    {
+      resolvedFields.insert( *prepFieldIt );
+    }
+  }
 
-    QgsDistanceArea da;
-    da.setSourceCrs( mSource->mCrsId );
-    da.setEllipsoidalMode( true );
-    da.setEllipsoid( QgsProject::instance()->readEntry( "Measure", "/Ellipsoid", GEO_NONE ) );
-    exp->setGeomCalculator( da );
-    exp->setDistanceUnits( QgsProject::instance()->distanceUnits() );
-    exp->setAreaUnits( QgsProject::instance()->areaUnits() );
+  //iterate through the joins. If target field is not yet covered, move the entry to the end of the list
 
-    exp->prepare( mExpressionContext.data() );
-    mExpressionFieldInfo.insert( fieldIdx, exp );
+  //some join combinations might not have a resolution at all
+  int maxIterations = ( mOrderedJoinInfoList.size() + 1 ) * mOrderedJoinInfoList.size() / 2.0;
+  int currentIteration = 0;
 
-    Q_FOREACH ( const QString& col, exp->referencedColumns() )
+  for ( int i = 0; i < mOrderedJoinInfoList.size() - 1; ++i )
+  {
+    if ( !resolvedFields.contains( mOrderedJoinInfoList.at( i ).targetField ) )
+    {
+      mOrderedJoinInfoList.append( mOrderedJoinInfoList.at( i ) );
+      mOrderedJoinInfoList.removeAt( i );
+      --i;
+    }
+    else
     {
-      int dependantFieldIdx = mSource->mFields.fieldNameIndex( col );
-      if ( mRequest.flags() & QgsFeatureRequest::SubsetOfAttributes )
+      int offset = mOrderedJoinInfoList.at( i ).indexOffset;
+      int joinField = mOrderedJoinInfoList.at( i ).joinField;
+
+      QgsAttributeList attributes = mOrderedJoinInfoList.at( i ).attributes;
+      QgsAttributeList::const_iterator attIt = attributes.constBegin();
+      for ( ; attIt != attributes.constEnd(); ++attIt )
       {
-        mRequest.setSubsetOfAttributes( mRequest.subsetOfAttributes() << dependantFieldIdx );
+        if ( *attIt != joinField )
+        {
+          resolvedFields.insert( joinField < *attIt ? *attIt + offset - 1 : *attIt + offset );
+        }
       }
-      // also need to fetch this dependant field
-      if ( mSource->mFields.fieldOrigin( dependantFieldIdx ) == QgsFields::OriginExpression )
-        virtualFieldsToFetch << dependantFieldIdx;
     }
 
-    if ( exp->needsGeometry() )
+    ++currentIteration;
+    if ( currentIteration >= maxIterations )
     {
-      mRequest.setFlags( mRequest.flags() & ~QgsFeatureRequest::NoGeometry );
+      break;
     }
   }
+}
+
+void QgsVectorLayerFeatureIterator::prepareField( int fieldIdx )
+{
+  switch ( mSource->mFields.fieldOrigin( fieldIdx ) )
+  {
+    case QgsFields::OriginExpression:
+      prepareExpression( fieldIdx );
+      break;
+
+    case QgsFields::OriginJoin:
+      if ( mSource->mJoinBuffer->containsJoins() )
+      {
+        prepareJoin( fieldIdx );
+      }
+      break;
 
+    case QgsFields::OriginUnknown:
+    case QgsFields::OriginProvider:
+    case QgsFields::OriginEdit:
+      break;
+  }
 }
 
 void QgsVectorLayerFeatureIterator::addJoinedAttributes( QgsFeature &f )
 {
-  QMap<const QgsVectorJoinInfo*, FetchJoinInfo>::const_iterator joinIt = mFetchJoinInfo.constBegin();
-  for ( ; joinIt != mFetchJoinInfo.constEnd(); ++joinIt )
+  QList< FetchJoinInfo >::const_iterator joinIt = mOrderedJoinInfoList.constBegin();
+  for ( ; joinIt != mOrderedJoinInfoList.constEnd(); ++joinIt )
   {
-    const FetchJoinInfo& info = joinIt.value();
-    Q_ASSERT( joinIt.key() );
+    QVariant targetFieldValue = f.attribute( joinIt->targetField );
 
-    QVariant targetFieldValue = f.attribute( info.targetField );
     if ( !targetFieldValue.isValid() )
       continue;
 
-    const QHash< QString, QgsAttributes>& memoryCache = info.joinInfo->cachedAttributes;
+    const QHash< QString, QgsAttributes>& memoryCache = joinIt->joinInfo->cachedAttributes;
     if ( memoryCache.isEmpty() )
-      info.addJoinedAttributesDirect( f, targetFieldValue );
+      joinIt->addJoinedAttributesDirect( f, targetFieldValue );
     else
-      info.addJoinedAttributesCached( f, targetFieldValue );
+      joinIt->addJoinedAttributesCached( f, targetFieldValue );
   }
 }
 
@@ -623,24 +686,48 @@ void QgsVectorLayerFeatureIterator::addVirtualAttributes( QgsFeature& f )
   attr.resize( mSource->mFields.count() );  // Provider attrs count + joined attrs count + expression attrs count
   f.setAttributes( attr );
 
+  // possible TODO - handle combinations of expression -> join -> expression -> join?
+  // but for now, write that off as too complex and an unlikely rare, unsupported use case
+
+  QList< int > fetchedVirtualAttributes;
+  //first, check through joins for any virtual fields we need
+  QMap<const QgsVectorJoinInfo*, FetchJoinInfo>::const_iterator joinIt = mFetchJoinInfo.constBegin();
+  for ( ; joinIt != mFetchJoinInfo.constEnd(); ++joinIt )
+  {
+    if ( mExpressionFieldInfo.contains( joinIt->targetField ) )
+    {
+      // have to calculate expression field before we can handle this join
+      addExpressionAttribute( f, joinIt->targetField );
+      fetchedVirtualAttributes << joinIt->targetField;
+    }
+  }
+
   if ( !mFetchJoinInfo.isEmpty() )
     addJoinedAttributes( f );
 
+  // add remaining expression fields
   if ( !mExpressionFieldInfo.isEmpty() )
   {
     QMap<int, QgsExpression*>::ConstIterator it = mExpressionFieldInfo.constBegin();
-
     for ( ; it != mExpressionFieldInfo.constEnd(); ++it )
     {
-      QgsExpression* exp = it.value();
-      mExpressionContext->setFeature( f );
-      QVariant val = exp->evaluate( mExpressionContext.data() );
-      mSource->mFields.at( it.key() ).convertCompatible( val );
-      f.setAttribute( it.key(), val );
+      if ( fetchedVirtualAttributes.contains( it.key() ) )
+        continue;
+
+      addExpressionAttribute( f, it.key() );
     }
   }
 }
 
+void QgsVectorLayerFeatureIterator::addExpressionAttribute( QgsFeature& f, int attrIndex )
+{
+  QgsExpression* exp = mExpressionFieldInfo.value( attrIndex );
+  mExpressionContext->setFeature( f );
+  QVariant val = exp->evaluate( mExpressionContext.data() );
+  mSource->mFields.at( attrIndex ).convertCompatible( val );
+  f.setAttribute( attrIndex, val );
+}
+
 bool QgsVectorLayerFeatureIterator::prepareSimplification( const QgsSimplifyMethod& simplifyMethod )
 {
   delete mEditGeometrySimplifier;
diff --git a/src/core/qgsvectorlayerfeatureiterator.h b/src/core/qgsvectorlayerfeatureiterator.h
index a047a90..3f837ad 100644
--- a/src/core/qgsvectorlayerfeatureiterator.h
+++ b/src/core/qgsvectorlayerfeatureiterator.h
@@ -97,10 +97,19 @@ class CORE_EXPORT QgsVectorLayerFeatureIterator : public QgsAbstractFeatureItera
 
     //! @note not available in Python bindings
     void rewindEditBuffer();
+
+    //! @note not available in Python bindings
+    void prepareJoin( int fieldIdx );
+
     //! @note not available in Python bindings
-    void prepareJoins();
+    void prepareExpression( int fieldIdx );
+
     //! @note not available in Python bindings
-    void prepareExpressions();
+    void prepareFields();
+
+    //! @note not available in Python bindings
+    void prepareField( int fieldIdx );
+
     //! @note not available in Python bindings
     bool fetchNextAddedFeature( QgsFeature& f );
     //! @note not available in Python bindings
@@ -127,6 +136,14 @@ class CORE_EXPORT QgsVectorLayerFeatureIterator : public QgsAbstractFeatureItera
      */
     void addVirtualAttributes( QgsFeature &f );
 
+    /** Adds an expression based attribute to a feature
+     * @param f feature
+     * @param attrIndex attribute index
+     * @note added in QGIS 2.14
+     * @note not available in Python bindings
+     */
+    void addExpressionAttribute( QgsFeature& f, int attrIndex );
+
     /** Update feature with uncommited attribute updates.
      * @note not available in Python bindings
      */
@@ -179,6 +196,12 @@ class CORE_EXPORT QgsVectorLayerFeatureIterator : public QgsAbstractFeatureItera
 
     QScopedPointer<QgsExpressionContext> mExpressionContext;
 
+    QList< int > mPreparedFields;
+    QList< int > mFieldsToPrepare;
+
+    /** Join list sorted by dependency*/
+    QList< FetchJoinInfo > mOrderedJoinInfoList;
+
     /**
      * Will always return true. We assume that ordering has been done on provider level already.
      *
@@ -187,6 +210,8 @@ class CORE_EXPORT QgsVectorLayerFeatureIterator : public QgsAbstractFeatureItera
 
     //! returns whether the iterator supports simplify geometries on provider side
     virtual bool providerCanSimplify( QgsSimplifyMethod::MethodType methodType ) const override;
+
+    void createOrderedJoinList();
 };
 
 #endif // QGSVECTORLAYERFEATUREITERATOR_H
diff --git a/src/core/qgsvectorlayerlabelprovider.h b/src/core/qgsvectorlayerlabelprovider.h
index fb3efaf..a3d7823 100644
--- a/src/core/qgsvectorlayerlabelprovider.h
+++ b/src/core/qgsvectorlayerlabelprovider.h
@@ -114,6 +114,8 @@ class CORE_EXPORT QgsVectorLayerLabelProvider : public QgsAbstractLabelProvider
 
     //! List of generated
     QList<QgsLabelFeature*> mLabels;
+
+    friend class TestQgsLabelingEngineV2;
 };
 
 #endif // QGSVECTORLAYERLABELPROVIDER_H
diff --git a/src/core/symbology-ng/qgsvectorcolorrampv2.cpp b/src/core/symbology-ng/qgsvectorcolorrampv2.cpp
index d03ce35..c7f6b44 100644
--- a/src/core/symbology-ng/qgsvectorcolorrampv2.cpp
+++ b/src/core/symbology-ng/qgsvectorcolorrampv2.cpp
@@ -296,8 +296,11 @@ double QgsVectorRandomColorRampV2::value( int index ) const
 
 QColor QgsVectorRandomColorRampV2::color( double value ) const
 {
+  if ( value < 0 || value > 1 )
+    return QColor();
+
   int colorCnt = mColors.count();
-  int colorIdx = static_cast< int >( value * ( colorCnt - 1 ) );
+  int colorIdx = qMin( static_cast< int >( value * colorCnt ), colorCnt - 1 );
 
   if ( colorIdx >= 0 && colorIdx < colorCnt )
     return mColors.at( colorIdx );
diff --git a/src/gui/editorwidgets/qgswebviewwidgetwrapper.cpp b/src/gui/editorwidgets/qgswebviewwidgetwrapper.cpp
index 039cd85..a5bc1c1 100644
--- a/src/gui/editorwidgets/qgswebviewwidgetwrapper.cpp
+++ b/src/gui/editorwidgets/qgswebviewwidgetwrapper.cpp
@@ -114,6 +114,7 @@ void QgsWebViewWidgetWrapper::initWidget( QWidget* editor )
     mWebView->page()->setNetworkAccessManager( QgsNetworkAccessManager::instance() );
     mWebView->settings()->setAttribute( QWebSettings::LocalContentCanAccessRemoteUrls, true );
     mWebView->settings()->setAttribute( QWebSettings::JavascriptCanOpenWindows, true );
+    mWebView->settings()->setAttribute( QWebSettings::PluginsEnabled, true );
 #ifdef QGISDEBUG
     mWebView->settings()->setAttribute( QWebSettings::DeveloperExtrasEnabled, true );
 #endif
diff --git a/src/providers/delimitedtext/qgsdelimitedtextfeatureiterator.cpp b/src/providers/delimitedtext/qgsdelimitedtextfeatureiterator.cpp
index 0638034..e963350 100644
--- a/src/providers/delimitedtext/qgsdelimitedtextfeatureiterator.cpp
+++ b/src/providers/delimitedtext/qgsdelimitedtextfeatureiterator.cpp
@@ -501,8 +501,16 @@ QgsDelimitedTextFeatureSource::QgsDelimitedTextFeatureSource( const QgsDelimited
     , mXyDms( p->mXyDms )
     , attributeColumns( p->attributeColumns )
 {
+  QUrl url = p->mFile->url();
+
+  // make sure watcher not created when using iterator (e.g. for rendering, see issue #15558)
+  if ( url.hasQueryItem( "watchFile" ) )
+  {
+    url.removeQueryItem( "watchFile" );
+  }
+
   mFile = new QgsDelimitedTextFile();
-  mFile->setFromUrl( p->mFile->url() );
+  mFile->setFromUrl( url );
 
   mExpressionContext << QgsExpressionContextUtils::globalScope()
   << QgsExpressionContextUtils::projectScope();
diff --git a/src/providers/delimitedtext/qgsdelimitedtextfile.cpp b/src/providers/delimitedtext/qgsdelimitedtextfile.cpp
index 4af29bf..b788c19 100644
--- a/src/providers/delimitedtext/qgsdelimitedtextfile.cpp
+++ b/src/providers/delimitedtext/qgsdelimitedtextfile.cpp
@@ -35,7 +35,7 @@ QgsDelimitedTextFile::QgsDelimitedTextFile( const QString& url ) :
     mEncoding( "UTF-8" ),
     mFile( nullptr ),
     mStream( nullptr ),
-    mUseWatcher( true ),
+    mUseWatcher( false ),
     mWatcher( nullptr ),
     mDefinitionValid( false ),
     mUseHeader( true ),
@@ -158,9 +158,9 @@ bool QgsDelimitedTextFile::setFromUrl( const QUrl &url )
   }
 
   //
-  if ( url.hasQueryItem( "useWatcher" ) )
+  if ( url.hasQueryItem( "watchFile" ) )
   {
-    mUseWatcher = ! url.queryItemValue( "useWatcher" ).toUpper().startsWith( 'N' );
+    mUseWatcher = url.queryItemValue( "watchFile" ).toUpper().startsWith( 'Y' );
   }
 
   // The default type is csv, to be consistent with the
@@ -269,9 +269,9 @@ QUrl QgsDelimitedTextFile::url()
     url.addQueryItem( "encoding", mEncoding );
   }
 
-  if ( !mUseWatcher )
+  if ( mUseWatcher )
   {
-    url.addQueryItem( "useWatcher", "no" );
+    url.addQueryItem( "watchFile", "yes" );
   }
 
   url.addQueryItem( "type", type() );
diff --git a/src/providers/ogr/qgsogrconnpool.h b/src/providers/ogr/qgsogrconnpool.h
index 5d28f78..7f7c1f5 100644
--- a/src/providers/ogr/qgsogrconnpool.h
+++ b/src/providers/ogr/qgsogrconnpool.h
@@ -17,6 +17,7 @@
 #define QGSOGRCONNPOOL_H
 
 #include "qgsconnectionpool.h"
+#include "qgsogrprovider.h"
 #include <ogr_api.h>
 
 
@@ -43,7 +44,7 @@ inline void qgsConnectionPool_ConnectionCreate( QString connInfo, QgsOgrConn*& c
 
 inline void qgsConnectionPool_ConnectionDestroy( QgsOgrConn* c )
 {
-  OGR_DS_Destroy( c->ds );
+  QgsOgrUtils::OGRDestroyWrapper( c->ds );
   delete c;
 }
 
diff --git a/src/providers/ogr/qgsogrfeatureiterator.cpp b/src/providers/ogr/qgsogrfeatureiterator.cpp
index 6b37691..70ea6f3 100644
--- a/src/providers/ogr/qgsogrfeatureiterator.cpp
+++ b/src/providers/ogr/qgsogrfeatureiterator.cpp
@@ -301,6 +301,12 @@ bool QgsOgrFeatureIterator::close()
 
   iteratorClosed();
 
+  // Will for example release SQLite3 statements
+  if ( ogrLayer )
+  {
+    OGR_L_ResetReading( ogrLayer );
+  }
+
   if ( mSubsetStringSet )
   {
     OGR_DS_ReleaseResultSet( mConn->ds, ogrLayer );
@@ -310,6 +316,7 @@ bool QgsOgrFeatureIterator::close()
     QgsOgrConnPool::instance()->releaseConnection( mConn );
 
   mConn = nullptr;
+  ogrLayer = nullptr;
 
   mClosed = true;
   return true;
diff --git a/src/providers/ogr/qgsogrprovider.cpp b/src/providers/ogr/qgsogrprovider.cpp
index 3249e4a..2ecc723 100644
--- a/src/providers/ogr/qgsogrprovider.cpp
+++ b/src/providers/ogr/qgsogrprovider.cpp
@@ -48,6 +48,13 @@ email                : sherman at mrcc.com
 #include "qgsvectorlayerimport.h"
 #include "qgslocalec.h"
 
+#ifdef Q_OS_WIN
+#include <windows.h>
+#endif
+#ifdef Q_OS_LINUX
+#include <sys/vfs.h>
+#endif
+
 static const QString TEXT_PROVIDER_KEY = "ogr";
 static const QString TEXT_PROVIDER_DESCRIPTION =
   QString( "OGR data provider" )
@@ -383,11 +390,14 @@ QgsOgrProvider::QgsOgrProvider( QString const & uri )
 
 QgsOgrProvider::~QgsOgrProvider()
 {
-  close();
   QgsOgrConnPool::instance()->unref( dataSourceUri() );
   // We must also make sure to flush unusef cached connections so that
   // the file can be removed (#15137)
   QgsOgrConnPool::instance()->invalidateConnections( dataSourceUri() );
+
+  // Do that as last step for final cleanup that might be prevented by
+  // still opened datasets.
+  close();
 }
 
 QgsAbstractFeatureSource* QgsOgrProvider::featureSource() const
@@ -2627,6 +2637,152 @@ void QgsOgrProvider::forceReload()
   QgsOgrConnPool::instance()->invalidateConnections( dataSourceUri() );
 }
 
+OGRDataSourceH QgsOgrUtils::OGROpenWrapper( const char* pszPath, bool bUpdate, OGRSFDriverH *phDriver )
+{
+  CPLErrorReset();
+  OGRSFDriverH hDriver = nullptr;
+  OGRDataSourceH hDS = OGROpen( pszPath, bUpdate, &hDriver );
+  if ( phDriver )
+    *phDriver = hDriver;
+  if ( !hDS )
+    return nullptr;
+  // GDAL < 1.11.5 has a crashing bug with GeoPackage databases with curve geometry
+  // types (https://trac.osgeo.org/gdal/ticket/6558)
+#if GDAL_VERSION_MAJOR == 1 && GDAL_VERSION_MINOR == 11 && GDAL_VERSION_MACRO < 5
+  const char* pszLastErrorMsg = CPLGetLastErrorMsg();
+  if ( hDriver == OGRGetDriverByName( "GPKG" ) &&
+       strstr( pszLastErrorMsg, "geometry column" ) &&
+       strstr( pszLastErrorMsg, "of type" ) &&
+       strstr( pszLastErrorMsg, "ignored" ) )
+  {
+    QgsDebugMsg( QString( "Ignoring %1 that is a GeoPackage DB with curve geometries" ).arg( pszPath ) );
+    OGR_DS_Destroy( hDS );
+    hDS = nullptr;
+  }
+#endif
+  return hDS;
+}
+
+static bool IsLocalFile( const QString& path )
+{
+  QString dirName( QFileInfo( path ).absolutePath() );
+  // Start with the OS specific methods since the QT >= 5.4 method just
+  // return a string and not an enumerated type.
+#if defined(Q_OS_WIN)
+  if ( dirName.startsWith( "\\\\" ) )
+    return false;
+  if ( dirName.length() >= 3 && dirName[1] == ':' &&
+       ( dirName[2] == '\\' || dirName[2] == '/' ) )
+  {
+    dirName.resize( 3 );
+    return GetDriveType( dirName.toAscii().constData() ) != DRIVE_REMOTE;
+  }
+  return true;
+#elif defined(Q_OS_LINUX)
+  struct statfs sStatFS;
+  if ( statfs( dirName.toAscii().constData(), &sStatFS ) == 0 )
+  {
+    // Codes from http://man7.org/linux/man-pages/man2/statfs.2.html
+    if ( sStatFS.f_type == 0x6969 /* NFS */ ||
+         sStatFS.f_type == 0x517b /* SMB */ ||
+         sStatFS.f_type == 0xff534d42 /* CIFS */ )
+    {
+      return false;
+    }
+  }
+  return true;
+#elif QT_VERSION >= QT_VERSION_CHECK(5, 4, 0)
+  QStorageInfo info( dirName );
+  QString fileSystem( info.fileSystemType() );
+  QgsDebugMsg( QString( "Filesystem for %1 is %2" ).arg( path ).arg( fileSystem ) );
+  return path != "nfs" && path != "smbfs";
+#else
+  return true;
+#endif
+}
+
+void QgsOgrUtils::OGRDestroyWrapper( OGRDataSourceH ogrDataSource )
+{
+  if ( !ogrDataSource )
+    return;
+  OGRSFDriverH ogrDriver = OGR_DS_GetDriver( ogrDataSource );
+  QString ogrDriverName = OGR_Dr_GetName( ogrDriver );
+  QString datasetName( FROM8( OGR_DS_GetName( ogrDataSource ) ) );
+  if ( ogrDriverName == "GPKG" &&
+       IsLocalFile( datasetName ) &&
+       !CPLGetConfigOption( "OGR_SQLITE_JOURNAL", NULL ) )
+  {
+    // We need to reset all iterators on layers, otherwise we will not
+    // be able to change journal_mode.
+    int layerCount = OGR_DS_GetLayerCount( ogrDataSource );
+    for ( int i = 0; i < layerCount; i ++ )
+    {
+      OGR_L_ResetReading( OGR_DS_GetLayer( ogrDataSource, i ) );
+    }
+
+    CPLPushErrorHandler( CPLQuietErrorHandler );
+    QgsDebugMsg( "GPKG: Trying to return to delete mode" );
+    bool bSuccess = false;
+    OGRLayerH hSqlLyr = OGR_DS_ExecuteSQL( ogrDataSource,
+                                           "PRAGMA journal_mode = delete",
+                                           NULL, NULL );
+    if ( hSqlLyr != NULL )
+    {
+      OGRFeatureH hFeat = OGR_L_GetNextFeature( hSqlLyr );
+      if ( hFeat != NULL )
+      {
+        const char* pszRet = OGR_F_GetFieldAsString( hFeat, 0 );
+        bSuccess = EQUAL( pszRet, "delete" );
+        QgsDebugMsg( QString( "Return: %1" ).arg( pszRet ) );
+        OGR_F_Destroy( hFeat );
+      }
+    }
+    else if ( CPLGetLastErrorType() != CE_None )
+    {
+      QgsDebugMsg( QString( "Return: %1" ).arg( CPLGetLastErrorMsg() ) );
+    }
+    OGR_DS_ReleaseResultSet( ogrDataSource, hSqlLyr );
+    CPLPopErrorHandler();
+    OGR_DS_Destroy( ogrDataSource );
+
+    // This may have not worked if the file was opened in read-only mode,
+    // so retry in update mode
+    if ( !bSuccess )
+    {
+      QgsDebugMsg( "GPKG: Trying again" );
+      CPLSetThreadLocalConfigOption( "OGR_SQLITE_JOURNAL", "DELETE" );
+      ogrDataSource = OGROpen( TO8F( datasetName ), TRUE, NULL );
+      CPLSetThreadLocalConfigOption( "OGR_SQLITE_JOURNAL", NULL );
+      if ( ogrDataSource )
+      {
+#ifdef QGISDEBUG
+        CPLPushErrorHandler( CPLQuietErrorHandler );
+        OGRLayerH hSqlLyr = OGR_DS_ExecuteSQL( ogrDataSource,
+                                               "PRAGMA journal_mode",
+                                               NULL, NULL );
+        CPLPopErrorHandler();
+        if ( hSqlLyr != NULL )
+        {
+          OGRFeatureH hFeat = OGR_L_GetNextFeature( hSqlLyr );
+          if ( hFeat != NULL )
+          {
+            const char* pszRet = OGR_F_GetFieldAsString( hFeat, 0 );
+            QgsDebugMsg( QString( "Return: %1" ).arg( pszRet ) );
+            OGR_F_Destroy( hFeat );
+          }
+          OGR_DS_ReleaseResultSet( ogrDataSource, hSqlLyr );
+        }
+#endif
+        OGR_DS_Destroy( ogrDataSource );
+      }
+    }
+  }
+  else
+  {
+    OGR_DS_Destroy( ogrDataSource );
+  }
+}
+
 QByteArray QgsOgrUtils::quotedIdentifier( QByteArray field, const QString& ogrDriverName )
 {
   if ( ogrDriverName == "MySQL" )
@@ -2855,7 +3011,22 @@ void QgsOgrProvider::open( OpenMode mode )
 
   // first try to open in update mode (unless specified otherwise)
   if ( !openReadOnly )
-    ogrDataSource = OGROpen( TO8F( mFilePath ), true, &ogrDriver );
+  {
+    if ( QFileInfo( mFilePath ).suffix().compare( "gpkg", Qt::CaseInsensitive ) == 0 &&
+         IsLocalFile( mFilePath ) &&
+         !CPLGetConfigOption( "OGR_SQLITE_JOURNAL", NULL ) &&
+         QSettings().value( "/qgis/walForSqlite3", true ).toBool() )
+    {
+      // For GeoPackage, we force opening of the file in WAL (Write Ahead Log)
+      // mode so as to avoid readers blocking writer(s), and vice-versa.
+      // https://www.sqlite.org/wal.html
+      // But only do that on a local file since WAL is advertized not to work
+      // on network shares
+      CPLSetThreadLocalConfigOption( "OGR_SQLITE_JOURNAL", "WAL" );
+    }
+    ogrDataSource = QgsOgrUtils::OGROpenWrapper( TO8F( mFilePath ), true, &ogrDriver );
+    CPLSetThreadLocalConfigOption( "OGR_SQLITE_JOURNAL", NULL );
+  }
 
   mValid = false;
   if ( ogrDataSource )
@@ -2985,7 +3156,7 @@ void QgsOgrProvider::close()
 
   if ( ogrDataSource )
   {
-    OGR_DS_Destroy( ogrDataSource );
+    QgsOgrUtils::OGRDestroyWrapper( ogrDataSource );
   }
   ogrDataSource = nullptr;
   ogrLayer = nullptr;
diff --git a/src/providers/ogr/qgsogrprovider.h b/src/providers/ogr/qgsogrprovider.h
index c1cf3aa..690ba7a 100644
--- a/src/providers/ogr/qgsogrprovider.h
+++ b/src/providers/ogr/qgsogrprovider.h
@@ -15,6 +15,9 @@ email                : sherman at mrcc.com
  *                                                                         *
  ***************************************************************************/
 
+#ifndef QGSOGRPROVIDER_H
+#define QGSOGRPROVIDER_H
+
 #include "QTextCodec"
 
 #include "qgsrectangle.h"
@@ -400,4 +403,9 @@ class QgsOgrUtils
     /** Quote a value for placement in a SQL string.
      */
     static QString quotedValue( const QVariant& value );
+
+    static OGRDataSourceH OGROpenWrapper( const char* pszPath, bool bUpdate, OGRSFDriverH *phDriver );
+    static void OGRDestroyWrapper( OGRDataSourceH ogrDataSource );
 };
+
+#endif // QGSOGRPROVIDER_H
diff --git a/src/providers/postgres/qgspostgresdataitems.cpp b/src/providers/postgres/qgspostgresdataitems.cpp
index 5d52ded..4c254a5 100644
--- a/src/providers/postgres/qgspostgresdataitems.cpp
+++ b/src/providers/postgres/qgspostgresdataitems.cpp
@@ -693,9 +693,13 @@ bool QgsPGSchemaItem::handleDrop( const QMimeData * data, Qt::DropAction )
 {
   QgsPGConnectionItem *conn = qobject_cast<QgsPGConnectionItem *>( parent() );
   if ( !conn )
-    return 0;
+    return false;
+
+  bool result = conn->handleDrop( data, mName );
+  if ( result )
+    refresh();
 
-  return conn->handleDrop( data, mName );
+  return result;
 }
 
 // ---------------------------------------------------------------------------
diff --git a/src/providers/postgres/qgspostgresprovider.cpp b/src/providers/postgres/qgspostgresprovider.cpp
index 0ce3044..948275f 100644
--- a/src/providers/postgres/qgspostgresprovider.cpp
+++ b/src/providers/postgres/qgspostgresprovider.cpp
@@ -2306,8 +2306,11 @@ void QgsPostgresProvider::appendGeomParam( const QgsGeometry *geom, QStringList
   }
 
   QString param;
-  const unsigned char *buf = geom->asWkb();
-  for ( int i = 0; i < geom->wkbSize(); ++i )
+  QScopedPointer<QgsGeometry> convertedGeom( convertToProviderType( *geom ) );
+  const unsigned char *buf = convertedGeom ? convertedGeom->asWkb() : geom->asWkb();
+  size_t wkbSize = convertedGeom ? convertedGeom->wkbSize() : geom->wkbSize();
+
+  for ( size_t i = 0; i < wkbSize; ++i )
   {
     if ( connectionRO()->useWkbHex() )
       param += QString( "%1" ).arg(( int ) buf[i], 2, 16, QChar( '0' ) );
diff --git a/src/providers/spatialite/qgsspatialitesourceselect.cpp b/src/providers/spatialite/qgsspatialitesourceselect.cpp
index a583fc9..da7a2ef 100644
--- a/src/providers/spatialite/qgsspatialitesourceselect.cpp
+++ b/src/providers/spatialite/qgsspatialitesourceselect.cpp
@@ -460,6 +460,10 @@ void QgsSpatiaLiteSourceSelect::on_btnConnect_clicked()
         QMessageBox::critical( this, tr( "SpatiaLite getTableInfo Error" ),
                                tr( "Failure exploring tables from: %1\n\n%2" ).arg( mSqlitePath, errCause ) );
         break;
+      case QgsSpatiaLiteConnection::FailedToCheckMetadata:
+        QMessageBox::critical( this, tr( "SpatiaLite metadata check failed" ),
+                               tr( "Failure getting table metadata ... is this really a SpatialLite database? %1\n\n%2" ).arg( mSqlitePath, errCause ) );
+        break;
       default:
         QMessageBox::critical( this, tr( "SpatiaLite Error" ),
                                tr( "Unexpected error when working with: %1\n\n%2" ).arg( mSqlitePath, errCause ) );
diff --git a/src/providers/virtual/qgsvirtuallayerqueryparser.cpp b/src/providers/virtual/qgsvirtuallayerqueryparser.cpp
index 9d1047d..1a1c10c 100644
--- a/src/providers/virtual/qgsvirtuallayerqueryparser.cpp
+++ b/src/providers/virtual/qgsvirtuallayerqueryparser.cpp
@@ -39,8 +39,8 @@ namespace QgsVirtualLayerQueryParser
     while ( true )
     {
       char *errMsg = nullptr;
-      int r = sqlite3_exec( db.get(), query.toLocal8Bit().constData(), nullptr, nullptr, &errMsg );
-      QString err = errMsg;
+      int r = sqlite3_exec( db.get(), query.toUtf8().constData(), nullptr, nullptr, &errMsg );
+      QString err = QString::fromUtf8( errMsg );
       if ( r && err.startsWith( noSuchError ) )
       {
         QString tableName = err.mid( noSuchError.size() );
@@ -48,7 +48,7 @@ namespace QgsVirtualLayerQueryParser
 
         // create a dummy table to skip this error
         QString createStr = QString( "CREATE TABLE \"%1\" (id int)" ).arg( tableName.replace( "\"", "\"\"" ) );
-        ( void )sqlite3_exec( db.get(), createStr.toLocal8Bit().constData(), nullptr, NULL, NULL );
+        ( void )sqlite3_exec( db.get(), createStr.toUtf8().constData(), nullptr, NULL, NULL );
       }
       else
       {
diff --git a/src/providers/virtual/qgsvirtuallayersqlitemodule.cpp b/src/providers/virtual/qgsvirtuallayersqlitemodule.cpp
index 5397ba9..e9b76b6 100644
--- a/src/providers/virtual/qgsvirtuallayersqlitemodule.cpp
+++ b/src/providers/virtual/qgsvirtuallayersqlitemodule.cpp
@@ -324,11 +324,11 @@ int vtableCreateConnect( sqlite3* sql, void* aux, int argc, const char* const* a
   Q_UNUSED( isCreated );
 
 #define RETURN_CSTR_ERROR(err) if (outErr) {size_t s = strlen(err); *outErr=reinterpret_cast<char*>(sqlite3_malloc( static_cast<int>( s ) +1)); strncpy(*outErr, err, s);}
-#define RETURN_CPPSTR_ERROR(err) if (outErr) {*outErr=reinterpret_cast<char*>(sqlite3_malloc( static_cast<int>( err.size() )+1)); strncpy(*outErr, err.c_str(), err.size());}
+#define RETURN_CPPSTR_ERROR(err) if (outErr) {*outErr=reinterpret_cast<char*>(sqlite3_malloc( static_cast<int>( err.toUtf8().size() )+1)); strncpy(*outErr, err.toUtf8().constData(), err.toUtf8().size());}
 
   if ( argc < 4 )
   {
-    std::string err( "Missing arguments: layer_id | provider, source" );
+    QString err( "Missing arguments: layer_id | provider, source" );
     RETURN_CPPSTR_ERROR( err );
     return SQLITE_ERROR;
   }
@@ -341,7 +341,7 @@ int vtableCreateConnect( sqlite3* sql, void* aux, int argc, const char* const* a
     // CREATE VIRTUAL TABLE vtab USING QgsVLayer(layer_id)
     // vtab = argv[2]
     // layer_id = argv[3]
-    QString layerid( argv[3] );
+    QString layerid = QString::fromUtf8( argv[3] );
     if ( layerid.size() >= 1 && layerid[0] == '\'' )
     {
       layerid = layerid.mid( 1, layerid.size() - 2 );
@@ -351,8 +351,8 @@ int vtableCreateConnect( sqlite3* sql, void* aux, int argc, const char* const* a
     {
       if ( outErr )
       {
-        std::string err( "Cannot find layer " );
-        err += argv[3];
+        QString err( "Cannot find layer " );
+        err += QString::fromUtf8( argv[3] );
         RETURN_CPPSTR_ERROR( err );
       }
       return SQLITE_ERROR;
@@ -368,7 +368,7 @@ int vtableCreateConnect( sqlite3* sql, void* aux, int argc, const char* const* a
     // source = argv[4]
     // encoding = argv[5]
     QString provider = argv[3];
-    QString source = argv[4];
+    QString source = QString::fromUtf8( argv[4] );
     QString encoding = "UTF-8";
     if ( argc == 6 )
     {
@@ -386,17 +386,16 @@ int vtableCreateConnect( sqlite3* sql, void* aux, int argc, const char* const* a
     }
     try
     {
-      newVtab.reset( new VTable( sql, provider, source, argv[2], encoding ) );
+      newVtab.reset( new VTable( sql, provider, source, QString::fromUtf8( argv[2] ), encoding ) );
     }
     catch ( std::runtime_error& e )
     {
-      std::string err( e.what() );
-      RETURN_CPPSTR_ERROR( err );
+      RETURN_CSTR_ERROR( e.what() );
       return SQLITE_ERROR;
     }
   }
 
-  r = sqlite3_declare_vtab( sql, newVtab->creationString().toLocal8Bit().constData() );
+  r = sqlite3_declare_vtab( sql, newVtab->creationString().toUtf8().constData() );
   if ( r )
   {
     RETURN_CSTR_ERROR( sqlite3_errmsg( sql ) );
diff --git a/tests/src/core/testqgsexpression.cpp b/tests/src/core/testqgsexpression.cpp
index b76db34..7f54fa7 100644
--- a/tests/src/core/testqgsexpression.cpp
+++ b/tests/src/core/testqgsexpression.cpp
@@ -614,6 +614,7 @@ class TestQgsExpression: public QObject
       QTest::newRow( "shortest_line geom" ) << "geom_to_wkt(shortest_line( geom_from_wkt('LineString( 1 1, 5 1, 5 5 )'),geom_from_wkt('Point( 6 3 )')))" << false << QVariant( "LineString (5 3, 6 3)" );
       QTest::newRow( "shortest_line not geom" ) << "shortest_line('g','a')" << true << QVariant();
       QTest::newRow( "shortest_line null" ) << "shortest_line(NULL,NULL)" << false << QVariant();
+      QTest::newRow( "transform invalid" ) << "transform(make_point(0,0),'EPSG:4326','EPSG:28356')" << false << QVariant();
 
       // string functions
       QTest::newRow( "lower" ) << "lower('HeLLo')" << false << QVariant( "hello" );
diff --git a/tests/src/core/testqgslabelingenginev2.cpp b/tests/src/core/testqgslabelingenginev2.cpp
index 9f70edf..c7dfed6 100644
--- a/tests/src/core/testqgslabelingenginev2.cpp
+++ b/tests/src/core/testqgslabelingenginev2.cpp
@@ -43,6 +43,7 @@ class TestQgsLabelingEngineV2 : public QObject
     void testRuleBased();
     void zOrder(); //test that labels are stacked correctly
     void testEncodeDecodePositionOrder();
+    void testCapitalization();
 
   private:
     QgsVectorLayer* vl;
@@ -413,6 +414,65 @@ void TestQgsLabelingEngineV2::testEncodeDecodePositionOrder()
   QCOMPARE( decoded, expected );
 }
 
+void TestQgsLabelingEngineV2::testCapitalization()
+{
+  QgsFeature f( vl->fields(), 1 );
+  f.setGeometry( QgsGeometry::fromPoint( QgsPoint( 1, 2 ) ) );
+
+  // make a fake render context
+  QSize size( 640, 480 );
+  QgsMapSettings mapSettings;
+  mapSettings.setOutputSize( size );
+  mapSettings.setExtent( vl->extent() );
+  mapSettings.setLayers( QStringList() << vl->id() );
+  mapSettings.setOutputDpi( 96 );
+  QgsRenderContext context = QgsRenderContext::fromMapSettings( mapSettings );
+  QStringList attributes;
+  QgsLabelingEngineV2 engine;
+  engine.setMapSettings( mapSettings );
+
+  // no change
+  QgsPalLayerSettings settings;
+  QFont font = settings.textFont;
+  font.setCapitalization( QFont::MixedCase );
+  settings.textFont = font;
+  settings.fieldName = QString( "'a teSt LABEL'" );
+  settings.isExpression = true;
+
+  QgsVectorLayerLabelProvider* provider = new QgsVectorLayerLabelProvider( vl, true, &settings );
+  engine.addProvider( provider );
+  provider->prepare( context, attributes );
+  provider->registerFeature( f, context );
+  QCOMPARE( provider->mLabels.at( 0 )->labelText(), QString( "a teSt LABEL" ) );
+
+  //uppercase
+  font.setCapitalization( QFont::AllUppercase );
+  settings.textFont = font;
+  QgsVectorLayerLabelProvider* provider2 = new QgsVectorLayerLabelProvider( vl, true, &settings );
+  engine.addProvider( provider2 );
+  provider2->prepare( context, attributes );
+  provider2->registerFeature( f, context );
+  QCOMPARE( provider2->mLabels.at( 0 )->labelText(), QString( "A TEST LABEL" ) );
+
+  //lowercase
+  font.setCapitalization( QFont::AllLowercase );
+  settings.textFont = font;
+  QgsVectorLayerLabelProvider* provider3 = new QgsVectorLayerLabelProvider( vl, true, &settings );
+  engine.addProvider( provider3 );
+  provider3->prepare( context, attributes );
+  provider3->registerFeature( f, context );
+  QCOMPARE( provider3->mLabels.at( 0 )->labelText(), QString( "a test label" ) );
+
+  //first letter uppercase
+  font.setCapitalization( QFont::Capitalize );
+  settings.textFont = font;
+  QgsVectorLayerLabelProvider* provider4 = new QgsVectorLayerLabelProvider( vl, true, &settings );
+  engine.addProvider( provider4 );
+  provider4->prepare( context, attributes );
+  provider4->registerFeature( f, context );
+  QCOMPARE( provider4->mLabels.at( 0 )->labelText(), QString( "A TeSt LABEL" ) );
+}
+
 bool TestQgsLabelingEngineV2::imageCheck( const QString& testName, QImage &image, int mismatchCount )
 {
   //draw background
diff --git a/tests/src/core/testqgslegendrenderer.cpp b/tests/src/core/testqgslegendrenderer.cpp
index 7d9e251..f6820e8 100644
--- a/tests/src/core/testqgslegendrenderer.cpp
+++ b/tests/src/core/testqgslegendrenderer.cpp
@@ -115,6 +115,8 @@ class TestQgsLegendRenderer : public QObject
     void testThreeColumns();
     void testFilterByMap();
     void testFilterByMapSameSymbol();
+    void testColumns_data();
+    void testColumns();
     void testRasterBorder();
     void testFilterByPolygon();
     void testFilterByExpression();
@@ -126,6 +128,7 @@ class TestQgsLegendRenderer : public QObject
     QgsVectorLayer* mVL3; // point
     QgsRasterLayer* mRL;
     QString mReport;
+    bool _testLegendColumns( int itemCount, int columnCount, const QString& testName );
 };
 
 
@@ -448,6 +451,65 @@ void TestQgsLegendRenderer::testFilterByMapSameSymbol()
   QgsMapLayerRegistry::instance()->removeMapLayer( vl4 );
 }
 
+bool TestQgsLegendRenderer::_testLegendColumns( int itemCount, int columnCount, const QString& testName )
+{
+  QgsFillSymbolV2* sym = new QgsFillSymbolV2();
+  sym->setColor( Qt::cyan );
+
+  QgsLayerTreeGroup* root = new QgsLayerTreeGroup();
+
+  QList< QgsVectorLayer* > layers;
+  for ( int i = 1; i <= itemCount; ++i )
+  {
+    QgsVectorLayer* vl = new QgsVectorLayer( "Polygon", QString( "Layer %1" ).arg( i ), "memory" );
+    QgsMapLayerRegistry::instance()->addMapLayer( vl );
+    vl->setRendererV2( new QgsSingleSymbolRendererV2( sym->clone() ) );
+    root->addLayer( vl );
+    layers << vl;
+  }
+  delete sym;
+
+  QgsLayerTreeModel legendModel( root );
+  QgsLegendSettings settings;
+  settings.setColumnCount( columnCount );
+  _setStandardTestFont( settings, "Bold" );
+  _renderLegend( testName, &legendModel, settings );
+  bool result = _verifyImage( testName, mReport );
+
+  Q_FOREACH ( QgsVectorLayer* l, layers )
+  {
+    QgsMapLayerRegistry::instance()->removeMapLayer( l );
+  }
+  return result;
+}
+
+void TestQgsLegendRenderer::testColumns_data()
+{
+  QTest::addColumn<QString>( "testName" );
+  QTest::addColumn<int>( "items" );
+  QTest::addColumn<int>( "columns" );
+
+  QTest::newRow( "2 items, 2 columns" ) << "legend_2_by_2" << 2 << 2;
+  QTest::newRow( "3 items, 2 columns" ) << "legend_3_by_2" << 3 << 2;
+  QTest::newRow( "4 items, 2 columns" ) << "legend_4_by_2" << 4 << 2;
+  QTest::newRow( "5 items, 2 columns" ) << "legend_5_by_2" << 5 << 2;
+  QTest::newRow( "3 items, 3 columns" ) << "legend_3_by_3" << 3 << 3;
+  QTest::newRow( "4 items, 3 columns" ) << "legend_4_by_3" << 4 << 3;
+  QTest::newRow( "5 items, 3 columns" ) << "legend_5_by_3" << 5 << 3;
+  QTest::newRow( "6 items, 3 columns" ) << "legend_6_by_3" << 6 << 3;
+  QTest::newRow( "7 items, 3 columns" ) << "legend_7_by_3" << 7 << 3;
+}
+
+void TestQgsLegendRenderer::testColumns()
+{
+  //test rendering legend with different combinations of columns and items
+
+  QFETCH( QString, testName );
+  QFETCH( int, items );
+  QFETCH( int, columns );
+  QVERIFY( _testLegendColumns( items, columns, testName ) );
+}
+
 void TestQgsLegendRenderer::testRasterBorder()
 {
   QString testName = "legend_raster_border";
diff --git a/tests/src/python/test_provider_ogr_gpkg.py b/tests/src/python/test_provider_ogr_gpkg.py
new file mode 100644
index 0000000..b746135
--- /dev/null
+++ b/tests/src/python/test_provider_ogr_gpkg.py
@@ -0,0 +1,164 @@
+# -*- coding: utf-8 -*-
+"""QGIS Unit tests for the OGR/GPKG provider.
+
+.. 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__ = 'Even Rouault'
+__date__ = '2016-04-21'
+__copyright__ = 'Copyright 2016, Even Rouault'
+# This will get replaced with a git SHA1 when you do a git archive
+__revision__ = '$Format:%H$'
+
+import qgis  # NOQA
+
+import os
+import tempfile
+import shutil
+import glob
+from osgeo import gdal, ogr
+
+from qgis.core import QgsVectorLayer, QgsFeature, QgsGeometry, QgsFeatureRequest
+from qgis.testing import start_app, unittest
+from utilities import unitTestDataPath
+
+start_app()
+
+
+def GDAL_COMPUTE_VERSION(maj, min, rev):
+    return ((maj) * 1000000 + (min) * 10000 + (rev) * 100)
+
+
+class ErrorReceiver():
+
+    def __init__(self):
+        self.msg = None
+
+    def receiveError(self, msg):
+        self.msg = msg
+
+
+class TestPyQgsOGRProviderGpkg(unittest.TestCase):
+
+    @classmethod
+    def setUpClass(cls):
+        """Run before all tests"""
+        # Create test layer
+        cls.basetestpath = tempfile.mkdtemp()
+
+    @classmethod
+    def tearDownClass(cls):
+        """Run after all tests"""
+        shutil.rmtree(cls.basetestpath, True)
+
+    def XXXXtestSingleToMultiPolygonPromotion(self):
+
+        tmpfile = os.path.join(self.basetestpath, 'testSingleToMultiPolygonPromotion.gpkg')
+        ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile)
+        lyr = ds.CreateLayer('test', geom_type=ogr.wkbMultiPolygon)
+        ds = None
+
+        vl = QgsVectorLayer(u'{}|layerid=0'.format(tmpfile), u'test', u'ogr')
+        f = QgsFeature()
+        f.setGeometry(QgsGeometry.fromWkt('POLYGON ((0 0,0 1,1 1,0 0))'))
+        vl.dataProvider().addFeatures([f])
+        got = [f for f in vl.getFeatures()][0]
+        got_geom = got.geometry()
+        reference = QgsGeometry.fromWkt('MultiPolygon (((0 0, 0 1, 1 1, 0 0)))')
+        # The geometries must be binarily identical
+        self.assertEqual(got_geom.asWkb(), reference.asWkb(), 'Expected {}, got {}'.format(reference.exportToWkt(), got_geom.exportToWkt()))
+
+    def XXXXtestCurveGeometryType(self):
+        if int(gdal.VersionInfo('VERSION_NUM')) < GDAL_COMPUTE_VERSION(2, 0, 0):
+            return
+
+        tmpfile = os.path.join(self.basetestpath, 'testCurveGeometryType.gpkg')
+        ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile)
+        lyr = ds.CreateLayer('test', geom_type=ogr.wkbCurvePolygon)
+        ds = None
+
+        vl = QgsVectorLayer(u'{}'.format(tmpfile), u'test', u'ogr')
+        self.assertEqual(vl.dataProvider().subLayers(), [u'0:test:0:CurvePolygon'])
+        f = QgsFeature()
+        f.setGeometry(QgsGeometry.fromWkt('POLYGON ((0 0,0 1,1 1,0 0))'))
+        vl.dataProvider().addFeatures([f])
+        got = [f for f in vl.getFeatures()][0]
+        got_geom = got.geometry()
+        reference = QgsGeometry.fromWkt('CurvePolygon (((0 0, 0 1, 1 1, 0 0)))')
+        # The geometries must be binarily identical
+        self.assertEqual(got_geom.asWkb(), reference.asWkb(), 'Expected {}, got {}'.format(reference.exportToWkt(), got_geom.exportToWkt()))
+
+    def internalTestBug15351(self, orderClosing):
+
+        tmpfile = os.path.join(self.basetestpath, 'testBug15351.gpkg')
+        ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile)
+        lyr = ds.CreateLayer('test', geom_type=ogr.wkbPoint)
+        f = ogr.Feature(lyr.GetLayerDefn())
+        f.SetGeometry(ogr.CreateGeometryFromWkt('POINT(0 0)'))
+        lyr.CreateFeature(f)
+        f = None
+        ds = None
+
+        vl = QgsVectorLayer(u'{}'.format(tmpfile), u'test', u'ogr')
+        self.assertTrue(vl.startEditing())
+        self.assertTrue(vl.changeGeometry(1, QgsGeometry.fromWkt('Point (3 50)')))
+
+        # Iterate over features (will open a new OGR connection), but do not
+        # close the iterator for now
+        it = vl.getFeatures()
+        f = QgsFeature()
+        it.nextFeature(f)
+
+        if orderClosing == 'closeIter_commit_closeProvider':
+            it = None
+
+        # Commit changes
+        cbk = ErrorReceiver()
+        vl.dataProvider().raiseError.connect(cbk.receiveError)
+        self.assertTrue(vl.commitChanges())
+        self.assertIsNone(cbk.msg)
+
+        # Close layer and iterator in different orders
+        if orderClosing == 'closeIter_commit_closeProvider':
+            vl = None
+        elif orderClosing == 'commit_closeProvider_closeIter':
+            vl = None
+            it = None
+        else:
+            assert orderClosing == 'commit_closeIter_closeProvider'
+            it = None
+            vl = None
+
+        # Test that we succeeded restoring default journal mode, and we
+        # are not let in WAL mode.
+        ds = ogr.Open(tmpfile)
+        lyr = ds.ExecuteSQL('PRAGMA journal_mode')
+        f = lyr.GetNextFeature()
+        res = f.GetField(0)
+        ds.ReleaseResultSet(lyr)
+        ds = None
+        self.assertEqual(res, 'delete')
+
+    # We need GDAL 2.0 to issue PRAGMA journal_mode
+    # Note: for that case, we don't strictly need turning on WAL
+    def testBug15351_closeIter_commit_closeProvider(self):
+        if int(gdal.VersionInfo('VERSION_NUM')) < GDAL_COMPUTE_VERSION(2, 0, 0):
+            return
+        self.internalTestBug15351('closeIter_commit_closeProvider')
+
+    # We need GDAL 2.0 to issue PRAGMA journal_mode
+    def testBug15351_closeIter_commit_closeProvider(self):
+        if int(gdal.VersionInfo('VERSION_NUM')) < GDAL_COMPUTE_VERSION(2, 0, 0):
+            return
+        self.internalTestBug15351('closeIter_commit_closeProvider')
+
+    # We need GDAL 2.0 to issue PRAGMA journal_mode
+    def testBug15351_commit_closeIter_closeProvider(self):
+        if int(gdal.VersionInfo('VERSION_NUM')) < GDAL_COMPUTE_VERSION(2, 0, 0):
+            return
+        self.internalTestBug15351('commit_closeIter_closeProvider')
+
+if __name__ == '__main__':
+    unittest.main()
diff --git a/tests/src/python/test_provider_virtual.py b/tests/src/python/test_provider_virtual.py
index 6ed2a72..7a4fe0c 100644
--- a/tests/src/python/test_provider_virtual.py
+++ b/tests/src/python/test_provider_virtual.py
@@ -738,6 +738,20 @@ class TestQgsVirtualLayerProvider(unittest.TestCase, ProviderTestCase):
         ids = [f.id() for f in vl2.getFeatures()]
         self.assertEqual(ids, [])
 
+    def test_layer_with_accents(self):
+        l1 = QgsVectorLayer(os.path.join(self.testDataDir, "france_parts.shp"), u"françéà", "ogr", False)
+        self.assertEqual(l1.isValid(), True)
+        QgsMapLayerRegistry.instance().addMapLayer(l1)
+
+        df = QgsVirtualLayerDefinition()
+        df.setQuery(u'select * from "françéà"')
+
+        vl = QgsVectorLayer(df.toString(), "testq", "virtual")
+        self.assertEqual(vl.isValid(), True)
+        ids = [f.id() for f in vl.getFeatures()]
+        self.assertEqual(len(ids), 4)
+
+        QgsMapLayerRegistry.instance().removeMapLayer(l1.id())
 
 if __name__ == '__main__':
     unittest.main()
diff --git a/tests/src/python/test_qgsfeatureiterator.py b/tests/src/python/test_qgsfeatureiterator.py
index 19f25c1..034d0a8 100644
--- a/tests/src/python/test_qgsfeatureiterator.py
+++ b/tests/src/python/test_qgsfeatureiterator.py
@@ -15,7 +15,7 @@ __revision__ = '$Format:%H$'
 import qgis
 import os
 
-from qgis.core import QgsVectorLayer, QgsFeatureRequest, QgsFeature, QgsField, NULL
+from qgis.core import QgsVectorLayer, QgsFeatureRequest, QgsFeature, QgsField, QgsMapLayerRegistry, QgsVectorJoinInfo, NULL
 from qgis.testing import (start_app,
                           unittest
                           )
@@ -23,6 +23,7 @@ from PyQt4.QtCore import QVariant
 from utilities import (unitTestDataPath,
                        compareWkt
                        )
+
 start_app()
 TEST_DATA_DIR = unitTestDataPath()
 
@@ -155,6 +156,91 @@ class TestQgsFeatureIterator(unittest.TestCase):
         fet = next(layer.getFeatures(QgsFeatureRequest().setSubsetOfAttributes(['exp2'], layer.fields())))
         self.assertEqual(fet['Class'], NULL)
 
+    def test_JoinUsingExpression(self):
+        """ test joining a layer using a virtual field """
+        joinLayer = QgsVectorLayer(
+            "Point?field=x:string&field=y:integer&field=z:integer",
+            "joinlayer", "memory")
+        pr = joinLayer.dataProvider()
+        f1 = QgsFeature()
+        f1.setAttributes(["foo", 246, 321])
+        f2 = QgsFeature()
+        f2.setAttributes(["bar", 456, 654])
+        self.assertTrue(pr.addFeatures([f1, f2]))
+
+        layer = QgsVectorLayer("Point?field=fldtxt:string&field=fldint:integer",
+                               "addfeat", "memory")
+        pr = layer.dataProvider()
+        f = QgsFeature()
+        f.setAttributes(["test", 123])
+        self.assertTrue(pr.addFeatures([f]))
+        layer.addExpressionField('"fldint"*2', QgsField('exp1', QVariant.LongLong))
+
+        QgsMapLayerRegistry.instance().addMapLayers([layer, joinLayer])
+
+        join = QgsVectorJoinInfo()
+        join.targetFieldName = "exp1"
+        join.joinLayerId = joinLayer.id()
+        join.joinFieldName = "y"
+        join.memoryCache = True
+        layer.addJoin(join)
+
+        f = QgsFeature()
+        fi = layer.getFeatures()
+        self.assertTrue(fi.nextFeature(f))
+        attrs = f.attributes()
+        self.assertEqual(attrs[0], "test")
+        self.assertEqual(attrs[1], 123)
+        self.assertEqual(attrs[2], "foo")
+        self.assertEqual(attrs[3], 321)
+        self.assertEqual(attrs[4], 246)
+        self.assertFalse(fi.nextFeature(f))
+
+        QgsMapLayerRegistry.instance().removeMapLayers([layer, joinLayer])
+
+    def test_JoinUsingExpression2(self):
+        """ test joining a layer using a virtual field (the other way!) """
+        joinLayer = QgsVectorLayer(
+            "Point?field=x:string&field=y:integer&field=z:integer",
+            "joinlayer", "memory")
+        pr = joinLayer.dataProvider()
+        f1 = QgsFeature()
+        f1.setAttributes(["foo", 246, 321])
+        f2 = QgsFeature()
+        f2.setAttributes(["bar", 456, 654])
+        self.assertTrue(pr.addFeatures([f1, f2]))
+        joinLayer.addExpressionField('"y"/2', QgsField('exp1', QVariant.LongLong))
+
+        layer = QgsVectorLayer("Point?field=fldtxt:string&field=fldint:integer",
+                               "addfeat", "memory")
+        pr = layer.dataProvider()
+        f = QgsFeature()
+        f.setAttributes(["test", 123])
+        self.assertTrue(pr.addFeatures([f]))
+
+        QgsMapLayerRegistry.instance().addMapLayers([layer, joinLayer])
+
+        join = QgsVectorJoinInfo()
+        join.targetFieldName = "fldint"
+        join.joinLayerId = joinLayer.id()
+        join.joinFieldName = "exp1"
+        join.memoryCache = True
+        layer.addJoin(join)
+
+        f = QgsFeature()
+        fi = layer.getFeatures()
+        self.assertTrue(fi.nextFeature(f))
+        attrs = f.attributes()
+        self.assertEqual(attrs[0], "test")
+        self.assertEqual(attrs[1], 123)
+        self.assertEqual(attrs[2], "foo")
+        self.assertEqual(attrs[3], 246)
+        self.assertEqual(attrs[4], 321)
+        self.assertFalse(fi.nextFeature(f))
+
+        QgsMapLayerRegistry.instance().removeMapLayers([layer, joinLayer])
+        # try the other way too
+
 
 if __name__ == '__main__':
     unittest.main()
diff --git a/tests/testdata/control_images/legend/expected_legend_2_by_2/expected_legend_2_by_2.png b/tests/testdata/control_images/legend/expected_legend_2_by_2/expected_legend_2_by_2.png
new file mode 100644
index 0000000..33fce22
Binary files /dev/null and b/tests/testdata/control_images/legend/expected_legend_2_by_2/expected_legend_2_by_2.png differ
diff --git a/tests/testdata/control_images/legend/expected_legend_2_by_2/expected_legend_2_by_2_mask.png b/tests/testdata/control_images/legend/expected_legend_2_by_2/expected_legend_2_by_2_mask.png
new file mode 100644
index 0000000..b2f5f23
Binary files /dev/null and b/tests/testdata/control_images/legend/expected_legend_2_by_2/expected_legend_2_by_2_mask.png differ
diff --git a/tests/testdata/control_images/legend/expected_legend_3_by_2/expected_legend_3_by_2.png b/tests/testdata/control_images/legend/expected_legend_3_by_2/expected_legend_3_by_2.png
new file mode 100644
index 0000000..925aa73
Binary files /dev/null and b/tests/testdata/control_images/legend/expected_legend_3_by_2/expected_legend_3_by_2.png differ
diff --git a/tests/testdata/control_images/legend/expected_legend_3_by_2/expected_legend_3_by_2_mask.png b/tests/testdata/control_images/legend/expected_legend_3_by_2/expected_legend_3_by_2_mask.png
new file mode 100644
index 0000000..26a6e24
Binary files /dev/null and b/tests/testdata/control_images/legend/expected_legend_3_by_2/expected_legend_3_by_2_mask.png differ
diff --git a/tests/testdata/control_images/legend/expected_legend_3_by_3/expected_legend_3_by_3.png b/tests/testdata/control_images/legend/expected_legend_3_by_3/expected_legend_3_by_3.png
new file mode 100644
index 0000000..0273549
Binary files /dev/null and b/tests/testdata/control_images/legend/expected_legend_3_by_3/expected_legend_3_by_3.png differ
diff --git a/tests/testdata/control_images/legend/expected_legend_3_by_3/expected_legend_3_by_3_mask.png b/tests/testdata/control_images/legend/expected_legend_3_by_3/expected_legend_3_by_3_mask.png
new file mode 100644
index 0000000..619c13d
Binary files /dev/null and b/tests/testdata/control_images/legend/expected_legend_3_by_3/expected_legend_3_by_3_mask.png differ
diff --git a/tests/testdata/control_images/legend/expected_legend_4_by_2/expected_legend_4_by_2.png b/tests/testdata/control_images/legend/expected_legend_4_by_2/expected_legend_4_by_2.png
new file mode 100644
index 0000000..a3e7fb3
Binary files /dev/null and b/tests/testdata/control_images/legend/expected_legend_4_by_2/expected_legend_4_by_2.png differ
diff --git a/tests/testdata/control_images/legend/expected_legend_4_by_2/expected_legend_4_by_2_mask.png b/tests/testdata/control_images/legend/expected_legend_4_by_2/expected_legend_4_by_2_mask.png
new file mode 100644
index 0000000..5f83169
Binary files /dev/null and b/tests/testdata/control_images/legend/expected_legend_4_by_2/expected_legend_4_by_2_mask.png differ
diff --git a/tests/testdata/control_images/legend/expected_legend_4_by_3/expected_legend_4_by_3.png b/tests/testdata/control_images/legend/expected_legend_4_by_3/expected_legend_4_by_3.png
new file mode 100644
index 0000000..c1e72c6
Binary files /dev/null and b/tests/testdata/control_images/legend/expected_legend_4_by_3/expected_legend_4_by_3.png differ
diff --git a/tests/testdata/control_images/legend/expected_legend_4_by_3/expected_legend_4_by_3_mask.png b/tests/testdata/control_images/legend/expected_legend_4_by_3/expected_legend_4_by_3_mask.png
new file mode 100644
index 0000000..eb17139
Binary files /dev/null and b/tests/testdata/control_images/legend/expected_legend_4_by_3/expected_legend_4_by_3_mask.png differ
diff --git a/tests/testdata/control_images/legend/expected_legend_5_by_2/expected_legend_5_by_2.png b/tests/testdata/control_images/legend/expected_legend_5_by_2/expected_legend_5_by_2.png
new file mode 100644
index 0000000..e61cb2f
Binary files /dev/null and b/tests/testdata/control_images/legend/expected_legend_5_by_2/expected_legend_5_by_2.png differ
diff --git a/tests/testdata/control_images/legend/expected_legend_5_by_2/expected_legend_5_by_2_mask.png b/tests/testdata/control_images/legend/expected_legend_5_by_2/expected_legend_5_by_2_mask.png
new file mode 100644
index 0000000..b7c9aa4
Binary files /dev/null and b/tests/testdata/control_images/legend/expected_legend_5_by_2/expected_legend_5_by_2_mask.png differ
diff --git a/tests/testdata/control_images/legend/expected_legend_5_by_3/expected_legend_5_by_3.png b/tests/testdata/control_images/legend/expected_legend_5_by_3/expected_legend_5_by_3.png
new file mode 100644
index 0000000..56f1db3
Binary files /dev/null and b/tests/testdata/control_images/legend/expected_legend_5_by_3/expected_legend_5_by_3.png differ
diff --git a/tests/testdata/control_images/legend/expected_legend_5_by_3/expected_legend_5_by_3_mask.png b/tests/testdata/control_images/legend/expected_legend_5_by_3/expected_legend_5_by_3_mask.png
new file mode 100644
index 0000000..8fabd8d
Binary files /dev/null and b/tests/testdata/control_images/legend/expected_legend_5_by_3/expected_legend_5_by_3_mask.png differ
diff --git a/tests/testdata/control_images/legend/expected_legend_6_by_3/expected_legend_6_by_3.png b/tests/testdata/control_images/legend/expected_legend_6_by_3/expected_legend_6_by_3.png
new file mode 100644
index 0000000..26155b3
Binary files /dev/null and b/tests/testdata/control_images/legend/expected_legend_6_by_3/expected_legend_6_by_3.png differ
diff --git a/tests/testdata/control_images/legend/expected_legend_6_by_3/expected_legend_6_by_3_mask.png b/tests/testdata/control_images/legend/expected_legend_6_by_3/expected_legend_6_by_3_mask.png
new file mode 100644
index 0000000..0228bfc
Binary files /dev/null and b/tests/testdata/control_images/legend/expected_legend_6_by_3/expected_legend_6_by_3_mask.png differ
diff --git a/tests/testdata/control_images/legend/expected_legend_7_by_3/expected_legend_7_by_3.png b/tests/testdata/control_images/legend/expected_legend_7_by_3/expected_legend_7_by_3.png
new file mode 100644
index 0000000..bae0e2f
Binary files /dev/null and b/tests/testdata/control_images/legend/expected_legend_7_by_3/expected_legend_7_by_3.png differ
diff --git a/tests/testdata/control_images/legend/expected_legend_7_by_3/expected_legend_7_by_3_mask.png b/tests/testdata/control_images/legend/expected_legend_7_by_3/expected_legend_7_by_3_mask.png
new file mode 100644
index 0000000..63ef7e9
Binary files /dev/null and b/tests/testdata/control_images/legend/expected_legend_7_by_3/expected_legend_7_by_3_mask.png differ

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