QGIS API Documentation  2.11.0-Master
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 "qgsscaleexpression.h"
26 #include "qgsdatadefined.h"
27 
28 #include "qgsfeature.h"
29 #include "qgsvectorlayer.h"
30 #include "qgslogger.h"
31 
32 #include <QDomDocument>
33 #include <QDomElement>
34 #include <QSettings> // for legend
35 
37  : mRender( true )
38 {
39 }
40 
42  : mValue( value )
43  , mSymbol( symbol )
44  , mLabel( label )
45  , mRender( render )
46 {
47 }
48 
50  : mValue( cat.mValue )
51  , mSymbol( cat.mSymbol.data() ? cat.mSymbol->clone() : NULL )
52  , mLabel( cat.mLabel )
53  , mRender( cat.mRender )
54 {
55 }
56 
57 // copy+swap idion, the copy is done through the 'pass by value'
59 {
60  swap( cat );
61  return *this;
62 }
63 
65 {
66  qSwap( mValue, cat.mValue );
67  qSwap( mSymbol, cat.mSymbol );
68  qSwap( mLabel, cat.mLabel );
69 }
70 
72 {
73  return mValue;
74 }
75 
77 {
78  return mSymbol.data();
79 }
80 
82 {
83  return mLabel;
84 }
85 
87 {
88  return mRender;
89 }
90 
92 {
93  mValue = value;
94 }
95 
97 {
98  if ( mSymbol.data() != s ) mSymbol.reset( s );
99 }
100 
102 {
103  mLabel = label;
104 }
105 
107 {
108  mRender = render;
109 }
110 
112 {
113  return QString( "%1::%2::%3:%4\n" ).arg( mValue.toString() ).arg( mLabel ).arg( mSymbol->dump() ).arg( mRender );
114 }
115 
117 {
118  if ( !mSymbol.data() || props.value( "attribute", "" ).isEmpty() )
119  return;
120 
121  QString attrName = props[ "attribute" ];
122 
123  QDomElement ruleElem = doc.createElement( "se:Rule" );
124  element.appendChild( ruleElem );
125 
126  QDomElement nameElem = doc.createElement( "se:Name" );
127  nameElem.appendChild( doc.createTextNode( mLabel ) );
128  ruleElem.appendChild( nameElem );
129 
130  QDomElement descrElem = doc.createElement( "se:Description" );
131  QDomElement titleElem = doc.createElement( "se:Title" );
132  QString descrStr = QString( "%1 is '%2'" ).arg( attrName ).arg( mValue.toString() );
133  titleElem.appendChild( doc.createTextNode( !mLabel.isEmpty() ? mLabel : descrStr ) );
134  descrElem.appendChild( titleElem );
135  ruleElem.appendChild( descrElem );
136 
137  // create the ogc:Filter for the range
138  QString filterFunc = QString( "%1 = '%2'" )
139  .arg( attrName.replace( "\"", "\"\"" ) )
140  .arg( mValue.toString().replace( "'", "''" ) );
141  QgsSymbolLayerV2Utils::createFunctionElement( doc, ruleElem, filterFunc );
142 
143  mSymbol->toSld( doc, ruleElem, props );
144 }
145 
147 
149  : QgsFeatureRendererV2( "categorizedSymbol" )
150  , mAttrName( attrName )
151  , mCategories( categories )
152  , mInvertedColorRamp( false )
153  , mScaleMethod( DEFAULT_SCALE_METHOD )
154  , mAttrNum( -1 )
155  , mCounting( false )
156 {
157  for ( int i = 0; i < mCategories.count(); ++i )
158  {
160  if ( cat.symbol() == NULL )
161  {
162  QgsDebugMsg( "invalid symbol in a category! ignoring..." );
163  mCategories.removeAt( i-- );
164  }
165  //mCategories.insert(cat.value().toString(), cat);
166  }
167 }
168 
170 {
171 }
172 
174 {
175  mSymbolHash.clear();
176 
177  for ( int i = 0; i < mCategories.size(); ++i )
178  {
180  mSymbolHash.insert( cat.value().toString(), ( cat.renderState() || mCounting ) ? cat.symbol() : &sSkipRender );
181  }
182 }
183 
185 {
186  // TODO: special case for int, double
188  if ( it == mSymbolHash.end() )
189  {
190  if ( mSymbolHash.size() == 0 )
191  {
192  QgsDebugMsg( "there are no hashed symbols!!!" );
193  }
194  else
195  {
196  QgsDebugMsgLevel( "attribute value not found: " + value.toString(), 3 );
197  }
198  return NULL;
199  }
200 
201  return *it;
202 }
203 
205 {
206  QgsSymbolV2* symbol = originalSymbolForFeature( feature, context );
207  if ( !symbol )
208  return 0;
209 
210  if ( !mRotation.data() && !mSizeScale.data() )
211  return symbol; // no data-defined rotation/scaling - just return the symbol
212 
213  // find out rotation, size scale
214  const double rotation = mRotation.data() ? mRotation->evaluate( &context.expressionContext() ).toDouble() : 0;
215  const double sizeScale = mSizeScale.data() ? mSizeScale->evaluate( &context.expressionContext() ).toDouble() : 1.;
216 
217  // take a temporary symbol (or create it if doesn't exist)
218  QgsSymbolV2* tempSymbol = mTempSymbols[symbol];
219 
220  // modify the temporary symbol and return it
221  if ( tempSymbol->type() == QgsSymbolV2::Marker )
222  {
223  QgsMarkerSymbolV2* markerSymbol = static_cast<QgsMarkerSymbolV2*>( tempSymbol );
224  if ( mRotation.data() ) markerSymbol->setAngle( rotation );
225  markerSymbol->setSize( sizeScale * static_cast<QgsMarkerSymbolV2*>( symbol )->size() );
226  markerSymbol->setScaleMethod( mScaleMethod );
227  }
228  else if ( tempSymbol->type() == QgsSymbolV2::Line )
229  {
230  QgsLineSymbolV2* lineSymbol = static_cast<QgsLineSymbolV2*>( tempSymbol );
231  lineSymbol->setWidth( sizeScale * static_cast<QgsLineSymbolV2*>( symbol )->width() );
232  }
233 
234  return tempSymbol;
235 }
236 
237 
239 {
240  Q_UNUSED( context );
241  QgsAttributes attrs = feature.attributes();
242  QVariant value;
243  if ( mAttrNum == -1 )
244  {
245  Q_ASSERT( mExpression.data() );
246  value = mExpression->evaluate( &context.expressionContext() );
247  }
248  else
249  {
250  value = attrs.value( mAttrNum );
251  }
252 
253  // find the right symbol for the category
254  QgsSymbolV2 *symbol = symbolForValue( value );
255  if ( symbol == &sSkipRender )
256  return 0;
257 
258  if ( !symbol )
259  {
260  // if no symbol found use default one
261  return symbolForValue( QVariant( "" ) );
262  }
263 
264  return symbol;
265 }
266 
267 
269 {
270  for ( int i = 0; i < mCategories.count(); i++ )
271  {
272  if ( mCategories[i].value() == val )
273  return i;
274  }
275  return -1;
276 }
277 
279 {
280  int idx = -1;
281  for ( int i = 0; i < mCategories.count(); i++ )
282  {
283  if ( mCategories[i].label() == val )
284  {
285  if ( idx != -1 )
286  return -1;
287  else
288  idx = i;
289  }
290  }
291  return idx;
292 }
293 
295 {
296  if ( catIndex < 0 || catIndex >= mCategories.size() )
297  return false;
298  mCategories[catIndex].setValue( value );
299  return true;
300 }
301 
303 {
304  if ( catIndex < 0 || catIndex >= mCategories.size() )
305  return false;
306  mCategories[catIndex].setSymbol( symbol );
307  return true;
308 }
309 
311 {
312  if ( catIndex < 0 || catIndex >= mCategories.size() )
313  return false;
314  mCategories[catIndex].setLabel( label );
315  return true;
316 }
317 
319 {
320  if ( catIndex < 0 || catIndex >= mCategories.size() )
321  return false;
322  mCategories[catIndex].setRenderState( render );
323  return true;
324 }
325 
327 {
328  if ( !cat.symbol() )
329  {
330  QgsDebugMsg( "invalid symbol in a category! ignoring..." );
331  return;
332  }
333 
334  mCategories.append( cat );
335 }
336 
338 {
339  if ( catIndex < 0 || catIndex >= mCategories.size() )
340  return false;
341 
342  mCategories.removeAt( catIndex );
343  return true;
344 }
345 
347 {
348  mCategories.clear();
349 }
350 
352 {
353  if ( from < 0 || from >= mCategories.size() || to < 0 || to >= mCategories.size() ) return;
354  mCategories.move( from, to );
355 }
356 
358 {
359  return qgsVariantLessThan( c1.value(), c2.value() );
360 }
362 {
363  return qgsVariantGreaterThan( c1.value(), c2.value() );
364 }
365 
367 {
368  if ( order == Qt::AscendingOrder )
369  {
371  }
372  else
373  {
375  }
376 }
377 
379 {
380  return QString::localeAwareCompare( c1.label(), c2.label() ) < 0;
381 }
382 
384 {
385  return !labelLessThan( c1, c2 );
386 }
387 
389 {
390  if ( order == Qt::AscendingOrder )
391  {
393  }
394  else
395  {
397  }
398 }
399 
401 {
402  mCounting = context.rendererScale() == 0.0;
403 
404  // make sure that the hash table is up to date
405  rebuildHash();
406 
407  // find out classification attribute index from name
408  mAttrNum = fields.fieldNameIndex( mAttrName );
409  if ( mAttrNum == -1 )
410  {
412  mExpression->prepare( &context.expressionContext() );
413  }
414 
416  for ( ; it != mCategories.end(); ++it )
417  {
418  it->symbol()->startRender( context, &fields );
419 
420  if ( mRotation.data() || mSizeScale.data() )
421  {
422  QgsSymbolV2* tempSymbol = it->symbol()->clone();
425  tempSymbol->startRender( context, &fields );
426  mTempSymbols[ it->symbol()] = tempSymbol;
427  }
428  }
429  return;
430 }
431 
433 {
435  for ( ; it != mCategories.end(); ++it )
436  it->symbol()->stopRender( context );
437 
438  // cleanup mTempSymbols
440  for ( ; it2 != mTempSymbols.end(); ++it2 )
441  {
442  it2.value()->stopRender( context );
443  delete it2.value();
444  }
446  mExpression.reset();
447 }
448 
450 {
451  QSet<QString> attributes;
452 
453  // mAttrName can contain either attribute name or an expression.
454  // Sometimes it is not possible to distinguish between those two,
455  // e.g. "a - b" can be both a valid attribute name or expression.
456  // Since we do not have access to fields here, try both options.
457  attributes << mAttrName;
458 
459  QgsExpression testExpr( mAttrName );
460  if ( !testExpr.hasParserError() )
461  attributes.unite( testExpr.referencedColumns().toSet() );
462 
463  if ( mRotation.data() ) attributes.unite( mRotation->referencedColumns().toSet() );
464  if ( mSizeScale.data() ) attributes.unite( mSizeScale->referencedColumns().toSet() );
465 
467  for ( ; catIt != mCategories.constEnd(); ++catIt )
468  {
469  QgsSymbolV2* catSymbol = catIt->symbol();
470  if ( catSymbol )
471  {
472  attributes.unite( catSymbol->usedAttributes() );
473  }
474  }
475  return attributes.toList();
476 }
477 
479 {
480  QString s = QString( "CATEGORIZED: idx %1\n" ).arg( mAttrName );
481  for ( int i = 0; i < mCategories.count(); i++ )
482  s += mCategories[i].dump();
483  return s;
484 }
485 
487 {
489  if ( mSourceSymbol.data() )
490  r->setSourceSymbol( mSourceSymbol->clone() );
491  if ( mSourceColorRamp.data() )
492  {
493  r->setSourceColorRamp( mSourceColorRamp->clone() );
495  }
498 
499  copyPaintEffect( r );
500  return r;
501 }
502 
504 {
505  QgsStringMap props;
506  props[ "attribute" ] = mAttrName;
507  if ( mRotation.data() )
508  props[ "angle" ] = mRotation->expression();
509  if ( mSizeScale.data() )
510  props[ "scale" ] = mSizeScale->expression();
511 
512  // create a Rule for each range
514  {
515  QgsStringMap catProps( props );
516  it->toSld( doc, element, catProps );
517  }
518 }
519 
521 {
522  Q_UNUSED( context );
523  QgsSymbolV2List lst;
524  for ( int i = 0; i < mCategories.count(); i++ )
525  lst.append( mCategories[i].symbol() );
526  return lst;
527 }
528 
530 {
531  QDomElement symbolsElem = element.firstChildElement( "symbols" );
532  if ( symbolsElem.isNull() )
533  return NULL;
534 
535  QDomElement catsElem = element.firstChildElement( "categories" );
536  if ( catsElem.isNull() )
537  return NULL;
538 
539  QgsSymbolV2Map symbolMap = QgsSymbolLayerV2Utils::loadSymbols( symbolsElem );
540  QgsCategoryList cats;
541 
542  QDomElement catElem = catsElem.firstChildElement();
543  while ( !catElem.isNull() )
544  {
545  if ( catElem.tagName() == "category" )
546  {
547  QVariant value = QVariant( catElem.attribute( "value" ) );
548  QString symbolName = catElem.attribute( "symbol" );
549  QString label = catElem.attribute( "label" );
550  bool render = catElem.attribute( "render" ) != "false";
551  if ( symbolMap.contains( symbolName ) )
552  {
553  QgsSymbolV2* symbol = symbolMap.take( symbolName );
554  cats.append( QgsRendererCategoryV2( value, symbol, label, render ) );
555  }
556  }
557  catElem = catElem.nextSiblingElement();
558  }
559 
560  QString attrName = element.attribute( "attr" );
561 
563 
564  // delete symbols if there are any more
566 
567  // try to load source symbol (optional)
568  QDomElement sourceSymbolElem = element.firstChildElement( "source-symbol" );
569  if ( !sourceSymbolElem.isNull() )
570  {
571  QgsSymbolV2Map sourceSymbolMap = QgsSymbolLayerV2Utils::loadSymbols( sourceSymbolElem );
572  if ( sourceSymbolMap.contains( "0" ) )
573  {
574  r->setSourceSymbol( sourceSymbolMap.take( "0" ) );
575  }
576  QgsSymbolLayerV2Utils::clearSymbolMap( sourceSymbolMap );
577  }
578 
579  // try to load color ramp (optional)
580  QDomElement sourceColorRampElem = element.firstChildElement( "colorramp" );
581  if ( !sourceColorRampElem.isNull() && sourceColorRampElem.attribute( "name" ) == "[source]" )
582  {
583  r->setSourceColorRamp( QgsSymbolLayerV2Utils::loadColorRamp( sourceColorRampElem ) );
584  QDomElement invertedColorRampElem = element.firstChildElement( "invertedcolorramp" );
585  if ( !invertedColorRampElem.isNull() )
586  r->setInvertedColorRamp( invertedColorRampElem.attribute( "value" ) == "1" );
587  }
588 
589  QDomElement rotationElem = element.firstChildElement( "rotation" );
590  if ( !rotationElem.isNull() && !rotationElem.attribute( "field" ).isEmpty() )
591  {
593  for ( ; it != r->mCategories.end(); ++it )
594  {
595  convertSymbolRotation( it->symbol(), rotationElem.attribute( "field" ) );
596  }
597  if ( r->mSourceSymbol.data() )
598  {
599  convertSymbolRotation( r->mSourceSymbol.data(), rotationElem.attribute( "field" ) );
600  }
601  }
602 
603  QDomElement sizeScaleElem = element.firstChildElement( "sizescale" );
604  if ( !sizeScaleElem.isNull() && !sizeScaleElem.attribute( "field" ).isEmpty() )
605  {
607  for ( ; it != r->mCategories.end(); ++it )
608  {
609  convertSymbolSizeScale( it->symbol(),
610  QgsSymbolLayerV2Utils::decodeScaleMethod( sizeScaleElem.attribute( "scalemethod" ) ),
611  sizeScaleElem.attribute( "field" ) );
612  }
613  if ( r->mSourceSymbol.data() && r->mSourceSymbol->type() == QgsSymbolV2::Marker )
614  {
616  QgsSymbolLayerV2Utils::decodeScaleMethod( sizeScaleElem.attribute( "scalemethod" ) ),
617  sizeScaleElem.attribute( "field" ) );
618  }
619  }
620 
621  // TODO: symbol levels
622  return r;
623 }
624 
626 {
627  QDomElement rendererElem = doc.createElement( RENDERER_TAG_NAME );
628  rendererElem.setAttribute( "type", "categorizedSymbol" );
629  rendererElem.setAttribute( "symbollevels", ( mUsingSymbolLevels ? "1" : "0" ) );
630  rendererElem.setAttribute( "forceraster", ( mForceRaster ? "1" : "0" ) );
631  rendererElem.setAttribute( "attr", mAttrName );
632 
633  // categories
634  int i = 0;
636  QDomElement catsElem = doc.createElement( "categories" );
638  for ( ; it != mCategories.end(); ++it )
639  {
640  const QgsRendererCategoryV2& cat = *it;
641  QString symbolName = QString::number( i );
642  symbols.insert( symbolName, cat.symbol() );
643 
644  QDomElement catElem = doc.createElement( "category" );
645  catElem.setAttribute( "value", cat.value().toString() );
646  catElem.setAttribute( "symbol", symbolName );
647  catElem.setAttribute( "label", cat.label() );
648  catElem.setAttribute( "render", cat.renderState() ? "true" : "false" );
649  catsElem.appendChild( catElem );
650  i++;
651  }
652 
653  rendererElem.appendChild( catsElem );
654 
655  // save symbols
656  QDomElement symbolsElem = QgsSymbolLayerV2Utils::saveSymbols( symbols, "symbols", doc );
657  rendererElem.appendChild( symbolsElem );
658 
659  // save source symbol
660  if ( mSourceSymbol.data() )
661  {
662  QgsSymbolV2Map sourceSymbols;
663  sourceSymbols.insert( "0", mSourceSymbol.data() );
664  QDomElement sourceSymbolElem = QgsSymbolLayerV2Utils::saveSymbols( sourceSymbols, "source-symbol", doc );
665  rendererElem.appendChild( sourceSymbolElem );
666  }
667 
668  // save source color ramp
669  if ( mSourceColorRamp.data() )
670  {
671  QDomElement colorRampElem = QgsSymbolLayerV2Utils::saveColorRamp( "[source]", mSourceColorRamp.data(), doc );
672  rendererElem.appendChild( colorRampElem );
673  QDomElement invertedElem = doc.createElement( "invertedcolorramp" );
674  invertedElem.setAttribute( "value", mInvertedColorRamp );
675  rendererElem.appendChild( invertedElem );
676  }
677 
678  QDomElement rotationElem = doc.createElement( "rotation" );
679  if ( mRotation.data() )
681  rendererElem.appendChild( rotationElem );
682 
683  QDomElement sizeScaleElem = doc.createElement( "sizescale" );
684  if ( mSizeScale.data() )
686  sizeScaleElem.setAttribute( "scalemethod", QgsSymbolLayerV2Utils::encodeScaleMethod( mScaleMethod ) );
687  rendererElem.appendChild( sizeScaleElem );
688 
689  if ( mPaintEffect )
690  mPaintEffect->saveProperties( doc, rendererElem );
691 
692  return rendererElem;
693 }
694 
696 {
698  int count = categories().count();
699  for ( int i = 0; i < count; i++ )
700  {
701  const QgsRendererCategoryV2& cat = categories()[i];
703  lst << qMakePair( cat.label(), pix );
704  }
705  return lst;
706 }
707 
709 {
710  Q_UNUSED( scaleDenominator );
712 
713  foreach ( const QgsRendererCategoryV2& cat, mCategories )
714  {
715  if ( rule.isEmpty() || cat.label() == rule )
716  {
717  lst << qMakePair( cat.label(), cat.symbol() );
718  }
719  }
720  return lst;
721 }
722 
724 {
726  if ( mSourceSymbol.data() && mSourceSymbol->type() == QgsSymbolV2::Marker )
727  {
728  // check that all symbols that have the same size expression
729  QgsDataDefined ddSize;
730  foreach ( QgsRendererCategoryV2 category, mCategories )
731  {
732  const QgsMarkerSymbolV2 * symbol = static_cast<const QgsMarkerSymbolV2 *>( category.symbol() );
733  if ( !ddSize.hasDefaultValues() && symbol->dataDefinedSize() != ddSize )
734  {
735  // no common size expression
737  }
738  else
739  {
740  ddSize = symbol->dataDefinedSize();
741  }
742  }
743 
744  if ( !ddSize.isActive() || !ddSize.useExpression() )
745  {
747  }
748 
749  QgsScaleExpression exp( ddSize.expressionString() );
750  if ( exp.type() != QgsScaleExpression::Unknown )
751  {
752  QgsLegendSymbolItemV2 title( NULL, exp.baseExpression(), "" );
753  lst << title;
754  foreach ( double v, QgsSymbolLayerV2Utils::prettyBreaks( exp.minValue(), exp.maxValue(), 4 ) )
755  {
757  QgsMarkerSymbolV2 * s = static_cast<QgsMarkerSymbolV2 *>( si.symbol() );
759  s->setSize( exp.size( v ) );
760  lst << si;
761  }
762  // now list the categorized symbols
764  foreach ( QgsLegendSymbolItemV2 item, list2 )
765  lst << item;
766  return lst;
767  }
768  }
769 
771 }
772 
774 {
775  return mSourceSymbol.data();
776 }
778 {
779  mSourceSymbol.reset( sym );
780 }
781 
783 {
784  return mSourceColorRamp.data();
785 }
786 
788 {
789  mSourceColorRamp.reset( ramp );
790 }
791 
793 {
794  setSourceColorRamp( ramp );
795  setInvertedColorRamp( inverted );
796  double num = mCategories.count() - 1;
797  double count = 0;
798 
799  QgsRandomColorsV2* randomRamp = dynamic_cast<QgsRandomColorsV2*>( ramp );
800  if ( randomRamp )
801  {
802  //ramp is a random colors ramp, so inform it of the total number of required colors
803  //this allows the ramp to pregenerate a set of visually distinctive colors
804  randomRamp->setTotalColorCount( mCategories.count() );
805  }
806 
807  foreach ( const QgsRendererCategoryV2 &cat, mCategories )
808  {
809  double value = count / num;
810  if ( mInvertedColorRamp ) value = 1.0 - value;
811  cat.symbol()->setColor( mSourceColorRamp->color( value ) );
812  count += 1;
813  }
814 }
815 
817 {
818  if ( mSourceSymbol && mSourceSymbol->type() == QgsSymbolV2::Marker )
819  {
820  QgsMarkerSymbolV2 * s = static_cast<QgsMarkerSymbolV2 *>( mSourceSymbol.data() );
821  s->setDataDefinedAngle( QgsDataDefined( fieldOrExpression ) );
822  }
823 }
824 
826 {
827  if ( mSourceSymbol && mSourceSymbol->type() == QgsSymbolV2::Marker )
828  {
829  QgsMarkerSymbolV2 * s = static_cast<QgsMarkerSymbolV2 *>( mSourceSymbol.data() );
830  QgsDataDefined ddAngle = s->dataDefinedAngle();
831  return ddAngle.useExpression() ? ddAngle.expressionString() : ddAngle.field();
832  }
833 
834  return QString();
835 }
836 
838 {
840 }
841 
843 {
845 }
846 
848 {
849  int i = 0;
850  foreach ( QgsRendererCategoryV2 cat, mCategories )
851  {
852  QgsSymbolV2* symbol = sym->clone();
853  symbol->setColor( cat.symbol()->color() );
854  updateCategorySymbol( i, symbol );
855  ++i;
856  }
857 }
858 
860 {
863  for ( ; catIt != mCategories.constEnd(); ++catIt )
864  {
865  setScaleMethodToSymbol( catIt->symbol(), scaleMethod );
866  }
867 }
868 
870 {
871  return true;
872 }
873 
875 {
876  bool ok;
877  int index = key.toInt( &ok );
878  if ( ok && index >= 0 && index < mCategories.size() )
879  return mCategories[ index ].renderState();
880  else
881  return true;
882 }
883 
885 {
886  bool ok;
887  int index = key.toInt( &ok );
888  if ( ok )
889  updateCategoryRenderState( index, state );
890 }
891 
893 
895 {
896  if ( renderer->type() == "categorizedSymbol" )
897  {
898  return dynamic_cast<QgsCategorizedSymbolRendererV2*>( renderer->clone() );
899  }
900  if ( renderer->type() == "pointDisplacement" )
901  {
902  const QgsPointDisplacementRenderer* pointDisplacementRenderer = dynamic_cast<const QgsPointDisplacementRenderer*>( renderer );
903  if ( pointDisplacementRenderer )
904  return convertFromRenderer( pointDisplacementRenderer->embeddedRenderer() );
905  }
906  if ( renderer->type() == "invertedPolygonRenderer" )
907  {
908  const QgsInvertedPolygonRenderer* invertedPolygonRenderer = dynamic_cast<const QgsInvertedPolygonRenderer*>( renderer );
909  if ( invertedPolygonRenderer )
910  return convertFromRenderer( invertedPolygonRenderer->embeddedRenderer() );
911  }
912 
913  // If not one of the specifically handled renderers, then just grab the symbol from the renderer
914  // Could have applied this to specific renderer types (singleSymbol, graduatedSymbo)
915 
917  QgsRenderContext context;
918  QgsSymbolV2List symbols = const_cast<QgsFeatureRendererV2 *>( renderer )->symbols( context );
919  if ( symbols.size() > 0 )
920  {
921  r->setSourceSymbol( symbols.at( 0 )->clone() );
922  }
923 
924  return r;
925 }
Class for parsing and evaluation of expressions (formerly called "search strings").
Definition: qgsexpression.h:88
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.
Definition: qgsexpression.h:95
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).
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:86
QSet< QString > usedAttributes() const
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).
int fieldNameIndex(const QString &fieldName) const
Look up field's index from name - case insensitive TODO: sort out case sensitive (indexFromName()) vs...
Definition: qgsfield.cpp:356
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).
const T & at(int i) const
int categoryIndexForLabel(QString val)
return index of category with specified label (-1 if not found or not unique)
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
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:162
bool qgsVariantGreaterThan(const QVariant &lhs, const QVariant &rhs)
Definition: qgis.cpp:264
void setSizeScaleField(QString fieldOrExpression)
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:237
void setWidth(double width)
int size() const
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)
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)
static QDomElement saveColorRamp(QString name, QgsVectorColorRampV2 *ramp, QDomDocument &doc)
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
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)
virtual QgsLegendSymbolList legendSymbolItems(double scaleDenominator=-1, QString rule=QString()) override
return a list of item text / symbol
QgsAttributes attributes() const
Returns the feature's attributes.
Definition: qgsfeature.cpp:90
bool labelGreaterThan(const QgsRendererCategoryV2 &c1, const QgsRendererCategoryV2 &c2)
void setAttribute(const QString &name, const QString &value)
#define DEFAULT_SCALE_METHOD
static bool createFunctionElement(QDomDocument &doc, QDomElement &element, QString function)
QgsSymbolV2 * symbolForValue(QVariant value)
int toInt(bool *ok, int base) const
static QDomElement saveSymbols(QgsSymbolV2Map &symbols, QString tagName, QDomDocument &doc)
static QgsFeatureRendererV2 * create(QDomElement &element)
create renderer from XML element
bool isEmpty() const
iterator begin()
int categoryIndexForValue(QVariant val)
return index of category with specified value (-1 if not found)
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 void checkLegendSymbolItem(QString key, bool state=true) override
item in symbology was checked
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.
virtual bool legendSymbolItemChecked(QString key) override
item in symbology was checked
A renderer that automatically displaces points with the same position.
bool isNull() const
bool updateCategoryLabel(int catIndex, QString label)
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).
QgsCategorizedSymbolRendererV2(QString attrName=QString(), QgsCategoryList categories=QgsCategoryList())
void copyPaintEffect(QgsFeatureRendererV2 *destRenderer) const
Copies paint effect of this renderer to another renderer.
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.
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:182
static void clearSymbolMap(QgsSymbolV2Map &symbols)
Q_DECL_DEPRECATED void setRotationField(QString fieldOrExpression) override
sets rotation field of renderer (if supported by the renderer)
static QgsSymbolV2::ScaleMethod decodeScaleMethod(QString str)
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)
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