Skip to content

Commit 43bbf68

Browse files
committedJan 23, 2017
Port labeling to properties framework
1 parent 1e0c62b commit 43bbf68

28 files changed

+833
-1394
lines changed
 

‎python/core/qgspallabeling.sip

Lines changed: 19 additions & 142 deletions
Original file line numberDiff line numberDiff line change
@@ -1,83 +1,3 @@
1-
// QMap<QgsPalLayerSettings::DataDefinedProperties, QgsDataDefined*> is implemented as a Python dictionary.
2-
%MappedType QMap<QgsPalLayerSettings::DataDefinedProperties, QgsDataDefined*> /DocType="dict-of-QgsPalLayerSettings.DataDefinedProperties-QgsDataDefined*"/
3-
{
4-
%TypeHeaderCode
5-
#include <qmap.h>
6-
#include <qgspallabeling.h>
7-
#include <qgsdatadefined.h>
8-
%End
9-
%ConvertFromTypeCode
10-
// Create the dictionary.
11-
PyObject *d = PyDict_New();
12-
if (!d)
13-
return NULL;
14-
// Set the dictionary elements.
15-
QMap<QgsPalLayerSettings::DataDefinedProperties, QgsDataDefined*>::const_iterator i = sipCpp->constBegin();
16-
while (i != sipCpp->constEnd())
17-
{
18-
QgsDataDefined *t = i.value();
19-
PyObject *kobj = sipConvertFromEnum(i.key(), sipType_QgsPalLayerSettings_DataDefinedProperties);
20-
PyObject *tobj = sipConvertFromType(t, sipType_QgsDataDefined, sipTransferObj);
21-
if (kobj == NULL || tobj == NULL || PyDict_SetItem(d, kobj, tobj) < 0)
22-
{
23-
Py_DECREF(d);
24-
if (kobj)
25-
{
26-
Py_DECREF(kobj);
27-
}
28-
if (tobj)
29-
{
30-
Py_DECREF(tobj);
31-
}
32-
else
33-
{
34-
delete t;
35-
}
36-
return NULL;
37-
}
38-
Py_DECREF(kobj);
39-
Py_DECREF(tobj);
40-
++i;
41-
}
42-
return d;
43-
%End
44-
%ConvertToTypeCode
45-
PyObject *kobj, *tobj;
46-
SIP_SSIZE_T i = 0;
47-
// Check the type if that is all that is required.
48-
if (sipIsErr == NULL)
49-
{
50-
if (!PyDict_Check(sipPy))
51-
return 0;
52-
while (PyDict_Next(sipPy, &i, &kobj, &tobj))
53-
if (!sipCanConvertToType(tobj, sipType_QgsDataDefined, SIP_NOT_NONE))
54-
return 0;
55-
return 1;
56-
}
57-
QMap<QgsPalLayerSettings::DataDefinedProperties, QgsDataDefined*> *qm = new QMap<QgsPalLayerSettings::DataDefinedProperties, QgsDataDefined*>;
58-
59-
while (PyDict_Next(sipPy, &i, &kobj, &tobj))
60-
{
61-
int state, k = SIPLong_AsLong(kobj);
62-
QgsDataDefined *t = reinterpret_cast<QgsDataDefined *>(sipConvertToType(tobj, sipType_QgsDataDefined, sipTransferObj, SIP_NOT_NONE, &state, sipIsErr));
63-
64-
if (*sipIsErr)
65-
{
66-
sipReleaseType(t, sipType_QgsDataDefined, state);
67-
delete qm;
68-
return 0;
69-
}
70-
qm->insert(QgsPalLayerSettings::DataDefinedProperties(k), t);
71-
sipReleaseType(t, sipType_QgsDataDefined, state);
72-
}
73-
74-
*sipCppPtr = qm;
75-
76-
return sipGetState(sipTransferObj);
77-
%End
78-
};
79-
80-
811
class QgsLabelPosition
822
{
833
%TypeHeaderCode
@@ -239,7 +159,7 @@ class QgsPalLayerSettings
239159
};
240160

