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

Bas Couwenberg sebastic at debian.org
Sat Jan 20 14:42:55 UTC 2018


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

sebastic pushed a commit to branch upstream
in repository qgis.

commit 292915741040747b940b8b3f389a3027f7fd8ebd
Author: Bas Couwenberg <sebastic at xs4all.nl>
Date:   Sat Jan 20 09:07:55 2018 +0100

    New upstream version 2.18.16+dfsg
---
 CMakeLists.txt                                     |   2 +-
 ChangeLog                                          | 267 +++++++++++++++++++++
 debian/changelog                                   |  10 +-
 debian/compat.in                                   |   2 +-
 debian/control.in                                  |  27 ++-
 debian/python-qgis.install.in                      |   4 +-
 debian/qgis-providers.install.in                   |   4 +-
 debian/rules                                       |   6 +-
 doc/TRANSLATORS                                    |  76 +++---
 i18n/qgis_de.ts                                    | 107 +++++++--
 i18n/qgis_fi.ts                                    |   2 +-
 i18n/qgis_fr.ts                                    |  73 +++---
 i18n/qgis_pl.ts                                    |  28 +--
 python/core/symbology-ng/qgsarrowsymbollayer.sip   |   2 +-
 python/gui/editorwidgets/qgsdatetimeedit.sip       |  12 +-
 python/plugins/MetaSearch/dialogs/maindialog.py    |   5 +-
 .../algs/grass7/description/v.segment.txt          |   2 +-
 .../plugins/processing/gui/ScriptEditorDialog.py   |  25 ++
 python/plugins/processing/images/search.png        | Bin 0 -> 2104 bytes
 python/plugins/processing/ui/DlgScriptEditor.ui    | 101 +++++++-
 src/analysis/raster/qgsalignraster.cpp             |   2 +-
 src/app/qgsbookmarks.cpp                           | 113 +++++----
 src/app/qgsbookmarks.h                             |   8 +-
 src/app/qgsmaptoolreshape.cpp                      | 154 ++++++++----
 src/app/qgsmaptoolreshape.h                        |   7 +
 src/app/qgsoptions.cpp                             |   3 +-
 src/app/qgsversioninfo.cpp                         |   2 +-
 src/core/qgsdataitem.cpp                           |  33 ++-
 src/core/qgsmaprendererjob.h                       |   2 +-
 src/core/qgsofflineediting.cpp                     |   2 +-
 src/core/symbology-ng/qgsarrowsymbollayer.h        |   2 +-
 src/gui/editorwidgets/qgsdatetimeedit.cpp          | 176 ++++++++++++--
 src/gui/editorwidgets/qgsdatetimeedit.h            |  14 +-
 src/gui/editorwidgets/qgsdatetimeeditconfig.cpp    |  59 +++--
 src/gui/editorwidgets/qgsdatetimeeditfactory.h     |   3 +
 src/gui/editorwidgets/qgsdatetimeeditwrapper.cpp   | 105 ++++++--
 .../qgsdatetimesearchwidgetwrapper.cpp             |  11 +-
 .../editorwidgets/qgsrelationreferencewidget.cpp   |  25 +-
 .../qgsrelationreferencewidgetwrapper.cpp          |   2 +-
 .../qgsvaluerelationwidgetwrapper.cpp              |   2 +
 src/gui/qgsmaptoolcapture.cpp                      |   2 +-
 src/gui/qgsmaptoolcapture.h                        |   4 +-
 src/plugins/georeferencer/qgsimagewarper.cpp       |  19 +-
 src/plugins/grass/modules/r.in.wms.qgm             |   1 -
 .../oracle_raster/qgsselectgeoraster_ui.cpp        |   3 +-
 src/providers/gdal/qgsgdalprovider.cpp             |   2 +-
 src/providers/ogr/qgsogrprovider.cpp               | 191 ++++++++-------
 src/providers/ogr/qgsogrprovider.h                 |   3 +
 .../virtual/qgsvirtuallayersqlitemodule.cpp        |   2 +-
 src/providers/wcs/qgswcsprovider.cpp               |   2 +-
 src/ui/editorwidgets/qgsdatetimeeditconfig.ui      |  27 +--
 tests/src/app/CMakeLists.txt                       |   2 +
 tests/src/app/testqgsmaptoolreshape.cpp            | 150 ++++++++++++
 tests/src/gui/testqgsrelationreferencewidget.cpp   |  12 +
 tests/src/python/test_provider_ogr_gpkg.py         |  26 +-
 tests/src/python/test_provider_shapefile.py        |  24 ++
 tests/src/python/test_provider_virtual.py          |  24 ++
 tests/testdata/provider/bug_17795.gpkg             | Bin 0 -> 118784 bytes
 58 files changed, 1511 insertions(+), 463 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 2f9bf04..2e2ffe5 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,6 +1,6 @@
 SET(CPACK_PACKAGE_VERSION_MAJOR "2")
 SET(CPACK_PACKAGE_VERSION_MINOR "18")
-SET(CPACK_PACKAGE_VERSION_PATCH "15")
+SET(CPACK_PACKAGE_VERSION_PATCH "16")
 SET(COMPLETE_VERSION ${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH})
 SET(RELEASE_NAME "Las Palmas")
 IF (POLICY CMP0048) # in CMake 3.0.0+
