38 #include <QDomDocument> 
   39 #include <QDomElement> 
   46   , mMaximumScale( scaleMinDenom )
 
   47   , mMinimumScale( scaleMaxDenom )
 
   48   , mFilterExp( filterExp )
 
   50   , mDescription( description )
 
   51   , mElseRule( elseRule )
 
   54     mFilterExp = QStringLiteral( 
"ELSE" );
 
   56   mRuleKey = QUuid::createUuid().toString();
 
   62   qDeleteAll( mChildren );
 
   68   if ( mFilterExp.trimmed().compare( QLatin1String( 
"ELSE" ), Qt::CaseInsensitive ) == 0 )
 
   73   else if ( mFilterExp.trimmed().isEmpty() )
 
   81     mFilter = std::make_unique< QgsExpression >( mFilterExp );
 
   87   mChildren.append( rule );
 
   94   mChildren.insert( i, rule );
 
  101   mChildren.removeAll( rule );
 
  108   delete mChildren.takeAt( i );
 
  114   mChildren.removeAll( rule );
 
  115   rule->mParent = 
nullptr;
 
  122   Rule *rule = mChildren.takeAt( i );
 
  123   rule->mParent = 
nullptr;
 
  132   if ( key == mRuleKey )
 
  135   const auto constMChildren = mChildren;
 
  136   for ( 
Rule *rule : constMChildren )
 
  145 void QgsRuleBasedRenderer::Rule::updateElseRules()
 
  148   const auto constMChildren = mChildren;
 
  149   for ( 
Rule *rule : constMChildren )
 
  151     if ( rule->isElse() )
 
  158   mFilterExp = QStringLiteral( 
"ELSE" );
 
  176   if ( !mChildren.empty() )
 
  178     for ( 
const Rule *rule : mChildren )
 
  181       if ( !rule->accept( visitor ) )
 
  195   off.fill( QChar( 
' ' ), indent );
 
  196   QString symbolDump = ( mSymbol ? mSymbol->dump() : QStringLiteral( 
"[]" ) );
 
  197   QString msg = off + QStringLiteral( 
"RULE %1 - scale [%2,%3] - filter %4 - symbol %5\n" )
 
  198                 .arg( mLabel ).arg( mMaximumScale ).arg( mMinimumScale )
 
  199                 .arg( mFilterExp, symbolDump );
 
  202   const auto constMChildren = mChildren;
 
  203   for ( 
Rule *rule : constMChildren )
 
  205     lst.append( rule->dump( indent + 2 ) );
 
  207   msg += lst.join( QLatin1Char( 
'\n' ) );
 
  216     attrs.unite( 
mFilter->referencedColumns() );
 
  218     attrs.unite( mSymbol->usedAttributes( context ) );
 
  221   const auto constMChildren = mChildren;
 
  222   for ( 
Rule *rule : constMChildren )
 
  224     attrs.unite( rule->usedAttributes( context ) );
 
  234   const auto constMChildren = mChildren;
 
  235   for ( 
Rule *rule : constMChildren )
 
  237     if ( rule->needsGeometry() )
 
  248     lst.append( mSymbol.get() );
 
  250   const auto constMChildren = mChildren;
 
  251   for ( 
Rule *rule : constMChildren )
 
  253     lst += rule->symbols( context );
 
  260   mSymbol.reset( sym );
 
  265   mFilterExp = filterExp;
 
  272   if ( currentLevel != -1 ) 
 
  274     lst << 
QgsLegendSymbolItem( mSymbol.get(), mLabel, mRuleKey, 
true, mMaximumScale, mMinimumScale, currentLevel, mParent ? mParent->mRuleKey : QString() );
 
  277   for ( RuleList::const_iterator it = mChildren.constBegin(); it != mChildren.constEnd(); ++it )
 
  288   if ( ! 
mFilter || mElseRule || ! context )
 
  302   if ( !
qgsDoubleNear( mMaximumScale, 0.0 ) && mMaximumScale > scale )
 
  304   if ( !
qgsDoubleNear( mMinimumScale, 0.0 ) && mMinimumScale < scale )
 
  312   Rule *newrule = 
new Rule( sym, mMaximumScale, mMinimumScale, mFilterExp, mLabel, mDescription );
 
  315   const auto constMChildren = mChildren;
 
  316   for ( 
Rule *rule : constMChildren )
 
  323   QDomElement ruleElem = doc.createElement( QStringLiteral( 
"rule" ) );
 
  327     int symbolIndex = symbolMap.size();
 
  328     symbolMap[QString::number( symbolIndex )] = mSymbol.get();
 
  329     ruleElem.setAttribute( QStringLiteral( 
"symbol" ), symbolIndex );
 
  331   if ( !mFilterExp.isEmpty() )
 
  332     ruleElem.setAttribute( QStringLiteral( 
"filter" ), mFilterExp );
 
  333   if ( mMaximumScale != 0 )
 
  334     ruleElem.setAttribute( QStringLiteral( 
"scalemindenom" ), mMaximumScale );
 
  335   if ( mMinimumScale != 0 )
 
  336     ruleElem.setAttribute( QStringLiteral( 
"scalemaxdenom" ), mMinimumScale );
 
  337   if ( !mLabel.isEmpty() )
 
  338     ruleElem.setAttribute( QStringLiteral( 
"label" ), mLabel );
 
  339   if ( !mDescription.isEmpty() )
 
  340     ruleElem.setAttribute( QStringLiteral( 
"description" ), mDescription );
 
  342     ruleElem.setAttribute( QStringLiteral( 
"checkstate" ), 0 );
 
  343   ruleElem.setAttribute( QStringLiteral( 
"key" ), mRuleKey );
 
  345   const auto constMChildren = mChildren;
 
  346   for ( 
Rule *rule : constMChildren )
 
  348     ruleElem.appendChild( rule->save( doc, symbolMap ) );
 
  357   if ( 
symbols( context ).isEmpty() )
 
  360   if ( !mFilterExp.isEmpty() )
 
  362     QString 
