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 matchedAChild = 
false;
 
  591   const auto constMChildren = mChildren;
 
  592   for ( 
Rule *rule : constMChildren )
 
  595     if ( !rule->isElse() )
 
  597       const RenderResult res = rule->renderFeature( featToRender, context, renderQueue );
 
  599       matchedAChild |= ( res == Rendered || res == Inactive );
 
  600       rendered |= ( res == Rendered );
 
  605   if ( !matchedAChild )
 
  607     const auto constMElseRules = mElseRules;
 
  608     for ( 
Rule *rule : constMElseRules )
 
  610       const RenderResult res = rule->renderFeature( featToRender, context, renderQueue );
 
  611       matchedAChild |= ( res == Rendered || res == Inactive );
 
  612       rendered |= res == Rendered;
 
  615   if ( !mIsActive || ( mSymbol && !rendered ) || ( matchedAChild && !rendered ) )
 
  625   if ( !isFilterOK( feature, context ) )
 
  631   const auto constMActiveChildren = mActiveChildren;
 
  632   for ( 
Rule *rule : constMActiveChildren )
 
  634     if ( rule->isElse() )
 
  636       if ( rule->children().isEmpty() )
 
  638         RuleList lst = rulesForFeature( feature, context, 
false );
 
  639         lst.removeOne( rule );
 
  648         return rule->willRenderFeature( feature, context );
 
  651     else if ( rule->willRenderFeature( feature, context ) )
 
  662   if ( !isFilterOK( feature, context ) )
 
  665     lst.append( mSymbol.get() );
 
  667   const auto constMActiveChildren = mActiveChildren;
 
  668   for ( 
Rule *rule : constMActiveChildren )
 
  670     lst += rule->symbolsForFeature( feature, context );
 
  678   if ( !isFilterOK( feature, context ) )
 
  680   lst.insert( mRuleKey );
 
  682   const auto constMActiveChildren = mActiveChildren;
 
  683   for ( 
Rule *rule : constMActiveChildren )
 
  685     bool validKey = 
false;
 
  686     if ( rule->isElse() )
 
  688       RuleList lst = rulesForFeature( feature, context, 
false );
 
  689       lst.removeOne( rule );
 
  696     else if ( !rule->isElse( ) && rule->willRenderFeature( feature, context ) )
 
  703       lst.unite( rule->legendKeysForFeature( feature, context ) );
 
  712   if ( ! isFilterOK( feature, context ) || ( context && ! isScaleOK( context->
rendererScale() ) ) )
 
  720     listChildren = mActiveChildren;
 
  722   const auto constListChildren = listChildren;
 
  723   for ( 
Rule *rule : constListChildren )
 
  725     lst += rule->rulesForFeature( feature, context, onlyActive );
 
  733     mSymbol->stopRender( context );
 
  735   const auto constMActiveChildren = mActiveChildren;
 
  736   for ( 
Rule *rule : constMActiveChildren )
 
  738     rule->stopRender( context );
 
  741   mActiveChildren.clear();
 
  742   mSymbolNormZLevels.clear();
 
  747   QString symbolIdx = ruleElem.attribute( QStringLiteral( 
"symbol" ) );
 
  749   if ( !symbolIdx.isEmpty() )
 
  751     if ( symbolMap.contains( symbolIdx ) )
 
  753       symbol = symbolMap.take( symbolIdx );
 
  757       QgsDebugMsg( 
"symbol for rule " + symbolIdx + 
" not found!" );
 
  761   QString filterExp = ruleElem.attribute( QStringLiteral( 
"filter" ) );
 
  762   QString label = ruleElem.attribute( QStringLiteral( 
"label" ) );
 
  763   QString description = ruleElem.attribute( QStringLiteral( 
"description" ) );
 
  764   int scaleMinDenom = ruleElem.attribute( QStringLiteral( 
"scalemindenom" ), QStringLiteral( 
"0" ) ).toInt();
 
  765   int scaleMaxDenom = ruleElem.attribute( QStringLiteral( 
"scalemaxdenom" ), QStringLiteral( 
"0" ) ).toInt();
 
  766   QString ruleKey = ruleElem.attribute( QStringLiteral( 
"key" ) );
 
  767   Rule *rule = 