241161
// update mDataDefinedNames QMap in constructor when adding/deleting enum value
242-
enum DataDefinedProperties
162+
enum Property
243163
{
244164
// text style
245165
Size,
@@ -507,67 +427,24 @@ class QgsPalLayerSettings
507427
*/
508428
QDomElement writeXml( QDomDocument& doc );
509429

510-
/** Get a data defined property pointer
511-
* @note helpful for Python access
512-
*/
513-
QgsDataDefined* dataDefinedProperty( QgsPalLayerSettings::DataDefinedProperties p );
514-
515-
/** Set a property as data defined
516-
* @note helpful for Python access
517-
*/
518-
void setDataDefinedProperty( QgsPalLayerSettings::DataDefinedProperties p,
519-
bool active, bool useExpr, const QString& expr, const QString& field );
520-
521-
/** Set a property to static instead data defined */
522-
void removeDataDefinedProperty( QgsPalLayerSettings::DataDefinedProperties p );
523-
524-
/** Clear all data-defined properties
525-
* @note added in QGIS 2.12
526-
*/
527-
void removeAllDataDefinedProperties();
528-
529-
/** Convert old property value to new one as delimited values
530-
* @note not available in python bindings; as temporary solution until refactoring of project settings
531-
*/
532-
QString updateDataDefinedString( const QString& value );
533-
534-
/** Get property value as separate values split into Qmap
535-
* @note not available in python bindings
536-
*/
537-
QMap<QString, QString> dataDefinedMap( QgsPalLayerSettings::DataDefinedProperties p ) const;
538-
539-
/** Get data defined property value from expression string or attribute field name
540-
* @returns value inside QVariant
541-
* @note not available in python bindings
542-
*/
543-
//QVariant dataDefinedValue( QgsPalLayerSettings::DataDefinedProperties p, QgsFeature& f, const QgsFields& fields,
544-
// const QgsExpressionContext* context = 0 ) const;
545-
546-
/** Get data defined property value from expression string or attribute field name
547-
* @returns true/false whether result is null or invalid
548-
* @note not available in python bindings
549-
*/
550-
//bool dataDefinedEvaluate( QgsPalLayerSettings::DataDefinedProperties p, QVariant& exprVal, const QgsExpressionContext* context = 0 ) const;
551-
552-
/** Whether data definition is active
553-
*/
554-
bool dataDefinedIsActive( QgsPalLayerSettings::DataDefinedProperties p ) const;
555-
556-
/** Whether data definition is set to use an expression
430+
/** Returns a reference to the label's property collection, used for data defined overrides.
431+
* @note added in QGIS 3.0
432+
* @see setProperties()
557433
*/
558-
bool dataDefinedUseExpression( QgsPalLayerSettings::DataDefinedProperties p ) const;
434+
QgsPropertyCollection& properties();
559435

560-
/** Map of current data defined properties
561-
*
562-
* Pointers to QgsDataDefined should never be null, the pointers are owned by this class
436+
/** Returns a reference to the label's property collection, used for data defined overrides.
437+
* @note added in QGIS 3.0
438+
* @see setProperties()
563439
*/
564-
QMap< QgsPalLayerSettings::DataDefinedProperties, QgsDataDefined* > dataDefinedProperties;
440+
//const QgsPropertyCollection& properties() const { return mProperties; }
565441

566-
/** Map of data defined enum to names and old-style indecies
567-
* The QPair contains a new string for layer property key, and a reference to old-style numeric key (< QGIS 2.0)
568-
* @note not available in python bindings;
442+
/** Sets the label's property collection, used for data defined overrides.
443+
* @param collection property collection. Existing properties will be replaced.
444+
* @note added in QGIS 3.0
445+
* @see properties()
569446
*/
570-
// QMap<QgsPalLayerSettings::DataDefinedProperties, QPair<QString, int> > dataDefinedNames() const;
447+
void setProperties( const QgsPropertyCollection& collection );
571448

572449
/** Returns the label text formatting settings, e.g., font settings, buffer settings, etc.
573450
* @see setFormat()
@@ -737,23 +614,23 @@ class QgsPalLabeling
737614
protected:
738615
// update temporary QgsPalLayerSettings with any data defined text style values
739616
void dataDefinedTextStyle( QgsPalLayerSettings& tmpLyr,
740-
const QMap< QgsPalLayerSettings::DataDefinedProperties, QVariant >& ddValues );
617+
const QMap< QgsPalLayerSettings::Property, QVariant >& ddValues );
741618

742619
// update temporary QgsPalLayerSettings with any data defined text formatting values
743620
void dataDefinedTextFormatting( QgsPalLayerSettings& tmpLyr,
744-
const QMap< QgsPalLayerSettings::DataDefinedProperties, QVariant >& ddValues );
621+
const QMap< QgsPalLayerSettings::Property, QVariant >& ddValues );
745622

746623
// update temporary QgsPalLayerSettings with any data defined text buffer values
747624
void dataDefinedTextBuffer( QgsPalLayerSettings& tmpLyr,
748-
const QMap< QgsPalLayerSettings::DataDefinedProperties, QVariant >& ddValues );
625+
const QMap< QgsPalLayerSettings::Property, QVariant >& ddValues );
749626

750627
// update temporary QgsPalLayerSettings with any data defined shape background values
751628
void dataDefinedShapeBackground( QgsPalLayerSettings& tmpLyr,
752-
const QMap< QgsPalLayerSettings::DataDefinedProperties, QVariant >& ddValues );
629+
const QMap< QgsPalLayerSettings::Property, QVariant >& ddValues );
753630

754631
// update temporary QgsPalLayerSettings with any data defined drop shadow values
755632
void dataDefinedDropShadow( QgsPalLayerSettings& tmpLyr,
756-
const QMap< QgsPalLayerSettings::DataDefinedProperties, QVariant >& ddValues );
633+
const QMap< QgsPalLayerSettings::Property, QVariant >& ddValues );
757634

758635
void deleteTemporaryData();
759636

‎python/core/qgsproperty.sip

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,17 @@ class QgsAbstractProperty
123123
*/
124124
int valueAsInt( const QgsExpressionContext& context, int defaultValue = 0 ) const;
125125

126+
/**
127+
* Calculates the current value of the property and interprets it as an boolean.
128+
* @param context QgsExpressionContext to evaluate the property for.
129+
* @param defaultValue default boolean to return if the property cannot be calculated as an boolean
130+
* @returns value parsed to boolean
131+
* @see value()
132+
* @see valueAsDouble()
133+
* @see valueAsColor()
134+
*/
135+
bool valueAsBool( const QgsExpressionContext& context, bool defaultValue = false ) const;
136+
126137
/** Writes the current state of the property into an XML element
127138
* @param propertyElem destination element for the property's state
128139
* @param doc DOM document

‎python/core/qgspropertycollection.sip

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
typedef QMap< int, QString > QgsPropertyDefinition;
2+
13
/**
24
* \ingroup core
35
* \class QgsAbstractPropertyCollection
@@ -126,6 +128,20 @@ class QgsAbstractPropertyCollection
126128
*/
127129
int valueAsInt( int key, const QgsExpressionContext& context, int defaultValue = 0 ) const;
128130

131+
/**
132+
* Calculates the current value of the property with the specified key and interprets it as an boolean.
133+
* @param key integer key for property to return. The intended use case is that a context specific enum is cast to
134+
* int and used for the key value.
135+
* @param context QgsExpressionContext to evaluate the property for.
136+
* @param defaultValue default boolean to return if the property cannot be calculated as a boolean
137+
* @returns value parsed to bool
138+
* @see value()
139+
* @see valueAsDouble()
140+
* @see valueAsColor()
141+
*/
142+
bool valueAsBool( int key, const QgsExpressionContext& context, bool defaultValue = false ) const;
143+
144+
129145
/**
130146
* Prepares the collection against a specified expression context. Calling prepare before evaluating the
131147
* collection's properties multiple times allows precalculation of expensive setup tasks such as parsing expressions.
@@ -168,7 +184,7 @@ class QgsAbstractPropertyCollection
168184
* to avoid writing the raw integer key values to XML, for readability and future-proofness.
169185
* @see readXML()
170186
*/
171-
virtual bool writeXml( QDomElement& collectionElem, QDomDocument& doc, const QMap< int, QString >& propertyNameMap ) const = 0;
187+
virtual bool writeXml( QDomElement& collectionElem, QDomDocument& doc, const QgsPropertyDefinition& propertyNameMap ) const = 0;
172188

173189
/**
174190
* Reads property collection state from an XML element.
@@ -178,7 +194,7 @@ class QgsAbstractPropertyCollection
178194
* the propertyNameMap specified when writeXML() was called.
179195
* @see writeXML()
180196
*/
181-
virtual bool readXml( const QDomElement& collectionElem, const QDomDocument& doc, const QMap<int, QString> &propertyNameMap ) = 0;
197+
virtual bool readXml( const QDomElement& collectionElem, const QDomDocument& doc, const QgsPropertyDefinition &propertyNameMap ) = 0;
182198

183199
};
184200

@@ -227,8 +243,8 @@ class QgsPropertyCollection : QgsAbstractPropertyCollection
227243
bool isActive( int key ) const;
228244
bool hasActiveProperties() const;
229245
bool hasActiveDynamicProperties() const;
230-
bool writeXml( QDomElement& collectionElem, QDomDocument& doc, const QMap< int, QString >& propertyNameMap ) const;
231-
bool readXml( const QDomElement& collectionElem, const QDomDocument& doc, const QMap<int, QString> &propertyNameMap );
246+
bool writeXml( QDomElement& collectionElem, QDomDocument& doc, const QgsPropertyDefinition& propertyNameMap ) const;
247+
bool readXml( const QDomElement& collectionElem, const QDomDocument& doc, const QgsPropertyDefinition& propertyNameMap );
232248

