Branch data Line data Source code
1 : : /***************************************************************************
2 : : qgscategorizedsymbolrenderer.h
3 : : ---------------------
4 : : begin : November 2009
5 : : copyright : (C) 2009 by Martin Dobias
6 : : email : wonder dot sk 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 QGSCATEGORIZEDSYMBOLRENDERER_H
16 : : #define QGSCATEGORIZEDSYMBOLRENDERER_H
17 : :
18 : : #include "qgis_core.h"
19 : : #include "qgis.h"
20 : : #include "qgsrenderer.h"
21 : :
22 : : #include <QHash>
23 : :
24 : : class QgsVectorLayer;
25 : : class QgsStyle;
26 : : class QgsDataDefinedSizeLegend;
27 : : class QgsSymbol;
28 : : class QgsExpression;
29 : : class QgsColorRamp;
30 : :
31 : : /**
32 : : * \ingroup core
33 : : * \brief Represents an individual category (class) from a QgsCategorizedSymbolRenderer.
34 : : */
35 : 0 : class CORE_EXPORT QgsRendererCategory
36 : : {
37 : : public:
38 : :
39 : : /**
40 : : * Constructor for QgsRendererCategory.
41 : : */
42 : 0 : QgsRendererCategory() = default;
43 : :
44 : : /**
45 : : * Constructor for a new QgsRendererCategory, with the specified \a value and \a symbol.
46 : : *
47 : : * If \a value is a list, then the category will match any of the values from this list.
48 : : *
49 : : * The ownership of \a symbol is transferred to the category.
50 : : *
51 : : * The \a label argument specifies the label used for this category in legends and the layer tree.
52 : : *
53 : : * The \a render argument indicates whether the category should initially be rendered and appear checked in the layer tree.
54 : : */
55 : : QgsRendererCategory( const QVariant &value, QgsSymbol *symbol SIP_TRANSFER, const QString &label, bool render = true );
56 : :
57 : : /**
58 : : * Copy constructor.
59 : : */
60 : : QgsRendererCategory( const QgsRendererCategory &cat );
61 : : QgsRendererCategory &operator=( QgsRendererCategory cat );
62 : :
63 : : /**
64 : : * Returns the value corresponding to this category.
65 : : *
66 : : * If the returned value is a list, then the category will match any of the values from this list.
67 : : *
68 : : * \see setValue()
69 : : */
70 : : QVariant value() const;
71 : :
72 : : /**
73 : : * Returns the symbol which will be used to render this category.
74 : : * \see setSymbol()
75 : : */
76 : : QgsSymbol *symbol() const;
77 : :
78 : : /**
79 : : * Returns the label for this category, which is used to represent the category within
80 : : * legends and the layer tree.
81 : : * \see setLabel()
82 : : */
83 : : QString label() const;
84 : :
85 : : /**
86 : : * Sets the \a value corresponding to this category.
87 : : *
88 : : * If \a value is a list, then the category will match any of the values from this list.
89 : : *
90 : : * \see value()
91 : : */
92 : : void setValue( const QVariant &value );
93 : :
94 : : /**
95 : : * Sets the symbol which will be used to render this category.
96 : : *
97 : : * Ownership of the symbol is transferred to the category.
98 : : *
99 : : * \see symbol()
100 : : */
101 : : void setSymbol( QgsSymbol *s SIP_TRANSFER );
102 : :
103 : : /**
104 : : * Sets the \a label for this category, which is used to represent the category within
105 : : * legends and the layer tree.
106 : : * \see label()
107 : : */
108 : : void setLabel( const QString &label );
109 : :
110 : : /**
111 : : * Returns TRUE if the category is currently enabled and should be rendered.
112 : : * \see setRenderState()
113 : : * \since QGIS 2.5
114 : : */
115 : : bool renderState() const;
116 : :
117 : : /**
118 : : * Sets whether the category is currently enabled and should be rendered.
119 : : * \see renderState()
120 : : * \since QGIS 2.5
121 : : */
122 : : void setRenderState( bool render );
123 : :
124 : : // debugging
125 : :
126 : : /**
127 : : * Returns a string representing the categories settings, used for debugging purposes only.
128 : : */
129 : : QString dump() const;
130 : :
131 : : /**
132 : : * Converts the category to a matching SLD rule, within the specified DOM document and \a element.
133 : : */
134 : : void toSld( QDomDocument &doc, QDomElement &element, QVariantMap props ) const;
135 : :
136 : : protected:
137 : : QVariant mValue;
138 : : std::unique_ptr<QgsSymbol> mSymbol;
139 : : QString mLabel;
140 : 0 : bool mRender = true;
141 : :
142 : : void swap( QgsRendererCategory &other );
143 : : };
144 : :
145 : : typedef QList<QgsRendererCategory> QgsCategoryList;
146 : :
147 : : /**
148 : : * \ingroup core
149 : : * \class QgsCategorizedSymbolRenderer
150 : : */
151 : : class CORE_EXPORT QgsCategorizedSymbolRenderer : public QgsFeatureRenderer
152 : : {
153 : : public:
154 : :
155 : : /**
156 : : * Constructor for QgsCategorizedSymbolRenderer.
157 : : *
158 : : * The \a attrName argument specifies the layer's field name, or expression, which the categories will be matched against.
159 : : *
160 : : * A list of renderer \a categories can optionally be specified. If no categories are specified in the constructor, they
161 : : * can be added later by calling addCategory().
162 : : */
163 : : QgsCategorizedSymbolRenderer( const QString &attrName = QString(), const QgsCategoryList &categories = QgsCategoryList() );
164 : : ~QgsCategorizedSymbolRenderer() override;
165 : :
166 : : QgsSymbol *symbolForFeature( const QgsFeature &feature, QgsRenderContext &context ) const override;
167 : : QgsSymbol *originalSymbolForFeature( const QgsFeature &feature, QgsRenderContext &context ) const override;
168 : : void startRender( QgsRenderContext &context, const QgsFields &fields ) override;
169 : : void stopRender( QgsRenderContext &context ) override;
170 : : QSet<QString> usedAttributes( const QgsRenderContext &context ) const override;
171 : : bool filterNeedsGeometry() const override;
172 : : QString dump() const override;
173 : : QgsCategorizedSymbolRenderer *clone() const override SIP_FACTORY;
174 : : void toSld( QDomDocument &doc, QDomElement &element, const QVariantMap &props = QVariantMap() ) const override;
175 : 0 : QgsFeatureRenderer::Capabilities capabilities() override { return SymbolLevels | Filter; }
176 : : QString filter( const QgsFields &fields = QgsFields() ) override;
177 : : QgsSymbolList symbols( QgsRenderContext &context ) const override;
178 : : bool accept( QgsStyleEntityVisitorInterface *visitor ) const override;
179 : :
180 : : /**
181 : : * Update all the symbols but leave categories and colors. This method also sets the source
182 : : * symbol for the renderer.
183 : : * \param sym source symbol to use for categories. Ownership is not transferred.
184 : : * \see setSourceSymbol()
185 : : */
186 : : void updateSymbols( QgsSymbol *sym );
187 : :
188 : : /**
189 : : * Returns a list of all categories recognized by the renderer.
190 : : */
191 : 0 : const QgsCategoryList &categories() const { return mCategories; }
192 : :
193 : : /**
194 : : * Returns the index for the category with the specified value (or -1 if not found).
195 : : */
196 : : int categoryIndexForValue( const QVariant &val );
197 : :
198 : : /**
199 : : * Returns the index of the category with the specified label (or -1 if the label was not found, or is not unique).
200 : : * \since QGIS 2.5
201 : : */
202 : : int categoryIndexForLabel( const QString &val );
203 : :
204 : : /**
205 : : * Changes the value for the category with the specified index.
206 : : *
207 : : * If \a value is a list, then the category will match any of the values from this list.
208 : : *
209 : : * \see updateCategorySymbol()
210 : : * \see updateCategoryLabel()
211 : : * \see updateCategoryRenderState()
212 : : */
213 : : bool updateCategoryValue( int catIndex, const QVariant &value );
214 : :
215 : : /**
216 : : * Changes the \a symbol for the category with the specified index.
217 : : *
218 : : * Ownership of \a symbol is transferred to the renderer.
219 : : *
220 : : * \see updateCategoryValue()
221 : : * \see updateCategoryLabel()
222 : : * \see updateCategoryRenderState()
223 : : */
224 : : bool updateCategorySymbol( int catIndex, QgsSymbol *symbol SIP_TRANSFER );
225 : :
226 : : /**
227 : : * Changes the \a label for the category with the specified index.
228 : : *
229 : : * A category's label is used to represent the category within
230 : : * legends and the layer tree.
231 : : *
232 : : * \see updateCategoryValue()
233 : : * \see updateCategoryLabel()
234 : : * \see updateCategoryRenderState()
235 : : */
236 : : bool updateCategoryLabel( int catIndex, const QString &label );
237 : :
238 : : /**
239 : : * Changes the render state for the category with the specified index.
240 : : *
241 : : * The render state indicates whether or not the category will be rendered,
242 : : * and is reflected in whether the category is checked with the project's layer tree.
243 : : *
244 : : * \see updateCategoryValue()
245 : : * \see updateCategorySymbol()
246 : : * \see updateCategoryLabel()
247 : : *
248 : : * \since QGIS 2.5
249 : : */
250 : : bool updateCategoryRenderState( int catIndex, bool render );
251 : :
252 : : /**
253 : : * Adds a new \a category to the renderer.
254 : : *
255 : : * \see categories()
256 : : */
257 : : void addCategory( const QgsRendererCategory &category );
258 : :
259 : : /**
260 : : * Deletes the category with the specified index from the renderer.
261 : : *
262 : : * \see deleteAllCategories()
263 : : */
264 : : bool deleteCategory( int catIndex );
265 : :
266 : : /**
267 : : * Deletes all existing categories from the renderer.
268 : : *
269 : : * \see deleteCategory()
270 : : */
271 : : void deleteAllCategories();
272 : :
273 : : /**
274 : : * Moves an existing category at index position from to index position to.
275 : : */
276 : : void moveCategory( int from, int to );
277 : :
278 : : /**
279 : : * Sorts the existing categories by their value.
280 : : *
281 : : * \see sortByLabel()
282 : : */
283 : : void sortByValue( Qt::SortOrder order = Qt::AscendingOrder );
284 : :
285 : : /**
286 : : * Sorts the existing categories by their label.
287 : : *
288 : : * \see sortByValue()
289 : : */
290 : : void sortByLabel( Qt::SortOrder order = Qt::AscendingOrder );
291 : :
292 : : /**
293 : : * Returns the class attribute for the renderer, which is the field name
294 : : * or expression string from the layer which will be matched against the
295 : : * renderer categories.
296 : : *
297 : : * \see setClassAttribute()
298 : : */
299 : 0 : QString classAttribute() const { return mAttrName; }
300 : :
301 : : /**
302 : : * Sets the class attribute for the renderer, which is the field name
303 : : * or expression string from the layer which will be matched against the
304 : : * renderer categories.
305 : : *
306 : : * \see classAttribute()
307 : : */
308 : 0 : void setClassAttribute( const QString &attr ) { mAttrName = attr; }
309 : :
310 : : /**
311 : : * Creates a categorized renderer from an XML \a element.
312 : : */
313 : : static QgsFeatureRenderer *create( QDomElement &element, const QgsReadWriteContext &context ) SIP_FACTORY;
314 : :
315 : : QDomElement save( QDomDocument &doc, const QgsReadWriteContext &context ) override;
316 : : QgsLegendSymbolList legendSymbolItems() const override;
317 : : QSet< QString > legendKeysForFeature( const QgsFeature &feature, QgsRenderContext &context ) const override;
318 : :
319 : : /**
320 : : * Returns the renderer's source symbol, which is the base symbol used for the each categories' symbol before applying
321 : : * the categories' color.
322 : : * \see setSourceSymbol()
323 : : * \see sourceColorRamp()
324 : : */
325 : : QgsSymbol *sourceSymbol();
326 : :
327 : : /**
328 : : * Returns the renderer's source symbol, which is the base symbol used for the each categories' symbol before applying
329 : : * the categories' color.
330 : : * \see setSourceSymbol()
331 : : * \see sourceColorRamp()
332 : : * \note Not available in Python bindings.
333 : : */
334 : : const QgsSymbol *sourceSymbol() const SIP_SKIP;
335 : :
336 : : /**
337 : : * Sets the source symbol for the renderer, which is the base symbol used for the each categories' symbol before applying
338 : : * the categories' color.
339 : : * \param sym source symbol, ownership is transferred to the renderer
340 : : * \see sourceSymbol()
341 : : * \see setSourceColorRamp()
342 : : */
343 : : void setSourceSymbol( QgsSymbol *sym SIP_TRANSFER );
344 : :
345 : : /**
346 : : * Returns the source color ramp, from which each categories' color is derived.
347 : : * \see setSourceColorRamp()
348 : : * \see sourceSymbol()
349 : : */
350 : : QgsColorRamp *sourceColorRamp();
351 : :
352 : : /**
353 : : * Returns the source color ramp, from which each categories' color is derived.
354 : : * \see setSourceColorRamp()
355 : : * \see sourceSymbol()
356 : : * \note Not available in Python bindings.
357 : : */
358 : : const QgsColorRamp *sourceColorRamp() const SIP_SKIP;
359 : :
360 : : /**
361 : : * Sets the source color ramp.
362 : : * \param ramp color ramp. Ownership is transferred to the renderer
363 : : * \see sourceColorRamp()
364 : : * \see setSourceSymbol()
365 : : */
366 : : void setSourceColorRamp( QgsColorRamp *ramp SIP_TRANSFER );
367 : :
368 : : /**
369 : : * Update the color ramp used and all symbols colors.
370 : : * \param ramp color ramp. Ownership is transferred to the renderer
371 : : * \since QGIS 2.5
372 : : */
373 : : void updateColorRamp( QgsColorRamp *ramp SIP_TRANSFER );
374 : :
375 : : bool legendSymbolItemsCheckable() const override;
376 : : bool legendSymbolItemChecked( const QString &key ) override;
377 : : void setLegendSymbolItem( const QString &key, QgsSymbol *symbol SIP_TRANSFER ) override;
378 : : void checkLegendSymbolItem( const QString &key, bool state = true ) override;
379 : 0 : QString legendClassificationAttribute() const override { return classAttribute(); }
380 : :
381 : : /**
382 : : * Creates a new QgsCategorizedSymbolRenderer from an existing \a renderer.
383 : : *
384 : : * Since QGIS 3.20, the optional \a layer parameter is required for conversions of some renderer types.
385 : : *
386 : : * \returns a new renderer if the conversion was possible, otherwise NULLPTR.
387 : : * \since QGIS 2.5
388 : : */
389 : : static QgsCategorizedSymbolRenderer *convertFromRenderer( const QgsFeatureRenderer *renderer, QgsVectorLayer *layer = nullptr ) SIP_FACTORY;
390 : :
391 : : /**
392 : : * Configures appearance of legend when renderer is configured to use data-defined size for marker symbols.
393 : : * This allows configuring for which values (symbol sizes) should be shown in the legend, whether to display
394 : : * different symbol sizes collapsed in one legend node or separated across multiple legend nodes etc.
395 : : *
396 : : * When renderer does not use data-defined size or does not use marker symbols, these settings will be ignored.
397 : : * Takes ownership of the passed settings objects. NULLPTR is a valid input that disables data-defined
398 : : * size legend.
399 : : * \since QGIS 3.0
400 : : */
401 : : void setDataDefinedSizeLegend( QgsDataDefinedSizeLegend *settings SIP_TRANSFER );
402 : :
403 : : /**
404 : : * Returns configuration of appearance of legend when using data-defined size for marker symbols.
405 : : * Will return NULLPTR if the functionality is disabled.
406 : : * \since QGIS 3.0
407 : : */
408 : : QgsDataDefinedSizeLegend *dataDefinedSizeLegend() const;
409 : :
410 : : /**
411 : : * Replaces category symbols with the symbols from a \a style that have a matching
412 : : * name and symbol \a type.
413 : : *
414 : : * The \a unmatchedCategories list will be filled with all existing categories which could not be matched
415 : : * to a symbol in \a style.
416 : : *
417 : : * The \a unmatchedSymbols list will be filled with all symbol names from \a style which were not matched
418 : : * to an existing category.
419 : : *
420 : : * If \a caseSensitive is FALSE, then a case-insensitive match will be performed. If \a useTolerantMatch
421 : : * is TRUE, then non-alphanumeric characters in style and category names will be ignored during the match.
422 : : *
423 : : * Returns the count of symbols matched.
424 : : *
425 : : * \since QGIS 3.4
426 : : */
427 : : int matchToSymbols( QgsStyle *style, QgsSymbol::SymbolType type,
428 : : QVariantList &unmatchedCategories SIP_OUT, QStringList &unmatchedSymbols SIP_OUT, bool caseSensitive = true, bool useTolerantMatch = false );
429 : :
430 : :
431 : : /**
432 : : * Create categories for a list of \a values.
433 : : * The returned symbols in the category list will be a modification of \a symbol.
434 : : *
435 : : * If \a layer and \a fieldName are specified it will try to find nicer values
436 : : * to represent the description for the categories based on the respective field
437 : : * configuration.
438 : : *
439 : : * \since QGIS 3.6
440 : : */
441 : : static QgsCategoryList createCategories( const QVariantList &values, const QgsSymbol *symbol, QgsVectorLayer *layer = nullptr, const QString &fieldName = QString() );
442 : :
443 : : protected:
444 : : QString mAttrName;
445 : : QgsCategoryList mCategories;
446 : : std::unique_ptr<QgsSymbol> mSourceSymbol;
447 : : std::unique_ptr<QgsColorRamp> mSourceColorRamp;
448 : : std::unique_ptr<QgsExpression> mExpression;
449 : :
450 : : std::unique_ptr<QgsDataDefinedSizeLegend> mDataDefinedSizeLegend;
451 : :
452 : : //! attribute index (derived from attribute name in startRender)
453 : : int mAttrNum = -1;
454 : :
455 : : //! hashtable for faster access to symbols
456 : : QHash<QString, QgsSymbol *> mSymbolHash;
457 : : bool mCounting = false;
458 : :
459 : : void rebuildHash();
460 : :
461 : : /**
462 : : * \deprecated No longer used, will be removed in QGIS 4.0
463 : : */
464 : : Q_DECL_DEPRECATED QgsSymbol *skipRender() SIP_DEPRECATED;
465 : :
466 : : /**
467 : : * Returns the matching symbol corresponding to an attribute \a value.
468 : : * \deprecated use variant which takes a second bool argument instead.
469 : : */
470 : : Q_DECL_DEPRECATED QgsSymbol *symbolForValue( const QVariant &value ) const SIP_DEPRECATED;
471 : :
472 : : // TODO QGIS 4.0 - rename Python method to symbolForValue
473 : :
474 : : /**
475 : : * Returns the matching symbol corresponding to an attribute \a value.
476 : : *
477 : : * Will return NULLPTR if no matching symbol was found for \a value, or
478 : : * if the category corresponding to \a value is currently disabled (see QgsRendererCategory::renderState()).
479 : : *
480 : : * If \a foundMatchingSymbol is specified then it will be set to TRUE if
481 : : * a matching category was found. This can be used to differentiate between
482 : : * NULLPTR returned as a result of no matching category vs NULLPTR as a result
483 : : * of disabled categories.
484 : : *
485 : : * \note available in Python bindings as symbolForValue2
486 : : */
487 : : QgsSymbol *symbolForValue( const QVariant &value, bool &foundMatchingSymbol SIP_OUT ) const SIP_PYNAME( symbolForValue2 );
488 : :
489 : : private:
490 : : #ifdef SIP_RUN
491 : : QgsCategorizedSymbolRenderer( const QgsCategorizedSymbolRenderer & );
492 : : QgsCategorizedSymbolRenderer &operator=( const QgsCategorizedSymbolRenderer & );
493 : : #endif
494 : :
495 : : //! Returns calculated classification value for a feature
496 : : QVariant valueForFeature( const QgsFeature &feature, QgsRenderContext &context ) const;
497 : :
498 : : //! Returns list of legend symbol items from individual categories
499 : : QgsLegendSymbolList baseLegendSymbolItems() const;
500 : : };
501 : :
502 : : #endif // QGSCATEGORIZEDSYMBOLRENDERER_H
|