filter = props.value( QStringLiteral( 
"filter" ), QString() ).toString();
 
  364       filter += QLatin1String( 
" AND " );
 
  366     props[ QStringLiteral( 
"filter" )] = 
filter;
 
  373     QDomElement ruleElem = doc.createElement( QStringLiteral( 
"se:Rule" ) );
 
  374     element.appendChild( ruleElem );
 
  378     QDomElement nameElem = doc.createElement( QStringLiteral( 
"se:Name" ) );
 
  379     nameElem.appendChild( doc.createTextNode( mLabel ) );
 
  380     ruleElem.appendChild( nameElem );
 
  382     if ( !mLabel.isEmpty() || !mDescription.isEmpty() )
 
  384       QDomElement descrElem = doc.createElement( QStringLiteral( 
"se:Description" ) );
 
  385       if ( !mLabel.isEmpty() )
 
  387         QDomElement titleElem = doc.createElement( QStringLiteral( 
"se:Title" ) );
 
  388         titleElem.appendChild( doc.createTextNode( mLabel ) );
 
  389         descrElem.appendChild( titleElem );
 
  391       if ( !mDescription.isEmpty() )
 
  393         QDomElement abstractElem = doc.createElement( QStringLiteral( 
"se:Abstract" ) );
 
  394         abstractElem.appendChild( doc.createTextNode( mDescription ) );
 
  395         descrElem.appendChild( abstractElem );
 
  397       ruleElem.appendChild( descrElem );
 
  400     if ( !props.value( QStringLiteral( 
"filter" ), QString() ).toString().isEmpty() )
 
  407     mSymbol->toSld( doc, ruleElem, props );
 
  411   const auto constMChildren = mChildren;
 
  412   for ( 
Rule *rule : constMChildren )
 
  414     rule->toSld( doc, element, props );
 
  420   mActiveChildren.clear();
 
  433     mSymbol->startRender( context, fields );
 
  437   QStringList subfilters;
 
  438   const auto constMChildren = mChildren;
 
  439   for ( 
Rule *rule : constMChildren )
 
  442     if ( rule->startRender( context, fields, subfilter ) )
 
  445       mActiveChildren.append( rule );
 
  446       subfilters.append( subfilter );
 
  454   if ( subfilters.length() > 1 || !subfilters.value( 0 ).isEmpty() )
 
  456     if ( subfilters.contains( QStringLiteral( 
"TRUE" ) ) )
 
  458       sf = QStringLiteral( 
"TRUE" );
 
  469       else if ( subfilters.count() > 50 )
 
  471         std::function<QString( 
const QStringList & )>bt = [ &bt ]( 
const QStringList & subf )
 
  473           if ( subf.count( ) == 1 )
 
  477           else if ( subf.count( ) == 2 )
 
  479             return subf.join( QLatin1String( 
") OR (" ) ).prepend( 
'(' ).append( 
')' );
 
  483             int midpos = 
static_cast<int>( subf.length() / 2 );
 
  484             return QStringLiteral( 
"(%1) OR (%2)" ).arg( bt( subf.mid( 0, midpos ) ), bt( subf.mid( midpos ) ) );
 
  487         sf = bt( subfilters );
 
  491         sf = subfilters.join( QLatin1String( 
") OR (" ) ).prepend( 
'(' ).append( 
')' );
 
  503     if ( mSymbol || sf.isEmpty() )
 
  504       filter = QStringLiteral( 
"TRUE" );
 
  510   else if ( !mFilterExp.trimmed().isEmpty() && !sf.isEmpty() )
 
  511     filter = QStringLiteral( 
"(%1) AND (%2)" ).arg( mFilterExp, sf );
 
  512   else if ( !mFilterExp.trimmed().isEmpty() )
 
  514   else if ( sf.isEmpty() )
 
  515     filter = QStringLiteral( 
"TRUE" );
 
  526   QSet<int> symbolZLevelsSet;
 
  532     for ( 
int i = 0; i < mSymbol->symbolLayerCount(); i++ )
 
  534       symbolZLevelsSet.insert( mSymbol->symbolLayer( i )->renderingPass() );
 
  539   QList<Rule *>::iterator it;
 
  540   for ( it = mActiveChildren.begin(); it != mActiveChildren.end(); ++it )
 
  545   return symbolZLevelsSet;
 
  552     for ( 
int i = 0; i < mSymbol->symbolLayerCount(); i++ )
 
  554       int normLevel = zLevelsToNormLevels.value( mSymbol->symbolLayer( i )->renderingPass() );
 
  555       mSymbolNormZLevels.insert( normLevel );
 
  560   const auto constMActiveChildren = mActiveChildren;
 
  561   for ( 
Rule *rule : constMActiveChildren )
 
  563     rule->setNormZLevels( zLevelsToNormLevels );
 
  570   if ( !isFilterOK( featToRender.
feat, &context ) )
 
  573   bool rendered = 
false;
 
  576   if ( mSymbol && mIsActive )
 
  579     const auto constMSymbolNormZLevels = mSymbolNormZLevels;
 
  580     for ( 
int normZLevel : constMSymbolNormZLevels )
 
  583       renderQueue[normZLevel].jobs.append( 
new RenderJob( featToRender, mSymbol.get() ) );
 
  588   bool willrendersomething = 
