QGIS API Documentation  3.21.0-Master (5b68dc587e)
qgspropertycollection.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgspropertycollection.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 "qgspropertycollection.h"
17 #include "qgsproperty.h"
18 #include "qgsxmlutils.h"
19 
20 //
21 // QgsAbstractPropertyCollection
22 //
23 
25  : mName( name )
26 {
27 
28 }
29 
30 QDateTime QgsAbstractPropertyCollection::valueAsDateTime( int key, const QgsExpressionContext &context, const QDateTime &defaultDateTime, bool *ok ) const
31 {
32  if ( ok )
33  *ok = false;
34 
35  QgsProperty prop = property( key );
36  if ( !prop || !prop.isActive() )
37  return defaultDateTime;
38 
39  return prop.valueAsDateTime( context, defaultDateTime, ok );
40 }
41 
42 QString QgsAbstractPropertyCollection::valueAsString( int key, const QgsExpressionContext &context, const QString &defaultString, bool *ok ) const
43 {
44  if ( ok )
45  *ok = false;
46 
47  QgsProperty prop = property( key );
48  if ( !prop || !prop.isActive() )
49  return defaultString;
50 
51  return prop.valueAsString( context, defaultString, ok );
52 }
53 
54 QColor QgsAbstractPropertyCollection::valueAsColor( int key, const QgsExpressionContext &context, const QColor &defaultColor, bool *ok ) const
55 {
56  if ( ok )
57  *ok = false;
58 
59  QgsProperty prop = property( key );
60  if ( !prop || !prop.isActive() )
61  return defaultColor;
62 
63  return prop.valueAsColor( context, defaultColor, ok );
64 }
65 
66 double QgsAbstractPropertyCollection::valueAsDouble( int key, const QgsExpressionContext &context, double defaultValue, bool *ok ) const
67 {
68  if ( ok )
69  *ok = false;
70  QgsProperty prop = property( key );
71  if ( !prop || !prop.isActive() )
72  return defaultValue;
73 
74  return prop.valueAsDouble( context, defaultValue, ok );
75 }
76 
77 int QgsAbstractPropertyCollection::valueAsInt( int key, const QgsExpressionContext &context, int defaultValue, bool *ok ) const
78 {
79  if ( ok )
80  *ok = false;
81  QgsProperty prop = property( key );
82  if ( !prop || !prop.isActive() )
83  return defaultValue;
84 
85  return prop.valueAsInt( context, defaultValue, ok );
86 }
87 
88 bool QgsAbstractPropertyCollection::valueAsBool( int key, const QgsExpressionContext &context, bool defaultValue, bool *ok ) const
89 {
90  if ( ok )
91  *ok = false;
92  QgsProperty prop = property( key );
93  if ( !prop || !prop.isActive() )
94  return defaultValue;
95 
96  return prop.valueAsBool( context, defaultValue, ok );
97 }
98 
99 bool QgsAbstractPropertyCollection::writeXml( QDomElement &collectionElem, const QgsPropertiesDefinition &definitions ) const
100 {
101  QVariant collection = toVariant( definitions );
102  QDomDocument doc = collectionElem.ownerDocument();
103  QDomElement element = QgsXmlUtils::writeVariant( collection, doc );
104  collectionElem.appendChild( element );
105  return true;
106 }
107 
108 bool QgsAbstractPropertyCollection::readXml( const QDomElement &collectionElem, const QgsPropertiesDefinition &definitions )
109 {
110  QVariant collection = QgsXmlUtils::readVariant( collectionElem.firstChild().toElement() );
111  return loadVariant( collection.toMap(), definitions );
112 }
113 
114 
115 
116 //
117 // QgsPropertyCollection
118 //
119 
122 {}
123 
126  , mProperties( other.mProperties )
127  , mDirty( other.mDirty )
128  , mHasActiveProperties( other.mHasActiveProperties )
129  , mHasDynamicProperties( other.mHasDynamicProperties )
130  , mCount( other.mCount )
131 {
132  mProperties.detach();
133 }
134 
136 {
137  QgsAbstractPropertyCollection::operator=( other );
138  mProperties = other.mProperties;
139  mProperties.detach();
140  mDirty = other.mDirty;
141  mHasActiveProperties = other.mHasActiveProperties;
142  mHasDynamicProperties = other.mHasDynamicProperties;
143  mCount = other.mCount;
144  return *this;
145 }
146 
148 {
149  return mProperties == other.mProperties;
150 }
151 
153 {
154  return !( *this == other );
155 }
156 
158 {
159  if ( !mDirty )
160  return mCount;
161 
162  rescan();
163  return mCount;
164 }
165 
167 {
168  QSet<int> keys;
169  QHash<int, QgsProperty>::const_iterator it = mProperties.constBegin();
170  for ( ; it != mProperties.constEnd(); ++it )
171  {
172  if ( it.value() )
173  keys.insert( it.key() );
174  }
175  return keys;
176 }
177 
179 {
180  mProperties.clear();
181  mDirty = false;
182  mHasActiveProperties = false;
183  mHasDynamicProperties = false;
184  mCount = 0;
185 }
186 
187 void QgsPropertyCollection::setProperty( int key, const QgsProperty &property )
188 {
189  if ( property )
190  mProperties.insert( key, property );
191  else
192  mProperties.remove( key );
193 
194  mDirty = true;
195 }
196 
197 void QgsPropertyCollection::setProperty( int key, const QVariant &value )
198 {
199  mProperties.insert( key, QgsProperty::fromValue( value ) );
200  mDirty = true;
201 }
202 
204 {
205  if ( mProperties.isEmpty() )
206  return false;
207 
208  auto it = mProperties.constFind( key );
209  if ( it != mProperties.constEnd() )
210  return ( *it );
211  return false;
212 }
213 
215 {
216  if ( mProperties.isEmpty() )
217  return QgsProperty();
218 
219  return mProperties.value( key );
220 }
221 
223 {
224  mDirty = true;
225  return mProperties[ key ];
226 }
227 
228 QVariant QgsPropertyCollection::value( int key, const QgsExpressionContext &context, const QVariant &defaultValue ) const
229 {
230  if ( mProperties.isEmpty() )
231  return defaultValue;
232 
233  QgsProperty prop = mProperties.value( key );
234  if ( !prop || !prop.isActive() )
235  return defaultValue;
236 
237  return prop.value( context, defaultValue );
238 }
239 
241 {
242  bool result = true;
243  QHash<int, QgsProperty>::const_iterator it = mProperties.constBegin();
244  for ( ; it != mProperties.constEnd(); ++it )
245  {
246  if ( !it.value().isActive() )
247  continue;
248 
249  result = result && it.value().prepare( context );
250  }
251  return result;
252 }
253 
254 QSet< QString > QgsPropertyCollection::referencedFields( const QgsExpressionContext &context, bool ignoreContext ) const
255 {
256  QSet< QString > cols;
257  QHash<int, QgsProperty>::const_iterator it = mProperties.constBegin();
258  for ( ; it != mProperties.constEnd(); ++it )
259  {
260  if ( !it.value().isActive() )
261  continue;
262 
263  cols.unite( it.value().referencedFields( context, ignoreContext ) );
264  }
265  return cols;
266 }
267 
268 bool QgsPropertyCollection::isActive( int key ) const
269 {
270  if ( mProperties.isEmpty() )
271  return false;
272 
273  auto it = mProperties.constFind( key );
274  if ( it != mProperties.constEnd() )
275  return ( *it ).isActive();
276  return false;
277 }
278 
279 void QgsPropertyCollection::rescan() const
280 {
281  mHasActiveProperties = false;
282  mHasDynamicProperties = false;
283  mCount = 0;
284  if ( !mProperties.isEmpty() )
285  {
286  QHash<int, QgsProperty>::const_iterator it = mProperties.constBegin();
287  for ( ; it != mProperties.constEnd(); ++it )
288  {
289  if ( it.value() )
290  mCount++;
291  if ( it.value().isActive() )
292  {
293  mHasActiveProperties = true;
294  if ( it.value().propertyType() != QgsProperty::StaticProperty )
295  {
296  mHasDynamicProperties = true;
297  }
298  }
299  }
300  }
301  mDirty = false;
302 }
303 
305 {
306  if ( mDirty )
307  rescan();
308 
309  return mHasActiveProperties;
310 }
311 
313 {
314  if ( mDirty )
315  rescan();
316 
317  return mHasDynamicProperties;
318 }
319 
320 QVariant QgsPropertyCollection::toVariant( const QgsPropertiesDefinition &definitions ) const
321 {
322  QVariantMap collection;
323 
324  collection.insert( QStringLiteral( "name" ), name() );
325  collection.insert( QStringLiteral( "type" ), QStringLiteral( "collection" ) );
326 
327  QVariantMap properties;
328 
329  QHash<int, QgsProperty>::const_iterator it = mProperties.constBegin();
330  for ( ; it != mProperties.constEnd(); ++it )
331  {
332  if ( it.value() )
333  {
334  properties.insert( definitions.value( it.key() ).name(), it.value().toVariant() );
335  }
336  }
337  collection.insert( QStringLiteral( "properties" ), properties );
338  return collection;
339 }
340 
341 bool QgsPropertyCollection::loadVariant( const QVariant &collection, const QgsPropertiesDefinition &definitions )
342 {
343  clear();
344 
345  QVariantMap collectionMap = collection.toMap();
346 
347  setName( collectionMap.value( QStringLiteral( "name" ) ).toString() );
348 
349  mCount = 0;
350  QVariantMap properties = collectionMap.value( QStringLiteral( "properties" ) ).toMap();
351  for ( auto propertyIterator = properties.constBegin(); propertyIterator != properties.constEnd(); ++propertyIterator )
352  {
353  // match name to int key
354  int key = -1;
355  QgsPropertiesDefinition::const_iterator it = definitions.constBegin();
356  for ( ; it != definitions.constEnd(); ++it )
357  {
358  if ( it->name() == propertyIterator.key() )
359  {
360  key = it.key();
361  break;
362  }
363  }
364 
365  if ( key < 0 )
366  continue;
367 
368  QgsProperty prop;
369  prop.loadVariant( propertyIterator.value() );
370  mProperties.insert( key, prop );
371 
372  mCount++;
373 
374  mHasActiveProperties = mHasActiveProperties || prop.isActive();
375  mHasDynamicProperties = mHasDynamicProperties ||
376  ( prop.isActive() &&
379  }
380  return true;
381 }
382 
383 //
384 // QgsPropertyCollectionStack
385 //
386 
388 {
389  clear();
390 }
391 
393  : QgsAbstractPropertyCollection( other ), mStack()
394 {
395  clear();
396 
397  for ( QgsPropertyCollection *collection : std::as_const( other.mStack ) )
398  {
399  mStack << new QgsPropertyCollection( *collection );
400  }
401 }
402 
404 {
405  setName( other.name() );
406  clear();
407 
408  for ( QgsPropertyCollection *collection : std::as_const( other.mStack ) )
409  {
410  mStack << new QgsPropertyCollection( *collection );
411  }
412 
413  return *this;
414 }
415 
417 {
418  return mStack.size();
419 }
420 
422 {
423  qDeleteAll( mStack );
424  mStack.clear();
425 }
426 
428 {
429  mStack.append( collection );
430 }
431 
433 {
434  return mStack.value( index );
435 }
436 
438 {
439  return mStack.value( index );
440 }
441 
443 {
444  const auto constMStack = mStack;
445  for ( QgsPropertyCollection *collection : constMStack )
446  {
447  if ( collection->name() == name )
448  return collection;
449  }
450  return nullptr;
451 }
452 
454 {
455  const auto constMStack = mStack;
456  for ( const QgsPropertyCollection *collection : constMStack )
457  {
459  return true;
460  }
461  return false;
462 }
463 
465 {
466  const auto constMStack = mStack;
467  for ( const QgsPropertyCollection *collection : constMStack )
468  {
470  return true;
471  }
472  return false;
473 }
474 
476 {
477  return static_cast< bool >( property( key ) );
478 }
479 
481 {
482  //loop through stack looking for last active matching property
483  for ( int i = mStack.size() - 1; i >= 0; --i )
484  {
485  const QgsPropertyCollection *collection = mStack.at( i );
486  QgsProperty property = collection->property( key );
487  if ( property && property.isActive() )
488  {
489  return property;
490  }
491  }
492  //not found
493  return QgsProperty();
494 }
495 
496 
497 QVariant QgsPropertyCollectionStack::value( int key, const QgsExpressionContext &context, const QVariant &defaultValue ) const
498 {
499  QgsProperty p = property( key );
500  if ( !p )
501  {
502  return defaultValue;
503  }
504  return p.value( context, defaultValue );
505 }
506 
507 QSet< QString > QgsPropertyCollectionStack::referencedFields( const QgsExpressionContext &context, bool ignoreContext ) const
508 {
509  QSet< QString > cols;
510  const auto constMStack = mStack;
511  for ( QgsPropertyCollection *collection : constMStack )
512  {
513  cols.unite( collection->referencedFields( context, ignoreContext ) );
514  }
515  return cols;
516 }
517 
519 {
520  bool result = true;
521  const auto constMStack = mStack;
522  for ( QgsPropertyCollection *collection : constMStack )
523  {
524  result = result && collection->prepare( context );
525  }
526  return result;
527 }
528 
530 {
531  QSet<int> keys;
532  const auto constMStack = mStack;
533  for ( QgsPropertyCollection *collection : constMStack )
534  {
535  keys.unite( collection->propertyKeys() );
536  }
537  return keys;
538 }
539 
541 {
542  const auto constMStack = mStack;
543  for ( QgsPropertyCollection *collection : constMStack )
544  {
545  if ( collection->hasProperty( key ) )
546  return true;
547  }
548  return false;
549 }
550 
552 {
553  QVariantMap collection;
554  collection.insert( QStringLiteral( "type" ), QStringLiteral( "stack" ) );
555  collection.insert( QStringLiteral( "name" ), name() );
556 
557  QVariantList properties;
558 
559  const auto constMStack = mStack;
560  for ( QgsPropertyCollection *child : constMStack )
561  {
562  properties.append( child->toVariant( definitions ) );
563  }
564 
565  collection.insert( QStringLiteral( "properties" ), properties );
566 
567  return collection;
568 }
569 
570 bool QgsPropertyCollectionStack::loadVariant( const QVariant &collection, const QgsPropertiesDefinition &definitions )
571 {
572  clear();
573 
574  QVariantMap collectionMap = collection.toMap();
575 
576  setName( collectionMap.value( QStringLiteral( "name" ) ).toString() );
577 
578  QVariantList properties = collectionMap.value( QStringLiteral( "properties" ) ).toList();
579 
580  const auto constProperties = properties;
581  for ( const QVariant &property : constProperties )
582  {
583  QgsPropertyCollection *propertyCollection = new QgsPropertyCollection();
584  propertyCollection->loadVariant( property.toMap(), definitions );
585  mStack.append( propertyCollection );
586  }
587 
588  return true;
589 }
Abstract base class for QgsPropertyCollection like objects.
void setName(const QString &name)
Sets the descriptive name for the property collection.
QColor valueAsColor(int key, const QgsExpressionContext &context, const QColor &defaultColor=QColor(), bool *ok=nullptr) const
Calculates the current value of the property with the specified key and interprets it as a color.
QDateTime valueAsDateTime(int key, const QgsExpressionContext &context, const QDateTime &defaultDateTime=QDateTime(), bool *ok=nullptr) const
Calculates the current value of the property with the specified key and interprets it as a datetime.
int valueAsInt(int key, const QgsExpressionContext &context, int defaultValue=0, bool *ok=nullptr) const
Calculates the current value of the property with the specified key and interprets it as an integer.
virtual QgsProperty property(int key) const =0
Returns a matching property from the collection, if one exists.
bool valueAsBool(int key, const QgsExpressionContext &context, bool defaultValue=false, bool *ok=nullptr) const
Calculates the current value of the property with the specified key and interprets it as an boolean.
double valueAsDouble(int key, const QgsExpressionContext &context, double defaultValue=0.0, bool *ok=nullptr) const
Calculates the current value of the property with the specified key and interprets it as a double.
QgsAbstractPropertyCollection(const QString &name=QString())
Constructor for QgsAbstractPropertyCollection.
virtual bool loadVariant(const QVariant &configuration, const QgsPropertiesDefinition &definitions)=0
Loads this property collection from a QVariantMap, wrapped in a QVariant.
QString name() const
Returns the descriptive name of the property collection.
virtual bool readXml(const QDomElement &collectionElem, const QgsPropertiesDefinition &definitions)
Reads property collection state from an XML element.
QString valueAsString(int key, const QgsExpressionContext &context, const QString &defaultString=QString(), bool *ok=nullptr) const
Calculates the current value of the property with the specified key and interprets it as a string.
virtual bool writeXml(QDomElement &collectionElem, const QgsPropertiesDefinition &definitions) const
Writes the current state of the property collection into an XML element.
virtual QVariant toVariant(const QgsPropertiesDefinition &definitions) const =0
Saves this property collection to a QVariantMap, wrapped in a QVariant.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
An ordered stack of QgsPropertyCollection containers, where collections added later to the stack will...
QgsPropertyCollectionStack & operator=(const QgsPropertyCollectionStack &other)
int count() const
Returns the number of collections contained within the stack.
QVariant value(int key, const QgsExpressionContext &context, const QVariant &defaultValue=QVariant()) const override
Returns the calculated value of the highest priority property with the specified key from within the ...
QgsPropertyCollectionStack()=default
Constructor for QgsPropertyCollectionStack.
bool hasProperty(int key) const override
Returns true if the collection contains a property with the specified key.
void appendCollection(QgsPropertyCollection *collection)
Appends a collection to the end of the stack, and transfers ownership of the collection to the stack.
QgsPropertyCollection * at(int index)
Returns the collection at the corresponding index from the stack.
bool prepare(const QgsExpressionContext &context=QgsExpressionContext()) const override
Prepares the collection against a specified expression context.
bool hasActiveProperties() const override
Returns true if the collection has any active properties, or false if all properties within the colle...
QSet< int > propertyKeys() const override
Returns a list of property keys contained within the collection.
QSet< QString > referencedFields(const QgsExpressionContext &context=QgsExpressionContext(), bool ignoreContext=false) const override
Returns the set of any fields referenced by the active properties from the stack.
bool loadVariant(const QVariant &collection, const QgsPropertiesDefinition &definitions) override
Loads this property collection from a QVariantMap, wrapped in a QVariant.
QgsProperty property(int key) const override
Returns the highest priority property with a matching key from within the stack.
void clear() override
Removes all collections from the stack.
bool isActive(int key) const override
Returns true if the stack contains an active property with the specified key.
QgsPropertyCollection * collection(const QString &name)
Returns the first collection with a matching name from the stack.
bool hasDynamicProperties() const override
Returns true if the collection has any active, non-static properties, or false if either all non-stat...
QVariant toVariant(const QgsPropertiesDefinition &definitions) const override
Saves this property collection to a QVariantMap, wrapped in a QVariant.
A grouped map of multiple QgsProperty objects, each referenced by a integer key value.
bool hasProperty(int key) const override
Returns true if the collection contains a property with the specified key.
QgsProperty property(int key) const override
Returns a matching property from the collection, if one exists.
QgsPropertyCollection & operator=(const QgsPropertyCollection &other)
QVariant value(int key, const QgsExpressionContext &context, const QVariant &defaultValue=QVariant()) const override
Returns the calculated value of the property with the specified key from within the collection.
void setProperty(int key, const QgsProperty &property)
Adds a property to the collection and takes ownership of it.
bool loadVariant(const QVariant &configuration, const QgsPropertiesDefinition &definitions) override
Loads this property collection from a QVariantMap, wrapped in a QVariant.
QSet< QString > referencedFields(const QgsExpressionContext &context=QgsExpressionContext(), bool ignoreContext=false) const override
Returns the set of any fields referenced by the active properties from the collection.
bool operator!=(const QgsPropertyCollection &other) const
bool operator==(const QgsPropertyCollection &other) const
QVariant toVariant(const QgsPropertiesDefinition &definitions) const override
Saves this property collection to a QVariantMap, wrapped in a QVariant.
bool hasDynamicProperties() const override
Returns true if the collection has any active, non-static properties, or false if either all non-stat...
int count() const
Returns the number of properties contained within the collection.
void clear() override
Removes all properties from the collection.
QSet< int > propertyKeys() const override
Returns a list of property keys contained within the collection.
bool isActive(int key) const override
Returns true if the collection contains an active property with the specified key.
bool hasActiveProperties() const override
Returns true if the collection has any active properties, or false if all properties within the colle...
bool prepare(const QgsExpressionContext &context=QgsExpressionContext()) const override
Prepares the collection against a specified expression context.
QgsPropertyCollection(const QString &name=QString())
Constructor for QgsPropertyCollection.
A store for object properties.
Definition: qgsproperty.h:232
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.
@ ExpressionBasedProperty
Expression based property (QgsExpressionBasedProperty)
Definition: qgsproperty.h:241
@ StaticProperty
Static property (QgsStaticProperty)
Definition: qgsproperty.h:239
@ FieldBasedProperty
Field based property (QgsFieldBasedProperty)
Definition: qgsproperty.h:240
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.
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.
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...
bool isActive() const
Returns whether the property is currently active.
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.
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.
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.
bool loadVariant(const QVariant &property)
Loads this property from a QVariantMap, wrapped in a QVariant.
Type propertyType() const
Returns the property type.
static QgsProperty fromValue(const QVariant &value, bool isActive=true)
Returns a new StaticProperty created from the specified value.
static QDomElement writeVariant(const QVariant &value, QDomDocument &doc)
Write a QVariant to a QDomElement.
static QVariant readVariant(const QDomElement &element)
Read a QVariant from a QDomElement.
QMap< int, QgsPropertyDefinition > QgsPropertiesDefinition
Definition of available properties.