QGIS API Documentation  2.12.0-Lyon
qgscategorizedsymbolrendererv2.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgscategorizedsymbolrendererv2.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 
19 #include "qgssymbolv2.h"
20 #include "qgssymbollayerv2utils.h"
21 #include "qgsvectorcolorrampv2.h"
24 #include "qgspainteffect.h"
25 #include "qgspainteffectregistry.h"
26 #include "qgsscaleexpression.h"
27 #include "qgsdatadefined.h"
28 
29 #include "qgsfeature.h"
30 #include "qgsvectorlayer.h"
31 #include "qgslogger.h"
32 
33 #include <QDomDocument>
34 #include <QDomElement>
35 #include <QSettings> // for legend
36 
38  : mRender( true )
39 {
40 }
41 
42 QgsRendererCategoryV2::QgsRendererCategoryV2( const QVariant& value, QgsSymbolV2* symbol, const QString& label, bool render )
43  : mValue( value )
44  , mSymbol( symbol )
45  , mLabel( label )
46  , mRender( render )
47 {
48 }
49 
51  : mValue( cat.mValue )
52  , mSymbol( cat.mSymbol.data() ? cat.mSymbol->clone() : NULL )
53  , mLabel( cat.mLabel )
54  , mRender( cat.mRender )
55 {
56 }
57 
58 // copy+swap idion, the copy is done through the 'pass by value'
60 {
61  swap( cat );
62  return *this;
63 }
64 
66 {
67  qSwap( mValue, cat.mValue );
68  qSwap( mSymbol, cat.mSymbol );
69  qSwap( mLabel, cat.mLabel );
70 }
71 
73 {
74  return mValue;
75 }
76 
78 {
79  return mSymbol.data();
80 }
81 
83 {
84  return mLabel;
85 }
86 
88 {
89  return mRender;
90 }
91 
93 {
94  mValue = value;
95 }
96 
98 {
99  if ( mSymbol.data() != s ) mSymbol.reset( s );
100 }
101 
103 {
104  mLabel = label;
105 }
106 
108 {
109  mRender = render;
110 }
111 
113 {
114  return QString( "%1::%2::%3:%4\n" ).arg( mValue.toString(), mLabel, mSymbol->dump() ).arg( mRender );
115 }
116 
118 {
119  if ( !mSymbol.data() || props.value( "attribute", "" ).isEmpty() )
120  return;
121 
122  QString attrName = props[ "attribute" ];
123 
124  QDomElement ruleElem = doc.createElement( "se:Rule" );
125  element.appendChild( ruleElem );
126 
127  QDomElement nameElem = doc.createElement( "se:Name" );
128  nameElem.appendChild( doc.createTextNode( mLabel ) );
129  ruleElem.appendChild( nameElem );
130 
131  QDomElement descrElem = doc.createElement( "se:Description" );
132  QDomElement titleElem = doc.createElement( "se:Title" );
133  QString descrStr = QString( "%1 is '%2'" ).arg( attrName, mValue.toString() );
134  titleElem.appendChild( doc.createTextNode( !mLabel.isEmpty() ? mLabel : descrStr ) );
135  descrElem.appendChild( titleElem );
136  ruleElem.appendChild( descrElem );
137 
138  // create the ogc:Filter for the range
139  QString filterFunc = QString( "%1 = '%2'" )
140  .arg( attrName.replace( "\"", "\"\"" ),
141  mValue.toString().replace( "'", "''" ) );
142  QgsSymbolLayerV2Utils::createFunctionElement( doc, ruleElem, filterFunc );
143 
144  mSymbol->toSld( doc, ruleElem, props );
145 }
146 
148 
150  : QgsFeatureRendererV2( "categorizedSymbol" )
151  , mAttrName( attrName )
152  , mCategories( categories )
153  , mInvertedColorRamp( false )
154  , mScaleMethod( DEFAULT_SCALE_METHOD )
155  , mAttrNum( -1 )
156  , mCounting( false )
157 {
158  for ( int i = 0; i < mCategories.count(); ++i )
159  {
161  if ( cat.symbol() == NULL )
162  {
163  QgsDebugMsg( "invalid symbol in a category! ignoring..." );
164  mCategories.removeAt( i-- );
165  }
166  //mCategories.insert(cat.value().toString(), cat);
167  }
168 }
169 
171 {
172 }
173 
175 {
176  mSymbolHash.clear();
177 
178  for ( int i = 0; i < mCategories.size(); ++i )
179  {
181  mSymbolHash.insert( cat.value().toString(), ( cat.renderState() || mCounting ) ? cat.symbol() : &sSkipRender );
182  }
183 }
184 
186 {
187  // TODO: special case for int, double
189  if ( it == mSymbolHash.end() )
190  {
191  if ( mSymbolHash.size() == 0 )
192  {
193  QgsDebugMsg( "there are no hashed symbols!!!" );
194  }
195  else
196  {
197  QgsDebugMsgLevel( "attribute value not found: " + value.toString(), 3 );
198  }
199  return NULL;
200  }
201 
202  return *it;
203 }
204 
206 {
207  QgsSymbolV2* symbol = originalSymbolForFeature( feature, context );
208  if ( !symbol )
209  return 0;
210 
211  if ( !mRotation.data() && !mSizeScale.data() )
212  return symbol; // no data-defined rotation/scaling - just return the symbol
213 
214  // find out rotation, size scale
215  const double rotation = mRotation.data() ? mRotation->evaluate( &context.expressionContext() ).toDouble() : 0;
216  const double sizeScale = mSizeScale.data() ? mSizeScale->evaluate( &context.expressionContext() ).toDouble() : 1.;
217 
218  // take a temporary symbol (or create it if doesn't exist)
219  QgsSymbolV2* tempSymbol = mTempSymbols[symbol];
220 
221  // modify the temporary symbol and return it
222  if ( tempSymbol->type() == QgsSymbolV2::Marker )
223  {
224  QgsMarkerSymbolV2* markerSymbol = static_cast<QgsMarkerSymbolV2*>( tempSymbol );
225  if ( mRotation.data() ) markerSymbol->setAngle( rotation );
226  markerSymbol->setSize( sizeScale * static_cast<QgsMarkerSymbolV2*>( symbol )->size() );
227  markerSymbol->setScaleMethod( mScaleMethod );
228  }
229  else if ( tempSymbol->type() == QgsSymbolV2::Line )
230  {
231  QgsLineSymbolV2* lineSymbol = static_cast<QgsLineSymbolV2*>( tempSymbol );
232  lineSymbol->setWidth( sizeScale * static_cast<QgsLineSymbolV2*>( symbol )->width() );
233  }
234 
235  return tempSymbol;
236 }
237 
238 
240 {
241  Q_UNUSED( context );
242  QgsAttributes attrs = feature.attributes();
243  QVariant value;
244  if ( mAttrNum == -1 )
245  {
246  Q_ASSERT( mExpression.data() );
247  value = mExpression->evaluate( &context.expressionContext() );
248  }
249  else
250  {
251  value = attrs.value( mAttrNum );
252  }
253 
254  // find the right symbol for the category
255  QgsSymbolV2 *symbol = symbolForValue( value );
256  if ( symbol == &sSkipRender )
257  return 0;
258 
259  if ( !symbol )
260  {
261  // if no symbol found use default one
262  return symbolForValue( QVariant( "" ) );
263  }
264 
265  return symbol;
266 }
267 
268 
270 {
271  for ( int i = 0; i < mCategories.count(); i++ )
272  {
273  if ( mCategories[i].value() == val )
274  return i;
275  }
276  return -1;
277 }
278 
280 {
281  int idx = -1;
282  for ( int i = 0; i < mCategories.count(); i++ )
283  {
284  if ( mCategories[i].label() == val )
285  {
286  if ( idx != -1 )
287  return -1;
288  else
289  idx = i;
290  }
291  }
292  return idx;
293 }
294 
296 {
297  if ( catIndex < 0 || catIndex >= mCategories.size() )
298  return false;
299  mCategories[catIndex].setValue( value );
300  return true;
301 }
302 
304 {
305  if ( catIndex < 0 || catIndex >= mCategories.size() )
306  return false;
307  mCategories[catIndex].setSymbol( symbol );
308  return true;
309 }
310 
312 {
313  if ( catIndex < 0 || catIndex >= mCategories.size() )
314  return false;
315  mCategories[catIndex].setLabel( label );
316  return true;
317 }
318 
320 {
321  if ( catIndex < 0 || catIndex >= mCategories.size() )
322  return false;
323  mCategories[catIndex].setRenderState( render );
324  return true;
325 }
326 
328 {
329  if ( !cat.symbol() )
330  {
331  QgsDebugMsg( "invalid symbol in a category! ignoring..." );
332  return;
333  }
334 
335  mCategories.append( cat );
336 }
337 
339 {
340  if ( catIndex < 0 || catIndex >= mCategories.size() )
341  return false;
342 
343  mCategories.removeAt( catIndex );
344  return true;
345 }
346 
348 {
349  mCategories.clear();
350 }
351 
353 {
354  if ( from < 0 || from >= mCategories.size() || to < 0 || to >= mCategories.size() ) return;
355  mCategories.move( from, to );
356 }
357 
359 {
360  return qgsVariantLessThan( c1.value(), c2.value() );
361 }
363 {
364  return qgsVariantGreaterThan( c1.value(), c2.value() );
365 }
366 
368 {
369  if ( order == Qt::AscendingOrder )
370  {
372  }
373  else
374  {
376  }
377 }
378 
380 {
381  return QString::localeAwareCompare( c1.label(), c2.label() ) < 0;
382 }
383 
385 {
386  return !labelLessThan( c1, c2 );
387 }
388 
390 {
391  if ( order == Qt::AscendingOrder )
392  {
394  }
395  else
396  {
398  }
399 }
400 
402 {
403  mCounting = context.rendererScale() == 0.0;
404 
405  // make sure that the hash table is up to date
406  rebuildHash();
407 
408  // find out classification attribute index from name
409  mAttrNum = fields.fieldNameIndex( mAttrName );
410  if ( mAttrNum == -1 )
411  {
413  mExpression->prepare( &context.expressionContext() );
414  }
415 
417  for ( ; it != mCategories.end(); ++it )
418  {
419  it->symbol()->startRender( context, &fields );
420 
421  if ( mRotation.data() || mSizeScale.data() )
422  {
423  QgsSymbolV2* tempSymbol = it->symbol()->clone();
426  tempSymbol->startRender( context, &fields );
427  mTempSymbols[ it->symbol()] = tempSymbol;
428  }
429  }
430  return;
431 }
432 
434 {
436  for ( ; it != mCategories.end(); ++it )
437  it->symbol()->stopRender( context );
438 
439  // cleanup mTempSymbols
441  for ( ; it2 != mTempSymbols.end(); ++it2 )
442  {
443  it2.value()->stopRender( context );
444  delete it2.value();
445  }
447  mExpression.reset();
448 }
449 
451 {
452  QSet<QString> attributes;
453 
454  // mAttrName can contain either attribute name or an expression.
455  // Sometimes it is not possible to distinguish between those two,
456  // e.g. "a - b" can be both a valid attribute name or expression.
457  // Since we do not have access to fields here, try both options.
458  attributes << mAttrName;
459 
460  QgsExpression testExpr( mAttrName );
461  if ( !testExpr.hasParserError() )
462  attributes.unite( testExpr.referencedColumns().toSet() );
463 
464  if ( mRotation.data() ) attributes.unite( mRotation->referencedColumns().toSet() );
465  if ( mSizeScale.data() ) attributes.unite( mSizeScale->referencedColumns().toSet() );
466 
468  for ( ; catIt != mCategories.constEnd(); ++catIt )
469  {
470  QgsSymbolV2* catSymbol = catIt->symbol();
471  if ( catSymbol )
472  {
473  attributes.unite( catSymbol->usedAttributes() );
474  }
475  }
476  return attributes.toList();
477 }
478 
480 {
481  QString s = QString( "CATEGORIZED: idx %1\n" ).arg( mAttrName );
482  for ( int i = 0; i < mCategories.count(); i++ )
483  s += mCategories[i].dump();
484  return s;
485 }
486 
488 {
490  if ( mSourceSymbol.data() )
491  r->setSourceSymbol( mSourceSymbol->clone() );
492  if ( mSourceColorRamp.data() )
493  {
494  r->setSourceColorRamp( mSourceColorRamp->clone() );
496  }
499 
500  copyPaintEffect( r );
501  return r;
502 }
503 
505 {
506  QgsStringMap props;
507  props[ "attribute" ] = mAttrName;
508  if ( mRotation.data() )
509  props[ "angle" ] = mRotation->expression();
510  if ( mSizeScale.data() )
511  props[ "scale" ] = mSizeScale->expression();
512 
513  // create a Rule for each range
515  {
516  QgsStringMap catProps( props );
517  it->toSld( doc, element, catProps );
518  }
519 }
520 
522 {
523  Q_UNUSED( context );
524  QgsSymbolV2List lst;
525  lst.reserve( mCategories.count() );
526  for ( int i = 0; i < mCategories.count(); i++ )
527  lst.append( mCategories[i].symbol() );
528  return lst;
529 }
530 
532 {
533  QDomElement symbolsElem = element.firstChildElement( "symbols" );
534  if ( symbolsElem.isNull() )
535  return NULL;
536 
537  QDomElement catsElem = element.firstChildElement( "categories" );
538  if ( catsElem.isNull() )
539  return NULL;
540 
541  QgsSymbolV2Map symbolMap = QgsSymbolLayerV2Utils::loadSymbols( symbolsElem );
542  QgsCategoryList cats;
543 
544  QDomElement catElem = catsElem.firstChildElement();
545  while ( !catElem.isNull() )
546  {
547  if ( catElem.tagName() == "category" )
548  {
549  QVariant value = QVariant( catElem.attribute( "value" ) );
550  QString symbolName = catElem.attribute( "symbol" );
551  QString label = catElem.attribute( "label" );
552  bool render = catElem.attribute( "render" ) != "false";
553  if ( symbolMap.contains( symbolName ) )
554  {
555  QgsSymbolV2* symbol = symbolMap.take( symbolName );
556  cats.append( QgsRendererCategoryV2( value, symbol, label, render ) );
557  }
558  }
559  catElem = catElem.nextSiblingElement();
560  }
561 
562  QString attrName = element.attribute( "attr" );
563 
565 
566  // delete symbols if there are any more
568 
569  // try to load source symbol (optional)
570  QDomElement sourceSymbolElem = element.firstChildElement( "source-symbol" );
571  if ( !sourceSymbolElem.isNull() )
572  {
573  QgsSymbolV2Map sourceSymbolMap = QgsSymbolLayerV2Utils::loadSymbols( sourceSymbolElem );
574  if ( sourceSymbolMap.contains( "0" ) )
575  {
576  r->setSourceSymbol( sourceSymbolMap.take( "0" ) );
577  }
578  QgsSymbolLayerV2Utils::clearSymbolMap( sourceSymbolMap );
579  }
580 
581  // try to load color ramp (optional)
582  QDomElement sourceColorRampElem = element.firstChildElement( "colorramp" );
583  if ( !sourceColorRampElem.isNull() && sourceColorRampElem.attribute( "name" ) == "[source]" )
584  {
585  r->setSourceColorRamp( QgsSymbolLayerV2Utils::loadColorRamp( sourceColorRampElem ) );
586  QDomElement invertedColorRampElem = element.firstChildElement( "invertedcolorramp" );
587  if ( !invertedColorRampElem.isNull() )
588  r->setInvertedColorRamp( invertedColorRampElem.attribute( "value" ) == "1" );
589  }
590 
591  QDomElement rotationElem = element.firstChildElement( "rotation" );
592  if ( !rotationElem.isNull() && !rotationElem.attribute( "field" ).isEmpty() )
593  {
595  for ( ; it != r->mCategories.end(); ++it )
596  {
597  convertSymbolRotation( it->symbol(), rotationElem.attribute( "field" ) );
598  }
599  if ( r->mSourceSymbol.data() )
600  {
601  convertSymbolRotation( r->mSourceSymbol.data(), rotationElem.attribute( "field" ) );
602  }
603  }
604 
605  QDomElement sizeScaleElem = element.firstChildElement( "sizescale" );
606  if ( !sizeScaleElem.isNull() && !sizeScaleElem.attribute( "field" ).isEmpty() )
607  {
609  for ( ; it != r->mCategories.end(); ++it )
610  {
611  convertSymbolSizeScale( it->symbol(),
612  QgsSymbolLayerV2Utils::decodeScaleMethod( sizeScaleElem.attribute( "scalemethod" ) ),
613  sizeScaleElem.attribute( "field" ) );
614  }
615  if ( r->mSourceSymbol.data() && r->mSourceSymbol->type() == QgsSymbolV2::Marker )
616  {
618  QgsSymbolLayerV2Utils::decodeScaleMethod( sizeScaleElem.attribute( "scalemethod" ) ),
619  sizeScaleElem.attribute( "field" ) );
620  }
621  }
622 
623  // TODO: symbol levels
624  return r;
625 }
626 
628 {
629  QDomElement rendererElem = doc.createElement( RENDERER_TAG_NAME );
630  rendererElem.setAttribute( "type", "categorizedSymbol" );
631  rendererElem.setAttribute( "symbollevels", ( mUsingSymbolLevels ? "1" : "0" ) );
632  rendererElem.setAttribute( "forceraster", ( mForceRaster ? "1" : "0" ) );
633  rendererElem.setAttribute( "attr", mAttrName );
634 
635  // categories
636  int i = 0;
638  QDomElement catsElem = doc.createElement( "categories" );
640  for ( ; it != mCategories.end(); ++it )
641  {
642  const QgsRendererCategoryV2& cat = *it;
643  QString symbolName = QString::number( i );
644  symbols.insert( symbolName, cat.symbol() );
645 
646  QDomElement catElem = doc.createElement( "category" );
647  catElem.setAttribute( "value", cat.value().toString() );
648  catElem.setAttribute( "symbol", symbolName );
649  catElem.setAttribute( "label", cat.label() );
650  catElem.setAttribute( "render", cat.renderState() ? "true" : "false" );
651  catsElem.appendChild( catElem );
652  i++;
653  }
654 
655  rendererElem.appendChild( catsElem );
656 
657  // save symbols
658  QDomElement symbolsElem = QgsSymbolLayerV2Utils::saveSymbols( symbols, "symbols", doc );
659  rendererElem.appendChild( symbolsElem );
660 
661  // save source symbol
662  if ( mSourceSymbol.data() )
663  {
664  QgsSymbolV2Map sourceSymbols;
665  sourceSymbols.insert( "0", mSourceSymbol.data() );
666  QDomElement sourceSymbolElem = QgsSymbolLayerV2Utils::saveSymbols( sourceSymbols, "source-symbol", doc );
667  rendererElem.appendChild( sourceSymbolElem );
668  }
669 
670  // save source color ramp
671  if ( mSourceColorRamp.data() )
672  {
673  QDomElement colorRampElem = QgsSymbolLayerV2Utils::saveColorRamp( "[source]", mSourceColorRamp.data(), doc );
674  rendererElem.appendChild( colorRampElem );
675  QDomElement invertedElem = doc.createElement( "invertedcolorramp" );
676  invertedElem.setAttribute( "value", mInvertedColorRamp );
677  rendererElem.appendChild( invertedElem );
678  }
679 
680  QDomElement rotationElem = doc.createElement( "rotation" );
681  if ( mRotation.data() )
683  rendererElem.appendChild( rotationElem );
684 
685  QDomElement sizeScaleElem = doc.createElement( "sizescale" );
686  if ( mSizeScale.data() )
688  sizeScaleElem.setAttribute( "scalemethod", QgsSymbolLayerV2Utils::encodeScaleMethod( mScaleMethod ) );
689  rendererElem.appendChild( sizeScaleElem );
690 
692  mPaintEffect->saveProperties( doc, rendererElem );
693 
694  return rendererElem;
695 }
696 
698 {
700  int count = categories().count();
701  lst.reserve( count );
702  for ( int i = 0; i < count; i++ )
703  {
704  const QgsRendererCategoryV2& cat = categories()[i];
706  lst << qMakePair( cat.label(), pix );
707  }
708  return lst;
709 }
710 
712 {
713  Q_UNUSED( scaleDenominator );
715 
716  Q_FOREACH ( const QgsRendererCategoryV2& cat, mCategories )
717  {
718  if ( rule.isEmpty() || cat.label() == rule )
719  {
720  lst << qMakePair( cat.label(), cat.symbol() );
721  }
722  }
723  return lst;
724 }
725 
727 {
729  if ( mSourceSymbol.data() && mSourceSymbol->type() == QgsSymbolV2::Marker )
730  {
731  // check that all symbols that have the same size expression
732  QgsDataDefined ddSize;
733  Q_FOREACH ( const QgsRendererCategoryV2& category, mCategories )
734  {
735  const QgsMarkerSymbolV2 * symbol = static_cast<const QgsMarkerSymbolV2 *>( category.symbol() );
736  if ( !ddSize.hasDefaultValues() && symbol->dataDefinedSize() != ddSize )
737  {
738  // no common size expression
740  }
741  else
742  {
743  ddSize = symbol->dataDefinedSize();
744  }
745  }
746 
747  if ( !ddSize.isActive() || !ddSize.useExpression() )
748  {
750  }
751 
752  QgsScaleExpression exp( ddSize.expressionString() );
753  if ( exp.type() != QgsScaleExpression::Unknown )
754  {
755  QgsLegendSymbolItemV2 title( NULL, exp.baseExpression(), "" );
756  lst << title;
757  Q_FOREACH ( double v, QgsSymbolLayerV2Utils::prettyBreaks( exp.minValue(), exp.maxValue(), 4 ) )
758  {
760  QgsMarkerSymbolV2 * s = static_cast<QgsMarkerSymbolV2 *>( si.symbol() );
762  s->setSize( exp.size( v ) );
763  lst << si;
764  }
765  // now list the categorized symbols
767  Q_FOREACH ( const QgsLegendSymbolItemV2& item, list2 )
768  lst << item;
769  return lst;
770  }
771  }
772 
774 }
775 
777 {
778  return mSourceSymbol.data();
779 }
781 {
782  mSourceSymbol.reset( sym );
783 }
784 
786 {
787  return mSourceColorRamp.data();
788 }
789 
791 {
792  mSourceColorRamp.reset( ramp );
793 }
794 
796 {
797  setSourceColorRamp( ramp );
798  setInvertedColorRamp( inverted );
799  double num = mCategories.count() - 1;
800  double count = 0;
801 
802  QgsRandomColorsV2* randomRamp = dynamic_cast<QgsRandomColorsV2*>( ramp );
803  if ( randomRamp )
804  {
805  //ramp is a random colors ramp, so inform it of the total number of required colors
806  //this allows the ramp to pregenerate a set of visually distinctive colors
807  randomRamp->setTotalColorCount( mCategories.count() );
808  }
809 
810  Q_FOREACH ( const QgsRendererCategoryV2 &cat, mCategories )
811  {
812  double value = count / num;
813  if ( mInvertedColorRamp ) value = 1.0 - value;
814  cat.symbol()->setColor( mSourceColorRamp->color( value ) );
815  count += 1;
816  }
817 }
818 
820 {
821  if ( mSourceSymbol && mSourceSymbol->type() == QgsSymbolV2::Marker )
822  {
823  QgsMarkerSymbolV2 * s = static_cast<QgsMarkerSymbolV2 *>( mSourceSymbol.data() );
824  s->setDataDefinedAngle( QgsDataDefined( fieldOrExpression ) );
825  }
826 }
827 
829 {
830  if ( mSourceSymbol && mSourceSymbol->type() == QgsSymbolV2::Marker )
831  {
832  QgsMarkerSymbolV2 * s = static_cast<QgsMarkerSymbolV2 *>( mSourceSymbol.data() );
833  QgsDataDefined ddAngle = s->dataDefinedAngle();
834  return ddAngle.useExpression() ? ddAngle.expressionString() : ddAngle.field();
835  }
836 
837  return QString();
838 }
839 
841 {
843 }
844 
846 {
848 }
849 
851 {
852  int i = 0;
853  Q_FOREACH ( const QgsRendererCategoryV2& cat, mCategories )
854  {
855  QgsSymbolV2* symbol = sym->clone();
856  symbol->setColor( cat.symbol()->color() );
857  updateCategorySymbol( i, symbol );
858  ++i;
859  }
860 }
861 
863 {
866  for ( ; catIt != mCategories.constEnd(); ++catIt )
867  {
868  setScaleMethodToSymbol( catIt->symbol(), scaleMethod );
869  }
870 }
871 
873 {
874  return true;
875 }
876 
878 {
879  bool ok;
880  int index = key.toInt( &ok );
881  if ( ok && index >= 0 && index < mCategories.size() )
882  return mCategories[ index ].renderState();
883  else
884  return true;
885 }
886 
888 {
889  bool ok;
890  int index = key.toInt( &ok );
891  if ( ok )
892  updateCategoryRenderState( index, state );
893 }
894 
896 
898 {
899  if ( renderer->type() == "categorizedSymbol" )
900  {
901  return dynamic_cast<QgsCategorizedSymbolRendererV2*>( renderer->clone() );
902  }
903  if ( renderer->type() == "pointDisplacement" )
904  {
905  const QgsPointDisplacementRenderer* pointDisplacementRenderer = dynamic_cast<const QgsPointDisplacementRenderer*>( renderer );
906  if ( pointDisplacementRenderer )
907  return convertFromRenderer( pointDisplacementRenderer->embeddedRenderer() );
908  }
909  if ( renderer->type() == "invertedPolygonRenderer" )
910  {
911  const QgsInvertedPolygonRenderer* invertedPolygonRenderer = dynamic_cast<const QgsInvertedPolygonRenderer*>( renderer );
912  if ( invertedPolygonRenderer )
913  return convertFromRenderer( invertedPolygonRenderer->embeddedRenderer() );
914  }
915 
916  // If not one of the specifically handled renderers, then just grab the symbol from the renderer
917  // Could have applied this to specific renderer types (singleSymbol, graduatedSymbo)
918 
920  QgsRenderContext context;
921  QgsSymbolV2List symbols = const_cast<QgsFeatureRendererV2 *>( renderer )->symbols( context );
922  if ( symbols.size() > 0 )
923  {
924  r->setSourceSymbol( symbols.at( 0 )->clone() );
925  }
926 
927  return r;
928 }
static QDomElement saveSymbols(QgsSymbolV2Map &symbols, const QString &tagName, QDomDocument &doc)
Class for parsing and evaluation of expressions (formerly called "search strings").
Definition: qgsexpression.h:92
void clear()
static QgsSymbolV2Map loadSymbols(QDomElement &element)
void setValue(const QVariant &value)
void setLabel(const QString &label)
#define RENDERER_TAG_NAME
Definition: qgsrendererv2.h:48
static unsigned index
iterator insert(const Key &key, const T &value)
bool hasParserError() const
Returns true if an error occurred when parsing the input expression.
virtual void stopRender(QgsRenderContext &context) override
QStringList referencedColumns() const
Get list of columns referenced by the expression.
void setDataDefinedAngle(const QgsDataDefined &dd)
Set data defined angle for whole symbol (including all symbol layers).
int categoryIndexForValue(const QVariant &val)
return index of category with specified value (-1 if not found)
A container class for data source field mapping or expression.
virtual bool legendSymbolItemsCheckable() const override
items of symbology items in legend should be checkable
const QgsCategoryList & categories() const
static QList< double > prettyBreaks(double minimum, double maximum, int classes)
Computes a sequence of about 'classes' equally spaced round values which cover the range of values fr...
bool contains(const Key &key) const
static QgsVectorColorRampV2 * loadColorRamp(QDomElement &element)
int localeAwareCompare(const QString &other) const
QDomNode appendChild(const QDomNode &newChild)
SymbolType type() const
Definition: qgssymbolv2.h:95
QSet< QString > usedAttributes() const
virtual bool legendSymbolItemChecked(const QString &key) override
item in symbology was checked
QString field() const
Get the field which this QgsDataDefined represents.
QString attribute(const QString &name, const QString &defValue) const
#define QgsDebugMsg(str)
Definition: qgslogger.h:33
void setDataDefinedSize(const QgsDataDefined &dd)
Set data defined size for whole symbol (including all symbol layers).
void reserve(int alloc)
int categoryIndexForLabel(const QString &val)
return index of category with specified label (-1 if not found or not unique)
static QDomElement saveColorRamp(const QString &name, QgsVectorColorRampV2 *ramp, QDomDocument &doc)
int fieldNameIndex(const QString &fieldName) const
Look up field's index from name also looks up case-insensitive if there is no match otherwise...
Definition: qgsfield.cpp:382
double rendererScale() const
virtual QgsSymbolV2 * clone() const =0
Class storing parameters of a scale expression, which is a subclass of QgsExpression for expressions ...
int size() const
QgsDataDefined dataDefinedSize() const
Returns data defined size for whole symbol (including all symbol layers).
static QgsSymbolV2::ScaleMethod decodeScaleMethod(const QString &str)
const T & at(int i) const
static bool isDefaultStack(QgsPaintEffect *effect)
Tests whether a paint effect matches the default effects stack.
void removeAt(int i)
QScopedPointer< QgsSymbolV2 > mSourceSymbol
bool updateCategoryRenderState(int catIndex, bool render)
QDomElement nextSiblingElement(const QString &tagName) const
QScopedPointer< QgsExpression > mRotation
Container of fields for a vector layer.
Definition: qgsfield.h:177
Line symbol.
Definition: qgssymbolv2.h:71
virtual void setTotalColorCount(const int colorCount)
Sets the desired total number of unique colors for the resultant ramp.
QString expressionString() const
Returns the expression string of this QgsDataDefined.
void move(int from, int to)
QSet< T > toSet() const
void moveCategory(int from, int to)
Moves the category at index position from to index position to.
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:176
bool qgsVariantGreaterThan(const QVariant &lhs, const QVariant &rhs)
Definition: qgis.cpp:315
QScopedPointer< QgsSymbolV2 > mSymbol
QgsPaintEffect * mPaintEffect
void setSourceColorRamp(QgsVectorColorRampV2 *ramp)
Sets the source color ramp.
bool qgsVariantLessThan(const QVariant &lhs, const QVariant &rhs)
Definition: qgis.cpp:288
void setWidth(double width)
Marker symbol.
Definition: qgssymbolv2.h:70
int size() const
Q_DECL_DEPRECATED void setRotationField(const QString &fieldOrExpression) override
sets rotation field of renderer (if supported by the renderer)
QHash< QString, QgsSymbolV2 * > mSymbolHash
hashtable for faster access to symbols
virtual QDomElement save(QDomDocument &doc) override
store renderer info to XML element
void reset(T *other)
T value(int i) const
Q_DECL_DEPRECATED QString rotationField() const override
return rotation field name (or empty string if not set or not supported by renderer) ...
QScopedPointer< QgsExpression > mSizeScale
QString type() const
Definition: qgsrendererv2.h:82
void sortByLabel(Qt::SortOrder order=Qt::AscendingOrder)
void setColor(const QColor &color)
QgsSymbolV2 * symbolForValue(const QVariant &value)
virtual QgsFeatureRendererV2 * clone() const =0
QList< QgsRendererCategoryV2 > QgsCategoryList
QString number(int n, int base)
int count(const T &value) const
void append(const T &value)
QgsLegendSymbolListV2 legendSymbolItemsV2() const override
bool isNull() const
virtual void toSld(QDomDocument &doc, QDomElement &element) const override
used from subclasses to create SLD Rule elements following SLD v1.1 specs
QScopedPointer< QgsVectorColorRampV2 > mSourceColorRamp
virtual void checkLegendSymbolItem(const QString &key, bool state=true) override
item in symbology was checked
QgsInvertedPolygonRenderer is a polygon-only feature renderer used to display features inverted...
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:34
void startRender(QgsRenderContext &context, const QgsFields *fields=0)
QgsCategorizedSymbolRendererV2(const QString &attrName=QString(), const QgsCategoryList &categories=QgsCategoryList())
QgsAttributes attributes() const
Returns the feature's attributes.
Definition: qgsfeature.cpp:92
bool labelGreaterThan(const QgsRendererCategoryV2 &c1, const QgsRendererCategoryV2 &c2)
void setAttribute(const QString &name, const QString &value)
#define DEFAULT_SCALE_METHOD
int toInt(bool *ok, int base) const
bool updateCategoryLabel(int catIndex, const QString &label)
static QgsFeatureRendererV2 * create(QDomElement &element)
create renderer from XML element
virtual QgsLegendSymbolList legendSymbolItems(double scaleDenominator=-1, const QString &rule=QString()) override
return a list of item text / symbol
bool isEmpty() const
iterator begin()
void setAngle(double angle)
virtual void startRender(QgsRenderContext &context, const QgsFields &fields) override
Needs to be called when a new render cycle is started.
void setSize(double size)
virtual QgsFeatureRendererV2 * clone() const override
virtual Q_DECL_DEPRECATED QgsSymbolV2List symbols()
for symbol levels
virtual QgsSymbolV2 * originalSymbolForFeature(QgsFeature &feature, QgsRenderContext &context) override
Return symbol for feature.
void setScaleMethod(QgsSymbolV2::ScaleMethod scaleMethod)
bool labelLessThan(const QgsRendererCategoryV2 &c1, const QgsRendererCategoryV2 &c2)
static QgsCategorizedSymbolRendererV2 * convertFromRenderer(const QgsFeatureRendererV2 *renderer)
creates a QgsCategorizedSymbolRendererV2 from an existing renderer.
static void convertSymbolSizeScale(QgsSymbolV2 *symbol, QgsSymbolV2::ScaleMethod method, const QString &field)
QgsFeatureRendererV2 * embeddedRenderer() const
bool useExpression() const
Returns if the field or the expression part is active.
QDomText createTextNode(const QString &value)
void updateColorRamp(QgsVectorColorRampV2 *ramp, bool inverted=false)
Update the color ramp used and all symbols colors.
T * data() const
void clear()
iterator end()
const T value(const Key &key) const
iterator find(const Key &key)
QHash< QgsSymbolV2 *, QgsSymbolV2 * > mTempSymbols
temporary symbols, used for data-defined rotation and scaling
void toSld(QDomDocument &doc, QDomElement &element, QgsStringMap props) const
QgsExpressionContext & expressionContext()
Gets the expression context.
A renderer that automatically displaces points with the same position.
bool isNull() const
void setUsingSymbolLevels(bool usingSymbolLevels)
QString & replace(int position, int n, QChar after)
virtual bool saveProperties(QDomDocument &doc, QDomElement &element) const
Saves the current state of the effect to a DOM element.
bool valueLessThan(const QgsRendererCategoryV2 &c1, const QgsRendererCategoryV2 &c2)
Contains information about the context of a rendering operation.
const QgsFeatureRendererV2 * embeddedRenderer() const
virtual QList< QString > usedAttributes() override
QgsDataDefined dataDefinedAngle() const
Returns data defined angle for whole symbol (including all symbol layers).
void copyPaintEffect(QgsFeatureRendererV2 *destRenderer) const
Copies paint effect of this renderer to another renderer.
static bool createFunctionElement(QDomDocument &doc, QDomElement &element, const QString &function)
QSet< T > & unite(const QSet< T > &other)
static QgsExpression * fieldOrExpressionToExpression(const QString &fieldOrExpression)
Return a new valid expression instance for given field or expression string.
ScaleMethod
Scale method.
Definition: qgssymbolv2.h:78
virtual QgsLegendSymbolListV2 legendSymbolItemsV2() const
Return a list of symbology items for the legend.
static QString encodeScaleMethod(QgsSymbolV2::ScaleMethod scaleMethod)
bool updateCategoryValue(int catIndex, const QVariant &value)
QDomElement firstChildElement(const QString &tagName) const
bool valueGreaterThan(const QgsRendererCategoryV2 &c1, const QgsRendererCategoryV2 &c2)
static QString fieldOrExpressionFromExpression(QgsExpression *expression)
Return a field name if the whole expression is just a name of the field .
bool usingSymbolLevels() const
void setScaleMethodToSymbol(QgsSymbolV2 *symbol, int scaleMethod)
bool updateCategorySymbol(int catIndex, QgsSymbolV2 *symbol)
int mAttrNum
attribute index (derived from attribute name in startRender)
QList< T > toList() const
void setRenderHints(int hints)
Definition: qgssymbolv2.h:195
static void clearSymbolMap(QgsSymbolV2Map &symbols)
virtual QgsSymbolV2 * symbolForFeature(QgsFeature &feature, QgsRenderContext &context) override
To be overridden.
iterator insert(const Key &key, const T &value)
void swap(QgsRendererCategoryV2 &other)
QgsRendererCategoryV2 & operator=(QgsRendererCategoryV2 cat)
QString tagName() const
bool hasDefaultValues() const
Returns whether the data defined container is set to all the default values, ie, disabled, with empty expression and no assigned field.
QgsSymbolV2::ScaleMethod scaleMethod() const
iterator end()
const_iterator constEnd() const
QDomElement createElement(const QString &tagName)
const_iterator constBegin() const
static QPixmap symbolPreviewPixmap(QgsSymbolV2 *symbol, QSize size, QgsRenderContext *customContext=0)
A vector of attributes.
Definition: qgsfeature.h:109
void addCategory(const QgsRendererCategoryV2 &category)
The class stores information about one class/rule of a vector layer renderer in a unified way that ca...
QString arg(qlonglong a, int fieldWidth, int base, const QChar &fillChar) const
QString toString() const
void sortByValue(Qt::SortOrder order=Qt::AscendingOrder)
void setSizeScaleField(const QString &fieldOrExpression)
bool isActive() const
iterator begin()
T take(const Key &key)
virtual QgsLegendSymbologyList legendSymbologyItems(QSize iconSize) override
return a list of symbology items for the legend
void setScaleMethod(QgsSymbolV2::ScaleMethod scaleMethod)
QScopedPointer< QgsExpression > mExpression
const T value(const Key &key) const
static void convertSymbolRotation(QgsSymbolV2 *symbol, const QString &field)
QColor color() const
virtual QString dump() const override
for debugging