QGIS API Documentation  2.0.1-Dufour
 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"
24 
25 #include <QSet>
26 
27 #include <QDomDocument>
28 #include <QDomElement>
29 
30 
31 
32 QgsRuleBasedRendererV2::Rule::Rule( QgsSymbolV2* symbol, int scaleMinDenom, int scaleMaxDenom, QString filterExp, QString label, QString description )
33  : mParent( NULL ), mSymbol( symbol ),
34  mScaleMinDenom( scaleMinDenom ), mScaleMaxDenom( scaleMaxDenom ),
35  mFilterExp( filterExp ), mLabel( label ), mDescription( description ),
36  mFilter( NULL )
37 {
38  initFilter();
39 }
40 
42 {
43  delete mSymbol;
44  delete mFilter;
45  qDeleteAll( mChildren );
46  // do NOT delete parent
47 }
48 
50 {
51  if ( !mFilterExp.isEmpty() )
52  {
53  delete mFilter;
54  mFilter = new QgsExpression( mFilterExp );
55  }
56  else
57  {
58  mFilter = NULL;
59  }
60 }
61 
62 QString QgsRuleBasedRendererV2::Rule::dump( int offset ) const
63 {
64  QString off;
65  off.fill( QChar( ' ' ), offset );
66  QString symbolDump = ( mSymbol ? mSymbol->dump() : QString( "[]" ) );
67  QString msg = off + QString( "RULE %1 - scale [%2,%3] - filter %4 - symbol %5\n" )
68  .arg( mLabel ).arg( mScaleMinDenom ).arg( mScaleMaxDenom )
69  .arg( mFilterExp ).arg( symbolDump );
70 
71  QStringList lst;
72  foreach ( Rule* rule, mChildren )
73  {
74  lst.append( rule->dump( offset + 2 ) );
75  }
76  msg += lst.join( "\n" );
77  return msg;
78 }
79 
81 {
82  // attributes needed by this rule
83  QSet<QString> attrs;
84  if ( mFilter )
85  attrs.unite( mFilter->referencedColumns().toSet() );
86  if ( mSymbol )
87  attrs.unite( mSymbol->usedAttributes() );
88 
89  // attributes needed by child rules
90  for ( RuleList::iterator it = mChildren.begin(); it != mChildren.end(); ++it )
91  {
92  Rule* rule = *it;
93  attrs.unite( rule->usedAttributes() );
94  }
95  return attrs;
96 }
97 
99 {
100  QgsSymbolV2List lst;
101  if ( mSymbol )
102  lst.append( mSymbol );
103 
104  for ( RuleList::iterator it = mChildren.begin(); it != mChildren.end(); ++it )
105  {
106  Rule* rule = *it;
107  lst += rule->symbols();
108  }
109  return lst;
110 }
111 
113 {
114  delete mSymbol;
115  mSymbol = sym;
116 }
117 
119 {
121  if ( mSymbol )
122  lst << qMakePair( mLabel, mSymbol );
123 
124  for ( RuleList::iterator it = mChildren.begin(); it != mChildren.end(); ++it )
125  {
126  Rule* rule = *it;
127  lst << rule->legendSymbolItems();
128  }
129  return lst;
130 }
131 
132 
134 {
135  if ( ! mFilter )
136  return true;
137 
138  QVariant res = mFilter->evaluate( &f );
139  return res.toInt() != 0;
140 }
141 
142 bool QgsRuleBasedRendererV2::Rule::isScaleOK( double scale ) const
143 {
144  if ( scale == 0 ) // so that we can count features in classes without scale context
145  return true;
146  if ( mScaleMinDenom == 0 && mScaleMaxDenom == 0 )
147  return true;
148  if ( mScaleMinDenom != 0 && mScaleMinDenom > scale )
149  return false;
150  if ( mScaleMaxDenom != 0 && mScaleMaxDenom < scale )
151  return false;
152  return true;
153 }
154 
156 {
157  QgsSymbolV2* sym = mSymbol ? mSymbol->clone() : NULL;
158  Rule* newrule = new Rule( sym, mScaleMinDenom, mScaleMaxDenom, mFilterExp, mLabel, mDescription );
159  // clone children
160  foreach ( Rule* rule, mChildren )
161  newrule->appendChild( rule->clone() );
162  return newrule;
163 }
164 
165 QDomElement QgsRuleBasedRendererV2::Rule::save( QDomDocument& doc, QgsSymbolV2Map& symbolMap )
166 {
167  QDomElement ruleElem = doc.createElement( "rule" );
168 
169  if ( mSymbol )
170  {
171  int symbolIndex = symbolMap.size();
172  symbolMap[QString::number( symbolIndex )] = mSymbol;
173  ruleElem.setAttribute( "symbol", symbolIndex );
174  }
175  if ( !mFilterExp.isEmpty() )
176  ruleElem.setAttribute( "filter", mFilterExp );
177  if ( mScaleMinDenom != 0 )
178  ruleElem.setAttribute( "scalemindenom", mScaleMinDenom );
179  if ( mScaleMaxDenom != 0 )
180  ruleElem.setAttribute( "scalemaxdenom", mScaleMaxDenom );
181  if ( !mLabel.isEmpty() )
182  ruleElem.setAttribute( "label", mLabel );
183  if ( !mDescription.isEmpty() )
184  ruleElem.setAttribute( "description", mDescription );
185 
186  for ( RuleList::iterator it = mChildren.begin(); it != mChildren.end(); ++it )
187  {
188  Rule* rule = *it;
189  ruleElem.appendChild( rule->save( doc, symbolMap ) );
190  }
191  return ruleElem;
192 }
193 
194 void QgsRuleBasedRendererV2::Rule::toSld( QDomDocument& doc, QDomElement &element, QgsStringMap props )
195 {
196  // do not convert this rule if there are no symbols
197  if ( symbols().isEmpty() )
198  return;
199 
200  if ( !mFilterExp.isEmpty() )
201  {
202  if ( !props.value( "filter", "" ).isEmpty() )
203  props[ "filter" ] += " AND ";
204  props[ "filter" ] += mFilterExp;
205  }
206 
207  if ( mScaleMinDenom != 0 )
208  {
209  bool ok;
210  int parentScaleMinDenom = props.value( "scaleMinDenom", "0" ).toInt( &ok );
211  if ( !ok || parentScaleMinDenom <= 0 )
212  props[ "scaleMinDenom" ] = QString::number( mScaleMinDenom );
213  else
214  props[ "scaleMinDenom" ] = QString::number( qMax( parentScaleMinDenom, mScaleMinDenom ) );
215  }
216 
217  if ( mScaleMaxDenom != 0 )
218  {
219  bool ok;
220  int parentScaleMaxDenom = props.value( "scaleMaxDenom", "0" ).toInt( &ok );
221  if ( !ok || parentScaleMaxDenom <= 0 )
222  props[ "scaleMaxDenom" ] = QString::number( mScaleMaxDenom );
223  else
224  props[ "scaleMaxDenom" ] = QString::number( qMin( parentScaleMaxDenom, mScaleMaxDenom ) );
225  }
226 
227  if ( mSymbol )
228  {
229  QDomElement ruleElem = doc.createElement( "se:Rule" );
230  element.appendChild( ruleElem );
231 
232  //XXX: <se:Name> is the rule identifier, but our the Rule objects
233  // have no properties could be used as identifier. Use the label.
234  QDomElement nameElem = doc.createElement( "se:Name" );
235  nameElem.appendChild( doc.createTextNode( mLabel ) );
236  ruleElem.appendChild( nameElem );
237 
238  if ( !mLabel.isEmpty() || !mDescription.isEmpty() )
239  {
240  QDomElement descrElem = doc.createElement( "se:Description" );
241  if ( !mLabel.isEmpty() )
242  {
243  QDomElement titleElem = doc.createElement( "se:Title" );
244  titleElem.appendChild( doc.createTextNode( mLabel ) );
245  descrElem.appendChild( titleElem );
246  }
247  if ( !mDescription.isEmpty() )
248  {
249  QDomElement abstractElem = doc.createElement( "se:Abstract" );
250  abstractElem.appendChild( doc.createTextNode( mDescription ) );
251  descrElem.appendChild( abstractElem );
252  }
253  ruleElem.appendChild( descrElem );
254  }
255 
256  if ( !props.value( "filter", "" ).isEmpty() )
257  {
258  QgsSymbolLayerV2Utils::createFunctionElement( doc, ruleElem, props.value( "filter", "" ) );
259  }
260 
261  if ( !props.value( "scaleMinDenom", "" ).isEmpty() )
262  {
263  QDomElement scaleMinDenomElem = doc.createElement( "se:MinScaleDenominator" );
264  scaleMinDenomElem.appendChild( doc.createTextNode( props.value( "scaleMinDenom", "" ) ) );
265  ruleElem.appendChild( scaleMinDenomElem );
266  }
267 
268  if ( !props.value( "scaleMaxDenom", "" ).isEmpty() )
269  {
270  QDomElement scaleMaxDenomElem = doc.createElement( "se:MaxScaleDenominator" );
271  scaleMaxDenomElem.appendChild( doc.createTextNode( props.value( "scaleMaxDenom", "" ) ) );
272  ruleElem.appendChild( scaleMaxDenomElem );
273  }
274 
275  mSymbol->toSld( doc, ruleElem, props );
276  }
277 
278  // loop into childern rule list
279  for ( RuleList::iterator it = mChildren.begin(); it != mChildren.end(); ++it )
280  {
281  ( *it )->toSld( doc, element, props );
282  }
283 }
284 
286 {
287  mActiveChildren.clear();
288 
289  // filter out rules which are not compatible with this scale
290  if ( !isScaleOK( context.rendererScale() ) )
291  return false;
292 
293  // init this rule
294  if ( mFilter )
295  mFilter->prepare( vlayer->pendingFields() );
296  if ( mSymbol )
297  mSymbol->startRender( context, vlayer );
298 
299  // init children
300  // build temporary list of active rules (usable with this scale)
301  for ( RuleList::iterator it = mChildren.begin(); it != mChildren.end(); ++it )
302  {
303  Rule* rule = *it;
304  if ( rule->startRender( context, vlayer ) )
305  {
306  // only add those which are active with current scale
307  mActiveChildren.append( rule );
308  }
309  }
310  return true;
311 }
312 
314 {
315  QSet<int> symbolZLevelsSet;
316 
317  // process this rule
318  if ( mSymbol )
319  {
320  // find out which Z-levels are used
321  for ( int i = 0; i < mSymbol->symbolLayerCount(); i++ )
322  {
323  symbolZLevelsSet.insert( mSymbol->symbolLayer( i )->renderingPass() );
324  }
325  }
326 
327  // process children
328  QList<Rule*>::iterator it;
329  for ( it = mActiveChildren.begin(); it != mActiveChildren.end(); ++it )
330  {
331  Rule* rule = *it;
332  symbolZLevelsSet.unite( rule->collectZLevels() );
333  }
334  return symbolZLevelsSet;
335 }
336 
337 void QgsRuleBasedRendererV2::Rule::setNormZLevels( const QMap<int, int>& zLevelsToNormLevels )
338 {
339  if ( mSymbol )
340  {
341  for ( int i = 0; i < mSymbol->symbolLayerCount(); i++ )
342  {
343  int normLevel = zLevelsToNormLevels.value( mSymbol->symbolLayer( i )->renderingPass() );
344  mSymbolNormZLevels.append( normLevel );
345  }
346  }
347 
348  // prepare list of normalized levels for each rule
349  for ( QList<Rule*>::iterator it = mActiveChildren.begin(); it != mActiveChildren.end(); ++it )
350  {
351  Rule* rule = *it;
352  rule->setNormZLevels( zLevelsToNormLevels );
353  }
354 }
355 
356 
358 {
359  if ( !isFilterOK( featToRender.feat ) )
360  return false;
361 
362  bool rendered = false;
363 
364  // create job for this feature and this symbol, add to list of jobs
365  if ( mSymbol )
366  {
367  // add job to the queue: each symbol's zLevel must be added
368  foreach ( int normZLevel, mSymbolNormZLevels )
369  {
370  //QgsDebugMsg(QString("add job at level %1").arg(normZLevel));
371  renderQueue[normZLevel].jobs.append( new RenderJob( featToRender, mSymbol ) );
372  }
373  rendered = true;
374  }
375 
376  // process children
377  for ( QList<Rule*>::iterator it = mActiveChildren.begin(); it != mActiveChildren.end(); ++it )
378  {
379  Rule* rule = *it;
380  rendered |= rule->renderFeature( featToRender, context, renderQueue );
381  }
382  return rendered;
383 }
384 
386 {
387  if ( !isFilterOK( feat ) )
388  return false;
389  if ( mSymbol )
390  return true;
391 
392  for ( QList<Rule*>::iterator it = mActiveChildren.begin(); it != mActiveChildren.end(); ++it )
393  {
394  Rule* rule = *it;
395  if ( rule->willRenderFeature( feat ) )
396  return true;
397  }
398  return false;
399 }
400 
402 {
403  QgsSymbolV2List lst;
404  if ( !isFilterOK( feat ) )
405  return lst;
406  if ( mSymbol )
407  lst.append( mSymbol );
408 
409  for ( QList<Rule*>::iterator it = mActiveChildren.begin(); it != mActiveChildren.end(); ++it )
410  {
411  Rule* rule = *it;
412  lst += rule->symbolsForFeature( feat );
413  }
414  return lst;
415 }
416 
418 {
419  RuleList lst;
420  if ( !isFilterOK( feat ) )
421  return lst;
422 
423  if ( mSymbol )
424  lst.append( this );
425 
426  for ( QList<Rule*>::iterator it = mActiveChildren.begin(); it != mActiveChildren.end(); ++it )
427  {
428  Rule* rule = *it;
429  lst += rule->rulesForFeature( feat );
430  }
431  return lst;
432 }
433 
435 {
436  if ( mSymbol )
437  mSymbol->stopRender( context );
438 
439  for ( QList<Rule*>::iterator it = mActiveChildren.begin(); it != mActiveChildren.end(); ++it )
440  {
441  Rule* rule = *it;
442  rule->stopRender( context );
443  }
444 
445  mActiveChildren.clear();
446  mSymbolNormZLevels.clear();
447 }
448 
450 {
451  QString symbolIdx = ruleElem.attribute( "symbol" );
452  QgsSymbolV2* symbol = NULL;
453  if ( !symbolIdx.isEmpty() )
454  {
455  if ( symbolMap.contains( symbolIdx ) )
456  {
457  symbol = symbolMap.take( symbolIdx );
458  }
459  else
460  {
461  QgsDebugMsg( "symbol for rule " + symbolIdx + " not found!" );
462  }
463  }
464 
465  QString filterExp = ruleElem.attribute( "filter" );
466  QString label = ruleElem.attribute( "label" );
467  QString description = ruleElem.attribute( "description" );
468  int scaleMinDenom = ruleElem.attribute( "scalemindenom", "0" ).toInt();
469  int scaleMaxDenom = ruleElem.attribute( "scalemaxdenom", "0" ).toInt();
470  Rule* rule = new Rule( symbol, scaleMinDenom, scaleMaxDenom, filterExp, label, description );
471 
472  QDomElement childRuleElem = ruleElem.firstChildElement( "rule" );
473  while ( !childRuleElem.isNull() )
474  {
475  Rule* childRule = create( childRuleElem, symbolMap );
476  if ( childRule )
477  {
478  rule->appendChild( childRule );
479  }
480  else
481  {
482  QgsDebugMsg( "failed to init a child rule!" );
483  }
484  childRuleElem = childRuleElem.nextSiblingElement( "rule" );
485  }
486 
487  return rule;
488 }
489 
491 {
492  if ( ruleElem.localName() != "Rule" )
493  {
494  QgsDebugMsg( QString( "invalid element: Rule element expected, %1 found!" ).arg( ruleElem.tagName() ) );
495  return NULL;
496  }
497 
498  QString label, description, filterExp;
499  int scaleMinDenom = 0, scaleMaxDenom = 0;
500  QgsSymbolLayerV2List layers;
501 
502  // retrieve the Rule element child nodes
503  QDomElement childElem = ruleElem.firstChildElement();
504  while ( !childElem.isNull() )
505  {
506  if ( childElem.localName() == "Name" )
507  {
508  // <se:Name> tag contains the rule identifier,
509  // so prefer title tag for the label property value
510  if ( label.isEmpty() )
511  label = childElem.firstChild().nodeValue();
512  }
513  else if ( childElem.localName() == "Description" )
514  {
515  // <se:Description> can contains a title and an abstract
516  QDomElement titleElem = childElem.firstChildElement( "Title" );
517  if ( !titleElem.isNull() )
518  {
519  label = titleElem.firstChild().nodeValue();
520  }
521 
522  QDomElement abstractElem = childElem.firstChildElement( "Abstract" );
523  if ( !abstractElem.isNull() )
524  {
525  description = abstractElem.firstChild().nodeValue();
526  }
527  }
528  else if ( childElem.localName() == "Abstract" )
529  {
530  // <sld:Abstract> (v1.0)
531  description = childElem.firstChild().nodeValue();
532  }
533  else if ( childElem.localName() == "Title" )
534  {
535  // <sld:Title> (v1.0)
536  label = childElem.firstChild().nodeValue();
537  }
538  else if ( childElem.localName() == "Filter" )
539  {
541  if ( filter )
542  {
543  if ( filter->hasParserError() )
544  {
545  QgsDebugMsg( "parser error: " + filter->parserErrorString() );
546  }
547  else
548  {
549  filterExp = filter->dump();
550  }
551  delete filter;
552  }
553  }
554  else if ( childElem.localName() == "MinScaleDenominator" )
555  {
556  bool ok;
557  int v = childElem.firstChild().nodeValue().toInt( &ok );
558  if ( ok )
559  scaleMinDenom = v;
560  }
561  else if ( childElem.localName() == "MaxScaleDenominator" )
562  {
563  bool ok;
564  int v = childElem.firstChild().nodeValue().toInt( &ok );
565  if ( ok )
566  scaleMaxDenom = v;
567  }
568  else if ( childElem.localName().endsWith( "Symbolizer" ) )
569  {
570  // create symbol layers for this symbolizer
571  QgsSymbolLayerV2Utils::createSymbolLayerV2ListFromSld( childElem, geomType, layers );
572  }
573 
574  childElem = childElem.nextSiblingElement();
575  }
576 
577  // now create the symbol
578  QgsSymbolV2 *symbol = 0;
579  if ( layers.size() > 0 )
580  {
581  switch ( geomType )
582  {
583  case QGis::Line:
584  symbol = new QgsLineSymbolV2( layers );
585  break;
586 
587  case QGis::Polygon:
588  symbol = new QgsFillSymbolV2( layers );
589  break;
590 
591  case QGis::Point:
592  symbol = new QgsMarkerSymbolV2( layers );
593  break;
594 
595  default:
596  QgsDebugMsg( QString( "invalid geometry type: found %1" ).arg( geomType ) );
597  return NULL;
598  }
599  }
600 
601  // and then create and return the new rule
602  return new Rule( symbol, scaleMinDenom, scaleMaxDenom, filterExp, label, description );
603 }
604 
605 
607 
609  : QgsFeatureRendererV2( "RuleRenderer" ), mRootRule( root )
610 {
611 }
612 
614  : QgsFeatureRendererV2( "RuleRenderer" )
615 {
616  mRootRule = new Rule( NULL ); // root has no symbol, no filter etc - just a container
617  mRootRule->appendChild( new Rule( defaultSymbol ) );
618 }
619 
621 {
622  delete mRootRule;
623 }
624 
625 
627 {
628  // not used at all
629  return 0;
630 }
631 
633  QgsRenderContext& context,
634  int layer,
635  bool selected,
636  bool drawVertexMarker )
637 {
638  Q_UNUSED( layer );
639 
640  int flags = ( selected ? FeatIsSelected : 0 ) | ( drawVertexMarker ? FeatDrawMarkers : 0 );
641  mCurrentFeatures.append( FeatureToRender( feature, flags ) );
642 
643  // check each active rule
644  return mRootRule->renderFeature( mCurrentFeatures.last(), context, mRenderQueue );
645 }
646 
647 
649 {
650  // prepare active children
651  mRootRule->startRender( context, vlayer );
652 
653  QSet<int> symbolZLevelsSet = mRootRule->collectZLevels();
654  QList<int> symbolZLevels = symbolZLevelsSet.toList();
655  qSort( symbolZLevels );
656 
657  // create mapping from unnormalized levels [unlimited range] to normalized levels [0..N-1]
658  // and prepare rendering queue
659  QMap<int, int> zLevelsToNormLevels;
660  int maxNormLevel = -1;
661  foreach ( int zLevel, symbolZLevels )
662  {
663  zLevelsToNormLevels[zLevel] = ++maxNormLevel;
664  mRenderQueue.append( RenderLevel( zLevel ) );
665  QgsDebugMsg( QString( "zLevel %1 -> %2" ).arg( zLevel ).arg( maxNormLevel ) );
666  }
667 
668  mRootRule->setNormZLevels( zLevelsToNormLevels );
669 }
670 
672 {
673  //
674  // do the actual rendering
675  //
676 
677  // go through all levels
678  foreach ( const RenderLevel& level, mRenderQueue )
679  {
680  //QgsDebugMsg(QString("level %1").arg(level.zIndex));
681  // go through all jobs at the level
682  foreach ( const RenderJob* job, level.jobs )
683  {
684  //QgsDebugMsg(QString("job fid %1").arg(job->f->id()));
685  // render feature - but only with symbol layers with specified zIndex
686  QgsSymbolV2* s = job->symbol;
687  int count = s->symbolLayerCount();
688  for ( int i = 0; i < count; i++ )
689  {
690  // TODO: better solution for this
691  // renderFeatureWithSymbol asks which symbol layer to draw
692  // but there are multiple transforms going on!
693  if ( s->symbolLayer( i )->renderingPass() == level.zIndex )
694  {
695  int flags = job->ftr.flags;
696  renderFeatureWithSymbol( job->ftr.feat, job->symbol, context, i, flags & FeatIsSelected, flags & FeatDrawMarkers );
697  }
698  }
699  }
700  }
701 
702  // clean current features
703  mCurrentFeatures.clear();
704 
705  // clean render queue
706  mRenderQueue.clear();
707 
708  // clean up rules from temporary stuff
709  mRootRule->stopRender( context );
710 }
711 
713 {
714  QSet<QString> attrs = mRootRule->usedAttributes();
715  return attrs.values();
716 }
717 
719 {
721 
724  return r;
725 }
726 
727 void QgsRuleBasedRendererV2::toSld( QDomDocument& doc, QDomElement &element ) const
728 {
729  mRootRule->toSld( doc, element, QgsStringMap() );
730 }
731 
732 // TODO: ideally this function should be removed in favor of legendSymbol(ogy)Items
734 {
735  return mRootRule->symbols();
736 }
737 
738 QDomElement QgsRuleBasedRendererV2::save( QDomDocument& doc )
739 {
740  QDomElement rendererElem = doc.createElement( RENDERER_TAG_NAME );
741  rendererElem.setAttribute( "type", "RuleRenderer" );
742  rendererElem.setAttribute( "symbollevels", ( mUsingSymbolLevels ? "1" : "0" ) );
743 
745 
746  QDomElement rulesElem = mRootRule->save( doc, symbols );
747  rulesElem.setTagName( "rules" ); // instead of just "rule"
748  rendererElem.appendChild( rulesElem );
749 
750  QDomElement symbolsElem = QgsSymbolLayerV2Utils::saveSymbols( symbols, "symbols", doc );
751  rendererElem.appendChild( symbolsElem );
752 
753  return rendererElem;
754 }
755 
757 {
760  for ( QgsLegendSymbolList::iterator it = items.begin(); it != items.end(); it++ )
761  {
762  QPair<QString, QgsSymbolV2*> pair = *it;
763  QPixmap pix = QgsSymbolLayerV2Utils::symbolPreviewPixmap( pair.second, iconSize );
764  lst << qMakePair( pair.first, pix );
765  }
766  return lst;
767 }
768 
770 {
771  return mRootRule->legendSymbolItems();
772 }
773 
774 
776 {
777  // load symbols
778  QDomElement symbolsElem = element.firstChildElement( "symbols" );
779  if ( symbolsElem.isNull() )
780  return NULL;
781 
782  QgsSymbolV2Map symbolMap = QgsSymbolLayerV2Utils::loadSymbols( symbolsElem );
783 
784  QDomElement rulesElem = element.firstChildElement( "rules" );
785 
786  Rule* root = Rule::create( rulesElem, symbolMap );
787  if ( root == NULL )
788  return NULL;
789 
791 
792  // delete symbols if there are any more
794 
795  return r;
796 }
797 
799 {
800  // retrieve child rules
801  Rule* root = 0;
802 
803  QDomElement ruleElem = element.firstChildElement( "Rule" );
804  while ( !ruleElem.isNull() )
805  {
806  Rule *child = Rule::createFromSld( ruleElem, geomType );
807  if ( child )
808  {
809  // create the root rule if not done before
810  if ( !root )
811  root = new Rule( 0 );
812 
813  root->appendChild( child );
814  }
815 
816  ruleElem = ruleElem.nextSiblingElement( "Rule" );
817  }
818 
819  if ( !root )
820  {
821  // no valid rules was found
822  return NULL;
823  }
824 
825  // create and return the new renderer
826  return new QgsRuleBasedRendererV2( root );
827 }
828 
831 
833 {
834  foreach ( const QgsRendererCategoryV2& cat, r->categories() )
835  {
836  QString attr = QgsExpression::quotedColumnRef( r->classAttribute() );
837  QString value;
838  // not quoting numbers saves a type cast
839  if ( cat.value().type() == QVariant::Int )
840  value = cat.value().toString();
841  else if ( cat.value().type() == QVariant::Double )
842  // we loose precision here - so we may miss some categories :-(
843  // TODO: have a possibility to construct expressions directly as a parse tree to avoid loss of precision
844  value = QString::number( cat.value().toDouble(), 'f', 4 );
845  else
846  value = QgsExpression::quotedString( cat.value().toString() );
847  QString filter = QString( "%1 = %2" ).arg( attr ).arg( value );
848  QString label = filter;
849  initialRule->appendChild( new Rule( cat.symbol()->clone(), 0, 0, filter, label ) );
850  }
851 }
852 
854 {
855  foreach ( const QgsRendererRangeV2& rng, r->ranges() )
856  {
857  // due to the loss of precision in double->string conversion we may miss out values at the limit of the range
858  // TODO: have a possibility to construct expressions directly as a parse tree to avoid loss of precision
859  QString attr = QgsExpression::quotedColumnRef( r->classAttribute() );
860  QString filter = QString( "%1 >= %2 AND %1 <= %3" ).arg( attr )
861  .arg( QString::number( rng.lowerValue(), 'f', 4 ) )
862  .arg( QString::number( rng.upperValue(), 'f', 4 ) );
863  QString label = filter;
864  initialRule->appendChild( new Rule( rng.symbol()->clone(), 0, 0, filter, label ) );
865  }
866 }
867 
869 {
870  qSort( scales ); // make sure the scales are in ascending order
871  int oldScale = initialRule->scaleMinDenom();
872  int maxDenom = initialRule->scaleMaxDenom();
873  QgsSymbolV2* symbol = initialRule->symbol();
874  foreach ( int scale, scales )
875  {
876  if ( initialRule->scaleMinDenom() >= scale )
877  continue; // jump over the first scales out of the interval
878  if ( maxDenom != 0 && maxDenom <= scale )
879  break; // ignore the latter scales out of the interval
880  initialRule->appendChild( new Rule( symbol->clone(), oldScale, scale, QString(), QString( "%1 - %2" ).arg( oldScale ).arg( scale ) ) );
881  oldScale = scale;
882  }
883  // last rule
884  initialRule->appendChild( new Rule( symbol->clone(), oldScale, maxDenom, QString(), QString( "%1 - %2" ).arg( oldScale ).arg( maxDenom ) ) );
885 }
886 
888 {
889  QString msg( "Rule-based renderer:\n" );
890  msg += mRootRule->dump();
891  return msg;
892 }
893 
895 {
896  return mRootRule->willRenderFeature( feat );
897 }
898 
900 {
901  return mRootRule->symbolsForFeature( feat );
902 }