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