233249
/** Adds a property to the collection and takes ownership of it.
234250
* @param key integer key for property. Any existing property with the same key will be deleted
@@ -353,7 +369,7 @@ class QgsPropertyCollectionStack : QgsAbstractPropertyCollection
353369

354370
QSet<int> propertyKeys() const;
355371
bool hasProperty( int key ) const;
356-
bool writeXml( QDomElement& collectionElem, QDomDocument& doc, const QMap< int, QString >& propertyNameMap ) const;
357-
bool readXml( const QDomElement& collectionElem, const QDomDocument& doc, const QMap<int, QString> &propertyNameMap );
372+
bool writeXml( QDomElement& collectionElem, QDomDocument& doc, const QgsPropertyDefinition& propertyNameMap ) const;
373+
bool readXml( const QDomElement& collectionElem, const QDomDocument& doc, const QgsPropertyDefinition &propertyNameMap );
358374
};
359375

‎src/app/dwg/qgsdwgimportdialog.cpp

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
#include "qgsgenericprojectionselector.h"
4343
#include "qgsmessagelog.h"
4444
#include "qgslogger.h"
45+
#include "qgsproperty.h"
4546

4647

4748
struct CursorOverride
@@ -358,14 +359,13 @@ void QgsDwgImportDialog::createGroup( QgsLayerTreeGroup *group, QString name, QS
358359
pls.drawLabels = true;
359360
pls.fieldName = "text";
360361
pls.wrapChar = "\\P";
361-
pls.setDataDefinedProperty( QgsPalLayerSettings::Size, true, false, "", "height" );
362-
pls.setDataDefinedProperty( QgsPalLayerSettings::Color, true, false, "", "color" );
363-
pls.setDataDefinedProperty( QgsPalLayerSettings::MultiLineHeight, true, true, "CASE WHEN interlin<0 THEN 1 ELSE interlin*1.5 END", "" );
364-
pls.placement = QgsPalLayerSettings::OrderedPositionsAroundPoint;
365-
pls.setDataDefinedProperty( QgsPalLayerSettings::PositionX, true, true, "$x", "" );
366-
pls.setDataDefinedProperty( QgsPalLayerSettings::PositionY, true, true, "$y", "" );
367-
pls.setDataDefinedProperty( QgsPalLayerSettings::Hali, true, true, QString(
368-
"CASE"
362+
363+
pls.properties().setProperty( QgsPalLayerSettings::Size, new QgsFieldBasedProperty( QStringLiteral( "height" ) ) );
364+
pls.properties().setProperty( QgsPalLayerSettings::Color, new QgsFieldBasedProperty( QStringLiteral( "color" ) ) );
365+
pls.properties().setProperty( QgsPalLayerSettings::MultiLineHeight, new QgsExpressionBasedProperty( QStringLiteral( "CASE WHEN interlin<0 THEN 1 ELSE interlin*1.5 END" ) ) );
366+
pls.properties().setProperty( QgsPalLayerSettings::PositionX, new QgsExpressionBasedProperty( QStringLiteral( "$x" ) ) );
367+
pls.properties().setProperty( QgsPalLayerSettings::PositionY, new QgsExpressionBasedProperty( QStringLiteral( "$y" ) ) );
368+
pls.properties().setProperty( QgsPalLayerSettings::Hali, new QgsExpressionBasedProperty( QStringLiteral( "CASE"
369369
" WHEN etype=%1 THEN"
370370
" CASE"
371371
" WHEN alignv IN (1,4,7) THEN 'Left'"
@@ -380,10 +380,8 @@ void QgsDwgImportDialog::createGroup( QgsLayerTreeGroup *group, QString name, QS
380380
" WHEN alignh=3 THEN 'Left'"
381381
" WHEN alignh=4 THEN 'Left'"
382382
" END "
383-
" END" ).arg( DRW::MTEXT ), "" );
384-
385-
pls.setDataDefinedProperty( QgsPalLayerSettings::Vali, true, true, QString(
386-
"CASE"
383+
" END" ).arg( DRW::MTEXT ) ) );
384+
pls.properties().setProperty( QgsPalLayerSettings::Vali, new QgsExpressionBasedProperty( QStringLiteral( "CASE"
387385
" WHEN etype=%1 THEN"
388386
" CASE"
389387
" WHEN alignv < 4 THEN 'Top'"
@@ -397,10 +395,10 @@ void QgsDwgImportDialog::createGroup( QgsLayerTreeGroup *group, QString name, QS
397395
" WHEN alignv=2 THEN 'Half'"
398396
" WHEN alignv=3 THEN 'Top'"
399397
" END"
400-
" END" ).arg( DRW::MTEXT ), "" );
401-
402-
pls.setDataDefinedProperty( QgsPalLayerSettings::Rotation, true, true, "angle*180.0/pi()", "" );
398+
" END" ).arg( DRW::MTEXT ) ) );
399+
pls.properties().setProperty( QgsPalLayerSettings::Rotation, new QgsExpressionBasedProperty( QStringLiteral( "angle*180.0/pi()" ) ) );
403400

401+
pls.placement = QgsPalLayerSettings::OrderedPositionsAroundPoint;
404402
pls.writeToLayer( l );
405403
}
406404

‎src/app/qgslabelinggui.cpp

Lines changed: 235 additions & 339 deletions
Large diffs are not rendered by default.

‎src/app/qgslabelinggui.h

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
#include "qgspallabeling.h"
2222
#include "qgstextformatwidget.h"
23+
#include "qgsdatadefinedbuttonv2.h"
2324
#include "qgis_app.h"
2425

2526
class APP_EXPORT QgsLabelingGui : public QgsTextFormatWidget, private QgsExpressionContextGenerator
@@ -51,18 +52,23 @@ class APP_EXPORT QgsLabelingGui : public QgsTextFormatWidget, private QgsExpress
5152

5253
protected:
5354
void blockInitSignals( bool block );
54-
void syncDefinedCheckboxFrame( QgsDataDefinedButton* ddBtn, QCheckBox* chkBx, QFrame* f );
55-
void populateDataDefinedButtons( QgsPalLayerSettings& s );
56-
//! Sets data defined property attribute to map
57-
void setDataDefinedProperty( const QgsDataDefinedButton* ddBtn, QgsPalLayerSettings::DataDefinedProperties p, QgsPalLayerSettings& lyr );
55+
void syncDefinedCheckboxFrame( QgsDataDefinedButtonV2* ddBtn, QCheckBox* chkBx, QFrame* f );
5856

5957
private:
6058
QgsVectorLayer* mLayer;
6159
const QgsPalLayerSettings* mSettings;
60+
QgsPropertyCollection mProperties;
6261
LabelMode mMode;
6362

6463
QgsExpressionContext createExpressionContext() const override;
6564

65+
void populateDataDefinedButtons();
66+
void registerDataDefinedButton( QgsDataDefinedButtonV2 *button, QgsPalLayerSettings::Property key, QgsDataDefinedButtonV2::DataType type, const QString &description );
67+
68+
private slots:
69+
70+
void updateProperty();
71+
6672
};
6773

6874
#endif // QGSLABELINGGUI_H

‎src/app/qgslabelpropertydialog.cpp

Lines changed: 22 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
#include "qgisapp.h"
2626
#include "qgsmapcanvas.h"
2727
#include "qgsvectorlayerlabeling.h"
28-
28+
#include "qgsproperty.h"
2929
#include <QColorDialog>
3030
#include <QFontDatabase>
3131
#include <QSettings>
@@ -49,8 +49,6 @@ QgsLabelPropertyDialog::~QgsLabelPropertyDialog()
4949
{
5050
QSettings settings;
5151
settings.setValue( QStringLiteral( "/Windows/ChangeLabelProps/geometry" ), saveGeometry() );
52-
53-
qDeleteAll( mDataDefinedProperties );
5452
}
5553

5654
void QgsLabelPropertyDialog::on_buttonBox_clicked( QAbstractButton *button )
@@ -153,14 +151,10 @@ void QgsLabelPropertyDialog::init( const QString& layerId, const QString& provid
153151

154152
disableGuiElements();
155153

156-
QMap< QgsPalLayerSettings::DataDefinedProperties, QgsDataDefined* >::const_iterator it = layerSettings.dataDefinedProperties.constBegin();
157-
for ( ; it != layerSettings.dataDefinedProperties.constEnd(); ++it )
158-
{
159-
mDataDefinedProperties.insert( it.key(), it.value() ? new QgsDataDefined( *it.value() ) : nullptr );
160-
}
154+
mDataDefinedProperties = layerSettings.properties();
161155

162156
//set widget values from data defined results
163-
setDataDefinedValues( layerSettings, vlayer );
157+
setDataDefinedValues( vlayer );
164158
//enable widgets connected to data defined fields
165159
enableDataDefinedWidgets( vlayer );
166160

@@ -215,7 +209,7 @@ void QgsLabelPropertyDialog::blockElementSignals( bool block )
215209
mRotationSpinBox->blockSignals( block );
216210
}
217211

218-
void QgsLabelPropertyDialog::setDataDefinedValues( const QgsPalLayerSettings &layerSettings, QgsVectorLayer* vlayer )
212+
void QgsLabelPropertyDialog::setDataDefinedValues( QgsVectorLayer* vlayer )
219213
{
220214
//loop through data defined properties and set all the GUI widget values. We can do this
221215
//even if the data defined property is set to an expression, as it's useful to show
@@ -229,30 +223,21 @@ void QgsLabelPropertyDialog::setDataDefinedValues( const QgsPalLayerSettings &la
229223
<< QgsExpressionContextUtils::layerScope( vlayer );
230224
context.setFeature( mCurLabelFeat );
231225

232-
QMap< QgsPalLayerSettings::DataDefinedProperties, QgsDataDefined* >::const_iterator propIt = mDataDefinedProperties.constBegin();
233-
for ( ; propIt != mDataDefinedProperties.constEnd(); ++propIt )
226+
Q_FOREACH ( int key, mDataDefinedProperties.propertyKeys() )
234227
{
235-
QgsDataDefined* dd = propIt.value();
236-
if ( !dd || !dd->isActive() )
237-
{
228+
if ( !mDataDefinedProperties.isActive( key ) )
238229
continue;
239-
}
240-
241-
if ( !dd->expressionIsPrepared() )
242-
{
243-
dd->prepareExpression( context );
244-
}
245230

246231
//TODO - pass expression context
247-
QVariant result = layerSettings.dataDefinedValue( propIt.key(), mCurLabelFeat, vlayer->fields(), &context );
232+
QVariant result = mDataDefinedProperties.value( key, context );
248233
if ( !result.isValid() || result.isNull() )
249234
{
250235
//could not evaluate data defined value
251236
continue;
252237
}
253238

254239
bool ok = false;
255-
switch ( propIt.key() )
240+
switch ( key )
256241
{
257242
case QgsPalLayerSettings::Show:
258243
{
@@ -362,18 +347,18 @@ void QgsLabelPropertyDialog::enableDataDefinedWidgets( QgsVectorLayer* vlayer )
362347
{
363348
//loop through data defined properties, this time setting whether or not the widgets are enabled
364349
//this can only be done for properties which are assigned to fields
365-
QMap< QgsPalLayerSettings::DataDefinedProperties, QgsDataDefined* >::const_iterator propIt = mDataDefinedProperties.constBegin();
366-
for ( ; propIt != mDataDefinedProperties.constEnd(); ++propIt )
350+
Q_FOREACH ( int key, mDataDefinedProperties.propertyKeys() )
367351
{
368-
QgsDataDefined* dd = propIt.value();
369-
if ( !dd )
352+
QgsAbstractProperty* prop = mDataDefinedProperties.property( key );
353+
if ( !prop || !prop->isActive() || prop->propertyType() != QgsAbstractProperty::FieldBasedProperty )
370354
{
371-
continue;
355+
continue; // can only modify attributes with an active data definition of a mapped field
372356
}
373-
QString ddField = dd->field();
374-
if ( !dd->isActive() || dd->useExpression() || ddField.isEmpty() )
357+
358+
QString ddField = static_cast< QgsFieldBasedProperty*>( prop )->field();
359+
if ( ddField.isEmpty() )
375360
{
376-
continue; // can only modify attributes with an active data definition of a mapped field
361+
continue;
377362
}
378363

379364
int ddIndx = vlayer->fields().lookupField( ddField );
@@ -384,7 +369,7 @@ void QgsLabelPropertyDialog::enableDataDefinedWidgets( QgsVectorLayer* vlayer )
384369

385370
QgsDebugMsg( QString( "ddField: %1" ).arg( ddField ) );
386371

387-
switch ( propIt.key() )
372+
switch ( key )
388373
{
389374
case QgsPalLayerSettings::Show:
390375
mShowLabelChkbx->setEnabled( true );
@@ -664,16 +649,14 @@ void QgsLabelPropertyDialog::on_mLabelTextLineEdit_textChanged( const QString& t
664649
}
665650
}
666651

667-
void QgsLabelPropertyDialog::insertChangedValue( QgsPalLayerSettings::DataDefinedProperties p, const QVariant& value )
652+
void QgsLabelPropertyDialog::insertChangedValue( QgsPalLayerSettings::Property p, const QVariant& value )
668653
{
669-
QMap< QgsPalLayerSettings::DataDefinedProperties, QgsDataDefined* >::const_iterator ddIt = mDataDefinedProperties.constFind( p );
670-
if ( ddIt != mDataDefinedProperties.constEnd() )
654+
if ( mDataDefinedProperties.isActive( p ) )
671655
{
672-
QgsDataDefined* dd = ddIt.value();
673-
674-
if ( dd && dd->isActive() && !dd->useExpression() && !dd->field().isEmpty() )
656+
QgsAbstractProperty* prop = mDataDefinedProperties.property( p );
657+
if ( prop->propertyType() == QgsAbstractProperty::FieldBasedProperty )
675658
{
676-
mChangedProperties.insert( mCurLabelFeat.fieldNameIndex( dd->field() ), value );
659+
mChangedProperties.insert( mCurLabelFeat.fieldNameIndex( static_cast< QgsFieldBasedProperty* >( prop )->field() ), value );
677660
}
678661
}
679662
}

‎src/app/qgslabelpropertydialog.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ class APP_EXPORT QgsLabelPropertyDialog: public QDialog, private Ui::QgsLabelPro
7474
//! Block / unblock all input element signals
7575
void blockElementSignals( bool block );
7676

77-
void setDataDefinedValues( const QgsPalLayerSettings &layerSettings, QgsVectorLayer* vlayer );
77+
void setDataDefinedValues( QgsVectorLayer* vlayer );
7878
void enableDataDefinedWidgets( QgsVectorLayer* vlayer );
7979

8080
//! Updates font when family or style is updated
@@ -87,10 +87,10 @@ class APP_EXPORT QgsLabelPropertyDialog: public QDialog, private Ui::QgsLabelPro
8787
void fillValiComboBox();
8888

8989
//! Insert changed value into mChangedProperties
90-
void insertChangedValue( QgsPalLayerSettings::DataDefinedProperties p, const QVariant& value );
90+
void insertChangedValue( QgsPalLayerSettings::Property p, const QVariant& value );
9191

9292
QgsAttributeMap mChangedProperties;
93-
QMap< QgsPalLayerSettings::DataDefinedProperties, QgsDataDefined* > mDataDefinedProperties;
93+
QgsPropertyCollection mDataDefinedProperties;
9494
QFont mLabelFont;
9595

9696
QFontDatabase mFontDB;

‎src/app/qgsmaptoollabel.cpp

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -409,23 +409,19 @@ bool QgsMapToolLabel::hasDataDefinedColumn( QgsPalLayerSettings::DataDefinedProp
409409
}
410410
#endif
411411

412-
QString QgsMapToolLabel::dataDefinedColumnName( QgsPalLayerSettings::DataDefinedProperties p, const QgsPalLayerSettings& labelSettings ) const
412+
QString QgsMapToolLabel::dataDefinedColumnName( QgsPalLayerSettings::Property p, const QgsPalLayerSettings& labelSettings ) const
413413
{
414-
//QgsDebugMsg( QString( "dataDefinedProperties count:%1" ).arg( labelSettings.dataDefinedProperties.size() ) );
414+
if ( !labelSettings.properties().isActive( p ) )
415+
return QString();
415416

416-
QMap< QgsPalLayerSettings::DataDefinedProperties, QgsDataDefined* >::const_iterator dIt = labelSettings.dataDefinedProperties.constFind( p );
417-
if ( dIt != labelSettings.dataDefinedProperties.constEnd() )
418-
{
419-
QgsDataDefined* dd = dIt.value();
417+
const QgsAbstractProperty* prop = labelSettings.properties().property( p );
418+
if ( prop->propertyType() != QgsAbstractProperty::FieldBasedProperty )
419+
return QString();
420420

421-
// can only modify attributes that are data defined with a mapped field
422-
if ( dd->isActive() && !dd->useExpression() && !dd->field().isEmpty() )
423-
return dd->field();
424-
}
425-
return QString();
421+
return static_cast< const QgsFieldBasedProperty* >( prop )->field();
426422
}
427423

428-
int QgsMapToolLabel::dataDefinedColumnIndex( QgsPalLayerSettings::DataDefinedProperties p, const QgsPalLayerSettings& labelSettings, const QgsVectorLayer* vlayer ) const
424+
int QgsMapToolLabel::dataDefinedColumnIndex( QgsPalLayerSettings::Property p, const QgsPalLayerSettings& labelSettings, const QgsVectorLayer* vlayer ) const
429425
{
430426
QString fieldname = dataDefinedColumnName( p, labelSettings );
431427
if ( !fieldname.isEmpty() )

‎src/app/qgsmaptoollabel.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,11 +117,11 @@ class APP_EXPORT QgsMapToolLabel: public QgsMapTool
117117
QFont currentLabelFont();
118118

119119
//! Returns a data defined attribute column name for particular property or empty string if not defined
120-
QString dataDefinedColumnName( QgsPalLayerSettings::DataDefinedProperties p, const QgsPalLayerSettings& labelSettings ) const;
120+
QString dataDefinedColumnName( QgsPalLayerSettings::Property p, const QgsPalLayerSettings& labelSettings ) const;
121121

122122
/** Returns a data defined attribute column index
123123
@return -1 if column does not exist or an expression is used instead */
124-
int dataDefinedColumnIndex( QgsPalLayerSettings::DataDefinedProperties p, const QgsPalLayerSettings& labelSettings, const QgsVectorLayer* vlayer ) const;
124+
int dataDefinedColumnIndex( QgsPalLayerSettings::Property p, const QgsPalLayerSettings& labelSettings, const QgsVectorLayer* vlayer ) const;
125125

