QGIS API Documentation  3.12.1-BucureČ™ti (121cc00ff0)
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  if ( val.type() == QVariant::List )
190  {
191  const QVariantList list = val.toList();
192  for ( const QVariant &v : list )
193  {
194  mSymbolHash.insert( v.toString(), ( cat.renderState() || mCounting ) ? cat.symbol() : nullptr );
195  }
196  }
197  else
198  {
199  mSymbolHash.insert( val.toString(), ( cat.renderState() || mCounting ) ? cat.symbol() : nullptr );
200  }
201  }
202 }
203 
205 {
206  return nullptr;
207 }
208 
210 {
211  bool found = false;
212  return symbolForValue( value, found );
213 }
214 
215 QgsSymbol *QgsCategorizedSymbolRenderer::symbolForValue( const QVariant &value, bool &foundMatchingSymbol ) const
216 {
217  foundMatchingSymbol = false;
218 
219  // TODO: special case for int, double
220  QHash<QString, QgsSymbol *>::const_iterator it = mSymbolHash.constFind( value.isNull() ? QString() : value.toString() );
221  if ( it == mSymbolHash.constEnd() )
222  {
223  if ( mSymbolHash.isEmpty() )
224  {
225  QgsDebugMsg( QStringLiteral( "there are no hashed symbols!!!" ) );
226  }
227  else
228  {
229  QgsDebugMsgLevel( "attribute value not found: " + value.toString(), 3 );
230  }
231  return nullptr;
232  }
233 
234  foundMatchingSymbol = true;
235 
236  return *it;
237 }
238 
240 {
241  return originalSymbolForFeature( feature, context );
242 }
243 
244 QVariant QgsCategorizedSymbolRenderer::valueForFeature( const QgsFeature &feature, QgsRenderContext &context ) const
245 {
246  QgsAttributes attrs = feature.attributes();
247  QVariant value;
248  if ( mAttrNum == -1 )
249  {
250  Q_ASSERT( mExpression );
251 
252  value = mExpression->evaluate( &context.expressionContext() );
253  }
254  else
255  {
256  value = attrs.value( mAttrNum );
257  }
258 
259  return value;
260 }
261 
263 {
264  QVariant value = valueForFeature( feature, context );
265 
266  bool foundCategory = false;
267  // find the right symbol for the category
268  QgsSymbol *symbol = symbolForValue( value, foundCategory );
269 
270  if ( !foundCategory )
271  {
272  // if no symbol found, use default symbol
273  return symbolForValue( QVariant( "" ), foundCategory );
274  }
275 
276  return symbol;
277 }
278 
279 
281 {
282  for ( int i = 0; i < mCategories.count(); i++ )
283  {
284  if ( mCategories[i].value() == val )
285  return i;
286  }
287  return -1;
288 }
289 
291 {
292  int idx = -1;
293  for ( int i = 0; i < mCategories.count(); i++ )
294  {
295  if ( mCategories[i].label() == val )
296  {
297  if ( idx != -1 )
298  return -1;
299  else
300  idx = i;
301  }
302  }
303  return idx;
304 }
305 
306 bool QgsCategorizedSymbolRenderer::updateCategoryValue( int catIndex, const QVariant &value )
307 {
308  if ( catIndex < 0 || catIndex >= mCategories.size() )
309  return false;
310  mCategories[catIndex].setValue( value );
311  return true;
312 }
313 
315 {
316  if ( catIndex < 0 || catIndex >= mCategories.size() )
317  return false;
318  mCategories[catIndex].setSymbol( symbol );
319  return true;
320 }
321 
322 bool QgsCategorizedSymbolRenderer::updateCategoryLabel( int catIndex, const QString &label )
323 {
324  if ( catIndex < 0 || catIndex >= mCategories.size() )
325  return false;
326  mCategories[catIndex].setLabel( label );
327  return true;
328 }
329 
331 {
332  if ( catIndex < 0 || catIndex >= mCategories.size() )
333  return false;
334  mCategories[catIndex].setRenderState( render );
335  return true;
336 }
337 
339 {
340  if ( !cat.symbol() )
341  {
342  QgsDebugMsg( QStringLiteral( "invalid symbol in a category! ignoring..." ) );
343  return;
344  }
345 
346  mCategories.append( cat );
347 }
348 
350 {
351  if ( catIndex < 0 || catIndex >= mCategories.size() )
352  return false;
353 
354  mCategories.removeAt( catIndex );
355  return true;
356 }
357 
359 {
360  mCategories.clear();
361 }
362 
364 {
365  if ( from < 0 || from >= mCategories.size() || to < 0 || to >= mCategories.size() ) return;
366  mCategories.move( from, to );
367 }
368 
370 {
371  return qgsVariantLessThan( c1.value(), c2.value() );
372 }
374 {
375  return qgsVariantGreaterThan( c1.value(), c2.value() );
376 }
377 
378 void QgsCategorizedSymbolRenderer::sortByValue( Qt::SortOrder order )
379 {
380  if ( order == Qt::AscendingOrder )
381  {
382  std::sort( mCategories.begin(), mCategories.end(), valueLessThan );
383  }
384  else
385  {
386  std::sort( mCategories.begin(), mCategories.end(), valueGreaterThan );
387  }
388 }
389 
391 {
392  return QString::localeAwareCompare( c1.label(), c2.label() ) < 0;
393 }
394 
396 {
397  return !labelLessThan( c1, c2 );
398 }
399 
400 void QgsCategorizedSymbolRenderer::sortByLabel( Qt::SortOrder order )
401 {
402  if ( order == Qt::AscendingOrder )
403  {
404  std::sort( mCategories.begin(), mCategories.end(), labelLessThan );
405  }
406  else
407  {
408  std::sort( mCategories.begin(), mCategories.end(), labelGreaterThan );
409  }
410 }
411 
413 {
414  QgsFeatureRenderer::startRender( context, fields );
415 
416  mCounting = context.rendererScale() == 0.0;
417 
418  // make sure that the hash table is up to date
419  rebuildHash();
420 
421  // find out classification attribute index from name
422  mAttrNum = fields.lookupField( mAttrName );
423  if ( mAttrNum == -1 )
424  {
425  mExpression.reset( new QgsExpression( mAttrName ) );
426  mExpression->prepare( &context.expressionContext() );
427  }
428 
429  for ( const QgsRendererCategory &cat : qgis::as_const( mCategories ) )
430  {
431  cat.symbol()->startRender( context, fields );
432  }
433 }
434 
436 {
438 
439  for ( const QgsRendererCategory &cat : qgis::as_const( mCategories ) )
440  {
441  cat.symbol()->stopRender( context );
442  }
443  mExpression.reset();
444 }
445 
447 {
448  QSet<QString> attributes;
449 
450  // mAttrName can contain either attribute name or an expression.
451  // Sometimes it is not possible to distinguish between those two,
452  // e.g. "a - b" can be both a valid attribute name or expression.
453  // Since we do not have access to fields here, try both options.
454  attributes << mAttrName;
455 
456  QgsExpression testExpr( mAttrName );
457  if ( !testExpr.hasParserError() )
458  attributes.unite( testExpr.referencedColumns() );
459 
460  QgsCategoryList::const_iterator catIt = mCategories.constBegin();
461  for ( ; catIt != mCategories.constEnd(); ++catIt )
462  {
463  QgsSymbol *catSymbol = catIt->symbol();
464  if ( catSymbol )
465  {
466  attributes.unite( catSymbol->usedAttributes( context ) );
467  }
468  }
469  return attributes;
470 }
471 
473 {
474  QgsExpression testExpr( mAttrName );
475  if ( !testExpr.hasParserError() )
476  {
477  QgsExpressionContext context;
478  context.appendScopes( QgsExpressionContextUtils::globalProjectLayerScopes( nullptr ) ); // unfortunately no layer access available!
479  testExpr.prepare( &context );
480  return testExpr.needsGeometry();
481  }
482  return false;
483 }
484 
486 {
487  QString s = QStringLiteral( "CATEGORIZED: idx %1\n" ).arg( mAttrName );
488  for ( int i = 0; i < mCategories.count(); i++ )
489  s += mCategories[i].dump();
490  return s;
491 }
492 
494 {
496  if ( mSourceSymbol )
497  r->setSourceSymbol( mSourceSymbol->clone() );
498  if ( mSourceColorRamp )
499  {
500  r->setSourceColorRamp( mSourceColorRamp->clone() );
501  }
504 
505  copyRendererData( r );
506  return r;
507 }
508 
509 void QgsCategorizedSymbolRenderer::toSld( QDomDocument &doc, QDomElement &element, const QgsStringMap &props ) const
510 {
511  QgsStringMap newProps = props;
512  newProps[ QStringLiteral( "attribute" )] = mAttrName;
513 
514  // create a Rule for each range
515  for ( QgsCategoryList::const_iterator it = mCategories.constBegin(); it != mCategories.constEnd(); ++it )
516  {
517  it->toSld( doc, element, newProps );
518  }
519 }
520 
522 {
523  int attrNum = fields.lookupField( mAttrName );
524  bool isExpression = ( attrNum == -1 );
525 
526  bool hasDefault = false;
527  bool defaultActive = false;
528  bool allActive = true;
529  bool noneActive = true;
530 
531  //we need to build lists of both inactive and active values, as either list may be required
532  //depending on whether the default category is active or not
533  QString activeValues;
534  QString inactiveValues;
535 
536  for ( const QgsRendererCategory &cat : qgis::as_const( mCategories ) )
537  {
538  if ( cat.value() == "" || cat.value().isNull() )
539  {
540  hasDefault = true;
541  defaultActive = cat.renderState();
542  }
543 
544  noneActive = noneActive && !cat.renderState();
545  allActive = allActive && cat.renderState();
546 
547  QVariant::Type valType = isExpression ? cat.value().type() : fields.at( attrNum ).type();
548  const bool isList = cat.value().type() == QVariant::List;
549  QString value = QgsExpression::quotedValue( cat.value(), valType );
550 
551  if ( !cat.renderState() )
552  {
553  if ( cat.value() != "" )
554  {
555  if ( isList )
556  {
557  const QVariantList list = cat.value().toList();
558  for ( const QVariant &v : list )
559  {
560  if ( !inactiveValues.isEmpty() )
561  inactiveValues.append( ',' );
562 
563  inactiveValues.append( QgsExpression::quotedValue( v, isExpression ? v.type() : fields.at( attrNum ).type() ) );
564  }
565  }
566  else
567  {
568  if ( !inactiveValues.isEmpty() )
569  inactiveValues.append( ',' );
570 
571  inactiveValues.append( value );
572  }
573  }
574  }
575  else
576  {
577  if ( cat.value() != "" )
578  {
579  if ( isList )
580  {
581  const QVariantList list = cat.value().toList();
582  for ( const QVariant &v : list )
583  {
584  if ( !activeValues.isEmpty() )
585  activeValues.append( ',' );
586 
587  activeValues.append( QgsExpression::quotedValue( v, isExpression ? v.type() : fields.at( attrNum ).type() ) );
588  }
589  }
590  else
591  {
592  if ( !activeValues.isEmpty() )
593  activeValues.append( ',' );
594 
595  activeValues.append( value );
596  }
597  }
598  }
599  }
600 
601  QString attr = isExpression ? mAttrName : QStringLiteral( "\"%1\"" ).arg( mAttrName );
602 
603  if ( allActive && hasDefault )
604  {
605  return QString();
606  }
607  else if ( noneActive )
608  {
609  return QStringLiteral( "FALSE" );
610  }
611  else if ( defaultActive )
612  {
613  return QStringLiteral( "(%1) NOT IN (%2) OR (%1) IS NULL" ).arg( attr, inactiveValues );
614  }
615  else
616  {
617  return QStringLiteral( "(%1) IN (%2)" ).arg( attr, activeValues );
618  }
619 }
620 
622 {
623  Q_UNUSED( context )
624  QgsSymbolList lst;
625  lst.reserve( mCategories.count() );
626  for ( const QgsRendererCategory &cat : mCategories )
627  {
628  lst.append( cat.symbol() );
629  }
630  return lst;
631 }
632 
634 {
635  for ( const QgsRendererCategory &cat : mCategories )
636  {
637  QgsStyleSymbolEntity entity( cat.symbol() );
638  if ( !visitor->visit( QgsStyleEntityVisitorInterface::StyleLeaf( &entity, cat.value().toString(), cat.label() ) ) )
639  return false;
640  }
641 
642  if ( mSourceColorRamp )
643  {
645  if ( !visitor->visit( QgsStyleEntityVisitorInterface::StyleLeaf( &entity ) ) )
646  return false;
647  }
648 
649  return true;
650 }
651 
653 {
654  QDomElement symbolsElem = element.firstChildElement( QStringLiteral( "symbols" ) );
655  if ( symbolsElem.isNull() )
656  return nullptr;
657 
658  QDomElement catsElem = element.firstChildElement( QStringLiteral( "categories" ) );
659  if ( catsElem.isNull() )
660  return nullptr;
661 
662  QgsSymbolMap symbolMap = QgsSymbolLayerUtils::loadSymbols( symbolsElem, context );
663  QgsCategoryList cats;
664 
665  QDomElement catElem = catsElem.firstChildElement();
666  while ( !catElem.isNull() )
667  {
668  if ( catElem.tagName() == QLatin1String( "category" ) )
669  {
670  QVariant value;
671  if ( catElem.hasAttribute( QStringLiteral( "value" ) ) )
672  {
673  value = QVariant( catElem.attribute( QStringLiteral( "value" ) ) );
674  }
675  else
676  {
677  QVariantList values;
678  QDomElement valElem = catElem.firstChildElement();
679  while ( !valElem.isNull() )
680  {
681  if ( valElem.tagName() == QLatin1String( "val" ) )
682  {
683  values << QVariant( valElem.attribute( QStringLiteral( "value" ) ) );
684  }
685  valElem = valElem.nextSiblingElement();
686  }
687  if ( !values.isEmpty() )
688  value = values;
689  }
690  QString symbolName = catElem.attribute( QStringLiteral( "symbol" ) );
691  QString label = catElem.attribute( QStringLiteral( "label" ) );
692  bool render = catElem.attribute( QStringLiteral( "render" ) ) != QLatin1String( "false" );
693  if ( symbolMap.contains( symbolName ) )
694  {
695  QgsSymbol *symbol = symbolMap.take( symbolName );
696  cats.append( QgsRendererCategory( value, symbol, label, render ) );
697  }
698  }
699  catElem = catElem.nextSiblingElement();
700  }
701 
702  QString attrName = element.attribute( QStringLiteral( "attr" ) );
703 
705 
706  // delete symbols if there are any more
708 
709  // try to load source symbol (optional)
710  QDomElement sourceSymbolElem = element.firstChildElement( QStringLiteral( "source-symbol" ) );
711  if ( !sourceSymbolElem.isNull() )
712  {
713  QgsSymbolMap sourceSymbolMap = QgsSymbolLayerUtils::loadSymbols( sourceSymbolElem, context );
714  if ( sourceSymbolMap.contains( QStringLiteral( "0" ) ) )
715  {
716  r->setSourceSymbol( sourceSymbolMap.take( QStringLiteral( "0" ) ) );
717  }
718  QgsSymbolLayerUtils::clearSymbolMap( sourceSymbolMap );
719  }
720 
721  // try to load color ramp (optional)
722  QDomElement sourceColorRampElem = element.firstChildElement( QStringLiteral( "colorramp" ) );
723  if ( !sourceColorRampElem.isNull() && sourceColorRampElem.attribute( QStringLiteral( "name" ) ) == QLatin1String( "[source]" ) )
724  {
725  r->setSourceColorRamp( QgsSymbolLayerUtils::loadColorRamp( sourceColorRampElem ) );
726  }
727 
728  QDomElement rotationElem = element.firstChildElement( QStringLiteral( "rotation" ) );
729  if ( !rotationElem.isNull() && !rotationElem.attribute( QStringLiteral( "field" ) ).isEmpty() )
730  {
731  for ( const QgsRendererCategory &cat : r->mCategories )
732  {
733  convertSymbolRotation( cat.symbol(), rotationElem.attribute( QStringLiteral( "field" ) ) );
734  }
735  if ( r->mSourceSymbol )
736  {
737  convertSymbolRotation( r->mSourceSymbol.get(), rotationElem.attribute( QStringLiteral( "field" ) ) );
738  }
739  }
740 
741  QDomElement sizeScaleElem = element.firstChildElement( QStringLiteral( "sizescale" ) );
742  if ( !sizeScaleElem.isNull() && !sizeScaleElem.attribute( QStringLiteral( "field" ) ).isEmpty() )
743  {
744  for ( const QgsRendererCategory &cat : r->mCategories )
745  {
747  QgsSymbolLayerUtils::decodeScaleMethod( sizeScaleElem.attribute( QStringLiteral( "scalemethod" ) ) ),
748  sizeScaleElem.attribute( QStringLiteral( "field" ) ) );
749  }
750  if ( r->mSourceSymbol && r->mSourceSymbol->type() == QgsSymbol::Marker )
751  {
753  QgsSymbolLayerUtils::decodeScaleMethod( sizeScaleElem.attribute( QStringLiteral( "scalemethod" ) ) ),
754  sizeScaleElem.attribute( QStringLiteral( "field" ) ) );
755  }
756  }
757 
758  QDomElement ddsLegendSizeElem = element.firstChildElement( QStringLiteral( "data-defined-size-legend" ) );
759  if ( !ddsLegendSizeElem.isNull() )
760  {
761  r->mDataDefinedSizeLegend.reset( QgsDataDefinedSizeLegend::readXml( ddsLegendSizeElem, context ) );
762  }
763 
764  // TODO: symbol levels
765  return r;
766 }
767 
768 QDomElement QgsCategorizedSymbolRenderer::save( QDomDocument &doc, const QgsReadWriteContext &context )
769 {
770  // clazy:skip
771  QDomElement rendererElem = doc.createElement( RENDERER_TAG_NAME );
772  rendererElem.setAttribute( QStringLiteral( "type" ), QStringLiteral( "categorizedSymbol" ) );
773  rendererElem.setAttribute( QStringLiteral( "symbollevels" ), ( mUsingSymbolLevels ? QStringLiteral( "1" ) : QStringLiteral( "0" ) ) );
774  rendererElem.setAttribute( QStringLiteral( "forceraster" ), ( mForceRaster ? QStringLiteral( "1" ) : QStringLiteral( "0" ) ) );
775  rendererElem.setAttribute( QStringLiteral( "attr" ), mAttrName );
776 
777  // categories
778  if ( !mCategories.isEmpty() )
779  {
780  int i = 0;
782  QDomElement catsElem = doc.createElement( QStringLiteral( "categories" ) );
783  QgsCategoryList::const_iterator it = mCategories.constBegin();
784  for ( ; it != mCategories.constEnd(); ++it )
785  {
786  const QgsRendererCategory &cat = *it;
787  QString symbolName = QString::number( i );
788  symbols.insert( symbolName, cat.symbol() );
789 
790  QDomElement catElem = doc.createElement( QStringLiteral( "category" ) );
791  if ( cat.value().type() == QVariant::List )
792  {
793  const QVariantList list = cat.value().toList();
794  for ( const QVariant &v : list )
795  {
796  QDomElement valueElem = doc.createElement( QStringLiteral( "val" ) );
797  valueElem.setAttribute( "value", v.toString() );
798  catElem.appendChild( valueElem );
799  }
800  }
801  else
802  {
803  catElem.setAttribute( QStringLiteral( "value" ), cat.value().toString() );
804  }
805  catElem.setAttribute( QStringLiteral( "symbol" ), symbolName );
806  catElem.setAttribute( QStringLiteral( "label" ), cat.label() );
807  catElem.setAttribute( QStringLiteral( "render" ), cat.renderState() ? "true" : "false" );
808  catsElem.appendChild( catElem );
809  i++;
810  }
811  rendererElem.appendChild( catsElem );
812 
813  // save symbols
814  QDomElement symbolsElem = QgsSymbolLayerUtils::saveSymbols( symbols, QStringLiteral( "symbols" ), doc, context );
815  rendererElem.appendChild( symbolsElem );
816 
817  }
818 
819  // save source symbol
820  if ( mSourceSymbol )
821  {
822  QgsSymbolMap sourceSymbols;
823  sourceSymbols.insert( QStringLiteral( "0" ), mSourceSymbol.get() );
824  QDomElement sourceSymbolElem = QgsSymbolLayerUtils::saveSymbols( sourceSymbols, QStringLiteral( "source-symbol" ), doc, context );
825  rendererElem.appendChild( sourceSymbolElem );
826  }
827 
828  // save source color ramp
829  if ( mSourceColorRamp )
830  {
831  QDomElement colorRampElem = QgsSymbolLayerUtils::saveColorRamp( QStringLiteral( "[source]" ), mSourceColorRamp.get(), doc );
832  rendererElem.appendChild( colorRampElem );
833  }
834 
835  QDomElement rotationElem = doc.createElement( QStringLiteral( "rotation" ) );
836  rendererElem.appendChild( rotationElem );
837 
838  QDomElement sizeScaleElem = doc.createElement( QStringLiteral( "sizescale" ) );
839  rendererElem.appendChild( sizeScaleElem );
840 
842  mPaintEffect->saveProperties( doc, rendererElem );
843 
844  if ( !mOrderBy.isEmpty() )
845  {
846  QDomElement orderBy = doc.createElement( QStringLiteral( "orderby" ) );
847  mOrderBy.save( orderBy );
848  rendererElem.appendChild( orderBy );
849  }
850  rendererElem.setAttribute( QStringLiteral( "enableorderby" ), ( mOrderByEnabled ? QStringLiteral( "1" ) : QStringLiteral( "0" ) ) );
851 
853  {
854  QDomElement ddsLegendElem = doc.createElement( QStringLiteral( "data-defined-size-legend" ) );
855  mDataDefinedSizeLegend->writeXml( ddsLegendElem, context );
856  rendererElem.appendChild( ddsLegendElem );
857  }
858 
859  return rendererElem;
860 }
861 
862 
863 QgsLegendSymbolList QgsCategorizedSymbolRenderer::baseLegendSymbolItems() const
864 {
866  int i = 0;
867  for ( const QgsRendererCategory &cat : mCategories )
868  {
869  lst << QgsLegendSymbolItem( cat.symbol(), cat.label(), QString::number( i++ ), true );
870  }
871  return lst;
872 }
873 
875 {
877  {
878  // check that all symbols that have the same size expression
879  QgsProperty ddSize;
880  for ( const QgsRendererCategory &category : mCategories )
881  {
882  const QgsMarkerSymbol *symbol = static_cast<const QgsMarkerSymbol *>( category.symbol() );
883  if ( ddSize )
884  {
885  QgsProperty sSize( symbol->dataDefinedSize() );
886  if ( sSize != ddSize )
887  {
888  // no common size expression
889  return baseLegendSymbolItems();
890  }
891  }
892  else
893  {
894  ddSize = symbol->dataDefinedSize();
895  }
896  }
897 
898  if ( ddSize && ddSize.isActive() )
899  {
901 
903  ddSizeLegend.updateFromSymbolAndProperty( static_cast<const QgsMarkerSymbol *>( mSourceSymbol.get() ), ddSize );
904  lst += ddSizeLegend.legendSymbolList();
905 
906  lst += baseLegendSymbolItems();
907  return lst;
908  }
909  }
910 
911  return baseLegendSymbolItems();
912 }
913 
915 {
916  QString value = valueForFeature( feature, context ).toString();
917  int i = 0;
918 
919  for ( const QgsRendererCategory &cat : mCategories )
920  {
921  bool match = false;
922  if ( cat.value().type() == QVariant::List )
923  {
924  const QVariantList list = cat.value().toList();
925  for ( const QVariant &v : list )
926  {
927  if ( value == v )
928  {
929  match = true;
930  break;
931  }
932  }
933  }
934  else
935  {
936  match = value == cat.value();
937  }
938 
939  if ( match )
940  {
941  if ( cat.renderState() || mCounting )
942  return QSet< QString >() << QString::number( i );
943  else
944  return QSet< QString >();
945  }
946  i++;
947  }
948 
949  return QSet< QString >();
950 }
951 
953 {
954  return mSourceSymbol.get();
955 }
956 
958 {
959  return mSourceSymbol.get();
960 }
961 
963 {
964  mSourceSymbol.reset( sym );
965 }
966 
968 {
969  return mSourceColorRamp.get();
970 }
971 
973 {
974  return mSourceColorRamp.get();
975 }
976 
978 {
979  mSourceColorRamp.reset( ramp );
980 }
981 
983 {
984  setSourceColorRamp( ramp );
985  double num = mCategories.count() - 1;
986  double count = 0;
987 
988  QgsRandomColorRamp *randomRamp = dynamic_cast<QgsRandomColorRamp *>( ramp );
989  if ( randomRamp )
990  {
991  //ramp is a random colors ramp, so inform it of the total number of required colors
992  //this allows the ramp to pregenerate a set of visually distinctive colors
993  randomRamp->setTotalColorCount( mCategories.count() );
994  }
995 
996  for ( const QgsRendererCategory &cat : mCategories )
997  {
998  double value = count / num;
999  cat.symbol()->setColor( mSourceColorRamp->color( value ) );
1000  count += 1;
1001  }
1002 }
1003 
1005 {
1006  int i = 0;
1007  for ( const QgsRendererCategory &cat : mCategories )
1008  {
1009  QgsSymbol *symbol = sym->clone();
1010  symbol->setColor( cat.symbol()->color() );
1011  updateCategorySymbol( i, symbol );
1012  ++i;
1013  }
1014  setSourceSymbol( sym->clone() );
1015 }
1016 
1018 {
1019  return true;
1020 }
1021 
1023 {
1024  bool ok;
1025  int index = key.toInt( &ok );
1026  if ( ok && index >= 0 && index < mCategories.size() )
1027  return mCategories.at( index ).renderState();
1028  else
1029  return true;
1030 }
1031 
1033 {
1034  bool ok;
1035  int index = key.toInt( &ok );
1036  if ( ok )
1037  updateCategorySymbol( index, symbol );
1038  else
1039  delete symbol;
1040 }
1041 
1042 void QgsCategorizedSymbolRenderer::checkLegendSymbolItem( const QString &key, bool state )
1043 {
1044  bool ok;
1045  int index = key.toInt( &ok );
1046  if ( ok )
1047  updateCategoryRenderState( index, state );
1048 }
1049 
1051 {
1052  std::unique_ptr< QgsCategorizedSymbolRenderer > r;
1053  if ( renderer->type() == QLatin1String( "categorizedSymbol" ) )
1054  {
1055  r.reset( static_cast<QgsCategorizedSymbolRenderer *>( renderer->clone() ) );
1056  }
1057  else if ( renderer->type() == QLatin1String( "graduatedSymbol" ) )
1058  {
1059  const QgsGraduatedSymbolRenderer *graduatedSymbolRenderer = dynamic_cast<const QgsGraduatedSymbolRenderer *>( renderer );
1060  if ( graduatedSymbolRenderer )
1061  {
1062  r.reset( new QgsCategorizedSymbolRenderer( QString(), QgsCategoryList() ) );
1063  if ( graduatedSymbolRenderer->sourceSymbol() )
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:544
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:62
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:51
void setUsingSymbolLevels(bool usingSymbolLevels)
Definition: qgsrenderer.h:284
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:473
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:528
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:189
void swap(QgsRendererCategory &other)
QMap< QString, QString > QgsStringMap
Definition: qgis.h:694
A marker symbol type, for rendering Point and MultiPoint geometries.
Definition: qgssymbol.h:895
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 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:84
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:45
QString type() const
Definition: qgsrenderer.h:141
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:49
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:1601
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:86
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:718
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:283
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:46
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:57
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:481
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.