27 #include <QDomDocument>
28 #include <QDomElement>
33 : mParent( NULL ), mSymbol( symbol )
34 , mScaleMinDenom( scaleMinDenom ), mScaleMaxDenom( scaleMaxDenom )
35 , mFilterExp( filterExp ), mLabel( label ), mDescription( description )
36 , mElseRule( elseRule ), mFilter( NULL )
45 qDeleteAll( mChildren );
51 if ( mElseRule || mFilterExp.compare(
"ELSE", Qt::CaseInsensitive ) == 0 )
56 else if ( !mFilterExp.isEmpty() )
69 mChildren.append( rule );
76 mChildren.insert( i, rule );
83 mChildren.removeAll( rule );
90 Rule* rule = mChildren[i];
91 mChildren.removeAt( i );
98 mChildren.removeAll( rule );
105 Rule* rule = mChildren.takeAt( i );
114 foreach (
Rule* rule, mChildren )
125 off.fill( QChar(
' ' ), offset );
126 QString symbolDump = ( mSymbol ? mSymbol->dump() : QString(
"[]" ) );
127 QString msg = off + QString(
"RULE %1 - scale [%2,%3] - filter %4 - symbol %5\n" )
128 .arg( mLabel ).arg( mScaleMinDenom ).arg( mScaleMaxDenom )
129 .arg( mFilterExp ).arg( symbolDump );
132 foreach (
Rule* rule, mChildren )
134 lst.append( rule->
dump( offset + 2 ) );
136 msg += lst.join(
"\n" );
145 attrs.unite( mFilter->referencedColumns().toSet() );
147 attrs.unite( mSymbol->usedAttributes() );
150 for ( RuleList::iterator it = mChildren.begin(); it != mChildren.end(); ++it )
162 lst.append( mSymbol );
164 for ( RuleList::iterator it = mChildren.begin(); it != mChildren.end(); ++it )
181 if ( mSymbol && ( ruleFilter.isEmpty() || mLabel == ruleFilter ) )
182 lst << qMakePair( mLabel, mSymbol );
184 for ( RuleList::iterator it = mChildren.begin(); it != mChildren.end(); ++it )
187 if ( scaleDenominator == -1 || rule->
isScaleOK( scaleDenominator ) )
198 if ( ! mFilter || mElseRule )
201 QVariant res = mFilter->evaluate( &f );
202 return res.toInt() != 0;
209 if ( mScaleMinDenom == 0 && mScaleMaxDenom == 0 )
211 if ( mScaleMinDenom != 0 && mScaleMinDenom > scale )
213 if ( mScaleMaxDenom != 0 && mScaleMaxDenom < scale )
221 Rule* newrule =
new Rule( sym, mScaleMinDenom, mScaleMaxDenom, mFilterExp, mLabel, mDescription );
223 foreach (
Rule* rule, mChildren )
230 QDomElement ruleElem = doc.createElement(
"rule" );
234 int symbolIndex = symbolMap.size();
235 symbolMap[QString::number( symbolIndex )] = mSymbol;
236 ruleElem.setAttribute(
"symbol", symbolIndex );
238 if ( !mFilterExp.isEmpty() )
239 ruleElem.setAttribute(
"filter", mFilterExp );
240 if ( mScaleMinDenom != 0 )
241 ruleElem.setAttribute(
"scalemindenom", mScaleMinDenom );
242 if ( mScaleMaxDenom != 0 )
243 ruleElem.setAttribute(
"scalemaxdenom", mScaleMaxDenom );
244 if ( !mLabel.isEmpty() )
245 ruleElem.setAttribute(
"label", mLabel );
246 if ( !mDescription.isEmpty() )
247 ruleElem.setAttribute(
"description", mDescription );
249 for ( RuleList::iterator it = mChildren.begin(); it != mChildren.end(); ++it )
263 if ( !mFilterExp.isEmpty() )
265 if ( !props.value(
"filter",
"" ).isEmpty() )
266 props[
"filter" ] +=
" AND ";
267 props[
"filter" ] += mFilterExp;
270 if ( mScaleMinDenom != 0 )
273 int parentScaleMinDenom = props.value(
"scaleMinDenom",
"0" ).toInt( &ok );
274 if ( !ok || parentScaleMinDenom <= 0 )
275 props[
"scaleMinDenom" ] = QString::number( mScaleMinDenom );
277 props[
"scaleMinDenom" ] = QString::number( qMax( parentScaleMinDenom, mScaleMinDenom ) );
280 if ( mScaleMaxDenom != 0 )
283 int parentScaleMaxDenom = props.value(
"scaleMaxDenom",
"0" ).toInt( &ok );
284 if ( !ok || parentScaleMaxDenom <= 0 )
285 props[
"scaleMaxDenom" ] = QString::number( mScaleMaxDenom );
287 props[
"scaleMaxDenom" ] = QString::number( qMin( parentScaleMaxDenom, mScaleMaxDenom ) );
292 QDomElement ruleElem = doc.createElement(
"se:Rule" );
293 element.appendChild( ruleElem );
297 QDomElement nameElem = doc.createElement(
"se:Name" );
298 nameElem.appendChild( doc.createTextNode( mLabel ) );
299 ruleElem.appendChild( nameElem );
301 if ( !mLabel.isEmpty() || !mDescription.isEmpty() )
303 QDomElement descrElem = doc.createElement(
"se:Description" );
304 if ( !mLabel.isEmpty() )
306 QDomElement titleElem = doc.createElement(
"se:Title" );
307 titleElem.appendChild( doc.createTextNode( mLabel ) );
308 descrElem.appendChild( titleElem );
310 if ( !mDescription.isEmpty() )
312 QDomElement abstractElem = doc.createElement(
"se:Abstract" );
313 abstractElem.appendChild( doc.createTextNode( mDescription ) );
314 descrElem.appendChild( abstractElem );
316 ruleElem.appendChild( descrElem );
319 if ( !props.value(
"filter",
"" ).isEmpty() )
324 if ( !props.value(
"scaleMinDenom",
"" ).isEmpty() )
326 QDomElement scaleMinDenomElem = doc.createElement(
"se:MinScaleDenominator" );
327 scaleMinDenomElem.appendChild( doc.createTextNode( props.value(
"scaleMinDenom",
"" ) ) );
328 ruleElem.appendChild( scaleMinDenomElem );
331 if ( !props.value(
"scaleMaxDenom",
"" ).isEmpty() )
333 QDomElement scaleMaxDenomElem = doc.createElement(
"se:MaxScaleDenominator" );
334 scaleMaxDenomElem.appendChild( doc.createTextNode( props.value(
"scaleMaxDenom",
"" ) ) );
335 ruleElem.appendChild( scaleMaxDenomElem );
338 mSymbol->toSld( doc, ruleElem, props );
342 for ( RuleList::iterator it = mChildren.begin(); it != mChildren.end(); ++it )
344 ( *it )->toSld( doc, element, props );
350 mActiveChildren.clear();
358 mFilter->prepare( fields );
360 mSymbol->startRender( context, &fields );
364 for ( RuleList::iterator it = mChildren.begin(); it != mChildren.end(); ++it )
370 mActiveChildren.append( rule );
378 QSet<int> symbolZLevelsSet;
384 for (
int i = 0; i < mSymbol->symbolLayerCount(); i++ )
386 symbolZLevelsSet.insert( mSymbol->symbolLayer( i )->renderingPass() );
391 QList<Rule*>::iterator it;
392 for ( it = mActiveChildren.begin(); it != mActiveChildren.end(); ++it )
397 return symbolZLevelsSet;
404 for (
int i = 0; i < mSymbol->symbolLayerCount(); i++ )
406 int normLevel = zLevelsToNormLevels.value( mSymbol->symbolLayer( i )->renderingPass() );
407 mSymbolNormZLevels.append( normLevel );
412 for ( QList<Rule*>::iterator it = mActiveChildren.begin(); it != mActiveChildren.end(); ++it )
422 if ( !isFilterOK( featToRender.
feat ) )
425 bool rendered =
false;
431 foreach (
int normZLevel, mSymbolNormZLevels )
434 renderQueue[normZLevel].jobs.append(
new RenderJob( featToRender, mSymbol ) );
439 bool willrendersomething =
false;
442 for ( QList<Rule*>::iterator it = mActiveChildren.begin(); it != mActiveChildren.end(); ++it )
450 willrendersomething |= rule->
renderFeature( featToRender, context, renderQueue );
451 rendered |= willrendersomething;
455 if ( !willrendersomething )
457 foreach (
Rule* rule, mElseRules )
459 rendered |= rule->
renderFeature( featToRender, context, renderQueue );
468 if ( !isFilterOK( feat ) )
473 for ( QList<Rule*>::iterator it = mActiveChildren.begin(); it != mActiveChildren.end(); ++it )
485 if ( !isFilterOK( feat ) )
488 lst.append( mSymbol );
490 for ( QList<Rule*>::iterator it = mActiveChildren.begin(); it != mActiveChildren.end(); ++it )
501 if ( !isFilterOK( feat ) )
507 for ( QList<Rule*>::iterator it = mActiveChildren.begin(); it != mActiveChildren.end(); ++it )
518 mSymbol->stopRender( context );
520 for ( QList<Rule*>::iterator it = mActiveChildren.begin(); it != mActiveChildren.end(); ++it )
526 mActiveChildren.clear();
527 mSymbolNormZLevels.clear();
532 QString symbolIdx = ruleElem.attribute(
"symbol" );
534 if ( !symbolIdx.isEmpty() )
536 if ( symbolMap.contains( symbolIdx ) )
538 symbol = symbolMap.take( symbolIdx );
542 QgsDebugMsg(
"symbol for rule " + symbolIdx +
" not found!" );
546 QString filterExp = ruleElem.attribute(
"filter" );
547 QString label = ruleElem.attribute(
"label" );
548 QString description = ruleElem.attribute(
"description" );
549 int scaleMinDenom = ruleElem.attribute(
"scalemindenom",
"0" ).toInt();
550 int scaleMaxDenom = ruleElem.attribute(
"scalemaxdenom",
"0" ).toInt();
551 Rule* rule =
new Rule( symbol, scaleMinDenom, scaleMaxDenom, filterExp, label, description );
553 QDomElement childRuleElem = ruleElem.firstChildElement(
"rule" );
554 while ( !childRuleElem.isNull() )
556 Rule* childRule =
create( childRuleElem, symbolMap );
565 childRuleElem = childRuleElem.nextSiblingElement(
"rule" );
573 if ( ruleElem.localName() !=
"Rule" )
575 QgsDebugMsg( QString(
"invalid element: Rule element expected, %1 found!" ).arg( ruleElem.tagName() ) );
579 QString label, description, filterExp;
580 int scaleMinDenom = 0, scaleMaxDenom = 0;
584 QDomElement childElem = ruleElem.firstChildElement();
585 while ( !childElem.isNull() )
587 if ( childElem.localName() ==
"Name" )
591 if ( label.isEmpty() )
592 label = childElem.firstChild().nodeValue();
594 else if ( childElem.localName() ==
"Description" )
597 QDomElement titleElem = childElem.firstChildElement(
"Title" );
598 if ( !titleElem.isNull() )
600 label = titleElem.firstChild().nodeValue();
603 QDomElement abstractElem = childElem.firstChildElement(
"Abstract" );
604 if ( !abstractElem.isNull() )
606 description = abstractElem.firstChild().nodeValue();
609 else if ( childElem.localName() ==
"Abstract" )
612 description = childElem.firstChild().nodeValue();
614 else if ( childElem.localName() ==
"Title" )
617 label = childElem.firstChild().nodeValue();
619 else if ( childElem.localName() ==
"Filter" )
635 else if ( childElem.localName() ==
"MinScaleDenominator" )
638 int v = childElem.firstChild().nodeValue().toInt( &ok );
642 else if ( childElem.localName() ==
"MaxScaleDenominator" )
645 int v = childElem.firstChild().nodeValue().toInt( &ok );
649 else if ( childElem.localName().endsWith(
"Symbolizer" ) )
655 childElem = childElem.nextSiblingElement();
660 if ( layers.size() > 0 )
677 QgsDebugMsg( QString(
"invalid geometry type: found %1" ).arg( geomType ) );
683 return new Rule( symbol, scaleMinDenom, scaleMaxDenom, filterExp, label, description );
717 bool drawVertexMarker )
735 QList<int> symbolZLevels = symbolZLevelsSet.toList();
736 qSort( symbolZLevels );
740 QMap<int, int> zLevelsToNormLevels;
741 int maxNormLevel = -1;
742 foreach (
int zLevel, symbolZLevels )
744 zLevelsToNormLevels[zLevel] = ++maxNormLevel;
746 QgsDebugMsg( QString(
"zLevel %1 -> %2" ).arg( zLevel ).arg( maxNormLevel ) );
769 for (
int i = 0; i < count; i++ )
796 return attrs.values();
822 rendererElem.setAttribute(
"type",
"RuleRenderer" );
828 rulesElem.setTagName(
"rules" );
829 rendererElem.appendChild( rulesElem );
832 rendererElem.appendChild( symbolsElem );
841 for ( QgsLegendSymbolList::iterator it = items.begin(); it != items.end(); ++it )
843 QPair<QString, QgsSymbolV2*> pair = *it;
845 lst << qMakePair( pair.first, pix );
859 QDomElement symbolsElem = element.firstChildElement(
"symbols" );
860 if ( symbolsElem.isNull() )
865 QDomElement rulesElem = element.firstChildElement(
"rules" );
884 QDomElement ruleElem = element.firstChildElement(
"Rule" );
885 while ( !ruleElem.isNull() )
892 root =
new Rule( 0 );
897 ruleElem = ruleElem.nextSiblingElement(
"Rule" );
920 if ( cat.
value().type() == QVariant::Int )
921 value = cat.
value().toString();
922 else if ( cat.
value().type() == QVariant::Double )
925 value = QString::number( cat.
value().toDouble(),
'f', 4 );
928 QString filter = QString(
"%1 = %2" ).arg( attr ).arg( value );
929 QString label = filter;
941 QString filter = QString(
"%1 >= %2 AND %1 <= %3" ).arg( attr )
942 .arg( QString::number( rng.
lowerValue(),
'f', 4 ) )
943 .arg( QString::number( rng.
upperValue(),
'f', 4 ) );
944 QString label = filter;
955 foreach (
int scale, scales )
959 if ( maxDenom != 0 && maxDenom <= scale )
961 initialRule->
appendChild(
new Rule( symbol->
clone(), oldScale, scale, QString(), QString(
"%1 - %2" ).arg( oldScale ).arg( scale ) ) );
965 initialRule->
appendChild(
new Rule( symbol->
clone(), oldScale, maxDenom, QString(), QString(
"%1 - %2" ).arg( oldScale ).arg( maxDenom ) ) );
970 QString msg(
"Rule-based renderer:\n" );
void toSld(QDomDocument &doc, QDomElement &element, QgsStringMap props)
QMap< QString, QgsSymbolV2 * > QgsSymbolV2Map
virtual void startRender(QgsRenderContext &context, const QgsFields &fields)
Class for parsing and evaluation of expressions (formerly called "search strings").
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
bool hasParserError() const
Returns true if an error occurred when parsing the input expression.
virtual QgsSymbolV2List symbolsForFeature(QgsFeature &feat)
return list of symbols used for rendering the feature.
virtual QString dump() const
for debugging
const QgsCategoryList & categories() const
static QString quotedColumnRef(QString name)
return quoted column reference (in double quotes)
QList< QgsSymbolV2 * > QgsSymbolV2List
QSet< int > collectZLevels()
get all used z-levels from this rule and children
const QString expression() const
Alias for dump()
static QgsFeatureRendererV2 * create(QDomElement &element)
QString classAttribute() const
double rendererScale() const
virtual QgsSymbolV2 * clone() const =0
static QgsFeatureRendererV2 * createFromSld(QDomElement &element, QGis::GeometryType geomType)
virtual void stopRender(QgsRenderContext &context)
bool isScaleOK(double scale) const
virtual QgsLegendSymbologyList legendSymbologyItems(QSize iconSize)
return a list of symbology items for the legend
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
~QgsRuleBasedRendererV2()
RuleList rulesForFeature(QgsFeature &feat)
tell which rules will be used to render the feature
Container of fields for a vector layer.
void removeChild(Rule *rule)
delete child rule
virtual QDomElement save(QDomDocument &doc)
store renderer info to XML element
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
QMap< QString, QString > QgsStringMap
void removeChildAt(int i)
delete child rule
void renderFeatureWithSymbol(QgsFeature &feature, QgsSymbolV2 *symbol, QgsRenderContext &context, int layer, bool selected, bool drawVertexMarker)
double upperValue() const
static bool createSymbolLayerV2ListFromSld(QDomElement &element, QGis::GeometryType geomType, QgsSymbolLayerV2List &layers)
void stopRender(QgsRenderContext &context)
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 ...
int scaleMinDenom() const
void takeChild(Rule *rule)
take child rule out, set parent as null
const QgsRangeList & ranges()
virtual QgsLegendSymbolList legendSymbolItems(double scaleDenominator=-1, QString rule="")
return a list of item text / symbol
static bool createFunctionElement(QDomDocument &doc, QDomElement &element, QString function)
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)
QgsSymbolV2 * symbol() const
QDomElement save(QDomDocument &doc, QgsSymbolV2Map &symbolMap)
bool isFilterOK(QgsFeature &f) const
This class keeps data about a rules for rule-based renderer.
virtual bool renderFeature(QgsFeature &feature, QgsRenderContext &context, int layer=-1, bool selected=false, bool drawVertexMarker=false)
virtual QgsFeatureRendererV2 * clone()
QgsLegendSymbolList legendSymbolItems(double scaleDenominator=-1, QString rule="")
QList< RenderJob * > jobs
Rule * mRootRule
the root node with hierarchical list of rules
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)
QList< QPair< QString, QPixmap > > QgsLegendSymbologyList
int renderingPass() const
virtual bool willRenderFeature(QgsFeature &feat)
return whether the renderer will render a feature or not.
QgsRuleBasedRendererV2(QgsRuleBasedRendererV2::Rule *root)
Constructs the renderer from given tree of rules (takes ownership)
void setUsingSymbolLevels(bool usingSymbolLevels)
int scaleMaxDenom() const
Contains information about the context of a rendering operation.
double lowerValue() const
QList< QgsSymbolLayerV2 * > QgsSymbolLayerV2List
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)
bool usingSymbolLevels() const
static QgsExpression * expressionFromOgcFilter(const QDomElement &element)
Parse XML with OGC filter into QGIS expression.
QSet< QString > usedAttributes()
static QString quotedString(QString text)
return quoted string (in single quotes)
static QPixmap symbolPreviewPixmap(QgsSymbolV2 *symbol, QSize size)
QString classAttribute() const
static void clearSymbolMap(QgsSymbolV2Map &symbols)
void setSymbol(QgsSymbolV2 *sym)
set a new symbol (or NULL). Deletes old symbol.
virtual QgsSymbolV2 * symbolForFeature(QgsFeature &feature)
return symbol for current feature. Should not be used individually: there could be more symbols for a...
QList< RenderLevel > RenderQueue
QgsSymbolLayerV2 * symbolLayer(int layer)
void insertChild(int i, Rule *rule)
add child rule, take ownership, sets this as parent
bool willRenderFeature(QgsFeature &feat)
only tell whether a feature will be rendered without actually rendering it
QList< QPair< QString, QgsSymbolV2 * > > QgsLegendSymbolList
QString parserErrorString() const
Returns parser error.
virtual QList< QString > usedAttributes()
QgsSymbolV2 * symbol() const
virtual void toSld(QDomDocument &doc, QDomElement &element) const
used from subclasses to create SLD Rule elements following SLD v1.1 specs
QList< FeatureToRender > mCurrentFeatures
QgsSymbolV2List symbols()
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 symbols()
for symbol levels