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