QGIS API Documentation  2.11.0-Master
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
qgscategorizedsymbolrendererv2.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgscategorizedsymbolrendererv2.cpp
3  ---------------------
4  begin : November 2009
5  copyright : (C) 2009 by Martin Dobias
6  email : wonder dot sk at gmail dot com
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
15 #include <algorithm>
16 
18 
19 #include "qgssymbolv2.h"
20 #include "qgssymbollayerv2utils.h"
21 #include "qgsvectorcolorrampv2.h"
24 #include "qgspainteffect.h"
25 #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  return;
429 }
430 
432 {
434  for ( ; it != mCategories.end(); ++it )
435  it->symbol()->stopRender( context );
436 
437  // cleanup mTempSymbols
439  for ( ; it2 != mTempSymbols.end(); ++it2 )
440  {
441  it2.value()->stopRender( context );
442  delete it2.value();
443  }
445  mExpression.reset();
446 }
447 
449 {
450  QSet<QString> attributes;
451 
452  // mAttrName can contain either attribute name or an expression.
453  // Sometimes it is not possible to distinguish between those two,
454  // e.g. "a - b" can be both a valid attribute name or expression.
455  // Since we do not have access to fields here, try both options.
456  attributes << mAttrName;
457 
458  QgsExpression testExpr( mAttrName );
459  if ( !testExpr.hasParserError() )
460  attributes.unite( testExpr.referencedColumns().toSet() );
461 
462  if ( mRotation.data() ) attributes.unite( mRotation->referencedColumns().toSet() );
463  if ( mSizeScale.data() ) attributes.unite( mSizeScale->referencedColumns().toSet() );
464 
466  for ( ; catIt != mCategories.constEnd(); ++catIt )
467  {
468  QgsSymbolV2* catSymbol = catIt->symbol();
469  if ( catSymbol )
470  {
471  attributes.unite( catSymbol->usedAttributes() );
472  }
473  }
474  return attributes.toList();
475 }
476 
478 {
479  QString s = QString( "CATEGORIZED: idx %1\n" ).arg( mAttrName );
480  for ( int i = 0; i < mCategories.count(); i++ )
481  s += mCategories[i].dump();
482  return s;
483 }
484 
486 {
488  if ( mSourceSymbol.data() )
489  r->setSourceSymbol( mSourceSymbol->clone() );
490  if ( mSourceColorRamp.data() )
491  {
492  r->setSourceColorRamp( mSourceColorRamp->clone() );
494  }
498  //r->setScaleMethod( scaleMethod() );
499 
500  copyPaintEffect( r );
501  return r;
502 }
503 
505 {
506  QgsStringMap props;
507  props[ "attribute" ] = mAttrName;
508  if ( mRotation.data() )
509  props[ "angle" ] = mRotation->expression();
510  if ( mSizeScale.data() )
511  props[ "scale" ] = mSizeScale->expression();
512 
513  // create a Rule for each range
515  {
516  QgsStringMap catProps( props );
517  it->toSld( doc, element, catProps );
518  }
519 }
520 
522 {
523  QgsSymbolV2List lst;
524  for ( int i = 0; i < mCategories.count(); i++ )
525  lst.append( mCategories[i].symbol() );
526  return lst;
527 }
528 
530 {
531  QDomElement symbolsElem = element.firstChildElement( "symbols" );
532  if ( symbolsElem.isNull() )
533  return NULL;
534 
535  QDomElement catsElem = element.firstChildElement( "categories" );
536  if ( catsElem.isNull() )
537  return NULL;
538 
539  QgsSymbolV2Map symbolMap = QgsSymbolLayerV2Utils::loadSymbols( symbolsElem );
540  QgsCategoryList cats;
541 
542  QDomElement catElem = catsElem.firstChildElement();
543  while ( !catElem.isNull() )
544  {
545  if ( catElem.tagName() == "category" )
546  {
547  QVariant value = QVariant( catElem.attribute( "value" ) );
548  QString symbolName = catElem.attribute( "symbol" );
549  QString label = catElem.attribute( "label" );
550  bool render = catElem.attribute( "render" ) != "false";
551  if ( symbolMap.contains( symbolName ) )
552  {
553  QgsSymbolV2* symbol = symbolMap.take( symbolName );
554  cats.append( QgsRendererCategoryV2( value, symbol, label, render ) );
555  }
556  }
557  catElem = catElem.nextSiblingElement();
558  }
559 
560  QString attrName = element.attribute( "attr" );
561 
563 
564  // delete symbols if there are any more
566 
567  // try to load source symbol (optional)
568  QDomElement sourceSymbolElem = element.firstChildElement( "source-symbol" );
569  if ( !sourceSymbolElem.isNull() )
570  {
571  QgsSymbolV2Map sourceSymbolMap = QgsSymbolLayerV2Utils::loadSymbols( sourceSymbolElem );
572  if ( sourceSymbolMap.contains( "0" ) )
573  {
574  r->setSourceSymbol( sourceSymbolMap.take( "0" ) );
575  }
576  QgsSymbolLayerV2Utils::clearSymbolMap( sourceSymbolMap );
577  }
578 
579  // try to load color ramp (optional)
580  QDomElement sourceColorRampElem = element.firstChildElement( "colorramp" );
581  if ( !sourceColorRampElem.isNull() && sourceColorRampElem.attribute( "name" ) == "[source]" )
582  {
583  r->setSourceColorRamp( QgsSymbolLayerV2Utils::loadColorRamp( sourceColorRampElem ) );
584  QDomElement invertedColorRampElem = element.firstChildElement( "invertedcolorramp" );
585  if ( !invertedColorRampElem.isNull() )
586  r->setInvertedColorRamp( invertedColorRampElem.attribute( "value" ) == "1" );
587  }
588 
589  QDomElement rotationElem = element.firstChildElement( "rotation" );
590  if ( !rotationElem.isNull() && !rotationElem.attribute( "field" ).isEmpty() )
591  {
593  for ( ; it != r->mCategories.end(); ++it )
594  {
595  convertSymbolRotation( it->symbol(), rotationElem.attribute( "field" ) );
596  }
597  if ( r->mSourceSymbol.data() )
598  {
599  convertSymbolRotation( r->mSourceSymbol.data(), rotationElem.attribute( "field" ) );
600  }
601  }
602 
603  QDomElement sizeScaleElem = element.firstChildElement( "sizescale" );
604  if ( !sizeScaleElem.isNull() && !sizeScaleElem.attribute( "field" ).isEmpty() )
605  {
607  for ( ; it != r->mCategories.end(); ++it )
608  {
609  convertSymbolSizeScale( it->symbol(),
610  QgsSymbolLayerV2Utils::decodeScaleMethod( sizeScaleElem.attribute( "scalemethod" ) ),
611  sizeScaleElem.attribute( "field" ) );
612  }
613  if ( r->mSourceSymbol.data() && r->mSourceSymbol->type() == QgsSymbolV2::Marker )
614  {
616  QgsSymbolLayerV2Utils::decodeScaleMethod( sizeScaleElem.attribute( "scalemethod" ) ),
617  sizeScaleElem.attribute( "field" ) );
618  }
619  }
620 
621  // TODO: symbol levels
622  return r;
623 }
624 
626 {
627  QDomElement rendererElem = doc.createElement( RENDERER_TAG_NAME );
628  rendererElem.setAttribute( "type", "categorizedSymbol" );
629  rendererElem.setAttribute( "symbollevels", ( mUsingSymbolLevels ? "1" : "0" ) );
630  rendererElem.setAttribute( "forceraster", ( mForceRaster ? "1" : "0" ) );
631  rendererElem.setAttribute( "attr", mAttrName );
632 
633  // categories
634  int i = 0;
636  QDomElement catsElem = doc.createElement( "categories" );
638  for ( ; it != mCategories.end(); ++it )
639  {
640  const QgsRendererCategoryV2& cat = *it;
641  QString symbolName = QString::number( i );
642  symbols.insert( symbolName, cat.symbol() );
643 
644  QDomElement catElem = doc.createElement( "category" );
645  catElem.setAttribute( "value", cat.value().toString() );
646  catElem.setAttribute( "symbol", symbolName );
647  catElem.setAttribute( "label", cat.label() );
648  catElem.setAttribute( "render", cat.renderState() ? "true" : "false" );
649  catsElem.appendChild( catElem );
650  i++;
651  }
652 
653  rendererElem.appendChild( catsElem );
654 
655  // save symbols
656  QDomElement symbolsElem = QgsSymbolLayerV2Utils::saveSymbols( symbols, "symbols", doc );
657  rendererElem.appendChild( symbolsElem );
658 
659  // save source symbol
660  if ( mSourceSymbol.data() )
661  {
662  QgsSymbolV2Map sourceSymbols;
663  sourceSymbols.insert( "0", mSourceSymbol.data() );
664  QDomElement sourceSymbolElem = QgsSymbolLayerV2Utils::saveSymbols( sourceSymbols, "source-symbol", doc );
665  rendererElem.appendChild( sourceSymbolElem );
666  }
667 
668  // save source color ramp
669  if ( mSourceColorRamp.data() )
670  {
671  QDomElement colorRampElem = QgsSymbolLayerV2Utils::saveColorRamp( "[source]", mSourceColorRamp.data(), doc );
672  rendererElem.appendChild( colorRampElem );
673  QDomElement invertedElem = doc.createElement( "invertedcolorramp" );
674  invertedElem.setAttribute( "value", mInvertedColorRamp );
675  rendererElem.appendChild( invertedElem );
676  }
677 
678  QDomElement rotationElem = doc.createElement( "rotation" );
679  if ( mRotation.data() )
681  rendererElem.appendChild( rotationElem );
682 
683  QDomElement sizeScaleElem = doc.createElement( "sizescale" );
684  if ( mSizeScale.data() )
686  sizeScaleElem.setAttribute( "scalemethod", QgsSymbolLayerV2Utils::encodeScaleMethod( mScaleMethod ) );
687  rendererElem.appendChild( sizeScaleElem );
688 
689  if ( mPaintEffect )
690  mPaintEffect->saveProperties( doc, rendererElem );
691 
692  return rendererElem;
693 }
694 
696 {
698  int count = categories().count();
699  for ( int i = 0; i < count; i++ )
700  {
701  const QgsRendererCategoryV2& cat = categories()[i];
703  lst << qMakePair( cat.label(), pix );
704  }
705  return lst;
706 }
707 
709 {
710  Q_UNUSED( scaleDenominator );
712 
713  foreach ( const QgsRendererCategoryV2& cat, mCategories )
714  {
715  if ( rule.isEmpty() || cat.label() == rule )
716  {
717  lst << qMakePair( cat.label(), cat.symbol() );
718  }
719  }
720  return lst;
721 }
722 
724 {
726  if ( mSourceSymbol.data() && mSourceSymbol->type() == QgsSymbolV2::Marker )
727  {
728  // check that all symbols that have the same size expression
729  QgsDataDefined ddSize;
730  foreach ( QgsRendererCategoryV2 category, mCategories )
731  {
732  const QgsMarkerSymbolV2 * symbol = static_cast<const QgsMarkerSymbolV2 *>( category.symbol() );
733  if ( !ddSize.hasDefaultValues() && symbol->dataDefinedSize() != ddSize )
734  {
735  // no common size expression
737  }
738  else
739  {
740  ddSize = symbol->dataDefinedSize();
741  }
742  }
743 
744  if ( !ddSize.isActive() || !ddSize.useExpression() )
745  {
747  }
748 
749  QgsScaleExpression exp( ddSize.expressionString() );
750  if ( exp.type() != QgsScaleExpression::Unknown )
751  {
752  QgsLegendSymbolItemV2 title( NULL, exp.baseExpression(), "" );
753  lst << title;
754  foreach ( double v, QgsSymbolLayerV2Utils::prettyBreaks( exp.minValue(), exp.maxValue(), 4 ) )
755  {
757  QgsMarkerSymbolV2 * s = static_cast<QgsMarkerSymbolV2 *>( si.symbol() );
759  s->setSize( exp.size( v ) );
760  lst << si;
761  }
762  // now list the categorized symbols
764  foreach ( QgsLegendSymbolItemV2 item, list2 )
765  lst << item;
766  return lst;
767  }
768  }
769 
771 }
772 
774 {
775  return mSourceSymbol.data();
776 }
778 {
779  mSourceSymbol.reset( sym );
780 }
781 
783 {
784  return mSourceColorRamp.data();
785 }
786 
788 {
789  mSourceColorRamp.reset( ramp );
790 }
791 
793 {
794  setSourceColorRamp( ramp );
795  setInvertedColorRamp( inverted );
796  double num = mCategories.count() - 1;
797  double count = 0;
798 
799  QgsRandomColorsV2* randomRamp = dynamic_cast<QgsRandomColorsV2*>( ramp );
800  if ( randomRamp )
801  {
802  //ramp is a random colors ramp, so inform it of the total number of required colors
803  //this allows the ramp to pregenerate a set of visually distinctive colors
804  randomRamp->setTotalColorCount( mCategories.count() );
805  }
806 
807  foreach ( const QgsRendererCategoryV2 &cat, mCategories )
808  {
809  double value = count / num;
810  if ( mInvertedColorRamp ) value = 1.0 - value;
811  cat.symbol()->setColor( mSourceColorRamp->color( value ) );
812  count += 1;
813  }
814 }
815 
817 {
819 }
820 
822 {
824 }
825 
827 {
829 }
830 
832 {
834 }
835 
837 {
838  int i = 0;
839  foreach ( QgsRendererCategoryV2 cat, mCategories )
840  {
841  QgsSymbolV2* symbol = sym->clone();
842  symbol->setColor( cat.symbol()->color() );
843  updateCategorySymbol( i, symbol );
844  ++i;
845  }
846 }
847 
849 {
852  for ( ; catIt != mCategories.constEnd(); ++catIt )
853  {
854  setScaleMethodToSymbol( catIt->symbol(), scaleMethod );
855  }
856 }
857 
859 {
860  return true;
861 }
862 
864 {
865  bool ok;
866  int index = key.toInt( &ok );
867  if ( ok && index >= 0 && index < mCategories.size() )
868  return mCategories[ index ].renderState();
869  else
870  return true;
871 }
872 
874 {
875  bool ok;
876  int index = key.toInt( &ok );
877  if ( ok )
878  updateCategoryRenderState( index, state );
879 }
880 
882 
884 {
885  if ( renderer->type() == "categorizedSymbol" )
886  {
887  return dynamic_cast<QgsCategorizedSymbolRendererV2*>( renderer->clone() );
888  }
889  if ( renderer->type() == "pointDisplacement" )
890  {
891  const QgsPointDisplacementRenderer* pointDisplacementRenderer = dynamic_cast<const QgsPointDisplacementRenderer*>( renderer );
892  if ( pointDisplacementRenderer )
893  return convertFromRenderer( pointDisplacementRenderer->embeddedRenderer() );
894  }
895  if ( renderer->type() == "invertedPolygonRenderer" )
896  {
897  const QgsInvertedPolygonRenderer* invertedPolygonRenderer = dynamic_cast<const QgsInvertedPolygonRenderer*>( renderer );
898  if ( invertedPolygonRenderer )
899  return convertFromRenderer( invertedPolygonRenderer->embeddedRenderer() );
900  }
901 
902  // If not one of the specifically handled renderers, then just grab the symbol from the renderer
903  // Could have applied this to specific renderer types (singleSymbol, graduatedSymbo)
904 
906  QgsSymbolV2List symbols = const_cast<QgsFeatureRendererV2 *>( renderer )->symbols();
907  if ( symbols.size() > 0 )
908  {
909  r->setSourceSymbol( symbols.at( 0 )->clone() );
910  }
911 
912  return r;
913 }
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:162
bool qgsVariantGreaterThan(const QVariant &lhs, const QVariant &rhs)
Definition: qgis.cpp:264
void setSizeScaleField(QString fieldOrExpression)
QScopedPointer< QgsSymbolV2 > mSymbol
QgsPaintEffect * mPaintEffect
void setSourceColorRamp(QgsVectorColorRampV2 *ramp)
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
Needs to be called when a new render cycle is started.
void setSize(double size)
virtual void checkLegendSymbolItem(QString key, bool state=true) override
item in symbology was checked
virtual QgsFeatureRendererV2 * clone() const override
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:182
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)
A vector of attributes.
Definition: qgsfeature.h:109
void addCategory(const QgsRendererCategoryV2 &category)
The class stores information about one class/rule of a vector layer renderer in a unified way that ca...
QString arg(qlonglong a, int fieldWidth, int base, const QChar &fillChar) const
QString toString() const
void sortByValue(Qt::SortOrder order=Qt::AscendingOrder)
bool isActive() const
iterator begin()
T take(const Key &key)
virtual QgsLegendSymbologyList legendSymbologyItems(QSize iconSize) override
return a list of symbology items for the legend
void setScaleMethod(QgsSymbolV2::ScaleMethod scaleMethod)
QScopedPointer< QgsExpression > mExpression
const T value(const Key &key) const
static void convertSymbolRotation(QgsSymbolV2 *symbol, const QString &field)
QColor color() const
virtual QString dump() const override
for debugging