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