mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-14 00:07:35 -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* )
|
||||
{
|
||||
QString layerString = value.toString();
|
||||
QgsVectorLayer* vl = qobject_cast<QgsVectorLayer*>( QgsMapLayerRegistry::instance()->mapLayer( layerString ) ); //search by id first
|
||||
QgsVectorLayer* vl = value.value<QgsVectorLayer*>();
|
||||
if ( !vl )
|
||||
{
|
||||
QList<QgsMapLayer *> layersByName = QgsMapLayerRegistry::instance()->mapLayersByName( layerString );
|
||||
if ( !layersByName.isEmpty() )
|
||||
QString layerString = value.toString();
|
||||
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
|
||||
QString layerId = context->variable( QStringLiteral( "layer_id" ) ).toString();
|
||||
QgsVectorLayer* vl = qobject_cast<QgsVectorLayer*>( QgsMapLayerRegistry::instance()->mapLayer( layerId ) );
|
||||
QgsVectorLayer* vl = getVectorLayer( context->variable( "layer" ), parent );
|
||||
if ( !vl )
|
||||
{
|
||||
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
|
||||
QString layerId = context->variable( QStringLiteral( "layer_id" ) ).toString();
|
||||
QgsVectorLayer* vl = qobject_cast<QgsVectorLayer*>( QgsMapLayerRegistry::instance()->mapLayer( layerId ) );
|
||||
QgsVectorLayer* vl = getVectorLayer( context->variable( "layer" ), parent );
|
||||
if ( !vl )
|
||||
{
|
||||
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 );
|
||||
}
|
||||
|
||||
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 )
|
||||
{
|
||||
QString concat;
|
||||
@ -3665,10 +3725,37 @@ const QList<QgsExpression::Function*>& QgsExpression::Functions()
|
||||
<< Parameter( QStringLiteral( "vertex" ) ), fcnAngleAtVertex, QStringLiteral( "GeometryGroup" ) )
|
||||
<< new StaticFunction( QStringLiteral( "distance_to_vertex" ), ParameterList() << Parameter( QStringLiteral( "geometry" ) )
|
||||
<< Parameter( QStringLiteral( "vertex" ) ), fcnDistanceToVertex, QStringLiteral( "GeometryGroup" ) )
|
||||
|
||||
|
||||
// **Record** functions
|
||||
|
||||
<< new StaticFunction( QStringLiteral( "$id" ), 0, fcnFeatureId, 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( "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( "var" ), 1, fcnGetVariable, QStringLiteral( "General" ) )
|
||||
|
||||
@ -5290,6 +5377,7 @@ void QgsExpression::initVariableHelp()
|
||||
//layer variables
|
||||
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" ), QCoreApplication::translate( "variable_help", "The current layer." ) );
|
||||
|
||||
//composition variables
|
||||
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_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 );
|
||||
if ( vLayer )
|
||||
|
@ -581,7 +581,7 @@ class CORE_EXPORT QgsExpressionContextUtils
|
||||
/** Creates a new scope which contains variables and functions relating to a QgsMapLayer.
|
||||
* 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
|
||||
* layerScope().
|
||||
|
@ -1355,6 +1355,55 @@ class TestQgsExpression: public QObject
|
||||
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()
|
||||
{
|
||||
QgsExpressionContext context;
|
||||
|
Loading…
x
Reference in New Issue
Block a user