mirror of
https://github.com/qgis/QGIS.git
synced 2025-10-04 00:04:03 -04:00
Add new variable form of current feature expression functions
This adds a newer style variable form of referencing the current feature and its attributes in expressions. The newly introduced variables are: - @feature: a replacement for $currentfeature, contains the current feature - @id: a replacement for $id, contains the current feature id - @geometry: a replacement for $geometry, contains the current feature geometry This is intended as a step towards eventually deprecating the older $ style functions, and providing a more consistent approach to expressions instead of the older unpredictable mix of @/$. For now these old functions still work (and likely will ALWAYS remain working for old project compatibility), AND they are also still exposed in the UI just to avoid user confusion (eventually we can hide them).
This commit is contained in:
parent
8fcd7913ea
commit
341add8cb9
@ -2,7 +2,7 @@
|
||||
"name": "$currentfeature",
|
||||
"type": "function",
|
||||
"groups": ["Record and Attributes"],
|
||||
"description": "Returns the current feature being evaluated. This can be used with the 'attribute' function to evaluate attribute values from the current feature.",
|
||||
"description": "Returns the current feature being evaluated. This can be used with the 'attribute' function to evaluate attribute values from the current feature. <b>WARNING: This function is deprecated. It is recommended to use the replacement @feature variable instead.</b>",
|
||||
"examples": [{
|
||||
"expression": "attribute( $currentfeature, 'name' )",
|
||||
"returns": "value stored in 'name' attribute for the current feature"
|
||||
|
@ -2,7 +2,7 @@
|
||||
"name": "$geometry",
|
||||
"type": "function",
|
||||
"groups": ["GeometryGroup"],
|
||||
"description": "Returns the geometry of the current feature. Can be used for processing with other functions.",
|
||||
"description": "Returns the geometry of the current feature. Can be used for processing with other functions. <b>WARNING: This function is deprecated. It is recommended to use the replacement @geometry variable instead.</b>",
|
||||
"examples": [{
|
||||
"expression": "geom_to_wkt( $geometry )",
|
||||
"returns": "'POINT(6 50)'"
|
||||
|
@ -2,7 +2,7 @@
|
||||
"name": "$id",
|
||||
"type": "function",
|
||||
"groups": ["Record and Attributes"],
|
||||
"description": "Returns the feature id of the current row.",
|
||||
"description": "Returns the feature id of the current row. <b>WARNING: This function is deprecated. It is recommended to use the replacement @id variable instead.</b>",
|
||||
"examples": [{
|
||||
"expression": "$id",
|
||||
"returns": "42"
|
||||
|
@ -748,6 +748,11 @@ void QgsExpression::initVariableHelp()
|
||||
sVariableHelpTexts()->insert( QStringLiteral( "layer_crs" ), QCoreApplication::translate( "variable_help", "CRS Authority ID of current layer." ) );
|
||||
sVariableHelpTexts()->insert( QStringLiteral( "layer" ), QCoreApplication::translate( "variable_help", "The current layer." ) );
|
||||
|
||||
//feature variables
|
||||
sVariableHelpTexts()->insert( QStringLiteral( "current_feature" ), QCoreApplication::translate( "variable_help", "The current feature being evaluated. This can be used with the 'attribute' function to evaluate attribute values from the current feature." ) );
|
||||
sVariableHelpTexts()->insert( QStringLiteral( "id" ), QCoreApplication::translate( "variable_help", "The ID of the current feature being evaluated." ) );
|
||||
sVariableHelpTexts()->insert( QStringLiteral( "geometry" ), QCoreApplication::translate( "variable_help", "The geometry of the current feature being evaluated." ) );
|
||||
|
||||
//composition variables
|
||||
sVariableHelpTexts()->insert( QStringLiteral( "layout_name" ), QCoreApplication::translate( "variable_help", "Name of composition." ) );
|
||||
sVariableHelpTexts()->insert( QStringLiteral( "layout_numpages" ), QCoreApplication::translate( "variable_help", "Number of pages in composition." ) );
|
||||
|
@ -286,8 +286,28 @@ static QVariant fcnGetVariable( const QVariantList &values, const QgsExpressionC
|
||||
if ( !context )
|
||||
return QVariant();
|
||||
|
||||
QString name = QgsExpressionUtils::getStringValue( values.at( 0 ), parent );
|
||||
return context->variable( name );
|
||||
const QString name = QgsExpressionUtils::getStringValue( values.at( 0 ), parent );
|
||||
|
||||
if ( name == QLatin1String( "feature" ) )
|
||||
{
|
||||
return context->hasFeature() ? QVariant::fromValue( context->feature() ) : QVariant();
|
||||
}
|
||||
else if ( name == QLatin1String( "id" ) )
|
||||
{
|
||||
return context->hasFeature() ? QVariant::fromValue( context->feature().id() ) : QVariant();
|
||||
}
|
||||
else if ( name == QLatin1String( "geometry" ) )
|
||||
{
|
||||
if ( !context->hasFeature() )
|
||||
return QVariant();
|
||||
|
||||
const QgsFeature feature = context->feature();
|
||||
return feature.hasGeometry() ? QVariant::fromValue( feature.geometry() ) : QVariant();
|
||||
}
|
||||
else
|
||||
{
|
||||
return context->variable( name );
|
||||
}
|
||||
}
|
||||
|
||||
static QVariant fcnEvalTemplate( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
|
||||
@ -8383,7 +8403,9 @@ const QList<QgsExpressionFunction *> &QgsExpression::Functions()
|
||||
if ( !argNode->isStatic( parent, context ) )
|
||||
return false;
|
||||
|
||||
QString varName = argNode->eval( parent, context ).toString();
|
||||
const QString varName = argNode->eval( parent, context ).toString();
|
||||
if ( varName == QLatin1String( "feature" ) || varName == QLatin1String( "id" ) || varName == QLatin1String( "geometry" ) )
|
||||
return false;
|
||||
|
||||
const QgsExpressionContextScope *scope = context->activeScopeForVariable( varName );
|
||||
return scope ? scope->isStatic( varName ) : false;
|
||||
|
@ -119,6 +119,14 @@ QVariant QgsExpressionContextScope::variable( const QString &name ) const
|
||||
QStringList QgsExpressionContextScope::variableNames() const
|
||||
{
|
||||
QStringList names = mVariables.keys();
|
||||
|
||||
if ( hasFeature() )
|
||||
{
|
||||
names.append( QStringLiteral( "feature" ) );
|
||||
names.append( QStringLiteral( "id" ) );
|
||||
names.append( QStringLiteral( "geometry" ) );
|
||||
}
|
||||
|
||||
return names;
|
||||
}
|
||||
|
||||
|
@ -42,6 +42,12 @@ void QgsCodeEditorExpression::setExpressionContext( const QgsExpressionContext &
|
||||
mVariables << '@' + var;
|
||||
}
|
||||
|
||||
// always show feature variables in autocomplete -- they may not be available in the context
|
||||
// at time of showing an expression builder, but they'll generally be available at evaluation time.
|
||||
mVariables << QStringLiteral( "@feature" );
|
||||
mVariables << QStringLiteral( "@id" );
|
||||
mVariables << QStringLiteral( "@geometry" );
|
||||
|
||||
mContextFunctions = context.functionNames();
|
||||
|
||||
mFunctions.clear();
|
||||
|
@ -19,7 +19,6 @@
|
||||
|
||||
#include "qgsexpressiontreeview.h"
|
||||
#include "qgis.h"
|
||||
#include "qgsfieldformatterregistry.h"
|
||||
#include "qgsvectorlayer.h"
|
||||
#include "qgsexpressioncontextutils.h"
|
||||
#include "qgssettings.h"
|
||||
@ -463,11 +462,32 @@ void QgsExpressionTreeView::loadFieldNames()
|
||||
{
|
||||
QgsExpressionItem *node = mExpressionGroups.value( QStringLiteral( "Fields and Values" ) );
|
||||
node->removeRows( 0, node->rowCount() );
|
||||
// Re-add NULL
|
||||
// use -1 as sort order here -- NULL should always show before the field list
|
||||
// Re-add NULL and feature variables
|
||||
// use -1 as sort order here -- NULL and feature variables should always show before the field list
|
||||
registerItem( QStringLiteral( "Fields and Values" ), QStringLiteral( "NULL" ), QStringLiteral( "NULL" ), QString(), QgsExpressionItem::ExpressionNode, false, -1 );
|
||||
}
|
||||
|
||||
if ( mLayer )
|
||||
{
|
||||
// Add feature variables to record and attributes group (and highlighted items)
|
||||
|
||||
const QString currentFeatureHelp = formatVariableHelp( QStringLiteral( "feature" ), QgsExpression::variableHelpText( QStringLiteral( "feature" ) ), false, QVariant() );
|
||||
const QString currentFeatureIdHelp = formatVariableHelp( QStringLiteral( "id" ), QgsExpression::variableHelpText( QStringLiteral( "id" ) ), false, QVariant() );
|
||||
const QString currentGeometryHelp = formatVariableHelp( QStringLiteral( "geometry" ), QgsExpression::variableHelpText( QStringLiteral( "geometry" ) ), false, QVariant() );
|
||||
|
||||
registerItem( QStringLiteral( "Fields and Values" ), QStringLiteral( "feature" ), QStringLiteral( "@feature" ), currentFeatureHelp, QgsExpressionItem::ExpressionNode, false, -1 );
|
||||
registerItem( QStringLiteral( "Fields and Values" ), QStringLiteral( "id" ), QStringLiteral( "@id" ), currentFeatureIdHelp, QgsExpressionItem::ExpressionNode, false, -1 );
|
||||
registerItem( QStringLiteral( "Fields and Values" ), QStringLiteral( "geometry" ), QStringLiteral( "@geometry" ), currentGeometryHelp, QgsExpressionItem::ExpressionNode, false, -1 );
|
||||
|
||||
registerItem( tr( "Variables" ), QStringLiteral( "feature" ), QStringLiteral( "@feature" ), currentFeatureHelp, QgsExpressionItem::ExpressionNode );
|
||||
registerItem( tr( "Variables" ), QStringLiteral( "id" ), QStringLiteral( "@id" ), currentFeatureIdHelp, QgsExpressionItem::ExpressionNode );
|
||||
registerItem( tr( "Variables" ), QStringLiteral( "geometry" ), QStringLiteral( "@geometry" ), currentGeometryHelp, QgsExpressionItem::ExpressionNode, false );
|
||||
|
||||
registerItem( tr( "Record and Attributes" ), QStringLiteral( "feature" ), QStringLiteral( "@feature" ), currentFeatureHelp, QgsExpressionItem::ExpressionNode, true, -1 );
|
||||
registerItem( tr( "Record and Attributes" ), QStringLiteral( "id" ), QStringLiteral( "@id" ), currentFeatureIdHelp, QgsExpressionItem::ExpressionNode, true, -1 );
|
||||
registerItem( tr( "Record and Attributes" ), QStringLiteral( "geometry" ), QStringLiteral( "@geometry" ), currentGeometryHelp, QgsExpressionItem::ExpressionNode, true, -1 );
|
||||
}
|
||||
|
||||
// this can happen if fields are manually set
|
||||
if ( !mLayer )
|
||||
return;
|
||||
|
@ -2298,20 +2298,56 @@ class TestQgsExpression: public QObject
|
||||
void eval_feature_id()
|
||||
{
|
||||
QgsFeature f( 100 );
|
||||
// older form
|
||||
QgsExpression exp( QStringLiteral( "$id * 2" ) );
|
||||
QgsExpressionContext context = QgsExpressionContextUtils::createFeatureBasedContext( f, QgsFields() );
|
||||
QVariant v = exp.evaluate( &context );
|
||||
QCOMPARE( v.toInt(), 200 );
|
||||
|
||||
// newer form
|
||||
QgsExpression exp2( QStringLiteral( "@id * 2" ) );
|
||||
v = exp.evaluate( &context );
|
||||
QCOMPARE( v.toInt(), 200 );
|
||||
}
|
||||
|
||||
void eval_current_feature()
|
||||
{
|
||||
QgsFeature f( 100 );
|
||||
// older form
|
||||
QgsExpression exp( QStringLiteral( "$currentfeature" ) );
|
||||
QgsExpressionContext context = QgsExpressionContextUtils::createFeatureBasedContext( f, QgsFields() );
|
||||
QVariant v = exp.evaluate( &context );
|
||||
QgsFeature evalFeature = v.value<QgsFeature>();
|
||||
QCOMPARE( evalFeature.id(), f.id() );
|
||||
|
||||
// newer form
|
||||
QgsExpression exp2( QStringLiteral( "@feature" ) );
|
||||
v = exp2.evaluate( &context );
|
||||
evalFeature = v.value<QgsFeature>();
|
||||
QCOMPARE( evalFeature.id(), f.id() );
|
||||
}
|
||||
|
||||
void eval_current_geometry()
|
||||
{
|
||||
QgsFeature featureWithGeometry( 100 );
|
||||
featureWithGeometry.setGeometry( QgsGeometry::fromPointXY( QgsPointXY( 1, 2 ) ) );
|
||||
QgsFeature featureWithNoGeometry( 100 );
|
||||
|
||||
// older form
|
||||
QgsExpression exp( QStringLiteral( "geom_to_wkt($geometry)" ) );
|
||||
QgsExpressionContext contextWithGeometry = QgsExpressionContextUtils::createFeatureBasedContext( featureWithGeometry, QgsFields() );
|
||||
QgsExpressionContext contextWithNoGeometry = QgsExpressionContextUtils::createFeatureBasedContext( featureWithNoGeometry, QgsFields() );
|
||||
QVariant v = exp.evaluate( &contextWithGeometry );
|
||||
QCOMPARE( v.toString(), QStringLiteral( "Point (1 2)" ) );
|
||||
v = exp.evaluate( &contextWithNoGeometry );
|
||||
QVERIFY( v.isNull() );
|
||||
|
||||
// newer form
|
||||
QgsExpression exp2( QStringLiteral( "geom_to_wkt(@geometry)" ) );
|
||||
v = exp2.evaluate( &contextWithGeometry );
|
||||
QCOMPARE( v.toString(), QStringLiteral( "Point (1 2)" ) );
|
||||
v = exp2.evaluate( &contextWithNoGeometry );
|
||||
QVERIFY( v.isNull() );
|
||||
}
|
||||
|
||||
void eval_feature_attribute()
|
||||
|
Loading…
x
Reference in New Issue
Block a user