126126
//! Returns whether to preserve predefined rotation data during label pin/unpin operations
127127
bool currentLabelPreserveRotation();

‎src/core/dxf/qgsdxfexport.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4259,7 +4259,7 @@ void QgsDxfExport::drawLabel( const QString& layerId, QgsRenderContext& context,
42594259
QgsPalLayerSettings tmpLyr( settings );
42604260

42614261
// apply any previously applied data defined settings for the label
4262-
const QMap< QgsPalLayerSettings::DataDefinedProperties, QVariant >& ddValues = lf->dataDefinedValues();
4262+
const QMap< QgsPalLayerSettings::Property, QVariant >& ddValues = lf->dataDefinedValues();
42634263

42644264
//font
42654265
QFont dFont = lf->definedFont();

‎src/core/qgsdiagramrenderer.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
#include <QDomElement>
2626
#include <QPainter>
2727

28-
const QMap< int, QString > QgsDiagramLayerSettings::sPropertyNameMap
28+
const QgsPropertyDefinition QgsDiagramLayerSettings::sPropertyNameMap
2929
{
3030
{ QgsDiagramLayerSettings::BackgroundColor, "backgroundColor" },
3131
{ QgsDiagramLayerSettings::OutlineColor, "outlineColor" },

‎src/core/qgsdiagramrenderer.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -308,7 +308,7 @@ class CORE_EXPORT QgsDiagramLayerSettings
308308
//! Property collection for data defined diagram settings
309309
QgsPropertyCollection mProperties;
310310

311-
static const QMap< int, QString > sPropertyNameMap;
311+
static const QgsPropertyDefinition sPropertyNameMap;
312312
};
313313

314314
/** \ingroup core

‎src/core/qgspallabeling.cpp

Lines changed: 217 additions & 612 deletions
Large diffs are not rendered by default.

‎src/core/qgspallabeling.h

Lines changed: 36 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
#include "qgsmapunitscale.h"
3939
#include "qgsstringutils.h"
4040
#include "qgstextrenderer.h"
41+
#include "qgspropertycollection.h"
4142

4243
namespace pal
4344
{
@@ -261,7 +262,7 @@ class CORE_EXPORT QgsPalLayerSettings
261262

262263
//! Data definable properties.
263264
// update sPropertyNameMap QMap in constructor when adding/deleting enum value
264-
enum DataDefinedProperties
265+
enum Property
265266
{
266267
// text style
267268
Size = 0, //!< Label size
@@ -529,61 +530,24 @@ class CORE_EXPORT QgsPalLayerSettings
529530
*/
530531
QDomElement writeXml( QDomDocument& doc );
531532

532-
/** Get a data defined property pointer
533-
* @note helpful for Python access
534-
*/
535-
QgsDataDefined* dataDefinedProperty( QgsPalLayerSettings::DataDefinedProperties p );
536-
537-
/** Set a property as data defined
538-
* @note helpful for Python access
539-
*/
540-
void setDataDefinedProperty( QgsPalLayerSettings::DataDefinedProperties p,
541-
bool active, bool useExpr, const QString& expr, const QString& field );
542-
543-
//! Set a property to static instead data defined
544-
void removeDataDefinedProperty( QgsPalLayerSettings::DataDefinedProperties p );
545-
546-
/** Clear all data-defined properties
547-
* @note added in QGIS 2.12
548-
*/
549-
void removeAllDataDefinedProperties();
550-
551-
/** Convert old property value to new one as delimited values
552-
* @note not available in python bindings; as temporary solution until refactoring of project settings
553-
*/
554-
QString updateDataDefinedString( const QString& value );
555-
556-
/** Get property value as separate values split into Qmap
557-
* @note not available in python bindings
558-
*/
559-
QMap<QString, QString> dataDefinedMap( QgsPalLayerSettings::DataDefinedProperties p ) const;
560-
561-
/** Get data defined property value from expression string or attribute field name
562-
* @returns value inside QVariant
563-
* @note not available in python bindings
564-
*/
565-
QVariant dataDefinedValue( QgsPalLayerSettings::DataDefinedProperties p, QgsFeature& f, const QgsFields& fields,
566-
const QgsExpressionContext* context = nullptr ) const;
567-
568-
/** Get data defined property value from expression string or attribute field name
569-
* @returns true/false whether result is null or invalid
570-
* @note not available in python bindings
571-
*/
572-
bool dataDefinedEvaluate( QgsPalLayerSettings::DataDefinedProperties p, QVariant& exprVal, QgsExpressionContext* context = nullptr, const QVariant& originalValue = QVariant() ) const;
573-
574-
/** Whether data definition is active
533+
/** Returns a reference to the label's property collection, used for data defined overrides.
534+
* @note added in QGIS 3.0
535+
* @see setProperties()
575536
*/
576-
bool dataDefinedIsActive( QgsPalLayerSettings::DataDefinedProperties p ) const;
537+
QgsPropertyCollection& properties() { return mProperties; }
577538

578-
/** Whether data definition is set to use an expression
539+
/** Returns a reference to the label's property collection, used for data defined overrides.
540+
* @note added in QGIS 3.0
541+
* @see setProperties()
579542
*/
580-
bool dataDefinedUseExpression( QgsPalLayerSettings::DataDefinedProperties p ) const;
543+
const QgsPropertyCollection& properties() const { return mProperties; }
581544

582-
/** Map of current data defined properties
583-
*
584-
* Pointers to QgsDataDefined should never be null, the pointers are owned by this class
545+
/** Sets the label's property collection, used for data defined overrides.
546+
* @param collection property collection. Existing properties will be replaced.
547+
* @note added in QGIS 3.0
548+
* @see properties()
585549
*/
586-
QMap< QgsPalLayerSettings::DataDefinedProperties, QgsDataDefined* > dataDefinedProperties;
550+
void setProperties( const QgsPropertyCollection& collection ) { mProperties = collection; }
587551

588552
/** Returns the label text formatting settings, e.g., font settings, buffer settings, etc.
589553
* @see setFormat()
@@ -614,16 +578,15 @@ class CORE_EXPORT QgsPalLayerSettings
614578

615579
private:
616580

617-
void readDataDefinedPropertyMap( QgsVectorLayer* layer, QDomElement* parentElem,
618-
QMap < QgsPalLayerSettings::DataDefinedProperties,
619-
QgsDataDefined* > & propertyMap );
620-
void writeDataDefinedPropertyMap( QgsVectorLayer* layer, QDomElement* parentElem,
621-
const QMap < QgsPalLayerSettings::DataDefinedProperties,
622-
QgsDataDefined* > & propertyMap );
623-
void readDataDefinedProperty( QgsVectorLayer* layer,
624-
QgsPalLayerSettings::DataDefinedProperties p,
625-
QMap < QgsPalLayerSettings::DataDefinedProperties,
626-
QgsDataDefined* > & propertyMap );
581+
/**
582+
* Reads data defined properties from a QGIS 2.x project.
583+
*/
584+
void readOldDataDefinedPropertyMap( QgsVectorLayer* layer, QDomElement* parentElem );
585+
586+
/**
587+
* Reads a data defined property from a QGIS 2.x project.
588+
*/
589+
void readOldDataDefinedProperty( QgsVectorLayer* layer, QgsPalLayerSettings::Property p );
627590

628591
enum DataDefinedValueType
629592
{
@@ -644,7 +607,7 @@ class CORE_EXPORT QgsPalLayerSettings
644607

645608
// convenience data defined evaluation function
646609
bool dataDefinedValEval( DataDefinedValueType valType,
647-
QgsPalLayerSettings::DataDefinedProperties p,
610+
QgsPalLayerSettings::Property p,
648611
QVariant& exprVal, QgsExpressionContext &context, const QVariant& originalValue = QVariant() );
649612

650613
void parseTextStyle( QFont& labelFont,
@@ -667,14 +630,18 @@ class CORE_EXPORT QgsPalLayerSettings
667630
*/
668631
void registerObstacleFeature( QgsFeature &f, QgsRenderContext &context, QgsLabelFeature** obstacleFeature, QgsGeometry* obstacleGeometry = nullptr );
669632

670-
QMap<DataDefinedProperties, QVariant> dataDefinedValues;
633+
QMap<Property, QVariant> dataDefinedValues;
634+
635+
//! Property collection for data defined label settings
636+
QgsPropertyCollection mProperties;
637+
671638
QgsExpression* expression;
672639

673640
QFontDatabase mFontDB;
674641

675642
QgsTextFormat mFormat;
676643

677-
static const QMap< int, QString > sPropertyNameMap;
644+
static const QgsPropertyDefinition sPropertyNameMap;
678645
static const QVector< PredefinedPointPosition > DEFAULT_PLACEMENT_ORDER;
679646
};
680647

@@ -821,23 +788,23 @@ class CORE_EXPORT QgsPalLabeling
821788
protected:
822789
// update temporary QgsPalLayerSettings with any data defined text style values
823790
static void dataDefinedTextStyle( QgsPalLayerSettings& tmpLyr,
824-
const QMap< QgsPalLayerSettings::DataDefinedProperties, QVariant >& ddValues );
791+
const QMap< QgsPalLayerSettings::Property, QVariant >& ddValues );
825792

826793
// update temporary QgsPalLayerSettings with any data defined text formatting values
827794
static void dataDefinedTextFormatting( QgsPalLayerSettings& tmpLyr,
828-
const QMap< QgsPalLayerSettings::DataDefinedProperties, QVariant >& ddValues );
795+
const QMap< QgsPalLayerSettings::Property, QVariant >& ddValues );
829796

