Added QgsRenderContext arg to referencedFields() + unit tests

This commit is contained in:
Martin Dobias 2020-04-13 18:46:22 +02:00 committed by Nyall Dawson
parent 8ec0dc53fe
commit 8c488b4ef0
9 changed files with 57 additions and 11 deletions

View File

@ -321,7 +321,7 @@ names which the labeling requires for the rendering.
.. versionadded:: 3.8
%End
QSet<QString> referencedFields() const;
QSet<QString> referencedFields( const QgsRenderContext &context ) const;
%Docstring
Returns all field names referenced by the configuration (e.g. field name or expression, data defined properties).

View File

@ -483,7 +483,7 @@ bool QgsPalLayerSettings::prepare( QgsRenderContext &context, QSet<QString> &att
return true;
}
QSet<QString> QgsPalLayerSettings::referencedFields() const
QSet<QString> QgsPalLayerSettings::referencedFields( const QgsRenderContext &context ) const
{
QSet<QString> referenced;
if ( drawLabels )
@ -498,7 +498,10 @@ QSet<QString> QgsPalLayerSettings::referencedFields() const
}
}
referenced.unite( mDataDefinedProperties.referencedFields( QgsExpressionContext(), true ) );
// calling referencedFields() with ignoreContext=true because in our expression context
// we do not have valid QgsFields yet - because of that the field names from expressions
// wouldn't get reported
referenced.unite( mDataDefinedProperties.referencedFields( context.expressionContext(), true ) );
if ( geometryGeneratorEnabled )
{
@ -508,8 +511,7 @@ QSet<QString> QgsPalLayerSettings::referencedFields() const
if ( mCallout )
{
// TODO: this needs further attention
referenced.unite( mCallout->referencedFields( QgsRenderContext() ) );
referenced.unite( mCallout->referencedFields( context ) );
}
return referenced;

View File

@ -479,7 +479,7 @@ class CORE_EXPORT QgsPalLayerSettings
* Returns all field names referenced by the configuration (e.g. field name or expression, data defined properties).
* \since QGIS 3.14
*/
QSet<QString> referencedFields() const;
QSet<QString> referencedFields( const QgsRenderContext &context ) const;
/**
* Prepares the label settings for rendering.

View File

@ -123,7 +123,7 @@ QgsVectorTileBasicLabelProvider::QgsVectorTileBasicLabelProvider( QgsVectorTileL
}
}
QMap<QString, QSet<QString> > QgsVectorTileBasicLabelProvider::usedAttributes( int tileZoom ) const
QMap<QString, QSet<QString> > QgsVectorTileBasicLabelProvider::usedAttributes( const QgsRenderContext &context, int tileZoom ) const
{
QMap<QString, QSet<QString> > requiredFields;
for ( const QgsVectorTileBasicLabelingStyle &layerStyle : qgis::as_const( mStyles ) )
@ -137,7 +137,7 @@ QMap<QString, QSet<QString> > QgsVectorTileBasicLabelProvider::usedAttributes( i
requiredFields[layerStyle.layerName()].unite( expr.referencedColumns() );
}
requiredFields[layerStyle.layerName()].unite( layerStyle.labelSettings().referencedFields() );
requiredFields[layerStyle.layerName()].unite( layerStyle.labelSettings().referencedFields( context ) );
}
return requiredFields;
}

View File

@ -142,8 +142,10 @@ class QgsVectorTileBasicLabelProvider : public QgsVectorTileLabelProvider
QList<QgsAbstractLabelProvider *> subProviders() override;
bool prepare( QgsRenderContext &context, QSet<QString> &attributeNames ) override;
// virtual functions from QgsVectorTileLabelProvider
void registerTileFeatures( const QgsVectorTileRendererData &tile, QgsRenderContext &context ) override;
QMap<QString, QSet<QString> > usedAttributes( int tileZoom ) const override;
QMap<QString, QSet<QString> > usedAttributes( const QgsRenderContext &context, int tileZoom ) const override;
void setFields( const QMap<QString, QSet<QString>> &requiredFields ) override;
private:

View File

@ -37,7 +37,7 @@ class QgsVectorTileLabelProvider : public QgsVectorLayerLabelProvider
explicit QgsVectorTileLabelProvider( QgsVectorTileLayer *layer );
//! Returns field names for each sub-layer that are required for labeling
virtual QMap<QString, QSet<QString> > usedAttributes( int tileZoom ) const = 0;
virtual QMap<QString, QSet<QString> > usedAttributes( const QgsRenderContext &context, int tileZoom ) const = 0;
//! Sets required fields
virtual void setFields( const QMap<QString, QSet<QString>> &requiredFields ) = 0;

View File

@ -124,7 +124,7 @@ bool QgsVectorTileLayerRenderer::render()
if ( mLabelProvider )
{
QMap<QString, QSet<QString> > requiredFieldsLabeling = mLabelProvider->usedAttributes( mTileZoom );
QMap<QString, QSet<QString> > requiredFieldsLabeling = mLabelProvider->usedAttributes( ctx, mTileZoom );
for ( QString layerName : requiredFieldsLabeling.keys() )
{
requiredFields[layerName].unite( requiredFieldsLabeling[layerName] );

View File

@ -79,6 +79,7 @@ class TestQgsLabelingEngine : public QObject
void testRotationBasedOrientationLine();
void testMapUnitLetterSpacing();
void testMapUnitWordSpacing();
void testReferencedFields();
private:
QgsVectorLayer *vl = nullptr;
@ -2631,5 +2632,22 @@ void TestQgsLabelingEngine::testMapUnitWordSpacing()
QVERIFY( imageCheck( QStringLiteral( "label_word_spacing_map_units" ), img, 20 ) );
}
void TestQgsLabelingEngine::testReferencedFields()
{
QgsPalLayerSettings settings;
settings.fieldName = QStringLiteral( "hello+world" );
settings.isExpression = false;
QCOMPARE( settings.referencedFields( QgsRenderContext() ), QSet<QString>() << QStringLiteral( "hello+world" ) );
settings.isExpression = true;
QCOMPARE( settings.referencedFields( QgsRenderContext() ), QSet<QString>() << QStringLiteral( "hello" ) << QStringLiteral( "world" ) );
settings.dataDefinedProperties().setProperty( QgsPalLayerSettings::Size, QgsProperty::fromField( QStringLiteral( "my_dd_size" ) ) );
QCOMPARE( settings.referencedFields( QgsRenderContext() ), QSet<QString>() << QStringLiteral( "hello" ) << QStringLiteral( "world" ) << QStringLiteral( "my_dd_size" ) );
}
QGSTEST_MAIN( TestQgsLabelingEngine )
#include "testqgslabelingengine.moc"

View File

@ -94,6 +94,7 @@ class TestQgsProperty : public QObject
void curveTransform();
void asVariant();
void isProjectColor();
void referencedFieldsIgnoreContext();
private:
@ -1803,6 +1804,29 @@ void TestQgsProperty::isProjectColor()
QVERIFY( p.isProjectColor() );
}
void TestQgsProperty::referencedFieldsIgnoreContext()
{
// Currently QgsProperty::referencedFields() for an expression will return field names
// only if those field names are present in the context's fields. The ignoreContext
// argument is a workaround for the case when we don't have fields yet.
QgsProperty p = QgsProperty::fromExpression( QStringLiteral( "foo + bar" ) );
QCOMPARE( p.referencedFields( QgsExpressionContext() ), QSet<QString>() );
QCOMPARE( p.referencedFields( QgsExpressionContext(), true ), QSet<QString>() << QStringLiteral( "foo" ) << QStringLiteral( "bar" ) );
// if the property is from a field, the ignoreContext does not make a difference
QgsProperty p2 = QgsProperty::fromField( QStringLiteral( "boo" ) );
QCOMPARE( p2.referencedFields( QgsExpressionContext() ), QSet<QString>() << QStringLiteral( "boo" ) );
QCOMPARE( p2.referencedFields( QgsExpressionContext(), true ), QSet<QString>() << QStringLiteral( "boo" ) );
QgsPropertyCollection collection;
collection.setProperty( 0, p );
collection.setProperty( 1, p2 );
QCOMPARE( collection.referencedFields( QgsExpressionContext() ), QSet<QString>() << QStringLiteral( "boo" ) );
QCOMPARE( collection.referencedFields( QgsExpressionContext(), true ), QSet<QString>() << QStringLiteral( "boo" ) << QStringLiteral( "foo" ) << QStringLiteral( "bar" ) );
}
void TestQgsProperty::checkCurveResult( const QList<QgsPointXY> &controlPoints, const QVector<double> &x, const QVector<double> &y )
{
// build transform