false;
 
  591   const auto constMChildren = mChildren;
 
  592   for ( 
Rule *rule : constMChildren )
 
  595     if ( !rule->isElse() )
 
  597       RenderResult res = rule->renderFeature( featToRender, context, renderQueue );
 
  599       willrendersomething |= ( res == Rendered || res == Inactive );
 
  600       rendered |= ( res == Rendered );
 
  605   if ( !willrendersomething )
 
  607     const auto constMElseRules = mElseRules;
 
  608     for ( 
Rule *rule : constMElseRules )
 
  610       rendered |= rule->renderFeature( featToRender, context, renderQueue ) == Rendered;
 
  613   if ( !mIsActive || ( mSymbol && !rendered ) )
 
  623   if ( !isFilterOK( feature, context ) )
 
  629   const auto constMActiveChildren = mActiveChildren;
 
  630   for ( 
Rule *rule : constMActiveChildren )
 
  632     if ( rule->isElse() )
 
  634       if ( rule->children().isEmpty() )
 
  636         RuleList lst = rulesForFeature( feature, context, 
false );
 
  637         lst.removeOne( rule );
 
  646         return rule->willRenderFeature( feature, context );
 
  649     else if ( rule->willRenderFeature( feature, context ) )
 
  660   if ( !isFilterOK( feature, context ) )
 
  663     lst.append( mSymbol.get() );
 
  665   const auto constMActiveChildren = mActiveChildren;
 
  666   for ( 
Rule *rule : constMActiveChildren )
 
  668     lst += rule->symbolsForFeature( feature, context );
 
  676   if ( !isFilterOK( feature, context ) )
 
  678   lst.insert( mRuleKey );
 
  680   const auto constMActiveChildren = mActiveChildren;
 
  681   for ( 
Rule *rule : constMActiveChildren )
 
  683     bool validKey = 
false;
 
  684     if ( rule->isElse() )
 
  686       RuleList lst = rulesForFeature( feature, context, 
false );
 
  687       lst.removeOne( rule );
 
  694     else if ( !rule->isElse( ) && rule->willRenderFeature( feature, context ) )
 
  701       lst.unite( rule->legendKeysForFeature( feature, context ) );
 
  710   if ( ! isFilterOK( feature, context ) || ( context && ! isScaleOK( context->
rendererScale() ) ) )
 
  718     listChildren = mActiveChildren;
 
  720   const auto constListChildren = listChildren;
 
  721   for ( 
Rule *rule : constListChildren )
 
  723     lst += rule->rulesForFeature( feature, context, onlyActive );
 
  731     mSymbol->stopRender( context );
 
  733   const auto constMActiveChildren = mActiveChildren;
 
  734   for ( 
Rule *rule : constMActiveChildren )
 
  736     rule->stopRender( context );
 
  739   mActiveChildren.clear();
 
  740   mSymbolNormZLevels.clear();
 
  745   QString symbolIdx = ruleElem.attribute( QStringLiteral( 
"symbol" ) );
 
  747   if ( !symbolIdx.isEmpty() )
 
  749     if ( symbolMap.contains( symbolIdx ) )
 
  751       symbol = symbolMap.take( symbolIdx );
 
  755       QgsDebugMsg( 
"symbol for rule " + symbolIdx + 
" not found!" );
 
  759   QString filterExp = ruleElem.attribute( QStringLiteral( 
"filter" ) );
 
  760   QString label = ruleElem.attribute( QStringLiteral( 
"label" ) );
 
  761   QString description = ruleElem.attribute( QStringLiteral( 
"description" ) );
 
  762   int scaleMinDenom = ruleElem.attribute( QStringLiteral( 
"scalemindenom" ), QStringLiteral( 
"0" ) ).toInt();
 
  763   int scaleMaxDenom = ruleElem.attribute( QStringLiteral( 
"scalemaxdenom" ), QStringLiteral( 
"0" ) ).toInt();
 
  764   QString ruleKey = ruleElem.attribute( QStringLiteral( 
"key" ) );
 
  765   Rule *rule = 
new Rule( symbol, scaleMinDenom, scaleMaxDenom, filterExp, label, description );
 
  767   if ( !ruleKey.isEmpty() )
 
  768     rule->mRuleKey = ruleKey;
 
  770   rule->
setActive( ruleElem.attribute( QStringLiteral( 
"checkstate" ), QStringLiteral( 
"1" ) ).toInt() );
 
  772   QDomElement childRuleElem = ruleElem.firstChildElement( QStringLiteral( 
"rule" ) );
 
  773   while ( !childRuleElem.isNull() )
 
  775     Rule *childRule = 
create( childRuleElem, symbolMap );
 
  782       QgsDebugMsg( QStringLiteral( 
"failed to init a child rule!" ) );
 
  784     childRuleElem = childRuleElem.nextSiblingElement( QStringLiteral( 
"rule" ) );
 
  796     l += 
c->descendants();
 
  803   if ( ruleElem.localName() != QLatin1String( 
"Rule" ) )
 
  805     QgsDebugMsg( QStringLiteral( 
"invalid element: Rule element expected, %1 found!" ).arg( ruleElem.tagName() ) );
 
  809   QString label, description, filterExp;
 
  810   int scaleMinDenom = 0, scaleMaxDenom = 0;
 
  814   QDomElement childElem = ruleElem.firstChildElement();
 
  815   while ( !childElem.isNull() )
 
  817     if ( childElem.localName() == QLatin1String( 
"Name" ) )
 
  821       if ( label.isEmpty() )
 
  822         label = childElem.firstChild().nodeValue();
 
  824     else if ( childElem.localName() == QLatin1String( 
"Description" ) )
 
  827       QDomElement titleElem = childElem.firstChildElement( QStringLiteral( 
"Title" ) );
 
  828       if ( !titleElem.isNull() )
 
  830         label = titleElem.firstChild().nodeValue();
 
  833       QDomElement abstractElem = childElem.firstChildElement( QStringLiteral( 
"Abstract" ) );
 
  834       if ( !abstractElem.isNull() )
 
  836         description = abstractElem.firstChild().nodeValue();
 
  839     else if ( childElem.localName() == QLatin1String( 
"Abstract" ) )
 
  842       description = childElem.firstChild().nodeValue();
 
  844     else if ( childElem.localName() == QLatin1String( 
"Title" ) )
 
  847       label = childElem.firstChild().nodeValue();
 
  849     else if ( childElem.localName() == QLatin1String( 
"Filter" ) )
 
  854         if ( 
filter->hasParserError() )
 
  860           filterExp = 
