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 );
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( feature ).toDouble() : 0;
215  const double sizeScale = mSizeScale.data() ? mSizeScale->evaluate( feature ).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  QgsAttributes attrs = feature.attributes();
241  QVariant value;
242  if ( mAttrNum == -1 )
243  {
244  Q_ASSERT( mExpression.data() );
245  value = mExpression->evaluate( &feature );
246  }
247  else
248  {
249  value = attrs.value( mAttrNum );
250  }
251 
252  // find the right symbol for the category
253  QgsSymbolV2 *symbol = symbolForValue( value );
254  if ( symbol == &sSkipRender )
255  return 0;
256 
257  if ( !symbol )
258  {
259  // if no symbol found use default one
260  return symbolForValue( QVariant( "" ) );
261  }
262 
263  return symbol;
264 }
265 
266 
268 {
269  for ( int i = 0; i < mCategories.count(); i++ )
270  {
271  if ( mCategories[i].value() == val )
272  return i;
273  }
274  return -1;
275 }
276 
278 {
279  int idx = -1;
280  for ( int i = 0; i < mCategories.count(); i++ )
281  {
282  if ( mCategories[i].label() == val )
283  {
284  if ( idx != -1 )
285  return -1;
286  else
287  idx = i;
288  }
289  }
290  return idx;
291 }
292 
294 {
295  if ( catIndex < 0 || catIndex >= mCategories.size() )
296  return false;
297  mCategories[catIndex].setValue( value );
298  return true;
299 }
300 
302 {
303  if ( catIndex < 0 || catIndex >= mCategories.size() )
304  return false;
305  mCategories[catIndex].setSymbol( symbol );
306  return true;
307 }
308 
310 {
311  if ( catIndex < 0 || catIndex >= mCategories.size() )
312  return false;
313  mCategories[catIndex].setLabel( label );
314  return true;
315 }
316 
318 {
319  if ( catIndex < 0 || catIndex >= mCategories.size() )
320  return false;
321  mCategories[catIndex].setRenderState( render );
322  return true;
323 }
324 
326 {
327  if ( !cat.symbol() )
328  {
329  QgsDebugMsg( "invalid symbol in a category! ignoring..." );
330  return;
331  }
332 
333  mCategories.append( cat );
334 }
335 
337 {
338  if ( catIndex < 0 || catIndex >= mCategories.size() )
339  return false;
340 
341  mCategories.removeAt( catIndex );
342  return true;
343 }
344 
346 {
347  mCategories.clear();
348 }
349 
351 {
352  if ( from < 0 || from >= mCategories.size() || to < 0 || to >= mCategories.size() ) return;
353  mCategories.move( from, to );
354 }
355 
357 {
358  return qgsVariantLessThan( c1.value(), c2.value() );
359 }
361 {
362  return qgsVariantGreaterThan( c1.value(), c2.value() );
363 }
364 
366 {
367  if ( order == Qt::AscendingOrder )
368  {
370  }
371  else
372  {
374  }
375 }
376 
378 {
379  return QString::localeAwareCompare( c1.label(), c2.label() ) < 0;
380 }
381 
383 {
384  return !labelLessThan( c1, c2 );
385 }
386 
388 {
389  if ( order == Qt::AscendingOrder )
390  {
392  }
393  else
394  {
396  }
397 }
398 
400 {
401  mCounting = context.rendererScale() == 0.0;
402 
403  // make sure that the hash table is up to date
404  rebuildHash();
405 
406  // find out classification attribute index from name
407  mAttrNum = fields.fieldNameIndex( mAttrName );
408  if ( mAttrNum == -1 )
409  {
411  mExpression->prepare( fields );
412  }
413 
415  for ( ; it != mCategories.end(); ++it )
416  {
417  it->symbol()->startRender( context, &fields );
418 
419  if ( mRotation.data() || mSizeScale.data() )
420  {
421  QgsSymbolV2* tempSymbol = it->symbol()->clone();
424  tempSymbol->startRender( context, &fields );
425  mTempSymbols[ it->symbol()] = tempSymbol;
426  }
427  }
428 }
429 
431 {
433  for ( ; it != mCategories.end(); ++it )
434  it->symbol()->stopRender( context );
435 
436  // cleanup mTempSymbols
438  for ( ; it2 != mTempSymbols.end(); ++it2 )
439  {
440  it2.value()->stopRender( context );
441  delete it2.value();
442  }
444  mExpression.reset();
445 }
446 
448 {
449  QSet<QString> attributes;
450 
451  // mAttrName can contain either attribute name or an expression.
452  // Sometimes it is not possible to distinguish between those two,
453  // e.g. "a - b" can be both a valid attribute name or expression.
454  // Since we do not have access to fields here, try both options.
455  attributes << mAttrName;
456 
457  QgsExpression testExpr( mAttrName );
458  if ( !testExpr.hasParserError() )
459  attributes.unite( testExpr.referencedColumns().toSet() );
460 
461  if ( mRotation.data() ) attributes.unite( mRotation->referencedColumns().toSet() );
462  if ( mSizeScale.data() ) attributes.unite( mSizeScale->referencedColumns().toSet() );
463 
465  for ( ; catIt != mCategories.constEnd(); ++catIt )
466  {
467  QgsSymbolV2* catSymbol = catIt->symbol();
468  if ( catSymbol )
469  {
470  attributes.unite( catSymbol->usedAttributes() );
471  }
472  }
473  return attributes.toList();
474 }
475 
477 {
478  QString s = QString( "CATEGORIZED: idx %1\n" ).arg( mAttrName );
479  for ( int i = 0; i < mCategories.count(); i++ )
480  s += mCategories[i].dump();
481  return s;
482 }
483 
485 {
487  if ( mSourceSymbol.data() )
488  r->setSourceSymbol( mSourceSymbol->clone() );
489  if ( mSourceColorRamp.data() )
490  {
491  r->setSourceColorRamp( mSourceColorRamp->clone() );
493  }
497  //r->setScaleMethod( scaleMethod() );
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  QgsSymbolV2List lst;
523  for ( int i = 0; i < mCategories.count(); i++ )
524  lst.append( mCategories[i].symbol() );
525  return lst;
526 }
527 
529 {
530  QDomElement symbolsElem = element.firstChildElement( "symbols" );
531  if ( symbolsElem.isNull() )
532  return NULL;
533 
534  QDomElement catsElem = element.firstChildElement( "categories" );
535  if ( catsElem.isNull() )
536  return NULL;
537 
538  QgsSymbolV2Map symbolMap = QgsSymbolLayerV2Utils::loadSymbols( symbolsElem );
539  QgsCategoryList cats;
540 
541  QDomElement catElem = catsElem.firstChildElement();
542  while ( !catElem.isNull() )
543  {
544  if ( catElem.tagName() == "category" )
545  {
546  QVariant value = QVariant( catElem.attribute( "value" ) );
547  QString symbolName = catElem.attribute( "symbol" );
548  QString label = catElem.attribute( "label" );
549  bool render = catElem.attribute( "render" ) != "false";
550  if ( symbolMap.contains( symbolName ) )
551  {
552  QgsSymbolV2* symbol = symbolMap.take( symbolName );
553  cats.append( QgsRendererCategoryV2( value, symbol, label, render ) );
554  }
555  }
556  catElem = catElem.nextSiblingElement();
557  }
558 
559  QString attrName = element.attribute( "attr" );
560 
562 
563  // delete symbols if there are any more
565 
566  // try to load source symbol (optional)
567  QDomElement sourceSymbolElem = element.firstChildElement( "source-symbol" );
568  if ( !sourceSymbolElem.isNull() )
569  {
570  QgsSymbolV2Map sourceSymbolMap = QgsSymbolLayerV2Utils::loadSymbols( sourceSymbolElem );
571  if ( sourceSymbolMap.contains( "0" ) )
572  {
573  r->setSourceSymbol( sourceSymbolMap.take( "0" ) );
574  }
575  QgsSymbolLayerV2Utils::clearSymbolMap( sourceSymbolMap );
576  }
577 
578  // try to load color ramp (optional)
579  QDomElement sourceColorRampElem = element.firstChildElement( "colorramp" );
580  if ( !sourceColorRampElem.isNull() && sourceColorRampElem.attribute( "name" ) == "[source]" )
581  {
582  r->setSourceColorRamp( QgsSymbolLayerV2Utils::loadColorRamp( sourceColorRampElem ) );
583  QDomElement invertedColorRampElem = element.firstChildElement( "invertedcolorramp" );
584  if ( !invertedColorRampElem.isNull() )
585  r->setInvertedColorRamp( invertedColorRampElem.attribute( "value" ) == "1" );
586  }
587 
588  QDomElement rotationElem = element.firstChildElement( "rotation" );
589  if ( !rotationElem.isNull() && !rotationElem.attribute( "field" ).isEmpty() )
590  {
592  for ( ; it != r->mCategories.end(); ++it )
593  {
594  convertSymbolRotation( it->symbol(), rotationElem.attribute( "field" ) );
595  }
596  if ( r->mSourceSymbol.data() )
597  {
598  convertSymbolRotation( r->mSourceSymbol.data(), rotationElem.attribute( "field" ) );
599  }
600  }
601 
602  QDomElement sizeScaleElem = element.firstChildElement( "sizescale" );
603  if ( !sizeScaleElem.isNull() && !sizeScaleElem.attribute( "field" ).isEmpty() )
604  {
606  for ( ; it != r->mCategories.end(); ++it )
607  {
608  convertSymbolSizeScale( it->symbol(),
609  QgsSymbolLayerV2Utils::decodeScaleMethod( sizeScaleElem.attribute( "scalemethod" ) ),
610  sizeScaleElem.attribute( "field" ) );
611  }
612  if ( r->mSourceSymbol.data() && r->mSourceSymbol->type() == QgsSymbolV2::Marker )
613  {
615  QgsSymbolLayerV2Utils::decodeScaleMethod( sizeScaleElem.attribute( "scalemethod" ) ),
616  sizeScaleElem.attribute( "field" ) );
617  }
618  }
619 
620  // TODO: symbol levels
621  return r;
622 }
623 
625 {
626  QDomElement rendererElem = doc.createElement( RENDERER_TAG_NAME );
627  rendererElem.setAttribute( "type", "categorizedSymbol" );
628  rendererElem.setAttribute( "symbollevels", ( mUsingSymbolLevels ? "1" : "0" ) );
629  rendererElem.setAttribute( "attr", mAttrName );
630 
631  // categories
632  int i = 0;
634  QDomElement catsElem = doc.createElement( "categories" );
636  for ( ; it != mCategories.end(); ++it )
637  {
638  const QgsRendererCategoryV2& cat = *it;
639  QString symbolName = QString::number( i );
640  symbols.insert( symbolName, cat.symbol() );
641 
642  QDomElement catElem = doc.createElement( "category" );
643  catElem.setAttribute( "value", cat.value().toString() );
644  catElem.setAttribute( "symbol", symbolName );
645  catElem.setAttribute( "label", cat.label() );
646  catElem.setAttribute( "render", cat.renderState() ? "true" : "false" );
647  catsElem.appendChild( catElem );
648  i++;
649  }
650 
651  rendererElem.appendChild( catsElem );
652 
653  // save symbols
654  QDomElement symbolsElem = QgsSymbolLayerV2Utils::saveSymbols( symbols, "symbols", doc );
655  rendererElem.appendChild( symbolsElem );
656 
657  // save source symbol
658  if ( mSourceSymbol.data() )
659  {
660  QgsSymbolV2Map sourceSymbols;
661  sourceSymbols.insert( "0", mSourceSymbol.data() );
662  QDomElement sourceSymbolElem = QgsSymbolLayerV2Utils::saveSymbols( sourceSymbols, "source-symbol", doc );
663  rendererElem.appendChild( sourceSymbolElem );
664  }
665 
666  // save source color ramp
667  if ( mSourceColorRamp.data() )
668  {
669  QDomElement colorRampElem = QgsSymbolLayerV2Utils::saveColorRamp( "[source]", mSourceColorRamp.data(), doc );
670  rendererElem.appendChild( colorRampElem );
671  QDomElement invertedElem = doc.createElement( "invertedcolorramp" );
672  invertedElem.setAttribute( "value", mInvertedColorRamp );
673  rendererElem.appendChild( invertedElem );
674  }
675 
676  QDomElement rotationElem = doc.createElement( "rotation" );
677  if ( mRotation.data() )
679  rendererElem.appendChild( rotationElem );
680 
681  QDomElement sizeScaleElem = doc.createElement( "sizescale" );
682  if ( mSizeScale.data() )
684  sizeScaleElem.setAttribute( "scalemethod", QgsSymbolLayerV2Utils::encodeScaleMethod( mScaleMethod ) );
685  rendererElem.appendChild( sizeScaleElem );
686 
687  if ( mPaintEffect )
688  mPaintEffect->saveProperties( doc, rendererElem );
689 
690  return rendererElem;
691 }
692 
694 {
696  int count = categories().count();
697  for ( int i = 0; i < count; i++ )
698  {
699  const QgsRendererCategoryV2& cat = categories()[i];
701  lst << qMakePair( cat.label(), pix );
702  }
703  return lst;
704 }
705 
707 {
708  Q_UNUSED( scaleDenominator );
710 
711  foreach ( const QgsRendererCategoryV2& cat, mCategories )
712  {
713  if ( rule.isEmpty() || cat.label() == rule )
714  {
715  lst << qMakePair( cat.label(), cat.symbol() );
716  }
717  }
718  return lst;
719 }
720 
722 {
724  if ( mSourceSymbol.data() && mSourceSymbol->type() == QgsSymbolV2::Marker )
725  {
726  // check that all symbols that have the same size expression
727  QgsDataDefined ddSize;
728  foreach ( QgsRendererCategoryV2 category, mCategories )
729  {
730  const QgsMarkerSymbolV2 * symbol = static_cast<const QgsMarkerSymbolV2 *>( category.symbol() );
731  if ( !ddSize.hasDefaultValues() && symbol->dataDefinedSize() != ddSize )
732  {
733  // no common size expression
735  }
736  else
737  {
738  ddSize = symbol->dataDefinedSize();
739  }
740  }
741 
742  if ( !ddSize.isActive() || !ddSize.useExpression() )
743  {
745  }
746 
747  QgsScaleExpression exp( ddSize.expressionString() );
748  if ( exp.type() != QgsScaleExpression::Unknown )
749  {
750  QgsLegendSymbolItemV2 title( NULL, exp.baseExpression(), "" );
751  lst << title;
752  foreach ( double v, QgsSymbolLayerV2Utils::prettyBreaks( exp.minValue(), exp.maxValue(), 4 ) )
753  {
755  QgsMarkerSymbolV2 * s = static_cast<QgsMarkerSymbolV2 *>( si.symbol() );
757  s->setSize( exp.size( v ) );
758  lst << si;
759  }
760  // now list the categorized symbols
762  foreach ( QgsLegendSymbolItemV2 item, list2 )
763  lst << item;
764  return lst;
765  }
766  }
767 
769 }
770 
772 {
773  return mSourceSymbol.data();
774 }
776 {
777  mSourceSymbol.reset( sym );
778 }
779 
781 {
782  return mSourceColorRamp.data();
783 }
784 
786 {
787  mSourceColorRamp.reset( ramp );
788 }
789 
791 {
792  setSourceColorRamp( ramp );
793  setInvertedColorRamp( inverted );
794  double num = mCategories.count() - 1;
795  double count = 0;
796 
797  QgsRandomColorsV2* randomRamp = dynamic_cast<QgsRandomColorsV2*>( ramp );
798  if ( randomRamp )
799  {
800  //ramp is a random colors ramp, so inform it of the total number of required colors
801  //this allows the ramp to pregenerate a set of visually distinctive colors
802  randomRamp->setTotalColorCount( mCategories.count() );
803  }
804 
805  foreach ( const QgsRendererCategoryV2 &cat, mCategories )
806  {
807  double value = count / num;
808  if ( mInvertedColorRamp ) value = 1.0 - value;
809  cat.symbol()->setColor( mSourceColorRamp->color( value ) );
810  count += 1;
811  }
812 }
813 
815 {
817 }
818 
820 {
822 }
823 
825 {
827 }
828 
830 {
832 }
833 
835 {
836  int i = 0;
837  foreach ( QgsRendererCategoryV2 cat, mCategories )
838  {
839  QgsSymbolV2* symbol = sym->clone();
840  symbol->setColor( cat.symbol()->color() );
841  updateCategorySymbol( i, symbol );
842  ++i;
843  }
844 }
845 
847 {
850  for ( ; catIt != mCategories.constEnd(); ++catIt )
851  {
852  setScaleMethodToSymbol( catIt->symbol(), scaleMethod );
853  }
854 }
855 
857 {
858  return true;
859 }
860 
862 {
863  bool ok;
864  int index = key.toInt( &ok );
865  if ( ok && index >= 0 && index < mCategories.size() )
866  return mCategories[ index ].renderState();
867  else
868  return true;
869 }
870 
872 {
873  bool ok;
874  int index = key.toInt( &ok );
875  if ( ok )
876  updateCategoryRenderState( index, state );
877 }
878 
880 
882 {
883  if ( renderer->type() == "categorizedSymbol" )
884  {
885  return dynamic_cast<QgsCategorizedSymbolRendererV2*>( renderer->clone() );
886  }
887  if ( renderer->type() == "pointDisplacement" )
888  {
889  const QgsPointDisplacementRenderer* pointDisplacementRenderer = dynamic_cast<const QgsPointDisplacementRenderer*>( renderer );
890  if ( pointDisplacementRenderer )
891  return convertFromRenderer( pointDisplacementRenderer->embeddedRenderer() );
892  }
893  if ( renderer->type() == "invertedPolygonRenderer" )
894  {
895  const QgsInvertedPolygonRenderer* invertedPolygonRenderer = dynamic_cast<const QgsInvertedPolygonRenderer*>( renderer );
896  if ( invertedPolygonRenderer )
897  return convertFromRenderer( invertedPolygonRenderer->embeddedRenderer() );
898  }
899 
900  // If not one of the specifically handled renderers, then just grab the symbol from the renderer
901  // Could have applied this to specific renderer types (singleSymbol, graduatedSymbo)
902 
904  QgsSymbolV2List symbols = const_cast<QgsFeatureRendererV2 *>( renderer )->symbols();
905  if ( symbols.size() > 0 )
906  {
907  r->setSourceSymbol( symbols.at( 0 )->clone() );
908  }
909 
910  return r;
911 }
Class for parsing and evaluation of expressions (formerly called "search strings").
Definition: qgsexpression.h:86
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:93
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.
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 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:354
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:173
virtual void setTotalColorCount(const int colorCount)
Sets the desired total number of unique colors for the resultant ramp.
QString expressionString() const
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:119
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)
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
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
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.
static void convertSymbolSizeScale(QgsSymbolV2 *symbol, QgsSymbolV2::ScaleMethod method, const QString &field)
QgsFeatureRendererV2 * embeddedRenderer() const
bool useExpression() const
QDomText createTextNode(const QString &value)
void updateColorRamp(QgsVectorColorRampV2 *ramp, bool inverted=false)
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
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 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
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:162
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)
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
virtual QgsSymbolV2List symbols() override
for symbol levels
static QPixmap symbolPreviewPixmap(QgsSymbolV2 *symbol, QSize size, QgsRenderContext *customContext=0)
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