830797
// update temporary QgsPalLayerSettings with any data defined text buffer values
831798
static void dataDefinedTextBuffer( QgsPalLayerSettings& tmpLyr,
832-
const QMap< QgsPalLayerSettings::DataDefinedProperties, QVariant >& ddValues );
799+
const QMap< QgsPalLayerSettings::Property, QVariant >& ddValues );
833800

834801
// update temporary QgsPalLayerSettings with any data defined shape background values
835802
static void dataDefinedShapeBackground( QgsPalLayerSettings& tmpLyr,
836-
const QMap< QgsPalLayerSettings::DataDefinedProperties, QVariant >& ddValues );
803+
const QMap< QgsPalLayerSettings::Property, QVariant >& ddValues );
837804

838805
// update temporary QgsPalLayerSettings with any data defined drop shadow values
839806
static void dataDefinedDropShadow( QgsPalLayerSettings& tmpLyr,
840-
const QMap< QgsPalLayerSettings::DataDefinedProperties, QVariant >& ddValues );
807+
const QMap< QgsPalLayerSettings::Property, QVariant >& ddValues );
841808

842809
friend class QgsVectorLayerLabelProvider; // to allow calling the static methods above
843810
friend class QgsDxfExport; // to allow calling the static methods above

‎src/core/qgsproperty.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,16 @@ int QgsAbstractProperty::valueAsInt( const QgsExpressionContext &context, int de
140140
return integer;
141141
}
142142

