34 #include <QDomDocument>
35 #include <QDomElement>
42 , mMaximumScale( scaleMinDenom )
43 , mMinimumScale( scaleMaxDenom )
44 , mFilterExp( filterExp )
46 , mDescription( description )
47 , mElseRule( elseRule )
50 mFilterExp = QStringLiteral(
"ELSE" );
52 mRuleKey = QUuid::createUuid().toString();
58 qDeleteAll( mChildren );
64 if ( mFilterExp.trimmed().compare( QLatin1String(
"ELSE" ), Qt::CaseInsensitive ) == 0 )
69 else if ( mFilterExp.trimmed().isEmpty() )
77 mFilter = qgis::make_unique< QgsExpression >( mFilterExp );
83 mChildren.append( rule );
90 mChildren.insert( i, rule );
97 mChildren.removeAll( rule );
104 delete mChildren.takeAt( i );
110 mChildren.removeAll( rule );
111 rule->mParent =
nullptr;
118 Rule *rule = mChildren.takeAt( i );
119 rule->mParent =
nullptr;
128 if ( key == mRuleKey )
131 const auto constMChildren = mChildren;
132 for (
Rule *rule : constMChildren )
141 void QgsRuleBasedRenderer::Rule::updateElseRules()
144 const auto constMChildren = mChildren;
145 for (
Rule *rule : constMChildren )
147 if ( rule->isElse() )
154 mFilterExp = QStringLiteral(
"ELSE" );
172 if ( !mChildren.empty() )
174 for (
const Rule *rule : mChildren )
177 if ( !rule->accept( visitor ) )
191 off.fill( QChar(
' ' ), indent );
192 QString symbolDump = ( mSymbol ? mSymbol->dump() : QStringLiteral(
"[]" ) );
193 QString msg = off + QStringLiteral(
"RULE %1 - scale [%2,%3] - filter %4 - symbol %5\n" )
194 .arg( mLabel ).arg( mMaximumScale ).arg( mMinimumScale )
195 .arg( mFilterExp, symbolDump );
198 const auto constMChildren = mChildren;
199 for (
Rule *rule : constMChildren )
201 lst.append( rule->dump( indent + 2 ) );
203 msg += lst.join( QLatin1Char(
'\n' ) );
212 attrs.unite(
mFilter->referencedColumns() );
214 attrs.unite( mSymbol->usedAttributes( context ) );
217 const auto constMChildren = mChildren;
218 for (
Rule *rule : constMChildren )
220 attrs.unite( rule->usedAttributes( context ) );
230 const auto constMChildren = mChildren;
231 for (
Rule *rule : constMChildren )
233 if ( rule->needsGeometry() )
244 lst.append( mSymbol.get() );
246 const auto constMChildren = mChildren;
247 for (
Rule *rule : constMChildren )
249 lst += rule->symbols( context );
256 mSymbol.reset( sym );
261 mFilterExp = filterExp;
268 if ( currentLevel != -1 )
270 lst <<
QgsLegendSymbolItem( mSymbol.get(), mLabel, mRuleKey,
true, mMaximumScale, mMinimumScale, currentLevel, mParent ? mParent->mRuleKey : QString() );
273 for ( RuleList::const_iterator it = mChildren.constBegin(); it != mChildren.constEnd(); ++it )
284 if ( !
mFilter || mElseRule || ! context )
298 if ( !
qgsDoubleNear( mMaximumScale, 0.0 ) && mMaximumScale > scale )
300 if ( !
qgsDoubleNear( mMinimumScale, 0.0 ) && mMinimumScale < scale )
308 Rule *newrule =
new Rule( sym, mMaximumScale, mMinimumScale, mFilterExp, mLabel, mDescription );
311 const auto constMChildren = mChildren;
312 for (
Rule *rule : constMChildren )
319 QDomElement ruleElem = doc.createElement( QStringLiteral(
"rule" ) );
323 int symbolIndex = symbolMap.size();
324 symbolMap[QString::number( symbolIndex )] = mSymbol.get();
325 ruleElem.setAttribute( QStringLiteral(
"symbol" ), symbolIndex );
327 if ( !mFilterExp.isEmpty() )
328 ruleElem.setAttribute( QStringLiteral(
"filter" ), mFilterExp );
329 if ( mMaximumScale != 0 )
330 ruleElem.setAttribute( QStringLiteral(
"scalemindenom" ), mMaximumScale );
331 if ( mMinimumScale != 0 )
332 ruleElem.setAttribute( QStringLiteral(
"scalemaxdenom" ), mMinimumScale );
333 if ( !mLabel.isEmpty() )
334 ruleElem.setAttribute( QStringLiteral(
"label" ), mLabel );
335 if ( !mDescription.isEmpty() )
336 ruleElem.setAttribute( QStringLiteral(
"description" ), mDescription );
338 ruleElem.setAttribute( QStringLiteral(
"checkstate" ), 0 );
339 ruleElem.setAttribute( QStringLiteral(
"key" ), mRuleKey );
341 const auto constMChildren = mChildren;
342 for (
Rule *rule : constMChildren )
344 ruleElem.appendChild( rule->save( doc, symbolMap ) );
353 if (
symbols( context ).isEmpty() )
356 if ( !mFilterExp.isEmpty() )
358 if ( !props.value( QStringLiteral(
"filter" ), QString() ).isEmpty() )
359 props[ QStringLiteral(
"filter" )] += QLatin1String(
" AND " );
360 props[ QStringLiteral(
"filter" )] += mFilterExp;
367 QDomElement ruleElem = doc.createElement( QStringLiteral(
"se:Rule" ) );
368 element.appendChild( ruleElem );
372 QDomElement nameElem = doc.createElement( QStringLiteral(
"se:Name" ) );
373 nameElem.appendChild( doc.createTextNode( mLabel ) );
374 ruleElem.appendChild( nameElem );
376 if ( !mLabel.isEmpty() || !mDescription.isEmpty() )
378 QDomElement descrElem = doc.createElement( QStringLiteral(
"se:Description" ) );
379 if ( !mLabel.isEmpty() )
381 QDomElement titleElem = doc.createElement( QStringLiteral(
"se:Title" ) );
382 titleElem.appendChild( doc.createTextNode( mLabel ) );
383 descrElem.appendChild( titleElem );
385 if ( !mDescription.isEmpty() )
387 QDomElement abstractElem = doc.createElement( QStringLiteral(
"se:Abstract" ) );
388 abstractElem.appendChild( doc.createTextNode( mDescription ) );
389 descrElem.appendChild( abstractElem );
391 ruleElem.appendChild( descrElem );
394 if ( !props.value( QStringLiteral(
"filter" ), QString() ).isEmpty() )
401 mSymbol->toSld( doc, ruleElem, props );
405 const auto constMChildren = mChildren;
406 for (
Rule *rule : constMChildren )
408 rule->toSld( doc, element, props );
414 mActiveChildren.clear();
427 mSymbol->startRender( context, fields );
431 QStringList subfilters;
432 const auto constMChildren = mChildren;
433 for (
Rule *rule : constMChildren )
436 if ( rule->startRender( context, fields, subfilter ) )
439 mActiveChildren.append( rule );
440 subfilters.append( subfilter );
448 if ( subfilters.length() > 1 || !subfilters.value( 0 ).isEmpty() )
450 if ( subfilters.contains( QStringLiteral(
"TRUE" ) ) )
452 sf = QStringLiteral(
"TRUE" );
456 else if ( subfilters.count() > 50 )
458 std::function<QString(
const QStringList & )>bt = [ &bt ](
const QStringList & subf )
460 if ( subf.count( ) == 1 )
464 else if ( subf.count( ) == 2 )
466 return subf.join( QLatin1String(
") OR (" ) ).prepend(
'(' ).append(
')' );
470 int midpos =
static_cast<int>( subf.length() / 2 );
471 return QStringLiteral(
"(%1) OR (%2)" ).arg( bt( subf.mid( 0, midpos ) ) ).arg( bt( subf.mid( midpos ) ) );
474 sf = bt( subfilters );
478 sf = subfilters.join( QLatin1String(
") OR (" ) ).prepend(
'(' ).append(
')' );
489 if ( mSymbol || sf.isEmpty() )
490 filter = QStringLiteral(
"TRUE" );
496 else if ( !mFilterExp.trimmed().isEmpty() && !sf.isEmpty() )
497 filter = QStringLiteral(
"(%1) AND (%2)" ).arg( mFilterExp, sf );
498 else if ( !mFilterExp.trimmed().isEmpty() )
500 else if ( sf.isEmpty() )
501 filter = QStringLiteral(
"TRUE" );
512 QSet<int> symbolZLevelsSet;
518 for (
int i = 0; i < mSymbol->symbolLayerCount(); i++ )
520 symbolZLevelsSet.insert( mSymbol->symbolLayer( i )->renderingPass() );
525 QList<Rule *>::iterator it;
526 for ( it = mActiveChildren.begin(); it != mActiveChildren.end(); ++it )
531 return symbolZLevelsSet;
538 for (
int i = 0; i < mSymbol->symbolLayerCount(); i++ )
540 int normLevel = zLevelsToNormLevels.value( mSymbol->symbolLayer( i )->renderingPass() );
541 mSymbolNormZLevels.insert( normLevel );
546 const auto constMActiveChildren = mActiveChildren;
547 for (
Rule *rule : constMActiveChildren )
549 rule->setNormZLevels( zLevelsToNormLevels );
556 if ( !isFilterOK( featToRender.
feat, &context ) )
559 bool rendered =
false;
562 if ( mSymbol && mIsActive )
565 const auto constMSymbolNormZLevels = mSymbolNormZLevels;
566 for (
int normZLevel : constMSymbolNormZLevels )
569 renderQueue[normZLevel].jobs.append(
new RenderJob( featToRender, mSymbol.get() ) );
574 bool willrendersomething =
false;
577 const auto constMChildren = mChildren;
578 for (
Rule *rule : constMChildren )
581 if ( !rule->isElse() )
583 RenderResult res = rule->renderFeature( featToRender, context, renderQueue );
585 willrendersomething |= ( res == Rendered || res == Inactive );
586 rendered |= ( res == Rendered );
591 if ( !willrendersomething )
593 const auto constMElseRules = mElseRules;
594 for (
Rule *rule : constMElseRules )
596 rendered |= rule->renderFeature( featToRender, context, renderQueue ) == Rendered;
599 if ( !mIsActive || ( mSymbol && !rendered ) )
609 if ( !isFilterOK( feature, context ) )
615 const auto constMActiveChildren = mActiveChildren;
616 for (
Rule *rule : constMActiveChildren )
618 if ( rule->isElse() )
620 if ( rule->children().isEmpty() )
622 RuleList lst = rulesForFeature( feature, context,
false );
623 lst.removeOne( rule );
632 return rule->willRenderFeature( feature, context );
635 else if ( rule->willRenderFeature( feature, context ) )
646 if ( !isFilterOK( feature, context ) )
649 lst.append( mSymbol.get() );
651 const auto constMActiveChildren = mActiveChildren;
652 for (
Rule *rule : constMActiveChildren )
654 lst += rule->symbolsForFeature( feature, context );
662 if ( !isFilterOK( feature, context ) )
664 lst.insert( mRuleKey );
666 const auto constMActiveChildren = mActiveChildren;
667 for (
Rule *rule : constMActiveChildren )
669 bool validKey =
false;
670 if ( rule->isElse() )
672 RuleList lst = rulesForFeature( feature, context,
false );
673 lst.removeOne( rule );
680 else if ( !rule->isElse( ) && rule->willRenderFeature( feature, context ) )
687 lst.unite( rule->legendKeysForFeature( feature, context ) );
696 if ( ! isFilterOK( feature, context ) || ( context && ! isScaleOK( context->
rendererScale() ) ) )
704 listChildren = mActiveChildren;
706 const auto constListChildren = listChildren;
707 for (
Rule *rule : constListChildren )
709 lst += rule->rulesForFeature( feature, context, onlyActive );
717 mSymbol->stopRender( context );
719 const auto constMActiveChildren = mActiveChildren;
720 for (
Rule *rule : constMActiveChildren )
722 rule->stopRender( context );
725 mActiveChildren.clear();
726 mSymbolNormZLevels.clear();
731 QString symbolIdx = ruleElem.attribute( QStringLiteral(
"symbol" ) );
733 if ( !symbolIdx.isEmpty() )
735 if ( symbolMap.contains( symbolIdx ) )
737 symbol = symbolMap.take( symbolIdx );
741 QgsDebugMsg(
"symbol for rule " + symbolIdx +
" not found!" );
745 QString filterExp = ruleElem.attribute( QStringLiteral(
"filter" ) );
746 QString label = ruleElem.attribute( QStringLiteral(
"label" ) );
747 QString description = ruleElem.attribute( QStringLiteral(
"description" ) );
748 int scaleMinDenom = ruleElem.attribute( QStringLiteral(
"scalemindenom" ), QStringLiteral(
"0" ) ).toInt();
749 int scaleMaxDenom = ruleElem.attribute( QStringLiteral(
"scalemaxdenom" ), QStringLiteral(
"0" ) ).toInt();
750 QString ruleKey = ruleElem.attribute( QStringLiteral(
"key" ) );
751 Rule *rule =
new Rule( symbol, scaleMinDenom, scaleMaxDenom, filterExp, label, description );
753 if ( !ruleKey.isEmpty() )
754 rule->mRuleKey = ruleKey;
756 rule->
setActive( ruleElem.attribute( QStringLiteral(
"checkstate" ), QStringLiteral(
"1" ) ).toInt() );
758 QDomElement childRuleElem = ruleElem.firstChildElement( QStringLiteral(
"rule" ) );
759 while ( !childRuleElem.isNull() )
761 Rule *childRule =
create( childRuleElem, symbolMap );
768 QgsDebugMsg( QStringLiteral(
"failed to init a child rule!" ) );
770 childRuleElem = childRuleElem.nextSiblingElement( QStringLiteral(
"rule" ) );
782 l +=
c->descendants();
789 if ( ruleElem.localName() != QLatin1String(
"Rule" ) )
791 QgsDebugMsg( QStringLiteral(
"invalid element: Rule element expected, %1 found!" ).arg( ruleElem.tagName() ) );
795 QString label, description, filterExp;
796 int scaleMinDenom = 0, scaleMaxDenom = 0;
800 QDomElement childElem = ruleElem.firstChildElement();
801 while ( !childElem.isNull() )
803 if ( childElem.localName() == QLatin1String(
"Name" ) )
807 if ( label.isEmpty() )
808 label = childElem.firstChild().nodeValue();
810 else if ( childElem.localName() == QLatin1String(
"Description" ) )
813 QDomElement titleElem = childElem.firstChildElement( QStringLiteral(
"Title" ) );
814 if ( !titleElem.isNull() )
816 label = titleElem.firstChild().nodeValue();
819 QDomElement abstractElem = childElem.firstChildElement( QStringLiteral(
"Abstract" ) );
820 if ( !abstractElem.isNull() )
822 description = abstractElem.firstChild().nodeValue();
825 else if ( childElem.localName() == QLatin1String(
"Abstract" ) )
828 description = childElem.firstChild().nodeValue();
830 else if ( childElem.localName() == QLatin1String(
"Title" ) )
833 label = childElem.firstChild().nodeValue();
835 else if ( childElem.localName() == QLatin1String(
"Filter" ) )
840 if (
filter->hasParserError() )
846 filterExp =
filter->expression();
851 else if ( childElem.localName() == QLatin1String(
"MinScaleDenominator" ) )
854 int v = childElem.firstChild().nodeValue().toInt( &ok );
858 else if ( childElem.localName() == QLatin1String(
"MaxScaleDenominator" ) )
861 int v = childElem.firstChild().nodeValue().toInt( &ok );
865 else if ( childElem.localName().endsWith( QLatin1String(
"Symbolizer" ) ) )
871 childElem = childElem.nextSiblingElement();
876 if ( !layers.isEmpty() )
893 QgsDebugMsg( QStringLiteral(
"invalid geometry type: found %1" ).arg( geomType ) );
899 return new Rule( symbol, scaleMinDenom, scaleMaxDenom, filterExp, label, description );
934 bool drawVertexMarker )
954 QList<int> symbolZLevels = qgis::setToList( symbolZLevelsSet );
955 std::sort( symbolZLevels.begin(), symbolZLevels.end() );
959 QMap<int, int> zLevelsToNormLevels;
960 int maxNormLevel = -1;
961 const auto constSymbolZLevels = symbolZLevels;
962 for (
int zLevel : constSymbolZLevels )
964 zLevelsToNormLevels[zLevel] = ++maxNormLevel;
966 QgsDebugMsgLevel( QStringLiteral(
"zLevel %1 -> %2" ).arg( zLevel ).arg( maxNormLevel ), 4 );
984 for (
const RenderLevel &level : constMRenderQueue )
988 for (
const RenderJob *job : qgis::as_const( level.jobs ) )
995 for (
int i = 0; i < count; i++ )
1002 int flags = job->ftr.flags;
1044 Q_ASSERT( origDescendants.count() == clonedDescendants.count() );
1045 for (
int i = 0; i < origDescendants.count(); ++i )
1046 clonedDescendants[i]->setRuleKey( origDescendants[i]->ruleKey() );
1069 rendererElem.setAttribute( QStringLiteral(
"type" ), QStringLiteral(
"RuleRenderer" ) );
1070 rendererElem.setAttribute( QStringLiteral(
"symbollevels" ), (
mUsingSymbolLevels ? QStringLiteral(
"1" ) : QStringLiteral(
"0" ) ) );
1071 rendererElem.setAttribute( QStringLiteral(
"forceraster" ), (
mForceRaster ? QStringLiteral(
"1" ) : QStringLiteral(
"0" ) ) );
1076 rulesElem.setTagName( QStringLiteral(
"rules" ) );
1077 rendererElem.appendChild( rulesElem );
1080 rendererElem.appendChild( symbolsElem );
1087 QDomElement
orderBy = doc.createElement( QStringLiteral(
"orderby" ) );
1089 rendererElem.appendChild(
orderBy );
1091 rendererElem.setAttribute( QStringLiteral(
"enableorderby" ), (
mOrderByEnabled ? QStringLiteral(
"1" ) : QStringLiteral(
"0" ) ) );
1093 return rendererElem;
1104 return rule ? rule->
active() :
true;
1132 QDomElement symbolsElem = element.firstChildElement( QStringLiteral(
"symbols" ) );
1133 if ( symbolsElem.isNull() )
1138 QDomElement rulesElem = element.firstChildElement( QStringLiteral(
"rules" ) );
1155 Rule *root =
nullptr;
1157 QDomElement ruleElem = element.firstChildElement( QStringLiteral(
"Rule" ) );
1158 while ( !ruleElem.isNull() )
1165 root =
new Rule(
nullptr );
1170 ruleElem = ruleElem.nextSiblingElement( QStringLiteral(
"Rule" ) );
1198 const auto constCategories = r->
categories();
1203 if ( cat.value().type() == QVariant::Int )
1204 value = cat.value().toString();
1205 else if ( cat.value().type() == QVariant::Double )
1208 value = QString::number( cat.value().toDouble(),
'f', 4 );
1211 QString
filter = QStringLiteral(
"%1 = %2" ).arg( attr, value );
1228 else if ( !testExpr.
isField() )
1231 attr = QStringLiteral(
"(%1)" ).arg( attr );
1234 bool firstRange =
true;
1235 const auto constRanges = r->
ranges();
1240 QString
filter = QStringLiteral(
"%1 %2 %3 AND %1 <= %4" ).arg( attr, firstRange ? QStringLiteral(
">=" ) : QStringLiteral(
">" ),
1241 QString::number( rng.lowerValue(),
'f', 4 ),
1242 QString::number( rng.upperValue(),
'f', 4 ) );
1244 QString label = rng.label().isEmpty() ?
filter : rng.label();
1251 std::sort( scales.begin(), scales.end() );
1255 const auto constScales = scales;
1256 for (
int scale : constScales )
1260 if ( maxDenom != 0 && maxDenom <= scale )
1262 initialRule->
appendChild(
new Rule( symbol->
clone(), oldScale, scale, QString(), QStringLiteral(
"%1 - %2" ).arg( oldScale ).arg( scale ) ) );
1266 initialRule->
appendChild(
new Rule( symbol->
clone(), oldScale, maxDenom, QString(), QStringLiteral(
"%1 - %2" ).arg( oldScale ).arg( maxDenom ) ) );
1271 QString msg( QStringLiteral(
"Rule-based renderer:\n" ) );
1303 std::unique_ptr< QgsRuleBasedRenderer > r;
1304 if ( renderer->
type() == QLatin1String(
"RuleRenderer" ) )
1308 else if ( renderer->
type() == QLatin1String(
"singleSymbol" ) )
1311 if ( !singleSymbolRenderer )
1314 std::unique_ptr< QgsSymbol > origSymbol( singleSymbolRenderer->
symbol()->
clone() );
1315 r = qgis::make_unique< QgsRuleBasedRenderer >( origSymbol.release() );
1317 else if ( renderer->
type() == QLatin1String(
"categorizedSymbol" ) )
1320 if ( !categorizedRenderer )
1333 std::unique_ptr< QgsRuleBasedRenderer::Rule > rootrule = qgis::make_unique< QgsRuleBasedRenderer::Rule >(
nullptr );
1340 std::unique_ptr< QgsRuleBasedRenderer::Rule > rule = qgis::make_unique< QgsRuleBasedRenderer::Rule >(
nullptr );
1342 rule->setLabel( category.
label() );
1345 if ( category.
value().type() == QVariant::List )
1348 const QVariantList list = category.
value().toList();
1349 for (
const QVariant &v : list )
1352 if ( QVariant( v ).convert( QVariant::Double ) )
1354 values << v.toString();
1362 if ( values.empty() )
1364 expression = QStringLiteral(
"ELSE" );
1368 expression = QStringLiteral(
"%1 IN (%2)" ).arg( attr, values.join(
',' ) );
1374 if ( category.
value().convert( QVariant::Double ) )
1376 value = category.
value().toString();
1384 if ( value == QLatin1String(
"''" ) )
1386 expression = QStringLiteral(
"ELSE" );
1390 expression = QStringLiteral(
"%1 = %2" ).arg( attr, value );
1393 rule->setFilterExpression( expression );
1399 std::unique_ptr< QgsSymbol > origSymbol( category.
symbol()->
clone() );
1400 rule->setSymbol( origSymbol.release() );
1402 rootrule->appendChild( rule.release() );
1405 r = qgis::make_unique< QgsRuleBasedRenderer >( rootrule.release() );
1407 else if ( renderer->
type() == QLatin1String(
"graduatedSymbol" ) )
1410 if ( !graduatedRenderer )
1422 else if ( !testExpr.
isField() )
1425 attr = QStringLiteral(
"(%1)" ).arg( attr );
1428 std::unique_ptr< QgsRuleBasedRenderer::Rule > rootrule = qgis::make_unique< QgsRuleBasedRenderer::Rule >(
nullptr );
1432 for (
int i = 0; i < graduatedRenderer->
ranges().size(); ++i )
1434 range = graduatedRenderer->
ranges().value( i );
1435 std::unique_ptr< QgsRuleBasedRenderer::Rule > rule = qgis::make_unique< QgsRuleBasedRenderer::Rule >(
nullptr );
1436 rule->setLabel( range.
label() );
1439 expression = attr +
" >= " + QString::number( range.
lowerValue(),
'f' ) +
" AND " + \
1440 attr +
" <= " + QString::number( range.
upperValue(),
'f' );
1444 expression = attr +
" > " + QString::number( range.
lowerValue(),
'f' ) +
" AND " + \
1445 attr +
" <= " + QString::number( range.
upperValue(),
'f' );
1447 rule->setFilterExpression( expression );
1453 std::unique_ptr< QgsSymbol > symbol( range.
symbol()->
clone() );
1454 rule->setSymbol( symbol.release() );
1456 rootrule->appendChild( rule.release() );
1459 r = qgis::make_unique< QgsRuleBasedRenderer >( rootrule.release() );
1461 else if ( renderer->
type() == QLatin1String(
"pointDisplacement" ) || renderer->
type() == QLatin1String(
"pointCluster" ) )
1464 if ( pointDistanceRenderer )
1467 else if ( renderer->
type() == QLatin1String(
"invertedPolygonRenderer" ) )
1470 if ( invertedPolygonRenderer )
1485 QString sizeExpression;
1486 switch ( symbol->
type() )
1492 if ( ! sizeScaleField.isEmpty() )
1494 sizeExpression = QStringLiteral(
"%1*(%2)" ).arg( msl->
size() ).arg( sizeScaleField );
1497 if ( ! rotationField.isEmpty() )
1504 if ( ! sizeScaleField.isEmpty() )
1511 sizeExpression = QStringLiteral(
"%1*(%2)" ).arg( lsl->
width() ).arg( sizeScaleField );
1520 sizeExpression = QStringLiteral(
"%1*(%2)" ).arg( msl->
size() ).arg( sizeScaleField );