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