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