Branch data Line data Source code
1 : : /***************************************************************************
2 : : qgsrulebasedlabeling.cpp
3 : : ---------------------
4 : : begin : September 2015
5 : : copyright : (C) 2015 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 : : #include "qgsrulebasedlabeling.h"
16 : : #include "qgssymbollayerutils.h"
17 : : #include "qgsstyleentityvisitor.h"
18 : :
19 : 0 : QgsRuleBasedLabelProvider::QgsRuleBasedLabelProvider( const QgsRuleBasedLabeling &rules, QgsVectorLayer *layer, bool withFeatureLoop )
20 : 0 : : QgsVectorLayerLabelProvider( layer, QString(), withFeatureLoop, nullptr )
21 : 0 : {
22 : 0 : mRules.reset( rules.clone() );
23 : 0 : mRules->rootRule()->createSubProviders( layer, mSubProviders, this );
24 : 0 : }
25 : :
26 : 0 : QgsVectorLayerLabelProvider *QgsRuleBasedLabelProvider::createProvider( QgsVectorLayer *layer, const QString &providerId, bool withFeatureLoop, const QgsPalLayerSettings *settings )
27 : : {
28 : 0 : return new QgsVectorLayerLabelProvider( layer, providerId, withFeatureLoop, settings );
29 : 0 : }
30 : :
31 : 0 : bool QgsRuleBasedLabelProvider::prepare( QgsRenderContext &context, QSet<QString> &attributeNames )
32 : : {
33 : 0 : for ( QgsVectorLayerLabelProvider *provider : std::as_const( mSubProviders ) )
34 : 0 : provider->setEngine( mEngine );
35 : :
36 : : // populate sub-providers
37 : 0 : mRules->rootRule()->prepare( context, attributeNames, mSubProviders );
38 : 0 : return true;
39 : : }
40 : :
41 : 0 : void QgsRuleBasedLabelProvider::registerFeature( const QgsFeature &feature, QgsRenderContext &context, const QgsGeometry &obstacleGeometry, const QgsSymbol *symbol )
42 : : {
43 : : // will register the feature to relevant sub-providers
44 : 0 : mRules->rootRule()->registerFeature( feature, context, mSubProviders, obstacleGeometry, symbol );
45 : 0 : }
46 : :
47 : 0 : QList<QgsAbstractLabelProvider *> QgsRuleBasedLabelProvider::subProviders()
48 : : {
49 : 0 : QList<QgsAbstractLabelProvider *> lst;
50 : 0 : for ( QgsVectorLayerLabelProvider *subprovider : std::as_const( mSubProviders ) )
51 : 0 : lst << subprovider;
52 : 0 : return lst;
53 : 0 : }
54 : :
55 : :
56 : : ////////////////////
57 : :
58 : 0 : QgsRuleBasedLabeling::Rule::Rule( QgsPalLayerSettings *settings, double scaleMinDenom, double scaleMaxDenom, const QString &filterExp, const QString &description, bool elseRule )
59 : 0 : : mSettings( settings )
60 : 0 : , mMaximumScale( scaleMinDenom )
61 : 0 : , mMinimumScale( scaleMaxDenom )
62 : 0 : , mFilterExp( filterExp )
63 : 0 : , mDescription( description )
64 : 0 : , mElseRule( elseRule )
65 : :
66 : : {
67 : 0 : initFilter();
68 : 0 : }
69 : :
70 : 0 : QgsRuleBasedLabeling::Rule::~Rule()
71 : : {
72 : 0 : qDeleteAll( mChildren );
73 : : // do NOT delete parent
74 : 0 : }
75 : :
76 : 0 : void QgsRuleBasedLabeling::Rule::setSettings( QgsPalLayerSettings *settings )
77 : : {
78 : 0 : if ( mSettings.get() == settings )
79 : 0 : return;
80 : :
81 : 0 : mSettings.reset( settings );
82 : 0 : }
83 : :
84 : 0 : QgsRuleBasedLabeling::RuleList QgsRuleBasedLabeling::Rule::descendants() const
85 : : {
86 : 0 : RuleList l;
87 : 0 : for ( Rule *c : mChildren )
88 : : {
89 : 0 : l += c;
90 : 0 : l += c->descendants();
91 : : }
92 : 0 : return l;
93 : 0 : }
94 : :
95 : 0 : void QgsRuleBasedLabeling::Rule::initFilter()
96 : : {
97 : 0 : if ( mElseRule || mFilterExp.compare( QLatin1String( "ELSE" ), Qt::CaseInsensitive ) == 0 )
98 : : {
99 : 0 : mElseRule = true;
100 : 0 : mFilter.reset( nullptr );
101 : 0 : }
102 : 0 : else if ( !mFilterExp.isEmpty() )
103 : : {
104 : 0 : mFilter.reset( new QgsExpression( mFilterExp ) );
105 : 0 : }
106 : : else
107 : : {
108 : 0 : mFilter.reset( nullptr );
109 : : }
110 : 0 : }
111 : :
112 : 0 : void QgsRuleBasedLabeling::Rule::updateElseRules()
113 : : {
114 : 0 : mElseRules.clear();
115 : 0 : for ( Rule *rule : std::as_const( mChildren ) )
116 : : {
117 : 0 : if ( rule->isElse() )
118 : 0 : mElseRules << rule;
119 : : }
120 : 0 : }
121 : :
122 : 0 : bool QgsRuleBasedLabeling::Rule::requiresAdvancedEffects() const
123 : : {
124 : 0 : if ( mSettings && mSettings->format().containsAdvancedEffects() )
125 : 0 : return true;
126 : :
127 : 0 : for ( Rule *rule : std::as_const( mChildren ) )
128 : : {
129 : 0 : if ( rule->requiresAdvancedEffects() )
130 : 0 : return true;
131 : : }
132 : :
133 : 0 : return false;
134 : 0 : }
135 : :
136 : 0 : bool QgsRuleBasedLabeling::Rule::accept( QgsStyleEntityVisitorInterface *visitor ) const
137 : : {
138 : : // NOTE: if visitEnter returns false it means "don't visit the rule", not "abort all further visitations"
139 : 0 : if ( mParent && !visitor->visitEnter( QgsStyleEntityVisitorInterface::Node( QgsStyleEntityVisitorInterface::NodeType::SymbolRule, mRuleKey, mDescription ) ) )
140 : 0 : return true;
141 : :
142 : 0 : if ( mSettings )
143 : : {
144 : 0 : QgsStyleLabelSettingsEntity entity( *mSettings );
145 : 0 : if ( !visitor->visit( QgsStyleEntityVisitorInterface::StyleLeaf( &entity ) ) )
146 : 0 : return false;
147 : 0 : }
148 : :
149 : 0 : if ( !mChildren.empty() )
150 : : {
151 : 0 : for ( const Rule *rule : mChildren )
152 : : {
153 : 0 : if ( !rule->accept( visitor ) )
154 : 0 : return false;
155 : : }
156 : 0 : }
157 : :
158 : 0 : if ( mParent && !visitor->visitExit( QgsStyleEntityVisitorInterface::Node( QgsStyleEntityVisitorInterface::NodeType::SymbolRule, mRuleKey, mDescription ) ) )
159 : 0 : return false;
160 : :
161 : 0 : return true;
162 : 0 : }
163 : :
164 : 0 : void QgsRuleBasedLabeling::Rule::subProviderIds( QStringList &list ) const
165 : : {
166 : 0 : for ( const Rule *rule : std::as_const( mChildren ) )
167 : : {
168 : 0 : if ( rule->settings() )
169 : 0 : list << rule->ruleKey();
170 : :
171 : 0 : rule->subProviderIds( list );
172 : : }
173 : 0 : }
174 : :
175 : :
176 : 0 : void QgsRuleBasedLabeling::Rule::appendChild( QgsRuleBasedLabeling::Rule *rule )
177 : : {
178 : 0 : mChildren.append( rule );
179 : 0 : rule->mParent = this;
180 : 0 : updateElseRules();
181 : 0 : }
182 : :
183 : 0 : void QgsRuleBasedLabeling::Rule::insertChild( int i, QgsRuleBasedLabeling::Rule *rule )
184 : : {
185 : 0 : mChildren.insert( i, rule );
186 : 0 : rule->mParent = this;
187 : 0 : updateElseRules();
188 : 0 : }
189 : :
190 : 0 : void QgsRuleBasedLabeling::Rule::removeChildAt( int i )
191 : : {
192 : 0 : delete mChildren.at( i );
193 : 0 : mChildren.removeAt( i );
194 : 0 : updateElseRules();
195 : 0 : }
196 : :
197 : 0 : const QgsRuleBasedLabeling::Rule *QgsRuleBasedLabeling::Rule::findRuleByKey( const QString &key ) const
198 : : {
199 : : // we could use a hash / map for search if this will be slow...
200 : :
201 : 0 : if ( key == mRuleKey )
202 : 0 : return this;
203 : :
204 : 0 : for ( Rule *rule : mChildren )
205 : : {
206 : 0 : const Rule *r = rule->findRuleByKey( key );
207 : 0 : if ( r )
208 : 0 : return r;
209 : : }
210 : 0 : return nullptr;
211 : 0 : }
212 : :
213 : 0 : QgsRuleBasedLabeling::Rule *QgsRuleBasedLabeling::Rule::findRuleByKey( const QString &key )
214 : : {
215 : 0 : if ( key == mRuleKey )
216 : 0 : return this;
217 : :
218 : 0 : for ( Rule *rule : std::as_const( mChildren ) )
219 : : {
220 : 0 : Rule *r = rule->findRuleByKey( key );
221 : 0 : if ( r )
222 : 0 : return r;
223 : : }
224 : 0 : return nullptr;
225 : 0 : }
226 : :
227 : 0 : QgsRuleBasedLabeling::Rule *QgsRuleBasedLabeling::Rule::clone() const
228 : : {
229 : 0 : QgsPalLayerSettings *s = mSettings.get() ? new QgsPalLayerSettings( *mSettings ) : nullptr;
230 : 0 : Rule *newrule = new Rule( s, mMaximumScale, mMinimumScale, mFilterExp, mDescription );
231 : 0 : newrule->setActive( mIsActive );
232 : : // clone children
233 : 0 : for ( Rule *rule : mChildren )
234 : 0 : newrule->appendChild( rule->clone() );
235 : 0 : return newrule;
236 : 0 : }
237 : :
238 : 0 : QgsRuleBasedLabeling::Rule *QgsRuleBasedLabeling::Rule::create( const QDomElement &ruleElem, const QgsReadWriteContext &context )
239 : : {
240 : 0 : QgsPalLayerSettings *settings = nullptr;
241 : 0 : QDomElement settingsElem = ruleElem.firstChildElement( QStringLiteral( "settings" ) );
242 : 0 : if ( !settingsElem.isNull() )
243 : : {
244 : 0 : settings = new QgsPalLayerSettings;
245 : 0 : settings->readXml( settingsElem, context );
246 : 0 : }
247 : :
248 : 0 : QString filterExp = ruleElem.attribute( QStringLiteral( "filter" ) );
249 : 0 : QString description = ruleElem.attribute( QStringLiteral( "description" ) );
250 : 0 : int scaleMinDenom = ruleElem.attribute( QStringLiteral( "scalemindenom" ), QStringLiteral( "0" ) ).toInt();
251 : 0 : int scaleMaxDenom = ruleElem.attribute( QStringLiteral( "scalemaxdenom" ), QStringLiteral( "0" ) ).toInt();
252 : 0 : QString ruleKey = ruleElem.attribute( QStringLiteral( "key" ) );
253 : 0 : Rule *rule = new Rule( settings, scaleMinDenom, scaleMaxDenom, filterExp, description );
254 : :
255 : 0 : if ( !ruleKey.isEmpty() )
256 : 0 : rule->mRuleKey = ruleKey;
257 : :
258 : 0 : rule->setActive( ruleElem.attribute( QStringLiteral( "active" ), QStringLiteral( "1" ) ).toInt() );
259 : :
260 : 0 : QDomElement childRuleElem = ruleElem.firstChildElement( QStringLiteral( "rule" ) );
261 : 0 : while ( !childRuleElem.isNull() )
262 : : {
263 : 0 : Rule *childRule = create( childRuleElem, context );
264 : 0 : if ( childRule )
265 : : {
266 : 0 : rule->appendChild( childRule );
267 : 0 : }
268 : : else
269 : : {
270 : : //QgsDebugMsg( QStringLiteral( "failed to init a child rule!" ) );
271 : : }
272 : 0 : childRuleElem = childRuleElem.nextSiblingElement( QStringLiteral( "rule" ) );
273 : : }
274 : :
275 : 0 : return rule;
276 : 0 : }
277 : :
278 : 0 : QDomElement QgsRuleBasedLabeling::Rule::save( QDomDocument &doc, const QgsReadWriteContext &context ) const
279 : : {
280 : 0 : QDomElement ruleElem = doc.createElement( QStringLiteral( "rule" ) );
281 : :
282 : 0 : if ( mSettings )
283 : : {
284 : 0 : ruleElem.appendChild( mSettings->writeXml( doc, context ) );
285 : 0 : }
286 : 0 : if ( !mFilterExp.isEmpty() )
287 : 0 : ruleElem.setAttribute( QStringLiteral( "filter" ), mFilterExp );
288 : 0 : if ( !qgsDoubleNear( mMaximumScale, 0 ) )
289 : 0 : ruleElem.setAttribute( QStringLiteral( "scalemindenom" ), mMaximumScale );
290 : 0 : if ( !qgsDoubleNear( mMinimumScale, 0 ) )
291 : 0 : ruleElem.setAttribute( QStringLiteral( "scalemaxdenom" ), mMinimumScale );
292 : 0 : if ( !mDescription.isEmpty() )
293 : 0 : ruleElem.setAttribute( QStringLiteral( "description" ), mDescription );
294 : 0 : if ( !mIsActive )
295 : 0 : ruleElem.setAttribute( QStringLiteral( "active" ), 0 );
296 : 0 : ruleElem.setAttribute( QStringLiteral( "key" ), mRuleKey );
297 : :
298 : 0 : for ( RuleList::const_iterator it = mChildren.constBegin(); it != mChildren.constEnd(); ++it )
299 : : {
300 : 0 : Rule *rule = *it;
301 : 0 : ruleElem.appendChild( rule->save( doc, context ) );
302 : 0 : }
303 : 0 : return ruleElem;
304 : 0 : }
305 : :
306 : 0 : void QgsRuleBasedLabeling::Rule::createSubProviders( QgsVectorLayer *layer, QgsRuleBasedLabeling::RuleToProviderMap &subProviders, QgsRuleBasedLabelProvider *provider )
307 : : {
308 : 0 : if ( mSettings )
309 : : {
310 : : // add provider!
311 : 0 : QgsVectorLayerLabelProvider *p = provider->createProvider( layer, mRuleKey, false, mSettings.get() );
312 : 0 : delete subProviders.value( this, nullptr );
313 : 0 : subProviders[this] = p;
314 : 0 : }
315 : :
316 : : // call recursively
317 : 0 : for ( Rule *rule : std::as_const( mChildren ) )
318 : : {
319 : 0 : rule->createSubProviders( layer, subProviders, provider );
320 : : }
321 : 0 : }
322 : :
323 : 0 : void QgsRuleBasedLabeling::Rule::prepare( QgsRenderContext &context, QSet<QString> &attributeNames, QgsRuleBasedLabeling::RuleToProviderMap &subProviders )
324 : : {
325 : 0 : if ( mSettings )
326 : : {
327 : 0 : QgsVectorLayerLabelProvider *p = subProviders[this];
328 : 0 : if ( !p->prepare( context, attributeNames ) )
329 : : {
330 : 0 : subProviders.remove( this );
331 : 0 : delete p;
332 : 0 : }
333 : 0 : }
334 : :
335 : 0 : if ( mFilter )
336 : : {
337 : 0 : attributeNames.unite( mFilter->referencedColumns() );
338 : 0 : mFilter->prepare( &context.expressionContext() );
339 : 0 : }
340 : :
341 : 0 : // call recursively
342 : 0 : for ( Rule *rule : std::as_const( mChildren ) )
343 : : {
344 : 0 : rule->prepare( context, attributeNames, subProviders );
345 : : }
346 : 0 : }
347 : :
348 : 0 : QgsRuleBasedLabeling::Rule::RegisterResult QgsRuleBasedLabeling::Rule::registerFeature( const QgsFeature &feature, QgsRenderContext &context, QgsRuleBasedLabeling::RuleToProviderMap &subProviders, const QgsGeometry &obstacleGeometry, const QgsSymbol *symbol )
349 : : {
350 : 0 : if ( !isFilterOK( feature, context )
351 : 0 : || !isScaleOK( context.rendererScale() ) )
352 : 0 : {
353 : 0 : return Filtered;
354 : : }
355 : :
356 : 0 : bool registered = false;
357 : :
358 : : // do we have active subprovider for the rule?
359 : 0 : if ( subProviders.contains( this ) && mIsActive )
360 : : {
361 : 0 : subProviders[this]->registerFeature( feature, context, obstacleGeometry, symbol );
362 : 0 : registered = true;
363 : 0 : }
364 : :
365 : 0 : bool willRegisterSomething = false;
366 : :
367 : : // call recursively
368 : 0 : for ( Rule *rule : std::as_const( mChildren ) )
369 : : {
370 : : // Don't process else rules yet
371 : 0 : if ( !rule->isElse() )
372 : : {
373 : 0 : RegisterResult res = rule->registerFeature( feature, context, subProviders, obstacleGeometry );
374 : : // consider inactive items as "registered" so the else rule will ignore them
375 : 0 : willRegisterSomething |= ( res == Registered || res == Inactive );
376 : 0 : registered |= willRegisterSomething;
377 : 0 : }
378 : : }
379 : :
380 : : // If none of the rules passed then we jump into the else rules and process them.
381 : 0 : if ( !willRegisterSomething )
382 : : {
383 : 0 : for ( Rule *rule : std::as_const( mElseRules ) )
384 : : {
385 : 0 : registered |= rule->registerFeature( feature, context, subProviders, obstacleGeometry, symbol ) != Filtered;
386 : : }
387 : 0 : }
388 : :
389 : 0 : if ( !mIsActive )
390 : 0 : return Inactive;
391 : 0 : else if ( registered )
392 : 0 : return Registered;
393 : : else
394 : 0 : return Filtered;
395 : 0 : }
396 : :
397 : 0 : bool QgsRuleBasedLabeling::Rule::isFilterOK( const QgsFeature &f, QgsRenderContext &context ) const
398 : : {
399 : 0 : if ( ! mFilter || mElseRule )
400 : 0 : return true;
401 : :
402 : 0 : context.expressionContext().setFeature( f );
403 : 0 : QVariant res = mFilter->evaluate( &context.expressionContext() );
404 : 0 : return res.toBool();
405 : 0 : }
406 : :
407 : 0 : bool QgsRuleBasedLabeling::Rule::isScaleOK( double scale ) const
408 : : {
409 : 0 : if ( qgsDoubleNear( scale, 0.0 ) ) // so that we can count features in classes without scale context
410 : 0 : return true;
411 : 0 : if ( qgsDoubleNear( mMaximumScale, 0.0 ) && qgsDoubleNear( mMinimumScale, 0.0 ) )
412 : 0 : return true;
413 : 0 : if ( !qgsDoubleNear( mMaximumScale, 0.0 ) && mMaximumScale > scale )
414 : 0 : return false;
415 : 0 : if ( !qgsDoubleNear( mMinimumScale, 0.0 ) && mMinimumScale < scale )
416 : 0 : return false;
417 : 0 : return true;
418 : 0 : }
419 : :
420 : : ////////////////////
421 : :
422 : 0 : QgsRuleBasedLabeling::QgsRuleBasedLabeling( QgsRuleBasedLabeling::Rule *root )
423 : 0 : : mRootRule( root )
424 : 0 : {
425 : 0 : }
426 : :
427 : 0 : QgsRuleBasedLabeling *QgsRuleBasedLabeling::clone() const
428 : : {
429 : 0 : Rule *rootRule = mRootRule->clone();
430 : :
431 : : // normally with clone() the individual rules get new keys (UUID), but here we want to keep
432 : : // the tree of rules intact, so that other components that may use the rule keys work nicely (e.g. map themes)
433 : 0 : rootRule->setRuleKey( mRootRule->ruleKey() );
434 : 0 : RuleList origDescendants = mRootRule->descendants();
435 : 0 : RuleList clonedDescendants = rootRule->descendants();
436 : : Q_ASSERT( origDescendants.count() == clonedDescendants.count() );
437 : 0 : for ( int i = 0; i < origDescendants.count(); ++i )
438 : 0 : clonedDescendants[i]->setRuleKey( origDescendants[i]->ruleKey() );
439 : :
440 : 0 : return new QgsRuleBasedLabeling( rootRule );
441 : 0 : }
442 : :
443 : 0 : QgsRuleBasedLabeling::~QgsRuleBasedLabeling()
444 : 0 : {
445 : 0 : }
446 : :
447 : 0 : QgsRuleBasedLabeling::Rule *QgsRuleBasedLabeling::rootRule()
448 : : {
449 : 0 : return mRootRule.get();
450 : : }
451 : :
452 : 0 : const QgsRuleBasedLabeling::Rule *QgsRuleBasedLabeling::rootRule() const
453 : : {
454 : 0 : return mRootRule.get();
455 : : }
456 : :
457 : :
458 : 0 : QgsRuleBasedLabeling *QgsRuleBasedLabeling::create( const QDomElement &element, const QgsReadWriteContext &context )
459 : : {
460 : 0 : QDomElement rulesElem = element.firstChildElement( QStringLiteral( "rules" ) );
461 : :
462 : 0 : Rule *root = Rule::create( rulesElem, context );
463 : 0 : if ( !root )
464 : 0 : return nullptr;
465 : :
466 : 0 : QgsRuleBasedLabeling *rl = new QgsRuleBasedLabeling( root );
467 : 0 : return rl;
468 : 0 : }
469 : :
470 : 0 : QString QgsRuleBasedLabeling::type() const
471 : : {
472 : 0 : return QStringLiteral( "rule-based" );
473 : : }
474 : :
475 : 0 : QDomElement QgsRuleBasedLabeling::save( QDomDocument &doc, const QgsReadWriteContext &context ) const
476 : : {
477 : 0 : QDomElement elem = doc.createElement( QStringLiteral( "labeling" ) );
478 : 0 : elem.setAttribute( QStringLiteral( "type" ), QStringLiteral( "rule-based" ) );
479 : :
480 : 0 : QDomElement rulesElem = mRootRule->save( doc, context );
481 : 0 : rulesElem.setTagName( QStringLiteral( "rules" ) ); // instead of just "rule"
482 : 0 : elem.appendChild( rulesElem );
483 : :
484 : 0 : return elem;
485 : 0 : }
486 : :
487 : 0 : QgsVectorLayerLabelProvider *QgsRuleBasedLabeling::provider( QgsVectorLayer *layer ) const
488 : : {
489 : 0 : return new QgsRuleBasedLabelProvider( *this, layer, false );
490 : 0 : }
491 : :
492 : 0 : QStringList QgsRuleBasedLabeling::subProviders() const
493 : : {
494 : 0 : QStringList lst;
495 : 0 : mRootRule->subProviderIds( lst );
496 : 0 : return lst;
497 : 0 : }
498 : :
499 : 0 : QgsPalLayerSettings QgsRuleBasedLabeling::settings( const QString &providerId ) const
500 : : {
501 : 0 : const Rule *rule = mRootRule->findRuleByKey( providerId );
502 : 0 : if ( rule && rule->settings() )
503 : 0 : return *rule->settings();
504 : :
505 : 0 : return QgsPalLayerSettings();
506 : 0 : }
507 : :
508 : 0 : bool QgsRuleBasedLabeling::accept( QgsStyleEntityVisitorInterface *visitor ) const
509 : : {
510 : 0 : return mRootRule->accept( visitor );
511 : : }
512 : :
513 : 0 : bool QgsRuleBasedLabeling::requiresAdvancedEffects() const
514 : : {
515 : 0 : return mRootRule->requiresAdvancedEffects();
516 : : }
517 : :
518 : 0 : void QgsRuleBasedLabeling::setSettings( QgsPalLayerSettings *settings, const QString &providerId )
519 : : {
520 : 0 : if ( settings )
521 : : {
522 : 0 : Rule *rule = mRootRule->findRuleByKey( providerId );
523 : 0 : if ( rule && rule->settings() )
524 : 0 : rule->setSettings( settings );
525 : 0 : }
526 : 0 : }
527 : :
528 : 0 : void QgsRuleBasedLabeling::toSld( QDomNode &parent, const QVariantMap &props ) const
529 : : {
530 : 0 : if ( !mRootRule )
531 : : {
532 : 0 : return;
533 : : }
534 : :
535 : 0 : const QgsRuleBasedLabeling::RuleList rules = mRootRule->children();
536 : 0 : for ( Rule *rule : rules )
537 : : {
538 : 0 : QgsPalLayerSettings *settings = rule->settings();
539 : :
540 : 0 : if ( settings && settings->drawLabels )
541 : : {
542 : 0 : QDomDocument doc = parent.ownerDocument();
543 : :
544 : 0 : QDomElement ruleElement = doc.createElement( QStringLiteral( "se:Rule" ) );
545 : 0 : parent.appendChild( ruleElement );
546 : :
547 : 0 : if ( !rule->filterExpression().isEmpty() )
548 : : {
549 : 0 : QgsSymbolLayerUtils::createFunctionElement( doc, ruleElement, rule->filterExpression() );
550 : 0 : }
551 : :
552 : : // scale dependencies, the actual behavior is that the PAL settings min/max and
553 : : // the rule min/max get intersected
554 : 0 : QVariantMap localProps = QVariantMap( props );
555 : 0 : QgsSymbolLayerUtils::mergeScaleDependencies( rule->maximumScale(), rule->minimumScale(), localProps );
556 : 0 : if ( settings->scaleVisibility )
557 : : {
558 : 0 : QgsSymbolLayerUtils::mergeScaleDependencies( settings->maximumScale, settings->minimumScale, localProps );
559 : 0 : }
560 : 0 : QgsSymbolLayerUtils::applyScaleDependency( doc, ruleElement, localProps );
561 : :
562 : 0 : QgsAbstractVectorLayerLabeling::writeTextSymbolizer( ruleElement, *settings, props );
563 : 0 : }
564 : :
565 : : }
566 : :
567 : 0 : }
|