Skip to content

Commit

Permalink
Expression context fixes:
Browse files Browse the repository at this point in the history
- Fix python API break in QgsExpression::Function
- Add convenience methods for retrieving feature/fields from a
context
  • Loading branch information
nyalldawson committed Sep 5, 2015
1 parent 8611543 commit 1c079ea
Show file tree
Hide file tree
Showing 6 changed files with 47 additions and 4 deletions.
3 changes: 2 additions & 1 deletion python/core/qgsexpression.sip
Expand Up @@ -290,8 +290,9 @@ class QgsExpression
* @param context context expression is being evaluated against
* @param parent parent expression
* @returns result of function
* @note named funcV2 in Python bindings. Will be renamed to func to replace deprecated method in QGIS 3.0.
*/
virtual QVariant func( const QVariantList& values, const QgsExpressionContext* context, QgsExpression* parent );
virtual QVariant func( const QVariantList& values, const QgsExpressionContext* context, QgsExpression* parent ) /PyName=funcV2/;

virtual bool handlesNull() const;
};
Expand Down
12 changes: 12 additions & 0 deletions python/core/qgsexpressioncontext.sip
Expand Up @@ -346,16 +346,28 @@ class QgsExpressionContext
* will be set within the last scope of the context, so will override any
* existing features within the context.
* @param feature feature for context
* @see feature()
*/
void setFeature( const QgsFeature& feature );

/** Convenience function for retrieving the feature for the context, if set.
* @see setFeature
*/
QgsFeature feature() const;

/** Convenience function for setting a fields for the context. The fields
* will be set within the last scope of the context, so will override any
* existing fields within the context.
* @param fields fields for context
* @see fields()
*/
void setFields( const QgsFields& fields );

/** Convenience function for retrieving the fields for the context, if set.
* @see setFields
*/
QgsFields fields() const;

};

/** \ingroup core
Expand Down
8 changes: 5 additions & 3 deletions src/core/qgsexpression.h
Expand Up @@ -399,7 +399,9 @@ class CORE_EXPORT QgsExpression
* @param context context expression is being evaluated against
* @param parent parent expression
* @returns result of function
* @note named funcV2 in Python bindings. Will be renamed to func to replace deprecated method in QGIS 3.0.
*/
//TODO QGIS 3.0 - rename python method
virtual QVariant func( const QVariantList& values, const QgsExpressionContext* context, QgsExpression* parent );

bool operator==( const Function& other ) const
Expand Down Expand Up @@ -752,10 +754,10 @@ class CORE_EXPORT QgsExpression

virtual QStringList referencedColumns() const override { QStringList lst( mNode->referencedColumns() ); foreach ( Node* n, mList->list() ) lst.append( n->referencedColumns() ); return lst; }
virtual bool needsGeometry() const override { bool needs = false; foreach ( Node* n, mList->list() ) needs |= n->needsGeometry(); return needs; }
virtual void accept( Visitor& v ) const override { v.visit( *this ); }
virtual void accept( Visitor& v ) const override { v.visit( *this ); }

protected:
Node* mNode;
protected:
Node* mNode;
NodeList* mList;
bool mNotIn;
};
Expand Down
10 changes: 10 additions & 0 deletions src/core/qgsexpressioncontext.cpp
Expand Up @@ -350,6 +350,11 @@ void QgsExpressionContext::setFeature( const QgsFeature &feature )
mStack.last()->setFeature( feature );
}

QgsFeature QgsExpressionContext::feature() const
{
return qvariant_cast<QgsFeature>( variable( QgsExpressionContext::EXPR_FEATURE ) );
}

void QgsExpressionContext::setFields( const QgsFields &fields )
{
if ( mStack.isEmpty() )
Expand All @@ -358,6 +363,11 @@ void QgsExpressionContext::setFields( const QgsFields &fields )
mStack.last()->setFields( fields );
}

QgsFields QgsExpressionContext::fields() const
{
return qvariant_cast<QgsFields>( variable( QgsExpressionContext::EXPR_FIELDS ) );
}


