Ensure atlas expression evaluation has access to coverage layer scope

Fixes #31807
This commit is contained in:
Nyall Dawson 2019-09-17 15:01:14 +10:00
parent 421e68cf5a
commit 3de0593957
4 changed files with 35 additions and 6 deletions

View File

@ -8,7 +8,7 @@
class QgsLayoutAtlas : QObject, QgsAbstractLayoutIterator, QgsLayoutSerializableObject
class QgsLayoutAtlas : QObject, QgsAbstractLayoutIterator, QgsLayoutSerializableObject, QgsExpressionContextGenerator
{
%Docstring
Class used to render QgsLayout as an atlas, by iterating over the features from an associated vector layer.
@ -277,6 +277,9 @@ number of matching features.
Returns the current feature number, where a value of 0 corresponds to the first feature.
%End
virtual QgsExpressionContext createExpressionContext() const;
public slots:
virtual bool next();

View File

@ -439,7 +439,7 @@ QString QgsLayoutAtlas::currentFilename() const
return mCurrentFilename;
}
QgsExpressionContext QgsLayoutAtlas::createExpressionContext()
QgsExpressionContext QgsLayoutAtlas::createExpressionContext() const
{
QgsExpressionContext expressionContext;
expressionContext << QgsExpressionContextUtils::globalScope();
@ -447,10 +447,10 @@ QgsExpressionContext QgsLayoutAtlas::createExpressionContext()
expressionContext << QgsExpressionContextUtils::projectScope( mLayout->project() )
<< QgsExpressionContextUtils::layoutScope( mLayout );
expressionContext.appendScope( QgsExpressionContextUtils::atlasScope( this ) );
expressionContext.appendScope( QgsExpressionContextUtils::atlasScope( const_cast< QgsLayoutAtlas * >( this ) ) );
if ( mCoverageLayer )
expressionContext.lastScope()->setFields( mCoverageLayer->fields() );
expressionContext.appendScope( mCoverageLayer->createExpressionContextScope() );
if ( mLayout && mEnabled )
expressionContext.lastScope()->setFeature( mCurrentFeature );

View File

@ -20,6 +20,7 @@
#include "qgsvectorlayerref.h"
#include "qgslayoutserializableobject.h"
#include "qgsabstractlayoutiterator.h"
#include "qgsexpressioncontextgenerator.h"
#include <QObject>
class QgsLayout;
@ -37,7 +38,7 @@ class QgsLayout;
*
* \since QGIS 3.0
*/
class CORE_EXPORT QgsLayoutAtlas : public QObject, public QgsAbstractLayoutIterator, public QgsLayoutSerializableObject
class CORE_EXPORT QgsLayoutAtlas : public QObject, public QgsAbstractLayoutIterator, public QgsLayoutSerializableObject, public QgsExpressionContextGenerator
{
Q_OBJECT
public:
@ -252,6 +253,8 @@ class CORE_EXPORT QgsLayoutAtlas : public QObject, public QgsAbstractLayoutItera
*/
int currentFeatureNumber() const { return mCurrentFeatureNo; }
QgsExpressionContext createExpressionContext() const override;
public slots:
bool next() override;
@ -390,7 +393,6 @@ class CORE_EXPORT QgsLayoutAtlas : public QObject, public QgsAbstractLayoutItera
int mCurrentFeatureNo = -1;
QgsFeature mCurrentFeature;
QgsExpressionContext createExpressionContext();
friend class AtlasFeatureSorter;
};

View File

@ -67,6 +67,8 @@ class TestQgsLayoutAtlas : public QObject
// test removing coverage layer while atlas is enabled
void test_remove_layer();
void context();
private:
QgsPrintLayout *mLayout = nullptr;
QgsLayoutItemLabel *mLabel1 = nullptr;
@ -426,5 +428,27 @@ void TestQgsLayoutAtlas::test_remove_layer()
QVERIFY( spyToggled.count() == 1 );
}
void TestQgsLayoutAtlas::context()
{
std::unique_ptr< QgsVectorLayer> vl2( new QgsVectorLayer( QStringLiteral( "Point?crs=epsg:4326&field=id:integer&field=labelx:integer" ), QStringLiteral( "vl" ), QStringLiteral( "memory" ) ) );
QgsFeature f;
QVERIFY( vl2->dataProvider()->addFeature( f ) );
QgsFeature f2;
QVERIFY( vl2->dataProvider()->addFeature( f2 ) );
mAtlas->setCoverageLayer( vl2.get() );
mAtlas->setEnabled( true );
QgsExpressionContext context = mAtlas->createExpressionContext();
QVERIFY( context.hasVariable( QStringLiteral( "project_title" ) ) );
QVERIFY( context.hasVariable( QStringLiteral( "layout_name" ) ) );
QVERIFY( context.hasVariable( QStringLiteral( "atlas_totalfeatures" ) ) );
QVERIFY( context.hasVariable( QStringLiteral( "layer_id" ) ) );
QCOMPARE( context.fields().at( 1 ).name(), QStringLiteral( "labelx" ) );
QVERIFY( context.hasFeature() );
mAtlas->setCoverageLayer( nullptr );
}
QGSTEST_MAIN( TestQgsLayoutAtlas )
#include "testqgslayoutatlas.moc"