This is an automated email from the git hooks/post-receive script. sebastic pushed a commit to branch master in repository qgis.
commit bf5cbed3365f03250d0c8f4f8b8416d4071eded7 Author: Bas Couwenberg <[email protected]> Date: Fri May 20 14:59:53 2016 +0200 Imported Upstream version 2.14.3+dfsg --- CMakeLists.txt | 2 +- ChangeLog | 179 +++++++++++++++++++++ debian/changelog | 10 +- debian/python-qgis.install.in | 3 +- ms-windows/osgeo4w/browser-grass.bat.tmpl | 1 + python/PyQt/CMakeLists.txt | 22 ++- python/PyQt/PyQt4/QtCore.py | 40 +++++ python/PyQt/PyQt4/{QtCore.py => QtNetwork.py} | 16 +- python/PyQt/PyQt4/{QtCore.py => QtSql.py} | 16 +- python/PyQt/PyQt4/{QtCore.py => QtSvg.py} | 16 +- python/PyQt/PyQt4/{QtCore.py => QtTest.py} | 16 +- python/PyQt/PyQt4/{QtCore.py => QtXml.py} | 16 +- python/PyQt/PyQt4/{QtCore.py => uic/__init__.py} | 19 ++- python/PyQt/PyQt4/uic/properties.py | 1 + python/PyQt/PyQt4/{QtCore.py => uic/pyuic.py} | 21 ++- python/PyQt/PyQt5/QtCore.py | 2 + python/PyQt/PyQt5/QtNetwork.py | 1 + python/PyQt/PyQt5/QtSql.py | 1 + python/PyQt/PyQt5/QtSvg.py | 1 + python/PyQt/PyQt5/QtTest.py | 1 + python/PyQt/PyQt5/QtWidgets.py | 2 + python/PyQt/PyQt5/QtXml.py | 1 + .../{PyQt4/QtCore.py => PyQt5/uic/__init__.py} | 19 ++- python/PyQt/PyQt5/uic/properties.py | 1 + python/PyQt/PyQt5/uic/pyuic.py | 1 + python/core/__init__.py | 2 +- python/core/symbology-ng/qgsfillsymbollayerv2.sip | 4 + python/core/symbology-ng/qgslinesymbollayerv2.sip | 1 + python/plugins/processing/gui/ParametersPanel.py | 4 +- .../plugins/processing/gui/ScriptEditorDialog.py | 3 + resources/function_help/json/$scale | 2 +- scripts/qgis_fixes/fix_pyqt.py | 18 +-- scripts/release.pl | 6 +- src/app/qgisapp.cpp | 13 +- src/app/qgsfieldsproperties.cpp | 2 +- src/core/geometry/qgsgeometry.cpp | 2 +- src/core/qgsapplication.cpp | 4 +- src/core/qgsexpression.cpp | 16 +- src/core/qgsvectorlayerfeatureiterator.cpp | 15 +- src/core/symbology-ng/qgsfillsymbollayerv2.cpp | 22 +++ src/core/symbology-ng/qgsfillsymbollayerv2.h | 5 +- src/core/symbology-ng/qgslinesymbollayerv2.cpp | 5 + src/core/symbology-ng/qgslinesymbollayerv2.h | 1 + src/gui/qgsadvanceddigitizingdockwidget.cpp | 4 +- src/gui/qgsfieldproxymodel.cpp | 4 +- src/gui/symbology-ng/qgssymbollayerv2widget.cpp | 1 + .../qgsdelimitedtextfeatureiterator.cpp | 1 + src/providers/mssql/qgsmssqlfeatureiterator.cpp | 5 +- src/providers/ogr/qgsogrconnpool.h | 3 +- src/providers/ogr/qgsogrfeatureiterator.cpp | 15 +- src/providers/ogr/qgsogrfeatureiterator.h | 2 +- src/providers/ogr/qgsogrprovider.cpp | 16 +- src/providers/oracle/qgsoraclefeatureiterator.cpp | 4 + .../postgres/qgspostgresfeatureiterator.cpp | 4 +- .../postgres/qgspostgresfeatureiterator.h | 1 + .../spatialite/qgsspatialitefeatureiterator.cpp | 4 + .../virtual/qgsvirtuallayerfeatureiterator.cpp | 4 +- src/python/qgspythonutilsimpl.cpp | 6 +- src/server/qgswfsserver.cpp | 33 ++-- tests/src/core/CMakeLists.txt | 1 + tests/src/core/testqgsconnectionpool.cpp | 141 ++++++++++++++++ tests/src/core/testqgsexpression.cpp | 41 +++++ tests/src/core/testqgsgeometry.cpp | 6 + tests/src/gui/testqgsfieldexpressionwidget.cpp | 50 ++++++ tests/src/python/providertestbase.py | 5 +- tests/src/python/qgis_interface.py | 2 +- tests/src/python/test_qgsblendmodes.py | 1 + tests/src/python/test_qgscomposition.py | 1 + .../test_qgsgeometrygeneratorsymbollayerv2.py | 2 +- tests/src/python/test_qgsrelationeditwidget.py | 6 +- tests/src/python/test_qgssymbollayerv2.py | 41 ++++- tests/src/python/test_qgsvectorlayer.py | 11 +- tests/src/python/utilities.py | 4 +- 73 files changed, 792 insertions(+), 160 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 21fdbc4..6e16eac 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ SET(CPACK_PACKAGE_VERSION_MAJOR "2") SET(CPACK_PACKAGE_VERSION_MINOR "14") -SET(CPACK_PACKAGE_VERSION_PATCH "2") +SET(CPACK_PACKAGE_VERSION_PATCH "3") SET(COMPLETE_VERSION ${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}) SET(RELEASE_NAME "Essen") IF (POLICY CMP0048) # in CMake 3.0.0+ diff --git a/ChangeLog b/ChangeLog index 73312a3..9760ef2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,182 @@ +Nyall Dawson <[email protected]> 2016-05-20 + + Precise that scale function returns the denominator and not the scale itself + + (cherry-picked from 69a8c381abeb810625bf972354e3492827b28915) + +Nyall Dawson <[email protected]> 2016-05-20 + + Save annotations to project.qgs in creation order (fix #14812) + + Save annotations to project file in the order they were loaded or + created, so that annotations have the same display order each + time the project is opened. + + (cherry-picked from 82d465cd9434d4445fe4fa44af8a5fd085cbc566) + +Nyall Dawson <[email protected]> 2016-05-20 + + Ensure that providers fetch geometry for a QgsFeatureRequest + with an expression filter which requires geometry + + (cherry-picked from 858914eef589b2426209d500c162c4773c41fbd5) + +Nyall Dawson <[email protected]> 2016-05-20 + + Set expression context for geometry generator builder (fix #14833) + + (cherry-picked from 7187148afb9d7c2d6670ef82b361f7d3b116fdc7) + +Juergen E. Fischer <[email protected]> 2016-05-17 + + osgeo4w: add qt plugin directories to browser with grass (followup b758a8c) + + (cherry picked from commit 6663a4cc821a9cf3ddc7ced1e65ba42f8fa945da) + +Matthias Kuhn <[email protected]> 2016-05-16 + + Fix bug in edit virtual field + + The index was transformed twice from field index to field origin index, + resulting in a corrupted index (most often being 0 in the end). + +Nyall Dawson <[email protected]> 2016-05-16 + + [expressions] Fix fetching joined column refs when expression is + not prepared (fix #14746) + + (cherry-picked from febe30d991111712f95a476e97862ca5a890b9aa) + +Nyall Dawson <[email protected]> 2016-05-16 + + [cad] Fix invalid coordinates when x/y snapping is enabled and + subsequent segments are parallel + + (cherry-picked from 90d116c6f509098f001bf1b10e8a58d081e46a14) + +Nyall Dawson <[email protected]> 2016-05-16 + + Ensure that @symbol_color is always correct for symbol layer types + with subsymbols + + (cherry-picked from cda387cb6f96e01d0c677c974f1a18e5d0bcbce9) + +Nyall Dawson <[email protected]> 2016-05-16 + + Fix memory leak in OGR provider when feature has no geometry + and FilterRect is used + + (cherry-picked from 6b80518a5b55ab30fb19493266d5626d0f89d26b) + +Nyall Dawson <[email protected]> 2016-05-16 + + Fix major(?) memory leak with python code execution + + (cherry-picked from 73733a65edd2bbc8156bf36484995457c35f6b68) + +Nyall Dawson <[email protected]> 2016-05-16 + + Avoid refreshing canvas for every joined feature + + Instead of setting the provider's subsetString to fetch joined + features, use a feature request with FilterExpression instead. + (Setting the subsetString results in a canvas refresh.) + + Performance should be similar (if expression compilation is + enabled) and this also has the advantage of avoiding provider- + specific behaviour (eg case insensitive matching). + + (fix #14800) + + (cherry-picked from 22acf3b1a3e7a6afe094ec6dec83776256d2655a) + +Nyall Dawson <[email protected]> 2016-05-16 + + Fix QgsFieldComboWidget not updating fields when calling setFilter() + + (cherry-picked from a389d237fcff1f61941cdba5237079e80abe6717) + +Nyall Dawson <[email protected]> 2016-05-16 + + Fix datetime fields not shown in QgsFieldComboWidget when set to date filter + + (cherry-picked from b4029dc7f0169b60117c4ece7c15a31a8766cb4f) + +Alexander Bruy <[email protected]> 2016-05-09 + + [processing] don't crash if user canceled script loading + + (cherry picked from commit 583eaeff7f1994290b1a9428d8b1a7c42848a5c9) + +Alexander Bruy <[email protected]> 2016-05-09 + + [processing] add support for int64 fields (fix #14777) + + (cherry picked from commit f1e6d8731b67b47ce44dc03c5e4d9b7dfe676a0f) + +Nyall Dawson <[email protected]> 2016-05-10 + + Fix feature fields does not include virtual or joined fields when + feature is requested using a QgsFeatureRequest with FilterFid + +Alessandro Pasotti <[email protected]> 2016-05-05 + + [server] Fixes segfault on wrong TypeName + + Unreported - WFS-T + + (cherry-picked from 8e781b4ec01b276e0c2be76db5742cf5227d6bd7) + + Funded by Boundless + +Sandro Mani <[email protected]> 2016-05-04 + + Also use datasource instead of filepath when ref/unref-ing and invalidating. + +Juergen E. Fischer <[email protected]> 2016-05-04 + + release.pl: don't created branches from tag names + + (cherry picked from commit 919c54ef5fabe7b7c2eef9c91094642c47b2eb7c) + +Matthias Kuhn <[email protected]> 2016-05-02 + + Fixup for AppStartup test which requires SIP API V1 + +Matthias Kuhn <[email protected]> 2016-05-02 + + Early import qgis in tests to set SIP API + +Matthias Kuhn <[email protected]> 2016-05-02 + + Improve qgis.PyQt compatibility layer + +Sandro Mani <[email protected]> 2016-04-20 + + Add connection pool test + +Sandro Mani <[email protected]> 2016-04-11 + + Move QgsProviderRegistry::instance delete call after deferred delete call + +Sandro Mani <[email protected]> 2016-04-10 + + Pass the full ogr data source URI as connInfo in qgsConnectionPool_ConnectionCreate. + + This fixes corrupt rendering when loading the same dataset twice with different options (i.e. layers), see issue #14560. + +rldhont <[email protected]> 2016-04-29 + + [BUGFIX][QGIS Server] WFS GetFeature with propertyname retrieves requested fields + +rldhont <[email protected]> 2016-04-29 + + [BUGFIX] QgsGeometry exportToGeoJSON return 'null' for null Geometry + +Juergen E. Fischer <[email protected]> 2016-04-29 + + Release of 2.14.2 + Nyall Dawson <[email protected]> 2016-04-29 Fix calculation of point symbol bounds using data defined rotation or offset diff --git a/debian/changelog b/debian/changelog index 2c0290e..8d1b55c 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,8 +1,14 @@ -qgis (2.14.2) UNRELEASED; urgency=medium +qgis (2.14.3) UNRELEASED; urgency=medium + + * Release of 2.14.3 + + -- Jürgen E. Fischer <[email protected]> Fri, 20 May 2016 14:05:10 +0200 + +qgis (2.14.2) unstable; urgency=medium * Release of 2.14.2 - -- Jürgen E. Fischer <[email protected]> Fri, 29 Apr 2016 14:00:28 +0200 + -- Jürgen E. Fischer <[email protected]> Fri, 20 May 2016 14:05:09 +0200 qgis (2.14.1) unstable; urgency=medium diff --git a/debian/python-qgis.install.in b/debian/python-qgis.install.in index 34a677a..87920d8 100644 --- a/debian/python-qgis.install.in +++ b/debian/python-qgis.install.in @@ -1,8 +1,9 @@ usr/lib/python*/*-packages/qgis/*.py usr/lib/python*/*-packages/qgis/*.so +usr/lib/python*/*-packages/qgis/PyQt/* +usr/lib/python*/*-packages/qgis/analysis/* usr/lib/python*/*-packages/qgis/core/* usr/lib/python*/*-packages/qgis/gui/* -usr/lib/python*/*-packages/qgis/analysis/* usr/lib/python*/*-packages/qgis/networkanalysis/* usr/lib/python*/*-packages/qgis/server/* usr/lib/python*/*-packages/qgis/testing/* diff --git a/ms-windows/osgeo4w/browser-grass.bat.tmpl b/ms-windows/osgeo4w/browser-grass.bat.tmpl index ef05a8c..72f77e9 100644 --- a/ms-windows/osgeo4w/browser-grass.bat.tmpl +++ b/ms-windows/osgeo4w/browser-grass.bat.tmpl @@ -4,4 +4,5 @@ call "%OSGEO4W_ROOT%"\apps\grass\grass-@grassversion@\etc\env.bat @echo off path %OSGEO4W_ROOT%\apps\@package@\bin;%OSGEO4W_ROOT%\apps\grass\grass-@grassversion@\lib;%OSGEO4W_ROOT%\apps\grass\grass-@grassversion@\bin;%PATH% set QGIS_PREFIX_PATH=%OSGEO4W_ROOT:\=/%/apps/@package@ +set QT_PLUGIN_PATH=%OSGEO4W_ROOT%\apps\@package@\qtplugins;%OSGEO4W_ROOT%\apps\qt4\plugins start "QGIS Browser" /B "%OSGEO4W_ROOT%"\bin\@[email protected] %* diff --git a/python/PyQt/CMakeLists.txt b/python/PyQt/CMakeLists.txt index e005a81..80fe79c 100644 --- a/python/PyQt/CMakeLists.txt +++ b/python/PyQt/CMakeLists.txt @@ -1,5 +1,5 @@ -SET (QGIS_PYQT_DIR ${QGIS_DATA_DIR}/python/PyQt) -SET (PYTHON_OUTPUT_DIRECTORY ${QGIS_OUTPUT_DIRECTORY}/python) +SET (QGIS_PYQT_DIR ${PYTHON_SITE_PACKAGES_DIR}/qgis/PyQt) +SET (PYTHON_OUTPUT_DIRECTORY ${QGIS_OUTPUT_DIRECTORY}/python/qgis/PyQt) SET(PYQT_COMPAT_FILES __init__.py @@ -9,7 +9,15 @@ SET(PYQT_COMPAT_FILES QtPrintSupport.py QtWebKit.py QtWebKitWidgets.py + QtNetwork.py + QtXml.py + QtSql.py + QtTest.py + QtSvg.py Qsci.py + uic/__init__.py + uic/pyuic.py + uic/properties.py ) ADD_CUSTOM_TARGET(pyqtcompat ALL) @@ -21,16 +29,16 @@ ELSE(ENABLE_QT5) ENDIF(ENABLE_QT5) FOREACH(pyfile ${PYQT_COMPAT_FILES}) + GET_FILENAME_COMPONENT(_dir ${pyfile} PATH) SET(pyfile ${PYQT_PREFIX}/${pyfile}) - LIST(APPEND PYQT_COMPAT_FILES_PREFIXED ${pyfile}) ADD_CUSTOM_COMMAND(TARGET pyqtcompat POST_BUILD - COMMAND ${CMAKE_COMMAND} -E make_directory ${PYTHON_OUTPUT_DIRECTORY}/PyQt - COMMAND ${CMAKE_COMMAND} -E copy ${pyfile} ${PYTHON_OUTPUT_DIRECTORY}/PyQt + COMMAND ${CMAKE_COMMAND} -E make_directory ${PYTHON_OUTPUT_DIRECTORY}/${_dir} + COMMAND ${CMAKE_COMMAND} -E copy ${pyfile} ${PYTHON_OUTPUT_DIRECTORY}/${_dir} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} DEPENDS ${pyfile} ) + INSTALL(FILES ${pyfile} DESTINATION "${QGIS_PYQT_DIR}/${_dir}") ENDFOREACH(pyfile) -PY_COMPILE(pyqtcompat "${PYTHON_OUTPUT_DIRECTORY}/PyQt") -INSTALL(FILES ${PYQT_COMPAT_FILES_PREFIXED} DESTINATION "${QGIS_PYQT_DIR}") +PY_COMPILE(pyqtcompat "${PYTHON_OUTPUT_DIRECTORY}") diff --git a/python/PyQt/PyQt4/QtCore.py b/python/PyQt/PyQt4/QtCore.py index cca3d6b..b4cdbf9 100644 --- a/python/PyQt/PyQt4/QtCore.py +++ b/python/PyQt/PyQt4/QtCore.py @@ -23,4 +23,44 @@ __copyright__ = '(C) 2015, Matthias Kuhn' # This will get replaced with a git SHA1 when you do a git archive __revision__ = '$Format:%H$' +import sip +for api in ["QDate", "QDateTime", "QString", "QTextStream", "QTime", "QUrl", "QVariant"]: + sip.setapi(api, 2) + from PyQt4.QtCore import * +from PyQt4.QtGui import QItemSelectionModel, QSortFilterProxyModel + +# Add a __nonzero__ method onto QPyNullVariant so we can check for null values easier. +# >>> value = QPyNullVariant("int") +# >>> if value: +# >>> print "Not a null value" +from types import MethodType +from PyQt4.QtCore import QPyNullVariant + + +def __nonzero__(self): + return False + + +def __repr__(self): + return 'NULL' + + +def __eq__(self, other): + return isinstance(other, QPyNullVariant) or other is None + + +def __ne__(self, other): + return not isinstance(other, QPyNullVariant) and other is not None + + +def __hash__(self): + return 2178309 + +QPyNullVariant.__nonzero__ = MethodType(__nonzero__, None, QPyNullVariant) +QPyNullVariant.__repr__ = MethodType(__repr__, None, QPyNullVariant) +QPyNullVariant.__eq__ = MethodType(__eq__, None, QPyNullVariant) +QPyNullVariant.__ne__ = MethodType(__ne__, None, QPyNullVariant) +QPyNullVariant.__hash__ = MethodType(__hash__, None, QPyNullVariant) + +NULL = QPyNullVariant(int) diff --git a/python/PyQt/PyQt4/QtCore.py b/python/PyQt/PyQt4/QtNetwork.py similarity index 73% copy from python/PyQt/PyQt4/QtCore.py copy to python/PyQt/PyQt4/QtNetwork.py index cca3d6b..98192db 100644 --- a/python/PyQt/PyQt4/QtCore.py +++ b/python/PyQt/PyQt4/QtNetwork.py @@ -2,11 +2,11 @@ """ *************************************************************************** - QtCore.py + QtNetwork.py --------------------- - Date : November 2015 - Copyright : (C) 2015 by Matthias Kuhn - Email : matthias at opengis dot ch + Date : February 2016 + Copyright : (C) 2016 by Jürgen E. Fischer + Email : jef at norbit dot de *************************************************************************** * * * This program is free software; you can redistribute it and/or modify * @@ -17,10 +17,10 @@ *************************************************************************** """ -__author__ = 'Matthias Kuhn' -__date__ = 'November 2015' -__copyright__ = '(C) 2015, Matthias Kuhn' +__author__ = 'Jürgen E. Fischer' +__date__ = 'February 2016' +__copyright__ = '(C) 2016, Jürgen E. Fischer' # This will get replaced with a git SHA1 when you do a git archive __revision__ = '$Format:%H$' -from PyQt4.QtCore import * +from PyQt4.QtNetwork import * diff --git a/python/PyQt/PyQt4/QtCore.py b/python/PyQt/PyQt4/QtSql.py similarity index 74% copy from python/PyQt/PyQt4/QtCore.py copy to python/PyQt/PyQt4/QtSql.py index cca3d6b..a5a0638 100644 --- a/python/PyQt/PyQt4/QtCore.py +++ b/python/PyQt/PyQt4/QtSql.py @@ -2,11 +2,11 @@ """ *************************************************************************** - QtCore.py + QtSql.py --------------------- - Date : November 2015 - Copyright : (C) 2015 by Matthias Kuhn - Email : matthias at opengis dot ch + Date : February 2016 + Copyright : (C) 2016 by Jürgen E. Fischer + Email : jef at norbit dot de *************************************************************************** * * * This program is free software; you can redistribute it and/or modify * @@ -17,10 +17,10 @@ *************************************************************************** """ -__author__ = 'Matthias Kuhn' -__date__ = 'November 2015' -__copyright__ = '(C) 2015, Matthias Kuhn' +__author__ = 'Jürgen E. Fischer' +__date__ = 'February 2016' +__copyright__ = '(C) 2016, Jürgen E. Fischer' # This will get replaced with a git SHA1 when you do a git archive __revision__ = '$Format:%H$' -from PyQt4.QtCore import * +from PyQt4.QtSql import * diff --git a/python/PyQt/PyQt4/QtCore.py b/python/PyQt/PyQt4/QtSvg.py similarity index 74% copy from python/PyQt/PyQt4/QtCore.py copy to python/PyQt/PyQt4/QtSvg.py index cca3d6b..9b14b4b 100644 --- a/python/PyQt/PyQt4/QtCore.py +++ b/python/PyQt/PyQt4/QtSvg.py @@ -2,11 +2,11 @@ """ *************************************************************************** - QtCore.py + QtSvg.py --------------------- - Date : November 2015 - Copyright : (C) 2015 by Matthias Kuhn - Email : matthias at opengis dot ch + Date : March 2016 + Copyright : (C) 2016 by Jürgen E. Fischer + Email : jef at norbit dot de *************************************************************************** * * * This program is free software; you can redistribute it and/or modify * @@ -17,10 +17,10 @@ *************************************************************************** """ -__author__ = 'Matthias Kuhn' -__date__ = 'November 2015' -__copyright__ = '(C) 2015, Matthias Kuhn' +__author__ = 'Jürgen E. Fischer' +__date__ = 'March 2016' +__copyright__ = '(C) 2016, Jürgen E. Fischer' # This will get replaced with a git SHA1 when you do a git archive __revision__ = '$Format:%H$' -from PyQt4.QtCore import * +from PyQt4.QtSvg import * diff --git a/python/PyQt/PyQt4/QtCore.py b/python/PyQt/PyQt4/QtTest.py similarity index 73% copy from python/PyQt/PyQt4/QtCore.py copy to python/PyQt/PyQt4/QtTest.py index cca3d6b..19ebec2 100644 --- a/python/PyQt/PyQt4/QtCore.py +++ b/python/PyQt/PyQt4/QtTest.py @@ -2,11 +2,11 @@ """ *************************************************************************** - QtCore.py + QtTest.py --------------------- - Date : November 2015 - Copyright : (C) 2015 by Matthias Kuhn - Email : matthias at opengis dot ch + Date : February 2016 + Copyright : (C) 2016 by Jürgen E. Fischer + Email : jef at norbit dot de *************************************************************************** * * * This program is free software; you can redistribute it and/or modify * @@ -17,10 +17,10 @@ *************************************************************************** """ -__author__ = 'Matthias Kuhn' -__date__ = 'November 2015' -__copyright__ = '(C) 2015, Matthias Kuhn' +__author__ = 'Jürgen E. Fischer' +__date__ = 'February 2016' +__copyright__ = '(C) 2016, Jürgen E. Fischer' # This will get replaced with a git SHA1 when you do a git archive __revision__ = '$Format:%H$' -from PyQt4.QtCore import * +from PyQt4.QtTest import * diff --git a/python/PyQt/PyQt4/QtCore.py b/python/PyQt/PyQt4/QtXml.py similarity index 74% copy from python/PyQt/PyQt4/QtCore.py copy to python/PyQt/PyQt4/QtXml.py index cca3d6b..e73e911 100644 --- a/python/PyQt/PyQt4/QtCore.py +++ b/python/PyQt/PyQt4/QtXml.py @@ -2,11 +2,11 @@ """ *************************************************************************** - QtCore.py + QtXml.py --------------------- - Date : November 2015 - Copyright : (C) 2015 by Matthias Kuhn - Email : matthias at opengis dot ch + Date : February 2016 + Copyright : (C) 2016 by Jürgen E. Fischer + Email : jef at norbit dot de *************************************************************************** * * * This program is free software; you can redistribute it and/or modify * @@ -17,10 +17,10 @@ *************************************************************************** """ -__author__ = 'Matthias Kuhn' -__date__ = 'November 2015' -__copyright__ = '(C) 2015, Matthias Kuhn' +__author__ = 'Jürgen E. Fischer' +__date__ = 'February 2016' +__copyright__ = '(C) 2016, Jürgen E. Fischer' # This will get replaced with a git SHA1 when you do a git archive __revision__ = '$Format:%H$' -from PyQt4.QtCore import * +from PyQt4.QtXml import * diff --git a/python/PyQt/PyQt4/QtCore.py b/python/PyQt/PyQt4/uic/__init__.py similarity index 65% copy from python/PyQt/PyQt4/QtCore.py copy to python/PyQt/PyQt4/uic/__init__.py index cca3d6b..99123d9 100644 --- a/python/PyQt/PyQt4/QtCore.py +++ b/python/PyQt/PyQt4/uic/__init__.py @@ -2,11 +2,11 @@ """ *************************************************************************** - QtCore.py + __init__.py --------------------- - Date : November 2015 - Copyright : (C) 2015 by Matthias Kuhn - Email : matthias at opengis dot ch + Date : February 2016 + Copyright : (C) 2016 by Jürgen E. Fischer + Email : jef at norbit dot de *************************************************************************** * * * This program is free software; you can redistribute it and/or modify * @@ -17,10 +17,13 @@ *************************************************************************** """ -__author__ = 'Matthias Kuhn' -__date__ = 'November 2015' -__copyright__ = '(C) 2015, Matthias Kuhn' +__author__ = 'Jürgen E. Fischer' +__date__ = 'February 2016' +__copyright__ = '(C) 2016, Jürgen E. Fischer' # This will get replaced with a git SHA1 when you do a git archive __revision__ = '$Format:%H$' -from PyQt4.QtCore import * +from PyQt4.uic.Compiler import indenter, compiler +from PyQt4.uic.objcreator import widgetPluginPath +from PyQt4.uic import properties, uiparser, Compiler +from PyQt4.uic import * diff --git a/python/PyQt/PyQt4/uic/properties.py b/python/PyQt/PyQt4/uic/properties.py new file mode 100644 index 0000000..4601fce --- /dev/null +++ b/python/PyQt/PyQt4/uic/properties.py @@ -0,0 +1 @@ +from PyQt4.uic import properties diff --git a/python/PyQt/PyQt4/QtCore.py b/python/PyQt/PyQt4/uic/pyuic.py similarity index 66% copy from python/PyQt/PyQt4/QtCore.py copy to python/PyQt/PyQt4/uic/pyuic.py index cca3d6b..68a0cb8 100644 --- a/python/PyQt/PyQt4/QtCore.py +++ b/python/PyQt/PyQt4/uic/pyuic.py @@ -2,11 +2,11 @@ """ *************************************************************************** - QtCore.py + pyuic.py --------------------- - Date : November 2015 - Copyright : (C) 2015 by Matthias Kuhn - Email : matthias at opengis dot ch + Date : February 2016 + Copyright : (C) 2016 by Jürgen E. Fischer + Email : jef at norbit dot de *************************************************************************** * * * This program is free software; you can redistribute it and/or modify * @@ -17,10 +17,15 @@ *************************************************************************** """ -__author__ = 'Matthias Kuhn' -__date__ = 'November 2015' -__copyright__ = '(C) 2015, Matthias Kuhn' +__author__ = 'Jürgen E. Fischer' +__date__ = 'February 2016' +__copyright__ = '(C) 2016, Jürgen E. Fischer' # This will get replaced with a git SHA1 when you do a git archive __revision__ = '$Format:%H$' -from PyQt4.QtCore import * + +import sip +for api in ["QDate", "QDateTime", "QString", "QTextStream", "QTime", "QUrl", "QVariant"]: + sip.setapi(api, 2) + +from PyQt4.uic import pyuic diff --git a/python/PyQt/PyQt5/QtCore.py b/python/PyQt/PyQt5/QtCore.py index 3518202..b024ae8 100644 --- a/python/PyQt/PyQt5/QtCore.py +++ b/python/PyQt/PyQt5/QtCore.py @@ -1 +1,3 @@ from PyQt5.QtCore import * +NULL = QVariant() +QPyNullVariant = QVariant() diff --git a/python/PyQt/PyQt5/QtNetwork.py b/python/PyQt/PyQt5/QtNetwork.py new file mode 100644 index 0000000..aff365e --- /dev/null +++ b/python/PyQt/PyQt5/QtNetwork.py @@ -0,0 +1 @@ +from PyQt5.QtNetwork import * diff --git a/python/PyQt/PyQt5/QtSql.py b/python/PyQt/PyQt5/QtSql.py new file mode 100644 index 0000000..736745e --- /dev/null +++ b/python/PyQt/PyQt5/QtSql.py @@ -0,0 +1 @@ +from PyQt5.QtSql import * diff --git a/python/PyQt/PyQt5/QtSvg.py b/python/PyQt/PyQt5/QtSvg.py new file mode 100644 index 0000000..7f76c2b --- /dev/null +++ b/python/PyQt/PyQt5/QtSvg.py @@ -0,0 +1 @@ +from PyQt5.QtSvg import * diff --git a/python/PyQt/PyQt5/QtTest.py b/python/PyQt/PyQt5/QtTest.py new file mode 100644 index 0000000..7230171 --- /dev/null +++ b/python/PyQt/PyQt5/QtTest.py @@ -0,0 +1 @@ +from PyQt5.QtTest import * diff --git a/python/PyQt/PyQt5/QtWidgets.py b/python/PyQt/PyQt5/QtWidgets.py index c82e3d4..738ebfb 100644 --- a/python/PyQt/PyQt5/QtWidgets.py +++ b/python/PyQt/PyQt5/QtWidgets.py @@ -1 +1,3 @@ from PyQt5.QtWidgets import * + +QLayout.setMargin = lambda self, m: self.setContentsMargins(m, m, m, m) diff --git a/python/PyQt/PyQt5/QtXml.py b/python/PyQt/PyQt5/QtXml.py new file mode 100644 index 0000000..b556556 --- /dev/null +++ b/python/PyQt/PyQt5/QtXml.py @@ -0,0 +1 @@ +from PyQt5.QtXml import * diff --git a/python/PyQt/PyQt4/QtCore.py b/python/PyQt/PyQt5/uic/__init__.py similarity index 65% copy from python/PyQt/PyQt4/QtCore.py copy to python/PyQt/PyQt5/uic/__init__.py index cca3d6b..fe97eb1 100644 --- a/python/PyQt/PyQt4/QtCore.py +++ b/python/PyQt/PyQt5/uic/__init__.py @@ -2,11 +2,11 @@ """ *************************************************************************** - QtCore.py + __init__.py --------------------- - Date : November 2015 - Copyright : (C) 2015 by Matthias Kuhn - Email : matthias at opengis dot ch + Date : February 2016 + Copyright : (C) 2016 by Jürgen E. Fischer + Email : jef at norbit dot de *************************************************************************** * * * This program is free software; you can redistribute it and/or modify * @@ -17,10 +17,13 @@ *************************************************************************** """ -__author__ = 'Matthias Kuhn' -__date__ = 'November 2015' -__copyright__ = '(C) 2015, Matthias Kuhn' +__author__ = 'Jürgen E. Fischer' +__date__ = 'February 2016' +__copyright__ = '(C) 2016, Jürgen E. Fischer' # This will get replaced with a git SHA1 when you do a git archive __revision__ = '$Format:%H$' -from PyQt4.QtCore import * +from PyQt5.uic.Compiler import indenter, compiler +from PyQt5.uic.objcreator import widgetPluginPath +from PyQt5.uic import properties, uiparser, Compiler +from PyQt5.uic import * diff --git a/python/PyQt/PyQt5/uic/properties.py b/python/PyQt/PyQt5/uic/properties.py new file mode 100644 index 0000000..95c9981 --- /dev/null +++ b/python/PyQt/PyQt5/uic/properties.py @@ -0,0 +1 @@ +from PyQt5.uic import properties diff --git a/python/PyQt/PyQt5/uic/pyuic.py b/python/PyQt/PyQt5/uic/pyuic.py new file mode 100644 index 0000000..98e5be2 --- /dev/null +++ b/python/PyQt/PyQt5/uic/pyuic.py @@ -0,0 +1 @@ +from PyQt5.uic import pyuic diff --git a/python/core/__init__.py b/python/core/__init__.py index 647de19..e8fe1b7 100644 --- a/python/core/__init__.py +++ b/python/core/__init__.py @@ -174,7 +174,7 @@ except ImportError: # TODO: Fixme, this creates an invalid variant, not a NULL one from PyQt5.QtCore import QVariant NULL = QVariant() - except ImportError: + except (ImportError, RuntimeError): pass diff --git a/python/core/symbology-ng/qgsfillsymbollayerv2.sip b/python/core/symbology-ng/qgsfillsymbollayerv2.sip index 353f10c..0f4fbaf 100644 --- a/python/core/symbology-ng/qgsfillsymbollayerv2.sip +++ b/python/core/symbology-ng/qgsfillsymbollayerv2.sip @@ -843,6 +843,9 @@ class QgsPointPatternFillSymbolLayer : QgsImageFillSymbolLayer virtual QSet<QString> usedAttributes() const; + void setColor( const QColor& c ); + virtual QColor color() const; + protected: void applyDataDefinedSettings( QgsSymbolV2RenderContext& context ); }; @@ -879,6 +882,7 @@ class QgsCentroidFillSymbolLayerV2 : QgsFillSymbolLayerV2 void toSld( QDomDocument &doc, QDomElement &element, const QgsStringMap& props ) const; void setColor( const QColor& color ); + QColor color() const; QgsSymbolV2* subSymbol(); bool setSubSymbol( QgsSymbolV2* symbol /Transfer/ ); diff --git a/python/core/symbology-ng/qgslinesymbollayerv2.sip b/python/core/symbology-ng/qgslinesymbollayerv2.sip index e7ba989..d376e9c 100644 --- a/python/core/symbology-ng/qgslinesymbollayerv2.sip +++ b/python/core/symbology-ng/qgslinesymbollayerv2.sip @@ -145,6 +145,7 @@ class QgsMarkerLineSymbolLayerV2 : QgsLineSymbolLayerV2 void toSld( QDomDocument &doc, QDomElement &element, const QgsStringMap& props ) const; void setColor( const QColor& color ); + virtual QColor color() const; QgsSymbolV2* subSymbol(); bool setSubSymbol( QgsSymbolV2* symbol /Transfer/); diff --git a/python/plugins/processing/gui/ParametersPanel.py b/python/plugins/processing/gui/ParametersPanel.py index 27dc9d8..bf3dcf7 100644 --- a/python/plugins/processing/gui/ParametersPanel.py +++ b/python/plugins/processing/gui/ParametersPanel.py @@ -437,8 +437,8 @@ class ParametersPanel(BASE, WIDGET): if datatype == ParameterTableField.DATA_TYPE_STRING: fieldTypes = [QVariant.String] elif datatype == ParameterTableField.DATA_TYPE_NUMBER: - fieldTypes = [QVariant.Int, QVariant.Double, QVariant.ULongLong, - QVariant.UInt] + fieldTypes = [QVariant.Int, QVariant.Double, QVariant.LongLong, + QVariant.UInt, QVariant.ULongLong] fieldNames = set() for field in layer.pendingFields(): diff --git a/python/plugins/processing/gui/ScriptEditorDialog.py b/python/plugins/processing/gui/ScriptEditorDialog.py index 1870be0..db7e6bf 100644 --- a/python/plugins/processing/gui/ScriptEditorDialog.py +++ b/python/plugins/processing/gui/ScriptEditorDialog.py @@ -202,6 +202,9 @@ class ScriptEditorDialog(BASE, WIDGET): self.filename = QFileDialog.getOpenFileName( self, self.tr('Save script'), scriptDir, filterName) + if self.filename == '': + return + QApplication.setOverrideCursor(QCursor(Qt.WaitCursor)) with codecs.open(self.filename, 'r', encoding='utf-8') as f: txt = f.read() diff --git a/resources/function_help/json/$scale b/resources/function_help/json/$scale index 35c171c..34d1734 100644 --- a/resources/function_help/json/$scale +++ b/resources/function_help/json/$scale @@ -1,7 +1,7 @@ { "name": "$scale", "type": "function", - "description": "Returns the current scale of the map canvas.<br><br>Note: This function is only available in some contexts and will be 0 otherwise.", + "description": "Returns the current scale denominator of the map canvas.<br><br>Note: This function is only available in some contexts and will be 0 otherwise.", "examples": [ { "expression":"$scale", "returns":"10000"} ] diff --git a/scripts/qgis_fixes/fix_pyqt.py b/scripts/qgis_fixes/fix_pyqt.py index c464ad0..2717d10 100644 --- a/scripts/qgis_fixes/fix_pyqt.py +++ b/scripts/qgis_fixes/fix_pyqt.py @@ -11,7 +11,7 @@ from lib2to3.fixer_util import (Name, Comma, FromImport, Newline, MAPPING = { "PyQt4.QtGui": [ - ("PyQt.QtGui", [ + ("qgis.PyQt.QtGui", [ "QIcon", "QCursor", "QColor", @@ -34,7 +34,7 @@ MAPPING = { "QFontMetricsF", "QGradient", ]), - ("PyQt.QtWidgets", [ + ("qgis.PyQt.QtWidgets", [ "QAbstractButton", "QAbstractGraphicsShapeItem", "QAbstractItemDelegate", @@ -235,7 +235,7 @@ MAPPING = { "qDrawWinButton", "qDrawWinPanel", ]), - ("PyQt.QtPrintSupport", [ + ("qgis.PyQt.QtPrintSupport", [ "QPrinter", "QAbstractPrintDialog", "QPageSetupDialog", @@ -245,13 +245,13 @@ MAPPING = { "QPrintPreviewWidget", "QPrinterInfo", ]), - ("PyQt.QtCore", [ + ("qgis.PyQt.QtCore", [ "QItemSelectionModel", "QSortFilterProxyModel", ]), ], "PyQt4.QtCore": [ - ("PyQt.QtCore", [ + ("qgis.PyQt.QtCore", [ "QAbstractItemModel", "QAbstractTableModel", "QByteArray", @@ -304,15 +304,15 @@ MAPPING = { ]), ], "PyQt4.QtNetwork": [ - ("PyQt.QtNetwork", ["QNetworkReply", "QNetworkRequest"]) + ("qgis.PyQt.QtNetwork", ["QNetworkReply", "QNetworkRequest"]) ], "PyQt4.QtXml": [ - ("PyQt.QtXml", [ + ("qgis.PyQt.QtXml", [ "QDomDocument" ]), ], "PyQt4.QtSci": [ - ("PyQt.QtSci", [ + ("qgis.PyQt.QtSci", [ "QsciAPIs", "QsciLexerCustom", "QsciLexerPython", @@ -321,7 +321,7 @@ MAPPING = { ]), ], "PyQt4.QtWebkit": [ - ("PyQt.QtWebkitWidgets", [ + ("qgis.PyQt.QtWebkitWidgets", [ "QGraphicsWebView", "QWebFrame", "QWebHitTestResult", diff --git a/scripts/release.pl b/scripts/release.pl index 1032af2..4fdd30c 100755 --- a/scripts/release.pl +++ b/scripts/release.pl @@ -202,11 +202,11 @@ unless( $dopoint ) { run( "git commit -a -m 'Bump version to $newmajor.$newminor'", "bump version failed" ); } -my $topush = ($dopoint ? "" : "master ") . "$relbranch $reltag $ltrtag"; +my $topush = ($dopoint ? "" : "master ") . "$relbranch"; print "Push dry-run...\n"; -run( "git push -n origin $topush", "push dry run failed" ); -print "Now manually push and upload the tarballs :\n\tgit push origin $topush\n\trsync qgis-$version.tar.bz2* qgis.org:/var/www/downloads/\n\n"; +run( "git push -n --follow-tags origin $topush", "push dry run failed" ); +print "Now manually push and upload the tarballs :\n\tgit push --follow-tags origin $topush\n\trsync qgis-$version.tar.bz2* qgis.org:/var/www/downloads/\n\n"; =head1 NAME diff --git a/src/app/qgisapp.cpp b/src/app/qgisapp.cpp index 928d3cb..cb05993 100644 --- a/src/app/qgisapp.cpp +++ b/src/app/qgisapp.cpp @@ -1574,14 +1574,19 @@ void QgisApp::showStyleManagerV2() void QgisApp::writeAnnotationItemsToProject( QDomDocument& doc ) { QList<QgsAnnotationItem*> items = annotationItems(); - QList<QgsAnnotationItem*>::const_iterator itemIt = items.constBegin(); - for ( ; itemIt != items.constEnd(); ++itemIt ) + QgsAnnotationItem* item; + QListIterator<QgsAnnotationItem*> i( items ); + // save lowermost annotation (at end of list) first + i.toBack(); + while ( i.hasPrevious() ) { - if ( ! *itemIt ) + item = i.previous(); + + if ( ! item ) { continue; } - ( *itemIt )->writeXML( doc ); + item->writeXML( doc ); } } diff --git a/src/app/qgsfieldsproperties.cpp b/src/app/qgsfieldsproperties.cpp index 6b43ab4..c47ef2e 100644 --- a/src/app/qgsfieldsproperties.cpp +++ b/src/app/qgsfieldsproperties.cpp @@ -289,7 +289,7 @@ void QgsFieldsProperties::setRow( int row, int idx, const QgsField& field ) QWidget* expressionWidget = new QWidget; expressionWidget->setLayout( new QHBoxLayout ); QToolButton* editExpressionButton = new QToolButton; - editExpressionButton->setProperty( "Index", mLayer->fields().fieldOriginIndex( idx ) ); + editExpressionButton->setProperty( "Index", idx ); editExpressionButton->setIcon( QgsApplication::getThemeIcon( "/mIconExpression.svg" ) ); connect( editExpressionButton, SIGNAL( clicked() ), this, SLOT( updateExpression() ) ); expressionWidget->layout()->setContentsMargins( 0, 0, 0, 0 ); diff --git a/src/core/geometry/qgsgeometry.cpp b/src/core/geometry/qgsgeometry.cpp index 1395d0b..ae3a176 100644 --- a/src/core/geometry/qgsgeometry.cpp +++ b/src/core/geometry/qgsgeometry.cpp @@ -912,7 +912,7 @@ QString QgsGeometry::exportToGeoJSON( int precision ) const { if ( !d->geometry ) { - return QString(); + return QString( "null" ); } return d->geometry->asJSON( precision ); } diff --git a/src/core/qgsapplication.cpp b/src/core/qgsapplication.cpp index 986a797..dc6f26b 100644 --- a/src/core/qgsapplication.cpp +++ b/src/core/qgsapplication.cpp @@ -867,8 +867,6 @@ void QgsApplication::initQgis() void QgsApplication::exitQgis() { - delete QgsProviderRegistry::instance(); - delete QgsAuthManager::instance(); //Ensure that all remaining deleteLater QObjects are actually deleted before we exit. @@ -876,6 +874,8 @@ void QgsApplication::exitQgis() //LeakSanitiser noise which hides real issues QgsApplication::sendPostedEvents( nullptr, QEvent::DeferredDelete ); + delete QgsProviderRegistry::instance(); + //delete all registered functions from expression engine (see above comment) QgsExpression::cleanRegisteredFunctions(); diff --git a/src/core/qgsexpression.cpp b/src/core/qgsexpression.cpp index 737f6ce..a478da7 100644 --- a/src/core/qgsexpression.cpp +++ b/src/core/qgsexpression.cpp @@ -4262,11 +4262,23 @@ QgsExpression::Node*QgsExpression::NodeLiteral::clone() const QVariant QgsExpression::NodeColumnRef::eval( QgsExpression *parent, const QgsExpressionContext *context ) { Q_UNUSED( parent ); + int index = mIndex; + + if ( index < 0 ) + { + // have not yet found field index - first check explicitly set fields collection + if ( context && context->hasVariable( QgsExpressionContext::EXPR_FIELDS ) ) + { + QgsFields fields = qvariant_cast<QgsFields>( context->variable( QgsExpressionContext::EXPR_FIELDS ) ); + index = fields.fieldNameIndex( mName ); + } + } + if ( context && context->hasVariable( QgsExpressionContext::EXPR_FEATURE ) ) { QgsFeature feature = qvariant_cast<QgsFeature>( context->variable( QgsExpressionContext::EXPR_FEATURE ) ); - if ( mIndex >= 0 ) - return feature.attribute( mIndex ); + if ( index >= 0 ) + return feature.attribute( index ); else return feature.attribute( mName ); } diff --git a/src/core/qgsvectorlayerfeatureiterator.cpp b/src/core/qgsvectorlayerfeatureiterator.cpp index 0694001..184e5ca 100644 --- a/src/core/qgsvectorlayerfeatureiterator.cpp +++ b/src/core/qgsvectorlayerfeatureiterator.cpp @@ -685,12 +685,7 @@ void QgsVectorLayerFeatureIterator::FetchJoinInfo::addJoinedAttributesCached( Qg void QgsVectorLayerFeatureIterator::FetchJoinInfo::addJoinedAttributesDirect( QgsFeature& f, const QVariant& joinValue ) const { // no memory cache, query the joined values by setting substring - QString subsetString = joinLayer->dataProvider()->subsetString(); // provider might already have a subset string - QString bkSubsetString = subsetString; - if ( !subsetString.isEmpty() ) - { - subsetString.prepend( '(' ).append( ") AND " ); - } + QString subsetString; QString joinFieldName; if ( joinInfo->joinFieldName.isEmpty() && joinInfo->joinFieldIndex >= 0 && joinInfo->joinFieldIndex < joinLayer->fields().count() ) @@ -723,8 +718,6 @@ void QgsVectorLayerFeatureIterator::FetchJoinInfo::addJoinedAttributesDirect( Qg subsetString += '=' + v; } - joinLayer->dataProvider()->setSubsetString( subsetString, false ); - // maybe user requested just a subset of layer's attributes // so we do not have to cache everything bool hasSubset = joinInfo->joinFieldNamesSubset(); @@ -736,6 +729,8 @@ void QgsVectorLayerFeatureIterator::FetchJoinInfo::addJoinedAttributesDirect( Qg QgsFeatureRequest request; request.setFlags( QgsFeatureRequest::NoGeometry ); request.setSubsetOfAttributes( attributes ); + request.setFilterExpression( subsetString ); + request.setLimit( 1 ); QgsFeatureIterator fi = joinLayer->getFeatures( request ); // get first feature @@ -765,8 +760,6 @@ void QgsVectorLayerFeatureIterator::FetchJoinInfo::addJoinedAttributesDirect( Qg { // no suitable join feature found, keeping empty (null) attributes } - - joinLayer->dataProvider()->setSubsetString( bkSubsetString, false ); } @@ -801,6 +794,8 @@ bool QgsVectorLayerFeatureIterator::nextFeatureFid( QgsFeature& f ) QgsFeatureIterator fi = mSource->mProviderFeatureSource->getFeatures( mProviderRequest ); if ( fi.nextFeature( f ) ) { + f.setFields( mSource->mFields ); + if ( mSource->mHasEditBuffer ) updateChangedAttributes( f ); diff --git a/src/core/symbology-ng/qgsfillsymbollayerv2.cpp b/src/core/symbology-ng/qgsfillsymbollayerv2.cpp index ec27bd5..ba5229e 100644 --- a/src/core/symbology-ng/qgsfillsymbollayerv2.cpp +++ b/src/core/symbology-ng/qgsfillsymbollayerv2.cpp @@ -2317,6 +2317,11 @@ void QgsLinePatternFillSymbolLayer::setColor( const QColor& c ) mColor = c; } +QColor QgsLinePatternFillSymbolLayer::color() const +{ + return mFillLineSymbol ? mFillLineSymbol->color() : mColor; +} + QgsLinePatternFillSymbolLayer::~QgsLinePatternFillSymbolLayer() { delete mFillLineSymbol; @@ -3370,6 +3375,18 @@ QSet<QString> QgsPointPatternFillSymbolLayer::usedAttributes() const return attributes; } +void QgsPointPatternFillSymbolLayer::setColor( const QColor& c ) +{ + mColor = c; + if ( mMarkerSymbol ) + mMarkerSymbol->setColor( c ); +} + +QColor QgsPointPatternFillSymbolLayer::color() const +{ + return mMarkerSymbol ? mMarkerSymbol->color() : mColor; +} + ////////////// @@ -3404,6 +3421,11 @@ void QgsCentroidFillSymbolLayerV2::setColor( const QColor& color ) mColor = color; } +QColor QgsCentroidFillSymbolLayerV2::color() const +{ + return mMarker ? mMarker->color() : mColor; +} + void QgsCentroidFillSymbolLayerV2::startRender( QgsSymbolV2RenderContext& context ) { mMarker->setAlpha( context.alpha() ); diff --git a/src/core/symbology-ng/qgsfillsymbollayerv2.h b/src/core/symbology-ng/qgsfillsymbollayerv2.h index 48bca51..d14dd30 100644 --- a/src/core/symbology-ng/qgsfillsymbollayerv2.h +++ b/src/core/symbology-ng/qgsfillsymbollayerv2.h @@ -896,7 +896,7 @@ class CORE_EXPORT QgsLinePatternFillSymbolLayer: public QgsImageFillSymbolLayer void setLineWidth( double w ); double lineWidth() const { return mLineWidth; } void setColor( const QColor& c ) override; - QColor color() const override { return mColor; } + QColor color() const override; void setOffset( double offset ) { mOffset = offset; } double offset() const { return mOffset; } @@ -1026,6 +1026,8 @@ class CORE_EXPORT QgsPointPatternFillSymbolLayer: public QgsImageFillSymbolLayer QgsMapUnitScale mapUnitScale() const override; virtual QSet<QString> usedAttributes() const override; + void setColor( const QColor& c ) override; + virtual QColor color() const override; protected: QgsMarkerSymbolV2* mMarkerSymbol; @@ -1077,6 +1079,7 @@ class CORE_EXPORT QgsCentroidFillSymbolLayerV2 : public QgsFillSymbolLayerV2 void toSld( QDomDocument &doc, QDomElement &element, const QgsStringMap& props ) const override; void setColor( const QColor& color ) override; + QColor color() const override; QgsSymbolV2* subSymbol() override; bool setSubSymbol( QgsSymbolV2* symbol ) override; diff --git a/src/core/symbology-ng/qgslinesymbollayerv2.cpp b/src/core/symbology-ng/qgslinesymbollayerv2.cpp index 26b6843..cfd9d48 100644 --- a/src/core/symbology-ng/qgslinesymbollayerv2.cpp +++ b/src/core/symbology-ng/qgslinesymbollayerv2.cpp @@ -809,6 +809,11 @@ void QgsMarkerLineSymbolLayerV2::setColor( const QColor& color ) mColor = color; } +QColor QgsMarkerLineSymbolLayerV2::color() const +{ + return mMarker ? mMarker->color() : mColor; +} + void QgsMarkerLineSymbolLayerV2::startRender( QgsSymbolV2RenderContext& context ) { mMarker->setAlpha( context.alpha() ); diff --git a/src/core/symbology-ng/qgslinesymbollayerv2.h b/src/core/symbology-ng/qgslinesymbollayerv2.h index 83a118f..0b0cbda 100644 --- a/src/core/symbology-ng/qgslinesymbollayerv2.h +++ b/src/core/symbology-ng/qgslinesymbollayerv2.h @@ -194,6 +194,7 @@ class CORE_EXPORT QgsMarkerLineSymbolLayerV2 : public QgsLineSymbolLayerV2 void toSld( QDomDocument &doc, QDomElement &element, const QgsStringMap& props ) const override; void setColor( const QColor& color ) override; + virtual QColor color() const override; QgsSymbolV2* subSymbol() override; bool setSubSymbol( QgsSymbolV2* symbol ) override; diff --git a/src/gui/qgsadvanceddigitizingdockwidget.cpp b/src/gui/qgsadvanceddigitizingdockwidget.cpp index 87dec83..03d1c3c 100644 --- a/src/gui/qgsadvanceddigitizingdockwidget.cpp +++ b/src/gui/qgsadvanceddigitizingdockwidget.cpp @@ -574,7 +574,7 @@ bool QgsAdvancedDigitizingDockWidget::applyConstraints( QgsMapMouseEvent* e ) } else if ( mXConstraint->isLocked() ) { - if ( cosa == 0 ) + if ( qgsDoubleNear( cosa, 0.0 ) ) { res = false; } @@ -590,7 +590,7 @@ bool QgsAdvancedDigitizingDockWidget::applyConstraints( QgsMapMouseEvent* e ) } else if ( mYConstraint->isLocked() ) { - if ( sina == 0 ) + if ( qgsDoubleNear( sina, 0.0 ) ) { res = false; } diff --git a/src/gui/qgsfieldproxymodel.cpp b/src/gui/qgsfieldproxymodel.cpp index f0a14aa..d65c693 100644 --- a/src/gui/qgsfieldproxymodel.cpp +++ b/src/gui/qgsfieldproxymodel.cpp @@ -28,6 +28,7 @@ QgsFieldProxyModel::QgsFieldProxyModel( QObject *parent ) QgsFieldProxyModel *QgsFieldProxyModel::setFilters( const Filters& filters ) { mFilters = filters; + invalidateFilter(); return this; } @@ -52,7 +53,8 @@ bool QgsFieldProxyModel::filterAcceptsRow( int source_row, const QModelIndex &so ( mFilters.testFlag( LongLong ) && type == QVariant::LongLong ) || ( mFilters.testFlag( Int ) && type == QVariant::Int ) || ( mFilters.testFlag( Double ) && type == QVariant::Double ) || - ( mFilters.testFlag( Date ) && type == QVariant::Date ) ) + ( mFilters.testFlag( Date ) && type == QVariant::Date ) || + ( mFilters.testFlag( Date ) && type == QVariant::DateTime ) ) return true; return false; diff --git a/src/gui/symbology-ng/qgssymbollayerv2widget.cpp b/src/gui/symbology-ng/qgssymbollayerv2widget.cpp index a840de9..ed76136 100644 --- a/src/gui/symbology-ng/qgssymbollayerv2widget.cpp +++ b/src/gui/symbology-ng/qgssymbollayerv2widget.cpp @@ -3109,6 +3109,7 @@ QgsGeometryGeneratorSymbolLayerWidget::QgsGeometryGeneratorSymbolLayerWidget( co setupUi( this ); modificationExpressionSelector->setLayer( const_cast<QgsVectorLayer*>( vl ) ); modificationExpressionSelector->loadFieldNames(); + modificationExpressionSelector->setExpressionContext( _getExpressionContext( this ) ); cbxGeometryType->addItem( QgsApplication::getThemeIcon( "/mIconPolygonLayer.svg" ), tr( "Polygon / MultiPolygon" ), QgsSymbolV2::Fill ); cbxGeometryType->addItem( QgsApplication::getThemeIcon( "/mIconLineLayer.svg" ), tr( "LineString / MultiLineString" ), QgsSymbolV2::Line ); cbxGeometryType->addItem( QgsApplication::getThemeIcon( "/mIconPointLayer.svg" ), tr( "Point / MultiPoint" ), QgsSymbolV2::Marker ); diff --git a/src/providers/delimitedtext/qgsdelimitedtextfeatureiterator.cpp b/src/providers/delimitedtext/qgsdelimitedtextfeatureiterator.cpp index 6af54bf..43eacf8 100644 --- a/src/providers/delimitedtext/qgsdelimitedtextfeatureiterator.cpp +++ b/src/providers/delimitedtext/qgsdelimitedtextfeatureiterator.cpp @@ -128,6 +128,7 @@ QgsDelimitedTextFeatureIterator::QgsDelimitedTextFeatureIterator( QgsDelimitedTe !( mRequest.flags() & QgsFeatureRequest::NoGeometry ) || mTestGeometry || ( mTestSubset && mSource->mSubsetExpression->needsGeometry() ) + || ( request.filterType() == QgsFeatureRequest::FilterExpression && request.filterExpression()->needsGeometry() ) ) ) { diff --git a/src/providers/mssql/qgsmssqlfeatureiterator.cpp b/src/providers/mssql/qgsmssqlfeatureiterator.cpp index 5cff00a..d315b52 100644 --- a/src/providers/mssql/qgsmssqlfeatureiterator.cpp +++ b/src/providers/mssql/qgsmssqlfeatureiterator.cpp @@ -102,7 +102,10 @@ void QgsMssqlFeatureIterator::BuildStatement( const QgsFeatureRequest& request ) } // get geometry col - if ( !( request.flags() & QgsFeatureRequest::NoGeometry ) && mSource->isSpatial() ) + if (( !( request.flags() & QgsFeatureRequest::NoGeometry ) + || ( request.filterType() == QgsFeatureRequest::FilterExpression && request.filterExpression()->needsGeometry() ) + ) + && mSource->isSpatial() ) { mStatement += QString( ",[%1]" ).arg( mSource->mGeometryColName ); } diff --git a/src/providers/ogr/qgsogrconnpool.h b/src/providers/ogr/qgsogrconnpool.h index 6f5e059..5d28f78 100644 --- a/src/providers/ogr/qgsogrconnpool.h +++ b/src/providers/ogr/qgsogrconnpool.h @@ -35,7 +35,8 @@ inline QString qgsConnectionPool_ConnectionToName( QgsOgrConn* c ) inline void qgsConnectionPool_ConnectionCreate( QString connInfo, QgsOgrConn*& c ) { c = new QgsOgrConn; - c->ds = OGROpen( connInfo.toUtf8().constData(), false, nullptr ); + QString filePath = connInfo.left( connInfo.indexOf( "|" ) ); + c->ds = OGROpen( filePath.toUtf8().constData(), false, nullptr ); c->path = connInfo; c->valid = true; } diff --git a/src/providers/ogr/qgsogrfeatureiterator.cpp b/src/providers/ogr/qgsogrfeatureiterator.cpp index 9bb8294..8850109 100644 --- a/src/providers/ogr/qgsogrfeatureiterator.cpp +++ b/src/providers/ogr/qgsogrfeatureiterator.cpp @@ -43,7 +43,7 @@ QgsOgrFeatureIterator::QgsOgrFeatureIterator( QgsOgrFeatureSource* source, bool { mFeatureFetched = false; - mConn = QgsOgrConnPool::instance()->acquireConnection( mSource->mFilePath ); + mConn = QgsOgrConnPool::instance()->acquireConnection( mSource->mProvider->dataSourceUri() ); if ( mSource->mLayerName.isNull() ) { @@ -74,6 +74,10 @@ QgsOgrFeatureIterator::QgsOgrFeatureIterator( QgsOgrFeatureSource* source, bool } mRequest.setSubsetOfAttributes( attrs ); } + if ( request.filterType() == QgsFeatureRequest::FilterExpression && request.filterExpression()->needsGeometry() ) + { + mFetchGeometry = true; + } // make sure we fetch just relevant fields // unless it's a VRT data source filtered by geometry as we don't know which @@ -226,13 +230,14 @@ bool QgsOgrFeatureIterator::fetchFeature( QgsFeature& feature ) { if ( !readFeature( fet, feature ) ) continue; + else + OGR_F_Destroy( fet ); if ( !mRequest.filterRect().isNull() && !feature.constGeometry() ) continue; // we have a feature, end this cycle feature.setValid( true ); - OGR_F_Destroy( fet ); return true; } // while @@ -408,7 +413,7 @@ bool QgsOgrFeatureIterator::readFeature( OGRFeatureH fet, QgsFeature& feature ) QgsOgrFeatureSource::QgsOgrFeatureSource( const QgsOgrProvider* p ) : mProvider( p ) { - mFilePath = p->filePath(); + mDataSource = p->dataSourceUri(); mLayerName = p->layerName(); mLayerIndex = p->layerIndex(); mSubsetString = p->mSubsetString; @@ -416,12 +421,12 @@ QgsOgrFeatureSource::QgsOgrFeatureSource( const QgsOgrProvider* p ) mFields = p->mAttributeFields; mDriverName = p->ogrDriverName; mOgrGeometryTypeFilter = wkbFlatten( p->mOgrGeometryTypeFilter ); - QgsOgrConnPool::instance()->ref( mFilePath ); + QgsOgrConnPool::instance()->ref( mDataSource ); } QgsOgrFeatureSource::~QgsOgrFeatureSource() { - QgsOgrConnPool::instance()->unref( mFilePath ); + QgsOgrConnPool::instance()->unref( mDataSource ); } QgsFeatureIterator QgsOgrFeatureSource::getFeatures( const QgsFeatureRequest& request ) diff --git a/src/providers/ogr/qgsogrfeatureiterator.h b/src/providers/ogr/qgsogrfeatureiterator.h index f9732b7..57b2a82 100644 --- a/src/providers/ogr/qgsogrfeatureiterator.h +++ b/src/providers/ogr/qgsogrfeatureiterator.h @@ -34,7 +34,7 @@ class QgsOgrFeatureSource : public QgsAbstractFeatureSource protected: const QgsOgrProvider* mProvider; - QString mFilePath; + QString mDataSource; QString mLayerName; int mLayerIndex; QString mSubsetString; diff --git a/src/providers/ogr/qgsogrprovider.cpp b/src/providers/ogr/qgsogrprovider.cpp index 7e6df60..a170890 100644 --- a/src/providers/ogr/qgsogrprovider.cpp +++ b/src/providers/ogr/qgsogrprovider.cpp @@ -374,7 +374,7 @@ QgsOgrProvider::QgsOgrProvider( QString const & uri ) << QgsVectorDataProvider::NativeType( tr( "Date & Time" ), "datetime", QVariant::DateTime ); } - QgsOgrConnPool::instance()->ref( mFilePath ); + QgsOgrConnPool::instance()->ref( dataSourceUri() ); } QgsOgrProvider::~QgsOgrProvider() @@ -685,7 +685,7 @@ OGRwkbGeometryType QgsOgrProvider::getOgrGeomType( OGRLayerH ogrLayer ) void QgsOgrProvider::loadFields() { - QgsOgrConnPool::instance()->invalidateConnections( filePath() ); + QgsOgrConnPool::instance()->invalidateConnections( dataSourceUri() ); //the attribute fields need to be read again when the encoding changes mAttributeFields.clear(); @@ -1276,7 +1276,7 @@ bool QgsOgrProvider::changeAttributeValues( const QgsChangedAttributesMap &attr_ { pushError( tr( "OGR error syncing to disk: %1" ).arg( CPLGetLastErrorMsg() ) ); } - QgsOgrConnPool::instance()->invalidateConnections( filePath() ); + QgsOgrConnPool::instance()->invalidateConnections( dataSourceUri() ); return true; } @@ -1341,7 +1341,7 @@ bool QgsOgrProvider::changeGeometryValues( const QgsGeometryMap &geometry_map ) OGR_F_Destroy( theOGRFeature ); } - QgsOgrConnPool::instance()->invalidateConnections( filePath() ); + QgsOgrConnPool::instance()->invalidateConnections( dataSourceUri() ); return syncToDisc(); } @@ -2540,7 +2540,7 @@ QByteArray QgsOgrProvider::quotedIdentifier( QByteArray field ) const void QgsOgrProvider::forceReload() { - QgsOgrConnPool::instance()->invalidateConnections( filePath() ); + QgsOgrConnPool::instance()->invalidateConnections( dataSourceUri() ); } QByteArray QgsOgrUtils::quotedIdentifier( QByteArray field, const QString& ogrDriverName ) @@ -2605,7 +2605,7 @@ bool QgsOgrProvider::syncToDisc() { shapeIndex = true; close(); - QgsOgrConnPool::instance()->invalidateConnections( mFilePath ); + QgsOgrConnPool::instance()->invalidateConnections( dataSourceUri() ); QFile::remove( sbnIndexFile ); open(); } @@ -2621,7 +2621,7 @@ bool QgsOgrProvider::syncToDisc() mShapefileMayBeCorrupted = false; - QgsOgrConnPool::instance()->ref( mFilePath ); + QgsOgrConnPool::instance()->ref( dataSourceUri() ); if ( shapeIndex ) { return createSpatialIndex(); @@ -2671,7 +2671,7 @@ void QgsOgrProvider::recalculateFeatureCount() OGR_L_SetSpatialFilter( ogrLayer, filter ); } - QgsOgrConnPool::instance()->invalidateConnections( filePath() ); + QgsOgrConnPool::instance()->invalidateConnections( dataSourceUri() ); } bool QgsOgrProvider::doesStrictFeatureTypeCheck() const diff --git a/src/providers/oracle/qgsoraclefeatureiterator.cpp b/src/providers/oracle/qgsoraclefeatureiterator.cpp index e73fe33..f3ae92e 100644 --- a/src/providers/oracle/qgsoraclefeatureiterator.cpp +++ b/src/providers/oracle/qgsoraclefeatureiterator.cpp @@ -68,6 +68,10 @@ QgsOracleFeatureIterator::QgsOracleFeatureIterator( QgsOracleFeatureSource* sour { // fetch geometry if requested mFetchGeometry = ( mRequest.flags() & QgsFeatureRequest::NoGeometry ) == 0; + if ( mRequest.filterType() == QgsFeatureRequest::FilterExpression && mRequest.filterExpression()->needsGeometry() ) + { + mFetchGeometry = true; + } if ( !mRequest.filterRect().isNull() ) { diff --git a/src/providers/postgres/qgspostgresfeatureiterator.cpp b/src/providers/postgres/qgspostgresfeatureiterator.cpp index 8cbc710..c66eaf3 100644 --- a/src/providers/postgres/qgspostgresfeatureiterator.cpp +++ b/src/providers/postgres/qgspostgresfeatureiterator.cpp @@ -37,6 +37,7 @@ QgsPostgresFeatureIterator::QgsPostgresFeatureIterator( QgsPostgresFeatureSource , mExpressionCompiled( false ) , mOrderByCompiled( false ) , mLastFetch( false ) + , mFilterRequiresGeometry( false ) { if ( !source->mTransactionConnection ) { @@ -101,6 +102,7 @@ QgsPostgresFeatureIterator::QgsPostgresFeatureIterator( QgsPostgresFeatureSource } mRequest.setSubsetOfAttributes( attrs ); } + mFilterRequiresGeometry = request.filterExpression()->needsGeometry(); if ( QSettings().value( "/qgis/compileExpressions", true ).toBool() ) { @@ -436,7 +438,7 @@ QString QgsPostgresFeatureIterator::whereClauseRect() bool QgsPostgresFeatureIterator::declareCursor( const QString& whereClause, long limit, bool closeOnFail, const QString& orderBy ) { - mFetchGeometry = !( mRequest.flags() & QgsFeatureRequest::NoGeometry ) && !mSource->mGeometryColumn.isNull(); + mFetchGeometry = ( !( mRequest.flags() & QgsFeatureRequest::NoGeometry ) || mFilterRequiresGeometry ) && !mSource->mGeometryColumn.isNull(); #if 0 // TODO: check that all field indexes exist if ( !hasAllFields ) diff --git a/src/providers/postgres/qgspostgresfeatureiterator.h b/src/providers/postgres/qgspostgresfeatureiterator.h index aad3a1b..c61deda 100644 --- a/src/providers/postgres/qgspostgresfeatureiterator.h +++ b/src/providers/postgres/qgspostgresfeatureiterator.h @@ -129,6 +129,7 @@ class QgsPostgresFeatureIterator : public QgsAbstractFeatureIteratorFromSource<Q bool mExpressionCompiled; bool mOrderByCompiled; bool mLastFetch; + bool mFilterRequiresGeometry; }; #endif // QGSPOSTGRESFEATUREITERATOR_H diff --git a/src/providers/spatialite/qgsspatialitefeatureiterator.cpp b/src/providers/spatialite/qgsspatialitefeatureiterator.cpp index 72dbd5b..d2b5b79 100644 --- a/src/providers/spatialite/qgsspatialitefeatureiterator.cpp +++ b/src/providers/spatialite/qgsspatialitefeatureiterator.cpp @@ -95,6 +95,10 @@ QgsSpatiaLiteFeatureIterator::QgsSpatiaLiteFeatureIterator( QgsSpatiaLiteFeature } mRequest.setSubsetOfAttributes( attrs ); } + if ( request.filterExpression()->needsGeometry() ) + { + mFetchGeometry = true; + } if ( QSettings().value( "/qgis/compileExpressions", true ).toBool() ) { diff --git a/src/providers/virtual/qgsvirtuallayerfeatureiterator.cpp b/src/providers/virtual/qgsvirtuallayerfeatureiterator.cpp index 3c70825..21c06e2 100644 --- a/src/providers/virtual/qgsvirtuallayerfeatureiterator.cpp +++ b/src/providers/virtual/qgsvirtuallayerfeatureiterator.cpp @@ -121,7 +121,9 @@ QgsVirtualLayerFeatureIterator::QgsVirtualLayerFeatureIterator( QgsVirtualLayerF } } // the last column is the geometry, if any - if ( !( request.flags() & QgsFeatureRequest::NoGeometry ) && !mDefinition.geometryField().isNull() && mDefinition.geometryField() != "*no*" ) + if (( !( request.flags() & QgsFeatureRequest::NoGeometry ) + || ( request.filterType() == QgsFeatureRequest::FilterExpression && request.filterExpression()->needsGeometry() ) ) + && !mDefinition.geometryField().isNull() && mDefinition.geometryField() != "*no*" ) { columns += "," + quotedColumn( mDefinition.geometryField() ); } diff --git a/src/python/qgspythonutilsimpl.cpp b/src/python/qgspythonutilsimpl.cpp index 3607f74..1c8f5ad 100644 --- a/src/python/qgspythonutilsimpl.cpp +++ b/src/python/qgspythonutilsimpl.cpp @@ -298,9 +298,9 @@ bool QgsPythonUtilsImpl::runStringUnsafe( const QString& command, bool single ) // TODO: convert special characters from unicode strings u"..." to \uXXXX // so that they're not mangled to utf-8 // (non-unicode strings can be mangled) - PyRun_String( command.toUtf8().data(), single ? Py_single_input : Py_file_input, mMainDict, mMainDict ); - + PyObject* obj = PyRun_String( command.toUtf8().data(), single ? Py_single_input : Py_file_input, mMainDict, mMainDict ); bool res = nullptr == PyErr_Occurred(); + Py_DECREF( obj ); // we are done calling python API, release global interpreter lock PyGILState_Release( gstate ); @@ -581,6 +581,8 @@ bool QgsPythonUtilsImpl::evalString( const QString& command, QString& result ) if ( success ) result = PyObjectToQString( res ); + Py_XDECREF( res ); + // we are done calling python API, release global interpreter lock PyGILState_Release( gstate ); diff --git a/src/server/qgswfsserver.cpp b/src/server/qgswfsserver.cpp index 4e4fbcb..51115ba 100644 --- a/src/server/qgswfsserver.cpp +++ b/src/server/qgswfsserver.cpp @@ -507,7 +507,8 @@ int QgsWFSServer::getFeature( QgsRequestHandler& request, const QString& format QgsFeature feature; mWithGeom = true; - //QgsAttributeList attrIndexes = provider->attributeIndexes(); + + //Using pending attributes and pending fields QgsAttributeList attrIndexes = layer->pendingAllAttributesList(); QDomNodeList queryChildNodes = queryElem.childNodes(); @@ -515,8 +516,7 @@ int QgsWFSServer::getFeature( QgsRequestHandler& request, const QString& format { QStringList::const_iterator alstIt; QList<int> idxList; - QMap<QString, int> fieldMap = provider->fieldNameMap(); - QMap<QString, int>::const_iterator fieldIt; + QgsFields fields = layer->pendingFields(); QString fieldName; QDomElement propertyElem; for ( int q = 0; q < queryChildNodes.size(); q++ ) @@ -529,10 +529,10 @@ int QgsWFSServer::getFeature( QgsRequestHandler& request, const QString& format { fieldName = fieldName.section( ":", 1, 1 ); } - fieldIt = fieldMap.find( fieldName ); - if ( fieldIt != fieldMap.end() ) + int fieldNameIdx = fields.fieldNameIndex( fieldName ); + if ( fieldNameIdx > -1 ) { - idxList.append( fieldIt.value() ); + idxList.append( fieldNameIdx ); } } } @@ -896,7 +896,7 @@ int QgsWFSServer::getFeature( QgsRequestHandler& request, const QString& format //map extent searchRect = layer->extent(); - //QgsAttributeList attrIndexes = provider->attributeIndexes(); + //Using pending attributes and pending fields QgsAttributeList attrIndexes = layer->pendingAllAttributesList(); if ( mPropertyName != "*" ) { @@ -905,16 +905,15 @@ int QgsWFSServer::getFeature( QgsRequestHandler& request, const QString& format { QStringList::const_iterator alstIt; QList<int> idxList; - QMap<QString, int> fieldMap = provider->fieldNameMap(); - QMap<QString, int>::const_iterator fieldIt; + QgsFields fields = layer->pendingFields(); QString fieldName; for ( alstIt = attrList.begin(); alstIt != attrList.end(); ++alstIt ) { fieldName = *alstIt; - fieldIt = fieldMap.find( fieldName ); - if ( fieldIt != fieldMap.end() ) + int fieldNameIdx = fields.fieldNameIndex( fieldName ); + if ( fieldNameIdx > -1 ) { - idxList.append( fieldIt.value() ); + idxList.append( fieldNameIdx ); } } if ( !idxList.isEmpty() ) @@ -1475,7 +1474,15 @@ QDomDocument QgsWFSServer::transaction( const QString& requestBody ) mTypeName = typeNameElem.tagName(); layerList = mConfigParser->mapLayerFromTypeName( mTypeName ); - currentLayer = layerList.at( 0 ); + // Could be empty! + if ( layerList.count() > 0 ) + { + currentLayer = layerList.at( 0 ); + } + else + { + throw QgsMapServiceException( "RequestNotWellFormed", QString( "Wrong TypeName: %1" ).arg( mTypeName ) ); + } QgsVectorLayer* layer = qobject_cast<QgsVectorLayer*>( currentLayer ); // it's a vectorlayer and defined by the administrator as a WFS layer diff --git a/tests/src/core/CMakeLists.txt b/tests/src/core/CMakeLists.txt index 9c69357..2e19743 100644 --- a/tests/src/core/CMakeLists.txt +++ b/tests/src/core/CMakeLists.txt @@ -112,6 +112,7 @@ ADD_QGIS_TEST(composertabletest testqgscomposertable.cpp) ADD_QGIS_TEST(composertablev2test testqgscomposertablev2.cpp) ADD_QGIS_TEST(composerutils testqgscomposerutils.cpp) ADD_QGIS_TEST(compositiontest testqgscomposition.cpp) +ADD_QGIS_TEST(connectionpooltest testqgsconnectionpool.cpp) ADD_QGIS_TEST(contrastenhancementtest testcontrastenhancements.cpp) ADD_QGIS_TEST(coordinatereferencesystemtest testqgscoordinatereferencesystem.cpp) ADD_QGIS_TEST(coordinatetransformtest testqgscoordinatetransform.cpp) diff --git a/tests/src/core/testqgsconnectionpool.cpp b/tests/src/core/testqgsconnectionpool.cpp new file mode 100644 index 0000000..a350997 --- /dev/null +++ b/tests/src/core/testqgsconnectionpool.cpp @@ -0,0 +1,141 @@ +/*************************************************************************** + testqgsconnectionpool.cpp + ----------------------- + begin : April 2016 + copyright : (C) 2016 by Sandro Mani + email : [email protected] + ***************************************************************************/ + +/*************************************************************************** + * * + * 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 "qgsapplication.h" +#include "qgsgeometry.h" +#include "qgspointv2.h" +#include "qgslinestringv2.h" +#include "qgsvectorlayer.h" +#include <QEventLoop> +#include <QObject> +#include <QTemporaryFile> +#include <QtConcurrentMap> +#include <QtTest/QtTest> + +class TestQgsConnectionPool: public QObject +{ + Q_OBJECT + + private slots: + void initTestCase(); + void cleanupTestCase(); + void layersFromSameDatasetGPX(); + + private: + struct ReadJob + { + ReadJob( QgsVectorLayer* _layer ) : layer( _layer ) {} + QgsVectorLayer* layer; + QList<QgsFeature> features; + }; + + static void processJob( ReadJob& job ) + { + QgsFeatureIterator it = job.layer->getFeatures(); + QgsFeature f; + while ( it.nextFeature( f ) ) + { + job.features.append( f ); + } + } + +}; + +void TestQgsConnectionPool::initTestCase() +{ + QgsApplication::init(); + QgsApplication::initQgis(); + +} + +void TestQgsConnectionPool::cleanupTestCase() +{ + QgsApplication::exitQgis(); +} + +void TestQgsConnectionPool::layersFromSameDatasetGPX() +{ + // Tests whether features are correctly retrevied from different layers which are + // loaded from the same dataset. See issue #14560 + int nWaypoints = 100000; + int nRoutes = 100000; + int nRoutePts = 10; + QTemporaryFile testFile( "testXXXXXX.gpx" ); + testFile.setAutoRemove( false ); + testFile.open(); + testFile.write( "<gpx version=\"1.1\" creator=\"qgis\">\n" ); + for ( int i = 0; i < nWaypoints; ++i ) + { + testFile.write( QString( "<wpt lon=\"%1\" lat=\"%1\"><name></name></wpt>\n" ).arg( i ).toLocal8Bit() ); + } + for ( int i = 0; i < nRoutes; ++i ) + { + testFile.write( "<rte><name></name><number></number>\n" ); + for ( int j = 0; j < nRoutePts; ++j ) + { + testFile.write( QString( "<rtept lon=\"%1\" lat=\"%2\"/>\n" ).arg( j ).arg( i ).toLocal8Bit() ); + } + testFile.write( "</rte>\n" ); + } + testFile.write( "</gpx>\n" ); + testFile.close(); + + QgsVectorLayer* layer1 = new QgsVectorLayer( testFile.fileName() + "|layername=waypoints", "Waypoints", "ogr" ); + QVERIFY( layer1->isValid() ); + QgsVectorLayer* layer2 = new QgsVectorLayer( testFile.fileName() + "|layername=routes", "Routes", "ogr" ); + QVERIFY( layer2->isValid() ); + + QList<ReadJob> jobs = QList<ReadJob>() << ReadJob( layer1 ) << ReadJob( layer2 ); + + QEventLoop evLoop; + QFutureWatcher<void> futureWatcher; + connect( &futureWatcher, SIGNAL( finished() ), &evLoop, SLOT( quit() ) ); + futureWatcher.setFuture( QtConcurrent::map( jobs, processJob ) ); + evLoop.exec(); + + QList<QgsFeature>& layer1Features = jobs[0].features; + QList<QgsFeature>& layer2Features = jobs[1].features; + + QVERIFY( layer1Features.count() == nWaypoints ); + QVERIFY( layer2Features.count() == nRoutes ); + + for ( int i = 0, n = layer1Features.count(); i < n; ++i ) + { + const QgsPointV2* geom = dynamic_cast<const QgsPointV2*>( layer1Features[i].geometry()->geometry() ); + QVERIFY( geom != nullptr ); + QVERIFY( qFuzzyCompare( geom->x(), i ) ); + QVERIFY( qFuzzyCompare( geom->y(), i ) ); + } + for ( int i = 0, n = layer2Features.count(); i < n; ++i ) + { + const QgsLineStringV2* geom = dynamic_cast<const QgsLineStringV2*>( layer2Features[i].geometry()->geometry() ); + QVERIFY( geom != nullptr ); + int nVtx = geom->vertexCount(); + QVERIFY( nVtx == nRoutePts ); + for ( int j = 0; j < nVtx; ++j ) + { + QgsPointV2 p = geom->vertexAt( QgsVertexId( 0, 0, j ) ); + QVERIFY( qFuzzyCompare( p.x(), j ) ); + QVERIFY( qFuzzyCompare( p.y(), i ) ); + } + } + delete layer1; + delete layer2; + QFile( testFile.fileName() ).remove(); +} + +QTEST_MAIN( TestQgsConnectionPool ) +#include "testqgsconnectionpool.moc" diff --git a/tests/src/core/testqgsexpression.cpp b/tests/src/core/testqgsexpression.cpp index ad81e47..4edfe0b 100644 --- a/tests/src/core/testqgsexpression.cpp +++ b/tests/src/core/testqgsexpression.cpp @@ -2036,6 +2036,47 @@ class TestQgsExpression: public QObject QgsExpression nodeExpression( "1 IN (1, 2, 3, 4)" ); QgsExpression nodeExpression2( nodeExpression ); } + + void test_columnRefUnprepared() + { + //test retrieving fields from feature when expression is unprepared - explicitly specified fields collection + //should take precedence over feature's field collection + + QgsFields fields; + fields.append( QgsField( "f1", QVariant::String ) ); + + QgsFeature f( 1 ); + f.setFields( fields ); + + //also add a joined field - this will not be available in feature's field collection + fields.append( QgsField( "j1", QVariant::String ), QgsFields::OriginJoin, 1 ); + + f.setAttributes( QgsAttributes() << QVariant( "f1" ) << QVariant( "j1" ) ); + f.setValid( true ); + + QgsExpression e( "\"f1\"" ); + QgsExpressionContext context; + context.setFeature( f ); + context.setFields( fields ); + QVariant result = e.evaluate( &context ); + QCOMPARE( result.toString(), QString( "f1" ) ); + + //test joined field + QgsExpression e2( "\"j1\"" ); + result = e2.evaluate( &context ); + QCOMPARE( result.toString(), QString( "j1" ) ); + + // final test - check that feature's field collection is also used when corresponding field NOT found + // in explicitly passed field collection + fields.append( QgsField( "f2", QVariant::String ) ); + f.setFields( fields ); + f.setAttributes( QgsAttributes() << QVariant( "f1" ) << QVariant( "j1" ) << QVariant( "f2" ) ); + context.setFeature( f ); + QgsExpression e3( "\"f2\"" ); + result = e3.evaluate( &context ); + QCOMPARE( result.toString(), QString( "f2" ) ); + } + }; QTEST_MAIN( TestQgsExpression ) diff --git a/tests/src/core/testqgsgeometry.cpp b/tests/src/core/testqgsgeometry.cpp index f0e9663..9a05468 100644 --- a/tests/src/core/testqgsgeometry.cpp +++ b/tests/src/core/testqgsgeometry.cpp @@ -3311,6 +3311,12 @@ void TestQgsGeometry::exportToGeoJSON() obtained = geom->exportToGeoJSON(); geojson = "{\"type\": \"MultiPolygon\", \"coordinates\": [[[ [0, 0], [10, 0], [10, 10], [0, 10], [0, 0]]], [[ [2, 2], [4, 2], [4, 4], [2, 4], [2, 2]]]] }"; QCOMPARE( obtained, geojson ); + + // no geometry + QgsGeometry nullGeom( nullptr ); + obtained = nullGeom.exportToGeoJSON(); + geojson = "null"; + QCOMPARE( obtained, geojson ); } bool TestQgsGeometry::renderCheck( const QString& theTestName, const QString& theComment, int mismatchCount ) diff --git a/tests/src/gui/testqgsfieldexpressionwidget.cpp b/tests/src/gui/testqgsfieldexpressionwidget.cpp index ff8d5f0..9700f38 100644 --- a/tests/src/gui/testqgsfieldexpressionwidget.cpp +++ b/tests/src/gui/testqgsfieldexpressionwidget.cpp @@ -50,6 +50,7 @@ class TestQgsFieldExpressionWidget : public QObject void testRemoveJoin(); void asExpression(); void testIsValid(); + void testFilters(); private: QgsFieldExpressionWidget* mWidget; @@ -219,6 +220,55 @@ void TestQgsFieldExpressionWidget::testIsValid() QgsMapLayerRegistry::instance()->removeMapLayer( layer ); } +void TestQgsFieldExpressionWidget::testFilters() +{ + QgsVectorLayer* layer = new QgsVectorLayer( "point?field=intfld:int&field=stringfld:string&field=string2fld:string&field=longfld:long&field=doublefld:double&field=datefld:date&field=timefld:time&field=datetimefld:datetime", "x", "memory" ); + QgsMapLayerRegistry::instance()->addMapLayer( layer ); + + QScopedPointer< QgsFieldExpressionWidget > widget( new QgsFieldExpressionWidget() ); + widget->setLayer( layer ); + + QCOMPARE( widget->mCombo->count(), 8 ); + QCOMPARE( widget->mCombo->itemText( 0 ), QString( "intfld" ) ); + QCOMPARE( widget->mCombo->itemText( 1 ), QString( "stringfld" ) ); + QCOMPARE( widget->mCombo->itemText( 2 ), QString( "string2fld" ) ); + QCOMPARE( widget->mCombo->itemText( 3 ), QString( "longfld" ) ); + QCOMPARE( widget->mCombo->itemText( 4 ), QString( "doublefld" ) ); + QCOMPARE( widget->mCombo->itemText( 5 ), QString( "datefld" ) ); + QCOMPARE( widget->mCombo->itemText( 6 ), QString( "timefld" ) ); + QCOMPARE( widget->mCombo->itemText( 7 ), QString( "datetimefld" ) ); + + widget->setFilters( QgsFieldProxyModel::String ); + QCOMPARE( widget->mCombo->count(), 2 ); + QCOMPARE( widget->mCombo->itemText( 0 ), QString( "stringfld" ) ); + QCOMPARE( widget->mCombo->itemText( 1 ), QString( "string2fld" ) ); + + widget->setFilters( QgsFieldProxyModel::Int ); + QCOMPARE( widget->mCombo->count(), 1 ); + QCOMPARE( widget->mCombo->itemText( 0 ), QString( "intfld" ) ); + + widget->setFilters( QgsFieldProxyModel::LongLong ); + QCOMPARE( widget->mCombo->count(), 1 ); + QCOMPARE( widget->mCombo->itemText( 0 ), QString( "longfld" ) ); + + widget->setFilters( QgsFieldProxyModel::Double ); + QCOMPARE( widget->mCombo->count(), 1 ); + QCOMPARE( widget->mCombo->itemText( 0 ), QString( "doublefld" ) ); + + widget->setFilters( QgsFieldProxyModel::Numeric ); + QCOMPARE( widget->mCombo->count(), 3 ); + QCOMPARE( widget->mCombo->itemText( 0 ), QString( "intfld" ) ); + QCOMPARE( widget->mCombo->itemText( 1 ), QString( "longfld" ) ); + QCOMPARE( widget->mCombo->itemText( 2 ), QString( "doublefld" ) ); + + widget->setFilters( QgsFieldProxyModel::Date ); + QCOMPARE( widget->mCombo->count(), 2 ); + QCOMPARE( widget->mCombo->itemText( 0 ), QString( "datefld" ) ); + QCOMPARE( widget->mCombo->itemText( 1 ), QString( "datetimefld" ) ); + + QgsMapLayerRegistry::instance()->removeMapLayer( layer ); +} + QTEST_MAIN( TestQgsFieldExpressionWidget ) #include "testqgsfieldexpressionwidget.moc" diff --git a/tests/src/python/providertestbase.py b/tests/src/python/providertestbase.py index be585b2..c2ff215 100644 --- a/tests/src/python/providertestbase.py +++ b/tests/src/python/providertestbase.py @@ -62,7 +62,7 @@ class ProviderTestCase(object): self.assertFalse(geometries[pk], 'Expected null geometry for {}'.format(pk)) def assert_query(self, provider, expression, expected): - result = set([f['pk'] for f in provider.getFeatures(QgsFeatureRequest().setFilterExpression(expression))]) + result = set([f['pk'] for f in provider.getFeatures(QgsFeatureRequest().setFilterExpression(expression).setFlags(QgsFeatureRequest.NoGeometry))]) assert set(expected) == result, 'Expected {} and got {} when testing expression "{}"'.format(set(expected), result, expression) # Also check that filter works when referenced fields are not being retrieved by request @@ -154,6 +154,9 @@ class ProviderTestCase(object): # against numeric literals self.assert_query(provider, 'num_char IN (2, 4, 5)', [2, 4, 5]) + # geometry + self.assert_query(provider, 'intersects($geometry,geom_from_wkt( \'Polygon ((-72.2 66.1, -65.2 66.1, -65.2 72.0, -72.2 72.0, -72.2 66.1))\'))', [1, 2]) + def testGetFeaturesUncompiled(self): try: self.disableCompiler() diff --git a/tests/src/python/qgis_interface.py b/tests/src/python/qgis_interface.py index 6c73118..3732205 100644 --- a/tests/src/python/qgis_interface.py +++ b/tests/src/python/qgis_interface.py @@ -26,7 +26,7 @@ __copyright__ = ('Copyright (c) 2010 by Ivan Mincik, [email protected] and ' import qgis -from PyQt.QtCore import QObject +from qgis.PyQt.QtCore import QObject from qgis.core import QgsMapLayerRegistry diff --git a/tests/src/python/test_qgsblendmodes.py b/tests/src/python/test_qgsblendmodes.py index 76aa6b6..2878eea 100644 --- a/tests/src/python/test_qgsblendmodes.py +++ b/tests/src/python/test_qgsblendmodes.py @@ -23,6 +23,7 @@ __copyright__ = '(C) 2013, Nyall Dawson, Massimo Endrighi' # This will get replaced with a git SHA1 when you do a git archive __revision__ = '$Format:%H$' +import qgis import os from PyQt4.QtCore import QSize diff --git a/tests/src/python/test_qgscomposition.py b/tests/src/python/test_qgscomposition.py index 518a6ce..f758c5b 100644 --- a/tests/src/python/test_qgscomposition.py +++ b/tests/src/python/test_qgscomposition.py @@ -12,6 +12,7 @@ __copyright__ = 'Copyright 2012, The QGIS Project' # This will get replaced with a git SHA1 when you do a git archive __revision__ = '$Format:%H$' +import qgis import os from PyQt4.QtCore import QFileInfo, QDir diff --git a/tests/src/python/test_qgsgeometrygeneratorsymbollayerv2.py b/tests/src/python/test_qgsgeometrygeneratorsymbollayerv2.py index 0ef8302..f9e145b 100644 --- a/tests/src/python/test_qgsgeometrygeneratorsymbollayerv2.py +++ b/tests/src/python/test_qgsgeometrygeneratorsymbollayerv2.py @@ -25,7 +25,7 @@ __revision__ = '$Format:%H$' import os -from PyQt.QtCore import QSize +from qgis.PyQt.QtCore import QSize from qgis.core import ( QgsVectorLayer, diff --git a/tests/src/python/test_qgsrelationeditwidget.py b/tests/src/python/test_qgsrelationeditwidget.py index 0097d36..5ca8350 100644 --- a/tests/src/python/test_qgsrelationeditwidget.py +++ b/tests/src/python/test_qgsrelationeditwidget.py @@ -36,18 +36,18 @@ from qgis.gui import ( QgsFeatureListView ) -from PyQt.QtCore import ( +from qgis.PyQt.QtCore import ( QTimer ) -from PyQt.QtWidgets import ( +from qgis.PyQt.QtWidgets import ( QWidget, QToolButton, QTableView, QListView ) -from PyQt.QtGui import ( +from qgis.PyQt.QtGui import ( QApplication ) diff --git a/tests/src/python/test_qgssymbollayerv2.py b/tests/src/python/test_qgssymbollayerv2.py index 9a673d4..bc96748 100644 --- a/tests/src/python/test_qgssymbollayerv2.py +++ b/tests/src/python/test_qgssymbollayerv2.py @@ -364,6 +364,14 @@ class TestQgsSymbolLayerV2(unittest.TestCase): mMessage = 'Expected "%s" got "%s"' % (mExpectedValue, mValue) assert mExpectedValue == mValue, mMessage + # test colors, need to make sure colors are passed/retrieved from subsymbol + mSymbolLayer.setColor(QColor(150, 50, 100)) + self.assertEqual(mSymbolLayer.color(), QColor(150, 50, 100)) + self.assertEqual(mSymbolLayer.subSymbol().color(), QColor(150, 50, 100)) + mSymbolLayer.subSymbol().setColor(QColor(250, 150, 200)) + self.assertEqual(mSymbolLayer.subSymbol().color(), QColor(250, 150, 200)) + self.assertEqual(mSymbolLayer.color(), QColor(250, 150, 200)) + def testQgsLinePatternFillSymbolLayer(self): """ Create a new style from a .sld file and match test @@ -404,8 +412,16 @@ class TestQgsSymbolLayerV2(unittest.TestCase): mMessage = 'Expected "%s" got "%s"' % (mExpectedValue, mValue) assert mExpectedValue == mValue, mMessage + # test colors, need to make sure colors are passed/retrieved from subsymbol + mSymbolLayer.setColor(QColor(150, 50, 100)) + self.assertEqual(mSymbolLayer.color(), QColor(150, 50, 100)) + self.assertEqual(mSymbolLayer.subSymbol().color(), QColor(150, 50, 100)) + mSymbolLayer.subSymbol().setColor(QColor(250, 150, 200)) + self.assertEqual(mSymbolLayer.subSymbol().color(), QColor(250, 150, 200)) + self.assertEqual(mSymbolLayer.color(), QColor(250, 150, 200)) + @unittest.expectedFailure - def testQgsPointPatternFillSymbolLayer(self): + def testQgsPointPatternFillSymbolLayerSld(self): """ Create a new style from a .sld file and match test """ @@ -452,6 +468,20 @@ class TestQgsSymbolLayerV2(unittest.TestCase): mMessage = 'Expected "%s" got "%s"' % (mExpectedValue, mValue) assert mExpectedValue == mValue, mMessage + def testQgsPointPatternFillSymbolLayer(self): + """ + Test point pattern fill + """ + # test colors, need to make sure colors are passed/retrieved from subsymbol + mSymbolLayer = QgsPointPatternFillSymbolLayer.create() + + mSymbolLayer.setColor(QColor(150, 50, 100)) + self.assertEqual(mSymbolLayer.color(), QColor(150, 50, 100)) + self.assertEqual(mSymbolLayer.subSymbol().color(), QColor(150, 50, 100)) + mSymbolLayer.subSymbol().setColor(QColor(250, 150, 200)) + self.assertEqual(mSymbolLayer.subSymbol().color(), QColor(250, 150, 200)) + self.assertEqual(mSymbolLayer.color(), QColor(250, 150, 200)) + def testQgsSVGFillSymbolLayer(self): """ Create a new style from a .sld file and match test @@ -522,6 +552,14 @@ class TestQgsSymbolLayerV2(unittest.TestCase): mMessage = 'Expected "%s" got "%s"' % (mExpectedValue, mValue) assert mExpectedValue == mValue, mMessage + # test colors, need to make sure colors are passed/retrieved from subsymbol + mSymbolLayer.setColor(QColor(150, 50, 100)) + self.assertEqual(mSymbolLayer.color(), QColor(150, 50, 100)) + self.assertEqual(mSymbolLayer.subSymbol().color(), QColor(150, 50, 100)) + mSymbolLayer.subSymbol().setColor(QColor(250, 150, 200)) + self.assertEqual(mSymbolLayer.subSymbol().color(), QColor(250, 150, 200)) + self.assertEqual(mSymbolLayer.color(), QColor(250, 150, 200)) + def testQgsSimpleLineSymbolLayerV2(self): """ Create a new style from a .sld file and match test @@ -692,6 +730,5 @@ class TestQgsSymbolLayerV2(unittest.TestCase): mMessage = 'Expected "%s" got "%s"' % (mExpectedValue, mValue) assert mExpectedValue == mValue, mMessage - if __name__ == '__main__': unittest.main() diff --git a/tests/src/python/test_qgsvectorlayer.py b/tests/src/python/test_qgsvectorlayer.py index ce3a835..6849901 100644 --- a/tests/src/python/test_qgsvectorlayer.py +++ b/tests/src/python/test_qgsvectorlayer.py @@ -967,8 +967,15 @@ class TestQgsVectorLayer(unittest.TestCase): idx = layer.addExpressionField('5', QgsField('test', QVariant.LongLong)) - self.assertEquals(layer.getFeatures().next()[idx], 5) - self.assertEquals(layer.pendingFields().count(), cnt + 1) + fet = next(layer.getFeatures()) + self.assertEqual(fet[idx], 5) + # check fields + self.assertEqual(layer.fields().count(), cnt + 1) + self.assertEqual(fet.fields(), layer.fields()) + + # retrieve single feature and check fields + fet = next(layer.getFeatures(QgsFeatureRequest().setFilterFid(1))) + self.assertEqual(fet.fields(), layer.fields()) layer.updateExpressionField(idx, '9') diff --git a/tests/src/python/utilities.py b/tests/src/python/utilities.py index 1f5f6fa..14930a7 100644 --- a/tests/src/python/utilities.py +++ b/tests/src/python/utilities.py @@ -18,8 +18,8 @@ import glob import platform import tempfile -from PyQt.QtCore import QSize, QDir -from PyQt.QtWidgets import QWidget +from PyQt4.QtCore import QSize, QDir +from PyQt4.QtGui import QWidget from qgis.core import ( QgsApplication, -- Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-grass/qgis.git _______________________________________________ Pkg-grass-devel mailing list [email protected] http://lists.alioth.debian.org/cgi-bin/mailman/listinfo/pkg-grass-devel

