QGIS API Documentation  2.11.0-Master
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
qgsrulebasedrendererv2.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsrulebasedrendererv2.cpp - Rule-based renderer (symbology-ng)
3  ---------------------
4  begin : May 2010
5  copyright : (C) 2010 by Martin Dobias
6  email : wonder dot sk at gmail dot com
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
15 
16 #include "qgsrulebasedrendererv2.h"
17 #include "qgssymbollayerv2.h"
18 #include "qgsexpression.h"
19 #include "qgssymbollayerv2utils.h"
20 #include "qgsrendercontext.h"
21 #include "qgsvectorlayer.h"
22 #include "qgslogger.h"
23 #include "qgsogcutils.h"
27 #include "qgspainteffect.h"
28 #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 if ( !sf.length() )
455  filter = "TRUE";
456  else
457  filter = sf;
458 
459  filter = filter.trimmed();
460 
461  return true;
462 }
463 
465 {
466  QSet<int> symbolZLevelsSet;
467 
468  // process this rule
469  if ( mSymbol )
470  {
471  // find out which Z-levels are used
472  for ( int i = 0; i < mSymbol->symbolLayerCount(); i++ )
473  {
474  symbolZLevelsSet.insert( mSymbol->symbolLayer( i )->renderingPass() );
475  }
476  }
477 
478  // process children
480  for ( it = mActiveChildren.begin(); it != mActiveChildren.end(); ++it )
481  {
482  Rule* rule = *it;
483  symbolZLevelsSet.unite( rule->collectZLevels() );
484  }
485  return symbolZLevelsSet;
486 }
487 
489 {
490  if ( mSymbol )
491  {
492  for ( int i = 0; i < mSymbol->symbolLayerCount(); i++ )
493  {
494  int normLevel = zLevelsToNormLevels.value( mSymbol->symbolLayer( i )->renderingPass() );
495  mSymbolNormZLevels.append( normLevel );
496  }
497  }
498 
499  // prepare list of normalized levels for each rule
500  for ( QList<Rule*>::iterator it = mActiveChildren.begin(); it != mActiveChildren.end(); ++it )
501  {
502  Rule* rule = *it;
503  rule->setNormZLevels( zLevelsToNormLevels );
504  }
505 }
506 
507 
509 {
510  if ( !isFilterOK( featToRender.feat, &context ) )
511  return false;
512 
513  bool rendered = false;
514 
515  // create job for this feature and this symbol, add to list of jobs
516  if ( mSymbol )
517  {
518  // add job to the queue: each symbol's zLevel must be added
519  foreach ( int normZLevel, mSymbolNormZLevels )
520  {
521  //QgsDebugMsg(QString("add job at level %1").arg(normZLevel));
522  renderQueue[normZLevel].jobs.append( new RenderJob( featToRender, mSymbol ) );
523  }
524  rendered = true;
525  }
526 
527  bool willrendersomething = false;
528 
529  // process children
530  for ( QList<Rule*>::iterator it = mActiveChildren.begin(); it != mActiveChildren.end(); ++it )
531  {
532  Rule* rule = *it;
533  if ( rule->isElse() )
534  {
535  // Don't process else rules yet
536  continue;
537  }
538  willrendersomething |= rule->renderFeature( featToRender, context, renderQueue );
539  rendered |= willrendersomething;
540  }
541 
542  // If none of the rules passed then we jump into the else rules and process them.
543  if ( !willrendersomething )
544  {
545  foreach ( Rule* rule, mElseRules )
546  {
547  rendered |= rule->renderFeature( featToRender, context, renderQueue );
548  }
549  }
550 
551  return rendered;
552 }
553 
555 {
556  if ( !isFilterOK( feat, context ) )
557  return false;
558  if ( mSymbol )
559  return true;
560 
561  for ( QList<Rule*>::iterator it = mActiveChildren.begin(); it != mActiveChildren.end(); ++it )
562  {
563  Rule* rule = *it;
564  if ( rule->willRenderFeature( feat, context ) )
565  return true;
566  }
567  return false;
568 }
569 
571 {
572  QgsSymbolV2List lst;
573  if ( !isFilterOK( feat, context ) )
574  return lst;
575  if ( mSymbol )
576  lst.append( mSymbol );
577 
578  for ( QList<Rule*>::iterator it = mActiveChildren.begin(); it != mActiveChildren.end(); ++it )
579  {
580  Rule* rule = *it;
581  lst += rule->symbolsForFeature( feat, context );
582  }
583  return lst;
584 }
585 
587 {
588  RuleList lst;
589  if ( !isFilterOK( feat, context ) )
590  return lst;
591 
592  if ( mSymbol )
593  lst.append( this );
594 
595  for ( QList<Rule*>::iterator it = mActiveChildren.begin(); it != mActiveChildren.end(); ++it )
596  {
597  Rule* rule = *it;
598  lst += rule->rulesForFeature( feat, context );
599  }
600  return lst;
601 }
602 
604 {
605  if ( mSymbol )
606  mSymbol->stopRender( context );
607 
608  for ( QList<Rule*>::iterator it = mActiveChildren.begin(); it != mActiveChildren.end(); ++it )
609  {
610  Rule* rule = *it;
611  rule->stopRender( context );
612  }
613 
614  mActiveChildren.clear();
615  mSymbolNormZLevels.clear();
616 }
617 
619 {
620  QString symbolIdx = ruleElem.attribute( "symbol" );
621  QgsSymbolV2* symbol = NULL;
622  if ( !symbolIdx.isEmpty() )
623  {
624  if ( symbolMap.contains( symbolIdx ) )
625  {
626  symbol = symbolMap.take( symbolIdx );
627  }
628  else
629  {
630  QgsDebugMsg( "symbol for rule " + symbolIdx + " not found!" );
631  }
632  }
633 
634  QString filterExp = ruleElem.attribute( "filter" );
635  QString label = ruleElem.attribute( "label" );
636  QString description = ruleElem.attribute( "description" );
637  int scaleMinDenom = ruleElem.attribute( "scalemindenom", "0" ).toInt();
638  int scaleMaxDenom = ruleElem.attribute( "scalemaxdenom", "0" ).toInt();
639  QString ruleKey = ruleElem.attribute( "key" );
640  Rule* rule = new Rule( symbol, scaleMinDenom, scaleMaxDenom, filterExp, label, description );
641 
642  if ( !ruleKey.isEmpty() )
643  rule->mRuleKey = ruleKey;
644 
645  rule->setCheckState( ruleElem.attribute( "checkstate", "1" ).toInt() );
646 
647  QDomElement childRuleElem = ruleElem.firstChildElement( "rule" );
648  while ( !childRuleElem.isNull() )
649  {
650  Rule* childRule = create( childRuleElem, symbolMap );
651  if ( childRule )
652  {
653  rule->appendChild( childRule );
654  }
655  else
656  {
657  QgsDebugMsg( "failed to init a child rule!" );
658  }
659  childRuleElem = childRuleElem.nextSiblingElement( "rule" );
660  }
661 
662  return rule;
663 }
664 
666 {
667  if ( ruleElem.localName() != "Rule" )
668  {
669  QgsDebugMsg( QString( "invalid element: Rule element expected, %1 found!" ).arg( ruleElem.tagName() ) );
670  return NULL;
671  }
672 
673  QString label, description, filterExp;
674  int scaleMinDenom = 0, scaleMaxDenom = 0;
675  QgsSymbolLayerV2List layers;
676 
677  // retrieve the Rule element child nodes
678  QDomElement childElem = ruleElem.firstChildElement();
679  while ( !childElem.isNull() )
680  {
681  if ( childElem.localName() == "Name" )
682  {
683  // <se:Name> tag contains the rule identifier,
684  // so prefer title tag for the label property value
685  if ( label.isEmpty() )
686  label = childElem.firstChild().nodeValue();
687  }
688  else if ( childElem.localName() == "Description" )
689  {
690  // <se:Description> can contains a title and an abstract
691  QDomElement titleElem = childElem.firstChildElement( "Title" );
692  if ( !titleElem.isNull() )
693  {
694  label = titleElem.firstChild().nodeValue();
695  }
696 
697  QDomElement abstractElem = childElem.firstChildElement( "Abstract" );
698  if ( !abstractElem.isNull() )
699  {
700  description = abstractElem.firstChild().nodeValue();
701  }
702  }
703  else if ( childElem.localName() == "Abstract" )
704  {
705  // <sld:Abstract> (v1.0)
706  description = childElem.firstChild().nodeValue();
707  }
708  else if ( childElem.localName() == "Title" )
709  {
710  // <sld:Title> (v1.0)
711  label = childElem.firstChild().nodeValue();
712  }
713  else if ( childElem.localName() == "Filter" )
714  {
716  if ( filter )
717  {
718  if ( filter->hasParserError() )
719  {
720  QgsDebugMsg( "parser error: " + filter->parserErrorString() );
721  }
722  else
723  {
724  filterExp = filter->expression();
725  }
726  delete filter;
727  }
728  }
729  else if ( childElem.localName() == "MinScaleDenominator" )
730  {
731  bool ok;
732  int v = childElem.firstChild().nodeValue().toInt( &ok );
733  if ( ok )
734  scaleMinDenom = v;
735  }
736  else if ( childElem.localName() == "MaxScaleDenominator" )
737  {
738  bool ok;
739  int v = childElem.firstChild().nodeValue().toInt( &ok );
740  if ( ok )
741  scaleMaxDenom = v;
742  }
743  else if ( childElem.localName().endsWith( "Symbolizer" ) )
744  {
745  // create symbol layers for this symbolizer
746  QgsSymbolLayerV2Utils::createSymbolLayerV2ListFromSld( childElem, geomType, layers );
747  }
748 
749  childElem = childElem.nextSiblingElement();
750  }
751 
752  // now create the symbol
753  QgsSymbolV2 *symbol = 0;
754  if ( layers.size() > 0 )
755  {
756  switch ( geomType )
757  {
758  case QGis::Line:
759  symbol = new QgsLineSymbolV2( layers );
760  break;
761 
762  case QGis::Polygon:
763  symbol = new QgsFillSymbolV2( layers );
764  break;
765 
766  case QGis::Point:
767  symbol = new QgsMarkerSymbolV2( layers );
768  break;
769 
770  default:
771  QgsDebugMsg( QString( "invalid geometry type: found %1" ).arg( geomType ) );
772  return NULL;
773  }
774  }
775 
776  // and then create and return the new rule
777  return new Rule( symbol, scaleMinDenom, scaleMaxDenom, filterExp, label, description );
778 }
779 
780 
782 
784  : QgsFeatureRendererV2( "RuleRenderer" ), mRootRule( root )
785 {
786 }
787 
789  : QgsFeatureRendererV2( "RuleRenderer" )
790 {
791  mRootRule = new Rule( NULL ); // root has no symbol, no filter etc - just a container
792  mRootRule->appendChild( new Rule( defaultSymbol ) );
793 }
794 
796 {
797  delete mRootRule;
798 }
799 
800 
802 {
803  // not used at all
804  return 0;
805 }
806 
808  QgsRenderContext& context,
809  int layer,
810  bool selected,
811  bool drawVertexMarker )
812 {
813  Q_UNUSED( layer );
814 
815  int flags = ( selected ? FeatIsSelected : 0 ) | ( drawVertexMarker ? FeatDrawMarkers : 0 );
816  mCurrentFeatures.append( FeatureToRender( feature, flags ) );
817 
818  // check each active rule
819  return mRootRule->renderFeature( mCurrentFeatures.last(), context, mRenderQueue );
820 }
821 
822 
824 {
825  // prepare active children
826  mRootRule->startRender( context, fields, mFilter );
827 
828  QSet<int> symbolZLevelsSet = mRootRule->collectZLevels();
829  QList<int> symbolZLevels = symbolZLevelsSet.toList();
830  qSort( symbolZLevels );
831 
832  // create mapping from unnormalized levels [unlimited range] to normalized levels [0..N-1]
833  // and prepare rendering queue
834  QMap<int, int> zLevelsToNormLevels;
835  int maxNormLevel = -1;
836  foreach ( int zLevel, symbolZLevels )
837  {
838  zLevelsToNormLevels[zLevel] = ++maxNormLevel;
839  mRenderQueue.append( RenderLevel( zLevel ) );
840  QgsDebugMsg( QString( "zLevel %1 -> %2" ).arg( zLevel ).arg( maxNormLevel ) );
841  }
842 
843  mRootRule->setNormZLevels( zLevelsToNormLevels );
844 }
845 
847 {
848  //
849  // do the actual rendering
850  //
851 
852  // go through all levels
853  foreach ( const RenderLevel& level, mRenderQueue )
854  {
855  //QgsDebugMsg(QString("level %1").arg(level.zIndex));
856  // go through all jobs at the level
857  foreach ( const RenderJob* job, level.jobs )
858  {
859  //QgsDebugMsg(QString("job fid %1").arg(job->f->id()));
860  // render feature - but only with symbol layers with specified zIndex
861  QgsSymbolV2* s = job->symbol;
862  int count = s->symbolLayerCount();
863  for ( int i = 0; i < count; i++ )
864  {
865  // TODO: better solution for this
866  // renderFeatureWithSymbol asks which symbol layer to draw
867  // but there are multiple transforms going on!
868  if ( s->symbolLayer( i )->renderingPass() == level.zIndex )
869  {
870  int flags = job->ftr.flags;
871  renderFeatureWithSymbol( job->ftr.feat, job->symbol, context, i, flags & FeatIsSelected, flags & FeatDrawMarkers );
872  }
873  }
874  }
875  }
876 
877  // clean current features
878  mCurrentFeatures.clear();
879 
880  // clean render queue
882 
883  // clean up rules from temporary stuff
884  mRootRule->stopRender( context );
885 }
886 
888 {
889  return mFilter;
890 }
891 
893 {
895  return attrs.values();
896 }
897 
899 {
901 
902  // normally with clone() the individual rules get new keys (UUID), but here we want to keep
903  // the tree of rules intact, so that other components that may use the rule keys work nicely (e.g. visibility presets)
904  clonedRoot->setRuleKey( mRootRule->ruleKey() );
905  RuleList origDescendants = mRootRule->descendants();
906  RuleList clonedDescendants = clonedRoot->descendants();
907  Q_ASSERT( origDescendants.count() == clonedDescendants.count() );
908  for ( int i = 0; i < origDescendants.count(); ++i )
909  clonedDescendants[i]->setRuleKey( origDescendants[i]->ruleKey() );
910 
911  QgsRuleBasedRendererV2* r = new QgsRuleBasedRendererV2( clonedRoot );
912 
914  copyPaintEffect( r );
915  return r;
916 }
917 
919 {
920  mRootRule->toSld( doc, element, QgsStringMap() );
921 }
922 
923 // TODO: ideally this function should be removed in favor of legendSymbol(ogy)Items
925 {
926  return mRootRule->symbols( context );
927 }
928 
930 {
931  QDomElement rendererElem = doc.createElement( RENDERER_TAG_NAME );
932  rendererElem.setAttribute( "type", "RuleRenderer" );
933  rendererElem.setAttribute( "symbollevels", ( mUsingSymbolLevels ? "1" : "0" ) );
934  rendererElem.setAttribute( "forceraster", ( mForceRaster ? "1" : "0" ) );
935 
937 
938  QDomElement rulesElem = mRootRule->save( doc, symbols );
939  rulesElem.setTagName( "rules" ); // instead of just "rule"
940  rendererElem.appendChild( rulesElem );
941 
942  QDomElement symbolsElem = QgsSymbolLayerV2Utils::saveSymbols( symbols, "symbols", doc );
943  rendererElem.appendChild( symbolsElem );
944 
945  if ( mPaintEffect )
946  mPaintEffect->saveProperties( doc, rendererElem );
947 
948  return rendererElem;
949 }
950 
952 {
955  for ( QgsLegendSymbolList::iterator it = items.begin(); it != items.end(); ++it )
956  {
957  QPair<QString, QgsSymbolV2*> pair = *it;
958  QPixmap pix = QgsSymbolLayerV2Utils::symbolPreviewPixmap( pair.second, iconSize );
959  lst << qMakePair( pair.first, pix );
960  }
961  return lst;
962 }
963 
965 {
966  return true;
967 }
968 
970 {
971  Rule* rule = mRootRule->findRuleByKey( key );
972  return rule ? rule->checkState() : true;
973 }
974 
976 {
977  Rule* rule = mRootRule->findRuleByKey( key );
978  if ( rule )
979  rule->setCheckState( state );
980 }
981 
983 {
984  return mRootRule->legendSymbolItems( scaleDenominator, rule );
985 }
986 
988 {
989  return mRootRule->legendSymbolItemsV2();
990 }
991 
992 
994 {
995  // load symbols
996  QDomElement symbolsElem = element.firstChildElement( "symbols" );
997  if ( symbolsElem.isNull() )
998  return NULL;
999 
1000  QgsSymbolV2Map symbolMap = QgsSymbolLayerV2Utils::loadSymbols( symbolsElem );
1001 
1002  QDomElement rulesElem = element.firstChildElement( "rules" );
1003 
1004  Rule* root = Rule::create( rulesElem, symbolMap );
1005  if ( root == NULL )
1006  return NULL;
1007 
1009 
1010  // delete symbols if there are any more
1012 
1013  return r;
1014 }
1015 
1017 {
1018  // retrieve child rules
1019  Rule* root = 0;
1020 
1021  QDomElement ruleElem = element.firstChildElement( "Rule" );
1022  while ( !ruleElem.isNull() )
1023  {
1024  Rule *child = Rule::createFromSld( ruleElem, geomType );
1025  if ( child )
1026  {
1027  // create the root rule if not done before
1028  if ( !root )
1029  root = new Rule( 0 );
1030 
1031  root->appendChild( child );
1032  }
1033 
1034  ruleElem = ruleElem.nextSiblingElement( "Rule" );
1035  }
1036 
1037  if ( !root )
1038  {
1039  // no valid rules was found
1040  return NULL;
1041  }
1042 
1043  // create and return the new renderer
1044  return new QgsRuleBasedRendererV2( root );
1045 }
1046 
1049 
1051 {
1052  foreach ( const QgsRendererCategoryV2& cat, r->categories() )
1053  {
1055  QString value;
1056  // not quoting numbers saves a type cast
1057  if ( cat.value().type() == QVariant::Int )
1058  value = cat.value().toString();
1059  else if ( cat.value().type() == QVariant::Double )
1060  // we loose precision here - so we may miss some categories :-(
1061  // TODO: have a possibility to construct expressions directly as a parse tree to avoid loss of precision
1062  value = QString::number( cat.value().toDouble(), 'f', 4 );
1063  else
1064  value = QgsExpression::quotedString( cat.value().toString() );
1065  QString filter = QString( "%1 = %2" ).arg( attr ).arg( value );
1066  QString label = filter;
1067  initialRule->appendChild( new Rule( cat.symbol()->clone(), 0, 0, filter, label ) );
1068  }
1069 }
1070 
1072 {
1073  foreach ( const QgsRendererRangeV2& rng, r->ranges() )
1074  {
1075  // due to the loss of precision in double->string conversion we may miss out values at the limit of the range
1076  // TODO: have a possibility to construct expressions directly as a parse tree to avoid loss of precision
1078  QString filter = QString( "%1 >= %2 AND %1 <= %3" ).arg( attr )
1079  .arg( QString::number( rng.lowerValue(), 'f', 4 ) )
1080  .arg( QString::number( rng.upperValue(), 'f', 4 ) );
1081  QString label = filter;
1082  initialRule->appendChild( new Rule( rng.symbol()->clone(), 0, 0, filter, label ) );
1083  }
1084 }
1085 
1087 {
1088  qSort( scales ); // make sure the scales are in ascending order
1089  int oldScale = initialRule->scaleMinDenom();
1090  int maxDenom = initialRule->scaleMaxDenom();
1091  QgsSymbolV2* symbol = initialRule->symbol();
1092  foreach ( int scale, scales )
1093  {
1094  if ( initialRule->scaleMinDenom() >= scale )
1095  continue; // jump over the first scales out of the interval
1096  if ( maxDenom != 0 && maxDenom <= scale )
1097  break; // ignore the latter scales out of the interval
1098  initialRule->appendChild( new Rule( symbol->clone(), oldScale, scale, QString(), QString( "%1 - %2" ).arg( oldScale ).arg( scale ) ) );
1099  oldScale = scale;
1100  }
1101  // last rule
1102  initialRule->appendChild( new Rule( symbol->clone(), oldScale, maxDenom, QString(), QString( "%1 - %2" ).arg( oldScale ).arg( maxDenom ) ) );
1103 }
1104 
1106 {
1107  QString msg( "Rule-based renderer:\n" );
1108  msg += mRootRule->dump();
1109  return msg;
1110 }
1111 
1113 {
1114  return mRootRule->willRenderFeature( feat, &context );
1115 }
1116 
1118 {
1119  return mRootRule->symbolsForFeature( feat, &context );
1120 }
1121 
1123 {
1124  return mRootRule->symbolsForFeature( feat, &context );
1125 }
1126 
1128 {
1129  if ( renderer->type() == "RuleRenderer" )
1130  {
1131  return dynamic_cast<QgsRuleBasedRendererV2*>( renderer->clone() );
1132  }
1133 
1134  if ( renderer->type() == "singleSymbol" )
1135  {
1136  const QgsSingleSymbolRendererV2* singleSymbolRenderer = dynamic_cast<const QgsSingleSymbolRendererV2*>( renderer );
1137  if ( !singleSymbolRenderer )
1138  return 0;
1139 
1140  QgsSymbolV2* origSymbol = singleSymbolRenderer->symbol()->clone();
1141  convertToDataDefinedSymbology( origSymbol, singleSymbolRenderer->sizeScaleField() );
1142  return new QgsRuleBasedRendererV2( origSymbol );
1143  }
1144 
1145  if ( renderer->type() == "categorizedSymbol" )
1146  {
1147  const QgsCategorizedSymbolRendererV2* categorizedRenderer = dynamic_cast<const QgsCategorizedSymbolRendererV2*>( renderer );
1148  if ( !categorizedRenderer )
1149  return 0;
1150 
1152 
1153  QString expression;
1154  QString value;
1155  QgsRendererCategoryV2 category;
1156  for ( int i = 0; i < categorizedRenderer->categories().size(); ++i )
1157  {
1158  category = categorizedRenderer->categories().value( i );
1160 
1161  rule->setLabel( category.label() );
1162 
1163  //We first define the rule corresponding to the category
1164  //If the value is a number, we can use it directly, otherwise we need to quote it in the rule
1165  if ( QVariant( category.value() ).convert( QVariant::Double ) )
1166  {
1167  value = category.value().toString();
1168  }
1169  else
1170  {
1171  value = "'" + category.value().toString() + "'";
1172  }
1173 
1174  //An empty category is equivalent to the ELSE keyword
1175  if ( value == "''" )
1176  {
1177  expression = "ELSE";
1178  }
1179  else
1180  {
1181  expression = categorizedRenderer->classAttribute() + " = " + value;
1182  }
1183  rule->setFilterExpression( expression );
1184 
1185  //Then we construct an equivalent symbol.
1186  //Ideally we could simply copy the symbol, but the categorized renderer allows a separate interface to specify
1187  //data dependent area and rotation, so we need to convert these to obtain the same rendering
1188 
1189  QgsSymbolV2* origSymbol = category.symbol()->clone();
1190  convertToDataDefinedSymbology( origSymbol, categorizedRenderer->sizeScaleField() );
1191  rule->setSymbol( origSymbol );
1192 
1193  rootrule->appendChild( rule );
1194  }
1195 
1196  return new QgsRuleBasedRendererV2( rootrule );
1197  }
1198 
1199  if ( renderer->type() == "graduatedSymbol" )
1200  {
1201 
1202  const QgsGraduatedSymbolRendererV2* graduatedRenderer = dynamic_cast<const QgsGraduatedSymbolRendererV2*>( renderer );
1203  if ( !graduatedRenderer )
1204  return 0;
1205 
1207 
1208  QString expression;
1209  QgsRendererRangeV2 range;
1210  for ( int i = 0; i < graduatedRenderer->ranges().size();++i )
1211  {
1212  range = graduatedRenderer->ranges().value( i );
1214  rule->setLabel( range.label() );
1215  if ( i == 0 )//The lower boundary of the first range is included, while it is excluded for the others
1216  {
1217  expression = graduatedRenderer->classAttribute() + " >= " + QString::number( range.lowerValue(), 'f' ) + " AND " + \
1218  graduatedRenderer->classAttribute() + " <= " + QString::number( range.upperValue(), 'f' );
1219  }
1220  else
1221  {
1222  expression = graduatedRenderer->classAttribute() + " > " + QString::number( range.lowerValue(), 'f' ) + " AND " + \
1223  graduatedRenderer->classAttribute() + " <= " + QString::number( range.upperValue(), 'f' );
1224  }
1225  rule->setFilterExpression( expression );
1226 
1227  //Then we construct an equivalent symbol.
1228  //Ideally we could simply copy the symbol, but the graduated renderer allows a separate interface to specify
1229  //data dependent area and rotation, so we need to convert these to obtain the same rendering
1230 
1231  QgsSymbolV2* symbol = range.symbol()->clone();
1232  convertToDataDefinedSymbology( symbol, graduatedRenderer->sizeScaleField() );
1233 
1234  rule->setSymbol( symbol );
1235 
1236  rootrule->appendChild( rule );
1237  }
1238 
1239  return new QgsRuleBasedRendererV2( rootrule );
1240  }
1241 
1242  if ( renderer->type() == "pointDisplacement" )
1243  {
1244  const QgsPointDisplacementRenderer* pointDisplacementRenderer = dynamic_cast<const QgsPointDisplacementRenderer*>( renderer );
1245  if ( pointDisplacementRenderer )
1246  return convertFromRenderer( pointDisplacementRenderer->embeddedRenderer() );
1247  }
1248  if ( renderer->type() == "invertedPolygonRenderer" )
1249  {
1250  const QgsInvertedPolygonRenderer* invertedPolygonRenderer = dynamic_cast<const QgsInvertedPolygonRenderer*>( renderer );
1251  if ( invertedPolygonRenderer )
1252  return convertFromRenderer( invertedPolygonRenderer->embeddedRenderer() );
1253  }
1254 
1255  return NULL;
1256 }
1257 
1259 {
1260  QString sizeExpression;
1261  switch ( symbol->type() )
1262  {
1263  case QgsSymbolV2::Marker:
1264  for ( int j = 0; j < symbol->symbolLayerCount();++j )
1265  {
1266  QgsMarkerSymbolLayerV2* msl = static_cast<QgsMarkerSymbolLayerV2*>( symbol->symbolLayer( j ) );
1267  if ( ! sizeScaleField.isEmpty() )
1268  {
1269  sizeExpression = QString( "%1*(%2)" ).arg( msl->size() ).arg( sizeScaleField );
1270  msl->setDataDefinedProperty( "size", new QgsDataDefined( sizeExpression ) );
1271  }
1272  if ( ! rotationField.isEmpty() )
1273  {
1274  msl->setDataDefinedProperty( "angle", new QgsDataDefined( true, false, QString(), rotationField ) );
1275  }
1276  }
1277  break;
1278  case QgsSymbolV2::Line:
1279  if ( ! sizeScaleField.isEmpty() )
1280  {
1281  for ( int j = 0; j < symbol->symbolLayerCount();++j )
1282  {
1283  if ( symbol->symbolLayer( j )->layerType() == "SimpleLine" )
1284  {
1285  QgsLineSymbolLayerV2* lsl = static_cast<QgsLineSymbolLayerV2*>( symbol->symbolLayer( j ) );
1286  sizeExpression = QString( "%1*(%2)" ).arg( lsl->width() ).arg( sizeScaleField );
1287  lsl->setDataDefinedProperty( "width", new QgsDataDefined( sizeExpression ) );
1288  }
1289  if ( symbol->symbolLayer( j )->layerType() == "MarkerLine" )
1290  {
1291  QgsSymbolV2* marker = symbol->symbolLayer( j )->subSymbol();
1292  for ( int k = 0; k < marker->symbolLayerCount();++k )
1293  {
1294  QgsMarkerSymbolLayerV2* msl = static_cast<QgsMarkerSymbolLayerV2*>( marker->symbolLayer( k ) );
1295  sizeExpression = QString( "%1*(%2)" ).arg( msl->size() ).arg( sizeScaleField );
1296  msl->setDataDefinedProperty( "size", new QgsDataDefined( sizeExpression ) );
1297  }
1298  }
1299  }
1300  }
1301  break;
1302  default:
1303  break;
1304  }
1305 }
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.