new Rule( symbol, scaleMinDenom, scaleMaxDenom, filterExp, label, description );
 
  769   if ( !ruleKey.isEmpty() )
 
  770     rule->mRuleKey = ruleKey;
 
  772   rule->
setActive( ruleElem.attribute( QStringLiteral( 
"checkstate" ), QStringLiteral( 
"1" ) ).toInt() );
 
  774   QDomElement childRuleElem = ruleElem.firstChildElement( QStringLiteral( 
"rule" ) );
 
  775   while ( !childRuleElem.isNull() )
 
  777     Rule *childRule = 
create( childRuleElem, symbolMap );
 
  784       QgsDebugMsg( QStringLiteral( 
"failed to init a child rule!" ) );
 
  786     childRuleElem = childRuleElem.nextSiblingElement( QStringLiteral( 
"rule" ) );
 
  798     l += 
c->descendants();
 
  805   if ( ruleElem.localName() != QLatin1String( 
"Rule" ) )
 
  807     QgsDebugMsg( QStringLiteral( 
"invalid element: Rule element expected, %1 found!" ).arg( ruleElem.tagName() ) );
 
  811   QString label, description, filterExp;
 
  812   int scaleMinDenom = 0, scaleMaxDenom = 0;
 
  816   QDomElement childElem = ruleElem.firstChildElement();
 
  817   while ( !childElem.isNull() )
 
  819     if ( childElem.localName() == QLatin1String( 
"Name" ) )
 
  823       if ( label.isEmpty() )
 
  824         label = childElem.firstChild().nodeValue();
 
  826     else if ( childElem.localName() == QLatin1String( 
"Description" ) )
 
  829       QDomElement titleElem = childElem.firstChildElement( QStringLiteral( 
"Title" ) );
 
  830       if ( !titleElem.isNull() )
 
  832         label = titleElem.firstChild().nodeValue();
 
  835       QDomElement abstractElem = childElem.firstChildElement( QStringLiteral( 
"Abstract" ) );
 
  836       if ( !abstractElem.isNull() )
 
  838         description = abstractElem.firstChild().nodeValue();
 
  841     else if ( childElem.localName() == QLatin1String( 
"Abstract" ) )
 
  844       description = childElem.firstChild().nodeValue();
 
  846     else if ( childElem.localName() == QLatin1String( 
"Title" ) )
 
  849       label = childElem.firstChild().nodeValue();
 
  851     else if ( childElem.localName() == QLatin1String( 
"Filter" ) )
 
  856         if ( 
filter->hasParserError() )
 
  862           filterExp = 
filter->expression();
 
  867     else if ( childElem.localName() == QLatin1String( 
"MinScaleDenominator" ) )
 
  870       int v = childElem.firstChild().nodeValue().toInt( &ok );
 
  874     else if ( childElem.localName() == QLatin1String( 
"MaxScaleDenominator" ) )
 
  877       int v = childElem.firstChild().nodeValue().toInt( &ok );
 
  881     else if ( childElem.localName().endsWith( QLatin1String( 
"Symbolizer" ) ) )
 
  887     childElem = childElem.nextSiblingElement();
 
  892   if ( !layers.isEmpty() )
 
  909         QgsDebugMsg( QStringLiteral( 
"invalid geometry type: found %1" ).arg( geomType ) );
 
  915   return new Rule( symbol, scaleMinDenom, scaleMaxDenom, filterExp, label, description );
 
  950     bool drawVertexMarker )
 
  970   QList<int> symbolZLevels = qgis::setToList( symbolZLevelsSet );
 
  971   std::sort( symbolZLevels.begin(), symbolZLevels.end() );
 
  975   QMap<int, int> zLevelsToNormLevels;
 
  976   int maxNormLevel = -1;
 
  977   const auto constSymbolZLevels = symbolZLevels;
 
  978   for ( 
int zLevel : constSymbolZLevels )
 
  980     zLevelsToNormLevels[zLevel] = ++maxNormLevel;
 
  982     QgsDebugMsgLevel( QStringLiteral( 
"zLevel %1 -> %2" ).arg( zLevel ).arg( maxNormLevel ), 4 );
 
 1000     for ( 
const RenderLevel &level : constMRenderQueue )
 
 1004       for ( 
const RenderJob *job : std::as_const( level.jobs ) )
 
 1011         for ( 
int i = 0; i < count; i++ )
 
 1018             int flags = job->ftr.flags;
 
 1060   Q_ASSERT( origDescendants.count() == clonedDescendants.count() );
 
 1061   for ( 
int i = 0; i < origDescendants.count(); ++i )
 
 1062     clonedDescendants[i]->setRuleKey( origDescendants[i]->ruleKey() );
 
 1084   rendererElem.setAttribute( QStringLiteral( 
"type" ), QStringLiteral( 
"RuleRenderer" ) );
 
 1089   rulesElem.setTagName( QStringLiteral( 
"rules" ) ); 
 
 1090   rendererElem.appendChild( rulesElem );
 
 1093   rendererElem.appendChild( symbolsElem );
 
 1097   return rendererElem;
 
 1108   return rule ? rule->
