mirror of
https://github.com/qgis/QGIS.git
synced 2025-10-07 00:15:48 -04:00
add maptip, expression display and eval_template expressions
This commit is contained in:
parent
6a0ae060bc
commit
e7556c4ea6
39
resources/function_help/json/display_expression
Normal file
39
resources/function_help/json/display_expression
Normal file
@ -0,0 +1,39 @@
|
||||
{
|
||||
"name": "display_expression",
|
||||
"type": "function",
|
||||
"description": "Returns the display expression for a given feature in a layer. If called with no parameters, it evaluates the current feature. The expression is evaluated by default.",
|
||||
"arguments": [
|
||||
{
|
||||
"arg": "feature",
|
||||
"optional": true,
|
||||
"default": "current feature",
|
||||
"description": "The feature which should be evaluated."
|
||||
},
|
||||
{
|
||||
"arg": "layer",
|
||||
"optional": true,
|
||||
"default": "current layer",
|
||||
"description": "The layer (or its id or name)."
|
||||
},
|
||||
{
|
||||
"arg": "evaluate",
|
||||
"description": "If the expression must be evaluated. If false, the expression will be returned as a string literal only (which could potentially be later evaluated using the 'eval' function).",
|
||||
"optional": true,
|
||||
"default": "true"
|
||||
}
|
||||
],
|
||||
"examples": [
|
||||
{
|
||||
"expression": "display_expression()",
|
||||
"returns": "The display expression of the current feature."
|
||||
},
|
||||
{
|
||||
"expression": "display_expression($currentfeature)",
|
||||
"returns": "The display expression for a given feature."
|
||||
},
|
||||
{
|
||||
"expression": "display_expression('a_layer_id', $currentfeature, 'False')",
|
||||
"returns": "The display expression of the current feature not evaluated."
|
||||
}
|
||||
]
|
||||
}
|
13
resources/function_help/json/eval_template
Normal file
13
resources/function_help/json/eval_template
Normal file
@ -0,0 +1,13 @@
|
||||
{
|
||||
"name": "eval_template",
|
||||
"type": "function",
|
||||
"description": "Evaluates a template which is passed in a string. Useful to expand dynamic parameters passed as context variables or fields.",
|
||||
"arguments": [{
|
||||
"arg": "template",
|
||||
"description": "a template string"
|
||||
}],
|
||||
"examples": [{
|
||||
"expression": "eval_template('QGIS [% upper(\\\\'rocks\\\\') %]')",
|
||||
"returns": "QGIS ROCKS"
|
||||
}]
|
||||
}
|
39
resources/function_help/json/maptip
Normal file
39
resources/function_help/json/maptip
Normal file
@ -0,0 +1,39 @@
|
||||
{
|
||||
"name": "maptip",
|
||||
"type": "function",
|
||||
"description": "Returns the maptip for a given feature in a layer. If called with no parameters, it evaluates the current feature. The maptip is evaluated by default.",
|
||||
"arguments": [
|
||||
{
|
||||
"arg": "feature",
|
||||
"optional": true,
|
||||
"default": "current feature",
|
||||
"description": "The feature which should be evaluated."
|
||||
},
|
||||
{
|
||||
"arg": "layer",
|
||||
"optional": true,
|
||||
"default": "current layer",
|
||||
"description": "The layer (or its id or name)."
|
||||
},
|
||||
{
|
||||
"arg": "evaluate",
|
||||
"description": "If the expression must be evaluated. If false, the expression will be returned as a string literal only (which could potentially be later evaluated using the 'eval_template' function).",
|
||||
"optional": true,
|
||||
"default": "true"
|
||||
}
|
||||
],
|
||||
"examples": [
|
||||
{
|
||||
"expression": "maptip()",
|
||||
"returns": "The maptip of the current feature."
|
||||
},
|
||||
{
|
||||
"expression": "maptip($currentFeature)",
|
||||
"returns": "The maptip of the current feature."
|
||||
},
|
||||
{
|
||||
"expression": "maptip('a_layer_id', $currentFeature, 'False')",
|
||||
"returns": "The maptip of the current feature not evaluated."
|
||||
}
|
||||
]
|
||||
}
|
@ -272,6 +272,12 @@ static QVariant fcnGetVariable( const QVariantList &values, const QgsExpressionC
|
||||
return context->variable( name );
|
||||
}
|
||||
|
||||
static QVariant fcnEvalTemplate( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
|
||||
{
|
||||
QString templateString = QgsExpressionUtils::getStringValue( values.at( 0 ), parent );
|
||||
return QgsExpression::replaceExpressionText( templateString, context );
|
||||
}
|
||||
|
||||
static QVariant fcnEval( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
|
||||
{
|
||||
if ( !context )
|
||||
@ -1513,6 +1519,96 @@ static QVariant fcnAttributes( const QVariantList &values, const QgsExpressionCo
|
||||
return result;
|
||||
}
|
||||
|
||||
static QVariant fcnCoreFeatureMaptipDisplay( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const bool isMaptip )
|
||||
{
|
||||
QgsVectorLayer *layer = nullptr;
|
||||
QgsFeature feature;
|
||||
bool evaluate = true;
|
||||
|
||||
if ( values.isEmpty() )
|
||||
{
|
||||
feature = context->feature();
|
||||
layer = QgsExpressionUtils::getVectorLayer( context->variable( QStringLiteral( "layer" ) ), parent );
|
||||
}
|
||||
else if ( values.size() == 1 )
|
||||
{
|
||||
layer = QgsExpressionUtils::getVectorLayer( context->variable( QStringLiteral( "layer" ) ), parent );
|
||||
feature = QgsExpressionUtils::getFeature( values.at( 0 ), parent );
|
||||
}
|
||||
else if ( values.size() == 2 )
|
||||
{
|
||||
layer = QgsExpressionUtils::getVectorLayer( values.at( 0 ), parent );
|
||||
feature = QgsExpressionUtils::getFeature( values.at( 1 ), parent );
|
||||
}
|
||||
else if ( values.size() == 3 )
|
||||
{
|
||||
layer = QgsExpressionUtils::getVectorLayer( values.at( 0 ), parent );
|
||||
feature = QgsExpressionUtils::getFeature( values.at( 1 ), parent );
|
||||
evaluate = values.value( 2 ).toBool();
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( isMaptip )
|
||||
{
|
||||
parent->setEvalErrorString( QObject::tr( "Function `maptip` requires no more than three parameters. %1 given." ).arg( values.length() ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
parent->setEvalErrorString( QObject::tr( "Function `display` requires no more than three parameters. %1 given." ).arg( values.length() ) );
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
if ( !layer )
|
||||
{
|
||||
parent->setEvalErrorString( QObject::tr( "The layer is not valid." ) );
|
||||
return QVariant( );
|
||||
}
|
||||
|
||||
if ( !feature.isValid() )
|
||||
{
|
||||
parent->setEvalErrorString( QObject::tr( "The feature is not valid." ) );
|
||||
return QVariant( );
|
||||
}
|
||||
|
||||
if ( ! evaluate )
|
||||
{
|
||||
if ( isMaptip )
|
||||
{
|
||||
return layer->mapTipTemplate();
|
||||
}
|
||||
else
|
||||
{
|
||||
return layer->displayExpression();
|
||||
}
|
||||
}
|
||||
|
||||
QgsExpressionContext subContext( *context );
|
||||
subContext.appendScopes( QgsExpressionContextUtils::globalProjectLayerScopes( layer ) );
|
||||
subContext.setFeature( feature );
|
||||
|
||||
if ( isMaptip )
|
||||
{
|
||||
return QgsExpression::replaceExpressionText( layer->mapTipTemplate(), &subContext );
|
||||
}
|
||||
else
|
||||
{
|
||||
QgsExpression exp( layer->displayExpression() );
|
||||
exp.prepare( &subContext );
|
||||
return exp.evaluate( &subContext ).toString();
|
||||
}
|
||||
}
|
||||
|
||||
static QVariant fcnFeatureDisplayExpression( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
|
||||
{
|
||||
return fcnCoreFeatureMaptipDisplay( values, context, parent, false );
|
||||
}
|
||||
|
||||
static QVariant fcnFeatureMaptip( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
|
||||
{
|
||||
return fcnCoreFeatureMaptipDisplay( values, context, parent, true );
|
||||
}
|
||||
|
||||
static QVariant fcnIsSelected( const QVariantList &values, const QgsExpressionContext *context, QgsExpression *parent, const QgsExpressionNodeFunction * )
|
||||
{
|
||||
QgsVectorLayer *layer = nullptr;
|
||||
@ -5903,6 +5999,30 @@ const QList<QgsExpressionFunction *> &QgsExpression::Functions()
|
||||
<< new QgsStaticExpressionFunction( QStringLiteral( "attributes" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "feature" ), true ),
|
||||
fcnAttributes, QStringLiteral( "Record and Attributes" ), QString(), false, QSet<QString>() << QgsFeatureRequest::ALL_ATTRIBUTES );
|
||||
|
||||
QgsStaticExpressionFunction *maptipFunc = new QgsStaticExpressionFunction(
|
||||
QStringLiteral( "maptip" ),
|
||||
-1,
|
||||
fcnFeatureMaptip,
|
||||
QStringLiteral( "Record and Attributes" ),
|
||||
QString(),
|
||||
false,
|
||||
QSet<QString>()
|
||||
);
|
||||
maptipFunc->setIsStatic( false );
|
||||
functions << maptipFunc;
|
||||
|
||||
QgsStaticExpressionFunction *displayFunc = new QgsStaticExpressionFunction(
|
||||
QStringLiteral( "display_expression" ),
|
||||
-1,
|
||||
fcnFeatureDisplayExpression,
|
||||
QStringLiteral( "Record and Attributes" ),
|
||||
QString(),
|
||||
false,
|
||||
QSet<QString>()
|
||||
);
|
||||
displayFunc->setIsStatic( false );
|
||||
functions << displayFunc;
|
||||
|
||||
QgsStaticExpressionFunction *isSelectedFunc = new QgsStaticExpressionFunction(
|
||||
QStringLiteral( "is_selected" ),
|
||||
-1,
|
||||
@ -6015,6 +6135,9 @@ const QList<QgsExpressionFunction *> &QgsExpression::Functions()
|
||||
|
||||
functions
|
||||
<< varFunction;
|
||||
|
||||
functions << new QgsStaticExpressionFunction( QStringLiteral( "eval_template" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "template" ) ), fcnEvalTemplate, QStringLiteral( "General" ), QString(), true );
|
||||
|
||||
QgsStaticExpressionFunction *evalFunc = new QgsStaticExpressionFunction( QStringLiteral( "eval" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "expression" ) ), fcnEval, QStringLiteral( "General" ), QString(), true, QSet<QString>() << QgsFeatureRequest::ALL_ATTRIBUTES );
|
||||
evalFunc->setIsStaticFunction(
|
||||
[]( const QgsExpressionNodeFunction * node, QgsExpression * parent, const QgsExpressionContext * context )
|
||||
|
@ -94,6 +94,8 @@ class TestQgsExpression: public QObject
|
||||
mPointsLayer->setAttributionUrl( QStringLiteral( "attribution url" ) );
|
||||
mPointsLayer->setMinimumScale( 500 );
|
||||
mPointsLayer->setMaximumScale( 1000 );
|
||||
mPointsLayer->setMapTipTemplate( QStringLiteral( "Maptip with class = [% \"Class\" %]" ) );
|
||||
mPointsLayer->setDisplayExpression( QStringLiteral( "'Display expression with class = ' || \"Class\"" ) );
|
||||
|
||||
mPointsLayerMetadata = new QgsVectorLayer( pointFileInfo.filePath(),
|
||||
pointFileInfo.completeBaseName() + "_metadata", QStringLiteral( "ogr" ) );
|
||||
@ -1411,6 +1413,11 @@ class TestQgsExpression: public QObject
|
||||
QTest::newRow( "right associativity" ) << "(2^3)^2" << false << QVariant( 64. );
|
||||
QTest::newRow( "left associativity" ) << "1-(2-1)" << false << QVariant( 0 );
|
||||
|
||||
// eval_template tests
|
||||
QTest::newRow( "eval_template" ) << QStringLiteral( "eval_template(\'this is a [% \\'template\\' || \\'!\\' %]\')" ) << false << QVariant( "this is a template!" );
|
||||
QTest::newRow( "eval_template string" ) << QStringLiteral( "eval_template('string')" ) << false << QVariant( "string" );
|
||||
QTest::newRow( "eval_template expression" ) << QStringLiteral( "eval_template('a' || ' string')" ) << false << QVariant( "a string" );
|
||||
|
||||
// layer_property tests
|
||||
QTest::newRow( "layer_property no layer" ) << "layer_property('','title')" << false << QVariant();
|
||||
QTest::newRow( "layer_property bad layer" ) << "layer_property('bad','title')" << false << QVariant();
|
||||
@ -2015,6 +2022,63 @@ class TestQgsExpression: public QObject
|
||||
QTest::newRow( "group by with null value" ) << "sum(\"col1\", \"col4\")" << false << QVariant( 8 );
|
||||
}
|
||||
|
||||
void maptip_display_data()
|
||||
{
|
||||
QTest::addColumn<QString>( "string" );
|
||||
QTest::addColumn<QgsFeature>( "feature" );
|
||||
QTest::addColumn<QgsVectorLayer *>( "layer" );
|
||||
QTest::addColumn<bool>( "evalError" );
|
||||
QTest::addColumn<QVariant>( "result" );
|
||||
|
||||
QgsFeature firstFeature = mPointsLayer->getFeature( 1 );
|
||||
QgsVectorLayer *noLayer = nullptr;
|
||||
|
||||
QTest::newRow( "display not evaluated" ) << QStringLiteral( "display_expression(@layer_id, $currentfeature, False)" ) << firstFeature << mPointsLayer << false << QVariant( "'Display expression with class = ' || \"Class\"" );
|
||||
QTest::newRow( "display wrong layer" ) << QStringLiteral( "display_expression()" ) << firstFeature << noLayer << true << QVariant();
|
||||
QTest::newRow( "display wrong feature" ) << QStringLiteral( "display_expression()" ) << QgsFeature() << mPointsLayer << true << QVariant();
|
||||
|
||||
QTest::newRow( "maptip wrong feature" ) << QStringLiteral( "maptip()" ) << QgsFeature() << mPointsLayer << true << QVariant();
|
||||
QTest::newRow( "maptip wrong layer" ) << QStringLiteral( "maptip()" ) << firstFeature << noLayer << true << QVariant();
|
||||
QTest::newRow( "maptip not evaluated" ) << QStringLiteral( "maptip(@layer_id, $currentfeature, False)" ) << firstFeature << mPointsLayer << false << QVariant( "Maptip with class = [% \"Class\" %]" );
|
||||
|
||||
QTest::newRow( "maptip with 2 params" ) << QStringLiteral( "maptip(@layer_id, $currentfeature)" ) << firstFeature << mPointsLayer << false << QVariant( "Maptip with class = Biplane" );
|
||||
QTest::newRow( "maptip with 1 param" ) << QStringLiteral( "maptip($currentfeature)" ) << firstFeature << mPointsLayer << false << QVariant( "Maptip with class = Biplane" );
|
||||
QTest::newRow( "maptip with 0 param" ) << QStringLiteral( "maptip()" ) << firstFeature << mPointsLayer << false << QVariant( "Maptip with class = Biplane" );
|
||||
|
||||
QTest::newRow( "display with 2 params" ) << QStringLiteral( "display_expression(@layer_id, $currentfeature)" ) << firstFeature << mPointsLayer << false << QVariant( "Display expression with class = Biplane" );
|
||||
QTest::newRow( "display with 1 param" ) << QStringLiteral( "display_expression($currentfeature)" ) << firstFeature << mPointsLayer << false << QVariant( "Display expression with class = Biplane" );
|
||||
QTest::newRow( "display with 0 param" ) << QStringLiteral( "display_expression()" ) << firstFeature << mPointsLayer << false << QVariant( "Display expression with class = Biplane" );
|
||||
}
|
||||
|
||||
void maptip_display()
|
||||
{
|
||||
QFETCH( QString, string );
|
||||
QFETCH( QgsFeature, feature );
|
||||
QFETCH( QgsVectorLayer *, layer );
|
||||
QFETCH( bool, evalError );
|
||||
QFETCH( QVariant, result );
|
||||
|
||||
QgsExpressionContext context;
|
||||
context.appendScope( QgsExpressionContextUtils::globalScope() );
|
||||
context.appendScope( QgsExpressionContextUtils::projectScope( QgsProject::instance() ) );
|
||||
if ( layer )
|
||||
{
|
||||
//layer->setDisplayExpression( QStringLiteral( "Display expression with class = ' || Class" ) );
|
||||
context.appendScope( QgsExpressionContextUtils::layerScope( layer ) );
|
||||
}
|
||||
context.setFeature( feature );
|
||||
|
||||
QgsExpression exp( string );
|
||||
exp.prepare( &context );
|
||||
|
||||
if ( exp.hasParserError() )
|
||||
qDebug() << exp.parserErrorString();
|
||||
QCOMPARE( exp.hasParserError(), false );
|
||||
QVariant res = exp.evaluate( &context );
|
||||
QCOMPARE( exp.hasEvalError(), evalError );
|
||||
QCOMPARE( res.toString(), result.toString() );
|
||||
}
|
||||
|
||||
void selection()
|
||||
{
|
||||
QFETCH( QgsFeatureIds, selectedFeatures );
|
||||
|
Loading…
x
Reference in New Issue
Block a user