filter->expression();
 
  865     else if ( childElem.localName() == QLatin1String( 
"MinScaleDenominator" ) )
 
  868       int v = childElem.firstChild().nodeValue().toInt( &ok );
 
  872     else if ( childElem.localName() == QLatin1String( 
"MaxScaleDenominator" ) )
 
  875       int v = childElem.firstChild().nodeValue().toInt( &ok );
 
  879     else if ( childElem.localName().endsWith( QLatin1String( 
"Symbolizer" ) ) )
 
  885     childElem = childElem.nextSiblingElement();
 
  890   if ( !layers.isEmpty() )
 
  907         QgsDebugMsg( QStringLiteral( 
"invalid geometry type: found %1" ).arg( geomType ) );
 
  913   return new Rule( symbol, scaleMinDenom, scaleMaxDenom, filterExp, label, description );
 
  948     bool drawVertexMarker )
 
  968   QList<int> symbolZLevels = qgis::setToList( symbolZLevelsSet );
 
  969   std::sort( symbolZLevels.begin(), symbolZLevels.end() );
 
  973   QMap<int, int> zLevelsToNormLevels;
 
  974   int maxNormLevel = -1;
 
  975   const auto constSymbolZLevels = symbolZLevels;
 
  976   for ( 
int zLevel : constSymbolZLevels )
 
  978     zLevelsToNormLevels[zLevel] = ++maxNormLevel;
 
  980     QgsDebugMsgLevel( QStringLiteral( 
"zLevel %1 -> %2" ).arg( zLevel ).arg( maxNormLevel ), 4 );
 
  998     for ( 
const RenderLevel &level : constMRenderQueue )
 
 1002       for ( 
const RenderJob *job : std::as_const( level.jobs ) )
 
 1009         for ( 
int i = 0; i < count; i++ )
 
 1016             int flags = job->ftr.flags;
 
 1058   Q_ASSERT( origDescendants.count() == clonedDescendants.count() );
 
 1059   for ( 
int i = 0; i < origDescendants.count(); ++i )
 
 1060     clonedDescendants[i]->setRuleKey( origDescendants[i]->ruleKey() );
 
 1082   rendererElem.setAttribute( QStringLiteral( 
"type" ), QStringLiteral( 
"RuleRenderer" ) );
 
 1083   rendererElem.setAttribute( QStringLiteral( 
"symbollevels" ), ( 
mUsingSymbolLevels ? QStringLiteral( 
"1" ) : QStringLiteral( 
"0" ) ) );
 
 1084   rendererElem.setAttribute( QStringLiteral( 
"forceraster" ), ( 
mForceRaster ? QStringLiteral( 
"1" ) : QStringLiteral( 
"0" ) ) );
 
 1089   rulesElem.setTagName( QStringLiteral( 
"rules" ) ); 
 
 1090   rendererElem.appendChild( rulesElem );
 
 1093   rendererElem.appendChild( symbolsElem );
 
 1100     QDomElement 
orderBy = doc.createElement( QStringLiteral( 
"orderby" ) );
 
 1102     rendererElem.appendChild( 
orderBy );
 
 1104   rendererElem.setAttribute( QStringLiteral( 
"enableorderby" ), ( 
mOrderByEnabled ? QStringLiteral( 
"1" ) : QStringLiteral( 
"0" ) ) );
 
 1106   return rendererElem;
 
 1117   return rule ? rule->
active() : 
true;
 
 1145   QDomElement symbolsElem = element.firstChildElement( QStringLiteral( 
"symbols" ) );
 
 1146   if ( symbolsElem.isNull() )
 
 1151   QDomElement rulesElem = element.firstChildElement( QStringLiteral( 
"rules" ) );
 
 1168   Rule *root = 
nullptr;
 
 1170   QDomElement ruleElem = element.firstChildElement( QStringLiteral( 
"Rule" ) );
 
 1171   while ( !ruleElem.isNull() )
 
 1178         root = 
new Rule( 
nullptr );
 
 1183     ruleElem = ruleElem.nextSiblingElement( QStringLiteral( 
"Rule" ) );
 
 1211   const auto constCategories = r->
categories();
 
 1216     if ( cat.value().type() == QVariant::Int )
 
 1217       value = cat.value().toString();
 
 1218     else if ( cat.value().type() == QVariant::Double )
 
 1221       value = QString::number( cat.value().toDouble(), 
'f', 4 );
 
 1224     QString 
filter = QStringLiteral( 
"%1 = %2" ).arg( attr, value );
 
 1241   else if ( !testExpr.
isField() )
 
 1244     attr = QStringLiteral( 
"(%1)" ).arg( attr );
 
 1247   bool firstRange = 
true;
 
 1248   const auto constRanges = r->
ranges();
 
 1253     QString 
filter = QStringLiteral( 
"%1 %2 %3 AND %1 <= %4" ).arg( attr, firstRange ? QStringLiteral( 
">=" ) : QStringLiteral( 
">" ),
 
 1254                      QString::number( rng.lowerValue(), 
'f', 4 ),
 
 1255                      QString::number( rng.upperValue(), 
'f', 4 ) );
 
 1257     QString label =  rng.label().isEmpty() ? 
filter : rng.label();
 
 1264   std::sort( scales.begin(), scales.end() ); 
 
 1268   const auto constScales = scales;
 
 1269   for ( 
int scale : constScales )
 
 1273     if ( maxDenom != 0 && maxDenom  <= scale )
 
 1275     initialRule->
appendChild( 
new Rule( symbol->
clone(), oldScale, scale, QString(), QStringLiteral( 
"%1 - %2" ).arg( oldScale ).arg( scale ) ) );
 
 1279   initialRule->
