QGIS API Documentation  3.8.0-Zanzibar (11aff65)
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  for ( QgsPropertyCollection *collection : qgis::as_const( other.mStack ) )
370  {
371  mStack << new QgsPropertyCollection( *collection );
372  }
373 }
374 
376 {
377  setName( other.name() );
378  clear();
379 
380  for ( QgsPropertyCollection *collection : qgis::as_const( 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  const auto constMStack = mStack;
417  for ( QgsPropertyCollection *collection : constMStack )
418  {
419  if ( collection->name() == name )
420  return collection;
421  }
422  return nullptr;
423 }
424 
426 {
427  const auto constMStack = mStack;
428  for ( const QgsPropertyCollection *collection : constMStack )
429  {
431  return true;
432  }
433  return false;
434 }
435 
437 {
438  const auto constMStack = mStack;
439  for ( const QgsPropertyCollection *collection : constMStack )
440  {
442  return true;
443  }
444  return false;
445 }
446 
448 {
449  return static_cast< bool >( property( key ) );
450 }
451 
453 {
454  //loop through stack looking for last active matching property
455  for ( int i = mStack.size() - 1; i >= 0; --i )
456  {
457  const QgsPropertyCollection *collection = mStack.at( i );
458  QgsProperty property = collection->property( key );
459  if ( property && property.isActive() )
460  {
461  return property;
462  }
463  }
464  //not found
465  return QgsProperty();
466 }
467 
468 
469 QVariant QgsPropertyCollectionStack::value( int key, const QgsExpressionContext &context, const QVariant &defaultValue ) const
470 {
471  QgsProperty p = property( key );
472  if ( !p )
473  {
474  return defaultValue;
475  }
476  return p.value( context, defaultValue );
477 }
478 
480 {
481  QSet< QString > cols;
482  const auto constMStack = mStack;
483  for ( QgsPropertyCollection *collection : constMStack )
484  {
485  cols.unite( collection->referencedFields( context ) );
486  }
487  return cols;
488 }
489 
491 {
492  bool result = true;
493  const auto constMStack = mStack;
494  for ( QgsPropertyCollection *collection : constMStack )
495  {
496  result = result && collection->prepare( context );
497  }
498  return result;
499 }
500 
502 {
503  QSet<int> keys;
504  const auto constMStack = mStack;
505  for ( QgsPropertyCollection *collection : constMStack )
506  {
507  keys.unite( collection->propertyKeys() );
508  }
509  return keys;
510 }
511 
513 {
514  const auto constMStack = mStack;
515  for ( QgsPropertyCollection *collection : constMStack )
516  {
517  if ( collection->hasProperty( key ) )
518  return true;
519  }
520  return false;
521 }
522 
524 {
525  QVariantMap collection;
526  collection.insert( QStringLiteral( "type" ), QStringLiteral( "stack" ) );
527  collection.insert( QStringLiteral( "name" ), name() );
528 
529  QVariantList properties;
530 
531  const auto constMStack = mStack;
532  for ( QgsPropertyCollection *child : constMStack )
533  {
534  properties.append( child->toVariant( definitions ) );
535  }
536 
537  collection.insert( QStringLiteral( "properties" ), properties );
538 
539  return collection;
540 }
541 
543 {
544  clear();
545 
546  QVariantMap collectionMap = collection.toMap();
547 
548  setName( collectionMap.value( QStringLiteral( "name" ) ).toString() );
549 
550  QVariantList properties = collectionMap.value( QStringLiteral( "properties" ) ).toList();
551 
552  const auto constProperties = properties;
553  for ( const QVariant &property : constProperties )
554  {
555  QgsPropertyCollection *propertyCollection = new QgsPropertyCollection();
556  propertyCollection->loadVariant( property.toMap(), definitions );
557  mStack.append( propertyCollection );
558  }
559 
560  return true;
561 }
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.