QGIS API Documentation  3.18.1-Zürich (202f1bf7e5)
qgscategorizedsymbolrenderer.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgscategorizedsymbolrenderer.cpp
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 #include <algorithm>
16 
18 
20 #include "qgssymbol.h"
21 #include "qgssymbollayerutils.h"
22 #include "qgscolorramp.h"
26 #include "qgspainteffect.h"
27 #include "qgspainteffectregistry.h"
28 #include "qgssymbollayer.h"
29 #include "qgsfeature.h"
30 #include "qgsvectorlayer.h"
31 #include "qgslogger.h"
32 #include "qgsproperty.h"
33 #include "qgsstyle.h"
34 #include "qgsfieldformatter.h"
36 #include "qgsapplication.h"
38 #include "qgsstyleentityvisitor.h"
39 
40 #include <QDomDocument>
41 #include <QDomElement>
42 #include <QSettings> // for legend
43 #include <QRegularExpression>
44 
45 QgsRendererCategory::QgsRendererCategory( const QVariant &value, QgsSymbol *symbol, const QString &label, bool render )
46  : mValue( value )
47  , mSymbol( symbol )
48  , mLabel( label )
49  , mRender( render )
50 {
51 }
52 
54  : mValue( cat.mValue )
55  , mSymbol( cat.mSymbol ? cat.mSymbol->clone() : nullptr )
56  , mLabel( cat.mLabel )
57  , mRender( cat.mRender )
58 {
59 }
60 
61 // copy+swap idion, the copy is done through the 'pass by value'
63 {
64  swap( cat );
65  return *this;
66 }
67 
69 {
70  std::swap( mValue, cat.mValue );
71  std::swap( mSymbol, cat.mSymbol );
72  std::swap( mLabel, cat.mLabel );
73 }
74 
76 {
77  return mValue;
78 }
79 
81 {
82  return mSymbol.get();
83 }
84 
86 {
87  return mLabel;
88 }
89 
91 {
92  return mRender;
93 }
94 
95 void QgsRendererCategory::setValue( const QVariant &value )
96 {
97  mValue = value;
98 }
99 
101 {
102  if ( mSymbol.get() != s ) mSymbol.reset( s );
103 }
104 
105 void QgsRendererCategory::setLabel( const QString &label )
106 {
107  mLabel = label;
108 }
109 
111 {
112  mRender = render;
113 }
114 
116 {
117  return QStringLiteral( "%1::%2::%3:%4\n" ).arg( mValue.toString(), mLabel, mSymbol->dump() ).arg( mRender );
118 }
119 
120 void QgsRendererCategory::toSld( QDomDocument &doc, QDomElement &element, QVariantMap props ) const
121 {
122  if ( !mSymbol.get() || props.value( QStringLiteral( "attribute" ), QString() ).toString().isEmpty() )
123  return;
124 
125  QString attrName = props[ QStringLiteral( "attribute" )].toString();
126 
127  QDomElement ruleElem = doc.createElement( QStringLiteral( "se:Rule" ) );
128  element.appendChild( ruleElem );
129 
130  QDomElement nameElem = doc.createElement( QStringLiteral( "se:Name" ) );
131  nameElem.appendChild( doc.createTextNode( mLabel ) );
132  ruleElem.appendChild( nameElem );
133 
134  QDomElement descrElem = doc.createElement( QStringLiteral( "se:Description" ) );
135  QDomElement titleElem = doc.createElement( QStringLiteral( "se:Title" ) );
136  QString descrStr = QStringLiteral( "%1 is '%2'" ).arg( attrName, mValue.toString() );
137  titleElem.appendChild( doc.createTextNode( !mLabel.isEmpty() ? mLabel : descrStr ) );
138  descrElem.appendChild( titleElem );
139  ruleElem.appendChild( descrElem );
140 
141  // create the ogc:Filter for the range
142  QString filterFunc;
143  if ( mValue.isNull() || mValue.toString().isEmpty() )
144  {
145  filterFunc = QStringLiteral( "%1 = '%2' or %1 is null" )
146  .arg( attrName.replace( '\"', QLatin1String( "\"\"" ) ),
147  mValue.toString().replace( '\'', QLatin1String( "''" ) ) );
148  }
149  else
150  {
151  filterFunc = QStringLiteral( "%1 = '%2'" )
152  .arg( attrName.replace( '\"', QLatin1String( "\"\"" ) ),
153  mValue.toString().replace( '\'', QLatin1String( "''" ) ) );
154  }
155 
156  QgsSymbolLayerUtils::createFunctionElement( doc, ruleElem, filterFunc );
157 
158  // add the mix/max scale denoms if we got any from the callers
159  QgsSymbolLayerUtils::applyScaleDependency( doc, ruleElem, props );
160 
161  mSymbol->toSld( doc, ruleElem, props );
162 }
163 
165 
167  : QgsFeatureRenderer( QStringLiteral( "categorizedSymbol" ) )
168  , mAttrName( attrName )
169 {
170  //important - we need a deep copy of the categories list, not a shared copy. This is required because
171  //QgsRendererCategory::symbol() is marked const, and so retrieving the symbol via this method does not
172  //trigger a detachment and copy of mCategories BUT that same method CAN be used to modify a symbol in place
173  for ( const QgsRendererCategory &cat : categories )
174  {
175  if ( !cat.symbol() )
176  {
177  QgsDebugMsg( QStringLiteral( "invalid symbol in a category! ignoring..." ) );
178  }
179  mCategories << cat;
180  }
181 }
182 
184 
186 {
187  mSymbolHash.clear();
188 
189  for ( const QgsRendererCategory &cat : qgis::as_const( mCategories ) )
190  {
191  const QVariant val = cat.value();
192  if ( val.type() == QVariant::List )
193  {
194  const QVariantList list = val.toList();
195  for ( const QVariant &v : list )
196  {
197  mSymbolHash.insert( v.toString(), ( cat.renderState() || mCounting ) ? cat.symbol() : nullptr );
198  }
199  }
200  else
201  {
202  mSymbolHash.insert( val.toString(), ( cat.renderState() || mCounting ) ? cat.symbol() : nullptr );
203  }
204  }
205 }
206 
208 {
209  return nullptr;
210 }
211 
213 {
214  bool found = false;
215  return symbolForValue( value, found );
216 }
217 
218 QgsSymbol *QgsCategorizedSymbolRenderer::symbolForValue( const QVariant &value, bool &foundMatchingSymbol ) const
219 {
220  foundMatchingSymbol = false;
221 
222  // TODO: special case for int, double
223  QHash<QString, QgsSymbol *>::const_iterator it = mSymbolHash.constFind( value.isNull() ? QString() : value.toString() );
224  if ( it == mSymbolHash.constEnd() )
225  {
226  if ( mSymbolHash.isEmpty() )
227  {
228  QgsDebugMsg( QStringLiteral( "there are no hashed symbols!!!" ) );
229  }
230  else
231  {
232  QgsDebugMsgLevel( "attribute value not found: " + value.toString(), 3 );
233  }
234  return nullptr;
235  }
236 
237  foundMatchingSymbol = true;
238 
239  return *it;
240 }
241 
243 {
244  return originalSymbolForFeature( feature, context );
245 }
246 
247 QVariant QgsCategorizedSymbolRenderer::valueForFeature( const QgsFeature &feature, QgsRenderContext &context ) const
248 {
249  QgsAttributes attrs = feature.attributes();
250  QVariant value;
251  if ( mAttrNum == -1 )
252  {
253  Q_ASSERT( mExpression );
254 
255  value = mExpression->evaluate( &context.expressionContext() );
256  }
257  else
258  {
259  value = attrs.value( mAttrNum );
260  }
261 
262  return value;
263 }
264 
266 {
267  QVariant value = valueForFeature( feature, context );
268 
269  bool foundCategory = false;
270  // find the right symbol for the category
271  QgsSymbol *symbol = symbolForValue( value, foundCategory );
272 
273  if ( !foundCategory )
274  {
275  // if no symbol found, use default symbol
276  return symbolForValue( QVariant( "" ), foundCategory );
277  }
278 
279  return symbol;
280 }
281 
282 
284 {
285  for ( int i = 0; i < mCategories.count(); i++ )
286  {
287  if ( mCategories[i].value() == val )
288  return i;
289  }
290  return -1;
291 }
292 
294 {
295  int idx = -1;
296  for ( int i = 0; i < mCategories.count(); i++ )
297  {
298  if ( mCategories[i].label() == val )
299  {
300  if ( idx != -1 )
301  return -1;
302  else
303  idx = i;
304  }
305  }
306  return idx;
307 }
308 
309 bool QgsCategorizedSymbolRenderer::updateCategoryValue( int catIndex, const QVariant &value )
310 {
311  if ( catIndex < 0 || catIndex >= mCategories.size() )
312  return false;
313  mCategories[catIndex].setValue( value );
314  return true;
315 }
316 
318 {
319  if ( catIndex < 0 || catIndex >= mCategories.size() )
320  return false;
321  mCategories[catIndex].setSymbol( symbol );
322  return true;
323 }
324 
325 bool QgsCategorizedSymbolRenderer::updateCategoryLabel( int catIndex, const QString &label )
326 {
327  if ( catIndex < 0 || catIndex >= mCategories.size() )
328  return false;
329  mCategories[catIndex].setLabel( label );
330  return true;
331 }
332 
334 {
335  if ( catIndex < 0 || catIndex >= mCategories.size() )
336  return false;
337  mCategories[catIndex].setRenderState( render );
338  return true;
339 }
340 
342 {
343  if ( !cat.symbol() )
344  {
345  QgsDebugMsg( QStringLiteral( "invalid symbol in a category! ignoring..." ) );
346  return;
347  }
348 
349  mCategories.append( cat );
350 }
351 
353 {
354  if ( catIndex < 0 || catIndex >= mCategories.size() )
355  return false;
356 
357  mCategories.removeAt( catIndex );
358  return true;
359 }
360 
362 {
363  mCategories.clear();
364 }
365 
367 {
368  if ( from < 0 || from >= mCategories.size() || to < 0 || to >= mCategories.size() ) return;
369  mCategories.move( from, to );
370 }
371 
373 {
374  return qgsVariantLessThan( c1.value(), c2.value() );
375 }
377 {
378  return qgsVariantGreaterThan( c1.value(), c2.value() );
379 }
380 
381 void QgsCategorizedSymbolRenderer::sortByValue( Qt::SortOrder order )
382 {
383  if ( order == Qt::AscendingOrder )
384  {
385  std::sort( mCategories.begin(), mCategories.end(), valueLessThan );
386  }
387  else
388  {
389  std::sort( mCategories.begin(), mCategories.end(), valueGreaterThan );
390  }
391 }
392 
394 {
395  return QString::localeAwareCompare( c1.label(), c2.label() ) < 0;
396 }
397 
399 {
400  return !labelLessThan( c1, c2 );
401 }
402 
403 void QgsCategorizedSymbolRenderer::sortByLabel( Qt::SortOrder order )
404 {
405  if ( order == Qt::AscendingOrder )
406  {
407  std::sort( mCategories.begin(), mCategories.end(), labelLessThan );
408  }
409  else
410  {
411  std::sort( mCategories.begin(), mCategories.end(), labelGreaterThan );
412  }
413 }
414 
416 {
417  QgsFeatureRenderer::startRender( context, fields );
418 
419  mCounting = context.rendererScale() == 0.0;
420 
421  // make sure that the hash table is up to date
422  rebuildHash();
423 
424  // find out classification attribute index from name
425  mAttrNum = fields.lookupField( mAttrName );
426  if ( mAttrNum == -1 )
427  {
428  mExpression.reset( new QgsExpression( mAttrName ) );
429  mExpression->prepare( &context.expressionContext() );
430  }
431 
432  for ( const QgsRendererCategory &cat : qgis::as_const( mCategories ) )
433  {
434  cat.symbol()->startRender( context, fields );
435  }
436 }
437 
439 {
441 
442  for ( const QgsRendererCategory &cat : qgis::as_const( mCategories ) )
443  {
444  cat.symbol()->stopRender( context );
445  }
446  mExpression.reset();
447 }
448 
450 {
451  QSet<QString> attributes;
452 
453  // mAttrName can contain either attribute name or an expression.
454  // Sometimes it is not possible to distinguish between those two,
455  // e.g. "a - b" can be both a valid attribute name or expression.
456  // Since we do not have access to fields here, try both options.
457  attributes << mAttrName;
458 
459  QgsExpression testExpr( mAttrName );
460  if ( !testExpr.hasParserError() )
461  attributes.unite( testExpr.referencedColumns() );
462 
463  QgsCategoryList::const_iterator catIt = mCategories.constBegin();
464  for ( ; catIt != mCategories.constEnd(); ++catIt )
465  {
466  QgsSymbol *catSymbol = catIt->symbol();
467  if ( catSymbol )
468  {
469  attributes.unite( catSymbol->usedAttributes( context ) );
470  }
471  }
472  return attributes;
473 }
474 
476 {
477  QgsExpression testExpr( mAttrName );
478  if ( !testExpr.hasParserError() )
479  {
480  QgsExpressionContext context;
481  context.appendScopes( QgsExpressionContextUtils::globalProjectLayerScopes( nullptr ) ); // unfortunately no layer access available!
482  testExpr.prepare( &context );
483  return testExpr.needsGeometry();
484  }
485  return false;
486 }
487 
489 {
490  QString s = QStringLiteral( "CATEGORIZED: idx %1\n" ).arg( mAttrName );
491  for ( int i = 0; i < mCategories.count(); i++ )
492  s += mCategories[i].dump();
493  return s;
494 }
495 
497 {
499  if ( mSourceSymbol )
500  r->setSourceSymbol( mSourceSymbol->clone() );
501  if ( mSourceColorRamp )
502  {
503  r->setSourceColorRamp( mSourceColorRamp->clone() );
504  }
507 
508  copyRendererData( r );
509  return r;
510 }
511 
512 void QgsCategorizedSymbolRenderer::toSld( QDomDocument &doc, QDomElement &element, const QVariantMap &props ) const
513 {
514  QVariantMap newProps = props;
515  newProps[ QStringLiteral( "attribute" )] = mAttrName;
516 
517  // create a Rule for each range
518  for ( QgsCategoryList::const_iterator it = mCategories.constBegin(); it != mCategories.constEnd(); ++it )
519  {
520  it->toSld( doc, element, newProps );
521  }
522 }
523 
525 {
526  int attrNum = fields.lookupField( mAttrName );
527  bool isExpression = ( attrNum == -1 );
528 
529  bool hasDefault = false;
530  bool defaultActive = false;
531  bool allActive = true;
532  bool noneActive = true;
533 
534  //we need to build lists of both inactive and active values, as either list may be required
535  //depending on whether the default category is active or not
536  QString activeValues;
537  QString inactiveValues;
538 
539  for ( const QgsRendererCategory &cat : qgis::as_const( mCategories ) )
540  {
541  if ( cat.value() == "" || cat.value().isNull() )
542  {
543  hasDefault = true;
544  defaultActive = cat.renderState();
545  }
546 
547  noneActive = noneActive && !cat.renderState();
548  allActive = allActive && cat.renderState();
549 
550  QVariant::Type valType = isExpression ? cat.value().type() : fields.at( attrNum ).type();
551  const bool isList = cat.value().type() == QVariant::List;
552  QString value = QgsExpression::quotedValue( cat.value(), valType );
553 
554  if ( !cat.renderState() )
555  {
556  if ( cat.value() != "" )
557  {
558  if ( isList )
559  {
560  const QVariantList list = cat.value().toList();
561  for ( const QVariant &v : list )
562  {
563  if ( !inactiveValues.isEmpty() )
564  inactiveValues.append( ',' );
565 
566  inactiveValues.append( QgsExpression::quotedValue( v, isExpression ? v.type() : fields.at( attrNum ).type() ) );
567  }
568  }
569  else
570  {
571  if ( !inactiveValues.isEmpty() )
572  inactiveValues.append( ',' );
573 
574  inactiveValues.append( value );
575  }
576  }
577  }
578  else
579  {
580  if ( cat.value() != "" )
581  {
582  if ( isList )
583  {
584  const QVariantList list = cat.value().toList();
585  for ( const QVariant &v : list )
586  {
587  if ( !activeValues.isEmpty() )
588  activeValues.append( ',' );
589 
590  activeValues.append( QgsExpression::quotedValue( v, isExpression ? v.type() : fields.at( attrNum ).type() ) );
591  }
592  }
593  else
594  {
595  if ( !activeValues.isEmpty() )
596  activeValues.append( ',' );
597 
598  activeValues.append( value );
599  }
600  }
601  }
602  }
603 
604  QString attr = isExpression ? mAttrName : QStringLiteral( "\"%1\"" ).arg( mAttrName );
605 
606  if ( allActive && hasDefault )
607  {
608  return QString();
609  }
610  else if ( noneActive )
611  {
612  return QStringLiteral( "FALSE" );
613  }
614  else if ( defaultActive )
615  {
616  return QStringLiteral( "(%1) NOT IN (%2) OR (%1) IS NULL" ).arg( attr, inactiveValues );
617  }
618  else
619  {
620  return QStringLiteral( "(%1) IN (%2)" ).arg( attr, activeValues );
621  }
622 }
623 
625 {
626  Q_UNUSED( context )
627  QgsSymbolList lst;
628  lst.reserve( mCategories.count() );
629  for ( const QgsRendererCategory &cat : mCategories )
630  {
631  lst.append( cat.symbol() );
632  }
633  return lst;
634 }
635 
637 {
638  for ( const QgsRendererCategory &cat : mCategories )
639  {
640  QgsStyleSymbolEntity entity( cat.symbol() );
641  if ( !visitor->visit( QgsStyleEntityVisitorInterface::StyleLeaf( &entity, cat.value().toString(), cat.label() ) ) )
642  return false;
643  }
644 
645  if ( mSourceColorRamp )
646  {
648  if ( !visitor->visit( QgsStyleEntityVisitorInterface::StyleLeaf( &entity ) ) )
649  return false;
650  }
651 
652  return true;
653 }
654 
656 {
657  QDomElement symbolsElem = element.firstChildElement( QStringLiteral( "symbols" ) );
658  if ( symbolsElem.isNull() )
659  return nullptr;
660 
661  QDomElement catsElem = element.firstChildElement( QStringLiteral( "categories" ) );
662  if ( catsElem.isNull() )
663  return nullptr;
664 
665  QgsSymbolMap symbolMap = QgsSymbolLayerUtils::loadSymbols( symbolsElem, context );
666  QgsCategoryList cats;
667 
668  QDomElement catElem = catsElem.firstChildElement();
669  while ( !catElem.isNull() )
670  {
671  if ( catElem.tagName() == QLatin1String( "category" ) )
672  {
673  QVariant value;
674  if ( catElem.hasAttribute( QStringLiteral( "value" ) ) )
675  {
676  value = QVariant( catElem.attribute( QStringLiteral( "value" ) ) );
677  }
678  else
679  {
680  QVariantList values;
681  QDomElement valElem = catElem.firstChildElement();
682  while ( !valElem.isNull() )
683  {
684  if ( valElem.tagName() == QLatin1String( "val" ) )
685  {
686  values << QVariant( valElem.attribute( QStringLiteral( "value" ) ) );
687  }
688  valElem = valElem.nextSiblingElement();
689  }
690  if ( !values.isEmpty() )
691  value = values;
692  }
693  QString symbolName = catElem.attribute( QStringLiteral( "symbol" ) );
694  QString label = catElem.attribute( QStringLiteral( "label" ) );
695  bool render = catElem.attribute( QStringLiteral( "render" ) ) != QLatin1String( "false" );
696  if ( symbolMap.contains( symbolName ) )
697  {
698  QgsSymbol *symbol = symbolMap.take( symbolName );
699  cats.append( QgsRendererCategory( value, symbol, label, render ) );
700  }
701  }
702  catElem = catElem.nextSiblingElement();
703  }
704 
705  QString attrName = element.attribute( QStringLiteral( "attr" ) );
706 
708 
709  // delete symbols if there are any more
711 
712  // try to load source symbol (optional)
713  QDomElement sourceSymbolElem = element.firstChildElement( QStringLiteral( "source-symbol" ) );
714  if ( !sourceSymbolElem.isNull() )
715  {
716  QgsSymbolMap sourceSymbolMap = QgsSymbolLayerUtils::loadSymbols( sourceSymbolElem, context );
717  if ( sourceSymbolMap.contains( QStringLiteral( "0" ) ) )
718  {
719  r->setSourceSymbol( sourceSymbolMap.take( QStringLiteral( "0" ) ) );
720  }
721  QgsSymbolLayerUtils::clearSymbolMap( sourceSymbolMap );
722  }
723 
724  // try to load color ramp (optional)
725  QDomElement sourceColorRampElem = element.firstChildElement( QStringLiteral( "colorramp" ) );
726  if ( !sourceColorRampElem.isNull() && sourceColorRampElem.attribute( QStringLiteral( "name" ) ) == QLatin1String( "[source]" ) )
727  {
728  r->setSourceColorRamp( QgsSymbolLayerUtils::loadColorRamp( sourceColorRampElem ) );
729  }
730 
731  QDomElement rotationElem = element.firstChildElement( QStringLiteral( "rotation" ) );
732  if ( !rotationElem.isNull() && !rotationElem.attribute( QStringLiteral( "field" ) ).isEmpty() )
733  {
734  for ( const QgsRendererCategory &cat : r->mCategories )
735  {
736  convertSymbolRotation( cat.symbol(), rotationElem.attribute( QStringLiteral( "field" ) ) );
737  }
738  if ( r->mSourceSymbol )
739  {
740  convertSymbolRotation( r->mSourceSymbol.get(), rotationElem.attribute( QStringLiteral( "field" ) ) );
741  }
742  }
743 
744  QDomElement sizeScaleElem = element.firstChildElement( QStringLiteral( "sizescale" ) );
745  if ( !sizeScaleElem.isNull() && !sizeScaleElem.attribute( QStringLiteral( "field" ) ).isEmpty() )
746  {
747  for ( const QgsRendererCategory &cat : r->mCategories )
748  {
750  QgsSymbolLayerUtils::decodeScaleMethod( sizeScaleElem.attribute( QStringLiteral( "scalemethod" ) ) ),
751  sizeScaleElem.attribute( QStringLiteral( "field" ) ) );
752  }
753  if ( r->mSourceSymbol && r->mSourceSymbol->type() == QgsSymbol::Marker )
754  {
756  QgsSymbolLayerUtils::decodeScaleMethod( sizeScaleElem.attribute( QStringLiteral( "scalemethod" ) ) ),
757  sizeScaleElem.attribute( QStringLiteral( "field" ) ) );
758  }
759  }
760 
761  QDomElement ddsLegendSizeElem = element.firstChildElement( QStringLiteral( "data-defined-size-legend" ) );
762  if ( !ddsLegendSizeElem.isNull() )
763  {
764  r->mDataDefinedSizeLegend.reset( QgsDataDefinedSizeLegend::readXml( ddsLegendSizeElem, context ) );
765  }
766 
767  // TODO: symbol levels
768  return r;
769 }
770 
771 QDomElement QgsCategorizedSymbolRenderer::save( QDomDocument &doc, const QgsReadWriteContext &context )
772 {
773  // clazy:skip
774  QDomElement rendererElem = doc.createElement( RENDERER_TAG_NAME );
775  rendererElem.setAttribute( QStringLiteral( "type" ), QStringLiteral( "categorizedSymbol" ) );
776  rendererElem.setAttribute( QStringLiteral( "symbollevels" ), ( mUsingSymbolLevels ? QStringLiteral( "1" ) : QStringLiteral( "0" ) ) );
777  rendererElem.setAttribute( QStringLiteral( "forceraster" ), ( mForceRaster ? QStringLiteral( "1" ) : QStringLiteral( "0" ) ) );
778  rendererElem.setAttribute( QStringLiteral( "attr" ), mAttrName );
779 
780  // categories
781  if ( !mCategories.isEmpty() )
782  {
783  int i = 0;
785  QDomElement catsElem = doc.createElement( QStringLiteral( "categories" ) );
786  QgsCategoryList::const_iterator it = mCategories.constBegin();
787  for ( ; it != mCategories.constEnd(); ++it )
788  {
789  const QgsRendererCategory &cat = *it;
790  QString symbolName = QString::number( i );
791  symbols.insert( symbolName, cat.symbol() );
792 
793  QDomElement catElem = doc.createElement( QStringLiteral( "category" ) );
794  if ( cat.value().type() == QVariant::List )
795  {
796  const QVariantList list = cat.value().toList();
797  for ( const QVariant &v : list )
798  {
799  QDomElement valueElem = doc.createElement( QStringLiteral( "val" ) );
800  valueElem.setAttribute( "value", v.toString() );
801  catElem.appendChild( valueElem );
802  }
803  }
804  else
805  {
806  catElem.setAttribute( QStringLiteral( "value" ), cat.value().toString() );
807  }
808  catElem.setAttribute( QStringLiteral( "symbol" ), symbolName );
809  catElem.setAttribute( QStringLiteral( "label" ), cat.label() );
810  catElem.setAttribute( QStringLiteral( "render" ), cat.renderState() ? "true" : "false" );
811  catsElem.appendChild( catElem );
812  i++;
813  }
814  rendererElem.appendChild( catsElem );
815 
816  // save symbols
817  QDomElement symbolsElem = QgsSymbolLayerUtils::saveSymbols( symbols, QStringLiteral( "symbols" ), doc, context );
818  rendererElem.appendChild( symbolsElem );
819 
820  }
821 
822  // save source symbol
823  if ( mSourceSymbol )
824  {
825  QgsSymbolMap sourceSymbols;
826  sourceSymbols.insert( QStringLiteral( "0" ), mSourceSymbol.get() );
827  QDomElement sourceSymbolElem = QgsSymbolLayerUtils::saveSymbols( sourceSymbols, QStringLiteral( "source-symbol" ), doc, context );
828  rendererElem.appendChild( sourceSymbolElem );
829  }
830 
831  // save source color ramp
832  if ( mSourceColorRamp )
833  {
834  QDomElement colorRampElem = QgsSymbolLayerUtils::saveColorRamp( QStringLiteral( "[source]" ), mSourceColorRamp.get(), doc );
835  rendererElem.appendChild( colorRampElem );
836  }
837 
838  QDomElement rotationElem = doc.createElement( QStringLiteral( "rotation" ) );
839  rendererElem.appendChild( rotationElem );
840 
841  QDomElement sizeScaleElem = doc.createElement( QStringLiteral( "sizescale" ) );
842  rendererElem.appendChild( sizeScaleElem );
843 
845  mPaintEffect->saveProperties( doc, rendererElem );
846 
847  if ( !mOrderBy.isEmpty() )
848  {
849  QDomElement orderBy = doc.createElement( QStringLiteral( "orderby" ) );
850  mOrderBy.save( orderBy );
851  rendererElem.appendChild( orderBy );
852  }
853  rendererElem.setAttribute( QStringLiteral( "enableorderby" ), ( mOrderByEnabled ? QStringLiteral( "1" ) : QStringLiteral( "0" ) ) );
854 
856  {
857  QDomElement ddsLegendElem = doc.createElement( QStringLiteral( "data-defined-size-legend" ) );
858  mDataDefinedSizeLegend->writeXml( ddsLegendElem, context );
859  rendererElem.appendChild( ddsLegendElem );
860  }
861 
862  return rendererElem;
863 }
864 
865 
866 QgsLegendSymbolList QgsCategorizedSymbolRenderer::baseLegendSymbolItems() const
867 {
869  int i = 0;
870  for ( const QgsRendererCategory &cat : mCategories )
871  {
872  lst << QgsLegendSymbolItem( cat.symbol(), cat.label(), QString::number( i++ ), true );
873  }
874  return lst;
875 }
876 
878 {
880  {
881  // check that all symbols that have the same size expression
882  QgsProperty ddSize;
883  for ( const QgsRendererCategory &category : mCategories )
884  {
885  const QgsMarkerSymbol *symbol = static_cast<const QgsMarkerSymbol *>( category.symbol() );
886  if ( ddSize )
887  {
888  QgsProperty sSize( symbol->dataDefinedSize() );
889  if ( sSize != ddSize )
890  {
891  // no common size expression
892  return baseLegendSymbolItems();
893  }
894  }
895  else
896  {
897  ddSize = symbol->dataDefinedSize();
898  }
899  }
900 
901  if ( ddSize && ddSize.isActive() )
902  {
904 
906  ddSizeLegend.updateFromSymbolAndProperty( static_cast<const QgsMarkerSymbol *>( mSourceSymbol.get() ), ddSize );
907  lst += ddSizeLegend.legendSymbolList();
908 
909  lst += baseLegendSymbolItems();
910  return lst;
911  }
912  }
913 
914  return baseLegendSymbolItems();
915 }
916 
918 {
919  QString value = valueForFeature( feature, context ).toString();
920  int i = 0;
921 
922  for ( const QgsRendererCategory &cat : mCategories )
923  {
924  bool match = false;
925  if ( cat.value().type() == QVariant::List )
926  {
927  const QVariantList list = cat.value().toList();
928  for ( const QVariant &v : list )
929  {
930  if ( value == v )
931  {
932  match = true;
933  break;
934  }
935  }
936  }
937  else
938  {
939  match = value == cat.value();
940  }
941 
942  if ( match )
943  {
944  if ( cat.renderState() || mCounting )
945  return QSet< QString >() << QString::number( i );
946  else
947  return QSet< QString >();
948  }
949  i++;
950  }
951 
952  return QSet< QString >();
953 }
954 
956 {
957  return mSourceSymbol.get();
958 }
959 
961 {
962  return mSourceSymbol.get();
963 }
964 
966 {
967  mSourceSymbol.reset( sym );
968 }
969 
971 {
972  return mSourceColorRamp.get();
973 }
974 
976 {
977  return mSourceColorRamp.get();
978 }
979 
981 {
982  mSourceColorRamp.reset( ramp );
983 }
984 
986 {
987  setSourceColorRamp( ramp );
988  double num = mCategories.count() - 1;
989  double count = 0;
990 
991  QgsRandomColorRamp *randomRamp = dynamic_cast<QgsRandomColorRamp *>( ramp );
992  if ( randomRamp )
993  {
994  //ramp is a random colors ramp, so inform it of the total number of required colors
995  //this allows the ramp to pregenerate a set of visually distinctive colors
996  randomRamp->setTotalColorCount( mCategories.count() );
997  }
998 
999  for ( const QgsRendererCategory &cat : mCategories )
1000  {
1001  double value = count / num;
1002  cat.symbol()->setColor( mSourceColorRamp->color( value ) );
1003  count += 1;
1004  }
1005 }
1006 
1008 {
1009  int i = 0;
1010  for ( const QgsRendererCategory &cat : mCategories )
1011  {
1012  QgsSymbol *symbol = sym->clone();
1013  symbol->setColor( cat.symbol()->color() );
1014  updateCategorySymbol( i, symbol );
1015  ++i;
1016  }
1017  setSourceSymbol( sym->clone() );
1018 }
1019 
1021 {
1022  return true;
1023 }
1024 
1026 {
1027  bool ok;
1028  int index = key.toInt( &ok );
1029  if ( ok && index >= 0 && index < mCategories.size() )
1030  return mCategories.at( index ).renderState();
1031  else
1032  return true;
1033 }
1034 
1036 {
1037  bool ok;
1038  int index = key.toInt( &ok );
1039  if ( ok )
1040  updateCategorySymbol( index, symbol );
1041  else
1042  delete symbol;
1043 }
1044 
1045 void QgsCategorizedSymbolRenderer::checkLegendSymbolItem( const QString &key, bool state )
1046 {
1047  bool ok;
1048  int index = key.toInt( &ok );
1049  if ( ok )
1050  updateCategoryRenderState( index, state );
1051 }
1052 
1054 {
1055  std::unique_ptr< QgsCategorizedSymbolRenderer > r;
1056  if ( renderer->type() == QLatin1String( "categorizedSymbol" ) )
1057  {
1058  r.reset( static_cast<QgsCategorizedSymbolRenderer *>( renderer->clone() ) );
1059  }
1060  else if ( renderer->type() == QLatin1String( "graduatedSymbol" ) )
1061  {
1062  const QgsGraduatedSymbolRenderer *graduatedSymbolRenderer = dynamic_cast<const QgsGraduatedSymbolRenderer *>( renderer );
1063  if ( graduatedSymbolRenderer )
1064  {
1065  r.reset( new QgsCategorizedSymbolRenderer( QString(), QgsCategoryList() ) );
1066  if ( graduatedSymbolRenderer->sourceSymbol() )
1067  r->setSourceSymbol( graduatedSymbolRenderer->sourceSymbol()->clone() );
1068  if ( graduatedSymbolRenderer->sourceColorRamp() )
1069  {
1070  r->setSourceColorRamp( graduatedSymbolRenderer->sourceColorRamp()->clone() );
1071  }
1072  r->setClassAttribute( graduatedSymbolRenderer->classAttribute() );
1073  }
1074  }
1075  else if ( renderer->type() == QLatin1String( "pointDisplacement" ) || renderer->type() == QLatin1String( "pointCluster" ) )
1076  {
1077  const QgsPointDistanceRenderer *pointDistanceRenderer = dynamic_cast<const QgsPointDistanceRenderer *>( renderer );
1078  if ( pointDistanceRenderer )
1079  r.reset( convertFromRenderer( pointDistanceRenderer->embeddedRenderer() ) );
1080  }
1081  else if ( renderer->type() == QLatin1String( "invertedPolygonRenderer" ) )
1082  {
1083  const QgsInvertedPolygonRenderer *invertedPolygonRenderer = dynamic_cast<const QgsInvertedPolygonRenderer *>( renderer );
1084  if ( invertedPolygonRenderer )
1085  r.reset( convertFromRenderer( invertedPolygonRenderer->embeddedRenderer() ) );
1086  }
1087 
1088  // If not one of the specifically handled renderers, then just grab the symbol from the renderer
1089  // Could have applied this to specific renderer types (singleSymbol, graduatedSymbol)
1090 
1091  if ( !r )
1092  {
1093  r = qgis::make_unique< QgsCategorizedSymbolRenderer >( QString(), QgsCategoryList() );
1094  QgsRenderContext context;
1095  QgsSymbolList symbols = const_cast<QgsFeatureRenderer *>( renderer )->symbols( context );
1096  if ( !symbols.isEmpty() )
1097  {
1098  r->setSourceSymbol( symbols.at( 0 )->clone() );
1099  }
1100  }
1101 
1102  r->setOrderBy( renderer->orderBy() );
1103  r->setOrderByEnabled( renderer->orderByEnabled() );
1104 
1105  return r.release();
1106 }
1107 
1109 {
1110  mDataDefinedSizeLegend.reset( settings );
1111 }
1112 
1114 {
1115  return mDataDefinedSizeLegend.get();
1116 }
1117 
1118 int QgsCategorizedSymbolRenderer::matchToSymbols( QgsStyle *style, const QgsSymbol::SymbolType type, QVariantList &unmatchedCategories, QStringList &unmatchedSymbols, const bool caseSensitive, const bool useTolerantMatch )
1119 {
1120  if ( !style )
1121  return 0;
1122 
1123  int matched = 0;
1124  unmatchedSymbols = style->symbolNames();
1125  const QSet< QString > allSymbolNames = qgis::listToSet( unmatchedSymbols );
1126 
1127  const QRegularExpression tolerantMatchRe( QStringLiteral( "[^\\w\\d ]" ), QRegularExpression::UseUnicodePropertiesOption );
1128 
1129  for ( int catIdx = 0; catIdx < mCategories.count(); ++catIdx )
1130  {
1131  const QVariant value = mCategories.at( catIdx ).value();
1132  const QString val = value.toString().trimmed();
1133  std::unique_ptr< QgsSymbol > symbol( style->symbol( val ) );
1134  // case-sensitive match
1135  if ( symbol && symbol->type() == type )
1136  {
1137  matched++;
1138  unmatchedSymbols.removeAll( val );
1139  updateCategorySymbol( catIdx, symbol.release() );
1140  continue;
1141  }
1142 
1143  if ( !caseSensitive || useTolerantMatch )
1144  {
1145  QString testVal = val;
1146  if ( useTolerantMatch )
1147  testVal.replace( tolerantMatchRe, QString() );
1148 
1149  bool foundMatch = false;
1150  for ( const QString &name : allSymbolNames )
1151  {
1152  QString testName = name.trimmed();
1153  if ( useTolerantMatch )
1154  testName.replace( tolerantMatchRe, QString() );
1155 
1156  if ( testName == testVal || ( !caseSensitive && testName.trimmed().compare( testVal, Qt::CaseInsensitive ) == 0 ) )
1157  {
1158  // found a case-insensitive match
1159  std::unique_ptr< QgsSymbol > symbol( style->symbol( name ) );
1160  if ( symbol && symbol->type() == type )
1161  {
1162  matched++;
1163  unmatchedSymbols.removeAll( name );
1164  updateCategorySymbol( catIdx, symbol.release() );
1165  foundMatch = true;
1166  break;
1167  }
1168  }
1169  }
1170  if ( foundMatch )
1171  continue;
1172  }
1173 
1174  unmatchedCategories << value;
1175  }
1176 
1177  return matched;
1178 }
1179 
1180 QgsCategoryList QgsCategorizedSymbolRenderer::createCategories( const QList<QVariant> &values, const QgsSymbol *symbol, QgsVectorLayer *layer, const QString &attributeName )
1181 {
1182  QgsCategoryList cats;
1183  QVariantList vals = values;
1184  // sort the categories first
1185  QgsSymbolLayerUtils::sortVariantList( vals, Qt::AscendingOrder );
1186 
1187  if ( layer && !attributeName.isNull() )
1188  {
1189  const QgsFields fields = layer->fields();
1190  for ( const QVariant &value : vals )
1191  {
1192  QgsSymbol *newSymbol = symbol->clone();
1193  if ( !value.isNull() )
1194  {
1195  int fieldIdx = fields.lookupField( attributeName );
1196  QString categoryName = value.toString();
1197  if ( fieldIdx != -1 )
1198  {
1199  const QgsField field = fields.at( fieldIdx );
1202  categoryName = formatter->representValue( layer, fieldIdx, setup.config(), QVariant(), value );
1203  }
1204  cats.append( QgsRendererCategory( value, newSymbol, categoryName, true ) );
1205  }
1206  }
1207  }
1208 
1209  // add null (default) value
1210  QgsSymbol *newSymbol = symbol->clone();
1211  cats.append( QgsRendererCategory( QVariant(), newSymbol, QString(), true ) );
1212 
1213  return cats;
1214 }
1215 
static QgsFieldFormatterRegistry * fieldFormatterRegistry()
Gets the registry of available field formatters.
A vector of attributes.
Definition: qgsattributes.h:58
void sortByValue(Qt::SortOrder order=Qt::AscendingOrder)
Sorts the existing categories by their value.
const QgsCategoryList & categories() const
Returns a list of all categories recognized by the renderer.
QString filter(const QgsFields &fields=QgsFields()) override
If a renderer does not require all the features this method may be overridden and return an expressio...
QgsSymbol * symbolForFeature(const QgsFeature &feature, QgsRenderContext &context) const override
To be overridden.
static QgsCategorizedSymbolRenderer * convertFromRenderer(const QgsFeatureRenderer *renderer)
creates a QgsCategorizedSymbolRenderer from an existing renderer.
void updateSymbols(QgsSymbol *sym)
Update all the symbols but leave categories and colors.
bool updateCategoryRenderState(int catIndex, bool render)
Changes the render state for the category with the specified index.
void setSourceColorRamp(QgsColorRamp *ramp)
Sets the source color ramp.
void stopRender(QgsRenderContext &context) override
Must be called when a render cycle has finished, to allow the renderer to clean up.
QgsSymbol * sourceSymbol()
Returns the renderer's source symbol, which is the base symbol used for the each categories' symbol b...
std::unique_ptr< QgsColorRamp > mSourceColorRamp
Q_DECL_DEPRECATED QgsSymbol * symbolForValue(const QVariant &value) const
Returns the matching symbol corresponding to an attribute value.
std::unique_ptr< QgsSymbol > mSourceSymbol
void updateColorRamp(QgsColorRamp *ramp)
Update the color ramp used and all symbols colors.
QgsDataDefinedSizeLegend * dataDefinedSizeLegend() const
Returns configuration of appearance of legend when using data-defined size for marker symbols.
static QgsCategoryList createCategories(const QVariantList &values, const QgsSymbol *symbol, QgsVectorLayer *layer=nullptr, const QString &fieldName=QString())
Create categories for a list of values.
QHash< QString, QgsSymbol * > mSymbolHash
hashtable for faster access to symbols
bool filterNeedsGeometry() const override
Returns true if this renderer requires the geometry to apply the filter.
QSet< QString > usedAttributes(const QgsRenderContext &context) const override
Returns a list of attributes required by this renderer.
void setSourceSymbol(QgsSymbol *sym)
Sets the source symbol for the renderer, which is the base symbol used for the each categories' symbo...
void startRender(QgsRenderContext &context, const QgsFields &fields) override
Must be called when a new render cycle is started.
QgsSymbolList symbols(QgsRenderContext &context) const override
Returns list of symbols used by the renderer.
int categoryIndexForValue(const QVariant &val)
Returns the index for the category with the specified value (or -1 if not found).
static QgsFeatureRenderer * create(QDomElement &element, const QgsReadWriteContext &context)
Creates a categorized renderer from an XML element.
bool updateCategorySymbol(int catIndex, QgsSymbol *symbol)
Changes the symbol for the category with the specified index.
bool accept(QgsStyleEntityVisitorInterface *visitor) const override
Accepts the specified symbology visitor, causing it to visit all symbols associated with the renderer...
void setLegendSymbolItem(const QString &key, QgsSymbol *symbol) override
Sets the symbol to be used for a legend symbol item.
std::unique_ptr< QgsExpression > mExpression
std::unique_ptr< QgsDataDefinedSizeLegend > mDataDefinedSizeLegend
bool legendSymbolItemChecked(const QString &key) override
items of symbology items in legend is checked
bool legendSymbolItemsCheckable() const override
items of symbology items in legend should be checkable
void addCategory(const QgsRendererCategory &category)
Adds a new category to the renderer.
QgsCategorizedSymbolRenderer(const QString &attrName=QString(), const QgsCategoryList &categories=QgsCategoryList())
Constructor for QgsCategorizedSymbolRenderer.
void sortByLabel(Qt::SortOrder order=Qt::AscendingOrder)
Sorts the existing categories by their label.
QgsSymbol * originalSymbolForFeature(const QgsFeature &feature, QgsRenderContext &context) const override
Returns symbol for feature.
int mAttrNum
attribute index (derived from attribute name in startRender)
QgsLegendSymbolList legendSymbolItems() const override
Returns a list of symbology items for the legend.
void moveCategory(int from, int to)
Moves an existing category at index position from to index position to.
QDomElement save(QDomDocument &doc, const QgsReadWriteContext &context) override
store renderer info to XML element
bool deleteCategory(int catIndex)
Deletes the category with the specified index from the renderer.
Q_DECL_DEPRECATED QgsSymbol * skipRender()
void checkLegendSymbolItem(const QString &key, bool state=true) override
item in symbology was checked
QString dump() const override
Returns debug information about this renderer.
QSet< QString > legendKeysForFeature(const QgsFeature &feature, QgsRenderContext &context) const override
Returns legend keys matching a specified feature.
QgsColorRamp * sourceColorRamp()
Returns the source color ramp, from which each categories' color is derived.
bool updateCategoryValue(int catIndex, const QVariant &value)
Changes the value for the category with the specified index.
void toSld(QDomDocument &doc, QDomElement &element, const QVariantMap &props=QVariantMap()) const override
used from subclasses to create SLD Rule elements following SLD v1.1 specs
QgsCategorizedSymbolRenderer * clone() const override
Create a deep copy of this renderer.
int matchToSymbols(QgsStyle *style, QgsSymbol::SymbolType type, QVariantList &unmatchedCategories, QStringList &unmatchedSymbols, bool caseSensitive=true, bool useTolerantMatch=false)
Replaces category symbols with the symbols from a style that have a matching name and symbol type.
void deleteAllCategories()
Deletes all existing categories from the renderer.
void setDataDefinedSizeLegend(QgsDataDefinedSizeLegend *settings)
Configures appearance of legend when renderer is configured to use data-defined size for marker symbo...
bool updateCategoryLabel(int catIndex, const QString &label)
Changes the label for the category with the specified index.
~QgsCategorizedSymbolRenderer() override
int categoryIndexForLabel(const QString &val)
Returns the index of the category with the specified label (or -1 if the label was not found,...
Abstract base class for color ramps.
Definition: qgscolorramp.h:32
virtual QgsColorRamp * clone() const =0
Creates a clone of the color ramp.
Object that keeps configuration of appearance of marker symbol's data-defined size in legend.
static QgsDataDefinedSizeLegend * readXml(const QDomElement &elem, const QgsReadWriteContext &context) SIP_FACTORY
Creates instance from given element and returns it (caller takes ownership). Returns nullptr on error...
void updateFromSymbolAndProperty(const QgsMarkerSymbol *symbol, const QgsProperty &ddSize)
Updates the list of classes, source symbol and title label from given symbol and property.
QgsLegendSymbolList legendSymbolList() const
Generates legend symbol items according to the configuration.
Holder for the widget type and its configuration for a field.
QVariantMap config() const
static QList< QgsExpressionContextScope * > globalProjectLayerScopes(const QgsMapLayer *layer)
Creates a list of three scopes: global, layer's project and layer.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
void appendScopes(const QList< QgsExpressionContextScope * > &scopes)
Appends a list of scopes to the end of the context.
Class for parsing and evaluation of expressions (formerly called "search strings").
bool prepare(const QgsExpressionContext *context)
Gets the expression ready for evaluation - find out column indexes.
static QString quotedValue(const QVariant &value)
Returns a string representation of a literal value, including appropriate quotations where required.
bool hasParserError() const
Returns true if an error occurred when parsing the input expression.
QSet< QString > referencedColumns() const
Gets list of columns referenced by the expression.
bool needsGeometry() const
Returns true if the expression uses feature geometry for some computation.
virtual QgsFeatureRenderer * clone() const =0
Create a deep copy of this renderer.
static void convertSymbolSizeScale(QgsSymbol *symbol, QgsSymbol::ScaleMethod method, const QString &field)
virtual void stopRender(QgsRenderContext &context)
Must be called when a render cycle has finished, to allow the renderer to clean up.
QgsPaintEffect * mPaintEffect
Definition: qgsrenderer.h:529
QString type() const
Definition: qgsrenderer.h:141
void copyRendererData(QgsFeatureRenderer *destRenderer) const
Clones generic renderer data to another renderer.
Definition: qgsrenderer.cpp:50
bool usingSymbolLevels() const
Definition: qgsrenderer.h:283
void setUsingSymbolLevels(bool usingSymbolLevels)
Definition: qgsrenderer.h:284
bool orderByEnabled() const
Returns whether custom ordering will be applied before features are processed by this renderer.
static void convertSymbolRotation(QgsSymbol *symbol, const QString &field)
QgsFeatureRequest::OrderBy mOrderBy
Definition: qgsrenderer.h:545
virtual void startRender(QgsRenderContext &context, const QgsFields &fields)
Must be called when a new render cycle is started.
Definition: qgsrenderer.cpp:94
QgsFeatureRequest::OrderBy orderBy() const
Gets the order in which features shall be processed by this renderer.
void CORE_EXPORT save(QDomElement &elem) const
Serialize to XML.
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:56
QgsAttributes attributes
Definition: qgsfeature.h:65
QgsFieldFormatter * fieldFormatter(const QString &id) const
Gets a field formatter by its id.
A field formatter helps to handle and display values for a field.
Encapsulate a field in an attribute table or data source.
Definition: qgsfield.h:51
QVariant::Type type
Definition: qgsfield.h:58
QgsEditorWidgetSetup editorWidgetSetup() const
Gets the editor widget setup for the field.
Definition: qgsfield.cpp:559
Container of fields for a vector layer.
Definition: qgsfields.h:45
QgsField at(int i) const
Gets field at particular index (must be in range 0..N-1)
Definition: qgsfields.cpp:163
int lookupField(const QString &fieldName) const
Looks up field's index from the field name.
Definition: qgsfields.cpp:344
QgsSymbol * sourceSymbol()
Returns the renderer's source symbol, which is the base symbol used for the each classes' symbol befo...
QgsColorRamp * sourceColorRamp()
Returns the source color ramp, from which each classes' color is derived.
void setSourceSymbol(QgsSymbol *sym)
Sets the source symbol for the renderer, which is the base symbol used for the each classes' symbol b...
QgsInvertedPolygonRenderer is a polygon-only feature renderer used to display features inverted,...
The class stores information about one class/rule of a vector layer renderer in a unified way that ca...
A marker symbol type, for rendering Point and MultiPoint geometries.
Definition: qgssymbol.h:1004
QgsProperty dataDefinedSize() const
Returns data defined size for whole symbol (including all symbol layers).
Definition: qgssymbol.cpp:1869
const QgsFeatureRenderer * embeddedRenderer() const override
Returns the current embedded renderer (subrenderer) for this feature renderer.
static bool isDefaultStack(QgsPaintEffect *effect)
Tests whether a paint effect matches the default effects stack.
virtual bool saveProperties(QDomDocument &doc, QDomElement &element) const
Saves the current state of the effect to a DOM element.
An abstract base class for distance based point renderers (e.g., clusterer and displacement renderers...
const QgsFeatureRenderer * embeddedRenderer() const override
Returns the current embedded renderer (subrenderer) for this feature renderer.
A store for object properties.
Definition: qgsproperty.h:232
bool isActive() const
Returns whether the property is currently active.
Totally random color ramp.
Definition: qgscolorramp.h:455
virtual void setTotalColorCount(int colorCount)
Sets the desired total number of unique colors for the resultant ramp.
The class is used as a container of context for various read/write operations on other objects.
Contains information about the context of a rendering operation.
double rendererScale() const
Returns the renderer map scale.
QgsExpressionContext & expressionContext()
Gets the expression context.
Represents an individual category (class) from a QgsCategorizedSymbolRenderer.
void setRenderState(bool render)
Sets whether the category is currently enabled and should be rendered.
void swap(QgsRendererCategory &other)
std::unique_ptr< QgsSymbol > mSymbol
QgsSymbol * symbol() const
Returns the symbol which will be used to render this category.
void setSymbol(QgsSymbol *s)
Sets the symbol which will be used to render this category.
QgsRendererCategory()=default
Constructor for QgsRendererCategory.
bool renderState() const
Returns true if the category is currently enabled and should be rendered.
QString dump() const
Returns a string representing the categories settings, used for debugging purposes only.
void setLabel(const QString &label)
Sets the label for this category, which is used to represent the category within legends and the laye...
void toSld(QDomDocument &doc, QDomElement &element, QVariantMap props) const
Converts the category to a matching SLD rule, within the specified DOM document and element.
void setValue(const QVariant &value)
Sets the value corresponding to this category.
QVariant value() const
Returns the value corresponding to this category.
QString label() const
Returns the label for this category, which is used to represent the category within legends and the l...
QgsRendererCategory & operator=(QgsRendererCategory cat)
A color ramp entity for QgsStyle databases.
Definition: qgsstyle.h:1233
An interface for classes which can visit style entity (e.g.
virtual bool visit(const QgsStyleEntityVisitorInterface::StyleLeaf &entity)
Called when the visitor will visit a style entity.
A symbol entity for QgsStyle databases.
Definition: qgsstyle.h:1201
QgsSymbol * symbol(const QString &name)
Returns a NEW copy of symbol.
Definition: qgsstyle.cpp:270
QStringList symbolNames() const
Returns a list of names of symbols.
Definition: qgsstyle.cpp:286
static void sortVariantList(QList< QVariant > &list, Qt::SortOrder order)
Sorts the passed list in requested order.
static void applyScaleDependency(QDomDocument &doc, QDomElement &ruleElem, QVariantMap &props)
Checks if the properties contain scaleMinDenom and scaleMaxDenom, if available, they are added into t...
static bool createFunctionElement(QDomDocument &doc, QDomElement &element, const QString &function)
static QgsColorRamp * loadColorRamp(QDomElement &element)
Creates a color ramp from the settings encoded in an XML element.
static QDomElement saveColorRamp(const QString &name, QgsColorRamp *ramp, QDomDocument &doc)
Encodes a color ramp's settings to an XML element.
static void clearSymbolMap(QgsSymbolMap &symbols)
static QgsSymbol::ScaleMethod decodeScaleMethod(const QString &str)
static QgsSymbolMap loadSymbols(QDomElement &element, const QgsReadWriteContext &context)
Reads a collection of symbols from XML and returns them in a map. Caller is responsible for deleting ...
static QDomElement saveSymbols(QgsSymbolMap &symbols, const QString &tagName, QDomDocument &doc, const QgsReadWriteContext &context)
Writes a collection of symbols to XML with specified tagName for the top-level element.
Abstract base class for all rendered symbols.
Definition: qgssymbol.h:65
QSet< QString > usedAttributes(const QgsRenderContext &context) const
Returns a list of attributes required to render this feature.
Definition: qgssymbol.cpp:789
void setColor(const QColor &color)
Sets the color for the symbol.
Definition: qgssymbol.cpp:532
SymbolType
Type of the symbol.
Definition: qgssymbol.h:87
@ Marker
Marker symbol.
Definition: qgssymbol.h:88
virtual QgsSymbol * clone() const =0
Returns a deep copy of this symbol.
Represents a vector layer which manages a vector based data sets.
QgsFields fields() const FINAL
Returns the list of fields of this layer.
bool qgsVariantLessThan(const QVariant &lhs, const QVariant &rhs)
Compares two QVariant values and returns whether the first is less than the second.
Definition: qgis.cpp:121
bool qgsVariantGreaterThan(const QVariant &lhs, const QVariant &rhs)
Compares two QVariant values and returns whether the first is greater than the second.
Definition: qgis.cpp:189
bool labelGreaterThan(const QgsRendererCategory &c1, const QgsRendererCategory &c2)
bool valueLessThan(const QgsRendererCategory &c1, const QgsRendererCategory &c2)
bool valueGreaterThan(const QgsRendererCategory &c1, const QgsRendererCategory &c2)
bool labelLessThan(const QgsRendererCategory &c1, const QgsRendererCategory &c2)
QList< QgsRendererCategory > QgsCategoryList
const QgsField & field
Definition: qgsfield.h:472
QList< QgsLegendSymbolItem > QgsLegendSymbolList
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
#define RENDERER_TAG_NAME
Definition: qgsrenderer.h:51
QMap< QString, QgsSymbol * > QgsSymbolMap
Definition: qgsrenderer.h:46
QList< QgsSymbol * > QgsSymbolList
Definition: qgsrenderer.h:45
Contains information relating to the style entity currently being visited.