143+
bool QgsAbstractProperty::valueAsBool( const QgsExpressionContext& context, bool defaultValue ) const
144+
{
145+
QVariant val = value( context, defaultValue );
146+
147+
if ( !val.isValid() )
148+
return defaultValue;
149+
150+
return val.toBool();
151+
}
152+
143153
bool QgsAbstractProperty::writeXml( QDomElement &propertyElem, QDomDocument &doc ) const
144154
{
145155
Q_UNUSED( doc );

‎src/core/qgsproperty.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,17 @@ class CORE_EXPORT QgsAbstractProperty
152152
*/
153153
int valueAsInt( const QgsExpressionContext& context, int defaultValue = 0 ) const;
154154

155+
/**
156+
* Calculates the current value of the property and interprets it as an boolean.
157+
* @param context QgsExpressionContext to evaluate the property for.
158+
* @param defaultValue default boolean to return if the property cannot be calculated as an boolean
159+
* @returns value parsed to boolean
160+
* @see value()
161+
* @see valueAsDouble()
162+
* @see valueAsColor()
163+
*/
164+
bool valueAsBool( const QgsExpressionContext& context, bool defaultValue = false ) const;
165+
155166
/**
156167
* Writes the current state of the property into an XML element
157168
* @param propertyElem destination element for the property's state

‎src/core/qgspropertycollection.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,15 @@ int QgsAbstractPropertyCollection::valueAsInt( int key, const QgsExpressionConte
5353
return prop->valueAsInt( context, defaultValue );
5454
}
5555

56+
bool QgsAbstractPropertyCollection::valueAsBool( int key, const QgsExpressionContext& context, bool defaultValue ) const
57+
{
58+
const QgsAbstractProperty* prop = property( key );
59+
if ( !prop || !prop->isActive() )
60+
return defaultValue;
61+
62+
return prop->valueAsBool( context, defaultValue );
63+
}
64+
5665

5766

5867
//
@@ -148,22 +157,34 @@ void QgsPropertyCollection::setProperty( int key, const QVariant& value )
148157

149158
bool QgsPropertyCollection::hasProperty( int key ) const
150159
{
160+
if ( mProperties.isEmpty() )
161+
return false;
162+
151163
return mProperties.contains( key );
152164
}
153165

154166
QgsAbstractProperty* QgsPropertyCollection::property( int key )
155167
{
168+
if ( mProperties.isEmpty() )
169+
return nullptr;
170+
156171
mDirty = true;
157172
return mProperties.value( key, nullptr );
158173
}
159174

160175
const QgsAbstractProperty *QgsPropertyCollection::property( int key ) const
161176
{
177+
if ( mProperties.isEmpty() )
178+
return nullptr;
179+
162180
return mProperties.value( key, nullptr );
163181
}
164182

165183
QVariant QgsPropertyCollection::value( int key, const QgsExpressionContext& context, const QVariant& defaultValue ) const
166184
{
185+
if ( mProperties.isEmpty() )
186+
return defaultValue;
187+
167188
QgsAbstractProperty* prop = mProperties.value( key, nullptr );
168189
if ( !prop || !prop->isActive() )
169190
return defaultValue;
@@ -201,6 +222,9 @@ QSet< QString > QgsPropertyCollection::referencedFields( const QgsExpressionCont
201222

202223
bool QgsPropertyCollection::isActive( int key ) const
203224
{
225+
if ( mProperties.isEmpty() )
226+
return false;
227+
204228
QgsAbstractProperty* prop = mProperties.value( key, nullptr );
205229
return prop && prop->isActive();
206230
}

‎src/core/qgspropertycollection.h

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@ class QgsAbstractProperty;
2525
class QDomElement;
2626
class QDomDocument;
2727

28+
//! Definition of available properties
29+
typedef QMap< int, QString > QgsPropertyDefinition;
30+
2831
/**
2932
* \ingroup core
3033
* \class QgsAbstractPropertyCollection
@@ -141,6 +144,19 @@ class CORE_EXPORT QgsAbstractPropertyCollection
141144
*/
142145
int valueAsInt( int key, const QgsExpressionContext& context, int defaultValue = 0 ) const;
143146

147+
/**
148+
* Calculates the current value of the property with the specified key and interprets it as an boolean.
149+
* @param key integer key for property to return. The intended use case is that a context specific enum is cast to
150+
* int and used for the key value.
151+
* @param context QgsExpressionContext to evaluate the property for.
152+
* @param defaultValue default boolean to return if the property cannot be calculated as a boolean
153+
* @returns value parsed to bool
154+
* @see value()
155+
* @see valueAsDouble()
156+
* @see valueAsColor()
157+
*/
158+
bool valueAsBool( int key, const QgsExpressionContext& context, bool defaultValue = false ) const;
159+
144160
/**
145161
* Prepares the collection against a specified expression context. Calling prepare before evaluating the
146162
* collection's properties multiple times allows precalculation of expensive setup tasks such as parsing expressions.
@@ -183,7 +199,7 @@ class CORE_EXPORT QgsAbstractPropertyCollection
183199
* to avoid writing the raw integer key values to XML, for readability and future-proofness.
184200
* @see readXml()
185201
*/
186-
virtual bool writeXml( QDomElement& collectionElem, QDomDocument& doc, const QMap< int, QString >& propertyNameMap ) const = 0;
202+
virtual bool writeXml( QDomElement& collectionElem, QDomDocument& doc, const QgsPropertyDefinition& propertyNameMap ) const = 0;
187203

188204
/**
189205
* Reads property collection state from an XML element.
@@ -244,7 +260,7 @@ class CORE_EXPORT QgsPropertyCollection : public QgsAbstractPropertyCollection
244260
bool isActive( int key ) const override;
245261
bool hasActiveProperties() const override;
246262
bool hasActiveDynamicProperties() const override;
247-
bool writeXml( QDomElement& collectionElem, QDomDocument& doc, const QMap< int, QString >& propertyNameMap ) const override;
263+
bool writeXml( QDomElement& collectionElem, QDomDocument& doc, const QgsPropertyDefinition& propertyNameMap ) const override;
248264
bool readXml( const QDomElement& collectionElem, const QDomDocument& doc, const QMap<int, QString> &propertyNameMap ) override;
249265

250266
/**
@@ -399,7 +415,7 @@ class CORE_EXPORT QgsPropertyCollectionStack : public QgsAbstractPropertyCollect
399415

400416
QSet<int> propertyKeys() const override;
401417
bool hasProperty( int key ) const override;
402-
bool writeXml( QDomElement& collectionElem, QDomDocument& doc, const QMap< int, QString >& propertyNameMap ) const override;
418+
bool writeXml( QDomElement& collectionElem, QDomDocument& doc, const QgsPropertyDefinition& propertyNameMap ) const override;
403419
bool readXml( const QDomElement& collectionElem, const QDomDocument& doc, const QMap<int, QString> &propertyNameMap ) override;
404420

405421
private:

‎src/core/qgstextlabelfeature.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,9 @@ class QgsTextLabelFeature : public QgsLabelFeature
4242
void calculateInfo( bool curvedLabeling, QFontMetricsF* fm, const QgsMapToPixel* xform, double maxinangle, double maxoutangle );
4343

4444
//! Get data-defined values
45-
const QMap< QgsPalLayerSettings::DataDefinedProperties, QVariant >& dataDefinedValues() const { return mDataDefinedValues; }
45+
const QMap< QgsPalLayerSettings::Property, QVariant >& dataDefinedValues() const { return mDataDefinedValues; }
4646
//! Set data-defined values
47-
void setDataDefinedValues( const QMap< QgsPalLayerSettings::DataDefinedProperties, QVariant >& values ) { mDataDefinedValues = values; }
47+
void setDataDefinedValues( const QMap< QgsPalLayerSettings::Property, QVariant >& values ) { mDataDefinedValues = values; }
4848

4949
//! Set font to be used for rendering
5050
void setDefinedFont( const QFont& f ) { mDefinedFont = f; }
@@ -62,7 +62,7 @@ class QgsTextLabelFeature : public QgsLabelFeature
6262
//! Metrics of the font for rendering
6363
QFontMetricsF* mFontMetrics;
6464
//! Stores attribute values for data defined properties
65-
QMap< QgsPalLayerSettings::DataDefinedProperties, QVariant > mDataDefinedValues;
65+
QMap< QgsPalLayerSettings::Property, QVariant > mDataDefinedValues;
6666

6767
};
6868

‎src/core/qgsvectorlayerdiagramprovider.cpp

Lines changed: 5 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -220,21 +220,11 @@ QgsLabelFeature* QgsVectorLayerDiagramProvider::registerDiagram( QgsFeature& fea
220220
}
221221

222222
// data defined show diagram? check this before doing any other processing
223-
if ( mSettings.properties().hasProperty( QgsDiagramLayerSettings::Show )
224-
&& mSettings.properties().property( QgsDiagramLayerSettings::Show )->isActive() )
225-
{
226-
bool show = mSettings.properties().valueAsInt( QgsDiagramLayerSettings::Show, context.expressionContext(), true );
227-
if ( !show )
228-
return nullptr;
229-
}
223+
if ( !mSettings.properties().valueAsBool( QgsDiagramLayerSettings::Show, context.expressionContext(), true ) )
224+
return nullptr;
230225

231226
// data defined obstacle?
232-
bool isObstacle = mSettings.isObstacle();
233-
if ( mSettings.properties().hasProperty( QgsDiagramLayerSettings::IsObstacle )
234-
&& mSettings.properties().property( QgsDiagramLayerSettings::IsObstacle )->isActive() )
235-
{
236-
isObstacle = mSettings.properties().valueAsInt( QgsDiagramLayerSettings::IsObstacle, context.expressionContext(), isObstacle );
237-
}
227+
bool isObstacle = mSettings.properties().valueAsBool( QgsDiagramLayerSettings::IsObstacle, context.expressionContext(), mSettings.isObstacle() );
238228

239229
//convert geom to geos
240230
QgsGeometry geom = feat.geometry();
@@ -289,12 +279,8 @@ QgsLabelFeature* QgsVectorLayerDiagramProvider::registerDiagram( QgsFeature& fea
289279

290280
// feature to the layer
291281
bool alwaysShow = mSettings.showAllDiagrams();
292-
if ( mSettings.properties().hasProperty( QgsDiagramLayerSettings::AlwaysShow )
293-
&& mSettings.properties().property( QgsDiagramLayerSettings::AlwaysShow )->isActive() )
294-
{
295-
context.expressionContext().setOriginalValueVariable( alwaysShow );
296-
alwaysShow = mSettings.properties().valueAsInt( QgsDiagramLayerSettings::AlwaysShow, context.expressionContext(), alwaysShow );
297-
}
282+
context.expressionContext().setOriginalValueVariable( alwaysShow );
283+
alwaysShow = mSettings.properties().valueAsBool( QgsDiagramLayerSettings::AlwaysShow, context.expressionContext(), alwaysShow );
298284

299285
// new style data defined position
300286
bool ddPos = false;

‎src/core/qgsvectorlayerlabelprovider.cpp

Lines changed: 3 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -177,26 +177,9 @@ bool QgsVectorLayerLabelProvider::prepare( const QgsRenderContext& context, QSet
177177
attributeNames.insert( lyr.fieldName );
178178
}
179179

180+
lyr.properties().prepare( context.expressionContext() );
180181
// add field indices of data defined expression or field
181-
QMap< QgsPalLayerSettings::DataDefinedProperties, QgsDataDefined* >::const_iterator dIt = lyr.dataDefinedProperties.constBegin();
182-
for ( ; dIt != lyr.dataDefinedProperties.constEnd(); ++dIt )
183-
{
184-
QgsDataDefined* dd = dIt.value();
185-
if ( !dd->isActive() )
186-
{
187-
continue;
188-
}
189-
190-
// this will return columns for expressions or field name, depending upon what is set to be used
191-
// this also prepares any expressions, too
192-
QSet<QString> cols = dd->referencedColumns( context.expressionContext() );
193-
194-
//QgsDebugMsgLevel( QString( "Data defined referenced columns:" ) + cols.join( "," ), 4 );
195-
Q_FOREACH ( const QString& name, cols )
196-
{
197-
attributeNames.insert( name );
198-
}
199-
}
182+
attributeNames.unite( lyr.properties().referencedFields( context.expressionContext() ) );
200183
}
201184

202185
// NOW INITIALIZE QgsPalLayerSettings
@@ -389,7 +372,7 @@ void QgsVectorLayerLabelProvider::drawLabel( QgsRenderContext& context, pal::Lab
389372
QgsPalLayerSettings tmpLyr( mSettings );
390373

391374
// apply any previously applied data defined settings for the label
392-
const QMap< QgsPalLayerSettings::DataDefinedProperties, QVariant >& ddValues = lf->dataDefinedValues();
375+
const QMap< QgsPalLayerSettings::Property, QVariant >& ddValues = lf->dataDefinedValues();
393376

394377
//font
395378
QFont dFont = lf->definedFont();

‎src/gui/qgsdatadefinedbuttonv2.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,11 @@ QgsAbstractProperty* QgsDataDefinedButtonV2::toProperty()
180180
return p;
181181
}
182182

183+
void QgsDataDefinedButtonV2::registerCheckedWidget( QWidget* widget )
184+
{
185+
//TODO
186+
}
187+
183188
void QgsDataDefinedButtonV2::mouseReleaseEvent( QMouseEvent *event )
184189
{
185190
// Ctrl-click to toggle activated state

‎src/gui/qgsdatadefinedbuttonv2.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ class GUI_EXPORT QgsDataDefinedButtonV2: public QToolButton
3939
{
4040
Q_OBJECT
4141
Q_PROPERTY( QString usageInfo READ usageInfo WRITE setUsageInfo )
42+
Q_PROPERTY( bool active READ isActive WRITE setActive )
4243

4344
public:
4445

@@ -82,6 +83,11 @@ class GUI_EXPORT QgsDataDefinedButtonV2: public QToolButton
8283

8384
QgsAbstractProperty* toProperty();
8485

86+
/**
87+
* Returns true if the button has an active property.
88+
*/
89+
bool isActive() const { return mActive; }
90+
8591
/**
8692
* The valid data types that will work for the definition (QVariant-coercible to expected type)
8793
* Compared against the variant type of the QgsField from data source and expression result
@@ -103,6 +109,11 @@ class GUI_EXPORT QgsDataDefinedButtonV2: public QToolButton
103109
*/
104110
void setUsageInfo( const QString& info ) { mUsageInfo = info; updateGui(); }
105111

112+
/**
113+
* Register a sibling widget that get checked when data definition or expression is active
114+
*/
115+
void registerCheckedWidget( QWidget* widget );
116+
106117
//! Callback function for retrieving the expression context for the button
107118
typedef QgsExpressionContext( *ExpressionContextCallback )( const void* context );
108119

‎src/gui/qgstextformatwidget.cpp

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -518,7 +518,7 @@ void QgsTextFormatWidget::setWidgetMode( QgsTextFormatWidget::Mode mode )
518518

519519
void QgsTextFormatWidget::toggleDDButtons( bool visible )
520520
{
521-
Q_FOREACH ( QgsDataDefinedButton* button, findChildren< QgsDataDefinedButton* >() )
521+
Q_FOREACH ( QgsDataDefinedButtonV2* button, findChildren< QgsDataDefinedButtonV2* >() )
522522
{
523523
button->setVisible( visible );
524524
}
@@ -544,10 +544,9 @@ void QgsTextFormatWidget::connectValueChanged( const QList<QWidget *>& widgets,
544544
{
545545
Q_FOREACH ( QWidget* widget, widgets )
546546
{
547-
if ( QgsDataDefinedButton* w = qobject_cast<QgsDataDefinedButton*>( widget ) )
547+
if ( QgsDataDefinedButtonV2* w = qobject_cast<QgsDataDefinedButtonV2*>( widget ) )
548548
{
549-
connect( w, SIGNAL( dataDefinedActivated( bool ) ), this, slot );
550-
connect( w, SIGNAL( dataDefinedChanged( QString ) ), this, slot );
549+
connect( w, SIGNAL( changed() ), this, slot );
551550
}
552551
else if ( QgsFieldExpressionWidget* w = qobject_cast< QgsFieldExpressionWidget*>( widget ) )
553552
{

‎src/ui/qgstextformatwidgetbase.ui

Lines changed: 93 additions & 93 deletions
Large diffs are not rendered by default.

‎tests/src/core/testqgslabelingengine.cpp

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,8 @@ void TestQgsLabelingEngine::testRuleBased()
237237
s2.placement = QgsPalLayerSettings::OverPoint;
238238
s2.quadOffset = QgsPalLayerSettings::QuadrantBelowRight;
239239
s2.displayAll = true;
240-
s2.setDataDefinedProperty( QgsPalLayerSettings::Size, true, true, QStringLiteral( "18" ), QString() );
240+
241+
s2.properties().setProperty( QgsPalLayerSettings::Size, new QgsStaticProperty( QStringLiteral( "18" ) ) );
241242

242243
root->appendChild( new QgsRuleBasedLabeling::Rule( new QgsPalLayerSettings( s2 ), 0, 0, QStringLiteral( "Class = 'Jet'" ) ) );
243244

@@ -311,8 +312,8 @@ void TestQgsLabelingEngine::zOrder()
311312
pls1.setFormat( format );
312313

313314
//use data defined coloring and font size so that stacking order of labels can be determined
314-
pls1.setDataDefinedProperty( QgsPalLayerSettings::Color, true, true, QStringLiteral( "case when \"Class\"='Jet' then '#ff5500' when \"Class\"='B52' then '#00ffff' else '#ff00ff' end" ), QString() );
315-
pls1.setDataDefinedProperty( QgsPalLayerSettings::Size, true, true, QStringLiteral( "case when \"Class\"='Jet' then 100 when \"Class\"='B52' then 30 else 50 end" ), QString() );
315+
pls1.properties().setProperty( QgsPalLayerSettings::Color, new QgsExpressionBasedProperty( QStringLiteral( "case when \"Class\"='Jet' then '#ff5500' when \"Class\"='B52' then '#00ffff' else '#ff00ff' end" ) ) );
316+
pls1.properties().setProperty( QgsPalLayerSettings::Size, new QgsExpressionBasedProperty( QStringLiteral( "case when \"Class\"='Jet' then 100 when \"Class\"='B52' then 30 else 50 end" ) ) );
316317

317318
QgsVectorLayerLabelProvider* provider1 = new QgsVectorLayerLabelProvider( vl, QString(), true, &pls1 );
318319
QgsLabelingEngine engine;
@@ -329,7 +330,7 @@ void TestQgsLabelingEngine::zOrder()
329330
img = job.renderedImage();
330331

331332
//test data defined z-index
332-
pls1.setDataDefinedProperty( QgsPalLayerSettings::ZIndex, true, true, QStringLiteral( "case when \"Class\"='Jet' then 3 when \"Class\"='B52' then 1 else 2 end" ), QString() );
333+
pls1.properties().setProperty( QgsPalLayerSettings::ZIndex, new QgsExpressionBasedProperty( QStringLiteral( "case when \"Class\"='Jet' then 3 when \"Class\"='B52' then 1 else 2 end" ) ) );
333334
provider1 = new QgsVectorLayerLabelProvider( vl, QString(), true, &pls1 );
334335
engine.addProvider( provider1 );
335336
p.begin( &img );
@@ -341,7 +342,7 @@ void TestQgsLabelingEngine::zOrder()
341342
QVERIFY( imageCheck( "label_order_zindex", img, 20 ) );
342343
img = job.renderedImage();
343344

344-
pls1.removeAllDataDefinedProperties();
345+
pls1.properties().clear();
345346
format = pls1.format();
346347
format.setColor( QColor( 255, 50, 100 ) );
347348
format.setSize( 30 );
@@ -386,7 +387,7 @@ void TestQgsLabelingEngine::zOrder()
386387

387388
//try mixing layer order and z-index
388389
engine.removeProvider( provider1 );
389-
pls1.setDataDefinedProperty( QgsPalLayerSettings::ZIndex, true, true, QStringLiteral( "if(\"Class\"='Jet',3,0)" ), QString() );
390+
pls1.properties().setProperty( QgsPalLayerSettings::ZIndex, new QgsExpressionBasedProperty( QStringLiteral( "if(\"Class\"='Jet',3,0)" ) ) );
390391
provider1 = new QgsVectorLayerLabelProvider( vl, QString(), true, &pls1 );
391392
engine.addProvider( provider1 );
392393

‎tests/src/core/testqgsproperty.cpp

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,44 @@ void TestQgsProperty::conversions()
190190
i1->setStaticValue( "i am not a int" ); //not a int, should return default value
191191
QCOMPARE( i1->valueAsInt( context, -11 ), -11 );
192192
QCOMPARE( collection.valueAsInt( 2, context, -11 ), -11 );
193+
194+
// test boolean conversions
195+
QgsStaticProperty* b1 = new QgsStaticProperty( QVariant(), true );
196+
collection.setProperty( 3, b1 );
197+
QCOMPARE( b1->valueAsBool( context , false ), false );
198+
QCOMPARE( b1->valueAsBool( context , true ), true );
199+
QCOMPARE( collection.valueAsBool( 3, context , false ), false );
200+
QCOMPARE( collection.valueAsBool( 3, context , true ), true );
201+
b1->setStaticValue( true );
202+
QCOMPARE( b1->valueAsBool( context , false ), true );
203+
QCOMPARE( b1->valueAsBool( context , true ), true );
204+
QCOMPARE( collection.valueAsBool( 3, context , false ), true );
205+
QCOMPARE( collection.valueAsBool( 3, context , true ), true );
206+
b1->setStaticValue( false );
207+
QCOMPARE( b1->valueAsBool( context , false ), false );
208+
QCOMPARE( b1->valueAsBool( context , true ), false );
209+
QCOMPARE( collection.valueAsBool( 3, context , false ), false );
210+
QCOMPARE( collection.valueAsBool( 3, context , true ), false );
211+
b1->setStaticValue( 1 );
212+
QCOMPARE( b1->valueAsBool( context , false ), true );
213+
QCOMPARE( b1->valueAsBool( context , true ), true );
214+
QCOMPARE( collection.valueAsBool( 3, context , false ), true );
215+
QCOMPARE( collection.valueAsBool( 3, context , true ), true );
216+
b1->setStaticValue( 0 );
217+
QCOMPARE( b1->valueAsBool( context , false ), false );
218+
QCOMPARE( b1->valueAsBool( context , true ), false );
219+
QCOMPARE( collection.valueAsBool( 3, context , false ), false );
220+
QCOMPARE( collection.valueAsBool( 3, context , true ), false );
221+
b1->setStaticValue( "true" );
222+
QCOMPARE( b1->valueAsBool( context , false ), true );
223+
QCOMPARE( b1->valueAsBool( context , true ), true );
224+
QCOMPARE( collection.valueAsBool( 3, context , false ), true );
225+
QCOMPARE( collection.valueAsBool( 3, context , true ), true );
226+
b1->setStaticValue( "" );
227+
QCOMPARE( b1->valueAsBool( context , false ), false );
228+
QCOMPARE( b1->valueAsBool( context , true ), false );
229+
QCOMPARE( collection.valueAsBool( 3, context , false ), false );
230+
QCOMPARE( collection.valueAsBool( 3, context , true ), false );
193231
}
194232

195233
void TestQgsProperty::staticProperty()

0 commit comments

Comments
 (0)
Please sign in to comment.