QGIS API Documentation  3.26.3-Buenos Aires (65e4edfdad)
qgsproperty.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsproperty.cpp
3  ---------------
4  Date : January 2017
5  Copyright : (C) 2017 by Nyall Dawson
6  Email : nyall dot dawson at gmail dot com
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
15 
16 #include "qgsproperty.h"
17 #include "qgsproperty_p.h"
18 
19 #include "qgslogger.h"
20 #include "qgsexpression.h"
21 #include "qgsfeature.h"
22 #include "qgssymbollayerutils.h"
23 #include "qgscolorramp.h"
24 #include "qgsexpressionnodeimpl.h"
25 
26 #include <QRegularExpression>
27 
28 QgsPropertyDefinition::QgsPropertyDefinition( const QString &name, const QString &description, QgsPropertyDefinition::StandardPropertyTemplate type, const QString &origin, const QString &comment )
29  : mName( name )
30  , mDescription( description )
31  , mStandardType( type )
32  , mOrigin( origin )
33  , mComment( comment )
34 {
35  switch ( mStandardType )
36  {
37  case Boolean:
38  mTypes = DataTypeBoolean;
39  mHelpText = QObject::tr( "bool [<b>1</b>=True|<b>0</b>=False]" );
40  break;
41 
42  case Integer:
43  mTypes = DataTypeNumeric;
44  mHelpText = QObject::tr( "int [≤ 0 ≥]" );
45  break;
46 
47  case IntegerPositive:
48  mTypes = DataTypeNumeric;
49  mHelpText = QObject::tr( "int [≥ 0]" );
50  break;
51 
53  mTypes = DataTypeNumeric;
54  mHelpText = QObject::tr( "int [≥ 1]" );
55  break;
56 
57  case Double:
58  mTypes = DataTypeNumeric;
59  mHelpText = QObject::tr( "double [≤ 0.0 ≥]" );
60  break;
61 
62  case DoublePositive:
63  mTypes = DataTypeNumeric;
64  mHelpText = QObject::tr( "double [≥ 0.0]" );
65  break;
66 
67  case Double0To1:
68  mTypes = DataTypeNumeric;
69  mHelpText = QObject::tr( "double [0.0-1.0]" );
70  break;
71 
72  case Rotation:
73  mTypes = DataTypeNumeric;
74  mHelpText = QObject::tr( "double [0.0-360.0]" );
75  break;
76 
77  case String:
78  mTypes = DataTypeString;
79  mHelpText = QObject::tr( "string of variable length" );
80  break;
81 
82  case Opacity:
83  mTypes = DataTypeNumeric;
84  mHelpText = QObject::tr( "int [0-100]" );
85  break;
86 
87  case RenderUnits:
88  mTypes = DataTypeString;
89  mHelpText = trString() + QStringLiteral( "[<b>MM</b>|<b>MapUnit</b>|<b>Pixel</b>|<b>Point</b>]" );
90  break;
91 
92  case ColorWithAlpha:
93  mTypes = DataTypeString;
94  mHelpText = QObject::tr( "string [<b>r,g,b,a</b>] as int 0-255 or #<b>AARRGGBB</b> as hex or <b>color</b> as color's name" );
95  break;
96 
97  case ColorNoAlpha:
98  mTypes = DataTypeString;
99  mHelpText = QObject::tr( "string [<b>r,g,b</b>] as int 0-255 or #<b>RRGGBB</b> as hex or <b>color</b> as color's name" );
100  break;
101 
102  case PenJoinStyle:
103  mTypes = DataTypeString;
104  mHelpText = trString() + QStringLiteral( "[<b>bevel</b>|<b>miter</b>|<b>round</b>]" );
105  break;
106 
107  case BlendMode:
108  mTypes = DataTypeString;
109  mHelpText = trString() + QStringLiteral( "[<b>Normal</b>|<b>Lighten</b>|<b>Screen</b>|<b>Dodge</b>|<br>"
110  "<b>Addition</b>|<b>Darken</b>|<b>Multiply</b>|<b>Burn</b>|<b>Overlay</b>|<br>"
111  "<b>SoftLight</b>|<b>HardLight</b>|<b>Difference</b>|<b>Subtract</b>]" );
112  break;
113 
114  case Point:
115  mTypes = DataTypeString;
116  mHelpText = QObject::tr( "double coord [<b>X,Y</b>]" );
117  break;
118 
119  case Size:
120  mTypes = DataTypeNumeric;
121  mHelpText = QObject::tr( "double [≥ 0.0]" );
122  break;
123 
124  case Size2D:
125  mTypes = DataTypeString;
126  mHelpText = QObject::tr( "string of doubles '<b>width,height</b>' or array of doubles <b>[width, height]</b>" );
127  break;
128 
129  case LineStyle:
130  mTypes = DataTypeString;
131  mHelpText = trString() + QStringLiteral( "[<b>no</b>|<b>solid</b>|<b>dash</b>|<b>dot</b>|<b>dash dot</b>|<b>dash dot dot</b>]" );
132  break;
133 
134  case StrokeWidth:
135  mTypes = DataTypeNumeric;
136  mHelpText = QObject::tr( "double [≥ 0.0]" );
137  break;
138 
139  case FillStyle:
140  mTypes = DataTypeString;
141  mHelpText = trString() + QStringLiteral( "[<b>solid</b>|<b>horizontal</b>|<b>vertical</b>|<b>cross</b>|<b>b_diagonal</b>|<b>f_diagonal"
142  "</b>|<b>diagonal_x</b>|<b>dense1</b>|<b>dense2</b>|<b>dense3</b>|<b>dense4</b>|<b>dense5"
143  "</b>|<b>dense6</b>|<b>dense7</b>|<b>no]" );
144  break;
145 
146  case CapStyle:
147  mTypes = DataTypeString;
148  mHelpText = trString() + QStringLiteral( "[<b>square</b>|<b>flat</b>|<b>round</b>]" );
149  break;
150 
151  case HorizontalAnchor:
152  mTypes = DataTypeString;
153  mHelpText = trString() + QStringLiteral( "[<b>left</b>|<b>center</b>|<b>right</b>]" );
154  break;
155 
156  case VerticalAnchor:
157  mTypes = DataTypeString;
158  mHelpText = trString() + QStringLiteral( "[<b>top</b>|<b>center</b>|<b>bottom</b>]" );
159  break;
160 
161  case SvgPath:
162  mTypes = DataTypeString;
163  mHelpText = trString() + QStringLiteral( "[<b>filepath</b>] as<br>"
164  "<b>''</b>=empty|absolute|search-paths-relative|<br>"
165  "project-relative|URL" );
166  break;
167 
168  case Offset:
169  mTypes = DataTypeString;
170  mHelpText = QObject::tr( "string of doubles '<b>x,y</b>' or array of doubles <b>[x, y]</b>" );
171  break;
172 
173  case DateTime:
174  mTypes = DataTypeString;
175  mHelpText = QObject::tr( "DateTime or string representation of a DateTime" );
176  break;
177 
178  case Custom:
179  mTypes = DataTypeString;
180  }
181 }
182 
183 QgsPropertyDefinition::QgsPropertyDefinition( const QString &name, DataType dataType, const QString &description, const QString &helpText, const QString &origin, const QString &comment )
184  : mName( name )
185  , mDescription( description )
186  , mTypes( dataType )
187  , mHelpText( helpText )
188  , mOrigin( origin )
189  , mComment( comment )
190 {}
191 
193 {
194  return mTypes == DataTypeNumeric || mStandardType == Size || mStandardType == StrokeWidth || mStandardType == ColorNoAlpha || mStandardType == ColorWithAlpha
195  || mStandardType == Rotation;
196 }
197 
198 QString QgsPropertyDefinition::trString()
199 {
200  // just something to reduce translation redundancy
201  return QObject::tr( "string " );
202 }
203 
204 //
205 // QgsProperty
206 //
207 
208 QVariantMap QgsProperty::propertyMapToVariantMap( const QMap<QString, QgsProperty> &propertyMap )
209 {
210  QVariantMap variantMap;
211  QMap<QString, QgsProperty>::const_iterator it = propertyMap.constBegin();
212  for ( ; it != propertyMap.constEnd(); ++it )
213  variantMap.insert( it.key(), it.value().toVariant() );
214  return variantMap;
215 }
216 
217 QMap<QString, QgsProperty> QgsProperty::variantMapToPropertyMap( const QVariantMap &variantMap )
218 {
219  QMap<QString, QgsProperty> propertyMap;
220  QVariantMap::const_iterator it = variantMap.constBegin();
221  for ( ; it != variantMap.constEnd(); ++it )
222  {
223  QgsProperty property;
224  if ( property.loadVariant( it.value() ) )
225  propertyMap.insert( it.key(), property );
226  }
227  return propertyMap;
228 }
229 
231 {
232  d = new QgsPropertyPrivate();
233 }
234 
235 QgsProperty::~QgsProperty() = default;
236 
237 QgsProperty QgsProperty::fromExpression( const QString &expression, bool isActive )
238 {
239  QgsProperty p;
240  p.setExpressionString( expression );
241  p.setActive( isActive );
242  return p;
243 }
244 
245 QgsProperty QgsProperty::fromField( const QString &fieldName, bool isActive )
246 {
247  QgsProperty p;
248  p.setField( fieldName );
249  p.setActive( isActive );
250  return p;
251 }
252 
253 QgsProperty QgsProperty::fromValue( const QVariant &value, bool isActive )
254 {
255  QgsProperty p;
256  p.setStaticValue( value );
257  p.setActive( isActive );
258  return p;
259 }
260 
261 QgsProperty::QgsProperty( const QgsProperty &other ) //NOLINT
262  : d( other.d )
263 {}
264 
266 {
267  d = other.d;
268  return *this;
269 }
270 
271 bool QgsProperty::operator==( const QgsProperty &other ) const
272 {
273  return d->active == other.d->active
274  && d->type == other.d->type
275  && ( d->type != StaticProperty || d->staticValue == other.d->staticValue )
276  && ( d->type != FieldBasedProperty || d->fieldName == other.d->fieldName )
277  && ( d->type != ExpressionBasedProperty || d->expressionString == other.d->expressionString )
278  && ( ( !d->transformer && !other.d->transformer ) || ( d->transformer && other.d->transformer && d->transformer->toExpression( QString() ) == other.d->transformer->toExpression( QString() ) ) );
279 }
280 
281 bool QgsProperty::operator!=( const QgsProperty &other ) const
282 {
283  return ( !( ( *this ) == other ) );
284 }
285 
287 {
288  return static_cast< Type >( d->type );
289 }
290 
292 {
293  return d->type != InvalidProperty && d->active;
294 }
295 
296 bool QgsProperty::isStaticValueInContext( const QgsExpressionContext &context, QVariant &staticValue ) const
297 {
298  staticValue = QVariant();
299  switch ( d->type )
300  {
301  case InvalidProperty:
302  return true;
303 
304  case StaticProperty:
305  staticValue = d->staticValue;
306  return true;
307 
308  case FieldBasedProperty:
309  return false;
310 
312  {
313  QgsExpression exp = d->expression;
314  if ( exp.prepare( &context ) && exp.rootNode() )
315  {
316  if ( exp.rootNode()->hasCachedStaticValue() )
317  {
319  return true;
320  }
321  }
322  return false;
323  }
324  }
325  return false;
326 }
327 
328 void QgsProperty::setActive( bool active )
329 {
330  d.detach();
331  d->active = active;
332 }
333 
334 void QgsProperty::setStaticValue( const QVariant &value )
335 {
336  d.detach();
337  d->type = StaticProperty;
338  d->staticValue = value;
339 }
340 
341 QVariant QgsProperty::staticValue() const
342 {
343  if ( d->type != StaticProperty )
344  return QVariant();
345 
346  return d->staticValue;
347 }
348 
349 void QgsProperty::setField( const QString &field )
350 {
351  d.detach();
352  d->type = FieldBasedProperty;
353  d->fieldName = field;
354  d->cachedFieldIdx = -1;
355 }
356 
357 QString QgsProperty::field() const
358 {
359  if ( d->type != FieldBasedProperty )
360  return QString();
361 
362  return d->fieldName;
363 }
364 
365 QgsProperty::operator bool() const
366 {
367  return d->type != InvalidProperty;
368 }
369 
370 void QgsProperty::setExpressionString( const QString &expression )
371 {
372  d.detach();
373  d->expressionString = expression;
374  d->expression = QgsExpression( expression );
375  d->expressionPrepared = false;
376  d->expressionIsInvalid = false;
377 
378  if ( d->expressionString.isEmpty() )
379  {
380  d->active = false;
381  d->type = InvalidProperty;
382  }
383  else
384  {
385  d->type = ExpressionBasedProperty;
386  }
387 }
388 
390 {
391  if ( d->type != ExpressionBasedProperty )
392  return QString();
393 
394  return d->expressionString;
395 }
396 
397 
399 {
400  QString exp;
401  switch ( d->type )
402  {
403  case StaticProperty:
404  exp = QgsExpression::quotedValue( d->staticValue );
405  break;
406 
407  case FieldBasedProperty:
408  exp = QgsExpression::quotedColumnRef( d->fieldName );
409  break;
410 
412  exp = d->expressionString;
413  break;
414 
415  case InvalidProperty:
416  exp = QString();
417  break;
418  }
419  return d->transformer ? d->transformer->toExpression( exp ) : exp;
420 }
421 
422 bool QgsProperty::prepare( const QgsExpressionContext &context ) const
423 {
424  if ( !d->active )
425  return true;
426 
427  switch ( d->type )
428  {
429  case StaticProperty:
430  return true;
431 
432  case FieldBasedProperty:
433  {
434  d.detach();
435  // cache field index to avoid subsequent lookups
436  const QgsFields f = context.fields();
437  d->cachedFieldIdx = f.lookupField( d->fieldName );
438  return true;
439  }
440 
442  {
443  d.detach();
444  if ( !d->expression.prepare( &context ) )
445  {
446  d->expressionReferencedCols.clear();
447  d->expressionPrepared = false;
448  d->expressionIsInvalid = true;
449  return false;
450  }
451 
452  d->expressionPrepared = true;
453  d->expressionIsInvalid = false;
454  d->expressionReferencedCols = d->expression.referencedColumns();
455  return true;
456  }
457 
458  case InvalidProperty:
459  return true;
460 
461  }
462 
463  return false;
464 }
465 
466 QSet<QString> QgsProperty::referencedFields( const QgsExpressionContext &context, bool ignoreContext ) const
467 {
468  if ( !d->active )
469  return QSet<QString>();
470 
471  switch ( d->type )
472  {
473  case StaticProperty:
474  case InvalidProperty:
475  return QSet<QString>();
476 
477  case FieldBasedProperty:
478  {
479  QSet< QString > fields;
480  if ( !d->fieldName.isEmpty() )
481  fields.insert( d->fieldName );
482  return fields;
483  }
484 
486  {
487  if ( ignoreContext )
488  {
489  return d->expression.referencedColumns();
490  }
491 
492  if ( d->expressionIsInvalid )
493  return QSet< QString >();
494 
495  d.detach();
496  if ( !d->expressionPrepared && !prepare( context ) )
497  {
498  d->expressionIsInvalid = true;
499  return QSet< QString >();
500  }
501 
502  return d->expressionReferencedCols;
503  }
504 
505  }
506  return QSet<QString>();
507 }
508 
510 {
511  const QRegularExpression rx( QStringLiteral( "^project_color\\('.*'\\)$" ) );
512  return d->type == QgsProperty::ExpressionBasedProperty && !d->expressionString.isEmpty()
513  && rx.match( d->expressionString ).hasMatch();
514 }
515 
516 QVariant QgsProperty::propertyValue( const QgsExpressionContext &context, const QVariant &defaultValue, bool *ok ) const
517 {
518  if ( ok )
519  *ok = false;
520 
521  if ( !d->active )
522  return defaultValue;
523 
524  switch ( d->type )
525  {
526  case StaticProperty:
527  {
528  if ( ok )
529  *ok = true;
530  return d->staticValue;
531  }
532 
533  case FieldBasedProperty:
534  {
535  const QgsFeature f = context.feature();
536  if ( !f.isValid() )
537  return defaultValue;
538 
539  //shortcut the field lookup
540  if ( d->cachedFieldIdx >= 0 )
541  {
542  if ( ok )
543  *ok = true;
544  return f.attribute( d->cachedFieldIdx );
545  }
546  prepare( context );
547  if ( d->cachedFieldIdx < 0 )
548  return defaultValue;
549 
550  if ( ok )
551  *ok = true;
552  return f.attribute( d->cachedFieldIdx );
553  }
554 
556  {
557  if ( d->expressionIsInvalid )
558  return defaultValue;
559 
560  if ( !d->expressionPrepared && !prepare( context ) )
561  return defaultValue;
562 
563  QVariant result = d->expression.evaluate( &context );
564  if ( !result.isNull() )
565  {
566  if ( ok )
567  *ok = true;
568  return result;
569  }
570  else
571  {
572  return defaultValue;
573  }
574  }
575 
576  case InvalidProperty:
577  return defaultValue;
578 
579  }
580 
581  return QVariant();
582 }
583 
584 
585 QVariant QgsProperty::value( const QgsExpressionContext &context, const QVariant &defaultValue, bool *ok ) const
586 {
587  if ( ok )
588  *ok = false;
589 
590  bool valOk = false;
591  QVariant val = propertyValue( context, defaultValue, &valOk );
592  if ( !d->transformer && !valOk ) // if transformer present, let it handle null values
593  return defaultValue;
594 
595  if ( d->transformer )
596  {
597  if ( !valOk )
598  val = QVariant();
599  val = d->transformer->transform( context, val );
600  }
601 
602  if ( ok )
603  *ok = true;
604 
605  return val;
606 }
607 
608 QDateTime QgsProperty::valueAsDateTime( const QgsExpressionContext &context, const QDateTime &defaultDateTime, bool *ok ) const
609 {
610  bool valOk = false;
611  const QVariant val = value( context, defaultDateTime, &valOk );
612 
613  if ( !valOk || val.isNull() )
614  {
615  if ( ok )
616  *ok = false;
617  return defaultDateTime;
618  }
619 
620  QDateTime dateTime;
621  if ( val.type() == QVariant::DateTime )
622  {
623  dateTime = val.value<QDateTime>();
624  }
625  else
626  {
627  dateTime = val.toDateTime();
628  }
629 
630  if ( !dateTime.isValid() )
631  return defaultDateTime;
632  else
633  {
634  if ( ok )
635  *ok = true;
636  return dateTime;
637  }
638 }
639 
640 QString QgsProperty::valueAsString( const QgsExpressionContext &context, const QString &defaultString, bool *ok ) const
641 {
642  bool valOk = false;
643  const QVariant val = value( context, defaultString, &valOk );
644 
645  if ( !valOk || val.isNull() )
646  {
647  if ( ok )
648  *ok = false;
649  return defaultString;
650  }
651  else
652  {
653  if ( ok )
654  *ok = true;
655  return val.toString();
656  }
657 }
658 
659 QColor QgsProperty::valueAsColor( const QgsExpressionContext &context, const QColor &defaultColor, bool *ok ) const
660 {
661  if ( ok )
662  *ok = false;
663 
664  bool valOk = false;
665  const QVariant val = value( context, defaultColor, &valOk );
666 
667  if ( !valOk || val.isNull() )
668  return defaultColor;
669 
670  QColor color;
671  if ( val.type() == QVariant::Color )
672  {
673  color = val.value<QColor>();
674  }
675  else
676  {
677  color = QgsSymbolLayerUtils::decodeColor( val.toString() );
678  }
679 
680  if ( !color.isValid() )
681  return defaultColor;
682  else
683  {
684  if ( ok )
685  *ok = true;
686  return color;
687  }
688 }
689 
690 double QgsProperty::valueAsDouble( const QgsExpressionContext &context, double defaultValue, bool *ok ) const
691 {
692  if ( ok )
693  *ok = false;
694 
695  bool valOk = false;
696  const QVariant val = value( context, defaultValue, &valOk );
697 
698  if ( !valOk || val.isNull() )
699  return defaultValue;
700 
701  bool convertOk = false;
702  const double dbl = val.toDouble( &convertOk );
703  if ( !convertOk )
704  return defaultValue;
705  else
706  {
707  if ( ok )
708  *ok = true;
709  return dbl;
710  }
711 }
712 
713 int QgsProperty::valueAsInt( const QgsExpressionContext &context, int defaultValue, bool *ok ) const
714 {
715  if ( ok )
716  *ok = false;
717 
718  bool valOk = false;
719  const QVariant val = value( context, defaultValue, &valOk );
720 
721  if ( !valOk || val.isNull() )
722  return defaultValue;
723 
724  bool convertOk = false;
725  const int integer = val.toInt( &convertOk );
726  if ( !convertOk )
727  {
728  //one more option to try
729  const double dbl = val.toDouble( &convertOk );
730  if ( convertOk )
731  {
732  if ( ok )
733  *ok = true;
734  return std::round( dbl );
735  }
736  else
737  {
738  return defaultValue;
739  }
740  }
741  else
742  {
743  if ( ok )
744  *ok = true;
745  return integer;
746  }
747 }
748 
749 bool QgsProperty::valueAsBool( const QgsExpressionContext &context, bool defaultValue, bool *ok ) const
750 {
751  if ( ok )
752  *ok = false;
753 
754  bool valOk = false;
755  const QVariant val = value( context, defaultValue, &valOk );
756 
757  if ( !valOk || val.isNull() )
758  return defaultValue;
759 
760  if ( ok )
761  *ok = true;
762  return val.toBool();
763 }
764 
765 QVariant QgsProperty::toVariant() const
766 {
767  QVariantMap propertyMap;
768 
769  propertyMap.insert( QStringLiteral( "active" ), d->active );
770  propertyMap.insert( QStringLiteral( "type" ), d->type );
771 
772  switch ( d->type )
773  {
774  case StaticProperty:
775  // propertyMap.insert( QStringLiteral( "valType" ), d->staticValue.typeName() );
776  propertyMap.insert( QStringLiteral( "val" ), d->staticValue.toString() );
777  break;
778 
779  case FieldBasedProperty:
780  propertyMap.insert( QStringLiteral( "field" ), d->fieldName );
781  break;
782 
784  propertyMap.insert( QStringLiteral( "expression" ), d->expressionString );
785  break;
786 
787  case InvalidProperty:
788  break;
789  }
790 
791  if ( d->transformer )
792  {
793  QVariantMap transformer;
794  transformer.insert( QStringLiteral( "t" ), d->transformer->transformerType() );
795  transformer.insert( QStringLiteral( "d" ), d->transformer->toVariant() );
796 
797  propertyMap.insert( QStringLiteral( "transformer" ), transformer );
798  }
799 
800  return propertyMap;
801 }
802 
803 bool QgsProperty::loadVariant( const QVariant &property )
804 {
805  const QVariantMap propertyMap = property.toMap();
806 
807  d.detach();
808  d->active = propertyMap.value( QStringLiteral( "active" ) ).toBool();
809  d->type = static_cast< Type >( propertyMap.value( QStringLiteral( "type" ), InvalidProperty ).toInt() );
810 
811  switch ( d->type )
812  {
813  case StaticProperty:
814  d->staticValue = propertyMap.value( QStringLiteral( "val" ) );
815  // d->staticValue.convert( QVariant::nameToType( propertyElem.attribute( "valType", "QString" ).toLocal8Bit().constData() ) );
816  break;
817 
818  case FieldBasedProperty:
819  d->fieldName = propertyMap.value( QStringLiteral( "field" ) ).toString();
820  if ( d->fieldName.isEmpty() )
821  d->active = false;
822  break;
823 
825  d->expressionString = propertyMap.value( QStringLiteral( "expression" ) ).toString();
826  if ( d->expressionString.isEmpty() )
827  d->active = false;
828 
829  d->expression = QgsExpression( d->expressionString );
830  d->expressionPrepared = false;
831  d->expressionIsInvalid = false;
832  d->expressionReferencedCols.clear();
833  break;
834 
835  case InvalidProperty:
836  break;
837 
838  }
839 
840  //restore transformer if present
841  delete d->transformer;
842  d->transformer = nullptr;
843 
844 
845  const QVariant transform = propertyMap.value( QStringLiteral( "transformer" ) );
846 
847  if ( transform.isValid() )
848  {
849  const QVariantMap transformerMap = transform.toMap();
850 
851  const QgsPropertyTransformer::Type type = static_cast< QgsPropertyTransformer::Type >( transformerMap.value( QStringLiteral( "t" ), QgsPropertyTransformer::GenericNumericTransformer ).toInt() );
852  std::unique_ptr< QgsPropertyTransformer > transformer( QgsPropertyTransformer::create( type ) );
853 
854  if ( transformer )
855  {
856  if ( transformer->loadVariant( transformerMap.value( QStringLiteral( "d" ) ) ) )
857  d->transformer = transformer.release();
858  }
859  }
860 
861  return true;
862 }
863 
864 
866 {
867  d.detach();
868  d->transformer = transformer;
869 }
870 
872 {
873  return d->transformer;
874 }
875 
877 {
878  if ( d->type != ExpressionBasedProperty )
879  return false;
880 
881  if ( d->transformer )
882  return false; // already a transformer
883 
884  QString baseExpression;
885  QString fieldName;
886  std::unique_ptr< QgsPropertyTransformer > transformer( QgsPropertyTransformer::fromExpression( d->expressionString, baseExpression, fieldName ) );
887  if ( !transformer )
888  return false;
889 
890  d.detach();
891  d->transformer = transformer.release();
892  if ( !fieldName.isEmpty() )
893  setField( fieldName );
894  else
895  setExpressionString( baseExpression );
896  return true;
897 }
898 
899 
900 
QgsPropertyDefinition::RenderUnits
@ RenderUnits
Render units (eg mm/pixels/map units)
Definition: qgsproperty.h:63
QgsProperty::setTransformer
void setTransformer(QgsPropertyTransformer *transformer)
Sets an optional transformer to use for manipulating the calculated values for the property.
Definition: qgsproperty.cpp:865
QgsExpressionContext
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
Definition: qgsexpressioncontext.h:406
QgsProperty::isActive
bool isActive() const
Returns whether the property is currently active.
Definition: qgsproperty.cpp:291
QgsProperty::fromField
static QgsProperty fromField(const QString &fieldName, bool isActive=true)
Returns a new FieldBasedProperty created from the specified field name.
Definition: qgsproperty.cpp:245
QgsProperty::variantMapToPropertyMap
static QMap< QString, QgsProperty > variantMapToPropertyMap(const QVariantMap &variantMap)
Convert a map of QVariant to a map of QgsProperty This is useful to restore a map of properties.
Definition: qgsproperty.cpp:217
QgsPropertyDefinition::Offset
@ Offset
2D offset
Definition: qgsproperty.h:78
QgsProperty::operator==
bool operator==(const QgsProperty &other) const
Definition: qgsproperty.cpp:271
QgsPropertyDefinition::StandardPropertyTemplate
StandardPropertyTemplate
Predefined standard property templates.
Definition: qgsproperty.h:51
QgsProperty
A store for object properties.
Definition: qgsproperty.h:230
QgsPropertyDefinition::HorizontalAnchor
@ HorizontalAnchor
Horizontal anchor point.
Definition: qgsproperty.h:75
QgsPropertyDefinition::BlendMode
@ BlendMode
Blend mode.
Definition: qgsproperty.h:67
QgsPropertyTransformer
Abstract base class for objects which transform the calculated value of a property....
Definition: qgspropertytransformer.h:170
qgsexpression.h
QgsProperty::operator=
QgsProperty & operator=(const QgsProperty &other)
Definition: qgsproperty.cpp:265
QgsPropertyDefinition::DataTypeString
@ DataTypeString
Property requires a string value.
Definition: qgsproperty.h:92
QgsExpression::rootNode
const QgsExpressionNode * rootNode() const
Returns the root node of the expression.
Definition: qgsexpression.cpp:1355
QgsProperty::FieldBasedProperty
@ FieldBasedProperty
Field based property (QgsFieldBasedProperty)
Definition: qgsproperty.h:239
qgssymbollayerutils.h
QgsFields
Container of fields for a vector layer.
Definition: qgsfields.h:44
QgsProperty::Type
Type
Property types.
Definition: qgsproperty.h:235
qgsfeature.h
QgsProperty::asExpression
QString asExpression() const
Returns an expression string representing the state of the property, or an empty string if the proper...
Definition: qgsproperty.cpp:398
QgsPropertyDefinition::IntegerPositiveGreaterZero
@ IntegerPositiveGreaterZero
Non-zero positive integer values.
Definition: qgsproperty.h:56
QgsPropertyDefinition::DataTypeBoolean
@ DataTypeBoolean
Property requires a boolean value.
Definition: qgsproperty.h:106
QgsPropertyDefinition::FillStyle
@ FillStyle
Fill style (eg solid, lines)
Definition: qgsproperty.h:73
QgsPropertyDefinition::DataTypeNumeric
@ DataTypeNumeric
Property requires a numeric value.
Definition: qgsproperty.h:99
QgsPropertyDefinition::Double
@ Double
Double value (including negative values)
Definition: qgsproperty.h:57
QgsPropertyDefinition::PenJoinStyle
@ PenJoinStyle
Pen join style.
Definition: qgsproperty.h:66
QgsPropertyDefinition::Point
@ Point
2D point
Definition: qgsproperty.h:68
QgsProperty::isProjectColor
bool isProjectColor() const
Returns true if the property is set to a linked project color.
Definition: qgsproperty.cpp:509
QgsProperty::fromExpression
static QgsProperty fromExpression(const QString &expression, bool isActive=true)
Returns a new ExpressionBasedProperty created from the specified expression.
Definition: qgsproperty.cpp:237
field
const QgsField & field
Definition: qgsfield.h:463
QgsProperty::propertyType
Type propertyType() const
Returns the property type.
Definition: qgsproperty.cpp:286
QgsProperty::QgsProperty
QgsProperty()
Constructor for a QgsProperty.
Definition: qgsproperty.cpp:230
QgsProperty::valueAsColor
QColor valueAsColor(const QgsExpressionContext &context, const QColor &defaultColor=QColor(), bool *ok=nullptr) const
Calculates the current value of the property and interprets it as a color.
Definition: qgsproperty.cpp:659
QgsProperty::loadVariant
bool loadVariant(const QVariant &property)
Loads this property from a QVariantMap, wrapped in a QVariant.
Definition: qgsproperty.cpp:803
QgsPropertyDefinition::DateTime
@ DateTime
DateTime value.
Definition: qgsproperty.h:79
QgsProperty::transformer
const QgsPropertyTransformer * transformer() const
Returns the existing transformer used for manipulating the calculated values for the property,...
Definition: qgsproperty.cpp:871
QgsSymbolLayerUtils::decodeColor
static QColor decodeColor(const QString &str)
Definition: qgssymbollayerutils.cpp:69
QgsProperty::value
QVariant value(const QgsExpressionContext &context, const QVariant &defaultValue=QVariant(), bool *ok=nullptr) const
Calculates the current value of the property, including any transforms which are set for the property...
Definition: qgsproperty.cpp:585
QgsExpressionContext::fields
QgsFields fields() const
Convenience function for retrieving the fields for the context, if set.
Definition: qgsexpressioncontext.cpp:595
QgsProperty::referencedFields
QSet< QString > referencedFields(const QgsExpressionContext &context=QgsExpressionContext(), bool ignoreContext=false) const
Returns the set of any fields referenced by the property for a specified expression context.
Definition: qgsproperty.cpp:466
QgsProperty::setActive
void setActive(bool active)
Sets whether the property is currently active.
Definition: qgsproperty.cpp:328
QgsPropertyDefinition::String
@ String
Any string value.
Definition: qgsproperty.h:61
QgsProperty::expressionString
QString expressionString() const
Returns the expression used for the property value.
Definition: qgsproperty.cpp:389
QgsExpression::quotedValue
static QString quotedValue(const QVariant &value)
Returns a string representation of a literal value, including appropriate quotations where required.
Definition: qgsexpression.cpp:82
QgsPropertyDefinition::Rotation
@ Rotation
Rotation (value between 0-360 degrees)
Definition: qgsproperty.h:60
QgsProperty::fromValue
static QgsProperty fromValue(const QVariant &value, bool isActive=true)
Returns a new StaticProperty created from the specified value.
Definition: qgsproperty.cpp:253
QgsProperty::isStaticValueInContext
bool isStaticValueInContext(const QgsExpressionContext &context, QVariant &staticValue) const
Returns true if the property is effectively a static value in the specified context.
Definition: qgsproperty.cpp:296
QgsProperty::convertToTransformer
bool convertToTransformer()
Attempts to convert an existing expression based property to a base expression with corresponding tra...
Definition: qgsproperty.cpp:876
QgsProperty::ExpressionBasedProperty
@ ExpressionBasedProperty
Expression based property (QgsExpressionBasedProperty)
Definition: qgsproperty.h:240
QgsPropertyDefinition::DataType
DataType
Valid data types required by property.
Definition: qgsproperty.h:84
QgsProperty::propertyMapToVariantMap
static QVariantMap propertyMapToVariantMap(const QMap< QString, QgsProperty > &propertyMap)
Convert a map of QgsProperty to a map of QVariant This is useful to save a map of properties.
Definition: qgsproperty.cpp:208
QgsProperty::toVariant
QVariant toVariant() const
Saves this property to a QVariantMap, wrapped in a QVariant.
Definition: qgsproperty.cpp:765
QgsProperty::setField
void setField(const QString &field)
Sets the field name the property references.
Definition: qgsproperty.cpp:349
QgsFeature::isValid
bool isValid() const
Returns the validity of this feature.
Definition: qgsfeature.cpp:216
QgsPropertyDefinition::VerticalAnchor
@ VerticalAnchor
Vertical anchor point.
Definition: qgsproperty.h:76
qgscolorramp.h
QgsPropertyDefinition::ColorWithAlpha
@ ColorWithAlpha
Color with alpha channel.
Definition: qgsproperty.h:64
QgsPropertyDefinition::CapStyle
@ CapStyle
Line cap style (eg round)
Definition: qgsproperty.h:74
QgsProperty::setExpressionString
void setExpressionString(const QString &expression)
Sets the expression to use for the property value.
Definition: qgsproperty.cpp:370
QgsProperty::~QgsProperty
~QgsProperty()
QgsFeature::attribute
QVariant attribute(const QString &name) const
Lookup attribute value by attribute name.
Definition: qgsfeature.cpp:327
QgsProperty::valueAsString
QString valueAsString(const QgsExpressionContext &context, const QString &defaultString=QString(), bool *ok=nullptr) const
Calculates the current value of the property and interprets it as a string.
Definition: qgsproperty.cpp:640
QgsExpression::prepare
bool prepare(const QgsExpressionContext *context)
Gets the expression ready for evaluation - find out column indexes.
Definition: qgsexpression.cpp:327
QgsPropertyDefinition::Double0To1
@ Double0To1
Double value between 0-1 (inclusive)
Definition: qgsproperty.h:59
QgsProperty::valueAsBool
bool valueAsBool(const QgsExpressionContext &context, bool defaultValue=false, bool *ok=nullptr) const
Calculates the current value of the property and interprets it as an boolean.
Definition: qgsproperty.cpp:749
QgsPropertyDefinition::IntegerPositive
@ IntegerPositive
Positive integer values (including 0)
Definition: qgsproperty.h:55
QgsPropertyDefinition::Size
@ Size
1D size (eg marker radius, or square marker height/width)
Definition: qgsproperty.h:69
qgsproperty_p.h
QgsProperty::operator!=
bool operator!=(const QgsProperty &other) const
Definition: qgsproperty.cpp:281
qgsexpressionnodeimpl.h
QgsPropertyTransformer::GenericNumericTransformer
@ GenericNumericTransformer
Generic transformer for numeric values (QgsGenericNumericTransformer)
Definition: qgspropertytransformer.h:191
QgsPropertyDefinition::Boolean
@ Boolean
Boolean value.
Definition: qgsproperty.h:53
QgsPropertyDefinition::LineStyle
@ LineStyle
Line style (eg solid/dashed)
Definition: qgsproperty.h:71
QgsPropertyDefinition::Size2D
@ Size2D
2D size (width/height different)
Definition: qgsproperty.h:70
QgsExpressionContext::feature
QgsFeature feature() const
Convenience function for retrieving the feature for the context, if set.
Definition: qgsexpressioncontext.cpp:543
QgsProperty::field
QString field() const
Returns the current field name the property references.
Definition: qgsproperty.cpp:357
QgsPropertyDefinition::Integer
@ Integer
Integer value (including negative values)
Definition: qgsproperty.h:54
QgsPropertyTransformer::fromExpression
static QgsPropertyTransformer * fromExpression(const QString &expression, QString &baseExpression, QString &fieldName)
Attempts to parse an expression into a corresponding property transformer.
Definition: qgspropertytransformer.cpp:102
qgsproperty.h
QgsProperty::setStaticValue
void setStaticValue(const QVariant &value)
Sets the static value for the property.
Definition: qgsproperty.cpp:334
QgsPropertyTransformer::Type
Type
Transformer types.
Definition: qgspropertytransformer.h:189
QgsExpression::quotedColumnRef
static QString quotedColumnRef(QString name)
Returns a quoted column reference (in double quotes)
Definition: qgsexpression.cpp:68
QgsProperty::valueAsDouble
double valueAsDouble(const QgsExpressionContext &context, double defaultValue=0.0, bool *ok=nullptr) const
Calculates the current value of the property and interprets it as a double.
Definition: qgsproperty.cpp:690
QgsPropertyTransformer::loadVariant
virtual bool loadVariant(const QVariant &transformer)
Loads this transformer from a QVariantMap, wrapped in a QVariant.
Definition: qgspropertytransformer.cpp:69
QgsPropertyTransformer::create
static QgsPropertyTransformer * create(Type type)
Factory method for creating a new property transformer of the specified type.
Definition: qgspropertytransformer.cpp:30
QgsProperty::valueAsDateTime
QDateTime valueAsDateTime(const QgsExpressionContext &context, const QDateTime &defaultDateTime=QDateTime(), bool *ok=nullptr) const
Calculates the current value of the property and interprets it as a datetime.
Definition: qgsproperty.cpp:608
QgsExpressionNode::hasCachedStaticValue
bool hasCachedStaticValue() const
Returns true if the node can be replaced by a static cached value.
Definition: qgsexpressionnode.h:326
QgsPropertyDefinition::supportsAssistant
bool supportsAssistant() const
Returns true if the property is of a type which is compatible with property override assistants.
Definition: qgsproperty.cpp:192
QgsPropertyDefinition::SvgPath
@ SvgPath
Path to an SVG file.
Definition: qgsproperty.h:77
QgsFeature
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition: qgsfeature.h:55
QgsProperty::staticValue
QVariant staticValue() const
Returns the current static value for the property.
Definition: qgsproperty.cpp:341
QgsProperty::prepare
bool prepare(const QgsExpressionContext &context=QgsExpressionContext()) const
Prepares the property against a specified expression context.
Definition: qgsproperty.cpp:422
QgsPropertyDefinition::Opacity
@ Opacity
Opacity (0-100)
Definition: qgsproperty.h:62
qgslogger.h
QgsPropertyDefinition::QgsPropertyDefinition
QgsPropertyDefinition()=default
Constructs an empty property.
QgsFields::lookupField
int lookupField(const QString &fieldName) const
Looks up field's index from the field name.
Definition: qgsfields.cpp:349
QgsExpression
Class for parsing and evaluation of expressions (formerly called "search strings")....
Definition: qgsexpression.h:102
QgsProperty::StaticProperty
@ StaticProperty
Static property (QgsStaticProperty)
Definition: qgsproperty.h:238
QgsProperty::valueAsInt
int valueAsInt(const QgsExpressionContext &context, int defaultValue=0, bool *ok=nullptr) const
Calculates the current value of the property and interprets it as an integer.
Definition: qgsproperty.cpp:713
QgsPropertyDefinition::StrokeWidth
@ StrokeWidth
Line stroke width.
Definition: qgsproperty.h:72
QgsPropertyDefinition::ColorNoAlpha
@ ColorNoAlpha
Color with no alpha channel.
Definition: qgsproperty.h:65
QgsProperty::InvalidProperty
@ InvalidProperty
Invalid (not set) property.
Definition: qgsproperty.h:237
QgsPropertyDefinition::Custom
@ Custom
Custom property types.
Definition: qgsproperty.h:80
QgsPropertyDefinition::DoublePositive
@ DoublePositive
Positive double value (including 0)
Definition: qgsproperty.h:58
QgsExpressionNode::cachedStaticValue
QVariant cachedStaticValue() const
Returns the node's static cached value.
Definition: qgsexpressionnode.h:334