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