QGIS API Documentation  3.2.0-Bonn (bc43194)
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  return mProperties.contains( key ) && mProperties.value( key );
187 }
188 
190 {
191  if ( mProperties.isEmpty() )
192  return QgsProperty();
193 
194  return mProperties.value( key );
195 }
196 
198 {
199  mDirty = true;
200  return mProperties[ key ];
201 }
202 
203 QVariant QgsPropertyCollection::value( int key, const QgsExpressionContext &context, const QVariant &defaultValue ) const
204 {
205  if ( mProperties.isEmpty() )
206  return defaultValue;
207 
208  QgsProperty prop = mProperties.value( key );
209  if ( !prop || !prop.isActive() )
210  return defaultValue;
211 
212  return prop.value( context, defaultValue );
213 }
214 
216 {
217  bool result = true;
218  QHash<int, QgsProperty>::const_iterator it = mProperties.constBegin();
219  for ( ; it != mProperties.constEnd(); ++it )
220  {
221  if ( !it.value().isActive() )
222  continue;
223 
224  result = result && it.value().prepare( context );
225  }
226  return result;
227 }
228 
229 QSet< QString > QgsPropertyCollection::referencedFields( const QgsExpressionContext &context ) const
230 {
231  QSet< QString > cols;
232  QHash<int, QgsProperty>::const_iterator it = mProperties.constBegin();
233  for ( ; it != mProperties.constEnd(); ++it )
234  {
235  if ( !it.value().isActive() )
236  continue;
237 
238  cols.unite( it.value().referencedFields( context ) );
239  }
240  return cols;
241 }
242 
243 bool QgsPropertyCollection::isActive( int key ) const
244 {
245  if ( mProperties.isEmpty() )
246  return false;
247 
248  return mProperties.value( key ).isActive();
249 }
250 
251 void QgsPropertyCollection::rescan() const
252 {
253  mHasActiveProperties = false;
254  mHasDynamicProperties = false;
255  mCount = 0;
256  if ( !mProperties.isEmpty() )
257  {
258  QHash<int, QgsProperty>::const_iterator it = mProperties.constBegin();
259  for ( ; it != mProperties.constEnd(); ++it )
260  {
261  if ( it.value() )
262  mCount++;
263  if ( it.value().isActive() )
264  {
265  mHasActiveProperties = true;
266  if ( it.value().propertyType() != QgsProperty::StaticProperty )
267  {
268  mHasDynamicProperties = true;
269  }
270  }
271  }
272  }
273  mDirty = false;
274 }
275 
277 {
278  if ( mDirty )
279  rescan();
280 
281  return mHasActiveProperties;
282 }
283 
285 {
286  if ( mDirty )
287  rescan();
288 
289  return mHasDynamicProperties;
290 }
291 
292 QVariant QgsPropertyCollection::toVariant( const QgsPropertiesDefinition &definitions ) const
293 {
294  QVariantMap collection;
295 
296  collection.insert( QStringLiteral( "name" ), name() );
297  collection.insert( QStringLiteral( "type" ), QStringLiteral( "collection" ) );
298 
299  QVariantMap properties;
300 
301  QHash<int, QgsProperty>::const_iterator it = mProperties.constBegin();
302  for ( ; it != mProperties.constEnd(); ++it )
303  {
304  if ( it.value() )
305  {
306  properties.insert( definitions.value( it.key() ).name(), it.value().toVariant() );
307  }
308  }
309  collection.insert( QStringLiteral( "properties" ), properties );
310  return collection;
311 }
312 
313 bool QgsPropertyCollection::loadVariant( const QVariant &collection, const QgsPropertiesDefinition &definitions )
314 {
315  clear();
316 
317  QVariantMap collectionMap = collection.toMap();
318 
319  setName( collectionMap.value( QStringLiteral( "name" ) ).toString() );
320 
321  mCount = 0;
322  QVariantMap properties = collectionMap.value( QStringLiteral( "properties" ) ).toMap();
323  for ( auto propertyIterator = properties.constBegin(); propertyIterator != properties.constEnd(); ++propertyIterator )
324  {
325  // match name to int key
326  int key = -1;
327  QgsPropertiesDefinition::const_iterator it = definitions.constBegin();
328  for ( ; it != definitions.constEnd(); ++it )
329  {
330  if ( it->name() == propertyIterator.key() )
331  {
332  key = it.key();
333  break;
334  }
335  }
336 
337  if ( key < 0 )
338  continue;
339 
340  QgsProperty prop;
341  prop.loadVariant( propertyIterator.value() );
342  mProperties.insert( key, prop );
343 
344  mCount++;
345 
346  mHasActiveProperties = mHasActiveProperties || prop.isActive();
347  mHasDynamicProperties = mHasDynamicProperties ||
348  ( prop.isActive() &&
351  }
352  return true;
353 }
354 
355 //
356 // QgsPropertyCollectionStack
357 //
358 
360 {
361  clear();
362 }
363 
366 {
367  clear();
368 
369  Q_FOREACH ( QgsPropertyCollection *collection, other.mStack )
370  {
371  mStack << new QgsPropertyCollection( *collection );
372  }
373 }
374 
376 {
377  setName( other.name() );
378  clear();
379 
380  Q_FOREACH ( QgsPropertyCollection *collection, other.mStack )
381  {
382  mStack << new QgsPropertyCollection( *collection );
383  }
384 
385  return *this;
386 }
387 
389 {
390  return mStack.size();
391 }
392 
394 {
395  qDeleteAll( mStack );
396  mStack.clear();
397 }
398 
400 {
401  mStack.append( collection );
402 }
403 
405 {
406  return mStack.value( index );
407 }
408 
410 {
411  return mStack.value( index );
412 }
413 
415 {
416  Q_FOREACH ( QgsPropertyCollection *collection, mStack )
417  {
418  if ( collection->name() == name )
419  return collection;
420  }
421  return nullptr;
422 }
423 
425 {
426  Q_FOREACH ( const QgsPropertyCollection *collection, mStack )
427  {
428  if ( collection->hasActiveProperties() )
429  return true;
430  }
431  return false;
432 }
433 
435 {
436  Q_FOREACH ( const QgsPropertyCollection *collection, mStack )
437  {
438  if ( collection->hasDynamicProperties() )
439  return true;
440  }
441  return false;
442 }
443 
445 {
446  return static_cast< bool >( property( key ) );
447 }
448 
450 {
451  //loop through stack looking for last active matching property
452  for ( int i = mStack.size() - 1; i >= 0; --i )
453  {
454  const QgsPropertyCollection *collection = mStack.at( i );
455  QgsProperty property = collection->property( key );
456  if ( property && property.isActive() )
457  {
458  return property;
459  }
460  }
461  //not found
462  return QgsProperty();
463 }
464 
465 
466 QVariant QgsPropertyCollectionStack::value( int key, const QgsExpressionContext &context, const QVariant &defaultValue ) const
467 {
468  QgsProperty p = property( key );
469  if ( !p )
470  {
471  return defaultValue;
472  }
473  return p.value( context, defaultValue );
474 }
475 
477 {
478  QSet< QString > cols;
479  Q_FOREACH ( QgsPropertyCollection *collection, mStack )
480  {
481  cols.unite( collection->referencedFields( context ) );
482  }
483  return cols;
484 }
485 
487 {
488  bool result = true;
489  Q_FOREACH ( QgsPropertyCollection *collection, mStack )
490  {
491  result = result && collection->prepare( context );
492  }
493  return result;
494 }
495 
497 {
498  QSet<int> keys;
499  Q_FOREACH ( QgsPropertyCollection *collection, mStack )
500  {
501  keys.unite( collection->propertyKeys() );
502  }
503  return keys;
504 }
505 
507 {
508  Q_FOREACH ( QgsPropertyCollection *collection, mStack )
509  {
510  if ( collection->hasProperty( key ) )
511  return true;
512  }
513  return false;
514 }
515 
517 {
518  QVariantMap collection;
519  collection.insert( QStringLiteral( "type" ), QStringLiteral( "stack" ) );
520  collection.insert( QStringLiteral( "name" ), name() );
521 
522  QVariantList properties;
523 
524  Q_FOREACH ( QgsPropertyCollection *child, mStack )
525  {
526  properties.append( child->toVariant( definitions ) );
527  }
528 
529  collection.insert( QStringLiteral( "properties" ), properties );
530 
531  return collection;
532 }
533 
535 {
536  clear();
537 
538  QVariantMap collectionMap = collection.toMap();
539 
540  setName( collectionMap.value( QStringLiteral( "name" ) ).toString() );
541 
542  QVariantList properties = collectionMap.value( QStringLiteral( "properties" ) ).toList();
543 
544  Q_FOREACH ( const QVariant &property, properties )
545  {
546  QgsPropertyCollection *propertyCollection = new QgsPropertyCollection();
547  propertyCollection->loadVariant( property.toMap(), definitions );
548  mStack.append( propertyCollection );
549  }
550 
551  return true;
552 }
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.
Invalid (not set) property.
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.