appendChild( 
new Rule( symbol->
clone(), oldScale, maxDenom, QString(), QStringLiteral( 
"%1 - %2" ).arg( oldScale ).arg( maxDenom ) ) );
 
 1284   QString msg( QStringLiteral( 
"Rule-based renderer:\n" ) );
 
 1316   std::unique_ptr< QgsRuleBasedRenderer > r;
 
 1317   if ( renderer->
type() == QLatin1String( 
"RuleRenderer" ) )
 
 1321   else if ( renderer->
type() == QLatin1String( 
"singleSymbol" ) )
 
 1324     if ( !singleSymbolRenderer )
 
 1327     std::unique_ptr< QgsSymbol > origSymbol( singleSymbolRenderer->
symbol()->
clone() );
 
 1328     r = std::make_unique< QgsRuleBasedRenderer >( origSymbol.release() );
 
 1330   else if ( renderer->
type() == QLatin1String( 
"categorizedSymbol" ) )
 
 1333     if ( !categorizedRenderer )
 
 1346     std::unique_ptr< QgsRuleBasedRenderer::Rule > rootrule = std::make_unique< QgsRuleBasedRenderer::Rule >( 
nullptr );
 
 1353       std::unique_ptr< QgsRuleBasedRenderer::Rule > rule = std::make_unique< QgsRuleBasedRenderer::Rule >( 
nullptr );
 
 1355       rule->setLabel( category.
label() );
 
 1358       if ( category.
value().type() == QVariant::List )
 
 1361         const QVariantList list = category.
value().toList();
 
 1362         for ( 
const QVariant &v : list )
 
 1365           if ( QVariant( v ).convert( QVariant::Double ) )
 
 1367             values << v.toString();
 
 1375         if ( values.empty() )
 
 1377           expression = QStringLiteral( 
"ELSE" );
 
 1381           expression = QStringLiteral( 
"%1 IN (%2)" ).arg( attr, values.join( 
',' ) );
 
 1387         if ( category.
value().convert( QVariant::Double ) )
 
 1389           value = category.
value().toString();
 
 1397         if ( value == QLatin1String( 
"''" ) )
 
 1399           expression = QStringLiteral( 
"ELSE" );
 
 1403           expression = QStringLiteral( 
"%1 = %2" ).arg( attr, value );
 
 1406       rule->setFilterExpression( expression );
 
 1412       std::unique_ptr< QgsSymbol > origSymbol( category.
symbol()->
clone() );
 
 1413       rule->setSymbol( origSymbol.release() );
 
 1415       rootrule->appendChild( rule.release() );
 
 1418     r = std::make_unique< QgsRuleBasedRenderer >( rootrule.release() );
 
 1420   else if ( renderer->
type() == QLatin1String( 
"graduatedSymbol" ) )
 
 1423     if ( !graduatedRenderer )
 
 1435     else if ( !testExpr.
isField() )
 
 1438       attr = QStringLiteral( 
"(%1)" ).arg( attr );
 
 1441     std::unique_ptr< QgsRuleBasedRenderer::Rule > rootrule = std::make_unique< QgsRuleBasedRenderer::Rule >( 
nullptr );
 
 1445     for ( 
int i = 0; i < graduatedRenderer->
ranges().size(); ++i )
 
 1447       range = graduatedRenderer->
ranges().value( i );
 
 1448       std::unique_ptr< QgsRuleBasedRenderer::Rule > rule = std::make_unique< QgsRuleBasedRenderer::Rule >( 
nullptr );
 
 1449       rule->setLabel( range.
label() );
 
 1452         expression = attr + 
" >= " + QString::number( range.
lowerValue(), 
'f' ) + 
" AND " + \
 
 1453                      attr + 
" <= " + QString::number( range.
upperValue(), 
'f' );
 
 1457         expression = attr + 
" > " + QString::number( range.
lowerValue(), 
'f' ) + 
" AND " + \
 
 1458                      attr + 
" <= " + QString::number( range.
upperValue(), 
'f' );
 
 1460       rule->setFilterExpression( expression );
 
 1466       std::unique_ptr< QgsSymbol > symbol( range.
symbol()->
clone() );
 
 1467       rule->setSymbol( symbol.release() );
 
 1469       rootrule->appendChild( rule.release() );
 
 1472     r = std::make_unique< QgsRuleBasedRenderer >( rootrule.release() );
 
 1474   else if ( renderer->
type() == QLatin1String( 
"pointDisplacement" ) || renderer->
type() == QLatin1String( 
"pointCluster" ) )
 
 1479   else if ( renderer->
type() == QLatin1String( 
"invertedPolygonRenderer" ) )
 
 1484   else if ( renderer->
type() == QLatin1String( 
"mergedFeatureRenderer" ) )
 
 1489   else if ( renderer->
type() == QLatin1String( 
"embeddedSymbol" ) && layer )
 
 1493     std::unique_ptr< QgsRuleBasedRenderer::Rule > rootrule = std::make_unique< QgsRuleBasedRenderer::Rule >( 
nullptr );
 
 1500     while ( it.
nextFeature( feature ) && rootrule->children().size() < 500 )
 
 1504         std::unique_ptr< QgsRuleBasedRenderer::Rule > rule = std::make_unique< QgsRuleBasedRenderer::Rule >( 
nullptr );
 
 1505         rule->setFilterExpression( QStringLiteral( 
"$id=%1" ).arg( feature.
id() ) );
 
 1506         rule->setLabel( QString::number( feature.
id() ) );
 
 1508         rootrule->appendChild( rule.release() );
 
 1512     std::unique_ptr< QgsRuleBasedRenderer::Rule > rule = std::make_unique< QgsRuleBasedRenderer::Rule >( 
nullptr );
 
 1513     rule->setFilterExpression( QStringLiteral( 
"ELSE" ) );
 
 1514     rule->setLabel( QObject::tr( 
"All other features" ) );
 
 1516     rootrule->appendChild( rule.release() );
 
 1518     r = std::make_unique< QgsRuleBasedRenderer >( rootrule.release() );
 
 1523     r->setOrderBy( renderer->
orderBy() );
 
 1532   QString sizeExpression;
 
 1533   switch ( symbol->
type() )
 
 1539         if ( ! sizeScaleField.isEmpty() )
 
 1541           sizeExpression = QStringLiteral( 
"%1*(%2)" ).arg( msl->
size() ).arg( sizeScaleField );
 
 1544         if ( ! rotationField.isEmpty() )
 
 1551       if ( ! sizeScaleField.isEmpty() )
 
 1558             sizeExpression = QStringLiteral( 
"%1*(%2)" ).arg( lsl->
width() ).arg( sizeScaleField );
 
 1567               sizeExpression = QStringLiteral( 
"%1*(%2)" ).arg( msl->
size() ).arg( sizeScaleField );
 
