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