QGIS API Documentation  2.9.0-Master
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
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 
26 #include "qgsfeature.h"
27 #include "qgsvectorlayer.h"
28 #include "qgslogger.h"
29 
30 #include <QDomDocument>
31 #include <QDomElement>
32 #include <QSettings> // for legend
33 
35  : mRender( true )
36 {
37 }
38 
39 QgsRendererCategoryV2::QgsRendererCategoryV2( QVariant value, QgsSymbolV2* symbol, QString label, bool render )
40  : mValue( value )
41  , mSymbol( symbol )
42  , mLabel( label )
43  , mRender( render )
44 {
45 }
46 
48  : mValue( cat.mValue )
49  , mSymbol( cat.mSymbol.data() ? cat.mSymbol->clone() : NULL )
50  , mLabel( cat.mLabel )
51  , mRender( cat.mRender )
52 {
53 }
54 
55 // copy+swap idion, the copy is done through the 'pass by value'
57 {
58  swap( cat );
59  return *this;
60 }
61 
63 {
64  qSwap( mValue, cat.mValue );
65  qSwap( mSymbol, cat.mSymbol );
66  qSwap( mLabel, cat.mLabel );
67 }
68 
70 {
71  return mValue;
72 }
73 
75 {
76  return mSymbol.data();
77 }
78 
80 {
81  return mLabel;
82 }
83 
85 {
86  return mRender;
87 }
88 
89 void QgsRendererCategoryV2::setValue( const QVariant &value )
90 {
91  mValue = value;
92 }
93 
95 {
96  if ( mSymbol.data() != s ) mSymbol.reset( s );
97 }
98 
99 void QgsRendererCategoryV2::setLabel( const QString &label )
100 {
101  mLabel = label;
102 }
103 
105 {
106  mRender = render;
107 }
108 
110 {
111  return QString( "%1::%2::%3:%4\n" ).arg( mValue.toString() ).arg( mLabel ).arg( mSymbol->dump() ).arg( mRender );
112 }
113 
114 void QgsRendererCategoryV2::toSld( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const
115 {
116  if ( !mSymbol.data() || props.value( "attribute", "" ).isEmpty() )
117  return;
118 
119  QString attrName = props[ "attribute" ];
120 
121  QDomElement ruleElem = doc.createElement( "se:Rule" );
122  element.appendChild( ruleElem );
123 
124  QDomElement nameElem = doc.createElement( "se:Name" );
125  nameElem.appendChild( doc.createTextNode( mLabel ) );
126  ruleElem.appendChild( nameElem );
127 
128  QDomElement descrElem = doc.createElement( "se:Description" );
129  QDomElement titleElem = doc.createElement( "se:Title" );
130  QString descrStr = QString( "%1 is '%2'" ).arg( attrName ).arg( mValue.toString() );
131  titleElem.appendChild( doc.createTextNode( !mLabel.isEmpty() ? mLabel : descrStr ) );
132  descrElem.appendChild( titleElem );
133  ruleElem.appendChild( descrElem );
134 
135  // create the ogc:Filter for the range
136  QString filterFunc = QString( "%1 = '%2'" )
137  .arg( attrName.replace( "\"", "\"\"" ) )
138  .arg( mValue.toString().replace( "'", "''" ) );
139  QgsSymbolLayerV2Utils::createFunctionElement( doc, ruleElem, filterFunc );
140 
141  mSymbol->toSld( doc, ruleElem, props );
142 }
143 
145 
147  : QgsFeatureRendererV2( "categorizedSymbol" )
148  , mAttrName( attrName )
149  , mCategories( categories )
150  , mInvertedColorRamp( false )
151  , mScaleMethod( DEFAULT_SCALE_METHOD )
152  , mAttrNum( -1 )
153  , mCounting( false )
154 {
155  for ( int i = 0; i < mCategories.count(); ++i )
156  {
158  if ( cat.symbol() == NULL )
159  {
160  QgsDebugMsg( "invalid symbol in a category! ignoring..." );
161  mCategories.removeAt( i-- );
162  }
163  //mCategories.insert(cat.value().toString(), cat);
164  }
165 }
166 
168 {
169 }
170 
172 {
173  mSymbolHash.clear();
174 
175  for ( int i = 0; i < mCategories.size(); ++i )
176  {
178  mSymbolHash.insert( cat.value().toString(), ( cat.renderState() || mCounting ) ? cat.symbol() : &sSkipRender );
179  }
180 }
181 
183 {
184  // TODO: special case for int, double
185  QHash<QString, QgsSymbolV2*>::iterator it = mSymbolHash.find( value.isNull() ? "" : value.toString() );
186  if ( it == mSymbolHash.end() )
187  {
188  if ( mSymbolHash.size() == 0 )
189  {
190  QgsDebugMsg( "there are no hashed symbols!!!" );
191  }
192  else
193  {
194  QgsDebugMsgLevel( "attribute value not found: " + value.toString(), 3 );
195  }
196  return NULL;
197  }
198 
199  return *it;
200 }
201 
203 {
204  QgsSymbolV2* symbol = originalSymbolForFeature( feature );
205  if ( !symbol )
206  return 0;
207 
208  if ( !mRotation.data() && !mSizeScale.data() )
209  return symbol; // no data-defined rotation/scaling - just return the symbol
210 
211  // find out rotation, size scale
212  const double rotation = mRotation.data() ? mRotation->evaluate( feature ).toDouble() : 0;
213  const double sizeScale = mSizeScale.data() ? mSizeScale->evaluate( feature ).toDouble() : 1.;
214 
215  // take a temporary symbol (or create it if doesn't exist)
216  QgsSymbolV2* tempSymbol = mTempSymbols[symbol];
217 
218  // modify the temporary symbol and return it
219  if ( tempSymbol->type() == QgsSymbolV2::Marker )
220  {
221  QgsMarkerSymbolV2* markerSymbol = static_cast<QgsMarkerSymbolV2*>( tempSymbol );
222  if ( mRotation.data() ) markerSymbol->setAngle( rotation );
223  markerSymbol->setSize( sizeScale * static_cast<QgsMarkerSymbolV2*>( symbol )->size() );
224  markerSymbol->setScaleMethod( mScaleMethod );
225  }
226  else if ( tempSymbol->type() == QgsSymbolV2::Line )
227  {
228  QgsLineSymbolV2* lineSymbol = static_cast<QgsLineSymbolV2*>( tempSymbol );
229  lineSymbol->setWidth( sizeScale * static_cast<QgsLineSymbolV2*>( symbol )->width() );
230  }
231 
232  return tempSymbol;
233 }
234 
235 
237 {
238  const QgsAttributes& attrs = feature.attributes();
239  QVariant value;
240  if ( mAttrNum == -1 )
241  {
242  Q_ASSERT( mExpression.data() );
243  value = mExpression->evaluate( &feature );
244  }
245  else
246  {
247  value = attrs.value( mAttrNum );
248  }
249 
250  // find the right symbol for the category
251  QgsSymbolV2 *symbol = symbolForValue( value );
252  if ( symbol == &sSkipRender )
253  return 0;
254 
255  if ( !symbol )
256  {
257  // if no symbol found use default one
258  return symbolForValue( QVariant( "" ) );
259  }
260 
261  return symbol;
262 }
263 
264 
266 {
267  for ( int i = 0; i < mCategories.count(); i++ )
268  {
269  if ( mCategories[i].value() == val )
270  return i;
271  }
272  return -1;
273 }
274 
276 {
277  int idx = -1;
278  for ( int i = 0; i < mCategories.count(); i++ )
279  {
280  if ( mCategories[i].label() == val )
281  {
282  if ( idx != -1 )
283  return -1;
284  else
285  idx = i;
286  }
287  }
288  return idx;
289 }
290 
291 bool QgsCategorizedSymbolRendererV2::updateCategoryValue( int catIndex, const QVariant &value )
292 {
293  if ( catIndex < 0 || catIndex >= mCategories.size() )
294  return false;
295  mCategories[catIndex].setValue( value );
296  return true;
297 }
298 
300 {
301  if ( catIndex < 0 || catIndex >= mCategories.size() )
302  return false;
303  mCategories[catIndex].setSymbol( symbol );
304  return true;
305 }
306 
307 bool QgsCategorizedSymbolRendererV2::updateCategoryLabel( int catIndex, QString label )
308 {
309  if ( catIndex < 0 || catIndex >= mCategories.size() )
310  return false;
311  mCategories[catIndex].setLabel( label );
312  return true;
313 }
314 
316 {
317  if ( catIndex < 0 || catIndex >= mCategories.size() )
318  return false;
319  mCategories[catIndex].setRenderState( render );
320  return true;
321 }
322 
324 {
325  if ( !cat.symbol() )
326  {
327  QgsDebugMsg( "invalid symbol in a category! ignoring..." );
328  return;
329  }
330 
331  mCategories.append( cat );
332 }
333 
335 {
336  if ( catIndex < 0 || catIndex >= mCategories.size() )
337  return false;
338 
339  mCategories.removeAt( catIndex );
340  return true;
341 }
342 
344 {
345  mCategories.clear();
346 }
347 
349 {
350  if ( from < 0 || from >= mCategories.size() || to < 0 || to >= mCategories.size() ) return;
351  mCategories.move( from, to );
352 }
353 
355 {
356  return qgsVariantLessThan( c1.value(), c2.value() );
357 }
359 {
360  return qgsVariantGreaterThan( c1.value(), c2.value() );
361 }
362 
364 {
365  if ( order == Qt::AscendingOrder )
366  {
367  qSort( mCategories.begin(), mCategories.end(), valueLessThan );
368  }
369  else
370  {
371  qSort( mCategories.begin(), mCategories.end(), valueGreaterThan );
372  }
373 }
374 
376 {
377  return QString::localeAwareCompare( c1.label(), c2.label() ) < 0;
378 }
379 
381 {
382  return !labelLessThan( c1, c2 );
383 }
384 
386 {
387  if ( order == Qt::AscendingOrder )
388  {
389  qSort( mCategories.begin(), mCategories.end(), labelLessThan );
390  }
391  else
392  {
393  qSort( mCategories.begin(), mCategories.end(), labelGreaterThan );
394  }
395 }
396 
398 {
399  mCounting = context.rendererScale() == 0.0;
400 
401  // make sure that the hash table is up to date
402  rebuildHash();
403 
404  // find out classification attribute index from name
405  mAttrNum = fields.fieldNameIndex( mAttrName );
406  if ( mAttrNum == -1 )
407  {
408  mExpression.reset( new QgsExpression( mAttrName ) );
409  mExpression->prepare( fields );
410  }
411 
412  QgsCategoryList::iterator it = mCategories.begin();
413  for ( ; it != mCategories.end(); ++it )
414  {
415  it->symbol()->startRender( context, &fields );
416 
417  if ( mRotation.data() || mSizeScale.data() )
418  {
419  QgsSymbolV2* tempSymbol = it->symbol()->clone();
420  tempSymbol->setRenderHints(( mRotation.data() ? QgsSymbolV2::DataDefinedRotation : 0 ) |
422  tempSymbol->startRender( context, &fields );
423  mTempSymbols[ it->symbol()] = tempSymbol;
424  }
425  }
426 }
427 
429 {
430  QgsCategoryList::iterator it = mCategories.begin();
431  for ( ; it != mCategories.end(); ++it )
432  it->symbol()->stopRender( context );
433 
434  // cleanup mTempSymbols
435  QHash<QgsSymbolV2*, QgsSymbolV2*>::iterator it2 = mTempSymbols.begin();
436  for ( ; it2 != mTempSymbols.end(); ++it2 )
437  {
438  it2.value()->stopRender( context );
439  delete it2.value();
440  }
441  mTempSymbols.clear();
442  mExpression.reset();
443 }
444 
446 {
447  QSet<QString> attributes;
448 
449  // mAttrName can contain either attribute name or an expression.
450  // Sometimes it is not possible to distinguish between those two,
451  // e.g. "a - b" can be both a valid attribute name or expression.
452  // Since we do not have access to fields here, try both options.
453  attributes << mAttrName;
454 
455  QgsExpression testExpr( mAttrName );
456  if ( !testExpr.hasParserError() )
457  attributes.unite( testExpr.referencedColumns().toSet() );
458 
459  if ( mRotation.data() ) attributes.unite( mRotation->referencedColumns().toSet() );
460  if ( mSizeScale.data() ) attributes.unite( mSizeScale->referencedColumns().toSet() );
461 
462  QgsCategoryList::const_iterator catIt = mCategories.constBegin();
463  for ( ; catIt != mCategories.constEnd(); ++catIt )
464  {
465  QgsSymbolV2* catSymbol = catIt->symbol();
466  if ( catSymbol )
467  {
468  attributes.unite( catSymbol->usedAttributes() );
469  }
470  }
471  return attributes.toList();
472 }
473 
475 {
476  QString s = QString( "CATEGORIZED: idx %1\n" ).arg( mAttrName );
477  for ( int i = 0; i < mCategories.count(); i++ )
478  s += mCategories[i].dump();
479  return s;
480 }
481 
483 {
485  if ( mSourceSymbol.data() )
486  r->setSourceSymbol( mSourceSymbol->clone() );
487  if ( mSourceColorRamp.data() )
488  {
489  r->setSourceColorRamp( mSourceColorRamp->clone() );
491  }
495  r->setScaleMethod( scaleMethod() );
496 
497  copyPaintEffect( r );
498  return r;
499 }
500 
501 void QgsCategorizedSymbolRendererV2::toSld( QDomDocument &doc, QDomElement &element ) const
502 {
503  QgsStringMap props;
504  props[ "attribute" ] = mAttrName;
505  if ( mRotation.data() )
506  props[ "angle" ] = mRotation->expression();
507  if ( mSizeScale.data() )
508  props[ "scale" ] = mSizeScale->expression();
509 
510  // create a Rule for each range
511  for ( QgsCategoryList::const_iterator it = mCategories.constBegin(); it != mCategories.constEnd(); ++it )
512  {
513  QgsStringMap catProps( props );
514  it->toSld( doc, element, catProps );
515  }
516 }
517 
519 {
520  QgsSymbolV2List lst;
521  for ( int i = 0; i < mCategories.count(); i++ )
522  lst.append( mCategories[i].symbol() );
523  return lst;
524 }
525 
527 {
528  QDomElement symbolsElem = element.firstChildElement( "symbols" );
529  if ( symbolsElem.isNull() )
530  return NULL;
531 
532  QDomElement catsElem = element.firstChildElement( "categories" );
533  if ( catsElem.isNull() )
534  return NULL;
535 
536  QgsSymbolV2Map symbolMap = QgsSymbolLayerV2Utils::loadSymbols( symbolsElem );
537  QgsCategoryList cats;
538 
539  QDomElement catElem = catsElem.firstChildElement();
540  while ( !catElem.isNull() )
541  {
542  if ( catElem.tagName() == "category" )
543  {
544  QVariant value = QVariant( catElem.attribute( "value" ) );
545  QString symbolName = catElem.attribute( "symbol" );
546  QString label = catElem.attribute( "label" );
547  bool render = catElem.attribute( "render" ) != "false";
548  if ( symbolMap.contains( symbolName ) )
549  {
550  QgsSymbolV2* symbol = symbolMap.take( symbolName );
551  cats.append( QgsRendererCategoryV2( value, symbol, label, render ) );
552  }
553  }
554  catElem = catElem.nextSiblingElement();
555  }
556 
557  QString attrName = element.attribute( "attr" );
558 
560 
561  // delete symbols if there are any more
563 
564  // try to load source symbol (optional)
565  QDomElement sourceSymbolElem = element.firstChildElement( "source-symbol" );
566  if ( !sourceSymbolElem.isNull() )
567  {
568  QgsSymbolV2Map sourceSymbolMap = QgsSymbolLayerV2Utils::loadSymbols( sourceSymbolElem );
569  if ( sourceSymbolMap.contains( "0" ) )
570  {
571  r->setSourceSymbol( sourceSymbolMap.take( "0" ) );
572  }
573  QgsSymbolLayerV2Utils::clearSymbolMap( sourceSymbolMap );
574  }
575 
576  // try to load color ramp (optional)
577  QDomElement sourceColorRampElem = element.firstChildElement( "colorramp" );
578  if ( !sourceColorRampElem.isNull() && sourceColorRampElem.attribute( "name" ) == "[source]" )
579  {
580  r->setSourceColorRamp( QgsSymbolLayerV2Utils::loadColorRamp( sourceColorRampElem ) );
581  QDomElement invertedColorRampElem = element.firstChildElement( "invertedcolorramp" );
582  if ( !invertedColorRampElem.isNull() )
583  r->setInvertedColorRamp( invertedColorRampElem.attribute( "value" ) == "1" );
584  }
585 
586  QDomElement rotationElem = element.firstChildElement( "rotation" );
587  if ( !rotationElem.isNull() )
588  r->setRotationField( rotationElem.attribute( "field" ) );
589 
590  QDomElement sizeScaleElem = element.firstChildElement( "sizescale" );
591  if ( !sizeScaleElem.isNull() )
592  {
593  r->setSizeScaleField( sizeScaleElem.attribute( "field" ) );
594  r->setScaleMethod( QgsSymbolLayerV2Utils::decodeScaleMethod( sizeScaleElem.attribute( "scalemethod" ) ) );
595  }
596 
597  // TODO: symbol levels
598  return r;
599 }
600 
601 QDomElement QgsCategorizedSymbolRendererV2::save( QDomDocument& doc )
602 {
603  QDomElement rendererElem = doc.createElement( RENDERER_TAG_NAME );
604  rendererElem.setAttribute( "type", "categorizedSymbol" );
605  rendererElem.setAttribute( "symbollevels", ( mUsingSymbolLevels ? "1" : "0" ) );
606  rendererElem.setAttribute( "attr", mAttrName );
607 
608  // categories
609  int i = 0;
611  QDomElement catsElem = doc.createElement( "categories" );
612  QgsCategoryList::const_iterator it = mCategories.constBegin();
613  for ( ; it != mCategories.end(); ++it )
614  {
615  const QgsRendererCategoryV2& cat = *it;
616  QString symbolName = QString::number( i );
617  symbols.insert( symbolName, cat.symbol() );
618 
619  QDomElement catElem = doc.createElement( "category" );
620  catElem.setAttribute( "value", cat.value().toString() );
621  catElem.setAttribute( "symbol", symbolName );
622  catElem.setAttribute( "label", cat.label() );
623  catElem.setAttribute( "render", cat.renderState() ? "true" : "false" );
624  catsElem.appendChild( catElem );
625  i++;
626  }
627 
628  rendererElem.appendChild( catsElem );
629 
630  // save symbols
631  QDomElement symbolsElem = QgsSymbolLayerV2Utils::saveSymbols( symbols, "symbols", doc );
632  rendererElem.appendChild( symbolsElem );
633 
634  // save source symbol
635  if ( mSourceSymbol.data() )
636  {
637  QgsSymbolV2Map sourceSymbols;
638  sourceSymbols.insert( "0", mSourceSymbol.data() );
639  QDomElement sourceSymbolElem = QgsSymbolLayerV2Utils::saveSymbols( sourceSymbols, "source-symbol", doc );
640  rendererElem.appendChild( sourceSymbolElem );
641  }
642 
643  // save source color ramp
644  if ( mSourceColorRamp.data() )
645  {
646  QDomElement colorRampElem = QgsSymbolLayerV2Utils::saveColorRamp( "[source]", mSourceColorRamp.data(), doc );
647  rendererElem.appendChild( colorRampElem );
648  QDomElement invertedElem = doc.createElement( "invertedcolorramp" );
649  invertedElem.setAttribute( "value", mInvertedColorRamp );
650  rendererElem.appendChild( invertedElem );
651  }
652 
653  QDomElement rotationElem = doc.createElement( "rotation" );
654  if ( mRotation.data() )
655  rotationElem.setAttribute( "field", QgsSymbolLayerV2Utils::fieldOrExpressionFromExpression( mRotation.data() ) );
656  rendererElem.appendChild( rotationElem );
657 
658  QDomElement sizeScaleElem = doc.createElement( "sizescale" );
659  if ( mSizeScale.data() )
660  sizeScaleElem.setAttribute( "field", QgsSymbolLayerV2Utils::fieldOrExpressionFromExpression( mSizeScale.data() ) );
661  sizeScaleElem.setAttribute( "scalemethod", QgsSymbolLayerV2Utils::encodeScaleMethod( mScaleMethod ) );
662  rendererElem.appendChild( sizeScaleElem );
663 
664  if ( mPaintEffect )
665  mPaintEffect->saveProperties( doc, rendererElem );
666 
667  return rendererElem;
668 }
669 
671 {
673  int count = categories().count();
674  for ( int i = 0; i < count; i++ )
675  {
676  const QgsRendererCategoryV2& cat = categories()[i];
677  QPixmap pix = QgsSymbolLayerV2Utils::symbolPreviewPixmap( cat.symbol(), iconSize );
678  lst << qMakePair( cat.label(), pix );
679  }
680  return lst;
681 }
682 
684 {
685  Q_UNUSED( scaleDenominator );
687 
688  foreach ( const QgsRendererCategoryV2& cat, mCategories )
689  {
690  if ( rule.isEmpty() || cat.label() == rule )
691  {
692  lst << qMakePair( cat.label(), cat.symbol() );
693  }
694  }
695  return lst;
696 }
697 
698 
700 {
701  return mSourceSymbol.data();
702 }
704 {
705  mSourceSymbol.reset( sym );
706 }
707 
709 {
710  return mSourceColorRamp.data();
711 }
712 
714 {
715  mSourceColorRamp.reset( ramp );
716 }
717 
719 {
720  setSourceColorRamp( ramp );
721  setInvertedColorRamp( inverted );
722  double num = mCategories.count() - 1;
723  double count = 0;
724 
725  QgsRandomColorsV2* randomRamp = dynamic_cast<QgsRandomColorsV2*>( ramp );
726  if ( randomRamp )
727  {
728  //ramp is a random colors ramp, so inform it of the total number of required colors
729  //this allows the ramp to pregenerate a set of visually distinctive colors
730  randomRamp->setTotalColorCount( mCategories.count() );
731  }
732 
733  foreach ( const QgsRendererCategoryV2 &cat, mCategories )
734  {
735  double value = count / num;
736  if ( mInvertedColorRamp ) value = 1.0 - value;
737  cat.symbol()->setColor( mSourceColorRamp->color( value ) );
738  count += 1;
739  }
740 }
741 
742 void QgsCategorizedSymbolRendererV2::setRotationField( QString fieldOrExpression )
743 {
745 }
746 
748 {
749  return mRotation.data() ? QgsSymbolLayerV2Utils::fieldOrExpressionFromExpression( mRotation.data() ) : QString();
750 }
751 
752 void QgsCategorizedSymbolRendererV2::setSizeScaleField( QString fieldOrExpression )
753 {
755 }
756 
758 {
760 }
761 
763 {
764  int i = 0;
765  foreach ( QgsRendererCategoryV2 cat, mCategories )
766  {
767  QgsSymbolV2* symbol = sym->clone();
768  symbol->setColor( cat.symbol()->color() );
769  updateCategorySymbol( i, symbol );
770  ++i;
771  }
772 }
773 
775 {
777  QgsCategoryList::const_iterator catIt = mCategories.constBegin();
778  for ( ; catIt != mCategories.constEnd(); ++catIt )
779  {
780  setScaleMethodToSymbol( catIt->symbol(), scaleMethod );
781  }
782 }
783 
785 {
786  return true;
787 }
788 
790 {
791  bool ok;
792  int index = key.toInt( &ok );
793  if ( ok && index >= 0 && index < mCategories.size() )
794  return mCategories[ index ].renderState();
795  else
796  return true;
797 }
798 
800 {
801  bool ok;
802  int index = key.toInt( &ok );
803  if ( ok )
804  updateCategoryRenderState( index, state );
805 }
806 
808 
810 {
811  if ( renderer->type() == "categorizedSymbol" )
812  {
813  return dynamic_cast<QgsCategorizedSymbolRendererV2*>( renderer->clone() );
814  }
815  if ( renderer->type() == "pointDisplacement" )
816  {
817  const QgsPointDisplacementRenderer* pointDisplacementRenderer = dynamic_cast<const QgsPointDisplacementRenderer*>( renderer );
818  if ( pointDisplacementRenderer )
819  return convertFromRenderer( pointDisplacementRenderer->embeddedRenderer() );
820  }
821  if ( renderer->type() == "invertedPolygonRenderer" )
822  {
823  const QgsInvertedPolygonRenderer* invertedPolygonRenderer = dynamic_cast<const QgsInvertedPolygonRenderer*>( renderer );
824  if ( invertedPolygonRenderer )
825  return convertFromRenderer( invertedPolygonRenderer->embeddedRenderer() );
826  }
827 
828  // If not one of the specifically handled renderers, then just grab the symbol from the renderer
829  // Could have applied this to specific renderer types (singleSymbol, graduatedSymbo)
830 
832  QgsSymbolV2List symbols = const_cast<QgsFeatureRendererV2 *>( renderer )->symbols();
833  if ( symbols.size() > 0 )
834  {
835  r->setSourceSymbol( symbols.at( 0 )->clone() );
836  }
837 
838  return r;
839 }
QMap< QString, QgsSymbolV2 * > QgsSymbolV2Map
Definition: qgsrendererv2.h:40
Class for parsing and evaluation of expressions (formerly called "search strings").
Definition: qgsexpression.h:87
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
bool hasParserError() const
Returns true if an error occurred when parsing the input expression.
Definition: qgsexpression.h:94
virtual void stopRender(QgsRenderContext &context) override
virtual QgsSymbolV2 * originalSymbolForFeature(QgsFeature &feature) override
Return symbol for feature.
QStringList referencedColumns() const
Get list of columns referenced by the expression.
virtual bool legendSymbolItemsCheckable() const override
items of symbology items in legend should be checkable
const QgsCategoryList & categories() const
static QgsVectorColorRampV2 * loadColorRamp(QDomElement &element)
QList< QgsSymbolV2 * > QgsSymbolV2List
Definition: qgsrendererv2.h:39
SymbolType type() const
Definition: qgssymbolv2.h:85
QSet< QString > usedAttributes() const
#define QgsDebugMsg(str)
Definition: qgslogger.h:33
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:234
double rendererScale() const
virtual QgsSymbolV2 * clone() const =0
int categoryIndexForLabel(QString val)
return index of category with specified label (-1 if not found or not unique)
QScopedPointer< QgsSymbolV2 > mSourceSymbol
bool updateCategoryRenderState(int catIndex, bool render)
QScopedPointer< QgsExpression > mRotation
Container of fields for a vector layer.
Definition: qgsfield.h:172
virtual void setTotalColorCount(const int colorCount)
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:113
bool qgsVariantGreaterThan(const QVariant &lhs, const QVariant &rhs)
Definition: qgis.cpp:264
void setSizeScaleField(QString fieldOrExpression)
QScopedPointer< QgsSymbolV2 > mSymbol
QMap< QString, QString > QgsStringMap
Definition: qgis.h:438
QgsPaintEffect * mPaintEffect
void setSourceColorRamp(QgsVectorColorRampV2 *ramp)
bool qgsVariantLessThan(const QVariant &lhs, const QVariant &rhs)
Definition: qgis.cpp:237
void setWidth(double width)
QHash< QString, QgsSymbolV2 * > mSymbolHash
hashtable for faster access to symbols
virtual QDomElement save(QDomDocument &doc) override
store renderer info to XML element
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
static QDomElement saveColorRamp(QString name, QgsVectorColorRampV2 *ramp, QDomDocument &doc)
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
bool labelGreaterThan(const QgsRendererCategoryV2 &c1, const QgsRendererCategoryV2 &c2)
#define DEFAULT_SCALE_METHOD
static bool createFunctionElement(QDomDocument &doc, QDomElement &element, QString function)
QgsSymbolV2 * symbolForValue(QVariant value)
static QDomElement saveSymbols(QgsSymbolV2Map &symbols, QString tagName, QDomDocument &doc)
static QgsFeatureRendererV2 * create(QDomElement &element)
create renderer from XML element
int categoryIndexForValue(QVariant val)
return index of category with specified value (-1 if not found)
void setAngle(double angle)
const QgsAttributes & attributes() const
Definition: qgsfeature.h:142
virtual void startRender(QgsRenderContext &context, const QgsFields &fields) override
void setSize(double size)
virtual void checkLegendSymbolItem(QString key, bool state=true) override
item in symbology was checked
virtual QgsFeatureRendererV2 * clone() const override
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.
QList< QPair< QString, QPixmap > > QgsLegendSymbologyList
QgsFeatureRendererV2 * embeddedRenderer() const
void updateColorRamp(QgsVectorColorRampV2 *ramp, bool inverted=false)
QHash< QgsSymbolV2 *, QgsSymbolV2 * > mTempSymbols
temporary symbols, used for data-defined rotation and scaling
void toSld(QDomDocument &doc, QDomElement &element, QgsStringMap props) const
virtual bool legendSymbolItemChecked(QString key) override
item in symbology was checked
virtual QgsSymbolV2 * symbolForFeature(QgsFeature &feature) override
to be overridden
A renderer that automatically displaces points with the same position.
bool updateCategoryLabel(int catIndex, QString label)
void setUsingSymbolLevels(bool usingSymbolLevels)
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
QgsCategorizedSymbolRendererV2(QString attrName=QString(), QgsCategoryList categories=QgsCategoryList())
void copyPaintEffect(QgsFeatureRendererV2 *destRenderer) const
Copies paint effect of this renderer to another renderer.
static QgsExpression * fieldOrExpressionToExpression(const QString &fieldOrExpression)
Return a new valid expression instance for given field or expression string.
QVector< QVariant > QgsAttributes
Definition: qgsfeature.h:100
static QString encodeScaleMethod(QgsSymbolV2::ScaleMethod scaleMethod)
bool updateCategoryValue(int catIndex, const QVariant &value)
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)
void setRenderHints(int hints)
Definition: qgssymbolv2.h:161
static void clearSymbolMap(QgsSymbolV2Map &symbols)
void setRotationField(QString fieldOrExpression) override
sets rotation field of renderer (if supported by the renderer)
static QgsSymbolV2::ScaleMethod decodeScaleMethod(QString str)
void swap(QgsRendererCategoryV2 &other)
QgsRendererCategoryV2 & operator=(QgsRendererCategoryV2 cat)
QgsSymbolV2::ScaleMethod scaleMethod() const
virtual QgsSymbolV2List symbols() override
for symbol levels
static QPixmap symbolPreviewPixmap(QgsSymbolV2 *symbol, QSize size, QgsRenderContext *customContext=0)
void addCategory(const QgsRendererCategoryV2 &category)
double size
Definition: qgssvgcache.cpp:77
QList< QPair< QString, QgsSymbolV2 * > > QgsLegendSymbolList
Definition: qgsrendererv2.h:43
void sortByValue(Qt::SortOrder order=Qt::AscendingOrder)
virtual QgsLegendSymbologyList legendSymbologyItems(QSize iconSize) override
return a list of symbology items for the legend
void setScaleMethod(QgsSymbolV2::ScaleMethod scaleMethod)
QScopedPointer< QgsExpression > mExpression
QColor color() const
virtual QString dump() const override
for debugging