Branch data Line data Source code
1 : : /***************************************************************************
2 : : qgspropertycollection.h
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 : : #ifndef QGSPROPERTYCOLLECTION_H
16 : : #define QGSPROPERTYCOLLECTION_H
17 : :
18 : : #include "qgis_core.h"
19 : : #include "qgis_sip.h"
20 : : #include "qgsexpressioncontext.h"
21 : : #include "qgsproperty.h"
22 : :
23 : : #include <QString>
24 : : #include <QVariant>
25 : : #include <QColor>
26 : : #include <QDateTime>
27 : :
28 : : class QDomElement;
29 : : class QDomDocument;
30 : :
31 : : //! Definition of available properties
32 : : typedef QMap< int, QgsPropertyDefinition > QgsPropertiesDefinition;
33 : :
34 : : /**
35 : : * \ingroup core
36 : : * \class QgsAbstractPropertyCollection
37 : : * \brief Abstract base class for QgsPropertyCollection like objects.
38 : : * \since QGIS 3.0
39 : : */
40 : :
41 : 0 : class CORE_EXPORT QgsAbstractPropertyCollection
42 : : {
43 : :
44 : : #ifdef SIP_RUN
45 : : SIP_CONVERT_TO_SUBCLASS_CODE
46 : : if ( dynamic_cast<QgsPropertyCollection *>( sipCpp ) )
47 : : sipType = sipType_QgsPropertyCollection;
48 : : else if ( dynamic_cast<QgsPropertyCollectionStack *>( sipCpp ) )
49 : : sipType = sipType_QgsPropertyCollectionStack;
50 : : else
51 : : sipType = sipType_QgsAbstractPropertyCollection;
52 : : SIP_END
53 : : #endif
54 : :
55 : : public:
56 : :
57 : : /**
58 : : * Constructor for QgsAbstractPropertyCollection. The name
59 : : * parameter should be set to a descriptive name for the collection.
60 : : */
61 : : QgsAbstractPropertyCollection( const QString &name = QString() );
62 : :
63 : 1749 : virtual ~QgsAbstractPropertyCollection() = default;
64 : :
65 : : /**
66 : : * Returns the descriptive name of the property collection.
67 : : * \see setName()
68 : : */
69 : 0 : QString name() const { return mName; }
70 : :
71 : : /**
72 : : * Sets the descriptive name for the property collection.
73 : : * \see name()
74 : : */
75 : 1570 : void setName( const QString &name ) { mName = name; }
76 : :
77 : : /**
78 : : * Returns a list of property keys contained within the collection.
79 : : */
80 : : virtual QSet<int> propertyKeys() const = 0;
81 : :
82 : : /**
83 : : * Removes all properties from the collection.
84 : : */
85 : : virtual void clear() = 0;
86 : :
87 : : /**
88 : : * Returns TRUE if the collection contains a property with the specified key.
89 : : * \param key integer key for property. The intended use case is that a context specific enum is cast to
90 : : * int and used for the key value.
91 : : * \see property()
92 : : */
93 : : virtual bool hasProperty( int key ) const = 0;
94 : :
95 : : /**
96 : : * Returns a matching property from the collection, if one exists.
97 : : * \param key integer key for property to return. The intended use case is that a context specific enum is cast to
98 : : * int and used for the key value.
99 : : * \returns matching property, or null if no matching, active property found.
100 : : * \see hasProperty()
101 : : */
102 : : virtual QgsProperty property( int key ) const = 0;
103 : :
104 : : /**
105 : : * Returns the calculated value of the property with the specified key from within the collection.
106 : : * If you need the validity of the value (like ok provided from the
107 : : * valueAs* variants) refer to the property() and QgsProperty::value()
108 : : * \param key integer key for property to return. The intended use case is that a context specific enum is cast to
109 : : * int and used for the key value.
110 : : * \param context expression context to evaluate property against
111 : : * \param defaultValue default value to return if no matching, active property found or if the property value
112 : : * cannot be calculated
113 : : * \returns calculated property value, or default value if property could not be evaluated
114 : : * \see valueAsString()
115 : : * \see valueAsColor()
116 : : * \see valueAsDouble()
117 : : * \see valueAsInt()
118 : : * \see valueAsBool()
119 : : */
120 : : virtual QVariant value( int key, const QgsExpressionContext &context, const QVariant &defaultValue = QVariant() ) const = 0;
121 : :
122 : : /**
123 : : * Calculates the current value of the property with the specified key and interprets it as a datetime.
124 : : * \param key integer key for property to return. The intended use case is that a context specific enum is cast to
125 : : * int and used for the key value.
126 : : * \param context QgsExpressionContext to evaluate the property for.
127 : : * \param defaultDateTime default datetime to return if the property cannot be calculated as a datetime
128 : : * \param ok if specified, will be set to TRUE if conversion was successful
129 : : * \returns value parsed to datetime
130 : : * \see value()
131 : : * \see valueAsString()
132 : : * \see valueAsColor()
133 : : * \see valueAsDouble()
134 : : * \see valueAsInt()
135 : : * \see valueAsBool()
136 : : * \since QGIS 3.14
137 : : */
138 : : QDateTime valueAsDateTime( int key, const QgsExpressionContext &context, const QDateTime &defaultDateTime = QDateTime(), bool *ok SIP_OUT = nullptr ) const;
139 : :
140 : : /**
141 : : * Calculates the current value of the property with the specified key and interprets it as a string.
142 : : * \param key integer key for property to return. The intended use case is that a context specific enum is cast to
143 : : * int and used for the key value.
144 : : * \param context QgsExpressionContext to evaluate the property for.
145 : : * \param defaultString default string to return if the property cannot be calculated as a string
146 : : * \param ok if specified, will be set to TRUE if conversion was successful
147 : : * \returns value parsed to string
148 : : * \see value()
149 : : * \see valueAsDateTime()
150 : : * \see valueAsColor()
151 : : * \see valueAsDouble()
152 : : * \see valueAsInt()
153 : : * \see valueAsBool()
154 : : */
155 : : QString valueAsString( int key, const QgsExpressionContext &context, const QString &defaultString = QString(), bool *ok SIP_OUT = nullptr ) const;
156 : :
157 : : /**
158 : : * Calculates the current value of the property with the specified key and interprets it as a color.
159 : : * \param key integer key for property to return. The intended use case is that a context specific enum is cast to
160 : : * int and used for the key value.
161 : : * \param context QgsExpressionContext to evaluate the property for.
162 : : * \param defaultColor default color to return if the property cannot be calculated as a color
163 : : * \param ok if specified, will be set to TRUE if conversion was successful
164 : : * \returns value parsed to color
165 : : * \see value()
166 : : * \see valueAsDateTime()
167 : : * \see valueAsString()
168 : : * \see valueAsDouble()
169 : : * \see valueAsInt()
170 : : * \see valueAsBool()
171 : : */
172 : : QColor valueAsColor( int key, const QgsExpressionContext &context, const QColor &defaultColor = QColor(), bool *ok SIP_OUT = nullptr ) const;
173 : :
174 : : /**
175 : : * Calculates the current value of the property with the specified key and interprets it as a double.
176 : : * \param key integer key for property to return. The intended use case is that a context specific enum is cast to
177 : : * int and used for the key value.
178 : : * \param context QgsExpressionContext to evaluate the property for.
179 : : * \param defaultValue default double to return if the property cannot be calculated as a double
180 : : * \param ok if specified, will be set to TRUE if conversion was successful
181 : : * \returns value parsed to double
182 : : * \see value()
183 : : * \see valueAsDateTime()
184 : : * \see valueAsString()
185 : : * \see valueAsColor()
186 : : * \see valueAsInt()
187 : : * \see valueAsBool()
188 : : */
189 : : double valueAsDouble( int key, const QgsExpressionContext &context, double defaultValue = 0.0, bool *ok SIP_OUT = nullptr ) const;
190 : :
191 : : /**
192 : : * Calculates the current value of the property with the specified key and interprets it as an integer.
193 : : * \param key integer key for property to return. The intended use case is that a context specific enum is cast to
194 : : * int and used for the key value.
195 : : * \param context QgsExpressionContext to evaluate the property for.
196 : : * \param defaultValue default integer to return if the property cannot be calculated as a integer
197 : : * \param ok if specified, will be set to TRUE if conversion was successful
198 : : * \returns value parsed to integer
199 : : * \see value()
200 : : * \see valueAsDateTime()
201 : : * \see valueAsString()
202 : : * \see valueAsColor()
203 : : * \see valueAsDouble()
204 : : * \see valueAsBool()
205 : : */
206 : : int valueAsInt( int key, const QgsExpressionContext &context, int defaultValue = 0, bool *ok SIP_OUT = nullptr ) const;
207 : :
208 : : /**
209 : : * Calculates the current value of the property with the specified key and interprets it as an boolean.
210 : : * \param key integer key for property to return. The intended use case is that a context specific enum is cast to
211 : : * int and used for the key value.
212 : : * \param context QgsExpressionContext to evaluate the property for.
213 : : * \param defaultValue default boolean to return if the property cannot be calculated as a boolean
214 : : * \param ok if specified, will be set to TRUE if conversion was successful
215 : : * \returns value parsed to bool
216 : : * \see value()
217 : : * \see valueAsDateTime()
218 : : * \see valueAsString()
219 : : * \see valueAsColor()
220 : : * \see valueAsDouble()
221 : : * \see valueAsInt()
222 : : */
223 : : bool valueAsBool( int key, const QgsExpressionContext &context, bool defaultValue = false, bool *ok SIP_OUT = nullptr ) const;
224 : :
225 : : /**
226 : : * Prepares the collection against a specified expression context. Calling prepare before evaluating the
227 : : * collection's properties multiple times allows precalculation of expensive setup tasks such as parsing expressions.
228 : : * Returns TRUE if preparation was successful.
229 : : */
230 : : virtual bool prepare( const QgsExpressionContext &context = QgsExpressionContext() ) const = 0;
231 : :
232 : : /**
233 : : * Returns the set of any fields referenced by the active properties from the collection.
234 : : * \param context expression context the properties will be evaluated against.
235 : : * \param ignoreContext This parameter has been added in QGIS 3.14. When set to TRUE, even fields not set
236 : : * in context's fields() will be reported - this is useful e.g. with vector tiles
237 : : * where the actual available field names may not be known beforehand.
238 : : */
239 : : virtual QSet< QString > referencedFields( const QgsExpressionContext &context = QgsExpressionContext(), bool ignoreContext = false ) const = 0;
240 : :
241 : : /**
242 : : * Returns TRUE if the collection contains an active property with the specified key.
243 : : * \param key integer key for property to test. The intended use case is that a context specific enum is cast to
244 : : * int and used for the key value.
245 : : */
246 : : virtual bool isActive( int key ) const = 0;
247 : :
248 : : /**
249 : : * Returns TRUE if the collection has any active properties, or FALSE if all properties
250 : : * within the collection are deactivated.
251 : : * \see hasDynamicProperties()
252 : : */
253 : : virtual bool hasActiveProperties() const = 0;
254 : :
255 : : /**
256 : : * Returns TRUE if the collection has any active, non-static properties, or FALSE if either all non-static properties
257 : : * within the collection are deactivated or if the collection only contains static properties.
258 : : * \see hasActiveProperties()
259 : : */
260 : : virtual bool hasDynamicProperties() const = 0;
261 : :
262 : : /**
263 : : * Writes the current state of the property collection into an XML element
264 : : * \param collectionElem destination element for the property collection's state
265 : : * \param definitions property definitions
266 : : * \see readXml()
267 : : */
268 : : virtual bool writeXml( QDomElement &collectionElem, const QgsPropertiesDefinition &definitions ) const;
269 : :
270 : : /**
271 : : * Reads property collection state from an XML element.
272 : : * \param collectionElem source DOM element for property collection's state
273 : : * \param definitions property definitions
274 : : * \see writeXml()
275 : : */
276 : : virtual bool readXml( const QDomElement &collectionElem, const QgsPropertiesDefinition &definitions );
277 : :
278 : : /**
279 : : * Saves this property collection to a QVariantMap, wrapped in a QVariant.
280 : : * You can use QgsXmlUtils::writeVariant to save it to an XML document.
281 : : *
282 : : * \see loadVariant()
283 : : */
284 : : virtual QVariant toVariant( const QgsPropertiesDefinition &definitions ) const = 0;
285 : :
286 : : /**
287 : : * Loads this property collection from a QVariantMap, wrapped in a QVariant.
288 : : * You can use QgsXmlUtils::readVariant to save it to an XML document.
289 : : *
290 : : * \see toVariant()
291 : : */
292 : : virtual bool loadVariant( const QVariant &configuration, const QgsPropertiesDefinition &definitions ) = 0;
293 : :
294 : : private:
295 : :
296 : : QString mName;
297 : : };
298 : :
299 : : /**
300 : : * \ingroup core
301 : : * \class QgsPropertyCollection
302 : : * \brief A grouped map of multiple QgsProperty objects, each referenced by a integer key value.
303 : : *
304 : : * Properties within a collection are referenced by an integer key. This is done to avoid the cost of
305 : : * string creation and comparisons which would be required by a string key. The intended use case is that
306 : : * a context specific enum is cast to int and used for the key value.
307 : : * Examples of such enums are :
308 : : * \see QgsLayoutObject::DataDefinedProperty
309 : : * \see QgsSymbolLayer::Property
310 : : * \see QgsPalLabeling::Property
311 : : * \see QgsAbstract3DSymbol::Property
312 : : * \see QgsDiagramLayerSettings::Property
313 : : * \see QgsPalLayerSettings::Property
314 : : * \see QgsWidgetWrapper::Property
315 : : * \since QGIS 3.0
316 : : */
317 : :
318 : 1749 : class CORE_EXPORT QgsPropertyCollection : public QgsAbstractPropertyCollection
319 : : {
320 : : public:
321 : :
322 : : /**
323 : : * Constructor for QgsPropertyCollection
324 : : * \param name collection name
325 : : */
326 : : QgsPropertyCollection( const QString &name = QString() );
327 : :
328 : : /**
329 : : * Copy constructor.
330 : : */
331 : : QgsPropertyCollection( const QgsPropertyCollection &other );
332 : :
333 : : QgsPropertyCollection &operator=( const QgsPropertyCollection &other );
334 : :
335 : : bool operator==( const QgsPropertyCollection &other ) const;
336 : : bool operator!=( const QgsPropertyCollection &other ) const;
337 : :
338 : : /**
339 : : * Returns the number of properties contained within the collection.
340 : : */
341 : : int count() const;
342 : :
343 : : QSet<int> propertyKeys() const override;
344 : : void clear() override;
345 : : bool hasProperty( int key ) const override;
346 : : QgsProperty property( int key ) const override SIP_SKIP;
347 : :
348 : : /**
349 : : * Returns a reference to a matching property from the collection, if one exists.
350 : : * \param key integer key for property to return. The intended use case is that a context specific enum is cast to
351 : : * int and used for the key value.
352 : : * \returns matching property, or null if no matching, active property found.
353 : : * \see hasProperty()
354 : : */
355 : : virtual QgsProperty &property( int key );
356 : :
357 : : QVariant value( int key, const QgsExpressionContext &context, const QVariant &defaultValue = QVariant() ) const override;
358 : : bool prepare( const QgsExpressionContext &context = QgsExpressionContext() ) const override;
359 : : QSet< QString > referencedFields( const QgsExpressionContext &context = QgsExpressionContext(), bool ignoreContext = false ) const override;
360 : : bool isActive( int key ) const override;
361 : : bool hasActiveProperties() const override;
362 : : bool hasDynamicProperties() const override;
363 : :
364 : : QVariant toVariant( const QgsPropertiesDefinition &definitions ) const override;
365 : : bool loadVariant( const QVariant &configuration, const QgsPropertiesDefinition &definitions ) override;
366 : :
367 : : /**
368 : : * Adds a property to the collection and takes ownership of it.
369 : : * \param key integer key for property. Any existing property with the same key will be removed
370 : : * and replaced by this property. The intended use case is that a context specific enum is cast to
371 : : * int and used for the key value.
372 : : * \param property property to add. Ownership is transferred to the collection. Setting an invalid property
373 : : * will remove the property from the collection.
374 : : */
375 : : void setProperty( int key, const QgsProperty &property );
376 : :
377 : : /**
378 : : * Convenience method, creates a QgsStaticProperty and stores it within the collection.
379 : : * \param key integer key for property. Any existing property with the same key will be deleted
380 : : * and replaced by this property. The intended use case is that a context specific enum is cast to
381 : : * int and used for the key value.
382 : : * \param value static value for property
383 : : */
384 : : void setProperty( int key, const QVariant &value );
385 : :
386 : : private:
387 : :
388 : : QHash<int, QgsProperty> mProperties;
389 : :
390 : : mutable bool mDirty = false;
391 : : mutable bool mHasActiveProperties = false;
392 : : mutable bool mHasDynamicProperties = false;
393 : : mutable int mCount = 0;
394 : :
395 : : //! Scans through properties and updates cached values
396 : : void rescan() const;
397 : : };
398 : :
399 : :
400 : : /**
401 : : * \ingroup core
402 : : * \class QgsPropertyCollectionStack
403 : : * \brief An ordered stack of QgsPropertyCollection containers, where collections added later to the stack will take
404 : : * priority over earlier collections.
405 : : * \since QGIS 3.0
406 : : */
407 : :
408 : : class CORE_EXPORT QgsPropertyCollectionStack : public QgsAbstractPropertyCollection
409 : : {
410 : : public:
411 : :
412 : : /**
413 : : * Constructor for QgsPropertyCollectionStack.
414 : : */
415 : : QgsPropertyCollectionStack() = default;
416 : :
417 : : ~QgsPropertyCollectionStack() override;
418 : :
419 : : //! Copy constructor
420 : : QgsPropertyCollectionStack( const QgsPropertyCollectionStack &other );
421 : :
422 : : QgsPropertyCollectionStack &operator=( const QgsPropertyCollectionStack &other );
423 : :
424 : : /**
425 : : * Returns the number of collections contained within the stack.
426 : : */
427 : : int count() const;
428 : :
429 : : /**
430 : : * Removes all collections from the stack.
431 : : */
432 : : void clear() override;
433 : :
434 : : /**
435 : : * Appends a collection to the end of the stack, and transfers ownership of the collection to the stack. Properties
436 : : * from the newly added collection will take priority over any existing properties with the same name.
437 : : * \param collection collection to append. Ownership is transferred to the stack.
438 : : */
439 : : void appendCollection( QgsPropertyCollection *collection SIP_TRANSFER );
440 : :
441 : : /**
442 : : * Returns the collection at the corresponding index from the stack.
443 : : * \param index position of collection, 0 based
444 : : * \returns collection if one exists at the specified index
445 : : */
446 : : QgsPropertyCollection *at( int index );
447 : :
448 : : /**
449 : : * Returns the collection at the corresponding index from the stack.
450 : : * \param index position of collection, 0 based
451 : : * \returns collection if one exists at the specified index
452 : : * \note not available in Python bindings
453 : : */
454 : : const QgsPropertyCollection *at( int index ) const SIP_SKIP;
455 : :
456 : : /**
457 : : * Returns the first collection with a matching name from the stack.
458 : : * \param name name of collection to find
459 : : * \returns collection if one exists with the specified name
460 : : */
461 : : QgsPropertyCollection *collection( const QString &name );
462 : :
463 : : /**
464 : : * Returns TRUE if the collection has any active properties, or FALSE if all properties
465 : : * within the collection are deactivated.
466 : : * \see isActive()
467 : : * \see hasDynamicProperties()
468 : : */
469 : : bool hasActiveProperties() const override;
470 : :
471 : : /**
472 : : * Returns TRUE if the collection has any active, non-static properties, or FALSE if either all non-static properties
473 : : * within the collection are deactivated or if the collection only contains static properties.
474 : : * \see hasActiveProperties()
475 : : */
476 : : bool hasDynamicProperties() const override;
477 : :
478 : : /**
479 : : * Returns TRUE if the stack contains an active property with the specified key.
480 : : * \param key integer key for property to test. The intended use case is that a context specific enum is cast to
481 : : * int and used for the key value.
482 : : * \see hasActiveProperties()
483 : : */
484 : : bool isActive( int key ) const override;
485 : :
486 : : /**
487 : : * Returns the highest priority property with a matching key from within the stack.
488 : : * \param key integer key for property to return. The intended use case is that a context specific enum is cast to
489 : : * int and used for the key value.
490 : : * \returns matching property, or null if no matching, active property found.
491 : : * \see hasActiveProperty()
492 : : */
493 : : QgsProperty property( int key ) const override;
494 : :
495 : : /**
496 : : * Returns the calculated value of the highest priority property with the specified key from within the stack.
497 : : * \param key integer key for property to calculate. The intended use case is that a context specific enum is cast to
498 : : * int and used for the key value.
499 : : * \param context expression context to evaluate property against
500 : : * \param defaultValue default value to return if no matching, active property found or if the property value
501 : : * cannot be calculated
502 : : * \returns calculated property value, or default value if property could not be evaluated
503 : : */
504 : : QVariant value( int key, const QgsExpressionContext &context, const QVariant &defaultValue = QVariant() ) const override;
505 : :
506 : : /**
507 : : * Returns the set of any fields referenced by the active properties from the stack.
508 : : * \param context expression context the properties will be evaluated against.
509 : : * \param ignoreContext This parameter has been added in QGIS 3.14. When set to TRUE, even fields not set
510 : : * in context's fields() will be reported - this is useful e.g. with vector tiles
511 : : * where the actual available field names may not be known beforehand.
512 : : */
513 : : QSet< QString > referencedFields( const QgsExpressionContext &context = QgsExpressionContext(), bool ignoreContext = false ) const override;
514 : : bool prepare( const QgsExpressionContext &context = QgsExpressionContext() ) const override;
515 : :
516 : : QSet<int> propertyKeys() const override;
517 : : bool hasProperty( int key ) const override;
518 : :
519 : : QVariant toVariant( const QgsPropertiesDefinition &definitions ) const override;
520 : :
521 : : bool loadVariant( const QVariant &collection, const QgsPropertiesDefinition &definitions ) override;
522 : :
523 : : private:
524 : :
525 : : QList< QgsPropertyCollection * > mStack;
526 : :
527 : : };
528 : :
529 : : #endif // QGSPROPERTYCOLLECTION_H
|