QGIS API Documentation  2.7.0-Master
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
qgsrulebasedrendererv2.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsrulebasedrendererv2.cpp - Rule-based renderer (symbology-ng)
3  ---------------------
4  begin : May 2010
5  copyright : (C) 2010 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 
16 #include "qgsrulebasedrendererv2.h"
17 #include "qgssymbollayerv2.h"
18 #include "qgsexpression.h"
19 #include "qgssymbollayerv2utils.h"
20 #include "qgsrendercontext.h"
21 #include "qgsvectorlayer.h"
22 #include "qgslogger.h"
23 #include "qgsogcutils.h"
27 
28 #include <QSet>
29 
30 #include <QDomDocument>
31 #include <QDomElement>
32 #include <QUuid>
33 
34 
35 QgsRuleBasedRendererV2::Rule::Rule( QgsSymbolV2* symbol, int scaleMinDenom, int scaleMaxDenom, QString filterExp, QString label, QString description, bool elseRule )
36  : mParent( NULL ), mSymbol( symbol )
37  , mScaleMinDenom( scaleMinDenom ), mScaleMaxDenom( scaleMaxDenom )
38  , mFilterExp( filterExp ), mLabel( label ), mDescription( description )
39  , mElseRule( elseRule )
40  , mCheckState( true )
41  , mFilter( NULL )
42 {
43  mRuleKey = QUuid::createUuid().toString();
44  initFilter();
45 }
46 
48 {
49  delete mSymbol;
50  delete mFilter;
51  qDeleteAll( mChildren );
52  // do NOT delete parent
53 }
54 
56 {
57  if ( mElseRule || mFilterExp.compare( "ELSE", Qt::CaseInsensitive ) == 0 )
58  {
59  mElseRule = true;
60  mFilter = NULL;
61  }
62  else if ( !mFilterExp.isEmpty() )
63  {
64  delete mFilter;
65  mFilter = new QgsExpression( mFilterExp );
66  }
67  else
68  {
69  mFilter = NULL;
70  }
71 }
72 
74 {
75  mChildren.append( rule );
76  rule->mParent = this;
77  updateElseRules();
78 }
79 
81 {
82  mChildren.insert( i, rule );
83  rule->mParent = this;
84  updateElseRules();
85 }
86 
88 {
89  mChildren.removeAll( rule );
90  delete rule;
91  updateElseRules();
92 }
93 
95 {
96  Rule* rule = mChildren[i];
97  mChildren.removeAt( i );
98  delete rule;
99  updateElseRules();
100 }
101 
103 {
104  mChildren.removeAll( rule );
105  rule->mParent = NULL;
106  updateElseRules();
107 }
108 
110 {
111  Rule* rule = mChildren.takeAt( i );
112  rule->mParent = NULL;
113  return rule;
114  // updateElseRules();
115 }
116 
118 {
119  // we could use a hash / map for search if this will be slow...
120 
121  if ( key == mRuleKey )
122  return this;
123 
124  foreach ( Rule* rule, mChildren )
125  {
126  Rule* r = rule->findRuleByKey( key );
127  if ( r )
128  return r;
129  }
130  return 0;
131 }
132 
134 {
135  mElseRules.clear();
136  foreach ( Rule* rule, mChildren )
137  {
138  if ( rule->isElse() )
139  mElseRules << rule;
140  }
141 }
142 
143 
144 QString QgsRuleBasedRendererV2::Rule::dump( int offset ) const
145 {
146  QString off;
147  off.fill( QChar( ' ' ), offset );
148  QString symbolDump = ( mSymbol ? mSymbol->dump() : QString( "[]" ) );
149  QString msg = off + QString( "RULE %1 - scale [%2,%3] - filter %4 - symbol %5\n" )
150  .arg( mLabel ).arg( mScaleMinDenom ).arg( mScaleMaxDenom )
151  .arg( mFilterExp ).arg( symbolDump );
152 
153  QStringList lst;
154  foreach ( Rule* rule, mChildren )
155  {
156  lst.append( rule->dump( offset + 2 ) );
157  }
158  msg += lst.join( "\n" );
159  return msg;
160 }
161 
163 {
164  // attributes needed by this rule
165  QSet<QString> attrs;
166  if ( mFilter )
167  attrs.unite( mFilter->referencedColumns().toSet() );
168  if ( mSymbol )
169  attrs.unite( mSymbol->usedAttributes() );
170 
171  // attributes needed by child rules
172  for ( RuleList::iterator it = mChildren.begin(); it != mChildren.end(); ++it )
173  {
174  Rule* rule = *it;
175  attrs.unite( rule->usedAttributes() );
176  }
177  return attrs;
178 }
179 
181 {
182  QgsSymbolV2List lst;
183  if ( mSymbol )
184  lst.append( mSymbol );
185 
186  for ( RuleList::iterator it = mChildren.begin(); it != mChildren.end(); ++it )
187  {
188  Rule* rule = *it;
189  lst += rule->symbols();
190  }
191  return lst;
192 }
193 
195 {
196  delete mSymbol;
197  mSymbol = sym;
198 }
199 
200 QgsLegendSymbolList QgsRuleBasedRendererV2::Rule::legendSymbolItems( double scaleDenominator, QString ruleFilter )
201 {
203  if ( mSymbol && ( ruleFilter.isEmpty() || mLabel == ruleFilter ) )
204  lst << qMakePair( mLabel, mSymbol );
205 
206  for ( RuleList::iterator it = mChildren.begin(); it != mChildren.end(); ++it )
207  {
208  Rule* rule = *it;
209  if ( scaleDenominator == -1 || rule->isScaleOK( scaleDenominator ) )
210  {
211  lst << rule->legendSymbolItems( scaleDenominator, ruleFilter );
212  }
213  }
214  return lst;
215 }
216 
218 {
220  if ( currentLevel != -1 ) // root rule should not be shown
221  {
222  lst << QgsLegendSymbolItemV2( mSymbol, mLabel, mRuleKey, true, mScaleMinDenom, mScaleMaxDenom, currentLevel );
223  }
224 
225  for ( RuleList::const_iterator it = mChildren.constBegin(); it != mChildren.constEnd(); ++it )
226  {
227  Rule* rule = *it;
228  lst << rule->legendSymbolItemsV2( currentLevel + 1 );
229  }
230  return lst;
231 }
232 
233 
235 {
236  if ( ! mFilter || mElseRule )
237  return true;
238 
239  QVariant res = mFilter->evaluate( &f );
240  return res.toInt() != 0;
241 }
242 
243 bool QgsRuleBasedRendererV2::Rule::isScaleOK( double scale ) const
244 {
245  if ( scale == 0 ) // so that we can count features in classes without scale context
246  return true;
247  if ( mScaleMinDenom == 0 && mScaleMaxDenom == 0 )
248  return true;
249  if ( mScaleMinDenom != 0 && mScaleMinDenom > scale )
250  return false;
251  if ( mScaleMaxDenom != 0 && mScaleMaxDenom < scale )
252  return false;
253  return true;
254 }
255 
257 {
258  QgsSymbolV2* sym = mSymbol ? mSymbol->clone() : NULL;
259  Rule* newrule = new Rule( sym, mScaleMinDenom, mScaleMaxDenom, mFilterExp, mLabel, mDescription );
260  newrule->setCheckState( mCheckState );
261  // clone children
262  foreach ( Rule* rule, mChildren )
263  newrule->appendChild( rule->clone() );
264  return newrule;
265 }
266 
267 QDomElement QgsRuleBasedRendererV2::Rule::save( QDomDocument& doc, QgsSymbolV2Map& symbolMap )
268 {
269  QDomElement ruleElem = doc.createElement( "rule" );
270 
271  if ( mSymbol )
272  {
273  int symbolIndex = symbolMap.size();
274  symbolMap[QString::number( symbolIndex )] = mSymbol;
275  ruleElem.setAttribute( "symbol", symbolIndex );
276  }
277  if ( !mFilterExp.isEmpty() )
278  ruleElem.setAttribute( "filter", mFilterExp );
279  if ( mScaleMinDenom != 0 )
280  ruleElem.setAttribute( "scalemindenom", mScaleMinDenom );
281  if ( mScaleMaxDenom != 0 )
282  ruleElem.setAttribute( "scalemaxdenom", mScaleMaxDenom );
283  if ( !mLabel.isEmpty() )
284  ruleElem.setAttribute( "label", mLabel );
285  if ( !mDescription.isEmpty() )
286  ruleElem.setAttribute( "description", mDescription );
287  if ( !mCheckState )
288  ruleElem.setAttribute( "checkstate", 0 );
289  ruleElem.setAttribute( "key", mRuleKey );
290 
291  for ( RuleList::iterator it = mChildren.begin(); it != mChildren.end(); ++it )
292  {
293  Rule* rule = *it;
294  ruleElem.appendChild( rule->save( doc, symbolMap ) );
295  }
296  return ruleElem;
297 }
298 
299 void QgsRuleBasedRendererV2::Rule::toSld( QDomDocument& doc, QDomElement &element, QgsStringMap props )
300 {
301  // do not convert this rule if there are no symbols
302  if ( symbols().isEmpty() )
303  return;
304 
305  if ( !mFilterExp.isEmpty() )
306  {
307  if ( !props.value( "filter", "" ).isEmpty() )
308  props[ "filter" ] += " AND ";
309  props[ "filter" ] += mFilterExp;
310  }
311 
312  if ( mScaleMinDenom != 0 )
313  {
314  bool ok;
315  int parentScaleMinDenom = props.value( "scaleMinDenom", "0" ).toInt( &ok );
316  if ( !ok || parentScaleMinDenom <= 0 )
317  props[ "scaleMinDenom" ] = QString::number( mScaleMinDenom );
318  else
319  props[ "scaleMinDenom" ] = QString::number( qMax( parentScaleMinDenom, mScaleMinDenom ) );
320  }
321 
322  if ( mScaleMaxDenom != 0 )
323  {
324  bool ok;
325  int parentScaleMaxDenom = props.value( "scaleMaxDenom", "0" ).toInt( &ok );
326  if ( !ok || parentScaleMaxDenom <= 0 )
327  props[ "scaleMaxDenom" ] = QString::number( mScaleMaxDenom );
328  else
329  props[ "scaleMaxDenom" ] = QString::number( qMin( parentScaleMaxDenom, mScaleMaxDenom ) );
330  }
331 
332  if ( mSymbol )
333  {
334  QDomElement ruleElem = doc.createElement( "se:Rule" );
335  element.appendChild( ruleElem );
336 
337  //XXX: <se:Name> is the rule identifier, but our the Rule objects
338  // have no properties could be used as identifier. Use the label.
339  QDomElement nameElem = doc.createElement( "se:Name" );
340  nameElem.appendChild( doc.createTextNode( mLabel ) );
341  ruleElem.appendChild( nameElem );
342 
343  if ( !mLabel.isEmpty() || !mDescription.isEmpty() )
344  {
345  QDomElement descrElem = doc.createElement( "se:Description" );
346  if ( !mLabel.isEmpty() )
347  {
348  QDomElement titleElem = doc.createElement( "se:Title" );
349  titleElem.appendChild( doc.createTextNode( mLabel ) );
350  descrElem.appendChild( titleElem );
351  }
352  if ( !mDescription.isEmpty() )
353  {
354  QDomElement abstractElem = doc.createElement( "se:Abstract" );
355  abstractElem.appendChild( doc.createTextNode( mDescription ) );
356  descrElem.appendChild( abstractElem );
357  }
358  ruleElem.appendChild( descrElem );
359  }
360 
361  if ( !props.value( "filter", "" ).isEmpty() )
362  {
363  QgsSymbolLayerV2Utils::createFunctionElement( doc, ruleElem, props.value( "filter", "" ) );
364  }
365 
366  if ( !props.value( "scaleMinDenom", "" ).isEmpty() )
367  {
368  QDomElement scaleMinDenomElem = doc.createElement( "se:MinScaleDenominator" );
369  scaleMinDenomElem.appendChild( doc.createTextNode( props.value( "scaleMinDenom", "" ) ) );
370  ruleElem.appendChild( scaleMinDenomElem );
371  }
372 
373  if ( !props.value( "scaleMaxDenom", "" ).isEmpty() )
374  {
375  QDomElement scaleMaxDenomElem = doc.createElement( "se:MaxScaleDenominator" );
376  scaleMaxDenomElem.appendChild( doc.createTextNode( props.value( "scaleMaxDenom", "" ) ) );
377  ruleElem.appendChild( scaleMaxDenomElem );
378  }
379 
380  mSymbol->toSld( doc, ruleElem, props );
381  }
382 
383  // loop into childern rule list
384  for ( RuleList::iterator it = mChildren.begin(); it != mChildren.end(); ++it )
385  {
386  ( *it )->toSld( doc, element, props );
387  }
388 }
389 
391 {
392  mActiveChildren.clear();
393 
394  if ( ! mCheckState )
395  return false;
396 
397  // filter out rules which are not compatible with this scale
398  if ( !isScaleOK( context.rendererScale() ) )
399  return false;
400 
401  // init this rule
402  if ( mFilter )
403  mFilter->prepare( fields );
404  if ( mSymbol )
405  mSymbol->startRender( context, &fields );
406 
407  // init children
408  // build temporary list of active rules (usable with this scale)
409  for ( RuleList::iterator it = mChildren.begin(); it != mChildren.end(); ++it )
410  {
411  Rule* rule = *it;
412  if ( rule->startRender( context, fields ) )
413  {
414  // only add those which are active with current scale
415  mActiveChildren.append( rule );
416  }
417  }
418  return true;
419 }
420 
422 {
423  QSet<int> symbolZLevelsSet;
424 
425  // process this rule
426  if ( mSymbol )
427  {
428  // find out which Z-levels are used
429  for ( int i = 0; i < mSymbol->symbolLayerCount(); i++ )
430  {
431  symbolZLevelsSet.insert( mSymbol->symbolLayer( i )->renderingPass() );
432  }
433  }
434 
435  // process children
436  QList<Rule*>::iterator it;
437  for ( it = mActiveChildren.begin(); it != mActiveChildren.end(); ++it )
438  {
439  Rule* rule = *it;
440  symbolZLevelsSet.unite( rule->collectZLevels() );
441  }
442  return symbolZLevelsSet;
443 }
444 
445 void QgsRuleBasedRendererV2::Rule::setNormZLevels( const QMap<int, int>& zLevelsToNormLevels )
446 {
447  if ( mSymbol )
448  {
449  for ( int i = 0; i < mSymbol->symbolLayerCount(); i++ )
450  {
451  int normLevel = zLevelsToNormLevels.value( mSymbol->symbolLayer( i )->renderingPass() );
452  mSymbolNormZLevels.append( normLevel );
453  }
454  }
455 
456  // prepare list of normalized levels for each rule
457  for ( QList<Rule*>::iterator it = mActiveChildren.begin(); it != mActiveChildren.end(); ++it )
458  {
459  Rule* rule = *it;
460  rule->setNormZLevels( zLevelsToNormLevels );
461  }
462 }
463 
464 
466 {
467  if ( !isFilterOK( featToRender.feat ) )
468  return false;
469 
470  bool rendered = false;
471 
472  // create job for this feature and this symbol, add to list of jobs
473  if ( mSymbol )
474  {
475  // add job to the queue: each symbol's zLevel must be added
476  foreach ( int normZLevel, mSymbolNormZLevels )
477  {
478  //QgsDebugMsg(QString("add job at level %1").arg(normZLevel));
479  renderQueue[normZLevel].jobs.append( new RenderJob( featToRender, mSymbol ) );
480  }
481  rendered = true;
482  }
483 
484  bool willrendersomething = false;
485 
486  // process children
487  for ( QList<Rule*>::iterator it = mActiveChildren.begin(); it != mActiveChildren.end(); ++it )
488  {
489  Rule* rule = *it;
490  if ( rule->isElse() )
491  {
492  // Don't process else rules yet
493  continue;
494  }
495  willrendersomething |= rule->renderFeature( featToRender, context, renderQueue );
496  rendered |= willrendersomething;
497  }
498 
499  // If none of the rules passed then we jump into the else rules and process them.
500  if ( !willrendersomething )
501  {
502  foreach ( Rule* rule, mElseRules )
503  {
504  rendered |= rule->renderFeature( featToRender, context, renderQueue );
505  }
506  }
507 
508  return rendered;
509 }
510 
512 {
513  if ( !isFilterOK( feat ) )
514  return false;
515  if ( mSymbol )
516  return true;
517 
518  for ( QList<Rule*>::iterator it = mActiveChildren.begin(); it != mActiveChildren.end(); ++it )
519  {
520  Rule* rule = *it;
521  if ( rule->willRenderFeature( feat ) )
522  return true;
523  }
524  return false;
525 }
526 
528 {
529  QgsSymbolV2List lst;
530  if ( !isFilterOK( feat ) )
531  return lst;
532  if ( mSymbol )
533  lst.append( mSymbol );
534 
535  for ( QList<Rule*>::iterator it = mActiveChildren.begin(); it != mActiveChildren.end(); ++it )
536  {
537  Rule* rule = *it;
538  lst += rule->symbolsForFeature( feat );
539  }
540  return lst;
541 }
542 
544 {
545  RuleList lst;
546  if ( !isFilterOK( feat ) )
547  return lst;
548 
549  if ( mSymbol )
550  lst.append( this );
551 
552  for ( QList<Rule*>::iterator it = mActiveChildren.begin(); it != mActiveChildren.end(); ++it )
553  {
554  Rule* rule = *it;
555  lst += rule->rulesForFeature( feat );
556  }
557  return lst;
558 }
559 
561 {
562  if ( mSymbol )
563  mSymbol->stopRender( context );
564 
565  for ( QList<Rule*>::iterator it = mActiveChildren.begin(); it != mActiveChildren.end(); ++it )
566  {
567  Rule* rule = *it;
568  rule->stopRender( context );
569  }
570 
571  mActiveChildren.clear();
572  mSymbolNormZLevels.clear();
573 }
574 
576 {
577  QString symbolIdx = ruleElem.attribute( "symbol" );
578  QgsSymbolV2* symbol = NULL;
579  if ( !symbolIdx.isEmpty() )
580  {
581  if ( symbolMap.contains( symbolIdx ) )
582  {
583  symbol = symbolMap.take( symbolIdx );
584  }
585  else
586  {
587  QgsDebugMsg( "symbol for rule " + symbolIdx + " not found!" );
588  }
589  }
590 
591  QString filterExp = ruleElem.attribute( "filter" );
592  QString label = ruleElem.attribute( "label" );
593  QString description = ruleElem.attribute( "description" );
594  int scaleMinDenom = ruleElem.attribute( "scalemindenom", "0" ).toInt();
595  int scaleMaxDenom = ruleElem.attribute( "scalemaxdenom", "0" ).toInt();
596  QString ruleKey = ruleElem.attribute( "key" );
597  Rule* rule = new Rule( symbol, scaleMinDenom, scaleMaxDenom, filterExp, label, description );
598 
599  if ( !ruleKey.isEmpty() )
600  rule->mRuleKey = ruleKey;
601 
602  rule->setCheckState( ruleElem.attribute( "checkstate", "1" ).toInt() );
603 
604  QDomElement childRuleElem = ruleElem.firstChildElement( "rule" );
605  while ( !childRuleElem.isNull() )
606  {
607  Rule* childRule = create( childRuleElem, symbolMap );
608  if ( childRule )
609  {
610  rule->appendChild( childRule );
611  }
612  else
613  {
614  QgsDebugMsg( "failed to init a child rule!" );
615  }
616  childRuleElem = childRuleElem.nextSiblingElement( "rule" );
617  }
618 
619  return rule;
620 }
621 
623 {
624  if ( ruleElem.localName() != "Rule" )
625  {
626  QgsDebugMsg( QString( "invalid element: Rule element expected, %1 found!" ).arg( ruleElem.tagName() ) );
627  return NULL;
628  }
629 
630  QString label, description, filterExp;
631  int scaleMinDenom = 0, scaleMaxDenom = 0;
632  QgsSymbolLayerV2List layers;
633 
634  // retrieve the Rule element child nodes
635  QDomElement childElem = ruleElem.firstChildElement();
636  while ( !childElem.isNull() )
637  {
638  if ( childElem.localName() == "Name" )
639  {
640  // <se:Name> tag contains the rule identifier,
641  // so prefer title tag for the label property value
642  if ( label.isEmpty() )
643  label = childElem.firstChild().nodeValue();
644  }
645  else if ( childElem.localName() == "Description" )
646  {
647  // <se:Description> can contains a title and an abstract
648  QDomElement titleElem = childElem.firstChildElement( "Title" );
649  if ( !titleElem.isNull() )
650  {
651  label = titleElem.firstChild().nodeValue();
652  }
653 
654  QDomElement abstractElem = childElem.firstChildElement( "Abstract" );
655  if ( !abstractElem.isNull() )
656  {
657  description = abstractElem.firstChild().nodeValue();
658  }
659  }
660  else if ( childElem.localName() == "Abstract" )
661  {
662  // <sld:Abstract> (v1.0)
663  description = childElem.firstChild().nodeValue();
664  }
665  else if ( childElem.localName() == "Title" )
666  {
667  // <sld:Title> (v1.0)
668  label = childElem.firstChild().nodeValue();
669  }
670  else if ( childElem.localName() == "Filter" )
671  {
673  if ( filter )
674  {
675  if ( filter->hasParserError() )
676  {
677  QgsDebugMsg( "parser error: " + filter->parserErrorString() );
678  }
679  else
680  {
681  filterExp = filter->expression();
682  }
683  delete filter;
684  }
685  }
686  else if ( childElem.localName() == "MinScaleDenominator" )
687  {
688  bool ok;
689  int v = childElem.firstChild().nodeValue().toInt( &ok );
690  if ( ok )
691  scaleMinDenom = v;
692  }
693  else if ( childElem.localName() == "MaxScaleDenominator" )
694  {
695  bool ok;
696  int v = childElem.firstChild().nodeValue().toInt( &ok );
697  if ( ok )
698  scaleMaxDenom = v;
699  }
700  else if ( childElem.localName().endsWith( "Symbolizer" ) )
701  {
702  // create symbol layers for this symbolizer
703  QgsSymbolLayerV2Utils::createSymbolLayerV2ListFromSld( childElem, geomType, layers );
704  }
705 
706  childElem = childElem.nextSiblingElement();
707  }
708 
709  // now create the symbol
710  QgsSymbolV2 *symbol = 0;
711  if ( layers.size() > 0 )
712  {
713  switch ( geomType )
714  {
715  case QGis::Line:
716  symbol = new QgsLineSymbolV2( layers );
717  break;
718 
719  case QGis::Polygon:
720  symbol = new QgsFillSymbolV2( layers );
721  break;
722 
723  case QGis::Point:
724  symbol = new QgsMarkerSymbolV2( layers );
725  break;
726 
727  default:
728  QgsDebugMsg( QString( "invalid geometry type: found %1" ).arg( geomType ) );
729  return NULL;
730  }
731  }
732 
733  // and then create and return the new rule
734  return new Rule( symbol, scaleMinDenom, scaleMaxDenom, filterExp, label, description );
735 }
736 
737 
739 
741  : QgsFeatureRendererV2( "RuleRenderer" ), mRootRule( root )
742 {
743 }
744 
746  : QgsFeatureRendererV2( "RuleRenderer" )
747 {
748  mRootRule = new Rule( NULL ); // root has no symbol, no filter etc - just a container
749  mRootRule->appendChild( new Rule( defaultSymbol ) );
750 }
751 
753 {
754  delete mRootRule;
755 }
756 
757 
759 {
760  // not used at all
761  return 0;
762 }
763 
765  QgsRenderContext& context,
766  int layer,
767  bool selected,
768  bool drawVertexMarker )
769 {
770  Q_UNUSED( layer );
771 
772  int flags = ( selected ? FeatIsSelected : 0 ) | ( drawVertexMarker ? FeatDrawMarkers : 0 );
773  mCurrentFeatures.append( FeatureToRender( feature, flags ) );
774 
775  // check each active rule
776  return mRootRule->renderFeature( mCurrentFeatures.last(), context, mRenderQueue );
777 }
778 
779 
781 {
782  // prepare active children
783  mRootRule->startRender( context, fields );
784 
785  QSet<int> symbolZLevelsSet = mRootRule->collectZLevels();
786  QList<int> symbolZLevels = symbolZLevelsSet.toList();
787  qSort( symbolZLevels );
788 
789  // create mapping from unnormalized levels [unlimited range] to normalized levels [0..N-1]
790  // and prepare rendering queue
791  QMap<int, int> zLevelsToNormLevels;
792  int maxNormLevel = -1;
793  foreach ( int zLevel, symbolZLevels )
794  {
795  zLevelsToNormLevels[zLevel] = ++maxNormLevel;
796  mRenderQueue.append( RenderLevel( zLevel ) );
797  QgsDebugMsg( QString( "zLevel %1 -> %2" ).arg( zLevel ).arg( maxNormLevel ) );
798  }
799 
800  mRootRule->setNormZLevels( zLevelsToNormLevels );
801 }
802 
804 {
805  //
806  // do the actual rendering
807  //
808 
809  // go through all levels
810  foreach ( const RenderLevel& level, mRenderQueue )
811  {
812  //QgsDebugMsg(QString("level %1").arg(level.zIndex));
813  // go through all jobs at the level
814  foreach ( const RenderJob* job, level.jobs )
815  {
816  //QgsDebugMsg(QString("job fid %1").arg(job->f->id()));
817  // render feature - but only with symbol layers with specified zIndex
818  QgsSymbolV2* s = job->symbol;
819  int count = s->symbolLayerCount();
820  for ( int i = 0; i < count; i++ )
821  {
822  // TODO: better solution for this
823  // renderFeatureWithSymbol asks which symbol layer to draw
824  // but there are multiple transforms going on!
825  if ( s->symbolLayer( i )->renderingPass() == level.zIndex )
826  {
827  int flags = job->ftr.flags;
828  renderFeatureWithSymbol( job->ftr.feat, job->symbol, context, i, flags & FeatIsSelected, flags & FeatDrawMarkers );
829  }
830  }
831  }
832  }
833 
834  // clean current features
835  mCurrentFeatures.clear();
836 
837  // clean render queue
838  mRenderQueue.clear();
839 
840  // clean up rules from temporary stuff
841  mRootRule->stopRender( context );
842 }
843 
845 {
846  QSet<QString> attrs = mRootRule->usedAttributes();
847  return attrs.values();
848 }
849 
851 {
853 
854  // normally with clone() the individual rules get new keys (UUID), but here we want to keep
855  // the tree of rules intact, so that other components that may use the rule keys work nicely (e.g. visibility presets)
856  clonedRoot->setRuleKey( mRootRule->ruleKey() );
857  RuleList origDescendants = mRootRule->descendants();
858  RuleList clonedDescendants = clonedRoot->descendants();
859  Q_ASSERT( origDescendants.count() == clonedDescendants.count() );
860  for ( int i = 0; i < origDescendants.count(); ++i )
861  clonedDescendants[i]->setRuleKey( origDescendants[i]->ruleKey() );
862 
863  QgsRuleBasedRendererV2* r = new QgsRuleBasedRendererV2( clonedRoot );
864 
866  return r;
867 }
868 
869 void QgsRuleBasedRendererV2::toSld( QDomDocument& doc, QDomElement &element ) const
870 {
871  mRootRule->toSld( doc, element, QgsStringMap() );
872 }
873 
874 // TODO: ideally this function should be removed in favor of legendSymbol(ogy)Items
876 {
877  return mRootRule->symbols();
878 }
879 
880 QDomElement QgsRuleBasedRendererV2::save( QDomDocument& doc )
881 {
882  QDomElement rendererElem = doc.createElement( RENDERER_TAG_NAME );
883  rendererElem.setAttribute( "type", "RuleRenderer" );
884  rendererElem.setAttribute( "symbollevels", ( mUsingSymbolLevels ? "1" : "0" ) );
885 
887 
888  QDomElement rulesElem = mRootRule->save( doc, symbols );
889  rulesElem.setTagName( "rules" ); // instead of just "rule"
890  rendererElem.appendChild( rulesElem );
891 
892  QDomElement symbolsElem = QgsSymbolLayerV2Utils::saveSymbols( symbols, "symbols", doc );
893  rendererElem.appendChild( symbolsElem );
894 
895  return rendererElem;
896 }
897 
899 {
902  for ( QgsLegendSymbolList::iterator it = items.begin(); it != items.end(); ++it )
903  {
904  QPair<QString, QgsSymbolV2*> pair = *it;
905  QPixmap pix = QgsSymbolLayerV2Utils::symbolPreviewPixmap( pair.second, iconSize );
906  lst << qMakePair( pair.first, pix );
907  }
908  return lst;
909 }
910 
912 {
913  return true;
914 }
915 
917 {
918  Rule* rule = mRootRule->findRuleByKey( key );
919  return rule ? rule->checkState() : true;
920 }
921 
922 void QgsRuleBasedRendererV2::checkLegendSymbolItem( QString key, bool state )
923 {
924  Rule* rule = mRootRule->findRuleByKey( key );
925  if ( rule )
926  rule->setCheckState( state );
927 }
928 
929 QgsLegendSymbolList QgsRuleBasedRendererV2::legendSymbolItems( double scaleDenominator, QString rule )
930 {
931  return mRootRule->legendSymbolItems( scaleDenominator, rule );
932 }
933 
935 {
936  return mRootRule->legendSymbolItemsV2();
937 }
938 
939 
941 {
942  // load symbols
943  QDomElement symbolsElem = element.firstChildElement( "symbols" );
944  if ( symbolsElem.isNull() )
945  return NULL;
946 
947  QgsSymbolV2Map symbolMap = QgsSymbolLayerV2Utils::loadSymbols( symbolsElem );
948 
949  QDomElement rulesElem = element.firstChildElement( "rules" );
950 
951  Rule* root = Rule::create( rulesElem, symbolMap );
952  if ( root == NULL )
953  return NULL;
954 
956 
957  // delete symbols if there are any more
959 
960  return r;
961 }
962 
964 {
965  // retrieve child rules
966  Rule* root = 0;
967 
968  QDomElement ruleElem = element.firstChildElement( "Rule" );
969  while ( !ruleElem.isNull() )
970  {
971  Rule *child = Rule::createFromSld( ruleElem, geomType );
972  if ( child )
973  {
974  // create the root rule if not done before
975  if ( !root )
976  root = new Rule( 0 );
977 
978  root->appendChild( child );
979  }
980 
981  ruleElem = ruleElem.nextSiblingElement( "Rule" );
982  }
983 
984  if ( !root )
985  {
986  // no valid rules was found
987  return NULL;
988  }
989 
990  // create and return the new renderer
991  return new QgsRuleBasedRendererV2( root );
992 }
993 
996 
998 {
999  foreach ( const QgsRendererCategoryV2& cat, r->categories() )
1000  {
1001  QString attr = QgsExpression::quotedColumnRef( r->classAttribute() );
1002  QString value;
1003  // not quoting numbers saves a type cast
1004  if ( cat.value().type() == QVariant::Int )
1005  value = cat.value().toString();
1006  else if ( cat.value().type() == QVariant::Double )
1007  // we loose precision here - so we may miss some categories :-(
1008  // TODO: have a possibility to construct expressions directly as a parse tree to avoid loss of precision
1009  value = QString::number( cat.value().toDouble(), 'f', 4 );
1010  else
1011  value = QgsExpression::quotedString( cat.value().toString() );
1012  QString filter = QString( "%1 = %2" ).arg( attr ).arg( value );
1013  QString label = filter;
1014  initialRule->appendChild( new Rule( cat.symbol()->clone(), 0, 0, filter, label ) );
1015  }
1016 }
1017 
1019 {
1020  foreach ( const QgsRendererRangeV2& rng, r->ranges() )
1021  {
1022  // due to the loss of precision in double->string conversion we may miss out values at the limit of the range
1023  // TODO: have a possibility to construct expressions directly as a parse tree to avoid loss of precision
1024  QString attr = QgsExpression::quotedColumnRef( r->classAttribute() );
1025  QString filter = QString( "%1 >= %2 AND %1 <= %3" ).arg( attr )
1026  .arg( QString::number( rng.lowerValue(), 'f', 4 ) )
1027  .arg( QString::number( rng.upperValue(), 'f', 4 ) );
1028  QString label = filter;
1029  initialRule->appendChild( new Rule( rng.symbol()->clone(), 0, 0, filter, label ) );
1030  }
1031 }
1032 
1034 {
1035  qSort( scales ); // make sure the scales are in ascending order
1036  int oldScale = initialRule->scaleMinDenom();
1037  int maxDenom = initialRule->scaleMaxDenom();
1038  QgsSymbolV2* symbol = initialRule->symbol();
1039  foreach ( int scale, scales )
1040  {
1041  if ( initialRule->scaleMinDenom() >= scale )
1042  continue; // jump over the first scales out of the interval
1043  if ( maxDenom != 0 && maxDenom <= scale )
1044  break; // ignore the latter scales out of the interval
1045  initialRule->appendChild( new Rule( symbol->clone(), oldScale, scale, QString(), QString( "%1 - %2" ).arg( oldScale ).arg( scale ) ) );
1046  oldScale = scale;
1047  }
1048  // last rule
1049  initialRule->appendChild( new Rule( symbol->clone(), oldScale, maxDenom, QString(), QString( "%1 - %2" ).arg( oldScale ).arg( maxDenom ) ) );
1050 }
1051 
1053 {
1054  QString msg( "Rule-based renderer:\n" );
1055  msg += mRootRule->dump();
1056  return msg;
1057 }
1058 
1060 {
1061  return mRootRule->willRenderFeature( feat );
1062 }
1063 
1065 {
1066  return mRootRule->symbolsForFeature( feat );
1067 }
1068 
1070 {
1071  return mRootRule->symbolsForFeature( feat );
1072 }
1073 
1075 {
1076  if ( renderer->type() == "RuleRenderer" )
1077  {
1078  return dynamic_cast<QgsRuleBasedRendererV2*>( renderer->clone() );
1079  }
1080 
1081  if ( renderer->type() == "singleSymbol" )
1082  {
1083  const QgsSingleSymbolRendererV2* singleSymbolRenderer = dynamic_cast<const QgsSingleSymbolRendererV2*>( renderer );
1084  QgsSymbolV2* origSymbol = singleSymbolRenderer->symbol()->clone();
1085  convertToDataDefinedSymbology( origSymbol, singleSymbolRenderer->sizeScaleField(), singleSymbolRenderer->rotationField() );
1086  return new QgsRuleBasedRendererV2( origSymbol );
1087  }
1088 
1089  if ( renderer->type() == "categorizedSymbol" )
1090  {
1091  const QgsCategorizedSymbolRendererV2* categorizedRenderer = dynamic_cast<const QgsCategorizedSymbolRendererV2*>( renderer );
1093 
1094  QString expression;
1095  QString value;
1096  QgsRendererCategoryV2 category;
1097  for ( int i = 0; i < categorizedRenderer->categories().size(); ++i )
1098  {
1099  category = categorizedRenderer->categories().value( i );
1101 
1102  rule->setLabel( category.label() );
1103 
1104  //We first define the rule corresponding to the category
1105  //If the value is a number, we can use it directly, otherwise we need to quote it in the rule
1106  if ( QVariant( category.value() ).convert( QVariant::Double ) )
1107  {
1108  value = category.value().toString();
1109  }
1110  else
1111  {
1112  value = "'" + category.value().toString() + "'";
1113  }
1114 
1115  //An empty category is equivalent to the ELSE keyword
1116  if ( value == "''" )
1117  {
1118  expression = "ELSE";
1119  }
1120  else
1121  {
1122  expression = categorizedRenderer->classAttribute() + " = " + value;
1123  }
1124  rule->setFilterExpression( expression );
1125 
1126  //Then we construct an equivalent symbol.
1127  //Ideally we could simply copy the symbol, but the categorized renderer allows a separate interface to specify
1128  //data dependent area and rotation, so we need to convert these to obtain the same rendering
1129 
1130  QgsSymbolV2* origSymbol = category.symbol()->clone();
1131  convertToDataDefinedSymbology( origSymbol, categorizedRenderer->sizeScaleField(), categorizedRenderer->rotationField() );
1132  rule->setSymbol( origSymbol );
1133 
1134  rootrule->appendChild( rule );
1135  }
1136 
1137  return new QgsRuleBasedRendererV2( rootrule );
1138  }
1139 
1140  if ( renderer->type() == "graduatedSymbol" )
1141  {
1142 
1143  const QgsGraduatedSymbolRendererV2* graduatedRenderer = dynamic_cast<const QgsGraduatedSymbolRendererV2*>( renderer );
1144 
1146 
1147  QString expression;
1148  QgsRendererRangeV2 range;
1149  for ( int i = 0; i < graduatedRenderer->ranges().size();++i )
1150  {
1151  range = graduatedRenderer->ranges().value( i );
1153  rule->setLabel( range.label() );
1154  if ( i == 0 )//The lower boundary of the first range is included, while it is excluded for the others
1155  {
1156  expression = graduatedRenderer->classAttribute() + " >= " + QString::number( range.lowerValue(), 'f' ) + " AND " + \
1157  graduatedRenderer->classAttribute() + " <= " + QString::number( range.upperValue(), 'f' );
1158  }
1159  else
1160  {
1161  expression = graduatedRenderer->classAttribute() + " > " + QString::number( range.lowerValue(), 'f' ) + " AND " + \
1162  graduatedRenderer->classAttribute() + " <= " + QString::number( range.upperValue(), 'f' );
1163  }
1164  rule->setFilterExpression( expression );
1165 
1166  //Then we construct an equivalent symbol.
1167  //Ideally we could simply copy the symbol, but the graduated renderer allows a separate interface to specify
1168  //data dependent area and rotation, so we need to convert these to obtain the same rendering
1169 
1170  QgsSymbolV2* symbol = range.symbol()->clone();
1171  convertToDataDefinedSymbology( symbol, graduatedRenderer->sizeScaleField(), graduatedRenderer->rotationField() );
1172 
1173  rule->setSymbol( symbol );
1174 
1175  rootrule->appendChild( rule );
1176  }
1177 
1178  return new QgsRuleBasedRendererV2( rootrule );
1179  }
1180 
1181  if ( renderer->type() == "pointDisplacement" )
1182  {
1183  const QgsPointDisplacementRenderer* pointDisplacementRenderer = dynamic_cast<const QgsPointDisplacementRenderer*>( renderer );
1184  return convertFromRenderer( pointDisplacementRenderer->embeddedRenderer() );
1185  }
1186  if ( renderer->type() == "invertedPolygonRenderer" )
1187  {
1188  const QgsInvertedPolygonRenderer* invertedPolygonRenderer = dynamic_cast<const QgsInvertedPolygonRenderer*>( renderer );
1189  return convertFromRenderer( invertedPolygonRenderer->embeddedRenderer() );
1190  }
1191 
1192  return NULL;
1193 }
1194 
1195 void QgsRuleBasedRendererV2::convertToDataDefinedSymbology( QgsSymbolV2* symbol, QString sizeScaleField, QString rotationField )
1196 {
1197  QString sizeExpression;
1198  switch ( symbol->type() )
1199  {
1200  case QgsSymbolV2::Marker:
1201  for ( int j = 0; j < symbol->symbolLayerCount();++j )
1202  {
1203  QgsMarkerSymbolLayerV2* msl = static_cast<QgsMarkerSymbolLayerV2*>( symbol->symbolLayer( j ) );
1204  if ( ! sizeScaleField.isNull() )
1205  {
1206  sizeExpression = QString( "%1*(%2)" ).arg( msl->size() ).arg( sizeScaleField );
1207  msl->setDataDefinedProperty( "size", sizeExpression );
1208  }
1209  if ( ! rotationField.isNull() )
1210  {
1211  msl->setDataDefinedProperty( "angle", rotationField );
1212  }
1213  }
1214  break;
1215  case QgsSymbolV2::Line:
1216  if ( ! sizeScaleField.isNull() )
1217  {
1218  for ( int j = 0; j < symbol->symbolLayerCount();++j )
1219  {
1220  if ( symbol->symbolLayer( j )->layerType() == "SimpleLine" )
1221  {
1222  QgsLineSymbolLayerV2* lsl = static_cast<QgsLineSymbolLayerV2*>( symbol->symbolLayer( j ) );
1223  sizeExpression = QString( "%1*(%2)" ).arg( lsl->width() ).arg( sizeScaleField );
1224  lsl->setDataDefinedProperty( "width", sizeExpression );
1225  }
1226  if ( symbol->symbolLayer( j )->layerType() == "MarkerLine" )
1227  {
1228  QgsSymbolV2* marker = symbol->symbolLayer( j )->subSymbol();
1229  for ( int k = 0; k < marker->symbolLayerCount();++k )
1230  {
1231  QgsMarkerSymbolLayerV2* msl = static_cast<QgsMarkerSymbolLayerV2*>( marker->symbolLayer( k ) );
1232  sizeExpression = QString( "%1*(%2)" ).arg( msl->size() ).arg( sizeScaleField );
1233  msl->setDataDefinedProperty( "size", sizeExpression );
1234  }
1235  }
1236  }
1237  }
1238  break;
1239  default:
1240  break;
1241  }
1242 }
void toSld(QDomDocument &doc, QDomElement &element, QgsStringMap props)
QMap< QString, QgsSymbolV2 * > QgsSymbolV2Map
Definition: qgsrendererv2.h:38
virtual void startRender(QgsRenderContext &context, const QgsFields &fields)
Class for parsing and evaluation of expressions (formerly called "search strings").
Definition: qgsexpression.h:87
QgsSymbolV2List symbolsForFeature(QgsFeature &feat)
tell which symbols will be used to render the feature
static QgsSymbolV2Map loadSymbols(QDomElement &element)
void setNormZLevels(const QMap< int, int > &zLevelsToNormLevels)
assign normalized z-levels [0..N-1] for this rule's symbol for quick access during rendering ...
#define RENDERER_TAG_NAME
Definition: qgsrendererv2.h:46
bool hasParserError() const
Returns true if an error occurred when parsing the input expression.
Definition: qgsexpression.h:94
virtual QgsSymbolV2List symbolsForFeature(QgsFeature &feat)
return list of symbols used for rendering the feature.
virtual QString dump() const
for debugging
const QgsCategoryList & categories() const
QString rotationField() const
return rotation field name (or empty string if not set or not supported by renderer) ...
static QString quotedColumnRef(QString name)
return quoted column reference (in double quotes)
virtual double width() const
QList< QgsSymbolV2 * > QgsSymbolV2List
Definition: qgsrendererv2.h:37
QSet< int > collectZLevels()
get all used z-levels from this rule and children
const QString expression() const
Alias for dump()
static QgsFeatureRendererV2 * create(QDomElement &element)
SymbolType type() const
Definition: qgssymbolv2.h:79
#define QgsDebugMsg(str)
Definition: qgslogger.h:33
static void convertToDataDefinedSymbology(QgsSymbolV2 *symbol, QString sizeScaleField, QString rotationField)
helper function to convert the size scale and rotation fields present in some other renderers to data...
double rendererScale() const
virtual QgsSymbolV2 * clone() const =0
static QgsFeatureRendererV2 * createFromSld(QDomElement &element, QGis::GeometryType geomType)
virtual void stopRender(QgsRenderContext &context)
virtual QgsSymbolV2List originalSymbolsForFeature(QgsFeature &feat)
Equivalent of originalSymbolsForFeature() call extended to support renderers that may use more symbol...
QString rotationField() const
return rotation field name (or empty string if not set or not supported by renderer) ...
bool isScaleOK(double scale) const
virtual QgsLegendSymbologyList legendSymbologyItems(QSize iconSize)
return a list of symbology items for the legend
bool startRender(QgsRenderContext &context, const QgsFields &fields)
prepare the rule for rendering and its children (build active children array)
Rule * clone() const
clone this rule, return new instance
RuleList rulesForFeature(QgsFeature &feat)
tell which rules will be used to render the feature
Container of fields for a vector layer.
Definition: qgsfield.h:172
void removeChild(Rule *rule)
delete child rule
GeometryType
Definition: qgis.h:155
virtual QDomElement save(QDomDocument &doc)
store renderer info to XML element
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:113
QMap< QString, QString > QgsStringMap
Definition: qgis.h:412
void removeChildAt(int i)
delete child rule
void renderFeatureWithSymbol(QgsFeature &feature, QgsSymbolV2 *symbol, QgsRenderContext &context, int layer, bool selected, bool drawVertexMarker)
QString type() const
Definition: qgsrendererv2.h:80
static bool createSymbolLayerV2ListFromSld(QDomElement &element, QGis::GeometryType geomType, QgsSymbolLayerV2List &layers)
void stopRender(QgsRenderContext &context)
virtual QgsFeatureRendererV2 * clone() const
virtual QgsFeatureRendererV2 * clone() const =0
Rule(QgsSymbolV2 *symbol, int scaleMinDenom=0, int scaleMaxDenom=0, QString filterExp=QString(), QString label=QString(), QString description=QString(), bool elseRule=false)
Constructor takes ownership of the symbol.
static void refineRuleCategories(Rule *initialRule, QgsCategorizedSymbolRendererV2 *r)
take a rule and create a list of new rules based on the categories from categorized symbol renderer ...
virtual QgsLegendSymbolListV2 legendSymbolItemsV2() const
Return a list of symbology items for the legend.
void takeChild(Rule *rule)
take child rule out, set parent as null
QgsInvertedPolygonRenderer is a polygon-only feature renderer used to display features inverted...
virtual QgsLegendSymbolList legendSymbolItems(double scaleDenominator=-1, QString rule="")
return a list of item text / symbol
static bool createFunctionElement(QDomDocument &doc, QDomElement &element, QString function)
void appendChild(Rule *rule)
add child rule, take ownership, sets this as parent
static QDomElement saveSymbols(QgsSymbolV2Map &symbols, QString tagName, QDomDocument &doc)
static Rule * create(QDomElement &ruleElem, QgsSymbolV2Map &symbolMap)
QgsSymbolV2 * symbol() const
QDomElement save(QDomDocument &doc, QgsSymbolV2Map &symbolMap)
bool isFilterOK(QgsFeature &f) const
int symbolLayerCount()
Definition: qgssymbolv2.h:85
This class keeps data about a rules for rule-based renderer.
void setRuleKey(const QString &key)
Override the assigned rule key (should be used just internally by rule-based renderer) ...
virtual bool renderFeature(QgsFeature &feature, QgsRenderContext &context, int layer=-1, bool selected=false, bool drawVertexMarker=false)
QgsLegendSymbolList legendSymbolItems(double scaleDenominator=-1, QString rule="")
QString ruleKey() const
Unique rule identifier (for identification of rule within renderer)
Rule * mRootRule
the root node with hierarchical list of rules
static void refineRuleRanges(Rule *initialRule, QgsGraduatedSymbolRendererV2 *r)
take a rule and create a list of new rules based on the ranges from graduated symbol renderer ...
QString dump(int offset=0) const
Rule * takeChildAt(int i)
take child rule out, set parent as null
bool renderFeature(FeatureToRender &featToRender, QgsRenderContext &context, RenderQueue &renderQueue)
QList< QPair< QString, QPixmap > > QgsLegendSymbologyList
QgsFeatureRendererV2 * embeddedRenderer() const
QgsLegendSymbolListV2 legendSymbolItemsV2(int currentLevel=-1) const
int renderingPass() const
virtual QString layerType() const =0
A renderer that automatically displaces points with the same position.
virtual bool willRenderFeature(QgsFeature &feat)
return whether the renderer will render a feature or not.
virtual QgsSymbolV2 * subSymbol()
QgsRuleBasedRendererV2(QgsRuleBasedRendererV2::Rule *root)
Constructs the renderer from given tree of rules (takes ownership)
void setUsingSymbolLevels(bool usingSymbolLevels)
QString rotationField() const
return rotation field name (or empty string if not set or not supported by renderer) ...
Contains information about the context of a rendering operation.
const QgsFeatureRendererV2 * embeddedRenderer() const
QList< QgsSymbolLayerV2 * > QgsSymbolLayerV2List
Definition: qgssymbolv2.h:39
const QgsRangeList & ranges() const
When drawing a vector layer with rule-based renderer, it goes through the rules and draws features wi...
static Rule * createFromSld(QDomElement &element, QGis::GeometryType geomType)
bool usingSymbolLevels() const
static QgsExpression * expressionFromOgcFilter(const QDomElement &element)
Parse XML with OGC filter into QGIS expression.
static QString quotedString(QString text)
return quoted string (in single quotes)
static void clearSymbolMap(QgsSymbolV2Map &symbols)
void setSymbol(QgsSymbolV2 *sym)
set a new symbol (or NULL). Deletes old symbol.
virtual bool legendSymbolItemChecked(QString key)
items of symbology items in legend is checked
virtual QgsSymbolV2 * symbolForFeature(QgsFeature &feature)
return symbol for current feature. Should not be used individually: there could be more symbols for a...
static QgsRuleBasedRendererV2 * convertFromRenderer(const QgsFeatureRendererV2 *renderer)
creates a QgsRuleBasedRendererV2 from an existing renderer.
QList< QgsLegendSymbolItemV2 > QgsLegendSymbolListV2
virtual bool legendSymbolItemsCheckable() const
items of symbology items in legend should be checkable
QList< RenderLevel > RenderQueue
QgsSymbolLayerV2 * symbolLayer(int layer)
void insertChild(int i, Rule *rule)
add child rule, take ownership, sets this as parent
static QPixmap symbolPreviewPixmap(QgsSymbolV2 *symbol, QSize size, QgsRenderContext *customContext=0)
bool willRenderFeature(QgsFeature &feat)
only tell whether a feature will be rendered without actually rendering it
QList< QPair< QString, QgsSymbolV2 * > > QgsLegendSymbolList
Definition: qgsrendererv2.h:41
QString parserErrorString() const
Returns parser error.
Definition: qgsexpression.h:96
The class stores information about one class/rule of a vector layer renderer in a unified way that ca...
virtual QList< QString > usedAttributes()
void setFilterExpression(QString filterExp)
virtual void toSld(QDomDocument &doc, QDomElement &element) const
used from subclasses to create SLD Rule elements following SLD v1.1 specs
QList< FeatureToRender > mCurrentFeatures
virtual void checkLegendSymbolItem(QString key, bool state=true)
item in symbology was checked
Rule * findRuleByKey(QString key)
Try to find a rule given its unique key.
static void refineRuleScales(Rule *initialRule, QList< int > scales)
take a rule and create a list of new rules with intervals of scales given by the passed scale denomin...
virtual void setDataDefinedProperty(const QString &property, const QString &expressionString)
virtual QgsSymbolV2List symbols()
for symbol levels