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