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

Bas Couwenberg sebastic at debian.org
Sat Dec 9 02:14:37 UTC 2017


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

sebastic pushed a commit to branch upstream
in repository qgis.

commit 45b1d7c25b15cf12e128f482196ad207a8666796
Author: Bas Couwenberg <sebastic at xs4all.nl>
Date:   Sat Dec 9 02:58:42 2017 +0100

    New upstream version 2.18.15+dfsg
---
 CMakeLists.txt                                     |   2 +-
 ChangeLog                                          | 427 +++++++++++++++++++++
 debian/changelog                                   |  10 +-
 i18n/qgis_de.ts                                    |   6 +-
 i18n/qgis_es.ts                                    | 360 ++++++++---------
 i18n/qgis_pl.ts                                    | 293 +++++++-------
 python/core/qgsactionmanager.sip                   |  13 +-
 python/core/qgslayerdefinition.sip                 |   4 +-
 python/core/qgsmaplayer.sip                        |   9 +-
 python/core/qgsproject.sip                         |   4 +-
 python/gui/qgsactionmenu.sip                       |  14 +
 python/gui/qgsidentifymenu.sip                     |  14 +
 .../db_manager/db_plugins/gpkg/connector.py        |   2 +-
 .../db_manager/db_plugins/postgis/connector.py     |  69 ++--
 .../plugins/processing/algs/grass7/Grass7Utils.py  |   2 +-
 .../algs/qgis/scripts/Frequency_analysis.py        |   2 +-
 python/plugins/processing/gui/BatchPanel.py        |   2 +
 python/pyplugin_installer/installer_data.py        |   2 +-
 src/app/main.cpp                                   | 114 ++++--
 src/app/pluginmanager/qgspluginmanager.cpp         |   2 +-
 src/app/qgisapp.cpp                                |  33 +-
 src/app/qgsapplayertreeviewmenuprovider.cpp        |   1 +
 src/app/qgsbookmarks.cpp                           | 365 +++++++++++-------
 src/app/qgsbookmarks.h                             |  80 +++-
 src/app/qgsfieldsproperties.cpp                    |   8 +-
 src/app/qgsidentifyresultsdialog.cpp               |  12 +-
 src/app/qgsidentifyresultsdialog.h                 |  18 +
 src/app/qgsmaptoolidentifyaction.cpp               |  14 +
 src/app/qgsmaptoolidentifyaction.h                 |   2 +
 src/app/qgsrelationmanagerdialog.cpp               |   4 +-
 src/auth/basic/qgsauthbasicmethod.cpp              |  21 +
 src/core/auth/qgsauthmanager.cpp                   |  52 +++
 src/core/qgsactionmanager.cpp                      |   4 +-
 src/core/qgsactionmanager.h                        |  15 +-
 src/core/qgsgml.cpp                                |   7 +-
 src/core/qgslayerdefinition.cpp                    |   6 +-
 src/core/qgslayerdefinition.h                      |   4 +-
 src/core/qgsmaplayer.cpp                           |  24 +-
 src/core/qgsmaplayer.h                             |   9 +-
 src/core/qgsofflineediting.cpp                     |   8 +-
 src/core/qgsproject.cpp                            |   7 +-
 src/core/qgsproject.h                              |   4 +-
 src/core/raster/qgscontrastenhancement.cpp         |   5 +-
 src/core/raster/qgscontrastenhancementfunction.cpp |   8 +-
 src/core/raster/qgsrasterlayerrenderer.cpp         |  25 +-
 .../qgsrelationreferenceconfigdlg.cpp              |   6 +-
 .../editorwidgets/qgsrelationreferencewidget.cpp   |  12 +-
 src/gui/editorwidgets/qgsrelationreferencewidget.h |   3 +-
 .../qgsvaluerelationwidgetwrapper.cpp              |   8 +-
 .../editorwidgets/qgsvaluerelationwidgetwrapper.h  |   2 +-
 src/gui/qgsactionmenu.cpp                          |  11 +-
 src/gui/qgsactionmenu.h                            |  15 +
 src/gui/qgsattributeform.cpp                       |  26 +-
 src/gui/qgsattributeform.h                         |   2 +-
 src/gui/qgsexpressionbuilderwidget.cpp             |   6 +-
 src/gui/qgsfiledownloader.cpp                      |   2 +
 src/gui/qgsfilterlineedit.cpp                      |   8 +-
 src/gui/qgsidentifymenu.cpp                        |  11 +
 src/gui/qgsidentifymenu.h                          |  16 +
 src/gui/raster/qgssinglebandgrayrendererwidget.cpp |  19 +-
 .../qgscategorizedsymbolrendererv2widget.cpp       |  21 +-
 .../offline_editing/offline_editing_plugin_gui.cpp |  60 +++
 .../offline_editing/offline_editing_plugin_gui.h   |   2 +
 src/providers/arcgisrest/qgsafsprovider.cpp        |  26 +-
 src/providers/arcgisrest/qgsafsprovider.h          |   3 +
 src/providers/ogr/qgsogrprovider.cpp               |  25 +-
 src/providers/postgres/qgspostgresconn.cpp         |  21 +-
 .../postgres/qgspostgresfeatureiterator.cpp        |   8 +
 src/providers/postgres/qgspostgresprovider.cpp     |   6 +
 .../virtual/qgsvirtuallayerfeatureiterator.cpp     |  30 +-
 .../virtual/qgsvirtuallayersourceselect.cpp        |  21 +-
 src/providers/wfs/qgswfsfeatureiterator.cpp        |  16 +-
 src/providers/wfs/qgswfsfeatureiterator.h          |  14 +-
 src/providers/wfs/qgswfsshareddata.cpp             |   5 +-
 src/server/qgswmsserver.cpp                        |  85 ++--
 src/ui/qgsnewgeopackagelayerdialogbase.ui          |   2 +-
 tests/src/app/CMakeLists.txt                       |   1 +
 tests/src/app/testqgsmaptoolidentifyaction.cpp     |  58 +++
 tests/src/core/testqgsgml.cpp                      |  46 +++
 tests/src/python/test_provider_ogr_gpkg.py         |  33 ++
 tests/src/python/test_provider_virtual.py          |  40 ++
 81 files changed, 2007 insertions(+), 750 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index e44104f..2f9bf04 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 "14")
+SET(CPACK_PACKAGE_VERSION_PATCH "15")
 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 e1bd428..20572b6 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,430 @@
+Merge: bfe03370ae 89d52e5d42
+Alessandro Pasotti <elpaso at itopen.it>	2017-12-06
+
+    Merge pull request #5812 from elpaso/bookmarks-backport
+
+    [bugfix] Various Bookmarks issues backported
+
+Matthias Kuhn <matthias at opengis.ch>	2017-12-06
+
+    [offline] Apply attribute changes on multiple layers
+
+    Fix #17647
+
+Alessandro Pasotti <elpaso at itopen.it>	2017-12-06
+
+    [bugfix] Various Bookmarks issues backported
+
+    Backport of several master commits that
+    fix a series of issues in the bookmarks
+    panel
+
+Borys Jurgiel <info at borysjurgiel.pl>	2017-12-06
+
+    [tr] Polish translation update: don't redirect to non-existing Polish documentation
+
+Borys Jurgiel <info at borysjurgiel.pl>	2017-12-06
+
+    [tr] Polish translation update
+
+Borys Jurgiel <info at borysjurgiel.pl>	2017-12-06
+
+    [tr] Polish translation update
+
+Merge: 79e27895c5 33737a6321
+Blottiere Paul <blottiere.paul at gmail.com>	2017-12-05
+
+    Merge pull request #5775 from pblottiere/fix_ref_rel_null
+
+    [bugfix] Constraints are updated even if the key is deleted from the keyboard
+
+Borys Jurgiel <info at borysjurgiel.pl>	2017-12-05
+
+    Fix a tooltip (backport from 3.0). Fixes #17578
+
+Merge: 2aeb5a9a07 8f0306ba4f
+Alexander Bruy <alexander.bruy at gmail.com>	2017-12-05
+
+    Merge pull request #5782 from borysiasty/release-2_18
+
+    [processing] Fix Frequency_analysis' parent group
+
+cdavila <cdavilam at orangecorreo.es>	2017-12-02
+
+    [tr] Spanish translation update
+
+cdavila <cdavilam at orangecorreo.es>	2017-12-01
+
+    [tr] Spanish translation update
+
+Matthias Kuhn <matthias at opengis.ch>	2017-11-29
+
+    Revert force WMS rendering in non-gui thread
+
+    Fix #17379
+
+Borys Jurgiel <info at borysjurgiel.pl>	2017-12-01
+
+    [processing] Fix Frequency_analysis' parent group
+
+Merge: 825ff85ad9 774b9e7afd
+Werner Macho <werner.macho at gmail.com>	2017-12-01
+
+    Merge pull request #5777 from cdavila/release-2_18
+
+    [tr] Spanish translation update
+
+cdavila <cdavilam at orangecorreo.es>	2017-11-30
+
+    [tr] Spanish translation update
+
+Blottiere Paul <blottiere.paul at gmail.com>	2017-11-30
+
+    Update widget wrapper status only when necessary
+
+Blottiere Paul <blottiere.paul at gmail.com>	2017-11-30
+
+    Update constraints when foreign key is manually updated with empty string
+
+Borys Jurgiel <info at borysjurgiel.pl>	2017-11-29
+
+    Update Polish translation
+
+Merge: 2499a20a82 cf009252d5
+Alessandro Pasotti <elpaso at itopen.it>	2017-11-28
+
+    Merge pull request #5747 from elpaso/backport-pr-5720
+
+    [bugfix] Categorized style issue using numeric fields with NULL values
+
+Merge: 9204905479 106b8b634d
+Alessandro Pasotti <elpaso at itopen.it>	2017-11-28
+
+    Merge pull request #5746 from elpaso/backport-pr-5707
+
+    [ui][bugfix] lineedit add margin for X icon
+
+Merge: 5631094ba4 fa7082b9f5
+Alessandro Pasotti <elpaso at itopen.it>	2017-11-28
+
+    Merge pull request #5742 from elpaso/backport-bugfix-17517
+
+    [bugfix] Crash on raster layer render change from python
+
+Alessandro Pasotti <elpaso at itopen.it>	2017-11-27
+
+    [bugfix] Categorized style issue using numeric fields with NULL values
+
+    Backported from master PR 5720
+
+    Fixes #17442
+
+Alessandro Pasotti <elpaso at itopen.it>	2017-11-27
+
+    [ui][bugfix] lineedit add margin for X icon
+
+    Backported from master PR 5707
+
+    Fixes #17262
+
+Alessandro Pasotti <elpaso at itopen.it>	2017-11-27
+
+    [bugfix] Crash on raster layer render change from python
+
+    Backported from master PR https://github.com/qgis/QGIS/pull/5696
+
+    Fixes #17517
+
+Merge: f206a75701 0577b2e641
+Alessandro Pasotti <elpaso at itopen.it>	2017-11-27
+
+    Merge pull request #5741 from elpaso/ogr-filter-backport
+
+    [bugfix] Update layer editable state when filter is changed
+
+Alessandro Pasotti <elpaso at itopen.it>	2017-11-27
+
+    [bugfix] Update layer editable state when filter is changed
+
+    Fixes #17507 Unable to edit filtered GeoPackage layer
+
+    Backported from master https://github.com/qgis/QGIS/pull/5691
+
+Alessandro Pasotti <elpaso at itopen.it>	2017-11-27
+
+    Add override
+
+Alessandro Pasotti <elpaso at itopen.it>	2017-11-27
+
+    [bugfix] Add a warning icon and tooltip to WFS sources
+
+    Fixes #16753 off-line editing synchronization cripples
+    the original datasource if this is a WFS-T Layer
+
+    Backported from master commit 68ddf3b9916a1148b3f
+
+Merge: 193ead7398 4693f1a4b6
+Blottiere Paul <blottiere.paul at gmail.com>	2017-11-27
+
+    Merge pull request #5695 from pblottiere/bugfix_virtuallayer_218
+
+    [backport][bugfix] Fixes #16798 FilterFid feature requests with virtual layers
+
+Juergen E. Fischer <jef at norbit.de>	2017-11-26
+
+    Fix german translation (superceeds PR#5730)
+
+Juergen E. Fischer <jef at norbit.de>	2017-11-24
+
+    fix build
+
+Matthias Kuhn <matthias at opengis.ch>	2017-11-23
+
+    Avoid recursion in ValueRelation widget
+
+    Fix #17521
+
+Mathieu Pellerin <nirvn.asia at gmail.com>	2017-11-23
+
+    [ArcGIS REST] backport for crasher and mutex
+
+Blottiere Paul <blottiere.paul at gmail.com>	2017-11-22
+
+    Add some tests
+
+Blottiere Paul <blottiere.paul at gmail.com>	2017-11-22
+
+    Fixes #16798 FilterFid feature requests with virtual layers
+
+Merge: dbd4f9efc2 4fe001396d
+Blottiere Paul <blottiere.paul at gmail.com>	2017-11-22
+
+    Merge pull request #5660 from pblottiere/bugfix-clickxy-218
+
+    [backport][bugfix] Fixes #16852 by adding click_x and click_y variables to resolve actions
+
+Merge: ac109e4302 5fb970abbe
+Hugo Mercier <hugo.mercier at oslandia.com>	2017-11-20
+
+    Merge pull request #5677 from mhugo/fix_slow_relation_reference
+
+    Postgresql: don't fetch if there is nothing (fixes #17502)
+
+Alessandro Pasotti <apasotti at boundlessgeo.com>	2017-11-20
+
+    [bugfix] Do not crash when testing empty virtual layers
+
+    Fixes #17489
+
+    Backported from master
+
+Hugo Mercier <hugo.mercier at oslandia.com>	2017-11-20
+
+    Postgresql: don't fetch if there is nothing (fixes #17502)
+
+Blottiere Paul <blottiere.paul at gmail.com>	2017-11-16
+
+    Update doc and sip binding
+
+Blottiere Paul <blottiere.paul at gmail.com>	2017-11-16
+
+    Add some tests
+
+Blottiere Paul <blottiere.paul at gmail.com>	2017-11-16
+
+    Fixes #16852 by adding click_x and click_y variables to resolve actions
+
+Merge: de9d0b873b c56e29ef30
+Alexander Bruy <alexander.bruy at gmail.com>	2017-11-18
+
+    Merge pull request #5642 from NaturalGIS/2_18_grass74_support
+
+    [processing] add GRASS74 support
+
+Merge: 87dbb8842f 783e54fd7f
+rldhont <rldhont at gmail.com>	2017-11-16
+
+    Merge pull request #5548 from rldhont/release-2_18-server-getfeatureinfo-raster-display
+
+    Release 2-18 server getfeatureinfo raster display
+
+Salvatore Larosa <lrssvtml at gmail.com>	2017-11-16
+
+    truncate only last extension in oper recent project menu
+
+    cherry-picked from 7c9cc07e
+
+Salvatore Larosa <lrssvtml at gmail.com>	2017-11-16
+
+    [processing] fix batch execution when alg has ParameterPoint
+
+Even Rouault <even.rouault at spatialys.com>	2017-11-16
+
+    [QgsAuthManager] Protect all methods that do SQL queries with mutex (fixes #16966)
+
+Giovanni Manghi <giovanni.manghi at naturalgis.pt>	2017-11-15
+
+    add GRASS74 support in QGIS 2.18
+
+Alexander Bruy <alexander.bruy at gmail.com>	2017-11-14
+
+    correctly create new function file (fix #16752)
+
+    (cherry picked from commit d8398400f989147e8b9c89bf3c4beb87e2f8f97f)
+
+David <david at opengis.ch>	2017-11-14
+
+    Use id in gui if name is empty and crop layerid-part in the generated id
+
+    The name can be empty, so use the id instead in the combo box. To avoid so long ids, the part taken from the layerid in the relation id is cropped to 10 signs. They are unique anyway because there is used a suffix counting up.
+
+David <david at opengis.ch>	2017-11-13
+
+    Autogenerated relation names in dialog instead of ids
+
+    The autogenerated ids are quite long and this leads that they where very unconfortable to use in the configuration of relation reference in the attribute type widget of layer properties - attribute form. So now the names are used in the combo instead of the ids. This effects only the GUI.
+
+    Fix: #17441
+
+Even Rouault <even.rouault at spatialys.com>	2017-11-14
+
+    Raster renderer: fix so that raster in projected CRS is not rendered in geographic CRS if the extent exceeds -180,-90,180,90 (fixes #14229)
+
+Borys Jurgiel <info at borysjurgiel.pl>	2017-11-14
+
+    [Plugin manager] Don't truncate long names (#17451). Backport from 3.0.
+
+Even Rouault <even.rouault at spatialys.com>	2017-11-14
+
+    [Raster] Do not crash when displaying a raster with complex datatype (fixes #16405)
+
+    That said, complex datatypes are not handled, so QGIS cannot do anything useful
+    with such datasets.
+
+Even Rouault <even.rouault at spatialys.com>	2017-11-13
+
+    [OGR provider] Support 64bit FID (fixes #16404)
+
+Even Rouault <even.rouault at spatialys.com>	2017-11-12
+
+    [OGR provider] Make extent() return a isNull() rectangle on empty layer (fixes #16721)
+
+Even Rouault <even.rouault at spatialys.com>	2017-11-11
+
+    Formatting fix
+
+Even Rouault <even.rouault at spatialys.com>	2017-11-11
+
+    [GML parser/WFS provider] Fix crash when typename and geometry field name are identical (fixes #15942)
+
+Alessandro Pasotti <apasotti at boundlessgeo.com>	2017-11-10
+
+    [bugfix][postgresql] Fix crashes on featureCount()
+
+    Fixes #17388
+
+    Backported from master fe5653101a57
+
+Larry Shaffer <lshaffer at boundlessgeo.com>	2017-11-04
+
+    Fix updating QgsApplication::libraryPaths; load before any Qt plugin use
+
+    Previously, it was happening after setting the default window icon.
+
+    For macOS, refactor libraryPaths update to ensure both QT_PLUGIN_PATH
+    and qt.conf are properly honored (fixes 4.5 year old bug), with
+    prioritization of qgis libs or libs shipped with .app bundle.
+
+    Backported from master 4c78526203404553eab31bd8da08e6e3bea7d5c2
+
+Even Rouault <even.rouault at spatialys.com>	2017-11-09
+
+    [DB Manager / GPKG] Fix COMMIT with GDAL 2 (fix #16174)
+
+Even Rouault <even.rouault at spatialys.com>	2017-11-09
+
+    [WFS provider] Fix deadlock when adding WFS layer to project from Python console (fixes #17087)
+
+Alessandro Pasotti <apasotti at boundlessgeo.com>	2017-11-08
+
+    [bugfix] Fixes QgsFileDownloader abort on error
+
+    Backported from master 6b9b513
+
+David <david at opengis.ch>	2017-11-08
+
+    Fix #17412 Sorting fixed, no troubles when editing after sorting
+    Issue was, that the cellchange is triggered at re-sorting or renaming something in re-sorted table - so there was a bug that referenced to the row instead of the index
+
+Merge: 22a7b92d68 533a8f8a4d
+rldhont <rldhont at gmail.com>	2017-11-08
+
+    Merge pull request #5553 from rldhont/release-2_18-layerdefinition-relativepath
+
+    [BUGFIX] Load layer from definition does not use qlr as relative path
+
+rldhont <rldhont at gmail.com>	2017-11-07
+
+    [PATCH] [BUGFIX] Load layer from definition does not use qlr as relative path
+
+    Fixes #15656 Loading QLR file with relative path does not work correctly
+
+rldhont <rldhont at gmail.com>	2017-11-06
+
+    [Server] GetFeatureInfo: enhance raster data values displayed
+
+rldhont <rldhont at gmail.com>	2017-11-03
+
+    [BUGFIX][Server] GetFeaturInfo: do not identify raster data if point not contains
+
+Borys Jurgiel <info at borysjurgiel.pl>	2017-11-03
+
+    [Plugin installer] Fix broken warning about outdated plugin updates in the user directory masking a newer core version
+
+Merge: 08889c77c9 3fab14040b
+Alessandro Pasotti <elpaso at itopen.it>	2017-11-03
+
+    Merge pull request #5524 from boundlessgeo/basic_cas_backport
+
+    [bugfix][auth] Basic method uses trusted CAs when connecting to DB
+
+Alessandro Pasotti <apasotti at boundlessgeo.com>	2017-11-03
+
+    [bugfix][auth] Basic method uses trusted CAs when connecting to DB
+
+    Fixes #17392
+
+    Backport of Basic auth CAs fix from master
+
+Luigi Pirelli <luipir at gmail.com>	2017-11-01
+
+    Followup fix to ab74991; add missing QFile import
+
+Matthias Kuhn <matthias at opengis.ch>	2017-10-31
+
+    Clear WMS preview image
+
+Matthias Kuhn <matthias at opengis.ch>	2017-10-04
+
+    Do not paint WMS preview images. Because it crashes.
+
+    Fix #16803
+
+Merge: ff83b9a479 ab74991a89
+Alessandro Pasotti <elpaso at itopen.it>	2017-10-31
+
+    Merge pull request #5477 from boundlessgeo/certs_not_removed_with_pki_postgis_on_win
+
+    [security] Set permission to certs to allow correct removing on win
+
+Juergen E. Fischer <jef at norbit.de>	2017-10-27
+
+    Release of 2.18.14
+
+Luigi Pirelli <luipir at gmail.com>	2017-10-27
+
+    Set permission to certs to allow correct removing on win
+
 Luigi Pirelli <luipir at gmail.com>	2017-10-24
 
     reload only updated column
diff --git a/debian/changelog b/debian/changelog
index 7ffd657..566edd0 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,8 +1,14 @@
-qgis (2.18.14) UNRELEASED; urgency=medium
+qgis (2.18.15) UNRELEASED; urgency=medium
+
+  * Release of 2.18.15
+
+ -- Jürgen E. Fischer <jef at norbit.de>  Fri, 08 Dec 2017 14:00:24 +0100
+
+qgis (2.18.14) unstable; urgency=medium
 
   * Release of 2.18.14
 
- -- Jürgen E. Fischer <jef at norbit.de>  Fri, 27 Oct 2017 14:00:21 +0200
+ -- Jürgen E. Fischer <jef at norbit.de>  Fri, 08 Dec 2017 14:00:24 +0100
 
 qgis (2.18.13) unstable; urgency=medium
 
diff --git a/i18n/qgis_de.ts b/i18n/qgis_de.ts
index 6b3a545..f39ca26 100644
--- a/i18n/qgis_de.ts
+++ b/i18n/qgis_de.ts
@@ -24417,9 +24417,9 @@ Datenbank: %2</translation>
     <message numerus="yes">
         <source>Are you sure you want to delete %n bookmark(s)?</source>
         <comment>number of rows</comment>
-        <translation>
-            <numerusform>Sind Sie sicher, daß Sie das Lesezeichen löschen wollen?</numerusform>
-            <numerusform>Sind Sie sicher, daß Sie %n Lesezeichen löschen wollen?</numerusform>
+        <translation type="unfinished">
+            <numerusform>Soll das Lesezeichen wirklich gelöscht werden?</numerusform>
+            <numerusform>Sollen %n Lesezeichen wirklich gelöscht werden?</numerusform>
         </translation>
     </message>
     <message>
diff --git a/i18n/qgis_es.ts b/i18n/qgis_es.ts
index 9ce6d20..528ebec 100644
--- a/i18n/qgis_es.ts
+++ b/i18n/qgis_es.ts
@@ -1046,7 +1046,7 @@ Procesando algoritmo %d/%d...</translation>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="224"/>
         <source>Canopy Maxima</source>
-        <translation type="unfinished"></translation>
+        <translation>Dosel forestal máximo</translation>
     </message>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="225"/>
@@ -1094,7 +1094,7 @@ Procesando algoritmo %d/%d...</translation>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="236"/>
         <source>Canopy Model</source>
-        <translation type="unfinished"></translation>
+        <translation>Modelo de dosel forestal</translation>
     </message>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="237"/>
@@ -2839,7 +2839,7 @@ Consulta:
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="434"/>
         <source>Input canopy surface (.dtm)</source>
-        <translation type="unfinished"></translation>
+        <translation>Superficie de dosel forestal de entrada (.dtm)</translation>
     </message>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="435"/>
@@ -4647,7 +4647,7 @@ columnas</translation>
         <location filename="../python/plugins/processing/ui/DlgConfig.ui" line="14"/>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="696"/>
         <source>Processing options</source>
-        <translation>Opciones de procesado</translation>
+        <translation>Opciones de Procesos</translation>
     </message>
     <message>
         <location filename="../python/plugins/processing/ui/DlgConfig.ui" line="26"/>
@@ -9315,7 +9315,7 @@ Por favor, configúrela antes de ejecutar algoritmos de GRASS.</translation>
     <message>
         <location filename="../python/plugins/processing/processing-i18n.cpp" line="610"/>
         <source>i.eb.hsebal01.coords - Computes sensible heat flux iteration SEBAL 01. Inline coordinates</source>
-        <translation type="unfinished"></translation>
+        <translation>i.eb.hsebal01.coords - Prodesa iteración SEBAL 01 de flujo de calor sensible. Coordendas en línea.</translation>
     </message>
     <message>
         <location filename="../python/plugins/processing/processing-i18n.cpp" line="614"/>
@@ -9325,7 +9325,7 @@ Por favor, configúrela antes de ejecutar algoritmos de GRASS.</translation>
     <message>
         <location filename="../python/plugins/processing/processing-i18n.cpp" line="343"/>
         <source>Computes biomass growth, precursor of crop yield calculation.</source>
-        <translation type="unfinished"></translation>
+        <translation>Procesa el crecimiento de biomasa, precursor del cálculo de la producción de los cultivos.</translation>
     </message>
     <message>
         <location filename="../python/plugins/processing/processing-i18n.cpp" line="586"/>
@@ -9370,7 +9370,7 @@ Por favor, configúrela antes de ejecutar algoritmos de GRASS.</translation>
     <message>
         <location filename="../python/plugins/processing/processing-i18n.cpp" line="538"/>
         <source>Computes evaporative fraction (Bastiaanssen, 1995) and root zone soil moisture (Makin, Molden and Bastiaanssen, 2001).</source>
-        <translation type="unfinished"></translation>
+        <translation>Procesa la fracción evaporativa (Bastiaanssen, 1995) y la humedad de suelo en zona de la raíz (Makin, Molden y Bastiaanssen, 2001).</translation>
     </message>
     <message>
         <location filename="../python/plugins/processing/processing-i18n.cpp" line="530"/>
@@ -9400,7 +9400,7 @@ Por favor, configúrela antes de ejecutar algoritmos de GRASS.</translation>
     <message>
         <location filename="../python/plugins/processing/processing-i18n.cpp" line="537"/>
         <source>Computes broad band albedo from surface reflectance. </source>
-        <translation type="unfinished"></translation>
+        <translation>Procesa albedo de banda ancha a partir de la reflectividad de la superficie.</translation>
     </message>
     <message>
         <location filename="../python/plugins/processing/processing-i18n.cpp" line="461"/>
@@ -9410,12 +9410,12 @@ Por favor, configúrela antes de ejecutar algoritmos de GRASS.</translation>
     <message>
         <location filename="../python/plugins/processing/processing-i18n.cpp" line="426"/>
         <source>Computes sensible heat flux iteration SEBAL 01.</source>
-        <translation type="unfinished"></translation>
+        <translation>Procesa iteración SEBAL 01 de flujo de calor sensible.</translation>
     </message>
     <message>
         <location filename="../python/plugins/processing/processing-i18n.cpp" line="508"/>
         <source>Performs Landsat TM/ETM+ Automatic Cloud Cover Assessment (ACCA).</source>
-        <translation type="unfinished"></translation>
+        <translation>Realiza ensayo automático de cobertura de nubes Landsat TM/ETM+ (ACCA).</translation>
     </message>
     <message>
         <location filename="../python/plugins/processing/processing-i18n.cpp" line="480"/>
@@ -9435,7 +9435,7 @@ Por favor, configúrela antes de ejecutar algoritmos de GRASS.</translation>
     <message>
         <location filename="../python/plugins/processing/processing-i18n.cpp" line="657"/>
         <source>Calculates top-of-atmosphere radiance or reflectance and temperature for Landsat MSS/TM/ETM+/OLI</source>
-        <translation type="unfinished"></translation>
+        <translation>Calcula la radiación o reflectividad y temperatura de la parte superior de la atmósfera para Landsat MSS/TM/ETM+/OLI</translation>
     </message>
     <message>
         <location filename="../python/plugins/processing/processing-i18n.cpp" line="454"/>
@@ -9450,7 +9450,7 @@ Por favor, configúrela antes de ejecutar algoritmos de GRASS.</translation>
     <message>
         <location filename="../python/plugins/processing/processing-i18n.cpp" line="475"/>
         <source>Computes temporal integration of satellite ET actual (ETa) following the daily ET reference (ETo) from meteorological station(s).</source>
-        <translation type="unfinished"></translation>
+        <translation>Procesa la integración temporal de ET real (ETa) de satélite siguiendo la referencia de ET diaria (ETo) a partir de estaciones meteorológicas.</translation>
     </message>
     <message>
         <location filename="../python/plugins/processing/processing-i18n.cpp" line="355"/>
@@ -9470,17 +9470,17 @@ Por favor, configúrela antes de ejecutar algoritmos de GRASS.</translation>
     <message>
         <location filename="../python/plugins/processing/processing-i18n.cpp" line="570"/>
         <source>Soil heat flux approximation (Bastiaanssen, 1995).</source>
-        <translation type="unfinished"></translation>
+        <translation>Aproximación de flujo de calor en el suelo (Bastiaanssen, 1995).</translation>
     </message>
     <message>
         <location filename="../python/plugins/processing/processing-i18n.cpp" line="525"/>
         <source>Mosaics several images and extends colormap.</source>
-        <translation type="unfinished"></translation>
+        <translation>Hace mosaico de varias imágenes y extiende mapa de color.</translation>
     </message>
     <message>
         <location filename="../python/plugins/processing/processing-i18n.cpp" line="576"/>
         <source>Calculates Top of Atmosphere Radiance/Reflectance/Brightness Temperature from ASTER DN.</source>
-        <translation type="unfinished"></translation>
+        <translation>Calcula la radiación/reflectividad/brillo temperatura de la parte superior de la atmósfera a partir de ASTER DN.</translation>
     </message>
     <message>
         <location filename="../python/plugins/processing/processing-i18n.cpp" line="649"/>
@@ -9600,7 +9600,7 @@ Por favor, configúrela antes de ejecutar algoritmos de GRASS.</translation>
     <message>
         <location filename="../python/plugins/processing/processing-i18n.cpp" line="515"/>
         <source>r.li.mps.ascii - Calculates mean patch size index on a raster map, using a 4 neighbour algorithm</source>
-        <translation type="unfinished"></translation>
+        <translation>r.li.mps.ascii - Calcula el índice de tamaño de parche medio de un mapa ráster, usando un algoritmo de 4 vecinos.</translation>
     </message>
     <message>
         <location filename="../python/plugins/processing/processing-i18n.cpp" line="651"/>
@@ -9680,7 +9680,7 @@ Por favor, configúrela antes de ejecutar algoritmos de GRASS.</translation>
     <message>
         <location filename="../python/plugins/processing/processing-i18n.cpp" line="336"/>
         <source>Computes USLE R factor, Rainfall erosivity index.</source>
-        <translation type="unfinished"></translation>
+        <translation>Procesa el factor USLE R, índice de erosividad pluvial.</translation>
     </message>
     <message>
         <location filename="../python/plugins/processing/processing-i18n.cpp" line="527"/>
@@ -9735,7 +9735,7 @@ Por favor, configúrela antes de ejecutar algoritmos de GRASS.</translation>
     <message>
         <location filename="../python/plugins/processing/processing-i18n.cpp" line="441"/>
         <source>Computes USLE Soil Erodibility Factor (K).</source>
-        <translation type="unfinished"></translation>
+        <translation>Procesa el factor USLE de erosividad del suelo (K).</translation>
     </message>
     <message>
         <location filename="../python/plugins/processing/processing-i18n.cpp" line="502"/>
@@ -9790,7 +9790,7 @@ Por favor, configúrela antes de ejecutar algoritmos de GRASS.</translation>
     <message>
         <location filename="../python/plugins/processing/processing-i18n.cpp" line="335"/>
         <source>Drapes a color raster over an shaded relief or aspect map. </source>
-        <translation type="unfinished"></translation>
+        <translation>Cubre con un ráster de color un relieve sombreado o un mapa de orientación.</translation>
     </message>
     <message>
         <location filename="../python/plugins/processing/processing-i18n.cpp" line="427"/>
@@ -10045,7 +10045,7 @@ Por favor, configúrela antes de ejecutar algoritmos de GRASS.</translation>
     <message>
         <location filename="../python/plugins/processing/processing-i18n.cpp" line="635"/>
         <source>Computes minimum spanning tree for the network.</source>
-        <translation type="unfinished"></translation>
+        <translation>Calcula el árbol de alcance mínimo para la red.</translation>
     </message>
     <message>
         <location filename="../python/plugins/processing/processing-i18n.cpp" line="421"/>
@@ -10085,7 +10085,7 @@ Por favor, configúrela antes de ejecutar algoritmos de GRASS.</translation>
     <message>
         <location filename="../python/plugins/processing/processing-i18n.cpp" line="386"/>
         <source>r.aspect - Generates raster maps of aspect from an elevation raster map.</source>
-        <translation type="unfinished"></translation>
+        <translation>r.aspect - Genera mapas ráster de orientación a partir de un mapa ráster de elevación.</translation>
     </message>
     <message>
         <location filename="../python/plugins/processing/processing-i18n.cpp" line="393"/>
@@ -10375,7 +10375,7 @@ Por favor, configúrela antes de ejecutar algoritmos de GRASS.</translation>
     <message>
         <location filename="../python/plugins/processing/processing-i18n.cpp" line="583"/>
         <source>Finds line id and real km+offset for given points in vector map using linear reference system. </source>
-        <translation type="unfinished"></translation>
+        <translation>Encuentra ID de línea y km real+desplazamiento para puntos dados en un mapa vectorial usando un sistema de referencia lineal.</translation>
     </message>
     <message>
         <location filename="../python/plugins/processing/processing-i18n.cpp" line="604"/>
@@ -10415,7 +10415,7 @@ Por favor, configúrela antes de ejecutar algoritmos de GRASS.</translation>
     <message>
         <location filename="../python/plugins/processing/processing-i18n.cpp" line="389"/>
         <source>Extrudes flat vector object to 3D with defined height.</source>
-        <translation type="unfinished"></translation>
+        <translation>Extruye objetos vectoriales planos a 3D con una altura definida.</translation>
     </message>
     <message>
         <location filename="../python/plugins/processing/processing-i18n.cpp" line="456"/>
@@ -10495,7 +10495,7 @@ Por favor, configúrela antes de ejecutar algoritmos de GRASS.</translation>
     <message>
         <location filename="../python/plugins/processing/processing-i18n.cpp" line="556"/>
         <source>r.slope - Generates raster maps of slope from an elevation raster map.</source>
-        <translation type="unfinished"></translation>
+        <translation>r.slope - Genera mapas ráster de pendiente a partir de un mapa ráster de elevación.</translation>
     </message>
     <message>
         <location filename="../python/plugins/processing/processing-i18n.cpp" line="455"/>
@@ -10780,7 +10780,7 @@ Por favor, configúrela antes de ejecutar algoritmos de GRASS.</translation>
     <message>
         <location filename="../python/plugins/processing/processing-i18n.cpp" line="405"/>
         <source>Building contour determination and Region Growing algorithm for determining the building inside</source>
-        <translation type="unfinished"></translation>
+        <translation>Determinación del contorno de edificios y algoritmo de crecimiento regional para determinar el edificio dentro</translation>
     </message>
     <message>
         <location filename="../python/plugins/processing/processing-i18n.cpp" line="328"/>
@@ -17881,7 +17881,7 @@ Esto puede ocasionar resultados inesperados.</translation>
         <location filename="../python/plugins/processing/ui/ProcessingToolbox.ui" line="14"/>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="2322"/>
         <source>Processing Toolbox</source>
-        <translation>Caja de herramientas de procesado</translation>
+        <translation>Caja de herramientas de Procesos</translation>
     </message>
     <message>
         <location filename="../python/plugins/processing/ui/ProcessingToolbox.ui" line="27"/>
@@ -34907,7 +34907,7 @@ Por favor, pruebe una resolución menor o un tamaño de papel más pequeño.</tr
     <message>
         <location filename="../src/ui/composer/qgscomposerlegendwidgetbase.ui" line="737"/>
         <source>Hairline</source>
-        <translation type="unfinished"></translation>
+        <translation>Línea fina</translation>
     </message>
     <message>
         <location filename="../src/ui/composer/qgscomposerlegendwidgetbase.ui" line="762"/>
@@ -43838,7 +43838,7 @@ p, li { white-space: pre-wrap; }
     </message>
     <message>
         <source>closest_point</source>
-        <translation type="unfinished"></translation>
+        <translation>closest_point</translation>
     </message>
     <message>
         <source>geometry to find closest point on</source>
@@ -43854,7 +43854,7 @@ p, li { white-space: pre-wrap; }
     </message>
     <message>
         <source>Point(73.0769 115.384)</source>
-        <translation type="unfinished"></translation>
+        <translation>Point(73.0769 115.384)</translation>
     </message>
     <message>
         <source>Returns the first non-NULL value from the expression list.<br>This function can take any number of arguments.</source>
@@ -44246,7 +44246,7 @@ p, li { white-space: pre-wrap; }
     </message>
     <message>
         <source>darker('200,10,30',300)</source>
-        <translation type="unfinished"></translation>
+        <translation>darker('200,10,30',300)</translation>
     </message>
     <message>
         <source>'66,3,10,255'</source>
@@ -44338,7 +44338,7 @@ p, li { white-space: pre-wrap; }
     </message>
     <message>
         <source>degrees(3.14159)</source>
-        <translation type="unfinished"></translation>
+        <translation>degrees(3.14159)</translation>
     </message>
     <message>
         <source>180</source>
@@ -44346,7 +44346,7 @@ p, li { white-space: pre-wrap; }
     </message>
     <message>
         <source>degrees(1)</source>
-        <translation type="unfinished"></translation>
+        <translation>degrees(1)</translation>
     </message>
     <message>
         <source>57.2958</source>
@@ -44430,19 +44430,19 @@ p, li { white-space: pre-wrap; }
     </message>
     <message>
         <source>eval(''nice'')</source>
-        <translation type="unfinished"></translation>
+        <translation>eval(''nice'')</translation>
     </message>
     <message>
         <source>'nice'</source>
-        <translation type="unfinished"></translation>
+        <translation>'nice'</translation>
     </message>
     <message>
         <source>eval(@expression_var)</source>
-        <translation type="unfinished"></translation>
+        <translation>eval(@expression_var)</translation>
     </message>
     <message>
         <source>[whatever the result of evaluating @expression_var might be...]</source>
-        <translation type="unfinished"></translation>
+        <translation>[cualquiera que pueda ser el resultado de evaluar @expression_var ...]</translation>
     </message>
     <message>
         <source>Returns exponential of an value.</source>
@@ -44470,7 +44470,7 @@ p, li { white-space: pre-wrap; }
     </message>
     <message>
         <source>exterior_ring</source>
-        <translation type="unfinished"></translation>
+        <translation>exterior_ring</translation>
     </message>
     <message>
         <source>a polygon geometry</source>
@@ -44478,19 +44478,19 @@ p, li { white-space: pre-wrap; }
     </message>
     <message>
         <source>geom_to_wkt(exterior_ring(geom_from_wkt('POLYGON((-1 -1, 4 0, 4 2, 0 2, -1 -1),( 0.1 0.1, 0.1 0.2, 0.2 0.2, 0.2, 0.1, 0.1 0.1))')))</source>
-        <translation type="unfinished"></translation>
+        <translation>geom_to_wkt(exterior_ring(geom_from_wkt('POLYGON((-1 -1, 4 0, 4 2, 0 2, -1 -1),( 0.1 0.1, 0.1 0.2, 0.2 0.2, 0.2, 0.1, 0.1 0.1))')))</translation>
     </message>
     <message>
         <source>'LineString (-1 -1, 4 0, 4 2, 0 2, -1 -1)'</source>
-        <translation type="unfinished"></translation>
+        <translation>'LineString (-1 -1, 4 0, 4 2, 0 2, -1 -1)'</translation>
     </message>
     <message>
         <source>Returns an extruded version of the input (Multi-)Curve or (Multi-)Linestring geometry with an extension specified by x and y.</source>
-        <translation type="unfinished"></translation>
+        <translation>Devuelve una versión extruida de la geometría de entrada (multi)curva o (multi)línea, con una extensión especificada por X e Y.</translation>
     </message>
     <message>
         <source>extrude</source>
-        <translation type="unfinished"></translation>
+        <translation>extrude</translation>
     </message>
     <message>
         <source>Returns a point projected from a start point using a distance and bearing (azimuth) in radians.</source>
@@ -44530,19 +44530,19 @@ p, li { white-space: pre-wrap; }
     </message>
     <message>
         <source>extrude(geom_from_wkt('LineString(1 2, 3 2, 4 3)'), 1, 2)</source>
-        <translation type="unfinished"></translation>
+        <translation>extrude(geom_from_wkt('LineString(1 2, 3 2, 4 3)'), 1, 2)</translation>
     </message>
     <message>
         <source>Polygon ((1 2, 3 2, 4 3, 5 5, 4 4, 2 4, 1 2))</source>
-        <translation type="unfinished"></translation>
+        <translation>Polygon ((1 2, 3 2, 4 3, 5 5, 4 4, 2 4, 1 2))</translation>
     </message>
     <message>
         <source>extrude(geom_from_wkt('MultiLineString((1 2, 3 2), (4 3, 8 3)'), 1, 2)</source>
-        <translation type="unfinished"></translation>
+        <translation>extrude(geom_from_wkt('MultiLineString((1 2, 3 2), (4 3, 8 3)'), 1, 2)</translation>
     </message>
     <message>
         <source>MultiPolygon (((1 2, 3 2, 4 4, 2 4, 1 2)),((4 3, 8 3, 9 5, 5 5, 4 3)))</source>
-        <translation type="unfinished"></translation>
+        <translation>MultiPolygon (((1 2, 3 2, 4 4, 2 4, 1 2)),((4 3, 8 3, 9 5, 5 5, 4 3)))</translation>
     </message>
     <message>
         <source>Rounds a number downwards.</source>
@@ -44710,7 +44710,7 @@ p, li { white-space: pre-wrap; }
     </message>
     <message>
         <source>geometry_n</source>
-        <translation type="unfinished"></translation>
+        <translation>geometry_n</translation>
     </message>
     <message>
         <source>geometry collection</source>
@@ -44722,11 +44722,11 @@ p, li { white-space: pre-wrap; }
     </message>
     <message>
         <source>geom_to_wkt(geometry_n(geom_from_wkt('GEOMETRYCOLLECTION(POINT(0 1), POINT(0 0), POINT(1 0), POINT(1 1))'),3))</source>
-        <translation type="unfinished"></translation>
+        <translation>geom_to_wkt(geometry_n(geom_from_wkt('GEOMETRYCOLLECTION(POINT(0 1), POINT(0 0), POINT(1 0), POINT(1 1))'),3))</translation>
     </message>
     <message>
         <source>'Point (1 0)'</source>
-        <translation type="unfinished"></translation>
+        <translation>'Point (1 0)'</translation>
     </message>
     <message>
         <source>Returns the first feature of a layer matching a given attribute value.</source>
@@ -44862,7 +44862,7 @@ p, li { white-space: pre-wrap; }
     </message>
     <message>
         <source>interior_ring_n</source>
-        <translation type="unfinished"></translation>
+        <translation>interior_ring_n</translation>
     </message>
     <message>
         <source>polygon geometry</source>
@@ -44874,11 +44874,11 @@ p, li { white-space: pre-wrap; }
     </message>
     <message>
         <source>geom_to_wkt(interior_ring_n(geom_from_wkt('POLYGON((-1 -1, 4 0, 4 2, 0 2, -1 -1),(-0.1 -0.1, 0.4 0, 0.4 0.2, 0 0.2, -0.1 -0.1),(-1 -1, 4 0, 4 2, 0 2, -1 -1))'),1))</source>
-        <translation type="unfinished"></translation>
+        <translation>geom_to_wkt(interior_ring_n(geom_from_wkt('POLYGON((-1 -1, 4 0, 4 2, 0 2, -1 -1),(-0.1 -0.1, 0.4 0, 0.4 0.2, 0 0.2, -0.1 -0.1),(-1 -1, 4 0, 4 2, 0 2, -1 -1))'),1))</translation>
     </message>
     <message>
         <source>'LineString (-0.1 -0.1, 0.4 0, 0.4 0.2, 0 0.2, -0.1 -0.1))'</source>
-        <translation type="unfinished"></translation>
+        <translation>'LineString (-0.1 -0.1, 0.4 0, 0.4 0.2, 0 0.2, -0.1 -0.1))'</translation>
     </message>
     <message>
         <source>Returns a geometry that represents the shared portion of two geometries.</source>
@@ -44934,7 +44934,7 @@ p, li { white-space: pre-wrap; }
     </message>
     <message>
         <source>is_closed</source>
-        <translation type="unfinished"></translation>
+        <translation>is_closed</translation>
     </message>
     <message>
         <source>a line string geometry</source>
@@ -44942,11 +44942,11 @@ p, li { white-space: pre-wrap; }
     </message>
     <message>
         <source>is_closed(geom_from_wkt('LINESTRING(0 0, 1 1, 2 2)'))</source>
-        <translation type="unfinished"></translation>
+        <translation>is_closed(geom_from_wkt('LINESTRING(0 0, 1 1, 2 2)'))</translation>
     </message>
     <message>
         <source>is_closed(geom_from_wkt('LINESTRING(0 0, 1 1, 2 2, 0 0)'))</source>
-        <translation type="unfinished"></translation>
+        <translation>is_closed(geom_from_wkt('LINESTRING(0 0, 1 1, 2 2, 0 0)'))</translation>
     </message>
     <message>
         <source>Returns a matching layer property or metadata value.</source>
@@ -45082,7 +45082,7 @@ p, li { white-space: pre-wrap; }
     </message>
     <message>
         <source>lighter('200,10,30',200)</source>
-        <translation type="unfinished"></translation>
+        <translation>lighter('200,10,30',200)</translation>
     </message>
     <message>
         <source>'255,158,168,255'</source>
@@ -45230,7 +45230,7 @@ p, li { white-space: pre-wrap; }
     </message>
     <message>
         <source>m( geom_from_wkt( 'POINTM(2 5 4)' ) )</source>
-        <translation type="unfinished"></translation>
+        <translation>m( geom_from_wkt( 'POINTM(2 5 4)' ) )</translation>
     </message>
     <message>
         <source>Creates a line geometry from a series of point geometries.</source>
@@ -45238,23 +45238,23 @@ p, li { white-space: pre-wrap; }
     </message>
     <message>
         <source>make_line</source>
-        <translation type="unfinished"></translation>
+        <translation>make_line</translation>
     </message>
     <message>
         <source>geom_to_wkt(make_line(make_point(2,4),make_point(3,5)))</source>
-        <translation type="unfinished"></translation>
+        <translation>geom_to_wkt(make_line(make_point(2,4),make_point(3,5)))</translation>
     </message>
     <message>
         <source>'LineString (2 4, 3 5)'</source>
-        <translation type="unfinished"></translation>
+        <translation>'LineString (2 4, 3 5)'</translation>
     </message>
     <message>
         <source>geom_to_wkt(make_line(make_point(2,4),make_point(3,5),make_point(9,7)))</source>
-        <translation type="unfinished"></translation>
+        <translation>geom_to_wkt(make_line(make_point(2,4),make_point(3,5),make_point(9,7)))</translation>
     </message>
     <message>
         <source>'LineString (2 4, 3 5, 9 7)'</source>
-        <translation type="unfinished"></translation>
+        <translation>'LineString (2 4, 3 5, 9 7)'</translation>
     </message>
     <message>
         <source>Creates a point geometry from an x and y (and optional z and m) value.</source>
@@ -45310,7 +45310,7 @@ p, li { white-space: pre-wrap; }
     </message>
     <message>
         <source>'PointZ (2 4 6)'</source>
-        <translation type="unfinished"></translation>
+        <translation>'PointZ (2 4 6)'</translation>
     </message>
     <message>
         <source>geom_to_wkt(make_point(2,4,6,8))</source>
@@ -45318,7 +45318,7 @@ p, li { white-space: pre-wrap; }
     </message>
     <message>
         <source>'PointZM (2 4 6 8)'</source>
-        <translation type="unfinished"></translation>
+        <translation>'PointZM (2 4 6 8)'</translation>
     </message>
     <message>
         <source>Creates a point geometry from an x, y coordinate and m value.</source>
@@ -45326,7 +45326,7 @@ p, li { white-space: pre-wrap; }
     </message>
     <message>
         <source>make_point_m</source>
-        <translation type="unfinished"></translation>
+        <translation>make_point_m</translation>
     </message>
     <message>
         <source>m value of point</source>
@@ -45334,11 +45334,11 @@ p, li { white-space: pre-wrap; }
     </message>
     <message>
         <source>geom_to_wkt(make_point_m(2,4,6))</source>
-        <translation type="unfinished"></translation>
+        <translation>geom_to_wkt(make_point_m(2,4,6))</translation>
     </message>
     <message>
         <source>'PointM (2 4 6)'</source>
-        <translation type="unfinished"></translation>
+        <translation>'PointM (2 4 6)'</translation>
     </message>
     <message>
         <source>Creates a polygon geometry from an outer ring and optional series of inner ring geometries.</source>
@@ -45346,7 +45346,7 @@ p, li { white-space: pre-wrap; }
     </message>
     <message>
         <source>make_polygon</source>
-        <translation type="unfinished"></translation>
+        <translation>make_polygon</translation>
     </message>
     <message>
         <source>closed line geometry for polygon's outer ring</source>
@@ -45358,19 +45358,19 @@ p, li { white-space: pre-wrap; }
     </message>
     <message>
         <source>geom_to_wkt(make_polygon(geom_from_wkt('LINESTRING( 0 0, 0 1, 1 1, 1 0, 0 0 )')))</source>
-        <translation type="unfinished"></translation>
+        <translation>geom_to_wkt(make_polygon(geom_from_wkt('LINESTRING( 0 0, 0 1, 1 1, 1 0, 0 0 )')))</translation>
     </message>
     <message>
         <source>'Polygon ((0 0, 0 1, 1 1, 1 0, 0 0))'</source>
-        <translation type="unfinished"></translation>
+        <translation>'Polygon ((0 0, 0 1, 1 1, 1 0, 0 0))'</translation>
     </message>
     <message>
         <source>geom_to_wkt(make_polygon(geom_from_wkt('LINESTRING( 0 0, 0 1, 1 1, 1 0, 0 0 )'),geom_from_wkt('LINESTRING( 0.1 0.1, 0.1 0.2, 0.2 0.2, 0.2 0.1, 0.1 0.1 )'),geom_from_wkt('LINESTRING( 0.8 0.8, 0.8 0.9, 0.9 0.9, 0.9 0.8, 0.8 0.8 )')))</source>
-        <translation type="unfinished"></translation>
+        <translation>geom_to_wkt(make_polygon(geom_from_wkt('LINESTRING( 0 0, 0 1, 1 1, 1 0, 0 0 )'),geom_from_wkt('LINESTRING( 0.1 0.1, 0.1 0.2, 0.2 0.2, 0.2 0.1, 0.1 0.1 )'),geom_from_wkt('LINESTRING( 0.8 0.8, 0.8 0.9, 0.9 0.9, 0.9 0.8, 0.8 0.8 )')))</translation>
     </message>
     <message>
         <source>'Polygon ((0 0, 0 1, 1 1, 1 0, 0 0),(0.1 0.1, 0.1 0.2, 0.2 0.2, 0.2 0.1, 0.1 0.1),(0.8 0.8, 0.8 0.9, 0.9 0.9, 0.9 0.8, 0.8 0.8))'</source>
-        <translation type="unfinished"></translation>
+        <translation>'Polygon ((0 0, 0 1, 1 1, 1 0, 0 0),(0.1 0.1, 0.1 0.2, 0.2 0.2, 0.2 0.1, 0.1 0.1),(0.8 0.8, 0.8 0.9, 0.9 0.9, 0.9 0.8, 0.8 0.8))'</translation>
     </message>
     <message>
         <source>Returns the largest value in a set of values.</source>
@@ -45550,7 +45550,7 @@ p, li { white-space: pre-wrap; }
     </message>
     <message>
         <source>nodes_to_points</source>
-        <translation type="unfinished"></translation>
+        <translation>nodes_to_points</translation>
     </message>
     <message>
         <source>optional argument specifying whether to include duplicate nodes which close lines or polygons rings. Defaults to false, set to true to avoid including these duplicate nodes in the output collection.</source>
@@ -45558,19 +45558,19 @@ p, li { white-space: pre-wrap; }
     </message>
     <message>
         <source>geom_to_wkt(nodes_to_points(geom_from_wkt('LINESTRING(0 0, 1 1, 2 2)')))</source>
-        <translation type="unfinished"></translation>
+        <translation>geom_to_wkt(nodes_to_points(geom_from_wkt('LINESTRING(0 0, 1 1, 2 2)')))</translation>
     </message>
     <message>
         <source>'MultiPoint ((0 0),(1 1),(2 2))'</source>
-        <translation type="unfinished"></translation>
+        <translation>'MultiPoint ((0 0),(1 1),(2 2))'</translation>
     </message>
     <message>
         <source>geom_to_wkt(nodes_to_points(geom_from_wkt('POLYGON((-1 -1, 4 0, 4 2, 0 2, -1 -1))'),true))</source>
-        <translation type="unfinished"></translation>
+        <translation>geom_to_wkt(nodes_to_points(geom_from_wkt('POLYGON((-1 -1, 4 0, 4 2, 0 2, -1 -1))'),true))</translation>
     </message>
     <message>
         <source>'MultiPoint ((-1 -1),(4 0),(4 2),(0 2))'</source>
-        <translation type="unfinished"></translation>
+        <translation>'MultiPoint ((-1 -1),(4 0),(4 2),(0 2))'</translation>
     </message>
     <message>
         <source>Returns the current date and time.</source>
@@ -45594,11 +45594,11 @@ p, li { white-space: pre-wrap; }
     </message>
     <message>
         <source>num_geometries</source>
-        <translation type="unfinished"></translation>
+        <translation>num_geometries</translation>
     </message>
     <message>
         <source>num_geometries(geom_from_wkt('GEOMETRYCOLLECTION(POINT(0 1), POINT(0 0), POINT(1 0), POINT(1 1))'))'),3))</source>
-        <translation type="unfinished"></translation>
+        <translation>num_geometries(geom_from_wkt('GEOMETRYCOLLECTION(POINT(0 1), POINT(0 0), POINT(1 0), POINT(1 1))'))'),3))</translation>
     </message>
     <message>
         <source>Returns the number of interior rings in a polygon or geometry collection, or null if the input geometry is not a polygon or collection.</source>
@@ -45606,7 +45606,7 @@ p, li { white-space: pre-wrap; }
     </message>
     <message>
         <source>num_interior_rings</source>
-        <translation type="unfinished"></translation>
+        <translation>num_interior_rings</translation>
     </message>
     <message>
         <source>input geometry</source>
@@ -45614,7 +45614,7 @@ p, li { white-space: pre-wrap; }
     </message>
     <message>
         <source>num_interior_rings(geom_from_wkt('POLYGON((-1 -1, 4 0, 4 2, 0 2, -1 -1),(-0.1 -0.1, 0.4 0, 0.4 0.2, 0 0.2, -0.1 -0.1))'))</source>
-        <translation type="unfinished"></translation>
+        <translation>num_interior_rings(geom_from_wkt('POLYGON((-1 -1, 4 0, 4 2, 0 2, -1 -1),(-0.1 -0.1, 0.4 0, 0.4 0.2, 0 0.2, -0.1 -0.1))'))</translation>
     </message>
     <message>
         <source>Returns the number of vertices in a geometry.</source>
@@ -45638,11 +45638,11 @@ p, li { white-space: pre-wrap; }
     </message>
     <message>
         <source>num_rings</source>
-        <translation type="unfinished"></translation>
+        <translation>num_rings</translation>
     </message>
     <message>
         <source>num_rings(geom_from_wkt('POLYGON((-1 -1, 4 0, 4 2, 0 2, -1 -1),(-0.1 -0.1, 0.4 0, 0.4 0.2, 0 0.2, -0.1 -0.1))'))</source>
-        <translation type="unfinished"></translation>
+        <translation>num_rings(geom_from_wkt('POLYGON((-1 -1, 4 0, 4 2, 0 2, -1 -1),(-0.1 -0.1, 0.4 0, 0.4 0.2, 0 0.2, -0.1 -0.1))'))</translation>
     </message>
     <message>
         <source>Multiplication of two values</source>
@@ -45922,7 +45922,7 @@ p, li { white-space: pre-wrap; }
     </message>
     <message>
         <source>order_parts</source>
-        <translation type="unfinished"></translation>
+        <translation>order_parts</translation>
     </message>
     <message>
         <source>a multi-type geometry</source>
@@ -45938,19 +45938,19 @@ p, li { white-space: pre-wrap; }
     </message>
     <message>
         <source>order_parts(geom_from_wkt('MultiPolygon (((1 1, 5 1, 5 5, 1 5, 1 1)),((1 1, 9 1, 9 9, 1 9, 1 1)))'), 'area($geometry)', False)</source>
-        <translation type="unfinished"></translation>
+        <translation>order_parts(geom_from_wkt('MultiPolygon (((1 1, 5 1, 5 5, 1 5, 1 1)),((1 1, 9 1, 9 9, 1 9, 1 1)))'), 'area($geometry)', False)</translation>
     </message>
     <message>
         <source>MultiPolygon (((1 1, 9 1, 9 9, 1 9, 1 1)),((1 1, 5 1, 5 5, 1 5, 1 1)))</source>
-        <translation type="unfinished"></translation>
+        <translation>MultiPolygon (((1 1, 9 1, 9 9, 1 9, 1 1)),((1 1, 5 1, 5 5, 1 5, 1 1)))</translation>
     </message>
     <message>
         <source>order_parts(geom_from_wkt('LineString(1 2, 3 2, 4 3)'), '1', True)</source>
-        <translation type="unfinished"></translation>
+        <translation>order_parts(geom_from_wkt('LineString(1 2, 3 2, 4 3)'), '1', True)</translation>
     </message>
     <message>
         <source>LineString(1 2, 3 2, 4 3)</source>
-        <translation type="unfinished"></translation>
+        <translation>LineString(1 2, 3 2, 4 3)</translation>
     </message>
     <message>
         <source>Tests whether a geometry overlaps another. Returns true if the geometries share space, are of the same dimension, but are not completely contained by each other.</source>
@@ -46026,11 +46026,11 @@ p, li { white-space: pre-wrap; }
     </message>
     <message>
         <source>point_on_surface</source>
-        <translation type="unfinished"></translation>
+        <translation>point_on_surface</translation>
     </message>
     <message>
         <source>point_on_surface($geometry)</source>
-        <translation type="unfinished"></translation>
+        <translation>point_on_surface($geometry)</translation>
     </message>
     <message>
         <source>Returns a color from the project's color scheme.</source>
@@ -46046,7 +46046,7 @@ p, li { white-space: pre-wrap; }
     </message>
     <message>
         <source>project_color('Logo color')</source>
-        <translation type="unfinished"></translation>
+        <translation>project_color('Logo color')</translation>
     </message>
     <message>
         <source>20,140,50</source>
@@ -46254,7 +46254,7 @@ p, li { white-space: pre-wrap; }
     </message>
     <message>
         <source>Tests the Dimensional Extended 9 Intersection Model (DE-9IM) representation of the relationship between two geometries.</source>
-        <translation type="unfinished"></translation>
+        <translation>Prueba la representación del Modelo de Intersección 9 Extendido Dimensional (DE-9IM) de la relación entre dos geometrías.</translation>
     </message>
     <message>
         <source>Relationship variant</source>
@@ -46286,7 +46286,7 @@ p, li { white-space: pre-wrap; }
     </message>
     <message>
         <source>relate( geom_from_wkt( 'LINESTRING(40 40,120 120)' ), geom_from_wkt( 'LINESTRING(40 40,60 120)' ), '**1F001**' )</source>
-        <translation type="unfinished"></translation>
+        <translation>relate( geom_from_wkt( 'LINESTRING(40 40,120 120)' ), geom_from_wkt( 'LINESTRING(40 40,60 120)' ), '**1F001**' )</translation>
     </message>
     <message>
         <source>True</source>
@@ -46338,7 +46338,7 @@ p, li { white-space: pre-wrap; }
     </message>
     <message>
         <source>geom_to_wkt(reverse(geom_from_wkt('LINESTRING(0 0, 1 1, 2 2)')))</source>
-        <translation type="unfinished"></translation>
+        <translation>geom_to_wkt(reverse(geom_from_wkt('LINESTRING(0 0, 1 1, 2 2)')))</translation>
     </message>
     <message>
         <source>'LINESTRING(2 2, 1 1, 0 0)'</source>
@@ -46542,19 +46542,19 @@ p, li { white-space: pre-wrap; }
     </message>
     <message>
         <source>Returns a multi line geometry consisting of a line for every segment in the input geometry.</source>
-        <translation type="unfinished"></translation>
+        <translation>Devuelve una geometría multilínea que consiste en una línea para cada segmento de la geometría de entrada.</translation>
     </message>
     <message>
         <source>segments_to_lines</source>
-        <translation type="unfinished"></translation>
+        <translation>segments_to_lines</translation>
     </message>
     <message>
         <source>geom_to_wkt(segments_to_lines(geom_from_wkt('LINESTRING(0 0, 1 1, 2 2)')))</source>
-        <translation type="unfinished"></translation>
+        <translation>geom_to_wkt(segments_to_lines(geom_from_wkt('LINESTRING(0 0, 1 1, 2 2)')))</translation>
     </message>
     <message>
         <source>'MultiLineString ((0 0, 1 1),(1 1, 2 2))'</source>
-        <translation type="unfinished"></translation>
+        <translation>'MultiLineString ((0 0, 1 1),(1 1, 2 2))'</translation>
     </message>
     <message>
         <source>Sets a specific color component for a color string, eg the red component or alpha component.</source>
@@ -46586,7 +46586,7 @@ p, li { white-space: pre-wrap; }
     </message>
     <message>
         <source>shortest_line</source>
-        <translation type="unfinished"></translation>
+        <translation>shortest_line</translation>
     </message>
     <message>
         <source>geometry to find shortest line from</source>
@@ -46598,11 +46598,11 @@ p, li { white-space: pre-wrap; }
     </message>
     <message>
         <source>geom_to_wkt(shortest_line(geom_from_wkt('LINESTRING (20 80, 98 190, 110 180, 50 75 )'),geom_from_wkt('POINT(100 100)')))</source>
-        <translation type="unfinished"></translation>
+        <translation>geom_to_wkt(shortest_line(geom_from_wkt('LINESTRING (20 80, 98 190, 110 180, 50 75 )'),geom_from_wkt('POINT(100 100)')))</translation>
     </message>
     <message>
         <source>LineString(73.0769 115.384, 100 100)</source>
-        <translation type="unfinished"></translation>
+        <translation>LineString(73.0769 115.384, 100 100)</translation>
     </message>
     <message>
         <source>Returns the sine of an angle.</source>
@@ -46962,7 +46962,7 @@ p, li { white-space: pre-wrap; }
     </message>
     <message>
         <source>translate</source>
-        <translation type="unfinished"></translation>
+        <translation>translate</translation>
     </message>
     <message>
         <source>delta x</source>
@@ -46974,7 +46974,7 @@ p, li { white-space: pre-wrap; }
     </message>
     <message>
         <source>translate($geometry, 5, 10)</source>
-        <translation type="unfinished"></translation>
+        <translation>translate($geometry, 5, 10)</translation>
     </message>
     <message>
         <source>a geometry of the same type like the original one</source>
@@ -47259,7 +47259,7 @@ de Qt. Cada UUID tiene 38 caracteres de longitud.</translation>
     </message>
     <message>
         <source>z( geom_from_wkt( 'POINTZ(2 5 7)' ) )</source>
-        <translation type="unfinished"></translation>
+        <translation>z( geom_from_wkt( 'POINTZ(2 5 7)' ) )</translation>
     </message>
     <message>
         <source>i</source>
@@ -47575,7 +47575,7 @@ de Qt. Cada UUID tiene 38 caracteres de longitud.</translation>
     </message>
     <message>
         <source>ignore_closing_nodes</source>
-        <translation type="unfinished"></translation>
+        <translation>ignore_closing_nodes</translation>
     </message>
     <message>
         <source>orderby</source>
@@ -52808,7 +52808,7 @@ p, li { white-space: pre-wrap; }
     <message>
         <location filename="../src/plugins/globe/qgsglobevectorlayerpropertiespage.ui" line="39"/>
         <source>Clamping</source>
-        <translation type="unfinished"></translation>
+        <translation>Fijación</translation>
     </message>
     <message>
         <location filename="../src/plugins/globe/qgsglobevectorlayerpropertiespage.ui" line="46"/>
@@ -52893,17 +52893,17 @@ p, li { white-space: pre-wrap; }
     <message>
         <location filename="../src/plugins/globe/qgsglobevectorlayerpropertiespage.ui" line="170"/>
         <source>Wall gradient</source>
-        <translation type="unfinished"></translation>
+        <translation>Gradiente de pared</translation>
     </message>
     <message>
         <location filename="../src/plugins/globe/qgsglobevectorlayerpropertiespage.ui" line="177"/>
         <source>Wall coloring gradient</source>
-        <translation type="unfinished"></translation>
+        <translation>Gradiente de coloreado de pared</translation>
     </message>
     <message>
         <location filename="../src/plugins/globe/qgsglobevectorlayerpropertiespage.ui" line="193"/>
         <source>Whether the top cap of the extruded geometry should be flat</source>
-        <translation type="unfinished"></translation>
+        <translation>Si el remate superior de la geometría extruida debe ser plano</translation>
     </message>
     <message>
         <location filename="../src/plugins/globe/qgsglobevectorlayerpropertiespage.ui" line="196"/>
@@ -52918,12 +52918,12 @@ p, li { white-space: pre-wrap; }
     <message>
         <location filename="../src/plugins/globe/qgsglobevectorlayerpropertiespage.ui" line="215"/>
         <source>Declutter</source>
-        <translation type="unfinished"></translation>
+        <translation>No abarrotar</translation>
     </message>
     <message>
         <location filename="../src/plugins/globe/qgsglobevectorlayerpropertiespage.ui" line="225"/>
         <source>Lighting</source>
-        <translation type="unfinished"></translation>
+        <translation>Iluminación</translation>
     </message>
     <message>
         <location filename="../src/plugins/globe/qgsglobevectorlayerpropertiespage.ui" line="236"/>
@@ -52953,7 +52953,7 @@ p, li { white-space: pre-wrap; }
     <message>
         <location filename="../src/plugins/globe/qgsglobevectorlayerproperties.cpp" line="47"/>
         <source>Rasterize the layer to a texture, and drape it on the terrain</source>
-        <translation type="unfinished"></translation>
+        <translation>Rasterizar la capa a una textura y cubrir con ella el terreno</translation>
     </message>
     <message>
         <location filename="../src/plugins/globe/qgsglobevectorlayerproperties.cpp" line="48"/>
@@ -52983,7 +52983,7 @@ p, li { white-space: pre-wrap; }
     <message>
         <location filename="../src/plugins/globe/qgsglobevectorlayerproperties.cpp" line="55"/>
         <source>Do not clamp Z values to the terrain (but still apply the offset, if applicable)</source>
-        <translation type="unfinished"></translation>
+        <translation>No fijar lo valores Z al terreno (pero continuar aplicando el desplazamiento, si es aplicable)</translation>
     </message>
     <message>
         <location filename="../src/plugins/globe/qgsglobevectorlayerproperties.cpp" line="56"/>
@@ -53008,7 +53008,7 @@ p, li { white-space: pre-wrap; }
     <message>
         <location filename="../src/plugins/globe/qgsglobevectorlayerproperties.cpp" line="62"/>
         <source>Drape</source>
-        <translation type="unfinished"></translation>
+        <translation>Cubrir</translation>
     </message>
     <message>
         <location filename="../src/plugins/globe/qgsglobevectorlayerproperties.cpp" line="63"/>
@@ -53023,22 +53023,22 @@ p, li { white-space: pre-wrap; }
     <message>
         <location filename="../src/plugins/globe/qgsglobevectorlayerproperties.cpp" line="65"/>
         <source>Clamp geometry to the map model's elevation data</source>
-        <translation type="unfinished"></translation>
+        <translation>Fijar geometría a los datos de elevación del modelo del mapa</translation>
     </message>
     <message>
         <location filename="../src/plugins/globe/qgsglobevectorlayerproperties.cpp" line="66"/>
         <source>Clamp geometry to the terrain's scene graph</source>
-        <translation type="unfinished"></translation>
+        <translation>Fijar geometría al grafo de escena del terreno</translation>
     </message>
     <message>
         <location filename="../src/plugins/globe/qgsglobevectorlayerproperties.cpp" line="67"/>
         <source>Clamp geometry to the terrain as they are rendered by the GPU</source>
-        <translation type="unfinished"></translation>
+        <translation>Fijar geometrías al terreno tal como son renderizadas por la GPU</translation>
     </message>
     <message>
         <location filename="../src/plugins/globe/qgsglobevectorlayerproperties.cpp" line="68"/>
         <source>Clamp geometry at draw time using projective texturing</source>
-        <translation type="unfinished"></translation>
+        <translation>Fijar geometrías en el momento del dibujado usando un texturizado proyectivo</translation>
     </message>
     <message>
         <location filename="../src/plugins/globe/qgsglobevectorlayerproperties.cpp" line="71"/>
@@ -53053,12 +53053,12 @@ p, li { white-space: pre-wrap; }
     <message>
         <location filename="../src/plugins/globe/qgsglobevectorlayerproperties.cpp" line="73"/>
         <source>Clamp every vertex independently</source>
-        <translation type="unfinished"></translation>
+        <translation>Fijar cada vértice de forma independiente</translation>
     </message>
     <message>
         <location filename="../src/plugins/globe/qgsglobevectorlayerproperties.cpp" line="74"/>
         <source>Clamp to the centroid of the entire geometry</source>
-        <translation type="unfinished"></translation>
+        <translation>Fijar al centroide de toda la geometría</translation>
     </message>
 </context>
 <context>
@@ -53088,7 +53088,7 @@ p, li { white-space: pre-wrap; }
     <message>
         <location filename="../src/plugins/globe/qgsglobewidget.cpp" line="59"/>
         <source>Globe settings</source>
-        <translation type="unfinished"></translation>
+        <translation>Configuración de Globo</translation>
     </message>
     <message>
         <location filename="../src/plugins/globe/qgsglobewidget.cpp" line="68"/>
@@ -66485,7 +66485,8 @@ error: %2</translation>
     <message>
         <location filename="../src/providers/oracle/qgsoracleprovider.cpp" line="722"/>
         <source>No spatial index on column %1 found - expect poor performance.</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>No se encontró ningún índice espacial en la columna %1 - se espera un rendimiento pobre.</translatorcomment>
+        <translation></translation>
     </message>
     <message>
         <location filename="../src/providers/oracle/qgsoracleprovider.cpp" line="732"/>
@@ -73564,7 +73565,7 @@ especificadas más abajo.</translation>
     <message>
         <location filename="../src/ui/qgsrasterminmaxwidgetbase.ui" line="225"/>
         <source>Clip extent to canvas</source>
-        <translation type="unfinished"></translation>
+        <translation>Cortar extensión al lienzo</translation>
     </message>
     <message>
         <location filename="../src/ui/qgsrasterminmaxwidgetbase.ui" line="200"/>
@@ -76146,7 +76147,7 @@ contraste</translation>
     <message>
         <location filename="../src/gui/raster/qgssinglebandpseudocolorrendererwidget.cpp" line="859"/>
         <source>Value for color stop</source>
-        <translation type="unfinished"></translation>
+        <translation>Valor para paso de color</translation>
     </message>
     <message>
         <location filename="../src/gui/raster/qgssinglebandpseudocolorrendererwidget.cpp" line="862"/>
@@ -76210,7 +76211,8 @@ contraste</translation>
         <location filename="../src/ui/qgssinglebandpseudocolorrendererwidgetbase.ui" line="188"/>
         <source>Min / max 
 origin:</source>
-        <translation type="unfinished"></translation>
+        <translation>Mïn / máx 
+origen:</translation>
     </message>
     <message>
         <location filename="../src/ui/qgssinglebandpseudocolorrendererwidgetbase.ui" line="212"/>
@@ -76628,7 +76630,7 @@ sufijo</translation>
     <message>
         <location filename="../src/ui/qgssourceselectdialogbase.ui" line="111"/>
         <source>Fi&lter:</source>
-        <translation type="unfinished"></translation>
+        <translation>Fi&ltro:</translation>
     </message>
     <message>
         <location filename="../src/ui/qgssourceselectdialogbase.ui" line="124"/>
@@ -77542,7 +77544,7 @@ del resultado</translation>
     <message>
         <location filename="../src/app/qgssponsors.cpp" line="33"/>
         <source><p>We work really hard to make this nice software for you. See all the cool features it has? Get a warm fuzzy feeling when you use it? QGIS is a labour of love by a dedicated team of developers. We want you to copy &amp; share it and put it in the hands of as many people as possible. If QGIS is saving you money or you like our work and have the financial ability to help, please consider sponsoring the development of QGIS. We use money from sponsors to pay for tr [...]
-        <translation type="unfinished"></translation>
+        <translation><p>Trabajamos realmente duro para hacer este gran software para usted. ¿Ve todas las estupendas características que tiene? ¿Tiene una agradable sensación cuando lo usa? QGIS es el fruto de un dedicado grupo de desarrolladores. Queremos que lo copie, lo comparta y lo ponga en manos de cuanta gente sea posible. Si QGIS le está ahorrando dinero o le gusta nuestro trabajo y tiene la posibilidad económica de ayudar, por favor considere patrocinar el desarrollo de QG [...]
     </message>
 </context>
 <context>
@@ -78927,7 +78929,7 @@ Hubo un problema con su base de datos de símbolos.</translation>
     <message>
         <location filename="../src/app/qgstipfactory.cpp" line="221"/>
         <source>If you have a number of aerial photos spread across a wide area, instead of loading each file as a separate layer you can treat them all as a single layer by using a .vrt file. To create a .vrt, go to Raster -> Miscellaneous -> Build Virtual Raster (Catalog).</source>
-        <translation type="unfinished"></translation>
+        <translation>Si tiene cierto número de fotografías aéreas repartidas a lo largo de un área amplia, en vez de cargar cada archivo como una capa separada puede tratarlas todas ellas como una sola capa usando un archivo .vrt. Para crear un .vrt, vaya a Raster -> Miscellanea -> Construir ráster virtual (Catálogo).</translation>
     </message>
     <message>
         <location filename="../src/app/qgstipfactory.cpp" line="57"/>
@@ -78942,7 +78944,7 @@ Hubo un problema con su base de datos de símbolos.</translation>
     <message>
         <location filename="../src/app/qgstipfactory.cpp" line="94"/>
         <source>In the print composer toolbar you can find two buttons for moving elements. The left one (right arrow icon) selects and moves elements in the layout. After selecting the element with this tool you can also move them around with the arrow keys. For accurate positioning use the <strong>Position and Size</strong> section, which can be found in the tab <strong>Item Properties -> Position and Size</strong>. The other move tool (map canvas icon with r [...]
-        <translation type="unfinished"></translation>
+        <translation>En la barra de herramientas del diseñador de impresión puede encontrar dos botones para mover elementos. El izquierdo (<img src=":/images/themes/default/mActionSelect.svg"/>) selecciona y mueve elementos en la composición. Después de seleccionar el elemento con esta herramienta también puede moverlo con las teclas de desplazamiento. Para una colocación precisa use la sección <strong>Posición y tamaño</strong>, que puede encontrar en la pes [...]
     </message>
     <message>
         <location filename="../src/app/qgstipfactory.cpp" line="129"/>
@@ -78977,7 +78979,7 @@ Hubo un problema con su base de datos de símbolos.</translation>
     <message>
         <location filename="../src/app/qgstipfactory.cpp" line="30"/>
         <source>QGIS is open source software. This means that the software source code can be freely viewed and modified. The GPL places a restriction that any modifications you make must be made available in source form to whoever you give modified versions to, and that you can not create a new version of QGIS under a 'closed source' license. Visit <a href="https://qgis.org"> the QGIS home page (https://qgis.org)</a> for more information.</source>
-        <translation type="unfinished"></translation>
+        <translation>QGIS es un software de código abierto. Esto significa que el código fuente del software se puede ver y modificar libremente. La GPL establece la restricción de que cualquier modificación que se haga se debe poner a disposición de cualquiera a quien se dé la versión modificada en forma de código fuente y que no se puede crear una nueva versión de QGIS con una licencia de código cerrado. Visite <a href="https://qgis.org"> la página web de QGIS</a> [...]
     </message>
     <message>
         <location filename="../src/app/qgstipfactory.cpp" line="42"/>
@@ -78997,7 +78999,7 @@ Hubo un problema con su base de datos de símbolos.</translation>
     <message>
         <location filename="../src/app/qgstipfactory.cpp" line="86"/>
         <source>You can add a current date variable to your map layout. Create a regular text label and add the string $CURRENT_DATE(yyyy-MM-dd) to the text box. See the <a href="https://doc.qt.io/qt-4.8/qdate.html#toString">QDate::toString format documentation</a> for the possible date formats.</source>
-        <translation type="unfinished"></translation>
+        <translation>Puede añadir una variable de fecha actual a la vista de su mapa. Cree una etiqueta de texto normal y añada la cadena $CURRENT_DATE(yyyy-MM-dd) a la caja de texto. Vea la <a href="https://doc.qt.io/qt-4.8/qdate.html#toString">documentación del formato QDate::toString</a> para los formatos de fecha posibles.</translation>
     </message>
     <message>
         <location filename="../src/app/qgstipfactory.cpp" line="117"/>
@@ -79007,7 +79009,7 @@ Hubo un problema con su base de datos de símbolos.</translation>
     <message>
         <location filename="../src/app/qgstipfactory.cpp" line="184"/>
         <source>QGIS has plugins that extend its functionality. QGIS ships with some core plugins you can explore from the Plugins->Manage and Install Plugins menu. In addition there are a lot of <a href="https://plugins.qgis.org/">Python plugins </a> contributed by the user community that can be installed via this same menu. Don't miss out on all QGIS has to offer! Check out the plugins and see what they can do for you.</source>
-        <translation type="unfinished"></translation>
+        <translation>QGIS tiene complementos que extienden su funcionalidad. QGIS se distribuye con algunos complementos del núcleo incluidos, que puede explorar desde el menú <strong> Complementos -> Administrar e instalar complementos</strong>. Además, hay montón de <a href="https://plugins.qgis.org/">complementos en Python </a> aportados por la comunidad de usuarios, que se pueden instalar desde el mismo menú. ¡No deje pasar todo lo que QGIS le pue [...]
     </message>
     <message>
         <location filename="../src/app/qgstipfactory.cpp" line="195"/>
@@ -79037,7 +79039,7 @@ Hubo un problema con su base de datos de símbolos.</translation>
     <message>
         <location filename="../src/app/qgstipfactory.cpp" line="173"/>
         <source>If QGIS is saving you money or you like our work and have the financial ability to help, please consider sponsoring the development of QGIS. We use money from sponsors to pay for travel and costs related to our regular hackfest meetings, and to generally support the goals of our project. Please see the<a href="https://qgis.org/en/site/getinvolved/governance/sponsorship/sponsorship.html">QGIS Sponsorship Web Page</a> for more details.</source>
-        <translation type="unfinished"></translation>
+        <translation>Si QGIS le está ahorrando dinero o le gusta nuestro trabajo y tiene la posibilidad económica de ayudar, por favor considere patrocinar el desarrollo de QGIS. Usamos el dinero de los patrocinadores para pagar viajes y costes relacionados con nuestros encuentros bianuales de desarrolladores y en general para apoyar los objetivos de nuestro proyecto.</p><p>Por favor vea la <a href='http://qgis.org/en/site/getinvolved/governance/sponsorship/sponsorshi [...]
     </message>
     <message>
         <location filename="../src/app/qgstipfactory.cpp" line="183"/>
@@ -79838,7 +79840,7 @@ El error fue: %2</translation>
     <message>
         <location filename="../src/ui/qgsvectorgradientcolorrampv2dialogbase.ui" line="170"/>
         <source>Gradient stop</source>
-        <translation type="unfinished"></translation>
+        <translation>Paso de gradiente</translation>
     </message>
     <message>
         <location filename="../src/ui/qgsvectorgradientcolorrampv2dialogbase.ui" line="176"/>
@@ -79853,7 +79855,7 @@ El error fue: %2</translation>
     <message>
         <location filename="../src/ui/qgsvectorgradientcolorrampv2dialogbase.ui" line="196"/>
         <source>&Delete stop</source>
-        <translation type="unfinished"></translation>
+        <translation>&Borrar paso</translation>
     </message>
     <message>
         <location filename="../src/ui/qgsvectorgradientcolorrampv2dialogbase.ui" line="232"/>
@@ -85185,7 +85187,7 @@ Por favor, configúrela antes de ejecutar scripts de R.</translation>
     <message>
         <location filename="../src/plugins/roadgraph/shortestpathwidget.cpp" line="255"/>
         <source>Plugin isn't configured! Please go to the Vector menu, Road Graph, Settings option to configure it.</source>
-        <translation type="unfinished"></translation>
+        <translation>¡El complemento no está configurado! Por favor, vaya al menú Vectorial, Grafo de ruta, Configuración para configurarlo.</translation>
     </message>
     <message>
         <location filename="../src/plugins/roadgraph/shortestpathwidget.cpp" line="276"/>
@@ -85241,7 +85243,7 @@ Por favor, configúrela antes de ejecutar scripts de R.</translation>
         <location filename="../src/plugins/roadgraph/roadgraphplugin.cpp" line="116"/>
         <location filename="../src/plugins/roadgraph/roadgraphplugin.cpp" line="131"/>
         <source>Road Graph</source>
-        <translation type="unfinished"></translation>
+        <translation>Grafo de ruta</translation>
     </message>
 </context>
 <context>
@@ -85549,7 +85551,7 @@ Por favor, configúrela antes de ejecutar scripts de R.</translation>
     <message>
         <location filename="../python/plugins/processing/processing-i18n.cpp" line="136"/>
         <source>Transpose Grids</source>
-        <translation type="unfinished"></translation>
+        <translation>Transponer cuadrículas</translation>
     </message>
     <message>
         <location filename="../python/plugins/processing/processing-i18n.cpp" line="260"/>
@@ -89070,7 +89072,7 @@ Problema con la línea %d</translation>
     <message>
         <location filename="../src/ui/symbollayer/widget_ellipse.ui" line="393"/>
         <source>Hairline</source>
-        <translation type="unfinished"></translation>
+        <translation>Línea fina</translation>
     </message>
     <message>
         <location filename="../src/ui/symbollayer/widget_ellipse.ui" line="456"/>
@@ -89912,7 +89914,7 @@ Problema con la línea %d</translation>
     <message>
         <location filename="../src/ui/symbollayer/widget_simplefill.ui" line="164"/>
         <source>Hairline</source>
-        <translation type="unfinished"></translation>
+        <translation>Línea fina</translation>
     </message>
     <message>
         <location filename="../src/ui/symbollayer/widget_simplefill.ui" line="27"/>
@@ -89970,7 +89972,7 @@ Problema con la línea %d</translation>
     <message>
         <location filename="../src/ui/symbollayer/widget_simpleline.ui" line="28"/>
         <source>Hairline</source>
-        <translation type="unfinished"></translation>
+        <translation>Línea fina</translation>
     </message>
     <message>
         <location filename="../src/ui/symbollayer/widget_simpleline.ui" line="139"/>
@@ -90054,7 +90056,7 @@ Problema con la línea %d</translation>
     <message>
         <location filename="../src/ui/symbollayer/widget_simplemarker.ui" line="398"/>
         <source>Hairline</source>
-        <translation type="unfinished"></translation>
+        <translation>Línea fina</translation>
     </message>
     <message>
         <location filename="../src/ui/symbollayer/widget_simplemarker.ui" line="103"/>
@@ -90536,12 +90538,12 @@ Problema con la línea %d</translation>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="2998"/>
         <source>You can't use original Hargreaves flag and precipitation parameter together!</source>
-        <translation type="unfinished"></translation>
+        <translation>¡No se pueden usar la etiqueta Hargreaves original y el parámetro precipitación juntos!</translation>
     </message>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="2999"/>
         <source>If you don't use original Hargreaves flag, you must set the precipitation raster parameter!</source>
-        <translation type="unfinished"></translation>
+        <translation>¡Si no usa la etiqueta Hargreaves original debe establecer el parámetro ráster de precipitación!</translation>
     </message>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="2985"/>
@@ -98687,22 +98689,22 @@ archivo de el atributo)</translation>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="3412"/>
         <source>ASCII text file of control points</source>
-        <translation type="unfinished"></translation>
+        <translation>Archivo de texto ASCII de puntos de control</translation>
     </message>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="3413"/>
         <source>parse string marking which columns are xyz (use 's' for skip)</source>
-        <translation type="unfinished"></translation>
+        <translation>analizar cadena marcando qué columnas son XYZ (usar 's' para omitir)</translation>
     </message>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="3414"/>
         <source>which points to use for elevation checks</source>
-        <translation type="unfinished"></translation>
+        <translation>qué puntos usar para comprobaciones de elevación</translation>
     </message>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="3415"/>
         <source>adjust z elevation by translating away the average error</source>
-        <translation type="unfinished"></translation>
+        <translation>ajustar elevación Z eliminando el error promedio</translation>
     </message>
 </context>
 <context>
@@ -98720,17 +98722,17 @@ archivo de el atributo)</translation>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="3421"/>
         <source>other input LAS/LAZ file</source>
-        <translation type="unfinished"></translation>
+        <translation>otro archivo LAS/LAZ de entrada</translation>
     </message>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="3422"/>
         <source>stop reporting difference after this many points</source>
-        <translation type="unfinished"></translation>
+        <translation>parar de informar diferencias después de este número de puntos</translation>
     </message>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="3423"/>
         <source>create elevation difference file (if points are in the same order)</source>
-        <translation type="unfinished"></translation>
+        <translation>crear archivo de diferencia de elevación (si los puntos están en el mismo orden)</translation>
     </message>
 </context>
 <context>
@@ -99108,42 +99110,42 @@ archivo de el atributo)</translation>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="3525"/>
         <source>classify below height as</source>
-        <translation type="unfinished"></translation>
+        <translation>clasificar por debajo de la altura como</translation>
     </message>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="3526"/>
         <source>below height</source>
-        <translation type="unfinished"></translation>
+        <translation>por debajo de la altura</translation>
     </message>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="3527"/>
         <source>classify between height as</source>
-        <translation type="unfinished"></translation>
+        <translation>clasificar entre alturas como</translation>
     </message>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="3528"/>
         <source>between height ... </source>
-        <translation type="unfinished"></translation>
+        <translation>entre altura ... </translation>
     </message>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="3529"/>
         <source>... and height</source>
-        <translation type="unfinished"></translation>
+        <translation>... y altura</translation>
     </message>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="3530"/>
         <source>between height ...</source>
-        <translation type="unfinished"></translation>
+        <translation>entre altura ...</translation>
     </message>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="3531"/>
         <source>classify above</source>
-        <translation type="unfinished"></translation>
+        <translation>clasificar por encima</translation>
     </message>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="3532"/>
         <source>classify above height</source>
-        <translation type="unfinished"></translation>
+        <translation>clasificar por encima de la altura</translation>
     </message>
 </context>
 <context>
@@ -99166,42 +99168,42 @@ archivo de el atributo)</translation>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="3539"/>
         <source>classify below height as</source>
-        <translation type="unfinished"></translation>
+        <translation>clasificar por debajo de la altura como</translation>
     </message>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="3540"/>
         <source>below height</source>
-        <translation type="unfinished"></translation>
+        <translation>por debajo de la altura</translation>
     </message>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="3541"/>
         <source>classify between height as</source>
-        <translation type="unfinished"></translation>
+        <translation>clasificar entre alturas como</translation>
     </message>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="3542"/>
         <source>between height ... </source>
-        <translation type="unfinished"></translation>
+        <translation>entre altura ... </translation>
     </message>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="3543"/>
         <source>... and height</source>
-        <translation type="unfinished"></translation>
+        <translation>... y altura</translation>
     </message>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="3544"/>
         <source>between height ...</source>
-        <translation type="unfinished"></translation>
+        <translation>entre altura ...</translation>
     </message>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="3545"/>
         <source>classify above</source>
-        <translation type="unfinished"></translation>
+        <translation>clasificar por encima</translation>
     </message>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="3546"/>
         <source>classify above height</source>
-        <translation type="unfinished"></translation>
+        <translation>clasificar por encima de la altura</translation>
     </message>
 </context>
 <context>
@@ -99618,7 +99620,7 @@ archivo de el atributo)</translation>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="3663"/>
         <source>type of portal</source>
-        <translation type="unfinished"></translation>
+        <translation>tipo de portal</translation>
     </message>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="3664"/>
@@ -99628,7 +99630,7 @@ archivo de el atributo)</translation>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="3665"/>
         <source>show Skybox</source>
-        <translation type="unfinished"></translation>
+        <translation>mostrar SkyBox</translation>
     </message>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="3666"/>
@@ -99638,12 +99640,12 @@ archivo de el atributo)</translation>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="3667"/>
         <source>portal output directory</source>
-        <translation type="unfinished"></translation>
+        <translation>directorio de salida del portal</translation>
     </message>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="3668"/>
         <source>copy or move source LiDAR files into portal (only for download portals)</source>
-        <translation type="unfinished"></translation>
+        <translation>copiar o mover los archivos LIDAR de origen al portal (solo para portales de descarga)</translation>
     </message>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="3669"/>
@@ -99653,17 +99655,17 @@ archivo de el atributo)</translation>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="3670"/>
         <source>portal HTML page</source>
-        <translation type="unfinished"></translation>
+        <translation>página HTML del portal</translation>
     </message>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="3671"/>
         <source>portal title</source>
-        <translation type="unfinished"></translation>
+        <translation>título del portal</translation>
     </message>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="3672"/>
         <source>portal description</source>
-        <translation type="unfinished"></translation>
+        <translation>descripción del portal</translation>
     </message>
 </context>
 <context>
@@ -99691,7 +99693,7 @@ archivo de el atributo)</translation>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="3680"/>
         <source>show Skybox</source>
-        <translation type="unfinished"></translation>
+        <translation>mostrar SkyBox</translation>
     </message>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="3681"/>
@@ -99701,12 +99703,12 @@ archivo de el atributo)</translation>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="3682"/>
         <source>portal output directory</source>
-        <translation type="unfinished"></translation>
+        <translation>directorio de salida del portal</translation>
     </message>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="3683"/>
         <source>copy or move source LiDAR files into portal (only for download portals)</source>
-        <translation type="unfinished"></translation>
+        <translation>copiar o mover los archivos LIDAR de origen al portal (solo para portales de descarga)</translation>
     </message>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="3684"/>
@@ -99716,17 +99718,17 @@ archivo de el atributo)</translation>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="3685"/>
         <source>portal HTML page</source>
-        <translation type="unfinished"></translation>
+        <translation>página HTML del portal</translation>
     </message>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="3686"/>
         <source>portal title</source>
-        <translation type="unfinished"></translation>
+        <translation>título del portal</translation>
     </message>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="3687"/>
         <source>portal description</source>
-        <translation type="unfinished"></translation>
+        <translation>descripción del portal</translation>
     </message>
 </context>
 <context>
diff --git a/i18n/qgis_pl.ts b/i18n/qgis_pl.ts
index 19bb4e0..17cc3a1 100644
--- a/i18n/qgis_pl.ts
+++ b/i18n/qgis_pl.ts
@@ -523,7 +523,7 @@ Możesz go otworzyć w oknie Wyniki processingu.</translation>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="100"/>
         <source>Graphics</source>
-        <translation>Grafika</translation>
+        <translation>Wykresy</translation>
     </message>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="101"/>
@@ -1713,7 +1713,7 @@ Przetwarzanie algorytmu %d/%d...</translation>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="387"/>
         <source>Providers</source>
-        <translation>Źródła danych</translation>
+        <translation>Dostawcy algorytmów</translation>
     </message>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="388"/>
@@ -3218,7 +3218,7 @@ Zapytanie:
         <location filename="../python/plugins/db_manager/ui/DlgImportVector.ui" line="88"/>
         <location filename="../python/plugins/db_manager/python-i18n.cpp" line="263"/>
         <source>Update options</source>
-        <translation>Opcje</translation>
+        <translation>Wczytaj opcje z warstwy</translation>
     </message>
     <message>
         <location filename="../python/plugins/db_manager/ui/DlgImportVector.ui" line="100"/>
@@ -8922,7 +8922,7 @@ Więcej szczegółów w plikach dziennika</translation>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="1145"/>
         <source>Converted</source>
-        <translation>Warstwa ze zmienionym typem geometrii</translation>
+        <translation>Warstwa wyjściowa</translation>
     </message>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="1146"/>
@@ -10969,7 +10969,7 @@ Proszę go zainstalować przed uruchomieniem algorytmów GRASS.</translation>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="1215"/>
         <source>Vector creation tools</source>
-        <translation type="unfinished"></translation>
+        <translation>Narzędzia generowania obiektów wektorowych</translation>
     </message>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="1216"/>
@@ -11977,7 +11977,7 @@ Proszę go zainstalować przed uruchomieniem algorytmów GRASS.</translation>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="1394"/>
         <source>Vector analysis tools</source>
-        <translation type="unfinished"></translation>
+        <translation>Narzędzia analiz wektorowych</translation>
     </message>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="1395"/>
@@ -12075,7 +12075,7 @@ Proszę go zainstalować przed uruchomieniem algorytmów GRASS.</translation>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="1411"/>
         <source>Vector analysis tools</source>
-        <translation type="unfinished"></translation>
+        <translation>Narzędzia analiz wektorowych</translation>
     </message>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="1416"/>
@@ -13375,12 +13375,12 @@ Proszę go skonfigurować przed uruchomieniem algorytmów LAStools.</translation
     <message>
         <location filename="../src/ui/qgisapp.ui" line="2490"/>
         <source>Layer Diagram Options</source>
-        <translation>Opcje warstwy wykresu</translation>
+        <translation>Opcje kartodiagramu</translation>
     </message>
     <message>
         <location filename="../src/ui/qgisapp.ui" line="2499"/>
         <source>New GeoPackage Layer...</source>
-        <translation type="unfinished"></translation>
+        <translation>Nowa warstwa GeoPackage...</translation>
     </message>
     <message>
         <location filename="../src/ui/qgisapp.ui" line="2508"/>
@@ -13571,10 +13571,7 @@ Działa na wszystkich edytowanych warstwach</translation>
 Click or marquee on feature to show label and diagram
 Shift+click or marquee on label or diagram to hide it
 Acts on currently active editable layer</source>
-        <translation>Wyświetl/ukryj etykiety i wykresy
-Kliknij na znaczniku aby wyświetlić
-Shift+kliknięcie lub znacznik etykiety lub wykresu, aby ukryć
-Działa na aktualnie edytowanej warstwie</translation>
+        <translation>Wyświetl/ukryj etykiety i kartodiagramy. Kliknięcie na znaczniku wyświetla, shift+kliknięcie ukrywa (uwaga, działa na aktualnie edytowanej warstwie).</translation>
     </message>
     <message>
         <location filename="../src/ui/qgisapp.ui" line="2021"/>
@@ -13861,7 +13858,7 @@ Działa na aktualnie edytowanej warstwie</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>Pasek narzędzi projektu</translation>
     </message>
     <message>
         <location filename="../src/ui/qgisapp.ui" line="941"/>
@@ -13937,7 +13934,7 @@ Działa na aktualnie edytowanej warstwie</translation>
     <message>
         <location filename="../src/ui/qgisapp.ui" line="1607"/>
         <source>Help Contents</source>
-        <translation>Informacje i podręczniki (ang.)</translation>
+        <translation>Podręcznik użytkownika (ang.)</translation>
     </message>
     <message>
         <location filename="../src/ui/qgisapp.ui" line="1610"/>
@@ -13947,7 +13944,7 @@ Działa na aktualnie edytowanej warstwie</translation>
     <message>
         <location filename="../src/ui/qgisapp.ui" line="1624"/>
         <source>QGIS Home Page</source>
-        <translation>Strona projektu QGIS (ang.)</translation>
+        <translation>Strona projektu QGIS</translation>
     </message>
     <message>
         <location filename="../src/ui/qgisapp.ui" line="1627"/>
@@ -14232,22 +14229,22 @@ Ctl (Cmd) obraca o 15 stopni.</translation>
     <message>
         <location filename="../src/ui/qgisapp.ui" line="2520"/>
         <source>Add Arc&GIS MapServer Layer...</source>
-        <translation type="unfinished"></translation>
+        <translation>Dodaj warstwę Arc&GIS MapServer</translation>
     </message>
     <message>
         <location filename="../src/ui/qgisapp.ui" line="2523"/>
         <source>Add ArcGIS MapServer Layer</source>
-        <translation type="unfinished"></translation>
+        <translation>Dodaj warstwę ArcGIS MapServer</translation>
     </message>
     <message>
         <location filename="../src/ui/qgisapp.ui" line="2532"/>
         <source>Add Ar&cGIS FeatureServer Layer...</source>
-        <translation type="unfinished"></translation>
+        <translation>Dodaj warstwę Ar&cGIS FeatureServer</translation>
     </message>
     <message>
         <location filename="../src/ui/qgisapp.ui" line="2535"/>
         <source>Add ArcGIS FeatureServer Layer</source>
-        <translation type="unfinished"></translation>
+        <translation>Dodaj warstwę ArcGIS FeatureServer</translation>
     </message>
     <message>
         <location filename="../src/ui/qgisapp.ui" line="32"/>
@@ -14407,7 +14404,7 @@ Ctl (Cmd) obraca o 15 stopni.</translation>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="1590"/>
         <source>Graphics</source>
-        <translation>Grafika</translation>
+        <translation>Wykresy</translation>
     </message>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="1591"/>
@@ -14445,7 +14442,7 @@ Ctl (Cmd) obraca o 15 stopni.</translation>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="1600"/>
         <source>Vector analysis tools</source>
-        <translation type="unfinished"></translation>
+        <translation>Narzędzia analiz wektorowych</translation>
     </message>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="1601"/>
@@ -15551,7 +15548,7 @@ Więcej informacji znajduje się w dzienniku zdarzeń.</translation>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="1769"/>
         <source>Vector analysis tools</source>
-        <translation type="unfinished"></translation>
+        <translation>Narzędzia analiz wektorowych</translation>
     </message>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="1770"/>
@@ -15842,7 +15839,7 @@ Więcej informacji znajduje się w dzienniku zdarzeń.</translation>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="1831"/>
         <source>Converted</source>
-        <translation>Warstwa ze zmienionym typem geometrii</translation>
+        <translation>Warstwa wyjściowa</translation>
     </message>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="1826"/>
@@ -16582,7 +16579,7 @@ Więcej informacji znajduje się w dzienniku zdarzeń.</translation>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="1998"/>
         <source>Information</source>
-        <translation>Wyświetl informację o rastrze</translation>
+        <translation>Wyświetl informację o wektorze</translation>
     </message>
 </context>
 <context>
@@ -17042,7 +17039,7 @@ Proszę sprawdzić ustawienia geoprocesingu.</translation>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="2112"/>
         <source>Vector analysis tools</source>
-        <translation type="unfinished"></translation>
+        <translation>Narzędzia analiz wektorowych</translation>
     </message>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="2113"/>
@@ -17134,7 +17131,7 @@ Proszę sprawdzić ustawienia geoprocesingu.</translation>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="2135"/>
         <source>Vector analysis tools</source>
-        <translation type="unfinished"></translation>
+        <translation>Narzędzia analiz wektorowych</translation>
     </message>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="2136"/>
@@ -17162,7 +17159,7 @@ Proszę sprawdzić ustawienia geoprocesingu.</translation>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="2143"/>
         <source>Vector analysis tools</source>
-        <translation type="unfinished"></translation>
+        <translation>Narzędzia analiz wektorowych</translation>
     </message>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="2144"/>
@@ -17190,7 +17187,7 @@ Proszę sprawdzić ustawienia geoprocesingu.</translation>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="2151"/>
         <source>Vector analysis tools</source>
-        <translation type="unfinished"></translation>
+        <translation>Narzędzia analiz wektorowych</translation>
     </message>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="2152"/>
@@ -17223,7 +17220,7 @@ Proszę sprawdzić ustawienia geoprocesingu.</translation>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="2160"/>
         <source>Vector analysis tools</source>
-        <translation type="unfinished"></translation>
+        <translation>Narzędzia analiz wektorowych</translation>
     </message>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="2161"/>
@@ -17261,7 +17258,7 @@ Proszę sprawdzić ustawienia geoprocesingu.</translation>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="2170"/>
         <source>Vector analysis tools</source>
-        <translation type="unfinished"></translation>
+        <translation>Narzędzia analiz wektorowych</translation>
     </message>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="2171"/>
@@ -17300,7 +17297,7 @@ Pole do zapisu zliczeń</translation>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="2180"/>
         <source>Vector creation tools</source>
-        <translation type="unfinished"></translation>
+        <translation>Narzędzia generowania obiektów wektorowych</translation>
     </message>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="2181"/>
@@ -17338,7 +17335,7 @@ Pole do zapisu zliczeń</translation>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="2190"/>
         <source>Vector creation tools</source>
-        <translation type="unfinished"></translation>
+        <translation>Narzędzia generowania obiektów wektorowych</translation>
     </message>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="2191"/>
@@ -17381,7 +17378,7 @@ Pole do zapisu zliczeń</translation>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="2201"/>
         <source>Graphics</source>
-        <translation>Grafika</translation>
+        <translation>Wykresy</translation>
     </message>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="2202"/>
@@ -18395,7 +18392,7 @@ Może to skutkować nieoczekiwanymi rezultatami.</translation>
         <source>Python Console 
 Use iface to access QGIS API interface or Type help(iface) for more info</source>
         <translation>Konsola Pythona 
-Dostęp do interfejsu QGIS API uzyskać można za pomocą wyrażenia iface. Więcej informacji otrzymasz wpisując help(iface)</translation>
+Dostęp do API uzyskasz poprzez obiekt iface. Więcej informacji pod help(iface).</translation>
     </message>
     <message>
         <location filename="../python/python-i18n.cpp" line="119"/>
@@ -18637,7 +18634,7 @@ Dostęp do interfejsu QGIS API uzyskać można za pomocą wyrażenia iface. Wię
     <message>
         <location filename="../src/app/qgisapp.cpp" line="11905"/>
         <source>Crash dumped</source>
-        <translation>Awaria przy zrzucie</translation>
+        <translation>Awaria</translation>
     </message>
     <message>
         <location filename="../src/app/main.cpp" line="761"/>
@@ -20307,7 +20304,7 @@ Only %1 of %2 features written.</source>
     <message>
         <location filename="../src/core/symbology-ng/qgssymbollayerv2registry.cpp" line="37"/>
         <source>Filled marker</source>
-        <translation type="unfinished"></translation>
+        <translation>Znacznik z wypełnienia</translation>
     </message>
     <message>
         <location filename="../src/core/symbology-ng/qgssymbollayerv2registry.cpp" line="39"/>
@@ -20327,7 +20324,7 @@ Only %1 of %2 features written.</source>
     <message>
         <location filename="../src/core/symbology-ng/qgssymbollayerv2registry.cpp" line="45"/>
         <source>Vector field marker</source>
-        <translation type="unfinished"></translation>
+        <translation>Znacznik z wektorów pola</translation>
     </message>
     <message>
         <location filename="../src/core/symbology-ng/qgssymbollayerv2registry.cpp" line="48"/>
@@ -20367,7 +20364,7 @@ Only %1 of %2 features written.</source>
     <message>
         <location filename="../src/core/symbology-ng/qgssymbollayerv2registry.cpp" line="65"/>
         <source>Geometry generator</source>
-        <translation type="unfinished"></translation>
+        <translation>Generator geometrii</translation>
     </message>
     <message>
         <location filename="../src/gui/qgsprojectbadlayerguihandler.cpp" line="229"/>
@@ -23881,7 +23878,7 @@ Prosimy o kontakt z autorami.</translation>
         <location filename="../src/app/qgisapp.cpp" line="790"/>
         <location filename="../src/app/qgisapp.cpp" line="3029"/>
         <source>Layer Styling</source>
-        <translation type="unfinished"></translation>
+        <translation>Stylizacja warstw</translation>
     </message>
     <message>
         <location filename="../src/app/qgisapp.cpp" line="1013"/>
@@ -23906,7 +23903,7 @@ Prosimy o kontakt z autorami.</translation>
     <message>
         <location filename="../src/app/qgisapp.cpp" line="3031"/>
         <source>Open the layer styling dock</source>
-        <translation type="unfinished"></translation>
+        <translation>Otwórz panel stylizacji warstw</translation>
     </message>
     <message>
         <location filename="../src/app/qgisapp.cpp" line="3320"/>
@@ -25121,7 +25118,7 @@ Błędy: %3
         <location filename="../src/app/qgisapp.cpp" line="9079"/>
         <source>en</source>
         <comment>documentation language</comment>
-        <translation>pl</translation>
+        <translation>en</translation>
     </message>
     <message>
         <location filename="../src/app/qgisapp.cpp" line="9101"/>
@@ -28012,7 +28009,7 @@ Operation can NOT be undone!</source>
     <message>
         <location filename="../src/auth/basic/qgsauthbasicedit.ui" line="87"/>
         <source>Show</source>
-        <translation>Wyświetl</translation>
+        <translation>Dymki</translation>
     </message>
     <message>
         <location filename="../src/auth/basic/qgsauthbasicedit.ui" line="96"/>
@@ -30400,7 +30397,7 @@ Baza danych: %2</translation>
     <message>
         <location filename="../src/app/qgsbrowserdockwidget.cpp" line="393"/>
         <source>Add as a Favourite</source>
-        <translation>Dodaj jako Ulubione</translation>
+        <translation>Dodaj do ulubionych</translation>
     </message>
     <message>
         <location filename="../src/app/qgsbrowserdockwidget.cpp" line="398"/>
@@ -30486,7 +30483,7 @@ Baza danych: %2</translation>
     <message>
         <location filename="../src/ui/qgsbrowserdockwidgetbase.ui" line="256"/>
         <source>Enable/disable properties widget</source>
-        <translation>Włącz/wyłącz widżet właściwości</translation>
+        <translation>Pokaż/ukryj właściwości</translation>
     </message>
     <message>
         <location filename="../src/ui/qgsbrowserdockwidgetbase.ui" line="238"/>
@@ -39107,7 +39104,7 @@ a aktualną wersją pliku jest [%3]</translation>
     <message>
         <location filename="../src/gui/qgsdatadefinedbutton.cpp" line="196"/>
         <source>Field type: </source>
-        <translation>Typ pola: </translation>
+        <translation>Pole typu: </translation>
     </message>
     <message>
         <location filename="../src/gui/qgsdatadefinedbutton.cpp" line="125"/>
@@ -39149,7 +39146,7 @@ a aktualną wersją pliku jest [%3]</translation>
     <message>
         <location filename="../src/gui/qgsdatadefinedbutton.cpp" line="285"/>
         <source>Attribute field</source>
-        <translation>Pole atrybutu</translation>
+        <translation>Atrybut</translation>
     </message>
     <message>
         <location filename="../src/gui/qgsdatadefinedbutton.cpp" line="311"/>
@@ -39837,7 +39834,7 @@ a aktualną wersją pliku jest [%3]</translation>
     <message>
         <location filename="../src/providers/db2/qgsdb2provider.cpp" line="132"/>
         <source>Text, fixed length (char)</source>
-        <translation>Pole testowe stałej długości (char)</translation>
+        <translation>Pole tekstowe stałej długości (char)</translation>
     </message>
     <message>
         <location filename="../src/providers/db2/qgsdb2provider.cpp" line="133"/>
@@ -40878,7 +40875,7 @@ nie będą wyświetlane</translation>
     <message>
         <location filename="../src/providers/delimitedtext/qgsdelimitedtextprovider.cpp" line="92"/>
         <source>Text, unlimited length (text)</source>
-        <translation>Pole testowe maksymalnej długości (text)</translation>
+        <translation>Pole tekstowe maksymalnej długości (text)</translation>
     </message>
     <message>
         <location filename="../src/providers/delimitedtext/qgsdelimitedtextprovider.cpp" line="90"/>
@@ -41552,12 +41549,12 @@ nie będą wyświetlane</translation>
     <message>
         <location filename="../src/app/qgsdiagramproperties.cpp" line="74"/>
         <source>No diagrams</source>
-        <translation>Bez wykresu</translation>
+        <translation>Brak</translation>
     </message>
     <message>
         <location filename="../src/app/qgsdiagramproperties.cpp" line="78"/>
         <source>Text diagram</source>
-        <translation>Wykres tekstowy</translation>
+        <translation>Tekst</translation>
     </message>
     <message>
         <location filename="../src/app/qgsdiagramproperties.cpp" line="80"/>
@@ -42341,7 +42338,7 @@ Błąd:
     <message>
         <location filename="../src/gui/editorwidgets/core/qgseditorwidgetregistry.cpp" line="65"/>
         <source>Value Relation</source>
-        <translation>Relacja</translation>
+        <translation>Relacja (value relation)</translation>
     </message>
     <message>
         <location filename="../src/gui/editorwidgets/core/qgseditorwidgetregistry.cpp" line="66"/>
@@ -42366,7 +42363,7 @@ Błąd:
     <message>
         <location filename="../src/gui/editorwidgets/core/qgseditorwidgetregistry.cpp" line="72"/>
         <source>Relation Reference</source>
-        <translation>Relacja</translation>
+        <translation>Relacja (relation reference)</translation>
     </message>
     <message>
         <location filename="../src/gui/editorwidgets/core/qgseditorwidgetregistry.cpp" line="73"/>
@@ -54991,7 +54988,7 @@ w wierszu %2 kolumnie %3</translation>
     <message>
         <location filename="../src/providers/grass/qgsgrassprovider.cpp" line="268"/>
         <source>Text, limited variable length (varchar)</source>
-        <translation>Pole testowe zmiennej długości (varchar)</translation>
+        <translation>Pole tekstowe zmiennej długości (varchar)</translation>
     </message>
     <message>
         <location filename="../src/providers/grass/qgsgrassprovider.cpp" line="270"/>
@@ -58472,7 +58469,7 @@ Może to być spowodowane problemem w sieci lokalnej lub problemem serwera WMS.<
     <message>
         <location filename="../src/ui/qgsmapstylingwidgetbase.ui" line="114"/>
         <source>Live update</source>
-        <translation type="unfinished"></translation>
+        <translation>Aktualizuj w locie</translation>
     </message>
 </context>
 <context>
@@ -59063,12 +59060,12 @@ Może to być spowodowane problemem w sieci lokalnej lub problemem serwera WMS.<
     <message>
         <location filename="../src/gui/qgsmaplayerstylemanagerwidget.cpp" line="54"/>
         <source>Save as default</source>
-        <translation type="unfinished"></translation>
+        <translation>Zapisz jako domyślny</translation>
     </message>
     <message>
         <location filename="../src/gui/qgsmaplayerstylemanagerwidget.cpp" line="56"/>
         <source>Restore default</source>
-        <translation type="unfinished"></translation>
+        <translation>Przywróć domyślny</translation>
     </message>
     <message>
         <location filename="../src/gui/qgsmaplayerstylemanagerwidget.cpp" line="51"/>
@@ -59089,7 +59086,7 @@ Może to być spowodowane problemem w sieci lokalnej lub problemem serwera WMS.<
     <message>
         <location filename="../src/gui/qgsmaplayerstylemanagerwidget.cpp" line="194"/>
         <source>Save default style to: </source>
-        <translation>Zapisz domyślny styl jako: </translation>
+        <translation>Zapisz domyślny styl w: </translation>
     </message>
     <message>
         <location filename="../src/gui/qgsmaplayerstylemanagerwidget.cpp" line="196"/>
@@ -59107,7 +59104,7 @@ Może to być spowodowane problemem w sieci lokalnej lub problemem serwera WMS.<
         <location filename="../src/gui/qgsmaplayerstylemanagerwidget.cpp" line="198"/>
         <location filename="../src/gui/qgsmaplayerstylemanagerwidget.cpp" line="240"/>
         <source>Datasource database</source>
-        <translation>Źródło bazy danych</translation>
+        <translation>Źródłowa baza danych</translation>
     </message>
     <message>
         <location filename="../src/gui/qgsmaplayerstylemanagerwidget.cpp" line="221"/>
@@ -60314,7 +60311,7 @@ and re-encrypted using new password</source>
     <message>
         <location filename="../src/providers/memory/qgsmemoryprovider.cpp" line="104"/>
         <source>Text, unlimited length (text)</source>
-        <translation>Pole testowe nieograniczonej długości (text)</translation>
+        <translation>Pole tekstowe nieograniczonej długości (text)</translation>
     </message>
 </context>
 <context>
@@ -60704,32 +60701,32 @@ Untick save if you don't wish to be the case.</source>
     <message>
         <location filename="../src/providers/mssql/qgsmssqlprovider.cpp" line="170"/>
         <source>Text, fixed length (char)</source>
-        <translation>Pole testowe stałej długości (char)</translation>
+        <translation>Pole tekstowe stałej długości (char)</translation>
     </message>
     <message>
         <location filename="../src/providers/mssql/qgsmssqlprovider.cpp" line="171"/>
         <source>Text, limited variable length (varchar)</source>
-        <translation>Pole testowe zmiennej, ograniczonej długości (varchar)</translation>
+        <translation>Pole tekstowe zmiennej, ograniczonej długości (varchar)</translation>
     </message>
     <message>
         <location filename="../src/providers/mssql/qgsmssqlprovider.cpp" line="172"/>
         <source>Text, fixed length unicode (nchar)</source>
-        <translation>Pole testowe stałej długości Unicod (nchar)</translation>
+        <translation>Pole tekstowe stałej długości Unicode(nchar)</translation>
     </message>
     <message>
         <location filename="../src/providers/mssql/qgsmssqlprovider.cpp" line="173"/>
         <source>Text, limited variable length unicode (nvarchar)</source>
-        <translation>Pole testowe zmiennej, ograniczonej długości Unicod (nvarchar)</translation>
+        <translation>Pole tekstowe zmiennej, ograniczonej długości Unicode(nvarchar)</translation>
     </message>
     <message>
         <location filename="../src/providers/mssql/qgsmssqlprovider.cpp" line="174"/>
         <source>Text, unlimited length (text)</source>
-        <translation>Pole testowe nieograniczonej długości (text)</translation>
+        <translation>Pole tekstowe nieograniczonej długości (text)</translation>
     </message>
     <message>
         <location filename="../src/providers/mssql/qgsmssqlprovider.cpp" line="175"/>
         <source>Text, unlimited length unicode (ntext)</source>
-        <translation>Pole testowe nieograniczonej długości Unicod (ntext)</translation>
+        <translation>Pole tekstowe nieograniczonej długości Unicode(ntext)</translation>
     </message>
 </context>
 <context>
@@ -61227,7 +61224,7 @@ enhancement</source>
     <message>
         <location filename="../src/gui/qgsnewgeopackagelayerdialog.cpp" line="98"/>
         <source>Whole number (integer 64 bit)</source>
-        <translation type="unfinished"></translation>
+        <translation>Liczba całkowita (integer 64 bit)</translation>
     </message>
     <message>
         <location filename="../src/gui/qgsnewgeopackagelayerdialog.cpp" line="100"/>
@@ -61352,7 +61349,7 @@ enhancement</source>
     <message>
         <location filename="../src/ui/qgsnewgeopackagelayerdialogbase.ui" line="32"/>
         <source>New GeoPackage Layer</source>
-        <translation type="unfinished"></translation>
+        <translation>Nowa warstwa GeoPackage</translation>
     </message>
     <message>
         <location filename="../src/ui/qgsnewgeopackagelayerdialogbase.ui" line="72"/>
@@ -61362,7 +61359,7 @@ enhancement</source>
     <message>
         <location filename="../src/ui/qgsnewgeopackagelayerdialogbase.ui" line="75"/>
         <source>Create a spatial index</source>
-        <translation type="unfinished"></translation>
+        <translation>Twórz indeks przestrzenny</translation>
     </message>
     <message>
         <location filename="../src/ui/qgsnewgeopackagelayerdialogbase.ui" line="85"/>
@@ -61399,32 +61396,32 @@ enhancement</source>
     <message>
         <location filename="../src/ui/qgsnewgeopackagelayerdialogbase.ui" line="150"/>
         <source><html><head/><body><p>Field length / width</p></body></html></source>
-        <translation type="unfinished"></translation>
+        <translation><html><head/><body><p>Długość pola</p></body></html></translation>
     </message>
     <message>
         <location filename="../src/ui/qgsnewgeopackagelayerdialogbase.ui" line="168"/>
         <source><html><head/><body><p>Human-readable identifier (e.g. short name) for the layer content</p></body></html></source>
-        <translation type="unfinished"></translation>
+        <translation><html><head/><body><p>Czytelny dla człowieka identyfikator warstwy (np. krótka nazwa)</p></body></html></translation>
     </message>
     <message>
         <location filename="../src/ui/qgsnewgeopackagelayerdialogbase.ui" line="181"/>
         <source><html><head/><body><p>Name of the geometry column</p></body></html></source>
-        <translation type="unfinished"></translation>
+        <translation><html><head/><body><p>Nazwa kolumny geometrii</p></body></html></translation>
     </message>
     <message>
         <location filename="../src/ui/qgsnewgeopackagelayerdialogbase.ui" line="184"/>
         <source>geometry</source>
-        <translation>geom</translation>
+        <translation>geometry</translation>
     </message>
     <message>
         <location filename="../src/ui/qgsnewgeopackagelayerdialogbase.ui" line="199"/>
         <source><html><head/><body><p>Existing or new GeoPackage database file name</p></body></html></source>
-        <translation type="unfinished"></translation>
+        <translation><html><head/><body><p>Nazwa pliku z istniejącą lub nową bazą danych GeoPackage</p></body></html></translation>
     </message>
     <message>
         <location filename="../src/ui/qgsnewgeopackagelayerdialogbase.ui" line="206"/>
         <source><html><head/><body><p>Select an existing or create a new database</p></body></html></source>
-        <translation type="unfinished"></translation>
+        <translation><html><head/><body><p>Wybierz istniejącą lub stwórz nową bazę danych</p></body></html></translation>
     </message>
     <message>
         <location filename="../src/ui/qgsnewgeopackagelayerdialogbase.ui" line="209"/>
@@ -61434,7 +61431,7 @@ enhancement</source>
     <message>
         <location filename="../src/ui/qgsnewgeopackagelayerdialogbase.ui" line="218"/>
         <source>Layer description</source>
-        <translation type="unfinished"></translation>
+        <translation>Opis warstwy</translation>
     </message>
     <message>
         <location filename="../src/ui/qgsnewgeopackagelayerdialogbase.ui" line="231"/>
@@ -61449,12 +61446,12 @@ enhancement</source>
     <message>
         <location filename="../src/ui/qgsnewgeopackagelayerdialogbase.ui" line="254"/>
         <source><html><head/><body><p>Table name in the database</p></body></html></source>
-        <translation type="unfinished"></translation>
+        <translation><html><head/><body><p>Nazwa tabeli w bazie danych</p></body></html></translation>
     </message>
     <message>
         <location filename="../src/ui/qgsnewgeopackagelayerdialogbase.ui" line="267"/>
         <source><html><head/><body><p>Human-readable description for the layer content</p></body></html></source>
-        <translation type="unfinished"></translation>
+        <translation><html><head/><body><p>Czytelny dla człowieka opis zawartości warstwy</p></body></html></translation>
     </message>
     <message>
         <location filename="../src/ui/qgsnewgeopackagelayerdialogbase.ui" line="277"/>
@@ -61469,22 +61466,22 @@ enhancement</source>
     <message>
         <location filename="../src/ui/qgsnewgeopackagelayerdialogbase.ui" line="294"/>
         <source>Layer identifier</source>
-        <translation type="unfinished"></translation>
+        <translation>Identyfikator warstwy</translation>
     </message>
     <message>
         <location filename="../src/ui/qgsnewgeopackagelayerdialogbase.ui" line="313"/>
         <source><html><head/><body><p>Geometry type</p></body></html></source>
-        <translation type="unfinished"></translation>
+        <translation><html><head/><body><p>Typ geometrii</p></body></html></translation>
     </message>
     <message>
         <location filename="../src/ui/qgsnewgeopackagelayerdialogbase.ui" line="320"/>
         <source>Feature id column</source>
-        <translation type="unfinished"></translation>
+        <translation>Pole klucza (fid)</translation>
     </message>
     <message>
         <location filename="../src/ui/qgsnewgeopackagelayerdialogbase.ui" line="336"/>
         <source><html><head/><body><p>Name of the feature id column</p></body></html></source>
-        <translation type="unfinished"></translation>
+        <translation><html><head/><body><p>Nazwa kolumny identyfikatora obiektu</p></body></html></translation>
     </message>
     <message>
         <location filename="../src/ui/qgsnewgeopackagelayerdialogbase.ui" line="339"/>
@@ -62758,7 +62755,7 @@ Rozszerzona informacja o błędzie:
     <message>
         <location filename="../src/gui/qgsowssourceselect.cpp" line="622"/>
         <source>Several WMS servers have been added to the server list. Note that if you access the internet via a web proxy, you will need to set the proxy settings in the QGIS options dialog.</source>
-        <translation>Wiele serwerów WMS zostało dodanych do listy serwerów. Jeśli łączysz się z internetem przez serwer proxy, konieczne może okazać się skonfigurowanie ustawień proxy w oknie dialogowym QGIS.</translation>
+        <translation>Nowe serwery WMS zostały dodane do listy serwerów. Jeśli łączysz się z internetem przez serwer proxy, konieczne może okazać się skonfigurowanie ustawień proxy w oknie dialogowym QGIS.</translation>
     </message>
     <message>
         <location filename="../src/gui/qgsowssourceselect.cpp" line="703"/>
@@ -63280,7 +63277,7 @@ Zawsze z sieci: zawsze wczytuj z sieci, bez sprawdzania.</translation>
     <message>
         <location filename="../src/providers/ogr/qgsogrprovider.cpp" line="367"/>
         <source>Whole number (integer 64 bit)</source>
-        <translation type="unfinished"></translation>
+        <translation>Liczby całkowite (integer 64 bit)</translation>
     </message>
     <message>
         <location filename="../src/providers/ogr/qgsogrprovider.cpp" line="369"/>
@@ -63300,7 +63297,7 @@ Zawsze z sieci: zawsze wczytuj z sieci, bez sprawdzania.</translation>
     <message>
         <location filename="../src/providers/ogr/qgsogrprovider.cpp" line="378"/>
         <source>Time</source>
-        <translation>czas</translation>
+        <translation>Czas</translation>
     </message>
     <message>
         <location filename="../src/providers/ogr/qgsogrprovider.cpp" line="379"/>
@@ -63945,7 +63942,7 @@ Zawsze z sieci: zawsze wczytuj z sieci, bez sprawdzania.</translation>
     <message>
         <location filename="../src/app/qgsoptions.cpp" line="662"/>
         <source>Cumulative pixel count cut</source>
-        <translation>łącznej liczby pikseli</translation>
+        <translation>histogram bez skrajnych wartości</translation>
     </message>
     <message>
         <location filename="../src/app/qgsoptions.cpp" line="663"/>
@@ -64377,7 +64374,7 @@ Zawsze z sieci: zawsze wczytuj z sieci, bez sprawdzania.</translation>
     <message>
         <location filename="../src/ui/qgsoptionsbase.ui" line="359"/>
         <source>Style <i>(QGIS restart required)</i></source>
-        <translation>Motyw (wymaga ponownego uruchomienia QGIS)</translation>
+        <translation>Motyw interfejsu (wymaga ponownego uruchomienia QGIS)</translation>
     </message>
     <message>
         <location filename="../src/ui/qgsoptionsbase.ui" line="422"/>
@@ -64412,7 +64409,7 @@ Zawsze z sieci: zawsze wczytuj z sieci, bez sprawdzania.</translation>
     <message>
         <location filename="../src/ui/qgsoptionsbase.ui" line="557"/>
         <source>Timeout for timed messages or dialogs</source>
-        <translation>Limit czasu dla komunikatów</translation>
+        <translation>Czas wyświetlania komunikatów</translation>
     </message>
     <message>
         <location filename="../src/ui/qgsoptionsbase.ui" line="577"/>
@@ -64432,7 +64429,7 @@ Zawsze z sieci: zawsze wczytuj z sieci, bez sprawdzania.</translation>
     <message>
         <location filename="../src/ui/qgsoptionsbase.ui" line="660"/>
         <source>QGIS-styled group boxes</source>
-        <translation>Styl QGIS grupy</translation>
+        <translation>Użyj stylu QGIS dla grup widżetów</translation>
     </message>
     <message>
         <location filename="../src/ui/qgsoptionsbase.ui" line="701"/>
@@ -64497,7 +64494,7 @@ Zawsze z sieci: zawsze wczytuj z sieci, bez sprawdzania.</translation>
     <message>
         <location filename="../src/ui/qgsoptionsbase.ui" line="916"/>
         <source>Prompt to save project and data source changes when required</source>
-        <translation>Informuj o konieczności zapisu, gdy projekt i źródło ulegną zmianie</translation>
+        <translation>Ostrzegaj o niezapisanych zmianach w projekcie i na warstwach</translation>
     </message>
     <message>
         <location filename="../src/ui/qgsoptionsbase.ui" line="923"/>
@@ -64609,7 +64606,7 @@ Zawsze z sieci: zawsze wczytuj z sieci, bez sprawdzania.</translation>
     <message>
         <location filename="../src/ui/qgsoptionsbase.ui" line="389"/>
         <source>UI Theme</source>
-        <translation>Motyw interfejsu</translation>
+        <translation>Motyw interfejsu (kolory)</translation>
     </message>
     <message>
         <location filename="../src/ui/qgsoptionsbase.ui" line="461"/>
@@ -64624,7 +64621,7 @@ Zawsze z sieci: zawsze wczytuj z sieci, bez sprawdzania.</translation>
     <message>
         <location filename="../src/ui/qgsoptionsbase.ui" line="491"/>
         <source>&Qt default</source>
-        <translation>&Domyślny Qt</translation>
+        <translation>domyślna Qt</translation>
     </message>
     <message>
         <location filename="../src/ui/qgsoptionsbase.ui" line="649"/>
@@ -64664,12 +64661,12 @@ Zawsze z sieci: zawsze wczytuj z sieci, bez sprawdzania.</translation>
     <message>
         <location filename="../src/ui/qgsoptionsbase.ui" line="1478"/>
         <source>Feature attributes and table</source>
-        <translation>Atrybuty obiektów i tabele</translation>
+        <translation>Tabela i formularz atrybutów</translation>
     </message>
     <message>
         <location filename="../src/ui/qgsoptionsbase.ui" line="1484"/>
-        <source>Open attribute table in a dock window (QGIS restart required)</source>
-        <translation>Otwórz &tabelę atrybutówi w oknie dokowalnym (wymaga ponownego uruchomienia QGIS)</translation>
+        <source>Open attribute table in a dock window</source>
+        <translation>Otwórz tabelę atrybutów w oknie dokowalnym</translation>
     </message>
     <message>
         <location filename="../src/ui/qgsoptionsbase.ui" line="1506"/>
@@ -64730,7 +64727,7 @@ Zawsze z sieci: zawsze wczytuj z sieci, bez sprawdzania.</translation>
     <message>
         <location filename="../src/ui/qgsoptionsbase.ui" line="1582"/>
         <source>Copy features as</source>
-        <translation type="unfinished"></translation>
+        <translation>Kopiuj obiekty w postaci</translation>
     </message>
     <message>
         <location filename="../src/ui/qgsoptionsbase.ui" line="1592"/>
@@ -64740,12 +64737,12 @@ Zawsze z sieci: zawsze wczytuj z sieci, bez sprawdzania.</translation>
     <message>
         <location filename="../src/ui/qgsoptionsbase.ui" line="1600"/>
         <source>Scan for valid items in the browser dock</source>
-        <translation>Szukaj poprawnych obiektów w oknie przeglądarki</translation>
+        <translation>Skanując dysk w panelu przeglądarki</translation>
     </message>
     <message>
         <location filename="../src/ui/qgsoptionsbase.ui" line="1627"/>
         <source>Scan for contents of compressed files (.zip) in browser dock</source>
-        <translation>Szukaj w plikach skompresowanych (.zip) w oknie przeglądarki</translation>
+        <translation>Szukaj w plikach skompresowanych (.zip) w panelu przeglądarki</translation>
     </message>
     <message>
         <location filename="../src/ui/qgsoptionsbase.ui" line="1664"/>
@@ -64805,7 +64802,7 @@ Zawsze z sieci: zawsze wczytuj z sieci, bez sprawdzania.</translation>
     <message>
         <location filename="../src/ui/qgsoptionsbase.ui" line="2014"/>
         <source>Simplification algorithm: </source>
-        <translation type="unfinished"></translation>
+        <translation>Algorytm upraszczania</translation>
     </message>
     <message>
         <location filename="../src/ui/qgsoptionsbase.ui" line="2034"/>
@@ -64815,7 +64812,7 @@ Zawsze z sieci: zawsze wczytuj z sieci, bez sprawdzania.</translation>
     <message>
         <location filename="../src/ui/qgsoptionsbase.ui" line="2062"/>
         <source>Magnification level</source>
-        <translation type="unfinished"></translation>
+        <translation>Poziom powiększenia</translation>
     </message>
     <message>
         <location filename="../src/ui/qgsoptionsbase.ui" line="2093"/>
@@ -64830,22 +64827,22 @@ Zawsze z sieci: zawsze wczytuj z sieci, bez sprawdzania.</translation>
     <message>
         <location filename="../src/ui/qgsoptionsbase.ui" line="2121"/>
         <source>Curve segmentation</source>
-        <translation type="unfinished"></translation>
+        <translation>Segmentacja krzywych</translation>
     </message>
     <message>
         <location filename="../src/ui/qgsoptionsbase.ui" line="2127"/>
         <source>Segmentation tolerance</source>
-        <translation type="unfinished"></translation>
+        <translation>Tolerancja</translation>
     </message>
     <message>
         <location filename="../src/ui/qgsoptionsbase.ui" line="2137"/>
         <source>Tolerance type</source>
-        <translation type="unfinished"></translation>
+        <translation>Typ tolerancji</translation>
     </message>
     <message>
         <location filename="../src/ui/qgsoptionsbase.ui" line="2150"/>
         <source>Rasters</source>
-        <translation>Siatka</translation>
+        <translation>Rastry</translation>
     </message>
     <message>
         <location filename="../src/ui/qgsoptionsbase.ui" line="2171"/>
@@ -64890,12 +64887,12 @@ Zawsze z sieci: zawsze wczytuj z sieci, bez sprawdzania.</translation>
     <message>
         <location filename="../src/ui/qgsoptionsbase.ui" line="2394"/>
         <source>Limits (minimum/maximum)</source>
-        <translation>Ogranicz do (min./max.)</translation>
+        <translation>Gdzie zakres MinMax wyznacza</translation>
     </message>
     <message>
         <location filename="../src/ui/qgsoptionsbase.ui" line="2435"/>
         <source>Cumulative pixel count cut limits</source>
-        <translation>Łączna liczba pikseli</translation>
+        <translation>Granice obcięcia histogramu</translation>
     </message>
     <message>
         <location filename="../src/ui/qgsoptionsbase.ui" line="2449"/>
@@ -64960,7 +64957,7 @@ Zawsze z sieci: zawsze wczytuj z sieci, bez sprawdzania.</translation>
     <message>
         <location filename="../src/ui/qgsoptionsbase.ui" line="2924"/>
         <source>Open layer styling dock</source>
-        <translation type="unfinished"></translation>
+        <translation>Otwórz panel stylizacji warstw</translation>
     </message>
     <message>
         <location filename="../src/ui/qgsoptionsbase.ui" line="3172"/>
@@ -65025,7 +65022,7 @@ Zawsze z sieci: zawsze wczytuj z sieci, bez sprawdzania.</translation>
     <message>
         <location filename="../src/ui/qgsoptionsbase.ui" line="3712"/>
         <source>Path(s) to search for extra print templates</source>
-        <translation type="unfinished"></translation>
+        <translation>Ścieżki wyszukiwania dodatkowych szablonów wydruku</translation>
     </message>
     <message>
         <location filename="../src/ui/qgsoptionsbase.ui" line="3850"/>
@@ -65146,7 +65143,7 @@ Zawsze z sieci: zawsze wczytuj z sieci, bez sprawdzania.</translation>
     <message>
         <location filename="../src/ui/qgsoptionsbase.ui" line="1719"/>
         <source>Execute expressions on server-side if possible</source>
-        <translation>Jeśli można, wykonaj zapytania po stronie serwera</translation>
+        <translation>Jeśli można, wykonuj zapytania po stronie serwera</translation>
     </message>
     <message>
         <location filename="../src/ui/qgsoptionsbase.ui" line="1949"/>
@@ -65467,7 +65464,7 @@ Zawsze z sieci: zawsze wczytuj z sieci, bez sprawdzania.</translation>
     <message>
         <location filename="../src/ui/qgsoptionsbase.ui" line="4233"/>
         <source>Curve offset tool</source>
-        <translation>Przesunięcie krzywych</translation>
+        <translation>Narzędzie przesuwania krzywych</translation>
     </message>
     <message>
         <location filename="../src/ui/qgsoptionsbase.ui" line="4242"/>
@@ -66177,17 +66174,17 @@ Błąd: %2</translation>
     <message>
         <location filename="../src/providers/oracle/qgsoracleprovider.cpp" line="159"/>
         <source>Text, fixed length (char)</source>
-        <translation>Pole testowe stałej długości (char)</translation>
+        <translation>Pole tekstowe stałej długości (char)</translation>
     </message>
     <message>
         <location filename="../src/providers/oracle/qgsoracleprovider.cpp" line="160"/>
         <source>Text, limited variable length (varchar2)</source>
-        <translation>Pole testowe zmiennej długości (varchar2)</translation>
+        <translation>Pole tekstowe zmiennej długości (varchar2)</translation>
     </message>
     <message>
         <location filename="../src/providers/oracle/qgsoracleprovider.cpp" line="161"/>
         <source>Text, unlimited length (long)</source>
-        <translation>Pole testowe nieograniczonej długości (long)</translation>
+        <translation>Pole tekstowe nieograniczonej długości (long)</translation>
     </message>
     <message>
         <location filename="../src/providers/oracle/qgsoracleprovider.cpp" line="164"/>
@@ -67126,18 +67123,18 @@ Błąd: %2</translation>
         <location filename="../src/providers/postgres/qgspostgresdataitems.cpp" line="304"/>
         <location filename="../src/providers/postgres/qgspostgresdataitems.cpp" line="347"/>
         <source>View</source>
-        <translation>Widok</translation>
+        <translation>widok</translation>
     </message>
     <message>
         <location filename="../src/providers/postgres/qgspostgresdataitems.cpp" line="304"/>
         <location filename="../src/providers/postgres/qgspostgresdataitems.cpp" line="347"/>
         <source>Table</source>
-        <translation>Tabela</translation>
+        <translation>tabelę</translation>
     </message>
     <message>
         <location filename="../src/providers/postgres/qgspostgresdataitems.cpp" line="306"/>
         <source>Rename %1...</source>
-        <translation>Zmień nazwę %1...</translation>
+        <translation>Przemianuj %1...</translation>
     </message>
     <message>
         <location filename="../src/providers/postgres/qgspostgresdataitems.cpp" line="310"/>
@@ -67147,7 +67144,7 @@ Błąd: %2</translation>
     <message>
         <location filename="../src/providers/postgres/qgspostgresdataitems.cpp" line="316"/>
         <source>Truncate %1</source>
-        <translation type="unfinished"></translation>
+        <translation>Wyczyść %1</translation>
     </message>
     <message>
         <location filename="../src/providers/postgres/qgspostgresdataitems.cpp" line="335"/>
@@ -69412,17 +69409,17 @@ Rezultat: %3 (%4)</translation>
     <message>
         <location filename="../src/providers/postgres/qgspostgresprovider.cpp" line="208"/>
         <source>Text, fixed length (char)</source>
-        <translation>Pole testowe stałej długości (char)</translation>
+        <translation>Pole tekstowe stałej długości (char)</translation>
     </message>
     <message>
         <location filename="../src/providers/postgres/qgspostgresprovider.cpp" line="209"/>
         <source>Text, limited variable length (varchar)</source>
-        <translation>Pole testowe zmiennej długości (varchar)</translation>
+        <translation>Pole tekstowe zmiennej długości (varchar)</translation>
     </message>
     <message>
         <location filename="../src/providers/postgres/qgspostgresprovider.cpp" line="210"/>
         <source>Text, unlimited length (text)</source>
-        <translation>Pole testowe maksymalnej długości (text)</translation>
+        <translation>Pole tekstowe maksymalnej długości (text)</translation>
     </message>
     <message>
         <location filename="../src/providers/postgres/qgspostgresprovider.cpp" line="213"/>
@@ -75731,7 +75728,7 @@ and only the geometry column of the main typename can be used as the geometry co
     <message>
         <location filename="../src/gui/symbology-ng/qgssymbollayerv2widget.cpp" line="195"/>
         <source>Width Assistant...</source>
-        <translation type="unfinished"></translation>
+        <translation>Asystent szerokości...</translation>
     </message>
 </context>
 <context>
@@ -76321,12 +76318,12 @@ suffix</source>
     <message>
         <location filename="../src/ui/qgssnappingdialogbase.ui" line="22"/>
         <source>Layer selection</source>
-        <translation>zaznaczone warstwy</translation>
+        <translation>Przyciągaj do</translation>
     </message>
     <message>
         <location filename="../src/ui/qgssnappingdialogbase.ui" line="41"/>
         <source>All visible layers</source>
-        <translation type="unfinished"></translation>
+        <translation>wszystkich włączonych warstw</translation>
     </message>
     <message>
         <location filename="../src/ui/qgssnappingdialogbase.ui" line="196"/>
@@ -76356,12 +76353,12 @@ suffix</source>
     <message>
         <location filename="../src/ui/qgssnappingdialogbase.ui" line="36"/>
         <source>Current layer</source>
-        <translation>bieżąca warstwa</translation>
+        <translation>bieżącej warstwy</translation>
     </message>
     <message>
         <location filename="../src/ui/qgssnappingdialogbase.ui" line="46"/>
         <source>Advanced</source>
-        <translation>Zaawansowane</translation>
+        <translation>Ustawienia zaawansowane</translation>
     </message>
     <message>
         <location filename="../src/ui/qgssnappingdialogbase.ui" line="81"/>
@@ -77498,7 +77495,7 @@ p, li { white-space: pre-wrap; }
     <message>
         <location filename="../src/app/qgsstatusbarscalewidget.cpp" line="50"/>
         <source>Current map scale (formatted as x:y)</source>
-        <translation>Obecna skala mapy (zapisana jako x:y)</translation>
+        <translation>Obecna skala mapy</translation>
     </message>
     <message>
         <location filename="../src/app/qgsstatusbarscalewidget.cpp" line="54"/>
@@ -78483,7 +78480,7 @@ Im niższy numer, tym wcześniej rysowana jest warstwa.</translation>
     <message>
         <location filename="../src/gui/symbology-ng/qgssymbolslistwidget.cpp" line="114"/>
         <source>Width Assistant...</source>
-        <translation type="unfinished"></translation>
+        <translation>Asystent szerokości...</translation>
     </message>
     <message>
         <location filename="../src/gui/symbology-ng/qgssymbolslistwidget.cpp" line="119"/>
@@ -80156,7 +80153,7 @@ Błąd:%2</translation>
         <location filename="../src/app/qgsvectorlayerproperties.cpp" line="793"/>
         <location filename="../src/app/qgsvectorlayerproperties.cpp" line="848"/>
         <source>Datasource database</source>
-        <translation>Źródło bazy danych</translation>
+        <translation>Źródłowa baza danych</translation>
     </message>
     <message>
         <location filename="../src/app/qgsvectorlayerproperties.cpp" line="804"/>
@@ -80179,7 +80176,7 @@ Błąd:%2</translation>
     <message>
         <location filename="../src/app/qgsvectorlayerproperties.cpp" line="844"/>
         <source>Save default style to: </source>
-        <translation>Zapisz domyślny styl jako: </translation>
+        <translation>Zapisz domyślny styl w: </translation>
     </message>
     <message>
         <location filename="../src/app/qgsvectorlayerproperties.cpp" line="880"/>
@@ -80661,7 +80658,7 @@ Błąd:%2</translation>
         <location filename="../src/ui/qgsvectorlayerpropertiesbase.ui" line="206"/>
         <location filename="../src/ui/qgsvectorlayerpropertiesbase.ui" line="209"/>
         <source>Diagrams</source>
-        <translation>Wykresy</translation>
+        <translation>Kartodiagram</translation>
     </message>
     <message>
         <location filename="../src/ui/qgsvectorlayerpropertiesbase.ui" line="1319"/>
@@ -80785,7 +80782,7 @@ Błąd:%2</translation>
     <message>
         <location filename="../src/ui/qgsvectorlayersaveasdialogbase.ui" line="246"/>
         <source>Geometry type</source>
-        <translation type="unfinished">Typ geometrii</translation>
+        <translation>Typ geometrii</translation>
     </message>
     <message>
         <location filename="../src/ui/qgsvectorlayersaveasdialogbase.ui" line="258"/>
@@ -81973,7 +81970,7 @@ In particular, saving a virtual layer with embedded layers to a QLR file can be
     <message>
         <location filename="../src/providers/wms/qgswmssourceselect.cpp" line="1119"/>
         <source>Several WMS servers have been added to the server list. Note that if you access the internet via a web proxy, you will need to set the proxy settings in the QGIS options dialog.</source>
-        <translation>Wiele serwerów WMS zostało dodanych do listy serwerów. Jeśli łączysz się z internetem przez serwer proxy, konieczne może okazać się skonfigurowanie ustawień proxy w oknie dialogowym QGIS.</translation>
+        <translation>Nowe serwery WMS zostały dodane do listy serwerów. Jeśli łączysz się z internetem przez serwer proxy, konieczne może okazać się skonfigurowanie ustawień proxy w oknie dialogowym QGIS.</translation>
     </message>
     <message>
         <location filename="../src/providers/wms/qgswmssourceselect.cpp" line="1199"/>
@@ -84072,7 +84069,7 @@ Proszę go skonfigurować przed uruchomieniem skryptów R.</translation>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="2397"/>
         <source>Vector creation tools</source>
-        <translation type="unfinished"></translation>
+        <translation>Narzędzia generowania obiektów wektorowych</translation>
     </message>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="2398"/>
@@ -84110,7 +84107,7 @@ Proszę go skonfigurować przed uruchomieniem skryptów R.</translation>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="2407"/>
         <source>Vector creation tools</source>
-        <translation type="unfinished"></translation>
+        <translation>Narzędzia generowania obiektów wektorowych</translation>
     </message>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="2408"/>
@@ -84148,7 +84145,7 @@ Proszę go skonfigurować przed uruchomieniem skryptów R.</translation>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="2417"/>
         <source>Vector creation tools</source>
-        <translation type="unfinished"></translation>
+        <translation>Narzędzia generowania obiektów wektorowych</translation>
     </message>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="2418"/>
@@ -84186,7 +84183,7 @@ Proszę go skonfigurować przed uruchomieniem skryptów R.</translation>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="2427"/>
         <source>Vector creation tools</source>
-        <translation type="unfinished"></translation>
+        <translation>Narzędzia generowania obiektów wektorowych</translation>
     </message>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="2428"/>
@@ -84239,7 +84236,7 @@ Proszę go skonfigurować przed uruchomieniem skryptów R.</translation>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="2440"/>
         <source>Vector creation tools</source>
-        <translation type="unfinished"></translation>
+        <translation>Narzędzia generowania obiektów wektorowych</translation>
     </message>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="2441"/>
@@ -84446,7 +84443,7 @@ Proszę go skonfigurować przed uruchomieniem skryptów R.</translation>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="2491"/>
         <source>Graphics</source>
-        <translation>Grafika</translation>
+        <translation>Wykresy</translation>
     </message>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="2492"/>
@@ -84682,7 +84679,7 @@ Proszę go skonfigurować przed uruchomieniem skryptów R.</translation>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="2546"/>
         <source>Vector creation tools</source>
-        <translation type="unfinished"></translation>
+        <translation>Narzędzia generowania obiektów wektorowych</translation>
     </message>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="2547"/>
@@ -85056,7 +85053,7 @@ Proszę go skonfigurować przed uruchomieniem skryptów R.</translation>
     <message>
         <location filename="../src/plugins/roadgraph/roadgraphplugin.cpp" line="105"/>
         <source>Settings...</source>
-        <translation type="unfinished"></translation>
+        <translation>Ustawienia...</translation>
     </message>
     <message>
         <location filename="../src/plugins/roadgraph/roadgraphplugin.cpp" line="109"/>
@@ -85067,7 +85064,7 @@ Proszę go skonfigurować przed uruchomieniem skryptów R.</translation>
         <location filename="../src/plugins/roadgraph/roadgraphplugin.cpp" line="116"/>
         <location filename="../src/plugins/roadgraph/roadgraphplugin.cpp" line="131"/>
         <source>Road Graph</source>
-        <translation type="unfinished"></translation>
+        <translation>Optymalna droga</translation>
     </message>
 </context>
 <context>
@@ -86924,7 +86921,7 @@ Problem w linii %d</translation>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="2688"/>
         <source>Raster general tools</source>
-        <translation type="unfinished"></translation>
+        <translation>Ogólne narzędzia rastrowe</translation>
     </message>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="2689"/>
@@ -87770,7 +87767,7 @@ Problem w linii %d</translation>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="2816"/>
         <source>Vector analysis tools</source>
-        <translation type="unfinished"></translation>
+        <translation>Narzędzia analiz wektorowych</translation>
     </message>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="2817"/>
@@ -88339,7 +88336,7 @@ Problem w linii %d</translation>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="2881"/>
         <source> [{0} geoalgorithms]</source>
-        <translation type="unfinished"></translation>
+        <translation>[{0} geoalgorytmów]</translation>
     </message>
 </context>
 <context>
@@ -88487,7 +88484,7 @@ Problem w linii %d</translation>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="2916"/>
         <source>Vector creation tools</source>
-        <translation type="unfinished"></translation>
+        <translation>Narzędzia generowania obiektów wektorowych</translation>
     </message>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="2917"/>
@@ -88578,7 +88575,7 @@ Problem w linii %d</translation>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="2939"/>
         <source>Graphics</source>
-        <translation>Grafika</translation>
+        <translation>Wykresy</translation>
     </message>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="2940"/>
@@ -88611,7 +88608,7 @@ Problem w linii %d</translation>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="2948"/>
         <source>Graphics</source>
-        <translation>Grafika</translation>
+        <translation>Wykresy</translation>
     </message>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="2949"/>
@@ -100080,7 +100077,7 @@ Base Path (i.e. keep only filename from attribute)</source>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="3997"/>
         <source>Converted</source>
-        <translation>Warstwa ze zmienionym typem geometrii</translation>
+        <translation>Warstwa wyjściowa</translation>
     </message>
     <message>
         <location filename="../python/plugins/processing/python-i18n.cpp" line="3988"/>
diff --git a/python/core/qgsactionmanager.sip b/python/core/qgsactionmanager.sip
index 905e0f0..2e34721 100644
--- a/python/core/qgsactionmanager.sip
+++ b/python/core/qgsactionmanager.sip
@@ -62,13 +62,18 @@ class QgsActionManager
     //! Remove an action at given index
     void removeAction( int index );
 
-    /** Does the given values. defaultValueIndex is the index of the
-     *  field to be used if the action has a $currfield placeholder.
-     *  @note available in python bindings as doActionFeature
+    /**
+     * Does the given action.
+     *
+     * @param index Index of the action
+     * @param feat Feature to run action for
+     * @param defaultValueIndex Index of the field to be used if the action has a $currfield placeholder.
+     * @param scope Expression context scope to add during expression evaluation
      */
     void doAction( int index,
                    const QgsFeature &feat,
-                   int defaultValueIndex = 0 ) /PyName=doActionFeature/;
+                   int defaultValueIndex = 0,
+                 const QgsExpressionContextScope &scope = QgsExpressionContextScope() ) /PyName=doActionFeature/;
 
     /** Does the action using the expression engine to replace any embedded expressions
      * in the action definition.
diff --git a/python/core/qgslayerdefinition.sip b/python/core/qgslayerdefinition.sip
index d89fc51..4183f2a 100644
--- a/python/core/qgslayerdefinition.sip
+++ b/python/core/qgslayerdefinition.sip
@@ -14,11 +14,11 @@ class QgsLayerDefinition
     /** Loads the QLR at path into QGIS.  New layers are added to rootGroup and the map layer registry*/
     static bool loadLayerDefinition( const QString & path, QgsLayerTreeGroup* rootGroup, QString &errorMessage /Out/ );
     /** Loads the QLR from the XML document.  New layers are added to rootGroup and the map layer registry */
-    static bool loadLayerDefinition( QDomDocument doc, QgsLayerTreeGroup* rootGroup, QString &errorMessage /Out/ );
+    static bool loadLayerDefinition( QDomDocument doc, QgsLayerTreeGroup* rootGroup, QString &errorMessage, const QString& relativeBasePath = QString() );
     /** Export the selected layer tree nodes to a QLR file */
     static bool exportLayerDefinition( QString path, const QList<QgsLayerTreeNode*>& selectedTreeNodes, QString &errorMessage /Out/ );
     /** Export the selected layer tree nodes to a QLR-XML document */
-    static bool exportLayerDefinition( QDomDocument doc, const QList<QgsLayerTreeNode*>& selectedTreeNodes, QString &errorMessage, const QString& relativeBasePath = QString::null );
+    static bool exportLayerDefinition( QDomDocument doc, const QList<QgsLayerTreeNode*>& selectedTreeNodes, QString &errorMessage, const QString& relativeBasePath = QString() );
 
     /**
      * Class used to work with layer dependencies stored in a XML project or layer definition file
diff --git a/python/core/qgsmaplayer.sip b/python/core/qgsmaplayer.sip
index 4b20c39..9b153d9 100644
--- a/python/core/qgsmaplayer.sip
+++ b/python/core/qgsmaplayer.sip
@@ -288,6 +288,7 @@ class QgsMapLayer : QObject
 
     /** Sets state from Dom document
        @param layerElement The Dom element corresponding to ``maplayer'' tag
+       @param relativeBasePath base path for relative paths
        @note
 
        The Dom node corresponds to a Dom document project file XML element read
@@ -300,7 +301,7 @@ class QgsMapLayer : QObject
 
        @returns true if successful
      */
-    bool readLayerXML( const QDomElement& layerElement );
+    bool readLayerXML( const QDomElement& layerElement, const QString& relativeBasePath = QString() );
 
 
     /** Stores state in Dom node
@@ -319,18 +320,18 @@ class QgsMapLayer : QObject
      *
      * @returns true if successful
      */
-    bool writeLayerXML( QDomElement& layerElement, QDomDocument& document, const QString& relativeBasePath = QString::null );
+    bool writeLayerXML( QDomElement& layerElement, QDomDocument& document, const QString& relativeBasePath = QString() );
 
     /** Returns the given layer as a layer definition document
      *  Layer definitions store the data source as well as styling and custom properties.
      *
      *  Layer definitions can be used to load a layer and styling all from a single file.
      */
-    static QDomDocument asLayerDefinition( const QList<QgsMapLayer*>& layers, const QString& relativeBasePath = QString::null );
+    static QDomDocument asLayerDefinition( const QList<QgsMapLayer*>& layers, const QString& relativeBasePath = QString() );
 
     /** Creates a new layer from a layer defininition document
      */
-    static QList<QgsMapLayer*> fromLayerDefinition( QDomDocument& document, bool addToRegistry = false, bool addToLegend = false );
+    static QList<QgsMapLayer*> fromLayerDefinition( QDomDocument& document, bool addToRegistry = false, bool addToLegend = false, const QString& relativeBasePath = QString() );
     static QList<QgsMapLayer*> fromLayerDefinitionFile( const QString &qlrfile );
 
     /** Set a custom property for layer. Properties are stored in a map and saved in project file. */
diff --git a/python/core/qgsproject.sip b/python/core/qgsproject.sip
index dfae60a..cedb067 100644
--- a/python/core/qgsproject.sip
+++ b/python/core/qgsproject.sip
@@ -198,10 +198,10 @@ class QgsProject : QObject
     void dumpProperties() const;
 
     /** Prepare a filename to save it to the project file */
-    QString writePath( const QString& filename, const QString& relativeBasePath = QString::null ) const;
+    QString writePath( const QString& filename, const QString& relativeBasePath = QString() ) const;
 
     /** Turn filename read from the project file to an absolute path */
-    QString readPath( QString filename ) const;
+    QString readPath( QString filename, const QString& relativeBasePath = QString() ) const;
 
     /** Return error message from previous read/write */
     QString error() const;
diff --git a/python/gui/qgsactionmenu.sip b/python/gui/qgsactionmenu.sip
index 219937f..74fe66d 100644
--- a/python/gui/qgsactionmenu.sip
+++ b/python/gui/qgsactionmenu.sip
@@ -62,6 +62,20 @@ class QgsActionMenu : QMenu
      */
     void setFeature( QgsFeature* feature );
 
+    /**
+     * Sets an expression context scope used to resolve underlying actions.
+     *
+     * @note Added in QGIS 2.18
+     */
+    void setExpressionContextScope( const QgsExpressionContextScope &scope );
+
+    /**
+     * Returns an expression context scope used to resolve underlying actions.
+     *
+     * @note Added in QGIS 2.18
+     */
+    QgsExpressionContextScope expressionContextScope() const;
+
   signals:
     void reinit();
 
diff --git a/python/gui/qgsidentifymenu.sip b/python/gui/qgsidentifymenu.sip
index a475f79..b328117 100644
--- a/python/gui/qgsidentifymenu.sip
+++ b/python/gui/qgsidentifymenu.sip
@@ -83,6 +83,20 @@ class QgsIdentifyMenu : QMenu
      */
     QList<QgsMapToolIdentify::IdentifyResult> exec( const QList<QgsMapToolIdentify::IdentifyResult>& idResults, QPoint pos );
 
+    /**
+     * Sets an expression context scope used to resolve underlying actions.
+     *
+     * @note Added in QGIS 2.18
+     */
+    void setExpressionContextScope( const QgsExpressionContextScope &scope );
+
+    /**
+     * Returns an expression context scope used to resolve underlying actions.
+     *
+     * @note Added in QGIS 2.18
+     */
+    QgsExpressionContextScope expressionContextScope() const;
+
   protected:
     virtual void closeEvent( QCloseEvent *e );
 };
diff --git a/python/plugins/db_manager/db_plugins/gpkg/connector.py b/python/plugins/db_manager/db_plugins/gpkg/connector.py
index 3445835..b40965b 100644
--- a/python/plugins/db_manager/db_plugins/gpkg/connector.py
+++ b/python/plugins/db_manager/db_plugins/gpkg/connector.py
@@ -184,7 +184,7 @@ class GPKGDBConnector(DBConnector):
         return DBConnector._execute(self, cursor, sql)
 
     def _commit(self):
-        if self.gdal2:
+        if self.connection is None:
             return
 
         try:
diff --git a/python/plugins/db_manager/db_plugins/postgis/connector.py b/python/plugins/db_manager/db_plugins/postgis/connector.py
index 8819a42..de59f55 100644
--- a/python/plugins/db_manager/db_plugins/postgis/connector.py
+++ b/python/plugins/db_manager/db_plugins/postgis/connector.py
@@ -22,7 +22,7 @@ The content of this file is based on
  ***************************************************************************/
 """
 
-from qgis.PyQt.QtCore import QRegExp
+from qgis.PyQt.QtCore import QRegExp, QFile
 from qgis.core import QgsCredentials, QgsDataSourceURI
 from functools import cmp_to_key
 
@@ -63,6 +63,7 @@ class PostGisDBConnector(DBConnector):
         try:
             self.connection = psycopg2.connect(expandedConnInfo)
         except self.connection_error_types() as e:
+            # get credentials if cached or assking to the user no more than 3 times
             err = unicode(e)
             uri = self.uri()
             conninfo = uri.connectionInfo(False)
@@ -85,44 +86,13 @@ class PostGisDBConnector(DBConnector):
                 except self.connection_error_types() as e:
                     if i == 2:
                         raise ConnectionError(e)
-
                     err = unicode(e)
                 finally:
-                    # remove certs (if any) of the expanded connectionInfo
-                    expandedUri = QgsDataSourceURI(newExpandedConnInfo)
-
-                    sslCertFile = expandedUri.param("sslcert")
-                    if sslCertFile:
-                        sslCertFile = sslCertFile.replace("'", "")
-                        os.remove(sslCertFile)
-
-                    sslKeyFile = expandedUri.param("sslkey")
-                    if sslKeyFile:
-                        sslKeyFile = sslKeyFile.replace("'", "")
-                        os.remove(sslKeyFile)
-
-                    sslCAFile = expandedUri.param("sslrootcert")
-                    if sslCAFile:
-                        sslCAFile = sslCAFile.replace("'", "")
-                        os.remove(sslCAFile)
+                    # clear certs for each time trying to connect
+                    self._clearSslTempCertsIfAny(newExpandedConnInfo)
         finally:
-            # remove certs (if any) of the expanded connectionInfo
-            expandedUri = QgsDataSourceURI(expandedConnInfo)
-
-            sslCertFile = expandedUri.param("sslcert")
-            if sslCertFile:
-                sslCertFile = sslCertFile.replace("'", "")
-                os.remove(sslCertFile)
-
-            sslKeyFile = expandedUri.param("sslkey")
-            if sslKeyFile:
-                sslKeyFile = sslKeyFile.replace("'", "")
-                os.remove(sslKeyFile)
-
-            sslCAFile = expandedUri.param("sslrootcert")
-            if sslCAFile:
-                sslCAFile = sslCAFile.replace("'", "")
-                os.remove(sslCAFile)
+            # clear certs of the first connection try
+            self._clearSslTempCertsIfAny(expandedConnInfo)
 
         self.connection.set_isolation_level(psycopg2.extensions.ISOLATION_LEVEL_AUTOCOMMIT)
 
@@ -138,6 +108,33 @@ class PostGisDBConnector(DBConnector):
     def _connectionInfo(self):
         return str(self.uri().connectionInfo(True))
 
+    def _clearSslTempCertsIfAny(self, connectionInfo):
+        # remove certs (if any) of the connectionInfo
+        expandedUri = QgsDataSourceURI(connectionInfo)
+
+        def removeCert(certFile):
+            certFile = certFile.replace("'", "")
+            file = QFile(certFile)
+            # set permission to allow removing on Win.
+            # On linux and Mac if file is set with QFile::>ReadUser
+            # does not create problem removin certs
+            if not file.setPermissions(QFile.WriteOwner):
+                raise Exception('Cannot change permissions on {}: error code: {}'.format(file.fileName(), file.error()))
+            if not file.remove():
+                raise Exception('Cannot remove {}: error code: {}'.format(file.fileName(), file.error()))
+
+        sslCertFile = expandedUri.param("sslcert")
+        if sslCertFile:
+            removeCert(sslCertFile)
+
+        sslKeyFile = expandedUri.param("sslkey")
+        if sslKeyFile:
+            removeCert(sslKeyFile)
+
+        sslCAFile = expandedUri.param("sslrootcert")
+        if sslCAFile:
+            removeCert(sslCAFile)
+
     def _checkSpatial(self):
         """ check whether postgis_version is present in catalog """
         c = self._execute(None, u"SELECT COUNT(*) FROM pg_proc WHERE proname = 'postgis_version'")
diff --git a/python/plugins/processing/algs/grass7/Grass7Utils.py b/python/plugins/processing/algs/grass7/Grass7Utils.py
index d318c9f..d97b642 100644
--- a/python/plugins/processing/algs/grass7/Grass7Utils.py
+++ b/python/plugins/processing/algs/grass7/Grass7Utils.py
@@ -84,7 +84,7 @@ class Grass7Utils:
         if Grass7Utils.grassPath() is None:
             return None
 
-        for command in ["grass73", "grass72", "grass71", "grass70", "grass"]:
+        for command in ["grass74", "grass72", "grass71", "grass70", "grass"]:
             proc = subprocess.Popen(
                 ["{} -v".format(command)],
                 shell=True,
diff --git a/python/plugins/processing/algs/qgis/scripts/Frequency_analysis.py b/python/plugins/processing/algs/qgis/scripts/Frequency_analysis.py
index 4ee1615..cfc428f 100644
--- a/python/plugins/processing/algs/qgis/scripts/Frequency_analysis.py
+++ b/python/plugins/processing/algs/qgis/scripts/Frequency_analysis.py
@@ -1,4 +1,4 @@
-##Table=group
+##Vector table tools=group
 ##Input=vector
 ##Fields=Field Input
 ##Frequency=output table
diff --git a/python/plugins/processing/gui/BatchPanel.py b/python/plugins/processing/gui/BatchPanel.py
index 9a65cff..e3304b8 100644
--- a/python/plugins/processing/gui/BatchPanel.py
+++ b/python/plugins/processing/gui/BatchPanel.py
@@ -316,6 +316,8 @@ class BatchPanel(BASE, WIDGET):
             return param.setValue(widget.getValue())
         elif isinstance(param, ParameterGeometryPredicate):
             return param.setValue(widget.value())
+        elif isinstance(param, ParameterPoint):
+            return param.setValue(widget.getValue())
         else:
             return param.setValue(widget.text())
 
diff --git a/python/pyplugin_installer/installer_data.py b/python/pyplugin_installer/installer_data.py
index 6d4d95b..a4de6dc 100644
--- a/python/pyplugin_installer/installer_data.py
+++ b/python/pyplugin_installer/installer_data.py
@@ -716,10 +716,10 @@ class Plugins(QObject):
                         # failedToLoad = settings.value("/PythonPlugins/watchDog/" + key) is not None
                         testLoadThis = testLoad and key not in qgis.utils.plugins
                         plugin = self.getInstalledPlugin(key, path=path, readOnly=readOnly, testLoad=testLoadThis)
-                        self.localCache[key] = plugin
                         if key in self.localCache.keys() and compareVersions(self.localCache[key]["version_installed"], plugin["version_installed"]) == 1:
                             # An obsolete plugin in the "user" location is masking a newer one in the "system" location!
                             self.obsoletePlugins += [key]
+                        self.localCache[key] = plugin
             except:
                 # it's not necessary to stop if one of the dirs is inaccessible
                 pass
diff --git a/src/app/main.cpp b/src/app/main.cpp
index 3294cbff..a7d0cb0 100644
--- a/src/app/main.cpp
+++ b/src/app/main.cpp
@@ -806,6 +806,90 @@ int main( int argc, char *argv[] )
 
   QgsApplication myApp( argc, argv, myUseGuiFlag, configpath );
 
+  // Redefine QgsApplication::libraryPaths as necessary.
+  // IMPORTANT: Do *after* QgsApplication myApp(...), but *before* Qt uses any plugins,
+  //            e.g. loading splash screen, setting window icon, etc.
+  //            Always honor QT_PLUGIN_PATH env var or qt.conf, which will
+  //            be part of libraryPaths just after QgsApplication creation.
+#ifdef Q_OS_WIN
+  // For non static builds on win (static builds are not supported)
+  // we need to be sure we can find the qt image plugins.
+  QCoreApplication::addLibraryPath( QApplication::applicationDirPath()
+                                    + QDir::separator() + "qtplugins" );
+#endif
+#ifdef Q_OS_MAC
+  // Resulting libraryPaths has critical QGIS plugin paths first, then any Qt plugin paths, then
+  // any dev-defined paths (in app's qt.conf) and/or user-defined paths (QT_PLUGIN_PATH env var).
+  //
+  // NOTE: Minimizes, though does not fully protect against, crashes due to dev/user-defined libs
+  //       built against a different Qt/QGIS, while still allowing custom C++ plugins to load.
+  QStringList libPaths( QCoreApplication::libraryPaths() );
+
+  QgsDebugMsgLevel( QString( "Initial macOS QCoreApplication::libraryPaths: %1" )
+                    .arg( libPaths.join( " " ) ), 4 );
+
+  // Strip all critical paths that should always be prepended
+  if ( libPaths.removeAll( QDir::cleanPath( QgsApplication::pluginPath() ) ) )
+  {
+    QgsDebugMsgLevel( QString( "QgsApplication::pluginPath removed from initial libraryPaths" ), 4 );
+  }
+  if ( libPaths.removeAll( QCoreApplication::applicationDirPath() ) )
+  {
+    QgsDebugMsgLevel( QString( "QCoreApplication::applicationDirPath removed from initial libraryPaths" ), 4 );
+  }
+  // Prepend path, so a standard Qt bundle directory is parsed
+  QgsDebugMsgLevel( QString( "Prepending QCoreApplication::applicationDirPath to libraryPaths" ), 4 );
+  libPaths.prepend( QCoreApplication::applicationDirPath() );
+
+  // Check if we are running in a 'release' app bundle, i.e. contains copied-in
+  // standard Qt-specific plugin subdirectories (ones never created by QGIS, e.g. 'sqldrivers' is).
+  // Note: bundleclicked(...) is inadequate to determine which *type* of bundle was opened, e.g. release or build dir.
+  // An app bundled with QGIS_MACAPP_BUNDLE > 0 is considered a release bundle.
+  QString  relLibPath( QDir::cleanPath( QCoreApplication::applicationDirPath().append( "/../PlugIns" ) ) );
+  // Note: relLibPath becomes the defacto QT_PLUGINS_DIR of a release app bundle
+  if ( QFile::exists( relLibPath + "/imageformats" )
+       && QFile::exists( relLibPath + "/codecs" ) )
+  {
+    // We are in a release app bundle.
+    // Strip QT_PLUGINS_DIR because it will crash a launched release app bundle, since
+    // the appropriate Qt frameworks and plugins have been copied into the bundle.
+    if ( libPaths.removeAll( QT_PLUGINS_DIR ) )
+    {
+      QgsDebugMsgLevel( QString( "QT_PLUGINS_DIR removed from initial libraryPaths" ), 4 );
+    }
+    // Prepend the Plugins path, so copied-in Qt plugin bundle directories are parsed.
+    QgsDebugMsgLevel( QString( "Prepending <bundle>/Plugins to libraryPaths" ), 4 );
+    libPaths.prepend( relLibPath );
+
+    // TODO: see if this or another method can be used to avoid QCA's install prefix plugins
+    //       from being parsed and loaded (causes multi-Qt-loaded errors when bundled Qt should
+    //       be the only one loaded). QCA core (> v2.1.3) needs an update first.
+    //setenv( "QCA_PLUGIN_PATH", relLibPath.toUtf8().constData(), 1 );
+  }
+  else
+  {
+    // We are either running from build dir bundle, or launching Mach-O binary directly.
+    // Add system Qt plugins, since they are not bundled, and not always referenced by default.
+    // An app bundled with QGIS_MACAPP_BUNDLE = 0 will still have Plugins/qgis in it.
+    // Note: Don't always prepend.
+    //       User may have already defined it in QT_PLUGIN_PATH in a specific order.
+    if ( !libPaths.contains( QT_PLUGINS_DIR ) )
+    {
+      QgsDebugMsgLevel( QString( "Prepending QT_PLUGINS_DIR to libraryPaths" ), 4 );
+      libPaths.prepend( QT_PLUGINS_DIR );
+    }
+  }
+
+  QgsDebugMsgLevel( QString( "Prepending QgsApplication::pluginPath to libraryPaths" ), 4 );
+  libPaths.prepend( QDir::cleanPath( QgsApplication::pluginPath() ) );
+
+  // Redefine library search paths.
+  QCoreApplication::setLibraryPaths( libPaths );
+
+  QgsDebugMsgLevel( QString( "Rewritten macOS QCoreApplication::libraryPaths: %1" )
+                    .arg( QCoreApplication::libraryPaths().join( " " ) ), 4 );
+#endif
+
 #ifdef Q_OS_MAC
   // Set 1024x1024 icon for dock, app switcher, etc., rendering
   myApp.setWindowIcon( QIcon( QgsApplication::iconsPath() + QLatin1String( "qgis-icon-macos.png" ) ) );
@@ -1023,36 +1107,6 @@ int main( int argc, char *argv[] )
     }
   }
 
-  // For non static builds on mac and win (static builds are not supported)
-  // we need to be sure we can find the qt image
-  // plugins. In mac be sure to look in the
-  // application bundle...
-#ifdef Q_OS_WIN
-  QCoreApplication::addLibraryPath( QApplication::applicationDirPath()
-                                    + QDir::separator() + "qtplugins" );
-#endif
-#ifdef Q_OS_MACX
-  // IMPORTANT: do before Qt uses any plugins, e.g. before loading splash screen
-  QString  myPath( QCoreApplication::applicationDirPath().append( "/../PlugIns" ) );
-  // Check if it contains a standard Qt-specific plugin subdirectory
-  if ( !QFile::exists( myPath + "/imageformats" ) )
-  {
-    // We are either running from build dir bundle, or launching binary directly.
-    // Use system Qt plugins, since they are not bundled.
-    // An app bundled with QGIS_MACAPP_BUNDLE=0 will still have Plugins/qgis in it
-    myPath = QT_PLUGINS_DIR;
-  }
-
-  // First clear the plugin search paths so we can be sure only plugins we define
-  // are being used. Note: this strips QgsApplication::pluginPath()
-  QStringList myPathList;
-  QCoreApplication::setLibraryPaths( myPathList );
-
-  QgsDebugMsg( QString( "Adding Mac QGIS and Qt plugins dirs to search path: %1" ).arg( myPath ) );
-  QCoreApplication::addLibraryPath( QgsApplication::pluginPath() );
-  QCoreApplication::addLibraryPath( myPath );
-#endif
-
   // set authentication database directory
   if ( !authdbdirectory.isEmpty() )
   {
diff --git a/src/app/pluginmanager/qgspluginmanager.cpp b/src/app/pluginmanager/qgspluginmanager.cpp
index 1a610b0..7c710ba 100644
--- a/src/app/pluginmanager/qgspluginmanager.cpp
+++ b/src/app/pluginmanager/qgspluginmanager.cpp
@@ -499,7 +499,7 @@ void QgsPluginManager::reloadModelData()
       QString status = it->value( "status" );
       QString error = it->value( "error" );
 
-      QStandardItem * mypDetailItem = new QStandardItem( pluginName.left( 32 ) );
+      QStandardItem * mypDetailItem = new QStandardItem( pluginName );
 
       mypDetailItem->setData( baseName, PLUGIN_BASE_NAME_ROLE );
       mypDetailItem->setData( status, PLUGIN_STATUS_ROLE );
diff --git a/src/app/qgisapp.cpp b/src/app/qgisapp.cpp
index 97ba0e2..67f0d57 100644
--- a/src/app/qgisapp.cpp
+++ b/src/app/qgisapp.cpp
@@ -1190,6 +1190,8 @@ QgisApp::QgisApp()
   mLayerTreeView = new QgsLayerTreeView( this );
   mUndoWidget = new QgsUndoWidget( nullptr, mMapCanvas );
   mInfoBar = new QgsMessageBar( centralWidget() );
+  mPanelMenu = new QMenu( this );
+  mProgressBar = new QProgressBar( this );
   // More tests may need more members to be initialized
 }
 
@@ -3254,7 +3256,7 @@ void QgisApp::updateRecentProjectPaths()
 
   Q_FOREACH ( const QgsWelcomePageItemsModel::RecentProjectData& recentProject, mRecentProjects )
   {
-    QAction* action = mRecentProjectsMenu->addAction( QString( "%1 (%2)" ).arg( recentProject.title != recentProject.path ? recentProject.title : QFileInfo( recentProject.path ).baseName(), QDir::toNativeSeparators( recentProject.path ) ) );
+    QAction* action = mRecentProjectsMenu->addAction( QString( "%1 (%2)" ).arg( recentProject.title != recentProject.path ? recentProject.title : QFileInfo( recentProject.path ).completeBaseName(), QDir::toNativeSeparators( recentProject.path ) ) );
     action->setEnabled( QFile::exists(( recentProject.path ) ) );
     action->setData( recentProject.path );
   }
@@ -8271,17 +8273,13 @@ void QgisApp::layerSubsetString()
   // Set the sql in the query builder to the same in the prop dialog
   // (in case the user has already changed it)
   qb->setSql( vlayer->subsetString() );
-  // Open the query builder
-  if ( qb->exec() )
+  // Open the query builder and refresh symbology if sql has changed
+  // Note: repaintRequested is emitted directly from QgsQueryBuilder
+  //       when the sql is set in the layer.
+  if ( qb->exec() && ( subsetBefore != qb->sql() ) && mLayerTreeView )
   {
-    if ( subsetBefore != qb->sql() )
-    {
-      vlayer->triggerRepaint();
-      if ( mLayerTreeView )
-      {
-        mLayerTreeView->refreshLayerSymbology( vlayer->id() );
-      }
-    }
+    mLayerTreeView->refreshLayerSymbology( vlayer->id() );
+    activateDeactivateLayerRelatedActions( vlayer );
   }
 
   // delete the query builder object
@@ -10255,13 +10253,12 @@ void QgisApp::layersWereAdded( const QList<QgsMapLayer *>& theLayers )
       connect( vlayer, SIGNAL( labelingFontNotFound( QgsVectorLayer*, QString ) ), this, SLOT( labelingFontNotFound( QgsVectorLayer*, QString ) ) );
 
       QgsVectorDataProvider* vProvider = vlayer->dataProvider();
-      if ( vProvider && vProvider->capabilities() & QgsVectorDataProvider::EditingCapabilities )
-      {
-        connect( vlayer, SIGNAL( layerModified() ), this, SLOT( updateLayerModifiedActions() ) );
-        connect( vlayer, SIGNAL( editingStarted() ), this, SLOT( layerEditStateChanged() ) );
-        connect( vlayer, SIGNAL( editingStopped() ), this, SLOT( layerEditStateChanged() ) );
-      }
-
+      // Do not check for layer editing capabilities because they may change
+      // (for example when subsetString is added/removed) and signals need to
+      // be in place in order to update the GUI
+      connect( vlayer, SIGNAL( layerModified() ), this, SLOT( updateLayerModifiedActions() ) );
+      connect( vlayer, SIGNAL( editingStarted() ), this, SLOT( layerEditStateChanged() ) );
+      connect( vlayer, SIGNAL( editingStopped() ), this, SLOT( layerEditStateChanged() ) );
       connect( vlayer, SIGNAL( raiseError( QString ) ), this, SLOT( onLayerError( QString ) ) );
 
       provider = vProvider;
diff --git a/src/app/qgsapplayertreeviewmenuprovider.cpp b/src/app/qgsapplayertreeviewmenuprovider.cpp
index 20d37b6..e04e4b4 100644
--- a/src/app/qgsapplayertreeviewmenuprovider.cpp
+++ b/src/app/qgsapplayertreeviewmenuprovider.cpp
@@ -216,6 +216,7 @@ QMenu* QgsAppLayerTreeViewMenuProvider::createContextMenu()
           {
             menu->addAction( toggleEditingAction );
             toggleEditingAction->setChecked( vlayer->isEditable() );
+            toggleEditingAction->setEnabled( true );
           }
           if ( saveLayerEditsAction && vlayer->isModified() )
           {
diff --git a/src/app/qgsbookmarks.cpp b/src/app/qgsbookmarks.cpp
index 27b87c0..eaf6f81 100644
--- a/src/app/qgsbookmarks.cpp
+++ b/src/app/qgsbookmarks.cpp
@@ -17,38 +17,42 @@
 #include "qgisapp.h"
 #include "qgsapplication.h"
 #include "qgsbookmarks.h"
-#include "qgscontexthelp.h"
 #include "qgsmapcanvas.h"
-#include "qgsmaprenderer.h"
 #include "qgsproject.h"
 #include "qgsmessagelog.h"
-#include "qgscrscache.h"
-
 #include "qgslogger.h"
+#include "qgscrscache.h"
 
 #include <QFileDialog>
 #include <QFileInfo>
 #include <QMessageBox>
-#include <QSettings>
 #include <QSqlError>
 #include <QSqlQuery>
+#include <QSqlRecord>
 #include <QModelIndex>
+#include <QDoubleSpinBox>
 #include <QAbstractTableModel>
+#include <QToolButton>
 
 
+const int QgsDoubleSpinBoxBookmarksDelegate::DECIMAL_PLACES = 6;
+
 QgsBookmarks::QgsBookmarks( QWidget *parent )
     : QgsDockWidget( parent )
     , mQgisModel( nullptr )
     , mProjectModel( nullptr )
+    , mModel( nullptr )
+    , mProxyModel( nullptr )
 {
   setupUi( this );
+  connect( lstBookmarks, SIGNAL( doubleClicked( QModelIndex ) ), this, SLOT( lstBookmarks_doubleClicked( QModelIndex ) ) );
   restorePosition();
 
   bookmarksDockContents->layout()->setMargin( 0 );
   bookmarksDockContents->layout()->setContentsMargins( 0, 0, 0, 0 );
-  static_cast< QGridLayout* >( bookmarksDockContents->layout() )->setVerticalSpacing( 0 );
+  static_cast< QGridLayout * >( bookmarksDockContents->layout() )->setVerticalSpacing( 0 );
 
-  QToolButton* btnImpExp = new QToolButton;
+  QToolButton *btnImpExp = new QToolButton;
   btnImpExp->setAutoRaise( true );
   btnImpExp->setToolTip( tr( "Import/Export Bookmarks" ) );
   btnImpExp->setIcon( QgsApplication::getThemeIcon( "/mActionSharing.svg" ) );
@@ -59,20 +63,23 @@ QgsBookmarks::QgsBookmarks( QWidget *parent )
   QAction *btnImport = share->addAction( tr( "&Import" ) );
   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() ) );
   btnImpExp->setMenu( share );
 
+
   connect( actionAdd, SIGNAL( triggered() ), this, SLOT( addClicked() ) );
   connect( actionDelete, SIGNAL( triggered() ), this, SLOT( deleteClicked() ) );
   connect( actionZoomTo, SIGNAL( triggered() ), this, SLOT( zoomToBookmark() ) );
 
+
   mBookmarkToolbar->addWidget( btnImpExp );
 
   // open the database
   QSqlDatabase db = QSqlDatabase::addDatabase( "QSQLITE", "bookmarks" );
   db.setDatabaseName( QgsApplication::qgisUserDbFilePath() );
-  if ( !db.open() )
+  if ( ! db.open() )
   {
     QMessageBox::warning( this, tr( "Error" ),
                           tr( "Unable to open bookmarks database.\nDatabase: %1\nDriver: %2\nDatabase: %3" )
@@ -84,7 +91,8 @@ QgsBookmarks::QgsBookmarks( QWidget *parent )
     return;
   }
 
-  mQgisModel = new QSqlTableModel( this, db );
+  // Do not set parent or the destructor will try to write on the log viewer (and crash QGIS)
+  mQgisModel = new QSqlTableModel( nullptr, db );
   mQgisModel->setTable( "tbl_bookmarks" );
   mQgisModel->setSort( 0, Qt::AscendingOrder );
   mQgisModel->select();
@@ -100,13 +108,19 @@ QgsBookmarks::QgsBookmarks( QWidget *parent )
   mQgisModel->setHeaderData( 6, Qt::Horizontal, tr( "yMax" ) );
   mQgisModel->setHeaderData( 7, Qt::Horizontal, tr( "SRID" ) );
 
-  mProjectModel = new QgsProjectBookmarksTableModel();
-  mModel.reset( new QgsMergedBookmarksTableModel( *mQgisModel, *mProjectModel, lstBookmarks ) );
+  mProjectModel = new QgsProjectBookmarksTableModel( this );
+  mModel = new QgsMergedBookmarksTableModel( *mQgisModel, *mProjectModel, lstBookmarks, this );
+
+  mProxyModel = new QgsBookmarksProxyModel( this );
+  mProxyModel->setSourceModel( mModel );
+
+  lstBookmarks->setModel( mProxyModel );
+  lstBookmarks->setItemDelegate( new QgsDoubleSpinBoxBookmarksDelegate( this ) );
 
-  lstBookmarks->setModel( mModel.data() );
+  connect( mModel, SIGNAL( layoutChanged() ), mProxyModel, SLOT( _resetModel() ) );
 
   QSettings settings;
-  lstBookmarks->header()->restoreState( settings.value( "/Windows/Bookmarks/headerstate" ).toByteArray() );
+  lstBookmarks->header()->restoreState( settings.value( "Windows/Bookmarks/headerstate" ).toByteArray() );
 
 #ifndef QGISDEBUG
   lstBookmarks->setColumnHidden( 0, true );
@@ -116,7 +130,6 @@ QgsBookmarks::QgsBookmarks( QWidget *parent )
 QgsBookmarks::~QgsBookmarks()
 {
   delete mQgisModel;
-  delete mProjectModel;
   QSqlDatabase::removeDatabase( "bookmarks" );
   saveWindowLocation();
 }
@@ -124,14 +137,14 @@ QgsBookmarks::~QgsBookmarks()
 void QgsBookmarks::restorePosition()
 {
   QSettings settings;
-  restoreGeometry( settings.value( "/Windows/Bookmarks/geometry" ).toByteArray() );
+  restoreGeometry( settings.value( "Windows/Bookmarks/geometry" ).toByteArray() );
 }
 
 void QgsBookmarks::saveWindowLocation()
 {
   QSettings settings;
-  settings.setValue( "/Windows/Bookmarks/geometry", saveGeometry() );
-  settings.setValue( "/Windows/Bookmarks/headerstate", lstBookmarks->header()->saveState() );
+  settings.setValue( "Windows/Bookmarks/geometry" , saveGeometry() );
+  settings.setValue( "Windows/Bookmarks/headerstate" , lstBookmarks->header()->saveState() );
 }
 
 void QgsBookmarks::addClicked()
@@ -142,10 +155,6 @@ void QgsBookmarks::addClicked()
   QgsMapCanvas *canvas = QgisApp::instance()->mapCanvas();
   Q_ASSERT( canvas );
 
-  QSqlQuery query( "INSERT INTO tbl_bookmarks(bookmark_id,name,project_name,xmin,ymin,xmax,ymax,projection_srid)"
-                   "  VALUES (NULL,:name,:project_name,:xmin,:xmax,:ymin,:ymax,:projection_srid)",
-                   mQgisModel->database() );
-
   QString projStr( "" );
   if ( QgsProject::instance() )
   {
@@ -156,30 +165,34 @@ void QgsBookmarks::addClicked()
     else if ( !QgsProject::instance()->fileName().isEmpty() )
     {
       QFileInfo fi( QgsProject::instance()->fileName() );
-      projStr = fi.exists() ? fi.fileName() : "";
+      projStr = fi.exists() ? fi.fileName() : QLatin1String( "" );
     }
   }
 
-  query.bindValue( ":name", tr( "New bookmark" ) );
-  query.bindValue( ":project_name", projStr );
-  query.bindValue( ":xmin", canvas->extent().xMinimum() );
-  query.bindValue( ":ymin", canvas->extent().yMinimum() );
-  query.bindValue( ":xmax", canvas->extent().xMaximum() );
-  query.bindValue( ":ymax", canvas->extent().yMaximum() );
-  query.bindValue( ":projection_srid", QVariant::fromValue( canvas->mapSettings().destinationCrs().srsid() ) );
-  if ( query.exec() )
+  QSqlRecord record = mQgisModel->record();
+  record.setValue( 1, QVariant( tr( "New bookmark" ) ) );
+  record.setValue( 2, QVariant( projStr ) );
+  record.setValue( 3, QVariant( canvas->extent().xMinimum() ) );
+  record.setValue( 4, QVariant( canvas->extent().yMinimum() ) );
+  record.setValue( 5, QVariant( canvas->extent().xMaximum() ) );
+  record.setValue( 6, QVariant( canvas->extent().yMaximum() ) );
+  record.setValue( 7, QVariant::fromValue( canvas->mapSettings().destinationCrs().srsid() ) );
+
+  if ( mQgisModel->insertRecord( -1, record ) )
   {
     mQgisModel->setSort( 0, Qt::AscendingOrder );
     mQgisModel->select();
-    lstBookmarks->scrollTo( mModel->index( mQgisModel->rowCount() - 1, 1 ) );
-    lstBookmarks->setCurrentIndex( mModel->index( mQgisModel->rowCount() - 1, 1 ) );
-    lstBookmarks->edit( mModel->index( mQgisModel->rowCount() - 1, 1 ) );
+    QModelIndex newIdx = mProxyModel->mapFromSource( mModel->index( mQgisModel->rowCount() - 1, 1 ) );
+    // Edit new bookmark title
+    lstBookmarks->scrollTo( newIdx );
+    lstBookmarks->setCurrentIndex( newIdx );
+    lstBookmarks->edit( newIdx );
   }
   else
   {
-    QMessageBox::warning( this, tr( "Error" ), tr( "Unable to create the bookmark.\nDriver:%1\nDatabase:%2" )
-                          .arg( query.lastError().driverText(),
-                                query.lastError().databaseText() ) );
+    QMessageBox::warning( this, tr( "Error" ), tr( "Unable to create the bookmark.\nDriver: %1\nDatabase: %2" )
+                          .arg( mQgisModel->database().lastError().driverText(),
+                                mQgisModel->database().lastError().databaseText() ) );
   }
 }
 
@@ -198,7 +211,7 @@ void QgsBookmarks::deleteClicked()
     return;
 
   // make sure the user really wants to delete these bookmarks
-  if ( QMessageBox::Cancel == QMessageBox::information( this, tr( "Really Delete?" ),
+  if ( QMessageBox::Cancel == QMessageBox::information( this, tr( "Delete Bookmarks" ),
        tr( "Are you sure you want to delete %n bookmark(s)?", "number of rows", rows.size() ),
        QMessageBox::Ok | QMessageBox::Cancel ) )
     return;
@@ -211,7 +224,7 @@ void QgsBookmarks::deleteClicked()
   }
 }
 
-void QgsBookmarks::on_lstBookmarks_doubleClicked( const QModelIndex & index )
+void QgsBookmarks::lstBookmarks_doubleClicked( const QModelIndex &index )
 {
   Q_UNUSED( index );
   zoomToBookmark();
@@ -227,20 +240,19 @@ void QgsBookmarks::zoomToBookmark()
   double ymin = index.sibling( index.row(), 4 ).data().toDouble();
   double xmax = index.sibling( index.row(), 5 ).data().toDouble();
   double ymax = index.sibling( index.row(), 6 ).data().toDouble();
-  int srid = index.sibling( index.row(), 7 ).data().toInt();
+  QString authid = index.sibling( index.row(), 7 ).data().toString();
 
   QgsRectangle rect = QgsRectangle( xmin, ymin, xmax, ymax );
 
-  // backwards compatibility, older version had -1 in the srid column
-  if ( srid > 0 &&
-       srid != QgisApp::instance()->mapCanvas()->mapSettings().destinationCrs().srsid() )
+  if ( ! authid.isEmpty() &&
+       authid != QgisApp::instance()->mapCanvas()->mapSettings().destinationCrs().authid() )
   {
-    QgsCoordinateTransform ct( QgsCRSCache::instance()->crsBySrsId( srid ),
+    QgsCoordinateTransform ct( QgsCRSCache::instance()->crsByOgcWmsCrs( authid ),
                                QgisApp::instance()->mapCanvas()->mapSettings().destinationCrs() );
     rect = ct.transform( rect );
     if ( rect.isEmpty() )
     {
-      QMessageBox::warning( this, tr( "Empty extent" ), tr( "Reprojected extent is empty." ) );
+      QMessageBox::warning( this, tr( "Empty Extent" ), tr( "Reprojected extent is empty." ) );
       return;
     }
   }
@@ -250,11 +262,11 @@ void QgsBookmarks::zoomToBookmark()
   QgisApp::instance()->mapCanvas()->refresh();
 }
 
-void QgsBookmarks::importFromXML()
+void QgsBookmarks::importFromXml()
 {
   QSettings settings;
 
-  QString lastUsedDir = settings.value( "/Windows/Bookmarks/LastUsedDirectory", QDir::homePath() ).toString();
+  QString lastUsedDir = settings.value( "Windows/Bookmarks/LastUsedDirectory" , QDir::homePath() ).toString();
   QString fileName = QFileDialog::getOpenFileName( this, tr( "Import Bookmarks" ), lastUsedDir,
                      tr( "XML files (*.xml *XML)" ) );
   if ( fileName.isEmpty() )
@@ -282,14 +294,14 @@ void QgsBookmarks::importFromXML()
 
   QString queries;
 
-  for ( int i = 0;i < nodeList.count(); i++ )
+  for ( int i = 0; i < nodeList.count(); i++ )
   {
     QDomNode bookmark = nodeList.at( i );
     QDomElement name = bookmark.firstChildElement( "name" );
     QDomElement prjname = bookmark.firstChildElement( "project" );
     QDomElement xmin = bookmark.firstChildElement( "xmin" );
-    QDomElement xmax = bookmark.firstChildElement( "xmax" );
     QDomElement ymin = bookmark.firstChildElement( "ymin" );
+    QDomElement xmax = bookmark.firstChildElement( "xmax" );
     QDomElement ymax = bookmark.firstChildElement( "ymax" );
     QDomElement srid = bookmark.firstChildElement( "sr_id" );
 
@@ -307,7 +319,7 @@ void QgsBookmarks::importFromXML()
   QStringList queriesList = queries.split( ';' );
   QSqlQuery query( mQgisModel->database() );
 
-  Q_FOREACH ( const QString& queryTxt, queriesList )
+  Q_FOREACH ( const QString &queryTxt, queriesList )
   {
     if ( queryTxt.trimmed().isEmpty() )
     {
@@ -325,22 +337,22 @@ void QgsBookmarks::importFromXML()
   mQgisModel->select();
 }
 
-void QgsBookmarks::exportToXML()
+void QgsBookmarks::exportToXml()
 {
   QSettings settings;
 
-  QString lastUsedDir = settings.value( "/Windows/Bookmarks/LastUsedDirectory", QDir::homePath() ).toString();
-  QString fileName = QFileDialog::getSaveFileName( this, tr( "Export bookmarks" ), lastUsedDir,
-                     tr( "XML files( *.xml *.XML )" ) );
+  QString lastUsedDir = settings.value( "Windows/Bookmarks/LastUsedDirectory" , QDir::homePath() ).toString();
+  QString fileName = QFileDialog::getSaveFileName( this, tr( "Export Bookmarks" ), lastUsedDir,
+                     tr( "XML files (*.xml *.XML)" ) );
   if ( fileName.isEmpty() )
   {
     return;
   }
 
   // ensure the user never omitted the extension from the file name
-  if ( !fileName.endsWith( ".xml", Qt::CaseInsensitive ) )
+  if ( !fileName.endsWith( QLatin1String( ".xml" ), Qt::CaseInsensitive ) )
   {
-    fileName += ".xml";
+    fileName += QLatin1String( ".xml" );
   }
 
   QDomDocument doc( "qgis_bookmarks" );
@@ -351,7 +363,15 @@ void QgsBookmarks::exportToXML()
   int colCount = mModel->columnCount() - 1;  // exclude virtual "In project" column
 
   QList<QString> headerList;
-  headerList << "id" << "name" << "project" << "xmin" << "ymin" << "xmax" << "ymax" << "sr_id";
+  headerList
+  <<  "id"
+  <<  "name"
+  <<  "project"
+  <<  "xmin"
+  <<  "ymin"
+  <<  "xmax"
+  <<  "ymax"
+  <<  "sr_id";
 
   for ( int i = 0; i < rowCount; ++i )
   {
@@ -373,7 +393,7 @@ void QgsBookmarks::exportToXML()
   }
 
   QFile f( fileName );
-  if ( !f.open( QFile::WriteOnly ) )
+  if ( !f.open( QFile::WriteOnly | QIODevice::Truncate ) )
   {
     f.close();
     return;
@@ -384,30 +404,33 @@ void QgsBookmarks::exportToXML()
   doc.save( out, 2 );
   f.close();
 
-  settings.setValue( "/Windows/Bookmarks/LastUsedDirectory", QFileInfo( fileName ).path() );
+  settings.setValue( "Windows/Bookmarks/LastUsedDirectory", QFileInfo( fileName ).path() );
 }
 
-
-QgsProjectBookmarksTableModel::QgsProjectBookmarksTableModel()
+QgsProjectBookmarksTableModel::QgsProjectBookmarksTableModel( QObject *parent )
+    : QAbstractTableModel( parent )
 {
   QObject::connect(
     QgisApp::instance(), SIGNAL( projectRead() ),
     this, SLOT( projectRead() ) );
+  QObject::connect(
+    QgisApp::instance(), SIGNAL( newProject() ),
+    this, SLOT( projectRead() ) );
 }
 
-int QgsProjectBookmarksTableModel::rowCount( const QModelIndex& parent ) const
+int QgsProjectBookmarksTableModel::rowCount( const QModelIndex &parent ) const
 {
   Q_UNUSED( parent );
-
-  return QgsProject::instance()->readNumEntry( "Bookmarks", "/count" );
+  return QgsProject::instance()->readNumEntry( "Bookmarks" ,  "/count" );
 }
 
-int QgsProjectBookmarksTableModel::columnCount( const QModelIndex& parent ) const
+int QgsProjectBookmarksTableModel::columnCount( const QModelIndex &parent ) const
 {
   Q_UNUSED( parent );
-  return 7;
+  return 8;
 }
 
+
 QVariant QgsProjectBookmarksTableModel::data( const QModelIndex& index, int role ) const
 {
   Q_UNUSED( role );
@@ -467,111 +490,132 @@ bool QgsProjectBookmarksTableModel::setData( const QModelIndex& index, const QVa
   }
 }
 
-bool QgsProjectBookmarksTableModel::insertRows( int row, int count, const QModelIndex& parent )
+
+bool QgsProjectBookmarksTableModel::insertRows( int row, int count, const QModelIndex &parent )
 {
-  Q_UNUSED( row );
   Q_UNUSED( parent );
+  beginInsertRows( parent, row, row + count );
 
-  return QgsProject::instance()->writeEntry( "Bookmarks", "/count", QgsProject::instance()->readNumEntry( "Bookmarks", "/count" ) + count );
+  bool result = QgsProject::instance()->writeEntry( "Bookmarks" ,  "/count", QgsProject::instance()->readNumEntry( "Bookmarks",  "/count" ) + count );
+  endInsertRows();
+  return result;
 }
 
-bool QgsProjectBookmarksTableModel::removeRows( int row, int count, const QModelIndex& parent )
+bool QgsProjectBookmarksTableModel::removeRows( int row, int count, const QModelIndex &parent )
 {
   Q_UNUSED( parent );
-
+  beginRemoveRows( parent, row, row + count );
   for ( int newRow = row ; newRow < rowCount() - count ; newRow++ )
   {
-    for ( int column = 0 ; column < columnCount() ; column++ )
+    for ( int column = 0; column < columnCount() ; column++ )
     {
       setData( index( newRow, column ), data( index( newRow + count, column ) ) );
     }
   }
   for ( int newRow = rowCount() - count ; newRow < rowCount() ; newRow++ )
   {
-    QgsProject::instance()->removeEntry( "Bookmarks", QString( "/Row-%1" ).arg( newRow ) );
+    QgsProject::instance()->removeEntry( "Bookmarks" , QString( "/Row-%1" ).arg( newRow ) );
   }
 
-  QgsProject::instance()->writeEntry( "Bookmarks", "/count", QgsProject::instance()->readNumEntry( "Bookmarks", "/count" ) - count );
-
+  QgsProject::instance()->writeEntry( "Bookmarks" , QString( "/count" ), QgsProject::instance()->readNumEntry( "Bookmarks" ,  "/count" ) - count );
+  endRemoveRows();
   return true;
 }
 
-QgsMergedBookmarksTableModel::QgsMergedBookmarksTableModel( QAbstractTableModel& qgisTableModel, QAbstractTableModel& projectTableModel, QTreeView* treeView )
-    : mQgisTableModel( qgisTableModel )
+void QgsProjectBookmarksTableModel::projectRead()
+{
+  emit layoutChanged();
+}
+
+
+QgsMergedBookmarksTableModel::QgsMergedBookmarksTableModel( QAbstractTableModel &qgisTableModel, QAbstractTableModel &projectTableModel, QTreeView *treeView, QObject *parent )
+    : QAbstractTableModel( parent )
+    , mQgisTableModel( qgisTableModel )
     , mProjectTableModel( projectTableModel )
     , mTreeView( treeView )
-    , mProjectOpen( false )
 {
-  connect(
-    QgisApp::instance(), SIGNAL( projectRead() ),
-    this, SLOT( projectRead() ) );
 
   connect(
     &mQgisTableModel, SIGNAL( layoutChanged() ),
     this, SLOT( allLayoutChanged() ) );
-  connect(
-    &mQgisTableModel, SIGNAL( dataChanged( const QModelIndex&, const QModelIndex& ) ),
-    this, SLOT( qgisDataChanged( const QModelIndex&, const QModelIndex& ) ) );
+
   connect(
     &mQgisTableModel, SIGNAL( rowsInserted( const QModelIndex&, int, int ) ),
     this, SLOT( allLayoutChanged() ) );
+
   connect(
     &mQgisTableModel, SIGNAL( rowsRemoved( const QModelIndex&, int, int ) ),
     this, SLOT( allLayoutChanged() ) );
 
   connect(
-    &projectTableModel, SIGNAL( layoutChanged() ),
+    &mProjectTableModel, SIGNAL( layoutChanged() ),
+    this, SLOT( allLayoutChanged() ) );
+
+  connect(
+    &mProjectTableModel, SIGNAL( rowsInserted( const QModelIndex&, int, int ) ),
+    this, SLOT( allLayoutChanged() ) );
+
+  connect(
+    &mProjectTableModel, SIGNAL( rowsRemoved( const QModelIndex&, int, int ) ),
     this, SLOT( allLayoutChanged() ) );
+
 }
 
-int QgsMergedBookmarksTableModel::rowCount( const QModelIndex& parent ) const
+int QgsMergedBookmarksTableModel::rowCount( const QModelIndex &parent ) const
 {
   return mQgisTableModel.rowCount( parent ) + mProjectTableModel.rowCount( parent );
 }
 
-int QgsMergedBookmarksTableModel::columnCount( const QModelIndex& parent ) const
+int QgsMergedBookmarksTableModel::columnCount( const QModelIndex &parent ) const
 {
   return mQgisTableModel.columnCount( parent ) + 1;
 }
 
-QVariant QgsMergedBookmarksTableModel::data( const QModelIndex& index, int role ) const
+QVariant QgsMergedBookmarksTableModel::data( const QModelIndex &index, int role ) const
 {
-  // is project or application
-  if ( index.column() == mQgisTableModel.columnCount() )
+  QVariant value;
+  // Is it checkbox column?
+  if ( index.column() == mQgisTableModel.columnCount() && role == Qt::CheckStateRole )
   {
-    if ( role == Qt::CheckStateRole )
-    {
-      return index.row() < mQgisTableModel.rowCount() ? Qt::Unchecked : Qt::Checked;
-    }
-    else
-    {
-      return QVariant();
-    }
-  }
-  if ( index.row() < mQgisTableModel.rowCount() )
-  {
-    return mQgisTableModel.data( index, role );
+    value = index.row() < mQgisTableModel.rowCount() ? Qt::Unchecked : Qt::Checked;
   }
   else
   {
-    if ( role == Qt::DisplayRole || role == Qt::EditRole )
+    // Is it a SQLite stored entry ?
+    if ( index.row() < mQgisTableModel.rowCount() )
     {
-      return mProjectTableModel.data( this->index( index.row() - mQgisTableModel.rowCount(), index.column() ), role );
+      value = mQgisTableModel.data( index, role );
     }
-    else
+    else // ... it is a project stored bookmark
+    {
+      if ( role == Qt::DisplayRole || role == Qt::EditRole )
+      {
+        value = mProjectTableModel.data( this->index( index.row() - mQgisTableModel.rowCount(), index.column() ), role );
+      }
+      else // Default roles from base model
+      {
+        value = mQgisTableModel.data( this->index( 0, index.column() ), role );
+      }
+    }
+    // Is it the projection column ?
+    if (( role == Qt::DisplayRole || role == Qt::EditRole ) && index.column( ) == mQgisTableModel.columnCount() - 1 )
     {
-      return mQgisTableModel.data( this->index( 0, index.column() ), role );
+      QgsCoordinateReferenceSystem srs;
+      if ( srs.createFromSrsId( value.toInt( ) ) )
+        value = srs.authid( );
     }
   }
+  return value;
 }
 
-bool QgsMergedBookmarksTableModel::setData( const QModelIndex& index, const QVariant& value, int role )
+bool QgsMergedBookmarksTableModel::setData( const QModelIndex &index, const QVariant &value, int role )
 {
   // last column triggers a move from QGIS to project bookmark
   if ( index.column() == mQgisTableModel.columnCount() )
   {
     if ( index.row() < mQgisTableModel.rowCount() )
     {
+      // 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 ) );
@@ -579,6 +623,7 @@ bool QgsMergedBookmarksTableModel::setData( const QModelIndex& index, const QVar
     }
     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 ) );
@@ -597,14 +642,12 @@ bool QgsMergedBookmarksTableModel::setData( const QModelIndex& index, const QVar
   }
 }
 
-Qt::ItemFlags QgsMergedBookmarksTableModel::flags( const QModelIndex& index ) const
+Qt::ItemFlags QgsMergedBookmarksTableModel::flags( const QModelIndex &index ) const
 {
-  Q_UNUSED( index );
-
   Qt::ItemFlags flags = Qt::ItemIsSelectable | Qt::ItemIsEnabled;
   if ( index.column() == mQgisTableModel.columnCount() )
   {
-    if ( !mProjectOpen )
+    if ( !projectAvailable() )
     {
       return Qt::ItemIsSelectable;
     }
@@ -612,23 +655,31 @@ Qt::ItemFlags QgsMergedBookmarksTableModel::flags( const QModelIndex& index ) co
   }
   else
   {
-    flags |= Qt::ItemIsEditable;
+    // Skip projection: not editable!
+    if ( index.column() != mQgisTableModel.columnCount() - 1 )
+      flags |= Qt::ItemIsEditable;
   }
   return flags;
 }
 
-bool QgsMergedBookmarksTableModel::removeRows( int row, int count, const QModelIndex& parent )
+bool QgsMergedBookmarksTableModel::removeRows( int row, int count, const QModelIndex &parent )
 {
   Q_ASSERT( count == 1 );
-
+  bool result;
+  beginRemoveRows( parent, row, row + count );
   if ( row < mQgisTableModel.rowCount() )
   {
-    return mQgisTableModel.removeRows( row, count, parent );
+    QSqlTableModel *qgisModel = static_cast<QSqlTableModel *>( &mQgisTableModel );
+    Q_ASSERT( qgisModel );
+    result = qgisModel->removeRows( row, count, parent );
+    qgisModel->select();
   }
   else
   {
-    return mProjectTableModel.removeRows( row - mQgisTableModel.rowCount(), count, parent );
+    result = mProjectTableModel.removeRows( row - mQgisTableModel.rowCount(), count, parent );
   }
+  endRemoveRows();
+  return result;
 }
 
 QVariant QgsMergedBookmarksTableModel::headerData( int section, Qt::Orientation orientation, int role ) const
@@ -650,47 +701,95 @@ QVariant QgsMergedBookmarksTableModel::headerData( int section, Qt::Orientation
   }
 }
 
-QAbstractTableModel* QgsMergedBookmarksTableModel::qgisModel()
+QAbstractTableModel *QgsMergedBookmarksTableModel::qgisModel()
 {
   return &mQgisTableModel;
 }
 
-void QgsMergedBookmarksTableModel::moveBookmark( QAbstractTableModel& modelFrom, QAbstractTableModel& modelTo, int row )
+bool QgsMergedBookmarksTableModel::projectAvailable() const
 {
-  QSqlTableModel* qgisModel = dynamic_cast<QSqlTableModel*>( &modelTo );
-  if ( qgisModel == NULL )
+  return ! QgsProject::instance()->fileName().isEmpty();
+}
+
+void QgsMergedBookmarksTableModel::moveBookmark( QAbstractTableModel &modelFrom, QAbstractTableModel &modelTo, int row )
+{
+  emit beginResetModel();
+  QSqlTableModel *qgisModel = dynamic_cast<QSqlTableModel *>( &modelTo );
+  if ( !qgisModel )
   {
     modelTo.insertRow( -1 );
     for ( int column = 1 ; column < modelFrom.columnCount() ; column++ )
     {
+      Q_ASSERT( modelTo.index( modelTo.rowCount() - 1, column ).isValid( ) );
       modelTo.setData(
         modelTo.index( modelTo.rowCount() - 1, column ),
         modelFrom.data( modelFrom.index( row, column ) ) );
     }
+    qgisModel = dynamic_cast<QSqlTableModel *>( &modelFrom );
+    Q_ASSERT( qgisModel );
+    qgisModel->removeRows( row, 1 );
+    qgisModel->select();
   }
   else
   {
-    QSqlQuery query( "INSERT INTO tbl_bookmarks(bookmark_id,name,project_name,xmin,ymin,xmax,ymax,projection_srid)"
-                     "  VALUES (NULL,:name,:project_name,:xmin,:xmax,:ymin,:ymax,:projection_srid)",
-                     qgisModel->database() );
+    QSqlRecord record = qgisModel->record();
+    record.setValue( 1, modelFrom.data( modelFrom.index( row, 1 ) ).toString() );
+    record.setValue( 2, modelFrom.data( modelFrom.index( row, 2 ) ).toString() );
+    record.setValue( 3, modelFrom.data( modelFrom.index( row, 3 ) ).toDouble() );
+    record.setValue( 4, modelFrom.data( modelFrom.index( row, 4 ) ).toDouble() );
+    record.setValue( 5, modelFrom.data( modelFrom.index( row, 5 ) ).toDouble() );
+    record.setValue( 6, modelFrom.data( modelFrom.index( row, 6 ) ).toDouble() );
+    record.setValue( 7, modelFrom.data( modelFrom.index( row, 7 ) ).toInt() );
 
-    query.bindValue( ":name", modelFrom.data( modelFrom.index( row, 1 ) ).value<QString>() );
-    query.bindValue( ":project_name", modelFrom.data( modelFrom.index( row, 2 ) ).value<QString>() );
-    query.bindValue( ":xmin", modelFrom.data( modelFrom.index( row, 3 ) ).toDouble() );
-    query.bindValue( ":ymin", modelFrom.data( modelFrom.index( row, 4 ) ).toDouble() );
-    query.bindValue( ":xmax", modelFrom.data( modelFrom.index( row, 5 ) ).toDouble() );
-    query.bindValue( ":ymax", modelFrom.data( modelFrom.index( row, 6 ) ).toDouble() );
-    query.bindValue( ":projection_srid", modelFrom.data( modelFrom.index( row, 7 ) ).toInt() );
-
-    if ( !query.exec() )
+    if ( ! qgisModel->insertRecord( -1, record ) )
     {
       QgsDebugMsg( QString( "Could not move bookmark: %1" )
-                   .arg( query.lastError().text() ) );
+                   .arg( qgisModel->database().lastError().text() ) );
       return;
     }
     qgisModel->setSort( 0, Qt::AscendingOrder );
     qgisModel->select();
+    modelFrom.removeRows( row, 1 );
   }
+  emit endResetModel();
+  emit layoutChanged();
+}
 
-  modelFrom.removeRow( row );
+
+QgsBookmarksProxyModel::QgsBookmarksProxyModel( QObject *parent ):
+    QSortFilterProxyModel( parent )
+{
+
+}
+
+QVariant QgsBookmarksProxyModel::headerData( int section, Qt::Orientation orientation, int role ) const
+{
+  return sourceModel()->headerData( section, orientation, role );
+}
+
+QgsDoubleSpinBoxBookmarksDelegate::QgsDoubleSpinBoxBookmarksDelegate( QObject *parent )
+    : QStyledItemDelegate( parent )
+{
+
+}
+
+QString QgsDoubleSpinBoxBookmarksDelegate::displayText( const QVariant &value, const QLocale &locale ) const
+{
+  if ( value.userType() == QVariant::Double )
+  {
+    return locale.toString( value.toDouble(), 'f', QgsDoubleSpinBoxBookmarksDelegate::DECIMAL_PLACES );
+  }
+  else
+  {
+    return QStyledItemDelegate::displayText( value, locale );
+  }
+}
+
+QWidget *QgsDoubleSpinBoxBookmarksDelegate::createEditor( QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index ) const
+{
+  QWidget *widget = QStyledItemDelegate::createEditor( parent, option, index );
+  QDoubleSpinBox *spinbox = qobject_cast<QDoubleSpinBox *>( widget );
+  if ( spinbox )
+    spinbox->setDecimals( QgsDoubleSpinBoxBookmarksDelegate::DECIMAL_PLACES );
+  return widget;
 }
diff --git a/src/app/qgsbookmarks.h b/src/app/qgsbookmarks.h
index ca1f235..ca2b6b9 100644
--- a/src/app/qgsbookmarks.h
+++ b/src/app/qgsbookmarks.h
@@ -18,7 +18,8 @@
 #define QGSBOOKMARKS_H
 
 #include <QSqlTableModel>
-#include <QScopedPointer>
+#include <QSortFilterProxyModel>
+#include <QStyledItemDelegate>
 
 #include "ui_qgsbookmarksbase.h"
 #include "qgscontexthelp.h"
@@ -33,7 +34,7 @@ class QgsProjectBookmarksTableModel: public QAbstractTableModel
 
   public:
 
-    QgsProjectBookmarksTableModel();
+    QgsProjectBookmarksTableModel( QObject *parent = 0 );
 
     int rowCount( const QModelIndex& parent = QModelIndex() ) const override;
 
@@ -48,7 +49,28 @@ class QgsProjectBookmarksTableModel: public QAbstractTableModel
     bool removeRows( int row, int count, const QModelIndex& parent = QModelIndex() ) override;
 
   private slots:
-    void projectRead() { emit layoutChanged(); };
+
+    void projectRead();
+};
+
+
+class QgsBookmarksProxyModel: public QSortFilterProxyModel
+{
+    Q_OBJECT
+
+  public:
+
+    QgsBookmarksProxyModel( QObject *parent = 0 );
+
+    //! This override is required because the merge model only defines headers for the SQL model
+    QVariant headerData( int section, Qt::Orientation orientation, int role = Qt::DisplayRole ) const override;
+
+  public slots:
+
+    void _resetModel()
+    {
+      reset();
+    }
 };
 
 /*
@@ -60,7 +82,7 @@ class QgsMergedBookmarksTableModel: public QAbstractTableModel
 
   public:
 
-    QgsMergedBookmarksTableModel( QAbstractTableModel& qgisTableModel, QAbstractTableModel& projectTableModel, QTreeView* treeView );
+    QgsMergedBookmarksTableModel( QAbstractTableModel &qgisTableModel, QAbstractTableModel &projectTableModel, QTreeView *treeView, QObject *parent = 0 );
 
     int rowCount( const QModelIndex& parent = QModelIndex() ) const override;
 
@@ -79,25 +101,40 @@ class QgsMergedBookmarksTableModel: public QAbstractTableModel
     QAbstractTableModel& mQgisTableModel;
     QAbstractTableModel& mProjectTableModel;
     QTreeView* mTreeView;
-    bool mProjectOpen;
 
+    bool projectAvailable() const;
     void moveBookmark( QAbstractTableModel& modelFrom, QAbstractTableModel& modelTo, int row );
 
   private slots:
-    void projectRead() { mProjectOpen = true; };
-    void allLayoutChanged() { emit layoutChanged(); };
-    void qgisDataChanged( const QModelIndex& topLeft, const QModelIndex& bottomRight )
+    void allLayoutChanged()
     {
-      emit dataChanged( topLeft, bottomRight );
-    };
-    void projectDataChanged( const QModelIndex& topLeft, const QModelIndex& bottomRight )
-    {
-      emit dataChanged(
-        index( topLeft.row() + mQgisTableModel.rowCount(), topLeft.column() ),
-        index( bottomRight.row() + mQgisTableModel.rowCount(), bottomRight.column() ) );
+      emit layoutChanged();
     };
 };
 
+/**
+ * \brief QgsDoubleSpinBoxBookmarksDelegate class shows 6 digits when value is a double
+ */
+class QgsDoubleSpinBoxBookmarksDelegate : public QStyledItemDelegate
+{
+    Q_OBJECT
+
+  public:
+
+    explicit QgsDoubleSpinBoxBookmarksDelegate( QObject *parent = nullptr );
+
+    QString displayText( const QVariant &value, const QLocale &locale ) const override;
+
+    QWidget *createEditor( QWidget *parent,
+                           const QStyleOptionViewItem &option,
+                           const QModelIndex &index ) const override;
+  private:
+
+    static const int  DECIMAL_PLACES;
+
+};
+
+
 
 class APP_EXPORT QgsBookmarks : public QgsDockWidget, private Ui::QgsBookmarksBase
 {
@@ -113,15 +150,16 @@ class APP_EXPORT QgsBookmarks : public QgsDockWidget, private Ui::QgsBookmarksBa
   private slots:
     void deleteClicked();
     void zoomToBookmark();
-    void exportToXML();
-    void importFromXML();
+    void exportToXml();
+    void importFromXml();
 
-    void on_lstBookmarks_doubleClicked( const QModelIndex & );
+    void lstBookmarks_doubleClicked( const QModelIndex & );
 
   private:
-    QSqlTableModel* mQgisModel;
-    QgsProjectBookmarksTableModel* mProjectModel;
-    QScopedPointer<QgsMergedBookmarksTableModel> mModel;
+    QSqlTableModel *mQgisModel;
+    QgsProjectBookmarksTableModel *mProjectModel;
+    QgsMergedBookmarksTableModel *mModel;
+    QgsBookmarksProxyModel *mProxyModel;
 
     void saveWindowLocation();
     void restorePosition();
diff --git a/src/app/qgsfieldsproperties.cpp b/src/app/qgsfieldsproperties.cpp
index c737fbf..97483b7 100644
--- a/src/app/qgsfieldsproperties.cpp
+++ b/src/app/qgsfieldsproperties.cpp
@@ -776,15 +776,17 @@ void QgsFieldsProperties::attributesListCellChanged( int row, int column )
   }
   else if ( column == attrNameCol && mLayer && mLayer->isEditable() )
   {
+    int idx = mIndexedWidgets.indexOf( mFieldsList->item( row, attrIdCol ) );
+
     QTableWidgetItem *nameItem = mFieldsList->item( row, column );
     if ( !nameItem ||
          nameItem->text().isEmpty() ||
-         !mLayer->fields().exists( row ) ||
-         mLayer->fields().at( row ).name() == nameItem->text() )
+         !mLayer->fields().exists( idx ) ||
+         mLayer->fields().at( idx ).name() == nameItem->text() )
       return;
 
     mLayer->beginEditCommand( tr( "Rename attribute" ) );
-    if ( mLayer->renameAttribute( row,  nameItem->text() ) )
+    if ( mLayer->renameAttribute( idx,  nameItem->text() ) )
     {
       mLayer->endEditCommand();
     }
diff --git a/src/app/qgsidentifyresultsdialog.cpp b/src/app/qgsidentifyresultsdialog.cpp
index 4aab4d1..38cc1d2 100644
--- a/src/app/qgsidentifyresultsdialog.cpp
+++ b/src/app/qgsidentifyresultsdialog.cpp
@@ -1237,7 +1237,7 @@ void QgsIdentifyResultsDialog::doAction( QTreeWidgetItem *item, int action )
   }
 
   int featIdx = featItem->data( 0, Qt::UserRole + 1 ).toInt();
-  layer->actions()->doAction( action, mFeatures[ featIdx ], idx );
+  layer->actions()->doAction( action, mFeatures[ featIdx ], idx, mExpressionContextScope );
 }
 
 void QgsIdentifyResultsDialog::doMapLayerAction( QTreeWidgetItem *item, QgsMapLayerAction* action )
@@ -1951,6 +1951,16 @@ void QgsIdentifyResultsDialog::formatChanged( int index )
   }
 }
 
+void QgsIdentifyResultsDialog::setExpressionContextScope( const QgsExpressionContextScope &scope )
+{
+  mExpressionContextScope = scope;
+}
+
+QgsExpressionContextScope QgsIdentifyResultsDialog::expressionContextScope() const
+{
+  return mExpressionContextScope;
+}
+
 /*
  * QgsIdentifyResultsDialogMapLayerAction
  */
diff --git a/src/app/qgsidentifyresultsdialog.h b/src/app/qgsidentifyresultsdialog.h
index 4037389..fa8d593 100644
--- a/src/app/qgsidentifyresultsdialog.h
+++ b/src/app/qgsidentifyresultsdialog.h
@@ -152,6 +152,22 @@ class APP_EXPORT QgsIdentifyResultsDialog: public QDialog, private Ui::QgsIdenti
     /** Map tool was activated */
     void activate();
 
+    /**
+     * Sets an expression context scope to consider for resolving underlying
+     * actions.
+     *
+     * @note Added in QGIS 2.18
+     */
+    void setExpressionContextScope( const QgsExpressionContextScope &scope );
+
+    /**
+     * Returns an expression context scope used for resolving underlying
+     * actions.
+     *
+     * @note Added in QGIS 2.18
+     */
+    QgsExpressionContextScope expressionContextScope() const;
+
   signals:
     void selectedFeatureChanged( QgsVectorLayer *, QgsFeatureId featureId );
 
@@ -263,6 +279,8 @@ class APP_EXPORT QgsIdentifyResultsDialog: public QDialog, private Ui::QgsIdenti
     QgsDockWidget *mDock;
 
     QVector<QgsIdentifyPlotCurve *> mPlotCurves;
+
+    QgsExpressionContextScope mExpressionContextScope;
 };
 
 class QgsIdentifyResultsDialogMapLayerAction : public QAction
diff --git a/src/app/qgsmaptoolidentifyaction.cpp b/src/app/qgsmaptoolidentifyaction.cpp
index 766ed3e..1c7f016 100644
--- a/src/app/qgsmaptoolidentifyaction.cpp
+++ b/src/app/qgsmaptoolidentifyaction.cpp
@@ -118,6 +118,8 @@ void QgsMapToolIdentifyAction::canvasReleaseEvent( QgsMapMouseEvent* e )
   connect( this, SIGNAL( identifyProgress( int, int ) ), QgisApp::instance(), SLOT( showProgress( int, int ) ) );
   connect( this, SIGNAL( identifyMessage( QString ) ), QgisApp::instance(), SLOT( showStatusMessage( QString ) ) );
 
+  setClickContextScope( toMapCoordinates( e->pos() ) );
+
   identifyMenu()->setResultsIfExternalAction( false );
 
   // enable the right click for extended menu so it behaves as a contextual menu
@@ -200,4 +202,16 @@ void QgsMapToolIdentifyAction::handleCopyToClipboard( QgsFeatureStore & featureS
   emit copyToClipboard( featureStore );
 }
 
+void QgsMapToolIdentifyAction::setClickContextScope( const QgsPoint &point )
+{
+  QgsExpressionContextScope clickScope;
+  clickScope.addVariable( QgsExpressionContextScope::StaticVariable( QString( "click_x" ), point.x(), true ) );
+  clickScope.addVariable( QgsExpressionContextScope::StaticVariable( QString( "click_y" ), point.y(), true ) );
+
+  resultsDialog()->setExpressionContextScope( clickScope );
 
+  if ( mIdentifyMenu )
+  {
+    mIdentifyMenu->setExpressionContextScope( clickScope );
+  }
+}
diff --git a/src/app/qgsmaptoolidentifyaction.h b/src/app/qgsmaptoolidentifyaction.h
index fcff3c8..54053cc 100644
--- a/src/app/qgsmaptoolidentifyaction.h
+++ b/src/app/qgsmaptoolidentifyaction.h
@@ -82,7 +82,9 @@ class APP_EXPORT QgsMapToolIdentifyAction : public QgsMapToolIdentify
 
     virtual QGis::UnitType displayDistanceUnits() const override;
     virtual QgsUnitTypes::AreaUnit displayAreaUnits() const override;
+    void setClickContextScope( const QgsPoint &point );
 
+    friend class TestQgsMapToolIdentifyAction;
 };
 
 #endif
diff --git a/src/app/qgsrelationmanagerdialog.cpp b/src/app/qgsrelationmanagerdialog.cpp
index 938ea41..3bf16d6 100644
--- a/src/app/qgsrelationmanagerdialog.cpp
+++ b/src/app/qgsrelationmanagerdialog.cpp
@@ -92,9 +92,9 @@ void QgsRelationManagerDialog::on_mBtnAddRelation_clicked()
     QString relationId = addDlg.relationId();
     if ( addDlg.relationId() == "" )
       relationId = QString( "%1_%2_%3_%4" )
-                   .arg( addDlg.referencingLayerId(),
+                   .arg( addDlg.referencingLayerId().left( 10 ),
                          addDlg.references().at( 0 ).first,
-                         addDlg.referencedLayerId(),
+                         addDlg.referencedLayerId().left( 10 ),
                          addDlg.references().at( 0 ).second );
 
     QStringList existingNames;
diff --git a/src/auth/basic/qgsauthbasicmethod.cpp b/src/auth/basic/qgsauthbasicmethod.cpp
index 404c2a3..113c187 100644
--- a/src/auth/basic/qgsauthbasicmethod.cpp
+++ b/src/auth/basic/qgsauthbasicmethod.cpp
@@ -22,6 +22,7 @@
 
 #include <QNetworkProxy>
 #include <QMutexLocker>
+#include <QUuid>
 
 static const QString AUTH_METHOD_KEY = "Basic";
 static const QString AUTH_METHOD_DESCRIPTION = "Basic authentication";
@@ -126,6 +127,26 @@ bool QgsAuthBasicMethod::updateDataSourceUriItems( QStringList &connectionItems,
     connectionItems.append( passparam );
   }
 
+  // add extra CAs
+  // save CAs to temp file
+  QString tempFileBase = QLatin1String( "tmp_basic_%1.pem" );
+  QString caFilePath = QgsAuthCertUtils::pemTextToTempFile(
+                         tempFileBase.arg( QUuid::createUuid().toString() ),
+                         QgsAuthManager::instance()->getTrustedCaCertsPemText( ) );
+  if ( ! caFilePath.isEmpty() )
+  {
+    QString caparam = "sslrootcert='" + caFilePath + "'";
+    int sslcaindx = connectionItems.indexOf( QRegExp( "^sslrootcert='.*" ) );
+    if ( sslcaindx != -1 )
+    {
+      connectionItems.replace( sslcaindx, caparam );
+    }
+    else
+    {
+      connectionItems.append( caparam );
+    }
+  }
+
   return true;
 }
 
diff --git a/src/core/auth/qgsauthmanager.cpp b/src/core/auth/qgsauthmanager.cpp
index 7ee1cb3..669ec0a 100644
--- a/src/core/auth/qgsauthmanager.cpp
+++ b/src/core/auth/qgsauthmanager.cpp
@@ -319,6 +319,7 @@ bool QgsAuthManager::createConfigTables()
 
 bool QgsAuthManager::createCertTables()
 {
+  QMutexLocker locker( mMutex );
   // NOTE: these tables were added later, so IF NOT EXISTS is used
   QgsDebugMsg( "Creating cert tables in auth db" );
 
@@ -825,6 +826,7 @@ bool QgsAuthManager::hasConfigId( const QString &txt ) const
 
 QgsAuthMethodConfigsMap QgsAuthManager::availableAuthMethodConfigs( const QString &dataprovider )
 {
+  QMutexLocker locker( mMutex );
   QStringList providerAuthMethodsKeys;
   if ( !dataprovider.isEmpty() )
   {
@@ -869,6 +871,7 @@ QgsAuthMethodConfigsMap QgsAuthManager::availableAuthMethodConfigs( const QStrin
 
 void QgsAuthManager::updateConfigAuthMethods()
 {
+  QMutexLocker locker( mMutex );
   if ( isDisabled() )
     return;
 
@@ -978,6 +981,7 @@ QgsAuthMethod::Expansions QgsAuthManager::supportedAuthMethodExpansions( const Q
 
 bool QgsAuthManager::storeAuthenticationConfig( QgsAuthMethodConfig &mconfig )
 {
+  QMutexLocker locker( mMutex );
   if ( !setMasterPassword( true ) )
     return false;
 
@@ -1054,6 +1058,7 @@ bool QgsAuthManager::storeAuthenticationConfig( QgsAuthMethodConfig &mconfig )
 
 bool QgsAuthManager::updateAuthenticationConfig( const QgsAuthMethodConfig &config )
 {
+  QMutexLocker locker( mMutex );
   if ( !setMasterPassword( true ) )
     return false;
 
@@ -1124,6 +1129,7 @@ bool QgsAuthManager::updateAuthenticationConfig( const QgsAuthMethodConfig &conf
 
 bool QgsAuthManager::loadAuthenticationConfig( const QString &authcfg, QgsAuthMethodConfig &mconfig, bool full )
 {
+  QMutexLocker locker( mMutex );
   if ( isDisabled() )
     return false;
 
@@ -1190,6 +1196,7 @@ bool QgsAuthManager::loadAuthenticationConfig( const QString &authcfg, QgsAuthMe
 
 bool QgsAuthManager::removeAuthenticationConfig( const QString& authcfg )
 {
+  QMutexLocker locker( mMutex );
   if ( isDisabled() )
     return false;
 
@@ -1222,6 +1229,7 @@ bool QgsAuthManager::removeAuthenticationConfig( const QString& authcfg )
 
 bool QgsAuthManager::removeAllAuthenticationConfigs()
 {
+  QMutexLocker locker( mMutex );
   if ( isDisabled() )
     return false;
 
@@ -1242,6 +1250,7 @@ bool QgsAuthManager::removeAllAuthenticationConfigs()
 
 bool QgsAuthManager::backupAuthenticationDatabase( QString *backuppath )
 {
+  QMutexLocker locker( mMutex );
   if ( !QFile::exists( authenticationDbPath() ) )
   {
     const char* err = QT_TR_NOOP( "No authentication database found" );
@@ -1277,6 +1286,7 @@ bool QgsAuthManager::backupAuthenticationDatabase( QString *backuppath )
 
 bool QgsAuthManager::eraseAuthenticationDatabase( bool backup, QString *backuppath )
 {
+  QMutexLocker locker( mMutex );
   if ( isDisabled() )
     return false;
 
@@ -1474,6 +1484,7 @@ bool QgsAuthManager::storeAuthSetting( const QString &key, const QVariant& value
 
 QVariant QgsAuthManager::getAuthSetting( const QString &key, const QVariant& defaultValue, bool decrypt )
 {
+  QMutexLocker locker( mMutex );
   if ( key.isEmpty() )
     return QVariant();
 
@@ -1516,6 +1527,7 @@ QVariant QgsAuthManager::getAuthSetting( const QString &key, const QVariant& def
 
 bool QgsAuthManager::existsAuthSetting( const QString& key )
 {
+  QMutexLocker locker( mMutex );
   if ( key.isEmpty() )
     return false;
 
@@ -1548,6 +1560,7 @@ bool QgsAuthManager::existsAuthSetting( const QString& key )
 
 bool QgsAuthManager::removeAuthSetting( const QString& key )
 {
+  QMutexLocker locker( mMutex );
   if ( key.isEmpty() )
     return false;
 
@@ -1578,6 +1591,7 @@ bool QgsAuthManager::removeAuthSetting( const QString& key )
 
 bool QgsAuthManager::initSslCaches()
 {
+  QMutexLocker locker( mMutex );
   bool res = true;
   res = res && rebuildCaCertsCache();
   res = res && rebuildCertTrustCache();
@@ -1590,6 +1604,7 @@ bool QgsAuthManager::initSslCaches()
 
 bool QgsAuthManager::storeCertIdentity( const QSslCertificate &cert, const QSslKey &key )
 {
+  QMutexLocker locker( mMutex );
   if ( cert.isNull() )
   {
     QgsDebugMsg( "Passed certificate is null" );
@@ -1633,6 +1648,7 @@ bool QgsAuthManager::storeCertIdentity( const QSslCertificate &cert, const QSslK
 
 const QSslCertificate QgsAuthManager::getCertIdentity( const QString &id )
 {
+  QMutexLocker locker( mMutex );
   QSslCertificate emptycert;
   QSslCertificate cert;
   if ( id.isEmpty() )
@@ -1666,6 +1682,7 @@ const QSslCertificate QgsAuthManager::getCertIdentity( const QString &id )
 
 const QPair<QSslCertificate, QSslKey> QgsAuthManager::getCertIdentityBundle( const QString &id )
 {
+  QMutexLocker locker( mMutex );
   QPair<QSslCertificate, QSslKey> bundle;
   if ( id.isEmpty() )
     return bundle;
@@ -1720,6 +1737,7 @@ const QPair<QSslCertificate, QSslKey> QgsAuthManager::getCertIdentityBundle( con
 
 const QStringList QgsAuthManager::getCertIdentityBundleToPem( const QString &id )
 {
+  QMutexLocker locker( mMutex );
   QPair<QSslCertificate, QSslKey> bundle( getCertIdentityBundle( id ) );
   if ( bundle.first.isValid() && !bundle.second.isNull() )
   {
@@ -1730,6 +1748,7 @@ const QStringList QgsAuthManager::getCertIdentityBundleToPem( const QString &id
 
 const QList<QSslCertificate> QgsAuthManager::getCertIdentities()
 {
+  QMutexLocker locker( mMutex );
   QList<QSslCertificate> certs;
 
   QSqlQuery query( authDbConnection() );
@@ -1751,6 +1770,7 @@ const QList<QSslCertificate> QgsAuthManager::getCertIdentities()
 
 QStringList QgsAuthManager::getCertIdentityIds() const
 {
+  QMutexLocker locker( mMutex );
   QStringList identityids = QStringList();
 
   if ( isDisabled() )
@@ -1776,6 +1796,7 @@ QStringList QgsAuthManager::getCertIdentityIds() const
 
 bool QgsAuthManager::existsCertIdentity( const QString &id )
 {
+  QMutexLocker locker( mMutex );
   if ( id.isEmpty() )
     return false;
 
@@ -1808,6 +1829,7 @@ bool QgsAuthManager::existsCertIdentity( const QString &id )
 
 bool QgsAuthManager::removeCertIdentity( const QString &id )
 {
+  QMutexLocker locker( mMutex );
   if ( id.isEmpty() )
   {
     QgsDebugMsg( "Passed bundle ID is empty" );
@@ -1835,6 +1857,7 @@ bool QgsAuthManager::removeCertIdentity( const QString &id )
 
 bool QgsAuthManager::storeSslCertCustomConfig( const QgsAuthConfigSslServer &config )
 {
+  QMutexLocker locker( mMutex );
   if ( config.isNull() )
   {
     QgsDebugMsg( "Passed config is null" );
@@ -1876,6 +1899,7 @@ bool QgsAuthManager::storeSslCertCustomConfig( const QgsAuthConfigSslServer &con
 
 const QgsAuthConfigSslServer QgsAuthManager::getSslCertCustomConfig( const QString &id, const QString &hostport )
 {
+  QMutexLocker locker( mMutex );
   QgsAuthConfigSslServer config;
 
   if ( id.isEmpty() || hostport.isEmpty() )
@@ -1917,6 +1941,7 @@ const QgsAuthConfigSslServer QgsAuthManager::getSslCertCustomConfig( const QStri
 
 const QgsAuthConfigSslServer QgsAuthManager::getSslCertCustomConfigByHost( const QString &hostport )
 {
+  QMutexLocker locker( mMutex );
   QgsAuthConfigSslServer config;
 
   if ( hostport.isEmpty() )
@@ -1957,6 +1982,7 @@ const QgsAuthConfigSslServer QgsAuthManager::getSslCertCustomConfigByHost( const
 
 const QList<QgsAuthConfigSslServer> QgsAuthManager::getSslCertCustomConfigs()
 {
+  QMutexLocker locker( mMutex );
   QList<QgsAuthConfigSslServer> configs;
 
   QSqlQuery query( authDbConnection() );
@@ -1983,6 +2009,7 @@ const QList<QgsAuthConfigSslServer> QgsAuthManager::getSslCertCustomConfigs()
 
 bool QgsAuthManager::existsSslCertCustomConfig( const QString &id , const QString &hostport )
 {
+  QMutexLocker locker( mMutex );
   if ( id.isEmpty() || hostport.isEmpty() )
   {
     QgsDebugMsg( "Passed config ID or host:port is empty" );
@@ -2020,6 +2047,7 @@ bool QgsAuthManager::existsSslCertCustomConfig( const QString &id , const QStrin
 
 bool QgsAuthManager::removeSslCertCustomConfig( const QString &id, const QString &hostport )
 {
+  QMutexLocker locker( mMutex );
   if ( id.isEmpty() || hostport.isEmpty() )
   {
     QgsDebugMsg( "Passed config ID or host:port is empty" );
@@ -2055,6 +2083,7 @@ bool QgsAuthManager::removeSslCertCustomConfig( const QString &id, const QString
 
 void QgsAuthManager::dumpIgnoredSslErrorsCache_()
 {
+  QMutexLocker locker( mMutex );
   if ( !mIgnoredSslErrorsCache.isEmpty() )
   {
     QgsDebugMsg( "Ignored SSL errors cache items:" );
@@ -2078,6 +2107,7 @@ void QgsAuthManager::dumpIgnoredSslErrorsCache_()
 
 bool QgsAuthManager::updateIgnoredSslErrorsCacheFromConfig( const QgsAuthConfigSslServer &config )
 {
+  QMutexLocker locker( mMutex );
   if ( config.isNull() )
   {
     QgsDebugMsg( "Passed config is null" );
@@ -2106,6 +2136,7 @@ bool QgsAuthManager::updateIgnoredSslErrorsCacheFromConfig( const QgsAuthConfigS
 
 bool QgsAuthManager::updateIgnoredSslErrorsCache( const QString &shahostport, const QList<QSslError> &errors )
 {
+  QMutexLocker locker( mMutex );
   QRegExp rx( "\\S+:\\S+:\\d+" );
   if ( !rx.exactMatch( shahostport ) )
   {
@@ -2149,6 +2180,7 @@ bool QgsAuthManager::updateIgnoredSslErrorsCache( const QString &shahostport, co
 
 bool QgsAuthManager::rebuildIgnoredSslErrorCache()
 {
+  QMutexLocker locker( mMutex );
   QHash<QString, QSet<QSslError::SslError> > prevcache( mIgnoredSslErrorsCache );
   QHash<QString, QSet<QSslError::SslError> > nextcache;
 
@@ -2210,6 +2242,7 @@ bool QgsAuthManager::rebuildIgnoredSslErrorCache()
 
 bool QgsAuthManager::storeCertAuthorities( const QList<QSslCertificate> &certs )
 {
+  QMutexLocker locker( mMutex );
   if ( certs.size() < 1 )
   {
     QgsDebugMsg( "Passed certificate list has no certs" );
@@ -2226,6 +2259,7 @@ bool QgsAuthManager::storeCertAuthorities( const QList<QSslCertificate> &certs )
 
 bool QgsAuthManager::storeCertAuthority( const QSslCertificate& cert )
 {
+  QMutexLocker locker( mMutex );
   // don't refuse !cert.isValid() (actually just expired) CAs,
   // as user may want to ignore that SSL connection error
   if ( cert.isNull() )
@@ -2261,6 +2295,7 @@ bool QgsAuthManager::storeCertAuthority( const QSslCertificate& cert )
 
 const QSslCertificate QgsAuthManager::getCertAuthority( const QString &id )
 {
+  QMutexLocker locker( mMutex );
   QSslCertificate emptycert;
   QSslCertificate cert;
   if ( id.isEmpty() )
@@ -2294,6 +2329,7 @@ const QSslCertificate QgsAuthManager::getCertAuthority( const QString &id )
 
 bool QgsAuthManager::existsCertAuthority( const QSslCertificate& cert )
 {
+  QMutexLocker locker( mMutex );
   if ( cert.isNull() )
   {
     QgsDebugMsg( "Passed certificate is null" );
@@ -2331,6 +2367,7 @@ bool QgsAuthManager::existsCertAuthority( const QSslCertificate& cert )
 
 bool QgsAuthManager::removeCertAuthority( const QSslCertificate& cert )
 {
+  QMutexLocker locker( mMutex );
   if ( cert.isNull() )
   {
     QgsDebugMsg( "Passed certificate is null" );
@@ -2370,6 +2407,7 @@ const QList<QSslCertificate> QgsAuthManager::getSystemRootCAs()
 
 const QList<QSslCertificate> QgsAuthManager::getExtraFileCAs()
 {
+  QMutexLocker locker( mMutex );
   QList<QSslCertificate> certs;
   QList<QSslCertificate> filecerts;
   QVariant cafileval = QgsAuthManager::instance()->getAuthSetting( QString( "cafile" ) );
@@ -2403,6 +2441,7 @@ const QList<QSslCertificate> QgsAuthManager::getExtraFileCAs()
 
 const QList<QSslCertificate> QgsAuthManager::getDatabaseCAs()
 {
+  QMutexLocker locker( mMutex );
   QList<QSslCertificate> certs;
 
   QSqlQuery query( authDbConnection() );
@@ -2424,11 +2463,13 @@ const QList<QSslCertificate> QgsAuthManager::getDatabaseCAs()
 
 const QMap<QString, QSslCertificate> QgsAuthManager::getMappedDatabaseCAs()
 {
+  QMutexLocker locker( mMutex );
   return QgsAuthCertUtils::mapDigestToCerts( getDatabaseCAs() );
 }
 
 bool QgsAuthManager::rebuildCaCertsCache()
 {
+  QMutexLocker locker( mMutex );
   mCaCertsCache.clear();
   // in reverse order of precedence, with regards to duplicates, so QMap inserts overwrite
   insertCaCertInCache( QgsAuthCertUtils::SystemRoot, getSystemRootCAs() );
@@ -2442,6 +2483,7 @@ bool QgsAuthManager::rebuildCaCertsCache()
 
 bool QgsAuthManager::storeCertTrustPolicy( const QSslCertificate &cert, QgsAuthCertUtils::CertTrustPolicy policy )
 {
+  QMutexLocker locker( mMutex );
   if ( cert.isNull() )
   {
     QgsDebugMsg( "Passed certificate is null" );
@@ -2480,6 +2522,7 @@ bool QgsAuthManager::storeCertTrustPolicy( const QSslCertificate &cert, QgsAuthC
 
 QgsAuthCertUtils::CertTrustPolicy QgsAuthManager::getCertTrustPolicy( const QSslCertificate &cert )
 {
+  QMutexLocker locker( mMutex );
   if ( cert.isNull() )
   {
     QgsDebugMsg( "Passed certificate is null" );
@@ -2517,6 +2560,7 @@ QgsAuthCertUtils::CertTrustPolicy QgsAuthManager::getCertTrustPolicy( const QSsl
 
 bool QgsAuthManager::removeCertTrustPolicies( const QList<QSslCertificate> &certs )
 {
+  QMutexLocker locker( mMutex );
   if ( certs.size() < 1 )
   {
     QgsDebugMsg( "Passed certificate list has no certs" );
@@ -2533,6 +2577,7 @@ bool QgsAuthManager::removeCertTrustPolicies( const QList<QSslCertificate> &cert
 
 bool QgsAuthManager::removeCertTrustPolicy( const QSslCertificate &cert )
 {
+  QMutexLocker locker( mMutex );
   if ( cert.isNull() )
   {
     QgsDebugMsg( "Passed certificate is null" );
@@ -2563,6 +2608,7 @@ bool QgsAuthManager::removeCertTrustPolicy( const QSslCertificate &cert )
 
 QgsAuthCertUtils::CertTrustPolicy QgsAuthManager::getCertificateTrustPolicy( const QSslCertificate &cert )
 {
+  QMutexLocker locker( mMutex );
   if ( cert.isNull() )
   {
     return QgsAuthCertUtils::NoPolicy;
@@ -2596,6 +2642,7 @@ bool QgsAuthManager::setDefaultCertTrustPolicy( QgsAuthCertUtils::CertTrustPolic
 
 QgsAuthCertUtils::CertTrustPolicy QgsAuthManager::defaultCertTrustPolicy()
 {
+  QMutexLocker locker( mMutex );
   QVariant policy( getAuthSetting( "certdefaulttrust" ) );
   if ( policy.isNull() )
   {
@@ -2606,6 +2653,7 @@ QgsAuthCertUtils::CertTrustPolicy QgsAuthManager::defaultCertTrustPolicy()
 
 bool QgsAuthManager::rebuildCertTrustCache()
 {
+  QMutexLocker locker( mMutex );
   mCertTrustCache.clear();
 
   QSqlQuery query( authDbConnection() );
@@ -2639,6 +2687,7 @@ bool QgsAuthManager::rebuildCertTrustCache()
 
 const QList<QSslCertificate> QgsAuthManager::getTrustedCaCerts( bool includeinvalid )
 {
+  QMutexLocker locker( mMutex );
   QgsAuthCertUtils::CertTrustPolicy defaultpolicy( defaultCertTrustPolicy() );
   QStringList trustedids = mCertTrustCache.value( QgsAuthCertUtils::Trusted );
   QStringList untrustedids = mCertTrustCache.value( QgsAuthCertUtils::Untrusted );
@@ -2672,6 +2721,7 @@ const QList<QSslCertificate> QgsAuthManager::getTrustedCaCerts( bool includeinva
 
 const QList<QSslCertificate> QgsAuthManager::getUntrustedCaCerts( QList<QSslCertificate> trustedCAs )
 {
+  QMutexLocker locker( mMutex );
   if ( trustedCAs.isEmpty() )
   {
     if ( mTrustedCaCertsCache.isEmpty() )
@@ -2697,6 +2747,7 @@ const QList<QSslCertificate> QgsAuthManager::getUntrustedCaCerts( QList<QSslCert
 
 bool QgsAuthManager::rebuildTrustedCaCertsCache()
 {
+  QMutexLocker locker( mMutex );
   mTrustedCaCertsCache = getTrustedCaCerts();
   QgsDebugMsg( "Rebuilt trusted cert authorities cache" );
   // TODO: add some error trapping for the operation
@@ -2705,6 +2756,7 @@ bool QgsAuthManager::rebuildTrustedCaCertsCache()
 
 const QByteArray QgsAuthManager::getTrustedCaCertsPemText()
 {
+  QMutexLocker locker( mMutex );
   QByteArray capem;
   QList<QSslCertificate> certs( getTrustedCaCertsCache() );
   if ( !certs.isEmpty() )
diff --git a/src/core/qgsactionmanager.cpp b/src/core/qgsactionmanager.cpp
index e2413dc..ff2c887 100644
--- a/src/core/qgsactionmanager.cpp
+++ b/src/core/qgsactionmanager.cpp
@@ -63,10 +63,10 @@ void QgsActionManager::removeAction( int index )
   }
 }
 
-void QgsActionManager::doAction( int index, const QgsFeature& feat, int defaultValueIndex )
+void QgsActionManager::doAction( int index, const QgsFeature& feat, int defaultValueIndex, const QgsExpressionContextScope &scope )
 {
   QgsExpressionContext context = createExpressionContext();
-  QgsExpressionContextScope* actionScope = new QgsExpressionContextScope();
+  QgsExpressionContextScope* actionScope = new QgsExpressionContextScope( scope );
   actionScope->addVariable( QgsExpressionContextScope::StaticVariable( QString( "current_field" ), feat.attribute( defaultValueIndex ), true ) );
   context << actionScope;
   doAction( index, feat, context );
diff --git a/src/core/qgsactionmanager.h b/src/core/qgsactionmanager.h
index d87ac9a..e1735ae 100644
--- a/src/core/qgsactionmanager.h
+++ b/src/core/qgsactionmanager.h
@@ -78,13 +78,20 @@ class CORE_EXPORT QgsActionManager
     //! Remove an action at given index
     void removeAction( int index );
 
-    /** Does the given values. defaultValueIndex is the index of the
-     *  field to be used if the action has a $currfield placeholder.
-     *  @note available in python bindings as doActionFeature
+    /**
+     * Does the given action.
+     *
+     * @param index Index of the action
+     * @param feat Feature to run action for
+     * @param defaultValueIndex Index of the field to be used if the action has a $currfield placeholder.
+     * @param scope Expression context scope to add during expression evaluation
+     *
+     * @note available in python bindings as doActionFeature
      */
     void doAction( int index,
                    const QgsFeature &feat,
-                   int defaultValueIndex = 0 );
+                   int defaultValueIndex = 0,
+                   const QgsExpressionContextScope &scope = QgsExpressionContextScope() );
 
     /** Does the action using the expression engine to replace any embedded expressions
      * in the action definition.
diff --git a/src/core/qgsgml.cpp b/src/core/qgsgml.cpp
index b77202d..b0e4015 100644
--- a/src/core/qgsgml.cpp
+++ b/src/core/qgsgml.cpp
@@ -555,8 +555,10 @@ void QgsGmlStreamingParser::startElement( const XML_Char* el, const XML_Char** a
       }
     }
   }
-  else if ( localNameLen == static_cast<int>( mGeometryAttributeUTF8Len ) &&
-            memcmp( pszLocalName, mGeometryAttributePtr, localNameLen ) == 0 )
+  else if (( theParseMode == feature || theParseMode == featureTuple ) &&
+           mCurrentFeature &&
+           localNameLen == static_cast<int>( mGeometryAttributeUTF8Len ) &&
+           memcmp( pszLocalName, mGeometryAttributePtr, localNameLen ) == 0 )
   {
     mParseModeStack.push( QgsGmlStreamingParser::geometry );
     mFoundUnhandledGeometryElement = false;
@@ -903,6 +905,7 @@ void QgsGmlStreamingParser::endElement( const XML_Char* el )
         {
           g->transform( QTransform( 0, 1, 1, 0, 0, 0 ) );
         }
+        Q_ASSERT( mCurrentFeature );
         mCurrentFeature->setGeometry( g );
         OGR_G_DestroyGeometry( hGeom );
       }
diff --git a/src/core/qgslayerdefinition.cpp b/src/core/qgslayerdefinition.cpp
index 01c2251..7755095 100644
--- a/src/core/qgslayerdefinition.cpp
+++ b/src/core/qgslayerdefinition.cpp
@@ -45,10 +45,10 @@ bool QgsLayerDefinition::loadLayerDefinition( const QString &path, QgsLayerTreeG
   QFileInfo fileinfo( file );
   QDir::setCurrent( fileinfo.absoluteDir().path() );
 
-  return loadLayerDefinition( doc, rootGroup, errorMessage );
+  return loadLayerDefinition( doc, rootGroup, errorMessage, fileinfo.canonicalFilePath() );
 }
 
-bool QgsLayerDefinition::loadLayerDefinition( QDomDocument doc, QgsLayerTreeGroup *rootGroup, QString &errorMessage )
+bool QgsLayerDefinition::loadLayerDefinition( QDomDocument doc, QgsLayerTreeGroup *rootGroup, QString &errorMessage, const QString& relativeBasePath )
 {
   Q_UNUSED( errorMessage );
 
@@ -121,7 +121,7 @@ bool QgsLayerDefinition::loadLayerDefinition( QDomDocument doc, QgsLayerTreeGrou
     loadInLegend = false;
   }
 
-  QList<QgsMapLayer*> layers = QgsMapLayer::fromLayerDefinition( doc, /*addToRegistry*/ true, loadInLegend );
+  QList<QgsMapLayer*> layers = QgsMapLayer::fromLayerDefinition( doc, /*addToRegistry*/ true, loadInLegend, relativeBasePath );
 
   // Now that all layers are loaded, refresh the vectorjoins to get the joined fields
   Q_FOREACH ( QgsMapLayer* layer, layers )
diff --git a/src/core/qgslayerdefinition.h b/src/core/qgslayerdefinition.h
index 8f8b197..70dec8b 100644
--- a/src/core/qgslayerdefinition.h
+++ b/src/core/qgslayerdefinition.h
@@ -30,11 +30,11 @@ class CORE_EXPORT QgsLayerDefinition
     /** Loads the QLR at path into QGIS.  New layers are added to rootGroup and the map layer registry*/
     static bool loadLayerDefinition( const QString & path, QgsLayerTreeGroup* rootGroup, QString &errorMessage );
     /** Loads the QLR from the XML document.  New layers are added to rootGroup and the map layer registry */
-    static bool loadLayerDefinition( QDomDocument doc, QgsLayerTreeGroup* rootGroup, QString &errorMessage );
+    static bool loadLayerDefinition( QDomDocument doc, QgsLayerTreeGroup* rootGroup, QString &errorMessage, const QString& relativeBasePath = QString() );
     /** Export the selected layer tree nodes to a QLR file */
     static bool exportLayerDefinition( QString path, const QList<QgsLayerTreeNode*>& selectedTreeNodes, QString &errorMessage );
     /** Export the selected layer tree nodes to a QLR-XML document */
-    static bool exportLayerDefinition( QDomDocument doc, const QList<QgsLayerTreeNode*>& selectedTreeNodes, QString &errorMessage, const QString& relativeBasePath = QString::null );
+    static bool exportLayerDefinition( QDomDocument doc, const QList<QgsLayerTreeNode*>& selectedTreeNodes, QString &errorMessage, const QString& relativeBasePath = QString() );
 
     /**
      * \ingroup core
diff --git a/src/core/qgsmaplayer.cpp b/src/core/qgsmaplayer.cpp
index cb3b0f9..10aa535 100644
--- a/src/core/qgsmaplayer.cpp
+++ b/src/core/qgsmaplayer.cpp
@@ -174,7 +174,7 @@ void QgsMapLayer::drawLabels( QgsRenderContext& rendererContext )
   Q_UNUSED( rendererContext );
 }
 
-bool QgsMapLayer::readLayerXML( const QDomElement& layerElement )
+bool QgsMapLayer::readLayerXML( const QDomElement& layerElement, const QString& relativeBasePath )
 {
   bool layerError;
 
@@ -205,19 +205,19 @@ bool QgsMapLayer::readLayerXML( const QDomElement& layerElement )
   if ( provider == "spatialite" )
   {
     QgsDataSourceURI uri( mDataSource );
-    uri.setDatabase( QgsProject::instance()->readPath( uri.database() ) );
+    uri.setDatabase( QgsProject::instance()->readPath( uri.database(), relativeBasePath ) );
     mDataSource = uri.uri();
   }
   else if ( provider == "ogr" )
   {
     QStringList theURIParts = mDataSource.split( '|' );
-    theURIParts[0] = QgsProject::instance()->readPath( theURIParts[0] );
+    theURIParts[0] = QgsProject::instance()->readPath( theURIParts[0], relativeBasePath );
     mDataSource = theURIParts.join( "|" );
   }
   else if ( provider == "gpx" )
   {
     QStringList theURIParts = mDataSource.split( '?' );
-    theURIParts[0] = QgsProject::instance()->readPath( theURIParts[0] );
+    theURIParts[0] = QgsProject::instance()->readPath( theURIParts[0], relativeBasePath );
     mDataSource = theURIParts.join( "?" );
   }
   else if ( provider == "delimitedtext" )
@@ -231,7 +231,7 @@ bool QgsMapLayer::readLayerXML( const QDomElement& layerElement )
       urlSource.setPath( file.path() );
     }
 
-    QUrl urlDest = QUrl::fromLocalFile( QgsProject::instance()->readPath( urlSource.toLocalFile() ) );
+    QUrl urlDest = QUrl::fromLocalFile( QgsProject::instance()->readPath( urlSource.toLocalFile(), relativeBasePath ) );
     urlDest.setQueryItems( urlSource.queryItems() );
     mDataSource = QString::fromAscii( urlDest.toEncoded() );
   }
@@ -329,7 +329,7 @@ bool QgsMapLayer::readLayerXML( const QDomElement& layerElement )
           QString filename = r.cap( 1 );
           if ( filename.startsWith( '"' ) && filename.endsWith( '"' ) )
             filename = filename.mid( 1, filename.length() - 2 );
-          mDataSource = "NETCDF:\"" + QgsProject::instance()->readPath( filename ) + "\":" + r.cap( 2 );
+          mDataSource = "NETCDF:\"" + QgsProject::instance()->readPath( filename, relativeBasePath ) + "\":" + r.cap( 2 );
           handled = true;
         }
       }
@@ -343,7 +343,7 @@ bool QgsMapLayer::readLayerXML( const QDomElement& layerElement )
           QString filename = r.cap( 2 );
           if ( filename.startsWith( '"' ) && filename.endsWith( '"' ) )
             filename = filename.mid( 1, filename.length() - 2 );
-          mDataSource = "HDF4_SDS:" + r.cap( 1 ) + ":\"" + QgsProject::instance()->readPath( filename ) + "\":" + r.cap( 3 );
+          mDataSource = "HDF4_SDS:" + r.cap( 1 ) + ":\"" + QgsProject::instance()->readPath( filename, relativeBasePath ) + "\":" + r.cap( 3 );
           handled = true;
         }
       }
@@ -357,7 +357,7 @@ bool QgsMapLayer::readLayerXML( const QDomElement& layerElement )
           QString filename = r.cap( 1 );
           if ( filename.startsWith( '"' ) && filename.endsWith( '"' ) )
             filename = filename.mid( 1, filename.length() - 2 );
-          mDataSource = "HDF5:\"" + QgsProject::instance()->readPath( filename ) + "\":" + r.cap( 2 );
+          mDataSource = "HDF5:\"" + QgsProject::instance()->readPath( filename, relativeBasePath ) + "\":" + r.cap( 2 );
           handled = true;
         }
       }
@@ -368,14 +368,14 @@ bool QgsMapLayer::readLayerXML( const QDomElement& layerElement )
         QRegExp r( "([^:]+):([^:]+):(.+)" );
         if ( r.exactMatch( mDataSource ) )
         {
-          mDataSource = r.cap( 1 ) + ':' + r.cap( 2 ) + ':' + QgsProject::instance()->readPath( r.cap( 3 ) );
+          mDataSource = r.cap( 1 ) + ':' + r.cap( 2 ) + ':' + QgsProject::instance()->readPath( r.cap( 3 ), relativeBasePath );
           handled = true;
         }
       }
     }
 
     if ( !handled )
-      mDataSource = QgsProject::instance()->readPath( mDataSource );
+      mDataSource = QgsProject::instance()->readPath( mDataSource, relativeBasePath );
   }
 
   // Set the CRS from project file, asking the user if necessary.
@@ -817,7 +817,7 @@ QDomDocument QgsMapLayer::asLayerDefinition( const QList<QgsMapLayer *>& layers,
   return doc;
 }
 
-QList<QgsMapLayer*> QgsMapLayer::fromLayerDefinition( QDomDocument& document, bool addToRegistry, bool addToLegend )
+QList<QgsMapLayer*> QgsMapLayer::fromLayerDefinition( QDomDocument& document, bool addToRegistry, bool addToLegend, const QString& relativeBasePath )
 {
   QList<QgsMapLayer*> layers;
   QDomNodeList layernodes = document.elementsByTagName( "maplayer" );
@@ -847,7 +847,7 @@ QList<QgsMapLayer*> QgsMapLayer::fromLayerDefinition( QDomDocument& document, bo
     if ( !layer )
       continue;
 
-    bool ok = layer->readLayerXML( layerElem );
+    bool ok = layer->readLayerXML( layerElem, relativeBasePath );
     if ( ok )
     {
       layers << layer;
diff --git a/src/core/qgsmaplayer.h b/src/core/qgsmaplayer.h
index dcaf0bb..bc35f45 100644
--- a/src/core/qgsmaplayer.h
+++ b/src/core/qgsmaplayer.h
@@ -310,6 +310,7 @@ class CORE_EXPORT QgsMapLayer : public QObject
 
     /** Sets state from Dom document
        @param layerElement The Dom element corresponding to ``maplayer'' tag
+       @param relativeBasePath base path for relative paths
        @note
 
        The Dom node corresponds to a Dom document project file XML element read
@@ -322,7 +323,7 @@ class CORE_EXPORT QgsMapLayer : public QObject
 
        @returns true if successful
      */
-    bool readLayerXML( const QDomElement& layerElement );
+    bool readLayerXML( const QDomElement& layerElement, const QString& relativeBasePath = QString() );
 
 
     /** Stores state in Dom node
@@ -341,18 +342,18 @@ class CORE_EXPORT QgsMapLayer : public QObject
      *
      * @returns true if successful
      */
-    bool writeLayerXML( QDomElement& layerElement, QDomDocument& document, const QString& relativeBasePath = QString::null );
+    bool writeLayerXML( QDomElement& layerElement, QDomDocument& document, const QString& relativeBasePath = QString() );
 
     /** Returns the given layer as a layer definition document
      *  Layer definitions store the data source as well as styling and custom properties.
      *
      *  Layer definitions can be used to load a layer and styling all from a single file.
      */
-    static QDomDocument asLayerDefinition( const QList<QgsMapLayer*>& layers, const QString& relativeBasePath = QString::null );
+    static QDomDocument asLayerDefinition( const QList<QgsMapLayer*>& layers, const QString& relativeBasePath = QString() );
 
     /** Creates a new layer from a layer defininition document
      */
-    static QList<QgsMapLayer*> fromLayerDefinition( QDomDocument& document, bool addToRegistry = false, bool addToLegend = false );
+    static QList<QgsMapLayer*> fromLayerDefinition( QDomDocument& document, bool addToRegistry = false, bool addToLegend = false, const QString& relativeBasePath = QString() );
     static QList<QgsMapLayer*> fromLayerDefinitionFile( const QString &qlrfile );
 
     /** Set a custom property for layer. Properties are stored in a map and saved in project file. */
diff --git a/src/core/qgsofflineediting.cpp b/src/core/qgsofflineediting.cpp
index 8455251..a556212 100644
--- a/src/core/qgsofflineediting.cpp
+++ b/src/core/qgsofflineediting.cpp
@@ -307,10 +307,6 @@ void QgsOfflineEditing::synchronize()
             sqlExec( db, sql );
             sql = QString( "DELETE FROM 'log_geometry_updates' WHERE \"layer_id\" = %1" ).arg( layerId );
             sqlExec( db, sql );
-
-            // reset commitNo
-            QString sql = QString( "UPDATE 'log_indices' SET 'last_index' = 0 WHERE \"name\" = 'commit_no'" );
-            sqlExec( db, sql );
           }
           else
           {
@@ -347,6 +343,10 @@ void QgsOfflineEditing::synchronize()
     }
   }
 
+  // reset commitNo
+  QString sql = QString( "UPDATE 'log_indices' SET 'last_index' = 0 WHERE \"name\" = 'commit_no'" );
+  sqlExec( db, sql );
+
   emit progressStopped();
 
   sqlite3_close( db );
diff --git a/src/core/qgsproject.cpp b/src/core/qgsproject.cpp
index 01779c9..f9bb893 100644
--- a/src/core/qgsproject.cpp
+++ b/src/core/qgsproject.cpp
@@ -1432,7 +1432,7 @@ void QgsProject::dumpProperties() const
   dump_( imp_->properties_ );
 }
 
-QString QgsProject::readPath( QString src ) const
+QString QgsProject::readPath( QString src, const QString& relativeBasePath ) const
 {
   if ( readBoolEntry( "Paths", "/Absolute", false ) )
   {
@@ -1493,6 +1493,11 @@ QString QgsProject::readPath( QString src ) const
   QString srcPath = src;
   QString projPath = fileName();
 
+  if ( !relativeBasePath.isNull() )
+  {
+    projPath = relativeBasePath;
+  }
+
   if ( projPath.isEmpty() )
   {
     return vsiPrefix + src;
diff --git a/src/core/qgsproject.h b/src/core/qgsproject.h
index 5a8f1c7..6070c48 100644
--- a/src/core/qgsproject.h
+++ b/src/core/qgsproject.h
@@ -256,10 +256,10 @@ class CORE_EXPORT QgsProject : public QObject
     /** Prepare a filename to save it to the project file. Creates an absolute or relative path to writes
      * it to the project file.
     */
-    QString writePath( const QString& filename, const QString& relativeBasePath = QString::null ) const;
+    QString writePath( const QString& filename, const QString& relativeBasePath = QString() ) const;
 
     /** Turn filename read from the project file to an absolute path */
-    QString readPath( QString filename ) const;
+    QString readPath( QString filename, const QString& relativeBasePath = QString() ) const;
 
     /** Return error message from previous read/write */
     QString error() const;
diff --git a/src/core/raster/qgscontrastenhancement.cpp b/src/core/raster/qgscontrastenhancement.cpp
index c1d323a..efccbda 100644
--- a/src/core/raster/qgscontrastenhancement.cpp
+++ b/src/core/raster/qgscontrastenhancement.cpp
@@ -180,7 +180,10 @@ int QgsContrastEnhancement::enhanceContrast( double theValue )
 
   if ( mLookupTable && NoEnhancement != mContrastEnhancementAlgorithm )
   {
-    return mLookupTable[static_cast <int>( theValue + mLookupTableOffset )];
+    double shiftedValue = theValue + mLookupTableOffset;
+    if ( shiftedValue >= 0 && shiftedValue < mRasterDataTypeRange + 1 )
+      return mLookupTable[static_cast <int>( shiftedValue )];
+    return 0;
   }
   else
   {
diff --git a/src/core/raster/qgscontrastenhancementfunction.cpp b/src/core/raster/qgscontrastenhancementfunction.cpp
index 8206be4..0bdae9e 100644
--- a/src/core/raster/qgscontrastenhancementfunction.cpp
+++ b/src/core/raster/qgscontrastenhancementfunction.cpp
@@ -49,12 +49,8 @@ int QgsContrastEnhancementFunction::enhance( double theValue )
 bool QgsContrastEnhancementFunction::isValueInDisplayableRange( double theValue )
 {
   //A default check is to see if the provided value is with the range for the data type
-  if ( theValue < QgsContrastEnhancement::minimumValuePossible( mQgsRasterDataType ) || theValue > QgsContrastEnhancement::maximumValuePossible( mQgsRasterDataType ) )
-  {
-    return false;
-  }
-
-  return true;
+  // Write the test as ( v >= min && v <= max ) so that v = NaN returns false
+  return theValue >= QgsContrastEnhancement::minimumValuePossible( mQgsRasterDataType ) && theValue <= QgsContrastEnhancement::maximumValuePossible( mQgsRasterDataType );
 }
 
 void QgsContrastEnhancementFunction::setMaximumValue( double theValue )
diff --git a/src/core/raster/qgsrasterlayerrenderer.cpp b/src/core/raster/qgsrasterlayerrenderer.cpp
index 6921b30..07542f9 100644
--- a/src/core/raster/qgsrasterlayerrenderer.cpp
+++ b/src/core/raster/qgsrasterlayerrenderer.cpp
@@ -52,14 +52,29 @@ QgsRasterLayerRenderer::QgsRasterLayerRenderer( QgsRasterLayer* layer, QgsRender
   if ( rendererContext.coordinateTransform() )
   {
     QgsDebugMsgLevel( "coordinateTransform set -> project extents.", 4 );
-    try
+    if ( rendererContext.extent().xMinimum() == -DBL_MAX &&
+         rendererContext.extent().yMinimum() == -DBL_MAX &&
+         rendererContext.extent().xMaximum() == DBL_MAX &&
+         rendererContext.extent().yMaximum() == DBL_MAX )
     {
-      myProjectedViewExtent = rendererContext.coordinateTransform()->transformBoundingBox( rendererContext.extent() );
+      // We get in this situation if the view CRS is geographical and the
+      // extent goes beyond -180,-90,180,90. To avoid reprojection issues to the
+      // layer CRS, then this dummy extent is returned by QgsMapRendererJob::reprojectToLayerExtent()
+      // Don't try to reproject it now to view extent as this would return
+      // a null rectangle.
+      myProjectedViewExtent = rendererContext.extent();
     }
-    catch ( QgsCsException &cs )
+    else
     {
-      QgsMessageLog::logMessage( QObject::tr( "Could not reproject view extent: %1" ).arg( cs.what() ), QObject::tr( "Raster" ) );
-      myProjectedViewExtent.setMinimal();
+      try
+      {
+        myProjectedViewExtent = rendererContext.coordinateTransform()->transformBoundingBox( rendererContext.extent() );
+      }
+      catch ( QgsCsException &cs )
+      {
+        QgsMessageLog::logMessage( QObject::tr( "Could not reproject view extent: %1" ).arg( cs.what() ), QObject::tr( "Raster" ) );
+        myProjectedViewExtent.setMinimal();
+      }
     }
 
     try
diff --git a/src/gui/editorwidgets/qgsrelationreferenceconfigdlg.cpp b/src/gui/editorwidgets/qgsrelationreferenceconfigdlg.cpp
index a09e276..cab341e 100644
--- a/src/gui/editorwidgets/qgsrelationreferenceconfigdlg.cpp
+++ b/src/gui/editorwidgets/qgsrelationreferenceconfigdlg.cpp
@@ -47,7 +47,11 @@ QgsRelationReferenceConfigDlg::QgsRelationReferenceConfigDlg( QgsVectorLayer* vl
 
   Q_FOREACH ( const QgsRelation& relation, vl->referencingRelations( fieldIdx ) )
   {
-    mComboRelation->addItem( QString( "%1 (%2)" ).arg( relation.id(), relation.referencedLayerId() ), relation.id() );
+    if ( relation.name().isEmpty() )
+      mComboRelation->addItem( QString( "%1 (%2)" ).arg( relation.id(), relation.referencedLayerId() ), relation.id() );
+    else
+      mComboRelation->addItem( QString( "%1 (%2)" ).arg( relation.name(), relation.referencedLayerId() ), relation.id() );
+
     if ( relation.referencedLayer() )
     {
       mExpressionWidget->setField( relation.referencedLayer()->displayExpression() );
diff --git a/src/gui/editorwidgets/qgsrelationreferencewidget.cpp b/src/gui/editorwidgets/qgsrelationreferencewidget.cpp
index d3d54d3..41f2b73 100644
--- a/src/gui/editorwidgets/qgsrelationreferencewidget.cpp
+++ b/src/gui/editorwidgets/qgsrelationreferencewidget.cpp
@@ -164,7 +164,7 @@ QgsRelationReferenceWidget::QgsRelationReferenceWidget( QWidget* parent )
   connect( mMapIdentificationButton, SIGNAL( clicked() ), this, SLOT( mapIdentification() ) );
   connect( mRemoveFKButton, SIGNAL( clicked() ), this, SLOT( deleteForeignKey() ) );
   connect( mAddEntryButton, SIGNAL( clicked( bool ) ), this, SLOT( addEntry() ) );
-  connect( mComboBox, SIGNAL( editTextChanged( QString ) ), this, SLOT( updateAddEntryButton() ) );
+  connect( mComboBox, SIGNAL( editTextChanged( QString ) ), this, SLOT( editTextUpdated( const QString & ) ) );
 }
 
 QgsRelationReferenceWidget::~QgsRelationReferenceWidget()
@@ -990,3 +990,13 @@ void QgsRelationReferenceWidget::disableChainedComboBoxes( const QComboBox *scb
     ccb = cb;
   }
 }
+
+void QgsRelationReferenceWidget::editTextUpdated( const QString &text )
+{
+  updateAddEntryButton();
+
+  // allow to raise an invalid constraint on NULL values if necessary
+  // and when the combobox is updated manually from the keyboard
+  if ( text.isEmpty() && mAllowNull )
+    mComboBox->setCurrentIndex( 0 );
+}
diff --git a/src/gui/editorwidgets/qgsrelationreferencewidget.h b/src/gui/editorwidgets/qgsrelationreferencewidget.h
index e5eb7b1..e70affa 100644
--- a/src/gui/editorwidgets/qgsrelationreferencewidget.h
+++ b/src/gui/editorwidgets/qgsrelationreferencewidget.h
@@ -157,12 +157,13 @@ class GUI_EXPORT QgsRelationReferenceWidget : public QWidget
     void mapToolDeactivated();
     void filterChanged();
     void addEntry();
-    void updateAddEntryButton();
+    void editTextUpdated( const QString &text );
 
   private:
     void highlightFeature( QgsFeature f = QgsFeature(), CanvasExtent canvasExtent = Fixed );
     void updateAttributeEditorFrame( const QgsFeature& feature );
     void disableChainedComboBoxes( const QComboBox *scb );
+    void updateAddEntryButton();
 
     // initialized
     QgsAttributeEditorContext mEditorContext;
diff --git a/src/gui/editorwidgets/qgsvaluerelationwidgetwrapper.cpp b/src/gui/editorwidgets/qgsvaluerelationwidgetwrapper.cpp
index a1b42f2..c662d1b 100644
--- a/src/gui/editorwidgets/qgsvaluerelationwidgetwrapper.cpp
+++ b/src/gui/editorwidgets/qgsvaluerelationwidgetwrapper.cpp
@@ -43,7 +43,7 @@ QgsValueRelationWidgetWrapper::QgsValueRelationWidgetWrapper( QgsVectorLayer* vl
     , mListWidget( nullptr )
     , mLineEdit( nullptr )
     , mLayer( nullptr )
-    , mUpdating( false )
+    , mEnabled( false )
 {
 }
 
@@ -252,12 +252,13 @@ void QgsValueRelationWidgetWrapper::showIndeterminateState()
 
 void QgsValueRelationWidgetWrapper::setEnabled( bool enabled )
 {
-  if ( mUpdating )
+  if ( mEnabled == enabled )
     return;
 
+  mEnabled = enabled;
+
   if ( mListWidget )
   {
-    mUpdating = true;
     for ( int i = 0; i < mListWidget->count(); ++i )
     {
       QListWidgetItem *item = mListWidget->item( i );
@@ -267,7 +268,6 @@ void QgsValueRelationWidgetWrapper::setEnabled( bool enabled )
       else
         item->setFlags( item->flags() & ~Qt::ItemIsEnabled );
     }
-    mUpdating = false;
   }
   else
     QgsEditorWidgetWrapper::setEnabled( enabled );
diff --git a/src/gui/editorwidgets/qgsvaluerelationwidgetwrapper.h b/src/gui/editorwidgets/qgsvaluerelationwidgetwrapper.h
index e5f2e0e..7e25360 100644
--- a/src/gui/editorwidgets/qgsvaluerelationwidgetwrapper.h
+++ b/src/gui/editorwidgets/qgsvaluerelationwidgetwrapper.h
@@ -86,7 +86,7 @@ class GUI_EXPORT QgsValueRelationWidgetWrapper : public QgsEditorWidgetWrapper
     ValueRelationCache mCache;
     QgsVectorLayer* mLayer;
 
-    bool mUpdating;
+    bool mEnabled;
 
     friend class QgsValueRelationWidgetFactory;
     friend class TestQgsValueRelationWidgetWrapper;
diff --git a/src/gui/qgsactionmenu.cpp b/src/gui/qgsactionmenu.cpp
index 33e430c..661580b 100644
--- a/src/gui/qgsactionmenu.cpp
+++ b/src/gui/qgsactionmenu.cpp
@@ -106,7 +106,7 @@ void QgsActionMenu::triggerAction()
   }
   else if ( data.actionType == AttributeAction )
   {
-    mActions->doAction( data.actionId.id, *feature() );
+    mActions->doAction( data.actionId.id, *feature(), 0, mExpressionContextScope );
   }
 }
 
@@ -159,3 +159,12 @@ void QgsActionMenu::reloadActions()
   emit reinit();
 }
 
+void QgsActionMenu::setExpressionContextScope( const QgsExpressionContextScope &scope )
+{
+  mExpressionContextScope = scope;
+}
+
+QgsExpressionContextScope QgsActionMenu::expressionContextScope() const
+{
+  return mExpressionContextScope;
+}
diff --git a/src/gui/qgsactionmenu.h b/src/gui/qgsactionmenu.h
index 53c4f01..d9b9cd9 100644
--- a/src/gui/qgsactionmenu.h
+++ b/src/gui/qgsactionmenu.h
@@ -108,6 +108,20 @@ class GUI_EXPORT QgsActionMenu : public QMenu
      */
     void setFeature( QgsFeature* feature );
 
+    /**
+     * Sets an expression context scope used to resolve underlying actions.
+     *
+     * @note Added in QGIS 2.18
+     */
+    void setExpressionContextScope( const QgsExpressionContextScope &scope );
+
+    /**
+     * Returns an expression context scope used to resolve underlying actions.
+     *
+     * @note Added in QGIS 2.18
+     */
+    QgsExpressionContextScope expressionContextScope() const;
+
   private slots:
     void triggerAction();
     void reloadActions();
@@ -124,6 +138,7 @@ class GUI_EXPORT QgsActionMenu : public QMenu
     const QgsFeature* mFeature;
     QgsFeatureId mFeatureId;
     bool mOwnsFeature;
+    QgsExpressionContextScope mExpressionContextScope;
 };
 
 Q_DECLARE_METATYPE( QgsActionMenu::ActionData )
diff --git a/src/gui/qgsattributeform.cpp b/src/gui/qgsattributeform.cpp
index 6162a03..b2d2a30 100644
--- a/src/gui/qgsattributeform.cpp
+++ b/src/gui/qgsattributeform.cpp
@@ -740,8 +740,8 @@ void QgsAttributeForm::updateConstraints( QgsEditorWidgetWrapper *eww )
     Q_FOREACH ( QgsEditorWidgetWrapper* depsEww, deps )
       depsEww->updateConstraint( ft );
 
-    // sync ok button status
-    synchronizeEnabledState();
+    // sync ok button status only
+    synchronizeEnabledState( false );
 
     mExpressionContext.setFeature( ft );
 
@@ -986,23 +986,27 @@ void QgsAttributeForm::refreshFeature()
   setFeature( mFeature );
 }
 
-void QgsAttributeForm::synchronizeEnabledState()
+void QgsAttributeForm::synchronizeEnabledState( bool synchronizeWidgetWrapper )
 {
   bool isEditable = ( mFeature.isValid()
                       || mMode == AddFeatureMode
                       || mMode == MultiEditMode ) && mLayer->isEditable();
 
-  Q_FOREACH ( QgsWidgetWrapper* ww, mWidgets )
+  if ( synchronizeWidgetWrapper )
   {
-    bool fieldEditable = true;
-    QgsEditorWidgetWrapper* eww = qobject_cast<QgsEditorWidgetWrapper*>( ww );
-    if ( eww )
+    Q_FOREACH ( QgsWidgetWrapper* ww, mWidgets )
     {
-      fieldEditable = !mLayer->editFormConfig()->readOnly( eww->fieldIdx() ) &&
-                      (( mLayer->dataProvider() && layer()->dataProvider()->capabilities() & QgsVectorDataProvider::ChangeAttributeValues ) ||
-                       FID_IS_NEW( mFeature.id() ) );
+      bool fieldEditable = true;
+      QgsEditorWidgetWrapper* eww = qobject_cast<QgsEditorWidgetWrapper*>( ww );
+      if ( eww )
+      {
+        fieldEditable = !mLayer->editFormConfig()->readOnly( eww->fieldIdx() ) &&
+                        (( mLayer->dataProvider() && layer()->dataProvider()->capabilities() & QgsVectorDataProvider::ChangeAttributeValues ) ||
+                         FID_IS_NEW( mFeature.id() ) );
+      }
+
+      ww->setEnabled( isEditable && fieldEditable );
     }
-    ww->setEnabled( isEditable && fieldEditable );
   }
 
   // push a message and disable the OK button if constraints are invalid
diff --git a/src/gui/qgsattributeform.h b/src/gui/qgsattributeform.h
index 2296e5b..3d7e1dc 100644
--- a/src/gui/qgsattributeform.h
+++ b/src/gui/qgsattributeform.h
@@ -259,7 +259,7 @@ class GUI_EXPORT QgsAttributeForm : public QWidget
     void onConstraintStatusChanged( const QString& constraint,
                                     const QString& description, const QString& err, bool ok );
     void preventFeatureRefresh();
-    void synchronizeEnabledState();
+    void synchronizeEnabledState( bool synchronizeWidgetWrapper = true );
     void layerSelectionChanged();
 
     //! Save multi edit changes
diff --git a/src/gui/qgsexpressionbuilderwidget.cpp b/src/gui/qgsexpressionbuilderwidget.cpp
index 5f70a8c..085e04c 100644
--- a/src/gui/qgsexpressionbuilderwidget.cpp
+++ b/src/gui/qgsexpressionbuilderwidget.cpp
@@ -221,11 +221,13 @@ void QgsExpressionBuilderWidget::newFunctionFile( const QString& fileName )
   if ( !items.isEmpty() )
     return;
 
+  QListWidgetItem *item = new QListWidgetItem( QgsApplication::getThemeIcon( "console/iconTabEditorConsole.png" ), fileName );
+  cmbFileNames->insertItem( 0, item );
+  cmbFileNames->setCurrentRow( 0 );
+
   QString templatetxt;
   QgsPythonRunner::eval( "qgis.user.expressions.template", templatetxt );
   txtPython->setText( templatetxt );
-  cmbFileNames->insertItem( 0, fileName );
-  cmbFileNames->setCurrentRow( 0 );
   saveFunctionFile( fileName );
 }
 
diff --git a/src/gui/qgsfiledownloader.cpp b/src/gui/qgsfiledownloader.cpp
index 83520d2..4d3abe2 100644
--- a/src/gui/qgsfiledownloader.cpp
+++ b/src/gui/qgsfiledownloader.cpp
@@ -114,6 +114,8 @@ void QgsFileDownloader::error( QStringList errorMessages )
   {
     QMessageBox::warning( nullptr, tr( "Download failed" ), mErrors.join( "<br>" ) );
   }
+  if ( mReply )
+    mReply->abort();
   emit downloadError( mErrors );
 }
 
diff --git a/src/gui/qgsfilterlineedit.cpp b/src/gui/qgsfilterlineedit.cpp
index c437338..93abca5 100644
--- a/src/gui/qgsfilterlineedit.cpp
+++ b/src/gui/qgsfilterlineedit.cpp
@@ -35,11 +35,15 @@ QgsFilterLineEdit::QgsFilterLineEdit( QWidget* parent, const QString& nullValue
   setMouseTracking( true );
 
   QIcon clearIcon = QgsApplication::getThemeIcon( "/mIconClearText.svg" );
-  mClearIconSize = QSize( 16, 16 );
+  int size = fontMetrics().height();
+  mClearIconSize = QSize( size, size );
   mClearIconPixmap = clearIcon.pixmap( mClearIconSize );
   QIcon hoverIcon = QgsApplication::getThemeIcon( "/mIconClearTextHover.svg" );
   mClearHoverPixmap = hoverIcon.pixmap( mClearIconSize );
-
+  // Make some space for the clear icon
+  QMargins margins( textMargins( ) );
+  margins.setRight( size );
+  setTextMargins( margins );
   connect( this, SIGNAL( textChanged( const QString& ) ), this,
            SLOT( onTextChanged( const QString& ) ) );
 }
diff --git a/src/gui/qgsidentifymenu.cpp b/src/gui/qgsidentifymenu.cpp
index f16ea0b..8c2e6fa 100644
--- a/src/gui/qgsidentifymenu.cpp
+++ b/src/gui/qgsidentifymenu.cpp
@@ -349,6 +349,7 @@ void QgsIdentifyMenu::addVectorLayer( QgsVectorLayer* layer, const QList<QgsMapT
     if ( mShowFeatureActions )
     {
       featureActionMenu = new QgsActionMenu( layer, result.mFeature.id(), layerMenu );
+      featureActionMenu->setExpressionContextScope( mExpressionContextScope );
     }
 
     // feature title
@@ -643,3 +644,13 @@ void QgsIdentifyMenu::removeCustomActions()
   mCustomActionRegistry.clear();
 
 }
+
+void QgsIdentifyMenu::setExpressionContextScope( const QgsExpressionContextScope &scope )
+{
+  mExpressionContextScope = scope;
+}
+
+QgsExpressionContextScope QgsIdentifyMenu::expressionContextScope() const
+{
+  return mExpressionContextScope;
+}
diff --git a/src/gui/qgsidentifymenu.h b/src/gui/qgsidentifymenu.h
index e444d6a..5882619 100644
--- a/src/gui/qgsidentifymenu.h
+++ b/src/gui/qgsidentifymenu.h
@@ -148,6 +148,20 @@ class GUI_EXPORT QgsIdentifyMenu : public QMenu
      */
     QList<QgsMapToolIdentify::IdentifyResult> exec( const QList<QgsMapToolIdentify::IdentifyResult>& idResults, QPoint pos );
 
+    /**
+     * Sets an expression context scope used to resolve underlying actions.
+     *
+     * @note Added in QGIS 2.18
+     */
+    void setExpressionContextScope( const QgsExpressionContextScope &scope );
+
+    /**
+     * Returns an expression context scope used to resolve underlying actions.
+     *
+     * @note Added in QGIS 2.18
+     */
+    QgsExpressionContextScope expressionContextScope() const;
+
   protected:
     virtual void closeEvent( QCloseEvent *e ) override;
 
@@ -178,6 +192,8 @@ class GUI_EXPORT QgsIdentifyMenu : public QMenu
     int mMaxLayerDisplay;
     int mMaxFeatureDisplay;
 
+    QgsExpressionContextScope mExpressionContextScope;
+
     // name of the action to be displayed for feature default action, if other actions are shown
     QString mDefaultActionName;
 
diff --git a/src/gui/raster/qgssinglebandgrayrendererwidget.cpp b/src/gui/raster/qgssinglebandgrayrendererwidget.cpp
index 11dd31e..02d2121 100644
--- a/src/gui/raster/qgssinglebandgrayrendererwidget.cpp
+++ b/src/gui/raster/qgssinglebandgrayrendererwidget.cpp
@@ -152,14 +152,17 @@ void QgsSingleBandGrayRendererWidget::setFromRenderer( const QgsRasterRenderer*
   {
     //band
     mGrayBandComboBox->setCurrentIndex( mGrayBandComboBox->findData( gr->grayBand() ) );
-    const QgsContrastEnhancement* ce = gr->contrastEnhancement();
-
     mGradientComboBox->setCurrentIndex( mGradientComboBox->findData( gr->gradient() ) );
-    //minmax
-    mMinLineEdit->setText( QString::number( ce->minimumValue() ) );
-    mMaxLineEdit->setText( QString::number( ce->maximumValue() ) );
-    //contrast enhancement algorithm
-    mContrastEnhancementComboBox->setCurrentIndex(
-      mContrastEnhancementComboBox->findData(( int )( ce->contrastEnhancementAlgorithm() ) ) );
+
+    const QgsContrastEnhancement* ce = gr->contrastEnhancement();
+    if ( ce )
+    {
+      //minmax
+      mMinLineEdit->setText( QString::number( ce->minimumValue() ) );
+      mMaxLineEdit->setText( QString::number( ce->maximumValue() ) );
+      //contrast enhancement algorithm
+      mContrastEnhancementComboBox->setCurrentIndex(
+        mContrastEnhancementComboBox->findData(( int )( ce->contrastEnhancementAlgorithm() ) ) );
+    }
   }
 }
diff --git a/src/gui/symbology-ng/qgscategorizedsymbolrendererv2widget.cpp b/src/gui/symbology-ng/qgscategorizedsymbolrendererv2widget.cpp
index 1c6611b..719e403 100644
--- a/src/gui/symbology-ng/qgscategorizedsymbolrendererv2widget.cpp
+++ b/src/gui/symbology-ng/qgscategorizedsymbolrendererv2widget.cpp
@@ -630,27 +630,18 @@ static void _createCategories( QgsCategoryList& cats, QList<QVariant>& values, Q
   QgsSymbolLayerV2Utils::sortVariantList( values, Qt::AscendingOrder );
 
   int num = values.count();
-
-  bool hasNull = false;
-
   for ( int i = 0; i < num; i++ )
   {
     QVariant value = values[i];
-    if ( value.toString().isNull() )
+    if ( ! value.isNull() )
     {
-      hasNull = true;
+      QgsSymbolV2* newSymbol = symbol->clone();
+      cats.append( QgsRendererCategoryV2( value, newSymbol, value.toString(), true ) );
     }
-    QgsSymbolV2* newSymbol = symbol->clone();
-
-    cats.append( QgsRendererCategoryV2( value, newSymbol, value.toString(), true ) );
-  }
-
-  // add null (default) value if not exists
-  if ( !hasNull )
-  {
-    QgsSymbolV2* newSymbol = symbol->clone();
-    cats.append( QgsRendererCategoryV2( QVariant( "" ), newSymbol, QString(), true ) );
   }
+  // add null (default) value
+  QgsSymbolV2* newSymbol = symbol->clone();
+  cats.append( QgsRendererCategoryV2( QVariant( "" ), newSymbol, QString(), true ) );
 }
 
 QgsVectorColorRampV2* QgsCategorizedSymbolRendererV2Widget::getColorRamp()
diff --git a/src/plugins/offline_editing/offline_editing_plugin_gui.cpp b/src/plugins/offline_editing/offline_editing_plugin_gui.cpp
index 7e99407..fa555c0 100644
--- a/src/plugins/offline_editing/offline_editing_plugin_gui.cpp
+++ b/src/plugins/offline_editing/offline_editing_plugin_gui.cpp
@@ -30,6 +30,7 @@
 #include <QFileDialog>
 #include <QMessageBox>
 #include <QSettings>
+#include <QDebug>
 
 
 QgsSelectLayerTreeModel::QgsSelectLayerTreeModel( QgsLayerTreeGroup* rootNode, QObject* parent )
@@ -43,6 +44,12 @@ QgsSelectLayerTreeModel::~QgsSelectLayerTreeModel()
 {
 }
 
+int QgsSelectLayerTreeModel::columnCount( const QModelIndex &parent ) const
+{
+  return QgsLayerTreeModel::columnCount( parent ) + 1;
+}
+
+/*
 QVariant QgsSelectLayerTreeModel::data( const QModelIndex& index, int role ) const
 {
   if ( role == Qt::CheckStateRole )
@@ -65,7 +72,59 @@ QVariant QgsSelectLayerTreeModel::data( const QModelIndex& index, int role ) con
   }
   return QgsLayerTreeModel::data( index, role );
 }
+*/
 
+QVariant QgsSelectLayerTreeModel::data( const QModelIndex &index, int role ) const
+{
+  QgsLayerTreeNode *node = index2node( index );
+  if ( index.column() == 0 )
+  {
+    if ( role == Qt::CheckStateRole )
+    {
+      if ( QgsLayerTree::isLayer( node ) )
+      {
+        QgsLayerTreeLayer *nodeLayer = QgsLayerTree::toLayer( node );
+        return nodeLayer->isVisible();
+      }
+      else if ( QgsLayerTree::isGroup( node ) )
+      {
+        QgsLayerTreeGroup *nodeGroup = QgsLayerTree::toGroup( node );
+        return nodeGroup->isVisible();
+      }
+      else
+      {
+        return QVariant();
+      }
+    }
+  }
+  else
+  {
+    if ( QgsLayerTree::isLayer( node ) && index.column() > 0 )
+    {
+      QgsLayerTreeLayer *nodeLayer = QgsLayerTree::toLayer( node );
+      QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( nodeLayer->layer() );
+      if ( vlayer && vlayer->dataProvider()->name() == QLatin1String( "WFS" ) )
+      {
+        switch ( role )
+        {
+          case Qt::ToolTipRole:
+            return tr( "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." );
+            break;
+          case Qt::DecorationRole:
+            return QgsApplication::getThemeIcon( "/mIconWarning.svg" );
+            break;
+        }
+      }
+    }
+    return QVariant();
+  }
+  return QgsLayerTreeModel::data( index, role );
+}
 
 QgsOfflineEditingPluginGui::QgsOfflineEditingPluginGui( QWidget* parent, Qt::WindowFlags fl )
     : QDialog( parent, fl )
@@ -80,6 +139,7 @@ QgsOfflineEditingPluginGui::QgsOfflineEditingPluginGui( QWidget* parent, Qt::Win
   QgsLayerTreeGroup* rootNode = QgsLayerTree::toGroup( QgsProject::instance()->layerTreeRoot()->clone() );
   QgsLayerTreeModel* treeModel = new QgsSelectLayerTreeModel( rootNode, this );
   mLayerTree->setModel( treeModel );
+  mLayerTree->header()->setResizeMode( QHeaderView::ResizeToContents );
 
   connect( mSelectAllButton, SIGNAL( clicked() ), this, SLOT( selectAll() ) );
   connect( mUnselectAllButton, SIGNAL( clicked() ), this, SLOT( unSelectAll() ) );
diff --git a/src/plugins/offline_editing/offline_editing_plugin_gui.h b/src/plugins/offline_editing/offline_editing_plugin_gui.h
index 2a0b08e..492796d 100644
--- a/src/plugins/offline_editing/offline_editing_plugin_gui.h
+++ b/src/plugins/offline_editing/offline_editing_plugin_gui.h
@@ -32,6 +32,8 @@ class QgsSelectLayerTreeModel : public QgsLayerTreeModel
     QgsSelectLayerTreeModel( QgsLayerTreeGroup* rootNode, QObject *parent = nullptr );
     ~QgsSelectLayerTreeModel();
 
+    int columnCount( const QModelIndex &parent ) const override;
+
     QVariant data( const QModelIndex &index, int role = Qt::DisplayRole ) const override;
     // bool setData( const QModelIndex &index, const QVariant &value, int role = Qt::EditRole ) override;
 };
diff --git a/src/providers/arcgisrest/qgsafsprovider.cpp b/src/providers/arcgisrest/qgsafsprovider.cpp
index ecf886f..0a9b5c0 100644
--- a/src/providers/arcgisrest/qgsafsprovider.cpp
+++ b/src/providers/arcgisrest/qgsafsprovider.cpp
@@ -157,6 +157,8 @@ QgsFeatureIterator QgsAfsProvider::getFeatures( const QgsFeatureRequest& request
 
 bool QgsAfsProvider::getFeature( const QgsFeatureId &id, QgsFeature &f, bool fetchGeometry, const QList<int>& /*fetchAttributes*/, const QgsRectangle filterRect )
 {
+  QMutexLocker locker( &mMutex );
+
   // If cached, return cached feature
   QMap<QgsFeatureId, QgsFeature>::const_iterator it = mCache.find( id );
   if ( it != mCache.end() )
@@ -214,9 +216,7 @@ bool QgsAfsProvider::getFeature( const QgsFeatureId &id, QgsFeature &f, bool fet
   {
     QVariantMap featureData = featuresData[i].toMap();
     QgsFeature feature;
-
-    // Set FID
-    feature.setFeatureId( startId + i );
+    int featureId = startId + i;
 
     // Set attributes
     if ( !fetchAttribIdx.isEmpty() )
@@ -227,10 +227,17 @@ bool QgsAfsProvider::getFeature( const QgsFeatureId &id, QgsFeature &f, bool fet
       foreach ( int idx, fetchAttribIdx )
       {
         attributes[idx] = attributesData[mFields.at( idx ).name()];
+        if ( mFields.at( idx ).name() == "OBJECTID" )
+        {
+          featureId = startId + objectIds.indexOf( attributesData[mFields.at( idx ).name()].toInt() );
+        }
       }
       feature.setAttributes( attributes );
     }
 
+    // Set FID
+    feature.setFeatureId( featureId );
+
     // Set geometry
     if ( fetchGeometry )
     {
@@ -243,9 +250,16 @@ bool QgsAfsProvider::getFeature( const QgsFeatureId &id, QgsFeature &f, bool fet
     feature.setValid( true );
     mCache.insert( feature.id(), feature );
   }
-  f = mCache[id];
-  Q_ASSERT( f.isValid() );
-  return filterRect.isNull() || ( f.geometry() && f.geometry()->intersects( filterRect ) );
+
+  // If added to cached, return feature
+  it = mCache.find( id );
+  if ( it != mCache.end() )
+  {
+    f = it.value();
+    return filterRect.isNull() || ( f.geometry() && f.geometry()->intersects( filterRect ) );
+  }
+
+  return false;
 }
 
 void QgsAfsProvider::setDataSourceUri( const QString &uri )
diff --git a/src/providers/arcgisrest/qgsafsprovider.h b/src/providers/arcgisrest/qgsafsprovider.h
index 9d01b65..c523600 100644
--- a/src/providers/arcgisrest/qgsafsprovider.h
+++ b/src/providers/arcgisrest/qgsafsprovider.h
@@ -18,6 +18,8 @@
 #ifndef QGSAFSPROVIDER_H
 #define QGSAFSPROVIDER_H
 
+#include <QMutex>
+
 #include "qgsvectordataprovider.h"
 #include "qgsdatasourceuri.h"
 #include "qgscoordinatereferencesystem.h"
@@ -69,6 +71,7 @@ class QgsAfsProvider : public QgsVectorDataProvider
     void reloadData() override { mCache.clear(); }
 
   private:
+    QMutex mMutex;
     bool mValid;
     QgsDataSourceURI mDataSource;
     QgsRectangle mExtent;
diff --git a/src/providers/ogr/qgsogrprovider.cpp b/src/providers/ogr/qgsogrprovider.cpp
index 9be2a3d..dc0b47b 100644
--- a/src/providers/ogr/qgsogrprovider.cpp
+++ b/src/providers/ogr/qgsogrprovider.cpp
@@ -580,6 +580,9 @@ bool QgsOgrProvider::setSubsetString( const QString& theSQL, bool updateFeatureC
 
   invalidateCachedExtent( false );
 
+  // Changing the filter may change capabilities
+  computeCapabilities();
+
   emit dataChanged();
 
   return true;
@@ -1096,6 +1099,11 @@ QgsRectangle QgsOgrProvider::extent()
     }
 #endif
 
+    mExtent->MinX = std::numeric_limits<double>::max();
+    mExtent->MinY = std::numeric_limits<double>::max();
+    mExtent->MaxX = -std::numeric_limits<double>::max();
+    mExtent->MaxY = -std::numeric_limits<double>::max();
+
     // TODO: This can be expensive, do we really need it!
     if ( ogrLayer == ogrOrigLayer )
     {
@@ -1103,18 +1111,13 @@ QgsRectangle QgsOgrProvider::extent()
     }
     else
     {
-      mExtent->MinX = std::numeric_limits<double>::max();
-      mExtent->MinY = std::numeric_limits<double>::max();
-      mExtent->MaxX = -std::numeric_limits<double>::max();
-      mExtent->MaxY = -std::numeric_limits<double>::max();
-
       OGRFeatureH f;
 
       OGR_L_ResetReading( ogrLayer );
       while (( f = OGR_L_GetNextFeature( ogrLayer ) ) )
       {
         OGRGeometryH g = OGR_F_GetGeometryRef( f );
-        if ( g )
+        if ( g && !OGR_G_IsEmpty( g ) )
         {
           OGREnvelope env;
           OGR_G_GetEnvelope( g, &env );
@@ -1656,17 +1659,19 @@ bool QgsOgrProvider::changeAttributeValues( const QgsChangedAttributesMap &attr_
   {
     QgsFeatureId fid = it.key();
 
+#if !(defined(GDAL_COMPUTE_VERSION) && GDAL_VERSION_NUM < GDAL_COMPUTE_VERSION(2,0,0))
     if ( FID_TO_NUMBER( fid ) > std::numeric_limits<long>::max() )
     {
       pushError( tr( "OGR error on feature %1: id too large" ).arg( fid ) );
       continue;
     }
+#endif
 
     const QgsAttributeMap &attr = it.value();
     if ( attr.isEmpty() )
       continue;
 
-    OGRFeatureH of = OGR_L_GetFeature( ogrLayer, static_cast<long>( FID_TO_NUMBER( fid ) ) );
+    OGRFeatureH of = OGR_L_GetFeature( ogrLayer, FID_TO_NUMBER( fid ) );
     if ( !of )
     {
       pushError( tr( "Feature %1 for attribute update not found." ).arg( fid ) );
@@ -1803,13 +1808,15 @@ bool QgsOgrProvider::changeGeometryValues( const QgsGeometryMap &geometry_map )
 
   for ( QgsGeometryMap::const_iterator it = geometry_map.constBegin(); it != geometry_map.constEnd(); ++it )
   {
+#if !(defined(GDAL_COMPUTE_VERSION) && GDAL_VERSION_NUM < GDAL_COMPUTE_VERSION(2,0,0))
     if ( FID_TO_NUMBER( it.key() ) > std::numeric_limits<long>::max() )
     {
       pushError( tr( "OGR error on feature %1: id too large" ).arg( it.key() ) );
       continue;
     }
+#endif
 
-    OGRFeatureH theOGRFeature = OGR_L_GetFeature( ogrLayer, static_cast<long>( FID_TO_NUMBER( it.key() ) ) );
+    OGRFeatureH theOGRFeature = OGR_L_GetFeature( ogrLayer, FID_TO_NUMBER( it.key() ) );
     if ( !theOGRFeature )
     {
       pushError( tr( "OGR error changing geometry: feature %1 not found" ).arg( it.key() ) );
@@ -1959,11 +1966,13 @@ bool QgsOgrProvider::deleteFeature( QgsFeatureId id )
   if ( !doInitialActionsForEdition() )
     return false;
 
+#if !(defined(GDAL_COMPUTE_VERSION) && GDAL_VERSION_NUM < GDAL_COMPUTE_VERSION(2,0,0))
   if ( FID_TO_NUMBER( id ) > std::numeric_limits<long>::max() )
   {
     pushError( tr( "OGR error on feature %1: id too large" ).arg( id ) );
     return false;
   }
+#endif
 
   if ( OGR_L_DeleteFeature( ogrLayer, FID_TO_NUMBER( id ) ) != OGRERR_NONE )
   {
diff --git a/src/providers/postgres/qgspostgresconn.cpp b/src/providers/postgres/qgspostgresconn.cpp
index c46d362..207f900 100644
--- a/src/providers/postgres/qgspostgresconn.cpp
+++ b/src/providers/postgres/qgspostgresconn.cpp
@@ -222,7 +222,26 @@ QgsPostgresConn::QgsPostgresConn( const QString& conninfo, bool readOnly, bool s
     {
       QString fileName = expandedUri.param( param );
       fileName.remove( "'" );
-      QFile::remove( fileName );
+      QFile file( fileName );
+      // set minimal permission to allow removing on Win.
+      // On linux and Mac if file is set with QFile::>ReadUser
+      // does not create problem removin certs
+      if ( !file.setPermissions( QFile::WriteOwner ) )
+      {
+        QString errorMsg = tr( "Cannot set WriteOwner permission to cert: %0 to allow removing it" ).arg( file.fileName() );
+        PQfinish();
+        QgsMessageLog::logMessage( tr( "Client security failure" ) + '\n' + errorMsg, tr( "PostGIS" ) );
+        mRef = 0;
+        return;
+      }
+      if ( !file.remove() )
+      {
+        QString errorMsg = tr( "Cannot remove cert: %0 to allow removing it" ).arg( file.fileName() );
+        PQfinish();
+        QgsMessageLog::logMessage( tr( "Client security failure" ) + '\n' + errorMsg, tr( "PostGIS" ) );
+        mRef = 0;
+        return;
+      }
     }
   }
 
diff --git a/src/providers/postgres/qgspostgresfeatureiterator.cpp b/src/providers/postgres/qgspostgresfeatureiterator.cpp
index acce046..2ef8e68 100644
--- a/src/providers/postgres/qgspostgresfeatureiterator.cpp
+++ b/src/providers/postgres/qgspostgresfeatureiterator.cpp
@@ -31,6 +31,7 @@ const int QgsPostgresFeatureIterator::sFeatureQueueSize = 2000;
 
 QgsPostgresFeatureIterator::QgsPostgresFeatureIterator( QgsPostgresFeatureSource* source, bool ownSource, const QgsFeatureRequest& request )
     : QgsAbstractFeatureIteratorFromSource<QgsPostgresFeatureSource>( source, ownSource, request )
+    , mConn( nullptr )
     , mFeatureQueueSize( sFeatureQueueSize )
     , mFetched( 0 )
     , mFetchGeometry( false )
@@ -39,6 +40,13 @@ QgsPostgresFeatureIterator::QgsPostgresFeatureIterator( QgsPostgresFeatureSource
     , mLastFetch( false )
     , mFilterRequiresGeometry( false )
 {
+  if ( request.filterType() == QgsFeatureRequest::FilterFids && request.filterFids().isEmpty() )
+  {
+    mClosed = true;
+    iteratorClosed();
+    return;
+  }
+
   if ( !source->mTransactionConnection )
   {
     mConn = QgsPostgresConnPool::instance()->acquireConnection( mSource->mConnInfo );
diff --git a/src/providers/postgres/qgspostgresprovider.cpp b/src/providers/postgres/qgspostgresprovider.cpp
index c3c0f94..244d515 100644
--- a/src/providers/postgres/qgspostgresprovider.cpp
+++ b/src/providers/postgres/qgspostgresprovider.cpp
@@ -2923,6 +2923,12 @@ long QgsPostgresProvider::featureCount() const
   if ( featuresCounted >= 0 )
     return featuresCounted;
 
+  // See: https://issues.qgis.org/issues/17388 - QGIS crashes on featureCount())
+  if ( ! connectionRO() )
+  {
+    return 0;
+  }
+
   // get total number of features
   QString sql;
 
diff --git a/src/providers/virtual/qgsvirtuallayerfeatureiterator.cpp b/src/providers/virtual/qgsvirtuallayerfeatureiterator.cpp
index 7a3bb57..27b38cc 100644
--- a/src/providers/virtual/qgsvirtuallayerfeatureiterator.cpp
+++ b/src/providers/virtual/qgsvirtuallayerfeatureiterator.cpp
@@ -37,6 +37,7 @@ QgsVirtualLayerFeatureIterator::QgsVirtualLayerFeatureIterator( QgsVirtualLayerF
     QString tableName = mSource->provider()->mTableName;
 
     QStringList wheres;
+    QString offset;
     QString subset = mSource->provider()->mSubset;
     if ( !subset.isNull() )
     {
@@ -76,6 +77,17 @@ QgsVirtualLayerFeatureIterator::QgsVirtualLayerFeatureIterator( QgsVirtualLayerF
       values += ")";
       wheres << values;
     }
+    else if ( mDefinition.uid().isNull() && request.filterType() == QgsFeatureRequest::FilterFid )
+    {
+      if ( request.filterFid() >= 0 )
+      {
+        offset = QString( " LIMIT 1 OFFSET %1" ).arg( request.filterFid() );
+      }
+      else // never return a feature if the id is negative
+      {
+        offset = QString( " LIMIT 0" );
+      }
+    }
 
     mFields = mSource->provider()->fields();
     if ( request.flags() & QgsFeatureRequest::SubsetOfAttributes )
@@ -111,7 +123,15 @@ QgsVirtualLayerFeatureIterator::QgsVirtualLayerFeatureIterator( QgsVirtualLayerF
       }
       else
       {
-        columns = "0";
+        columns = QString( "0" );
+        if ( request.filterType() == QgsFeatureRequest::FilterFid )
+        {
+          columns = QString::number( request.filterFid() );
+        }
+        else
+        {
+          columns = QString( "0" );
+        }
       }
       Q_FOREACH ( int i, mAttributes )
       {
@@ -134,6 +154,11 @@ QgsVirtualLayerFeatureIterator::QgsVirtualLayerFeatureIterator( QgsVirtualLayerF
       mSqlQuery += " WHERE " + wheres.join( " AND " );
     }
 
+    if ( !offset.isEmpty() )
+    {
+      mSqlQuery += offset;
+    }
+
     mQuery.reset( new Sqlite::Query( mSqlite, mSqlQuery ) );
 
     mFid = 0;
@@ -191,7 +216,8 @@ bool QgsVirtualLayerFeatureIterator::fetchFeature( QgsFeature& feature )
 
   feature.setFields( mFields, /* init */ true );
 
-  if ( mDefinition.uid().isNull() )
+  if ( mDefinition.uid().isNull() &&
+       mRequest.filterType() != QgsFeatureRequest::FilterFid )
   {
     // no id column => autoincrement
     feature.setFeatureId( mFid++ );
diff --git a/src/providers/virtual/qgsvirtuallayersourceselect.cpp b/src/providers/virtual/qgsvirtuallayersourceselect.cpp
index 72575a9..d1f1b67 100644
--- a/src/providers/virtual/qgsvirtuallayersourceselect.cpp
+++ b/src/providers/virtual/qgsvirtuallayersourceselect.cpp
@@ -229,15 +229,20 @@ QgsVirtualLayerDefinition QgsVirtualLayerSourceSelect::getVirtualLayerDef()
 void QgsVirtualLayerSourceSelect::onTestQuery()
 {
   QgsVirtualLayerDefinition def = getVirtualLayerDef();
-
-  QScopedPointer<QgsVectorLayer> vl( new QgsVectorLayer( def.toString(), "test", "virtual" ) );
-  if ( vl->isValid() )
-  {
-    QMessageBox::information( nullptr, tr( "Virtual layer test" ), tr( "No error" ) );
-  }
-  else
+  // If the definition is empty just do nothing.
+  // TODO: a validation function that can enable/disable the test button
+  //       according to the validity of the active layer definition
+  if ( ! def.toString().isEmpty() )
   {
-    QMessageBox::critical( nullptr, tr( "Virtual layer test" ), vl->dataProvider()->error().summary() );
+    QScopedPointer<QgsVectorLayer> vl( new QgsVectorLayer( def.toString(), "test", "virtual" ) );
+    if ( vl->isValid() )
+    {
+      QMessageBox::information( nullptr, tr( "Virtual layer test" ), tr( "No error" ) );
+    }
+    else
+    {
+      QMessageBox::critical( nullptr, tr( "Virtual layer test" ), vl->dataProvider()->error().summary() );
+    }
   }
 }
 
diff --git a/src/providers/wfs/qgswfsfeatureiterator.cpp b/src/providers/wfs/qgswfsfeatureiterator.cpp
index f0b3774..562ae4e 100644
--- a/src/providers/wfs/qgswfsfeatureiterator.cpp
+++ b/src/providers/wfs/qgswfsfeatureiterator.cpp
@@ -759,11 +759,25 @@ void QgsWFSThreadedFeatureDownloader::stop()
   }
 }
 
+void QgsWFSThreadedFeatureDownloader::startAndWait()
+{
+  start();
+
+  QMutexLocker locker( &mWaitMutex );
+  while ( !mDownloader )
+  {
+    mWaitCond.wait( &mWaitMutex );
+  }
+}
+
 void QgsWFSThreadedFeatureDownloader::run()
 {
   // We need to construct it in the run() method (i.e. in the new thread)
   mDownloader = new QgsWFSFeatureDownloader( mShared );
-  emit ready();
+  {
+    QMutexLocker locker( &mWaitMutex );
+    mWaitCond.wakeOne();
+  }
   mDownloader->run( true, /* serialize features */
                     0 /* user max features */ );
 }
diff --git a/src/providers/wfs/qgswfsfeatureiterator.h b/src/providers/wfs/qgswfsfeatureiterator.h
index 6683d00..6af8fd6 100644
--- a/src/providers/wfs/qgswfsfeatureiterator.h
+++ b/src/providers/wfs/qgswfsfeatureiterator.h
@@ -24,6 +24,8 @@
 
 #include <QProgressDialog>
 #include <QPushButton>
+#include <QMutex>
+#include <QWaitCondition>
 
 class QgsWFSProvider;
 class QgsWFSSharedData;
@@ -164,13 +166,11 @@ class QgsWFSThreadedFeatureDownloader: public QThread
     /** Return downloader object */
     QgsWFSFeatureDownloader* downloader() { return mDownloader; }
 
-    /** Stops (synchronously) the download */
-    void stop();
-
-  signals:
-    /** Emitted when the thread is ready */
-    void ready();
+    //! Starts thread and wait for it to be started
+    void startAndWait();
 
+    //! Stops (synchronously) the download
+    void stop();
   protected:
     /** Inherited from QThread. Starts the download */
     void run() override;
@@ -178,6 +178,8 @@ class QgsWFSThreadedFeatureDownloader: public QThread
   private:
     QgsWFSSharedData* mShared;  //!< Mutable data shared between provider and feature sources
     QgsWFSFeatureDownloader* mDownloader;
+    QWaitCondition mWaitCond;
+    QMutex mWaitMutex;
 };
 
 class QgsWFSFeatureSource;
diff --git a/src/providers/wfs/qgswfsshareddata.cpp b/src/providers/wfs/qgswfsshareddata.cpp
index c935c2a..656422f 100644
--- a/src/providers/wfs/qgswfsshareddata.cpp
+++ b/src/providers/wfs/qgswfsshareddata.cpp
@@ -553,10 +553,7 @@ int QgsWFSSharedData::registerToCache( QgsWFSFeatureIterator* iterator, QgsRecta
     mDownloadFinished = false;
     mComputedExtent = QgsRectangle();
     mDownloader = new QgsWFSThreadedFeatureDownloader( this );
-    QEventLoop loop;
-    connect( mDownloader, SIGNAL( ready() ), &loop, SLOT( quit() ) );
-    mDownloader->start();
-    loop.exec( QEventLoop::ExcludeUserInputEvents );
+    mDownloader->startAndWait();
   }
   if ( mDownloadFinished )
     return -1;
diff --git a/src/server/qgswmsserver.cpp b/src/server/qgswmsserver.cpp
index 2dc9194..ad5942c 100644
--- a/src/server/qgswmsserver.cpp
+++ b/src/server/qgswmsserver.cpp
@@ -1832,26 +1832,26 @@ int QgsWMSServer::getFeatureInfo( QDomDocument& result, const QString& version )
       }
       else //raster layer
       {
+        QgsRasterLayer* rasterLayer = qobject_cast<QgsRasterLayer*>( currentLayer );
+        if ( !rasterLayer )
+        {
+          continue;
+        }
+        if ( !infoPoint.data() )
+        {
+          continue;
+        }
+        QgsPoint layerInfoPoint = mMapRenderer->mapToLayerCoordinates( currentLayer, *( infoPoint.data() ) );
+        if ( !rasterLayer->extent().contains( layerInfoPoint ) )
+        {
+          continue;
+        }
         if ( infoFormat.startsWith( "application/vnd.ogc.gml" ) )
         {
           layerElement = result.createElement( "gml:featureMember"/*wfs:FeatureMember*/ );
           getFeatureInfoElement.appendChild( layerElement );
         }
-
-        QgsRasterLayer* rasterLayer = qobject_cast<QgsRasterLayer*>( currentLayer );
-        if ( rasterLayer )
-        {
-          if ( !infoPoint.data() )
-          {
-            continue;
-          }
-          QgsPoint layerInfoPoint = mMapRenderer->mapToLayerCoordinates( currentLayer, *( infoPoint.data() ) );
-          if ( featureInfoFromRasterLayer( rasterLayer, &layerInfoPoint, result, layerElement, version, infoFormat ) != 0 )
-          {
-            continue;
-          }
-        }
-        else
+        if ( featureInfoFromRasterLayer( rasterLayer, &layerInfoPoint, result, layerElement, version, infoFormat ) != 0 )
         {
           continue;
         }
@@ -2563,17 +2563,36 @@ int QgsWMSServer::featureInfoFromRasterLayer( QgsRasterLayer* layer,
   if ( !identifyResult.isValid() )
     return 1;
 
-  QMap<int, QVariant> attributes = identifyResult.results();
+  QMap<int, QVariant> values = identifyResult.results();
   if ( infoFormat == "application/vnd.ogc.gml" )
   {
     QgsFeature feature;
     QgsFields fields;
-    feature.initAttributes( attributes.count() );
+    feature.initAttributes( values.count() );
     int index = 0;
-    for ( QMap<int, QVariant>::const_iterator it = attributes.constBegin(); it != attributes.constEnd(); ++it )
+    Q_FOREACH ( int bandNo, values.keys() )
     {
-      fields.append( QgsField( layer->bandName( it.key() ), QVariant::Double ) );
-      feature.setAttribute( index++, QString::number( it.value().toDouble() ) );
+      if ( values.value( bandNo ).isNull() )
+      {
+        fields.append( QgsField( layer->bandName( bandNo ), QVariant::String ) );
+        feature.setAttribute( index++, "no data" );
+      }
+      else
+      {
+        QVariant value( values.value( bandNo ) );
+        fields.append( QgsField( layer->bandName( bandNo ), QVariant::Double ) );
+        // The cast is legit. Quoting QT doc :
+        // "Although this function is declared as returning QVariant::Type,
+        // the return value should be interpreted as QMetaType::Type"
+        if ( static_cast<QMetaType::Type>( value.type() ) == QMetaType::Float )
+        {
+          feature.setAttribute( index++, QString::number( value.toFloat() ) );
+        }
+        else
+        {
+          feature.setAttribute( index++, QString::number( value.toDouble() ) );
+        }
+      }
     }
     feature.setFields( fields );
 
@@ -2590,11 +2609,31 @@ int QgsWMSServer::featureInfoFromRasterLayer( QgsRasterLayer* layer,
   }
   else
   {
-    for ( QMap<int, QVariant>::const_iterator it = attributes.constBegin(); it != attributes.constEnd(); ++it )
+    Q_FOREACH ( int bandNo, values.keys() )
     {
+      QString valueString;
+      if ( values.value( bandNo ).isNull() )
+      {
+        valueString = "no data";
+      }
+      else
+      {
+        QVariant value( values.value( bandNo ) );
+        // The cast is legit. Quoting QT doc :
+        // "Although this function is declared as returning QVariant::Type,
+        // the return value should be interpreted as QMetaType::Type"
+        if ( static_cast<QMetaType::Type>( value.type() ) == QMetaType::Float )
+        {
+          valueString = QgsRasterBlock::printValue( value.toFloat() );
+        }
+        else
+        {
+          valueString = QgsRasterBlock::printValue( value.toDouble() );
+        }
+      }
       QDomElement attributeElement = infoDocument.createElement( "Attribute" );
-      attributeElement.setAttribute( "name", layer->bandName( it.key() ) );
-      attributeElement.setAttribute( "value", QString::number( it.value().toDouble() ) );
+      attributeElement.setAttribute( "name", layer->bandName( bandNo ) );
+      attributeElement.setAttribute( "value", valueString );
       layerElement.appendChild( attributeElement );
     }
   }
diff --git a/src/ui/qgsnewgeopackagelayerdialogbase.ui b/src/ui/qgsnewgeopackagelayerdialogbase.ui
index 2da55c8..8bd1381 100644
--- a/src/ui/qgsnewgeopackagelayerdialogbase.ui
+++ b/src/ui/qgsnewgeopackagelayerdialogbase.ui
@@ -69,7 +69,7 @@
        <item row="4" column="0">
         <widget class="QCheckBox" name="mCheckBoxCreateSpatialIndex">
          <property name="toolTip">
-          <string>Add an integer id field as the primary key for the new layer</string>
+          <string>Create a spatial index for this layer</string>
          </property>
          <property name="text">
           <string>Create a spatial index</string>
diff --git a/tests/src/app/CMakeLists.txt b/tests/src/app/CMakeLists.txt
index a454860..56a66bb 100644
--- a/tests/src/app/CMakeLists.txt
+++ b/tests/src/app/CMakeLists.txt
@@ -23,6 +23,7 @@ INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}
 )
 INCLUDE_DIRECTORIES(SYSTEM
   ${QT_INCLUDE_DIR}
+  ${QWT_INCLUDE_DIR}
   ${GDAL_INCLUDE_DIR}
   ${PROJ_INCLUDE_DIR}
   ${GEOS_INCLUDE_DIR}
diff --git a/tests/src/app/testqgsmaptoolidentifyaction.cpp b/tests/src/app/testqgsmaptoolidentifyaction.cpp
index 0659112..e54e473 100644
--- a/tests/src/app/testqgsmaptoolidentifyaction.cpp
+++ b/tests/src/app/testqgsmaptoolidentifyaction.cpp
@@ -24,6 +24,9 @@
 #include "qgsmapcanvas.h"
 #include "qgsunittypes.h"
 #include "qgsmaptoolidentifyaction.h"
+#include "qgisapp.h"
+#include "qgsidentifymenu.h"
+#include "qgsidentifyresultsdialog.h"
 
 #include "cpl_conv.h"
 
@@ -46,9 +49,11 @@ class TestQgsMapToolIdentifyAction : public QObject
     void identifyRasterFloat32(); // test pixel identification and decimal precision
     void identifyRasterFloat64(); // test pixel identification and decimal precision
     void identifyInvalidPolygons(); // test selecting invalid polygons
+    void clickxy(); // test if click_x and click_y variables are propagated
 
   private:
     QgsMapCanvas* canvas;
+    QgisApp *mQgisApp;
 
     QString testIdentifyRaster( QgsRasterLayer* layer, double xGeoref, double yGeoref );
     QList<QgsMapToolIdentify::IdentifyResult> testIdentifyVector( QgsVectorLayer* layer, double xGeoref, double yGeoref );
@@ -91,6 +96,8 @@ void TestQgsMapToolIdentifyAction::initTestCase()
   // enforce C locale because the tests expect it
   // (decimal separators / thousand separators)
   QLocale::setDefault( QLocale::c() );
+
+  mQgisApp = new QgisApp();
 }
 
 void TestQgsMapToolIdentifyAction::cleanupTestCase()
@@ -108,6 +115,57 @@ void TestQgsMapToolIdentifyAction::cleanup()
   delete canvas;
 }
 
+void TestQgsMapToolIdentifyAction::clickxy()
+{
+  int clickxOk = 2484588;
+  int clickyOk = 2425722;
+
+  // create temp layer
+  QScopedPointer<QgsVectorLayer> tempLayer( new QgsVectorLayer( QString( "Point?crs=epsg:3111" ), QString( "vl" ), QString( "memory" ) ) );
+  QVERIFY( tempLayer->isValid() );
+
+  // add feature
+  QgsFeature f1( tempLayer->dataProvider()->fields(), 1 );
+  QgsPoint wordPoint( clickxOk, clickyOk );
+  QgsGeometry *geom = QgsGeometry::fromPoint( wordPoint ) ;
+  f1.setGeometry( geom );
+  tempLayer->dataProvider()->addFeatures( QgsFeatureList() << f1 );
+
+  // prepare canvas
+  QgsCoordinateReferenceSystem srs( 3111, QgsCoordinateReferenceSystem::EpsgCrsId );
+  canvas->setDestinationCrs( srs );
+  canvas->setCurrentLayer( tempLayer.data() );
+
+  // init map tool identify action
+  QScopedPointer<QgsMapToolIdentifyAction> identifyAction( new QgsMapToolIdentifyAction( canvas ) );
+
+  // simulate a click on the canvas
+  QgsPoint mapPoint = canvas->getCoordinateTransform()->transform( 2484588, 2425722 );
+  QPoint point = QPoint( mapPoint.x(), mapPoint.y() );
+  QMouseEvent releases( QEvent::MouseButtonRelease, point,
+                        Qt::RightButton, Qt::LeftButton, Qt::NoModifier );
+  QgsMapMouseEvent mapReleases( 0, &releases );
+
+  identifyAction->canvasReleaseEvent( &mapReleases );
+
+  // test QgsIdentifyMenu expression context scope
+  bool ok;
+  QgsIdentifyMenu *menu = identifyAction->identifyMenu();
+  int clickx = menu->expressionContextScope().variable( "click_x" ).toString().toInt( &ok, 10 );
+  QCOMPARE( clickx, clickxOk );
+
+  int clicky = menu->expressionContextScope().variable( "click_y" ).toString().toInt( &ok, 10 );
+  QCOMPARE( clicky, clickyOk );
+
+  // test QgsIdentifyResultsDialog expression context scope
+  QgsIdentifyResultsDialog *dlg = identifyAction->resultsDialog();
+  clickx = dlg->expressionContextScope().variable( "click_x" ).toString().toInt( &ok, 10 );
+  QCOMPARE( clickx, clickxOk );
+
+  clicky = dlg->expressionContextScope().variable( "click_y" ).toString().toInt( &ok, 10 );
+  QCOMPARE( clicky, clickyOk );
+}
+
 void TestQgsMapToolIdentifyAction::lengthCalculation()
 {
   QSettings s;
diff --git a/tests/src/core/testqgsgml.cpp b/tests/src/core/testqgsgml.cpp
index 7e1ea6b..81b185a 100644
--- a/tests/src/core/testqgsgml.cpp
+++ b/tests/src/core/testqgsgml.cpp
@@ -76,6 +76,7 @@ class TestQgsGML : public QObject
     void testThroughOGRGeometry();
     void testThroughOGRGeometry_urn_EPSG_4326();
     void testAccents();
+    void testSameTypeameAsGeomName();
 };
 
 const QString data1( "<myns:FeatureCollection "
@@ -1149,6 +1150,51 @@ void TestQgsGML::testAccents()
   QCOMPARE( multi[0][0].size(), 5 );
   delete features[0].first;
 }
+void TestQgsGML::testSameTypeameAsGeomName()
+{
+  QgsFields fields;
+  QgsGmlStreamingParser gmlParser( "foo", "foo", fields );
+  QCOMPARE( gmlParser.processData( QByteArray( "<myns:FeatureCollection "
+                                   "xmlns:myns='http://myns' "
+                                   "xmlns:gml='http://www.opengis.net/gml'>"
+                                   "<gml:featureMember>"
+                                   "<myns:foo fid='foo.1'>"
+                                   "<myns:foo>"
+                                   "<gml:MultiSurface srsName='EPSG:27700'>"
+                                   "<gml:surfaceMember>"
+                                   "<gml:Polygon srsName='EPSG:27700'>"
+                                   "<gml:exterior>"
+                                   "<gml:LinearRing>"
+                                   "<gml:posList>0 0 0 10 10 10 10 0 0 0</gml:posList>"
+                                   "</gml:LinearRing>"
+                                   "</gml:exterior>"
+                                   "</gml:Polygon>"
+                                   "</gml:surfaceMember>"
+                                   "<gml:surfaceMember>"
+                                   "<gml:Polygon srsName='EPSG:27700'>"
+                                   "<gml:exterior>"
+                                   "<gml:LinearRing>"
+                                   "<gml:posList>0 0 0 10 10 10 10 0 0 0</gml:posList>"
+                                   "</gml:LinearRing>"
+                                   "</gml:exterior>"
+                                   "</gml:Polygon>"
+                                   "</gml:surfaceMember>"
+                                   "</gml:MultiSurface>"
+                                   "</myns:foo>"
+                                   "</myns:foo>"
+                                   "</gml:featureMember>"
+                                   "</myns:FeatureCollection>" ), true ), true );
+  QCOMPARE( gmlParser.wkbType(), QGis::WKBMultiPolygon );
+  QVector<QgsGmlStreamingParser::QgsGmlFeaturePtrGmlIdPair> features = gmlParser.getAndStealReadyFeatures();
+  QCOMPARE( features.size(), 1 );
+  QVERIFY( features[0].first->constGeometry() != nullptr );
+  QCOMPARE( features[0].first->constGeometry()->wkbType(), QGis::WKBMultiPolygon );
+  QgsMultiPolygon multi = features[0].first->constGeometry()->asMultiPolygon();
+  QCOMPARE( multi.size(), 2 );
+  QCOMPARE( multi[0].size(), 1 );
+  QCOMPARE( multi[0][0].size(), 5 );
+  delete features[0].first;
+}
 
 QTEST_MAIN( TestQgsGML )
 #include "testqgsgml.moc"
diff --git a/tests/src/python/test_provider_ogr_gpkg.py b/tests/src/python/test_provider_ogr_gpkg.py
index 04e8d84..bec190a 100644
--- a/tests/src/python/test_provider_ogr_gpkg.py
+++ b/tests/src/python/test_provider_ogr_gpkg.py
@@ -386,6 +386,39 @@ class TestPyQgsOGRProviderGpkg(unittest.TestCase):
         reference = QgsGeometry.fromWkt('Point (5 5)')
         self.assertEqual(got_geom.asWkb(), reference.asWkb(), 'Expected {}, got {}'.format(reference.exportToWkt(), got_geom.exportToWkt()))
 
+    @unittest.expectedFailure(int(gdal.VersionInfo('VERSION_NUM')) < GDAL_COMPUTE_VERSION(2, 0, 0))
+    def testGeopackageLargeFID(self):
+
+        tmpfile = os.path.join(self.basetestpath, 'testGeopackageLargeFID.gpkg')
+        ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile)
+        lyr = ds.CreateLayer('test', geom_type=ogr.wkbPoint)
+        lyr.CreateField(ogr.FieldDefn('str_field', ogr.OFTString))
+        ds = None
+
+        vl = QgsVectorLayer(u'{}'.format(tmpfile) + "|layername=" + "test", 'test', u'ogr')
+        f = QgsFeature()
+        f.setAttributes([1234567890123, None])
+        self.assertTrue(vl.startEditing())
+        self.assertTrue(vl.dataProvider().addFeatures([f]))
+        self.assertTrue(vl.commitChanges())
+
+        got = [feat for feat in vl.getFeatures()][0]
+        self.assertEqual(got['fid'], 1234567890123)
+
+        self.assertTrue(vl.startEditing())
+        self.assertTrue(vl.changeGeometry(1234567890123, QgsGeometry.fromWkt('Point (3 50)')))
+        self.assertTrue(vl.changeAttributeValue(1234567890123, 1, 'foo'))
+        self.assertTrue(vl.commitChanges())
+
+        got = [feat for feat in vl.getFeatures()][0]
+        self.assertEqual(got['str_field'], 'foo')
+        got_geom = got.geometry()
+        self.assertIsNotNone(got_geom)
+
+        self.assertTrue(vl.startEditing())
+        self.assertTrue(vl.deleteFeature(1234567890123))
+        self.assertTrue(vl.commitChanges())
+
 
 if __name__ == '__main__':
     unittest.main()
diff --git a/tests/src/python/test_provider_virtual.py b/tests/src/python/test_provider_virtual.py
index f27d46a..07869e7 100644
--- a/tests/src/python/test_provider_virtual.py
+++ b/tests/src/python/test_provider_virtual.py
@@ -86,6 +86,46 @@ class TestQgsVirtualLayerProvider(unittest.TestCase, ProviderTestCase):
         """Run after each test."""
         pass
 
+    def test_filterfid_crossjoin(self):
+        l0 = QgsVectorLayer(os.path.join(self.testDataDir, "france_parts.shp"), "france_parts", "ogr")
+        self.assertTrue(l0.isValid())
+        QgsMapLayerRegistry.instance().addMapLayer(l0)
+
+        l1 = QgsVectorLayer(os.path.join(self.testDataDir, "points.shp"), "points", "ogr")
+        self.assertTrue(l1.isValid())
+        QgsMapLayerRegistry.instance().addMapLayer(l1)
+
+        # cross join
+        query = QUrl.toPercentEncoding("SELECT * FROM france_parts,points")
+        vl = QgsVectorLayer("?query=%s" % query, "tt", "virtual")
+
+        self.assertEqual(vl.featureCount(), l0.featureCount() * l1.featureCount())
+
+        # test with FilterFid requests
+        f = next(vl.getFeatures(QgsFeatureRequest().setFilterFid(0)))
+        idx = f.fields().fieldNameIndex('Class')
+        self.assertEqual(f.id(), 0)
+        self.assertEqual(f.attributes()[idx], 'Jet')
+
+        f = next(vl.getFeatures(QgsFeatureRequest().setFilterFid(5)))
+        self.assertEqual(f.id(), 5)
+        self.assertEqual(f.attributes()[idx], 'Biplane')
+
+        # test with FilterFid requests
+        fit = vl.getFeatures(QgsFeatureRequest().setFilterFids([0, 3, 5]))
+
+        f = next(fit)
+        self.assertEqual(f.id(), 0)
+        self.assertEqual(f.attributes()[idx], 'Jet')
+
+        f = next(fit)
+        self.assertEqual(f.id(), 3)
+        self.assertEqual(f.attributes()[idx], 'Jet')
+
+        f = next(fit)
+        self.assertEqual(f.id(), 5)
+        self.assertEqual(f.attributes()[idx], 'Biplane')
+
     def test_CsvNoGeometry(self):
         l1 = QgsVectorLayer(QUrl.fromLocalFile(os.path.join(self.testDataDir, "delimitedtext/test.csv")).toString() + "?type=csv&geomType=none&subsetIndex=no&watchFile=no", "test", "delimitedtext", False)
         self.assertEqual(l1.isValid(), True)

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