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();
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  QVariant res = mFilter->evaluate( &f );
242  return res.toInt() != 0;
243 }
244 
245 bool QgsRuleBasedRendererV2::Rule::isScaleOK( double scale ) const
246 {
247  if ( scale == 0 ) // so that we can count features in classes without scale context
248  return true;
249  if ( mScaleMinDenom == 0 && mScaleMaxDenom == 0 )
250  return true;
251  if ( mScaleMinDenom != 0 && mScaleMinDenom > scale )
252  return false;
253  if ( mScaleMaxDenom != 0 && mScaleMaxDenom < scale )
254  return false;
255  return true;
256 }
257 
259 {
260  QgsSymbolV2* sym = mSymbol ? mSymbol->clone() : NULL;
261  Rule* newrule = new Rule( sym, mScaleMinDenom, mScaleMaxDenom, mFilterExp, mLabel, mDescription );
262  newrule->setCheckState( mCheckState );
263  // clone children
264  foreach ( Rule* rule, mChildren )
265  newrule->appendChild( rule->clone() );
266  return newrule;
267 }
268 
270 {
271  QDomElement ruleElem = doc.createElement( "rule" );
272 
273  if ( mSymbol )
274  {
275  int symbolIndex = symbolMap.size();
276  symbolMap[QString::number( symbolIndex )] = mSymbol;
277  ruleElem.setAttribute( "symbol", symbolIndex );
278  }
279  if ( !mFilterExp.isEmpty() )
280  ruleElem.setAttribute( "filter", mFilterExp );
281  if ( mScaleMinDenom != 0 )
282  ruleElem.setAttribute( "scalemindenom", mScaleMinDenom );
283  if ( mScaleMaxDenom != 0 )
284  ruleElem.setAttribute( "scalemaxdenom", mScaleMaxDenom );
285  if ( !mLabel.isEmpty() )
286  ruleElem.setAttribute( "label", mLabel );
287  if ( !mDescription.isEmpty() )
288  ruleElem.setAttribute( "description", mDescription );
289  if ( !mCheckState )
290  ruleElem.setAttribute( "checkstate", 0 );
291  ruleElem.setAttribute( "key", mRuleKey );
292 
293  for ( RuleList::iterator it = mChildren.begin(); it != mChildren.end(); ++it )
294  {
295  Rule* rule = *it;
296  ruleElem.appendChild( rule->save( doc, symbolMap ) );
297  }
298  return ruleElem;
299 }
300 
302 {
303  // do not convert this rule if there are no symbols
304  if ( symbols().isEmpty() )
305  return;
306 
307  if ( !mFilterExp.isEmpty() )
308  {
309  if ( !props.value( "filter", "" ).isEmpty() )
310  props[ "filter" ] += " AND ";
311  props[ "filter" ] += mFilterExp;
312  }
313 
314  if ( mScaleMinDenom != 0 )
315  {
316  bool ok;
317  int parentScaleMinDenom = props.value( "scaleMinDenom", "0" ).toInt( &ok );
318  if ( !ok || parentScaleMinDenom <= 0 )
319  props[ "scaleMinDenom" ] = QString::number( mScaleMinDenom );
320  else
321  props[ "scaleMinDenom" ] = QString::number( qMax( parentScaleMinDenom, mScaleMinDenom ) );
322  }
323 
324  if ( mScaleMaxDenom != 0 )
325  {
326  bool ok;
327  int parentScaleMaxDenom = props.value( "scaleMaxDenom", "0" ).toInt( &ok );
328  if ( !ok || parentScaleMaxDenom <= 0 )
329  props[ "scaleMaxDenom" ] = QString::number( mScaleMaxDenom );
330  else
331  props[ "scaleMaxDenom" ] = QString::number( qMin( parentScaleMaxDenom, mScaleMaxDenom ) );
332  }
333 
334  if ( mSymbol )
335  {
336  QDomElement ruleElem = doc.createElement( "se:Rule" );
337  element.appendChild( ruleElem );
338 
339  //XXX: <se:Name> is the rule identifier, but our the Rule objects
340  // have no properties could be used as identifier. Use the label.
341  QDomElement nameElem = doc.createElement( "se:Name" );
342  nameElem.appendChild( doc.createTextNode( mLabel ) );
343  ruleElem.appendChild( nameElem );
344 
345  if ( !mLabel.isEmpty() || !mDescription.isEmpty() )
346  {
347  QDomElement descrElem = doc.createElement( "se:Description" );
348  if ( !mLabel.isEmpty() )
349  {
350  QDomElement titleElem = doc.createElement( "se:Title" );
351  titleElem.appendChild( doc.createTextNode( mLabel ) );
352  descrElem.appendChild( titleElem );
353  }
354  if ( !mDescription.isEmpty() )
355  {
356  QDomElement abstractElem = doc.createElement( "se:Abstract" );
357  abstractElem.appendChild( doc.createTextNode( mDescription ) );
358  descrElem.appendChild( abstractElem );
359  }
360  ruleElem.appendChild( descrElem );
361  }
362 
363  if ( !props.value( "filter", "" ).isEmpty() )
364  {
365  QgsSymbolLayerV2Utils::createFunctionElement( doc, ruleElem, props.value( "filter", "" ) );
366  }
367 
368  if ( !props.value( "scaleMinDenom", "" ).isEmpty() )
369  {
370  QDomElement scaleMinDenomElem = doc.createElement( "se:MinScaleDenominator" );
371  scaleMinDenomElem.appendChild( doc.createTextNode( props.value( "scaleMinDenom", "" ) ) );
372  ruleElem.appendChild( scaleMinDenomElem );
373  }
374 
375  if ( !props.value( "scaleMaxDenom", "" ).isEmpty() )
376  {
377  QDomElement scaleMaxDenomElem = doc.createElement( "se:MaxScaleDenominator" );
378  scaleMaxDenomElem.appendChild( doc.createTextNode( props.value( "scaleMaxDenom", "" ) ) );
379  ruleElem.appendChild( scaleMaxDenomElem );
380  }
381 
382  mSymbol->toSld( doc, ruleElem, props );
383  }
384 
385  // loop into childern rule list
386  for ( RuleList::iterator it = mChildren.begin(); it != mChildren.end(); ++it )
387  {
388  ( *it )->toSld( doc, element, props );
389  }
390 }
391 
393 {
394  mActiveChildren.clear();
395 
396  if ( ! mCheckState )
397  return false;
398 
399  // filter out rules which are not compatible with this scale
400  if ( !isScaleOK( context.rendererScale() ) )
401  return false;
402 
403  // init this rule
404  if ( mFilter )
405  mFilter->prepare( fields );
406  if ( mSymbol )
407  mSymbol->startRender( context, &fields );
408 
409  // init children
410  // build temporary list of active rules (usable with this scale)
411  for ( RuleList::iterator it = mChildren.begin(); it != mChildren.end(); ++it )
412  {
413  Rule* rule = *it;
414  if ( rule->startRender( context, fields ) )
415  {
416  // only add those which are active with current scale
417  mActiveChildren.append( rule );
418  }
419  }
420  return true;
421 }
422 
424 {
425  QSet<int> symbolZLevelsSet;
426 
427  // process this rule
428  if ( mSymbol )
429  {
430  // find out which Z-levels are used
431  for ( int i = 0; i < mSymbol->symbolLayerCount(); i++ )
432  {
433  symbolZLevelsSet.insert( mSymbol->symbolLayer( i )->renderingPass() );
434  }
435  }
436 
437  // process children
439  for ( it = mActiveChildren.begin(); it != mActiveChildren.end(); ++it )
440  {
441  Rule* rule = *it;
442  symbolZLevelsSet.unite( rule->collectZLevels() );
443  }
444  return symbolZLevelsSet;
445 }
446 
448 {
449  if ( mSymbol )
450  {
451  for ( int i = 0; i < mSymbol->symbolLayerCount(); i++ )
452  {
453  int normLevel = zLevelsToNormLevels.value( mSymbol->symbolLayer( i )->renderingPass() );
454  mSymbolNormZLevels.append( normLevel );
455  }
456  }
457 
458  // prepare list of normalized levels for each rule
459  for ( QList<Rule*>::iterator it = mActiveChildren.begin(); it != mActiveChildren.end(); ++it )
460  {
461  Rule* rule = *it;
462  rule->setNormZLevels( zLevelsToNormLevels );
463  }
464 }
465 
466 
468 {
469  if ( !isFilterOK( featToRender.feat ) )
470  return false;
471 
472  bool rendered = false;
473 
474  // create job for this feature and this symbol, add to list of jobs
475  if ( mSymbol )
476  {
477  // add job to the queue: each symbol's zLevel must be added
478  foreach ( int normZLevel, mSymbolNormZLevels )
479  {
480  //QgsDebugMsg(QString("add job at level %1").arg(normZLevel));
481  renderQueue[normZLevel].jobs.append( new RenderJob( featToRender, mSymbol ) );
482  }
483  rendered = true;
484  }
485 
486  bool willrendersomething = false;
487 
488  // process children
489  for ( QList<Rule*>::iterator it = mActiveChildren.begin(); it != mActiveChildren.end(); ++it )
490  {
491  Rule* rule = *it;
492  if ( rule->isElse() )
493  {
494  // Don't process else rules yet
495  continue;
496  }
497  willrendersomething |= rule->renderFeature( featToRender, context, renderQueue );
498  rendered |= willrendersomething;
499  }
500 
501  // If none of the rules passed then we jump into the else rules and process them.
502  if ( !willrendersomething )
503  {
504  foreach ( Rule* rule, mElseRules )
505  {
506  rendered |= rule->renderFeature( featToRender, context, renderQueue );
507  }
508  }
509 
510  return rendered;
511 }
512 
514 {
515  if ( !isFilterOK( feat ) )
516  return false;
517  if ( mSymbol )
518  return true;
519 
520  for ( QList<Rule*>::iterator it = mActiveChildren.begin(); it != mActiveChildren.end(); ++it )
521  {
522  Rule* rule = *it;
523  if ( rule->willRenderFeature( feat ) )
524  return true;
525  }
526  return false;
527 }
528 
530 {
531  QgsSymbolV2List lst;
532  if ( !isFilterOK( feat ) )
533  return lst;
534  if ( mSymbol )
535  lst.append( mSymbol );
536 
537  for ( QList<Rule*>::iterator it = mActiveChildren.begin(); it != mActiveChildren.end(); ++it )
538  {
539  Rule* rule = *it;
540  lst += rule->symbolsForFeature( feat );
541  }
542  return lst;
543 }
544 
546 {
547  RuleList lst;
548  if ( !isFilterOK( feat ) )
549  return lst;
550 
551  if ( mSymbol )
552  lst.append( this );
553 
554  for ( QList<Rule*>::iterator it = mActiveChildren.begin(); it != mActiveChildren.end(); ++it )
555  {
556  Rule* rule = *it;
557  lst += rule->rulesForFeature( feat );
558  }
559  return lst;
560 }
561 
563 {
564  if ( mSymbol )
565  mSymbol->stopRender( context );
566 
567  for ( QList<Rule*>::iterator it = mActiveChildren.begin(); it != mActiveChildren.end(); ++it )
568  {
569  Rule* rule = *it;
570  rule->stopRender( context );
571  }
572 
573  mActiveChildren.clear();
574  mSymbolNormZLevels.clear();
575 }
576 
578 {
579  QString symbolIdx = ruleElem.attribute( "symbol" );
580  QgsSymbolV2* symbol = NULL;
581  if ( !symbolIdx.isEmpty() )
582  {
583  if ( symbolMap.contains( symbolIdx ) )
584  {
585  symbol = symbolMap.take( symbolIdx );
586  }
587  else
588  {
589  QgsDebugMsg( "symbol for rule " + symbolIdx + " not found!" );
590  }
591  }
592 
593  QString filterExp = ruleElem.attribute( "filter" );
594  QString label = ruleElem.attribute( "label" );
595  QString description = ruleElem.attribute( "description" );
596  int scaleMinDenom = ruleElem.attribute( "scalemindenom", "0" ).toInt();
597  int scaleMaxDenom = ruleElem.attribute( "scalemaxdenom", "0" ).toInt();
598  QString ruleKey = ruleElem.attribute( "key" );
599  Rule* rule = new Rule( symbol, scaleMinDenom, scaleMaxDenom, filterExp, label, description );
600 
601  if ( !ruleKey.isEmpty() )
602  rule->mRuleKey = ruleKey;
603 
604  rule->setCheckState( ruleElem.attribute( "checkstate", "1" ).toInt() );
605 
606  QDomElement childRuleElem = ruleElem.firstChildElement( "rule" );
607  while ( !childRuleElem.isNull() )
608  {
609  Rule* childRule = create( childRuleElem, symbolMap );
610  if ( childRule )
611  {
612  rule->appendChild( childRule );
613  }
614  else
615  {
616  QgsDebugMsg( "failed to init a child rule!" );
617  }
618  childRuleElem = childRuleElem.nextSiblingElement( "rule" );
619  }
620 
621  return rule;
622 }
623 
625 {
626  if ( ruleElem.localName() != "Rule" )
627  {
628  QgsDebugMsg( QString( "invalid element: Rule element expected, %1 found!" ).arg( ruleElem.tagName() ) );
629  return NULL;
630  }
631 
632  QString label, description, filterExp;
633  int scaleMinDenom = 0, scaleMaxDenom = 0;
634  QgsSymbolLayerV2List layers;
635 
636  // retrieve the Rule element child nodes
637  QDomElement childElem = ruleElem.firstChildElement();
638  while ( !childElem.isNull() )
639  {
640  if ( childElem.localName() == "Name" )
641  {
642  // <se:Name> tag contains the rule identifier,
643  // so prefer title tag for the label property value
644  if ( label.isEmpty() )
645  label = childElem.firstChild().nodeValue();
646  }
647  else if ( childElem.localName() == "Description" )
648  {
649  // <se:Description> can contains a title and an abstract
650  QDomElement titleElem = childElem.firstChildElement( "Title" );
651  if ( !titleElem.isNull() )
652  {
653  label = titleElem.firstChild().nodeValue();
654  }
655 
656  QDomElement abstractElem = childElem.firstChildElement( "Abstract" );
657  if ( !abstractElem.isNull() )
658  {
659  description = abstractElem.firstChild().nodeValue();
660  }
661  }
662  else if ( childElem.localName() == "Abstract" )
663  {
664  // <sld:Abstract> (v1.0)
665  description = childElem.firstChild().nodeValue();
666  }
667  else if ( childElem.localName() == "Title" )
668  {
669  // <sld:Title> (v1.0)
670  label = childElem.firstChild().nodeValue();
671  }
672  else if ( childElem.localName() == "Filter" )
673  {
675  if ( filter )
676  {
677  if ( filter->hasParserError() )
678  {
679  QgsDebugMsg( "parser error: " + filter->parserErrorString() );
680  }
681  else
682  {
683  filterExp = filter->expression();
684  }
685  delete filter;
686  }
687  }
688  else if ( childElem.localName() == "MinScaleDenominator" )
689  {
690  bool ok;
691  int v = childElem.firstChild().nodeValue().toInt( &ok );
692  if ( ok )
693  scaleMinDenom = v;
694  }
695  else if ( childElem.localName() == "MaxScaleDenominator" )
696  {
697  bool ok;
698  int v = childElem.firstChild().nodeValue().toInt( &ok );
699  if ( ok )
700  scaleMaxDenom = v;
701  }
702  else if ( childElem.localName().endsWith( "Symbolizer" ) )
703  {
704  // create symbol layers for this symbolizer
705  QgsSymbolLayerV2Utils::createSymbolLayerV2ListFromSld( childElem, geomType, layers );
706  }
707 
708  childElem = childElem.nextSiblingElement();
709  }
710 
711  // now create the symbol
712  QgsSymbolV2 *symbol = 0;
713  if ( layers.size() > 0 )
714  {
715  switch ( geomType )
716  {
717  case QGis::Line:
718  symbol = new QgsLineSymbolV2( layers );
719  break;
720 
721  case QGis::Polygon:
722  symbol = new QgsFillSymbolV2( layers );
723  break;
724 
725  case QGis::Point:
726  symbol = new QgsMarkerSymbolV2( layers );
727  break;
728 
729  default:
730  QgsDebugMsg( QString( "invalid geometry type: found %1" ).arg( geomType ) );
731  return NULL;
732  }
733  }
734 
735  // and then create and return the new rule
736  return new Rule( symbol, scaleMinDenom, scaleMaxDenom, filterExp, label, description );
737 }
738 
739 
741 
743  : QgsFeatureRendererV2( "RuleRenderer" ), mRootRule( root )
744 {
745 }
746 
748  : QgsFeatureRendererV2( "RuleRenderer" )
749 {
750  mRootRule = new Rule( NULL ); // root has no symbol, no filter etc - just a container
751  mRootRule->appendChild( new Rule( defaultSymbol ) );
752 }
753 
755 {
756  delete mRootRule;
757 }
758 
759 
761 {
762  // not used at all
763  return 0;
764 }
765 
767  QgsRenderContext& context,
768  int layer,
769  bool selected,
770  bool drawVertexMarker )
771 {
772  Q_UNUSED( layer );
773 
774  int flags = ( selected ? FeatIsSelected : 0 ) | ( drawVertexMarker ? FeatDrawMarkers : 0 );
775  mCurrentFeatures.append( FeatureToRender( feature, flags ) );
776 
777  // check each active rule
778  return mRootRule->renderFeature( mCurrentFeatures.last(), context, mRenderQueue );
779 }
780 
781 
783 {
784  // prepare active children
785  mRootRule->startRender( context, fields );
786 
787  QSet<int> symbolZLevelsSet = mRootRule->collectZLevels();
788  QList<int> symbolZLevels = symbolZLevelsSet.toList();
789  qSort( symbolZLevels );
790 
791  // create mapping from unnormalized levels [unlimited range] to normalized levels [0..N-1]
792  // and prepare rendering queue
793  QMap<int, int> zLevelsToNormLevels;
794  int maxNormLevel = -1;
795  foreach ( int zLevel, symbolZLevels )
796  {
797  zLevelsToNormLevels[zLevel] = ++maxNormLevel;
798  mRenderQueue.append( RenderLevel( zLevel ) );
799  QgsDebugMsg( QString( "zLevel %1 -> %2" ).arg( zLevel ).arg( maxNormLevel ) );
800  }
801 
802  mRootRule->setNormZLevels( zLevelsToNormLevels );
803 }
804 
806 {
807  //
808  // do the actual rendering
809  //
810 
811  // go through all levels
812  foreach ( const RenderLevel& level, mRenderQueue )
813  {
814  //QgsDebugMsg(QString("level %1").arg(level.zIndex));
815  // go through all jobs at the level
816  foreach ( const RenderJob* job, level.jobs )
817  {
818  //QgsDebugMsg(QString("job fid %1").arg(job->f->id()));
819  // render feature - but only with symbol layers with specified zIndex
820  QgsSymbolV2* s = job->symbol;
821  int count = s->symbolLayerCount();
822  for ( int i = 0; i < count; i++ )
823  {
824  // TODO: better solution for this
825  // renderFeatureWithSymbol asks which symbol layer to draw
826  // but there are multiple transforms going on!
827  if ( s->symbolLayer( i )->renderingPass() == level.zIndex )
828  {
829  int flags = job->ftr.flags;
830  renderFeatureWithSymbol( job->ftr.feat, job->symbol, context, i, flags & FeatIsSelected, flags & FeatDrawMarkers );
831  }
832  }
833  }
834  }
835 
836  // clean current features
837  mCurrentFeatures.clear();
838 
839  // clean render queue
841 
842  // clean up rules from temporary stuff
843  mRootRule->stopRender( context );
844 }
845 
847 {
849  return attrs.values();
850 }
851 
853 {
855 
856  // normally with clone() the individual rules get new keys (UUID), but here we want to keep
857  // the tree of rules intact, so that other components that may use the rule keys work nicely (e.g. visibility presets)
858  clonedRoot->setRuleKey( mRootRule->ruleKey() );
859  RuleList origDescendants = mRootRule->descendants();
860  RuleList clonedDescendants = clonedRoot->descendants();
861  Q_ASSERT( origDescendants.count() == clonedDescendants.count() );
862  for ( int i = 0; i < origDescendants.count(); ++i )
863  clonedDescendants[i]->setRuleKey( origDescendants[i]->ruleKey() );
864 
865  QgsRuleBasedRendererV2* r = new QgsRuleBasedRendererV2( clonedRoot );
866 
868  copyPaintEffect( r );
869  return r;
870 }
871 
873 {
874  mRootRule->toSld( doc, element, QgsStringMap() );
875 }
876 
877 // TODO: ideally this function should be removed in favor of legendSymbol(ogy)Items
879 {
880  return mRootRule->symbols();
881 }
882 
884 {
885  QDomElement rendererElem = doc.createElement( RENDERER_TAG_NAME );
886  rendererElem.setAttribute( "type", "RuleRenderer" );
887  rendererElem.setAttribute( "symbollevels", ( mUsingSymbolLevels ? "1" : "0" ) );
888 
890 
891  QDomElement rulesElem = mRootRule->save( doc, symbols );
892  rulesElem.setTagName( "rules" ); // instead of just "rule"
893  rendererElem.appendChild( rulesElem );
894 
895  QDomElement symbolsElem = QgsSymbolLayerV2Utils::saveSymbols( symbols, "symbols", doc );
896  rendererElem.appendChild( symbolsElem );
897 
898  if ( mPaintEffect )
899  mPaintEffect->saveProperties( doc, rendererElem );
900 
901  return rendererElem;
902 }
903 
905 {
908  for ( QgsLegendSymbolList::iterator it = items.begin(); it != items.end(); ++it )
909  {
910  QPair<QString, QgsSymbolV2*> pair = *it;
911  QPixmap pix = QgsSymbolLayerV2Utils::symbolPreviewPixmap( pair.second, iconSize );
912  lst << qMakePair( pair.first, pix );
913  }
914  return lst;
915 }
916 
918 {
919  return true;
920 }
921 
923 {
924  Rule* rule = mRootRule->findRuleByKey( key );
925  return rule ? rule->checkState() : true;
926 }
927 
929 {
930  Rule* rule = mRootRule->findRuleByKey( key );
931  if ( rule )
932  rule->setCheckState( state );
933 }
934 
936 {
937  return mRootRule->legendSymbolItems( scaleDenominator, rule );
938 }
939 
941 {
942  return mRootRule->legendSymbolItemsV2();
943 }
944 
945 
947 {
948  // load symbols
949  QDomElement symbolsElem = element.firstChildElement( "symbols" );
950  if ( symbolsElem.isNull() )
951  return NULL;
952 
953  QgsSymbolV2Map symbolMap = QgsSymbolLayerV2Utils::loadSymbols( symbolsElem );
954 
955  QDomElement rulesElem = element.firstChildElement( "rules" );
956 
957  Rule* root = Rule::create( rulesElem, symbolMap );
958  if ( root == NULL )
959  return NULL;
960 
962 
963  // delete symbols if there are any more
965 
966  return r;
967 }
968 
970 {
971  // retrieve child rules
972  Rule* root = 0;
973 
974  QDomElement ruleElem = element.firstChildElement( "Rule" );
975  while ( !ruleElem.isNull() )
976  {
977  Rule *child = Rule::createFromSld( ruleElem, geomType );
978  if ( child )
979  {
980  // create the root rule if not done before
981  if ( !root )
982  root = new Rule( 0 );
983 
984  root->appendChild( child );
985  }
986 
987  ruleElem = ruleElem.nextSiblingElement( "Rule" );
988  }
989 
990  if ( !root )
991  {
992  // no valid rules was found
993  return NULL;
994  }
995 
996  // create and return the new renderer
997  return new QgsRuleBasedRendererV2( root );
998 }
999 
1002 
1004 {
1005  foreach ( const QgsRendererCategoryV2& cat, r->categories() )
1006  {
1008  QString value;
1009  // not quoting numbers saves a type cast
1010  if ( cat.value().type() == QVariant::Int )
1011  value = cat.value().toString();
1012  else if ( cat.value().type() == QVariant::Double )
1013  // we loose precision here - so we may miss some categories :-(
1014  // TODO: have a possibility to construct expressions directly as a parse tree to avoid loss of precision
1015  value = QString::number( cat.value().toDouble(), 'f', 4 );
1016  else
1017  value = QgsExpression::quotedString( cat.value().toString() );
1018  QString filter = QString( "%1 = %2" ).arg( attr ).arg( value );
1019  QString label = filter;
1020  initialRule->appendChild( new Rule( cat.symbol()->clone(), 0, 0, filter, label ) );
1021  }
1022 }
1023 
1025 {
1026  foreach ( const QgsRendererRangeV2& rng, r->ranges() )
1027  {
1028  // due to the loss of precision in double->string conversion we may miss out values at the limit of the range
1029  // TODO: have a possibility to construct expressions directly as a parse tree to avoid loss of precision
1031  QString filter = QString( "%1 >= %2 AND %1 <= %3" ).arg( attr )
1032  .arg( QString::number( rng.lowerValue(), 'f', 4 ) )
1033  .arg( QString::number( rng.upperValue(), 'f', 4 ) );
1034  QString label = filter;
1035  initialRule->appendChild( new Rule( rng.symbol()->clone(), 0, 0, filter, label ) );
1036  }
1037 }
1038 
1040 {
1041  qSort( scales ); // make sure the scales are in ascending order
1042  int oldScale = initialRule->scaleMinDenom();
1043  int maxDenom = initialRule->scaleMaxDenom();
1044  QgsSymbolV2* symbol = initialRule->symbol();
1045  foreach ( int scale, scales )
1046  {
1047  if ( initialRule->scaleMinDenom() >= scale )
1048  continue; // jump over the first scales out of the interval
1049  if ( maxDenom != 0 && maxDenom <= scale )
1050  break; // ignore the latter scales out of the interval
1051  initialRule->appendChild( new Rule( symbol->clone(), oldScale, scale, QString(), QString( "%1 - %2" ).arg( oldScale ).arg( scale ) ) );
1052  oldScale = scale;
1053  }
1054  // last rule
1055  initialRule->appendChild( new Rule( symbol->clone(), oldScale, maxDenom, QString(), QString( "%1 - %2" ).arg( oldScale ).arg( maxDenom ) ) );
1056 }
1057 
1059 {
1060  QString msg( "Rule-based renderer:\n" );
1061  msg += mRootRule->dump();
1062  return msg;
1063 }
1064 
1066 {
1067  return mRootRule->willRenderFeature( feat );
1068 }
1069 
1071 {
1072  return mRootRule->symbolsForFeature( feat );
1073 }
1074 
1076 {
1077  return mRootRule->symbolsForFeature( feat );
1078 }
1079 
1081 {
1082  if ( renderer->type() == "RuleRenderer" )
1083  {
1084  return dynamic_cast<QgsRuleBasedRendererV2*>( renderer->clone() );
1085  }
1086 
1087  if ( renderer->type() == "singleSymbol" )
1088  {
1089  const QgsSingleSymbolRendererV2* singleSymbolRenderer = dynamic_cast<const QgsSingleSymbolRendererV2*>( renderer );
1090  if ( !singleSymbolRenderer )
1091  return 0;
1092 
1093  QgsSymbolV2* origSymbol = singleSymbolRenderer->symbol()->clone();
1094  convertToDataDefinedSymbology( origSymbol, singleSymbolRenderer->sizeScaleField(), singleSymbolRenderer->rotationField() );
1095  return new QgsRuleBasedRendererV2( origSymbol );
1096  }
1097 
1098  if ( renderer->type() == "categorizedSymbol" )
1099  {
1100  const QgsCategorizedSymbolRendererV2* categorizedRenderer = dynamic_cast<const QgsCategorizedSymbolRendererV2*>( renderer );
1101  if ( !categorizedRenderer )
1102  return 0;
1103 
1105 
1106  QString expression;
1107  QString value;
1108  QgsRendererCategoryV2 category;
1109  for ( int i = 0; i < categorizedRenderer->categories().size(); ++i )
1110  {
1111  category = categorizedRenderer->categories().value( i );
1113 
1114  rule->setLabel( category.label() );
1115 
1116  //We first define the rule corresponding to the category
1117  //If the value is a number, we can use it directly, otherwise we need to quote it in the rule
1118  if ( QVariant( category.value() ).convert( QVariant::Double ) )
1119  {
1120  value = category.value().toString();
1121  }
1122  else
1123  {
1124  value = "'" + category.value().toString() + "'";
1125  }
1126 
1127  //An empty category is equivalent to the ELSE keyword
1128  if ( value == "''" )
1129  {
1130  expression = "ELSE";
1131  }
1132  else
1133  {
1134  expression = categorizedRenderer->classAttribute() + " = " + value;
1135  }
1136  rule->setFilterExpression( expression );
1137 
1138  //Then we construct an equivalent symbol.
1139  //Ideally we could simply copy the symbol, but the categorized renderer allows a separate interface to specify
1140  //data dependent area and rotation, so we need to convert these to obtain the same rendering
1141 
1142  QgsSymbolV2* origSymbol = category.symbol()->clone();
1143  convertToDataDefinedSymbology( origSymbol, categorizedRenderer->sizeScaleField(), categorizedRenderer->rotationField() );
1144  rule->setSymbol( origSymbol );
1145 
1146  rootrule->appendChild( rule );
1147  }
1148 
1149  return new QgsRuleBasedRendererV2( rootrule );
1150  }
1151 
1152  if ( renderer->type() == "graduatedSymbol" )
1153  {
1154 
1155  const QgsGraduatedSymbolRendererV2* graduatedRenderer = dynamic_cast<const QgsGraduatedSymbolRendererV2*>( renderer );
1156  if ( !graduatedRenderer )
1157  return 0;
1158 
1160 
1161  QString expression;
1162  QgsRendererRangeV2 range;
1163  for ( int i = 0; i < graduatedRenderer->ranges().size();++i )
1164  {
1165  range = graduatedRenderer->ranges().value( i );
1167  rule->setLabel( range.label() );
1168  if ( i == 0 )//The lower boundary of the first range is included, while it is excluded for the others
1169  {
1170  expression = graduatedRenderer->classAttribute() + " >= " + QString::number( range.lowerValue(), 'f' ) + " AND " + \
1171  graduatedRenderer->classAttribute() + " <= " + QString::number( range.upperValue(), 'f' );
1172  }
1173  else
1174  {
1175  expression = graduatedRenderer->classAttribute() + " > " + QString::number( range.lowerValue(), 'f' ) + " AND " + \
1176  graduatedRenderer->classAttribute() + " <= " + QString::number( range.upperValue(), 'f' );
1177  }
1178  rule->setFilterExpression( expression );
1179 
1180  //Then we construct an equivalent symbol.
1181  //Ideally we could simply copy the symbol, but the graduated renderer allows a separate interface to specify
1182  //data dependent area and rotation, so we need to convert these to obtain the same rendering
1183 
1184  QgsSymbolV2* symbol = range.symbol()->clone();
1185  convertToDataDefinedSymbology( symbol, graduatedRenderer->sizeScaleField(), graduatedRenderer->rotationField() );
1186 
1187  rule->setSymbol( symbol );
1188 
1189  rootrule->appendChild( rule );
1190  }
1191 
1192  return new QgsRuleBasedRendererV2( rootrule );
1193  }
1194 
1195  if ( renderer->type() == "pointDisplacement" )
1196  {
1197  const QgsPointDisplacementRenderer* pointDisplacementRenderer = dynamic_cast<const QgsPointDisplacementRenderer*>( renderer );
1198  if ( pointDisplacementRenderer )
1199  return convertFromRenderer( pointDisplacementRenderer->embeddedRenderer() );
1200  }
1201  if ( renderer->type() == "invertedPolygonRenderer" )
1202  {
1203  const QgsInvertedPolygonRenderer* invertedPolygonRenderer = dynamic_cast<const QgsInvertedPolygonRenderer*>( renderer );
1204  if ( invertedPolygonRenderer )
1205  return convertFromRenderer( invertedPolygonRenderer->embeddedRenderer() );
1206  }
1207 
1208  return NULL;
1209 }
1210 
1212 {
1213  QString sizeExpression;
1214  switch ( symbol->type() )
1215  {
1216  case QgsSymbolV2::Marker:
1217  for ( int j = 0; j < symbol->symbolLayerCount();++j )
1218  {
1219  QgsMarkerSymbolLayerV2* msl = static_cast<QgsMarkerSymbolLayerV2*>( symbol->symbolLayer( j ) );
1220  if ( ! sizeScaleField.isNull() )
1221  {
1222  sizeExpression = QString( "%1*(%2)" ).arg( msl->size() ).arg( sizeScaleField );
1223  msl->setDataDefinedProperty( "size", new QgsDataDefined( sizeExpression ) );
1224  }
1225  if ( ! rotationField.isNull() )
1226  {
1227  msl->setDataDefinedProperty( "angle", new QgsDataDefined( true, false, QString(), rotationField ) );
1228  }
1229  }
1230  break;
1231  case QgsSymbolV2::Line:
1232  if ( ! sizeScaleField.isNull() )
1233  {
1234  for ( int j = 0; j < symbol->symbolLayerCount();++j )
1235  {
1236  if ( symbol->symbolLayer( j )->layerType() == "SimpleLine" )
1237  {
1238  QgsLineSymbolLayerV2* lsl = static_cast<QgsLineSymbolLayerV2*>( symbol->symbolLayer( j ) );
1239  sizeExpression = QString( "%1*(%2)" ).arg( lsl->width() ).arg( sizeScaleField );
1240  lsl->setDataDefinedProperty( "width", new QgsDataDefined( sizeExpression ) );
1241  }
1242  if ( symbol->symbolLayer( j )->layerType() == "MarkerLine" )
1243  {
1244  QgsSymbolV2* marker = symbol->symbolLayer( j )->subSymbol();
1245  for ( int k = 0; k < marker->symbolLayerCount();++k )
1246  {
1247  QgsMarkerSymbolLayerV2* msl = static_cast<QgsMarkerSymbolLayerV2*>( marker->symbolLayer( k ) );
1248  sizeExpression = QString( "%1*(%2)" ).arg( msl->size() ).arg( sizeScaleField );
1249  msl->setDataDefinedProperty( "size", new QgsDataDefined( sizeExpression ) );
1250  }
1251  }
1252  }
1253  }
1254  break;
1255  default:
1256  break;
1257  }
1258 }
void toSld(QDomDocument &doc, QDomElement &element, QgsStringMap props)
Class for parsing and evaluation of expressions (formerly called "search strings").
Definition: qgsexpression.h:86
void clear()
QgsSymbolV2List symbolsForFeature(QgsFeature &feat)
tell which symbols will be used to render the feature
static QgsSymbolV2Map loadSymbols(QDomElement &element)
void setNormZLevels(const QMap< int, int > &zLevelsToNormLevels)
assign normalized z-levels [0..N-1] for this rule's symbol for quick access during rendering ...
#define RENDERER_TAG_NAME
Definition: qgsrendererv2.h:48
bool hasParserError() const
Returns true if an error occurred when parsing the input expression.
Definition: qgsexpression.h:93
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)
virtual QgsSymbolV2List symbols() override
for symbol levels
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
void setTagName(const QString &name)
QString nodeValue() const
#define QgsDebugMsg(str)
Definition: qgslogger.h:33
static void convertToDataDefinedSymbology(QgsSymbolV2 *symbol, QString sizeScaleField, QString rotationField)
helper function to convert the size scale and rotation fields present in some other renderers to data...
double rendererScale() const
virtual QgsSymbolV2 * clone() const =0
virtual QgsFeatureRendererV2 * clone() const override
static QgsFeatureRendererV2 * createFromSld(QDomElement &element, QGis::GeometryType geomType)
bool isScaleOK(double scale) const
QDomElement nextSiblingElement(const QString &tagName) const
bool startRender(QgsRenderContext &context, const QgsFields &fields)
prepare the rule for rendering and its children (build active children array)
Rule * clone() const
clone this rule, return new instance
RuleList rulesForFeature(QgsFeature &feat)
tell which rules will be used to render the feature
Container of fields for a vector layer.
Definition: qgsfield.h:173
void removeChild(Rule *rule)
delete child rule
GeometryType
Definition: qgis.h:155
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:119
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
bool isNull() const
QString rotationField() const override
return rotation field name (or empty string if not set or not supported by renderer) ...
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 QgsSymbolV2List originalSymbolsForFeature(QgsFeature &feat) override
Equivalent of originalSymbolsForFeature() call extended to support renderers that may use more symbol...
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 rotationField() const override
return rotation field name (or empty string if not set or not supported by renderer) ...
QgsSymbolV2 * symbol() const
QDomElement save(QDomDocument &doc, QgsSymbolV2Map &symbolMap)
bool isFilterOK(QgsFeature &f) const
int symbolLayerCount()
Returns total number of symbol layers contained in the symbol.
Definition: qgssymbolv2.h: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)
Rule * mRootRule
the root node with hierarchical list of rules
virtual bool renderFeature(QgsFeature &feature, QgsRenderContext &context, int layer=-1, bool selected=false, bool drawVertexMarker=false) override
virtual bool willRenderFeature(QgsFeature &feat) override
return whether the renderer will render a feature or not.
static void refineRuleRanges(Rule *initialRule, QgsGraduatedSymbolRendererV2 *r)
take a rule and create a list of new rules based on the ranges from graduated symbol renderer ...
QString dump(int offset=0) const
Rule * takeChildAt(int i)
take child rule out, set parent as null
bool renderFeature(FeatureToRender &featToRender, QgsRenderContext &context, RenderQueue &renderQueue)
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
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
QString rotationField() const override
return rotation field name (or empty string if not set or not supported by renderer) ...
virtual bool saveProperties(QDomDocument &doc, QDomElement &element) const
Saves the current state of the effect to a DOM element.
Contains information about the context of a rendering operation.
const QgsFeatureRendererV2 * embeddedRenderer() const
QDomNode firstChild() const
void copyPaintEffect(QgsFeatureRendererV2 *destRenderer) const
Copies paint effect of this renderer to another renderer.
QSet< T > & unite(const QSet< T > &other)
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
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.
void insertChild(int i, Rule *rule)
add child rule, take ownership, sets this as parent
QDomElement createElement(const QString &tagName)
Type type() const
virtual QgsSymbolV2 * symbolForFeature(QgsFeature &feature) override
return symbol for current feature. Should not be used individually: there could be more symbols for a...
static QPixmap symbolPreviewPixmap(QgsSymbolV2 *symbol, QSize size, QgsRenderContext *customContext=0)
bool willRenderFeature(QgsFeature &feat)
only tell whether a feature will be rendered without actually rendering it
QString parserErrorString() const
Returns parser error.
Definition: qgsexpression.h:95
The class stores information about one class/rule of a vector layer renderer in a unified way that ca...
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
Rule * findRuleByKey(QString key)
Try to find a rule given its unique key.
static void refineRuleScales(Rule *initialRule, QList< int > scales)
take a rule and create a list of new rules with intervals of scales given by the passed scale denomin...
virtual QgsSymbolV2List symbolsForFeature(QgsFeature &feat) override
return list of symbols used for rendering the feature.
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.