diff --git a/python/core/processing/qgsprocessingalgorithm.sip b/python/core/processing/qgsprocessingalgorithm.sip index 7f1d31cc19c..42a8fae6664 100644 --- a/python/core/processing/qgsprocessingalgorithm.sip +++ b/python/core/processing/qgsprocessingalgorithm.sip @@ -326,10 +326,12 @@ class QgsProcessingAlgorithm %End QgsExpressionContext createExpressionContext( const QVariantMap ¶meters, - QgsProcessingContext &context ) const; + QgsProcessingContext &context, QgsProcessingFeatureSource *source = 0 ) const; %Docstring Creates an expression context relating to the algorithm. This can be called by algorithms to create a new expression context ready for evaluating expressions within the algorithm. + Optionally, a ``source`` can be specified which will be used to populate the context if it + implements the QgsExpressionContextGenerator interface. :rtype: QgsExpressionContext %End diff --git a/python/core/processing/qgsprocessingutils.sip b/python/core/processing/qgsprocessingutils.sip index a92ff8803b0..88561de42cc 100644 --- a/python/core/processing/qgsprocessingutils.sip +++ b/python/core/processing/qgsprocessingutils.sip @@ -274,6 +274,12 @@ class QgsProcessingFeatureSource : QgsFeatureSource virtual QVariant maximumValue( int fieldIndex ) const; + QgsFeatureSource *source() const; +%Docstring + Access the underlying original ``source``. + :rtype: QgsFeatureSource +%End + }; diff --git a/python/core/qgsexpressioncontext.sip b/python/core/qgsexpressioncontext.sip index 9d206046912..84e48805314 100644 --- a/python/core/qgsexpressioncontext.sip +++ b/python/core/qgsexpressioncontext.sip @@ -562,6 +562,7 @@ Constructor for QgsExpressionContext %End + void setFeature( const QgsFeature &feature ); %Docstring Convenience function for setting a feature for the context. The feature diff --git a/src/core/processing/qgsprocessingalgorithm.cpp b/src/core/processing/qgsprocessingalgorithm.cpp index 383c6010f4b..ec103f09b58 100644 --- a/src/core/processing/qgsprocessingalgorithm.cpp +++ b/src/core/processing/qgsprocessingalgorithm.cpp @@ -124,16 +124,30 @@ QWidget *QgsProcessingAlgorithm::createCustomParametersWidget( QWidget * ) const } QgsExpressionContext QgsProcessingAlgorithm::createExpressionContext( const QVariantMap ¶meters, - QgsProcessingContext &context ) const + QgsProcessingContext &context, QgsProcessingFeatureSource *source ) const { // start with context's expression context QgsExpressionContext c = context.expressionContext(); - if ( c.scopeCount() == 0 ) + + // If there's a source capable of generating a context scope, use it + if ( source ) { - //empty scope, populate with initial scopes - c << QgsExpressionContextUtils::globalScope() - << QgsExpressionContextUtils::projectScope( context.project() ); + QgsExpressionContextGenerator *generator = dynamic_cast( source->source() ); + if ( generator ) + { + const auto &scopes = generator->createExpressionContext().takeScopes(); + for ( QgsExpressionContextScope *scope : scopes ) + c << scope; + } } + else + + if ( c.scopeCount() == 0 ) + { + //empty scope, populate with initial scopes + c << QgsExpressionContextUtils::globalScope() + << QgsExpressionContextUtils::projectScope( context.project() ); + } c << QgsExpressionContextUtils::processingAlgorithmScope( this, parameters, context ); return c; diff --git a/src/core/processing/qgsprocessingalgorithm.h b/src/core/processing/qgsprocessingalgorithm.h index 63cf78b1a18..126bda28ef5 100644 --- a/src/core/processing/qgsprocessingalgorithm.h +++ b/src/core/processing/qgsprocessingalgorithm.h @@ -339,9 +339,11 @@ class CORE_EXPORT QgsProcessingAlgorithm /** * Creates an expression context relating to the algorithm. This can be called by algorithms * to create a new expression context ready for evaluating expressions within the algorithm. + * Optionally, a \a source can be specified which will be used to populate the context if it + * implements the QgsExpressionContextGenerator interface. */ QgsExpressionContext createExpressionContext( const QVariantMap ¶meters, - QgsProcessingContext &context ) const; + QgsProcessingContext &context, QgsProcessingFeatureSource *source = nullptr ) const; /** * Checks whether the coordinate reference systems for the specified set of \a parameters diff --git a/src/core/processing/qgsprocessingutils.cpp b/src/core/processing/qgsprocessingutils.cpp index a4ab12d88e0..5d30a90349f 100644 --- a/src/core/processing/qgsprocessingutils.cpp +++ b/src/core/processing/qgsprocessingutils.cpp @@ -695,3 +695,8 @@ QVariant QgsProcessingFeatureSource::maximumValue( int fieldIndex ) const { return mSource->maximumValue( fieldIndex ); } + +QgsFeatureSource *QgsProcessingFeatureSource::source() const +{ + return mSource; +} diff --git a/src/core/processing/qgsprocessingutils.h b/src/core/processing/qgsprocessingutils.h index e1ed6674529..8d3654451a4 100644 --- a/src/core/processing/qgsprocessingutils.h +++ b/src/core/processing/qgsprocessingutils.h @@ -317,6 +317,11 @@ class CORE_EXPORT QgsProcessingFeatureSource : public QgsFeatureSource QVariant minimumValue( int fieldIndex ) const override; QVariant maximumValue( int fieldIndex ) const override; + /** + * Access the underlying original \a source. + */ + QgsFeatureSource *source() const; + private: QgsFeatureSource *mSource = nullptr; diff --git a/src/core/qgsexpressioncontext.cpp b/src/core/qgsexpressioncontext.cpp index 3b45ecc08e0..5f686058eb1 100644 --- a/src/core/qgsexpressioncontext.cpp +++ b/src/core/qgsexpressioncontext.cpp @@ -474,6 +474,13 @@ QgsExpressionContextScope *QgsExpressionContext::popScope() return nullptr; } +QList QgsExpressionContext::takeScopes() +{ + QList stack = mStack; + mStack.clear(); + return stack; +} + QgsExpressionContext &QgsExpressionContext::operator<<( QgsExpressionContextScope *scope ) { mStack.append( scope ); diff --git a/src/core/qgsexpressioncontext.h b/src/core/qgsexpressioncontext.h index fbbbd404a8d..b958054632b 100644 --- a/src/core/qgsexpressioncontext.h +++ b/src/core/qgsexpressioncontext.h @@ -581,6 +581,16 @@ class CORE_EXPORT QgsExpressionContext */ QgsExpressionContextScope *popScope(); + /** + * Return all scopes from this context and remove them, leaving this context without + * any context. + * Ownership is transferred to the caller. + * + * \since QGIS 3.0 + * \note Not available in Python + */ + QList takeScopes() SIP_SKIP; + /** * Appends a scope to the end of the context. This scope will override * any matching variables or functions provided by existing scopes within the