27 #include <QDomDocument>
28 #include <QDomElement>
33 : mParent( NULL ), mSymbol( symbol ),
34 mScaleMinDenom( scaleMinDenom ), mScaleMaxDenom( scaleMaxDenom ),
35 mFilterExp( filterExp ), mLabel( label ), mDescription( description ),
45 qDeleteAll( mChildren );
51 if ( !mFilterExp.isEmpty() )
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 );
72 foreach (
Rule* rule, mChildren )
74 lst.append( rule->
dump( offset + 2 ) );
76 msg += lst.join(
"\n" );
85 attrs.unite( mFilter->referencedColumns().toSet() );
87 attrs.unite( mSymbol->usedAttributes() );
90 for ( RuleList::iterator it = mChildren.begin(); it != mChildren.end(); ++it )
102 lst.append( mSymbol );
104 for ( RuleList::iterator it = mChildren.begin(); it != mChildren.end(); ++it )
122 lst << qMakePair( mLabel, mSymbol );
124 for ( RuleList::iterator it = mChildren.begin(); it != mChildren.end(); ++it )
138 QVariant res = mFilter->evaluate( &f );
139 return res.toInt() != 0;
146 if ( mScaleMinDenom == 0 && mScaleMaxDenom == 0 )
148 if ( mScaleMinDenom != 0 && mScaleMinDenom > scale )
150 if ( mScaleMaxDenom != 0 && mScaleMaxDenom < scale )
158 Rule* newrule =
new Rule( sym, mScaleMinDenom, mScaleMaxDenom, mFilterExp, mLabel, mDescription );
160 foreach (
Rule* rule, mChildren )
167 QDomElement ruleElem = doc.createElement(
"rule" );
171 int symbolIndex = symbolMap.size();
172 symbolMap[QString::number( symbolIndex )] = mSymbol;
173 ruleElem.setAttribute(
"symbol", symbolIndex );
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 );
186 for ( RuleList::iterator it = mChildren.begin(); it != mChildren.end(); ++it )
200 if ( !mFilterExp.isEmpty() )
202 if ( !props.value(
"filter",
"" ).isEmpty() )
203 props[
"filter" ] +=
" AND ";
204 props[
"filter" ] += mFilterExp;
207 if ( mScaleMinDenom != 0 )
210 int parentScaleMinDenom = props.value(
"scaleMinDenom",
"0" ).toInt( &ok );
211 if ( !ok || parentScaleMinDenom <= 0 )
212 props[
"scaleMinDenom" ] = QString::number( mScaleMinDenom );
214 props[
"scaleMinDenom" ] = QString::number( qMax( parentScaleMinDenom, mScaleMinDenom ) );
217 if ( mScaleMaxDenom != 0 )
220 int parentScaleMaxDenom = props.value(
"scaleMaxDenom",
"0" ).toInt( &ok );
221 if ( !ok || parentScaleMaxDenom <= 0 )
222 props[
"scaleMaxDenom" ] = QString::number( mScaleMaxDenom );
224 props[
"scaleMaxDenom" ] = QString::number( qMin( parentScaleMaxDenom, mScaleMaxDenom ) );
229 QDomElement ruleElem = doc.createElement(
"se:Rule" );
230 element.appendChild( ruleElem );
234 QDomElement nameElem = doc.createElement(
"se:Name" );
235 nameElem.appendChild( doc.createTextNode( mLabel ) );
236 ruleElem.appendChild( nameElem );
238 if ( !mLabel.isEmpty() || !mDescription.isEmpty() )
240 QDomElement descrElem = doc.createElement(
"se:Description" );
241 if ( !mLabel.isEmpty() )
243 QDomElement titleElem = doc.createElement(
"se:Title" );
244 titleElem.appendChild( doc.createTextNode( mLabel ) );
245 descrElem.appendChild( titleElem );
247 if ( !mDescription.isEmpty() )
249 QDomElement abstractElem = doc.createElement(
"se:Abstract" );
250 abstractElem.appendChild( doc.createTextNode( mDescription ) );
251 descrElem.appendChild( abstractElem );
253 ruleElem.appendChild( descrElem );
256 if ( !props.value(
"filter",
"" ).isEmpty() )
261 if ( !props.value(
"scaleMinDenom",
"" ).isEmpty() )
263 QDomElement scaleMinDenomElem = doc.createElement(
"se:MinScaleDenominator" );
264 scaleMinDenomElem.appendChild( doc.createTextNode( props.value(
"scaleMinDenom",
"" ) ) );
265 ruleElem.appendChild( scaleMinDenomElem );
268 if ( !props.value(
"scaleMaxDenom",
"" ).isEmpty() )
270 QDomElement scaleMaxDenomElem = doc.createElement(
"se:MaxScaleDenominator" );
271 scaleMaxDenomElem.appendChild( doc.createTextNode( props.value(
"scaleMaxDenom",
"" ) ) );
272 ruleElem.appendChild( scaleMaxDenomElem );
275 mSymbol->toSld( doc, ruleElem, props );
279 for ( RuleList::iterator it = mChildren.begin(); it != mChildren.end(); ++it )
281 ( *it )->toSld( doc, element, props );
287 mActiveChildren.clear();
297 mSymbol->startRender( context, vlayer );
301 for ( RuleList::iterator it = mChildren.begin(); it != mChildren.end(); ++it )
307 mActiveChildren.append( rule );
315 QSet<int> symbolZLevelsSet;
321 for (
int i = 0; i < mSymbol->symbolLayerCount(); i++ )
323 symbolZLevelsSet.insert( mSymbol->symbolLayer( i )->renderingPass() );
328 QList<Rule*>::iterator it;
329 for ( it = mActiveChildren.begin(); it != mActiveChildren.end(); ++it )
334 return symbolZLevelsSet;
341 for (
int i = 0; i < mSymbol->symbolLayerCount(); i++ )
343 int normLevel = zLevelsToNormLevels.value( mSymbol->symbolLayer( i )->renderingPass() );
344 mSymbolNormZLevels.append( normLevel );
349 for ( QList<Rule*>::iterator it = mActiveChildren.begin(); it != mActiveChildren.end(); ++it )
359 if ( !isFilterOK( featToRender.
feat ) )
362 bool rendered =
false;
368 foreach (
int normZLevel, mSymbolNormZLevels )
371 renderQueue[normZLevel].jobs.append(
new RenderJob( featToRender, mSymbol ) );
377 for ( QList<Rule*>::iterator it = mActiveChildren.begin(); it != mActiveChildren.end(); ++it )
380 rendered |= rule->
renderFeature( featToRender, context, renderQueue );
387 if ( !isFilterOK( feat ) )
392 for ( QList<Rule*>::iterator it = mActiveChildren.begin(); it != mActiveChildren.end(); ++it )
404 if ( !isFilterOK( feat ) )
407 lst.append( mSymbol );
409 for ( QList<Rule*>::iterator it = mActiveChildren.begin(); it != mActiveChildren.end(); ++it )
420 if ( !isFilterOK( feat ) )
426 for ( QList<Rule*>::iterator it = mActiveChildren.begin(); it != mActiveChildren.end(); ++it )
437 mSymbol->stopRender( context );
439 for ( QList<Rule*>::iterator it = mActiveChildren.begin(); it != mActiveChildren.end(); ++it )
445 mActiveChildren.clear();
446 mSymbolNormZLevels.clear();
451 QString symbolIdx = ruleElem.attribute(
"symbol" );
453 if ( !symbolIdx.isEmpty() )
455 if ( symbolMap.contains( symbolIdx ) )
457 symbol = symbolMap.take( symbolIdx );
461 QgsDebugMsg(
"symbol for rule " + symbolIdx +
" not found!" );
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 );
472 QDomElement childRuleElem = ruleElem.firstChildElement(
"rule" );
473 while ( !childRuleElem.isNull() )
475 Rule* childRule =
create( childRuleElem, symbolMap );
484 childRuleElem = childRuleElem.nextSiblingElement(
"rule" );
492 if ( ruleElem.localName() !=
"Rule" )
494 QgsDebugMsg( QString(
"invalid element: Rule element expected, %1 found!" ).arg( ruleElem.tagName() ) );
498 QString label, description, filterExp;
499 int scaleMinDenom = 0, scaleMaxDenom = 0;
503 QDomElement childElem = ruleElem.firstChildElement();
504 while ( !childElem.isNull() )
506 if ( childElem.localName() ==
"Name" )
510 if ( label.isEmpty() )
511 label = childElem.firstChild().nodeValue();
513 else if ( childElem.localName() ==
"Description" )
516 QDomElement titleElem = childElem.firstChildElement(
"Title" );
517 if ( !titleElem.isNull() )
519 label = titleElem.firstChild().nodeValue();
522 QDomElement abstractElem = childElem.firstChildElement(
"Abstract" );
523 if ( !abstractElem.isNull() )
525 description = abstractElem.firstChild().nodeValue();
528 else if ( childElem.localName() ==
"Abstract" )
531 description = childElem.firstChild().nodeValue();
533 else if ( childElem.localName() ==
"Title" )
536 label = childElem.firstChild().nodeValue();
538 else if ( childElem.localName() ==
"Filter" )
549 filterExp = filter->
dump();
554 else if ( childElem.localName() ==
"MinScaleDenominator" )
557 int v = childElem.firstChild().nodeValue().toInt( &ok );
561 else if ( childElem.localName() ==
"MaxScaleDenominator" )
564 int v = childElem.firstChild().nodeValue().toInt( &ok );
568 else if ( childElem.localName().endsWith(
"Symbolizer" ) )
574 childElem = childElem.nextSiblingElement();
579 if ( layers.size() > 0 )
596 QgsDebugMsg( QString(
"invalid geometry type: found %1" ).arg( geomType ) );
602 return new Rule( symbol, scaleMinDenom, scaleMaxDenom, filterExp, label, description );
636 bool drawVertexMarker )
654 QList<int> symbolZLevels = symbolZLevelsSet.toList();
655 qSort( symbolZLevels );
659 QMap<int, int> zLevelsToNormLevels;
660 int maxNormLevel = -1;
661 foreach (
int zLevel, symbolZLevels )
663 zLevelsToNormLevels[zLevel] = ++maxNormLevel;
665 QgsDebugMsg( QString(
"zLevel %1 -> %2" ).arg( zLevel ).arg( maxNormLevel ) );
688 for (
int i = 0; i < count; i++ )
715 return attrs.values();
741 rendererElem.setAttribute(
"type",
"RuleRenderer" );
747 rulesElem.setTagName(
"rules" );
748 rendererElem.appendChild( rulesElem );
751 rendererElem.appendChild( symbolsElem );
760 for ( QgsLegendSymbolList::iterator it = items.begin(); it != items.end(); it++ )
762 QPair<QString, QgsSymbolV2*> pair = *it;
764 lst << qMakePair( pair.first, pix );
778 QDomElement symbolsElem = element.firstChildElement(
"symbols" );
779 if ( symbolsElem.isNull() )
784 QDomElement rulesElem = element.firstChildElement(
"rules" );
803 QDomElement ruleElem = element.firstChildElement(
"Rule" );
804 while ( !ruleElem.isNull() )
811 root =
new Rule( 0 );
816 ruleElem = ruleElem.nextSiblingElement(
"Rule" );
839 if ( cat.
value().type() == QVariant::Int )
840 value = cat.
value().toString();
841 else if ( cat.
value().type() == QVariant::Double )
844 value = QString::number( cat.
value().toDouble(),
'f', 4 );
847 QString filter = QString(
"%1 = %2" ).arg( attr ).arg( value );
848 QString label = filter;
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;
874 foreach (
int scale, scales )
878 if ( maxDenom != 0 && maxDenom <= scale )
880 initialRule->
appendChild(
new Rule( symbol->
clone(), oldScale, scale, QString(), QString(
"%1 - %2" ).arg( oldScale ).arg( scale ) ) );
884 initialRule->
appendChild(
new Rule( symbol->
clone(), oldScale, maxDenom, QString(), QString(
"%1 - %2" ).arg( oldScale ).arg( maxDenom ) ) );
889 QString msg(
"Rule-based renderer:\n" );
void toSld(QDomDocument &doc, QDomElement &element, QgsStringMap props)
QMap< QString, QgsSymbolV2 * > QgsSymbolV2Map
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
virtual QgsLegendSymbolList legendSymbolItems()
return a list of item text / symbol
QList< QgsSymbolV2 * > QgsSymbolV2List
QSet< int > collectZLevels()
get all used z-levels from this rule and children
static QgsFeatureRendererV2 * create(QDomElement &element)
Rule(QgsSymbolV2 *symbol, int scaleMinDenom=0, int scaleMaxDenom=0, QString filterExp=QString(), QString label=QString(), QString description=QString())
Constructor takes ownership of the symbol.
QString classAttribute() const
double rendererScale() const
virtual QgsSymbolV2 * clone() const =0
static QgsFeatureRendererV2 * createFromSld(QDomElement &element, QGis::GeometryType geomType)
QList< QPair< QString, QPixmap > > QgsLegendSymbologyList
virtual void stopRender(QgsRenderContext &context)
bool isScaleOK(double scale) const
static QString quotedColumnRef(QString name)
return quoted column reference (in double quotes)
virtual QgsLegendSymbologyList legendSymbologyItems(QSize iconSize)
return a list of symbology items for the legend
Rule * clone() const
clone this rule, return new instance
~QgsRuleBasedRendererV2()
RuleList rulesForFeature(QgsFeature &feat)
tell which rules will be used to render the feature
virtual QDomElement save(QDomDocument &doc)
store renderer info to XML element
QString dump() const
Return the parsed expression as a string - useful for debugging.
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
QMap< QString, QString > QgsStringMap
static QString quotedString(QString text)
return quoted string (in single quotes)
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)
const QgsCategoryList & categories()
bool startRender(QgsRenderContext &context, const QgsVectorLayer *vlayer)
prepare the rule for rendering and its children (build active children array)
void stopRender(QgsRenderContext &context)
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
const QgsRangeList & ranges()
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()
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
bool renderFeature(FeatureToRender &featToRender, QgsRenderContext &context, RenderQueue &renderQueue)
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
QgsLegendSymbolList legendSymbolItems()
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 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...
virtual void startRender(QgsRenderContext &context, const QgsVectorLayer *vlayer)
const QgsFields & pendingFields() const
returns field list in the to-be-committed state
QList< RenderLevel > RenderQueue
QgsSymbolLayerV2 * symbolLayer(int layer)
bool willRenderFeature(QgsFeature &feat)
only tell whether a feature will be rendered without actually rendering it
Represents a vector layer which manages a vector based data sets.
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