//
// QgsExpressionContextUtils
Expand Down
12 changes: 12 additions & 0 deletions src/core/qgsexpressioncontext.h
Expand Up @@ -378,16 +378,28 @@ class CORE_EXPORT QgsExpressionContext
* will be set within the last scope of the context, so will override any
* existing features within the context.
* @param feature feature for context
* @see feature()
*/
void setFeature( const QgsFeature& feature );

/** Convenience function for retrieving the feature for the context, if set.
* @see setFeature
*/
QgsFeature feature() const;

/** Convenience function for setting a fields for the context. The fields
* will be set within the last scope of the context, so will override any
* existing fields within the context.
* @param fields fields for context
* @see fields()
*/
void setFields( const QgsFields& fields );

/** Convenience function for retrieving the fields for the context, if set.
* @see setFields
*/
QgsFields fields() const;

static const QString EXPR_FIELDS;
static const QString EXPR_FEATURE;

Expand Down
6 changes: 6 additions & 0 deletions tests/src/core/testqgsexpressioncontext.cpp
Expand Up @@ -411,18 +411,21 @@ void TestQgsExpressionContext::setFeature()

//test setting a feature in a context with no scopes
QgsExpressionContext emptyContext;
QVERIFY( !emptyContext.feature().isValid() );
emptyContext.setFeature( feature );
//setFeature should have created a scope
QCOMPARE( emptyContext.scopeCount(), 1 );
QVERIFY( emptyContext.hasVariable( QgsExpressionContext::EXPR_FEATURE ) );
QCOMPARE(( qvariant_cast<QgsFeature>( emptyContext.variable( QgsExpressionContext::EXPR_FEATURE ) ) ).id(), 50LL );
QCOMPARE( emptyContext.feature(), feature() );

QgsExpressionContext contextWithScope;
contextWithScope << new QgsExpressionContextScope();
contextWithScope.setFeature( feature );
QCOMPARE( contextWithScope.scopeCount(), 1 );
QVERIFY( contextWithScope.hasVariable( QgsExpressionContext::EXPR_FEATURE ) );
QCOMPARE(( qvariant_cast<QgsFeature>( contextWithScope.variable( QgsExpressionContext::EXPR_FEATURE ) ) ).id(), 50LL );
QCOMPARE( contextWithScope.feature(), feature() );
}

void TestQgsExpressionContext::setFields()
Expand All @@ -438,18 +441,21 @@ void TestQgsExpressionContext::setFields()

//test setting a fields in a context with no scopes
QgsExpressionContext emptyContext;
QVERIFY( emptyContext.fields().isEmpty() );
emptyContext.setFields( fields );
//setFeature should have created a scope
QCOMPARE( emptyContext.scopeCount(), 1 );
QVERIFY( emptyContext.hasVariable( QgsExpressionContext::EXPR_FIELDS ) );
QCOMPARE(( qvariant_cast<QgsFields>( emptyContext.variable( QgsExpressionContext::EXPR_FIELDS ) ) ).at( 0 ).name(), QString( "testfield" ) );
QCOMPARE( emptyContext.fields().at( 0 ).name(), QString( "testfield" ) );

QgsExpressionContext contextWithScope;
contextWithScope << new QgsExpressionContextScope();
contextWithScope.setFields( fields );
QCOMPARE( contextWithScope.scopeCount(), 1 );
QVERIFY( contextWithScope.hasVariable( QgsExpressionContext::EXPR_FIELDS ) );
QCOMPARE(( qvariant_cast<QgsFields>( contextWithScope.variable( QgsExpressionContext::EXPR_FIELDS ) ) ).at( 0 ).name(), QString( "testfield" ) );
QCOMPARE( contextWithScope.fields().at( 0 ).name(), QString( "testfield" ) );
}

void TestQgsExpressionContext::globalScope()
Expand Down

0 comments on commit 1c079ea

Please sign in to comment.