diff --git a/ChangeLog b/ChangeLog
index 20572b6..6dc8bd0 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,270 @@
+Nyall Dawson <nyall.dawson at gmail.com>	2018-01-19
+
+    Fix virtual layers fail if table field names have special characters
+
+    Fixes #16943
+
+    Cherry-picked from 6c392124
+
+Alexander Bruy <alexander.bruy at gmail.com>	2018-01-15
+
+    [processing] update parameter name for v.segments (fix #17850)
+
+Alexander Bruy <alexander.bruy at gmail.com>	2018-01-15
+
+    remove duplicated parameter from r.in.wms module (fix #17815)
+
+    (cherry picked from commit b8518aef9cb7a514cc2c98a5b24e90cd27658a33)
+
+Juergen E. Fischer <jef at norbit.de>	2018-01-14
+
+    avoid including GDAL C++ api (fixes #17849)
+
+Juergen E. Fischer <jef at norbit.de>	2018-01-13
+
+    debian packaging: add bionic
+
+Merge: 028bca432f fe737913ee
+Alessandro Pasotti <elpaso at itopen.it>	2018-01-11
+
+    Merge pull request #6032 from stevenmizuno/followup_17673
+
+    Follow up #17673 Spatial Bookmarks fixes backport to 2.18
+
+Steven Mizuno <spookster at netzero.net>	2018-01-10
+
+    Qt4 doesn't have QStringLiteral
+
+Juergen E. Fischer <jef at norbit.de>	2018-01-10
+
+    german translation update
+
+Borys Jurgiel <info at borysjurgiel.pl>	2018-01-10
+
+    [tr] Polish translation update
+
+Juergen E. Fischer <jef at norbit.de>	2018-01-08
+
+    debian packaging: update dependency
+
+Steven Mizuno <spookster at netzero.net>	2018-01-03
+
+    forgot that this is not 'master'
+
+Steven Mizuno <spookster at netzero.net>	2018-01-01
+
+    refresh the list properly
+
+Steven Mizuno <spookster at netzero.net>	2018-01-01
+
+    fix bookmark deletion
+
+Steven Mizuno <spookster at netzero.net>	2018-01-01
+
+    fix export
+
+Steven Mizuno <spookster at netzero.net>	2018-01-01
+
+    change mModel to mMergedModel
+
+    to better reflect the purpose; fix object deletion
+
+Merge: 8127c4c61d 0f2a5203c9
+Alessandro Pasotti <elpaso at itopen.it>	2018-01-06
+
+    Merge pull request #6002 from elpaso/bugfix-17795-2-18-backport
+
+    [bugfix][ogr] Recompute capabilities when subsetfilter is set
+
+Alessandro Pasotti <elpaso at itopen.it>	2018-01-06
+
+    Indentation 2
+
+Alessandro Pasotti <elpaso at itopen.it>	2018-01-06
+
+    Indentation
+
+Alessandro Pasotti <elpaso at itopen.it>	2018-01-06
+
+    [bugfix][ogr] Recompute capabilities when subsetfilter is set
+
+    Backported from master PR 6000
+
+    Fixes #17795
+
+Juergen E. Fischer <jef at norbit.de>	2018-01-05
+
+    date time edit: reapply 718581ff reverted by a8e292df
+
+Denis Rouzaud <denis.rouzaud at gmail.com>	2018-01-04
+
+    fix warning
+
+Denis Rouzaud <denis.rouzaud at gmail.com>	2018-01-04
+
+    use appropriate field type in date time edit widget wrapper
+
+Matthias Kuhn <matthias at opengis.ch>	2018-01-04
+
+    Fix processing models with finnish translation
+
+    Reported in https://gis.stackexchange.com/questions/266819/error-with-graphical-modeler-qgis-not-all-arguments-converted-during-string-for
+
+Juergen E. Fischer <jef at norbit.de>	2018-01-04
+
+    2.18 is pre-C++-11 (followup 8e292dff8)
+
+Denis Rouzaud <denis.rouzaud at gmail.com>	2018-01-03
+
+    fix date/time widget does not handle time zones
+
+    issue #16657
+    manually picked from QGIS3 bdf744ee3f94b5fc1a84e775fedc60a75ba45dcb
+
+Juergen E. Fischer <jef at norbit.de>	2018-01-04
+
+    debian packaging: use libqscintilla2-qt4-dev on unstable
+
+Denis Rouzaud <denis.rouzaud at gmail.com>	2018-01-02
+
+    [date time widget] do not use minimumDateTime for NULL values
+
+Juergen E. Fischer <jef at norbit.de>	2018-01-02
+
+    fetch version.txt from version.qgis.org instead of ubuntu.qgis.org
+    (fixes #17774)
+
+Denis Rouzaud <denis.rouzaud at gmail.com>	2018-01-01
+
+    [date widget] fix current date can't be picked
+
+    better solution has been found for Qt5 but can't be used in Qt4
+    see #16579
+
+Tom Kralidis <tomkralidis at gmail.com>	2017-12-22
+
+    [bugfix] [MetaSearch] make gml:Envelope CRS explicit for spatial queries (fixes #17739)
+
+Juergen E. Fischer <jef at norbit.de>	2017-12-19
+
+    2.18 also uses Qt4 which doesn't have QStringLiteral (followup a122e023 and c71e55036)
+
+Juergen E. Fischer <jef at norbit.de>	2017-12-19
+
+    2.18 lives in pre-C++11 land (followup c71e55036)
+
+Merge: 327785379d 9b2320acf7
+Blottiere Paul <blottiere.paul at gmail.com>	2017-12-18
+
+    Merge pull request #5879 from pblottiere/refrelfilter_218
+
+    [bugfix]  Fixes auto select foreign key when filters are updated in QgsRelationReferenceWidget
+
+Merge: f4b007ec1a 0dd8db610b
+Blottiere Paul <blottiere.paul at gmail.com>	2017-12-18
+
+    Merge pull request #5869 from pblottiere/bugfix_reshape2_218
+
+    [backport][bugfix] Do not add binding line in both side in reshape map tool
+
+Blottiere Paul <blottiere.paul at gmail.com>	2017-12-15
+
+    Add some tests
+
+Blottiere Paul <blottiere.paul at gmail.com>	2017-12-15
+
+    Fixes auto select foreign key when filters are updated
+
+Blottiere Paul <blottiere.paul at gmail.com>	2017-12-15
+
+    Fix indentation
+
+Merge: 2ef6a8299f fd7fc94cc7
+Blottiere Paul <blottiere.paul at gmail.com>	2017-12-15
+
+    Merge pull request #5783 from pblottiere/ref_rel_perf_218
+
+    [2.18] QgsRelationReferenceWidget slowness
+
+Blottiere Paul <blottiere.paul at gmail.com>	2017-12-14
+
+    Add some tests
+
+Blottiere Paul <blottiere.paul at gmail.com>	2017-12-14
+
+    [bugfix]  Do not add binding line in both side in reshape map tool
+
+Blottiere Paul <blottiere.paul at gmail.com>	2017-12-13
+
+    Add cacheSize as a QSettings
+
+Blottiere Paul <blottiere.paul at gmail.com>	2017-12-01
+
+    Reduce functionality in case of a widget already embedded by the same relation
+
+Blottiere Paul <blottiere.paul at gmail.com>	2017-11-29
+
+    Do not search data in case of an invalid feature
+
+Blottiere Paul <blottiere.paul at gmail.com>	2017-11-29
+
+    Increase cache size
+
+Borys Jurgiel <info at borysjurgiel.pl>	2017-12-13
+
+    [tr] Polish translation update
+
+Merge: eacbdb9aca 05e6ec246f
+Alexander Bruy <alexander.bruy at gmail.com>	2017-12-13
+
+    Merge pull request #5860 from volaya/script_search
+
+    [FEATURE][processing][needs-docs]Script search
+
+Alexander Bruy <alexander.bruy at gmail.com>	2017-12-13
+
+    fix indentation
+
+volaya <volayaf at gmail.com>	2017-12-13
+
+    [processing] added search and replace functionality to script editor
+
+Juergen E. Fischer <jef at norbit.de>	2017-12-12
+
+    german translation update
+
+Juergen E. Fischer <jef at norbit.de>	2017-12-12
+
+    spelling fixes
+
+Harrissou Sant-anna <delazj at gmail.com>	2017-12-05
+
+    Fix some french translation
+
+Frank Dekervel <kervel at gmail.com>	2017-12-09
+
+    Fix missing signal/slot connection resulting in non-woring autocompleter for value relation fields (fixes #16676). (#5821)
+
+    Backported from d7b08c78faeda9b35882f89913990a253d3b1ab8
+
+Merge: ac2d111ed1 e86c4e29dc
+Alessandro Pasotti <elpaso at itopen.it>	2017-12-08
+
+    Merge pull request #5829 from cjmayo/fix-xml-bookmarks-2.18
+
+    Fix bookmarks import and export menu items
+
+Chris Mayo <aklhfex at gmail.com>	2017-12-08
+
+    Fix bookmarks import and export menu items
+
+    Method names were changed by 89d52e5d426717cc ("[bugfix] Various
+    Bookmarks issues backported").
+
+Juergen E. Fischer <jef at norbit.de>	2017-12-08
+
+    Release of 2.18.15
+
 Merge: bfe03370ae 89d52e5d42
 Alessandro Pasotti <elpaso at itopen.it>	2017-12-06
 
diff --git a/debian/changelog b/debian/changelog
index 566edd0..317d87e 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,8 +1,14 @@
-qgis (2.18.15) UNRELEASED; urgency=medium
+qgis (2.18.16) UNRELEASED; urgency=medium
+
+  * Release of 2.18.16
+
+ -- Jürgen E. Fischer <jef at norbit.de>  Fri, 19 Jan 2018 14:13:44 +0100
+
+qgis (2.18.15) unstable; urgency=medium
 
   * Release of 2.18.15
 
- -- Jürgen E. Fischer <jef at norbit.de>  Fri, 08 Dec 2017 14:00:24 +0100
+ -- Jürgen E. Fischer <jef at norbit.de>  Fri, 19 Jan 2018 14:13:44 +0100
 
 qgis (2.18.14) unstable; urgency=medium
 
diff --git a/debian/compat.in b/debian/compat.in
index 1b5bad5..2296ba3 100644
--- a/debian/compat.in
+++ b/debian/compat.in
@@ -1,2 +1,2 @@
-#stretch sid jessie trusty xenial yakkety zesty artful#9
+#stretch sid jessie trusty xenial yakkety zesty artful bionic#9
 #jessie#8
diff --git a/debian/control.in b/debian/control.in
index b5d1534..114c4a6 100644
--- a/debian/control.in
+++ b/debian/control.in
@@ -15,8 +15,6 @@ Build-Depends:
  gdal-bin,
  python-gdal,
  libgeos-dev (>= 3.0.0),
-#    jessie         trusty                            # libgsl0-dev,
-#sid        stretch        xenial yakkety zesty artful# libgsl-dev,
  libpq-dev,
  libproj-dev,
  libqt4-dev (>= 4.7.0),
@@ -24,8 +22,10 @@ Build-Depends:
  libqca2-dev,
  libqca2-plugin-ossl,
  libqtwebkit-dev,
-#    jessie stretch                                   # libqwt-dev,
-#sid                trusty xenial yakkety zesty artful# libqwt5-qt4-dev,
+#    jessie         trusty                                   # libgsl0-dev, libqca2-plugin-ossl,
+#sid        stretch        xenial yakkety zesty artful bionic# libgsl-dev, libqca2-plugins,
+#    jessie stretch                                          # libqwt-dev,
+#sid                trusty xenial yakkety zesty artful bionic# libqwt5-qt4-dev,
  libqjson-dev,
  libspatialite-dev,
  libsqlite3-dev,
@@ -38,12 +38,13 @@ Build-Depends:
  python-qt4-sql,
  python-yaml, python-mock,
  python-all (>= 2.6.6-3~), python-all-dev (>= 2.6.6-3~), python-pyspatialite,
-#sid        stretch        xenial yakkety zesty artful# python-future,
-#sid jessie stretch        xenial yakkety zesty artful# pyqt4.qsci-dev, python-nose2,
+#sid        stretch        xenial yakkety zesty artful bionic# python-future,
+#sid jessie stretch        xenial yakkety zesty artful bionic# pyqt4.qsci-dev, python-nose2,
  python-sip (>= 4.5.0),
  python-sip-dev (>= 4.5.0),
  libosgearth-dev,
- libqscintilla2-dev,
+#    jessie stretch trusty xenial yakkety zesty artful bionic# libqscintilla2-dev,
+#sid                                                         # libqscintilla2-qt4-dev,
  git,
  doxygen,
  graphviz,
@@ -55,11 +56,11 @@ Build-Depends:
  qt4-dev-tools,
  libqt4-sql-sqlite, python-psycopg2, ca-certificates
 Build-Conflicts: libqgis-dev, qgis-dev
-#sid stretch xenial yakkety zesty artful#Standards-Version: 3.9.7
+#sid stretch xenial yakkety zesty artful bionic#Standards-Version: 3.9.7
 #jessie#Standards-Version: 3.9.6
 #trusty#Standards-Version: 3.8.4
 #sid stretch jessie#X-Python-Version: >= 2.7, << 2.8
-#trusty xenial yakkety zesty artful#XS-Python-Version: current
+#trusty xenial yakkety zesty artful bionic#XS-Python-Version: current
 Vcs-Browser: https://github.com/qgis/QGIS/
 Vcs-Git: https://github.com/qgis/QGIS.git
 Homepage: http://qgis.org/
@@ -234,8 +235,8 @@ Depends:
  libexpat1-dev,
  libgdal-dev (>= 1.10.1-0~),
  libgeos-dev (>= 3.0.0),
-#    jessie         trusty                            # libgsl0-dev,
-#sid        stretch        xenial yakkety zesty artful# libgsl-dev,
+#    jessie         trusty                                   # libgsl0-dev,
+#sid        stretch        xenial yakkety zesty artful bionic# libgsl-dev,
  libpq-dev,
  libproj-dev,
  libqgis-app{QGIS_ABI} (= ${binary:Version}),
@@ -372,8 +373,8 @@ Depends:
  python-pyproj,
  python-six,
  python-pyspatialite,
-#sid stretch               xenial yakkety zesty artful# python-future,
-#sid stretch jessie        xenial yakkety zesty artful# python-markupsafe, python-dateutil, python-yaml, python-owslib,
+#sid stretch               xenial yakkety zesty artful bionic# python-future,
+#sid stretch jessie        xenial yakkety zesty artful bionic# python-markupsafe, python-dateutil, python-yaml, python-owslib,
  libqgispython{QGIS_ABI},
  ${shlibs:Depends},
  ${python:Depends},
diff --git a/debian/python-qgis.install.in b/debian/python-qgis.install.in
index 54b9c8e..7983d25 100644
--- a/debian/python-qgis.install.in
+++ b/debian/python-qgis.install.in
@@ -7,5 +7,5 @@ usr/lib/python*/*-packages/qgis/networkanalysis/*
 usr/lib/python*/*-packages/qgis/PyQt/*
 usr/lib/python*/*-packages/qgis/server/*
 usr/lib/python*/*-packages/qgis/testing/*
-#sid stretch yakkety zesty artful#usr/lib/python*/*-packages/PyQt4/*.so
-#sid stretch yakkety zesty artful#usr/lib/python*/*-packages/PyQt4/uic/widget-plugins/qtwebkit.py
+#sid stretch yakkety zesty artful bionic#usr/lib/python*/*-packages/PyQt4/*.so
+#sid stretch yakkety zesty artful bionic#usr/lib/python*/*-packages/PyQt4/uic/widget-plugins/qtwebkit.py
diff --git a/debian/qgis-providers.install.in b/debian/qgis-providers.install.in
index 3877c1f..037d5a7 100644
--- a/debian/qgis-providers.install.in
+++ b/debian/qgis-providers.install.in
@@ -17,6 +17,6 @@ usr/lib/qgis/plugins/libvirtuallayerprovider.so
 usr/lib/qgis/plugins/libwcsprovider.so
 usr/lib/qgis/plugins/libwfsprovider.so
 usr/lib/qgis/plugins/libwmsprovider.so
-#sid stretch jessie trusty xenial yakkety zesty artful#usr/lib/qgis/plugins/libarcgismapserverprovider.so
-#sid stretch jessie trusty xenial yakkety zesty artful#usr/lib/qgis/plugins/libarcgisfeatureserverprovider.so
+#sid stretch jessie trusty xenial yakkety zesty artful bionic#usr/lib/qgis/plugins/libarcgismapserverprovider.so
+#sid stretch jessie trusty xenial yakkety zesty artful bionic#usr/lib/qgis/plugins/libarcgisfeatureserverprovider.so
 {QT_PLUGIN_DIR}/sqldrivers/libqsqlspatialite.so
diff --git a/debian/rules b/debian/rules
index f952372..f9b28c0 100755
--- a/debian/rules
+++ b/debian/rules
@@ -34,7 +34,7 @@ ifneq (,$(findstring -oracle,$(DISTRIBUTION)))
 	WITH_ORACLE=1
 endif
 
-ifneq ($(DISTRIBUTION),$(findstring $(DISTRIBUTION),"jessie stretch trusty xenial yakkety zesty artful"))
+ifneq ($(DISTRIBUTION),$(findstring $(DISTRIBUTION),"jessie stretch trusty xenial yakkety zesty artful bionic"))
 	DISTRIBUTION := sid
 endif
 
@@ -136,7 +136,7 @@ ifneq (,$(findstring $(DISTRIBUTION),"sid stretch"))
 	CMAKE_OPTS += -DPOSTGRES_LIBRARY=/usr/lib/$(DEB_BUILD_MULTIARCH)/libpq.so
 endif
 
-ifneq (,$(findstring $(DISTRIBUTION),"sid stretch yakkety zesty artful"))
+ifneq (,$(findstring $(DISTRIBUTION),"sid stretch yakkety zesty artful bionic"))
 	CMAKE_OPTS += -DWITH_INTERNAL_WEBKIT_BINDINGS=TRUE
 endif
 
@@ -144,7 +144,7 @@ ifneq (,$(findstring $(DISTRIBUTION),"sid"))
 	CMAKE_OPTS += -DGEOS_LIBRARY=/usr/lib/$(DEB_BUILD_MULTIARCH)/libgeos_c.so
 endif
 
-ifneq (,$(findstring $(DISTRIBUTION),"jessie stretch trusty xenial yakkety zesty artful sid"))
+ifneq (,$(findstring $(DISTRIBUTION),"jessie stretch trusty xenial yakkety zesty artful bionic sid"))
 	CMAKE_OPTS += -DPYTHON_LIBRARY=/usr/lib/$(DEB_BUILD_MULTIARCH)/libpython2.7.so
 endif
 
diff --git a/doc/TRANSLATORS b/doc/TRANSLATORS
index 8c97172..19a2ba1 100644
--- a/doc/TRANSLATORS
+++ b/doc/TRANSLATORS
@@ -1,40 +1,40 @@
 <style>table {font-size:80%;}th {text-align:left; }.bartodo{ background-color:red;width:100px;height:20px;}.bardone{ background-color:green;width:80px;height:20px;font-size:80%;text-align:center;padding-top:4px;height:16px;color:white;}</style><table><tr><th colspan="2" style="width:250px;">Language</th><th>Finished %</th><th>Translators</th></tr>
 
-<tr><td><img src="qrc:/images/flags/de.png"></td><td>German</td><td><div title="finished:18366 unfinished:0 untranslated:0" class="bartodo"><div class="bardone" style="width:100px">100.0</div></div></td><td>Jürgen E. Fischer, Stephan Holl, Otto Dassau, Werner Macho</td></tr>
-<tr><td><img src="qrc:/images/flags/sv.png"></td><td>Swedish</td><td><div title="finished:17813 unfinished:218 untranslated:335" class="bartodo"><div class="bardone" style="width:97px">97.6</div></div></td><td>Victor Axbom, Lars Luthman, Magnus Homann, Klas Karlsson, Isabelle J Wigren, Daniel Rosander, Anders Ekwall, Magnus Nilsson, Jonas Svensson, Christian Brinkenberg</td></tr>
-<tr><td><img src="qrc:/images/flags/eu.png"></td><td>Basque</td><td><div title="finished:17813 unfinished:214 untranslated:339" class="bartodo"><div class="bardone" style="width:97px">97.6</div></div></td><td>Asier Sarasua Garmendia, Irantzu Alvarez</td></tr>
-<tr><td><img src="qrc:/images/flags/gl.png"></td><td>Galician</td><td><div title="finished:17812 unfinished:211 untranslated:343" class="bartodo"><div class="bardone" style="width:97px">97.6</div></div></td><td>Xan Vieiro</td></tr>
-<tr><td><img src="qrc:/images/flags/nl.png"></td><td>Dutch</td><td><div title="finished:17808 unfinished:218 untranslated:340" class="bartodo"><div class="bardone" style="width:97px">97.6</div></div></td><td>Richard Duivenvoorde, Raymond Nijssen, Carlo van Rijswijk, Diethard Jansen, Willem Hoffmans, Dick Groskamp</td></tr>
-<tr><td><img src="qrc:/images/flags/ro.png"></td><td>Romanian</td><td><div title="finished:17813 unfinished:204 untranslated:349" class="bartodo"><div class="bardone" style="width:97px">97.5</div></div></td><td>Sorin Călinică, Tudor Bărăscu, Georgiana Ioanovici, Alex Bădescu, Lonut Losifescu-Enescu, Bogdan Pacurar</td></tr>
-<tr><td><img src="qrc:/images/flags/pt_BR.png"></td><td>Portuguese (Brazil)</td><td><div title="finished:17813 unfinished:202 untranslated:351" class="bartodo"><div class="bardone" style="width:97px">97.5</div></div></td><td>Sidney Schaberle Goveia, Arthur Nanni, Marcelo Soares Souza, Narcélio de Sá Pereira Filho, Leônidas Descovi Filho, Felipe Sodré Barros </td></tr>
-<tr><td><img src="qrc:/images/flags/fr.png"></td><td>French</td><td><div title="finished:17789 unfinished:210 untranslated:367" class="bartodo"><div class="bardone" style="width:97px">97.4</div></div></td><td>Arnaud Morvan, Augustin Roche, DelazJ, Didier Vanden Berghe, Dofabien, etrimaille, Jean-Roc Morreale, Jérémy Garniaux, Loïc Buscoz, Lsam, Marc-André Saia, Marie Silvestre, Mathieu Bossaert, Mathieu Lattes, Mayeul Kauffmann, Médéric Ribreux, Mehdi Semchaoui, Michael Douchin, Nicolas  [...]
-<tr><td><img src="qrc:/images/flags/bs.png"></td><td>Bosnian</td><td><div title="finished:17668 unfinished:220 untranslated:478" class="bartodo"><div class="bardone" style="width:96px">96.8</div></div></td><td>Almir Karabegovic</td></tr>
-<tr><td><img src="qrc:/images/flags/da.png"></td><td>Danish</td><td><div title="finished:17509 unfinished:173 untranslated:684" class="bartodo"><div class="bardone" style="width:95px">95.8</div></div></td><td>Jacob Overgaard Madsen, Bo Victor Thomsen</td></tr>
-<tr><td><img src="qrc:/images/flags/es.png"></td><td>Spanish</td><td><div title="finished:17370 unfinished:141 untranslated:855" class="bartodo"><div class="bardone" style="width:94px">95.0</div></div></td><td>Carlos Dávila, Javier César Aldariz, Gabriela Awad, Edwin Amado, Mayeul Kauffmann, Diana Galindo</td></tr>
-<tr><td><img src="qrc:/images/flags/ja.png"></td><td>Japanese</td><td><div title="finished:17130 unfinished:217 untranslated:1019" class="bartodo"><div class="bardone" style="width:93px">93.9</div></div></td><td>BABA Yoshihiko, Yoichi Kayama, Minoru Akagi, Takayuki Nuimura, Takayuki Mizutani, Norihiro Yamate</td></tr>
-<tr><td><img src="qrc:/images/flags/hu.png"></td><td>Hungarian</td><td><div title="finished:16386 unfinished:152 untranslated:1828" class="bartodo"><div class="bardone" style="width:89px">89.6</div></div></td><td>Zoltan Siki</td></tr>
-<tr><td><img src="qrc:/images/flags/vi.png"></td><td>Vietnamese</td><td><div title="finished:16229 unfinished:104 untranslated:2033" class="bartodo"><div class="bardone" style="width:88px">88.6</div></div></td><td>Phùng Văn Doanh, Bùi Hữu Mạnh, Nguyễn Văn Thanh, Nguyễn Hữu Phúc, Cao Minh Tu</td></tr>
-<tr><td><img src="qrc:/images/flags/zh.png"></td><td>Chinese simplified</td><td><div title="finished:15943 unfinished:111 untranslated:2312" class="bartodo"><div class="bardone" style="width:87px">87.1</div></div></td><td>Calvin Ngei, Lisashen</td></tr>
-<tr><td><img src="qrc:/images/flags/pt_PT.png"></td><td>Portuguese (Portugal)</td><td><div title="finished:15358 unfinished:99 untranslated:2909" class="bartodo"><div class="bardone" style="width:83px">83.9</div></div></td><td>Giovanni Manghi, Joana Simões, Duarte Carreira, Alexandre Neto, Pedro Pereira, Pedro Palheiro, Nelson Silva, Ricardo Sena, Leandro Infantini, João Gaspar</td></tr>
-<tr><td><img src="qrc:/images/flags/ru.png"></td><td>Russian</td><td><div title="finished:15314 unfinished:163 untranslated:2889" class="bartodo"><div class="bardone" style="width:83px">83.8</div></div></td><td>Alexander Bruy, Artem Popov</td></tr>
-<tr><td><img src="qrc:/images/flags/pl.png"></td><td>Polish</td><td><div title="finished:14688 unfinished:103 untranslated:3575" class="bartodo"><div class="bardone" style="width:80px">80.3</div></div></td><td>Robert Szczepanek, Milena Nowotarska, Borys Jurgiel, Mateusz Łoskot, Tomasz Paul, Andrzej Świąder, Radosław Pasiok, Michał Kułach, Ewelina Krawczak, Michał Smoczyk, Jakub Bobrowski</td></tr>
-<tr><td><img src="qrc:/images/flags/nb.png"></td><td>Norwegian Bokmal</td><td><div title="finished:14525 unfinished:142 untranslated:3699" class="bartodo"><div class="bardone" style="width:79px">79.5</div></div></td><td>James Stott, Maléne Peterson</td></tr>
-<tr><td><img src="qrc:/images/flags/cs.png"></td><td>Czech</td><td><div title="finished:14493 unfinished:140 untranslated:3733" class="bartodo"><div class="bardone" style="width:79px">79.3</div></div></td><td>Jan Helebrant, Martin Landa, Peter Antolik, Martin Dzurov, Stanislav Horáček</td></tr>
-<tr><td><img src="qrc:/images/flags/zh.png"></td><td>Chinese traditional</td><td><div title="finished:13975 unfinished:166 untranslated:4225" class="bartodo"><div class="bardone" style="width:76px">76.5</div></div></td><td>Calvin Ngei, Zhang Jun, Richard Xie</td></tr>
-<tr><td><img src="qrc:/images/flags/fi.png"></td><td>Finnish</td><td><div title="finished:13878 unfinished:356 untranslated:4132" class="bartodo"><div class="bardone" style="width:76px">76.5</div></div></td><td>Kari Mikkonen, Matti Mäntynen</td></tr>
-<tr><td><img src="qrc:/images/flags/it.png"></td><td>Italian</td><td><div title="finished:13964 unfinished:151 untranslated:4251" class="bartodo"><div class="bardone" style="width:76px">76.4</div></div></td><td>Roberto Angeletti, Michele Beneventi, Marco Braida, Stefano Campus, Luca Casagrande, Paolo Cavallini, Giuliano Curti, Luca Delucchi, Alessandro Fanna, Michele Ferretti, Matteo Ghetta, Anne Gishla, Maurizio Napolitano, Flavio Rigolon</td></tr>
-<tr><td><img src="qrc:/images/flags/et.png"></td><td>Estonian</td><td><div title="finished:13131 unfinished:171 untranslated:5064" class="bartodo"><div class="bardone" style="width:71px">72.0</div></div></td><td>Veiko Viil</td></tr>
-<tr><td><img src="qrc:/images/flags/ca.png"></td><td>Catalan</td><td><div title="finished:12806 unfinished:151 untranslated:5409" class="bartodo"><div class="bardone" style="width:70px">70.1</div></div></td><td>Albert F, Pau Reguant Ridó, Xavier Roijals</td></tr>
-<tr><td><img src="qrc:/images/flags/hi.png"></td><td>Hindi</td><td><div title="finished:12436 unfinished:197 untranslated:5733" class="bartodo"><div class="bardone" style="width:68px">68.2</div></div></td><td>Harish Kumar Solanki</td></tr>
-<tr><td><img src="qrc:/images/flags/bg.png"></td><td>Bulgarian</td><td><div title="finished:12336 unfinished:169 untranslated:5861" class="bartodo"><div class="bardone" style="width:67px">67.6</div></div></td><td>Захари Савов, Jordan Tzvetkov</td></tr>
-<tr><td><img src="qrc:/images/flags/ko.png"></td><td>Korean</td><td><div title="finished:11729 unfinished:187 untranslated:6450" class="bartodo"><div class="bardone" style="width:64px">64.4</div></div></td><td>OSGeo Korean Chapter</td></tr>
-<tr><td><img src="qrc:/images/flags/lt.png"></td><td>Lithuanian</td><td><div title="finished:11285 unfinished:201 untranslated:6880" class="bartodo"><div class="bardone" style="width:61px">62.0</div></div></td><td>Paulius Litvinas, Tomas Straupis, Kestas M</td></tr>
-<tr><td><img src="qrc:/images/flags/tr.png"></td><td>Turkish</td><td><div title="finished:10787 unfinished:162 untranslated:7417" class="bartodo"><div class="bardone" style="width:59px">59.2</div></div></td><td>Osman Yalçın YILMAZ, Omur Saygin</td></tr>
-<tr><td><img src="qrc:/images/flags/id.png"></td><td>Indonesian</td><td><div title="finished:10696 unfinished:331 untranslated:7339" class="bartodo"><div class="bardone" style="width:59px">59.1</div></div></td><td>Emir Hartato, Muhammad Iqnaul Haq Siregar, Trias Aditya, Januar V. Simarmata, I Made Anombawa</td></tr>
-<tr><td><img src="qrc:/images/flags/el.png"></td><td>Modern Greek (1453-)</td><td><div title="finished:10702 unfinished:129 untranslated:7535" class="bartodo"><div class="bardone" style="width:58px">58.6</div></div></td><td>Theodoros Vakkas, Ioannis Tsimpiris, Evripidis Argyropoulos, Mike Pegnigiannis, Nikos Ves</td></tr>
-<tr><td><img src="qrc:/images/flags/sl.png"></td><td>Slovenian</td><td><div title="finished:9492 unfinished:190 untranslated:8684" class="bartodo"><div class="bardone" style="width:52px">52.2</div></div></td><td>Jože Detečnik, Dejan Gregor, Jaka Kranjc</td></tr>
-<tr><td><img src="qrc:/images/flags/km.png"></td><td>Central Khmer</td><td><div title="finished:9317 unfinished:191 untranslated:8858" class="bartodo"><div class="bardone" style="width:51px">51.2</div></div></td><td>Khoem Sokhem</td></tr>
-<tr><td><img src="qrc:/images/flags/ar.png"></td><td>Arabic</td><td><div title="finished:9278 unfinished:190 untranslated:8898" class="bartodo"><div class="bardone" style="width:51px">51.0</div></div></td><td>Ichaouia Amine, Hosham Munier</td></tr>
-<tr><td><img src="qrc:/images/flags/lv.png"></td><td>Latvian</td><td><div title="finished:9151 unfinished:276 untranslated:8939" class="bartodo"><div class="bardone" style="width:50px">50.6</div></div></td><td>Maris Nartiss, Pēteris Brūns</td></tr>
-<tr><td><img src="qrc:/images/flags/sk.png"></td><td>Slovak</td><td><div title="finished:7745 unfinished:871 untranslated:9750" class="bartodo"><div class="bardone" style="width:44px">44.5</div></div></td><td>Lubos Balazovic, Jana Kormanikova, Ivan Mincik</td></tr>
-<tr><td><img src="qrc:/images/flags/hr.png"></td><td>Croatian</td><td><div title="finished:7277 unfinished:195 untranslated:10894" class="bartodo"><div class="bardone" style="width:40px">40.2</div></div></td><td>Zoran Jankovic</td></tr></table>
+<tr><td><img src="qrc:/images/flags/de.png"></td><td>German</td><td><div title="finished:18368 unfinished:0 untranslated:0" class="bartodo"><div class="bardone" style="width:100px">100.0</div></div></td><td>Jürgen E. Fischer, Stephan Holl, Otto Dassau, Werner Macho</td></tr>
+<tr><td><img src="qrc:/images/flags/sv.png"></td><td>Swedish</td><td><div title="finished:17798 unfinished:219 untranslated:351" class="bartodo"><div class="bardone" style="width:97px">97.5</div></div></td><td>Victor Axbom, Lars Luthman, Magnus Homann, Klas Karlsson, Isabelle J Wigren, Daniel Rosander, Anders Ekwall, Magnus Nilsson, Jonas Svensson, Christian Brinkenberg</td></tr>
+<tr><td><img src="qrc:/images/flags/eu.png"></td><td>Basque</td><td><div title="finished:17798 unfinished:215 untranslated:355" class="bartodo"><div class="bardone" style="width:97px">97.5</div></div></td><td>Asier Sarasua Garmendia, Irantzu Alvarez</td></tr>
+<tr><td><img src="qrc:/images/flags/gl.png"></td><td>Galician</td><td><div title="finished:17797 unfinished:213 untranslated:358" class="bartodo"><div class="bardone" style="width:97px">97.5</div></div></td><td>Xan Vieiro</td></tr>
+<tr><td><img src="qrc:/images/flags/nl.png"></td><td>Dutch</td><td><div title="finished:17793 unfinished:219 untranslated:356" class="bartodo"><div class="bardone" style="width:97px">97.5</div></div></td><td>Richard Duivenvoorde, Raymond Nijssen, Carlo van Rijswijk, Diethard Jansen, Willem Hoffmans, Dick Groskamp</td></tr>
+<tr><td><img src="qrc:/images/flags/ro.png"></td><td>Romanian</td><td><div title="finished:17798 unfinished:205 untranslated:365" class="bartodo"><div class="bardone" style="width:97px">97.5</div></div></td><td>Sorin Călinică, Tudor Bărăscu, Georgiana Ioanovici, Alex Bădescu, Lonut Losifescu-Enescu, Bogdan Pacurar</td></tr>
+<tr><td><img src="qrc:/images/flags/pt_BR.png"></td><td>Portuguese (Brazil)</td><td><div title="finished:17798 unfinished:204 untranslated:366" class="bartodo"><div class="bardone" style="width:97px">97.5</div></div></td><td>Sidney Schaberle Goveia, Arthur Nanni, Marcelo Soares Souza, Narcélio de Sá Pereira Filho, Leônidas Descovi Filho, Felipe Sodré Barros </td></tr>
+<tr><td><img src="qrc:/images/flags/fr.png"></td><td>French</td><td><div title="finished:17782 unfinished:212 untranslated:374" class="bartodo"><div class="bardone" style="width:97px">97.4</div></div></td><td>Arnaud Morvan, Augustin Roche, DelazJ, Didier Vanden Berghe, Dofabien, etrimaille, Jean-Roc Morreale, Jérémy Garniaux, Loïc Buscoz, Lsam, Marc-André Saia, Marie Silvestre, Mathieu Bossaert, Mathieu Lattes, Mayeul Kauffmann, Médéric Ribreux, Mehdi Semchaoui, Michael Douchin, Nicolas  [...]
+<tr><td><img src="qrc:/images/flags/es.png"></td><td>Spanish</td><td><div title="finished:17741 unfinished:132 untranslated:495" class="bartodo"><div class="bardone" style="width:96px">96.9</div></div></td><td>Carlos Dávila, Javier César Aldariz, Gabriela Awad, Edwin Amado, Mayeul Kauffmann, Diana Galindo</td></tr>
+<tr><td><img src="qrc:/images/flags/bs.png"></td><td>Bosnian</td><td><div title="finished:17653 unfinished:222 untranslated:493" class="bartodo"><div class="bardone" style="width:96px">96.7</div></div></td><td>Almir Karabegovic</td></tr>
+<tr><td><img src="qrc:/images/flags/da.png"></td><td>Danish</td><td><div title="finished:17494 unfinished:175 untranslated:699" class="bartodo"><div class="bardone" style="width:95px">95.7</div></div></td><td>Jacob Overgaard Madsen, Bo Victor Thomsen</td></tr>
+<tr><td><img src="qrc:/images/flags/ja.png"></td><td>Japanese</td><td><div title="finished:17115 unfinished:219 untranslated:1034" class="bartodo"><div class="bardone" style="width:93px">93.8</div></div></td><td>BABA Yoshihiko, Yoichi Kayama, Minoru Akagi, Takayuki Nuimura, Takayuki Mizutani, Norihiro Yamate</td></tr>
+<tr><td><img src="qrc:/images/flags/hu.png"></td><td>Hungarian</td><td><div title="finished:16372 unfinished:154 untranslated:1842" class="bartodo"><div class="bardone" style="width:89px">89.6</div></div></td><td>Zoltan Siki</td></tr>
+<tr><td><img src="qrc:/images/flags/vi.png"></td><td>Vietnamese</td><td><div title="finished:16216 unfinished:105 untranslated:2047" class="bartodo"><div class="bardone" style="width:88px">88.6</div></div></td><td>Phùng Văn Doanh, Bùi Hữu Mạnh, Nguyễn Văn Thanh, Nguyễn Hữu Phúc, Cao Minh Tu</td></tr>
+<tr><td><img src="qrc:/images/flags/zh.png"></td><td>Chinese simplified</td><td><div title="finished:15929 unfinished:113 untranslated:2326" class="bartodo"><div class="bardone" style="width:87px">87.0</div></div></td><td>Calvin Ngei, Lisashen</td></tr>
+<tr><td><img src="qrc:/images/flags/pt_PT.png"></td><td>Portuguese (Portugal)</td><td><div title="finished:15345 unfinished:101 untranslated:2922" class="bartodo"><div class="bardone" style="width:83px">83.8</div></div></td><td>Giovanni Manghi, Joana Simões, Duarte Carreira, Alexandre Neto, Pedro Pereira, Pedro Palheiro, Nelson Silva, Ricardo Sena, Leandro Infantini, João Gaspar</td></tr>
+<tr><td><img src="qrc:/images/flags/ru.png"></td><td>Russian</td><td><div title="finished:15300 unfinished:164 untranslated:2904" class="bartodo"><div class="bardone" style="width:83px">83.7</div></div></td><td>Alexander Bruy, Artem Popov</td></tr>
+<tr><td><img src="qrc:/images/flags/pl.png"></td><td>Polish</td><td><div title="finished:14744 unfinished:105 untranslated:3519" class="bartodo"><div class="bardone" style="width:80px">80.6</div></div></td><td>Robert Szczepanek, Milena Nowotarska, Borys Jurgiel, Mateusz Łoskot, Tomasz Paul, Andrzej Świąder, Radosław Pasiok, Michał Kułach, Ewelina Krawczak, Michał Smoczyk, Jakub Bobrowski</td></tr>
+<tr><td><img src="qrc:/images/flags/nb.png"></td><td>Norwegian Bokmal</td><td><div title="finished:14512 unfinished:143 untranslated:3713" class="bartodo"><div class="bardone" style="width:79px">79.4</div></div></td><td>James Stott, Maléne Peterson</td></tr>
+<tr><td><img src="qrc:/images/flags/cs.png"></td><td>Czech</td><td><div title="finished:14481 unfinished:142 untranslated:3745" class="bartodo"><div class="bardone" style="width:79px">79.2</div></div></td><td>Jan Helebrant, Martin Landa, Peter Antolik, Martin Dzurov, Stanislav Horáček</td></tr>
+<tr><td><img src="qrc:/images/flags/zh.png"></td><td>Chinese traditional</td><td><div title="finished:13963 unfinished:168 untranslated:4237" class="bartodo"><div class="bardone" style="width:76px">76.5</div></div></td><td>Calvin Ngei, Zhang Jun, Richard Xie</td></tr>
+<tr><td><img src="qrc:/images/flags/fi.png"></td><td>Finnish</td><td><div title="finished:13865 unfinished:357 untranslated:4146" class="bartodo"><div class="bardone" style="width:76px">76.5</div></div></td><td>Kari Mikkonen, Matti Mäntynen</td></tr>
+<tr><td><img src="qrc:/images/flags/it.png"></td><td>Italian</td><td><div title="finished:13951 unfinished:152 untranslated:4265" class="bartodo"><div class="bardone" style="width:76px">76.4</div></div></td><td>Roberto Angeletti, Michele Beneventi, Marco Braida, Stefano Campus, Luca Casagrande, Paolo Cavallini, Giuliano Curti, Luca Delucchi, Alessandro Fanna, Michele Ferretti, Matteo Ghetta, Anne Gishla, Maurizio Napolitano, Flavio Rigolon</td></tr>
+<tr><td><img src="qrc:/images/flags/et.png"></td><td>Estonian</td><td><div title="finished:13121 unfinished:173 untranslated:5074" class="bartodo"><div class="bardone" style="width:71px">71.9</div></div></td><td>Veiko Viil</td></tr>
+<tr><td><img src="qrc:/images/flags/ca.png"></td><td>Catalan</td><td><div title="finished:12793 unfinished:153 untranslated:5422" class="bartodo"><div class="bardone" style="width:70px">70.1</div></div></td><td>Albert F, Pau Reguant Ridó, Xavier Roijals</td></tr>
+<tr><td><img src="qrc:/images/flags/hi.png"></td><td>Hindi</td><td><div title="finished:12425 unfinished:198 untranslated:5745" class="bartodo"><div class="bardone" style="width:68px">68.2</div></div></td><td>Harish Kumar Solanki</td></tr>
+<tr><td><img src="qrc:/images/flags/bg.png"></td><td>Bulgarian</td><td><div title="finished:12325 unfinished:170 untranslated:5873" class="bartodo"><div class="bardone" style="width:67px">67.6</div></div></td><td>Захари Савов, Jordan Tzvetkov</td></tr>
+<tr><td><img src="qrc:/images/flags/ko.png"></td><td>Korean</td><td><div title="finished:11723 unfinished:189 untranslated:6456" class="bartodo"><div class="bardone" style="width:64px">64.3</div></div></td><td>OSGeo Korean Chapter</td></tr>
+<tr><td><img src="qrc:/images/flags/lt.png"></td><td>Lithuanian</td><td><div title="finished:11278 unfinished:203 untranslated:6887" class="bartodo"><div class="bardone" style="width:61px">62.0</div></div></td><td>Paulius Litvinas, Tomas Straupis, Kestas M</td></tr>
+<tr><td><img src="qrc:/images/flags/tr.png"></td><td>Turkish</td><td><div title="finished:10776 unfinished:163 untranslated:7429" class="bartodo"><div class="bardone" style="width:59px">59.1</div></div></td><td>Osman Yalçın YILMAZ, Omur Saygin</td></tr>
+<tr><td><img src="qrc:/images/flags/id.png"></td><td>Indonesian</td><td><div title="finished:10691 unfinished:332 untranslated:7345" class="bartodo"><div class="bardone" style="width:59px">59.1</div></div></td><td>Emir Hartato, Muhammad Iqnaul Haq Siregar, Trias Aditya, Januar V. Simarmata, I Made Anombawa</td></tr>
+<tr><td><img src="qrc:/images/flags/el.png"></td><td>Modern Greek (1453-)</td><td><div title="finished:10691 unfinished:131 untranslated:7546" class="bartodo"><div class="bardone" style="width:58px">58.6</div></div></td><td>Theodoros Vakkas, Ioannis Tsimpiris, Evripidis Argyropoulos, Mike Pegnigiannis, Nikos Ves</td></tr>
+<tr><td><img src="qrc:/images/flags/sl.png"></td><td>Slovenian</td><td><div title="finished:9487 unfinished:191 untranslated:8690" class="bartodo"><div class="bardone" style="width:52px">52.2</div></div></td><td>Jože Detečnik, Dejan Gregor, Jaka Kranjc</td></tr>
+<tr><td><img src="qrc:/images/flags/km.png"></td><td>Central Khmer</td><td><div title="finished:9311 unfinished:193 untranslated:8864" class="bartodo"><div class="bardone" style="width:51px">51.2</div></div></td><td>Khoem Sokhem</td></tr>
+<tr><td><img src="qrc:/images/flags/ar.png"></td><td>Arabic</td><td><div title="finished:9273 unfinished:191 untranslated:8904" class="bartodo"><div class="bardone" style="width:51px">51.0</div></div></td><td>Ichaouia Amine, Hosham Munier</td></tr>
+<tr><td><img src="qrc:/images/flags/lv.png"></td><td>Latvian</td><td><div title="finished:9146 unfinished:278 untranslated:8944" class="bartodo"><div class="bardone" style="width:50px">50.5</div></div></td><td>Maris Nartiss, Pēteris Brūns</td></tr>
+<tr><td><img src="qrc:/images/flags/sk.png"></td><td>Slovak</td><td><div title="finished:7741 unfinished:871 untranslated:9756" class="bartodo"><div class="bardone" style="width:44px">44.5</div></div></td><td>Lubos Balazovic, Jana Kormanikova, Ivan Mincik</td></tr>
+<tr><td><img src="qrc:/images/flags/hr.png"></td><td>Croatian</td><td><div title="finished:7274 unfinished:196 untranslated:10898" class="bartodo"><div class="bardone" style="width:40px">40.1</div></div></td><td>Zoran Jankovic</td></tr></table>
diff --git a/i18n/qgis_de.ts b/i18n/qgis_de.ts
index f39ca26..e213e35 100644
--- a/i18n/qgis_de.ts
+++ b/i18n/qgis_de.ts
@@ -6,9 +6,7 @@
     <message>
         <source><html><body><h2>Algorithm description</h2>
 </source>
-        <translation><html><body><h2>Algorithmenbeschreibung</h2>
-
-</translation>
+        <translation><html><body><h2>Algorithmenbeschreibung</h2></translation>
     </message>
     <message>
         <source>OTB execution console output</source>
@@ -4252,6 +4250,30 @@ Objektgeometriefehler: Eine oder mehrere Ausgabeobjekte mit ungültiger Geometri
         <source>A-</source>
         <translation>A-</translation>
     </message>
+    <message>
+        <source>Case sensitive</source>
+        <translation>Groß-/Kleinschreibung beachten</translation>
+    </message>
+    <message>
+        <source>Whole word</source>
+        <translation>Ganzes Wort</translation>
+    </message>
+    <message>
+        <source>Replace</source>
+        <translation>Ersetzen</translation>
+    </message>
+    <message>
+        <source>Find what:</source>
+        <translation>Zu suchender Text:</translation>
+    </message>
+    <message>
+        <source>Replace with:</source>
+        <translation>Ersetzen durch:</translation>
+    </message>
+    <message>
+        <source>Find</source>
+        <translation>Suchen</translation>
+    </message>
 </context>
 <context>
     <name>DlgSqlLayerWindow</name>
@@ -24406,25 +24428,25 @@ Datenbank: %3</translation>
         <source>Unable to create the bookmark.
 Driver:%1
 Database:%2</source>
-        <translation>Konnte das Lesezeichen nicht erzeugen.
+        <translation type="obsolete">Konnte das Lesezeichen nicht erzeugen.
 Treiber: %1
 Datenbank: %2</translation>
     </message>
     <message>
         <source>Really Delete?</source>
-        <translation>Wirklich löschen?</translation>
+        <translation type="obsolete">Wirklich löschen?</translation>
     </message>
     <message numerus="yes">
         <source>Are you sure you want to delete %n bookmark(s)?</source>
         <comment>number of rows</comment>
-        <translation type="unfinished">
+        <translation>
             <numerusform>Soll das Lesezeichen wirklich gelöscht werden?</numerusform>
             <numerusform>Sollen %n Lesezeichen wirklich gelöscht werden?</numerusform>
         </translation>
     </message>
     <message>
         <source>Empty extent</source>
-        <translation>Ausdehnung leer</translation>
+        <translation type="obsolete">Ausdehnung leer</translation>
     </message>
     <message>
         <source>Reprojected extent is empty.</source>
@@ -24456,10 +24478,26 @@ Datenbank: %2</translation>
     </message>
     <message>
         <source>Export bookmarks</source>
-        <translation>Exportiere Lesezeichen</translation>
+        <translation type="obsolete">Exportiere Lesezeichen</translation>
     </message>
     <message>
         <source>XML files( *.xml *.XML )</source>
+        <translation type="obsolete">XML-Dateien (*.xml *.XML)</translation>
+    </message>
+    <message>
+        <source>Delete Bookmarks</source>
+        <translation>Lesezeichen löschen</translation>
+    </message>
+    <message>
+        <source>Empty Extent</source>
+        <translation>Ausdehnung leer</translation>
+    </message>
+    <message>
+        <source>Export Bookmarks</source>
+        <translation>Lesezeichen exportieren</translation>
+    </message>
+    <message>
+        <source>XML files (*.xml *.XML)</source>
         <translation>XML-Dateien (*.xml *.XML)</translation>
     </message>
 </context>
@@ -31897,11 +31935,11 @@ und aktuelle Datei ist [%3]</translation>
     </message>
     <message>
         <source>Date & time</source>
-        <translation>Datum & Zeit</translation>
+        <translation type="obsolete">Datum & Zeit</translation>
     </message>
     <message>
         <source>Custom format</source>
-        <translation>Benutzerformat</translation>
+        <translation type="obsolete">Benutzerformat</translation>
     </message>
     <message>
         <source>Default</source>
@@ -31931,6 +31969,14 @@ und aktuelle Datei ist [%3]</translation>
         <source>Widget display</source>
         <translation>Bedienelementanzeige</translation>
     </message>
+    <message>
+        <source>Date time</source>
+        <translation>Datum mit Zeit</translation>
+    </message>
+    <message>
+        <source>ISO date time</source>
+        <translation>ISO-Datum mit Zeit</translation>
+    </message>
 </context>
 <context>
     <name>QgsDateTimeEditPlugin</name>
@@ -51074,7 +51120,7 @@ verbesserung</translation>
     </message>
     <message>
         <source>Add an integer id field as the primary key for the new layer</source>
-        <translation>Eine ganzzahliges Primärschlüsselfeld ergänzen</translation>
+        <translation type="obsolete">Eine ganzzahliges Primärschlüsselfeld ergänzen</translation>
     </message>
     <message>
         <source>Create a spatial index</source>
@@ -51196,6 +51242,10 @@ verbesserung</translation>
         <source>Length</source>
         <translation>Länge</translation>
     </message>
+    <message>
+        <source>Create a spatial index for this layer</source>
+        <translation>Räumlichen Index für diesen Layer erzeugen</translation>
+    </message>
 </context>
 <context>
     <name>QgsNewHttpConnection</name>
@@ -52445,7 +52495,7 @@ Immer Netzwerk: immer aus dem Netzwerk laden und nicht prüfen, ob im Cache ein
         <translation>In der Offline-Kopie werden Z- und M-Werte des Layers %1 weggelassen.</translation>
     </message>
     <message>
-        <source>Syncronization failed</source>
+        <source>Synchronization failed</source>
         <translation>Synchronisation gescheitert</translation>
     </message>
 </context>
@@ -57317,6 +57367,18 @@ Ergebnis: %3 (%4)</translation>
         <source>PQgetCancel failed</source>
         <translation>PQgetCancel gescheitert</translation>
     </message>
+    <message>
+        <source>Cannot set WriteOwner permission to cert: %0 to allow removing it</source>
+        <translation>Kann WriteOwner-Recht nicht auf Zertifikat %0 setzen, um es zu entfernen zu dürfen</translation>
+    </message>
+    <message>
+        <source>Client security failure</source>
+        <translation>Client-Sicherheitsfehler</translation>
+    </message>
+    <message>
+        <source>Cannot remove cert: %0 to allow removing it</source>
+        <translation>Kann Zertifikat %0 nicht löschen</translation>
+    </message>
 </context>
 <context>
     <name>QgsPostgresProvider</name>
@@ -62275,6 +62337,13 @@ und nur die Geometriespalte des Haupttypname kann als die Geometriespalte des Er
     </message>
 </context>
 <context>
+    <name>QgsSelectLayerTreeModel</name>
+    <message>
+        <source>The source of this layer is a <b>WFS</b> server.<br>Some WFS layers are not suitable for offline<br>editing due to unstable primary keys<br>please check with your system administrator<br>if this WFS layer can be used for offline<br>editing.</source>
+        <translation>Die Quelle diese Layers it ein <b>WFS</b>-Server.<br>Einige WFS-Layers sind nicht für die Offline-<br>Bearbeitung geeignet, durch instabile Primärschlüssel.<br>Bitte den Systemadministrator fragen,<br>ob dieser WFS-Layer offline bearbeitet<br>werden kann.</translation>
+    </message>
+</context>
+<context>
     <name>QgsSelectedFeature</name>
     <message>
         <source>Validation started.</source>
@@ -83382,31 +83451,31 @@ Base Path (i.e. keep only filename from attribute)</source>
     <name>nviz7</name>
     <message>
         <source>nviz7</source>
-        <translation>nviz7</translation>
+        <translation type="obsolete">nviz7</translation>
     </message>
     <message>
         <source>Visualization(NVIZ)</source>
-        <translation>Visualisierung (NVIZ)</translation>
+        <translation type="obsolete">Visualisierung (NVIZ)</translation>
     </message>
     <message>
         <source>Raster file(s) for elevation</source>
-        <translation>Rasterdatei(en) für Höhen</translation>
+        <translation type="obsolete">Rasterdatei(en) für Höhen</translation>
     </message>
     <message>
         <source>Vector lines/areas overlay file(s)</source>
-        <translation>Vektorlinien-/-flächenüberlagerungsdatei(en)</translation>
+        <translation type="obsolete">Vektorlinien-/-flächenüberlagerungsdatei(en)</translation>
     </message>
     <message>
         <source>Raster file(s) for color</source>
-        <translation>Rasterdatei(en) für Farbe</translation>
+        <translation type="obsolete">Rasterdatei(en) für Farbe</translation>
     </message>
     <message>
         <source>GRASS region extent</source>
-        <translation>GRASS-Regionengrenzen</translation>
+        <translation type="obsolete">GRASS-Regionengrenzen</translation>
     </message>
     <message>
         <source>GRASS region cellsize (leave 0 for default)</source>
-        <translation>GRASS-Regionenzellengröße (0 für um Voreinstellung beizubehalten)</translation>
+        <translation type="obsolete">GRASS-Regionenzellengröße (0 für um Voreinstellung beizubehalten)</translation>
     </message>
 </context>
 <context>
diff --git a/i18n/qgis_fi.ts b/i18n/qgis_fi.ts
index 7dcfe3d..2a5d12b 100644
--- a/i18n/qgis_fi.ts
+++ b/i18n/qgis_fi.ts
@@ -15013,7 +15013,7 @@ Ctl (Cmd) kiertää 15 astetta.</translation>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="1635"/>
         <source>Running %s [%i/%i]</source>
-        <translation>Suoritetaan %s </translation>
+        <translation>Suoritetaan %s [%i/%i]</translation>
     </message>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="1636"/>
diff --git a/i18n/qgis_fr.ts b/i18n/qgis_fr.ts
index 41bbe2b..713b04d 100644
--- a/i18n/qgis_fr.ts
+++ b/i18n/qgis_fr.ts
@@ -1465,7 +1465,7 @@ Traitement de l'algorithme %d/%d...</translation>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="326"/>
         <source>Additional creation parameters</source>
-        <translation>Paramètres supplémentaires de création </translation>
+        <translation>Paramètres supplémentaires de création</translation>
     </message>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="327"/>
@@ -12901,7 +12901,7 @@ Veuillez le configurer avant d'exécuter les algorithmes LAStools.</transla
     <message>
         <location filename="../src/ui/qgisapp.ui" line="648"/>
         <source>Composer Manager...</source>
-        <translation>Gestionnaire de composeurs</translation>
+        <translation>Gestionnaire de composeurs...</translation>
     </message>
     <message>
         <location filename="../src/ui/qgisapp.ui" line="42"/>
@@ -13360,12 +13360,12 @@ Veuillez le configurer avant d'exécuter les algorithmes LAStools.</transla
     <message>
         <location filename="../src/ui/qgisapp.ui" line="2440"/>
         <source>Add Circular String</source>
-        <translation type="unfinished"></translation>
+        <translation>Ajouter une courbe</translation>
     </message>
     <message>
         <location filename="../src/ui/qgisapp.ui" line="2455"/>
         <source>Add Circular String by Radius</source>
-        <translation type="unfinished"></translation>
+        <translation>Ajouter une courbe à partir d'un rayon</translation>
     </message>
     <message>
         <location filename="../src/ui/qgisapp.ui" line="2487"/>
@@ -13830,7 +13830,7 @@ Agit sur la couche en cours d'édition</translation>
     <message>
         <location filename="../src/ui/qgisapp.ui" line="1533"/>
         <source>Manage and Install Plugins...</source>
-        <translation>Installer/Gérer les extensions</translation>
+        <translation>Installer/Gérer les extensions...</translation>
     </message>
     <message>
         <location filename="../src/ui/qgisapp.ui" line="2245"/>
@@ -13840,7 +13840,7 @@ Agit sur la couche en cours d'édition</translation>
     <message>
         <location filename="../src/ui/qgisapp.ui" line="2254"/>
         <source>Add Delimited Text Layer...</source>
-        <translation>Ajouter une couche de texte délimité</translation>
+        <translation>Ajouter une couche de texte délimité...</translation>
     </message>
     <message>
         <location filename="../src/ui/qgisapp.ui" line="2257"/>
@@ -13861,7 +13861,7 @@ Agit sur la couche en cours d'édition</translation>
         <location filename="../src/ui/qgisapp.ui" line="315"/>
         <location filename="../src/ui/qgisapp.ui" line="318"/>
         <source>Project Toolbar</source>
-        <translation type="unfinished"></translation>
+        <translation>Barre d'outils Projet</translation>
     </message>
     <message>
         <location filename="../src/ui/qgisapp.ui" line="941"/>
@@ -17981,8 +17981,7 @@ Cela peut provoquer des effets inattendus.</translation>
     <message>
         <location filename="../python/python-i18n.cpp" line="28"/>
         <source>See message log (Python Error) for more details.</source>
-        <translation>
-Voir le journal des erreurs Python pour plus de détails</translation>
+        <translation>Voir le journal des erreurs Python pour plus de détails.</translation>
     </message>
     <message>
         <location filename="../python/python-i18n.cpp" line="29"/>
@@ -22048,7 +22047,7 @@ La réponse est :
     <message>
         <location filename="../src/gui/editorwidgets/qgsenumerationwidgetfactory.cpp" line="35"/>
         <source>Combo box with values that can be used within the column's type. Must be supported by the provider.</source>
-        <translation>Boîte de saisie avec des valeurs qui peuvent être utilisées par le type de la colonne. Nécessite le support par le fournisseur de données.</translation>
+        <translation>Liste déroulante des valeurs utilisables par le type de la colonne. Nécessite la prise en charge par le fournisseur de données.</translation>
     </message>
     <message>
         <location filename="../src/gui/editorwidgets/qgsfilenamewidgetfactory.cpp" line="33"/>
@@ -23142,7 +23141,7 @@ L'opération ne peut pas être annulée !
     <message>
         <location filename="../src/core/qgsunittypes.cpp" line="1055"/>
         <source> rad</source>
-        <translation>rad</translation>
+        <translation> rad</translation>
     </message>
     <message>
         <location filename="../src/core/qgsunittypes.cpp" line="1058"/>
@@ -23162,13 +23161,13 @@ L'opération ne peut pas être annulée !
     <message>
         <location filename="../src/core/qgsunittypes.cpp" line="1067"/>
         <source> tr</source>
-        <translation>tr</translation>
+        <translation> tr</translation>
     </message>
     <message>
         <location filename="../src/gui/editorwidgets/qgsclassificationwidgetwrapperfactory.cpp" line="34"/>
         <source>Displays a combo box containing values of attributes used for classification.
 Only available when the layer uses a categorized symbol renderer.</source>
-        <translation>Affiche une combo box contenant les valeurs des attributs utilisés pour la classification.
+        <translation>Affiche une liste déroulante contenant les valeurs des attributs utilisés pour la classification.
 Uniquement disponible lorsque la couche utilise le moteur de rendu des symboles catégorisés.</translation>
     </message>
     <message>
@@ -26761,7 +26760,7 @@ Erreur de l'analyseur:
     <message>
         <location filename="../src/ui/composer/qgsatlascompositionwidgetbase.ui" line="162"/>
         <source>Filter with</source>
-        <translation>Flitrer avec</translation>
+        <translation>Filtrer avec</translation>
     </message>
     <message>
         <location filename="../src/ui/composer/qgsatlascompositionwidgetbase.ui" line="194"/>
@@ -26927,7 +26926,7 @@ Erreur de l'analyseur:
     <message>
         <location filename="../src/ui/qgsattributeactiondialogbase.ui" line="238"/>
         <source>Combo Box</source>
-        <translation>Combo Box</translation>
+        <translation>Liste déroulante</translation>
     </message>
     <message>
         <location filename="../src/ui/qgsattributeactiondialogbase.ui" line="168"/>
@@ -35856,7 +35855,7 @@ Essayez une résolution ou une taille de papier inférieure.</translation>
         <location filename="../src/ui/composer/qgscomposermapwidgetbase.ui" line="662"/>
         <location filename="../src/ui/composer/qgscomposermapwidgetbase.ui" line="702"/>
         <source>X </source>
-        <translation>X</translation>
+        <translation>X </translation>
     </message>
     <message utf8="true">
         <location filename="../src/ui/composer/qgscomposermapwidgetbase.ui" line="145"/>
@@ -35867,7 +35866,7 @@ Essayez une résolution ou une taille de papier inférieure.</translation>
         <location filename="../src/ui/composer/qgscomposermapwidgetbase.ui" line="675"/>
         <location filename="../src/ui/composer/qgscomposermapwidgetbase.ui" line="715"/>
         <source>Y </source>
-        <translation>Y</translation>
+        <translation>Y </translation>
     </message>
     <message>
         <location filename="../src/ui/composer/qgscomposermapwidgetbase.ui" line="730"/>
@@ -35898,12 +35897,12 @@ Essayez une résolution ou une taille de papier inférieure.</translation>
     <message>
         <location filename="../src/ui/composer/qgscomposermapwidgetbase.ui" line="209"/>
         <source>Lock layers</source>
-        <translation type="unfinished"></translation>
+        <translation>Verrouiller les couches</translation>
     </message>
     <message>
         <location filename="../src/ui/composer/qgscomposermapwidgetbase.ui" line="248"/>
         <source>Lock styles for layers</source>
-        <translation type="unfinished"></translation>
+        <translation>Verrouiller le style des couches</translation>
     </message>
     <message>
         <location filename="../src/ui/composer/qgscomposermapwidgetbase.ui" line="488"/>
@@ -36060,7 +36059,7 @@ Essayez une résolution ou une taille de papier inférieure.</translation>
     <message>
         <location filename="../src/ui/composer/qgscomposermapwidgetbase.ui" line="1123"/>
         <source>Font...</source>
-        <translation>Police</translation>
+        <translation>Police...</translation>
     </message>
     <message>
         <location filename="../src/ui/composer/qgscomposermapwidgetbase.ui" line="1130"/>
@@ -42170,7 +42169,7 @@ Erreur d'analyse :
     <message>
         <location filename="../src/gui/attributetable/qgsdualview.cpp" line="613"/>
         <source>Sort ascending</source>
-        <translation type="unfinished"></translation>
+        <translation>Tri croissant</translation>
     </message>
     <message>
         <location filename="../src/gui/attributetable/qgsdualview.cpp" line="732"/>
@@ -48695,12 +48694,12 @@ Modifier le nom du script et l'enregistrer pour permettre à QGIS de le cha
     <message>
         <location filename="../src/customwidgets/qgsfieldcomboboxplugin.cpp" line="74"/>
         <source>A combo box to list the fields of a layer</source>
-        <translation>Une boîte combinée pour lister les champs d'une couche</translation>
+        <translation>Une liste déroulante affichant les champs d'une couche</translation>
     </message>
     <message>
         <location filename="../src/customwidgets/qgsfieldcomboboxplugin.cpp" line="79"/>
         <source>A combo box to list the field of a layer.</source>
-        <translation>Une boîte combinée pour lister les champs d'une couche.</translation>
+        <translation>Une liste déroulante affichant les champs d'une couche.</translation>
     </message>
 </context>
 <context>
@@ -48851,7 +48850,7 @@ Modifier le nom du script et l'enregistrer pour permettre à QGIS de le cha
     <message>
         <location filename="../src/customwidgets/qgsfieldexpressionwidgetplugin.cpp" line="74"/>
         <source>An editable combo box to enter an expression</source>
-        <translation>Une combo box éditable pour entrer une expression </translation>
+        <translation>Une liste déroulante éditable pour saisir une expression</translation>
     </message>
     <message>
         <location filename="../src/customwidgets/qgsfieldexpressionwidgetplugin.cpp" line="79"/>
@@ -51713,7 +51712,7 @@ Veuillez sélectionner un fichier valide.</translation>
         <location filename="../src/plugins/geometry_snapper/qgsgeometrysnapper.cpp" line="67"/>
         <location filename="../src/plugins/geometry_snapper/qgsgeometrysnapper.cpp" line="93"/>
         <source>Failed to read feature %1 of input layer.</source>
-        <translation>Échec lors de la lecture de l'entité %1 de la couche d'entrée</translation>
+        <translation>Échec lors de la lecture de l'entité %1 de la couche d'entrée.</translation>
     </message>
 </context>
 <context>
@@ -56283,7 +56282,7 @@ at line %2 column %3</source>
     <message>
         <location filename="../src/helpviewer/qgshelpviewerbase.ui" line="14"/>
         <source>QGIS Help</source>
-        <translation>Aide QGIS </translation>
+        <translation>Aide QGIS</translation>
     </message>
     <message>
         <location filename="../src/helpviewer/qgshelpviewerbase.ui" line="32"/>
@@ -58880,9 +58879,9 @@ Ceci est peut-être dû à votre connexion ou celle du serveur WMS.</numerusform
         <location filename="../src/app/qgsrulebasedlabelingwidget.cpp" line="687"/>
         <source>Filter returned %n feature(s)</source>
         <comment>number of filtered features</comment>
-        <translation type="unfinished">
-            <numerusform></numerusform>
-            <numerusform></numerusform>
+        <translation>
+            <numerusform>Le filtre a renvoyé %n entité</numerusform>
+            <numerusform>Le filtre a renvoyé %n entités</numerusform>
         </translation>
     </message>
 </context>
@@ -59516,12 +59515,12 @@ Ceci est peut-être dû à votre connexion ou celle du serveur WMS.</numerusform
     <message>
         <location filename="../src/customwidgets/qgsmaplayercomboboxplugin.cpp" line="74"/>
         <source>A combo box to list the layers</source>
-        <translation>Une combo box pour lister les couches</translation>
+        <translation>Une liste déroulante affichant les couches</translation>
     </message>
     <message>
         <location filename="../src/customwidgets/qgsmaplayercomboboxplugin.cpp" line="79"/>
         <source>A combo box to list the layers registered in QGIS. Layers might be filtered according to their type.</source>
-        <translation>Une combo box pour lister les couches présentes dans QGIS. Les couches peuvent être filtrées selon leur type.</translation>
+        <translation>Une liste déroulante affichant les couches présentes dans QGIS. Les couches peuvent être filtrées selon leur type.</translation>
     </message>
 </context>
 <context>
@@ -60188,7 +60187,7 @@ Ceci est peut-être dû à votre connexion ou celle du serveur WMS.</numerusform
     <message>
         <location filename="../src/app/nodetool/qgsmaptoolnodetool.cpp" line="231"/>
         <source>Could not snap to a feature in the current layer.</source>
-        <translation type="unfinished"></translation>
+        <translation>Impossible d'accrocher une entité de la couche actuelle.</translation>
     </message>
     <message>
         <location filename="../src/app/nodetool/qgsmaptoolnodetool.cpp" line="629"/>
@@ -79636,7 +79635,7 @@ p, li { white-space: pre-wrap; }
     <message>
         <location filename="../src/ui/editorwidgets/qgsuniquevaluesconfigdlgbase.ui" line="23"/>
         <source>The user can select one of the values already used in the field. If editable, a line edit is shown with autocompletion support, otherwise a combo box is used.</source>
-        <translation>L'utilisateur peut sélectionner l'une des valeurs déjà utilisées dans le champ. Une ligne est affichée avec le support de l'auto-complétion si "éditable" est coché, sinon une boîte de saisie est utilisée.</translation>
+        <translation>L'utilisateur peut sélectionner l'une des valeurs déjà utilisées dans le champ. Une zone de saisie est affichée avec le support de l'auto-complétion si "éditable" est coché, sinon une liste déroulante est utilisée.</translation>
     </message>
     <message>
         <location filename="../src/ui/editorwidgets/qgsuniquevaluesconfigdlgbase.ui" line="33"/>
@@ -79814,7 +79813,7 @@ L'erreur est : %2</translation>
     <message>
         <location filename="../src/ui/editorwidgets/qgsvaluemapconfigdlgbase.ui" line="20"/>
         <source>Combo box with predefined items. Value is stored in the attribute, description is shown in the combo box.</source>
-        <translation>Boîte de saisie avec des items prédéfinis. La valeur est stockée dans l'attribut, la description est affichée dans la boîte.</translation>
+        <translation>Liste déroulante avec des items prédéfinis. La valeur est stockée dans l'attribut, la description est affichée dans la liste.</translation>
     </message>
     <message>
         <location filename="../src/ui/editorwidgets/qgsvaluemapconfigdlgbase.ui" line="30"/>
@@ -95800,7 +95799,7 @@ p, li { white-space: pre-wrap; }
         <location filename="../src/plugins/evis/ui/evisgenericeventbrowserguibase.ui" line="710"/>
         <location filename="../src/plugins/evis/ui/evisgenericeventbrowserguibase.ui" line="774"/>
         <source>Remember this</source>
-        <translation>Ce souvenir de</translation>
+        <translation>Mémoriser</translation>
     </message>
     <message>
         <location filename="../src/plugins/evis/ui/evisgenericeventbrowserguibase.ui" line="267"/>
@@ -101517,7 +101516,7 @@ Base Path (i.e. keep only filename from attribute)</source>
     <message>
         <location filename="../python/plugins/MetaSearch/python-i18n.cpp" line="129"/>
         <source>Invalid CSW connections XML.</source>
-        <translation> XML de connexion CSW invalide.</translation>
+        <translation>XML de connexion CSW invalide.</translation>
     </message>
     <message>
         <location filename="../python/plugins/MetaSearch/python-i18n.cpp" line="132"/>
@@ -101976,7 +101975,7 @@ Base Path (i.e. keep only filename from attribute)</source>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="3937"/>
         <source>Spatialite files(*.sqlite)</source>
-        <translation>Fichiers Spatialite (*.sqlite) </translation>
+        <translation>Fichiers Spatialite (*.sqlite)</translation>
     </message>
 </context>
 <context>
diff --git a/i18n/qgis_pl.ts b/i18n/qgis_pl.ts
index 17cc3a1..8ce42ff 100644
--- a/i18n/qgis_pl.ts
+++ b/i18n/qgis_pl.ts
@@ -4586,7 +4586,7 @@ pola</translation>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="679"/>
         <source>Dissolved</source>
-        <translation>Agreguj</translation>
+        <translation>Wynik agregacji</translation>
     </message>
 </context>
 <context>
@@ -6165,7 +6165,7 @@ pola</translation>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="978"/>
         <source>Calculated</source>
-        <translation>Warstwa z obliczonym polem</translation>
+        <translation>Warstwa wynikowa</translation>
     </message>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="979"/>
@@ -6308,7 +6308,7 @@ pola</translation>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="1014"/>
         <source>Calculated</source>
-        <translation>Warstwa z obliczonym polem</translation>
+        <translation>Warstwa wynikowa</translation>
     </message>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="1015"/>
@@ -6564,7 +6564,7 @@ Blok kodu dla pola nie zwraca zmiennej "%s1"! Proszę nadać wartość
         <location filename="../python/plugins/processing/ui/widgetLayerSelector.ui" line="55"/>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="1103"/>
         <source>Iterate over this layer</source>
-        <translation>Kolejne na tej warstwie</translation>
+        <translation>Każdy obiekt przetwarzaj do osobnej warstwy</translation>
     </message>
     <message>
         <location filename="../python/plugins/processing/ui/widgetNumberSelector.ui" line="39"/>
@@ -16930,7 +16930,7 @@ Proszę sprawdzić ustawienia geoprocesingu.</translation>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="2083"/>
         <source>Iterate over this layer</source>
-        <translation>Kolejne na tej warstwie</translation>
+        <translation>Każdy obiekt przetwarzaj do osobnej warstwy</translation>
     </message>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="2084"/>
@@ -94105,7 +94105,7 @@ Base Path (i.e. keep only filename from attribute)</source>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="3165"/>
         <source>Number of raster band for raster A</source>
-        <translation>Numer pasma rastra A</translation>
+        <translation>Numer kanału warstwy A</translation>
     </message>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="3166"/>
@@ -94115,7 +94115,7 @@ Base Path (i.e. keep only filename from attribute)</source>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="3167"/>
         <source>Number of raster band for raster B</source>
-        <translation>Numer pasma rastra B</translation>
+        <translation>Numer kanału warstwy B</translation>
     </message>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="3168"/>
@@ -94125,7 +94125,7 @@ Base Path (i.e. keep only filename from attribute)</source>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="3169"/>
         <source>Number of raster band for raster C</source>
-        <translation>Numer pasma rastra C</translation>
+        <translation>Numer kanału warstwy C</translation>
     </message>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="3170"/>
@@ -94135,7 +94135,7 @@ Base Path (i.e. keep only filename from attribute)</source>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="3171"/>
         <source>Number of raster band for raster D</source>
-        <translation>Numer pasma rastra D</translation>
+        <translation>Numer kanału warstwy D</translation>
     </message>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="3172"/>
@@ -94145,7 +94145,7 @@ Base Path (i.e. keep only filename from attribute)</source>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="3173"/>
         <source>Number of raster band for raster E</source>
-        <translation>Numer pasma rastra E</translation>
+        <translation>Numer kanału warstwy E</translation>
     </message>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="3174"/>
@@ -94155,17 +94155,17 @@ Base Path (i.e. keep only filename from attribute)</source>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="3175"/>
         <source>Number of raster band for raster F</source>
-        <translation>Numer pasma rastra F</translation>
+        <translation>Numer kanału warstwy F</translation>
     </message>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="3176"/>
         <source>Calculation in gdalnumeric syntax using +-/* or any numpy array functions (i.e. logical_and())</source>
-        <translation>Obliczenia korzystają ze składni gdalnumeric +-/* i funkcji tablic numpy (np. logical_and())</translation>
+        <translation>Działanie (składnia gdalnumeric z użyciem +-/* i funkcji numpy, np. logical_and())</translation>
     </message>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="3177"/>
         <source>Set output nodata value</source>
-        <translation>Podaj wartość braku danych</translation>
+        <translation>Wartość dla braku danych</translation>
     </message>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="3178"/>
@@ -94180,7 +94180,7 @@ Base Path (i.e. keep only filename from attribute)</source>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="3180"/>
         <source>Calculated</source>
-        <translation>Warstwa z obliczonym polem</translation>
+        <translation>Warstwa wynikowa</translation>
     </message>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="3162"/>
diff --git a/python/core/symbology-ng/qgsarrowsymbollayer.sip b/python/core/symbology-ng/qgsarrowsymbollayer.sip
index 322b9b5..a9fbd9f 100644
--- a/python/core/symbology-ng/qgsarrowsymbollayer.sip
+++ b/python/core/symbology-ng/qgsarrowsymbollayer.sip
@@ -47,7 +47,7 @@ class QgsArrowSymbolLayer : public QgsLineSymbolLayerV2
     /** Set the scale for the arrow width */
     void setArrowWidthUnitScale( const QgsMapUnitScale& scale );
 
-    /** Get current arrow start width. Only meaningfull for single headed arrows */
+    /** Get current arrow start width. Only meaningful for single headed arrows */
     double arrowStartWidth() const;
     /** Set the arrow start width */
     void setArrowStartWidth( double width );
diff --git a/python/gui/editorwidgets/qgsdatetimeedit.sip b/python/gui/editorwidgets/qgsdatetimeedit.sip
index be658a1..144a174 100644
--- a/python/gui/editorwidgets/qgsdatetimeedit.sip
+++ b/python/gui/editorwidgets/qgsdatetimeedit.sip
@@ -36,8 +36,16 @@ class QgsDateTimeEdit : QDateTimeEdit
     void setEmpty();
 
   protected:
-    virtual void resizeEvent( QResizeEvent* event );
-    void mousePressEvent( QMouseEvent*event );
     virtual void fixup(QString & input) const;
     virtual QValidator::State validate(QString &text, int &pos) const;
+
+    virtual void resizeEvent( QResizeEvent *event );
+
+    virtual void mousePressEvent( QMouseEvent *event );
+
+    virtual void focusOutEvent( QFocusEvent *event );
+
+    virtual void wheelEvent( QWheelEvent *event );
+
+    virtual void showEvent( QShowEvent *event );
 };
diff --git a/python/plugins/MetaSearch/dialogs/maindialog.py b/python/plugins/MetaSearch/dialogs/maindialog.py
index 6b8267e..a451361 100644
--- a/python/plugins/MetaSearch/dialogs/maindialog.py
+++ b/python/plugins/MetaSearch/dialogs/maindialog.py
@@ -437,6 +437,8 @@ class MetaSearchDialog(QDialog, BASE_CLASS):
         self.timeout = self.spnTimeout.value()
 
         # bbox
+        # CRS is WGS84 with axis order longitude, latitude
+        # defined by 'urn:ogc:def:crs:OGC:1.3:CRS84'
         minx = self.leWest.text()
         miny = self.leSouth.text()
         maxx = self.leEast.text()
@@ -447,7 +449,8 @@ class MetaSearchDialog(QDialog, BASE_CLASS):
         # even for a global bbox, if a spatial filter is applied, then
         # the CSW server will skip records without a bbox
         if bbox != ['-180', '-90', '180', '90']:
-            self.constraints.append(BBox(bbox))
+            self.constraints.append(BBox(bbox,
+                                         crs='urn:ogc:def:crs:OGC:1.3:CRS84'))
 
         # keywords
         if self.leKeywords.text():
diff --git a/python/plugins/processing/algs/grass7/description/v.segment.txt b/python/plugins/processing/algs/grass7/description/v.segment.txt
index 481a791..9b3ca86 100644
--- a/python/plugins/processing/algs/grass7/description/v.segment.txt
+++ b/python/plugins/processing/algs/grass7/description/v.segment.txt
@@ -2,5 +2,5 @@ v.segment
 Creates points/segments from input vector lines and positions.
 Vector (v.*)
 ParameterVector|input|Input lines layer|1|False
-ParameterFile|file|File containing segment rules|False
+ParameterFile|rules|File containing segment rules|False
 OutputVector|output|Segments
diff --git a/python/plugins/processing/gui/ScriptEditorDialog.py b/python/plugins/processing/gui/ScriptEditorDialog.py
index 243a5c9..070ce1e 100644
--- a/python/plugins/processing/gui/ScriptEditorDialog.py
+++ b/python/plugins/processing/gui/ScriptEditorDialog.py
@@ -62,6 +62,8 @@ class ScriptEditorDialog(BASE, WIDGET):
         super(ScriptEditorDialog, self).__init__(None)
         self.setupUi(self)
 
+        self.searchWidget.setVisible(False)
+
         self.setWindowFlags(Qt.WindowMinimizeButtonHint |
                             Qt.WindowMaximizeButtonHint |
                             Qt.WindowCloseButtonHint)
@@ -76,6 +78,8 @@ class ScriptEditorDialog(BASE, WIDGET):
             QIcon(os.path.join(pluginPath, 'images', 'edithelp.png')))
         self.btnRun.setIcon(
             QIcon(os.path.join(pluginPath, 'images', 'runalgorithm.png')))
+        self.btnSearch.setIcon(
+            QIcon(os.path.join(pluginPath, 'images', 'search.png')))
         self.btnCut.setIcon(QgsApplication.getThemeIcon('/mActionEditCut.svg'))
         self.btnCopy.setIcon(
             QgsApplication.getThemeIcon('/mActionEditCopy.svg'))
@@ -97,10 +101,15 @@ class ScriptEditorDialog(BASE, WIDGET):
         self.btnPaste.clicked.connect(self.editor.paste)
         self.btnUndo.clicked.connect(self.editor.undo)
         self.btnRedo.clicked.connect(self.editor.redo)
+        self.btnSearch.clicked.connect(self.toggleSearchBox)
         self.btnIncreaseFont.clicked.connect(self.editor.zoomIn)
         self.btnDecreaseFont.clicked.connect(self.editor.zoomOut)
+        self.btnFind.clicked.connect(self.find)
+        self.btnReplace.clicked.connect(self.replace)
         self.editor.textChanged.connect(lambda: self.setHasChanged(True))
 
+        self.lastSearch = None
+
         self.alg = alg
         self.algType = algType
 
@@ -138,6 +147,22 @@ class ScriptEditorDialog(BASE, WIDGET):
 
         self.editor.setLexerType(self.algType)
 
+    def find(self):
+        txt = self.findBox.text()
+        cs = self.chkCaseSensitive.isChecked()
+        wo = self.chkWholeWord.isChecked()
+        if self.lastSearch is None or txt != self.lastSearch:
+            self.editor.findFirst(txt, False, cs, wo, True)
+        else:
+            self.editor.findNext()
+
+    def replace(self):
+        txt = self.replaceBox.text()
+        self.editor.replaceSelectedText(txt)
+
+    def toggleSearchBox(self):
+        self.searchWidget.setVisible(not self.searchWidget.isVisible())
+
     def showSnippets(self, evt):
         popupmenu = QMenu()
         for name, snippet in self.snippets.iteritems():
diff --git a/python/plugins/processing/images/search.png b/python/plugins/processing/images/search.png
new file mode 100644
index 0000000..0f1b117
Binary files /dev/null and b/python/plugins/processing/images/search.png differ
diff --git a/python/plugins/processing/ui/DlgScriptEditor.ui b/python/plugins/processing/ui/DlgScriptEditor.ui
index ad3001c..8b1c113 100644
--- a/python/plugins/processing/ui/DlgScriptEditor.ui
+++ b/python/plugins/processing/ui/DlgScriptEditor.ui
@@ -7,19 +7,13 @@
     <x>0</x>
     <y>0</y>
     <width>720</width>
-    <height>480</height>
+    <height>518</height>
    </rect>
   </property>
   <property name="windowTitle">
    <string>Script editor</string>
   </property>
   <layout class="QVBoxLayout" name="verticalLayout">
-   <property name="spacing">
-    <number>6</number>
-   </property>
-   <property name="margin">
-    <number>9</number>
-   </property>
    <item>
     <layout class="QHBoxLayout" name="horizontalLayout">
      <property name="spacing">
@@ -244,6 +238,20 @@
       </widget>
      </item>
      <item>
+      <widget class="QToolButton" name="btnSearch">
+       <property name="text">
+        <string>...</string>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="Line" name="line_7">
+       <property name="orientation">
+        <enum>Qt::Vertical</enum>
+       </property>
+      </widget>
+     </item>
+     <item>
       <widget class="QToolButton" name="btnIncreaseFont">
        <property name="text">
         <string>A+</string>
@@ -281,6 +289,85 @@
    <item>
     <widget class="ScriptEdit" name="editor"/>
    </item>
+   <item>
+    <widget class="QWidget" name="searchWidget" native="true">
+     <layout class="QGridLayout" name="gridLayout">
+      <property name="leftMargin">
+       <number>0</number>
+      </property>
+      <property name="topMargin">
+       <number>5</number>
+      </property>
+      <property name="rightMargin">
+       <number>0</number>
+      </property>
+      <property name="bottomMargin">
+       <number>5</number>
+      </property>
+      <item row="0" column="0">
+       <widget class="QCheckBox" name="chkCaseSensitive">
+        <property name="text">
+         <string>Case sensitive</string>
+        </property>
+       </widget>
+      </item>
+      <item row="1" column="0">
+       <widget class="QCheckBox" name="chkWholeWord">
+        <property name="text">
+         <string>Whole word</string>
+        </property>
+       </widget>
+      </item>
+      <item row="1" column="4" colspan="2">
+       <widget class="QPushButton" name="btnReplace">
+        <property name="sizePolicy">
+         <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
+          <horstretch>0</horstretch>
+          <verstretch>0</verstretch>
+         </sizepolicy>
+        </property>
+        <property name="text">
+         <string>Replace</string>
+        </property>
+       </widget>
+      </item>
+      <item row="0" column="2">
+       <widget class="QLabel" name="label">
+        <property name="text">
+         <string>Find what:</string>
+        </property>
+       </widget>
+      </item>
+      <item row="1" column="2">
+       <widget class="QLabel" name="label_2">
+        <property name="text">
+         <string>Replace with:</string>
+        </property>
+       </widget>
+      </item>
+      <item row="1" column="3">
+       <widget class="QLineEdit" name="replaceBox"/>
+      </item>
+      <item row="0" column="4" colspan="2">
+       <widget class="QPushButton" name="btnFind">
+        <property name="text">
+         <string>Find</string>
+        </property>
+       </widget>
+      </item>
+      <item row="0" column="3">
+       <widget class="QLineEdit" name="findBox"/>
+      </item>
+      <item row="0" column="1" rowspan="2">
+       <widget class="Line" name="line_8">
+        <property name="orientation">
+         <enum>Qt::Vertical</enum>
+        </property>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
   </layout>
  </widget>
  <customwidgets>
diff --git a/src/analysis/raster/qgsalignraster.cpp b/src/analysis/raster/qgsalignraster.cpp
index 1ff5d21..2cf38d6 100644
--- a/src/analysis/raster/qgsalignraster.cpp
+++ b/src/analysis/raster/qgsalignraster.cpp
@@ -16,7 +16,7 @@
 #include "qgsalignraster.h"
 
 #include <gdalwarper.h>
-#include <ogr_spatialref.h>
+#include <ogr_srs_api.h>
 #include <cpl_conv.h>
 #include <limits>
 
diff --git a/src/app/qgsbookmarks.cpp b/src/app/qgsbookmarks.cpp
index eaf6f81..ef4b6b5 100644
--- a/src/app/qgsbookmarks.cpp
+++ b/src/app/qgsbookmarks.cpp
@@ -41,7 +41,7 @@ QgsBookmarks::QgsBookmarks( QWidget *parent )
     : QgsDockWidget( parent )
     , mQgisModel( nullptr )
     , mProjectModel( nullptr )
-    , mModel( nullptr )
+    , mMergedModel( nullptr )
     , mProxyModel( nullptr )
 {
   setupUi( this );
@@ -64,8 +64,8 @@ QgsBookmarks::QgsBookmarks( QWidget *parent )
   btnExport->setIcon( QgsApplication::getThemeIcon( "/mActionSharingExport.svg" ) );
   btnImport->setIcon( QgsApplication::getThemeIcon( "/mActionSharingImport.svg" ) );
 
-  connect( btnExport, SIGNAL( triggered() ), this, SLOT( exportToXML() ) );
-  connect( btnImport, SIGNAL( triggered() ), this, SLOT( importFromXML() ) );
+  connect( btnExport, SIGNAL( triggered() ), this, SLOT( exportToXml() ) );
+  connect( btnImport, SIGNAL( triggered() ), this, SLOT( importFromXml() ) );
   btnImpExp->setMenu( share );
 
 
@@ -109,15 +109,20 @@ QgsBookmarks::QgsBookmarks( QWidget *parent )
   mQgisModel->setHeaderData( 7, Qt::Horizontal, tr( "SRID" ) );
 
   mProjectModel = new QgsProjectBookmarksTableModel( this );
-  mModel = new QgsMergedBookmarksTableModel( *mQgisModel, *mProjectModel, lstBookmarks, this );
+  mMergedModel = new QgsMergedBookmarksTableModel( *mQgisModel, *mProjectModel, lstBookmarks, this );
 
-  mProxyModel = new QgsBookmarksProxyModel( this );
-  mProxyModel->setSourceModel( mModel );
+  mProxyModel = new QgsBookmarksProxyModel( );
+  mProxyModel->setSourceModel( mMergedModel );
+  mProxyModel->setSortCaseSensitivity( Qt::CaseInsensitive );
 
   lstBookmarks->setModel( mProxyModel );
   lstBookmarks->setItemDelegate( new QgsDoubleSpinBoxBookmarksDelegate( this ) );
+  lstBookmarks->setSortingEnabled( true );
+  lstBookmarks->sortByColumn( 1, Qt::AscendingOrder );
 
-  connect( mModel, SIGNAL( layoutChanged() ), mProxyModel, SLOT( _resetModel() ) );
+  connect( mMergedModel, SIGNAL( layoutChanged() ), mProxyModel, SLOT( _resetModel() ) );
+
+  connect( mMergedModel, SIGNAL( &QgsMergedBookmarksTableModel::selectItem( const QModelIndex &index ) ), this, SLOT( scrollToIndex( const QModelIndex &index ) ) );
 
   QSettings settings;
   lstBookmarks->header()->restoreState( settings.value( "Windows/Bookmarks/headerstate" ).toByteArray() );
@@ -130,6 +135,7 @@ QgsBookmarks::QgsBookmarks( QWidget *parent )
 QgsBookmarks::~QgsBookmarks()
 {
   delete mQgisModel;
+  delete mProxyModel;
   QSqlDatabase::removeDatabase( "bookmarks" );
   saveWindowLocation();
 }
@@ -149,7 +155,7 @@ void QgsBookmarks::saveWindowLocation()
 
 void QgsBookmarks::addClicked()
 {
-  Q_ASSERT( mModel );
+  Q_ASSERT( mMergedModel );
   Q_ASSERT( mQgisModel );
 
   QgsMapCanvas *canvas = QgisApp::instance()->mapCanvas();
@@ -182,7 +188,7 @@ void QgsBookmarks::addClicked()
   {
     mQgisModel->setSort( 0, Qt::AscendingOrder );
     mQgisModel->select();
-    QModelIndex newIdx = mProxyModel->mapFromSource( mModel->index( mQgisModel->rowCount() - 1, 1 ) );
+    QModelIndex newIdx = mProxyModel->mapFromSource( mMergedModel->index( mQgisModel->rowCount() - 1, 1 ) );
     // Edit new bookmark title
     lstBookmarks->scrollTo( newIdx );
     lstBookmarks->setCurrentIndex( newIdx );
@@ -198,16 +204,17 @@ void QgsBookmarks::addClicked()
 
 void QgsBookmarks::deleteClicked()
 {
-  QList<int> rows;
-  Q_FOREACH ( const QModelIndex &idx, lstBookmarks->selectionModel()->selectedIndexes() )
+  QItemSelection selection( mProxyModel->mapSelectionToSource( lstBookmarks->selectionModel()->selection() ) );
+  std::vector<int> rows;
+  Q_FOREACH ( const QModelIndex &idx, selection.indexes() )
   {
     if ( idx.column() == 1 )
     {
-      rows << idx.row();
+      rows.push_back( idx.row() );
     }
   }
 
-  if ( rows.isEmpty() )
+  if ( rows.size() == 0 )
     return;
 
   // make sure the user really wants to delete these bookmarks
@@ -216,12 +223,14 @@ void QgsBookmarks::deleteClicked()
        QMessageBox::Ok | QMessageBox::Cancel ) )
     return;
 
-  int i = 0;
+  // Remove in reverse order to keep the merged model indexes
+  std::sort( rows.begin(), rows.end(), std::greater<int>() );
+
   Q_FOREACH ( int row, rows )
   {
-    mModel->removeRow( row - i );
-    i++;
+    mMergedModel->removeRow( row );
   }
+  mProxyModel->_resetModel();
 }
 
 void QgsBookmarks::lstBookmarks_doubleClicked( const QModelIndex &index )
@@ -290,7 +299,7 @@ void QgsBookmarks::importFromXml()
   QDomElement docElem = doc.documentElement();
   QDomNodeList nodeList = docElem.elementsByTagName( "bookmark" );
 
-  Q_ASSERT( mModel );
+  Q_ASSERT( mMergedModel );
 
   QString queries;
 
@@ -335,6 +344,7 @@ void QgsBookmarks::importFromXml()
   }
   mQgisModel->setSort( 0, Qt::AscendingOrder );
   mQgisModel->select();
+  mProxyModel->_resetModel();
 }
 
 void QgsBookmarks::exportToXml()
@@ -359,8 +369,8 @@ void QgsBookmarks::exportToXml()
   QDomElement root = doc.createElement( "qgis_bookmarks" );
   doc.appendChild( root );
 
-  int rowCount = mModel->rowCount();
-  int colCount = mModel->columnCount() - 1;  // exclude virtual "In project" column
+  int rowCount = mMergedModel->rowCount();
+  int colCount = mMergedModel->columnCount() - 1;  // exclude virtual "In project" column
 
   QList<QString> headerList;
   headerList
@@ -379,12 +389,21 @@ void QgsBookmarks::exportToXml()
     root.appendChild( bookmark );
     for ( int j = 0; j < colCount; j++ )
     {
-      QModelIndex idx = mModel->index( i, j );
+      QModelIndex idx = mMergedModel->index( i, j );
       if ( idx.isValid() )
       {
         QString value = idx.data( Qt::DisplayRole ).toString();
-        QDomText idText = doc.createTextNode( value );
         QString header = headerList.at( j );
+        // If it's the EPSG code, convert it to internal srid
+        if ( header == "sr_id" )
+        {
+          QgsCoordinateReferenceSystem crs = QgsCRSCache::instance()->crsByOgcWmsCrs( value );
+          if ( crs.isValid() )
+            value = QString::number( crs.srsid() );
+          else
+            value = QString();
+        }
+        QDomText idText = doc.createTextNode( value );
         QDomElement id = doc.createElement( header );
         id.appendChild( idText );
         bookmark.appendChild( id );
@@ -407,6 +426,13 @@ void QgsBookmarks::exportToXml()
   settings.setValue( "Windows/Bookmarks/LastUsedDirectory", QFileInfo( fileName ).path() );
 }
 
+void QgsBookmarks::scrollToIndex( const QModelIndex & index )
+{
+  QModelIndex proxyIndex( mProxyModel->mapFromSource( index ) );
+  lstBookmarks->scrollTo( proxyIndex );
+  lstBookmarks->setCurrentIndex( proxyIndex );
+}
+
 QgsProjectBookmarksTableModel::QgsProjectBookmarksTableModel( QObject *parent )
     : QAbstractTableModel( parent )
 {
@@ -433,8 +459,10 @@ int QgsProjectBookmarksTableModel::columnCount( const QModelIndex &parent ) cons
 
 QVariant QgsProjectBookmarksTableModel::data( const QModelIndex& index, int role ) const
 {
-  Q_UNUSED( role );
-  Q_ASSERT( role == Qt::DisplayRole );
+  if ( role != Qt::DisplayRole && role != Qt::EditRole )
+  {
+    return QVariant();
+  }
 
   switch ( index.column() )
   {
@@ -494,9 +522,11 @@ bool QgsProjectBookmarksTableModel::setData( const QModelIndex& index, const QVa
 bool QgsProjectBookmarksTableModel::insertRows( int row, int count, const QModelIndex &parent )
 {
   Q_UNUSED( parent );
-  beginInsertRows( parent, row, row + count );
-
-  bool result = QgsProject::instance()->writeEntry( "Bookmarks" ,  "/count", QgsProject::instance()->readNumEntry( "Bookmarks",  "/count" ) + count );
+  Q_UNUSED( row );
+  // append
+  int oldCount = QgsProject::instance()->readNumEntry( "Bookmarks", "/count" );
+  beginInsertRows( parent, oldCount, oldCount + count );
+  bool result = QgsProject::instance()->writeEntry( "Bookmarks", "/count", oldCount + count );
   endInsertRows();
   return result;
 }
@@ -610,6 +640,7 @@ QVariant QgsMergedBookmarksTableModel::data( const QModelIndex &index, int role
 
 bool QgsMergedBookmarksTableModel::setData( const QModelIndex &index, const QVariant &value, int role )
 {
+  bool result = false;
   // last column triggers a move from QGIS to project bookmark
   if ( index.column() == mQgisTableModel.columnCount() )
   {
@@ -617,29 +648,30 @@ bool QgsMergedBookmarksTableModel::setData( const QModelIndex &index, const QVar
     {
       // Move from SQLite storage to project
       moveBookmark( mQgisTableModel, mProjectTableModel, index.row() );
-      mTreeView->scrollTo( this->index( rowCount() - 1, 1 ) );
-      mTreeView->setCurrentIndex( this->index( rowCount() - 1, 1 ) );
-      mTreeView->selectionModel()->select( this->index( rowCount() - 1, 1 ), QItemSelectionModel::Rows );
+      emit selectItem( this->index( rowCount() - 1, 1 ) );
     }
     else
     {
       //Move from project to SQLite storage
       moveBookmark( mProjectTableModel, mQgisTableModel, index.row() - mQgisTableModel.rowCount() );
-      mTreeView->scrollTo( this->index( mQgisTableModel.rowCount() - 1, 1 ) );
-      mTreeView->setCurrentIndex( this->index( mQgisTableModel.rowCount() - 1, 1 ) );
-      mTreeView->selectionModel()->select( this->index( mQgisTableModel.rowCount() - 1, 1 ), QItemSelectionModel::Rows );
+      emit selectItem( this->index( mQgisTableModel.rowCount() - 1, 1 ) );
     }
-    return true;
-  }
-
-  if ( index.row() < mQgisTableModel.rowCount() )
-  {
-    return mQgisTableModel.setData( index, value, role );
+    result = true;
   }
   else
   {
-    return mProjectTableModel.setData( this->index( index.row() - mQgisTableModel.rowCount(), index.column() ), value, role );
+    if ( index.row() < mQgisTableModel.rowCount() )
+    {
+      result = mQgisTableModel.setData( index, value, role );
+    }
+    else
+    {
+      result = mProjectTableModel.setData( this->index( index.row() - mQgisTableModel.rowCount(), index.column() ), value, role );
+    }
   }
+  if ( result )
+    emit dataChanged( index, index );
+  return result;
 }
 
 Qt::ItemFlags QgsMergedBookmarksTableModel::flags( const QModelIndex &index ) const
@@ -666,7 +698,6 @@ bool QgsMergedBookmarksTableModel::removeRows( int row, int count, const QModelI
 {
   Q_ASSERT( count == 1 );
   bool result;
-  beginRemoveRows( parent, row, row + count );
   if ( row < mQgisTableModel.rowCount() )
   {
     QSqlTableModel *qgisModel = static_cast<QSqlTableModel *>( &mQgisTableModel );
@@ -678,7 +709,7 @@ bool QgsMergedBookmarksTableModel::removeRows( int row, int count, const QModelI
   {
     result = mProjectTableModel.removeRows( row - mQgisTableModel.rowCount(), count, parent );
   }
-  endRemoveRows();
+  allLayoutChanged();
   return result;
 }
 
diff --git a/src/app/qgsbookmarks.h b/src/app/qgsbookmarks.h
index ca2b6b9..5422042 100644
--- a/src/app/qgsbookmarks.h
+++ b/src/app/qgsbookmarks.h
@@ -105,6 +105,10 @@ class QgsMergedBookmarksTableModel: public QAbstractTableModel
     bool projectAvailable() const;
     void moveBookmark( QAbstractTableModel& modelFrom, QAbstractTableModel& modelTo, int row );
 
+  signals:
+
+    void selectItem( const QModelIndex &index );
+
   private slots:
     void allLayoutChanged()
     {
@@ -155,10 +159,12 @@ class APP_EXPORT QgsBookmarks : public QgsDockWidget, private Ui::QgsBookmarksBa
 
     void lstBookmarks_doubleClicked( const QModelIndex & );
 
+    void scrollToIndex( const QModelIndex & );
+
   private:
     QSqlTableModel *mQgisModel;
     QgsProjectBookmarksTableModel *mProjectModel;
-    QgsMergedBookmarksTableModel *mModel;
+    QgsMergedBookmarksTableModel *mMergedModel;
     QgsBookmarksProxyModel *mProxyModel;
 
     void saveWindowLocation();
diff --git a/src/app/qgsmaptoolreshape.cpp b/src/app/qgsmaptoolreshape.cpp
index 5c80c69..ed8680d 100644
--- a/src/app/qgsmaptoolreshape.cpp
+++ b/src/app/qgsmaptoolreshape.cpp
@@ -75,70 +75,122 @@ void QgsMapToolReshape::cadCanvasReleaseEvent( QgsMapMouseEvent * e )
       stopCapturing();
       return;
     }
-    QgsPoint firstPoint = points().at( 0 );
-    QgsRectangle bbox( firstPoint.x(), firstPoint.y(), firstPoint.x(), firstPoint.y() );
-    for ( int i = 1; i < size(); ++i )
-    {
-      bbox.combineExtentWith( points().at( i ).x(), points().at( i ).y() );
-    }
 
-    //query all the features that intersect bounding box of capture line
-    QgsFeatureIterator fit = vlayer->getFeatures( QgsFeatureRequest().setFilterRect( bbox ).setSubsetOfAttributes( QgsAttributeList() ) );
-    QgsFeature f;
-    int reshapeReturn;
-    bool reshapeDone = false;
+    reshape( vlayer );
+
+    stopCapturing();
+  }
+}
+
+void QgsMapToolReshape::reshape( QgsVectorLayer *vlayer )
+{
+  std::cout << "QgsMapToolReshape::reshape 0" << std::endl;
+  if ( !vlayer )
+    return;
+
+  QgsPoint firstPoint = points().at( 0 );
+  QgsRectangle bbox( firstPoint.x(), firstPoint.y(), firstPoint.x(), firstPoint.y() );
+  for ( int i = 1; i < size(); ++i )
+  {
+    bbox.combineExtentWith( points().at( i ).x(), points().at( i ).y() );
+  }
 
-    vlayer->beginEditCommand( tr( "Reshape" ) );
-    while ( fit.nextFeature( f ) )
+  //query all the features that intersect bounding box of capture line
+  std::cout << "QgsMapToolReshape::reshape 1" << std::endl;
+  QgsFeatureIterator fit = vlayer->getFeatures( QgsFeatureRequest().setFilterRect( bbox ).setSubsetOfAttributes( QgsAttributeList() ) );
+  QgsFeature f;
+  int reshapeReturn;
+  bool reshapeDone = false;
+  bool isBinding = isBindingLine( vlayer, bbox );
+
+  vlayer->beginEditCommand( tr( "Reshape" ) );
+  std::cout << "QgsMapToolReshape::reshape 2" << std::endl;
+  while ( fit.nextFeature( f ) )
+  {
+    std::cout << "QgsMapToolReshape::reshape 3" << std::endl;
+    //query geometry
+    //call geometry->reshape(mCaptureList)
+    //register changed geometry in vector layer
+    QgsGeometry* geom = f.geometry();
+    if ( geom )
     {
-      //query geometry
-      //call geometry->reshape(mCaptureList)
-      //register changed geometry in vector layer
-      QgsGeometry* geom = f.geometry();
-      if ( geom )
+      std::cout << "QgsMapToolReshape::reshape 4" << std::endl;
+      // in case of a binding line, we just want to update the line from
+      // the starting point and not both side
+      if ( isBinding && !geom->asPolyline().contains( points().first() ) )
+        continue;
+
+      std::cout << "QgsMapToolReshape::reshape 5" << std::endl;
+      reshapeReturn = geom->reshapeGeometry( pointsV2() );
+      if ( reshapeReturn == 0 )
       {
-        reshapeReturn = geom->reshapeGeometry( pointsV2() );
-        if ( reshapeReturn == 0 )
+        //avoid intersections on polygon layers
+        if ( vlayer->geometryType() == QGis::Polygon )
         {
-          //avoid intersections on polygon layers
-          if ( vlayer->geometryType() == QGis::Polygon )
+          //ignore all current layer features as they should be reshaped too
+          QMap<QgsVectorLayer*, QSet<QgsFeatureId> > ignoreFeatures;
+          ignoreFeatures.insert( vlayer, vlayer->allFeatureIds() );
+
+          if ( geom->avoidIntersections( ignoreFeatures ) != 0 )
           {
-            //ignore all current layer features as they should be reshaped too
-            QMap<QgsVectorLayer*, QSet<QgsFeatureId> > ignoreFeatures;
-            ignoreFeatures.insert( vlayer, vlayer->allFeatureIds() );
-
-            if ( geom->avoidIntersections( ignoreFeatures ) != 0 )
-            {
-              emit messageEmitted( tr( "An error was reported during intersection removal" ), QgsMessageBar::CRITICAL );
-              vlayer->destroyEditCommand();
-              stopCapturing();
-              return;
-            }
-
-            if ( geom->isGeosEmpty() ) //intersection removal might have removed the whole geometry
-            {
-              emit messageEmitted( tr( "The feature cannot be reshaped because the resulting geometry is empty" ), QgsMessageBar::CRITICAL );
-              vlayer->destroyEditCommand();
-              stopCapturing();
-              return;
-            }
+            emit messageEmitted( tr( "An error was reported during intersection removal" ), QgsMessageBar::CRITICAL );
+            vlayer->destroyEditCommand();
+            stopCapturing();
+            return;
           }
 
-          vlayer->changeGeometry( f.id(), geom );
-          reshapeDone = true;
+          if ( geom->isGeosEmpty() ) //intersection removal might have removed the whole geometry
+          {
+            emit messageEmitted( tr( "The feature cannot be reshaped because the resulting geometry is empty" ), QgsMessageBar::CRITICAL );
+            vlayer->destroyEditCommand();
+            stopCapturing();
+            return;
+          }
         }
+
+        vlayer->changeGeometry( f.id(), geom );
+        reshapeDone = true;
       }
     }
+  }
 
-    if ( reshapeDone )
-    {
-      vlayer->endEditCommand();
-    }
-    else
+  if ( reshapeDone )
+  {
+    vlayer->endEditCommand();
+  }
+  else
+  {
+    vlayer->destroyEditCommand();
+  }
+}
+
+bool QgsMapToolReshape::isBindingLine( QgsVectorLayer *vlayer, const QgsRectangle &bbox ) const
+{
+  if ( vlayer->geometryType() != QGis::Line )
+    return false;
+
+  bool begin = false;
+  bool end = false;
+  const QgsPoint beginPoint = points().first();
+  const QgsPoint endPoint = points().last();
+
+  QgsFeatureIterator fit = vlayer->getFeatures( QgsFeatureRequest().setFilterRect( bbox ).setSubsetOfAttributes( QgsAttributeList() ) );
+  QgsFeature f;
+
+  // check that extremities of the new line are contained by features
+  while ( fit.nextFeature( f ) )
+  {
+    const QgsGeometry *geom = f.geometry();
+    if ( geom )
     {
-      vlayer->destroyEditCommand();
-    }
+      const QgsPolyline line = geom->asPolyline();
 
-    stopCapturing();
+      if ( line.contains( beginPoint ) )
+        begin = true;
+      else if ( line.contains( endPoint ) )
+        end = true;
+    }
   }
+
+  return end && begin;
 }
diff --git a/src/app/qgsmaptoolreshape.h b/src/app/qgsmaptoolreshape.h
index c283bef..4dce6e0 100644
--- a/src/app/qgsmaptoolreshape.h
+++ b/src/app/qgsmaptoolreshape.h
@@ -28,6 +28,13 @@ class APP_EXPORT QgsMapToolReshape: public QgsMapToolCapture
     QgsMapToolReshape( QgsMapCanvas* canvas );
     virtual ~QgsMapToolReshape();
     void cadCanvasReleaseEvent( QgsMapMouseEvent * e ) override;
+
+  private:
+    void reshape( QgsVectorLayer *vlayer );
+
+    bool isBindingLine( QgsVectorLayer *vlayer, const QgsRectangle &bbox ) const;
+
+    friend class TestQgsMapToolReshape;
 };
 
 #endif
diff --git a/src/app/qgsoptions.cpp b/src/app/qgsoptions.cpp
index 031e8f4..6f05d4f 100644
--- a/src/app/qgsoptions.cpp
+++ b/src/app/qgsoptions.cpp
@@ -928,7 +928,8 @@ QgsOptions::QgsOptions( QWidget *parent, Qt::WindowFlags fl )
   mVariableEditor->reloadContext();
   mVariableEditor->setEditableScopeIndex( 0 );
 
-
+  const QString key = "/QgsRelationReferenceWidget/cacheSize";
+  mSettings->setValue( key, mSettings->value( key, 200000 ) );
 
   mAdvancedSettingsEditor->setSettingsObject( mSettings );
 
diff --git a/src/app/qgsversioninfo.cpp b/src/app/qgsversioninfo.cpp
index 30229d7..aa0210f 100644
--- a/src/app/qgsversioninfo.cpp
+++ b/src/app/qgsversioninfo.cpp
@@ -28,7 +28,7 @@ QgsVersionInfo::QgsVersionInfo( QObject *parent )
 
 void QgsVersionInfo::checkVersion()
 {
-  QNetworkReply *reply = QgsNetworkAccessManager::instance()->get( QNetworkRequest( QUrl( "https://ubuntu.qgis.org/version.txt" ) ) );
+  QNetworkReply *reply = QgsNetworkAccessManager::instance()->get( QNetworkRequest( QUrl( "https://version.qgis.org/version.txt" ) ) );
   connect( reply, SIGNAL( finished() ), this, SLOT( versionReplyFinished() ) );
 }
 
diff --git a/src/core/qgsdataitem.cpp b/src/core/qgsdataitem.cpp
index 1aa35a3..bf83ad0 100644
--- a/src/core/qgsdataitem.cpp
+++ b/src/core/qgsdataitem.cpp
@@ -40,6 +40,7 @@
 #include "qgsconfig.h"
 
 // use GDAL VSI mechanism
+#define CPL_SUPRESS_CPLUSPLUS
 #include "cpl_vsi.h"
 #include "cpl_string.h"
 
@@ -1301,7 +1302,7 @@ char **VSIReadDirRecursive1( const char *pszPath )
   char **papszFiles1 = nullptr;
   char **papszFiles2 = nullptr;
   VSIStatBufL psStatBuf;
-  CPLString osTemp1, osTemp2;
+  QString temp1, temp2;
   int i, j;
   int nCount1, nCount2;
 
@@ -1315,41 +1316,35 @@ char **VSIReadDirRecursive1( const char *pszPath )
   for ( i = 0; i < nCount1; i++ )
   {
     // build complete file name for stat
-    osTemp1.clear();
-    osTemp1.append( pszPath );
-    osTemp1.append( "/" );
-    osTemp1.append( papszFiles1[i] );
+    temp1 = QString( "%1/%2" ).arg( pszPath, papszFiles1[i] );
 
     // if is file, add it
-    if ( VSIStatL( osTemp1.c_str(), &psStatBuf ) == 0 &&
+    if ( VSIStatL( temp1.toUtf8(), &psStatBuf ) == 0 &&
          VSI_ISREG( psStatBuf.st_mode ) )
     {
       // oFiles.AddString( papszFiles1[i] );
       papszOFiles = CSLAddString( papszOFiles, papszFiles1[i] );
     }
-    else if ( VSIStatL( osTemp1.c_str(), &psStatBuf ) == 0 &&
+    else if ( VSIStatL( temp1.toUtf8(), &psStatBuf ) == 0 &&
               VSI_ISDIR( psStatBuf.st_mode ) )
     {
       // add directory entry
-      osTemp2.clear();
-      osTemp2.append( papszFiles1[i] );
-      osTemp2.append( "/" );
-      // oFiles.AddString( osTemp2.c_str() );
-      papszOFiles = CSLAddString( papszOFiles, osTemp2.c_str() );
+      temp2 = QString( "%1/" ).arg( papszFiles1[i] );
+
+      // oFiles.AddString( temp2.toUtf8() );
+      papszOFiles = CSLAddString( papszOFiles, temp2.toUtf8() );
 
       // recursively add files inside directory
-      papszFiles2 = VSIReadDirRecursive1( osTemp1.c_str() );
+      papszFiles2 = VSIReadDirRecursive1( temp1.toUtf8() );
       if ( papszFiles2 )
       {
         nCount2 = CSLCount( papszFiles2 );
         for ( j = 0; j < nCount2; j++ )
         {
-          osTemp2.clear();
-          osTemp2.append( papszFiles1[i] );
-          osTemp2.append( "/" );
-          osTemp2.append( papszFiles2[j] );
-          // oFiles.AddString( osTemp2.c_str() );
-          papszOFiles = CSLAddString( papszOFiles, osTemp2.c_str() );
+          temp2 = QString( "%1/%2" ).arg( papszFiles1[i], papszFiles2[j] );
+
+          // oFiles.AddString( temp2.toUtf8() );
+          papszOFiles = CSLAddString( papszOFiles, temp2.toUtf8() );
         }
         CSLDestroy( papszFiles2 );
       }
diff --git a/src/core/qgsmaprendererjob.h b/src/core/qgsmaprendererjob.h
index 62c844a..488515b 100644
--- a/src/core/qgsmaprendererjob.h
+++ b/src/core/qgsmaprendererjob.h
@@ -97,7 +97,7 @@ class CORE_EXPORT QgsMapRendererJob : public QObject
     virtual void cancel() = 0;
 
     /**
-     * Triggers cancelation of the rendering job without blocking. The render job will continue
+     * Triggers cancellation of the rendering job without blocking. The render job will continue
      * to operate until it is able to cancel, at which stage the finished() signal will be emitted.
      * Does nothing if the rendering is not active.
      */
diff --git a/src/core/qgsofflineediting.cpp b/src/core/qgsofflineediting.cpp
index a556212..cb5f52d 100644
--- a/src/core/qgsofflineediting.cpp
+++ b/src/core/qgsofflineediting.cpp
@@ -316,7 +316,7 @@ void QgsOfflineEditing::synchronize()
         else
         {
           remoteLayer->rollBack();
-          showWarning( tr( "Syncronization failed" ) );
+          showWarning( tr( "Synchronization failed" ) );
         }
       }
       else
diff --git a/src/core/symbology-ng/qgsarrowsymbollayer.h b/src/core/symbology-ng/qgsarrowsymbollayer.h
index 14ac204..6a92062 100644
--- a/src/core/symbology-ng/qgsarrowsymbollayer.h
+++ b/src/core/symbology-ng/qgsarrowsymbollayer.h
@@ -65,7 +65,7 @@ class CORE_EXPORT QgsArrowSymbolLayer : public QgsLineSymbolLayerV2
     /** Set the scale for the arrow width */
     void setArrowWidthUnitScale( const QgsMapUnitScale& scale ) { mArrowWidthUnitScale = scale; }
 
-    /** Get current arrow start width. Only meaningfull for single headed arrows */
+    /** Get current arrow start width. Only meaningful for single headed arrows */
     double arrowStartWidth() const { return mArrowStartWidth; }
     /** Set the arrow start width */
     void setArrowStartWidth( double width ) { mArrowStartWidth = width; }
diff --git a/src/gui/editorwidgets/qgsdatetimeedit.cpp b/src/gui/editorwidgets/qgsdatetimeedit.cpp
index 3d23252..be489fb 100644
--- a/src/gui/editorwidgets/qgsdatetimeedit.cpp
+++ b/src/gui/editorwidgets/qgsdatetimeedit.cpp
@@ -13,10 +13,12 @@
  *                                                                         *
  ***************************************************************************/
 
+#include <QCalendarWidget>
 #include <QLineEdit>
 #include <QMouseEvent>
 #include <QSettings>
 #include <QStyle>
+#include <QStyleOptionSpinBox>
 #include <QToolButton>
 
 #include "qgsdatetimeedit.h"
@@ -37,11 +39,6 @@ QgsDateTimeEdit::QgsDateTimeEdit( QWidget *parent )
   mClearButton->hide();
   connect( mClearButton, SIGNAL( clicked() ), this, SLOT( clear() ) );
 
-  mNullLabel = new QLineEdit( QSettings().value( "qgis/nullValue", "NULL" ).toString(), this );
-  mNullLabel->setReadOnly( true );
-  mNullLabel->setStyleSheet( "position: absolute; border: none; font-style: italic; color: grey;" );
-  mNullLabel->hide();
-
   setStyleSheet( QString( ".QWidget, QLineEdit, QToolButton { padding-right: %1px; }" ).arg( mClearButton->sizeHint().width() + spinButtonWidth() + frameWidth() + 1 ) );
 
   QSize msz = minimumSizeHint();
@@ -50,6 +47,9 @@ QgsDateTimeEdit::QgsDateTimeEdit( QWidget *parent )
 
   connect( this, SIGNAL( dateTimeChanged( QDateTime ) ), this, SLOT( changed( QDateTime ) ) );
 
+  // enable calendar widget by default so it's already created
+  setCalendarPopup( true );
+
   // init with current time so mIsNull is properly initialized
   QDateTimeEdit::setDateTime( QDateTime::currentDateTime() );
 }
@@ -58,41 +58,170 @@ void QgsDateTimeEdit::setAllowNull( bool allowNull )
 {
   mAllowNull = allowNull;
 
-  mNullLabel->setVisible(( mAllowNull && mIsNull ) && !mIsEmpty );
   mClearButton->setVisible( mAllowNull && ( !mIsNull || mIsEmpty ) );
-  lineEdit()->setVisible(( !mAllowNull || !mIsNull ) && !mIsEmpty );
 }
 
 
 void QgsDateTimeEdit::clear()
 {
-  changed( QDateTime() );
-  emit dateTimeChanged( QDateTime() );
+  if ( mAllowNull )
+  {
+    displayNull();
+
+    changed( QDateTime() );
+
+    // avoid slot double activation
+    disconnect( this, SIGNAL( dateTimeChanged() ), this, SLOT( changed() ) );
+    emit dateTimeChanged( QDateTime() );
+    connect( this, SIGNAL( dateTimeChanged() ), this, SLOT( changed() ) );
+  }
 }
 
 void QgsDateTimeEdit::setEmpty()
 {
-  mNullLabel->setVisible( false );
-  lineEdit()->setVisible( false );
   mClearButton->setVisible( mAllowNull );
+  mIsEmpty = true;
 }
 
-void QgsDateTimeEdit::mousePressEvent( QMouseEvent* event )
+void QgsDateTimeEdit::mousePressEvent( QMouseEvent *event )
 {
-  QRect lerect = rect().adjusted( 0, 0, -spinButtonWidth(), 0 );
-  if ( mAllowNull && mIsNull && lerect.contains( event->pos() ) )
-    return;
+  // catch mouse press on the button
+  // in non-calendar mode: modifiy the date  so it leads to showing current date (don't bother about time)
+  // in calendar mode: be sure NULL is displayed when needed and show page of current date in calendar widget
+
+  bool updateCalendar = false;
+
+  if ( mIsNull )
+  {
+    QStyleOptionSpinBox opt;
+    this->initStyleOption( &opt );
+    const QRect buttonUpRect = style()->subControlRect( QStyle::CC_SpinBox, &opt, QStyle::SC_SpinBoxUp );
+    const QRect buttonDownRect = style()->subControlRect( QStyle::CC_SpinBox, &opt, QStyle::SC_SpinBoxDown );
+    if ( buttonUpRect.contains( event->pos() ) || buttonDownRect.contains( event->pos() ) )
+    {
+      if ( calendarPopup() && calendarWidget() )
+      {
+        // ensure the line edit still displays NULL
+        displayNull( true );
+        updateCalendar = true;
+      }
+      else
+      {
+        blockSignals( true );
+        resetBeforeChange( buttonUpRect.contains( event->pos() ) ? -1 : 1 );
+        blockSignals( false );
+      }
+    }
+  }
 
   QDateTimeEdit::mousePressEvent( event );
+
+  if ( updateCalendar )
+  {
+    // set calendar page to current date to avoid going to minimal date page when value is null
+    calendarWidget()->setCurrentPage( QDate::currentDate().year(), QDate::currentDate().month() );
+  }
+}
+
+void QgsDateTimeEdit::focusOutEvent( QFocusEvent *event )
+{
+  if ( mAllowNull && mIsNull )
+  {
+    if ( lineEdit()->text() != QSettings().value( "qgis/nullValue", "NULL" ).toString() )
+    {
+      displayNull();
+    }
+    QWidget::focusOutEvent( event );
+    emit editingFinished();
+  }
+  else
+  {
+    QDateTimeEdit::focusOutEvent( event );
+  }
+}
+
+void QgsDateTimeEdit::wheelEvent( QWheelEvent *event )
+{
+  // dateTime might have been set to minimum in calendar mode
+  if ( mAllowNull && mIsNull )
+  {
+    resetBeforeChange( -event->delta() );
+  }
+  QDateTimeEdit::wheelEvent( event );
+}
+
+void QgsDateTimeEdit::showEvent( QShowEvent *event )
+{
+  QDateTimeEdit::showEvent( event );
+  if ( mAllowNull && mIsNull &&
+       lineEdit()->text() != QSettings().value( "qgis/nullValue", "NULL" ).toString() )
+  {
+    displayNull();
+  }
 }
 
-void QgsDateTimeEdit::changed( const QDateTime & dateTime )
+void QgsDateTimeEdit::changed( const QDateTime &dateTime )
 {
   mIsEmpty = false;
-  mIsNull = dateTime.isNull();
-  mNullLabel->setVisible( mAllowNull && mIsNull );
+  bool isNull = dateTime.isNull();
+  if ( isNull != mIsNull )
+  {
+    mIsNull = isNull;
+    if ( mIsNull )
+    {
+      if ( mOriginalStyleSheet.isNull() )
+      {
+        mOriginalStyleSheet = lineEdit()->styleSheet();
+      }
+      lineEdit()->setStyleSheet( "font-style: italic; color: grey; }" );
+    }
+    else
+    {
+      lineEdit()->setStyleSheet( mOriginalStyleSheet );
+    }
+  }
   mClearButton->setVisible( mAllowNull && !mIsNull );
-  lineEdit()->setVisible( !mAllowNull || !mIsNull );
+}
+
+void QgsDateTimeEdit::displayNull( bool updateCalendar )
+{
+  blockSignals( true );
+  if ( updateCalendar )
+  {
+    // set current time to minimum date time to avoid having
+    // a date selected in calendar widget
+    QDateTimeEdit::setDateTime( minimumDateTime() );
+  }
+  lineEdit()->setText( QSettings().value( "qgis/nullValue", "NULL" ).toString() );
+  blockSignals( false );
+}
+
+void QgsDateTimeEdit::resetBeforeChange( int delta )
+{
+  QDateTime dt = QDateTime::currentDateTime();
+  switch ( currentSection() )
+  {
+    case QDateTimeEdit::DaySection:
+      dt = dt.addDays( delta );
+      break;
+    case QDateTimeEdit::MonthSection:
+      dt = dt.addMonths( delta );
+      break;
+    case QDateTimeEdit::YearSection:
+      dt = dt.addYears( delta );
+      break;
+    default:
+      break;
+  }
+  if ( dt < minimumDateTime() )
+  {
+    dt = minimumDateTime();
+  }
+  else if ( dt > maximumDateTime() )
+  {
+    dt = maximumDateTime();
+  }
+  QDateTimeEdit::setDateTime( dt );
 }
 
 int QgsDateTimeEdit::spinButtonWidth() const
@@ -105,7 +234,9 @@ int QgsDateTimeEdit::frameWidth() const
   return style()->pixelMetric( QStyle::PM_DefaultFrameWidth );
 }
 
-void QgsDateTimeEdit::setDateTime( const QDateTime& dateTime )
+
+
+void QgsDateTimeEdit::setDateTime( const QDateTime &dateTime )
 {
   mIsEmpty = false;
 
@@ -117,7 +248,6 @@ void QgsDateTimeEdit::setDateTime( const QDateTime& dateTime )
   else
   {
     QDateTimeEdit::setDateTime( dateTime );
-    mIsNull = false;
     changed( dateTime );
   }
 }
@@ -143,8 +273,4 @@ void QgsDateTimeEdit::resizeEvent( QResizeEvent * event )
 
   mClearButton->move( rect().right() - frameWidth() - spinButtonWidth() - sz.width(),
                       ( rect().bottom() + 1 - sz.height() ) / 2 );
-
-  mNullLabel->move( 0, 0 );
-  mNullLabel->setMinimumSize( rect().adjusted( 0, 0, -spinButtonWidth(), 0 ).size() );
-  mNullLabel->setMaximumSize( rect().adjusted( 0, 0, -spinButtonWidth(), 0 ).size() );
 }
diff --git a/src/gui/editorwidgets/qgsdatetimeedit.h b/src/gui/editorwidgets/qgsdatetimeedit.h
index dc850dc..07671e6 100644
--- a/src/gui/editorwidgets/qgsdatetimeedit.h
+++ b/src/gui/editorwidgets/qgsdatetimeedit.h
@@ -59,25 +59,31 @@ class GUI_EXPORT QgsDateTimeEdit : public QDateTimeEdit
 
   protected:
     virtual void resizeEvent( QResizeEvent* event ) override;
-
     void mousePressEvent( QMouseEvent*event ) override;
+    void focusOutEvent( QFocusEvent *event ) override;
+    void wheelEvent( QWheelEvent *event ) override;
+    void showEvent( QShowEvent *event ) override;
 
 
   private slots:
-    void changed( const QDateTime & dateTime );
-
+    void changed( const QDateTime &dateTime );
 
   private:
     int spinButtonWidth() const;
     int frameWidth() const;
 
+    void displayNull( bool updateCalendar = false );
+
+    //! reset the value to current date time
+    void resetBeforeChange( int delta );
+
     bool mAllowNull;
     bool mIsNull;
     bool mIsEmpty;
 
     QLineEdit* mNullLabel;
     QToolButton* mClearButton;
-
+    QString mOriginalStyleSheet;
 };
 
 #endif // QGSDATETIMEEDIT_H
diff --git a/src/gui/editorwidgets/qgsdatetimeeditconfig.cpp b/src/gui/editorwidgets/qgsdatetimeeditconfig.cpp
index fc046cd..81615a0 100644
--- a/src/gui/editorwidgets/qgsdatetimeeditconfig.cpp
+++ b/src/gui/editorwidgets/qgsdatetimeeditconfig.cpp
@@ -21,6 +21,13 @@ QgsDateTimeEditConfig::QgsDateTimeEditConfig( QgsVectorLayer* vl, int fieldIdx,
 {
   setupUi( this );
 
+  mFieldFormatComboBox->clear();
+  mFieldFormatComboBox->addItem( tr( "Date" ), QGSDATETIMEEDIT_DATEFORMAT );
+  mFieldFormatComboBox->addItem( tr( "Time" ), QGSDATETIMEEDIT_TIMEFORMAT );
+  mFieldFormatComboBox->addItem( tr( "Date time" ), QGSDATETIMEEDIT_DATETIMEFORMAT );
+  mFieldFormatComboBox->addItem( tr( "ISO date time" ), QGSDATETIMEEDIT_ISODATETIMEFORMAT );
+  mFieldFormatComboBox->addItem( tr( "Custom" ), QString() );
+
   mDemoDateTimeEdit->setDateTime( QDateTime::currentDateTime() );
 
   connect( mDisplayFormatEdit, SIGNAL( textChanged( QString ) ), this, SLOT( updateDemoWidget() ) );
@@ -53,21 +60,15 @@ void QgsDateTimeEditConfig::updateDemoWidget()
 
 void QgsDateTimeEditConfig::updateFieldFormat( int idx )
 {
-  if ( idx == 0 )
-  {
-    mFieldFormatEdit->setText( QGSDATETIMEEDIT_DATEFORMAT );
-  }
-  else if ( idx == 1 )
-  {
-    mFieldFormatEdit->setText( QGSDATETIMEEDIT_TIMEFORMAT );
-  }
-  else if ( idx == 2 )
+  const QString format = mFieldFormatComboBox->itemData( idx ).toString();
+  bool custom = format.isEmpty();
+  if ( !custom )
   {
-    mFieldFormatEdit->setText( QGSDATETIMEEDIT_DATETIMEFORMAT );
+    mFieldFormatEdit->setText( format );
   }
 
-  mFieldFormatEdit->setVisible( idx == 3 );
-  mFieldHelpToolButton->setVisible( idx == 3 );
+  mFieldFormatEdit->setEnabled( custom );
+  mFieldHelpToolButton->setVisible( custom );
   if ( mFieldHelpToolButton->isHidden() && mDisplayHelpToolButton->isHidden() )
   {
     mHelpScrollArea->setVisible( false );
@@ -75,24 +76,34 @@ void QgsDateTimeEditConfig::updateFieldFormat( int idx )
 }
 
 
+
 void QgsDateTimeEditConfig::updateDisplayFormat( const QString& fieldFormat )
 {
   if ( mDisplayFormatComboBox->currentIndex() == 0 )
   {
-    mDisplayFormatEdit->setText( fieldFormat );
+    // i.e. display format is default
+    if ( mFieldFormatComboBox->itemData( mFieldFormatComboBox->currentIndex() ) == QGSDATETIMEEDIT_ISODATETIMEFORMAT )
+    {
+      mDisplayFormatEdit->setText( QGSDATETIMEEDIT_ISODISPLAYFORMAT );
+    }
+    else
+    {
+      mDisplayFormatEdit->setText( fieldFormat );
+    }
   }
 }
 
 
 void QgsDateTimeEditConfig::displayFormatChanged( int idx )
 {
-  mDisplayFormatEdit->setEnabled( idx == 1 );
-  mDisplayHelpToolButton->setVisible( idx == 1 );
+  const bool custom = idx == 1;
+  mDisplayFormatEdit->setEnabled( custom );
+  mDisplayHelpToolButton->setVisible( custom );
   if ( mFieldHelpToolButton->isHidden() && mDisplayHelpToolButton->isHidden() )
   {
     mHelpScrollArea->setVisible( false );
   }
-  if ( idx == 0 )
+  if ( !custom )
   {
     mDisplayFormatEdit->setText( mFieldFormatEdit->text() );
   }
@@ -110,6 +121,7 @@ QgsEditorWidgetConfig QgsDateTimeEditConfig::config()
 {
   QgsEditorWidgetConfig myConfig;
 
+  myConfig.insert( "field_iso_format", mFieldFormatEdit->text() == QGSDATETIMEEDIT_ISODATETIMEFORMAT );
   myConfig.insert( "field_format", mFieldFormatEdit->text() );
   myConfig.insert( "display_format", mDisplayFormatEdit->text() );
   myConfig.insert( "calendar_popup", mCalendarPopupCheckBox->isChecked() );
@@ -126,14 +138,15 @@ void QgsDateTimeEditConfig::setConfig( const QgsEditorWidgetConfig &config )
     const QString fieldFormat = config[ "field_format" ].toString();
     mFieldFormatEdit->setText( fieldFormat );
 
-    if ( fieldFormat == QGSDATETIMEEDIT_DATEFORMAT )
-      mFieldFormatComboBox->setCurrentIndex( 0 );
-    else if ( fieldFormat == QGSDATETIMEEDIT_TIMEFORMAT )
-      mFieldFormatComboBox->setCurrentIndex( 1 );
-    else if ( fieldFormat == QGSDATETIMEEDIT_DATETIMEFORMAT )
-      mFieldFormatComboBox->setCurrentIndex( 2 );
+    const int idx = mFieldFormatComboBox->findData( fieldFormat );
+    if ( idx >= 0 )
+    {
+      mFieldFormatComboBox->setCurrentIndex( idx );
+    }
     else
-      mFieldFormatComboBox->setCurrentIndex( 3 );
+    {
+      mFieldFormatComboBox->setCurrentIndex( 4 );
+    }
   }
 
   if ( config.contains( "display_format" ) )
diff --git a/src/gui/editorwidgets/qgsdatetimeeditfactory.h b/src/gui/editorwidgets/qgsdatetimeeditfactory.h
index efbb0de..6736ca0 100644
--- a/src/gui/editorwidgets/qgsdatetimeeditfactory.h
+++ b/src/gui/editorwidgets/qgsdatetimeeditfactory.h
@@ -21,6 +21,9 @@
 #define QGSDATETIMEEDIT_DATEFORMAT "yyyy-MM-dd"
 #define QGSDATETIMEEDIT_TIMEFORMAT "HH:mm:ss"
 #define QGSDATETIMEEDIT_DATETIMEFORMAT "yyyy-MM-dd HH:mm:ss"
+#define QGSDATETIMEEDIT_ISODATETIMEFORMAT "Qt ISO Date"
+#define QGSDATETIMEEDIT_ISODISPLAYFORMAT "yyyy-MM-dd HH:mm:ss+t"
+
 
 /** \ingroup gui
  * \class QgsDateTimeEditFactory
diff --git a/src/gui/editorwidgets/qgsdatetimeeditwrapper.cpp b/src/gui/editorwidgets/qgsdatetimeeditwrapper.cpp
index b59647a..2da337f 100644
--- a/src/gui/editorwidgets/qgsdatetimeeditwrapper.cpp
+++ b/src/gui/editorwidgets/qgsdatetimeeditwrapper.cpp
@@ -65,7 +65,11 @@ void QgsDateTimeEditWrapper::initWidget( QWidget *editor )
   mQDateTimeEdit->setDisplayFormat( displayFormat );
 
   const bool calendar = config( "calendar_popup", false ).toBool();
-  mQDateTimeEdit->setCalendarPopup( calendar );
+
+  if ( calendar != mQDateTimeEdit->calendarPopup() )
+  {
+    mQDateTimeEdit->setCalendarPopup( calendar );
+  }
   if ( calendar && mQDateTimeEdit->calendarWidget() )
   {
     // highlight today's date
@@ -109,8 +113,30 @@ void QgsDateTimeEditWrapper::showIndeterminateState()
 
 void QgsDateTimeEditWrapper::dateTimeChanged( const QDateTime& dateTime )
 {
-  const QString fieldFormat = config( "field_format", QGSDATETIMEEDIT_DATEFORMAT ).toString();
-  emit valueChanged( dateTime.toString( fieldFormat ) );
+  switch ( field().type() )
+  {
+    case QVariant::DateTime:
+      emit valueChanged( dateTime );
+      break;
+    case QVariant::Date:
+      emit valueChanged( dateTime.date() );
+      break;
+    case QVariant::Time:
+      emit valueChanged( dateTime.time() );
+      break;
+    default:
+      const bool fieldIsoFormat = config( "field_iso_format" , false ).toBool();
+      const QString fieldFormat = config( "field_format" , QGSDATETIMEEDIT_DATEFORMAT ).toString();
+      if ( fieldIsoFormat )
+      {
+        emit valueChanged( dateTime.toString( Qt::ISODate ) );
+      }
+      else
+      {
+        emit valueChanged( dateTime.toString( fieldFormat ) );
+      }
+      break;
+  }
 }
 
 QVariant QgsDateTimeEditWrapper::value() const
@@ -118,28 +144,41 @@ QVariant QgsDateTimeEditWrapper::value() const
   if ( !mQDateTimeEdit )
     return QVariant( field().type() );
 
-  if ( field().type() == QVariant::DateTime )
-  {
-    if ( mQgsDateTimeEdit )
-    {
-      return mQgsDateTimeEdit->dateTime();
-    }
-    else
-    {
-      return mQDateTimeEdit->dateTime();
-    }
-  }
-
-  const QString fieldFormat = config( "field_format", QGSDATETIMEEDIT_DATEFORMAT ).toString();
-
+  QDateTime dateTime;
   if ( mQgsDateTimeEdit )
   {
-    return mQgsDateTimeEdit->dateTime().toString( fieldFormat );
+    dateTime = mQgsDateTimeEdit->dateTime();
   }
   else
   {
-    return mQDateTimeEdit->dateTime().toString( fieldFormat );
+    dateTime = mQDateTimeEdit->dateTime();
+  }
+
+  switch ( field().type() )
+  {
+    case QVariant::DateTime:
+      return dateTime;
+      break;
+    case QVariant::Date:
+      return dateTime.date();
+      break;
+    case QVariant::Time:
+      return dateTime.time();
+      break;
+    default:
+      const bool fieldIsoFormat = config( "field_iso_format", false ).toBool();
+      const QString fieldFormat = config( "field_format", QGSDATETIMEEDIT_DATEFORMAT ).toString();
+      if ( fieldIsoFormat )
+      {
+        return dateTime.toString( Qt::ISODate );
+      }
+      else
+      {
+        return dateTime.toString( fieldFormat );
+      }
+      break;
   }
+  return QVariant();
 }
 
 void QgsDateTimeEditWrapper::setValue( const QVariant &value )
@@ -147,16 +186,36 @@ void QgsDateTimeEditWrapper::setValue( const QVariant &value )
   if ( !mQDateTimeEdit )
     return;
 
-  const QString fieldFormat = config( "field_format", QGSDATETIMEEDIT_DATEFORMAT ).toString();
-  const QDateTime date = field().type() == QVariant::DateTime ? value.toDateTime() : QDateTime::fromString( value.toString(), fieldFormat );
+
+  QDateTime dateTime;
+  switch ( field().type() )
+  {
+    case QVariant::DateTime:
+    case QVariant::Date:
+    case QVariant::Time:
+      dateTime = value.toDateTime();
+      break;
+    default:
+      const bool fieldIsoFormat = config( "field_iso_format", false ).toBool();
+      const QString fieldFormat = config( "field_format", QGSDATETIMEEDIT_DATEFORMAT ).toString();
+      if ( fieldIsoFormat )
+      {
+        dateTime = QDateTime::fromString( value.toString(), Qt::ISODate );
+      }
+      else
+      {
+        dateTime = QDateTime::fromString( value.toString(), fieldFormat );
+      }
+      break;
+  }
 
   if ( mQgsDateTimeEdit )
   {
-    mQgsDateTimeEdit->setDateTime( date );
+    mQgsDateTimeEdit->setDateTime( dateTime );
   }
   else
   {
-    mQDateTimeEdit->setDateTime( date );
+    mQDateTimeEdit->setDateTime( dateTime );
   }
 }
 
diff --git a/src/gui/editorwidgets/qgsdatetimesearchwidgetwrapper.cpp b/src/gui/editorwidgets/qgsdatetimesearchwidgetwrapper.cpp
index c814184..db0ca9d 100644
--- a/src/gui/editorwidgets/qgsdatetimesearchwidgetwrapper.cpp
+++ b/src/gui/editorwidgets/qgsdatetimesearchwidgetwrapper.cpp
@@ -45,8 +45,17 @@ QVariant QgsDateTimeSearchWidgetWrapper::value() const
   if ( ! mDateTimeEdit )
     return QDateTime();
 
+  const bool fieldIsoFormat = config( "field_iso_format", false ).toBool();
   const QString fieldFormat = config( "field_format", QGSDATETIMEEDIT_DATEFORMAT ).toString();
-  return mDateTimeEdit->dateTime().toString( fieldFormat );
+
+  if ( fieldIsoFormat )
+  {
+    return mDateTimeEdit->dateTime().toString( Qt::ISODate );
+  }
+  else
+  {
+    return mDateTimeEdit->dateTime().toString( fieldFormat );
+  }
 }
 
 QgsSearchWidgetWrapper::FilterFlags QgsDateTimeSearchWidgetWrapper::supportedFlags() const
diff --git a/src/gui/editorwidgets/qgsrelationreferencewidget.cpp b/src/gui/editorwidgets/qgsrelationreferencewidget.cpp
index 41f2b73..498b648 100644
--- a/src/gui/editorwidgets/qgsrelationreferencewidget.cpp
+++ b/src/gui/editorwidgets/qgsrelationreferencewidget.cpp
@@ -479,7 +479,8 @@ void QgsRelationReferenceWidget::init()
 
     QSet<QString> requestedAttrs;
 
-    QgsVectorLayerCache* layerCache = new QgsVectorLayerCache( mReferencedLayer, 100000, this );
+    const int cacheSize = QSettings().value( "/QgsRelationReferenceWidget/cacheSize" ).toInt();
+    QgsVectorLayerCache* layerCache = new QgsVectorLayerCache( mReferencedLayer, cacheSize, this );
 
     if ( !mFilterFields.isEmpty() )
     {
@@ -583,8 +584,14 @@ void QgsRelationReferenceWidget::init()
       }
     }
 
-    QVariant featId = mFeature.isValid() ? mFeature.id() : QVariant( QVariant::Int );
-    mComboBox->setCurrentIndex( mComboBox->findData( featId, QgsAttributeTableModel::FeatureIdRole ) );
+    if ( mFeature.isValid() )
+    {
+      mComboBox->setCurrentIndex( mComboBox->findData( mFeature.id(), QgsAttributeTableModel::FeatureIdRole ) );
+    }
+    else
+    {
+      mComboBox->setCurrentIndex( -1 );
+    }
 
     // Only connect after iterating, to have only one iterator on the referenced table at once
     connect( mComboBox, SIGNAL( currentIndexChanged( int ) ), this, SLOT( comboReferenceChanged( int ) ) );
@@ -934,6 +941,18 @@ void QgsRelationReferenceWidget::filterChanged()
   }
 
   mFilterModel->setFilteredFeatures( featureIds );
+
+  if ( mChainFilters && mComboBox->count() > 0 )
+  {
+    if ( scb->currentIndex() == 0 )
+    {
+      mComboBox->setCurrentIndex( 0 );
+    }
+    else if ( mComboBox->count() > 1 )
+    {
+      mComboBox->setCurrentIndex( 1 );
+    }
+  }
 }
 
 void QgsRelationReferenceWidget::addEntry()
diff --git a/src/gui/editorwidgets/qgsrelationreferencewidgetwrapper.cpp b/src/gui/editorwidgets/qgsrelationreferencewidgetwrapper.cpp
index 1b0aef1..e2ac5e6 100644
--- a/src/gui/editorwidgets/qgsrelationreferencewidgetwrapper.cpp
+++ b/src/gui/editorwidgets/qgsrelationreferencewidgetwrapper.cpp
@@ -71,7 +71,7 @@ void QgsRelationReferenceWidgetWrapper::initWidget( QWidget* editor )
     if ( ctx->relation().name() == relation.name() )
     {
       mWidget->setEmbedForm( false );
-      mWidget->setReadOnlySelector( false );
+      mWidget->setReadOnlySelector( true );
       mWidget->setAllowMapIdentification( false );
     }
     ctx = ctx->parentContext();
diff --git a/src/gui/editorwidgets/qgsvaluerelationwidgetwrapper.cpp b/src/gui/editorwidgets/qgsvaluerelationwidgetwrapper.cpp
index c662d1b..d22ea07 100644
--- a/src/gui/editorwidgets/qgsvaluerelationwidgetwrapper.cpp
+++ b/src/gui/editorwidgets/qgsvaluerelationwidgetwrapper.cpp
@@ -150,6 +150,8 @@ void QgsValueRelationWidgetWrapper::initWidget( QWidget* editor )
     QCompleter* completer = new QCompleter( m, mLineEdit );
     completer->setCaseSensitivity( Qt::CaseInsensitive );
     mLineEdit->setCompleter( completer );
+
+    connect( mLineEdit, SIGNAL( textChanged( QString ) ), this, SLOT( onValueChanged() ) );
   }
 }
 
diff --git a/src/gui/qgsmaptoolcapture.cpp b/src/gui/qgsmaptoolcapture.cpp
index 0b0f421..7dfe1ff 100644
--- a/src/gui/qgsmaptoolcapture.cpp
+++ b/src/gui/qgsmaptoolcapture.cpp
@@ -713,7 +713,7 @@ int QgsMapToolCapture::size()
   return mCaptureCurve.numPoints();
 }
 
-QList<QgsPoint> QgsMapToolCapture::points()
+QList<QgsPoint> QgsMapToolCapture::points() const
 {
   QgsPointSequenceV2 pts;
   QList<QgsPoint> points;
diff --git a/src/gui/qgsmaptoolcapture.h b/src/gui/qgsmaptoolcapture.h
index 1cc26b0..fbbb292 100644
--- a/src/gui/qgsmaptoolcapture.h
+++ b/src/gui/qgsmaptoolcapture.h
@@ -192,7 +192,7 @@ class GUI_EXPORT QgsMapToolCapture : public QgsMapToolAdvancedDigitizing
      * List of digitized points
      * @return List of points
      */
-    QList<QgsPoint> points();
+    QList<QgsPoint> points() const;
 
     /**
      * List of digitized points with z support
@@ -248,6 +248,8 @@ class GUI_EXPORT QgsMapToolCapture : public QgsMapToolAdvancedDigitizing
 
     QgsVertexMarker* mSnappingMarker;
 
+    friend class TestQgsMapToolReshape;
+
 #ifdef Q_OS_WIN
     int mSkipNextContextMenuEvent;
 #endif
diff --git a/src/plugins/georeferencer/qgsimagewarper.cpp b/src/plugins/georeferencer/qgsimagewarper.cpp
index a1ba893..f696bbe 100644
--- a/src/plugins/georeferencer/qgsimagewarper.cpp
+++ b/src/plugins/georeferencer/qgsimagewarper.cpp
@@ -20,7 +20,7 @@
 #include <cpl_string.h>
 #include <gdal.h>
 #include <gdalwarper.h>
-#include <ogr_spatialref.h>
+#include <ogr_srs_api.h>
 
 #include <QFile>
 #include <QProgressDialog>
@@ -35,6 +35,10 @@
 #define TO8F(x) QFile::encodeName( x ).constData()
 #endif
 
+#if defined(GDAL_VERSION_NUM) && GDAL_VERSION_NUM >= 2300
+#define OGRFree(x) CPLFree(x)
+#endif
+
 bool QgsImageWarper::mWarpCanceled = false;
 
 QgsImageWarper::QgsImageWarper( QWidget *theParent )
@@ -101,16 +105,23 @@ bool QgsImageWarper::createDestinationDataset( const QString &outputName, GDALDa
 
   if ( crs.isValid() )
   {
-    OGRSpatialReference oTargetSRS;
-    oTargetSRS.importFromProj4( crs.toProj4().toLatin1().data() );
+    OGRSpatialReferenceH oTargetSRS = OSRNewSpatialReference( nullptr );
+    OGRErr err = OSRImportFromProj4( oTargetSRS, crs.toProj4().toUtf8() );
+    if ( err != CE_None )
+    {
+      OSRDestroySpatialReference( oTargetSRS );
+      return false;
+    }
 
     char *wkt = nullptr;
-    OGRErr err = oTargetSRS.exportToWkt( &wkt );
+    err = OSRExportToWkt( oTargetSRS, &wkt );
     if ( err != CE_None || GDALSetProjection( hDstDS, wkt ) != CE_None )
     {
+      OSRDestroySpatialReference( oTargetSRS );
       OGRFree( wkt );
       return false;
     }
+    OSRDestroySpatialReference( oTargetSRS );
     OGRFree( wkt );
   }
 
diff --git a/src/plugins/grass/modules/r.in.wms.qgm b/src/plugins/grass/modules/r.in.wms.qgm
index 22be6f8..1963fb9 100644
--- a/src/plugins/grass/modules/r.in.wms.qgm
+++ b/src/plugins/grass/modules/r.in.wms.qgm
@@ -17,7 +17,6 @@
 	<flag key="k" answer="off" version_max="6.4"/>
 	<flag key="o" answer="off"/>
 	<flag key="p" answer="off" version_max="6.4"/>
-	<option key="method" />
 	<option key="output" />
 	<option key="maxcols" advanced="yes" version_min="7.0"/>
 	<option key="maxrows" advanced="yes" version_min="7.0"/>
diff --git a/src/plugins/oracle_raster/qgsselectgeoraster_ui.cpp b/src/plugins/oracle_raster/qgsselectgeoraster_ui.cpp
index 6563527..d2ffe68 100644
--- a/src/plugins/oracle_raster/qgsselectgeoraster_ui.cpp
+++ b/src/plugins/oracle_raster/qgsselectgeoraster_ui.cpp
@@ -20,8 +20,7 @@
 
 #include "gdal.h"
 #include "ogr_api.h"
-#include "ogrsf_frmts.h"
-#include <cpl_string.h>
+#include "cpl_string.h"
 
 #include "qgsvectorlayer.h"
 
diff --git a/src/providers/gdal/qgsgdalprovider.cpp b/src/providers/gdal/qgsgdalprovider.cpp
index 907ff74..1f9b6a2 100644
--- a/src/providers/gdal/qgsgdalprovider.cpp
+++ b/src/providers/gdal/qgsgdalprovider.cpp
@@ -49,7 +49,7 @@
 #include <QDebug>
 
 #include "gdalwarper.h"
-#include "ogr_spatialref.h"
+#include "ogr_srs_api.h"
 #include "cpl_conv.h"
 #include "cpl_string.h"
 
diff --git a/src/providers/ogr/qgsogrprovider.cpp b/src/providers/ogr/qgsogrprovider.cpp
index dc0b47b..fb9633a 100644
--- a/src/providers/ogr/qgsogrprovider.cpp
+++ b/src/providers/ogr/qgsogrprovider.cpp
@@ -503,89 +503,8 @@ QgsAbstractFeatureSource* QgsOgrProvider::featureSource() const
 
 bool QgsOgrProvider::setSubsetString( const QString& theSQL, bool updateFeatureCount )
 {
-  QgsCPLErrorHandler handler;
-
-  if ( !ogrDataSource )
-    return false;
-
-  if ( theSQL == mSubsetString && mFeaturesCounted >= 0 )
-    return true;
-
-  OGRLayerH prevLayer = ogrLayer;
-  QString prevSubsetString = mSubsetString;
-  mSubsetString = theSQL;
-
-  if ( !mSubsetString.isEmpty() )
-  {
-
-    ogrLayer = setSubsetString( ogrOrigLayer, ogrDataSource );
-    if ( !ogrLayer )
-    {
-      pushError( tr( "OGR[%1] error %2: %3" ).arg( CPLGetLastErrorType() ).arg( CPLGetLastErrorNo() ).arg( CPLGetLastErrorMsg() ) );
-      ogrLayer = prevLayer;
-      mSubsetString = prevSubsetString;
-      return false;
-    }
-  }
-  else
-  {
-    ogrLayer = ogrOrigLayer;
-  }
-
-  if ( prevLayer != ogrOrigLayer )
-  {
-    OGR_DS_ReleaseResultSet( ogrDataSource, prevLayer );
-  }
-
-  QString uri = mFilePath;
-  if ( !mLayerName.isNull() )
-  {
-    uri += QString( "|layername=%1" ).arg( mLayerName );
-  }
-  else if ( mLayerIndex >= 0 )
-  {
-    uri += QString( "|layerid=%1" ).arg( mLayerIndex );
-  }
-
-  if ( !mSubsetString.isEmpty() )
-  {
-    uri += QString( "|subset=%1" ).arg( mSubsetString );
-  }
-
-  if ( mOgrGeometryTypeFilter != wkbUnknown )
-  {
-    uri += QString( "|geometrytype=%1" ).arg( ogrWkbGeometryTypeName( mOgrGeometryTypeFilter ) );
-  }
-
-  if ( uri != dataSourceUri() )
-  {
-    QgsOgrConnPool::instance()->unref( dataSourceUri() );
-    setDataSourceUri( uri );
-    QgsOgrConnPool::instance()->ref( dataSourceUri() );
-  }
-
-  OGR_L_ResetReading( ogrLayer );
-
-  // getting the total number of features in the layer
-  // TODO: This can be expensive, do we really need it!
-  if ( updateFeatureCount )
-  {
-    recalculateFeatureCount();
-  }
-
-  // check the validity of the layer
-  QgsDebugMsg( "checking validity" );
-  loadFields();
-  QgsDebugMsg( "Done checking validity" );
-
-  invalidateCachedExtent( false );
-
-  // Changing the filter may change capabilities
-  computeCapabilities();
-
-  emit dataChanged();
-
-  return true;
+  // Always update capabilities
+  return _setSubsetString( theSQL, updateFeatureCount, true );
 }
 
 QString QgsOgrProvider::subsetString()
@@ -1640,6 +1559,94 @@ bool QgsOgrProvider::commitTransaction()
   return true;
 }
 
+bool QgsOgrProvider::_setSubsetString( const QString &theSQL, bool updateFeatureCount, bool updateCapabilities )
+{
+  QgsCPLErrorHandler handler;
+
+  if ( !ogrDataSource )
+    return false;
+
+  if ( theSQL == mSubsetString && mFeaturesCounted >= 0 )
+    return true;
+
+  OGRLayerH prevLayer = ogrLayer;
+  QString prevSubsetString = mSubsetString;
+  mSubsetString = theSQL;
+
+  if ( !mSubsetString.isEmpty() )
+  {
+
+    ogrLayer = setSubsetString( ogrOrigLayer, ogrDataSource );
+    if ( !ogrLayer )
+    {
+      pushError( tr( "OGR[%1] error %2: %3" ).arg( CPLGetLastErrorType() ).arg( CPLGetLastErrorNo() ).arg( CPLGetLastErrorMsg() ) );
+      ogrLayer = prevLayer;
+      mSubsetString = prevSubsetString;
+      return false;
+    }
+  }
+  else
+  {
+    ogrLayer = ogrOrigLayer;
+  }
+
+  if ( prevLayer != ogrOrigLayer )
+  {
+    OGR_DS_ReleaseResultSet( ogrDataSource, prevLayer );
+  }
+
+  QString uri = mFilePath;
+  if ( !mLayerName.isNull() )
+  {
+    uri += QString( "|layername=%1" ).arg( mLayerName );
+  }
+  else if ( mLayerIndex >= 0 )
+  {
+    uri += QString( "|layerid=%1" ).arg( mLayerIndex );
+  }
+
+  if ( !mSubsetString.isEmpty() )
+  {
+    uri += QString( "|subset=%1" ).arg( mSubsetString );
+  }
+
+  if ( mOgrGeometryTypeFilter != wkbUnknown )
+  {
+    uri += QString( "|geometrytype=%1" ).arg( ogrWkbGeometryTypeName( mOgrGeometryTypeFilter ) );
+  }
+
+  if ( uri != dataSourceUri() )
+  {
+    QgsOgrConnPool::instance()->unref( dataSourceUri() );
+    setDataSourceUri( uri );
+    QgsOgrConnPool::instance()->ref( dataSourceUri() );
+  }
+
+  OGR_L_ResetReading( ogrLayer );
+
+  // getting the total number of features in the layer
+  // TODO: This can be expensive, do we really need it!
+  if ( updateFeatureCount )
+  {
+    recalculateFeatureCount();
+  }
+
+  // check the validity of the layer
+  QgsDebugMsg( "checking validity" );
+  loadFields();
+  QgsDebugMsg( "Done checking validity" );
+
+  invalidateCachedExtent( false );
+
+  // Changing the filter may change capabilities
+  if ( updateCapabilities )
+    computeCapabilities();
+
+  emit dataChanged();
+
+  return true;
+}
+
 
 bool QgsOgrProvider::changeAttributeValues( const QgsChangedAttributesMap &attr_map )
 {
@@ -2008,10 +2015,18 @@ int QgsOgrProvider::capabilities() const
 void QgsOgrProvider::computeCapabilities()
 {
   int ability = 0;
+  bool updateModeActivated = false;
 
   // collect abilities reported by OGR
   if ( ogrLayer )
   {
+    // We want the layer in rw mode or capabilities will be wrong
+    // If mUpdateModeStackDepth > 0, it means that an updateMode is already active and that we have write access
+    if ( mUpdateModeStackDepth == 0 )
+    {
+      updateModeActivated = enterUpdateMode( );
+    }
+
     // Whilst the OGR documentation (e.g. at
     // http://www.gdal.org/ogr/classOGRLayer.html#a17) states "The capability
     // codes that can be tested are represented as strings, but #defined
@@ -2138,6 +2153,10 @@ void QgsOgrProvider::computeCapabilities()
     }
   }
 
+  if ( updateModeActivated )
+    leaveUpdateMode();
+
+
   mCapabilities = ability;
 }
 
@@ -3620,7 +3639,8 @@ void QgsOgrProvider::open( OpenMode mode )
       mSubsetString = "";
       // Block signals to avoid endless recusion reloadData -> emit dataChanged -> reloadData
       blockSignals( true );
-      mValid = setSubsetString( origSubsetString );
+      // Do not update capabilities: it will be done later
+      mValid = _setSubsetString( origSubsetString, true, false );
       blockSignals( false );
       if ( mValid )
       {
@@ -3696,7 +3716,8 @@ void QgsOgrProvider::open( OpenMode mode )
       {
         int featuresCountedBackup = mFeaturesCounted;
         mFeaturesCounted = -1;
-        mValid = setSubsetString( mSubsetString, false );
+        // Do not update capabilities here
+        mValid = _setSubsetString( mSubsetString, false, false );
         mFeaturesCounted = featuresCountedBackup;
       }
     }
diff --git a/src/providers/ogr/qgsogrprovider.h b/src/providers/ogr/qgsogrprovider.h
index 3c01afa..fb3fa96 100644
--- a/src/providers/ogr/qgsogrprovider.h
+++ b/src/providers/ogr/qgsogrprovider.h
@@ -312,6 +312,9 @@ class QgsOgrProvider : public QgsVectorDataProvider
     //! Commits a transaction
     bool commitTransaction();
 
+    //! Does the real job of settings the subset string and adds an argument to disable update capabilities
+    bool _setSubsetString( const QString &theSQL, bool updateFeatureCount = true, bool updateCapabilities = true );
+
     QgsFields mAttributeFields;
     bool mFirstFieldIsFid;
     OGRDataSourceH ogrDataSource;
diff --git a/src/providers/virtual/qgsvirtuallayersqlitemodule.cpp b/src/providers/virtual/qgsvirtuallayersqlitemodule.cpp
index 59dbc24..559f9dc 100644
--- a/src/providers/virtual/qgsvirtuallayersqlitemodule.cpp
+++ b/src/providers/virtual/qgsvirtuallayersqlitemodule.cpp
@@ -215,7 +215,7 @@ private:
           typeName = "text";
           break;
       }
-      sqlFields << field.name() + " " + typeName;
+      sqlFields << QString( "\"%1\" %2" ).arg( field.name(), typeName );
     }
 
     QgsVectorDataProvider* provider = mLayer ? mLayer->dataProvider() : mProvider;
diff --git a/src/providers/wcs/qgswcsprovider.cpp b/src/providers/wcs/qgswcsprovider.cpp
index 542e993..b7a9893 100644
--- a/src/providers/wcs/qgswcsprovider.cpp
+++ b/src/providers/wcs/qgswcsprovider.cpp
@@ -45,7 +45,7 @@
 #endif
 
 #include "gdalwarper.h"
-#include "ogr_spatialref.h"
+#include "ogr_srs_api.h"
 #include "cpl_conv.h"
 #include "cpl_string.h"
 
diff --git a/src/ui/editorwidgets/qgsdatetimeeditconfig.ui b/src/ui/editorwidgets/qgsdatetimeeditconfig.ui
index 76bbecb..023b3eb 100644
--- a/src/ui/editorwidgets/qgsdatetimeeditconfig.ui
+++ b/src/ui/editorwidgets/qgsdatetimeeditconfig.ui
@@ -24,8 +24,8 @@
        <rect>
         <x>0</x>
         <y>0</y>
-        <width>468</width>
-        <height>1033</height>
+        <width>478</width>
+        <height>971</height>
        </rect>
       </property>
       <layout class="QGridLayout" name="gridLayout_5">
@@ -80,26 +80,6 @@
           <height>0</height>
          </size>
         </property>
-        <item>
-         <property name="text">
-          <string>Date</string>
-         </property>
-        </item>
-        <item>
-         <property name="text">
-          <string>Time</string>
-         </property>
-        </item>
-        <item>
-         <property name="text">
-          <string>Date & time</string>
-         </property>
-        </item>
-        <item>
-         <property name="text">
-          <string>Custom format</string>
-         </property>
-        </item>
        </widget>
       </item>
       <item row="0" column="1">
@@ -250,6 +230,9 @@
  </widget>
  <resources>
   <include location="../../../images/images.qrc"/>
+  <include location="../../../images/images.qrc"/>
+  <include location="../../../images/images.qrc"/>
+  <include location="../../../images/images.qrc"/>
  </resources>
  <connections/>
 </ui>
diff --git a/tests/src/app/CMakeLists.txt b/tests/src/app/CMakeLists.txt
index 56a66bb..b760bb4 100644
--- a/tests/src/app/CMakeLists.txt
+++ b/tests/src/app/CMakeLists.txt
@@ -16,6 +16,7 @@ INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}
   ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/gui/attributetable
   ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/gui/symbology-ng
   ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/gui/raster
+  ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/gui/layertree
   ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/python
   ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/app
   ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/app/pluginmanager
@@ -108,5 +109,6 @@ ADD_QGIS_TEST(attributetabletest testqgsattributetable.cpp)
 ADD_QGIS_TEST(fieldcalculatortest testqgsfieldcalculator.cpp)
 ADD_QGIS_TEST(maptoolidentifyaction testqgsmaptoolidentifyaction.cpp)
 ADD_QGIS_TEST(maptoolselect testqgsmaptoolselect.cpp)
+ADD_QGIS_TEST(maptoolreshape testqgsmaptoolreshape.cpp)
 ADD_QGIS_TEST(measuretool testqgsmeasuretool.cpp)
 ADD_QGIS_TEST(vectorlayersaveasdialogtest testqgsvectorlayersaveasdialog.cpp)
diff --git a/tests/src/app/testqgsmaptoolreshape.cpp b/tests/src/app/testqgsmaptoolreshape.cpp
new file mode 100644
index 0000000..d5eaba0
--- /dev/null
+++ b/tests/src/app/testqgsmaptoolreshape.cpp
@@ -0,0 +1,150 @@
+/***************************************************************************
+  testqgsmaptoolreshape.cpp
+  --------------------------------
+Date                 : 2017-12-14
+Copyright            : (C) 2017 by Paul Blottiere
+Email                : paul.blottiere at oslandia.com
+ ***************************************************************************
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ ***************************************************************************/
+
+#include <QtTest/QtTest>
+#include "qgsapplication.h"
+#include "qgsmapcanvas.h"
+#include "qgsvectorlayer.h"
+#include "qgslinestringv2.h"
+#include "qgsmaptoolreshape.h"
+#include "qgsvectordataprovider.h"
+#include "qgsmaplayerregistry.h"
+#include "qgisapp.h"
+
+class TestQgsMapToolReshape : public QObject
+{
+    Q_OBJECT
+  public:
+    TestQgsMapToolReshape() : mQgisApp( nullptr ) {}
+
+  private slots:
+    void initTestCase(); // will be called before the first testfunction is executed.
+    void cleanupTestCase(); // will be called after the last testfunction was executed.
+    void init(); // will be called before each testfunction is executed.
+    void cleanup(); // will be called after every testfunction.
+
+    void reshapeWithBindingLine();
+
+  private:
+    QgisApp *mQgisApp;
+};
+
+void TestQgsMapToolReshape::initTestCase()
+{
+  QgsApplication::init();
+  QgsApplication::initQgis();
+
+  // Set up the QgsSettings environment
+  QCoreApplication::setOrganizationName( "QGIS" );
+  QCoreApplication::setOrganizationDomain( "qgis.org" );
+  QCoreApplication::setApplicationName( "QGIS-TEST" );
+
+  QgsApplication::showSettings();
+
+  // enforce C locale because the tests expect it
+  // (decimal separators / thousand separators)
+  QLocale::setDefault( QLocale::c() );
+
+  mQgisApp = new QgisApp();
+}
+
+void TestQgsMapToolReshape::cleanupTestCase()
+{
+  QgsApplication::exitQgis();
+}
+
+void TestQgsMapToolReshape::init()
+{
+}
+
+void TestQgsMapToolReshape::cleanup()
+{
+}
+
+void TestQgsMapToolReshape::reshapeWithBindingLine()
+{
+  // prepare vector layer
+  QgsVectorLayer *vl = new QgsVectorLayer( "LineString?crs=epsg:4326&field=name:string(20)", "vl", "memory" );
+
+  QgsGeometry *g0 = QgsGeometry::fromWkt( "LineString (0 0, 1 1, 1 2)" );
+  QgsFeature f0;
+  f0.setGeometry( g0 );
+  f0.setAttribute( 0, "polyline0" );
+
+  QgsGeometry *g1 = QgsGeometry::fromWkt( "LineString (2 1, 3 2, 3 3, 2 2)" );
+  QgsFeature f1;
+  f1.setGeometry( g1 );
+  f1.setAttribute( 0, "polyline1" );
+
+  vl->dataProvider()->addFeatures( QgsFeatureList() << f0 << f1 );
+
+  std::cout << "Feature count: " << vl->featureCount() << std::endl;
+
+  // prepare canvas
+  QList<QgsMapLayer *> layers;
+  layers.append( vl );
+
+  QgsCoordinateReferenceSystem srs( 4326, QgsCoordinateReferenceSystem::EpsgCrsId );
+  QgsMapLayerRegistry::instance()->addMapLayer( vl );
+  mQgisApp->mapCanvas()->setDestinationCrs( srs );
+  mQgisApp->mapCanvas()->setCurrentLayer( vl );
+
+  // reshape to add line to polyline0
+  QgsLineStringV2 cl0;
+  cl0.setPoints( QgsPointSequenceV2() << QgsPointV2( 1, 2 ) << QgsPointV2( 2, 1 ) );
+
+  QgsAbstractGeometryV2 *curveGgeom0 = cl0.toCurveType();
+  QgsCompoundCurveV2 curve0;
+  curve0.fromWkt( curveGgeom0->asWkt() );
+
+  QgsMapToolReshape tool0( mQgisApp->mapCanvas() );
+  tool0.mCaptureCurve = curve0;
+
+  vl->startEditing();
+  tool0.reshape( vl );
+
+  vl->getFeatures( QgsFeatureRequest().setFilterFid( 1 ) ).nextFeature( f0 );
+  QCOMPARE( f0.geometry()->exportToWkt(), QString( "LineString (0 0, 1 1, 1 2, 2 1)" ) );
+
+  vl->getFeatures( QgsFeatureRequest().setFilterFid( 2 ) ).nextFeature( f1 );
+  QCOMPARE( f1.geometry()->exportToWkt(), QString( "LineString (2 1, 3 2, 3 3, 2 2)" ) );
+
+  vl->rollBack();
+
+  // reshape to add line to polyline1
+  QgsLineStringV2 cl1;
+  cl1.setPoints( QgsPointSequenceV2() << QgsPointV2( 2, 1 ) << QgsPointV2( 1, 2 ) );
+
+  QgsAbstractGeometryV2 *curveGeom1 = cl1.toCurveType();
+  QgsCompoundCurveV2 curve1;
+  curve1.fromWkt( curveGeom1->asWkt() );
+
+  QgsMapToolReshape tool1( mQgisApp->mapCanvas() );
+  tool1.mCaptureCurve = curve1;
+
+  vl->startEditing();
+  tool1.reshape( vl );
+
+  vl->getFeatures( QgsFeatureRequest().setFilterFid( 1 ) ).nextFeature( f0 );
+  QCOMPARE( f0.geometry()->exportToWkt(), QString( "LineString (0 0, 1 1, 1 2)" ) );
+
+  vl->getFeatures( QgsFeatureRequest().setFilterFid( 2 ) ).nextFeature( f1 );
+  QCOMPARE( f1.geometry()->exportToWkt(), QString( "LineString (1 2, 2 1, 3 2, 3 3, 2 2)" ) );
+
+  vl->rollBack();
+}
+
+QTEST_MAIN( TestQgsMapToolReshape )
+#include "testqgsmaptoolreshape.moc"
diff --git a/tests/src/gui/testqgsrelationreferencewidget.cpp b/tests/src/gui/testqgsrelationreferencewidget.cpp
index 81b5710..eedb33f 100644
--- a/tests/src/gui/testqgsrelationreferencewidget.cpp
+++ b/tests/src/gui/testqgsrelationreferencewidget.cpp
@@ -174,8 +174,20 @@ void TestQgsRelationReferenceWidget::testChainFilter()
 
   // set the filter for "raccord" and then reset filter for "diameter". As
   // chain filter is activated, the filter on "raccord" field should be reset
+  cbs[0]->setCurrentIndex( 0 );
+  QCOMPARE( w.mComboBox->currentIndex(), 0 );
+
+  cbs[0]->setCurrentIndex( cbs[0]->findText( "iron" ) );
+  QCOMPARE( w.mComboBox->currentIndex(), 1 );
+
+  cbs[1]->setCurrentIndex( cbs[1]->findText( "120" ) );
+  QCOMPARE( w.mComboBox->currentIndex(), 1 );
+
   cbs[2]->setCurrentIndex( cbs[2]->findText( "brides" ) );
+  QCOMPARE( w.mComboBox->currentIndex(), 1 );
+
   cbs[1]->setCurrentIndex( cbs[1]->findText( "diameter" ) );
+  QCOMPARE( w.mComboBox->currentIndex(), 0 );
 
   // combobox should propose NULL, 10 and 11 because the filter is now:
   // "material" == 'iron'
diff --git a/tests/src/python/test_provider_ogr_gpkg.py b/tests/src/python/test_provider_ogr_gpkg.py
index bec190a..8c1dc81 100644
--- a/tests/src/python/test_provider_ogr_gpkg.py
+++ b/tests/src/python/test_provider_ogr_gpkg.py
@@ -21,10 +21,14 @@ import glob
 from osgeo import gdal, ogr
 
 from qgis.PyQt.QtCore import QCoreApplication, QSettings
-from qgis.core import QgsVectorLayer, QgsVectorLayerImport, QgsFeature, QgsGeometry, QgsFeatureRequest, QgsRectangle
+from qgis.core import QgsVectorLayer, QgsVectorLayerImport, QgsFeature, QgsGeometry, QgsFeatureRequest, QgsRectangle, QgsVectorDataProvider
 from qgis.testing import start_app, unittest
 from utilities import unitTestDataPath
 
+from utilities import unitTestDataPath
+
+TEST_DATA_DIR = unitTestDataPath()
+
 start_app()
 
 
@@ -419,6 +423,26 @@ class TestPyQgsOGRProviderGpkg(unittest.TestCase):
         self.assertTrue(vl.deleteFeature(1234567890123))
         self.assertTrue(vl.commitChanges())
 
+    def testSubSetStringEditable_bug17795(self):
+        """Test that a layer is not editable after setting a subset and it's reverted to editable after the filter is removed"""
+
+        isEditable = QgsVectorDataProvider.ChangeAttributeValues
+        testPath = TEST_DATA_DIR + '/' + 'provider/bug_17795.gpkg|layername=bug_17795'
+
+        vl = QgsVectorLayer(testPath, 'subset_test', 'ogr')
+        self.assertTrue(vl.isValid())
+        self.assertTrue(vl.dataProvider().capabilities() & isEditable)
+
+        vl = QgsVectorLayer(testPath, 'subset_test', 'ogr')
+        vl.setSubsetString('')
+        self.assertTrue(vl.isValid())
+        self.assertTrue(vl.dataProvider().capabilities() & isEditable)
+
+        vl = QgsVectorLayer(testPath, 'subset_test', 'ogr')
+        vl.setSubsetString('"category" = \'one\'')
+        self.assertTrue(vl.isValid())
+        self.assertFalse(vl.dataProvider().capabilities() & isEditable)
+
 
 if __name__ == '__main__':
     unittest.main()
diff --git a/tests/src/python/test_provider_shapefile.py b/tests/src/python/test_provider_shapefile.py
index bcb5772..e3cb88c 100644
--- a/tests/src/python/test_provider_shapefile.py
+++ b/tests/src/python/test_provider_shapefile.py
@@ -481,5 +481,29 @@ class TestPyQgsShapefileProvider(unittest.TestCase, ProviderTestCase):
         self.assertTrue(ds.GetLayer(0).GetFeatureCount(), original_feature_count - 1)
         ds = None
 
+    def testSubSetStringEditable_bug17795(self):
+        """Test that a layer is not editable after setting a subset and it's reverted to editable after the filter is removed"""
+
+        testPath = TEST_DATA_DIR + '/' + 'lines.shp'
+        isEditable = QgsVectorDataProvider.ChangeAttributeValues
+
+        vl = QgsVectorLayer(testPath, 'subset_test', 'ogr')
+        self.assertTrue(vl.isValid())
+        self.assertTrue(vl.dataProvider().capabilities() & isEditable)
+
+        vl = QgsVectorLayer(testPath, 'subset_test', 'ogr')
+        vl.setSubsetString('')
+        self.assertTrue(vl.isValid())
+        self.assertTrue(vl.dataProvider().capabilities() & isEditable)
+
+        vl = QgsVectorLayer(testPath, 'subset_test', 'ogr')
+        vl.setSubsetString('"Name" = \'Arterial\'')
+        self.assertTrue(vl.isValid())
+        self.assertFalse(vl.dataProvider().capabilities() & isEditable)
+
+        vl.setSubsetString('')
+        self.assertTrue(vl.dataProvider().capabilities() & isEditable)
+
+
 if __name__ == '__main__':
     unittest.main()
diff --git a/tests/src/python/test_provider_virtual.py b/tests/src/python/test_provider_virtual.py
index 07869e7..87bf0d6 100644
--- a/tests/src/python/test_provider_virtual.py
+++ b/tests/src/python/test_provider_virtual.py
@@ -16,6 +16,7 @@ import qgis  # NOQA
 import os
 
 from qgis.core import (QgsVectorLayer,
+                       QgsField,
                        QgsFeature,
                        QgsFeatureRequest,
                        QgsGeometry,
@@ -841,6 +842,29 @@ class TestQgsVirtualLayerProvider(unittest.TestCase, ProviderTestCase):
 
         QgsMapLayerRegistry.instance().removeMapLayers([v1, v2, v3])
 
+    def testFieldsWithSpecialCharacters(self):
+        ml = QgsVectorLayer("Point?srid=EPSG:4326&field=123:int", "mem_with_nontext_fieldnames", "memory")
+        self.assertEqual(ml.isValid(), True)
+        QgsMapLayerRegistry.instance().addMapLayer(ml)
+
+        ml.startEditing()
+        self.assertTrue(ml.addAttribute(QgsField('abc:123', QVariant.String)))
+        f1 = QgsFeature(ml.fields())
+        f1.setGeometry(QgsGeometry.fromWkt('POINT(0 0)'))
+        f2 = QgsFeature(ml.fields())
+        f2.setGeometry(QgsGeometry.fromWkt('POINT(1 1)'))
+        ml.addFeatures([f1, f2])
+        ml.commitChanges()
+
+        vl = QgsVectorLayer("?query=select * from mem_with_nontext_fieldnames", "vl", "virtual")
+        self.assertEqual(vl.isValid(), True)
+        self.assertEqual(vl.fields().at(0).name(), '123')
+        self.assertEqual(vl.fields().at(1).name(), 'abc:123')
+
+        self.assertEqual(vl.featureCount(), 2)
+
+        QgsMapLayerRegistry.instance().removeMapLayer(ml)
+
 
 if __name__ == '__main__':
     unittest.main()
diff --git a/tests/testdata/provider/bug_17795.gpkg b/tests/testdata/provider/bug_17795.gpkg
new file mode 100644
index 0000000..ea914cd
Binary files /dev/null and b/tests/testdata/provider/bug_17795.gpkg 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