Merge pull request #5086 from pblottiere/pr_auxiliary_storage

[Feature] Auxiliary Storage
This commit is contained in:
Blottiere Paul 2017-10-09 08:58:21 +01:00 committed by GitHub
commit ac66ced1c3
96 changed files with 5410 additions and 467 deletions

View File

@ -485,6 +485,7 @@
<file>themes/default/unlocked.svg</file>
<file>themes/default/unlockedGray.svg</file>
<file>themes/default/user.svg</file>
<file>themes/default/mIconAuxiliaryStorage.svg</file>
<file>flags/eu.png</file>
<file>flags/bn.png</file>
<file>flags/gl.png</file>

View File

@ -0,0 +1,280 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
height="24"
width="24"
version="1.1"
id="svg8"
sodipodi:docname="mIconAuxiliaryStorage2.svg"
inkscape:version="0.92.1 r15371">
<metadata
id="metadata14">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs12">
<clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath6054">
<rect
style="display:inline;fill:#a40000;fill-opacity:1;stroke:none"
id="rect6056"
width="48"
height="22"
x="-126"
y="-6"
transform="matrix(0.9545455,0,0,0.89256196,-4.6363639,-1.3719273)" />
</clipPath>
<filter
inkscape:collect="always"
id="filter4938"
x="-0.065465368"
width="1.1309307"
y="-0.34369317"
height="1.6873863"
style="color-interpolation-filters:sRGB">
<feGaussianBlur
inkscape:collect="always"
stdDeviation="1.1456439"
id="feGaussianBlur4940" />
</filter>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient_SkyBlue"
id="linearGradient5485"
gradientUnits="userSpaceOnUse"
x1="0.5"
y1="12"
x2="15.5"
y2="12"
gradientTransform="matrix(0.88966084,0,0,1.3582695,1.0687967,1.2233435)" />
<linearGradient
id="linearGradient_SkyBlue">
<stop
id="stop3832"
offset="0"
style="stop-color:#e7e7e7;stop-opacity:1;" />
<stop
id="stop3834"
offset="1"
style="stop-color:#c0c0c0;stop-opacity:1;" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3820"
id="linearGradient5487"
gradientUnits="userSpaceOnUse"
x1="-122.5"
y1="27"
x2="-81.5"
y2="27"
gradientTransform="matrix(0.32548569,0,0,0.52821591,41.385986,4.5812617)" />
<linearGradient
id="linearGradient3820">
<stop
style="stop-color:#dcdcdc;stop-opacity:1;"
offset="0"
id="stop3823" />
<stop
style="stop-color:#545454;stop-opacity:1;"
offset="1"
id="stop3825" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3829"
id="linearGradient5489"
gradientUnits="userSpaceOnUse"
x1="-122"
y1="23.5"
x2="-82"
y2="23.5"
gradientTransform="matrix(0.32548569,0,0,0.52821591,41.385986,5.1094941)" />
<linearGradient
id="linearGradient3829">
<stop
style="stop-color:#ffffff;stop-opacity:0.60000002;"
offset="0"
id="stop3831" />
<stop
style="stop-color:#ffffff;stop-opacity:0.20784314;"
offset="1"
id="stop3833" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4365"
id="linearGradient5491"
gradientUnits="userSpaceOnUse"
x1="-121"
y1="30"
x2="-102"
y2="30"
gradientTransform="matrix(0.32548569,0,0,0.52821591,41.385986,0.88373362)" />
<linearGradient
id="linearGradient4365">
<stop
id="stop4367"
offset="0"
style="stop-color:#000000;stop-opacity:0.80000001;" />
<stop
id="stop4369"
offset="1"
style="stop-color:#000000;stop-opacity:0.15384616;" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient_SkyBlue"
id="linearGradient5493"
gradientUnits="userSpaceOnUse"
x1="0.5"
y1="12"
x2="15.5"
y2="12"
gradientTransform="matrix(0.88966084,0,0,1.3582695,1.0687967,-4.5870147)" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3820"
id="linearGradient5495"
gradientUnits="userSpaceOnUse"
x1="-122.5"
y1="27"
x2="-81.5"
y2="27"
gradientTransform="matrix(0.32548569,0,0,0.52821591,41.385986,-1.2290967)" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3829"
id="linearGradient5497"
gradientUnits="userSpaceOnUse"
x1="-122"
y1="23.5"
x2="-82"
y2="23.5"
gradientTransform="matrix(0.32548569,0,0,0.52821591,41.385986,-0.70091386)" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4365"
id="linearGradient5499"
gradientUnits="userSpaceOnUse"
x1="-121"
y1="30"
x2="-102"
y2="30"
gradientTransform="matrix(0.32548569,0,0,0.52821591,41.385986,-4.9266245)" />
</defs>
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="958"
inkscape:window-height="1058"
id="namedview10"
showgrid="false"
inkscape:zoom="9.8333333"
inkscape:cx="12"
inkscape:cy="12"
inkscape:window-x="0"
inkscape:window-y="20"
inkscape:window-maximized="0"
inkscape:current-layer="svg8" />
<g
transform="translate(3.11,-1028.2722)"
id="g6"
style="fill-rule:evenodd;stroke:#727272;stroke-linejoin:round">
<path
d="m 4.5,1050.8618 v -21 h 10 l 5,5 v 16.0004 z"
id="path2"
inkscape:connector-curvature="0"
style="fill:#ffffff" />
<path
d="m 14.5,1029.8618 v 5 h 5 z"
id="path4"
inkscape:connector-curvature="0"
style="fill:#f0f0f0" />
</g>
<ellipse
style="display:inline;fill:#2e3436;fill-opacity:0.8;stroke:none;filter:url(#filter4938)"
id="path4932"
transform="matrix(0.340985,0,0,0.72629687,42.966917,16.334045)"
clip-path="url(#clipPath6054)"
cx="-102"
cy="6"
rx="21"
ry="4" />
<path
id="path4791"
d="m 8.1860847,12.768588 c -3.6850976,0 -6.6724579,1.216316 -6.6724579,2.716582 v 4.074822 c 0,1.500265 2.9873603,2.716483 6.6724579,2.716483 3.6850943,0 6.6724533,-1.216218 6.6724533,-2.716483 V 15.48517 c 0,-1.500266 -2.987359,-2.716582 -6.6724533,-2.716582 z"
style="display:inline;fill:url(#linearGradient5485);fill-opacity:1;stroke:none;stroke-width:0.41464046"
inkscape:connector-curvature="0" />
<path
style="display:inline;fill:url(#linearGradient5487);fill-opacity:1;stroke:none;stroke-width:0.41464046"
d="m 1.5648452,14.881468 c -0.034064,0.111272 -0.050856,0.231705 -0.050856,0.346691 v 4.324751 c 0,1.500315 2.9873603,2.723565 6.6724571,2.723565 3.6850967,0 6.6724557,-1.22325 6.6724557,-2.723565 v -4.324751 c 0,-0.114986 -0.01679,-0.235419 -0.05086,-0.346691 -0.410385,1.340067 -3.218924,2.376972 -6.6215988,2.376972 -3.4026751,0 -6.2112121,-1.036905 -6.6215998,-2.376972 z"
id="path4822"
sodipodi:nodetypes="cccscccsc"
inkscape:connector-curvature="0" />
<path
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:'Bitstream Vera Sans';-inkscape-font-specification:'Bitstream Vera Sans';text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-anchor:start;display:inline;overflow:visible;visibility:visible;fill:url(#linearGradient5489);fill-opacity:1;stroke:none;stroke-width:0.46920153;marker:none;enable-background:accumulate"
d="m 8.1864441,13.032729 c -1.8304566,0 -3.4817402,0.309105 -4.6686851,0.792324 -0.593475,0.241609 -1.0791673,0.506295 -1.3934864,0.808863 -0.3143181,0.30247 -0.4475406,0.613011 -0.4475406,0.858335 v 4.060659 c 0,0.245275 0.1332225,0.555766 0.4475406,0.858335 0.3143191,0.302519 0.8000114,0.567205 1.3934864,0.808814 1.1869449,0.483267 2.8382285,0.792323 4.6686851,0.792323 1.8304579,0 3.4817389,-0.309056 4.6686859,-0.792323 0.593473,-0.241609 1.079168,-0.506295 1.393485,-0.808814 0.314318,-0.302569 0.447543,-0.61306 0.447543,-0.858335 v -4.060659 c 0,-0.245324 -0.133225,-0.555865 -0.447543,-0.858335 -0.314317,-0.302568 -0.800012,-0.567254 -1.393485,-0.808863 -1.186947,-0.483219 -2.838228,-0.792324 -4.6686859,-0.792324 z m 0,0.528183 c 1.8032025,0 3.4332069,0.257406 4.5771429,0.726313 0.571968,0.234479 1.014393,0.500353 1.281599,0.759294 0.267207,0.258991 0.325487,0.443553 0.325487,0.429192 v 4.09369 c 0,-0.01436 -0.05828,0.170201 -0.325487,0.429142 -0.267206,0.258991 -0.709631,0.524865 -1.281599,0.759343 -1.143935,0.468907 -2.7739404,0.726264 -4.5771429,0.726264 -1.8032048,0 -3.4332067,-0.257357 -4.5771418,-0.726264 C 3.037333,20.523408 2.5949098,20.257534 2.3277026,19.998543 2.0604954,19.739602 2.0022155,19.55504 2.0022155,19.569401 v -4.09369 c 0,0.01436 0.058283,-0.170201 0.3254871,-0.429192 0.2672072,-0.258941 0.7096304,-0.524815 1.2815997,-0.759294 1.1439351,-0.468907 2.773937,-0.726313 4.5771418,-0.726313 z"
id="path4803"
sodipodi:nodetypes="cssccsssssccssccssccsssssccssc"
inkscape:connector-curvature="0" />
<path
style="display:inline;fill:none;stroke:#3f3f3f;stroke-width:0.4146404;stroke-opacity:1"
d="m 8.1860847,12.768588 c -3.6850976,0 -6.6724579,1.216316 -6.6724579,2.716582 v 4.074822 c 0,1.500265 2.9873603,2.716483 6.6724579,2.716483 3.6850943,0 6.6724533,-1.216218 6.6724533,-2.716483 V 15.48517 c 0,-1.500266 -2.987359,-2.716582 -6.6724533,-2.716582 z"
id="path4721"
inkscape:connector-curvature="0" />
<path
style="display:inline;fill:url(#linearGradient5491);fill-opacity:1;stroke:none;stroke-width:0.41464046"
d="m 2.0022155,15.558262 v 0.528232 c 0.9927301,0.993128 3.388153,1.700178 6.1842286,1.700178 2.7960739,0 5.1914989,-0.70705 6.1842289,-1.700178 v -0.528232 c -0.99273,0.993177 -3.388155,1.700178 -6.1842289,1.700178 -2.7960756,0 -5.1914985,-0.707001 -6.1842286,-1.700178 z"
id="path4831"
sodipodi:nodetypes="ccsccsc"
inkscape:connector-curvature="0" />
<path
style="display:inline;fill:url(#linearGradient5493);fill-opacity:1;stroke:none;stroke-width:1.09927213"
d="m 8.1860811,6.958283 c -3.685094,0 -6.6724543,1.2162175 -6.6724543,2.7165315 v 4.0747685 c 0,1.500315 2.9873603,2.716583 6.6724543,2.716583 3.6850979,0 6.6724569,-1.216268 6.6724569,-2.716583 V 9.6748145 c 0,-1.500314 -2.987359,-2.7165315 -6.6724569,-2.7165315 z"
id="path4882"
inkscape:connector-curvature="0" />
<path
sodipodi:nodetypes="cccscccsc"
id="path4884"
d="m 1.5648452,9.0711145 c -0.034064,0.111222 -0.050856,0.231655 -0.050856,0.346641 v 4.3247475 c 0,1.500314 2.9873603,2.723613 6.6724571,2.723613 3.6850967,0 6.6724557,-1.223299 6.6724557,-2.723613 V 9.4177555 c 0,-0.114986 -0.01679,-0.235419 -0.05086,-0.346641 -0.410385,1.3400645 -3.218924,2.3769665 -6.6215988,2.3769665 -3.4026751,0 -6.2112121,-1.036902 -6.6215998,-2.3769665 z"
style="display:inline;fill:url(#linearGradient5495);fill-opacity:1;stroke:none;stroke-width:0.41464046"
inkscape:connector-curvature="0" />
<path
sodipodi:nodetypes="cssccsssssccssccssccsssssccssc"
id="path4886"
d="m 8.1864441,7.2223249 c -1.8304566,0 -3.4817402,0.3091053 -4.6686851,0.7923235 C 2.924284,8.2563077 2.4385917,8.520944 2.1242726,8.823512 1.8099545,9.1260325 1.676732,9.4365735 1.676732,9.6818475 v 4.0606555 c 0,0.245273 0.1332225,0.555815 0.4475406,0.858334 0.3143191,0.302569 0.8000114,0.567254 1.3934864,0.808863 1.1869449,0.483219 2.8382285,0.792324 4.6686851,0.792324 1.8304579,0 3.4817389,-0.309105 4.6686859,-0.792324 0.593473,-0.241609 1.079168,-0.506294 1.393485,-0.808863 0.314318,-0.302519 0.447543,-0.613061 0.447543,-0.858334 V 9.6818475 c 0,-0.245274 -0.133225,-0.555815 -0.447543,-0.8583355 C 13.934298,8.520944 13.448603,8.2563077 12.85513,8.0146484 11.668183,7.5314302 10.016902,7.2223249 8.1864441,7.2223249 Z m 0,0.5282328 c 1.8032025,0 3.4332069,0.2574057 4.5771429,0.7263133 0.571968,0.234428 1.014393,0.5003525 1.281599,0.7592945 0.267207,0.258991 0.325487,0.443553 0.325487,0.429192 v 4.0936355 c 0,-0.01436 -0.05828,0.17025 -0.325487,0.429192 -0.267206,0.25899 -0.709631,0.524865 -1.281599,0.759294 -1.143935,0.468956 -2.7739404,0.726313 -4.5771429,0.726313 -1.8032048,0 -3.4332067,-0.257357 -4.5771418,-0.726313 C 3.037333,14.71305 2.5949098,14.447175 2.3277026,14.188185 2.0604954,13.929243 2.0022155,13.744632 2.0022155,13.758993 V 9.6653575 c 0,0.01436 0.058283,-0.170201 0.3254871,-0.429192 C 2.5949098,8.9772235 3.037333,8.711299 3.6093023,8.476871 4.7532374,8.0079634 6.3832393,7.7505577 8.1864441,7.7505577 Z"
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:'Bitstream Vera Sans';-inkscape-font-specification:'Bitstream Vera Sans';text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-anchor:start;display:inline;overflow:visible;visibility:visible;fill:url(#linearGradient5497);fill-opacity:1;stroke:none;stroke-width:0.46920153;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
id="path4888"
d="m 8.1860811,6.958283 c -3.685094,0 -6.6724543,1.2162175 -6.6724543,2.7165315 v 4.0747685 c 0,1.500315 2.9873603,2.716583 6.6724543,2.716583 3.6850979,0 6.6724569,-1.216268 6.6724569,-2.716583 V 9.6748145 c 0,-1.500314 -2.987359,-2.7165315 -6.6724569,-2.7165315 z"
style="display:inline;fill:none;stroke:#3f3f3f;stroke-width:0.4146404;stroke-opacity:1"
inkscape:connector-curvature="0" />
<path
sodipodi:nodetypes="ccsccsc"
id="path4892"
d="m 2.0022155,9.7478575 v 0.5282315 c 0.9927301,0.993175 3.388153,1.700175 6.1842286,1.700175 2.7960739,0 5.1914989,-0.707 6.1842289,-1.700175 V 9.7478575 c -0.99273,0.9932245 -3.388155,1.7002235 -6.1842289,1.7002235 -2.7960756,0 -5.1914985,-0.706999 -6.1842286,-1.7002235 z"
style="display:inline;fill:url(#linearGradient5499);fill-opacity:1;stroke:none;stroke-width:0.41464046"
inkscape:connector-curvature="0" />
</svg>

After

Width:  |  Height:  |  Size: 14 KiB

View File

@ -297,6 +297,7 @@
%Include qgsapplication.sip
%Include qgsactionscoperegistry.sip
%Include qgsanimatedicon.sip
%Include qgsauxiliarystorage.sip
%Include qgsbrowsermodel.sip
%Include qgscoordinatereferencesystem.sip
%Include qgscredentials.sip

View File

@ -124,6 +124,13 @@ class QgsProjectArchive : QgsArchive
:return: true if the file is well removed, false otherwise
:rtype: bool
%End
QString auxiliaryStorageFile() const;
%Docstring
Returns the current .qgd auxiliary storage file or an empty string if
there's none
:rtype: str
%End
};
/************************************************************************

View File

@ -0,0 +1,397 @@
/************************************************************************
* This file has been generated automatically from *
* *
* src/core/qgsauxiliarystorage.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/
class QgsAuxiliaryLayer : QgsVectorLayer
{
%Docstring
Class allowing to manage the auxiliary storage for a vector layer.
Such auxiliary data are data used mostly for the needs of QGIS (symbology)
and have no real interest in being stored with the native raw geospatial
data.
The need arises from the restrictions existing in the manual placement of
labels. Manual placement of labels are possible in QGIS by setting some
labeling properties (X and Y position, and rotation angle optionally) as
being "data-defined", meaning that values come from a column (or an
expression). But setting this up on an existing layer requires either to
add new columns to the source layer, while it is not always possible or
desirable.
This QgsAuxiliaryLayer provides the solution to this limitation. Actually
it's an editable join to the original vector layer with some
synchronisation mechanisms activated such as "Upsert On Edit" or "Delete
Cascade". Thus, auxiliary fields are editable even if the
source layer is not and edition of a joined field is also possible.
.. versionadded:: 3.0
%End
%TypeHeaderCode
#include "qgsauxiliarystorage.h"
%End
public:
QgsAuxiliaryLayer( const QString &pkField, const QString &filename, const QString &table, QgsVectorLayer *vlayer );
%Docstring
Constructor
\param pkField The primary key to use for joining
\param filename The database path
\param table The table name
\param vlayer The target vector layer in join definition
%End
virtual ~QgsAuxiliaryLayer();
%Docstring
Destructor
%End
QgsAuxiliaryLayer *clone( QgsVectorLayer *layer ) const /Factory/;
%Docstring
Returns a new instance equivalent to this one. The underlying table
is duplicate for the layer given in parameter. Note that the current
auxiliary layer should be saved to have a proper duplicated table.
\param layer The layer for which the clone is made
:rtype: QgsAuxiliaryLayer
%End
QgsVectorLayer *toSpatialLayer() const;
%Docstring
An auxiliary layer is not spatial. This method returns a spatial
representation of auxiliary data.
:return: A new spatial vector layer
:rtype: QgsVectorLayer
%End
bool clear();
%Docstring
Deletes all features from the layer. Changes are automatically committed
and the layer remains editable.
:return: true if changes are committed without error, false otherwise.
:rtype: bool
%End
QgsVectorLayerJoinInfo joinInfo() const;
%Docstring
Returns information to use for joining with primary key and so on.
:rtype: QgsVectorLayerJoinInfo
%End
bool exists( const QgsPropertyDefinition &definition ) const;
%Docstring
Returns true if the property is stored in the layer already, false
otherwise.
\param definition The property definition to check
:return: true if the property is stored, false otherwise
:rtype: bool
%End
bool addAuxiliaryField( const QgsPropertyDefinition &definition );
%Docstring
Add an an auxiliary field for the given property. Setup for widget
editors are updated in the target layer as weel as the attribute
table config to hide auxiliary fields by default.
\param definition The definition of the property to add
:return: true if the auxiliary field is well added, false otherwise
:rtype: bool
%End
QgsFields auxiliaryFields() const;
%Docstring
Returns a list of all auxiliary fields currently managed by the layer.
:rtype: QgsFields
%End
bool save();
%Docstring
Commit changes and starts editing then.
:return: true if commit step passed, false otherwise
:rtype: bool
%End
virtual bool deleteAttribute( int attr );
%Docstring
Remove attribute from the layer and commit changes. The layer remains
editable.
\param attr The index of the attribute to remove
:return: true if the attribute is well deleted, false otherwise
:rtype: bool
%End
bool isHiddenProperty( int index ) const;
%Docstring
Returns true if the underlying field have to be hidden from editing
tools like attribute table, false otherwise.
\param index The index of the field for which visibility is checked
:rtype: bool
%End
int indexOfPropertyDefinition( const QgsPropertyDefinition &definition ) const;
%Docstring
Returns the index of the auxiliary field for a specific property
definition.
\param definition The property definition
:return: The index of the field corresponding to the property or -1
:rtype: int
%End
int propertyFromIndex( int index ) const;
%Docstring
Returns the underlying property key for the field index. The key may be
a PAL, diagram or symbology property according to the underlying
property definition of the field. The key -1 is returned if an error
happened.
\param index The index of the field
:rtype: int
%End
QgsPropertyDefinition propertyDefinitionFromIndex( int index ) const;
%Docstring
Returns the property definition fir the underlying field index.
\param index The index of the field
:rtype: QgsPropertyDefinition
%End
static int createProperty( QgsPalLayerSettings::Property property, QgsVectorLayer *vlayer );
%Docstring
Creates if necessary a new auxiliary field for a PAL property and
activate this property in settings.
\param property The property to create
\param vlayer The vector layer
:return: The index of the auxiliary field or -1
:rtype: int
%End
static int createProperty( QgsDiagramLayerSettings::Property property, QgsVectorLayer *vlayer );
%Docstring
Creates if necessary a new auxiliary field for a diagram's property and
activate this this property in settings.
\param property The property to create
\param vlayer The vector layer
:return: The index of the auxiliary field or -1
:rtype: int
%End
static QgsField createAuxiliaryField( const QgsPropertyDefinition &definition );
%Docstring
Creates a new auxiliary field from a property definition.
\param definition The property definition of the auxiliary field to create
:rtype: QgsField
%End
static QgsField createAuxiliaryField( const QgsField &field );
%Docstring
Creates a new auxiliary field from a field.
\param field The field to use to create the auxiliary field
:rtype: QgsField
%End
static QString nameFromProperty( const QgsPropertyDefinition &def, bool joined = false );
%Docstring
Returns the name of the auxiliary field for a property definition.
\param def The property definition
\param joined The join prefix is taken into account if true
:rtype: str
%End
static QgsPropertyDefinition propertyDefinitionFromField( const QgsField &field );
%Docstring
Returns the property definition from an auxiliary field.
\param field The auxiliary field
:rtype: QgsPropertyDefinition
%End
};
class QgsAuxiliaryStorage
{
%Docstring
Class providing some utility methods to manage auxiliary storage.
.. versionadded:: 3.0
%End
%TypeHeaderCode
#include "qgsauxiliarystorage.h"
%End
public:
QgsAuxiliaryStorage( const QgsProject &project, bool copy = true );
%Docstring
Constructor.
The project filename is used to build a database path at the same
location, but with a different extension. Then, it's the same logic as
.. seealso:: QgsAuxiliaryStorage(const QString &, bool copy).
\param project The project for which the auxiliary storage has to be used
\param copy Parameter indicating if a copy of the database has to be used
%End
QgsAuxiliaryStorage( const QString &filename = QString(), bool copy = true );
%Docstring
Constructor.
If a valid database path is given in parameter and copy mode is
deactivated, then every changes is directly committed on the original
database. But if the copy mode is activated, then changes are committed
on a copy of the database (a temporary file) and a save action is
therefore necessary to keep modifications in the original file.
If an empty string for the database path is given in parameter, then
a database is created in a temporary file whatever the copy mode.
If the database path given in parameter is not empty but does not exist,
then a database is created at this location when copy mode is
deactivated. When copy mode is activated, a temporary database is used
instead and a save action will be necessary to create the database at
the original location given in parameter.
\param filename The path of the database
\param copy Parameter indicating if a copy of the database has to be used
%End
virtual ~QgsAuxiliaryStorage();
%Docstring
Destructor.
%End
bool isValid() const;
%Docstring
Returns the status of the auxiliary storage currently definied.
:return: true if the auxiliary storage is valid, false otherwise
:rtype: bool
%End
QString fileName() const;
%Docstring
Returns the target filename of the database.
:rtype: str
%End
QString currentFileName() const;
%Docstring
Returns the path of current database used. It may be different from the
target filename if the auxiliary storage is opened in copy mode.
:rtype: str
%End
bool saveAs( const QString &filename ) const;
%Docstring
Saves the current database to a new path.
:return: true if everything is saved, false otherwise
:rtype: bool
%End
bool saveAs( const QgsProject &project ) const;
%Docstring
Saves the current database to a new path for a specific project.
Actually, the current filename of the project is used to deduce the
path of the database to save.
:return: true if everything is saved, false otherwise
:rtype: bool
%End
bool save() const;
%Docstring
Saves the current database.
:return: true if everything is saved, false otherwise
:rtype: bool
%End
QgsAuxiliaryLayer *createAuxiliaryLayer( const QgsField &field, QgsVectorLayer *layer ) const /Factory/;
%Docstring
Creates an auxiliary layer for a vector layer. A new table is created if
necessary. The primary key to use to construct the auxiliary layer is
given in parameter.
\param field The primary key to join
\param layer The vector layer for which the auxiliary layer has to be created
:return: A new auxiliary layer or a None if an error happened.
:rtype: QgsAuxiliaryLayer
%End
static bool deleteTable( const QgsDataSourceUri &uri );
%Docstring
Removes a table from the auxiliary storage.
\param uri The uri of the table to remove
:return: true if the table is well deleted, false otherwise
:rtype: bool
%End
static bool duplicateTable( const QgsDataSourceUri &uri, const QString &newTable );
%Docstring
Duplicates a table and its content.
\param uri The uri of the table to duplicate
\param newTable The name of the new table
:return: true if the table is well duplicated, false otherwise
:rtype: bool
%End
static QString extension();
%Docstring
Returns the extension used for auxiliary databases.
:rtype: str
%End
};
/************************************************************************
* This file has been generated automatically from *
* *
* src/core/qgsauxiliarystorage.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/

View File

@ -811,6 +811,15 @@ Returns the number of registered layers.
:rtype: bool
%End
QgsAuxiliaryStorage *auxiliaryStorage();
%Docstring
Returns the current auxiliary storage.
.. versionadded:: 3.0
:rtype: QgsAuxiliaryStorage
%End
signals:
void readProject( const QDomDocument & );
%Docstring

View File

@ -72,15 +72,17 @@ class QgsPropertyDefinition
Constructs an empty property.
%End
QgsPropertyDefinition( const QString &name, const QString &description, StandardPropertyTemplate type );
QgsPropertyDefinition( const QString &name, const QString &description, StandardPropertyTemplate type, const QString &origin = QString(), const QString &comment = QString() );
%Docstring
Constructor for QgsPropertyDefinition, using a standard property template.
\param name is used internally and should be a unique, alphanumeric string.
\param description can be any localised string describing what the property is used for.
\param type one of the predefined standard property template
\param origin The origin of the property
\param comment A free comment for the property
%End
QgsPropertyDefinition( const QString &name, DataType dataType, const QString &description, const QString &helpText );
QgsPropertyDefinition( const QString &name, DataType dataType, const QString &description, const QString &helpText, const QString &origin = QString(), const QString &comment = QString() );
%Docstring
Constructor for custom QgsPropertyDefinitions.
\param name is used internally and should be a unique, alphanumeric string.
@ -88,6 +90,8 @@ class QgsPropertyDefinition
\param description can be any localised string describing what the property is used for.
\param helpText parameter should specify a descriptive string for users outlining the types
of value acceptable by the property (eg 'dashed' or 'solid' for a line style property).
\param origin The origin of the property
\param comment A free comment for the property
%End
QString name() const;
@ -96,18 +100,54 @@ class QgsPropertyDefinition
:rtype: str
%End
void setName( const QString &name );
%Docstring
Sets the name of the property
%End
QString origin() const;
%Docstring
Returns the origin of the property. For example, a PAL property has an
origin set to "labeling" while a diagram property has an origin set to
"diagram".
:rtype: str
%End
void setOrigin( const QString &origin );
%Docstring
Sets the origin of the property. For example, a PAL property has an
origin set to "labeling" while a diagram property has an origin set to
"diagram".
%End
QString description() const;
%Docstring
Descriptive name of the property.
:rtype: str
%End
QString comment() const;
%Docstring
Returns the comment of the property
:rtype: str
%End
void setComment( const QString &comment );
%Docstring
Sets comment of the property
%End
QString helpText() const;
%Docstring
Helper text for using the property, including a description of the valid values for the property.
:rtype: str
%End
void setDataType( DataType type );
%Docstring
Sets the data type
%End
DataType dataType() const;
%Docstring
Returns the allowable field/value data type for the property.

View File

@ -223,6 +223,7 @@ Try to find a rule given its unique key
:rtype: QgsRuleBasedLabeling.Rule
%End
QgsRuleBasedLabeling::Rule *clone() const /Factory/;
%Docstring
clone this rule, return new instance
@ -285,6 +286,16 @@ Create the instance from a DOM element with saved configuration
virtual QDomElement save( QDomDocument &doc, const QgsReadWriteContext &context ) const;
virtual QStringList subProviders() const;
virtual QgsPalLayerSettings settings( const QString &providerId = QString() ) const;
virtual void setSettings( QgsPalLayerSettings *settings /Transfer/, const QString &providerId = QString() );
%Docstring
Set pal settings for a specific provider (takes ownership).
\param settings Pal layer settings
\param providerId The id of the provider
.. versionadded:: 3.0
%End
virtual bool requiresAdvancedEffects() const;

View File

@ -774,6 +774,41 @@ Return the provider type for this layer
:rtype: str
%End
bool loadAuxiliaryLayer( const QgsAuxiliaryStorage &storage, const QString &key = QString() );
%Docstring
Loads the auxiliary layer for this vector layer. If there's no
corresponding table in the database, then nothing happens and false is
returned. The key is optional because if this layer has been read from
a XML document, then the key read in this document is used by default.
\param storage The auxiliary storage where to look for the table
\param key The key to use for joining.
:return: true if the auxiliary layer is well loaded, false otherwise
.. versionadded:: 3.0
:rtype: bool
%End
void setAuxiliaryLayer( QgsAuxiliaryLayer *layer /Transfer/ = 0 );
%Docstring
Sets the current auxiliary layer. The auxiliary layer is automatically
put in editable mode and fields are updated. Moreover, a join is created
between the current layer and the auxiliary layer. Ownership is
transferred.
.. versionadded:: 3.0
%End
QgsAuxiliaryLayer *auxiliaryLayer();
%Docstring
Returns the current auxiliary layer.
.. versionadded:: 3.0
:rtype: QgsAuxiliaryLayer
%End
virtual bool readSymbology( const QDomNode &layerNode, QString &errorMessage, const QgsReadWriteContext &context );
%Docstring
@ -1059,7 +1094,8 @@ Return the provider type for this layer
:rtype: int
%End
const QgsAbstractVectorLayerLabeling *labeling() const;
QgsAbstractVectorLayerLabeling *labeling();
%Docstring
Access to labeling configuration. May be null if labeling is not used.
.. versionadded:: 3.0
@ -1090,6 +1126,15 @@ Returns true if the provider has been modified since the last commit
:rtype: bool
%End
bool isAuxiliaryField( int index, int &srcIndex ) const;
%Docstring
Returns true if the field comes from the auxiliary layer,
false otherwise.
.. versionadded:: 3.0
:rtype: bool
%End
virtual void reload();
%Docstring
Synchronises with changes in the datasource
@ -1269,7 +1314,7 @@ Returns a map of field name to attribute alias
A set of attributes that are not advertised in WFS requests with QGIS server.
%End
bool deleteAttribute( int attr );
virtual bool deleteAttribute( int attr );
%Docstring
Delete an attribute field (but does not commit it)
:rtype: bool

View File

@ -130,6 +130,18 @@ Quick way to test if there is any join at all
:rtype: QgsFeature
%End
bool isAuxiliaryJoin( const QgsVectorLayerJoinInfo &info ) const;
%Docstring
Returns true if the join information is about auxiliary layer, false otherwise
\param info The join information
:return: true if the join information is about auxiliary layer, false otherwise
.. versionadded:: 3.0
:rtype: bool
%End
QgsVectorLayerJoinBuffer *clone() const /Factory/;
%Docstring
Create a copy of the join buffer

View File

@ -166,6 +166,39 @@ Returns whether values from the joined layer should be cached in memory to speed
:rtype: QgsFeature
%End
void setJoinFieldNamesBlackList( const QStringList &blackList );
%Docstring
Sets a list of fields to ignore whatever happens.
.. versionadded:: 3.0
%End
QStringList joinFieldNamesBlackList() const;
%Docstring
Returns the list of fields to ignore.
.. versionadded:: 3.0
:rtype: list of str
%End
bool hasSubset( bool blacklisted = true ) const;
%Docstring
Returns true if blacklisted fields is not empty or if a subset of names
has been set.
.. versionadded:: 3.0
:rtype: bool
%End
static QStringList joinFieldNamesSubset( const QgsVectorLayerJoinInfo &info, bool blacklisted = true );
%Docstring
Returns the list of field names to use for joining considering
blacklisted fields and subset.
.. versionadded:: 3.0
:rtype: list of str
%End
bool operator==( const QgsVectorLayerJoinInfo &other ) const;
void setJoinFieldNamesSubset( QStringList *fieldNamesSubset /Transfer/ );
@ -194,6 +227,7 @@ Returns whether values from the joined layer should be cached in memory to speed
};

View File

@ -61,6 +61,16 @@ Get list of sub-providers within the layer's labeling.
:rtype: QgsPalLayerSettings
%End
virtual void setSettings( QgsPalLayerSettings *settings /Transfer/, const QString &providerId = QString() ) = 0;
%Docstring
Set pal settings for a specific provider (takes ownership).
\param settings Pal layer settings
\param providerId The id of the provider
.. versionadded:: 3.0
%End
virtual bool requiresAdvancedEffects() const = 0;
%Docstring
Returns true if drawing labels requires advanced effects like composition
@ -109,6 +119,17 @@ Constructs simple labeling configuration with given initial settings
virtual QgsAbstractVectorLayerLabeling *clone() const /Factory/;
virtual QDomElement save( QDomDocument &doc, const QgsReadWriteContext &context ) const;
virtual QgsPalLayerSettings settings( const QString &providerId = QString() ) const;
virtual void setSettings( QgsPalLayerSettings *settings /Transfer/, const QString &providerId = QString() );
%Docstring
Set pal settings (takes ownership).
\param settings Pal layer settings
\param providerId Unused parameter
.. versionadded:: 3.0
%End
virtual bool requiresAdvancedEffects() const;
virtual void toSld( QDomNode &parent, const QgsStringMap &props ) const;

View File

@ -47,7 +47,7 @@ In C++ you can use QgsSymbolLayerMetadata convenience class.
Create a symbol layer of this type given the map of properties.
:rtype: QgsSymbolLayer
%End
virtual QgsSymbolLayerWidget *createSymbolLayerWidget( const QgsVectorLayer * ) /Factory/;
virtual QgsSymbolLayerWidget *createSymbolLayerWidget( QgsVectorLayer * ) /Factory/;
%Docstring
Create widget for symbol layer of this type. Can return NULL if there's no GUI
:rtype: QgsSymbolLayerWidget
@ -86,7 +86,7 @@ Convenience metadata class that uses static functions to create symbol layer and
virtual QgsSymbolLayer *createSymbolLayer( const QgsStringMap &map ) /Factory/;
virtual QgsSymbolLayerWidget *createSymbolLayerWidget( const QgsVectorLayer *vl ) /Factory/;
virtual QgsSymbolLayerWidget *createSymbolLayerWidget( QgsVectorLayer *vl ) /Factory/;
virtual QgsSymbolLayer *createSymbolLayerFromSld( QDomElement &elem ) /Factory/;
virtual void resolvePaths( QgsStringMap &properties, const QgsPathResolver &pathResolver, bool saving );

View File

@ -152,6 +152,8 @@
%Include qgsmessagelogviewer.sip
%Include qgsmessageviewer.sip
%Include qgsmetadatawidget.sip
%Include qgsnewauxiliarylayerdialog.sip
%Include qgsnewauxiliaryfielddialog.sip
%Include qgsnewhttpconnection.sip
%Include qgsnewmemorylayerdialog.sip
%Include qgsnewnamedialog.sip

View File

@ -0,0 +1,54 @@
/************************************************************************
* This file has been generated automatically from *
* *
* src/gui/qgsnewauxiliaryfielddialog.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/
class QgsNewAuxiliaryFieldDialog: QDialog
{
%Docstring
A dialog to create a new auxiliary field
.. versionadded:: 3.0
%End
%TypeHeaderCode
#include "qgsnewauxiliaryfielddialog.h"
%End
public:
QgsNewAuxiliaryFieldDialog( const QgsPropertyDefinition &definition, QgsVectorLayer *layer, bool nameOnly = true, QWidget *parent = 0 );
%Docstring
Constructor.
\param definition The property definition to use to create the auxiliary field
\param layer The vector layer for which the auxiliary layer has to be created
\param nameOnly True to indicate that only the name widget is enabled
\param parent Parent window
%End
QgsPropertyDefinition propertyDefinition() const;
%Docstring
Returns the underlying property definition.
:rtype: QgsPropertyDefinition
%End
protected:
virtual void accept();
};
/************************************************************************
* This file has been generated automatically from *
* *
* src/gui/qgsnewauxiliaryfielddialog.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/

View File

@ -0,0 +1,46 @@
/************************************************************************
* This file has been generated automatically from *
* *
* src/gui/qgsnewauxiliarylayerdialog.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/
class QgsNewAuxiliaryLayerDialog: QDialog
{
%Docstring
A dialog to create a new auxiliary layer
.. versionadded:: 3.0
%End
%TypeHeaderCode
#include "qgsnewauxiliarylayerdialog.h"
%End
public:
QgsNewAuxiliaryLayerDialog( QgsVectorLayer *layer, QWidget *parent = 0 );
%Docstring
Constructor.
\param layer The vector layer for which the auxiliary layer has to be created
\param parent Parent window
%End
protected:
virtual void accept();
};
/************************************************************************
* This file has been generated automatically from *
* *
* src/gui/qgsnewauxiliarylayerdialog.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/

View File

@ -42,25 +42,29 @@ class QgsPropertyOverrideButton: QToolButton
void init( int propertyKey,
const QgsProperty &property,
const QgsPropertiesDefinition &definitions,
const QgsVectorLayer *layer = 0 );
const QgsVectorLayer *layer = 0,
bool auxiliaryStorageEnabled = false );
%Docstring
Initialize a newly constructed property button (useful if button was included in a UI layout).
\param propertyKey key for corresponding property
\param property initial value of associated property to show in widget
\param definitions properties definitions for corresponding collection
\param layer associated vector layer
\param auxiliaryStorageEnabled If true, activate the button to store data defined in auxiliary storage
%End
void init( int propertyKey,
const QgsAbstractPropertyCollection &collection,
const QgsPropertiesDefinition &definitions,
const QgsVectorLayer *layer = 0 );
const QgsVectorLayer *layer = 0,
bool auxiliaryStorageEnabled = false );
%Docstring
Initialize a newly constructed property button (useful if button was included in a UI layout).
\param propertyKey key for corresponding property
\param collection associated property collection
\param definitions properties definitions for collection
\param layer associated vector layer
\param auxiliaryStorageEnabled If true, activate the button to store data defined in auxiliary storage
%End
QgsProperty toProperty() const;
@ -172,6 +176,13 @@ class QgsPropertyOverrideButton: QToolButton
an expression context for the button when required.
%End
void updateFieldLists();
%Docstring
Updates list of fields.
.. versionadded:: 3.0
%End
public slots:
@ -190,6 +201,11 @@ Emitted when property definition changes
void activated( bool isActive );
%Docstring
Emitted when the activated status of the widget changes
%End
void createAuxiliaryField();
%Docstring
Emitted when creating a new auxiliary field
%End
protected:

View File

@ -16,14 +16,14 @@ class QgsArrowSymbolLayerWidget: QgsSymbolLayerWidget
%End
public:
QgsArrowSymbolLayerWidget( const QgsVectorLayer *layer, QWidget *parent /TransferThis/ = 0 );
QgsArrowSymbolLayerWidget( QgsVectorLayer *layer, QWidget *parent /TransferThis/ = 0 );
%Docstring
Constructor
\param layer the layer where this symbol layer is applied
\param parent the parent widget
%End
static QgsSymbolLayerWidget *create( const QgsVectorLayer *layer ) /Factory/;
static QgsSymbolLayerWidget *create( QgsVectorLayer *layer ) /Factory/;
%Docstring
Static creation method
\param layer the layer where this symbol layer is applied

View File

@ -15,10 +15,18 @@ class QgsEllipseSymbolLayerWidget: QgsSymbolLayerWidget
#include "qgsellipsesymbollayerwidget.h"
%End
public:
QgsEllipseSymbolLayerWidget( const QgsVectorLayer *vl, QWidget *parent /TransferThis/ = 0 );
static QgsSymbolLayerWidget *create( const QgsVectorLayer *vl ) /Factory/;
QgsEllipseSymbolLayerWidget( QgsVectorLayer *vl, QWidget *parent /TransferThis/ = 0 );
%Docstring
Constructor for QgsEllipseSymbolLayerWidget.
\param vl associated vector layer
\param parent parent widget
%End
static QgsSymbolLayerWidget *create( QgsVectorLayer *vl ) /Factory/;
%Docstring
Creates a new QgsSymbolLayerWidget.
\param vl associated vector layer
:rtype: QgsSymbolLayerWidget
%End

View File

@ -18,7 +18,15 @@ class QgsLayerPropertiesWidget : QgsPanelWidget, QgsExpressionContextGenerator
#include "qgslayerpropertieswidget.h"
%End
public:
QgsLayerPropertiesWidget( QgsSymbolLayer *layer, const QgsSymbol *symbol, const QgsVectorLayer *vl, QWidget *parent /TransferThis/ = 0 );
QgsLayerPropertiesWidget( QgsSymbolLayer *layer, const QgsSymbol *symbol, QgsVectorLayer *vl, QWidget *parent /TransferThis/ = 0 );
%Docstring
Constructor for QgsLayerPropertiesWidget.
\param layer the symbol layer
\param symbol the symbol
\param vl associated vector layer
\param parent parent widget
%End
void setContext( const QgsSymbolWidgetContext &context );
%Docstring

View File

@ -16,7 +16,13 @@ class QgsSymbolLayerWidget : QWidget, protected QgsExpressionContextGenerator
#include "qgssymbollayerwidget.h"
%End
public:
QgsSymbolLayerWidget( QWidget *parent /TransferThis/, const QgsVectorLayer *vl = 0 );
QgsSymbolLayerWidget( QWidget *parent /TransferThis/, QgsVectorLayer *vl = 0 );
%Docstring
Constructor for QgsSymbolLayerWidget.
\param vl associated vector layer
\param parent parent widget
%End
virtual void setSymbolLayer( QgsSymbolLayer *layer ) = 0;
virtual QgsSymbolLayer *symbolLayer() = 0;
@ -91,10 +97,18 @@ class QgsSimpleLineSymbolLayerWidget : QgsSymbolLayerWidget
#include "qgssymbollayerwidget.h"
%End
public:
QgsSimpleLineSymbolLayerWidget( const QgsVectorLayer *vl, QWidget *parent /TransferThis/ = 0 );
static QgsSymbolLayerWidget *create( const QgsVectorLayer *vl ) /Factory/;
QgsSimpleLineSymbolLayerWidget( QgsVectorLayer *vl, QWidget *parent /TransferThis/ = 0 );
%Docstring
Constructor for QgsSimpleLineSymbolLayerWidget.
\param vl associated vector layer
\param parent parent widget
%End
static QgsSymbolLayerWidget *create( QgsVectorLayer *vl ) /Factory/;
%Docstring
Creates a new QgsSimpleLineSymbolLayerWidget.
\param vl associated vector layer
:rtype: QgsSymbolLayerWidget
%End
@ -117,10 +131,18 @@ class QgsSimpleMarkerSymbolLayerWidget : QgsSymbolLayerWidget
#include "qgssymbollayerwidget.h"
%End
public:
QgsSimpleMarkerSymbolLayerWidget( const QgsVectorLayer *vl, QWidget *parent /TransferThis/ = 0 );
static QgsSymbolLayerWidget *create( const QgsVectorLayer *vl ) /Factory/;
QgsSimpleMarkerSymbolLayerWidget( QgsVectorLayer *vl, QWidget *parent /TransferThis/ = 0 );
%Docstring
Constructor for QgsSimpleMarkerSymbolLayerWidget.
\param vl associated vector layer
\param parent parent widget
%End
static QgsSymbolLayerWidget *create( QgsVectorLayer *vl ) /Factory/;
%Docstring
Creates a new QgsSimpleMarkerSymbolLayerWidget.
\param vl associated vector layer
:rtype: QgsSymbolLayerWidget
%End
@ -146,10 +168,18 @@ class QgsSimpleFillSymbolLayerWidget : QgsSymbolLayerWidget
#include "qgssymbollayerwidget.h"
%End
public:
QgsSimpleFillSymbolLayerWidget( const QgsVectorLayer *vl, QWidget *parent /TransferThis/ = 0 );
static QgsSymbolLayerWidget *create( const QgsVectorLayer *vl ) /Factory/;
QgsSimpleFillSymbolLayerWidget( QgsVectorLayer *vl, QWidget *parent /TransferThis/ = 0 );
%Docstring
Constructor for QgsSimpleFillSymbolLayerWidget.
\param vl associated vector layer
\param parent parent widget
%End
static QgsSymbolLayerWidget *create( QgsVectorLayer *vl ) /Factory/;
%Docstring
Creates a new QgsSimpleFillSymbolLayerWidget.
\param vl associated vector layer
:rtype: QgsSymbolLayerWidget
%End
@ -180,14 +210,14 @@ class QgsFilledMarkerSymbolLayerWidget : QgsSymbolLayerWidget
%End
public:
QgsFilledMarkerSymbolLayerWidget( const QgsVectorLayer *vl, QWidget *parent /TransferThis/ = 0 );
QgsFilledMarkerSymbolLayerWidget( QgsVectorLayer *vl, QWidget *parent /TransferThis/ = 0 );
%Docstring
Constructor for QgsFilledMarkerSymbolLayerWidget.
\param vl associated vector layer
\param parent parent widget
%End
static QgsSymbolLayerWidget *create( const QgsVectorLayer *vl ) /Factory/;
static QgsSymbolLayerWidget *create( QgsVectorLayer *vl ) /Factory/;
%Docstring
Creates a new QgsFilledMarkerSymbolLayerWidget.
\param vl associated vector layer
@ -211,10 +241,18 @@ class QgsGradientFillSymbolLayerWidget : QgsSymbolLayerWidget
#include "qgssymbollayerwidget.h"
%End
public:
QgsGradientFillSymbolLayerWidget( const QgsVectorLayer *vl, QWidget *parent /TransferThis/ = 0 );
static QgsSymbolLayerWidget *create( const QgsVectorLayer *vl ) /Factory/;
QgsGradientFillSymbolLayerWidget( QgsVectorLayer *vl, QWidget *parent /TransferThis/ = 0 );
%Docstring
Constructor for QgsGradientFillSymbolLayerWidget.
\param vl associated vector layer
\param parent parent widget
%End
static QgsSymbolLayerWidget *create( QgsVectorLayer *vl ) /Factory/;
%Docstring
Creates a new QgsGradientFillSymbolLayerWidget.
\param vl associated vector layer
:rtype: QgsSymbolLayerWidget
%End
@ -247,10 +285,18 @@ class QgsShapeburstFillSymbolLayerWidget : QgsSymbolLayerWidget
#include "qgssymbollayerwidget.h"
%End
public:
QgsShapeburstFillSymbolLayerWidget( const QgsVectorLayer *vl, QWidget *parent /TransferThis/ = 0 );
static QgsSymbolLayerWidget *create( const QgsVectorLayer *vl ) /Factory/;
QgsShapeburstFillSymbolLayerWidget( QgsVectorLayer *vl, QWidget *parent /TransferThis/ = 0 );
%Docstring
Constructor for QgsShapeburstFillSymbolLayerWidget.
\param vl associated vector layer
\param parent parent widget
%End
static QgsSymbolLayerWidget *create( QgsVectorLayer *vl ) /Factory/;
%Docstring
Creates a new QgsShapeburstFillSymbolLayerWidget.
\param vl associated vector layer
:rtype: QgsSymbolLayerWidget
%End
@ -275,10 +321,18 @@ class QgsMarkerLineSymbolLayerWidget : QgsSymbolLayerWidget
#include "qgssymbollayerwidget.h"
%End
public:
QgsMarkerLineSymbolLayerWidget( const QgsVectorLayer *vl, QWidget *parent /TransferThis/ = 0 );
static QgsSymbolLayerWidget *create( const QgsVectorLayer *vl ) /Factory/;
QgsMarkerLineSymbolLayerWidget( QgsVectorLayer *vl, QWidget *parent /TransferThis/ = 0 );
%Docstring
Constructor for QgsMarkerLineSymbolLayerWidget.
\param vl associated vector layer
\param parent parent widget
%End
static QgsSymbolLayerWidget *create( QgsVectorLayer *vl ) /Factory/;
%Docstring
Creates a new QgsMarkerLineSymbolLayerWidget.
\param vl associated vector layer
:rtype: QgsSymbolLayerWidget
%End
@ -306,10 +360,18 @@ class QgsSvgMarkerSymbolLayerWidget : QgsSymbolLayerWidget
#include "qgssymbollayerwidget.h"
%End
public:
QgsSvgMarkerSymbolLayerWidget( const QgsVectorLayer *vl, QWidget *parent /TransferThis/ = 0 );
static QgsSymbolLayerWidget *create( const QgsVectorLayer *vl ) /Factory/;
QgsSvgMarkerSymbolLayerWidget( QgsVectorLayer *vl, QWidget *parent /TransferThis/ = 0 );
%Docstring
Constructor for QgsSvgMarkerSymbolLayerWidget.
\param vl associated vector layer
\param parent parent widget
%End
static QgsSymbolLayerWidget *create( QgsVectorLayer *vl ) /Factory/;
%Docstring
Creates a new QgsSvgMarkerSymbolLayerWidget.
\param vl associated vector layer
:rtype: QgsSymbolLayerWidget
%End
@ -334,10 +396,18 @@ class QgsRasterFillSymbolLayerWidget : QgsSymbolLayerWidget
#include "qgssymbollayerwidget.h"
%End
public:
QgsRasterFillSymbolLayerWidget( const QgsVectorLayer *vl, QWidget *parent /TransferThis/ = 0 );
static QgsSymbolLayerWidget *create( const QgsVectorLayer *vl ) /Factory/;
QgsRasterFillSymbolLayerWidget( QgsVectorLayer *vl, QWidget *parent /TransferThis/ = 0 );
%Docstring
Constructor for QgsRasterFillSymbolLayerWidget.
\param vl associated vector layer
\param parent parent widget
%End
static QgsSymbolLayerWidget *create( QgsVectorLayer *vl ) /Factory/;
%Docstring
Creates a new QgsRasterFillSymbolLayerWidget.
\param vl associated vector layer
:rtype: QgsSymbolLayerWidget
%End
@ -358,10 +428,18 @@ class QgsSVGFillSymbolLayerWidget : QgsSymbolLayerWidget
#include "qgssymbollayerwidget.h"
%End
public:
QgsSVGFillSymbolLayerWidget( const QgsVectorLayer *vl, QWidget *parent /TransferThis/ = 0 );
static QgsSymbolLayerWidget *create( const QgsVectorLayer *vl ) /Factory/;
QgsSVGFillSymbolLayerWidget( QgsVectorLayer *vl, QWidget *parent /TransferThis/ = 0 );
%Docstring
Constructor for QgsSVGFillSymbolLayerWidget.
\param vl associated vector layer
\param parent parent widget
%End
static QgsSymbolLayerWidget *create( QgsVectorLayer *vl ) /Factory/;
%Docstring
Creates a new QgsSVGFillSymbolLayerWidget.
\param vl associated vector layer
:rtype: QgsSymbolLayerWidget
%End
@ -392,9 +470,17 @@ class QgsLinePatternFillSymbolLayerWidget : QgsSymbolLayerWidget
%End
public:
QgsLinePatternFillSymbolLayerWidget( const QgsVectorLayer *vl, QWidget *parent /TransferThis/ = 0 );
static QgsSymbolLayerWidget *create( const QgsVectorLayer *vl ) /Factory/;
QgsLinePatternFillSymbolLayerWidget( QgsVectorLayer *vl, QWidget *parent /TransferThis/ = 0 );
%Docstring
Constructor for QgsLinePatternFillSymbolLayerWidget.
\param vl associated vector layer
\param parent parent widget
%End
static QgsSymbolLayerWidget *create( QgsVectorLayer *vl ) /Factory/;
%Docstring
Creates a new QgsLinePatternFillSymbolLayerWidget.
\param vl associated vector layer
:rtype: QgsSymbolLayerWidget
%End
@ -415,9 +501,18 @@ class QgsPointPatternFillSymbolLayerWidget: QgsSymbolLayerWidget
#include "qgssymbollayerwidget.h"
%End
public:
QgsPointPatternFillSymbolLayerWidget( const QgsVectorLayer *vl, QWidget *parent /TransferThis/ = 0 );
static QgsSymbolLayerWidget *create( const QgsVectorLayer *vl ) /Factory/;
QgsPointPatternFillSymbolLayerWidget( QgsVectorLayer *vl, QWidget *parent /TransferThis/ = 0 );
%Docstring
Constructor for QgsPointPatternFillSymbolLayerWidget.
\param vl associated vector layer
\param parent parent widget
%End
static QgsSymbolLayerWidget *create( QgsVectorLayer *vl ) /Factory/;
%Docstring
Creates a new QgsPointPatternFillSymbolLayerWidget.
\param vl associated vector layer
:rtype: QgsSymbolLayerWidget
%End
@ -438,10 +533,18 @@ class QgsFontMarkerSymbolLayerWidget : QgsSymbolLayerWidget
#include "qgssymbollayerwidget.h"
%End
public:
QgsFontMarkerSymbolLayerWidget( const QgsVectorLayer *vl, QWidget *parent /TransferThis/ = 0 );
static QgsSymbolLayerWidget *create( const QgsVectorLayer *vl ) /Factory/;
QgsFontMarkerSymbolLayerWidget( QgsVectorLayer *vl, QWidget *parent /TransferThis/ = 0 );
%Docstring
Constructor for QgsFontMarkerSymbolLayerWidget.
\param vl associated vector layer
\param parent parent widget
%End
static QgsSymbolLayerWidget *create( QgsVectorLayer *vl ) /Factory/;
%Docstring
Creates a new QgsFontMarkerSymbolLayerWidget.
\param vl associated vector layer
:rtype: QgsSymbolLayerWidget
%End
@ -476,10 +579,18 @@ class QgsCentroidFillSymbolLayerWidget : QgsSymbolLayerWidget
#include "qgssymbollayerwidget.h"
%End
public:
QgsCentroidFillSymbolLayerWidget( const QgsVectorLayer *vl, QWidget *parent /TransferThis/ = 0 );
static QgsSymbolLayerWidget *create( const QgsVectorLayer *vl ) /Factory/;
QgsCentroidFillSymbolLayerWidget( QgsVectorLayer *vl, QWidget *parent /TransferThis/ = 0 );
%Docstring
Constructor for QgsCentroidFillSymbolLayerWidget.
\param vl associated vector layer
\param parent parent widget
%End
static QgsSymbolLayerWidget *create( QgsVectorLayer *vl ) /Factory/;
%Docstring
Creates a new QgsCentroidFillSymbolLayerWidget.
\param vl associated vector layer
:rtype: QgsSymbolLayerWidget
%End
@ -500,9 +611,15 @@ class QgsGeometryGeneratorSymbolLayerWidget : QgsSymbolLayerWidget
#include "qgssymbollayerwidget.h"
%End
public:
QgsGeometryGeneratorSymbolLayerWidget( const QgsVectorLayer *vl, QWidget *parent /TransferThis/ = 0 );
static QgsSymbolLayerWidget *create( const QgsVectorLayer *vl ) /Factory/;
QgsGeometryGeneratorSymbolLayerWidget( QgsVectorLayer *vl, QWidget *parent /TransferThis/ = 0 );
%Docstring
Constructor for QgsGeometryGeneratorSymbolLayerWidget.
\param vl associated vector layer
\param parent parent widget
%End
static QgsSymbolLayerWidget *create( QgsVectorLayer *vl ) /Factory/;
%Docstring
Will be registered as factory
:rtype: QgsSymbolLayerWidget

View File

@ -28,7 +28,7 @@ class QgsSymbolSelectorWidget: QgsPanelWidget
%End
public:
QgsSymbolSelectorWidget( QgsSymbol *symbol, QgsStyle *style, const QgsVectorLayer *vl, QWidget *parent /TransferThis/ = 0 );
QgsSymbolSelectorWidget( QgsSymbol *symbol, QgsStyle *style, QgsVectorLayer *vl, QWidget *parent /TransferThis/ = 0 );
%Docstring
Symbol selector widget that can be used to select and build a symbol
\param symbol The symbol to load into the widget as a start point.
@ -184,7 +184,17 @@ class QgsSymbolSelectorDialog : QDialog
#include "qgssymbolselectordialog.h"
%End
public:
QgsSymbolSelectorDialog( QgsSymbol *symbol, QgsStyle *style, const QgsVectorLayer *vl, QWidget *parent /TransferThis/ = 0, bool embedded = false );
QgsSymbolSelectorDialog( QgsSymbol *symbol, QgsStyle *style, QgsVectorLayer *vl, QWidget *parent /TransferThis/ = 0, bool embedded = false );
%Docstring
Constructor for QgsSymbolSelectorDialog.
\param symbol The symbol
\param style The style
\param vl Associated vector layer
\param parent Parent widget
\param embedded True to embed in renderer properties dialog, false otherwise
%End
~QgsSymbolSelectorDialog();
QMenu *advancedMenu();

View File

@ -19,7 +19,16 @@ class QgsSymbolsListWidget : QWidget
#include "qgssymbolslistwidget.h"
%End
public:
QgsSymbolsListWidget( QgsSymbol *symbol, QgsStyle *style, QMenu *menu, QWidget *parent /TransferThis/, const QgsVectorLayer *layer = 0 );
QgsSymbolsListWidget( QgsSymbol *symbol, QgsStyle *style, QMenu *menu, QWidget *parent /TransferThis/, QgsVectorLayer *layer = 0 );
%Docstring
Constructor for QgsSymbolsListWidget.
\param symbol the symbol
\param style the style
\param menu the menu where to show it
\param parent parent widget
\param layer associated vector layer
%End
virtual ~QgsSymbolsListWidget();

View File

@ -15,10 +15,18 @@ class QgsVectorFieldSymbolLayerWidget: QgsSymbolLayerWidget
#include "qgsvectorfieldsymbollayerwidget.h"
%End
public:
QgsVectorFieldSymbolLayerWidget( const QgsVectorLayer *vl, QWidget *parent /TransferThis/ = 0 );
static QgsSymbolLayerWidget *create( const QgsVectorLayer *vl ) /Factory/;
QgsVectorFieldSymbolLayerWidget( QgsVectorLayer *vl, QWidget *parent /TransferThis/ = 0 );
%Docstring
Constructor for QgsVectorFieldSymbolLayerWidget.
\param vl associated vector layer
\param parent parent widget
%End
static QgsSymbolLayerWidget *create( QgsVectorLayer *vl ) /Factory/;
%Docstring
Creates a new QgsVectorFieldSymbolLayerWidget.
\param vl associated vector layer
:rtype: QgsSymbolLayerWidget
%End

View File

@ -98,6 +98,7 @@ typedef SInt32 SRefCon;
#include "qgsvectorlayer.h"
#include "qgis_app.h"
#include "qgscrashhandler.h"
#include "qgsziputils.h"
#include "qgsuserprofilemanager.h"
#include "qgsuserprofile.h"
@ -1169,7 +1170,8 @@ int main( int argc, char *argv[] )
{
QgsDebugMsg( QString( "Trying to load file : %1" ).arg( layerName ) );
// don't load anything with a .qgs extension - these are project files
if ( !layerName.endsWith( QLatin1String( ".qgs" ), Qt::CaseInsensitive ) )
if ( !layerName.endsWith( QLatin1String( ".qgs" ), Qt::CaseInsensitive )
&& !QgsZipUtils::isZipFile( layerName ) )
{
qgis->openLayer( layerName );
}

View File

@ -79,6 +79,7 @@
#include "qgstaskmanager.h"
#include "qgsziputils.h"
#include "qgsbrowsermodel.h"
#include "qgsvectorlayerjoinbuffer.h"
#ifdef HAVE_3D
#include "qgsabstract3drenderer.h"
@ -1856,7 +1857,7 @@ void QgisApp::createActions()
connect( mActionRollbackAllEdits, &QAction::triggered, this, &QgisApp::rollbackAllEdits );
connect( mActionCancelEdits, &QAction::triggered, this, [ = ] { cancelEdits(); } );
connect( mActionCancelAllEdits, &QAction::triggered, this, &QgisApp::cancelAllEdits );
connect( mActionLayerSaveAs, &QAction::triggered, this, &QgisApp::saveAsFile );
connect( mActionLayerSaveAs, &QAction::triggered, this, [ = ] { saveAsFile(); } );
connect( mActionSaveLayerDefinition, &QAction::triggered, this, &QgisApp::saveAsLayerDefinition );
connect( mActionRemoveLayer, &QAction::triggered, this, &QgisApp::removeLayer );
connect( mActionDuplicateLayer, &QAction::triggered, this, [ = ] { duplicateLayers(); } );
@ -6442,9 +6443,11 @@ void QgisApp::attributeTable()
// the dialog will be deleted by itself on close
}
void QgisApp::saveAsRasterFile()
void QgisApp::saveAsRasterFile( QgsRasterLayer *rasterLayer )
{
QgsRasterLayer *rasterLayer = qobject_cast<QgsRasterLayer *>( activeLayer() );
if ( !rasterLayer )
rasterLayer = qobject_cast<QgsRasterLayer *>( activeLayer() );
if ( !rasterLayer )
{
return;
@ -6578,20 +6581,22 @@ void QgisApp::saveAsRasterFile()
}
void QgisApp::saveAsFile()
void QgisApp::saveAsFile( QgsMapLayer *layer )
{
QgsMapLayer *layer = activeLayer();
if ( !layer )
layer = activeLayer();
if ( !layer )
return;
QgsMapLayer::LayerType layerType = layer->type();
if ( layerType == QgsMapLayer::RasterLayer )
{
saveAsRasterFile();
saveAsRasterFile( qobject_cast<QgsRasterLayer *>( layer ) );
}
else if ( layerType == QgsMapLayer::VectorLayer )
{
saveAsVectorFileGeneral();
saveAsVectorFileGeneral( qobject_cast<QgsVectorLayer *>( layer ) );
}
}
@ -8631,7 +8636,14 @@ void QgisApp::layerSubsetString()
if ( !vlayer )
return;
if ( !vlayer->vectorJoins().isEmpty() )
bool joins = !vlayer->vectorJoins().isEmpty();
if ( vlayer->vectorJoins().size() == 1 )
{
QgsVectorLayerJoinInfo info = vlayer->vectorJoins()[0];
joins = !vlayer->joinBuffer()->isAuxiliaryJoin( info );
}
if ( joins )
{
if ( QMessageBox::question( nullptr, tr( "Filter on joined fields" ),
tr( "You are about to set a subset filter on a layer that has joined fields. "
@ -8869,6 +8881,9 @@ void QgisApp::duplicateLayers( const QList<QgsMapLayer *> &lyrList )
}
else if ( vlayer )
{
if ( vlayer->auxiliaryLayer() )
vlayer->auxiliaryLayer()->save();
dupLayer = vlayer->clone();
}
}
@ -10993,38 +11008,16 @@ void QgisApp::updateLabelToolButtons()
for ( QMap<QString, QgsMapLayer *>::iterator it = layers.begin(); it != layers.end(); ++it )
{
QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( it.value() );
if ( !vlayer || !vlayer->isEditable() ||
( !vlayer->diagramsEnabled() && !vlayer->labelsEnabled() ) )
continue;
if ( vlayer && ( vlayer->diagramsEnabled() || vlayer->labelsEnabled() ) )
{
enablePin = true;
enableShowHide = true;
enableMove = true;
enableRotate = true;
enableChange = true;
int colX, colY, colShow, colAng;
enablePin =
enablePin ||
( qobject_cast<QgsMapToolPinLabels *>( mMapTools.mPinLabels ) &&
( qobject_cast<QgsMapToolPinLabels *>( mMapTools.mPinLabels )->labelMoveable( vlayer, colX, colY )
|| qobject_cast<QgsMapToolPinLabels *>( mMapTools.mPinLabels )->diagramMoveable( vlayer, colX, colY ) ) );
enableShowHide =
enableShowHide ||
( qobject_cast<QgsMapToolShowHideLabels *>( mMapTools.mShowHideLabels ) &&
( qobject_cast<QgsMapToolShowHideLabels *>( mMapTools.mShowHideLabels )->labelCanShowHide( vlayer, colShow )
|| qobject_cast<QgsMapToolShowHideLabels *>( mMapTools.mShowHideLabels )->diagramCanShowHide( vlayer, colShow ) ) );
enableMove =
enableMove ||
( qobject_cast<QgsMapToolMoveLabel *>( mMapTools.mMoveLabel ) &&
( qobject_cast<QgsMapToolMoveLabel *>( mMapTools.mMoveLabel )->labelMoveable( vlayer, colX, colY )
|| qobject_cast<QgsMapToolMoveLabel *>( mMapTools.mMoveLabel )->diagramMoveable( vlayer, colX, colY ) ) );
enableRotate =
enableRotate ||
( qobject_cast<QgsMapToolRotateLabel *>( mMapTools.mRotateLabel ) &&
qobject_cast<QgsMapToolRotateLabel *>( mMapTools.mRotateLabel )->layerIsRotatable( vlayer, colAng ) );
enableChange = true;
if ( enablePin && enableShowHide && enableMove && enableRotate && enableChange )
break;
}
}
mActionPinLabels->setEnabled( enablePin );

View File

@ -654,6 +654,9 @@ class APP_EXPORT QgisApp : public QMainWindow, private Ui::MainWindow
QSize iconSize( bool dockedToolbar = false ) const;
public slots:
//! save current vector layer
void saveAsFile( QgsMapLayer *layer = nullptr );
//! Process the list of URIs that have been dropped in QGIS
void handleDropUriList( const QgsMimeDataUtils::UriList &lst );
//! Convenience function to open either a project or a layer file.
@ -1439,13 +1442,10 @@ class APP_EXPORT QgisApp : public QMainWindow, private Ui::MainWindow
//! set the CAD dock widget visible
void setCadDockVisible( bool visible );
//! save current vector layer
void saveAsFile();
void saveAsLayerDefinition();
//! save current raster layer
void saveAsRasterFile();
void saveAsRasterFile( QgsRasterLayer *layer = nullptr );
//! show Python console
void showPythonDialog();

View File

@ -39,6 +39,8 @@
#include "qgslogger.h"
#include "qgisapp.h"
#include "qgssettings.h"
#include "qgsnewauxiliarylayerdialog.h"
#include "qgsauxiliarystorage.h"
#include <QList>
#include <QMessageBox>
@ -484,8 +486,9 @@ QgsDiagramProperties::~QgsDiagramProperties()
void QgsDiagramProperties::registerDataDefinedButton( QgsPropertyOverrideButton *button, QgsDiagramLayerSettings::Property key )
{
button->init( key, mDataDefinedProperties, QgsDiagramLayerSettings::propertyDefinitions(), mLayer );
button->init( key, mDataDefinedProperties, QgsDiagramLayerSettings::propertyDefinitions(), mLayer, true );
connect( button, &QgsPropertyOverrideButton::changed, this, &QgsDiagramProperties::updateProperty );
connect( button, &QgsPropertyOverrideButton::createAuxiliaryField, this, &QgsDiagramProperties::createAuxiliaryField );
button->registerExpressionContextGenerator( this );
}
@ -1048,3 +1051,35 @@ void QgsDiagramProperties::showHelp()
{
QgsHelp::openHelp( QStringLiteral( "working_with_vector/vector_properties.html#legend" ) );
}
void QgsDiagramProperties::createAuxiliaryField()
{
// try to create an auxiliary layer if not yet created
if ( !mLayer->auxiliaryLayer() )
{
QgsNewAuxiliaryLayerDialog dlg( mLayer, this );
dlg.exec();
}
// return if still not exists
if ( !mLayer->auxiliaryLayer() )
return;
QgsPropertyOverrideButton *button = qobject_cast<QgsPropertyOverrideButton *>( sender() );
const QgsDiagramLayerSettings::Property key = static_cast< QgsDiagramLayerSettings::Property >( button->propertyKey() );
const QgsPropertyDefinition def = QgsDiagramLayerSettings::propertyDefinitions()[key];
// create property in auxiliary storage if necessary
if ( !mLayer->auxiliaryLayer()->exists( def ) )
mLayer->auxiliaryLayer()->addAuxiliaryField( def );
// update property with join field name from auxiliary storage
QgsProperty property = button->toProperty();
property.setField( QgsAuxiliaryLayer::nameFromProperty( def, true ) );
property.setActive( true );
button->updateFieldLists();
button->setToProperty( property );
mDataDefinedProperties.setProperty( key, button->toProperty() );
emit auxiliaryFieldCreated();
}

View File

@ -39,6 +39,10 @@ class APP_EXPORT QgsDiagramProperties : public QWidget, private Ui::QgsDiagramPr
//! Adds an attribute from the list of available attributes to the assigned attributes with a random color.
void addAttribute( QTreeWidgetItem *item );
signals:
void auxiliaryFieldCreated();
public slots:
void apply();
void mDiagramTypeComboBox_currentIndexChanged( int index );
@ -95,6 +99,8 @@ class APP_EXPORT QgsDiagramProperties : public QWidget, private Ui::QgsDiagramPr
void updateProperty();
void showHelp();
void createAuxiliaryField();
};
class EditBlockerDelegate: public QStyledItemDelegate

View File

@ -21,6 +21,8 @@
#include "qgsmapcanvas.h"
#include "qgsvectorlayerlabeling.h"
#include "qgsproject.h"
#include "qgsauxiliarystorage.h"
#include "qgsnewauxiliarylayerdialog.h"
QgsExpressionContext QgsLabelingGui::createExpressionContext() const
{
@ -44,9 +46,12 @@ QgsExpressionContext QgsLabelingGui::createExpressionContext() const
void QgsLabelingGui::registerDataDefinedButton( QgsPropertyOverrideButton *button, QgsPalLayerSettings::Property key )
{
button->init( key, mDataDefinedProperties, QgsPalLayerSettings::propertyDefinitions(), mLayer );
button->init( key, mDataDefinedProperties, QgsPalLayerSettings::propertyDefinitions(), mLayer, true );
connect( button, &QgsPropertyOverrideButton::changed, this, &QgsLabelingGui::updateProperty );
connect( button, &QgsPropertyOverrideButton::createAuxiliaryField, this, &QgsLabelingGui::createAuxiliaryField );
button->registerExpressionContextGenerator( this );
mButtons[key] = button;
}
void QgsLabelingGui::updateProperty()
@ -610,6 +615,48 @@ void QgsLabelingGui::updateUi()
}
}
void QgsLabelingGui::createAuxiliaryField()
{
// try to create an auxiliary layer if not yet created
if ( !mLayer->auxiliaryLayer() )
{
QgsNewAuxiliaryLayerDialog dlg( mLayer, this );
dlg.exec();
}
// return if still not exists
if ( !mLayer->auxiliaryLayer() )
return;
QgsPropertyOverrideButton *button = qobject_cast<QgsPropertyOverrideButton *>( sender() );
const QgsPalLayerSettings::Property key = static_cast< QgsPalLayerSettings::Property >( button->propertyKey() );
const QgsPropertyDefinition def = QgsPalLayerSettings::propertyDefinitions()[key];
// create property in auxiliary storage if necessary
if ( !mLayer->auxiliaryLayer()->exists( def ) )
mLayer->auxiliaryLayer()->addAuxiliaryField( def );
// update property with join field name from auxiliary storage
QgsProperty property = button->toProperty();
property.setField( QgsAuxiliaryLayer::nameFromProperty( def, true ) );
property.setActive( true );
button->updateFieldLists();
button->setToProperty( property );
mDataDefinedProperties.setProperty( key, button->toProperty() );
emit auxiliaryFieldCreated();
}
void QgsLabelingGui::deactivateField( QgsPalLayerSettings::Property key )
{
if ( mButtons.contains( key ) )
{
QgsPropertyOverrideButton *button = mButtons[ key ];
QgsProperty p = button->toProperty();
p.setField( QString() );
p.setActive( false );
button->updateFieldLists();
button->setToProperty( p );
mDataDefinedProperties.setProperty( key, p );
}
}

View File

@ -43,10 +43,26 @@ class APP_EXPORT QgsLabelingGui : public QgsTextFormatWidget, private QgsExpress
void setLayer( QgsMapLayer *layer );
/**
* Deactivate a field from data defined properties and update the
* corresponding button.
*
* \param key The property key to deactivate
*
* \since QGIS 3.0
*/
void deactivateField( QgsPalLayerSettings::Property key );
signals:
void auxiliaryFieldCreated();
public slots:
void updateUi();
void createAuxiliaryField();
protected:
void blockInitSignals( bool block );
void syncDefinedCheckboxFrame( QgsPropertyOverrideButton *ddBtn, QCheckBox *chkBx, QFrame *f );
@ -62,6 +78,8 @@ class APP_EXPORT QgsLabelingGui : public QgsTextFormatWidget, private QgsExpress
void populateDataDefinedButtons();
void registerDataDefinedButton( QgsPropertyOverrideButton *button, QgsPalLayerSettings::Property key );
QMap<QgsPalLayerSettings::Property, QgsPropertyOverrideButton *> mButtons;
private slots:
void updateProperty();

View File

@ -40,6 +40,11 @@ QgsLabelingWidget::QgsLabelingWidget( QgsVectorLayer *layer, QgsMapCanvas *canva
setLayer( layer );
}
QgsLabelingGui *QgsLabelingWidget::labelingGui()
{
return qobject_cast<QgsLabelingGui *>( mWidget );
}
void QgsLabelingWidget::resetSettings()
{
if ( mOldSettings )
@ -96,6 +101,12 @@ void QgsLabelingWidget::adaptToLayer()
{
mLabelModeComboBox->setCurrentIndex( 0 );
}
QgsLabelingGui *lg = qobject_cast<QgsLabelingGui *>( mWidget );
if ( lg )
{
lg->updateUi();
}
}
void QgsLabelingWidget::writeSettingsToLayer()
@ -156,6 +167,7 @@ void QgsLabelingWidget::labelModeChanged( int index )
QgsLabelingGui *simpleWidget = new QgsLabelingGui( mLayer, mCanvas, *mSimpleSettings, this );
simpleWidget->setDockMode( dockMode() );
connect( simpleWidget, &QgsTextFormatWidget::widgetChanged, this, &QgsLabelingWidget::widgetChanged );
connect( simpleWidget, &QgsLabelingGui::auxiliaryFieldCreated, this, &QgsLabelingWidget::auxiliaryFieldCreated );
if ( index == 3 )
simpleWidget->setLabelMode( QgsLabelingGui::ObstaclesOnly );

View File

@ -38,6 +38,13 @@ class QgsLabelingWidget : public QgsMapLayerConfigWidget, private Ui::QgsLabelin
public:
QgsLabelingWidget( QgsVectorLayer *layer, QgsMapCanvas *canvas, QWidget *parent = nullptr );
/**
* Returns the labeling gui widget or a nullptr if none.
*
* \since QGIS 3.0
*/
QgsLabelingGui *labelingGui();
public slots:
void setLayer( QgsMapLayer *layer );
//! save config to layer
@ -51,6 +58,10 @@ class QgsLabelingWidget : public QgsMapLayerConfigWidget, private Ui::QgsLabelin
void resetSettings();
signals:
void auxiliaryFieldCreated();
protected slots:
void labelModeChanged( int index );
void showEngineConfigDialog();

View File

@ -131,6 +131,12 @@ void QgsLabelPropertyDialog::init( const QString &layerId, const QString &provid
if ( mCurLabelField >= 0 )
{
mLabelTextLineEdit->setText( attributeValues.at( mCurLabelField ).toString() );
if ( vlayer->isEditable() )
mLabelTextLineEdit->setEnabled( true );
else
mLabelTextLineEdit->setEnabled( false );
const QgsFields &layerFields = vlayer->fields();
switch ( layerFields.at( mCurLabelField ).type() )
{

View File

@ -23,6 +23,27 @@
QgsMapToolChangeLabelProperties::QgsMapToolChangeLabelProperties( QgsMapCanvas *canvas ): QgsMapToolLabel( canvas )
{
mPalProperties << QgsPalLayerSettings::PositionX;
mPalProperties << QgsPalLayerSettings::PositionY;
mPalProperties << QgsPalLayerSettings::Show;
mPalProperties << QgsPalLayerSettings::LabelRotation;
mPalProperties << QgsPalLayerSettings::Family;
mPalProperties << QgsPalLayerSettings::FontStyle;
mPalProperties << QgsPalLayerSettings::Size;
mPalProperties << QgsPalLayerSettings::Bold;
mPalProperties << QgsPalLayerSettings::Italic;
mPalProperties << QgsPalLayerSettings::Underline;
mPalProperties << QgsPalLayerSettings::Color;
mPalProperties << QgsPalLayerSettings::Strikeout;
mPalProperties << QgsPalLayerSettings::BufferSize;
mPalProperties << QgsPalLayerSettings::BufferColor;
mPalProperties << QgsPalLayerSettings::LabelDistance;
mPalProperties << QgsPalLayerSettings::Hali;
mPalProperties << QgsPalLayerSettings::Vali;
mPalProperties << QgsPalLayerSettings::ScaleVisibility;
mPalProperties << QgsPalLayerSettings::MinScale;
mPalProperties << QgsPalLayerSettings::MaxScale;
mPalProperties << QgsPalLayerSettings::AlwaysShow;
}
void QgsMapToolChangeLabelProperties::canvasPressEvent( QgsMapMouseEvent *e )
@ -37,12 +58,25 @@ void QgsMapToolChangeLabelProperties::canvasPressEvent( QgsMapMouseEvent *e )
}
mCurrentLabel = LabelDetails( labelPos );
if ( !mCurrentLabel.valid || !mCurrentLabel.layer || !mCurrentLabel.layer->isEditable() )
if ( !mCurrentLabel.valid || !mCurrentLabel.layer )
{
return;
}
createRubberBands();
if ( !mCurrentLabel.layer->isEditable() )
{
QgsPalIndexes indexes;
bool newAuxiliaryLayer = createAuxiliaryFields( indexes );
// in case of a new auxiliary layer, a dialog window is displayed and the
// canvas release event is lost.
if ( newAuxiliaryLayer )
{
canvasReleaseEvent( e );
}
}
}
void QgsMapToolChangeLabelProperties::canvasReleaseEvent( QgsMapMouseEvent *e )

View File

@ -25,6 +25,9 @@
#include "qgsvectorlayerlabeling.h"
#include "qgsdiagramrenderer.h"
#include "qgssettings.h"
#include "qgsvectorlayerjoininfo.h"
#include "qgsvectorlayerjoinbuffer.h"
#include "qgsauxiliarystorage.h"
#include <QMouseEvent>
@ -688,14 +691,14 @@ QgsMapToolLabel::LabelDetails::LabelDetails( const QgsLabelPosition &p )
: pos( p )
{
layer = qobject_cast<QgsVectorLayer *>( QgsProject::instance()->mapLayer( pos.layerID ) );
if ( layer && layer->labeling() )
if ( layer && layer->labeling() && !p.isDiagram )
{
settings = layer->labeling()->settings( pos.providerID );
if ( p.isDiagram )
valid = layer->diagramsEnabled();
else
valid = true;
valid = true;
}
else if ( layer && layer->diagramsEnabled() && p.isDiagram )
{
valid = true;
}
if ( !valid )
@ -704,3 +707,95 @@ QgsMapToolLabel::LabelDetails::LabelDetails( const QgsLabelPosition &p )
settings = QgsPalLayerSettings();
}
}
bool QgsMapToolLabel::createAuxiliaryFields( QgsPalIndexes &indexes )
{
return createAuxiliaryFields( mCurrentLabel, indexes );
}
bool QgsMapToolLabel::createAuxiliaryFields( LabelDetails &details, QgsPalIndexes &indexes ) const
{
bool newAuxiliaryLayer = false;
QgsVectorLayer *vlayer = details.layer;
QString providerId = details.pos.providerID;
if ( !vlayer || !vlayer->labeling() )
return newAuxiliaryLayer;
if ( !vlayer->auxiliaryLayer() )
{
QgsNewAuxiliaryLayerDialog dlg( vlayer );
dlg.exec();
newAuxiliaryLayer = true;
}
if ( !vlayer->auxiliaryLayer() )
return false;
for ( const QgsPalLayerSettings::Property &p : qgsAsConst( mPalProperties ) )
{
int index = -1;
// always use the default activated property
QgsProperty prop = details.settings.dataDefinedProperties().property( p );
if ( prop.propertyType() == QgsProperty::FieldBasedProperty && prop.isActive() )
{
index = vlayer->fields().lookupField( prop.field() );
}
else
{
index = QgsAuxiliaryLayer::createProperty( p, vlayer );
}
indexes[p] = index;
}
details.settings = vlayer->labeling()->settings( providerId );
return newAuxiliaryLayer;
}
bool QgsMapToolLabel::createAuxiliaryFields( QgsDiagramIndexes &indexes )
{
return createAuxiliaryFields( mCurrentLabel, indexes );
}
bool QgsMapToolLabel::createAuxiliaryFields( LabelDetails &details, QgsDiagramIndexes &indexes )
{
bool newAuxiliaryLayer = false;
QgsVectorLayer *vlayer = details.layer;
if ( !vlayer )
return newAuxiliaryLayer;
if ( !vlayer->auxiliaryLayer() )
{
QgsNewAuxiliaryLayerDialog dlg( vlayer );
dlg.exec();
newAuxiliaryLayer = true;
}
if ( !vlayer->auxiliaryLayer() )
return false;
for ( const QgsDiagramLayerSettings::Property &p : qgsAsConst( mDiagramProperties ) )
{
int index = -1;
// always use the default activated property
QgsProperty prop = vlayer->diagramLayerSettings()->dataDefinedProperties().property( p );
if ( prop.propertyType() == QgsProperty::FieldBasedProperty && prop.isActive() )
{
index = vlayer->fields().lookupField( prop.field() );
}
else
{
index = QgsAuxiliaryLayer::createProperty( p, vlayer );
}
indexes[p] = index;
}
return newAuxiliaryLayer;
}

View File

@ -20,10 +20,15 @@
#include "qgsmaptool.h"
#include "qgspallabeling.h"
#include "qgsnewauxiliarylayerdialog.h"
#include "qgsauxiliarystorage.h"
#include "qgis_app.h"
class QgsRubberBand;
typedef QMap<QgsPalLayerSettings::Property, int> QgsPalIndexes;
typedef QMap<QgsDiagramLayerSettings::Property, int> QgsDiagramIndexes;
//! Base class for map tools that modify label properties
class APP_EXPORT QgsMapToolLabel: public QgsMapTool
{
@ -175,6 +180,14 @@ class APP_EXPORT QgsMapToolLabel: public QgsMapTool
\since QGIS 2.16
*/
bool isPinned();
bool createAuxiliaryFields( QgsPalIndexes &palIndexes );
bool createAuxiliaryFields( LabelDetails &details, QgsPalIndexes &palIndexes ) const;
bool createAuxiliaryFields( QgsDiagramIndexes &diagIndexes );
bool createAuxiliaryFields( LabelDetails &details, QgsDiagramIndexes &diagIndexes );
QList<QgsPalLayerSettings::Property> mPalProperties;
QList<QgsDiagramLayerSettings::Property> mDiagramProperties;
};
#endif // QGSMAPTOOLLABEL_H

View File

@ -27,6 +27,12 @@ QgsMapToolMoveLabel::QgsMapToolMoveLabel( QgsMapCanvas *canvas )
, mClickOffsetY( 0 )
{
mToolName = tr( "Move label" );
mPalProperties << QgsPalLayerSettings::PositionX;
mPalProperties << QgsPalLayerSettings::PositionY;
mDiagramProperties << QgsDiagramLayerSettings::PositionX;
mDiagramProperties << QgsDiagramLayerSettings::PositionY;
}
void QgsMapToolMoveLabel::canvasPressEvent( QgsMapMouseEvent *e )
@ -43,14 +49,35 @@ void QgsMapToolMoveLabel::canvasPressEvent( QgsMapMouseEvent *e )
mCurrentLabel = LabelDetails( labelPos );
QgsVectorLayer *vlayer = mCurrentLabel.layer;
if ( !vlayer || !vlayer->isEditable() )
if ( !vlayer )
{
return;
}
int xCol, yCol;
if ( labelMoveable( vlayer, mCurrentLabel.settings, xCol, yCol ) ||
diagramMoveable( vlayer, xCol, yCol ) )
if ( !mCurrentLabel.pos.isDiagram && !labelMoveable( vlayer, mCurrentLabel.settings, xCol, yCol ) )
{
QgsPalIndexes indexes;
if ( createAuxiliaryFields( indexes ) )
return;
xCol = indexes[ QgsPalLayerSettings::PositionX ];
yCol = indexes[ QgsPalLayerSettings::PositionY ];
}
else if ( mCurrentLabel.pos.isDiagram && !diagramMoveable( vlayer, xCol, yCol ) )
{
QgsDiagramIndexes indexes;
if ( createAuxiliaryFields( indexes ) )
return;
xCol = indexes[ QgsDiagramLayerSettings::PositionX ];
yCol = indexes[ QgsDiagramLayerSettings::PositionY ];
}
if ( xCol >= 0 && yCol >= 0 )
{
mStartPointMapCoords = toMapCoordinates( e->pos() );
QgsPointXY referencePoint;
@ -91,7 +118,7 @@ void QgsMapToolMoveLabel::canvasReleaseEvent( QgsMapMouseEvent *e )
deleteRubberBands();
QgsVectorLayer *vlayer = mCurrentLabel.layer;
if ( !vlayer || !vlayer->isEditable() )
if ( !vlayer )
{
return;
}

View File

@ -260,13 +260,6 @@ void QgsMapToolPinLabels::pinUnpinLabels( const QgsRectangle &ext, QMouseEvent *
continue;
}
QgsVectorLayer *vlayer = mCurrentLabel.layer;
if ( !vlayer->isEditable() )
{
QgsDebugMsg( QString( "Vector layer not editable, skipping label" ) );
continue;
}
// unpin label
if ( isPinned() && ( doUnpin || toggleUnpinOrPin ) )
{
@ -297,7 +290,7 @@ void QgsMapToolPinLabels::pinUnpinLabels( const QgsRectangle &ext, QMouseEvent *
if ( labelChanged )
{
mCanvas->refresh();
mCurrentLabel.layer->triggerRepaint();
if ( !mShowPinned )
{

View File

@ -33,6 +33,7 @@ QgsMapToolRotateLabel::QgsMapToolRotateLabel( QgsMapCanvas *canvas )
, mCurrentMouseAzimuth( 0.0 )
, mCtrlPressed( false )
{
mPalProperties << QgsPalLayerSettings::LabelRotation;
}
QgsMapToolRotateLabel::~QgsMapToolRotateLabel()
@ -76,6 +77,14 @@ void QgsMapToolRotateLabel::canvasPressEvent( QgsMapMouseEvent *e )
bool hasRotationValue;
int rotationCol;
if ( !labelIsRotatable( mCurrentLabel.layer, mCurrentLabel.settings, rotationCol ) )
{
QgsPalIndexes indexes;
if ( createAuxiliaryFields( indexes ) )
return;
}
if ( currentLabelDataDefinedRotation( mCurrentRotation, hasRotationValue, rotationCol, true ) )
{
if ( !hasRotationValue )

View File

@ -35,6 +35,9 @@ QgsMapToolShowHideLabels::QgsMapToolShowHideLabels( QgsMapCanvas *canvas )
{
mToolName = tr( "Show/hide labels" );
mRubberBand = nullptr;
mPalProperties << QgsPalLayerSettings::Show;
mDiagramProperties << QgsDiagramLayerSettings::Show;
}
QgsMapToolShowHideLabels::~QgsMapToolShowHideLabels()
@ -45,6 +48,24 @@ QgsMapToolShowHideLabels::~QgsMapToolShowHideLabels()
void QgsMapToolShowHideLabels::canvasPressEvent( QgsMapMouseEvent *e )
{
Q_UNUSED( e );
QgsMapLayer *layer = mCanvas->currentLayer();
QgsVectorLayer *vlayer = dynamic_cast<QgsVectorLayer *>( layer );
if ( !vlayer )
return;
int showCol;
if ( !labelCanShowHide( vlayer, showCol )
|| !diagramCanShowHide( vlayer, showCol ) )
{
if ( !vlayer->auxiliaryLayer() )
{
QgsNewAuxiliaryLayerDialog dlg( vlayer );
dlg.exec();
return;
}
}
mSelectRect.setRect( 0, 0, 0, 0 );
mSelectRect.setTopLeft( e->pos() );
mSelectRect.setBottomRight( e->pos() );
@ -107,72 +128,46 @@ void QgsMapToolShowHideLabels::canvasReleaseEvent( QgsMapMouseEvent *e )
void QgsMapToolShowHideLabels::showHideLabels( QMouseEvent *e )
{
QgsMapLayer *layer = mCanvas->currentLayer();
QgsVectorLayer *vlayer = dynamic_cast<QgsVectorLayer *>( layer );
if ( !vlayer )
{
QgsDebugMsg( "Failed to cast label layer to vector layer" );
return;
}
if ( !vlayer->isEditable() )
{
QgsDebugMsg( "Vector layer not editable, skipping label" );
return;
}
bool doHide = e->modifiers() & Qt::ShiftModifier;
bool labelChanged = false;
QString editTxt = doHide ? tr( "Hid labels" ) : tr( "Showed labels" );
vlayer->beginEditCommand( editTxt );
if ( !doHide )
bool labelChanged = false;
if ( doHide )
{
QgsDebugMsg( "Showing labels operation" );
QgsFeatureIds selectedFeatIds;
if ( !selectedFeatures( vlayer, selectedFeatIds ) )
QList<QgsLabelPosition> positions;
if ( selectedLabelFeatures( vlayer, positions ) )
{
vlayer->destroyEditCommand();
return;
}
QgsDebugMsg( "Number of selected labels or features: " + QString::number( selectedFeatIds.size() ) );
if ( selectedFeatIds.isEmpty() )
{
vlayer->destroyEditCommand();
return;
}
Q_FOREACH ( QgsFeatureId fid, selectedFeatIds )
{
mCurrentLabel.pos.featureId = fid;
mCurrentLabel.pos.isDiagram = false;
bool labChanged = showHide( vlayer, true );
mCurrentLabel.pos.isDiagram = true;
bool diagChanged = showHide( vlayer, true );
if ( labChanged || diagChanged )
for ( const QgsLabelPosition &pos : qgsAsConst( positions ) )
{
// TODO: highlight features (maybe with QTimer?)
labelChanged = true;
if ( showHide( pos, false ) )
labelChanged = true;
}
}
}
else
{
QgsDebugMsg( "Hiding labels operation" );
QList<QgsLabelPosition> positions;
if ( selectedLabelFeatures( vlayer, positions ) )
QgsFeatureIds fids;
if ( selectedFeatures( vlayer, fids ) )
{
Q_FOREACH ( const QgsLabelPosition &pos, positions )
for ( const QgsFeatureId &fid : qgsAsConst( fids ) )
{
mCurrentLabel.pos = pos;
QgsLabelPosition pos;
pos.featureId = fid;
pos.layerID = vlayer->id();
if ( showHide( vlayer, false ) )
// we want to show labels...
pos.isDiagram = false;
if ( showHide( pos, true ) )
labelChanged = true;
// ... and diagrams
pos.isDiagram = true;
if ( showHide( pos, true ) )
labelChanged = true;
}
}
@ -274,42 +269,45 @@ bool QgsMapToolShowHideLabels::selectedLabelFeatures( QgsVectorLayer *vlayer,
return true;
}
bool QgsMapToolShowHideLabels::showHide( QgsVectorLayer *vl, const bool show )
bool QgsMapToolShowHideLabels::showHide( const QgsLabelPosition &pos, bool show )
{
// verify attribute table has proper field setup
bool showSuccess;
int showCol;
int showVal;
LabelDetails details = LabelDetails( pos );
if ( !dataDefinedShowHide( vl, mCurrentLabel.pos.featureId, showVal,
showSuccess, showCol ) )
{
if ( !details.valid )
return false;
QgsVectorLayer *vlayer = details.layer;
if ( !vlayer )
return false;
int showCol = -1;
if ( pos.isDiagram )
{
if ( !diagramCanShowHide( vlayer, showCol ) )
{
QgsDiagramIndexes indexes;
createAuxiliaryFields( details, indexes );
showCol = indexes[ QgsDiagramLayerSettings::Show ];
}
}
else
{
if ( !labelCanShowHide( vlayer, showCol ) )
{
QgsPalIndexes indexes;
createAuxiliaryFields( details, indexes );
showCol = indexes[ QgsPalLayerSettings::Show ];
}
}
// we need to pass int value to the provider
// (committing bool value would fail on int field)
int curVal = show ? 1 : 0;
// check if attribute value is already the same
if ( showSuccess && showVal == curVal )
if ( showCol >= 0 )
{
return false;
int showVal = show ? 1 : 0;
vlayer->changeAttributeValue( pos.featureId, showCol, showVal );
return true;
}
// allow NULL (maybe default) value to stand for show label (i.e. 1)
// skip NULL attributes if trying to show label
if ( !showSuccess && curVal == 1 )
{
return false;
}
// different attribute value, edit table
if ( ! vl->changeAttributeValue( mCurrentLabel.pos.featureId, showCol, curVal ) )
{
QgsDebugMsg( "Failed write to attribute table" );
return false;
}
return true;
return false;
}

View File

@ -64,8 +64,7 @@ class APP_EXPORT QgsMapToolShowHideLabels : public QgsMapToolLabel
bool selectedLabelFeatures( QgsVectorLayer *vlayer,
QList<QgsLabelPosition> &listPos );
//! Show label or diagram with feature ID
bool showHide( QgsVectorLayer *vl, const bool show );
bool showHide( const QgsLabelPosition &pos, bool show );
};
#endif // QGSMAPTOOLSHOWHIDELABELS_H

View File

@ -55,6 +55,11 @@
#include "qgssettings.h"
#include "qgsrendererpropertiesdialog.h"
#include "qgsstyle.h"
#include "qgsauxiliarystorage.h"
#include "qgsnewauxiliarylayerdialog.h"
#include "qgsnewauxiliaryfielddialog.h"
#include "qgslabelinggui.h"
#include "qgssymbollayer.h"
#include "layertree/qgslayertreelayer.h"
#include "qgslayertree.h"
@ -144,6 +149,7 @@ QgsVectorLayerProperties::QgsVectorLayerProperties(
layout->setMargin( 0 );
labelingDialog = new QgsLabelingWidget( mLayer, QgisApp::instance()->mapCanvas(), labelingFrame );
labelingDialog->layout()->setContentsMargins( -1, 0, -1, 0 );
connect( labelingDialog, &QgsLabelingWidget::auxiliaryFieldCreated, this, [ = ] { updateAuxiliaryStoragePage(); } );
layout->addWidget( labelingDialog );
labelingFrame->setLayout( layout );
}
@ -253,6 +259,7 @@ QgsVectorLayerProperties::QgsVectorLayerProperties(
diagLayout->setMargin( 0 );
diagramPropertiesDialog = new QgsDiagramProperties( mLayer, mDiagramFrame, QgisApp::instance()->mapCanvas() );
diagramPropertiesDialog->layout()->setContentsMargins( -1, 0, -1, 0 );
connect( diagramPropertiesDialog, &QgsDiagramProperties::auxiliaryFieldCreated, this, [ = ] { updateAuxiliaryStoragePage(); } );
diagLayout->addWidget( diagramPropertiesDialog );
mDiagramFrame->setLayout( diagLayout );
@ -349,6 +356,31 @@ QgsVectorLayerProperties::QgsVectorLayerProperties(
connect( mRefreshLayerCheckBox, &QCheckBox::toggled, mRefreshLayerIntervalSpinBox, &QDoubleSpinBox::setEnabled );
// auxiliary layer
QMenu *menu = new QMenu( this );
mAuxiliaryLayerActionNew = new QAction( tr( "Create" ), this );
menu->addAction( mAuxiliaryLayerActionNew );
connect( mAuxiliaryLayerActionNew, &QAction::triggered, this, &QgsVectorLayerProperties::onAuxiliaryLayerNew );
mAuxiliaryLayerActionClear = new QAction( tr( "Clear" ), this );
menu->addAction( mAuxiliaryLayerActionClear );
connect( mAuxiliaryLayerActionClear, &QAction::triggered, this, &QgsVectorLayerProperties::onAuxiliaryLayerClear );
mAuxiliaryLayerActionDelete = new QAction( tr( "Delete" ), this );
menu->addAction( mAuxiliaryLayerActionDelete );
connect( mAuxiliaryLayerActionDelete, &QAction::triggered, this, &QgsVectorLayerProperties::onAuxiliaryLayerDelete );
mAuxiliaryLayerActionExport = new QAction( tr( "Export" ), this );
menu->addAction( mAuxiliaryLayerActionExport );
connect( mAuxiliaryLayerActionExport, &QAction::triggered, this, &QgsVectorLayerProperties::onAuxiliaryLayerExport );
mAuxiliaryStorageActions->setMenu( menu );
connect( mAuxiliaryStorageFieldsDeleteBtn, &QPushButton::clicked, this, &QgsVectorLayerProperties::onAuxiliaryLayerDeleteField );
connect( mAuxiliaryStorageFieldsAddBtn, &QPushButton::clicked, this, &QgsVectorLayerProperties::onAuxiliaryLayerAddField );
updateAuxiliaryStoragePage();
}
void QgsVectorLayerProperties::toggleEditing()
@ -1245,6 +1277,11 @@ void QgsVectorLayerProperties::addJoinToTreeWidget( const QgsVectorLayerJoinInfo
}
joinItem->setText( 0, QStringLiteral( "Join layer" ) );
if ( mLayer->auxiliaryLayer() && mLayer->auxiliaryLayer()->id() == join.joinLayerId() )
{
return;
}
joinItem->setText( 1, joinLayer->name() );
QFont f = joinItem->font( 0 );
@ -1369,6 +1406,7 @@ void QgsVectorLayerProperties::updateSymbologyPage()
mRendererDialog->setMapCanvas( QgisApp::instance()->mapCanvas() );
connect( mRendererDialog, &QgsRendererPropertiesDialog::showPanel, this, &QgsVectorLayerProperties::openPanel );
connect( mRendererDialog, &QgsRendererPropertiesDialog::layerVariablesChanged, this, &QgsVectorLayerProperties::updateVariableEditor );
connect( mRendererDialog, &QgsRendererPropertiesDialog::widgetChanged, this, [ = ] { updateAuxiliaryStoragePage(); } );
// display the menu to choose the output format (fix #5136)
mActionSaveStyleAs->setText( tr( "Save Style" ) );
@ -1453,3 +1491,225 @@ void QgsVectorLayerProperties::showHelp()
{
QgsHelp::openHelp( QStringLiteral( "working_with_vector/vector_properties.html" ) );
}
void QgsVectorLayerProperties::updateAuxiliaryStoragePage( bool reset )
{
const QgsAuxiliaryLayer *alayer = mLayer->auxiliaryLayer();
if ( alayer )
{
// set widgets to enable state
mAuxiliaryStorageInformationGrpBox->setEnabled( true );
mAuxiliaryStorageFieldsGrpBox->setEnabled( true );
// update key
mAuxiliaryStorageKeyLineEdit->setText( alayer->joinInfo().targetFieldName() );
// update feature count
int features = alayer->featureCount();
mAuxiliaryStorageFeaturesLineEdit->setText( QString::number( features ) );
// update actions
mAuxiliaryLayerActionClear->setEnabled( true );
mAuxiliaryLayerActionDelete->setEnabled( true );
mAuxiliaryLayerActionExport->setEnabled( true );
mAuxiliaryLayerActionNew->setEnabled( false );
const QgsAuxiliaryLayer *alayer = mLayer->auxiliaryLayer();
if ( alayer )
{
const int fields = alayer->auxiliaryFields().count();
mAuxiliaryStorageFieldsLineEdit->setText( QString::number( fields ) );
// add fields
mAuxiliaryStorageFieldsTree->clear();
for ( const QgsField &field : alayer->auxiliaryFields() )
{
const QgsPropertyDefinition prop = QgsAuxiliaryLayer::propertyDefinitionFromField( field );
QTreeWidgetItem *item = new QTreeWidgetItem();
item->setText( 0, prop.origin() );
item->setText( 1, prop.name() );
item->setText( 2, prop.comment() );
item->setText( 3, field.typeName() );
item->setText( 4, field.name() );
mAuxiliaryStorageFieldsTree->addTopLevelItem( item );
}
}
}
else
{
mAuxiliaryStorageInformationGrpBox->setEnabled( false );
mAuxiliaryStorageFieldsGrpBox->setEnabled( false );
mAuxiliaryLayerActionClear->setEnabled( false );
mAuxiliaryLayerActionDelete->setEnabled( false );
mAuxiliaryLayerActionExport->setEnabled( false );
mAuxiliaryLayerActionNew->setEnabled( true );
mAuxiliaryStorageFieldsTree->clear();
mAuxiliaryStorageKeyLineEdit->setText( QString() );
mAuxiliaryStorageFieldsLineEdit->setText( QString() );
mAuxiliaryStorageFeaturesLineEdit->setText( QString() );
}
if ( reset && labelingDialog )
{
labelingDialog->setLayer( mLayer );
}
}
void QgsVectorLayerProperties::onAuxiliaryLayerNew()
{
QgsAuxiliaryLayer *alayer = mLayer->auxiliaryLayer();
if ( alayer )
return;
QgsNewAuxiliaryLayerDialog dlg( mLayer, this );
if ( dlg.exec() == QDialog::Accepted )
{
updateAuxiliaryStoragePage( true );
}
}
void QgsVectorLayerProperties::onAuxiliaryLayerClear()
{
QgsAuxiliaryLayer *alayer = mLayer->auxiliaryLayer();
if ( !alayer )
return;
const QString msg = tr( "Are you sure you want to clear auxiliary data for %1" ).arg( mLayer->name() );
QMessageBox::StandardButton reply;
reply = QMessageBox::question( this, "Clear auxiliary data", msg, QMessageBox::Yes | QMessageBox::No );
if ( reply == QMessageBox::Yes )
{
QApplication::setOverrideCursor( Qt::WaitCursor );
alayer->clear();
QApplication::restoreOverrideCursor();
updateAuxiliaryStoragePage( true );
mLayer->triggerRepaint();
}
}
void QgsVectorLayerProperties::onAuxiliaryLayerDelete()
{
QgsAuxiliaryLayer *alayer = mLayer->auxiliaryLayer();
if ( !alayer )
return;
const QString msg = tr( "Are you sure you want to delete auxiliary storage for %1" ).arg( mLayer->name() );
QMessageBox::StandardButton reply;
reply = QMessageBox::question( this, "Delete auxiliary storage", msg, QMessageBox::Yes | QMessageBox::No );
if ( reply == QMessageBox::Yes )
{
QApplication::setOverrideCursor( Qt::WaitCursor );
QgsDataSourceUri uri( alayer->source() );
// delete each attribute to correctly update layer settings and data
// defined buttons
while ( alayer->auxiliaryFields().size() > 0 )
{
QgsField aField = alayer->auxiliaryFields()[0];
deleteAuxiliaryField( alayer->fields().indexOf( aField.name() ) );
}
mLayer->setAuxiliaryLayer(); // remove auxiliary layer
QgsAuxiliaryStorage::deleteTable( uri );
QApplication::restoreOverrideCursor();
updateAuxiliaryStoragePage( true );
mLayer->triggerRepaint();
}
}
void QgsVectorLayerProperties::onAuxiliaryLayerExport()
{
const QgsAuxiliaryLayer *alayer = mLayer->auxiliaryLayer();
if ( !alayer )
return;
std::unique_ptr<QgsVectorLayer> clone;
clone.reset( alayer->toSpatialLayer() );
QgisApp::instance()->saveAsFile( clone.get() );
}
void QgsVectorLayerProperties::onAuxiliaryLayerDeleteField()
{
QgsAuxiliaryLayer *alayer = mLayer->auxiliaryLayer();
if ( !alayer )
return;
QList<QTreeWidgetItem *> items = mAuxiliaryStorageFieldsTree->selectedItems();
if ( items.count() < 1 )
return;
// get auxiliary field name and index from item
const QTreeWidgetItem *item = items[0];
QgsPropertyDefinition def;
def.setOrigin( item->text( 0 ) );
def.setName( item->text( 1 ) );
def.setComment( item->text( 2 ) );
const QString fieldName = QgsAuxiliaryLayer::nameFromProperty( def );
const int index = mLayer->auxiliaryLayer()->fields().indexOf( fieldName );
if ( index < 0 )
return;
// should be only 1 field
const QString msg = tr( "Are you sure you want to delete auxiliary field %1 for %2" ).arg( item->text( 1 ), item->text( 0 ) );
QMessageBox::StandardButton reply;
reply = QMessageBox::question( this, "Delete auxiliary field", msg, QMessageBox::Yes | QMessageBox::No );
if ( reply == QMessageBox::Yes )
{
QApplication::setOverrideCursor( Qt::WaitCursor );
deleteAuxiliaryField( index );
mLayer->triggerRepaint();
QApplication::restoreOverrideCursor();
}
}
void QgsVectorLayerProperties::onAuxiliaryLayerAddField()
{
QgsAuxiliaryLayer *alayer = mLayer->auxiliaryLayer();
if ( !alayer )
return;
QgsNewAuxiliaryFieldDialog dlg( QgsPropertyDefinition(), mLayer, false );
if ( dlg.exec() == QDialog::Accepted )
{
updateAuxiliaryStoragePage();
}
}
void QgsVectorLayerProperties::deleteAuxiliaryField( int index )
{
if ( !mLayer->auxiliaryLayer() )
return;
int key = mLayer->auxiliaryLayer()->propertyFromIndex( index );
QgsPropertyDefinition def = mLayer->auxiliaryLayer()->propertyDefinitionFromIndex( index );
if ( mLayer->auxiliaryLayer()->deleteAttribute( index ) )
{
mLayer->updateFields();
// immediately deactivate data defined button
if ( key >= 0 && def.origin().compare( "labeling", Qt::CaseInsensitive ) == 0
&& labelingDialog
&& labelingDialog->labelingGui() )
{
labelingDialog->labelingGui()->deactivateField( ( QgsPalLayerSettings::Property ) key );
}
updateAuxiliaryStoragePage( true );
mFieldsPropertiesDialog->init();
}
}

View File

@ -156,6 +156,18 @@ class APP_EXPORT QgsVectorLayerProperties : public QgsOptionsDialogBase, private
*/
void updateFieldsPropertiesDialog();
void onAuxiliaryLayerNew();
void onAuxiliaryLayerClear();
void onAuxiliaryLayerDelete();
void onAuxiliaryLayerDeleteField();
void onAuxiliaryLayerAddField();
void onAuxiliaryLayerExport();
private:
void saveStyleAs( StyleType styleType );
@ -206,6 +218,9 @@ class APP_EXPORT QgsVectorLayerProperties : public QgsOptionsDialogBase, private
//! Adds a new join to mJoinTreeWidget
void addJoinToTreeWidget( const QgsVectorLayerJoinInfo &join, const int insertIndex = -1 );
void updateAuxiliaryStoragePage( bool reset = false );
void deleteAuxiliaryField( int index );
QgsExpressionContext mContext;
QgsExpressionContext createExpressionContext() const override;
@ -217,6 +232,13 @@ class APP_EXPORT QgsVectorLayerProperties : public QgsOptionsDialogBase, private
QgsMetadataWidget *mMetadataWidget = nullptr;
QAction *mAuxiliaryLayerActionNew = nullptr;
QAction *mAuxiliaryLayerActionClear = nullptr;
QAction *mAuxiliaryLayerActionDelete = nullptr;
QAction *mAuxiliaryLayerActionExport = nullptr;
QAction *mAuxiliaryLayerActionDeleteField = nullptr;
QAction *mAuxiliaryLayerActionAddField = nullptr;
private slots:
void openPanel( QgsPanelWidget *panel );
};

View File

@ -134,6 +134,7 @@ SET(QGIS_CORE_SRCS
qgsattributes.cpp
qgsattributetableconfig.cpp
qgsattributeeditorelement.cpp
qgsauxiliarystorage.cpp
qgsbearingutils.cpp
qgsbrowsermodel.cpp
qgscachedfeatureiterator.cpp
@ -572,6 +573,7 @@ SET(QGIS_CORE_MOC_HDRS
qgsactionmanager.h
qgsactionscoperegistry.h
qgsanimatedicon.h
qgsauxiliarystorage.h
qgsbrowsermodel.h
qgscoordinatereferencesystem.h
qgscredentials.h

View File

@ -19,6 +19,7 @@
#include "qgsarchive.h"
#include "qgsziputils.h"
#include "qgsmessagelog.h"
#include "qgsauxiliarystorage.h"
#include <iostream>
QgsArchive::QgsArchive()
@ -136,3 +137,17 @@ bool QgsProjectArchive::clearProjectFile()
{
return removeFile( projectFile() );
}
QString QgsProjectArchive::auxiliaryStorageFile() const
{
const QString extension = QgsAuxiliaryStorage::extension();
for ( const QString &file : files() )
{
const QFileInfo fileInfo( file );
if ( fileInfo.suffix().compare( extension, Qt::CaseInsensitive ) == 0 )
return file;
}
return QString();
}

View File

@ -134,6 +134,12 @@ class CORE_EXPORT QgsProjectArchive : public QgsArchive
* \returns true if the file is well removed, false otherwise
*/
bool clearProjectFile();
/**
* Returns the current .qgd auxiliary storage file or an empty string if
* there's none
*/
QString auxiliaryStorageFile() const;
};
#endif

View File

@ -0,0 +1,829 @@
/***************************************************************************
qgsauxiliarystorage.cpp - description
-------------------
begin : Aug 28, 2017
copyright : (C) 2017 by Paul Blottiere
email : paul.blottiere@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 "qgsauxiliarystorage.h"
#include "qgslogger.h"
#include "qgsslconnect.h"
#include "qgsproject.h"
#include "qgsvectorlayerlabeling.h"
#include "qgsdiagramrenderer.h"
#include "qgsmemoryproviderutils.h"
#include "qgssymbollayer.h"
#include <QFile>
const QString AS_JOINFIELD = "ASPK";
const QString AS_EXTENSION = "qgd";
const QString AS_JOINPREFIX = "auxiliary_storage_";
const QVector<QgsPalLayerSettings::Property> palHiddenProperties
{
QgsPalLayerSettings::PositionX,
QgsPalLayerSettings::PositionY,
QgsPalLayerSettings::Show,
QgsPalLayerSettings::LabelRotation,
QgsPalLayerSettings::Family,
QgsPalLayerSettings::FontStyle,
QgsPalLayerSettings::Size,
QgsPalLayerSettings::Bold,
QgsPalLayerSettings::Italic,
QgsPalLayerSettings::Underline,
QgsPalLayerSettings::Color,
QgsPalLayerSettings::Strikeout,
QgsPalLayerSettings::BufferSize,
QgsPalLayerSettings::BufferColor,
QgsPalLayerSettings::LabelDistance,
QgsPalLayerSettings::Hali,
QgsPalLayerSettings::Vali,
QgsPalLayerSettings::ScaleVisibility,
QgsPalLayerSettings::MinScale,
QgsPalLayerSettings::MaxScale,
QgsPalLayerSettings::AlwaysShow
};
//
// QgsAuxiliaryLayer
//
QgsAuxiliaryLayer::QgsAuxiliaryLayer( const QString &pkField, const QString &filename, const QString &table, QgsVectorLayer *vlayer )
: QgsVectorLayer( QString( "%1|layername=%2" ).arg( filename, table ), QString( "%1_auxiliarystorage" ).arg( table ), "ogr" )
, mFileName( filename )
, mTable( table )
, mLayer( vlayer )
{
// init join info
mJoinInfo.setPrefix( AS_JOINPREFIX );
mJoinInfo.setJoinLayer( this );
mJoinInfo.setJoinFieldName( AS_JOINFIELD );
mJoinInfo.setTargetFieldName( pkField );
mJoinInfo.setEditable( true );
mJoinInfo.setUpsertOnEdit( true );
mJoinInfo.setCascadedDelete( true );
mJoinInfo.setJoinFieldNamesBlackList( QStringList() << QStringLiteral( "rowid" ) ); // introduced by ogr provider
}
QgsAuxiliaryLayer *QgsAuxiliaryLayer::clone( QgsVectorLayer *target ) const
{
QgsAuxiliaryStorage::duplicateTable( source(), target->id() );
return new QgsAuxiliaryLayer( mJoinInfo.targetFieldName(), mFileName, target->id(), target );
}
bool QgsAuxiliaryLayer::clear()
{
bool rc = deleteFeatures( allFeatureIds() );
commitChanges();
startEditing();
return rc;
}
QgsVectorLayer *QgsAuxiliaryLayer::toSpatialLayer() const
{
QgsVectorLayer *layer = QgsMemoryProviderUtils::createMemoryLayer( QStringLiteral( "auxiliary_layer" ), fields(), mLayer->wkbType(), mLayer->crs() );
QString pkField = mJoinInfo.targetFieldName();
QgsFeature joinFeature;
QgsFeature targetFeature;
QgsFeatureIterator it = getFeatures();
layer->startEditing();
while ( it.nextFeature( joinFeature ) )
{
QString filter = QgsExpression::createFieldEqualityExpression( pkField, joinFeature.attribute( AS_JOINFIELD ) );
QgsFeatureRequest request;
request.setFilterExpression( filter );
mLayer->getFeatures( request ).nextFeature( targetFeature );
if ( targetFeature.isValid() )
{
QgsFeature newFeature( joinFeature );
newFeature.setGeometry( targetFeature.geometry() );
layer->addFeature( newFeature );
}
}
layer->commitChanges();
return layer;
}
QgsVectorLayerJoinInfo QgsAuxiliaryLayer::joinInfo() const
{
return mJoinInfo;
}
bool QgsAuxiliaryLayer::exists( const QgsPropertyDefinition &definition ) const
{
return ( indexOfPropertyDefinition( definition ) >= 0 );
}
bool QgsAuxiliaryLayer::addAuxiliaryField( const QgsPropertyDefinition &definition )
{
if ( ( definition.name().isEmpty() && definition.comment().isEmpty() ) || exists( definition ) )
return false;
const QgsField af = createAuxiliaryField( definition );
const bool rc = addAttribute( af );
updateFields();
mLayer->updateFields();
if ( rc )
{
int auxIndex = indexOfPropertyDefinition( definition );
int index = mLayer->fields().indexOf( nameFromProperty( definition, true ) );
if ( index >= 0 && auxIndex >= 0 )
{
if ( isHiddenProperty( auxIndex ) )
{
// update editor widget
QgsEditorWidgetSetup setup = QgsEditorWidgetSetup( QStringLiteral( "Hidden" ), QVariantMap() );
setEditorWidgetSetup( auxIndex, setup );
// column is hidden
QgsAttributeTableConfig attrCfg = mLayer->attributeTableConfig();
attrCfg.update( mLayer->fields() );
QVector<QgsAttributeTableConfig::ColumnConfig> columns = attrCfg.columns();
QVector<QgsAttributeTableConfig::ColumnConfig>::iterator it;
for ( it = columns.begin(); it != columns.end(); ++it )
{
if ( it->name.compare( mLayer->fields().field( index ).name() ) == 0 )
it->hidden = true;
}
attrCfg.setColumns( columns );
mLayer->setAttributeTableConfig( attrCfg );
}
else if ( definition.standardTemplate() == QgsPropertyDefinition::ColorNoAlpha
|| definition.standardTemplate() == QgsPropertyDefinition::ColorWithAlpha )
{
QgsEditorWidgetSetup setup = QgsEditorWidgetSetup( QStringLiteral( "Color" ), QVariantMap() );
setEditorWidgetSetup( auxIndex, setup );
}
mLayer->setEditorWidgetSetup( index, editorWidgetSetup( auxIndex ) );
}
}
return rc;
}
QgsFields QgsAuxiliaryLayer::auxiliaryFields() const
{
QgsFields afields;
for ( int i = 2; i < fields().count(); i++ ) // ignore rowid and PK field
afields.append( createAuxiliaryField( fields().field( i ) ) );
return afields;
}
bool QgsAuxiliaryLayer::deleteAttribute( int attr )
{
QgsVectorLayer::deleteAttribute( attr );
bool rc = commitChanges();
startEditing();
return rc;
}
bool QgsAuxiliaryLayer::save()
{
bool rc = false;
if ( isEditable() )
{
rc = commitChanges();
}
startEditing();
return rc;
}
int QgsAuxiliaryLayer::createProperty( QgsPalLayerSettings::Property property, QgsVectorLayer *layer )
{
int index = -1;
if ( layer && layer->labeling() && layer->auxiliaryLayer() )
{
// property definition are identical whatever the provider id
const QgsPropertyDefinition def = layer->labeling()->settings().propertyDefinitions()[property];
const QString fieldName = nameFromProperty( def, true );
layer->auxiliaryLayer()->addAuxiliaryField( def );
if ( layer->auxiliaryLayer()->indexOfPropertyDefinition( def ) >= 0 )
{
const QgsProperty prop = QgsProperty::fromField( fieldName );
for ( const QString &providerId : layer->labeling()->subProviders() )
{
QgsPalLayerSettings *settings = new QgsPalLayerSettings( layer->labeling()->settings( providerId ) );
QgsPropertyCollection c = settings->dataDefinedProperties();
c.setProperty( property, prop );
settings->setDataDefinedProperties( c );
layer->labeling()->setSettings( settings, providerId );
}
emit layer->styleChanged();
}
index = layer->fields().lookupField( fieldName );
}
return index;
}
int QgsAuxiliaryLayer::createProperty( QgsDiagramLayerSettings::Property property, QgsVectorLayer *layer )
{
int index = -1;
if ( layer && layer->diagramLayerSettings() && layer->auxiliaryLayer() )
{
const QgsPropertyDefinition def = layer->diagramLayerSettings()->propertyDefinitions()[property];
if ( layer->auxiliaryLayer()->addAuxiliaryField( def ) )
{
const QString fieldName = nameFromProperty( def, true );
const QgsProperty prop = QgsProperty::fromField( fieldName );
QgsDiagramLayerSettings settings( *layer->diagramLayerSettings() );
QgsPropertyCollection c = settings.dataDefinedProperties();
c.setProperty( property, prop );
settings.setDataDefinedProperties( c );
layer->setDiagramLayerSettings( settings );
emit layer->styleChanged();
index = layer->fields().lookupField( fieldName );
}
}
return index;
}
bool QgsAuxiliaryLayer::isHiddenProperty( int index ) const
{
bool hidden = false;
QgsPropertyDefinition def = propertyDefinitionFromIndex( index );
if ( def.origin().compare( "labeling" ) == 0 )
{
for ( const QgsPalLayerSettings::Property &p : palHiddenProperties )
{
const QString propName = QgsPalLayerSettings::propertyDefinitions()[ p ].name();
if ( propName.compare( def.name() ) == 0 )
{
hidden = true;
break;
}
}
}
return hidden;
}
int QgsAuxiliaryLayer::propertyFromIndex( int index ) const
{
int p = -1;
QgsPropertyDefinition aDef = propertyDefinitionFromIndex( index );
if ( aDef.origin().compare( QStringLiteral( "labeling" ) ) == 0 )
{
const QgsPropertiesDefinition defs = QgsPalLayerSettings::propertyDefinitions();
QgsPropertiesDefinition::const_iterator it = defs.constBegin();
for ( ; it != defs.constEnd(); ++it )
{
if ( it->name().compare( aDef.name(), Qt::CaseInsensitive ) == 0 )
{
p = it.key();
break;
}
}
}
else if ( aDef.origin().compare( QStringLiteral( "symbol" ) ) == 0 )
{
const QgsPropertiesDefinition defs = QgsSymbolLayer::propertyDefinitions();
QgsPropertiesDefinition::const_iterator it = defs.constBegin();
for ( ; it != defs.constEnd(); ++it )
{
if ( it->name().compare( aDef.name(), Qt::CaseInsensitive ) == 0 )
{
p = it.key();
break;
}
}
}
else if ( aDef.origin().compare( QStringLiteral( "diagram" ) ) == 0 )
{
const QgsPropertiesDefinition defs = QgsDiagramLayerSettings::propertyDefinitions();
QgsPropertiesDefinition::const_iterator it = defs.constBegin();
for ( ; it != defs.constEnd(); ++it )
{
if ( it->name().compare( aDef.name(), Qt::CaseInsensitive ) == 0 )
{
p = it.key();
break;
}
}
}
return p;
}
QgsPropertyDefinition QgsAuxiliaryLayer::propertyDefinitionFromIndex( int index ) const
{
return propertyDefinitionFromField( fields().field( index ) );
}
int QgsAuxiliaryLayer::indexOfPropertyDefinition( const QgsPropertyDefinition &def ) const
{
return fields().indexOf( nameFromProperty( def ) );
}
QString QgsAuxiliaryLayer::nameFromProperty( const QgsPropertyDefinition &def, bool joined )
{
QString fieldName = def.origin();
if ( !def.name().isEmpty() )
fieldName = QString( "%1_%2" ).arg( fieldName, def.name().toLower() );
if ( !def.comment().isEmpty() )
fieldName = QString( "%1_%2" ).arg( fieldName ).arg( def.comment() );
if ( joined )
fieldName = QString( "%1%2" ).arg( AS_JOINPREFIX, fieldName );
return fieldName;
}
QgsField QgsAuxiliaryLayer::createAuxiliaryField( const QgsPropertyDefinition &def )
{
QgsField afield;
if ( !def.name().isEmpty() || !def.comment().isEmpty() )
{
QVariant::Type type;
QString typeName;
int len( 0 ), precision( 0 );
switch ( def.dataType() )
{
case QgsPropertyDefinition::DataTypeString:
type = QVariant::String;
len = 50;
typeName = "String";
break;
case QgsPropertyDefinition::DataTypeNumeric:
type = QVariant::Double;
len = 0;
precision = 0;
typeName = "Real";
break;
case QgsPropertyDefinition::DataTypeBoolean:
type = QVariant::Int; // sqlite does not have a bool type
typeName = "Integer";
break;
}
afield.setType( type );
afield.setName( nameFromProperty( def ) );
afield.setTypeName( typeName );
afield.setLength( len );
afield.setPrecision( precision );
}
return afield;
}
QgsPropertyDefinition QgsAuxiliaryLayer::propertyDefinitionFromField( const QgsField &f )
{
QgsPropertyDefinition def;
const QStringList parts = f.name().split( '_' );
if ( parts.size() <= 1 )
return def;
const QString origin = parts[0];
const QString propertyName = parts[1];
if ( origin.compare( "labeling", Qt::CaseInsensitive ) == 0 )
{
const QgsPropertiesDefinition props = QgsPalLayerSettings::propertyDefinitions();
for ( const QgsPropertyDefinition &p : props.values() )
{
if ( p.name().compare( propertyName, Qt::CaseInsensitive ) == 0 )
{
def = p;
if ( parts.size() == 3 )
def.setComment( parts[2] );
break;
}
}
}
else if ( origin.compare( "symbol", Qt::CaseInsensitive ) == 0 )
{
const QgsPropertiesDefinition props = QgsSymbolLayer::propertyDefinitions();
for ( const QgsPropertyDefinition &p : props.values() )
{
if ( p.name().compare( propertyName, Qt::CaseInsensitive ) == 0 )
{
def = p;
if ( parts.size() == 3 )
def.setComment( parts[2] );
break;
}
}
}
else if ( origin.compare( "diagram", Qt::CaseInsensitive ) == 0 )
{
const QgsPropertiesDefinition props = QgsDiagramLayerSettings::propertyDefinitions();
for ( const QgsPropertyDefinition &p : props.values() )
{
if ( p.name().compare( propertyName, Qt::CaseInsensitive ) == 0 )
{
def = p;
if ( parts.size() == 3 )
def.setComment( parts[2] );
break;
}
}
}
else
{
def.setOrigin( origin );
def.setName( propertyName );
if ( parts.size() == 3 )
def.setComment( parts[2] );
}
return def;
}
QgsField QgsAuxiliaryLayer::createAuxiliaryField( const QgsField &field )
{
QgsPropertyDefinition def = propertyDefinitionFromField( field );
QgsField afield;
if ( !def.name().isEmpty() || !def.comment().isEmpty() )
{
afield = createAuxiliaryField( def );
afield.setTypeName( field.typeName() );
}
return afield;
}
//
// QgsAuxiliaryStorage
//
QgsAuxiliaryStorage::QgsAuxiliaryStorage( const QgsProject &project, bool copy )
: mCopy( copy )
{
initTmpFileName();
if ( !project.fileInfo().fileName().isEmpty() )
{
const QFileInfo info = project.fileInfo();
const QString path = info.path() + QDir::separator() + info.baseName();
const QString asFileName = path + "." + QgsAuxiliaryStorage::extension();
mFileName = asFileName;
}
sqlite3 *handler = open( mFileName );
close( handler );
}
QgsAuxiliaryStorage::QgsAuxiliaryStorage( const QString &filename, bool copy )
: mFileName( filename )
, mCopy( copy )
{
initTmpFileName();
sqlite3 *handler = open( filename );
close( handler );
}
QgsAuxiliaryStorage::~QgsAuxiliaryStorage()
{
QFile::remove( mTmpFileName );
}
bool QgsAuxiliaryStorage::isValid() const
{
return mValid;
}
QString QgsAuxiliaryStorage::fileName() const
{
return mFileName;
}
bool QgsAuxiliaryStorage::save() const
{
if ( mFileName.isEmpty() )
{
// only a saveAs is available on a new database
return false;
}
else if ( mCopy )
{
if ( QFile::exists( mFileName ) )
QFile::remove( mFileName );
return QFile::copy( mTmpFileName, mFileName );
}
else
{
// if the file is not empty the copy mode is not activated, then we're
// directly working on the database since the beginning (no savepoints
// /rollback for now)
return true;
}
}
QgsAuxiliaryLayer *QgsAuxiliaryStorage::createAuxiliaryLayer( const QgsField &field, QgsVectorLayer *layer ) const
{
QgsAuxiliaryLayer *alayer = nullptr;
if ( mValid && layer )
{
const QString table( layer->id() );
sqlite3 *handler = openDB( currentFileName() );
if ( !tableExists( table, handler ) )
{
if ( !createTable( field.typeName(), table, handler ) )
{
close( handler );
return alayer;
}
}
alayer = new QgsAuxiliaryLayer( field.name(), currentFileName(), table, layer );
alayer->startEditing();
close( handler );
}
return alayer;
}
bool QgsAuxiliaryStorage::deleteTable( const QgsDataSourceUri &ogrUri )
{
bool rc = false;
QgsDataSourceUri uri = parseOgrUri( ogrUri );
if ( !uri.database().isEmpty() && !uri.table().isEmpty() )
{
sqlite3 *handler = openDB( uri.database() );
if ( handler )
{
QString sql = QString( "DROP TABLE %1" ).arg( uri.table() );
rc = exec( sql, handler );
sql = QString( "VACUUM" );
rc = exec( sql, handler );
close( handler );
}
}
return rc;
}
bool QgsAuxiliaryStorage::duplicateTable( const QgsDataSourceUri &ogrUri, const QString &newTable )
{
QgsDataSourceUri uri = parseOgrUri( ogrUri );
bool rc = false;
if ( !uri.table().isEmpty() && !uri.database().isEmpty() )
{
sqlite3 *handler = openDB( uri.database() );
if ( handler )
{
QString sql = QString( "CREATE TABLE %1 AS SELECT * FROM %2" ).arg( newTable, uri.table() );
rc = exec( sql, handler );
close( handler );
}
}
return rc;
}
bool QgsAuxiliaryStorage::saveAs( const QString &filename ) const
{
if ( QFile::exists( filename ) )
QFile::remove( filename );
return QFile::copy( currentFileName(), filename );
}
bool QgsAuxiliaryStorage::saveAs( const QgsProject &project ) const
{
return saveAs( filenameForProject( project ) );
}
QString QgsAuxiliaryStorage::extension()
{
return AS_EXTENSION;
}
bool QgsAuxiliaryStorage::exec( const QString &sql, sqlite3 *handler )
{
bool rc = false;
if ( handler )
{
const int err = sqlite3_exec( handler, sql.toStdString().c_str(), nullptr, nullptr, nullptr );
if ( err == SQLITE_OK )
rc = true;
else
debugMsg( sql, handler );
}
return rc;
}
void QgsAuxiliaryStorage::debugMsg( const QString &sql, sqlite3 *handler )
{
const QString err = QString::fromUtf8( sqlite3_errmsg( handler ) );
const QString msg = QObject::tr( "Unable to execute" );
const QString errMsg = QObject::tr( "%1 '%2': %3" ).arg( msg ).arg( sql ).arg( err );
QgsDebugMsg( errMsg );
}
sqlite3 *QgsAuxiliaryStorage::openDB( const QString &filename )
{
sqlite3 *handler = nullptr;
bool rc = QgsSLConnect::sqlite3_open_v2( filename.toUtf8().constData(), &handler, SQLITE_OPEN_READWRITE, nullptr );
if ( rc )
{
debugMsg( "sqlite3_open_v2", handler );
return nullptr;
}
return handler;
}
bool QgsAuxiliaryStorage::createTable( const QString &type, const QString &table, sqlite3 *handler )
{
const QString sql = QString( "CREATE TABLE IF NOT EXISTS '%1' ( '%2' %3 )" ).arg( table ).arg( AS_JOINFIELD ).arg( type );
if ( !exec( sql, handler ) )
return false;
return true;
}
sqlite3 *QgsAuxiliaryStorage::createDB( const QString &filename )
{
sqlite3 *handler = nullptr;
int rc;
// open/create database
rc = QgsSLConnect::sqlite3_open_v2( filename.toUtf8().constData(), &handler, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, nullptr );
if ( rc )
{
debugMsg( "sqlite3_open_v2", handler );
return handler;
}
// activating Foreign Key constraints
if ( !exec( "PRAGMA foreign_keys = 1", handler ) )
return handler;
return handler;
}
bool QgsAuxiliaryStorage::tableExists( const QString &table, sqlite3 *handler )
{
const QString sql = QString( "SELECT 1 FROM sqlite_master WHERE type='table' AND name='%1'" ).arg( table );
int rows = 0;
int columns = 0;
char **results = nullptr;
const int rc = sqlite3_get_table( handler, sql.toStdString().c_str(), &results, &rows, &columns, nullptr );
if ( rc != SQLITE_OK )
{
debugMsg( sql, handler );
return false;
}
sqlite3_free_table( results );
if ( rows >= 1 )
return true;
return false;
}
sqlite3 *QgsAuxiliaryStorage::open( const QString &filename )
{
sqlite3 *handler = nullptr;
if ( filename.isEmpty() )
{
if ( ( handler = createDB( currentFileName() ) ) )
mValid = true;
}
else if ( QFile::exists( filename ) )
{
if ( mCopy )
QFile::copy( filename, mTmpFileName );
if ( ( handler = openDB( currentFileName() ) ) )
mValid = true;
}
else
{
if ( ( handler = createDB( currentFileName() ) ) )
mValid = true;
}
return handler;
}
sqlite3 *QgsAuxiliaryStorage::open( const QgsProject &project )
{
return open( filenameForProject( project ) );
}
void QgsAuxiliaryStorage::close( sqlite3 *handler )
{
if ( handler )
{
QgsSLConnect::sqlite3_close_v2( handler );
handler = nullptr;
}
}
QString QgsAuxiliaryStorage::filenameForProject( const QgsProject &project )
{
const QFileInfo info = project.fileInfo();
const QString path = info.path() + QDir::separator() + info.baseName();
return path + "." + QgsAuxiliaryStorage::extension();
}
void QgsAuxiliaryStorage::initTmpFileName()
{
QTemporaryFile tmpFile;
tmpFile.open();
tmpFile.close();
mTmpFileName = tmpFile.fileName();
}
QString QgsAuxiliaryStorage::currentFileName() const
{
if ( mCopy || mFileName.isEmpty() )
return mTmpFileName;
else
return mFileName;
}
QgsDataSourceUri QgsAuxiliaryStorage::parseOgrUri( const QgsDataSourceUri &uri )
{
QgsDataSourceUri newUri;
// parsing for ogr style uri :
// " filePath|layername='tableName' table="" sql="
QStringList uriParts = uri.uri().split( '|' );
if ( uriParts.count() < 2 )
return newUri;
const QString databasePath = uriParts[0].replace( ' ', "" );
const QString table = uriParts[1];
QStringList tableParts = table.split( ' ' );
if ( tableParts.count() < 1 )
return newUri;
const QString tableName = tableParts[0].replace( "layername=", "" );
newUri.setDataSource( QString(), tableName, QString() );
newUri.setDatabase( databasePath );
return newUri;
}

View File

@ -0,0 +1,411 @@
/***************************************************************************
qgsauxiliarystorage.h - description
-------------------
begin : Aug 28, 2017
copyright : (C) 2017 by Paul Blottiere
email : paul.blottiere@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. *
* *
***************************************************************************/
#ifndef QGSAUXILIARYSTORAGE_H
#define QGSAUXILIARYSTORAGE_H
#include "qgis_core.h"
#include "qgsdatasourceuri.h"
#include "qgspallabeling.h"
#include "qgsdiagramrenderer.h"
#include "qgsvectorlayerjoininfo.h"
#include "qgsproperty.h"
#include <sqlite3.h>
#include <QString>
class QgsProject;
/**
* \class QgsAuxiliaryLayer
*
* \ingroup core
*
* Class allowing to manage the auxiliary storage for a vector layer.
*
* Such auxiliary data are data used mostly for the needs of QGIS (symbology)
* and have no real interest in being stored with the native raw geospatial
* data.
*
* The need arises from the restrictions existing in the manual placement of
* labels. Manual placement of labels are possible in QGIS by setting some
* labeling properties (X and Y position, and rotation angle optionally) as
* being "data-defined", meaning that values come from a column (or an
* expression). But setting this up on an existing layer requires either to
* add new columns to the source layer, while it is not always possible or
* desirable.
*
* This QgsAuxiliaryLayer provides the solution to this limitation. Actually
* it's an editable join to the original vector layer with some
* synchronisation mechanisms activated such as "Upsert On Edit" or "Delete
* Cascade". Thus, auxiliary fields are editable even if the
* source layer is not and edition of a joined field is also possible.
*
* \since QGIS 3.0
*/
class CORE_EXPORT QgsAuxiliaryLayer : public QgsVectorLayer
{
Q_OBJECT
public:
/**
* Constructor
*
* \param pkField The primary key to use for joining
* \param filename The database path
* \param table The table name
* \param vlayer The target vector layer in join definition
*/
QgsAuxiliaryLayer( const QString &pkField, const QString &filename, const QString &table, QgsVectorLayer *vlayer );
/**
* Destructor
*/
virtual ~QgsAuxiliaryLayer() = default;
/**
* Copy constructor deactivated
*/
QgsAuxiliaryLayer( const QgsAuxiliaryLayer &rhs ) = delete;
QgsAuxiliaryLayer &operator=( QgsAuxiliaryLayer const &rhs ) = delete;
/**
* Returns a new instance equivalent to this one. The underlying table
* is duplicate for the layer given in parameter. Note that the current
* auxiliary layer should be saved to have a proper duplicated table.
*
* \param layer The layer for which the clone is made
*/
QgsAuxiliaryLayer *clone( QgsVectorLayer *layer ) const SIP_FACTORY;
/**
* An auxiliary layer is not spatial. This method returns a spatial
* representation of auxiliary data.
*
* \returns A new spatial vector layer
*/
QgsVectorLayer *toSpatialLayer() const;
/**
* Deletes all features from the layer. Changes are automatically committed
* and the layer remains editable.
*
* \returns true if changes are committed without error, false otherwise.
*/
bool clear();
/**
* Returns information to use for joining with primary key and so on.
*/
QgsVectorLayerJoinInfo joinInfo() const;
/**
* Returns true if the property is stored in the layer already, false
* otherwise.
*
* \param definition The property definition to check
*
* \returns true if the property is stored, false otherwise
*/
bool exists( const QgsPropertyDefinition &definition ) const;
/**
* Add an an auxiliary field for the given property. Setup for widget
* editors are updated in the target layer as weel as the attribute
* table config to hide auxiliary fields by default.
*
* \param definition The definition of the property to add
*
* \returns true if the auxiliary field is well added, false otherwise
*/
bool addAuxiliaryField( const QgsPropertyDefinition &definition );
/**
* Returns a list of all auxiliary fields currently managed by the layer.
*/
QgsFields auxiliaryFields() const;
/**
* Commit changes and starts editing then.
*
* \returns true if commit step passed, false otherwise
*/
bool save();
/**
* Remove attribute from the layer and commit changes. The layer remains
* editable.
*
* \param attr The index of the attribute to remove
*
* \returns true if the attribute is well deleted, false otherwise
*/
virtual bool deleteAttribute( int attr ) override;
/**
* Returns true if the underlying field have to be hidden from editing
* tools like attribute table, false otherwise.
*
* \param index The index of the field for which visibility is checked
*/
bool isHiddenProperty( int index ) const;
/**
* Returns the index of the auxiliary field for a specific property
* definition.
*
* \param definition The property definition
*
* \returns The index of the field corresponding to the property or -1
*/
int indexOfPropertyDefinition( const QgsPropertyDefinition &definition ) const;
/**
* Returns the underlying property key for the field index. The key may be
* a PAL, diagram or symbology property according to the underlying
* property definition of the field. The key -1 is returned if an error
* happened.
*
* \param index The index of the field
*/
int propertyFromIndex( int index ) const;
/**
* Returns the property definition fir the underlying field index.
*
* \param index The index of the field
*/
QgsPropertyDefinition propertyDefinitionFromIndex( int index ) const;
/**
* Creates if necessary a new auxiliary field for a PAL property and
* activate this property in settings.
*
* \param property The property to create
* \param vlayer The vector layer
*
* \returns The index of the auxiliary field or -1
*/
static int createProperty( QgsPalLayerSettings::Property property, QgsVectorLayer *vlayer );
/**
* Creates if necessary a new auxiliary field for a diagram's property and
* activate this this property in settings.
*
* \param property The property to create
* \param vlayer The vector layer
*
* \returns The index of the auxiliary field or -1
*/
static int createProperty( QgsDiagramLayerSettings::Property property, QgsVectorLayer *vlayer );
/**
* Creates a new auxiliary field from a property definition.
*
* \param definition The property definition of the auxiliary field to create
*/
static QgsField createAuxiliaryField( const QgsPropertyDefinition &definition );
/**
* Creates a new auxiliary field from a field.
*
* \param field The field to use to create the auxiliary field
*/
static QgsField createAuxiliaryField( const QgsField &field );
/**
* Returns the name of the auxiliary field for a property definition.
*
* \param def The property definition
* \param joined The join prefix is taken into account if true
*/
static QString nameFromProperty( const QgsPropertyDefinition &def, bool joined = false );
/**
* Returns the property definition from an auxiliary field.
*
* \param field The auxiliary field
*/
static QgsPropertyDefinition propertyDefinitionFromField( const QgsField &field );
private:
QgsVectorLayerJoinInfo mJoinInfo;
QString mFileName;
QString mTable;
QgsVectorLayer *mLayer = nullptr;
};
/**
* \class QgsAuxiliaryStorage
*
* \ingroup core
*
* \brief Class providing some utility methods to manage auxiliary storage.
*
* \since QGIS 3.0
*/
class CORE_EXPORT QgsAuxiliaryStorage
{
public:
/**
* Constructor.
*
* The project filename is used to build a database path at the same
* location, but with a different extension. Then, it's the same logic as
* described for \see QgsAuxiliaryStorage(const QString &, bool copy).
*
*
* \param project The project for which the auxiliary storage has to be used
* \param copy Parameter indicating if a copy of the database has to be used
*/
QgsAuxiliaryStorage( const QgsProject &project, bool copy = true );
/**
* Constructor.
*
* If a valid database path is given in parameter and copy mode is
* deactivated, then every changes is directly committed on the original
* database. But if the copy mode is activated, then changes are committed
* on a copy of the database (a temporary file) and a save action is
* therefore necessary to keep modifications in the original file.
*
* If an empty string for the database path is given in parameter, then
* a database is created in a temporary file whatever the copy mode.
*
* If the database path given in parameter is not empty but does not exist,
* then a database is created at this location when copy mode is
* deactivated. When copy mode is activated, a temporary database is used
* instead and a save action will be necessary to create the database at
* the original location given in parameter.
*
* \param filename The path of the database
* \param copy Parameter indicating if a copy of the database has to be used
*/
QgsAuxiliaryStorage( const QString &filename = QString(), bool copy = true );
/**
* Destructor.
*/
virtual ~QgsAuxiliaryStorage();
/**
* Returns the status of the auxiliary storage currently definied.
*
* \returns true if the auxiliary storage is valid, false otherwise
*/
bool isValid() const;
/**
* Returns the target filename of the database.
*/
QString fileName() const;
/**
* Returns the path of current database used. It may be different from the
* target filename if the auxiliary storage is opened in copy mode.
*/
QString currentFileName() const;
/**
* Saves the current database to a new path.
*
* \returns true if everything is saved, false otherwise
*/
bool saveAs( const QString &filename ) const;
/**
* Saves the current database to a new path for a specific project.
* Actually, the current filename of the project is used to deduce the
* path of the database to save.
*
* \returns true if everything is saved, false otherwise
*/
bool saveAs( const QgsProject &project ) const;
/**
* Saves the current database.
*
* \returns true if everything is saved, false otherwise
*/
bool save() const;
/**
* Creates an auxiliary layer for a vector layer. A new table is created if
* necessary. The primary key to use to construct the auxiliary layer is
* given in parameter.
*
* \param field The primary key to join
* \param layer The vector layer for which the auxiliary layer has to be created
*
* \returns A new auxiliary layer or a nullptr if an error happened.
*/
QgsAuxiliaryLayer *createAuxiliaryLayer( const QgsField &field, QgsVectorLayer *layer ) const SIP_FACTORY;
/**
* Removes a table from the auxiliary storage.
*
* \param uri The uri of the table to remove
*
* \returns true if the table is well deleted, false otherwise
*/
static bool deleteTable( const QgsDataSourceUri &uri );
/**
* Duplicates a table and its content.
*
* \param uri The uri of the table to duplicate
* \param newTable The name of the new table
*
* \returns true if the table is well duplicated, false otherwise
*/
static bool duplicateTable( const QgsDataSourceUri &uri, const QString &newTable );
/**
* Returns the extension used for auxiliary databases.
*/
static QString extension();
private:
sqlite3 *open( const QString &filename = QString() );
sqlite3 *open( const QgsProject &project );
void initTmpFileName();
static QString filenameForProject( const QgsProject &project );
static sqlite3 *createDB( const QString &filename );
static sqlite3 *openDB( const QString &filename );
static void close( sqlite3 *handler );
static bool tableExists( const QString &table, sqlite3 *handler );
static bool createTable( const QString &type, const QString &table, sqlite3 *handler );
static bool exec( const QString &sql, sqlite3 *handler );
static void debugMsg( const QString &sql, sqlite3 *handler );
static QgsDataSourceUri parseOgrUri( const QgsDataSourceUri &uri );
bool mValid = false;
QString mFileName; // original filename
QString mTmpFileName; // temporary filename used in copy mode
bool mCopy = false;
};
#endif

View File

@ -34,20 +34,22 @@ void QgsDiagramLayerSettings::initPropertyDefinitions()
if ( !sPropertyDefinitions.isEmpty() )
return;
const QString origin = QStringLiteral( "diagram" );
sPropertyDefinitions = QgsPropertiesDefinition
{
{ QgsDiagramLayerSettings::BackgroundColor, QgsPropertyDefinition( "backgroundColor", QObject::tr( "Background color" ), QgsPropertyDefinition::ColorWithAlpha ) },
{ QgsDiagramLayerSettings::StrokeColor, QgsPropertyDefinition( "strokeColor", QObject::tr( "Stroke color" ), QgsPropertyDefinition::ColorWithAlpha ) },
{ QgsDiagramLayerSettings::StrokeWidth, QgsPropertyDefinition( "strokeWidth", QObject::tr( "Stroke width" ), QgsPropertyDefinition::StrokeWidth ) },
{ QgsDiagramLayerSettings::PositionX, QgsPropertyDefinition( "positionX", QObject::tr( "Position (X)" ), QgsPropertyDefinition::Double ) },
{ QgsDiagramLayerSettings::PositionY, QgsPropertyDefinition( "positionY", QObject::tr( "Position (Y)" ), QgsPropertyDefinition::Double ) },
{ QgsDiagramLayerSettings::Distance, QgsPropertyDefinition( "distance", QObject::tr( "Placement distance" ), QgsPropertyDefinition::DoublePositive ) },
{ QgsDiagramLayerSettings::Priority, QgsPropertyDefinition( "priority", QObject::tr( "Placement priority" ), QgsPropertyDefinition::DoublePositive ) },
{ QgsDiagramLayerSettings::ZIndex, QgsPropertyDefinition( "zIndex", QObject::tr( "Placement z-index" ), QgsPropertyDefinition::Double ) },
{ QgsDiagramLayerSettings::IsObstacle, QgsPropertyDefinition( "isObstacle", QObject::tr( "Diagram is an obstacle" ), QgsPropertyDefinition::Boolean ) },
{ QgsDiagramLayerSettings::Show, QgsPropertyDefinition( "show", QObject::tr( "Show diagram" ), QgsPropertyDefinition::Boolean ) },
{ QgsDiagramLayerSettings::AlwaysShow, QgsPropertyDefinition( "alwaysShow", QObject::tr( "Always show diagram" ), QgsPropertyDefinition::Boolean ) },
{ QgsDiagramLayerSettings::StartAngle, QgsPropertyDefinition( "startAngle", QObject::tr( "Pie chart start angle" ), QgsPropertyDefinition::Rotation ) },
{ QgsDiagramLayerSettings::BackgroundColor, QgsPropertyDefinition( "backgroundColor", QObject::tr( "Background color" ), QgsPropertyDefinition::ColorWithAlpha, origin ) },
{ QgsDiagramLayerSettings::StrokeColor, QgsPropertyDefinition( "strokeColor", QObject::tr( "Stroke color" ), QgsPropertyDefinition::ColorWithAlpha, origin ) },
{ QgsDiagramLayerSettings::StrokeWidth, QgsPropertyDefinition( "strokeWidth", QObject::tr( "Stroke width" ), QgsPropertyDefinition::StrokeWidth, origin ) },
{ QgsDiagramLayerSettings::PositionX, QgsPropertyDefinition( "positionX", QObject::tr( "Position (X)" ), QgsPropertyDefinition::Double, origin ) },
{ QgsDiagramLayerSettings::PositionY, QgsPropertyDefinition( "positionY", QObject::tr( "Position (Y)" ), QgsPropertyDefinition::Double, origin ) },
{ QgsDiagramLayerSettings::Distance, QgsPropertyDefinition( "distance", QObject::tr( "Placement distance" ), QgsPropertyDefinition::DoublePositive, origin ) },
{ QgsDiagramLayerSettings::Priority, QgsPropertyDefinition( "priority", QObject::tr( "Placement priority" ), QgsPropertyDefinition::DoublePositive, origin ) },
{ QgsDiagramLayerSettings::ZIndex, QgsPropertyDefinition( "zIndex", QObject::tr( "Placement z-index" ), QgsPropertyDefinition::Double, origin ) },
{ QgsDiagramLayerSettings::IsObstacle, QgsPropertyDefinition( "isObstacle", QObject::tr( "Diagram is an obstacle" ), QgsPropertyDefinition::Boolean, origin ) },
{ QgsDiagramLayerSettings::Show, QgsPropertyDefinition( "show", QObject::tr( "Show diagram" ), QgsPropertyDefinition::Boolean, origin ) },
{ QgsDiagramLayerSettings::AlwaysShow, QgsPropertyDefinition( "alwaysShow", QObject::tr( "Always show diagram" ), QgsPropertyDefinition::Boolean, origin ) },
{ QgsDiagramLayerSettings::StartAngle, QgsPropertyDefinition( "startAngle", QObject::tr( "Pie chart start angle" ), QgsPropertyDefinition::Rotation, origin ) },
};
}

View File

@ -97,134 +97,136 @@ void QgsPalLayerSettings::initPropertyDefinitions()
if ( !sPropertyDefinitions.isEmpty() )
return;
const QString origin = QStringLiteral( "labeling" );
sPropertyDefinitions = QgsPropertiesDefinition
{
{ QgsPalLayerSettings::Size, QgsPropertyDefinition( "Size", QObject::tr( "Font size" ), QgsPropertyDefinition::DoublePositive ) },
{ QgsPalLayerSettings::Bold, QgsPropertyDefinition( "Bold", QObject::tr( "Bold style" ), QgsPropertyDefinition::Boolean ) },
{ QgsPalLayerSettings::Italic, QgsPropertyDefinition( "Italic", QObject::tr( "Italic style" ), QgsPropertyDefinition::Boolean ) },
{ QgsPalLayerSettings::Underline, QgsPropertyDefinition( "Underline", QObject::tr( "Draw underline" ), QgsPropertyDefinition::Boolean ) },
{ QgsPalLayerSettings::Color, QgsPropertyDefinition( "Color", QObject::tr( "Text color" ), QgsPropertyDefinition::ColorNoAlpha ) },
{ QgsPalLayerSettings::Strikeout, QgsPropertyDefinition( "Strikeout", QObject::tr( "Draw strikeout" ), QgsPropertyDefinition::Boolean ) },
{ QgsPalLayerSettings::Size, QgsPropertyDefinition( "Size", QObject::tr( "Font size" ), QgsPropertyDefinition::DoublePositive, origin ) },
{ QgsPalLayerSettings::Bold, QgsPropertyDefinition( "Bold", QObject::tr( "Bold style" ), QgsPropertyDefinition::Boolean, origin ) },
{ QgsPalLayerSettings::Italic, QgsPropertyDefinition( "Italic", QObject::tr( "Italic style" ), QgsPropertyDefinition::Boolean, origin ) },
{ QgsPalLayerSettings::Underline, QgsPropertyDefinition( "Underline", QObject::tr( "Draw underline" ), QgsPropertyDefinition::Boolean, origin ) },
{ QgsPalLayerSettings::Color, QgsPropertyDefinition( "Color", QObject::tr( "Text color" ), QgsPropertyDefinition::ColorNoAlpha, origin ) },
{ QgsPalLayerSettings::Strikeout, QgsPropertyDefinition( "Strikeout", QObject::tr( "Draw strikeout" ), QgsPropertyDefinition::Boolean, origin ) },
{
QgsPalLayerSettings::Family, QgsPropertyDefinition( "Family", QgsPropertyDefinition::DataTypeString, QObject::tr( "Font family" ), QObject::tr( "string " ) + QObject::tr( "[<b>family</b>|<b>family[foundry]</b>],<br>"
"e.g. Helvetica or Helvetica [Cronyx]" ) )
"e.g. Helvetica or Helvetica [Cronyx]" ), origin )
},
{
QgsPalLayerSettings::FontStyle, QgsPropertyDefinition( "FontStyle", QgsPropertyDefinition::DataTypeString, QObject::tr( "Font style" ), QObject::tr( "string " ) + QObject::tr( "[<b>font style name</b>|<b>Ignore</b>],<br>"
"e.g. Bold Condensed or Light Italic" ) )
"e.g. Bold Condensed or Light Italic" ), origin )
},
{ QgsPalLayerSettings::FontSizeUnit, QgsPropertyDefinition( "FontSizeUnit", QObject::tr( "Font size units" ), QgsPropertyDefinition::RenderUnits ) },
{ QgsPalLayerSettings::FontTransp, QgsPropertyDefinition( "FontTransp", QObject::tr( "Text transparency" ), QgsPropertyDefinition::Opacity ) },
{ QgsPalLayerSettings::FontOpacity, QgsPropertyDefinition( "FontOpacity", QObject::tr( "Text opacity" ), QgsPropertyDefinition::Opacity ) },
{ QgsPalLayerSettings::FontCase, QgsPropertyDefinition( "FontCase", QgsPropertyDefinition::DataTypeString, QObject::tr( "Font case" ), QObject::tr( "string " ) + QStringLiteral( "[<b>NoChange</b>|<b>Upper</b>|<br><b>Lower</b>|<b>Capitalize</b>]" ) ) },
{ QgsPalLayerSettings::FontLetterSpacing, QgsPropertyDefinition( "FontLetterSpacing", QObject::tr( "Letter spacing" ), QgsPropertyDefinition::Double ) },
{ QgsPalLayerSettings::FontWordSpacing, QgsPropertyDefinition( "FontWordSpacing", QObject::tr( "Word spacing" ), QgsPropertyDefinition::Double ) },
{ QgsPalLayerSettings::FontBlendMode, QgsPropertyDefinition( "FontBlendMode", QObject::tr( "Text blend mode" ), QgsPropertyDefinition::BlendMode ) },
{ QgsPalLayerSettings::MultiLineWrapChar, QgsPropertyDefinition( "MultiLineWrapChar", QObject::tr( "Wrap character" ), QgsPropertyDefinition::String ) },
{ QgsPalLayerSettings::MultiLineHeight, QgsPropertyDefinition( "MultiLineHeight", QObject::tr( "Line height" ), QgsPropertyDefinition::DoublePositive ) },
{ QgsPalLayerSettings::MultiLineAlignment, QgsPropertyDefinition( "MultiLineAlignment", QgsPropertyDefinition::DataTypeString, QObject::tr( "Line alignment" ), QObject::tr( "string " ) + "[<b>Left</b>|<b>Center</b>|<b>Right</b>|<b>Follow</b>]" ) },
{ QgsPalLayerSettings::DirSymbDraw, QgsPropertyDefinition( "DirSymbDraw", QObject::tr( "Draw direction symbol" ), QgsPropertyDefinition::Boolean ) },
{ QgsPalLayerSettings::DirSymbLeft, QgsPropertyDefinition( "DirSymbLeft", QObject::tr( "Left direction symbol" ), QgsPropertyDefinition::String ) },
{ QgsPalLayerSettings::DirSymbRight, QgsPropertyDefinition( "DirSymbRight", QObject::tr( "Right direction symbol" ), QgsPropertyDefinition::String ) },
{ QgsPalLayerSettings::DirSymbPlacement, QgsPropertyDefinition( "DirSymbPlacement", QgsPropertyDefinition::DataTypeString, QObject::tr( "Direction symbol placement" ), QObject::tr( "string " ) + "[<b>LeftRight</b>|<b>Above</b>|<b>Below</b>]" ) },
{ QgsPalLayerSettings::DirSymbReverse, QgsPropertyDefinition( "DirSymbReverse", QObject::tr( "Reverse direction symbol" ), QgsPropertyDefinition::Boolean ) },
{ QgsPalLayerSettings::NumFormat, QgsPropertyDefinition( "NumFormat", QObject::tr( "Format as number" ), QgsPropertyDefinition::Boolean ) },
{ QgsPalLayerSettings::NumDecimals, QgsPropertyDefinition( "NumDecimals", QObject::tr( "Number of decimal places" ), QgsPropertyDefinition::IntegerPositive ) },
{ QgsPalLayerSettings::NumPlusSign, QgsPropertyDefinition( "NumPlusSign", QObject::tr( "Draw + sign" ), QgsPropertyDefinition::Boolean ) },
{ QgsPalLayerSettings::BufferDraw, QgsPropertyDefinition( "BufferDraw", QObject::tr( "Draw buffer" ), QgsPropertyDefinition::Boolean ) },
{ QgsPalLayerSettings::BufferSize, QgsPropertyDefinition( "BufferSize", QObject::tr( "Symbol size" ), QgsPropertyDefinition::DoublePositive ) },
{ QgsPalLayerSettings::BufferUnit, QgsPropertyDefinition( "BufferUnit", QObject::tr( "Buffer units" ), QgsPropertyDefinition::RenderUnits ) },
{ QgsPalLayerSettings::BufferColor, QgsPropertyDefinition( "BufferColor", QObject::tr( "Buffer color" ), QgsPropertyDefinition::ColorNoAlpha ) },
{ QgsPalLayerSettings::BufferTransp, QgsPropertyDefinition( "BufferTransp", QObject::tr( "Buffer transparency" ), QgsPropertyDefinition::Opacity ) },
{ QgsPalLayerSettings::BufferOpacity, QgsPropertyDefinition( "BufferOpacity", QObject::tr( "Buffer opacity" ), QgsPropertyDefinition::Opacity ) },
{ QgsPalLayerSettings::BufferJoinStyle, QgsPropertyDefinition( "BufferJoinStyle", QObject::tr( "Buffer join style" ), QgsPropertyDefinition::PenJoinStyle ) },
{ QgsPalLayerSettings::BufferBlendMode, QgsPropertyDefinition( "BufferBlendMode", QObject::tr( "Buffer blend mode" ), QgsPropertyDefinition::BlendMode ) },
{ QgsPalLayerSettings::ShapeDraw, QgsPropertyDefinition( "ShapeDraw", QObject::tr( "Draw shape" ), QgsPropertyDefinition::Boolean ) },
{ QgsPalLayerSettings::FontSizeUnit, QgsPropertyDefinition( "FontSizeUnit", QObject::tr( "Font size units" ), QgsPropertyDefinition::RenderUnits, origin ) },
{ QgsPalLayerSettings::FontTransp, QgsPropertyDefinition( "FontTransp", QObject::tr( "Text transparency" ), QgsPropertyDefinition::Opacity, origin ) },
{ QgsPalLayerSettings::FontOpacity, QgsPropertyDefinition( "FontOpacity", QObject::tr( "Text opacity" ), QgsPropertyDefinition::Opacity, origin ) },
{ QgsPalLayerSettings::FontCase, QgsPropertyDefinition( "FontCase", QgsPropertyDefinition::DataTypeString, QObject::tr( "Font case" ), QObject::tr( "string " ) + QStringLiteral( "[<b>NoChange</b>|<b>Upper</b>|<br><b>Lower</b>|<b>Capitalize</b>]" ), origin ) },
{ QgsPalLayerSettings::FontLetterSpacing, QgsPropertyDefinition( "FontLetterSpacing", QObject::tr( "Letter spacing" ), QgsPropertyDefinition::Double, origin ) },
{ QgsPalLayerSettings::FontWordSpacing, QgsPropertyDefinition( "FontWordSpacing", QObject::tr( "Word spacing" ), QgsPropertyDefinition::Double, origin ) },
{ QgsPalLayerSettings::FontBlendMode, QgsPropertyDefinition( "FontBlendMode", QObject::tr( "Text blend mode" ), QgsPropertyDefinition::BlendMode, origin ) },
{ QgsPalLayerSettings::MultiLineWrapChar, QgsPropertyDefinition( "MultiLineWrapChar", QObject::tr( "Wrap character" ), QgsPropertyDefinition::String, origin ) },
{ QgsPalLayerSettings::MultiLineHeight, QgsPropertyDefinition( "MultiLineHeight", QObject::tr( "Line height" ), QgsPropertyDefinition::DoublePositive, origin ) },
{ QgsPalLayerSettings::MultiLineAlignment, QgsPropertyDefinition( "MultiLineAlignment", QgsPropertyDefinition::DataTypeString, QObject::tr( "Line alignment" ), QObject::tr( "string " ) + "[<b>Left</b>|<b>Center</b>|<b>Right</b>|<b>Follow</b>]", origin ) },
{ QgsPalLayerSettings::DirSymbDraw, QgsPropertyDefinition( "DirSymbDraw", QObject::tr( "Draw direction symbol" ), QgsPropertyDefinition::Boolean, origin ) },
{ QgsPalLayerSettings::DirSymbLeft, QgsPropertyDefinition( "DirSymbLeft", QObject::tr( "Left direction symbol" ), QgsPropertyDefinition::String, origin ) },
{ QgsPalLayerSettings::DirSymbRight, QgsPropertyDefinition( "DirSymbRight", QObject::tr( "Right direction symbol" ), QgsPropertyDefinition::String, origin ) },
{ QgsPalLayerSettings::DirSymbPlacement, QgsPropertyDefinition( "DirSymbPlacement", QgsPropertyDefinition::DataTypeString, QObject::tr( "Direction symbol placement" ), QObject::tr( "string " ) + "[<b>LeftRight</b>|<b>Above</b>|<b>Below</b>]", origin ) },
{ QgsPalLayerSettings::DirSymbReverse, QgsPropertyDefinition( "DirSymbReverse", QObject::tr( "Reverse direction symbol" ), QgsPropertyDefinition::Boolean, origin ) },
{ QgsPalLayerSettings::NumFormat, QgsPropertyDefinition( "NumFormat", QObject::tr( "Format as number" ), QgsPropertyDefinition::Boolean, origin ) },
{ QgsPalLayerSettings::NumDecimals, QgsPropertyDefinition( "NumDecimals", QObject::tr( "Number of decimal places" ), QgsPropertyDefinition::IntegerPositive, origin ) },
{ QgsPalLayerSettings::NumPlusSign, QgsPropertyDefinition( "NumPlusSign", QObject::tr( "Draw + sign" ), QgsPropertyDefinition::Boolean, origin ) },
{ QgsPalLayerSettings::BufferDraw, QgsPropertyDefinition( "BufferDraw", QObject::tr( "Draw buffer" ), QgsPropertyDefinition::Boolean, origin ) },
{ QgsPalLayerSettings::BufferSize, QgsPropertyDefinition( "BufferSize", QObject::tr( "Symbol size" ), QgsPropertyDefinition::DoublePositive, origin ) },
{ QgsPalLayerSettings::BufferUnit, QgsPropertyDefinition( "BufferUnit", QObject::tr( "Buffer units" ), QgsPropertyDefinition::RenderUnits, origin ) },
{ QgsPalLayerSettings::BufferColor, QgsPropertyDefinition( "BufferColor", QObject::tr( "Buffer color" ), QgsPropertyDefinition::ColorNoAlpha, origin ) },
{ QgsPalLayerSettings::BufferTransp, QgsPropertyDefinition( "BufferTransp", QObject::tr( "Buffer transparency" ), QgsPropertyDefinition::Opacity, origin ) },
{ QgsPalLayerSettings::BufferOpacity, QgsPropertyDefinition( "BufferOpacity", QObject::tr( "Buffer opacity" ), QgsPropertyDefinition::Opacity, origin ) },
{ QgsPalLayerSettings::BufferJoinStyle, QgsPropertyDefinition( "BufferJoinStyle", QObject::tr( "Buffer join style" ), QgsPropertyDefinition::PenJoinStyle, origin ) },
{ QgsPalLayerSettings::BufferBlendMode, QgsPropertyDefinition( "BufferBlendMode", QObject::tr( "Buffer blend mode" ), QgsPropertyDefinition::BlendMode, origin ) },
{ QgsPalLayerSettings::ShapeDraw, QgsPropertyDefinition( "ShapeDraw", QObject::tr( "Draw shape" ), QgsPropertyDefinition::Boolean, origin ) },
{
QgsPalLayerSettings::ShapeKind, QgsPropertyDefinition( "ShapeKind", QgsPropertyDefinition::DataTypeString, QObject::tr( "Shape type" ), QObject::tr( "string " ) + QStringLiteral( "[<b>Rectangle</b>|<b>Square</b>|<br>"
"<b>Ellipse</b>|<b>Circle</b>|<b>SVG</b>]" ) )
"<b>Ellipse</b>|<b>Circle</b>|<b>SVG</b>]" ), origin )
},
{ QgsPalLayerSettings::ShapeSVGFile, QgsPropertyDefinition( "ShapeSVGFile", QObject::tr( "Shape SVG path" ), QgsPropertyDefinition::SvgPath ) },
{ QgsPalLayerSettings::ShapeSizeType, QgsPropertyDefinition( "ShapeSizeType", QgsPropertyDefinition::DataTypeString, QObject::tr( "Shape size type" ), QObject::tr( "string " ) + "[<b>Buffer</b>|<b>Fixed</b>]" ) },
{ QgsPalLayerSettings::ShapeSizeX, QgsPropertyDefinition( "ShapeSizeX", QObject::tr( "Shape size (X)" ), QgsPropertyDefinition::Double ) },
{ QgsPalLayerSettings::ShapeSizeY, QgsPropertyDefinition( "ShapeSizeY", QObject::tr( "Shape size (Y)" ), QgsPropertyDefinition::Double ) },
{ QgsPalLayerSettings::ShapeSizeUnits, QgsPropertyDefinition( "ShapeSizeUnits", QObject::tr( "Shape size units" ), QgsPropertyDefinition::RenderUnits ) },
{ QgsPalLayerSettings::ShapeRotationType, QgsPropertyDefinition( "ShapeRotationType", QgsPropertyDefinition::DataTypeString, QObject::tr( "Shape rotation type" ), QObject::tr( "string " ) + "[<b>Sync</b>|<b>Offset</b>|<b>Fixed</b>]" ) },
{ QgsPalLayerSettings::ShapeRotation, QgsPropertyDefinition( "ShapeRotation", QObject::tr( "Shape rotation" ), QgsPropertyDefinition::Rotation ) },
{ QgsPalLayerSettings::ShapeOffset, QgsPropertyDefinition( "ShapeOffset", QObject::tr( "Shape offset" ), QgsPropertyDefinition::Offset ) },
{ QgsPalLayerSettings::ShapeOffsetUnits, QgsPropertyDefinition( "ShapeOffsetUnits", QObject::tr( "Shape offset units" ), QgsPropertyDefinition::RenderUnits ) },
{ QgsPalLayerSettings::ShapeRadii, QgsPropertyDefinition( "ShapeRadii", QObject::tr( "Shape radii" ), QgsPropertyDefinition::Size2D ) },
{ QgsPalLayerSettings::ShapeRadiiUnits, QgsPropertyDefinition( "ShapeRadiiUnits", QObject::tr( "Symbol radii units" ), QgsPropertyDefinition::RenderUnits ) },
{ QgsPalLayerSettings::ShapeTransparency, QgsPropertyDefinition( "ShapeTransparency", QObject::tr( "Shape transparency" ), QgsPropertyDefinition::Opacity ) },
{ QgsPalLayerSettings::ShapeOpacity, QgsPropertyDefinition( "ShapeOpacity", QObject::tr( "Shape opacity" ), QgsPropertyDefinition::Opacity ) },
{ QgsPalLayerSettings::ShapeBlendMode, QgsPropertyDefinition( "ShapeBlendMode", QObject::tr( "Shape blend mode" ), QgsPropertyDefinition::BlendMode ) },
{ QgsPalLayerSettings::ShapeFillColor, QgsPropertyDefinition( "ShapeFillColor", QObject::tr( "Shape fill color" ), QgsPropertyDefinition::ColorWithAlpha ) },
{ QgsPalLayerSettings::ShapeStrokeColor, QgsPropertyDefinition( "ShapeBorderColor", QObject::tr( "Shape stroke color" ), QgsPropertyDefinition::ColorWithAlpha ) },
{ QgsPalLayerSettings::ShapeStrokeWidth, QgsPropertyDefinition( "ShapeBorderWidth", QObject::tr( "Shape stroke width" ), QgsPropertyDefinition::StrokeWidth ) },
{ QgsPalLayerSettings::ShapeStrokeWidthUnits, QgsPropertyDefinition( "ShapeBorderWidthUnits", QObject::tr( "Shape stroke width units" ), QgsPropertyDefinition::RenderUnits ) },
{ QgsPalLayerSettings::ShapeJoinStyle, QgsPropertyDefinition( "ShapeJoinStyle", QObject::tr( "Shape join style" ), QgsPropertyDefinition::PenJoinStyle ) },
{ QgsPalLayerSettings::ShadowDraw, QgsPropertyDefinition( "ShadowDraw", QObject::tr( "Draw shadow" ), QgsPropertyDefinition::Boolean ) },
{ QgsPalLayerSettings::ShapeSVGFile, QgsPropertyDefinition( "ShapeSVGFile", QObject::tr( "Shape SVG path" ), QgsPropertyDefinition::SvgPath, origin ) },
{ QgsPalLayerSettings::ShapeSizeType, QgsPropertyDefinition( "ShapeSizeType", QgsPropertyDefinition::DataTypeString, QObject::tr( "Shape size type" ), QObject::tr( "string " ) + "[<b>Buffer</b>|<b>Fixed</b>]", origin ) },
{ QgsPalLayerSettings::ShapeSizeX, QgsPropertyDefinition( "ShapeSizeX", QObject::tr( "Shape size (X)" ), QgsPropertyDefinition::Double, origin ) },
{ QgsPalLayerSettings::ShapeSizeY, QgsPropertyDefinition( "ShapeSizeY", QObject::tr( "Shape size (Y)" ), QgsPropertyDefinition::Double, origin ) },
{ QgsPalLayerSettings::ShapeSizeUnits, QgsPropertyDefinition( "ShapeSizeUnits", QObject::tr( "Shape size units" ), QgsPropertyDefinition::RenderUnits, origin ) },
{ QgsPalLayerSettings::ShapeRotationType, QgsPropertyDefinition( "ShapeRotationType", QgsPropertyDefinition::DataTypeString, QObject::tr( "Shape rotation type" ), QObject::tr( "string " ) + "[<b>Sync</b>|<b>Offset</b>|<b>Fixed</b>]", origin ) },
{ QgsPalLayerSettings::ShapeRotation, QgsPropertyDefinition( "ShapeRotation", QObject::tr( "Shape rotation" ), QgsPropertyDefinition::Rotation, origin ) },
{ QgsPalLayerSettings::ShapeOffset, QgsPropertyDefinition( "ShapeOffset", QObject::tr( "Shape offset" ), QgsPropertyDefinition::Offset, origin ) },
{ QgsPalLayerSettings::ShapeOffsetUnits, QgsPropertyDefinition( "ShapeOffsetUnits", QObject::tr( "Shape offset units" ), QgsPropertyDefinition::RenderUnits, origin ) },
{ QgsPalLayerSettings::ShapeRadii, QgsPropertyDefinition( "ShapeRadii", QObject::tr( "Shape radii" ), QgsPropertyDefinition::Size2D, origin ) },
{ QgsPalLayerSettings::ShapeRadiiUnits, QgsPropertyDefinition( "ShapeRadiiUnits", QObject::tr( "Symbol radii units" ), QgsPropertyDefinition::RenderUnits, origin ) },
{ QgsPalLayerSettings::ShapeTransparency, QgsPropertyDefinition( "ShapeTransparency", QObject::tr( "Shape transparency" ), QgsPropertyDefinition::Opacity, origin ) },
{ QgsPalLayerSettings::ShapeOpacity, QgsPropertyDefinition( "ShapeOpacity", QObject::tr( "Shape opacity" ), QgsPropertyDefinition::Opacity, origin ) },
{ QgsPalLayerSettings::ShapeBlendMode, QgsPropertyDefinition( "ShapeBlendMode", QObject::tr( "Shape blend mode" ), QgsPropertyDefinition::BlendMode, origin ) },
{ QgsPalLayerSettings::ShapeFillColor, QgsPropertyDefinition( "ShapeFillColor", QObject::tr( "Shape fill color" ), QgsPropertyDefinition::ColorWithAlpha, origin ) },
{ QgsPalLayerSettings::ShapeStrokeColor, QgsPropertyDefinition( "ShapeBorderColor", QObject::tr( "Shape stroke color" ), QgsPropertyDefinition::ColorWithAlpha, origin ) },
{ QgsPalLayerSettings::ShapeStrokeWidth, QgsPropertyDefinition( "ShapeBorderWidth", QObject::tr( "Shape stroke width" ), QgsPropertyDefinition::StrokeWidth, origin ) },
{ QgsPalLayerSettings::ShapeStrokeWidthUnits, QgsPropertyDefinition( "ShapeBorderWidthUnits", QObject::tr( "Shape stroke width units" ), QgsPropertyDefinition::RenderUnits, origin ) },
{ QgsPalLayerSettings::ShapeJoinStyle, QgsPropertyDefinition( "ShapeJoinStyle", QObject::tr( "Shape join style" ), QgsPropertyDefinition::PenJoinStyle, origin ) },
{ QgsPalLayerSettings::ShadowDraw, QgsPropertyDefinition( "ShadowDraw", QObject::tr( "Draw shadow" ), QgsPropertyDefinition::Boolean, origin ) },
{
QgsPalLayerSettings::ShadowUnder, QgsPropertyDefinition( "ShadowUnder", QgsPropertyDefinition::DataTypeString, QObject::tr( "Symbol size" ), QObject::tr( "string " ) + QStringLiteral( "[<b>Lowest</b>|<b>Text</b>|<br>"
"<b>Buffer</b>|<b>Background</b>]" ) )
"<b>Buffer</b>|<b>Background</b>]" ), origin )
},
{ QgsPalLayerSettings::ShadowOffsetAngle, QgsPropertyDefinition( "ShadowOffsetAngle", QObject::tr( "Shadow offset angle" ), QgsPropertyDefinition::Rotation ) },
{ QgsPalLayerSettings::ShadowOffsetDist, QgsPropertyDefinition( "ShadowOffsetDist", QObject::tr( "Shadow offset distance" ), QgsPropertyDefinition::DoublePositive ) },
{ QgsPalLayerSettings::ShadowOffsetUnits, QgsPropertyDefinition( "ShadowOffsetUnits", QObject::tr( "Shadow offset units" ), QgsPropertyDefinition::RenderUnits ) },
{ QgsPalLayerSettings::ShadowRadius, QgsPropertyDefinition( "ShadowRadius", QObject::tr( "Shadow blur radius" ), QgsPropertyDefinition::DoublePositive ) },
{ QgsPalLayerSettings::ShadowRadiusUnits, QgsPropertyDefinition( "ShadowRadiusUnits", QObject::tr( "Shadow blur units" ), QgsPropertyDefinition::RenderUnits ) },
{ QgsPalLayerSettings::ShadowTransparency, QgsPropertyDefinition( "ShadowTransparency", QObject::tr( "Shadow transparency" ), QgsPropertyDefinition::Opacity ) },
{ QgsPalLayerSettings::ShadowOpacity, QgsPropertyDefinition( "ShadowOpacity", QObject::tr( "Shadow opacity" ), QgsPropertyDefinition::Opacity ) },
{ QgsPalLayerSettings::ShadowScale, QgsPropertyDefinition( "ShadowScale", QObject::tr( "Shadow scale" ), QgsPropertyDefinition::IntegerPositive ) },
{ QgsPalLayerSettings::ShadowColor, QgsPropertyDefinition( "ShadowColor", QObject::tr( "Shadow color" ), QgsPropertyDefinition::ColorNoAlpha ) },
{ QgsPalLayerSettings::ShadowBlendMode, QgsPropertyDefinition( "ShadowBlendMode", QObject::tr( "Shadow blend mode" ), QgsPropertyDefinition::BlendMode ) },
{ QgsPalLayerSettings::ShadowOffsetAngle, QgsPropertyDefinition( "ShadowOffsetAngle", QObject::tr( "Shadow offset angle" ), QgsPropertyDefinition::Rotation, origin ) },
{ QgsPalLayerSettings::ShadowOffsetDist, QgsPropertyDefinition( "ShadowOffsetDist", QObject::tr( "Shadow offset distance" ), QgsPropertyDefinition::DoublePositive, origin ) },
{ QgsPalLayerSettings::ShadowOffsetUnits, QgsPropertyDefinition( "ShadowOffsetUnits", QObject::tr( "Shadow offset units" ), QgsPropertyDefinition::RenderUnits, origin ) },
{ QgsPalLayerSettings::ShadowRadius, QgsPropertyDefinition( "ShadowRadius", QObject::tr( "Shadow blur radius" ), QgsPropertyDefinition::DoublePositive, origin ) },
{ QgsPalLayerSettings::ShadowRadiusUnits, QgsPropertyDefinition( "ShadowRadiusUnits", QObject::tr( "Shadow blur units" ), QgsPropertyDefinition::RenderUnits, origin ) },
{ QgsPalLayerSettings::ShadowTransparency, QgsPropertyDefinition( "ShadowTransparency", QObject::tr( "Shadow transparency" ), QgsPropertyDefinition::Opacity, origin ) },
{ QgsPalLayerSettings::ShadowOpacity, QgsPropertyDefinition( "ShadowOpacity", QObject::tr( "Shadow opacity" ), QgsPropertyDefinition::Opacity, origin ) },
{ QgsPalLayerSettings::ShadowScale, QgsPropertyDefinition( "ShadowScale", QObject::tr( "Shadow scale" ), QgsPropertyDefinition::IntegerPositive, origin ) },
{ QgsPalLayerSettings::ShadowColor, QgsPropertyDefinition( "ShadowColor", QObject::tr( "Shadow color" ), QgsPropertyDefinition::ColorNoAlpha, origin ) },
{ QgsPalLayerSettings::ShadowBlendMode, QgsPropertyDefinition( "ShadowBlendMode", QObject::tr( "Shadow blend mode" ), QgsPropertyDefinition::BlendMode, origin ) },
{ QgsPalLayerSettings::CentroidWhole, QgsPropertyDefinition( "CentroidWhole", QgsPropertyDefinition::DataTypeString, QObject::tr( "Centroid of whole shape" ), QObject::tr( "string " ) + "[<b>Visible</b>|<b>Whole</b>]" ) },
{ QgsPalLayerSettings::CentroidWhole, QgsPropertyDefinition( "CentroidWhole", QgsPropertyDefinition::DataTypeString, QObject::tr( "Centroid of whole shape" ), QObject::tr( "string " ) + "[<b>Visible</b>|<b>Whole</b>]", origin ) },
{
QgsPalLayerSettings::OffsetQuad, QgsPropertyDefinition( "OffsetQuad", QgsPropertyDefinition::DataTypeString, QObject::tr( "Offset quadrant" ), QObject::tr( "int<br>" ) + QStringLiteral( "[<b>0</b>=Above Left|<b>1</b>=Above|<b>2</b>=Above Right|<br>"
"<b>3</b>=Left|<b>4</b>=Over|<b>5</b>=Right|<br>"
"<b>6</b>=Below Left|<b>7</b>=Below|<b>8</b>=Below Right]" ) )
"<b>6</b>=Below Left|<b>7</b>=Below|<b>8</b>=Below Right]" ), origin )
},
{ QgsPalLayerSettings::OffsetXY, QgsPropertyDefinition( "OffsetXY", QObject::tr( "Offset" ), QgsPropertyDefinition::Offset ) },
{ QgsPalLayerSettings::OffsetUnits, QgsPropertyDefinition( "OffsetUnits", QObject::tr( "Offset units" ), QgsPropertyDefinition::RenderUnits ) },
{ QgsPalLayerSettings::LabelDistance, QgsPropertyDefinition( "LabelDistance", QObject::tr( "Label distance" ), QgsPropertyDefinition::DoublePositive ) },
{ QgsPalLayerSettings::DistanceUnits, QgsPropertyDefinition( "DistanceUnits", QObject::tr( "Label distance units" ), QgsPropertyDefinition::RenderUnits ) },
{ QgsPalLayerSettings::OffsetRotation, QgsPropertyDefinition( "OffsetRotation", QObject::tr( "Offset rotation" ), QgsPropertyDefinition::Rotation ) },
{ QgsPalLayerSettings::CurvedCharAngleInOut, QgsPropertyDefinition( "CurvedCharAngleInOut", QgsPropertyDefinition::DataTypeString, QObject::tr( "Curved character angles" ), QObject::tr( "double coord [<b>in,out</b> as 20.0-60.0,20.0-95.0]" ) ) },
{ QgsPalLayerSettings::RepeatDistance, QgsPropertyDefinition( "RepeatDistance", QObject::tr( "Repeat distance" ), QgsPropertyDefinition::DoublePositive ) },
{ QgsPalLayerSettings::RepeatDistanceUnit, QgsPropertyDefinition( "RepeatDistanceUnit", QObject::tr( "Repeat distance unit" ), QgsPropertyDefinition::RenderUnits ) },
{ QgsPalLayerSettings::Priority, QgsPropertyDefinition( "Priority", QgsPropertyDefinition::DataTypeString, QObject::tr( "Label priority" ), QObject::tr( "double [0.0-10.0]" ) ) },
{ QgsPalLayerSettings::IsObstacle, QgsPropertyDefinition( "IsObstacle", QObject::tr( "Feature is a label obstacle" ), QgsPropertyDefinition::Boolean ) },
{ QgsPalLayerSettings::ObstacleFactor, QgsPropertyDefinition( "ObstacleFactor", QgsPropertyDefinition::DataTypeNumeric, QObject::tr( "Obstacle factor" ), QObject::tr( "double [0.0-10.0]" ) ) },
{ QgsPalLayerSettings::OffsetXY, QgsPropertyDefinition( "OffsetXY", QObject::tr( "Offset" ), QgsPropertyDefinition::Offset, origin ) },
{ QgsPalLayerSettings::OffsetUnits, QgsPropertyDefinition( "OffsetUnits", QObject::tr( "Offset units" ), QgsPropertyDefinition::RenderUnits, origin ) },
{ QgsPalLayerSettings::LabelDistance, QgsPropertyDefinition( "LabelDistance", QObject::tr( "Label distance" ), QgsPropertyDefinition::DoublePositive, origin ) },
{ QgsPalLayerSettings::DistanceUnits, QgsPropertyDefinition( "DistanceUnits", QObject::tr( "Label distance units" ), QgsPropertyDefinition::RenderUnits, origin ) },
{ QgsPalLayerSettings::OffsetRotation, QgsPropertyDefinition( "OffsetRotation", QObject::tr( "Offset rotation" ), QgsPropertyDefinition::Rotation, origin ) },
{ QgsPalLayerSettings::CurvedCharAngleInOut, QgsPropertyDefinition( "CurvedCharAngleInOut", QgsPropertyDefinition::DataTypeString, QObject::tr( "Curved character angles" ), QObject::tr( "double coord [<b>in,out</b> as 20.0-60.0,20.0-95.0]" ), origin ) },
{ QgsPalLayerSettings::RepeatDistance, QgsPropertyDefinition( "RepeatDistance", QObject::tr( "Repeat distance" ), QgsPropertyDefinition::DoublePositive, origin ) },
{ QgsPalLayerSettings::RepeatDistanceUnit, QgsPropertyDefinition( "RepeatDistanceUnit", QObject::tr( "Repeat distance unit" ), QgsPropertyDefinition::RenderUnits, origin ) },
{ QgsPalLayerSettings::Priority, QgsPropertyDefinition( "Priority", QgsPropertyDefinition::DataTypeString, QObject::tr( "Label priority" ), QObject::tr( "double [0.0-10.0]" ), origin ) },
{ QgsPalLayerSettings::IsObstacle, QgsPropertyDefinition( "IsObstacle", QObject::tr( "Feature is a label obstacle" ), QgsPropertyDefinition::Boolean, origin ) },
{ QgsPalLayerSettings::ObstacleFactor, QgsPropertyDefinition( "ObstacleFactor", QgsPropertyDefinition::DataTypeNumeric, QObject::tr( "Obstacle factor" ), QObject::tr( "double [0.0-10.0]" ), origin ) },
{
QgsPalLayerSettings::PredefinedPositionOrder, QgsPropertyDefinition( "PredefinedPositionOrder", QgsPropertyDefinition::DataTypeString, QObject::tr( "Predefined position order" ), QObject::tr( "Comma separated list of placements in order of priority<br>" )
+ QStringLiteral( "[<b>TL</b>=Top left|<b>TSL</b>=Top, slightly left|<b>T</b>=Top middle|<br>"
"<b>TSR</b>=Top, slightly right|<b>TR</b>=Top right|<br>"
"<b>L</b>=Left|<b>R</b>=Right|<br>"
"<b>BL</b>=Bottom left|<b>BSL</b>=Bottom, slightly left|<b>B</b>=Bottom middle|<br>"
"<b>BSR</b>=Bottom, slightly right|<b>BR</b>=Bottom right]" ) )
"<b>BSR</b>=Bottom, slightly right|<b>BR</b>=Bottom right]" ), origin )
},
{ QgsPalLayerSettings::PositionX, QgsPropertyDefinition( "PositionX", QObject::tr( "Position (X)" ), QgsPropertyDefinition::Double ) },
{ QgsPalLayerSettings::PositionY, QgsPropertyDefinition( "PositionY", QObject::tr( "Position (Y)" ), QgsPropertyDefinition::Double ) },
{ QgsPalLayerSettings::Hali, QgsPropertyDefinition( "Hali", QgsPropertyDefinition::DataTypeString, QObject::tr( "Horizontal alignment" ), QObject::tr( "string " ) + "[<b>Left</b>|<b>Center</b>|<b>Right</b>]" ) },
{ QgsPalLayerSettings::PositionX, QgsPropertyDefinition( "PositionX", QObject::tr( "Position (X)" ), QgsPropertyDefinition::Double, origin ) },
{ QgsPalLayerSettings::PositionY, QgsPropertyDefinition( "PositionY", QObject::tr( "Position (Y)" ), QgsPropertyDefinition::Double, origin ) },
{ QgsPalLayerSettings::Hali, QgsPropertyDefinition( "Hali", QgsPropertyDefinition::DataTypeString, QObject::tr( "Horizontal alignment" ), QObject::tr( "string " ) + "[<b>Left</b>|<b>Center</b>|<b>Right</b>]", origin ) },
{
QgsPalLayerSettings::Vali, QgsPropertyDefinition( "Vali", QgsPropertyDefinition::DataTypeString, QObject::tr( "Vertical alignment" ), QObject::tr( "string " ) + QStringLiteral( "[<b>Bottom</b>|<b>Base</b>|<br>"
"<b>Half</b>|<b>Cap</b>|<b>Top</b>]" ) )
"<b>Half</b>|<b>Cap</b>|<b>Top</b>]" ), origin )
},
{ QgsPalLayerSettings::Rotation, QgsPropertyDefinition( "Rotation", QObject::tr( "Label rotation (deprecated)" ), QgsPropertyDefinition::Rotation ) },
{ QgsPalLayerSettings::LabelRotation, QgsPropertyDefinition( "LabelRotation", QObject::tr( "Label rotation" ), QgsPropertyDefinition::Rotation ) },
{ QgsPalLayerSettings::ScaleVisibility, QgsPropertyDefinition( "ScaleVisibility", QObject::tr( "Scale based visibility" ), QgsPropertyDefinition::Boolean ) },
{ QgsPalLayerSettings::MinScale, QgsPropertyDefinition( "MinScale", QObject::tr( "Minimum scale (denominator)" ), QgsPropertyDefinition::Double ) },
{ QgsPalLayerSettings::MaxScale, QgsPropertyDefinition( "MaxScale", QObject::tr( "Maximum scale (denominator)" ), QgsPropertyDefinition::Double ) },
{ QgsPalLayerSettings::MinimumScale, QgsPropertyDefinition( "MinimumScale", QObject::tr( "Minimum scale (denominator)" ), QgsPropertyDefinition::Double ) },
{ QgsPalLayerSettings::MaximumScale, QgsPropertyDefinition( "MaximumScale", QObject::tr( "Maximum scale (denominator)" ), QgsPropertyDefinition::Double ) },
{ QgsPalLayerSettings::Rotation, QgsPropertyDefinition( "Rotation", QObject::tr( "Label rotation (deprecated)" ), QgsPropertyDefinition::Rotation, origin ) },
{ QgsPalLayerSettings::LabelRotation, QgsPropertyDefinition( "LabelRotation", QObject::tr( "Label rotation" ), QgsPropertyDefinition::Rotation, origin ) },
{ QgsPalLayerSettings::ScaleVisibility, QgsPropertyDefinition( "ScaleVisibility", QObject::tr( "Scale based visibility" ), QgsPropertyDefinition::Boolean, origin ) },
{ QgsPalLayerSettings::MinScale, QgsPropertyDefinition( "MinScale", QObject::tr( "Minimum scale (denominator)" ), QgsPropertyDefinition::Double, origin ) },
{ QgsPalLayerSettings::MaxScale, QgsPropertyDefinition( "MaxScale", QObject::tr( "Maximum scale (denominator)" ), QgsPropertyDefinition::Double, origin ) },
{ QgsPalLayerSettings::MinimumScale, QgsPropertyDefinition( "MinimumScale", QObject::tr( "Minimum scale (denominator)" ), QgsPropertyDefinition::Double, origin ) },
{ QgsPalLayerSettings::MaximumScale, QgsPropertyDefinition( "MaximumScale", QObject::tr( "Maximum scale (denominator)" ), QgsPropertyDefinition::Double, origin ) },
{ QgsPalLayerSettings::FontLimitPixel, QgsPropertyDefinition( "FontLimitPixel", QObject::tr( "Limit font pixel size" ), QgsPropertyDefinition::Boolean ) },
{ QgsPalLayerSettings::FontMinPixel, QgsPropertyDefinition( "FontMinPixel", QObject::tr( "Minimum pixel size" ), QgsPropertyDefinition::IntegerPositive ) },
{ QgsPalLayerSettings::FontMaxPixel, QgsPropertyDefinition( "FontMaxPixel", QObject::tr( "Maximum pixel size" ), QgsPropertyDefinition::IntegerPositive ) },
{ QgsPalLayerSettings::ZIndex, QgsPropertyDefinition( "ZIndex", QObject::tr( "Label z-index" ), QgsPropertyDefinition::Double ) },
{ QgsPalLayerSettings::Show, QgsPropertyDefinition( "Show", QObject::tr( "Show label" ), QgsPropertyDefinition::Boolean ) },
{ QgsPalLayerSettings::AlwaysShow, QgsPropertyDefinition( "AlwaysShow", QObject::tr( "Always show label" ), QgsPropertyDefinition::Boolean ) },
{ QgsPalLayerSettings::FontLimitPixel, QgsPropertyDefinition( "FontLimitPixel", QObject::tr( "Limit font pixel size" ), QgsPropertyDefinition::Boolean, origin ) },
{ QgsPalLayerSettings::FontMinPixel, QgsPropertyDefinition( "FontMinPixel", QObject::tr( "Minimum pixel size" ), QgsPropertyDefinition::IntegerPositive, origin ) },
{ QgsPalLayerSettings::FontMaxPixel, QgsPropertyDefinition( "FontMaxPixel", QObject::tr( "Maximum pixel size" ), QgsPropertyDefinition::IntegerPositive, origin ) },
{ QgsPalLayerSettings::ZIndex, QgsPropertyDefinition( "ZIndex", QObject::tr( "Label z-index" ), QgsPropertyDefinition::Double, origin ) },
{ QgsPalLayerSettings::Show, QgsPropertyDefinition( "Show", QObject::tr( "Show label" ), QgsPropertyDefinition::Boolean, origin ) },
{ QgsPalLayerSettings::AlwaysShow, QgsPropertyDefinition( "AlwaysShow", QObject::tr( "Always show label" ), QgsPropertyDefinition::Boolean, origin ) },
};
}

View File

@ -49,6 +49,7 @@
#include "qgslayoutmanager.h"
#include "qgsmaplayerstore.h"
#include "qgsziputils.h"
#include "qgsauxiliarystorage.h"
#include <QApplication>
#include <QFileInfo>
@ -335,6 +336,7 @@ QgsProject::QgsProject( QObject *parent )
, mRootGroup( new QgsLayerTree )
, mLabelingEngineSettings( new QgsLabelingEngineSettings )
, mArchive( new QgsProjectArchive() )
, mAuxiliaryStorage( new QgsAuxiliaryStorage() )
{
mProperties.setName( QStringLiteral( "properties" ) );
clear();
@ -424,8 +426,6 @@ void QgsProject::setFileName( const QString &name )
if ( newHomePath != oldHomePath )
emit homePathChanged();
mArchive->clear();
setDirty( true );
}
@ -493,6 +493,7 @@ void QgsProject::clear()
mLabelingEngineSettings->clear();
mAuxiliaryStorage.reset( new QgsAuxiliaryStorage() );
mArchive->clear();
emit labelingEngineSettingsChanged();
@ -776,9 +777,14 @@ bool QgsProject::read()
bool rc;
if ( QgsZipUtils::isZipFile( mFile.fileName() ) )
{
rc = unzip( mFile.fileName() );
}
else
{
mAuxiliaryStorage.reset( new QgsAuxiliaryStorage( *this ) );
rc = readProjectFile( mFile.fileName() );
}
mFile.setFileName( filename );
return rc;
@ -850,9 +856,11 @@ bool QgsProject::readProjectFile( const QString &filename )
projectFile.updateRevision( thisVersion );
}
// start new project, just keep the file name
// start new project, just keep the file name and auxiliary storage
QString fileName = mFile.fileName();
std::unique_ptr<QgsAuxiliaryStorage> aStorage = std::move( mAuxiliaryStorage );
clear();
mAuxiliaryStorage = std::move( aStorage );
mFile.setFileName( fileName );
// now get any properties
@ -1258,9 +1266,22 @@ bool QgsProject::write( const QString &filename )
bool QgsProject::write()
{
if ( QgsZipUtils::isZipFile( mFile.fileName() ) )
{
return zip( mFile.fileName() );
}
else
return writeProjectFile( mFile.fileName() );
{
// write project file even if the auxiliary storage is not correctly
// saved
const bool asOk = saveAuxiliaryStorage();
const bool writeOk = writeProjectFile( mFile.fileName() );
// errors raised during writing project file are more important
if ( !asOk && writeOk )
setError( tr( "Unable to save auxiliary storage" ) );
return asOk && writeOk;
}
}
bool QgsProject::writeProjectFile( const QString &filename )
@ -2132,6 +2153,18 @@ bool QgsProject::unzip( const QString &filename )
return false;
}
// load auxiliary storage
if ( !archive->auxiliaryStorageFile().isEmpty() )
{
// database file is already a copy as it's been unzipped. So we don't open
// auxiliary storage in copy mode in this case
mAuxiliaryStorage.reset( new QgsAuxiliaryStorage( archive->auxiliaryStorageFile(), false ) );
}
else
{
mAuxiliaryStorage.reset( new QgsAuxiliaryStorage( *this ) );
}
// read the project file
if ( ! readProjectFile( archive->projectFile() ) )
{
@ -2170,8 +2203,19 @@ bool QgsProject::zip( const QString &filename )
return false;
}
// save auxiliary storage
const QFileInfo info( qgsFile );
const QString asFileName = info.path() + QDir::separator() + info.completeBaseName() + "." + QgsAuxiliaryStorage::extension();
if ( ! saveAuxiliaryStorage( asFileName ) )
{
setError( tr( "Unable to save auxiliary storage" ) );
return false;
}
// create the archive
archive->addFile( qgsFile.fileName() );
archive->addFile( asFileName );
// zip
if ( !archive->zip( filename ) )
@ -2199,6 +2243,22 @@ QList<QgsMapLayer *> QgsProject::addMapLayers(
if ( addToLegend )
emit legendLayersAdded( myResultList );
}
if ( mAuxiliaryStorage )
{
for ( QgsMapLayer *mlayer : myResultList )
{
if ( mlayer->type() != QgsMapLayer::VectorLayer )
continue;
QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( mlayer );
if ( vl )
{
vl->loadAuxiliaryLayer( *mAuxiliaryStorage.get() );
}
}
}
return myResultList;
}
@ -2293,3 +2353,37 @@ void QgsProject::setTrustLayerMetadata( bool trust )
}
}
}
bool QgsProject::saveAuxiliaryStorage( const QString &filename )
{
for ( QgsMapLayer *l : mapLayers().values() )
{
if ( l->type() != QgsMapLayer::VectorLayer )
continue;
QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( l );
if ( vl && vl->auxiliaryLayer() )
{
vl->auxiliaryLayer()->save();
}
}
if ( !filename.isEmpty() )
{
return mAuxiliaryStorage->saveAs( filename );
}
else
{
return mAuxiliaryStorage->saveAs( *this );
}
}
const QgsAuxiliaryStorage *QgsProject::auxiliaryStorage() const
{
return mAuxiliaryStorage.get();
}
QgsAuxiliaryStorage *QgsProject::auxiliaryStorage()
{
return mAuxiliaryStorage.get();
}

View File

@ -61,6 +61,7 @@ class QgsAnnotationManager;
class QgsLayoutManager;
class QgsLayerTree;
class QgsLabelingEngineSettings;
class QgsAuxiliaryStorage;
/**
* \ingroup core
@ -809,6 +810,20 @@ class CORE_EXPORT QgsProject : public QObject, public QgsExpressionContextGenera
*/
bool trustLayerMetadata() const { return mTrustLayerMetadata; }
/**
* Returns the current const auxiliary storage.
*
* \since QGIS 3.0
*/
const QgsAuxiliaryStorage *auxiliaryStorage() const SIP_SKIP;
/**
* Returns the current auxiliary storage.
*
* \since QGIS 3.0
*/
QgsAuxiliaryStorage *auxiliaryStorage();
signals:
//! emitted when project is being read
void readProject( const QDomDocument & );
@ -1101,6 +1116,9 @@ class CORE_EXPORT QgsProject : public QObject, public QgsExpressionContextGenera
//! Zip project
bool zip( const QString &filename );
//! Save auxiliary storage to database
bool saveAuxiliaryStorage( const QString &filename = QString() );
std::unique_ptr< QgsMapLayerStore > mLayerStore;
QString mErrorMessage;
@ -1136,6 +1154,8 @@ class CORE_EXPORT QgsProject : public QObject, public QgsExpressionContextGenera
std::unique_ptr<QgsProjectArchive> mArchive;
std::unique_ptr<QgsAuxiliaryStorage> mAuxiliaryStorage;
QFile mFile; // current physical project file
mutable QgsProjectPropertyKey mProperties; // property hierarchy, TODO: this shouldn't be mutable
QString mTitle; // project title

View File

@ -21,10 +21,12 @@
#include "qgssymbollayerutils.h"
#include "qgscolorramp.h"
QgsPropertyDefinition::QgsPropertyDefinition( const QString &name, const QString &description, QgsPropertyDefinition::StandardPropertyTemplate type )
QgsPropertyDefinition::QgsPropertyDefinition( const QString &name, const QString &description, QgsPropertyDefinition::StandardPropertyTemplate type, const QString &origin, const QString &comment )
: mName( name )
, mDescription( description )
, mStandardType( type )
, mOrigin( origin )
, mComment( comment )
{
switch ( mStandardType )
{
@ -169,11 +171,13 @@ QgsPropertyDefinition::QgsPropertyDefinition( const QString &name, const QString
}
}
QgsPropertyDefinition::QgsPropertyDefinition( const QString &name, DataType dataType, const QString &description, const QString &helpText )
QgsPropertyDefinition::QgsPropertyDefinition( const QString &name, DataType dataType, const QString &description, const QString &helpText, const QString &origin, const QString &comment )
: mName( name )
, mDescription( description )
, mTypes( dataType )
, mHelpText( helpText )
, mOrigin( origin )
, mComment( comment )
{}
bool QgsPropertyDefinition::supportsAssistant() const
@ -622,7 +626,7 @@ bool QgsProperty::valueAsBool( const QgsExpressionContext &context, bool default
bool valOk = false;
QVariant val = value( context, defaultValue, &valOk );
if ( !valOk || !val.isValid() )
if ( !valOk || !val.isValid() || val.isNull() )
return defaultValue;
if ( ok )

View File

@ -115,8 +115,10 @@ class CORE_EXPORT QgsPropertyDefinition
* \param name is used internally and should be a unique, alphanumeric string.
* \param description can be any localised string describing what the property is used for.
* \param type one of the predefined standard property template
* \param origin The origin of the property
* \param comment A free comment for the property
*/
QgsPropertyDefinition( const QString &name, const QString &description, StandardPropertyTemplate type );
QgsPropertyDefinition( const QString &name, const QString &description, StandardPropertyTemplate type, const QString &origin = QString(), const QString &comment = QString() );
/**
* Constructor for custom QgsPropertyDefinitions.
@ -125,24 +127,60 @@ class CORE_EXPORT QgsPropertyDefinition
* \param description can be any localised string describing what the property is used for.
* \param helpText parameter should specify a descriptive string for users outlining the types
* of value acceptable by the property (eg 'dashed' or 'solid' for a line style property).
* \param origin The origin of the property
* \param comment A free comment for the property
*/
QgsPropertyDefinition( const QString &name, DataType dataType, const QString &description, const QString &helpText );
QgsPropertyDefinition( const QString &name, DataType dataType, const QString &description, const QString &helpText, const QString &origin = QString(), const QString &comment = QString() );
/**
* Returns the name of the property. This is used internally and should be a unique, alphanumeric string.
*/
QString name() const { return mName; }
/**
* Sets the name of the property
*/
void setName( const QString &name ) { mName = name; }
/**
* Returns the origin of the property. For example, a PAL property has an
* origin set to "labeling" while a diagram property has an origin set to
* "diagram".
*/
QString origin() const { return mOrigin; }
/**
* Sets the origin of the property. For example, a PAL property has an
* origin set to "labeling" while a diagram property has an origin set to
* "diagram".
*/
void setOrigin( const QString &origin ) { mOrigin = origin; }
/**
* Descriptive name of the property.
*/
QString description() const { return mDescription; }
/**
* Returns the comment of the property
*/
QString comment() const { return mComment; }
/**
* Sets comment of the property
*/
void setComment( const QString &comment ) { mComment = comment; }
/**
* Helper text for using the property, including a description of the valid values for the property.
*/
QString helpText() const { return mHelpText; }
/**
* Sets the data type
*/
void setDataType( DataType type ) { mTypes = type; }
/**
* Returns the allowable field/value data type for the property.
*/
@ -167,6 +205,8 @@ class CORE_EXPORT QgsPropertyDefinition
DataType mTypes = DataTypeString;
QString mHelpText;
StandardPropertyTemplate mStandardType = Custom;
QString mOrigin;
QString mComment;
static QString trString();
};

View File

@ -177,6 +177,20 @@ const QgsRuleBasedLabeling::Rule *QgsRuleBasedLabeling::Rule::findRuleByKey( con
return nullptr;
}
QgsRuleBasedLabeling::Rule *QgsRuleBasedLabeling::Rule::findRuleByKey( const QString &key )
{
if ( key == mRuleKey )
return this;
for ( Rule *rule : mChildren )
{
Rule *r = rule->findRuleByKey( key );
if ( r )
return r;
}
return nullptr;
}
QgsRuleBasedLabeling::Rule *QgsRuleBasedLabeling::Rule::clone() const
{
QgsPalLayerSettings *s = mSettings ? new QgsPalLayerSettings( *mSettings ) : nullptr;
@ -451,3 +465,13 @@ bool QgsRuleBasedLabeling::requiresAdvancedEffects() const
{
return mRootRule->requiresAdvancedEffects();
}
void QgsRuleBasedLabeling::setSettings( QgsPalLayerSettings *settings, const QString &providerId )
{
if ( settings )
{
Rule *rule = mRootRule->findRuleByKey( providerId );
if ( rule && rule->settings() )
return rule->setSettings( settings );
}
}

View File

@ -231,6 +231,17 @@ class CORE_EXPORT QgsRuleBasedLabeling : public QgsAbstractVectorLayerLabeling
//! Try to find a rule given its unique key
const QgsRuleBasedLabeling::Rule *findRuleByKey( const QString &key ) const;
/**
* Find a labeling rule thanks to its key.
*
* \param key The key of the rule to find
*
* \returns The rule or a nullptr if not found
*
* \since QGIS 3.0
*/
QgsRuleBasedLabeling::Rule *findRuleByKey( const QString &key ) SIP_SKIP;
//! clone this rule, return new instance
QgsRuleBasedLabeling::Rule *clone() const SIP_FACTORY;
@ -350,6 +361,16 @@ class CORE_EXPORT QgsRuleBasedLabeling : public QgsAbstractVectorLayerLabeling
virtual QgsVectorLayerLabelProvider *provider( QgsVectorLayer *layer ) const override SIP_SKIP;
virtual QStringList subProviders() const override;
virtual QgsPalLayerSettings settings( const QString &providerId = QString() ) const override;
/**
* Set pal settings for a specific provider (takes ownership).
*
* \param settings Pal layer settings
* \param providerId The id of the provider
*
* \since QGIS 3.0
*/
virtual void setSettings( QgsPalLayerSettings *settings SIP_TRANSFER, const QString &providerId = QString() ) override;
bool requiresAdvancedEffects() const override;
protected:

View File

@ -88,6 +88,7 @@
#include "qgsunittypes.h"
#include "qgstaskmanager.h"
#include "qgstransaction.h"
#include "qgsauxiliarystorage.h"
#include "diagram/qgsdiagram.h"
@ -139,6 +140,8 @@ QgsVectorLayer::QgsVectorLayer( const QString &vectorLayerPath,
bool readExtentFromXml )
: QgsMapLayer( VectorLayer, baseName, vectorLayerPath )
, mProviderKey( providerKey )
, mAuxiliaryLayer( nullptr )
, mAuxiliaryLayerKey( QString() )
, mReadExtentFromXml( readExtentFromXml )
{
mActions = new QgsActionManager( this );
@ -198,7 +201,10 @@ QgsVectorLayer *QgsVectorLayer::clone() const
QList<QgsVectorLayerJoinInfo> joins = vectorJoins();
Q_FOREACH ( const QgsVectorLayerJoinInfo &join, joins )
{
layer->addJoin( join );
// do not copy join information for auxiliary layer
if ( !auxiliaryLayer()
|| ( auxiliaryLayer() && auxiliaryLayer()->id() != join.joinLayerId() ) )
layer->addJoin( join );
}
layer->setProviderEncoding( dataProvider()->encoding() );
@ -261,6 +267,9 @@ QgsVectorLayer *QgsVectorLayer::clone() const
layer->setEditFormConfig( editFormConfig() );
if ( auxiliaryLayer() )
layer->setAuxiliaryLayer( auxiliaryLayer()->clone( layer ) );
return layer;
}
@ -1447,6 +1456,14 @@ bool QgsVectorLayer::readXml( const QDomNode &layer_node, const QgsReadWriteCont
}
}
// auxiliary layer
const QDomNode asNode = layer_node.namedItem( QStringLiteral( "auxiliaryLayer" ) );
const QDomElement asElem = asNode.toElement();
if ( !asElem.isNull() )
{
mAuxiliaryLayerKey = asElem.attribute( QStringLiteral( "key" ) );
}
return mValid; // should be true if read successfully
} // void QgsVectorLayer::readXml
@ -1667,6 +1684,15 @@ bool QgsVectorLayer::writeXml( QDomNode &layer_node,
writeStyleManager( layer_node, document );
// auxiliary layer
QDomElement asElem = document.createElement( QStringLiteral( "auxiliaryLayer" ) );
if ( mAuxiliaryLayer )
{
const QString pkField = mAuxiliaryLayer->joinInfo().targetFieldName();
asElem.setAttribute( QStringLiteral( "key" ), pkField );
}
layer_node.appendChild( asElem );
// renderer specific settings
QString errorMsg;
return writeSymbology( layer_node, document, errorMsg, context );
@ -2813,6 +2839,26 @@ bool QgsVectorLayer::isModified() const
return mEditBuffer && mEditBuffer->isModified();
}
bool QgsVectorLayer::isAuxiliaryField( int index, int &srcIndex ) const
{
bool auxiliaryField = false;
srcIndex = -1;
if ( !auxiliaryLayer() )
return auxiliaryField;
if ( index >= 0 && fields().fieldOrigin( index ) == QgsFields::OriginJoin )
{
const QgsVectorLayerJoinInfo *info = mJoinBuffer->joinForFieldIndex( index, fields(), srcIndex );
if ( info && info->joinLayerId() == auxiliaryLayer()->id() )
auxiliaryField = true;
}
return auxiliaryField;
}
void QgsVectorLayer::setRenderer( QgsFeatureRenderer *r )
{
if ( !isSpatial() )
@ -4223,6 +4269,66 @@ QString QgsVectorLayer::loadNamedStyle( const QString &theURI, bool &resultFlag
return loadNamedStyle( theURI, resultFlag, false );
}
bool QgsVectorLayer::loadAuxiliaryLayer( const QgsAuxiliaryStorage &storage, const QString &key )
{
bool rc = false;
QString joinKey = mAuxiliaryLayerKey;
if ( !key.isEmpty() )
joinKey = key;
if ( storage.isValid() && !joinKey.isEmpty() )
{
QgsAuxiliaryLayer *alayer = nullptr;
int idx = fields().lookupField( joinKey );
if ( idx >= 0 )
{
alayer = storage.createAuxiliaryLayer( fields().field( idx ), this );
if ( alayer )
{
setAuxiliaryLayer( alayer );
rc = true;
}
}
}
return rc;
}
void QgsVectorLayer::setAuxiliaryLayer( QgsAuxiliaryLayer *alayer )
{
mAuxiliaryLayerKey.clear();
if ( mAuxiliaryLayer )
removeJoin( mAuxiliaryLayer->id() );
if ( alayer )
{
addJoin( alayer->joinInfo() );
if ( !alayer->isEditable() )
alayer->startEditing();
mAuxiliaryLayerKey = alayer->joinInfo().targetFieldName();
}
mAuxiliaryLayer.reset( alayer );
updateFields();
}
const QgsAuxiliaryLayer *QgsVectorLayer::auxiliaryLayer() const
{
return mAuxiliaryLayer.get();
}
QgsAuxiliaryLayer *QgsVectorLayer::auxiliaryLayer()
{
return mAuxiliaryLayer.get();
}
QString QgsVectorLayer::loadNamedStyle( const QString &theURI, bool &resultFlag, bool loadFromLocalDB )
{
QgsDataSourceUri dsUri( theURI );

View File

@ -70,6 +70,8 @@ class QgsVectorLayerFeatureCounter;
class QgsAbstractVectorLayerLabeling;
class QgsPoint;
class QgsFeedback;
class QgsAuxiliaryStorage;
class QgsAuxiliaryLayer;
typedef QList<int> QgsAttributeList;
typedef QSet<int> QgsAttributeIds;
@ -783,6 +785,46 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer, public QgsExpressionConte
*/
virtual QString loadNamedStyle( const QString &theURI, bool &resultFlag SIP_OUT ) override;
/**
* Loads the auxiliary layer for this vector layer. If there's no
* corresponding table in the database, then nothing happens and false is
* returned. The key is optional because if this layer has been read from
* a XML document, then the key read in this document is used by default.
*
* \param storage The auxiliary storage where to look for the table
* \param key The key to use for joining.
*
* \returns true if the auxiliary layer is well loaded, false otherwise
*
* \since QGIS 3.0
*/
bool loadAuxiliaryLayer( const QgsAuxiliaryStorage &storage, const QString &key = QString() );
/**
* Sets the current auxiliary layer. The auxiliary layer is automatically
* put in editable mode and fields are updated. Moreover, a join is created
* between the current layer and the auxiliary layer. Ownership is
* transferred.
*
* \since QGIS 3.0
*
*/
void setAuxiliaryLayer( QgsAuxiliaryLayer *layer SIP_TRANSFER = nullptr );
/**
* Returns the current auxiliary layer.
*
* \since QGIS 3.0
*/
QgsAuxiliaryLayer *auxiliaryLayer();
/**
* Returns the current const auxiliary layer.
*
* \since QGIS 3.0
*/
const QgsAuxiliaryLayer *auxiliaryLayer() const SIP_SKIP;
/**
* Read the symbology for the current layer from the Dom node supplied.
* \param layerNode node that will contain the symbology definition for this layer.
@ -1093,11 +1135,17 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer, public QgsExpressionConte
*/
int addTopologicalPoints( const QgsPointXY &p );
/**
* Access to const labeling configuration. May be null if labeling is not used.
* \since QGIS 3.0
*/
const QgsAbstractVectorLayerLabeling *labeling() const SIP_SKIP { return mLabeling; }
/**
* Access to labeling configuration. May be null if labeling is not used.
* \since QGIS 3.0
*/
const QgsAbstractVectorLayerLabeling *labeling() const { return mLabeling; }
QgsAbstractVectorLayerLabeling *labeling() { return mLabeling; }
/**
* Set labeling configuration. Takes ownership of the object.
@ -1114,6 +1162,14 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer, public QgsExpressionConte
//! Returns true if the provider has been modified since the last commit
virtual bool isModified() const;
/**
* Returns true if the field comes from the auxiliary layer,
* false otherwise.
*
* \since QGIS 3.0
*/
bool isAuxiliaryField( int index, int &srcIndex ) const;
//! Synchronises with changes in the datasource
virtual void reload() override;
@ -1262,7 +1318,7 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer, public QgsExpressionConte
void setExcludeAttributesWfs( const QSet<QString> &att ) { mExcludeAttributesWFS = att; }
//! Delete an attribute field (but does not commit it)
bool deleteAttribute( int attr );
virtual bool deleteAttribute( int attr );
/**
* Deletes a list of attribute fields (but does not commit it)
@ -2145,6 +2201,12 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer, public QgsExpressionConte
mutable bool mValidExtent = false;
mutable bool mLazyExtent = true;
//! Auxiliary layer
std::unique_ptr<QgsAuxiliaryLayer> mAuxiliaryLayer;
//! Key to use to join auxiliary layer
QString mAuxiliaryLayerKey;
// Features in renderer classes counted
bool mSymbolFeatureCounted = false;

View File

@ -944,10 +944,12 @@ void QgsVectorLayerFeatureIterator::FetchJoinInfo::addJoinedAttributesDirect( Qg
// maybe user requested just a subset of layer's attributes
// so we do not have to cache everything
bool hasSubset = joinInfo->joinFieldNamesSubset();
QVector<int> subsetIndices;
if ( hasSubset )
subsetIndices = QgsVectorLayerJoinBuffer::joinSubsetIndices( joinLayer, *joinInfo->joinFieldNamesSubset() );
if ( joinInfo->hasSubset() )
{
const QStringList subsetNames = QgsVectorLayerJoinInfo::joinFieldNamesSubset( *joinInfo );
subsetIndices = QgsVectorLayerJoinBuffer::joinSubsetIndices( joinLayer, subsetNames );
}
// select (no geometry)
QgsFeatureRequest request;
@ -963,7 +965,7 @@ void QgsVectorLayerFeatureIterator::FetchJoinInfo::addJoinedAttributesDirect( Qg
{
int index = indexOffset;
QgsAttributes attr = fet.attributes();
if ( hasSubset )
if ( joinInfo->hasSubset() )
{
for ( int i = 0; i < subsetIndices.count(); ++i )
f.setAttribute( index++, attr.at( subsetIndices.at( i ) ) );

View File

@ -21,6 +21,7 @@
#include "qgslogger.h"
#include "qgsproject.h"
#include "qgsvectordataprovider.h"
#include "qgsauxiliarystorage.h"
#include <QDomElement>
@ -137,11 +138,11 @@ void QgsVectorLayerJoinBuffer::cacheJoinLayer( QgsVectorLayerJoinInfo &joinInfo
request.setFlags( QgsFeatureRequest::NoGeometry );
// maybe user requested just a subset of layer's attributes
// so we do not have to cache everything
bool hasSubset = joinInfo.joinFieldNamesSubset();
QVector<int> subsetIndices;
if ( hasSubset )
if ( joinInfo.hasSubset() )
{
subsetIndices = joinSubsetIndices( cacheLayer, *joinInfo.joinFieldNamesSubset() );
const QStringList subsetNames = QgsVectorLayerJoinInfo::joinFieldNamesSubset( joinInfo );
subsetIndices = joinSubsetIndices( cacheLayer, subsetNames );
// we need just subset of attributes - but make sure to include join field name
QgsAttributeList cacheLayerAttrs = subsetIndices.toList();
@ -156,7 +157,7 @@ void QgsVectorLayerJoinBuffer::cacheJoinLayer( QgsVectorLayerJoinInfo &joinInfo
{
QgsAttributes attrs = f.attributes();
QString key = attrs.at( joinFieldIndex ).toString();
if ( hasSubset )
if ( joinInfo.hasSubset() )
{
QgsAttributes subsetAttrs( subsetIndices.count() );
for ( int i = 0; i < subsetIndices.count(); ++i )
@ -213,11 +214,10 @@ void QgsVectorLayerJoinBuffer::updateFields( QgsFields &fields )
QString joinFieldName = joinIt->joinFieldName();
QSet<QString> subset;
bool hasSubset = false;
if ( joinIt->joinFieldNamesSubset() )
if ( joinIt->hasSubset() )
{
hasSubset = true;
subset = QSet<QString>::fromList( *joinIt->joinFieldNamesSubset() );
const QStringList subsetNames = QgsVectorLayerJoinInfo::joinFieldNamesSubset( *joinIt );
subset = QSet<QString>::fromList( subsetNames );
}
if ( joinIt->prefix().isNull() )
@ -232,12 +232,12 @@ void QgsVectorLayerJoinBuffer::updateFields( QgsFields &fields )
for ( int idx = 0; idx < joinFields.count(); ++idx )
{
// if using just a subset of fields, filter some of them out
if ( hasSubset && !subset.contains( joinFields.at( idx ).name() ) )
if ( joinIt->hasSubset() && !subset.contains( joinFields.at( idx ).name() ) )
continue;
//skip the join field to avoid double field names (fields often have the same name)
// when using subset of field, use all the selected fields
if ( hasSubset || joinFields.at( idx ).name() != joinFieldName )
if ( joinIt->hasSubset() || joinFields.at( idx ).name() != joinFieldName )
{
QgsField f = joinFields.at( idx );
f.setName( prefix + f.name() );
@ -266,6 +266,9 @@ void QgsVectorLayerJoinBuffer::writeXml( QDomNode &layer_node, QDomDocument &doc
QList< QgsVectorLayerJoinInfo >::const_iterator joinIt = mVectorJoins.constBegin();
for ( ; joinIt != mVectorJoins.constEnd(); ++joinIt )
{
if ( isAuxiliaryJoin( *joinIt ) )
continue;
QDomElement joinElem = document.createElement( QStringLiteral( "join" ) );
joinElem.setAttribute( QStringLiteral( "targetFieldName" ), joinIt->targetFieldName() );
@ -279,10 +282,12 @@ void QgsVectorLayerJoinBuffer::writeXml( QDomNode &layer_node, QDomDocument &doc
joinElem.setAttribute( QStringLiteral( "upsertOnEdit" ), joinIt->hasUpsertOnEdit() );
joinElem.setAttribute( QStringLiteral( "cascadedDelete" ), joinIt->hasCascadedDelete() );
if ( joinIt->joinFieldNamesSubset() )
if ( joinIt->hasSubset() )
{
QDomElement subsetElem = document.createElement( QStringLiteral( "joinFieldsSubset" ) );
Q_FOREACH ( const QString &fieldName, *joinIt->joinFieldNamesSubset() )
const QStringList subsetNames = QgsVectorLayerJoinInfo::joinFieldNamesSubset( *joinIt );
Q_FOREACH ( const QString &fieldName, subsetNames )
{
QDomElement fieldElem = document.createElement( QStringLiteral( "field" ) );
fieldElem.setAttribute( QStringLiteral( "name" ), fieldName );
@ -552,10 +557,10 @@ bool QgsVectorLayerJoinBuffer::addFeatures( QgsFeatureList &features, QgsFeature
if ( existingFeature.isValid() )
{
const QStringList *subsetFields = info.joinFieldNamesSubset();
if ( subsetFields )
if ( info.hasSubset() )
{
Q_FOREACH ( const QString &field, *subsetFields )
const QStringList subsetNames = QgsVectorLayerJoinInfo::joinFieldNamesSubset( info );
Q_FOREACH ( const QString &field, subsetNames )
{
QVariant newValue = joinFeature.attribute( field );
int fieldIndex = joinLayer->fields().indexOf( field );
@ -655,3 +660,13 @@ bool QgsVectorLayerJoinBuffer::deleteFeatures( const QgsFeatureIds &fids ) const
return true;
}
bool QgsVectorLayerJoinBuffer::isAuxiliaryJoin( const QgsVectorLayerJoinInfo &info ) const
{
const QgsAuxiliaryLayer *al = mLayer->auxiliaryLayer();
if ( al && al->id() == info.joinLayerId() )
return true;
else
return false;
}

View File

@ -121,6 +121,17 @@ class CORE_EXPORT QgsVectorLayerJoinBuffer : public QObject, public QgsFeatureSi
*/
QgsFeature targetedFeatureOf( const QgsVectorLayerJoinInfo *info, const QgsFeature &feature ) const;
/**
* Returns true if the join information is about auxiliary layer, false otherwise
*
* \param info The join information
*
* \returns true if the join information is about auxiliary layer, false otherwise
*
* \since QGIS 3.0
*/
bool isAuxiliaryJoin( const QgsVectorLayerJoinInfo &info ) const;
/**
* Create a copy of the join buffer
* \since QGIS 2.6

View File

@ -68,3 +68,50 @@ QgsFeature QgsVectorLayerJoinInfo::extractJoinedFeature( const QgsFeature &featu
return joinFeature;
}
QStringList QgsVectorLayerJoinInfo::joinFieldNamesSubset( const QgsVectorLayerJoinInfo &info, bool blacklisted )
{
QStringList fieldNames;
if ( blacklisted && !info.joinFieldNamesBlackList().isEmpty() )
{
QStringList *lst = info.joinFieldNamesSubset();
if ( lst )
{
for ( const QString &s : qgsAsConst( *lst ) )
{
if ( !info.joinFieldNamesBlackList().contains( s ) )
fieldNames.append( s );
}
}
else
{
for ( const QgsField &f : info.joinLayer()->fields() )
{
if ( !info.joinFieldNamesBlackList().contains( f.name() )
&& f.name() != info.joinFieldName() )
fieldNames.append( f.name() );
}
}
}
else
{
QStringList *lst = info.joinFieldNamesSubset();
if ( lst )
{
fieldNames = *lst;
}
}
return fieldNames;
}
bool QgsVectorLayerJoinInfo::hasSubset( bool blacklisted ) const
{
bool subset = joinFieldNamesSubset();
if ( blacklisted )
subset |= !joinFieldNamesBlackList().isEmpty();
return subset;
}

View File

@ -141,6 +141,36 @@ class CORE_EXPORT QgsVectorLayerJoinInfo
*/
QgsFeature extractJoinedFeature( const QgsFeature &feature ) const;
/**
* Sets a list of fields to ignore whatever happens.
*
* \since QGIS 3.0
*/
void setJoinFieldNamesBlackList( const QStringList &blackList ) { mBlackList = blackList; }
/**
* Returns the list of fields to ignore.
*
* \since QGIS 3.0
*/
QStringList joinFieldNamesBlackList() const { return mBlackList; }
/**
* Returns true if blacklisted fields is not empty or if a subset of names
* has been set.
*
* \since QGIS 3.0
*/
bool hasSubset( bool blacklisted = true ) const;
/**
* Returns the list of field names to use for joining considering
* blacklisted fields and subset.
*
* \since QGIS 3.0
*/
static QStringList joinFieldNamesSubset( const QgsVectorLayerJoinInfo &info, bool blacklisted = true );
bool operator==( const QgsVectorLayerJoinInfo &other ) const
{
return mTargetFieldName == other.mTargetFieldName &&
@ -197,6 +227,8 @@ class CORE_EXPORT QgsVectorLayerJoinInfo
bool mCascadedDelete = false;
QStringList mBlackList;
//! Cache for joined attributes to provide fast lookup (size is 0 if no memory caching)
QHash< QString, QgsAttributes> cachedAttributes;

View File

@ -546,3 +546,13 @@ void QgsVectorLayerSimpleLabeling::toSld( QDomNode &parent, const QgsStringMap &
}
void QgsVectorLayerSimpleLabeling::setSettings( QgsPalLayerSettings *settings, const QString &providerId )
{
Q_UNUSED( providerId );
if ( mSettings.get() == settings )
return;
mSettings.reset( settings );
}

View File

@ -68,6 +68,16 @@ class CORE_EXPORT QgsAbstractVectorLayerLabeling
*/
virtual QgsPalLayerSettings settings( const QString &providerId = QString() ) const = 0;
/**
* Set pal settings for a specific provider (takes ownership).
*
* \param settings Pal layer settings
* \param providerId The id of the provider
*
* \since QGIS 3.0
*/
virtual void setSettings( QgsPalLayerSettings *settings SIP_TRANSFER, const QString &providerId = QString() ) = 0;
/**
* Returns true if drawing labels requires advanced effects like composition
* modes, which could prevent it being used as an isolated cached image
@ -121,6 +131,17 @@ class CORE_EXPORT QgsVectorLayerSimpleLabeling : public QgsAbstractVectorLayerLa
virtual QgsVectorLayerLabelProvider *provider( QgsVectorLayer *layer ) const override SIP_SKIP;
virtual QDomElement save( QDomDocument &doc, const QgsReadWriteContext &context ) const override;
virtual QgsPalLayerSettings settings( const QString &providerId = QString() ) const override;
/**
* Set pal settings (takes ownership).
*
* \param settings Pal layer settings
* \param providerId Unused parameter
*
* \since QGIS 3.0
*/
virtual void setSettings( QgsPalLayerSettings *settings SIP_TRANSFER, const QString &providerId = QString() ) override;
bool requiresAdvancedEffects() const override;
virtual void toSld( QDomNode &parent, const QgsStringMap &props ) const override;

View File

@ -38,58 +38,60 @@ void QgsSymbolLayer::initPropertyDefinitions()
if ( !sPropertyDefinitions.isEmpty() )
return;
QString origin = QStringLiteral( "symbol" );
sPropertyDefinitions = QgsPropertiesDefinition
{
{ QgsSymbolLayer::PropertySize, QgsPropertyDefinition( "size", QObject::tr( "Symbol size" ), QgsPropertyDefinition::Size ) },
{ QgsSymbolLayer::PropertyAngle, QgsPropertyDefinition( "angle", QObject::tr( "Rotation angle" ), QgsPropertyDefinition::Rotation ) },
{ QgsSymbolLayer::PropertyName, QgsPropertyDefinition( "name", QObject::tr( "Symbol name" ), QgsPropertyDefinition::String ) },
{ QgsSymbolLayer::PropertyFillColor, QgsPropertyDefinition( "fillColor", QObject::tr( "Symbol fill color" ), QgsPropertyDefinition::ColorWithAlpha ) },
{ QgsSymbolLayer::PropertyStrokeColor, QgsPropertyDefinition( "outlineColor", QObject::tr( "Symbol stroke color" ), QgsPropertyDefinition::ColorWithAlpha ) },
{ QgsSymbolLayer::PropertyStrokeWidth, QgsPropertyDefinition( "outlineWidth", QObject::tr( "Symbol stroke width" ), QgsPropertyDefinition::StrokeWidth ) },
{ QgsSymbolLayer::PropertyStrokeStyle, QgsPropertyDefinition( "outlineStyle", QObject::tr( "Symbol stroke style" ), QgsPropertyDefinition::LineStyle )},
{ QgsSymbolLayer::PropertyOffset, QgsPropertyDefinition( "offset", QObject::tr( "Symbol offset" ), QgsPropertyDefinition::Offset )},
{ QgsSymbolLayer::PropertyCharacter, QgsPropertyDefinition( "char", QObject::tr( "Marker character(s)" ), QgsPropertyDefinition::String )},
{ QgsSymbolLayer::PropertyWidth, QgsPropertyDefinition( "width", QObject::tr( "Symbol width" ), QgsPropertyDefinition::DoublePositive )},
{ QgsSymbolLayer::PropertyHeight, QgsPropertyDefinition( "height", QObject::tr( "Symbol height" ), QgsPropertyDefinition::DoublePositive )},
{ QgsSymbolLayer::PropertyPreserveAspectRatio, QgsPropertyDefinition( "preserveAspectRatio", QObject::tr( "Preserve aspect ratio between width and height" ), QgsPropertyDefinition::Boolean )},
{ QgsSymbolLayer::PropertyFillStyle, QgsPropertyDefinition( "fillStyle", QObject::tr( "Symbol fill style" ), QgsPropertyDefinition::FillStyle )},
{ QgsSymbolLayer::PropertyJoinStyle, QgsPropertyDefinition( "joinStyle", QObject::tr( "Outline join style" ), QgsPropertyDefinition::PenJoinStyle )},
{ QgsSymbolLayer::PropertySecondaryColor, QgsPropertyDefinition( "color2", QObject::tr( "Secondary fill color" ), QgsPropertyDefinition::ColorWithAlpha )},
{ QgsSymbolLayer::PropertyLineAngle, QgsPropertyDefinition( "lineAngle", QObject::tr( "Angle for line fills" ), QgsPropertyDefinition::Rotation )},
{ QgsSymbolLayer::PropertyGradientType, QgsPropertyDefinition( "gradientType", QgsPropertyDefinition::DataTypeString, QObject::tr( "Gradient type" ), QObject::tr( "string " ) + QLatin1String( "[<b>linear</b>|<b>radial</b>|<b>conical</b>]" ) )},
{ QgsSymbolLayer::PropertyCoordinateMode, QgsPropertyDefinition( "gradientMode", QgsPropertyDefinition::DataTypeString, QObject::tr( "Gradient mode" ), QObject::tr( "string " ) + QLatin1String( "[<b>feature</b>|<b>viewport</b>]" ) )},
{ QgsSymbolLayer::PropertyGradientSpread, QgsPropertyDefinition( "gradientSpread", QgsPropertyDefinition::DataTypeString, QObject::tr( "Gradient spread" ), QObject::tr( "string " ) + QLatin1String( "[<b>pad</b>|<b>repeat</b>|<b>reflect</b>]" ) )},
{ QgsSymbolLayer::PropertyGradientReference1X, QgsPropertyDefinition( "gradientRef1X", QObject::tr( "Reference point 1 (X)" ), QgsPropertyDefinition::Double0To1 )},
{ QgsSymbolLayer::PropertyGradientReference1Y, QgsPropertyDefinition( "gradientRef1Y", QObject::tr( "Reference point 1 (Y)" ), QgsPropertyDefinition::Double0To1 )},
{ QgsSymbolLayer::PropertyGradientReference2X, QgsPropertyDefinition( "gradientRef2X", QObject::tr( "Reference point 2 (X)" ), QgsPropertyDefinition::Double0To1 )},
{ QgsSymbolLayer::PropertyGradientReference2Y, QgsPropertyDefinition( "gradientRef2Y", QObject::tr( "Reference point 2 (Y)" ), QgsPropertyDefinition::Double0To1 )},
{ QgsSymbolLayer::PropertyGradientReference1IsCentroid, QgsPropertyDefinition( "gradientRef1Centroid", QObject::tr( "Reference point 1 follows feature centroid" ), QgsPropertyDefinition::Boolean )},
{ QgsSymbolLayer::PropertyGradientReference2IsCentroid, QgsPropertyDefinition( "gradientRef2Centroid", QObject::tr( "Reference point 2 follows feature centroid" ), QgsPropertyDefinition::Boolean )},
{ QgsSymbolLayer::PropertyBlurRadius, QgsPropertyDefinition( "blurRadius", QgsPropertyDefinition::DataTypeNumeric, QObject::tr( "Blur radius" ), QObject::tr( "Integer between 0 and 18" ) )},
{ QgsSymbolLayer::PropertyLineDistance, QgsPropertyDefinition( "lineDistance", QObject::tr( "Distance between lines" ), QgsPropertyDefinition::DoublePositive )},
{ QgsSymbolLayer::PropertyShapeburstUseWholeShape, QgsPropertyDefinition( "shapeburstWholeShape", QObject::tr( "Shade whole shape" ), QgsPropertyDefinition::Boolean )},
{ QgsSymbolLayer::PropertyShapeburstMaxDistance, QgsPropertyDefinition( "shapeburstMaxDist", QObject::tr( "Maximum distance for shapeburst fill" ), QgsPropertyDefinition::DoublePositive )},
{ QgsSymbolLayer::PropertyShapeburstIgnoreRings, QgsPropertyDefinition( "shapeburstIgnoreRings", QObject::tr( "Ignore rings in feature" ), QgsPropertyDefinition::Boolean )},
{ QgsSymbolLayer::PropertyFile, QgsPropertyDefinition( "file", QObject::tr( "Symbol file path" ), QgsPropertyDefinition::String )},
{ QgsSymbolLayer::PropertyDistanceX, QgsPropertyDefinition( "distanceX", QObject::tr( "Horizontal distance between markers" ), QgsPropertyDefinition::DoublePositive )},
{ QgsSymbolLayer::PropertyDistanceY, QgsPropertyDefinition( "distanceY", QObject::tr( "Vertical distance between markers" ), QgsPropertyDefinition::DoublePositive )},
{ QgsSymbolLayer::PropertyDisplacementX, QgsPropertyDefinition( "displacementX", QObject::tr( "Horizontal displacement between rows" ), QgsPropertyDefinition::DoublePositive )},
{ QgsSymbolLayer::PropertyDisplacementY, QgsPropertyDefinition( "displacementY", QObject::tr( "Vertical displacement between columns" ), QgsPropertyDefinition::DoublePositive )},
{ QgsSymbolLayer::PropertyOpacity, QgsPropertyDefinition( "alpha", QObject::tr( "Opacity" ), QgsPropertyDefinition::Opacity )},
{ QgsSymbolLayer::PropertyCustomDash, QgsPropertyDefinition( "customDash", QgsPropertyDefinition::DataTypeString, QObject::tr( "Custom dash pattern" ), QObject::tr( "[<b><dash>;<space></b>] e.g. '8;2;1;2'" ) )},
{ QgsSymbolLayer::PropertyCapStyle, QgsPropertyDefinition( "capStyle", QObject::tr( "Line cap style" ), QgsPropertyDefinition::CapStyle )},
{ QgsSymbolLayer::PropertyPlacement, QgsPropertyDefinition( "placement", QgsPropertyDefinition::DataTypeString, QObject::tr( "Marker placement" ), QObject::tr( "string " ) + "[<b>interval</b>|<b>vertex</b>|<b>lastvertex</b>|<b>firstvertex</b>|<b>centerpoint</b>|<b>curvepoint</b>]" )},
{ QgsSymbolLayer::PropertyInterval, QgsPropertyDefinition( "interval", QObject::tr( "Marker interval" ), QgsPropertyDefinition::DoublePositive )},
{ QgsSymbolLayer::PropertyOffsetAlongLine, QgsPropertyDefinition( "offsetAlongLine", QObject::tr( "Offset along line" ), QgsPropertyDefinition::DoublePositive )},
{ QgsSymbolLayer::PropertyHorizontalAnchor, QgsPropertyDefinition( "hAnchor", QObject::tr( "Horizontal anchor point" ), QgsPropertyDefinition::HorizontalAnchor )},
{ QgsSymbolLayer::PropertyVerticalAnchor, QgsPropertyDefinition( "vAnchor", QObject::tr( "Vertical anchor point" ), QgsPropertyDefinition::VerticalAnchor )},
{ QgsSymbolLayer::PropertyLayerEnabled, QgsPropertyDefinition( "enabled", QObject::tr( "Layer enabled" ), QgsPropertyDefinition::Boolean )},
{ QgsSymbolLayer::PropertyArrowWidth, QgsPropertyDefinition( "arrowWidth", QObject::tr( "Arrow line width" ), QgsPropertyDefinition::StrokeWidth )},
{ QgsSymbolLayer::PropertyArrowStartWidth, QgsPropertyDefinition( "arrowStartWidth", QObject::tr( "Arrow line start width" ), QgsPropertyDefinition::StrokeWidth )},
{ QgsSymbolLayer::PropertyArrowHeadLength, QgsPropertyDefinition( "arrowHeadLength", QObject::tr( "Arrow head length" ), QgsPropertyDefinition::DoublePositive )},
{ QgsSymbolLayer::PropertyArrowHeadThickness, QgsPropertyDefinition( "arrowHeadThickness", QObject::tr( "Arrow head thickness" ), QgsPropertyDefinition::DoublePositive )},
{ QgsSymbolLayer::PropertyArrowHeadType, QgsPropertyDefinition( "arrowHeadType", QObject::tr( "Arrow head type" ), QgsPropertyDefinition::IntegerPositive )},
{ QgsSymbolLayer::PropertyArrowType, QgsPropertyDefinition( "arrowType", QObject::tr( "Arrow type" ), QgsPropertyDefinition::IntegerPositive )},
{ QgsSymbolLayer::PropertySize, QgsPropertyDefinition( "size", QObject::tr( "Symbol size" ), QgsPropertyDefinition::Size, origin ) },
{ QgsSymbolLayer::PropertyAngle, QgsPropertyDefinition( "angle", QObject::tr( "Rotation angle" ), QgsPropertyDefinition::Rotation, origin ) },
{ QgsSymbolLayer::PropertyName, QgsPropertyDefinition( "name", QObject::tr( "Symbol name" ), QgsPropertyDefinition::String, origin ) },
{ QgsSymbolLayer::PropertyFillColor, QgsPropertyDefinition( "fillColor", QObject::tr( "Symbol fill color" ), QgsPropertyDefinition::ColorWithAlpha, origin ) },
{ QgsSymbolLayer::PropertyStrokeColor, QgsPropertyDefinition( "outlineColor", QObject::tr( "Symbol stroke color" ), QgsPropertyDefinition::ColorWithAlpha, origin ) },
{ QgsSymbolLayer::PropertyStrokeWidth, QgsPropertyDefinition( "outlineWidth", QObject::tr( "Symbol stroke width" ), QgsPropertyDefinition::StrokeWidth, origin ) },
{ QgsSymbolLayer::PropertyStrokeStyle, QgsPropertyDefinition( "outlineStyle", QObject::tr( "Symbol stroke style" ), QgsPropertyDefinition::LineStyle, origin )},
{ QgsSymbolLayer::PropertyOffset, QgsPropertyDefinition( "offset", QObject::tr( "Symbol offset" ), QgsPropertyDefinition::Offset, origin )},
{ QgsSymbolLayer::PropertyCharacter, QgsPropertyDefinition( "char", QObject::tr( "Marker character(s)" ), QgsPropertyDefinition::String, origin )},
{ QgsSymbolLayer::PropertyWidth, QgsPropertyDefinition( "width", QObject::tr( "Symbol width" ), QgsPropertyDefinition::DoublePositive, origin )},
{ QgsSymbolLayer::PropertyHeight, QgsPropertyDefinition( "height", QObject::tr( "Symbol height" ), QgsPropertyDefinition::DoublePositive, origin )},
{ QgsSymbolLayer::PropertyPreserveAspectRatio, QgsPropertyDefinition( "preserveAspectRatio", QObject::tr( "Preserve aspect ratio between width and height" ), QgsPropertyDefinition::Boolean, origin )},
{ QgsSymbolLayer::PropertyFillStyle, QgsPropertyDefinition( "fillStyle", QObject::tr( "Symbol fill style" ), QgsPropertyDefinition::FillStyle, origin )},
{ QgsSymbolLayer::PropertyJoinStyle, QgsPropertyDefinition( "joinStyle", QObject::tr( "Outline join style" ), QgsPropertyDefinition::PenJoinStyle, origin )},
{ QgsSymbolLayer::PropertySecondaryColor, QgsPropertyDefinition( "color2", QObject::tr( "Secondary fill color" ), QgsPropertyDefinition::ColorWithAlpha, origin )},
{ QgsSymbolLayer::PropertyLineAngle, QgsPropertyDefinition( "lineAngle", QObject::tr( "Angle for line fills" ), QgsPropertyDefinition::Rotation, origin )},
{ QgsSymbolLayer::PropertyGradientType, QgsPropertyDefinition( "gradientType", QgsPropertyDefinition::DataTypeString, QObject::tr( "Gradient type" ), QObject::tr( "string " ) + QLatin1String( "[<b>linear</b>|<b>radial</b>|<b>conical</b>]" ), origin )},
{ QgsSymbolLayer::PropertyCoordinateMode, QgsPropertyDefinition( "gradientMode", QgsPropertyDefinition::DataTypeString, QObject::tr( "Gradient mode" ), QObject::tr( "string " ) + QLatin1String( "[<b>feature</b>|<b>viewport</b>]" ), origin )},
{ QgsSymbolLayer::PropertyGradientSpread, QgsPropertyDefinition( "gradientSpread", QgsPropertyDefinition::DataTypeString, QObject::tr( "Gradient spread" ), QObject::tr( "string " ) + QLatin1String( "[<b>pad</b>|<b>repeat</b>|<b>reflect</b>]" ), origin )},
{ QgsSymbolLayer::PropertyGradientReference1X, QgsPropertyDefinition( "gradientRef1X", QObject::tr( "Reference point 1 (X)" ), QgsPropertyDefinition::Double0To1, origin )},
{ QgsSymbolLayer::PropertyGradientReference1Y, QgsPropertyDefinition( "gradientRef1Y", QObject::tr( "Reference point 1 (Y)" ), QgsPropertyDefinition::Double0To1, origin )},
{ QgsSymbolLayer::PropertyGradientReference2X, QgsPropertyDefinition( "gradientRef2X", QObject::tr( "Reference point 2 (X)" ), QgsPropertyDefinition::Double0To1, origin )},
{ QgsSymbolLayer::PropertyGradientReference2Y, QgsPropertyDefinition( "gradientRef2Y", QObject::tr( "Reference point 2 (Y)" ), QgsPropertyDefinition::Double0To1, origin )},
{ QgsSymbolLayer::PropertyGradientReference1IsCentroid, QgsPropertyDefinition( "gradientRef1Centroid", QObject::tr( "Reference point 1 follows feature centroid" ), QgsPropertyDefinition::Boolean, origin )},
{ QgsSymbolLayer::PropertyGradientReference2IsCentroid, QgsPropertyDefinition( "gradientRef2Centroid", QObject::tr( "Reference point 2 follows feature centroid" ), QgsPropertyDefinition::Boolean, origin )},
{ QgsSymbolLayer::PropertyBlurRadius, QgsPropertyDefinition( "blurRadius", QgsPropertyDefinition::DataTypeNumeric, QObject::tr( "Blur radius" ), QObject::tr( "Integer between 0 and 18" ), origin )},
{ QgsSymbolLayer::PropertyLineDistance, QgsPropertyDefinition( "lineDistance", QObject::tr( "Distance between lines" ), QgsPropertyDefinition::DoublePositive, origin )},
{ QgsSymbolLayer::PropertyShapeburstUseWholeShape, QgsPropertyDefinition( "shapeburstWholeShape", QObject::tr( "Shade whole shape" ), QgsPropertyDefinition::Boolean, origin )},
{ QgsSymbolLayer::PropertyShapeburstMaxDistance, QgsPropertyDefinition( "shapeburstMaxDist", QObject::tr( "Maximum distance for shapeburst fill" ), QgsPropertyDefinition::DoublePositive, origin )},
{ QgsSymbolLayer::PropertyShapeburstIgnoreRings, QgsPropertyDefinition( "shapeburstIgnoreRings", QObject::tr( "Ignore rings in feature" ), QgsPropertyDefinition::Boolean, origin )},
{ QgsSymbolLayer::PropertyFile, QgsPropertyDefinition( "file", QObject::tr( "Symbol file path" ), QgsPropertyDefinition::String, origin )},
{ QgsSymbolLayer::PropertyDistanceX, QgsPropertyDefinition( "distanceX", QObject::tr( "Horizontal distance between markers" ), QgsPropertyDefinition::DoublePositive, origin )},
{ QgsSymbolLayer::PropertyDistanceY, QgsPropertyDefinition( "distanceY", QObject::tr( "Vertical distance between markers" ), QgsPropertyDefinition::DoublePositive, origin )},
{ QgsSymbolLayer::PropertyDisplacementX, QgsPropertyDefinition( "displacementX", QObject::tr( "Horizontal displacement between rows" ), QgsPropertyDefinition::DoublePositive, origin )},
{ QgsSymbolLayer::PropertyDisplacementY, QgsPropertyDefinition( "displacementY", QObject::tr( "Vertical displacement between columns" ), QgsPropertyDefinition::DoublePositive, origin )},
{ QgsSymbolLayer::PropertyOpacity, QgsPropertyDefinition( "alpha", QObject::tr( "Opacity" ), QgsPropertyDefinition::Opacity, origin )},
{ QgsSymbolLayer::PropertyCustomDash, QgsPropertyDefinition( "customDash", QgsPropertyDefinition::DataTypeString, QObject::tr( "Custom dash pattern" ), QObject::tr( "[<b><dash>;<space></b>] e.g. '8;2;1;2'" ), origin )},
{ QgsSymbolLayer::PropertyCapStyle, QgsPropertyDefinition( "capStyle", QObject::tr( "Line cap style" ), QgsPropertyDefinition::CapStyle, origin )},
{ QgsSymbolLayer::PropertyPlacement, QgsPropertyDefinition( "placement", QgsPropertyDefinition::DataTypeString, QObject::tr( "Marker placement" ), QObject::tr( "string " ) + "[<b>interval</b>|<b>vertex</b>|<b>lastvertex</b>|<b>firstvertex</b>|<b>centerpoint</b>|<b>curvepoint</b>]", origin )},
{ QgsSymbolLayer::PropertyInterval, QgsPropertyDefinition( "interval", QObject::tr( "Marker interval" ), QgsPropertyDefinition::DoublePositive, origin )},
{ QgsSymbolLayer::PropertyOffsetAlongLine, QgsPropertyDefinition( "offsetAlongLine", QObject::tr( "Offset along line" ), QgsPropertyDefinition::DoublePositive, origin )},
{ QgsSymbolLayer::PropertyHorizontalAnchor, QgsPropertyDefinition( "hAnchor", QObject::tr( "Horizontal anchor point" ), QgsPropertyDefinition::HorizontalAnchor, origin )},
{ QgsSymbolLayer::PropertyVerticalAnchor, QgsPropertyDefinition( "vAnchor", QObject::tr( "Vertical anchor point" ), QgsPropertyDefinition::VerticalAnchor, origin )},
{ QgsSymbolLayer::PropertyLayerEnabled, QgsPropertyDefinition( "enabled", QObject::tr( "Layer enabled" ), QgsPropertyDefinition::Boolean, origin )},
{ QgsSymbolLayer::PropertyArrowWidth, QgsPropertyDefinition( "arrowWidth", QObject::tr( "Arrow line width" ), QgsPropertyDefinition::StrokeWidth, origin )},
{ QgsSymbolLayer::PropertyArrowStartWidth, QgsPropertyDefinition( "arrowStartWidth", QObject::tr( "Arrow line start width" ), QgsPropertyDefinition::StrokeWidth, origin )},
{ QgsSymbolLayer::PropertyArrowHeadLength, QgsPropertyDefinition( "arrowHeadLength", QObject::tr( "Arrow head length" ), QgsPropertyDefinition::DoublePositive, origin )},
{ QgsSymbolLayer::PropertyArrowHeadThickness, QgsPropertyDefinition( "arrowHeadThickness", QObject::tr( "Arrow head thickness" ), QgsPropertyDefinition::DoublePositive, origin )},
{ QgsSymbolLayer::PropertyArrowHeadType, QgsPropertyDefinition( "arrowHeadType", QObject::tr( "Arrow head type" ), QgsPropertyDefinition::IntegerPositive, origin )},
{ QgsSymbolLayer::PropertyArrowType, QgsPropertyDefinition( "arrowType", QObject::tr( "Arrow type" ), QgsPropertyDefinition::IntegerPositive, origin )},
};
}

View File

@ -49,7 +49,7 @@ class CORE_EXPORT QgsSymbolLayerAbstractMetadata
//! Create a symbol layer of this type given the map of properties.
virtual QgsSymbolLayer *createSymbolLayer( const QgsStringMap &map ) = 0 SIP_FACTORY;
//! Create widget for symbol layer of this type. Can return NULL if there's no GUI
virtual QgsSymbolLayerWidget *createSymbolLayerWidget( const QgsVectorLayer * ) SIP_FACTORY { return nullptr; }
virtual QgsSymbolLayerWidget *createSymbolLayerWidget( QgsVectorLayer * ) SIP_FACTORY { return nullptr; }
//! Create a symbol layer of this type given the map of properties.
virtual QgsSymbolLayer *createSymbolLayerFromSld( QDomElement & ) SIP_FACTORY { return nullptr; }
@ -75,7 +75,7 @@ class CORE_EXPORT QgsSymbolLayerAbstractMetadata
};
typedef QgsSymbolLayer *( *QgsSymbolLayerCreateFunc )( const QgsStringMap & ) SIP_SKIP;
typedef QgsSymbolLayerWidget *( *QgsSymbolLayerWidgetFunc )( const QgsVectorLayer * ) SIP_SKIP;
typedef QgsSymbolLayerWidget *( *QgsSymbolLayerWidgetFunc )( QgsVectorLayer * ) SIP_SKIP;
typedef QgsSymbolLayer *( *QgsSymbolLayerCreateFromSldFunc )( QDomElement & ) SIP_SKIP;
typedef void ( *QgsSymbolLayerPathResolverFunc )( QgsStringMap &, const QgsPathResolver &, bool ) SIP_SKIP;
@ -113,7 +113,7 @@ class CORE_EXPORT QgsSymbolLayerMetadata : public QgsSymbolLayerAbstractMetadata
void setWidgetFunction( QgsSymbolLayerWidgetFunc f ) { mWidgetFunc = f; } SIP_SKIP
virtual QgsSymbolLayer *createSymbolLayer( const QgsStringMap &map ) override SIP_FACTORY { return mCreateFunc ? mCreateFunc( map ) : nullptr; }
virtual QgsSymbolLayerWidget *createSymbolLayerWidget( const QgsVectorLayer *vl ) override SIP_FACTORY { return mWidgetFunc ? mWidgetFunc( vl ) : nullptr; }
virtual QgsSymbolLayerWidget *createSymbolLayerWidget( QgsVectorLayer *vl ) override SIP_FACTORY { return mWidgetFunc ? mWidgetFunc( vl ) : nullptr; }
virtual QgsSymbolLayer *createSymbolLayerFromSld( QDomElement &elem ) override SIP_FACTORY { return mCreateFromSldFunc ? mCreateFromSldFunc( elem ) : nullptr; }
virtual void resolvePaths( QgsStringMap &properties, const QgsPathResolver &pathResolver, bool saving ) override
{

View File

@ -296,6 +296,8 @@ SET(QGIS_GUI_SRCS
qgsmessagelogviewer.cpp
qgsmessageviewer.cpp
qgsmetadatawidget.cpp
qgsnewauxiliarylayerdialog.cpp
qgsnewauxiliaryfielddialog.cpp
qgsnewhttpconnection.cpp
qgsnewmemorylayerdialog.cpp
qgsnewnamedialog.cpp
@ -456,6 +458,8 @@ SET(QGIS_GUI_MOC_HDRS
qgsmessagelogviewer.h
qgsmessageviewer.h
qgsmetadatawidget.h
qgsnewauxiliarylayerdialog.h
qgsnewauxiliaryfielddialog.h
qgsnewhttpconnection.h
qgsnewmemorylayerdialog.h
qgsnewnamedialog.h

View File

@ -1996,10 +1996,11 @@ void QgsAttributeForm::updateJoinedFields( const QgsEditorWidgetWrapper &eww )
mJoinedFeatures[info] = joinFeature;
QStringList *subsetFields = info->joinFieldNamesSubset();
if ( subsetFields )
if ( info->hasSubset() )
{
Q_FOREACH ( const QString &field, *subsetFields )
const QStringList subsetNames = QgsVectorLayerJoinInfo::joinFieldNamesSubset( *info );
Q_FOREACH ( const QString &field, subsetNames )
{
QString prefixedName = info->prefixedFieldName( field );
QVariant val;

View File

@ -0,0 +1,103 @@
/***************************************************************************
qgsnewauxiliaryfielddialog.cpp - description
-------------------
begin : Sept 05, 2017
copyright : (C) 2017 by Paul Blottiere
email : paul.blottiere@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 "qgsnewauxiliaryfielddialog.h"
#include "qgsauxiliarystorage.h"
#include <QMessageBox>
QgsNewAuxiliaryFieldDialog::QgsNewAuxiliaryFieldDialog( const QgsPropertyDefinition &def, QgsVectorLayer *layer, bool nameOnly, QWidget *parent )
: QDialog( parent )
, mLayer( layer )
, mNameOnly( nameOnly )
, mPropertyDefinition( def )
{
setupUi( this );
mType->addItem( tr( "String" ) );
mType->addItem( tr( "Real" ) );
mType->addItem( tr( "Integer" ) );
switch ( def.dataType() )
{
case QgsPropertyDefinition::DataTypeString:
mType->setCurrentIndex( mType->findText( tr( "String" ) ) );
break;
case QgsPropertyDefinition::DataTypeNumeric:
mType->setCurrentIndex( mType->findText( tr( "Real" ) ) );
break;
case QgsPropertyDefinition::DataTypeBoolean:
mType->setCurrentIndex( mType->findText( tr( "Integer" ) ) );
break;
}
if ( mNameOnly )
mType->setEnabled( false );
else
mType->setEnabled( true );
}
void QgsNewAuxiliaryFieldDialog::accept()
{
QgsPropertyDefinition def = mPropertyDefinition;
def.setComment( mName->text() );
if ( !mNameOnly )
{
if ( mType->currentText().compare( tr( "String" ) ) == 0 )
{
def.setDataType( QgsPropertyDefinition::DataTypeString );
}
else if ( mType->currentText().compare( tr( "Real" ) ) == 0 )
{
def.setDataType( QgsPropertyDefinition::DataTypeNumeric );
}
else
{
def.setDataType( QgsPropertyDefinition::DataTypeBoolean );
}
def.setOrigin( "user" );
def.setName( "custom" );
}
QString fieldName = QgsAuxiliaryLayer::nameFromProperty( def, true );
const int idx = mLayer->fields().lookupField( fieldName );
if ( idx >= 0 )
{
const QString title = tr( "Invalid name" );
const QString msg = tr( "Auxiliary field '%1' already exists" ).arg( fieldName );
QMessageBox::critical( this, title, msg, QMessageBox::Ok );
}
else if ( def.comment().isEmpty() )
{
const QString title = tr( "Invalid name" );
const QString msg = tr( "Name is a mandatory parameter" );
QMessageBox::critical( this, title, msg, QMessageBox::Ok );
}
else
{
if ( mLayer->auxiliaryLayer()->addAuxiliaryField( def ) )
mPropertyDefinition = def;
QDialog::accept();
}
}
QgsPropertyDefinition QgsNewAuxiliaryFieldDialog::propertyDefinition() const
{
return mPropertyDefinition;
}

View File

@ -0,0 +1,63 @@
/***************************************************************************
qgsnewauxiliaryfielddialog.h - description
-------------------
begin : Sept 05, 2017
copyright : (C) 2017 by Paul Blottiere
email : paul.blottiere@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. *
* *
***************************************************************************/
#ifndef QGSNEWAUXILIARYFIELDDIALOG_H
#define QGSNEWAUXILIARYFIELDDIALOG_H
#include "ui_qgsnewauxiliaryfielddialogbase.h"
#include "qgsguiutils.h"
#include "qgis_gui.h"
#include "qgsvectorlayer.h"
#include "qgsproperty.h"
/**
* \ingroup gui
*
* \brief A dialog to create a new auxiliary field
*
* \since QGIS 3.0
*/
class GUI_EXPORT QgsNewAuxiliaryFieldDialog: public QDialog, private Ui::QgsNewAuxiliaryFieldDialogBase
{
Q_OBJECT
public:
/**
* Constructor.
*
* \param definition The property definition to use to create the auxiliary field
* \param layer The vector layer for which the auxiliary layer has to be created
* \param nameOnly True to indicate that only the name widget is enabled
* \param parent Parent window
*/
QgsNewAuxiliaryFieldDialog( const QgsPropertyDefinition &definition, QgsVectorLayer *layer, bool nameOnly = true, QWidget *parent = nullptr );
/**
* Returns the underlying property definition.
*/
QgsPropertyDefinition propertyDefinition() const;
protected:
void accept() override;
QgsVectorLayer *mLayer = nullptr;
bool mNameOnly = true;
QgsPropertyDefinition mPropertyDefinition;
};
#endif

View File

@ -0,0 +1,50 @@
/***************************************************************************
qgsnewauxiliarylayerdialog.cpp - description
-------------------
begin : Aug 28, 2017
copyright : (C) 2017 by Paul Blottiere
email : paul.blottiere@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 "qgsnewauxiliarylayerdialog.h"
#include "qgsproject.h"
#include "qgsauxiliarystorage.h"
#include <QMessageBox>
QgsNewAuxiliaryLayerDialog::QgsNewAuxiliaryLayerDialog( QgsVectorLayer *layer, QWidget *parent )
: QDialog( parent )
, mLayer( layer )
{
setupUi( this );
for ( const QgsField &field : mLayer->fields() )
comboBox->addItem( field.name() );
}
void QgsNewAuxiliaryLayerDialog::accept()
{
const int idx = mLayer->fields().lookupField( comboBox->currentText() );
if ( idx >= 0 )
{
const QgsField field = mLayer->fields().field( idx );
QgsAuxiliaryLayer *alayer = QgsProject::instance()->auxiliaryStorage()->createAuxiliaryLayer( field, mLayer );
if ( alayer )
{
mLayer->setAuxiliaryLayer( alayer );
}
}
QDialog::accept();
}

View File

@ -0,0 +1,53 @@
/***************************************************************************
qgsnewauxiliarylayerdialog.h - description
-------------------
begin : Aug 28, 2017
copyright : (C) 2017 by Paul Blottiere
email : paul.blottiere@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. *
* *
***************************************************************************/
#ifndef QGSNEWAUXILIARYLAYERDIALOG_H
#define QGSNEWAUXILIARYLAYERDIALOG_H
#include "ui_qgsnewauxiliarylayerdialogbase.h"
#include "qgsguiutils.h"
#include "qgis_gui.h"
#include "qgsvectorlayer.h"
/**
* \ingroup gui
*
* \brief A dialog to create a new auxiliary layer
*
* \since QGIS 3.0
*/
class GUI_EXPORT QgsNewAuxiliaryLayerDialog: public QDialog, private Ui::QgsNewAuxiliaryLayerDialogBase
{
Q_OBJECT
public:
/**
* Constructor.
*
* \param layer The vector layer for which the auxiliary layer has to be created
* \param parent Parent window
*/
QgsNewAuxiliaryLayerDialog( QgsVectorLayer *layer, QWidget *parent = nullptr );
protected:
void accept() override;
QgsVectorLayer *mLayer = nullptr;
};
#endif

View File

@ -22,6 +22,7 @@
#include "qgsvectorlayer.h"
#include "qgspanelwidget.h"
#include "qgspropertyassistantwidget.h"
#include "qgsauxiliarystorage.h"
#include <QClipboard>
#include <QMenu>
@ -66,6 +67,9 @@ QgsPropertyOverrideButton::QgsPropertyOverrideButton( QWidget *parent,
mActionDescription = new QAction( tr( "Description..." ), this );
mActionCreateAuxiliaryField = new QAction( tr( "Store data in the project" ), this );
mActionCreateAuxiliaryField->setCheckable( true );
mActionExpDialog = new QAction( tr( "Edit..." ), this );
mActionExpression = nullptr;
mActionPasteExpr = new QAction( tr( "Paste" ), this );
@ -79,9 +83,10 @@ QgsPropertyOverrideButton::QgsPropertyOverrideButton( QWidget *parent,
}
void QgsPropertyOverrideButton::init( int propertyKey, const QgsProperty &property, const QgsPropertiesDefinition &definitions, const QgsVectorLayer *layer )
void QgsPropertyOverrideButton::init( int propertyKey, const QgsProperty &property, const QgsPropertiesDefinition &definitions, const QgsVectorLayer *layer, bool auxiliaryStorageEnabled )
{
mVectorLayer = layer;
mAuxiliaryStorageEnabled = auxiliaryStorageEnabled;
setToProperty( property );
mPropertyKey = propertyKey;
@ -122,9 +127,9 @@ void QgsPropertyOverrideButton::init( int propertyKey, const QgsProperty &proper
updateGui();
}
void QgsPropertyOverrideButton::init( int propertyKey, const QgsAbstractPropertyCollection &collection, const QgsPropertiesDefinition &definitions, const QgsVectorLayer *layer )
void QgsPropertyOverrideButton::init( int propertyKey, const QgsAbstractPropertyCollection &collection, const QgsPropertiesDefinition &definitions, const QgsVectorLayer *layer, bool auxiliaryStorageEnabled )
{
init( propertyKey, collection.property( propertyKey ), definitions, layer );
init( propertyKey, collection.property( propertyKey ), definitions, layer, auxiliaryStorageEnabled );
}
@ -329,6 +334,25 @@ void QgsPropertyOverrideButton::aboutToShowMenu()
mDefineMenu->addSeparator();
// deactivate button if field already exists
if ( mAuxiliaryStorageEnabled )
{
mDefineMenu->addAction( mActionCreateAuxiliaryField );
const QgsAuxiliaryLayer *alayer = mVectorLayer->auxiliaryLayer();
mActionCreateAuxiliaryField->setEnabled( true );
mActionCreateAuxiliaryField->setChecked( false );
int index = mVectorLayer->fields().indexFromName( mFieldName );
int srcIndex;
if ( index >= 0 && alayer && mVectorLayer->isAuxiliaryField( index, srcIndex ) )
{
mActionCreateAuxiliaryField->setEnabled( false );
mActionCreateAuxiliaryField->setChecked( true );
}
}
bool fieldActive = false;
if ( !mDataTypesString.isEmpty() )
{
@ -507,6 +531,10 @@ void QgsPropertyOverrideButton::menuActionTriggered( QAction *action )
{
showAssistant();
}
else if ( action == mActionCreateAuxiliaryField )
{
emit createAuxiliaryField();
}
else if ( mFieldsMenu->actions().contains( action ) ) // a field name clicked
{
if ( action->isEnabled() )

View File

@ -69,11 +69,13 @@ class GUI_EXPORT QgsPropertyOverrideButton: public QToolButton
* \param property initial value of associated property to show in widget
* \param definitions properties definitions for corresponding collection
* \param layer associated vector layer
* \param auxiliaryStorageEnabled If true, activate the button to store data defined in auxiliary storage
*/
void init( int propertyKey,
const QgsProperty &property,
const QgsPropertiesDefinition &definitions,
const QgsVectorLayer *layer = nullptr );
const QgsVectorLayer *layer = nullptr,
bool auxiliaryStorageEnabled = false );
/**
* Initialize a newly constructed property button (useful if button was included in a UI layout).
@ -81,11 +83,13 @@ class GUI_EXPORT QgsPropertyOverrideButton: public QToolButton
* \param collection associated property collection
* \param definitions properties definitions for collection
* \param layer associated vector layer
* \param auxiliaryStorageEnabled If true, activate the button to store data defined in auxiliary storage
*/
void init( int propertyKey,
const QgsAbstractPropertyCollection &collection,
const QgsPropertiesDefinition &definitions,
const QgsVectorLayer *layer = nullptr );
const QgsVectorLayer *layer = nullptr,
bool auxiliaryStorageEnabled = false );
/**
* Returns a QgsProperty object encapsulating the current state of the
@ -181,6 +185,13 @@ class GUI_EXPORT QgsPropertyOverrideButton: public QToolButton
*/
void registerExpressionContextGenerator( QgsExpressionContextGenerator *generator );
/**
* Updates list of fields.
*
* \since QGIS 3.0
*/
void updateFieldLists();
/**
* Sets a symbol which can be used for previews inside the widget or in any dialog created
* by the widget. If not specified, a default created symbol will be used instead.
@ -203,13 +214,14 @@ class GUI_EXPORT QgsPropertyOverrideButton: public QToolButton
//! Emitted when the activated status of the widget changes
void activated( bool isActive );
//! Emitted when creating a new auxiliary field
void createAuxiliaryField();
protected:
void mouseReleaseEvent( QMouseEvent *event ) override;
private:
void updateFieldLists();
void showDescriptionDialog();
void showExpressionDialog();
void showAssistant();
@ -246,6 +258,7 @@ class GUI_EXPORT QgsPropertyOverrideButton: public QToolButton
QAction *mActionCopyExpr = nullptr;
QAction *mActionClearExpr = nullptr;
QAction *mActionAssistant = nullptr;
QAction *mActionCreateAuxiliaryField = nullptr;
QgsPropertyDefinition mDefinition;
@ -280,6 +293,8 @@ class GUI_EXPORT QgsPropertyOverrideButton: public QToolButton
//! Internal property used for storing state of widget
QgsProperty mProperty;
bool mAuxiliaryStorageEnabled = false;
std::shared_ptr< QgsSymbol > mSymbol;
private slots:

View File

@ -17,7 +17,7 @@
#include "qgsvectorlayer.h"
#include <QColorDialog>
QgsArrowSymbolLayerWidget::QgsArrowSymbolLayerWidget( const QgsVectorLayer *vl, QWidget *parent )
QgsArrowSymbolLayerWidget::QgsArrowSymbolLayerWidget( QgsVectorLayer *vl, QWidget *parent )
: QgsSymbolLayerWidget( parent, vl )
{

View File

@ -37,13 +37,13 @@ class GUI_EXPORT QgsArrowSymbolLayerWidget: public QgsSymbolLayerWidget, private
* \param layer the layer where this symbol layer is applied
* \param parent the parent widget
*/
QgsArrowSymbolLayerWidget( const QgsVectorLayer *layer, QWidget *parent SIP_TRANSFERTHIS = 0 );
QgsArrowSymbolLayerWidget( QgsVectorLayer *layer, QWidget *parent SIP_TRANSFERTHIS = 0 );
/**
* Static creation method
* \param layer the layer where this symbol layer is applied
*/
static QgsSymbolLayerWidget *create( const QgsVectorLayer *layer ) SIP_FACTORY { return new QgsArrowSymbolLayerWidget( layer ); }
static QgsSymbolLayerWidget *create( QgsVectorLayer *layer ) SIP_FACTORY { return new QgsArrowSymbolLayerWidget( layer ); }
virtual void setSymbolLayer( QgsSymbolLayer *layer ) override;
virtual QgsSymbolLayer *symbolLayer() override;

View File

@ -17,7 +17,7 @@
#include "qgsvectorlayer.h"
#include <QColorDialog>
QgsEllipseSymbolLayerWidget::QgsEllipseSymbolLayerWidget( const QgsVectorLayer *vl, QWidget *parent )
QgsEllipseSymbolLayerWidget::QgsEllipseSymbolLayerWidget( QgsVectorLayer *vl, QWidget *parent )
: QgsSymbolLayerWidget( parent, vl )
{

View File

@ -31,9 +31,19 @@ class GUI_EXPORT QgsEllipseSymbolLayerWidget: public QgsSymbolLayerWidget, priva
Q_OBJECT
public:
QgsEllipseSymbolLayerWidget( const QgsVectorLayer *vl, QWidget *parent SIP_TRANSFERTHIS = 0 );
static QgsSymbolLayerWidget *create( const QgsVectorLayer *vl ) SIP_FACTORY { return new QgsEllipseSymbolLayerWidget( vl ); }
/**
* Constructor for QgsEllipseSymbolLayerWidget.
* \param vl associated vector layer
* \param parent parent widget
*/
QgsEllipseSymbolLayerWidget( QgsVectorLayer *vl, QWidget *parent SIP_TRANSFERTHIS = 0 );
/**
* Creates a new QgsSymbolLayerWidget.
* \param vl associated vector layer
*/
static QgsSymbolLayerWidget *create( QgsVectorLayer *vl ) SIP_FACTORY { return new QgsEllipseSymbolLayerWidget( vl ); }
// from base class
virtual void setSymbolLayer( QgsSymbolLayer *layer ) override;

View File

@ -89,7 +89,7 @@ static void _initWidgetFunctions()
}
QgsLayerPropertiesWidget::QgsLayerPropertiesWidget( QgsSymbolLayer *layer, const QgsSymbol *symbol, const QgsVectorLayer *vl, QWidget *parent )
QgsLayerPropertiesWidget::QgsLayerPropertiesWidget( QgsSymbolLayer *layer, const QgsSymbol *symbol, QgsVectorLayer *vl, QWidget *parent )
: QgsPanelWidget( parent )
, mLayer( layer )
, mSymbol( symbol )

View File

@ -43,7 +43,15 @@ class GUI_EXPORT QgsLayerPropertiesWidget : public QgsPanelWidget, public QgsExp
Q_OBJECT
public:
QgsLayerPropertiesWidget( QgsSymbolLayer *layer, const QgsSymbol *symbol, const QgsVectorLayer *vl, QWidget *parent SIP_TRANSFERTHIS = nullptr );
/**
* Constructor for QgsLayerPropertiesWidget.
* \param layer the symbol layer
* \param symbol the symbol
* \param vl associated vector layer
* \param parent parent widget
*/
QgsLayerPropertiesWidget( QgsSymbolLayer *layer, const QgsSymbol *symbol, QgsVectorLayer *vl, QWidget *parent SIP_TRANSFERTHIS = nullptr );
/**
* Sets the context in which the symbol widget is shown, e.g., the associated map canvas and expression contexts.
@ -93,7 +101,7 @@ class GUI_EXPORT QgsLayerPropertiesWidget : public QgsPanelWidget, public QgsExp
QgsSymbolLayer *mLayer = nullptr;
const QgsSymbol *mSymbol = nullptr;
const QgsVectorLayer *mVectorLayer = nullptr;
QgsVectorLayer *mVectorLayer = nullptr;
private slots:
void reloadLayer();

View File

@ -38,6 +38,9 @@
#include "qgssvgselectorwidget.h"
#include "qgslogger.h"
#include "qgssettings.h"
#include "qgsnewauxiliarylayerdialog.h"
#include "qgsnewauxiliaryfielddialog.h"
#include "qgsauxiliarystorage.h"
#include <QAbstractButton>
#include <QColorDialog>
@ -109,12 +112,53 @@ QgsSymbolWidgetContext QgsSymbolLayerWidget::context() const
void QgsSymbolLayerWidget::registerDataDefinedButton( QgsPropertyOverrideButton *button, QgsSymbolLayer::Property key )
{
button->init( key, symbolLayer()->dataDefinedProperties(), QgsSymbolLayer::propertyDefinitions(), mVectorLayer );
button->init( key, symbolLayer()->dataDefinedProperties(), QgsSymbolLayer::propertyDefinitions(), mVectorLayer, true );
connect( button, &QgsPropertyOverrideButton::changed, this, &QgsSymbolLayerWidget::updateDataDefinedProperty );
connect( button, &QgsPropertyOverrideButton::createAuxiliaryField, this, &QgsSymbolLayerWidget::createAuxiliaryField );
button->registerExpressionContextGenerator( this );
}
void QgsSymbolLayerWidget::createAuxiliaryField()
{
// try to create an auxiliary layer if not yet created
if ( !mVectorLayer->auxiliaryLayer() )
{
QgsNewAuxiliaryLayerDialog dlg( mVectorLayer, this );
dlg.exec();
}
// return if still not exists
if ( !mVectorLayer->auxiliaryLayer() )
return;
QgsPropertyOverrideButton *button = qobject_cast<QgsPropertyOverrideButton *>( sender() );
QgsSymbolLayer::Property key = static_cast< QgsSymbolLayer::Property >( button->propertyKey() );
QgsPropertyDefinition def = QgsSymbolLayer::propertyDefinitions()[key];
// create property in auxiliary storage if necessary
if ( !mVectorLayer->auxiliaryLayer()->exists( def ) )
{
QgsNewAuxiliaryFieldDialog dlg( def, mVectorLayer, true, this );
if ( dlg.exec() == QDialog::Accepted )
def = dlg.propertyDefinition();
}
// return if still not exist
if ( !mVectorLayer->auxiliaryLayer()->exists( def ) )
return;
// update property with join field name from auxiliary storage
QgsProperty property = button->toProperty();
property.setField( QgsAuxiliaryLayer::nameFromProperty( def, true ) );
property.setActive( true );
button->updateFieldLists();
button->setToProperty( property );
symbolLayer()->setDataDefinedProperty( key, button->toProperty() );
emit changed();
}
void QgsSymbolLayerWidget::updateDataDefinedProperty()
{
QgsPropertyOverrideButton *button = qobject_cast<QgsPropertyOverrideButton *>( sender() );
@ -123,7 +167,7 @@ void QgsSymbolLayerWidget::updateDataDefinedProperty()
emit changed();
}
QgsSimpleLineSymbolLayerWidget::QgsSimpleLineSymbolLayerWidget( const QgsVectorLayer *vl, QWidget *parent )
QgsSimpleLineSymbolLayerWidget::QgsSimpleLineSymbolLayerWidget( QgsVectorLayer *vl, QWidget *parent )
: QgsSymbolLayerWidget( parent, vl )
{
mLayer = nullptr;
@ -371,7 +415,7 @@ void QgsSimpleLineSymbolLayerWidget::updatePatternIcon()
///////////
QgsSimpleMarkerSymbolLayerWidget::QgsSimpleMarkerSymbolLayerWidget( const QgsVectorLayer *vl, QWidget *parent )
QgsSimpleMarkerSymbolLayerWidget::QgsSimpleMarkerSymbolLayerWidget( QgsVectorLayer *vl, QWidget *parent )
: QgsSymbolLayerWidget( parent, vl )
{
mLayer = nullptr;
@ -660,7 +704,7 @@ void QgsSimpleMarkerSymbolLayerWidget::updateAssistantSymbol()
///////////
QgsSimpleFillSymbolLayerWidget::QgsSimpleFillSymbolLayerWidget( const QgsVectorLayer *vl, QWidget *parent )
QgsSimpleFillSymbolLayerWidget::QgsSimpleFillSymbolLayerWidget( QgsVectorLayer *vl, QWidget *parent )
: QgsSymbolLayerWidget( parent, vl )
{
mLayer = nullptr;
@ -813,7 +857,7 @@ void QgsSimpleFillSymbolLayerWidget::mOffsetUnitWidget_changed()
///////////
QgsFilledMarkerSymbolLayerWidget::QgsFilledMarkerSymbolLayerWidget( const QgsVectorLayer *vl, QWidget *parent )
QgsFilledMarkerSymbolLayerWidget::QgsFilledMarkerSymbolLayerWidget( QgsVectorLayer *vl, QWidget *parent )
: QgsSymbolLayerWidget( parent, vl )
{
mLayer = nullptr;
@ -991,7 +1035,7 @@ void QgsFilledMarkerSymbolLayerWidget::updateAssistantSymbol()
///////////
QgsGradientFillSymbolLayerWidget::QgsGradientFillSymbolLayerWidget( const QgsVectorLayer *vl, QWidget *parent )
QgsGradientFillSymbolLayerWidget::QgsGradientFillSymbolLayerWidget( QgsVectorLayer *vl, QWidget *parent )
: QgsSymbolLayerWidget( parent, vl )
{
mLayer = nullptr;
@ -1322,7 +1366,7 @@ void QgsGradientFillSymbolLayerWidget::mOffsetUnitWidget_changed()
///////////
QgsShapeburstFillSymbolLayerWidget::QgsShapeburstFillSymbolLayerWidget( const QgsVectorLayer *vl, QWidget *parent )
QgsShapeburstFillSymbolLayerWidget::QgsShapeburstFillSymbolLayerWidget( QgsVectorLayer *vl, QWidget *parent )
: QgsSymbolLayerWidget( parent, vl )
{
mLayer = nullptr;
@ -1583,7 +1627,7 @@ void QgsShapeburstFillSymbolLayerWidget::mIgnoreRingsCheckBox_stateChanged( int
///////////
QgsMarkerLineSymbolLayerWidget::QgsMarkerLineSymbolLayerWidget( const QgsVectorLayer *vl, QWidget *parent )
QgsMarkerLineSymbolLayerWidget::QgsMarkerLineSymbolLayerWidget( QgsVectorLayer *vl, QWidget *parent )
: QgsSymbolLayerWidget( parent, vl )
{
mLayer = nullptr;
@ -1753,7 +1797,7 @@ void QgsMarkerLineSymbolLayerWidget::mOffsetAlongLineUnitWidget_changed()
///////////
QgsSvgMarkerSymbolLayerWidget::QgsSvgMarkerSymbolLayerWidget( const QgsVectorLayer *vl, QWidget *parent )
QgsSvgMarkerSymbolLayerWidget::QgsSvgMarkerSymbolLayerWidget( QgsVectorLayer *vl, QWidget *parent )
: QgsSymbolLayerWidget( parent, vl )
{
mLayer = nullptr;
@ -2239,7 +2283,7 @@ void QgsSvgMarkerSymbolLayerWidget::mVerticalAnchorComboBox_currentIndexChanged(
/////////////
QgsSVGFillSymbolLayerWidget::QgsSVGFillSymbolLayerWidget( const QgsVectorLayer *vl, QWidget *parent ): QgsSymbolLayerWidget( parent, vl )
QgsSVGFillSymbolLayerWidget::QgsSVGFillSymbolLayerWidget( QgsVectorLayer *vl, QWidget *parent ): QgsSymbolLayerWidget( parent, vl )
{
mLayer = nullptr;
setupUi( this );
@ -2538,7 +2582,7 @@ void QgsSVGFillSymbolLayerWidget::mSvgStrokeWidthUnitWidget_changed()
/////////////
QgsLinePatternFillSymbolLayerWidget::QgsLinePatternFillSymbolLayerWidget( const QgsVectorLayer *vl, QWidget *parent ):
QgsLinePatternFillSymbolLayerWidget::QgsLinePatternFillSymbolLayerWidget( QgsVectorLayer *vl, QWidget *parent ):
QgsSymbolLayerWidget( parent, vl )
{
setupUi( this );
@ -2645,7 +2689,7 @@ void QgsLinePatternFillSymbolLayerWidget::mOffsetUnitWidget_changed()
/////////////
QgsPointPatternFillSymbolLayerWidget::QgsPointPatternFillSymbolLayerWidget( const QgsVectorLayer *vl, QWidget *parent ):
QgsPointPatternFillSymbolLayerWidget::QgsPointPatternFillSymbolLayerWidget( QgsVectorLayer *vl, QWidget *parent ):
QgsSymbolLayerWidget( parent, vl )
{
setupUi( this );
@ -2795,7 +2839,7 @@ void QgsPointPatternFillSymbolLayerWidget::mVerticalDisplacementUnitWidget_chang
/////////////
QgsFontMarkerSymbolLayerWidget::QgsFontMarkerSymbolLayerWidget( const QgsVectorLayer *vl, QWidget *parent )
QgsFontMarkerSymbolLayerWidget::QgsFontMarkerSymbolLayerWidget( QgsVectorLayer *vl, QWidget *parent )
: QgsSymbolLayerWidget( parent, vl )
{
mLayer = nullptr;
@ -3034,7 +3078,7 @@ void QgsFontMarkerSymbolLayerWidget::updateAssistantSymbol()
///////////////
QgsCentroidFillSymbolLayerWidget::QgsCentroidFillSymbolLayerWidget( const QgsVectorLayer *vl, QWidget *parent )
QgsCentroidFillSymbolLayerWidget::QgsCentroidFillSymbolLayerWidget( QgsVectorLayer *vl, QWidget *parent )
: QgsSymbolLayerWidget( parent, vl )
{
mLayer = nullptr;
@ -3076,7 +3120,7 @@ void QgsCentroidFillSymbolLayerWidget::mDrawAllPartsCheckBox_stateChanged( int s
///////////////
QgsRasterFillSymbolLayerWidget::QgsRasterFillSymbolLayerWidget( const QgsVectorLayer *vl, QWidget *parent )
QgsRasterFillSymbolLayerWidget::QgsRasterFillSymbolLayerWidget( QgsVectorLayer *vl, QWidget *parent )
: QgsSymbolLayerWidget( parent, vl )
{
mLayer = nullptr;
@ -3359,7 +3403,7 @@ void QgsRasterFillSymbolLayerWidget::updatePreviewImage()
}
QgsGeometryGeneratorSymbolLayerWidget::QgsGeometryGeneratorSymbolLayerWidget( const QgsVectorLayer *vl, QWidget *parent )
QgsGeometryGeneratorSymbolLayerWidget::QgsGeometryGeneratorSymbolLayerWidget( QgsVectorLayer *vl, QWidget *parent )
: QgsSymbolLayerWidget( parent, vl )
{

View File

@ -36,7 +36,13 @@ class GUI_EXPORT QgsSymbolLayerWidget : public QWidget, protected QgsExpressionC
Q_OBJECT
public:
QgsSymbolLayerWidget( QWidget *parent SIP_TRANSFERTHIS, const QgsVectorLayer *vl = nullptr )
/**
* Constructor for QgsSymbolLayerWidget.
* \param vl associated vector layer
* \param parent parent widget
*/
QgsSymbolLayerWidget( QWidget *parent SIP_TRANSFERTHIS, QgsVectorLayer *vl = nullptr )
: QWidget( parent )
, mVectorLayer( vl )
{}
@ -78,7 +84,7 @@ class GUI_EXPORT QgsSymbolLayerWidget : public QWidget, protected QgsExpressionC
QgsExpressionContext createExpressionContext() const override;
private:
const QgsVectorLayer *mVectorLayer = nullptr;
QgsVectorLayer *mVectorLayer = nullptr;
QgsMapCanvas *mMapCanvas = nullptr;
@ -101,6 +107,9 @@ class GUI_EXPORT QgsSymbolLayerWidget : public QWidget, protected QgsExpressionC
protected slots:
void updateDataDefinedProperty();
private slots:
void createAuxiliaryField();
private:
QgsSymbolWidgetContext mContext;
};
@ -120,9 +129,19 @@ class GUI_EXPORT QgsSimpleLineSymbolLayerWidget : public QgsSymbolLayerWidget, p
Q_OBJECT
public:
QgsSimpleLineSymbolLayerWidget( const QgsVectorLayer *vl, QWidget *parent SIP_TRANSFERTHIS = nullptr );
static QgsSymbolLayerWidget *create( const QgsVectorLayer *vl ) SIP_FACTORY { return new QgsSimpleLineSymbolLayerWidget( vl ); }
/**
* Constructor for QgsSimpleLineSymbolLayerWidget.
* \param vl associated vector layer
* \param parent parent widget
*/
QgsSimpleLineSymbolLayerWidget( QgsVectorLayer *vl, QWidget *parent SIP_TRANSFERTHIS = nullptr );
/**
* Creates a new QgsSimpleLineSymbolLayerWidget.
* \param vl associated vector layer
*/
static QgsSymbolLayerWidget *create( QgsVectorLayer *vl ) SIP_FACTORY { return new QgsSimpleLineSymbolLayerWidget( vl ); }
// from base class
virtual void setSymbolLayer( QgsSymbolLayer *layer ) override;
@ -169,9 +188,19 @@ class GUI_EXPORT QgsSimpleMarkerSymbolLayerWidget : public QgsSymbolLayerWidget,
Q_OBJECT
public:
QgsSimpleMarkerSymbolLayerWidget( const QgsVectorLayer *vl, QWidget *parent SIP_TRANSFERTHIS = nullptr );
static QgsSymbolLayerWidget *create( const QgsVectorLayer *vl ) SIP_FACTORY { return new QgsSimpleMarkerSymbolLayerWidget( vl ); }
/**
* Constructor for QgsSimpleMarkerSymbolLayerWidget.
* \param vl associated vector layer
* \param parent parent widget
*/
QgsSimpleMarkerSymbolLayerWidget( QgsVectorLayer *vl, QWidget *parent SIP_TRANSFERTHIS = nullptr );
/**
* Creates a new QgsSimpleMarkerSymbolLayerWidget.
* \param vl associated vector layer
*/
static QgsSymbolLayerWidget *create( QgsVectorLayer *vl ) SIP_FACTORY { return new QgsSimpleMarkerSymbolLayerWidget( vl ); }
// from base class
virtual void setSymbolLayer( QgsSymbolLayer *layer ) override;
@ -220,9 +249,19 @@ class GUI_EXPORT QgsSimpleFillSymbolLayerWidget : public QgsSymbolLayerWidget, p
Q_OBJECT
public:
QgsSimpleFillSymbolLayerWidget( const QgsVectorLayer *vl, QWidget *parent SIP_TRANSFERTHIS = nullptr );
static QgsSymbolLayerWidget *create( const QgsVectorLayer *vl ) SIP_FACTORY { return new QgsSimpleFillSymbolLayerWidget( vl ); }
/**
* Constructor for QgsSimpleFillSymbolLayerWidget.
* \param vl associated vector layer
* \param parent parent widget
*/
QgsSimpleFillSymbolLayerWidget( QgsVectorLayer *vl, QWidget *parent SIP_TRANSFERTHIS = nullptr );
/**
* Creates a new QgsSimpleFillSymbolLayerWidget.
* \param vl associated vector layer
*/
static QgsSymbolLayerWidget *create( QgsVectorLayer *vl ) SIP_FACTORY { return new QgsSimpleFillSymbolLayerWidget( vl ); }
// from base class
virtual void setSymbolLayer( QgsSymbolLayer *layer ) override;
@ -269,13 +308,13 @@ class GUI_EXPORT QgsFilledMarkerSymbolLayerWidget : public QgsSymbolLayerWidget,
* \param vl associated vector layer
* \param parent parent widget
*/
QgsFilledMarkerSymbolLayerWidget( const QgsVectorLayer *vl, QWidget *parent SIP_TRANSFERTHIS = 0 );
QgsFilledMarkerSymbolLayerWidget( QgsVectorLayer *vl, QWidget *parent SIP_TRANSFERTHIS = 0 );
/**
* Creates a new QgsFilledMarkerSymbolLayerWidget.
* \param vl associated vector layer
*/
static QgsSymbolLayerWidget *create( const QgsVectorLayer *vl ) SIP_FACTORY { return new QgsFilledMarkerSymbolLayerWidget( vl ); }
static QgsSymbolLayerWidget *create( QgsVectorLayer *vl ) SIP_FACTORY { return new QgsFilledMarkerSymbolLayerWidget( vl ); }
// from base class
virtual void setSymbolLayer( QgsSymbolLayer *layer ) override;
@ -316,9 +355,19 @@ class GUI_EXPORT QgsGradientFillSymbolLayerWidget : public QgsSymbolLayerWidget,
Q_OBJECT
public:
QgsGradientFillSymbolLayerWidget( const QgsVectorLayer *vl, QWidget *parent SIP_TRANSFERTHIS = nullptr );
static QgsSymbolLayerWidget *create( const QgsVectorLayer *vl ) SIP_FACTORY { return new QgsGradientFillSymbolLayerWidget( vl ); }
/**
* Constructor for QgsGradientFillSymbolLayerWidget.
* \param vl associated vector layer
* \param parent parent widget
*/
QgsGradientFillSymbolLayerWidget( QgsVectorLayer *vl, QWidget *parent SIP_TRANSFERTHIS = nullptr );
/**
* Creates a new QgsGradientFillSymbolLayerWidget.
* \param vl associated vector layer
*/
static QgsSymbolLayerWidget *create( QgsVectorLayer *vl ) SIP_FACTORY { return new QgsGradientFillSymbolLayerWidget( vl ); }
// from base class
virtual void setSymbolLayer( QgsSymbolLayer *layer ) override;
@ -363,9 +412,19 @@ class GUI_EXPORT QgsShapeburstFillSymbolLayerWidget : public QgsSymbolLayerWidge
Q_OBJECT
public:
QgsShapeburstFillSymbolLayerWidget( const QgsVectorLayer *vl, QWidget *parent SIP_TRANSFERTHIS = nullptr );
static QgsSymbolLayerWidget *create( const QgsVectorLayer *vl ) SIP_FACTORY { return new QgsShapeburstFillSymbolLayerWidget( vl ); }
/**
* Constructor for QgsShapeburstFillSymbolLayerWidget.
* \param vl associated vector layer
* \param parent parent widget
*/
QgsShapeburstFillSymbolLayerWidget( QgsVectorLayer *vl, QWidget *parent SIP_TRANSFERTHIS = nullptr );
/**
* Creates a new QgsShapeburstFillSymbolLayerWidget.
* \param vl associated vector layer
*/
static QgsSymbolLayerWidget *create( QgsVectorLayer *vl ) SIP_FACTORY { return new QgsShapeburstFillSymbolLayerWidget( vl ); }
// from base class
virtual void setSymbolLayer( QgsSymbolLayer *layer ) override;
@ -405,9 +464,19 @@ class GUI_EXPORT QgsMarkerLineSymbolLayerWidget : public QgsSymbolLayerWidget, p
Q_OBJECT
public:
QgsMarkerLineSymbolLayerWidget( const QgsVectorLayer *vl, QWidget *parent SIP_TRANSFERTHIS = nullptr );
static QgsSymbolLayerWidget *create( const QgsVectorLayer *vl ) SIP_FACTORY { return new QgsMarkerLineSymbolLayerWidget( vl ); }
/**
* Constructor for QgsMarkerLineSymbolLayerWidget.
* \param vl associated vector layer
* \param parent parent widget
*/
QgsMarkerLineSymbolLayerWidget( QgsVectorLayer *vl, QWidget *parent SIP_TRANSFERTHIS = nullptr );
/**
* Creates a new QgsMarkerLineSymbolLayerWidget.
* \param vl associated vector layer
*/
static QgsSymbolLayerWidget *create( QgsVectorLayer *vl ) SIP_FACTORY { return new QgsMarkerLineSymbolLayerWidget( vl ); }
// from base class
virtual void setSymbolLayer( QgsSymbolLayer *layer ) override;
@ -448,9 +517,19 @@ class GUI_EXPORT QgsSvgMarkerSymbolLayerWidget : public QgsSymbolLayerWidget, pr
Q_OBJECT
public:
QgsSvgMarkerSymbolLayerWidget( const QgsVectorLayer *vl, QWidget *parent SIP_TRANSFERTHIS = nullptr );
static QgsSymbolLayerWidget *create( const QgsVectorLayer *vl ) SIP_FACTORY { return new QgsSvgMarkerSymbolLayerWidget( vl ); }
/**
* Constructor for QgsSvgMarkerSymbolLayerWidget.
* \param vl associated vector layer
* \param parent parent widget
*/
QgsSvgMarkerSymbolLayerWidget( QgsVectorLayer *vl, QWidget *parent SIP_TRANSFERTHIS = nullptr );
/**
* Creates a new QgsSvgMarkerSymbolLayerWidget.
* \param vl associated vector layer
*/
static QgsSymbolLayerWidget *create( QgsVectorLayer *vl ) SIP_FACTORY { return new QgsSvgMarkerSymbolLayerWidget( vl ); }
// from base class
virtual void setSymbolLayer( QgsSymbolLayer *layer ) override;
@ -507,9 +586,19 @@ class GUI_EXPORT QgsRasterFillSymbolLayerWidget : public QgsSymbolLayerWidget, p
Q_OBJECT
public:
QgsRasterFillSymbolLayerWidget( const QgsVectorLayer *vl, QWidget *parent SIP_TRANSFERTHIS = nullptr );
static QgsSymbolLayerWidget *create( const QgsVectorLayer *vl ) SIP_FACTORY { return new QgsRasterFillSymbolLayerWidget( vl ); }
/**
* Constructor for QgsRasterFillSymbolLayerWidget.
* \param vl associated vector layer
* \param parent parent widget
*/
QgsRasterFillSymbolLayerWidget( QgsVectorLayer *vl, QWidget *parent SIP_TRANSFERTHIS = nullptr );
/**
* Creates a new QgsRasterFillSymbolLayerWidget.
* \param vl associated vector layer
*/
static QgsSymbolLayerWidget *create( QgsVectorLayer *vl ) SIP_FACTORY { return new QgsRasterFillSymbolLayerWidget( vl ); }
// from base class
virtual void setSymbolLayer( QgsSymbolLayer *layer ) override;
@ -548,9 +637,19 @@ class GUI_EXPORT QgsSVGFillSymbolLayerWidget : public QgsSymbolLayerWidget, priv
Q_OBJECT
public:
QgsSVGFillSymbolLayerWidget( const QgsVectorLayer *vl, QWidget *parent SIP_TRANSFERTHIS = nullptr );
static QgsSymbolLayerWidget *create( const QgsVectorLayer *vl ) SIP_FACTORY { return new QgsSVGFillSymbolLayerWidget( vl ); }
/**
* Constructor for QgsSVGFillSymbolLayerWidget.
* \param vl associated vector layer
* \param parent parent widget
*/
QgsSVGFillSymbolLayerWidget( QgsVectorLayer *vl, QWidget *parent SIP_TRANSFERTHIS = nullptr );
/**
* Creates a new QgsSVGFillSymbolLayerWidget.
* \param vl associated vector layer
*/
static QgsSymbolLayerWidget *create( QgsVectorLayer *vl ) SIP_FACTORY { return new QgsSVGFillSymbolLayerWidget( vl ); }
// from base class
virtual void setSymbolLayer( QgsSymbolLayer *layer ) override;
@ -599,8 +698,18 @@ class GUI_EXPORT QgsLinePatternFillSymbolLayerWidget : public QgsSymbolLayerWidg
public:
QgsLinePatternFillSymbolLayerWidget( const QgsVectorLayer *vl, QWidget *parent SIP_TRANSFERTHIS = nullptr );
static QgsSymbolLayerWidget *create( const QgsVectorLayer *vl ) SIP_FACTORY { return new QgsLinePatternFillSymbolLayerWidget( vl ); }
/**
* Constructor for QgsLinePatternFillSymbolLayerWidget.
* \param vl associated vector layer
* \param parent parent widget
*/
QgsLinePatternFillSymbolLayerWidget( QgsVectorLayer *vl, QWidget *parent SIP_TRANSFERTHIS = nullptr );
/**
* Creates a new QgsLinePatternFillSymbolLayerWidget.
* \param vl associated vector layer
*/
static QgsSymbolLayerWidget *create( QgsVectorLayer *vl ) SIP_FACTORY { return new QgsLinePatternFillSymbolLayerWidget( vl ); }
virtual void setSymbolLayer( QgsSymbolLayer *layer ) override;
virtual QgsSymbolLayer *symbolLayer() override;
@ -631,8 +740,19 @@ class GUI_EXPORT QgsPointPatternFillSymbolLayerWidget: public QgsSymbolLayerWidg
Q_OBJECT
public:
QgsPointPatternFillSymbolLayerWidget( const QgsVectorLayer *vl, QWidget *parent SIP_TRANSFERTHIS = nullptr );
static QgsSymbolLayerWidget *create( const QgsVectorLayer *vl ) SIP_FACTORY { return new QgsPointPatternFillSymbolLayerWidget( vl ); }
/**
* Constructor for QgsPointPatternFillSymbolLayerWidget.
* \param vl associated vector layer
* \param parent parent widget
*/
QgsPointPatternFillSymbolLayerWidget( QgsVectorLayer *vl, QWidget *parent SIP_TRANSFERTHIS = nullptr );
/**
* Creates a new QgsPointPatternFillSymbolLayerWidget.
* \param vl associated vector layer
*/
static QgsSymbolLayerWidget *create( QgsVectorLayer *vl ) SIP_FACTORY { return new QgsPointPatternFillSymbolLayerWidget( vl ); }
virtual void setSymbolLayer( QgsSymbolLayer *layer ) override;
virtual QgsSymbolLayer *symbolLayer() override;
@ -667,9 +787,19 @@ class GUI_EXPORT QgsFontMarkerSymbolLayerWidget : public QgsSymbolLayerWidget, p
Q_OBJECT
public:
QgsFontMarkerSymbolLayerWidget( const QgsVectorLayer *vl, QWidget *parent SIP_TRANSFERTHIS = nullptr );
static QgsSymbolLayerWidget *create( const QgsVectorLayer *vl ) SIP_FACTORY { return new QgsFontMarkerSymbolLayerWidget( vl ); }
/**
* Constructor for QgsFontMarkerSymbolLayerWidget.
* \param vl associated vector layer
* \param parent parent widget
*/
QgsFontMarkerSymbolLayerWidget( QgsVectorLayer *vl, QWidget *parent SIP_TRANSFERTHIS = nullptr );
/**
* Creates a new QgsFontMarkerSymbolLayerWidget.
* \param vl associated vector layer
*/
static QgsSymbolLayerWidget *create( QgsVectorLayer *vl ) SIP_FACTORY { return new QgsFontMarkerSymbolLayerWidget( vl ); }
// from base class
virtual void setSymbolLayer( QgsSymbolLayer *layer ) override;
@ -724,9 +854,19 @@ class GUI_EXPORT QgsCentroidFillSymbolLayerWidget : public QgsSymbolLayerWidget,
Q_OBJECT
public:
QgsCentroidFillSymbolLayerWidget( const QgsVectorLayer *vl, QWidget *parent SIP_TRANSFERTHIS = nullptr );
static QgsSymbolLayerWidget *create( const QgsVectorLayer *vl ) SIP_FACTORY { return new QgsCentroidFillSymbolLayerWidget( vl ); }
/**
* Constructor for QgsCentroidFillSymbolLayerWidget.
* \param vl associated vector layer
* \param parent parent widget
*/
QgsCentroidFillSymbolLayerWidget( QgsVectorLayer *vl, QWidget *parent SIP_TRANSFERTHIS = nullptr );
/**
* Creates a new QgsCentroidFillSymbolLayerWidget.
* \param vl associated vector layer
*/
static QgsSymbolLayerWidget *create( QgsVectorLayer *vl ) SIP_FACTORY { return new QgsCentroidFillSymbolLayerWidget( vl ); }
// from base class
virtual void setSymbolLayer( QgsSymbolLayer *layer ) override;
@ -756,12 +896,18 @@ class GUI_EXPORT QgsGeometryGeneratorSymbolLayerWidget : public QgsSymbolLayerWi
Q_OBJECT
public:
QgsGeometryGeneratorSymbolLayerWidget( const QgsVectorLayer *vl, QWidget *parent SIP_TRANSFERTHIS = nullptr );
/**
* Constructor for QgsGeometryGeneratorSymbolLayerWidget.
* \param vl associated vector layer
* \param parent parent widget
*/
QgsGeometryGeneratorSymbolLayerWidget( QgsVectorLayer *vl, QWidget *parent SIP_TRANSFERTHIS = nullptr );
/**
* Will be registered as factory
*/
static QgsSymbolLayerWidget *create( const QgsVectorLayer *vl ) SIP_FACTORY { return new QgsGeometryGeneratorSymbolLayerWidget( vl ); }
static QgsSymbolLayerWidget *create( QgsVectorLayer *vl ) SIP_FACTORY { return new QgsGeometryGeneratorSymbolLayerWidget( vl ); }
// from base class
virtual void setSymbolLayer( QgsSymbolLayer *layer ) override;

View File

@ -215,7 +215,7 @@ class SymbolLayerItem : public QStandardItem
//////////
QgsSymbolSelectorWidget::QgsSymbolSelectorWidget( QgsSymbol *symbol, QgsStyle *style, const QgsVectorLayer *vl, QWidget *parent )
QgsSymbolSelectorWidget::QgsSymbolSelectorWidget( QgsSymbol *symbol, QgsStyle *style, QgsVectorLayer *vl, QWidget *parent )
: QgsPanelWidget( parent )
, mVectorLayer( vl )
{
@ -671,7 +671,7 @@ void QgsSymbolSelectorWidget::changeLayer( QgsSymbolLayer *newLayer )
layerChanged();
}
QgsSymbolSelectorDialog::QgsSymbolSelectorDialog( QgsSymbol *symbol, QgsStyle *style, const QgsVectorLayer *vl, QWidget *parent, bool embedded )
QgsSymbolSelectorDialog::QgsSymbolSelectorDialog( QgsSymbol *symbol, QgsStyle *style, QgsVectorLayer *vl, QWidget *parent, bool embedded )
: QDialog( parent )
{
setLayout( new QVBoxLayout() );

View File

@ -100,7 +100,7 @@ class GUI_EXPORT QgsSymbolSelectorWidget: public QgsPanelWidget, private Ui::Qgs
* \param vl The vector layer for the symbol.
* \param parent
*/
QgsSymbolSelectorWidget( QgsSymbol *symbol, QgsStyle *style, const QgsVectorLayer *vl, QWidget *parent SIP_TRANSFERTHIS = nullptr );
QgsSymbolSelectorWidget( QgsSymbol *symbol, QgsStyle *style, QgsVectorLayer *vl, QWidget *parent SIP_TRANSFERTHIS = nullptr );
//! return menu for "advanced" button - create it if doesn't exist and show the advanced button
QMenu *advancedMenu();
@ -242,7 +242,7 @@ class GUI_EXPORT QgsSymbolSelectorWidget: public QgsPanelWidget, private Ui::Qgs
QgsStyle *mStyle = nullptr;
QgsSymbol *mSymbol = nullptr;
QMenu *mAdvancedMenu = nullptr;
const QgsVectorLayer *mVectorLayer = nullptr;
QgsVectorLayer *mVectorLayer = nullptr;
QStandardItemModel *model = nullptr;
QWidget *mPresentWidget = nullptr;
@ -261,7 +261,17 @@ class GUI_EXPORT QgsSymbolSelectorDialog : public QDialog
Q_OBJECT
public:
QgsSymbolSelectorDialog( QgsSymbol *symbol, QgsStyle *style, const QgsVectorLayer *vl, QWidget *parent SIP_TRANSFERTHIS = nullptr, bool embedded = false );
/**
* Constructor for QgsSymbolSelectorDialog.
*
* \param symbol The symbol
* \param style The style
* \param vl Associated vector layer
* \param parent Parent widget
* \param embedded True to embed in renderer properties dialog, false otherwise
*/
QgsSymbolSelectorDialog( QgsSymbol *symbol, QgsStyle *style, QgsVectorLayer *vl, QWidget *parent SIP_TRANSFERTHIS = nullptr, bool embedded = false );
~QgsSymbolSelectorDialog();
//! return menu for "advanced" button - create it if doesn't exist and show the advanced button

View File

@ -27,6 +27,8 @@
#include "qgsapplication.h"
#include "qgsvectorlayer.h"
#include "qgssettings.h"
#include "qgsnewauxiliarylayerdialog.h"
#include "qgsauxiliarystorage.h"
#include <QAction>
#include <QString>
@ -41,7 +43,7 @@
#include <QPushButton>
QgsSymbolsListWidget::QgsSymbolsListWidget( QgsSymbol *symbol, QgsStyle *style, QMenu *menu, QWidget *parent, const QgsVectorLayer *layer )
QgsSymbolsListWidget::QgsSymbolsListWidget( QgsSymbol *symbol, QgsStyle *style, QMenu *menu, QWidget *parent, QgsVectorLayer *layer )
: QWidget( parent )
, mSymbol( symbol )
, mStyle( style )
@ -127,6 +129,61 @@ void QgsSymbolsListWidget::registerDataDefinedButton( QgsPropertyOverrideButton
{
button->setProperty( "propertyKey", key );
button->registerExpressionContextGenerator( this );
connect( button, &QgsPropertyOverrideButton::createAuxiliaryField, this, &QgsSymbolsListWidget::createAuxiliaryField );
}
void QgsSymbolsListWidget::createAuxiliaryField()
{
// try to create an auxiliary layer if not yet created
if ( !mLayer->auxiliaryLayer() )
{
QgsNewAuxiliaryLayerDialog dlg( mLayer, this );
dlg.exec();
}
// return if still not exists
if ( !mLayer->auxiliaryLayer() )
return;
QgsPropertyOverrideButton *button = qobject_cast<QgsPropertyOverrideButton *>( sender() );
QgsSymbolLayer::Property key = static_cast< QgsSymbolLayer::Property >( button->propertyKey() );
const QgsPropertyDefinition def = QgsSymbolLayer::propertyDefinitions()[key];
// create property in auxiliary storage if necessary
if ( !mLayer->auxiliaryLayer()->exists( def ) )
mLayer->auxiliaryLayer()->addAuxiliaryField( def );
// update property with join field name from auxiliary storage
QgsProperty property = button->toProperty();
property.setField( QgsAuxiliaryLayer::nameFromProperty( def, true ) );
property.setActive( true );
button->updateFieldLists();
button->setToProperty( property );
QgsMarkerSymbol *markerSymbol = static_cast<QgsMarkerSymbol *>( mSymbol );
QgsLineSymbol *lineSymbol = static_cast<QgsLineSymbol *>( mSymbol );
switch ( key )
{
case QgsSymbolLayer::PropertyAngle:
if ( markerSymbol )
markerSymbol->setDataDefinedAngle( button->toProperty() );
break;
case QgsSymbolLayer::PropertySize:
if ( markerSymbol )
{
markerSymbol->setDataDefinedSize( button->toProperty() );
markerSymbol->setScaleMethod( QgsSymbol::ScaleDiameter );
}
break;
case QgsSymbolLayer::PropertyStrokeWidth:
if ( lineSymbol )
lineSymbol->setDataDefinedWidth( button->toProperty() );
default:
break;
}
emit changed();
}
void QgsSymbolsListWidget::setContext( const QgsSymbolWidgetContext &context )
@ -510,10 +567,10 @@ void QgsSymbolsListWidget::updateSymbolInfo()
if ( mLayer )
{
QgsProperty ddSize( markerSymbol->dataDefinedSize() );
mSizeDDBtn->init( QgsSymbolLayer::PropertySize, ddSize, QgsSymbolLayer::propertyDefinitions(), mLayer );
mSizeDDBtn->init( QgsSymbolLayer::PropertySize, ddSize, QgsSymbolLayer::propertyDefinitions(), mLayer, true );
spinSize->setEnabled( !mSizeDDBtn->isActive() );
QgsProperty ddAngle( markerSymbol->dataDefinedAngle() );
mRotationDDBtn->init( QgsSymbolLayer::PropertyAngle, ddAngle, QgsSymbolLayer::propertyDefinitions(), mLayer );
mRotationDDBtn->init( QgsSymbolLayer::PropertyAngle, ddAngle, QgsSymbolLayer::propertyDefinitions(), mLayer, true );
spinAngle->setEnabled( !mRotationDDBtn->isActive() );
}
else
@ -530,7 +587,7 @@ void QgsSymbolsListWidget::updateSymbolInfo()
if ( mLayer )
{
QgsProperty dd( lineSymbol->dataDefinedWidth() );
mWidthDDBtn->init( QgsSymbolLayer::PropertyStrokeWidth, dd, QgsSymbolLayer::propertyDefinitions(), mLayer );
mWidthDDBtn->init( QgsSymbolLayer::PropertyStrokeWidth, dd, QgsSymbolLayer::propertyDefinitions(), mLayer, true );
spinWidth->setEnabled( !mWidthDDBtn->isActive() );
}
else

View File

@ -38,7 +38,16 @@ class GUI_EXPORT QgsSymbolsListWidget : public QWidget, private Ui::SymbolsListW
Q_OBJECT
public:
QgsSymbolsListWidget( QgsSymbol *symbol, QgsStyle *style, QMenu *menu, QWidget *parent SIP_TRANSFERTHIS, const QgsVectorLayer *layer = nullptr );
/**
* Constructor for QgsSymbolsListWidget.
* \param symbol the symbol
* \param style the style
* \param menu the menu where to show it
* \param parent parent widget
* \param layer associated vector layer
*/
QgsSymbolsListWidget( QgsSymbol *symbol, QgsStyle *style, QMenu *menu, QWidget *parent SIP_TRANSFERTHIS, QgsVectorLayer *layer = nullptr );
virtual ~QgsSymbolsListWidget();
@ -94,6 +103,7 @@ class GUI_EXPORT QgsSymbolsListWidget : public QWidget, private Ui::SymbolsListW
void groupsCombo_currentIndexChanged( int index );
void updateAssistantSymbol();
void opacityChanged( double value );
void createAuxiliaryField();
private:
QgsSymbol *mSymbol = nullptr;
@ -101,7 +111,7 @@ class GUI_EXPORT QgsSymbolsListWidget : public QWidget, private Ui::SymbolsListW
QgsStyle *mStyle = nullptr;
QMenu *mAdvancedMenu = nullptr;
QAction *mClipFeaturesAction = nullptr;
const QgsVectorLayer *mLayer = nullptr;
QgsVectorLayer *mLayer = nullptr;
QgsMapCanvas *mMapCanvas = nullptr;
void populateSymbolView();

View File

@ -16,7 +16,7 @@
#include "qgsvectorfieldsymbollayer.h"
#include "qgsvectorlayer.h"
QgsVectorFieldSymbolLayerWidget::QgsVectorFieldSymbolLayerWidget( const QgsVectorLayer *vl, QWidget *parent ): QgsSymbolLayerWidget( parent, vl )
QgsVectorFieldSymbolLayerWidget::QgsVectorFieldSymbolLayerWidget( QgsVectorLayer *vl, QWidget *parent ): QgsSymbolLayerWidget( parent, vl )
{
setupUi( this );
connect( mScaleSpinBox, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsVectorFieldSymbolLayerWidget::mScaleSpinBox_valueChanged );

View File

@ -30,9 +30,19 @@ class GUI_EXPORT QgsVectorFieldSymbolLayerWidget: public QgsSymbolLayerWidget, p
{
Q_OBJECT
public:
QgsVectorFieldSymbolLayerWidget( const QgsVectorLayer *vl, QWidget *parent SIP_TRANSFERTHIS = 0 );
static QgsSymbolLayerWidget *create( const QgsVectorLayer *vl ) SIP_FACTORY { return new QgsVectorFieldSymbolLayerWidget( vl ); }
/**
* Constructor for QgsVectorFieldSymbolLayerWidget.
* \param vl associated vector layer
* \param parent parent widget
*/
QgsVectorFieldSymbolLayerWidget( QgsVectorLayer *vl, QWidget *parent SIP_TRANSFERTHIS = 0 );
/**
* Creates a new QgsVectorFieldSymbolLayerWidget.
* \param vl associated vector layer
*/
static QgsSymbolLayerWidget *create( QgsVectorLayer *vl ) SIP_FACTORY { return new QgsVectorFieldSymbolLayerWidget( vl ); }
// from base class
virtual void setSymbolLayer( QgsSymbolLayer *layer ) override;

View File

@ -0,0 +1,111 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>QgsNewAuxiliaryFieldDialogBase</class>
<widget class="QDialog" name="QgsNewAuxiliaryFieldDialogBase">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>397</width>
<height>159</height>
</rect>
</property>
<property name="windowTitle">
<string>Auxiliary storage : new auxiliary field</string>
</property>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="geometry">
<rect>
<x>50</x>
<y>120</y>
<width>341</width>
<height>32</height>
</rect>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
<widget class="QWidget" name="verticalLayoutWidget">
<property name="geometry">
<rect>
<x>10</x>
<y>10</y>
<width>381</width>
<height>101</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="label_3">
<property name="text">
<string>New auxiliary field parameters</string>
</property>
</widget>
</item>
<item>
<layout class="QFormLayout" name="formLayout">
<item row="2" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Type</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QComboBox" name="mType"/>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Name</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QLineEdit" name="mName"/>
</item>
</layout>
</item>
</layout>
</widget>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>QgsNewAuxiliaryFieldDialogBase</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>QgsNewAuxiliaryFieldDialogBase</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -0,0 +1,93 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>QgsNewAuxiliaryLayerDialogBase</class>
<widget class="QDialog" name="QgsNewAuxiliaryLayerDialogBase">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>139</height>
</rect>
</property>
<property name="windowTitle">
<string>Auxiliary storage : choose primary key</string>
</property>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="geometry">
<rect>
<x>50</x>
<y>100</y>
<width>341</width>
<height>32</height>
</rect>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
<widget class="QWidget" name="verticalLayoutWidget">
<property name="geometry">
<rect>
<x>10</x>
<y>10</y>
<width>381</width>
<height>81</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Select the primary key to use for joining with internal data storage</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="comboBox"/>
</item>
</layout>
</widget>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>QgsNewAuxiliaryLayerDialogBase</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>QgsNewAuxiliaryLayerDialogBase</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -273,6 +273,15 @@
<normaloff>:/images/themes/default/propertyicons/overlay.png</normaloff>:/images/themes/default/propertyicons/overlay.png</iconset>
</property>
</item>
<item>
<property name="text">
<string>Auxiliary Storage</string>
</property>
<property name="icon">
<iconset resource="../../images/images.qrc">
<normaloff>:/images/themes/default/mIconAuxiliaryStorage.svg</normaloff>:/images/themes/default/mIconAuxiliaryStorage.svg</iconset>
</property>
</item>
</widget>
</item>
</layout>
@ -1995,6 +2004,237 @@ border-radius: 2px;</string>
</item>
</layout>
</widget>
<widget class="QWidget" name="mOptsPage_AuxiliaryStorage">
<widget class="QWidget" name="mAuxiliaryStorageScrollArea" native="true">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>671</width>
<height>551</height>
</rect>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="1" column="0">
<widget class="QgsCollapsibleGroupBox" name="mAuxiliaryStorageInformationGrpBox">
<property name="title">
<string>Information</string>
</property>
<property name="flat">
<bool>false</bool>
</property>
<property name="checkable">
<bool>false</bool>
</property>
<property name="syncGroup">
<string notr="true">vectormeta</string>
</property>
<layout class="QGridLayout" name="gridLayout_11">
<property name="sizeConstraint">
<enum>QLayout::SetDefaultConstraint</enum>
</property>
<item row="2" column="1">
<widget class="QLineEdit" name="mAuxiliaryStorageFeaturesLineEdit">
<property name="enabled">
<bool>false</bool>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="mAuxiliaryStorageFieldsLabel">
<property name="text">
<string>Fields</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="mAuxiliaryStorageFeaturesLabel">
<property name="text">
<string>Features</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLineEdit" name="mAuxiliaryStorageFieldsLineEdit">
<property name="enabled">
<bool>false</bool>
</property>
<property name="toolTip">
<string>A name used to identify the layer. The short name is a text string used for machine-to-machine communication.</string>
</property>
<property name="inputMask">
<string/>
</property>
<property name="text">
<string/>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
<property name="placeholderText">
<string/>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="mAuxiliaryStorageKeyLabel">
<property name="text">
<string>Key</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="mAuxiliaryStorageKeyLineEdit">
<property name="enabled">
<bool>false</bool>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="3" column="0">
<layout class="QHBoxLayout" name="horizontalLayout_6">
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QPushButton" name="mAuxiliaryStorageActions">
<property name="text">
<string>Auxiliary Layer</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_8">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item row="2" column="0">
<widget class="QgsCollapsibleGroupBox" name="mAuxiliaryStorageFieldsGrpBox">
<property name="title">
<string>Fields</string>
</property>
<layout class="QGridLayout" name="gridLayout_3">
<item row="3" column="0" rowspan="3">
<layout class="QHBoxLayout" name="horizontalLayout_5">
<property name="sizeConstraint">
<enum>QLayout::SetDefaultConstraint</enum>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="mAuxiliaryStorageFieldsAddBtn">
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../../images/images.qrc">
<normaloff>:/images/themes/default/symbologyAdd.svg</normaloff>:/images/themes/default/symbologyAdd.svg</iconset>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="mAuxiliaryStorageFieldsDeleteBtn">
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../../images/images.qrc">
<normaloff>:/images/themes/default/symbologyRemove.svg</normaloff>:/images/themes/default/symbologyRemove.svg</iconset>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_7">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item row="0" column="0">
<widget class="QTreeWidget" name="mAuxiliaryStorageFieldsTree">
<column>
<property name="text">
<string>Target</string>
</property>
</column>
<column>
<property name="text">
<string>Property</string>
</property>
</column>
<column>
<property name="text">
<string>Name</string>
</property>
</column>
<column>
<property name="text">
<string>Type</string>
</property>
</column>
<column>
<property name="text">
<string>Full Name</string>
</property>
</column>
</widget>
</item>
</layout>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>Auxiliary storage tables can contain additional data that should only belong to the project file. For instance, specific location or rotation for labels. Auxiliary data are saved in qgd files. New fields can be added from any data-defined widget when needed. Be aware that this information will NOT be saved in you datasource but only in the project file.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
</widget>
</item>
</layout>

View File

@ -186,6 +186,7 @@ ADD_PYTHON_TEST(PyQgsZipUtils test_qgsziputils.py)
ADD_PYTHON_TEST(PyQgsSourceSelectProvider test_qgssourceselectprovider.py)
ADD_PYTHON_TEST(PyQgsAuthManagerProxy test_authmanager_proxy.py)
ADD_PYTHON_TEST(PyQgsAuthSettingsWidget test_authsettingswidget.py)
ADD_PYTHON_TEST(PyQgsAuxiliaryStorage test_qgsauxiliarystorage.py)
IF (NOT WIN32)
ADD_PYTHON_TEST(PyQgsLogger test_qgslogger.py)

View File

@ -0,0 +1,390 @@
# -*- coding: utf-8 -*-
"""QGIS Unit tests for Auxiliary Storage.
.. note:: This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
"""
__author__ = 'Paul Blottiere'
__date__ = '06/09/2017'
__copyright__ = 'Copyright 2017, The QGIS Project'
# This will get replaced with a git SHA1 when you do a git archive
__revision__ = '$Format:%H$'
import qgis # NOQA
import os
from qgis.PyQt.QtCore import QTemporaryFile
from qgis.core import (QgsAuxiliaryStorage,
QgsAuxiliaryLayer,
QgsVectorLayer,
QgsFeature,
QgsGeometry,
QgsPropertyDefinition,
QgsProject,
QgsFeatureRequest,
QgsPalLayerSettings,
QgsSymbolLayer,
QgsVectorLayerSimpleLabeling,
NULL)
from qgis.testing import start_app, unittest
from utilities import unitTestDataPath, writeShape
start_app()
def tmpPath():
f = QTemporaryFile()
f.open()
f.close()
os.remove(f.fileName())
return f.fileName()
def createLayer():
vl = QgsVectorLayer(
'Point?crs=epsg:4326&field=pk:integer&field=cnt:integer&field=name:string(0)&field=name2:string(0)&field=num_char:string&key=pk', 'test', 'memory')
assert (vl.isValid())
f1 = QgsFeature()
f1.setAttributes([5, -200, NULL, 'NuLl', '5'])
f1.setGeometry(QgsGeometry.fromWkt('Point (-71.123 78.23)'))
f2 = QgsFeature()
f2.setAttributes([3, 300, 'Pear', 'PEaR', '3'])
f3 = QgsFeature()
f3.setAttributes([1, 100, 'Orange', 'oranGe', '1'])
f3.setGeometry(QgsGeometry.fromWkt('Point (-70.332 66.33)'))
f4 = QgsFeature()
f4.setAttributes([2, 200, 'Apple', 'Apple', '2'])
f4.setGeometry(QgsGeometry.fromWkt('Point (-68.2 70.8)'))
f5 = QgsFeature()
f5.setAttributes([4, 400, 'Honey', 'Honey', '4'])
f5.setGeometry(QgsGeometry.fromWkt('Point (-65.32 78.3)'))
vl.dataProvider().addFeatures([f1, f2, f3, f4, f5])
return vl
class TestQgsAuxiliaryStorage(unittest.TestCase):
def testCreateSaveOpenStorageWithString(self):
# Empty string in copy mode. A new database is created in a temporary
# file.
s0 = QgsAuxiliaryStorage()
self.assertTrue(s0.isValid())
# saveAs should be used instead of save in case of an empty string
# given to the constructor of QgsAuxiliaryStorage
self.assertEqual(s0.fileName(), "")
self.assertFalse(s0.save())
# Create a new auxiliary layer with 'pk' as key
vl0 = createLayer()
pkf = vl0.fields().field(vl0.fields().indexOf('pk'))
al0 = s0.createAuxiliaryLayer(pkf, vl0)
self.assertTrue(al0.isValid())
# Test the auxiliary key
key = al0.joinInfo().targetFieldName()
self.assertEqual(key, 'pk')
# Add a field in auxiliary layer
p = QgsPropertyDefinition('propName', QgsPropertyDefinition.DataTypeNumeric, '', '', 'user')
self.assertTrue(al0.addAuxiliaryField(p))
# saveAs without saving the auxiliary layer, the auxiliary field is lost
f = tmpPath()
self.assertTrue(s0.saveAs(f))
# Open the previous database.
s1 = QgsAuxiliaryStorage(f)
self.assertTrue(s1.isValid())
# Load the auxiliary layer from auxiliary storage
self.assertTrue(vl0.loadAuxiliaryLayer(s1, key))
# As the vl0 has not been saved before saving the storage, there
# shouldn't have auxiliary fields
self.assertEqual(len(vl0.auxiliaryLayer().auxiliaryFields()), 0)
# Save the layer before saving the storage
self.assertTrue(al0.save())
self.assertTrue(s0.saveAs(f))
# Open the previous database.
s2 = QgsAuxiliaryStorage(f)
self.assertTrue(s2.isValid())
# Load the auxiliary layer from auxiliary storage
self.assertTrue(vl0.loadAuxiliaryLayer(s2, key))
# As the vl0 has been saved before saving the storage, there
# should have 1 auxiliary field
self.assertEqual(len(vl0.auxiliaryLayer().auxiliaryFields()), 1)
# save is available on s2
self.assertTrue(s2.save())
def testCreateSaveOpenStorageWithProject(self):
# New project without fileName
p = QgsProject()
# Create storage
s0 = QgsAuxiliaryStorage(p)
self.assertTrue(s0.isValid())
# saveAs should be used instead of save in case of an empty string
# given to the constructor of QgsAuxiliaryStorage
self.assertEqual(s0.fileName(), "")
self.assertFalse(s0.save())
# saveAs
f = tmpPath()
self.assertTrue(s0.saveAs(f))
def testProjectStorage(self):
# New project without fileName
p0 = QgsProject()
self.assertTrue(p0.auxiliaryStorage().isValid())
# Create new layers with key otherwise auxiliary layers are not
# automacially created when added in project
vl0 = createLayer()
vl0Shp = writeShape(vl0, 'vl0.shp')
vl1 = createLayer()
vl1Shp = writeShape(vl1, 'vl1.shp')
vl0 = QgsVectorLayer(vl0Shp, 'points', 'ogr')
self.assertTrue(vl0.isValid())
vl1 = QgsVectorLayer(vl1Shp, 'points', 'ogr')
self.assertTrue(vl1.isValid())
# Add layers to project and check underlying auxiliary layers
p0.addMapLayers([vl0, vl1])
self.assertTrue(vl0.loadAuxiliaryLayer(p0.auxiliaryStorage(), 'pk'))
self.assertTrue(vl1.loadAuxiliaryLayer(p0.auxiliaryStorage(), 'num_char'))
al0 = vl0.auxiliaryLayer()
al1 = vl1.auxiliaryLayer()
self.assertEqual(al0.joinInfo().targetFieldName(), 'pk')
self.assertEqual(al1.joinInfo().targetFieldName(), 'num_char')
# Add a field in auxiliary layers
pdef0 = QgsPropertyDefinition('propname', QgsPropertyDefinition.DataTypeNumeric, '', '', 'ut')
self.assertTrue(al0.addAuxiliaryField(pdef0))
pdef1 = QgsPropertyDefinition('propname1', QgsPropertyDefinition.DataTypeString, '', '', 'ut')
self.assertTrue(al1.addAuxiliaryField(pdef1))
# Check auxiliary fields names
af0Name = QgsAuxiliaryLayer.nameFromProperty(pdef0, False)
self.assertEqual(af0Name, 'ut_propname')
af1Name = QgsAuxiliaryLayer.nameFromProperty(pdef1, False)
self.assertEqual(af1Name, 'ut_propname1')
# Set value for auxiliary fields
req = QgsFeatureRequest().setFilterExpression("name = 'Honey'")
f = QgsFeature()
vl0.getFeatures(req).nextFeature(f)
self.assertTrue(f.isValid())
af0Name = QgsAuxiliaryLayer.nameFromProperty(pdef0, True)
index0 = vl0.fields().indexOf(af0Name)
vl0.changeAttributeValue(f.id(), index0, 333)
req = QgsFeatureRequest().setFilterExpression("name = 'Apple'")
f = QgsFeature()
vl1.getFeatures(req).nextFeature(f)
self.assertTrue(f.isValid())
af1Name = QgsAuxiliaryLayer.nameFromProperty(pdef1, True)
index1 = vl1.fields().indexOf(af1Name)
vl1.changeAttributeValue(f.id(), index0, 'myvalue')
req = QgsFeatureRequest().setFilterExpression("name = 'Orange'")
f = QgsFeature()
vl1.getFeatures(req).nextFeature(f)
self.assertTrue(f.isValid())
vl1.changeAttributeValue(f.id(), index0, 'myvalue1')
# Save the project in a zip file
f = tmpPath() + '.qgz'
p0.write(f)
# Open the zip file with embedded auxiliary storage
p1 = QgsProject()
p1.read(f)
# Check that auxiliary fields are well loaded in layers
self.assertEqual(len(p1.mapLayers().values()), 2)
for vl in p1.mapLayers().values():
al = vl.auxiliaryLayer()
self.assertEqual(len(al.auxiliaryFields()), 1)
af = al.auxiliaryFields()[0]
afPropDef = QgsAuxiliaryLayer.propertyDefinitionFromField(af)
self.assertEqual(afPropDef.origin(), 'ut')
if vl.auxiliaryLayer().joinInfo().targetFieldName() == 'pk':
self.assertEqual(afPropDef.name(), 'propname')
self.assertEqual(al.featureCount(), 1)
req = QgsFeatureRequest().setFilterExpression("name = 'Honey'")
f = QgsFeature()
vl.getFeatures(req).nextFeature(f)
self.assertTrue(f.isValid())
self.assertEqual(f.attributes()[index0], 333.0)
else: # num_char
self.assertEqual(al.featureCount(), 2)
self.assertEqual(afPropDef.name(), 'propname1')
req = QgsFeatureRequest().setFilterExpression("name = 'Apple'")
f = QgsFeature()
vl.getFeatures(req).nextFeature(f)
self.assertTrue(f.isValid())
self.assertEqual(f.attributes()[index1], 'myvalue')
req = QgsFeatureRequest().setFilterExpression("name = 'Orange'")
f = QgsFeature()
vl.getFeatures(req).nextFeature(f)
self.assertTrue(f.isValid())
self.assertEqual(f.attributes()[index1], 'myvalue1')
def testAuxiliaryFieldWidgets(self):
# Init storage
s = QgsAuxiliaryStorage()
self.assertTrue(s.isValid())
# Create a new auxiliary layer with 'pk' as key
vl = createLayer()
pkf = vl.fields().field(vl.fields().indexOf('pk'))
al = s.createAuxiliaryLayer(pkf, vl)
self.assertTrue(al.isValid())
# Set the auxiliary layer to the vector layer
vl.setAuxiliaryLayer(al)
# Add a visible property
p = QgsPropertyDefinition('propName', QgsPropertyDefinition.DataTypeNumeric, '', '', 'user')
self.assertTrue(al.addAuxiliaryField(p))
index = al.indexOfPropertyDefinition(p)
self.assertFalse(al.isHiddenProperty(index))
afName = QgsAuxiliaryLayer.nameFromProperty(p, True)
index = vl.fields().indexOf(afName)
setup = vl.editorWidgetSetup(index)
self.assertEqual(setup.type(), '')
tested = False
for c in vl.attributeTableConfig().columns():
if c.name == afName:
self.assertFalse(c.hidden)
tested = True
break
self.assertTrue(tested)
# Add a hidden property
p = QgsPalLayerSettings.propertyDefinitions()[QgsPalLayerSettings.PositionX]
self.assertTrue(al.addAuxiliaryField(p))
index = al.indexOfPropertyDefinition(p)
self.assertTrue(al.isHiddenProperty(index))
afName = QgsAuxiliaryLayer.nameFromProperty(p, True)
index = vl.fields().indexOf(afName)
setup = vl.editorWidgetSetup(index)
self.assertEqual(setup.type(), 'Hidden')
tested = False
for c in vl.attributeTableConfig().columns():
if c.name == afName:
self.assertTrue(c.hidden)
tested = True
break
self.assertTrue(tested)
# Add a color property
p = QgsSymbolLayer.propertyDefinitions()[QgsSymbolLayer.PropertyFillColor]
self.assertTrue(al.addAuxiliaryField(p))
index = al.indexOfPropertyDefinition(p)
self.assertFalse(al.isHiddenProperty(index))
afName = QgsAuxiliaryLayer.nameFromProperty(p, True)
index = vl.fields().indexOf(afName)
setup = vl.editorWidgetSetup(index)
self.assertEqual(setup.type(), 'Color')
def testClear(self):
s = QgsAuxiliaryStorage()
self.assertTrue(s.isValid())
# Create a new auxiliary layer with 'pk' as key
vl = createLayer()
pkf = vl.fields().field(vl.fields().indexOf('pk'))
al = s.createAuxiliaryLayer(pkf, vl)
self.assertTrue(al.isValid())
vl.setAuxiliaryLayer(al)
# Add a field in auxiliary layer
p = QgsPropertyDefinition('myprop', QgsPropertyDefinition.DataTypeNumeric, '', '', 'me')
self.assertFalse(al.exists(p))
self.assertTrue(al.addAuxiliaryField(p))
self.assertTrue(al.exists(p))
# Count auxiliary features
self.assertEqual(al.featureCount(), 0)
# Set value for auxiliary fields
req = QgsFeatureRequest().setFilterExpression("name = 'Honey'")
f = QgsFeature()
vl.getFeatures(req).nextFeature(f)
self.assertTrue(f.isValid())
afName = QgsAuxiliaryLayer.nameFromProperty(p, True)
index = vl.fields().indexOf(afName)
vl.changeAttributeValue(f.id(), index, 333)
# Count auxiliary features
self.assertEqual(al.featureCount(), 1)
# Clear and count
al.clear()
self.assertEqual(al.featureCount(), 0)
def testCreateProperty(self):
s = QgsAuxiliaryStorage()
self.assertTrue(s.isValid())
# Create a new auxiliary layer with 'pk' as key
vl = createLayer()
pkf = vl.fields().field(vl.fields().indexOf('pk'))
al = s.createAuxiliaryLayer(pkf, vl)
self.assertTrue(al.isValid())
vl.setAuxiliaryLayer(al)
# Create a new labeling property on layer without labels
key = QgsPalLayerSettings.PositionX
index = QgsAuxiliaryLayer.createProperty(key, vl)
self.assertEqual(index, -1)
vl.setLabeling(QgsVectorLayerSimpleLabeling(QgsPalLayerSettings()))
index = QgsAuxiliaryLayer.createProperty(key, vl)
p = QgsPalLayerSettings.propertyDefinitions()[key]
afName = QgsAuxiliaryLayer.nameFromProperty(p, True)
afIndex = vl.fields().indexOf(afName)
self.assertEqual(index, afIndex)
if __name__ == '__main__':
unittest.main()

View File

@ -123,6 +123,8 @@ def writeShape(theMemoryLayer, theFileName):
mySkipAttributesFlag)
assert myResult == QgsVectorFileWriter.NoError, 'Writing shape failed, Error {} ({})'.format(myResult, myErrorMessage)
return myFileName
def doubleNear(a, b, tol=0.0000000001):
"""