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