diff --git a/images/images.qrc b/images/images.qrc
index 91542695ae3..e59a74bcb32 100644
--- a/images/images.qrc
+++ b/images/images.qrc
@@ -485,6 +485,7 @@
themes/default/unlocked.svg
themes/default/unlockedGray.svg
themes/default/user.svg
+ themes/default/mIconAuxiliaryStorage.svg
flags/eu.png
flags/bn.png
flags/gl.png
diff --git a/images/themes/default/mIconAuxiliaryStorage.svg b/images/themes/default/mIconAuxiliaryStorage.svg
new file mode 100644
index 00000000000..af064264ee8
--- /dev/null
+++ b/images/themes/default/mIconAuxiliaryStorage.svg
@@ -0,0 +1,280 @@
+
+
diff --git a/python/core/core_auto.sip b/python/core/core_auto.sip
index d18431bff75..23f21d1d293 100644
--- a/python/core/core_auto.sip
+++ b/python/core/core_auto.sip
@@ -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
diff --git a/python/core/qgsarchive.sip b/python/core/qgsarchive.sip
index e6c6effa3f2..a2a68c22875 100644
--- a/python/core/qgsarchive.sip
+++ b/python/core/qgsarchive.sip
@@ -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
};
/************************************************************************
diff --git a/python/core/qgsauxiliarystorage.sip b/python/core/qgsauxiliarystorage.sip
new file mode 100644
index 00000000000..7f10e460b73
--- /dev/null
+++ b/python/core/qgsauxiliarystorage.sip
@@ -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 *
+ ************************************************************************/
diff --git a/python/core/qgsproject.sip b/python/core/qgsproject.sip
index d9b03e6db1e..3d4dc8f4d54 100644
--- a/python/core/qgsproject.sip
+++ b/python/core/qgsproject.sip
@@ -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
diff --git a/python/core/qgsproperty.sip b/python/core/qgsproperty.sip
index 481b7366a3f..07a437e2807 100644
--- a/python/core/qgsproperty.sip
+++ b/python/core/qgsproperty.sip
@@ -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.
diff --git a/python/core/qgsrulebasedlabeling.sip b/python/core/qgsrulebasedlabeling.sip
index d5876aa7d09..372462c7276 100644
--- a/python/core/qgsrulebasedlabeling.sip
+++ b/python/core/qgsrulebasedlabeling.sip
@@ -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;
diff --git a/python/core/qgsvectorlayer.sip b/python/core/qgsvectorlayer.sip
index a1827cd1d29..dc831d58175 100644
--- a/python/core/qgsvectorlayer.sip
+++ b/python/core/qgsvectorlayer.sip
@@ -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
diff --git a/python/core/qgsvectorlayerjoinbuffer.sip b/python/core/qgsvectorlayerjoinbuffer.sip
index 84f75066c99..42e59063cf4 100644
--- a/python/core/qgsvectorlayerjoinbuffer.sip
+++ b/python/core/qgsvectorlayerjoinbuffer.sip
@@ -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
diff --git a/python/core/qgsvectorlayerjoininfo.sip b/python/core/qgsvectorlayerjoininfo.sip
index 9dfab650625..50965ef932a 100644
--- a/python/core/qgsvectorlayerjoininfo.sip
+++ b/python/core/qgsvectorlayerjoininfo.sip
@@ -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
+
};
diff --git a/python/core/qgsvectorlayerlabeling.sip b/python/core/qgsvectorlayerlabeling.sip
index f733f081c71..eeef3c6cf08 100644
--- a/python/core/qgsvectorlayerlabeling.sip
+++ b/python/core/qgsvectorlayerlabeling.sip
@@ -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;
diff --git a/python/core/symbology/qgssymbollayerregistry.sip b/python/core/symbology/qgssymbollayerregistry.sip
index e4549a733f5..d10dcad0f95 100644
--- a/python/core/symbology/qgssymbollayerregistry.sip
+++ b/python/core/symbology/qgssymbollayerregistry.sip
@@ -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 );
diff --git a/python/gui/gui_auto.sip b/python/gui/gui_auto.sip
index 565eca356e4..b4a496963c2 100644
--- a/python/gui/gui_auto.sip
+++ b/python/gui/gui_auto.sip
@@ -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
diff --git a/python/gui/qgsnewauxiliaryfielddialog.sip b/python/gui/qgsnewauxiliaryfielddialog.sip
new file mode 100644
index 00000000000..c75e67e6de8
--- /dev/null
+++ b/python/gui/qgsnewauxiliaryfielddialog.sip
@@ -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 *
+ ************************************************************************/
diff --git a/python/gui/qgsnewauxiliarylayerdialog.sip b/python/gui/qgsnewauxiliarylayerdialog.sip
new file mode 100644
index 00000000000..f861c469c74
--- /dev/null
+++ b/python/gui/qgsnewauxiliarylayerdialog.sip
@@ -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 *
+ ************************************************************************/
diff --git a/python/gui/qgspropertyoverridebutton.sip b/python/gui/qgspropertyoverridebutton.sip
index 4d82b727380..fe6bdbb3fb7 100644
--- a/python/gui/qgspropertyoverridebutton.sip
+++ b/python/gui/qgspropertyoverridebutton.sip
@@ -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:
diff --git a/python/gui/symbology/qgsarrowsymbollayerwidget.sip b/python/gui/symbology/qgsarrowsymbollayerwidget.sip
index 8ed0d9abd8e..2d37165b32b 100644
--- a/python/gui/symbology/qgsarrowsymbollayerwidget.sip
+++ b/python/gui/symbology/qgsarrowsymbollayerwidget.sip
@@ -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
diff --git a/python/gui/symbology/qgsellipsesymbollayerwidget.sip b/python/gui/symbology/qgsellipsesymbollayerwidget.sip
index efe01af92c3..772b0e3f5bd 100644
--- a/python/gui/symbology/qgsellipsesymbollayerwidget.sip
+++ b/python/gui/symbology/qgsellipsesymbollayerwidget.sip
@@ -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
diff --git a/python/gui/symbology/qgslayerpropertieswidget.sip b/python/gui/symbology/qgslayerpropertieswidget.sip
index 40b28e4fa77..07a44a3e420 100644
--- a/python/gui/symbology/qgslayerpropertieswidget.sip
+++ b/python/gui/symbology/qgslayerpropertieswidget.sip
@@ -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
diff --git a/python/gui/symbology/qgssymbollayerwidget.sip b/python/gui/symbology/qgssymbollayerwidget.sip
index 2ea46895fc0..c9239fea3ef 100644
--- a/python/gui/symbology/qgssymbollayerwidget.sip
+++ b/python/gui/symbology/qgssymbollayerwidget.sip
@@ -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
diff --git a/python/gui/symbology/qgssymbolselectordialog.sip b/python/gui/symbology/qgssymbolselectordialog.sip
index aa9e71c2050..657dc0963ba 100644
--- a/python/gui/symbology/qgssymbolselectordialog.sip
+++ b/python/gui/symbology/qgssymbolselectordialog.sip
@@ -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();
diff --git a/python/gui/symbology/qgssymbolslistwidget.sip b/python/gui/symbology/qgssymbolslistwidget.sip
index 8d51c063bbf..94b1a8e38c3 100644
--- a/python/gui/symbology/qgssymbolslistwidget.sip
+++ b/python/gui/symbology/qgssymbolslistwidget.sip
@@ -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();
diff --git a/python/gui/symbology/qgsvectorfieldsymbollayerwidget.sip b/python/gui/symbology/qgsvectorfieldsymbollayerwidget.sip
index 046ae80d018..0bbbff6f51d 100644
--- a/python/gui/symbology/qgsvectorfieldsymbollayerwidget.sip
+++ b/python/gui/symbology/qgsvectorfieldsymbollayerwidget.sip
@@ -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
diff --git a/src/app/main.cpp b/src/app/main.cpp
index 4532329938e..fd5d0ee8ec6 100644
--- a/src/app/main.cpp
+++ b/src/app/main.cpp
@@ -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 );
}
diff --git a/src/app/qgisapp.cpp b/src/app/qgisapp.cpp
index e22336be991..bfc4b9114e5 100644
--- a/src/app/qgisapp.cpp
+++ b/src/app/qgisapp.cpp
@@ -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( activeLayer() );
+ if ( !rasterLayer )
+ rasterLayer = qobject_cast( 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( layer ) );
}
else if ( layerType == QgsMapLayer::VectorLayer )
{
- saveAsVectorFileGeneral();
+ saveAsVectorFileGeneral( qobject_cast( 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 &lyrList )
}
else if ( vlayer )
{
+ if ( vlayer->auxiliaryLayer() )
+ vlayer->auxiliaryLayer()->save();
+
dupLayer = vlayer->clone();
}
}
@@ -10993,38 +11008,16 @@ void QgisApp::updateLabelToolButtons()
for ( QMap::iterator it = layers.begin(); it != layers.end(); ++it )
{
QgsVectorLayer *vlayer = qobject_cast( 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( mMapTools.mPinLabels ) &&
- ( qobject_cast( mMapTools.mPinLabels )->labelMoveable( vlayer, colX, colY )
- || qobject_cast( mMapTools.mPinLabels )->diagramMoveable( vlayer, colX, colY ) ) );
-
- enableShowHide =
- enableShowHide ||
- ( qobject_cast( mMapTools.mShowHideLabels ) &&
- ( qobject_cast( mMapTools.mShowHideLabels )->labelCanShowHide( vlayer, colShow )
- || qobject_cast( mMapTools.mShowHideLabels )->diagramCanShowHide( vlayer, colShow ) ) );
-
- enableMove =
- enableMove ||
- ( qobject_cast( mMapTools.mMoveLabel ) &&
- ( qobject_cast( mMapTools.mMoveLabel )->labelMoveable( vlayer, colX, colY )
- || qobject_cast( mMapTools.mMoveLabel )->diagramMoveable( vlayer, colX, colY ) ) );
-
- enableRotate =
- enableRotate ||
- ( qobject_cast( mMapTools.mRotateLabel ) &&
- qobject_cast( mMapTools.mRotateLabel )->layerIsRotatable( vlayer, colAng ) );
-
- enableChange = true;
-
- if ( enablePin && enableShowHide && enableMove && enableRotate && enableChange )
break;
+ }
}
mActionPinLabels->setEnabled( enablePin );
diff --git a/src/app/qgisapp.h b/src/app/qgisapp.h
index 7fd1c981728..246515bedc5 100644
--- a/src/app/qgisapp.h
+++ b/src/app/qgisapp.h
@@ -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();
diff --git a/src/app/qgsdiagramproperties.cpp b/src/app/qgsdiagramproperties.cpp
index dfefc578810..96c20001fbc 100644
--- a/src/app/qgsdiagramproperties.cpp
+++ b/src/app/qgsdiagramproperties.cpp
@@ -39,6 +39,8 @@
#include "qgslogger.h"
#include "qgisapp.h"
#include "qgssettings.h"
+#include "qgsnewauxiliarylayerdialog.h"
+#include "qgsauxiliarystorage.h"
#include
#include
@@ -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( 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();
+}
diff --git a/src/app/qgsdiagramproperties.h b/src/app/qgsdiagramproperties.h
index 75ef8400bf3..fb3ee6b8dd0 100644
--- a/src/app/qgsdiagramproperties.h
+++ b/src/app/qgsdiagramproperties.h
@@ -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
diff --git a/src/app/qgslabelinggui.cpp b/src/app/qgslabelinggui.cpp
index 6578738da94..3d11e6e8611 100644
--- a/src/app/qgslabelinggui.cpp
+++ b/src/app/qgslabelinggui.cpp
@@ -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( 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 );
+ }
+}
diff --git a/src/app/qgslabelinggui.h b/src/app/qgslabelinggui.h
index dac721c8d0f..fb9fcedd093 100644
--- a/src/app/qgslabelinggui.h
+++ b/src/app/qgslabelinggui.h
@@ -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 mButtons;
+
private slots:
void updateProperty();
diff --git a/src/app/qgslabelingwidget.cpp b/src/app/qgslabelingwidget.cpp
index 1c8e13232ed..a813582d2a0 100644
--- a/src/app/qgslabelingwidget.cpp
+++ b/src/app/qgslabelingwidget.cpp
@@ -40,6 +40,11 @@ QgsLabelingWidget::QgsLabelingWidget( QgsVectorLayer *layer, QgsMapCanvas *canva
setLayer( layer );
}
+QgsLabelingGui *QgsLabelingWidget::labelingGui()
+{
+ return qobject_cast( mWidget );
+}
+
void QgsLabelingWidget::resetSettings()
{
if ( mOldSettings )
@@ -96,6 +101,12 @@ void QgsLabelingWidget::adaptToLayer()
{
mLabelModeComboBox->setCurrentIndex( 0 );
}
+
+ QgsLabelingGui *lg = qobject_cast( 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 );
diff --git a/src/app/qgslabelingwidget.h b/src/app/qgslabelingwidget.h
index 7d3e42e971b..aaf272d6fcf 100644
--- a/src/app/qgslabelingwidget.h
+++ b/src/app/qgslabelingwidget.h
@@ -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();
diff --git a/src/app/qgslabelpropertydialog.cpp b/src/app/qgslabelpropertydialog.cpp
index 4b4d98ba97a..a9684fa0608 100644
--- a/src/app/qgslabelpropertydialog.cpp
+++ b/src/app/qgslabelpropertydialog.cpp
@@ -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() )
{
diff --git a/src/app/qgsmaptoolchangelabelproperties.cpp b/src/app/qgsmaptoolchangelabelproperties.cpp
index 60eeb2e16fc..9cdde66359b 100644
--- a/src/app/qgsmaptoolchangelabelproperties.cpp
+++ b/src/app/qgsmaptoolchangelabelproperties.cpp
@@ -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 )
diff --git a/src/app/qgsmaptoollabel.cpp b/src/app/qgsmaptoollabel.cpp
index 66b3bb4efc1..56acccbba58 100644
--- a/src/app/qgsmaptoollabel.cpp
+++ b/src/app/qgsmaptoollabel.cpp
@@ -25,6 +25,9 @@
#include "qgsvectorlayerlabeling.h"
#include "qgsdiagramrenderer.h"
#include "qgssettings.h"
+#include "qgsvectorlayerjoininfo.h"
+#include "qgsvectorlayerjoinbuffer.h"
+#include "qgsauxiliarystorage.h"
#include
@@ -688,14 +691,14 @@ QgsMapToolLabel::LabelDetails::LabelDetails( const QgsLabelPosition &p )
: pos( p )
{
layer = qobject_cast( 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;
+}
diff --git a/src/app/qgsmaptoollabel.h b/src/app/qgsmaptoollabel.h
index 055ce2bea25..72f3d1eea32 100644
--- a/src/app/qgsmaptoollabel.h
+++ b/src/app/qgsmaptoollabel.h
@@ -20,10 +20,15 @@
#include "qgsmaptool.h"
#include "qgspallabeling.h"
+#include "qgsnewauxiliarylayerdialog.h"
+#include "qgsauxiliarystorage.h"
#include "qgis_app.h"
class QgsRubberBand;
+typedef QMap QgsPalIndexes;
+typedef QMap 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 mPalProperties;
+ QList mDiagramProperties;
};
#endif // QGSMAPTOOLLABEL_H
diff --git a/src/app/qgsmaptoolmovelabel.cpp b/src/app/qgsmaptoolmovelabel.cpp
index 95af8dfa04c..330c0e65c25 100644
--- a/src/app/qgsmaptoolmovelabel.cpp
+++ b/src/app/qgsmaptoolmovelabel.cpp
@@ -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;
}
diff --git a/src/app/qgsmaptoolpinlabels.cpp b/src/app/qgsmaptoolpinlabels.cpp
index 256ae4ea3ab..c8e2f1f532f 100644
--- a/src/app/qgsmaptoolpinlabels.cpp
+++ b/src/app/qgsmaptoolpinlabels.cpp
@@ -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 )
{
diff --git a/src/app/qgsmaptoolrotatelabel.cpp b/src/app/qgsmaptoolrotatelabel.cpp
index 93865933ee3..6307c507470 100644
--- a/src/app/qgsmaptoolrotatelabel.cpp
+++ b/src/app/qgsmaptoolrotatelabel.cpp
@@ -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 )
diff --git a/src/app/qgsmaptoolshowhidelabels.cpp b/src/app/qgsmaptoolshowhidelabels.cpp
index fd0b3496198..cceef95ca2a 100644
--- a/src/app/qgsmaptoolshowhidelabels.cpp
+++ b/src/app/qgsmaptoolshowhidelabels.cpp
@@ -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( 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( 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 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 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;
}
diff --git a/src/app/qgsmaptoolshowhidelabels.h b/src/app/qgsmaptoolshowhidelabels.h
index 14346e147a9..0f8ffd53dc7 100644
--- a/src/app/qgsmaptoolshowhidelabels.h
+++ b/src/app/qgsmaptoolshowhidelabels.h
@@ -64,8 +64,7 @@ class APP_EXPORT QgsMapToolShowHideLabels : public QgsMapToolLabel
bool selectedLabelFeatures( QgsVectorLayer *vlayer,
QList &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
diff --git a/src/app/qgsvectorlayerproperties.cpp b/src/app/qgsvectorlayerproperties.cpp
index 7d6afe4a483..873f4c39bf9 100644
--- a/src/app/qgsvectorlayerproperties.cpp
+++ b/src/app/qgsvectorlayerproperties.cpp
@@ -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 clone;
+ clone.reset( alayer->toSpatialLayer() );
+
+ QgisApp::instance()->saveAsFile( clone.get() );
+}
+
+void QgsVectorLayerProperties::onAuxiliaryLayerDeleteField()
+{
+ QgsAuxiliaryLayer *alayer = mLayer->auxiliaryLayer();
+ if ( !alayer )
+ return;
+
+ QList 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();
+ }
+}
diff --git a/src/app/qgsvectorlayerproperties.h b/src/app/qgsvectorlayerproperties.h
index 13986419ec6..fe39d633b03 100644
--- a/src/app/qgsvectorlayerproperties.h
+++ b/src/app/qgsvectorlayerproperties.h
@@ -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 );
};
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index c0f5807c4a4..a52111947fd 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -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
diff --git a/src/core/qgsarchive.cpp b/src/core/qgsarchive.cpp
index 3ab36e7a6f4..3a504c5caf3 100644
--- a/src/core/qgsarchive.cpp
+++ b/src/core/qgsarchive.cpp
@@ -19,6 +19,7 @@
#include "qgsarchive.h"
#include "qgsziputils.h"
#include "qgsmessagelog.h"
+#include "qgsauxiliarystorage.h"
#include
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();
+}
diff --git a/src/core/qgsarchive.h b/src/core/qgsarchive.h
index a40577ef072..7fb0f1c54db 100644
--- a/src/core/qgsarchive.h
+++ b/src/core/qgsarchive.h
@@ -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
diff --git a/src/core/qgsauxiliarystorage.cpp b/src/core/qgsauxiliarystorage.cpp
new file mode 100644
index 00000000000..274572be1df
--- /dev/null
+++ b/src/core/qgsauxiliarystorage.cpp
@@ -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
+
+const QString AS_JOINFIELD = "ASPK";
+const QString AS_EXTENSION = "qgd";
+const QString AS_JOINPREFIX = "auxiliary_storage_";
+
+const QVector 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 columns = attrCfg.columns();
+ QVector::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;
+}
diff --git a/src/core/qgsauxiliarystorage.h b/src/core/qgsauxiliarystorage.h
new file mode 100644
index 00000000000..5e2762660c8
--- /dev/null
+++ b/src/core/qgsauxiliarystorage.h
@@ -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
+
+#include
+
+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
diff --git a/src/core/qgsdiagramrenderer.cpp b/src/core/qgsdiagramrenderer.cpp
index 55188baf8c0..a804e9316ce 100644
--- a/src/core/qgsdiagramrenderer.cpp
+++ b/src/core/qgsdiagramrenderer.cpp
@@ -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 ) },
};
}
diff --git a/src/core/qgspallabeling.cpp b/src/core/qgspallabeling.cpp
index 1bd722c129a..fc332195fdc 100644
--- a/src/core/qgspallabeling.cpp
+++ b/src/core/qgspallabeling.cpp
@@ -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( "[family|family[foundry]],
"
- "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( "[font style name|Ignore],
"
- "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( "[NoChange|Upper|
Lower|Capitalize]" ) ) },
- { 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 " ) + "[Left|Center|Right|Follow]" ) },
- { 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 " ) + "[LeftRight|Above|Below]" ) },
- { 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( "[NoChange|Upper|
Lower|Capitalize]" ), 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 " ) + "[Left|Center|Right|Follow]", 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 " ) + "[LeftRight|Above|Below]", 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( "[Rectangle|Square|
"
- "Ellipse|Circle|SVG]" ) )
+ "Ellipse|Circle|SVG]" ), 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 " ) + "[Buffer|Fixed]" ) },
- { 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 " ) + "[Sync|Offset|Fixed]" ) },
- { 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 " ) + "[Buffer|Fixed]", 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 " ) + "[Sync|Offset|Fixed]", 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( "[Lowest|Text|
"
- "Buffer|Background]" ) )
+ "Buffer|Background]" ), 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 " ) + "[Visible|Whole]" ) },
+ { QgsPalLayerSettings::CentroidWhole, QgsPropertyDefinition( "CentroidWhole", QgsPropertyDefinition::DataTypeString, QObject::tr( "Centroid of whole shape" ), QObject::tr( "string " ) + "[Visible|Whole]", origin ) },
{
QgsPalLayerSettings::OffsetQuad, QgsPropertyDefinition( "OffsetQuad", QgsPropertyDefinition::DataTypeString, QObject::tr( "Offset quadrant" ), QObject::tr( "int
" ) + QStringLiteral( "[0=Above Left|1=Above|2=Above Right|
"
"3=Left|4=Over|5=Right|
"
- "6=Below Left|7=Below|8=Below Right]" ) )
+ "6=Below Left|7=Below|8=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 [in,out 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 [in,out 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
" )
+ QStringLiteral( "[TL=Top left|TSL=Top, slightly left|T=Top middle|
"
"TSR=Top, slightly right|TR=Top right|
"
"L=Left|R=Right|
"
"BL=Bottom left|BSL=Bottom, slightly left|B=Bottom middle|
"
- "BSR=Bottom, slightly right|BR=Bottom right]" ) )
+ "BSR=Bottom, slightly right|BR=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 " ) + "[Left|Center|Right]" ) },
+ { 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 " ) + "[Left|Center|Right]", origin ) },
{
QgsPalLayerSettings::Vali, QgsPropertyDefinition( "Vali", QgsPropertyDefinition::DataTypeString, QObject::tr( "Vertical alignment" ), QObject::tr( "string " ) + QStringLiteral( "[Bottom|Base|
"
- "Half|Cap|Top]" ) )
+ "Half|Cap|Top]" ), 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 ) },
};
}
diff --git a/src/core/qgsproject.cpp b/src/core/qgsproject.cpp
index 02a73ed25b3..1dd3e6890f3 100644
--- a/src/core/qgsproject.cpp
+++ b/src/core/qgsproject.cpp
@@ -49,6 +49,7 @@
#include "qgslayoutmanager.h"
#include "qgsmaplayerstore.h"
#include "qgsziputils.h"
+#include "qgsauxiliarystorage.h"
#include
#include
@@ -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 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 QgsProject::addMapLayers(
if ( addToLegend )
emit legendLayersAdded( myResultList );
}
+
+ if ( mAuxiliaryStorage )
+ {
+ for ( QgsMapLayer *mlayer : myResultList )
+ {
+ if ( mlayer->type() != QgsMapLayer::VectorLayer )
+ continue;
+
+ QgsVectorLayer *vl = qobject_cast( 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( 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();
+}
diff --git a/src/core/qgsproject.h b/src/core/qgsproject.h
index 7b6cb23d41f..1f1a732ecf6 100644
--- a/src/core/qgsproject.h
+++ b/src/core/qgsproject.h
@@ -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 mArchive;
+ std::unique_ptr mAuxiliaryStorage;
+
QFile mFile; // current physical project file
mutable QgsProjectPropertyKey mProperties; // property hierarchy, TODO: this shouldn't be mutable
QString mTitle; // project title
diff --git a/src/core/qgsproperty.cpp b/src/core/qgsproperty.cpp
index cffb759d19b..df1bd5e35c8 100644
--- a/src/core/qgsproperty.cpp
+++ b/src/core/qgsproperty.cpp
@@ -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 )
diff --git a/src/core/qgsproperty.h b/src/core/qgsproperty.h
index bdb8e1401ae..d25d1bf3d11 100644
--- a/src/core/qgsproperty.h
+++ b/src/core/qgsproperty.h
@@ -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();
};
diff --git a/src/core/qgsrulebasedlabeling.cpp b/src/core/qgsrulebasedlabeling.cpp
index 3a074bf12e8..f24ef6eae35 100644
--- a/src/core/qgsrulebasedlabeling.cpp
+++ b/src/core/qgsrulebasedlabeling.cpp
@@ -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 );
+ }
+}
diff --git a/src/core/qgsrulebasedlabeling.h b/src/core/qgsrulebasedlabeling.h
index 345b11fbc05..5ec565d50b6 100644
--- a/src/core/qgsrulebasedlabeling.h
+++ b/src/core/qgsrulebasedlabeling.h
@@ -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:
diff --git a/src/core/qgsvectorlayer.cpp b/src/core/qgsvectorlayer.cpp
index efce0ca51e7..d31431b5008 100644
--- a/src/core/qgsvectorlayer.cpp
+++ b/src/core/qgsvectorlayer.cpp
@@ -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 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 );
diff --git a/src/core/qgsvectorlayer.h b/src/core/qgsvectorlayer.h
index ea1676f6508..f1ca934c947 100644
--- a/src/core/qgsvectorlayer.h
+++ b/src/core/qgsvectorlayer.h
@@ -70,6 +70,8 @@ class QgsVectorLayerFeatureCounter;
class QgsAbstractVectorLayerLabeling;
class QgsPoint;
class QgsFeedback;
+class QgsAuxiliaryStorage;
+class QgsAuxiliaryLayer;
typedef QList QgsAttributeList;
typedef QSet 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 &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 mAuxiliaryLayer;
+
+ //! Key to use to join auxiliary layer
+ QString mAuxiliaryLayerKey;
+
// Features in renderer classes counted
bool mSymbolFeatureCounted = false;
diff --git a/src/core/qgsvectorlayerfeatureiterator.cpp b/src/core/qgsvectorlayerfeatureiterator.cpp
index a9c73cdf7ef..f27f19678c7 100644
--- a/src/core/qgsvectorlayerfeatureiterator.cpp
+++ b/src/core/qgsvectorlayerfeatureiterator.cpp
@@ -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 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 ) ) );
diff --git a/src/core/qgsvectorlayerjoinbuffer.cpp b/src/core/qgsvectorlayerjoinbuffer.cpp
index 2caab0521f0..ae25748435c 100644
--- a/src/core/qgsvectorlayerjoinbuffer.cpp
+++ b/src/core/qgsvectorlayerjoinbuffer.cpp
@@ -21,6 +21,7 @@
#include "qgslogger.h"
#include "qgsproject.h"
#include "qgsvectordataprovider.h"
+#include "qgsauxiliarystorage.h"
#include
@@ -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 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 subset;
- bool hasSubset = false;
- if ( joinIt->joinFieldNamesSubset() )
+ if ( joinIt->hasSubset() )
{
- hasSubset = true;
- subset = QSet::fromList( *joinIt->joinFieldNamesSubset() );
+ const QStringList subsetNames = QgsVectorLayerJoinInfo::joinFieldNamesSubset( *joinIt );
+ subset = QSet::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;
+}
diff --git a/src/core/qgsvectorlayerjoinbuffer.h b/src/core/qgsvectorlayerjoinbuffer.h
index 80414e38d5c..f1ce1847e07 100644
--- a/src/core/qgsvectorlayerjoinbuffer.h
+++ b/src/core/qgsvectorlayerjoinbuffer.h
@@ -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
diff --git a/src/core/qgsvectorlayerjoininfo.cpp b/src/core/qgsvectorlayerjoininfo.cpp
index f2556331ef3..3486452b15f 100644
--- a/src/core/qgsvectorlayerjoininfo.cpp
+++ b/src/core/qgsvectorlayerjoininfo.cpp
@@ -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;
+}
diff --git a/src/core/qgsvectorlayerjoininfo.h b/src/core/qgsvectorlayerjoininfo.h
index e2f2d03e8e1..b96035ae7b8 100644
--- a/src/core/qgsvectorlayerjoininfo.h
+++ b/src/core/qgsvectorlayerjoininfo.h
@@ -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;
diff --git a/src/core/qgsvectorlayerlabeling.cpp b/src/core/qgsvectorlayerlabeling.cpp
index 7bd8637fd73..8723b6b567a 100644
--- a/src/core/qgsvectorlayerlabeling.cpp
+++ b/src/core/qgsvectorlayerlabeling.cpp
@@ -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 );
+}
diff --git a/src/core/qgsvectorlayerlabeling.h b/src/core/qgsvectorlayerlabeling.h
index 6c48f2bc70f..f65b82b1e59 100644
--- a/src/core/qgsvectorlayerlabeling.h
+++ b/src/core/qgsvectorlayerlabeling.h
@@ -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;
diff --git a/src/core/symbology/qgssymbollayer.cpp b/src/core/symbology/qgssymbollayer.cpp
index 00ce21f0b90..61910942919 100644
--- a/src/core/symbology/qgssymbollayer.cpp
+++ b/src/core/symbology/qgssymbollayer.cpp
@@ -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( "[linear|radial|conical]" ) )},
- { QgsSymbolLayer::PropertyCoordinateMode, QgsPropertyDefinition( "gradientMode", QgsPropertyDefinition::DataTypeString, QObject::tr( "Gradient mode" ), QObject::tr( "string " ) + QLatin1String( "[feature|viewport]" ) )},
- { QgsSymbolLayer::PropertyGradientSpread, QgsPropertyDefinition( "gradientSpread", QgsPropertyDefinition::DataTypeString, QObject::tr( "Gradient spread" ), QObject::tr( "string " ) + QLatin1String( "[pad|repeat|reflect]" ) )},
- { 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( "[;] 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 " ) + "[interval|vertex|lastvertex|firstvertex|centerpoint|curvepoint]" )},
- { 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( "[linear|radial|conical]" ), origin )},
+ { QgsSymbolLayer::PropertyCoordinateMode, QgsPropertyDefinition( "gradientMode", QgsPropertyDefinition::DataTypeString, QObject::tr( "Gradient mode" ), QObject::tr( "string " ) + QLatin1String( "[feature|viewport]" ), origin )},
+ { QgsSymbolLayer::PropertyGradientSpread, QgsPropertyDefinition( "gradientSpread", QgsPropertyDefinition::DataTypeString, QObject::tr( "Gradient spread" ), QObject::tr( "string " ) + QLatin1String( "[pad|repeat|reflect]" ), 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( "[;] 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 " ) + "[interval|vertex|lastvertex|firstvertex|centerpoint|curvepoint]", 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 )},
};
}
diff --git a/src/core/symbology/qgssymbollayerregistry.h b/src/core/symbology/qgssymbollayerregistry.h
index 5ffae9552dc..0c1f8491ffe 100644
--- a/src/core/symbology/qgssymbollayerregistry.h
+++ b/src/core/symbology/qgssymbollayerregistry.h
@@ -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
{
diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt
index 8c605a8ebe8..df3a6ffd177 100644
--- a/src/gui/CMakeLists.txt
+++ b/src/gui/CMakeLists.txt
@@ -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
diff --git a/src/gui/qgsattributeform.cpp b/src/gui/qgsattributeform.cpp
index e0fe6ecde31..48866ef0647 100644
--- a/src/gui/qgsattributeform.cpp
+++ b/src/gui/qgsattributeform.cpp
@@ -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;
diff --git a/src/gui/qgsnewauxiliaryfielddialog.cpp b/src/gui/qgsnewauxiliaryfielddialog.cpp
new file mode 100644
index 00000000000..d2c64083bb8
--- /dev/null
+++ b/src/gui/qgsnewauxiliaryfielddialog.cpp
@@ -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
+
+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;
+}
diff --git a/src/gui/qgsnewauxiliaryfielddialog.h b/src/gui/qgsnewauxiliaryfielddialog.h
new file mode 100644
index 00000000000..5f7b621c7d3
--- /dev/null
+++ b/src/gui/qgsnewauxiliaryfielddialog.h
@@ -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
diff --git a/src/gui/qgsnewauxiliarylayerdialog.cpp b/src/gui/qgsnewauxiliarylayerdialog.cpp
new file mode 100644
index 00000000000..cc96395943d
--- /dev/null
+++ b/src/gui/qgsnewauxiliarylayerdialog.cpp
@@ -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
+
+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();
+}
diff --git a/src/gui/qgsnewauxiliarylayerdialog.h b/src/gui/qgsnewauxiliarylayerdialog.h
new file mode 100644
index 00000000000..53f5e534f53
--- /dev/null
+++ b/src/gui/qgsnewauxiliarylayerdialog.h
@@ -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
diff --git a/src/gui/qgspropertyoverridebutton.cpp b/src/gui/qgspropertyoverridebutton.cpp
index 127e0cccc45..dd964677a42 100644
--- a/src/gui/qgspropertyoverridebutton.cpp
+++ b/src/gui/qgspropertyoverridebutton.cpp
@@ -22,6 +22,7 @@
#include "qgsvectorlayer.h"
#include "qgspanelwidget.h"
#include "qgspropertyassistantwidget.h"
+#include "qgsauxiliarystorage.h"
#include
#include
@@ -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() )
diff --git a/src/gui/qgspropertyoverridebutton.h b/src/gui/qgspropertyoverridebutton.h
index 0306b83e5e7..7875ae94f98 100644
--- a/src/gui/qgspropertyoverridebutton.h
+++ b/src/gui/qgspropertyoverridebutton.h
@@ -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:
diff --git a/src/gui/symbology/qgsarrowsymbollayerwidget.cpp b/src/gui/symbology/qgsarrowsymbollayerwidget.cpp
index 7334c070202..593207eafb8 100644
--- a/src/gui/symbology/qgsarrowsymbollayerwidget.cpp
+++ b/src/gui/symbology/qgsarrowsymbollayerwidget.cpp
@@ -17,7 +17,7 @@
#include "qgsvectorlayer.h"
#include
-QgsArrowSymbolLayerWidget::QgsArrowSymbolLayerWidget( const QgsVectorLayer *vl, QWidget *parent )
+QgsArrowSymbolLayerWidget::QgsArrowSymbolLayerWidget( QgsVectorLayer *vl, QWidget *parent )
: QgsSymbolLayerWidget( parent, vl )
{
diff --git a/src/gui/symbology/qgsarrowsymbollayerwidget.h b/src/gui/symbology/qgsarrowsymbollayerwidget.h
index 0c73661caa7..0e6244691b5 100644
--- a/src/gui/symbology/qgsarrowsymbollayerwidget.h
+++ b/src/gui/symbology/qgsarrowsymbollayerwidget.h
@@ -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;
diff --git a/src/gui/symbology/qgsellipsesymbollayerwidget.cpp b/src/gui/symbology/qgsellipsesymbollayerwidget.cpp
index b02239e79ef..3181b7d52aa 100644
--- a/src/gui/symbology/qgsellipsesymbollayerwidget.cpp
+++ b/src/gui/symbology/qgsellipsesymbollayerwidget.cpp
@@ -17,7 +17,7 @@
#include "qgsvectorlayer.h"
#include
-QgsEllipseSymbolLayerWidget::QgsEllipseSymbolLayerWidget( const QgsVectorLayer *vl, QWidget *parent )
+QgsEllipseSymbolLayerWidget::QgsEllipseSymbolLayerWidget( QgsVectorLayer *vl, QWidget *parent )
: QgsSymbolLayerWidget( parent, vl )
{
diff --git a/src/gui/symbology/qgsellipsesymbollayerwidget.h b/src/gui/symbology/qgsellipsesymbollayerwidget.h
index e3546eca640..bc5299177bc 100644
--- a/src/gui/symbology/qgsellipsesymbollayerwidget.h
+++ b/src/gui/symbology/qgsellipsesymbollayerwidget.h
@@ -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;
diff --git a/src/gui/symbology/qgslayerpropertieswidget.cpp b/src/gui/symbology/qgslayerpropertieswidget.cpp
index c9772c543d6..feeecaa83c5 100644
--- a/src/gui/symbology/qgslayerpropertieswidget.cpp
+++ b/src/gui/symbology/qgslayerpropertieswidget.cpp
@@ -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 )
diff --git a/src/gui/symbology/qgslayerpropertieswidget.h b/src/gui/symbology/qgslayerpropertieswidget.h
index 98f57e7c294..febd83e0e5f 100644
--- a/src/gui/symbology/qgslayerpropertieswidget.h
+++ b/src/gui/symbology/qgslayerpropertieswidget.h
@@ -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();
diff --git a/src/gui/symbology/qgssymbollayerwidget.cpp b/src/gui/symbology/qgssymbollayerwidget.cpp
index 902a7f515c4..02d7dda48fb 100644
--- a/src/gui/symbology/qgssymbollayerwidget.cpp
+++ b/src/gui/symbology/qgssymbollayerwidget.cpp
@@ -38,6 +38,9 @@
#include "qgssvgselectorwidget.h"
#include "qgslogger.h"
#include "qgssettings.h"
+#include "qgsnewauxiliarylayerdialog.h"
+#include "qgsnewauxiliaryfielddialog.h"
+#include "qgsauxiliarystorage.h"
#include
#include
@@ -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( 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( 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 )
{
diff --git a/src/gui/symbology/qgssymbollayerwidget.h b/src/gui/symbology/qgssymbollayerwidget.h
index ce7e34ab469..2c92514bc22 100644
--- a/src/gui/symbology/qgssymbollayerwidget.h
+++ b/src/gui/symbology/qgssymbollayerwidget.h
@@ -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;
diff --git a/src/gui/symbology/qgssymbolselectordialog.cpp b/src/gui/symbology/qgssymbolselectordialog.cpp
index fe6235ff9be..711cd4ed953 100644
--- a/src/gui/symbology/qgssymbolselectordialog.cpp
+++ b/src/gui/symbology/qgssymbolselectordialog.cpp
@@ -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() );
diff --git a/src/gui/symbology/qgssymbolselectordialog.h b/src/gui/symbology/qgssymbolselectordialog.h
index 7d44464ba36..d65fd7a03f2 100644
--- a/src/gui/symbology/qgssymbolselectordialog.h
+++ b/src/gui/symbology/qgssymbolselectordialog.h
@@ -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
diff --git a/src/gui/symbology/qgssymbolslistwidget.cpp b/src/gui/symbology/qgssymbolslistwidget.cpp
index 0c924f28b34..2171e3c8736 100644
--- a/src/gui/symbology/qgssymbolslistwidget.cpp
+++ b/src/gui/symbology/qgssymbolslistwidget.cpp
@@ -27,6 +27,8 @@
#include "qgsapplication.h"
#include "qgsvectorlayer.h"
#include "qgssettings.h"
+#include "qgsnewauxiliarylayerdialog.h"
+#include "qgsauxiliarystorage.h"
#include
#include
@@ -41,7 +43,7 @@
#include
-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( 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( mSymbol );
+ QgsLineSymbol *lineSymbol = static_cast( 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
diff --git a/src/gui/symbology/qgssymbolslistwidget.h b/src/gui/symbology/qgssymbolslistwidget.h
index 3df0b1f4cb2..5c361d44bfe 100644
--- a/src/gui/symbology/qgssymbolslistwidget.h
+++ b/src/gui/symbology/qgssymbolslistwidget.h
@@ -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();
diff --git a/src/gui/symbology/qgsvectorfieldsymbollayerwidget.cpp b/src/gui/symbology/qgsvectorfieldsymbollayerwidget.cpp
index fb6d7efd6d6..97eb7f7a674 100644
--- a/src/gui/symbology/qgsvectorfieldsymbollayerwidget.cpp
+++ b/src/gui/symbology/qgsvectorfieldsymbollayerwidget.cpp
@@ -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 );
diff --git a/src/gui/symbology/qgsvectorfieldsymbollayerwidget.h b/src/gui/symbology/qgsvectorfieldsymbollayerwidget.h
index 45e1308be30..52622e1840a 100644
--- a/src/gui/symbology/qgsvectorfieldsymbollayerwidget.h
+++ b/src/gui/symbology/qgsvectorfieldsymbollayerwidget.h
@@ -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;
diff --git a/src/ui/qgsnewauxiliaryfielddialogbase.ui b/src/ui/qgsnewauxiliaryfielddialogbase.ui
new file mode 100644
index 00000000000..c454b25b9c7
--- /dev/null
+++ b/src/ui/qgsnewauxiliaryfielddialogbase.ui
@@ -0,0 +1,111 @@
+
+
+ QgsNewAuxiliaryFieldDialogBase
+
+
+
+ 0
+ 0
+ 397
+ 159
+
+
+
+ Auxiliary storage : new auxiliary field
+
+
+
+
+ 50
+ 120
+ 341
+ 32
+
+
+
+ Qt::Horizontal
+
+
+ QDialogButtonBox::Cancel|QDialogButtonBox::Ok
+
+
+
+
+
+ 10
+ 10
+ 381
+ 101
+
+
+
+ -
+
+
+ New auxiliary field parameters
+
+
+
+ -
+
+
-
+
+
+ Type
+
+
+
+ -
+
+
+ -
+
+
+ Name
+
+
+
+ -
+
+
+
+
+
+
+
+
+
+
+ buttonBox
+ accepted()
+ QgsNewAuxiliaryFieldDialogBase
+ accept()
+
+
+ 248
+ 254
+
+
+ 157
+ 274
+
+
+
+
+ buttonBox
+ rejected()
+ QgsNewAuxiliaryFieldDialogBase
+ reject()
+
+
+ 316
+ 260
+
+
+ 286
+ 274
+
+
+
+
+
diff --git a/src/ui/qgsnewauxiliarylayerdialogbase.ui b/src/ui/qgsnewauxiliarylayerdialogbase.ui
new file mode 100644
index 00000000000..5e577d89c04
--- /dev/null
+++ b/src/ui/qgsnewauxiliarylayerdialogbase.ui
@@ -0,0 +1,93 @@
+
+
+ QgsNewAuxiliaryLayerDialogBase
+
+
+
+ 0
+ 0
+ 400
+ 139
+
+
+
+ Auxiliary storage : choose primary key
+
+
+
+
+ 50
+ 100
+ 341
+ 32
+
+
+
+ Qt::Horizontal
+
+
+ QDialogButtonBox::Cancel|QDialogButtonBox::Ok
+
+
+
+
+
+ 10
+ 10
+ 381
+ 81
+
+
+
+ -
+
+
+ Select the primary key to use for joining with internal data storage
+
+
+ true
+
+
+
+ -
+
+
+
+
+
+
+
+
+ buttonBox
+ accepted()
+ QgsNewAuxiliaryLayerDialogBase
+ accept()
+
+
+ 248
+ 254
+
+
+ 157
+ 274
+
+
+
+
+ buttonBox
+ rejected()
+ QgsNewAuxiliaryLayerDialogBase
+ reject()
+
+
+ 316
+ 260
+
+
+ 286
+ 274
+
+
+
+
+
diff --git a/src/ui/qgsvectorlayerpropertiesbase.ui b/src/ui/qgsvectorlayerpropertiesbase.ui
index 247cdf99261..08e9a4a2b2f 100644
--- a/src/ui/qgsvectorlayerpropertiesbase.ui
+++ b/src/ui/qgsvectorlayerpropertiesbase.ui
@@ -273,6 +273,15 @@
:/images/themes/default/propertyicons/overlay.png:/images/themes/default/propertyicons/overlay.png
+ -
+
+ Auxiliary Storage
+
+
+
+ :/images/themes/default/mIconAuxiliaryStorage.svg:/images/themes/default/mIconAuxiliaryStorage.svg
+
+
@@ -1995,6 +2004,237 @@ border-radius: 2px;
+
+
+
+
+ 0
+ 0
+ 671
+ 551
+
+
+
+ -
+
+
+ Information
+
+
+ false
+
+
+ false
+
+
+ vectormeta
+
+
+
+ QLayout::SetDefaultConstraint
+
+
-
+
+
+ false
+
+
+ true
+
+
+
+ -
+
+
+ Fields
+
+
+
+ -
+
+
+ Features
+
+
+
+ -
+
+
+ false
+
+
+ A name used to identify the layer. The short name is a text string used for machine-to-machine communication.
+
+
+
+
+
+
+
+
+ true
+
+
+
+
+
+
+ -
+
+
+ Key
+
+
+
+ -
+
+
+ false
+
+
+ true
+
+
+
+
+
+
+ -
+
+
+ 0
+
+
-
+
+
+ Auxiliary Layer
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+
+
+ -
+
+
+ Fields
+
+
+
-
+
+
+ QLayout::SetDefaultConstraint
+
+
+ 0
+
+
-
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+ -
+
+
+
+
+
+
+ :/images/themes/default/symbologyAdd.svg:/images/themes/default/symbologyAdd.svg
+
+
+
+ -
+
+
+
+
+
+
+ :/images/themes/default/symbologyRemove.svg:/images/themes/default/symbologyRemove.svg
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+
+
+ -
+
+
+
+ Target
+
+
+
+
+ Property
+
+
+
+
+ Name
+
+
+
+
+ Type
+
+
+
+
+ Full Name
+
+
+
+
+
+
+
+ -
+
+
+ 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.
+
+
+ true
+
+
+
+
+
+
diff --git a/tests/src/python/CMakeLists.txt b/tests/src/python/CMakeLists.txt
index a18b3846902..239f9ac3990 100644
--- a/tests/src/python/CMakeLists.txt
+++ b/tests/src/python/CMakeLists.txt
@@ -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)
diff --git a/tests/src/python/test_qgsauxiliarystorage.py b/tests/src/python/test_qgsauxiliarystorage.py
new file mode 100644
index 00000000000..cf5c6a47a74
--- /dev/null
+++ b/tests/src/python/test_qgsauxiliarystorage.py
@@ -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()
diff --git a/tests/src/python/utilities.py b/tests/src/python/utilities.py
index b437df87bd2..ba3fdb1041d 100644
--- a/tests/src/python/utilities.py
+++ b/tests/src/python/utilities.py
@@ -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):
"""