const QgsCategoryList & categories() const
Returns a list of all categories recognized by the renderer.
QString classAttribute() const
Returns the class attribute for the renderer, which is the field name or expression string from the l...
A vector feature renderer which uses embedded feature symbology to render per-feature symbols.
void setFeature(const QgsFeature &feature)
Convenience function for setting a feature for the context.
Class for parsing and evaluation of expressions (formerly called "search strings").
static QString quotedString(QString text)
Returns a quoted version of a string (in single quotes)
bool hasParserError() const
Returns true if an error occurred when parsing the input expression.
bool isField() const
Checks whether an expression consists only of a single field reference.
static QString quotedColumnRef(QString name)
Returns a quoted column reference (in double quotes)
static bool attemptReduceToInClause(const QStringList &expressions, QString &result)
Attempts to reduce a list of expressions to a single "field IN (val1, val2, ... )" type expression.
Wrapper for iterator of features from vector data provider or vector layer.
bool nextFeature(QgsFeature &f)
virtual QgsFeatureRenderer * clone() const =0
Create a deep copy of this renderer.
void renderFeatureWithSymbol(const QgsFeature &feature, QgsSymbol *symbol, QgsRenderContext &context, int layer, bool selected, bool drawVertexMarker) SIP_THROW(QgsCsException)
Render the feature with the symbol using context.
virtual void stopRender(QgsRenderContext &context)
Must be called when a render cycle has finished, to allow the renderer to clean up.
QgsPaintEffect * mPaintEffect
void copyRendererData(QgsFeatureRenderer *destRenderer) const
Clones generic renderer data to another renderer.
bool orderByEnabled() const
Returns whether custom ordering will be applied before features are processed by this renderer.
QgsFeatureRequest::OrderBy mOrderBy
virtual const QgsFeatureRenderer * embeddedRenderer() const
Returns the current embedded renderer (subrenderer) for this feature renderer.
virtual void startRender(QgsRenderContext &context, const QgsFields &fields)
Must be called when a new render cycle is started.
QgsFeatureRequest::OrderBy orderBy() const
Gets the order in which features shall be processed by this renderer.
void CORE_EXPORT save(QDomElement &elem) const
Serialize to XML.
This class wraps a request for features to a vector layer (or directly its vector data provider).
QgsFeatureRequest & setFlags(QgsFeatureRequest::Flags flags)
Sets flags that affect how features will be fetched.
@ EmbeddedSymbols
Retrieve any embedded feature symbology (since QGIS 3.20)
@ NoGeometry
Geometry is not required. It may still be returned if e.g. required for a filter condition.
QgsFeatureRequest & setNoAttributes()
Set that no attributes will be fetched.
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
const QgsSymbol * embeddedSymbol() const
Returns the feature's embedded symbology, or nullptr if the feature has no embedded symbol.
Container of fields for a vector layer.
A fill symbol type, for rendering Polygon and MultiPolygon geometries.
QString classAttribute() const
const QgsRangeList & ranges() const
QgsInvertedPolygonRenderer is a polygon-only feature renderer used to display features inverted,...
The class stores information about one class/rule of a vector layer renderer in a unified way that ca...
virtual double width() const
Returns the estimated width for the line symbol layer.
A line symbol type, for rendering LineString and MultiLineString geometries.
Abstract base class for marker symbol layers.
double size() const
Returns the symbol size.
A marker symbol type, for rendering Point and MultiPoint geometries.
QgsMergedFeatureRenderer is a polygon or line-only feature renderer used to renderer a set of feature...
static QgsExpression * expressionFromOgcFilter(const QDomElement &element, QgsVectorLayer *layer=nullptr)
Parse XML with OGC filter into QGIS expression.
static bool isDefaultStack(QgsPaintEffect *effect)
Tests whether a paint effect matches the default effects stack.
virtual bool saveProperties(QDomDocument &doc, QDomElement &element) const
Saves the current state of the effect to a DOM element.
An abstract base class for distance based point renderers (e.g., clusterer and displacement renderers...
static QgsProperty fromExpression(const QString &expression, bool isActive=true)
Returns a new ExpressionBasedProperty created from the specified expression.
static QgsProperty fromField(const QString &fieldName, bool isActive=true)
Returns a new FieldBasedProperty created from the specified field name.
The class is used as a container of context for various read/write operations on other objects.
Contains information about the context of a rendering operation.
double rendererScale() const
Returns the renderer map scale.
QgsExpressionContext & expressionContext()
Gets the expression context.
bool renderingStopped() const
Returns true if the rendering operation has been stopped and any ongoing rendering should be canceled...
Represents an individual category (class) from a QgsCategorizedSymbolRenderer.
QgsSymbol * symbol() const
Returns the symbol which will be used to render this category.
QVariant value() const
Returns the value corresponding to this category.
QString label() const
Returns the label for this category, which is used to represent the category within legends and the l...
QgsSymbol * symbol() const
double upperValue() const
double lowerValue() const
This class keeps data about a rules for rule-based renderer.
bool accept(QgsStyleEntityVisitorInterface *visitor) const
Accepts the specified symbology visitor, causing it to visit all child rules associated with the rule...
QgsRuleBasedRenderer::RuleList descendants() const
Returns all children, grand-children, grand-grand-children, grand-gra...
void setSymbol(QgsSymbol *sym)
Sets a new symbol (or nullptr). Deletes old symbol.
void removeChild(QgsRuleBasedRenderer::Rule *rule)
delete child rule
QgsRuleBasedRenderer::Rule * findRuleByKey(const QString &key)
Try to find a rule given its unique key.
void insertChild(int i, QgsRuleBasedRenderer::Rule *rule)
add child rule, take ownership, sets this as parent
QString ruleKey() const
Unique rule identifier (for identification of rule within renderer)
bool needsGeometry() const
Returns true if this rule or one of its children needs the geometry to be applied.
QgsRuleBasedRenderer::Rule * takeChild(QgsRuleBasedRenderer::Rule *rule)
take child rule out, set parent as nullptr
RenderResult
The result of rendering a rule.
@ Rendered
Something was rendered.
QgsRuleBasedRenderer::RuleList rulesForFeature(const QgsFeature &feature, QgsRenderContext *context=nullptr, bool onlyActive=true)
Returns the list of rules used to render the feature in a specific context.
double maximumScale() const
Returns the maximum map scale (i.e.
void setIsElse(bool iselse)
Sets if this rule is an ELSE rule.
QgsSymbolList symbolsForFeature(const QgsFeature &feature, QgsRenderContext *context=nullptr)
tell which symbols will be used to render the feature
QSet< QString > legendKeysForFeature(const QgsFeature &feature, QgsRenderContext *context=nullptr)
Returns which legend keys match the feature.
QgsRuleBasedRenderer::Rule * clone() const
clone this rule, return new instance
bool willRenderFeature(const QgsFeature &feature, QgsRenderContext *context=nullptr)
only tell whether a feature will be rendered without actually rendering it
static QgsRuleBasedRenderer::Rule * create(QDomElement &ruleElem, QgsSymbolMap &symbolMap)
Create a rule from an XML definition.
void removeChildAt(int i)
delete child rule
void setActive(bool state)
Sets if this rule is active.
Rule(QgsSymbol *symbol, int maximumScale=0, int minimumScale=0, const QString &filterExp=QString(), const QString &label=QString(), const QString &description=QString(), bool elseRule=false)
Constructor takes ownership of the symbol.
bool isFilterOK(const QgsFeature &f, QgsRenderContext *context=nullptr) const
Check if a given feature shall be rendered by this rule.
QgsSymbolList symbols(const QgsRenderContext &context=QgsRenderContext()) const
bool isScaleOK(double scale) const
Check if this rule applies for a given scale.
void setNormZLevels(const QMap< int, int > &zLevelsToNormLevels)
assign normalized z-levels [0..N-1] for this rule's symbol for quick access during rendering
QDomElement save(QDomDocument &doc, QgsSymbolMap &symbolMap) const
void appendChild(QgsRuleBasedRenderer::Rule *rule)
add child rule, take ownership, sets this as parent
QgsRuleBasedRenderer::Rule * takeChildAt(int i)
take child rule out, set parent as nullptr
QSet< int > collectZLevels()
Gets all used z-levels from this rule and children.
double minimumScale() const
Returns the minimum map scale (i.e.
void stopRender(QgsRenderContext &context)
Stop a rendering process.
QgsRuleBasedRenderer::Rule::RenderResult renderFeature(QgsRuleBasedRenderer::FeatureToRender &featToRender, QgsRenderContext &context, QgsRuleBasedRenderer::RenderQueue &renderQueue)
Render a given feature, will recursively call subclasses and only render if the constraints apply.
QgsLegendSymbolList legendSymbolItems(int currentLevel=-1) const
QSet< QString > usedAttributes(const QgsRenderContext &context) const
Returns the attributes used to evaluate the expression of this rule.
void setFilterExpression(const QString &filterExp)
Set the expression used to check if a given feature shall be rendered with this rule.
static QgsRuleBasedRenderer::Rule * createFromSld(QDomElement &element, QgsWkbTypes::GeometryType geomType)
Create a rule from the SLD provided in element and for the specified geometry type.
QString dump(int indent=0) const
Dump for debug purpose.
void setRuleKey(const QString &key)
Override the assigned rule key (should be used just internally by rule-based renderer)
bool startRender(QgsRenderContext &context, const QgsFields &fields, QString &filter)
prepare the rule for rendering and its children (build active children array)
bool active() const
Returns if this rule is active.
void toSld(QDomDocument &doc, QDomElement &element, QVariantMap props) const
Saves the symbol layer as SLD.
static void refineRuleCategories(QgsRuleBasedRenderer::Rule *initialRule, QgsCategorizedSymbolRenderer *r)
take a rule and create a list of new rules based on the categories from categorized symbol renderer
static void convertToDataDefinedSymbology(QgsSymbol *symbol, const QString &sizeScaleField, const QString &rotationField=QString())
helper function to convert the size scale and rotation fields present in some other renderers to data...
bool legendSymbolItemChecked(const QString &key) override
items of symbology items in legend is checked
void startRender(QgsRenderContext &context, const QgsFields &fields) override
Must be called when a new render cycle is started.
QDomElement save(QDomDocument &doc, const QgsReadWriteContext &context) override
store renderer info to XML element
void setLegendSymbolItem(const QString &key, QgsSymbol *symbol) override
Sets the symbol to be used for a legend symbol item.
void checkLegendSymbolItem(const QString &key, bool state=true) override
item in symbology was checked
QgsSymbol * symbolForFeature(const QgsFeature &feature, QgsRenderContext &context) const override
Returns symbol for current feature. Should not be used individually: there could be more symbols for ...
QList< QgsRuleBasedRenderer::RenderLevel > RenderQueue
Rendering queue: a list of rendering levels.
QSet< QString > legendKeysForFeature(const QgsFeature &feature, QgsRenderContext &context) const override
Returns legend keys matching a specified feature.
static void refineRuleRanges(QgsRuleBasedRenderer::Rule *initialRule, QgsGraduatedSymbolRenderer *r)
take a rule and create a list of new rules based on the ranges from graduated symbol renderer
QgsSymbolList symbolsForFeature(const QgsFeature &feature, QgsRenderContext &context) const override
Returns list of symbols used for rendering the feature.
QString dump() const override
Returns debug information about this renderer.
QgsSymbolList originalSymbolsForFeature(const QgsFeature &feature, QgsRenderContext &context) const override
Equivalent of originalSymbolsForFeature() call extended to support renderers that may use more symbol...
static QgsRuleBasedRenderer * convertFromRenderer(const QgsFeatureRenderer *renderer, QgsVectorLayer *layer=nullptr)
Creates a new QgsRuleBasedRenderer from an existing renderer.
bool legendSymbolItemsCheckable() const override
items of symbology items in legend should be checkable
QSet< QString > usedAttributes(const QgsRenderContext &context) const override
Returns a list of attributes required by this renderer.
QString filter(const QgsFields &fields=QgsFields()) override
If a renderer does not require all the features this method may be overridden and return an expressio...
bool willRenderFeature(const QgsFeature &feature, QgsRenderContext &context) const override
Returns whether the renderer will render a feature or not.
static void refineRuleScales(QgsRuleBasedRenderer::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...
QList< QgsRuleBasedRenderer::Rule * > RuleList
void stopRender(QgsRenderContext &context) override
Must be called when a render cycle has finished, to allow the renderer to clean up.
Rule * mRootRule
the root node with hierarchical list of rules
~QgsRuleBasedRenderer() override
bool accept(QgsStyleEntityVisitorInterface *visitor) const override
Accepts the specified symbology visitor, causing it to visit all symbols associated with the renderer...
bool filterNeedsGeometry() const override
Returns true if this renderer requires the geometry to apply the filter.
QgsRuleBasedRenderer * clone() const override
Create a deep copy of this renderer.
static QgsFeatureRenderer * create(QDomElement &element, const QgsReadWriteContext &context)
Creates a new rule-based renderer instance from XML.
bool renderFeature(const QgsFeature &feature, QgsRenderContext &context, int layer=-1, bool selected=false, bool drawVertexMarker=false) override SIP_THROW(QgsCsException)
Render a feature using this renderer in the given context.
QgsLegendSymbolList legendSymbolItems() const override
Returns a list of symbology items for the legend.
QList< FeatureToRender > mCurrentFeatures
static QgsFeatureRenderer * createFromSld(QDomElement &element, QgsWkbTypes::GeometryType geomType)
QgsRuleBasedRenderer(QgsRuleBasedRenderer::Rule *root)
Constructs the renderer from given tree of rules (takes ownership)
QgsSymbolList symbols(QgsRenderContext &context) const override
Returns list of symbols used by the renderer.
void toSld(QDomDocument &doc, QDomElement &element, const QVariantMap &props=QVariantMap()) const override
used from subclasses to create SLD Rule elements following SLD v1.1 specs
QgsSymbol * symbol() const
Returns the symbol which will be rendered for every feature.
An interface for classes which can visit style entity (e.g.
@ SymbolRule
Rule based symbology or label child rule.
virtual bool visitExit(const QgsStyleEntityVisitorInterface::Node &node)
Called when the visitor stops visiting a node.
virtual bool visitEnter(const QgsStyleEntityVisitorInterface::Node &node)
Called when the visitor starts visiting a node.
virtual bool visit(const QgsStyleEntityVisitorInterface::StyleLeaf &entity)
Called when the visitor will visit a style entity.
A symbol entity for QgsStyle databases.
static void applyScaleDependency(QDomDocument &doc, QDomElement &ruleElem, QVariantMap &props)
Checks if the properties contain scaleMinDenom and scaleMaxDenom, if available, they are added into t...
static bool createFunctionElement(QDomDocument &doc, QDomElement &element, const QString &function)
static bool createSymbolLayerListFromSld(QDomElement &element, QgsWkbTypes::GeometryType geomType, QList< QgsSymbolLayer * > &layers)
Creates a symbol layer list from a DOM element.
static void mergeScaleDependencies(double mScaleMinDenom, double mScaleMaxDenom, QVariantMap &props)
Merges the local scale limits, if any, with the ones already in the map, if any.
static void clearSymbolMap(QgsSymbolMap &symbols)
static QgsSymbolMap loadSymbols(QDomElement &element, const QgsReadWriteContext &context)
Reads a collection of symbols from XML and returns them in a map. Caller is responsible for deleting ...
static QDomElement saveSymbols(QgsSymbolMap &symbols, const QString &tagName, QDomDocument &doc, const QgsReadWriteContext &context)
Writes a collection of symbols to XML with specified tagName for the top-level element.
@ PropertyAngle
Symbol angle.
@ PropertySize
Symbol size.
@ PropertyStrokeWidth
Stroke width.
virtual QString layerType() const =0
Returns a string that represents this layer type.
int renderingPass() const
Specifies the rendering pass in which this symbol layer should be rendered.
virtual void setDataDefinedProperty(Property key, const QgsProperty &property)
Sets a data defined property for the layer.
virtual QgsSymbol * subSymbol()
Returns the symbol's sub symbol, if present.
Abstract base class for all rendered symbols.
QgsSymbolLayer * symbolLayer(int layer)
Returns the symbol layer at the specified index.
int symbolLayerCount() const
Returns the total number of symbol layers contained in the symbol.
Qgis::SymbolType type() const
Returns the symbol's type.
virtual QgsSymbol * clone() const =0
Returns a deep copy of this symbol.
Represents a vector layer which manages a vector based data sets.
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const FINAL
Queries the layer for features specified in request.
GeometryType
The geometry types are used to group QgsWkbTypes::Type in a coarse way.
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
QList< QgsLegendSymbolItem > QgsLegendSymbolList
#define QgsDebugMsgLevel(str, level)
#define RENDERER_TAG_NAME
QMap< QString, QgsSymbol * > QgsSymbolMap
QList< QgsSymbol * > QgsSymbolList
QList< QgsSymbolLayer * > QgsSymbolLayerList
Feature for rendering by a QgsRuleBasedRenderer.
A QgsRuleBasedRenderer rendering job, consisting of a feature to be rendered with a particular symbol...
Render level: a list of jobs to be drawn at particular level for a QgsRuleBasedRenderer.
Contains information relating to a node (i.e.
Contains information relating to the style entity currently being visited.