mirror of
https://github.com/qgis/QGIS.git
synced 2025-10-08 00:05:09 -04:00
[FEATURE] Add is_selected and num_selected functions
* is_selected() returns if the current feature is selected * num_selected() returns the number of selected features on the current layer * is_selected(layer, feature) returns if the "feature" is selected. "feature" must be on "layer". * num_selected(layer) returns the number of selected features on "layer"
This commit is contained in:
parent
f52dfba21e
commit
01f3c9ae38
13
resources/function_help/json/is_selected
Normal file
13
resources/function_help/json/is_selected
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"name": "is_selected",
|
||||||
|
"type": "function",
|
||||||
|
"description": "Returns if a feature is selected. If called with no parameters checks the current feature.",
|
||||||
|
"arguments": [
|
||||||
|
{"arg":"feature","description":"The feature which should be checked for selection"},
|
||||||
|
{"arg":"layer","description":"The layer (or its id or name) on which the selection will be checked"}
|
||||||
|
],
|
||||||
|
"examples": [
|
||||||
|
{ "expression":"is_selected()", "returns" : "True if the current feature is selected."},
|
||||||
|
{ "expression":"is_selected(get_feature('streets', 'name', \"street_name\"), 'streets')", "returns":"True if the current building's street is selected."}
|
||||||
|
]
|
||||||
|
}
|
12
resources/function_help/json/num_selected
Normal file
12
resources/function_help/json/num_selected
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"name": "num_selected",
|
||||||
|
"type": "function",
|
||||||
|
"description": "Returns the number of selected features on a given layer. By default works on the layer on which the expression is evaluated.",
|
||||||
|
"arguments": [
|
||||||
|
{"arg":"layer","description":"The layer (or its id or name) on which the selection will be checked"}
|
||||||
|
],
|
||||||
|
"examples": [
|
||||||
|
{ "expression":"num_selected()", "returns":"The number of selected features on the current layer."},
|
||||||
|
{ "expression":"num_selected('streets')", "returns":"The number of selected features on the layer streets"}
|
||||||
|
]
|
||||||
|
}
|
@ -312,14 +312,19 @@ static QgsExpression::Node* getNode( const QVariant& value, QgsExpression* paren
|
|||||||
|
|
||||||
QgsVectorLayer* getVectorLayer( const QVariant& value, QgsExpression* )
|
QgsVectorLayer* getVectorLayer( const QVariant& value, QgsExpression* )
|
||||||
{
|
{
|
||||||
QString layerString = value.toString();
|
QgsVectorLayer* vl = value.value<QgsVectorLayer*>();
|
||||||
QgsVectorLayer* vl = qobject_cast<QgsVectorLayer*>( QgsMapLayerRegistry::instance()->mapLayer( layerString ) ); //search by id first
|
|
||||||
if ( !vl )
|
if ( !vl )
|
||||||
{
|
{
|
||||||
QList<QgsMapLayer *> layersByName = QgsMapLayerRegistry::instance()->mapLayersByName( layerString );
|
QString layerString = value.toString();
|
||||||
if ( !layersByName.isEmpty() )
|
vl = qobject_cast<QgsVectorLayer*>( QgsMapLayerRegistry::instance()->mapLayer( layerString ) ); //search by id first
|
||||||
|
|
||||||
|
if ( !vl )
|
||||||
{
|
{
|
||||||
vl = qobject_cast<QgsVectorLayer*>( layersByName.at( 0 ) );
|
QList<QgsMapLayer *> layersByName = QgsMapLayerRegistry::instance()->mapLayersByName( layerString );
|
||||||
|
if ( !layersByName.isEmpty() )
|
||||||
|
{
|
||||||
|
vl = qobject_cast<QgsVectorLayer*>( layersByName.at( 0 ) );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -707,8 +712,7 @@ static QVariant fcnAggregateRelation( const QVariantList& values, const QgsExpre
|
|||||||
}
|
}
|
||||||
|
|
||||||
// first step - find current layer
|
// first step - find current layer
|
||||||
QString layerId = context->variable( QStringLiteral( "layer_id" ) ).toString();
|
QgsVectorLayer* vl = getVectorLayer( context->variable( "layer" ), parent );
|
||||||
QgsVectorLayer* vl = qobject_cast<QgsVectorLayer*>( QgsMapLayerRegistry::instance()->mapLayer( layerId ) );
|
|
||||||
if ( !vl )
|
if ( !vl )
|
||||||
{
|
{
|
||||||
parent->setEvalErrorString( QObject::tr( "Cannot use relation aggregate function in this context" ) );
|
parent->setEvalErrorString( QObject::tr( "Cannot use relation aggregate function in this context" ) );
|
||||||
@ -810,8 +814,7 @@ static QVariant fcnAggregateGeneric( QgsAggregateCalculator::Aggregate aggregate
|
|||||||
}
|
}
|
||||||
|
|
||||||
// first step - find current layer
|
// first step - find current layer
|
||||||
QString layerId = context->variable( QStringLiteral( "layer_id" ) ).toString();
|
QgsVectorLayer* vl = getVectorLayer( context->variable( "layer" ), parent );
|
||||||
QgsVectorLayer* vl = qobject_cast<QgsVectorLayer*>( QgsMapLayerRegistry::instance()->mapLayer( layerId ) );
|
|
||||||
if ( !vl )
|
if ( !vl )
|
||||||
{
|
{
|
||||||
parent->setEvalErrorString( QObject::tr( "Cannot use aggregate function in this context" ) );
|
parent->setEvalErrorString( QObject::tr( "Cannot use aggregate function in this context" ) );
|
||||||
@ -1358,6 +1361,63 @@ static QVariant fcnAttribute( const QVariantList& values, const QgsExpressionCon
|
|||||||
|
|
||||||
return feat.attribute( attr );
|
return feat.attribute( attr );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static QVariant fcnIsSelected( const QVariantList& values, const QgsExpressionContext* context, QgsExpression* parent )
|
||||||
|
{
|
||||||
|
QgsVectorLayer* layer = nullptr;
|
||||||
|
QgsFeature feature;
|
||||||
|
|
||||||
|
if ( values.isEmpty() )
|
||||||
|
{
|
||||||
|
feature = context->feature();
|
||||||
|
layer = getVectorLayer( context->variable( "layer" ), parent );
|
||||||
|
}
|
||||||
|
else if ( values.size() == 1 )
|
||||||
|
{
|
||||||
|
layer = getVectorLayer( context->variable( "layer" ), parent );
|
||||||
|
feature = getFeature( values.at( 0 ), parent );
|
||||||
|
}
|
||||||
|
else if ( values.size() == 2 )
|
||||||
|
{
|
||||||
|
layer = getVectorLayer( values.at( 0 ), parent );
|
||||||
|
feature = getFeature( values.at( 1 ), parent );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
parent->setEvalErrorString( QObject::tr( "Function `is_selected` requires no more than two parameters. %1 given." ).arg( values.length() ) );
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( !layer || !feature.isValid() )
|
||||||
|
{
|
||||||
|
return QVariant( QVariant::Bool );
|
||||||
|
}
|
||||||
|
|
||||||
|
return layer->selectedFeaturesIds().contains( feature.id() );
|
||||||
|
}
|
||||||
|
|
||||||
|
static QVariant fcnNumSelected( const QVariantList& values, const QgsExpressionContext* context, QgsExpression* parent )
|
||||||
|
{
|
||||||
|
QgsVectorLayer* layer = nullptr;
|
||||||
|
|
||||||
|
if ( values.isEmpty() )
|
||||||
|
layer = getVectorLayer( context->variable( "layer" ), parent );
|
||||||
|
else if ( values.count() == 1 )
|
||||||
|
layer = getVectorLayer( values.at( 0 ), parent );
|
||||||
|
else
|
||||||
|
{
|
||||||
|
parent->setEvalErrorString( QObject::tr( "Function `num_selected` requires no more than one parameter. %1 given." ).arg( values.length() ) );
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( !layer )
|
||||||
|
{
|
||||||
|
return QVariant( QVariant::LongLong );
|
||||||
|
}
|
||||||
|
|
||||||
|
return layer->selectedFeatureCount();
|
||||||
|
}
|
||||||
|
|
||||||
static QVariant fcnConcat( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
|
static QVariant fcnConcat( const QVariantList& values, const QgsExpressionContext*, QgsExpression *parent )
|
||||||
{
|
{
|
||||||
QString concat;
|
QString concat;
|
||||||
@ -3665,10 +3725,37 @@ const QList<QgsExpression::Function*>& QgsExpression::Functions()
|
|||||||
<< Parameter( QStringLiteral( "vertex" ) ), fcnAngleAtVertex, QStringLiteral( "GeometryGroup" ) )
|
<< Parameter( QStringLiteral( "vertex" ) ), fcnAngleAtVertex, QStringLiteral( "GeometryGroup" ) )
|
||||||
<< new StaticFunction( QStringLiteral( "distance_to_vertex" ), ParameterList() << Parameter( QStringLiteral( "geometry" ) )
|
<< new StaticFunction( QStringLiteral( "distance_to_vertex" ), ParameterList() << Parameter( QStringLiteral( "geometry" ) )
|
||||||
<< Parameter( QStringLiteral( "vertex" ) ), fcnDistanceToVertex, QStringLiteral( "GeometryGroup" ) )
|
<< Parameter( QStringLiteral( "vertex" ) ), fcnDistanceToVertex, QStringLiteral( "GeometryGroup" ) )
|
||||||
|
|
||||||
|
|
||||||
|
// **Record** functions
|
||||||
|
|
||||||
<< new StaticFunction( QStringLiteral( "$id" ), 0, fcnFeatureId, QStringLiteral( "Record" ) )
|
<< new StaticFunction( QStringLiteral( "$id" ), 0, fcnFeatureId, QStringLiteral( "Record" ) )
|
||||||
<< new StaticFunction( QStringLiteral( "$currentfeature" ), 0, fcnFeature, QStringLiteral( "Record" ) )
|
<< new StaticFunction( QStringLiteral( "$currentfeature" ), 0, fcnFeature, QStringLiteral( "Record" ) )
|
||||||
<< new StaticFunction( QStringLiteral( "uuid" ), 0, fcnUuid, QStringLiteral( "Record" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "$uuid" ) )
|
<< new StaticFunction( QStringLiteral( "uuid" ), 0, fcnUuid, QStringLiteral( "Record" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "$uuid" ) )
|
||||||
<< new StaticFunction( QStringLiteral( "get_feature" ), 3, fcnGetFeature, QStringLiteral( "Record" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "getFeature" ) )
|
<< new StaticFunction( QStringLiteral( "get_feature" ), 3, fcnGetFeature, QStringLiteral( "Record" ), QString(), false, QSet<QString>(), false, QStringList() << QStringLiteral( "getFeature" ) )
|
||||||
|
|
||||||
|
<< new StaticFunction(
|
||||||
|
QStringLiteral( "is_selected" ),
|
||||||
|
-1,
|
||||||
|
fcnIsSelected,
|
||||||
|
QStringLiteral( "Record" ),
|
||||||
|
QString(),
|
||||||
|
false,
|
||||||
|
QSet<QString>()
|
||||||
|
)
|
||||||
|
|
||||||
|
<< new StaticFunction(
|
||||||
|
QStringLiteral( "num_selected" ),
|
||||||
|
-1,
|
||||||
|
fcnNumSelected,
|
||||||
|
QStringLiteral( "Record" ),
|
||||||
|
QString(),
|
||||||
|
false,
|
||||||
|
QSet<QString>()
|
||||||
|
)
|
||||||
|
|
||||||
|
// **General** functions
|
||||||
|
|
||||||
<< new StaticFunction( QStringLiteral( "layer_property" ), 2, fcnGetLayerProperty, QStringLiteral( "General" ) )
|
<< new StaticFunction( QStringLiteral( "layer_property" ), 2, fcnGetLayerProperty, QStringLiteral( "General" ) )
|
||||||
<< new StaticFunction( QStringLiteral( "var" ), 1, fcnGetVariable, QStringLiteral( "General" ) )
|
<< new StaticFunction( QStringLiteral( "var" ), 1, fcnGetVariable, QStringLiteral( "General" ) )
|
||||||
|
|
||||||
@ -5290,6 +5377,7 @@ void QgsExpression::initVariableHelp()
|
|||||||
//layer variables
|
//layer variables
|
||||||
gVariableHelpTexts.insert( QStringLiteral( "layer_name" ), QCoreApplication::translate( "variable_help", "Name of current layer." ) );
|
gVariableHelpTexts.insert( QStringLiteral( "layer_name" ), QCoreApplication::translate( "variable_help", "Name of current layer." ) );
|
||||||
gVariableHelpTexts.insert( QStringLiteral( "layer_id" ), QCoreApplication::translate( "variable_help", "ID of current layer." ) );
|
gVariableHelpTexts.insert( QStringLiteral( "layer_id" ), QCoreApplication::translate( "variable_help", "ID of current layer." ) );
|
||||||
|
gVariableHelpTexts.insert( QStringLiteral( "layer" ), QCoreApplication::translate( "variable_help", "The current layer." ) );
|
||||||
|
|
||||||
//composition variables
|
//composition variables
|
||||||
gVariableHelpTexts.insert( QStringLiteral( "layout_numpages" ), QCoreApplication::translate( "variable_help", "Number of pages in composition." ) );
|
gVariableHelpTexts.insert( QStringLiteral( "layout_numpages" ), QCoreApplication::translate( "variable_help", "Number of pages in composition." ) );
|
||||||
|
@ -691,6 +691,7 @@ QgsExpressionContextScope* QgsExpressionContextUtils::layerScope( const QgsMapLa
|
|||||||
|
|
||||||
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "layer_name" ), layer->name(), true ) );
|
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "layer_name" ), layer->name(), true ) );
|
||||||
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "layer_id" ), layer->id(), true ) );
|
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "layer_id" ), layer->id(), true ) );
|
||||||
|
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "layer" ), QVariant::fromValue<QgsMapLayer*>( const_cast<QgsMapLayer*>( layer ) ), true ) );
|
||||||
|
|
||||||
const QgsVectorLayer* vLayer = dynamic_cast< const QgsVectorLayer* >( layer );
|
const QgsVectorLayer* vLayer = dynamic_cast< const QgsVectorLayer* >( layer );
|
||||||
if ( vLayer )
|
if ( vLayer )
|
||||||
|
@ -581,7 +581,7 @@ class CORE_EXPORT QgsExpressionContextUtils
|
|||||||
/** Creates a new scope which contains variables and functions relating to a QgsMapLayer.
|
/** Creates a new scope which contains variables and functions relating to a QgsMapLayer.
|
||||||
* For instance, layer name, id and fields.
|
* For instance, layer name, id and fields.
|
||||||
*/
|
*/
|
||||||
static QgsExpressionContextScope* layerScope( const QgsMapLayer *layer );
|
static QgsExpressionContextScope* layerScope( const QgsMapLayer* layer );
|
||||||
|
|
||||||
/** Sets a layer context variable. This variable will be contained within scopes retrieved via
|
/** Sets a layer context variable. This variable will be contained within scopes retrieved via
|
||||||
* layerScope().
|
* layerScope().
|
||||||
|
@ -1355,6 +1355,55 @@ class TestQgsExpression: public QObject
|
|||||||
QTest::newRow( "group by expression" ) << "sum(\"col1\", \"col1\" % 2)" << false << QVariant( 16 );
|
QTest::newRow( "group by expression" ) << "sum(\"col1\", \"col1\" % 2)" << false << QVariant( 16 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void selection()
|
||||||
|
{
|
||||||
|
QFETCH( QgsFeatureIds, selectedFeatures );
|
||||||
|
QFETCH( QString, expression );
|
||||||
|
QFETCH( QVariant, result );
|
||||||
|
QFETCH( QgsFeature, feature );
|
||||||
|
QFETCH( QgsVectorLayer*, layer );
|
||||||
|
|
||||||
|
QgsExpressionContext context;
|
||||||
|
if ( layer )
|
||||||
|
context.appendScope( QgsExpressionContextUtils::layerScope( layer ) );
|
||||||
|
|
||||||
|
QgsFeatureIds backupSelection = mMemoryLayer->selectedFeaturesIds();
|
||||||
|
context.setFeature( feature );
|
||||||
|
|
||||||
|
mMemoryLayer->selectByIds( selectedFeatures );
|
||||||
|
|
||||||
|
QgsExpression exp( expression );
|
||||||
|
QCOMPARE( exp.parserErrorString(), QString( "" ) );
|
||||||
|
exp.prepare( &context );
|
||||||
|
QVariant res = exp.evaluate( &context );
|
||||||
|
QCOMPARE( res, result );
|
||||||
|
|
||||||
|
mMemoryLayer->selectByIds( backupSelection );
|
||||||
|
}
|
||||||
|
|
||||||
|
void selection_data()
|
||||||
|
{
|
||||||
|
QTest::addColumn<QString>( "expression" );
|
||||||
|
QTest::addColumn<QgsFeatureIds>( "selectedFeatures" );
|
||||||
|
QTest::addColumn<QgsFeature>( "feature" );
|
||||||
|
QTest::addColumn<QgsVectorLayer*>( "layer" );
|
||||||
|
QTest::addColumn<QVariant>( "result" );
|
||||||
|
|
||||||
|
QgsFeature firstFeature = mMemoryLayer->getFeature( 1 );
|
||||||
|
QgsVectorLayer* noLayer = nullptr;
|
||||||
|
|
||||||
|
QTest::newRow( "empty selection num_selected" ) << "num_selected()" << QgsFeatureIds() << firstFeature << mMemoryLayer << QVariant( 0 );
|
||||||
|
QTest::newRow( "empty selection is_selected" ) << "is_selected()" << QgsFeatureIds() << firstFeature << mMemoryLayer << QVariant( false );
|
||||||
|
QTest::newRow( "two_selected" ) << "num_selected()" << ( QgsFeatureIds() << 1 << 2 ) << firstFeature << mMemoryLayer << QVariant( 2 );
|
||||||
|
QTest::newRow( "is_selected" ) << "is_selected()" << ( QgsFeatureIds() << 1 << 2 ) << firstFeature << mMemoryLayer << QVariant( true );
|
||||||
|
QTest::newRow( "not_selected" ) << "is_selected()" << ( QgsFeatureIds() << 4 << 2 ) << firstFeature << mMemoryLayer << QVariant( false );
|
||||||
|
QTest::newRow( "no layer num_selected" ) << "num_selected()" << ( QgsFeatureIds() << 4 << 2 ) << QgsFeature() << noLayer << QVariant( QVariant::LongLong );
|
||||||
|
QTest::newRow( "no layer is_selected" ) << "is_selected()" << ( QgsFeatureIds() << 4 << 2 ) << QgsFeature() << noLayer << QVariant( QVariant::Bool );
|
||||||
|
QTest::newRow( "no layer num_selected" ) << "num_selected()" << ( QgsFeatureIds() << 4 << 2 ) << QgsFeature() << noLayer << QVariant( QVariant::LongLong );
|
||||||
|
QTest::newRow( "is_selected with params" ) << "is_selected('test', get_feature('test', 'col1', 10))" << ( QgsFeatureIds() << 4 << 2 ) << QgsFeature() << noLayer << QVariant( QVariant::Bool );
|
||||||
|
QTest::newRow( "num_selected with params" ) << "num_selected('test')" << ( QgsFeatureIds() << 4 << 2 ) << QgsFeature() << noLayer << QVariant( 2 );
|
||||||
|
}
|
||||||
|
|
||||||
void layerAggregates()
|
void layerAggregates()
|
||||||
{
|
{
|
||||||
QgsExpressionContext context;
|
QgsExpressionContext context;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user