QGIS API Documentation  3.4.15-Madeira (e83d02e274)
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  Q_FOREACH ( QgsPropertyCollection *collection, other.mStack )
376  {
377  mStack << new QgsPropertyCollection( *collection );
378  }
379 }
380 
382 {
383  setName( other.name() );
384  clear();
385 
386  Q_FOREACH ( QgsPropertyCollection *collection, 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  Q_FOREACH ( QgsPropertyCollection *collection, mStack )
423  {
424  if ( collection->name() == name )
425  return collection;
426  }
427  return nullptr;
428 }
429 
431 {
432  Q_FOREACH ( const QgsPropertyCollection *collection, mStack )
433  {
434  if ( collection->hasActiveProperties() )
435  return true;
436  }
437  return false;
438 }
439 
441 {
442  Q_FOREACH ( const QgsPropertyCollection *collection, mStack )
443  {
444  if ( collection->hasDynamicProperties() )
445  return true;
446  }
447  return false;
448 }
449 
451 {
452  return static_cast< bool >( property( key ) );
453 }
454 
456 {
457  //loop through stack looking for last active matching property
458  for ( int i = mStack.size() - 1; i >= 0; --i )
459  {
460  const QgsPropertyCollection *collection = mStack.at( i );
461  QgsProperty property = collection->property( key );
462  if ( property && property.isActive() )
463  {
464  return property;
465  }
466  }
467  //not found
468  return QgsProperty();
469 }
470 
471 
472 QVariant QgsPropertyCollectionStack::value( int key, const QgsExpressionContext &context, const QVariant &defaultValue ) const
473 {
474  QgsProperty p = property( key );
475  if ( !p )
476  {
477  return defaultValue;
478  }
479  return p.value( context, defaultValue );
480 }
481 
483 {
484  QSet< QString > cols;
485  Q_FOREACH ( QgsPropertyCollection *collection, mStack )
486  {
487  cols.unite( collection->referencedFields( context ) );
488  }
489  return cols;
490 }
491 
493 {
494  bool result = true;
495  Q_FOREACH ( QgsPropertyCollection *collection, mStack )
496  {
497  result = result && collection->prepare( context );
498  }
499  return result;
500 }
501 
503 {
504  QSet<int> keys;
505  Q_FOREACH ( QgsPropertyCollection *collection, mStack )
506  {
507  keys.unite( collection->propertyKeys() );
508  }
509  return keys;
510 }
511 
513 {
514  Q_FOREACH ( QgsPropertyCollection *collection, mStack )
515  {
516  if ( collection->hasProperty( key ) )
517  return true;
518  }
519  return false;
520 }
521 
523 {
524  QVariantMap collection;
525  collection.insert( QStringLiteral( "type" ), QStringLiteral( "stack" ) );
526  collection.insert( QStringLiteral( "name" ), name() );
527 
528  QVariantList properties;
529 
530  Q_FOREACH ( QgsPropertyCollection *child, mStack )
531  {
532  properties.append( child->toVariant( definitions ) );
533  }
534 
535  collection.insert( QStringLiteral( "properties" ), properties );
536 
537  return collection;
538 }
539 
541 {
542  clear();
543 
544  QVariantMap collectionMap = collection.toMap();
545 
546  setName( collectionMap.value( QStringLiteral( "name" ) ).toString() );
547 
548  QVariantList properties = collectionMap.value( QStringLiteral( "properties" ) ).toList();
549 
550  Q_FOREACH ( const QVariant &property, properties )
551  {
552  QgsPropertyCollection *propertyCollection = new QgsPropertyCollection();
553  propertyCollection->loadVariant( property.toMap(), definitions );
554  mStack.append( propertyCollection );
555  }
556 
557  return true;
558 }
void setProperty(int key, const QgsProperty &property)
Adds a property to the collection and takes ownership of it.
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...
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.
virtual bool writeXml(QDomElement &collectionElem, const QgsPropertiesDefinition &definitions) const
Writes the current state of the property collection into an XML element.
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
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...
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(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 isActive() const
Returns whether the property is currently active.
bool hasProperty(int key) const override
Returns true if the collection contains a property with the specified key.
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.
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...
QgsPropertyCollectionStack()=default
Constructor for QgsPropertyCollectionStack.
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.
int count() const
Returns the number of collections contained within the stack.
bool prepare(const QgsExpressionContext &context=QgsExpressionContext()) const override
Prepares the collection against a specified expression context.
QString name() const
Returns the descriptive name of the property collection.
static QVariant readVariant(const QDomElement &element)
Read a QVariant from a QDomElement.
static QgsProperty fromValue(const QVariant &value, bool isActive=true)
Returns a new StaticProperty created from the specified value.
bool loadVariant(const QVariant &property)
Loads this property from a QVariantMap, wrapped in a QVariant.
QgsPropertyCollection & operator=(const QgsPropertyCollection &other)
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
Type propertyType() const
Returns the property type.
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.
virtual QgsProperty property(int key) const =0
Returns a matching property from the collection, if one exists.
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.
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
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 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. ...
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...
QMap< int, QgsPropertyDefinition > QgsPropertiesDefinition
Definition of available properties.
QSet< int > propertyKeys() const override
Returns a list of property keys contained within the collection.
int count() const
Returns the number of properties contained within the collection.
QSet< QString > referencedFields(const QgsExpressionContext &context=QgsExpressionContext()) const override
Returns the set of any fields referenced by the active properties from the collection.
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...
void clear() override
Removes all collections from the stack.
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...
QVariant toVariant(const QgsPropertiesDefinition &definitions) const override
Saves this property collection to a QVariantMap, wrapped in a QVariant.
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.
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.
QgsProperty property(int key) const override
Returns the highest priority property with a matching key from within the stack.
Invalid (not set) property.
Definition: qgsproperty.h:237
static QDomElement writeVariant(const QVariant &value, QDomDocument &doc)
Write a QVariant to a QDomElement.
QgsProperty property(int key) const override
Returns a matching property from the collection, if one exists.
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...