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