active() : 
true;
 
 1125   std::function<QString( 
Rule *rule )> ruleToExpression;
 
 1126   ruleToExpression = [&ruleToExpression]( 
Rule * rule ) -> QString
 
 1132       QStringList otherRules;
 
 1133       const QList<QgsRuleBasedRenderer::Rule *> siblings = rule->
parent()->
children();
 
 1134       for ( 
Rule *sibling : siblings )
 
 1136         if ( sibling == rule )
 
 1139         const QString siblingExpression = ruleToExpression( sibling );
 
 1140         if ( siblingExpression.isEmpty() )
 
 1141           return QStringLiteral( 
"FALSE" ); 
 
 1143         otherRules.append( siblingExpression );
 
 1146       if ( otherRules.empty() )
 
 1147         return QStringLiteral( 
"TRUE" ); 
 
 1150                  otherRules.size() > 1
 
 1151                  ?  QStringLiteral( 
"NOT ((%1))" ).arg( otherRules.join( QLatin1String( 
") OR (" ) ) )
 
 1152                  : QStringLiteral( 
"NOT (%1)" ).arg( otherRules.at( 0 ) )
 
 1157       QStringList ruleParts;
 
 1162         ruleParts.append( QStringLiteral( 
"@map_scale <= %1" ).arg( rule->
minimumScale() ) );
 
 1165         ruleParts.append( QStringLiteral( 
"@map_scale >= %1" ).arg( rule->
maximumScale() ) );
 
 1167       if ( !ruleParts.empty() )
 
 1170                  ruleParts.size() > 1
 
 1171                  ?  QStringLiteral( 
"(%1)" ).arg( ruleParts.join( QLatin1String( 
") AND (" ) ) )
 
 1185     const QString ruleFilter = ruleToExpression( rule );
 
 1186     if ( !ruleFilter.isEmpty() )
 
 1187       parts.append( ruleFilter );
 
 1193   return parts.empty() ? QStringLiteral( 
"TRUE" )
 
 1194          : ( parts.size() > 1
 
 1195              ?  QStringLiteral( 
"(%1)" ).arg( parts.join( QLatin1String( 
") AND (" ) ) )
 
 1217   QDomElement symbolsElem = element.firstChildElement( QStringLiteral( 
"symbols" ) );
 
 1218   if ( symbolsElem.isNull() )
 
 1223   QDomElement rulesElem = element.firstChildElement( QStringLiteral( 
"rules" ) );
 
 1240   Rule *root = 
nullptr;
 
 1242   QDomElement ruleElem = element.firstChildElement( QStringLiteral( 
"Rule" ) );
 
 1243   while ( !ruleElem.isNull() )
 
 1250         root = 
new Rule( 
nullptr );
 
 1255     ruleElem = ruleElem.nextSiblingElement( QStringLiteral( 
"Rule" ) );
 
 1283   const auto constCategories = r->
categories();
 
 1288     if ( cat.value().isNull() )
 
 1290     else if ( cat.value().type() == QVariant::Int )
 
 1291       value = cat.value().toString();
 
 1292     else if ( cat.value().type() == QVariant::Double )
 
 1295       value = QString::number( cat.value().toDouble(), 
'f', 4 );
 
 1298     const QString 
filter = QStringLiteral( 
"%1 %2 %3" ).arg( attr, cat.value().isNull() ? QStringLiteral( 
"IS" ) : QStringLiteral( 
"=" ), value );
 
 1299     const QString label = !cat.label().isEmpty() ? cat.label() :
 
 1300                           cat.value().isValid() ? value : QString();
 
 1316   else if ( !testExpr.
isField() )
 
 1319     attr = QStringLiteral( 
"(%1)" ).arg( attr );
 
 1322   bool firstRange = 
true;
 
 1323   const auto constRanges = r->
ranges();
 
 1328     QString 
filter = QStringLiteral( 
"%1 %2 %3 AND %1 <= %4" ).arg( attr, firstRange ? QStringLiteral( 
">=" ) : QStringLiteral( 
">" ),
 
 1329                      QString::number( rng.lowerValue(), 
'f', 4 ),
 
 1330                      QString::number( rng.upperValue(), 
'f', 4 ) );
 
 1332     QString label = rng.label().isEmpty() ? 
filter : rng.label();
 
 1339   std::sort( scales.begin(), scales.end() ); 
 
 1343   const auto constScales = scales;
 
 1344   for ( 
int scale : constScales )
 
 1348     if ( maxDenom != 0 && maxDenom  <= scale )
 
 1350     initialRule->
appendChild( 
new Rule( symbol->
clone(), oldScale, scale, QString(), QStringLiteral( 
"%1 - %2" ).arg( oldScale ).arg( scale ) ) );
 
 1354   initialRule->
appendChild( 
new Rule( symbol->
clone(), oldScale, maxDenom, QString(), QStringLiteral( 
"%1 - %2" ).arg( oldScale ).arg( maxDenom ) ) );
 
 1359   QString msg( QStringLiteral( 
"Rule-based renderer:\n" ) );
 
 1391   std::unique_ptr< QgsRuleBasedRenderer > r;
 
 1392   if ( renderer->
type() == QLatin1String( 
"RuleRenderer" ) )
 
 1396   else if ( renderer->
type() == QLatin1String( 
"singleSymbol" ) )
 
 1399     if ( !singleSymbolRenderer )
 
 1402     std::unique_ptr< QgsSymbol > origSymbol( singleSymbolRenderer->
symbol()->
clone() );
 
 1403     r = std::make_unique< QgsRuleBasedRenderer >( origSymbol.release() );
 
 1405   else if ( renderer->
type() == QLatin1String( 
"categorizedSymbol" ) )
 
 1408     if ( !categorizedRenderer )
 
 1413     bool isField = 
false;
 
 1423     if ( isField && !attr.contains( 
'\"' ) )
 
 1429     std::unique_ptr< QgsRuleBasedRenderer::Rule > rootrule = std::make_unique< QgsRuleBasedRenderer::Rule >( 
nullptr );
 
 1436       std::unique_ptr< QgsRuleBasedRenderer::Rule > rule = std::make_unique< QgsRuleBasedRenderer::Rule >( 
nullptr );
 
 1438       rule->setLabel( category.
label() );
 
 1441       if ( category.
value().type() == QVariant::List )
 
 1444         const QVariantList list = category.
value().toList();
 
 1445         for ( 
const QVariant &v : list )
 
 1448           if ( QVariant( v ).convert( QVariant::Double ) )
 
 1450             values << v.toString();
 
 1458         if ( values.empty() )
 
 1460           expression = QStringLiteral( 
"ELSE" );
 
 1464           expression = QStringLiteral( 
"%1 IN (%2)" ).arg( attr, values.join( 
',' ) );
 
 1470         if ( category.
value().convert( QVariant::Double ) )
 
 1472           value = category.
value().toString();
 
 1480         if ( value == QLatin1String( 
"''" ) )
 
 1482           expression = QStringLiteral( 
"ELSE" );
 
 1486           expression = QStringLiteral( 
"%1 = %2" ).arg( attr, value );
 
 1489       rule->setFilterExpression( expression );
 
 1495       std::unique_ptr< QgsSymbol > origSymbol( category.
symbol()->
clone() );
 
 1496       rule->setSymbol( origSymbol.release() );
 
 1498       rootrule->appendChild( rule.release() );
 
 1501     r = std::make_unique< QgsRuleBasedRenderer >( rootrule.release() );
 
 1503   else if ( renderer->
type() == QLatin1String( 
"graduatedSymbol" ) )
 
 1506     if ( !graduatedRenderer )
 
 1512     bool isField = 
false;
 
 1522     if ( isField  && !attr.contains( 
'\"' ) )
 
 1527     else if ( !isField )
 
 1530       attr = QStringLiteral( 
"(%1)" ).arg( attr );
 
 1533     std::unique_ptr< QgsRuleBasedRenderer::Rule > rootrule = std::make_unique< QgsRuleBasedRenderer::Rule >( 
nullptr );
 
 1537     for ( 
int i = 0; i < graduatedRenderer->
ranges().size(); ++i )
 
 1539       range = graduatedRenderer->
ranges().value( i );
 
 1540       std::unique_ptr< QgsRuleBasedRenderer::Rule > rule = std::make_unique< QgsRuleBasedRenderer::Rule >( 
nullptr );
 
 1541       rule->setLabel( range.
label() );
 
 1544         expression = attr + 
" >= " + QString::number( range.
lowerValue(), 
'f' ) + 
" AND " + \
 
 1545                      attr + 
" <= " + QString::number( range.
upperValue(), 
'f' );
 
 1549         expression = attr + 
" > " + QString::number( range.
lowerValue(), 
'f' ) + 
" AND " + \
 
 1550                      attr + 
" <= " + QString::number( range.
upperValue(), 
'f' );
 
 1552       rule->setFilterExpression( expression );
 
 1558       std::unique_ptr< QgsSymbol > symbol( range.
symbol()->
clone() );
 
 1559       rule->setSymbol( symbol.release() );
 
 1561       rootrule->appendChild( rule.release() );
 
 1564     r = std::make_unique< QgsRuleBasedRenderer >( rootrule.release() );
 
 1566   else if ( renderer->
type() == QLatin1String( 
"pointDisplacement" ) || renderer->
type() == QLatin1String( 
"pointCluster" ) )
 
 1571   else if ( renderer->
type() == QLatin1String( 
"invertedPolygonRenderer" ) )
 
 1576   else if ( renderer->
type() == QLatin1String( 
"mergedFeatureRenderer" ) )
 
 1581   else if ( renderer->
type() == QLatin1String( 
"embeddedSymbol" ) && layer )
 
 1585     std::unique_ptr< QgsRuleBasedRenderer::Rule > rootrule = std::make_unique< QgsRuleBasedRenderer::Rule >( 
nullptr );
 
 1592     while ( it.
nextFeature( feature ) && rootrule->children().size() < 500 )
 
 1596         std::unique_ptr< QgsRuleBasedRenderer::Rule > rule = std::make_unique< QgsRuleBasedRenderer::Rule >( 
nullptr );
 
 1597         rule->setFilterExpression( QStringLiteral( 
"$id=%1" ).arg( feature.
id() ) );
 
 1598         rule->setLabel( QString::number( feature.
id() ) );
 
 1600         rootrule->appendChild( rule.release() );
 
 1604     std::unique_ptr< QgsRuleBasedRenderer::Rule > rule = std::make_unique< QgsRuleBasedRenderer::Rule >( 
nullptr );
 
 1605     rule->setFilterExpression( QStringLiteral( 
"ELSE" ) );
 
 1606     rule->setLabel( QObject::tr( 
"All other features" ) );
 
 1608     rootrule->appendChild( rule.release() );
 
 1610     r = std::make_unique< QgsRuleBasedRenderer >( rootrule.release() );
 
 1623   QString sizeExpression;
 
 1624   switch ( symbol->
type() )
 
 1630         if ( ! sizeScaleField.isEmpty() )
 
 1632           sizeExpression = QStringLiteral( 
"%1*(%2)" ).arg( msl->
size() ).arg( sizeScaleField );
 
 1635         if ( ! rotationField.isEmpty() )
 
 1642       if ( ! sizeScaleField.isEmpty() )
 
 1649             sizeExpression = QStringLiteral( 
"%1*(%2)" ).arg( lsl->
width() ).arg( sizeScaleField );
 
 1658               sizeExpression = QStringLiteral( 
"%1*(%2)" ).arg( msl->
size() ).arg( sizeScaleField );