Skip to content

Commit ed09a8a

Browse files
committedJun 5, 2017
Create class for encapsulating settings relating to a feature source
input to a processing algorithm. This allows parameter inputs to encapsulate extra information relating to a feature source input, such as whether only selected features from the source layer should be used.
1 parent 0e991bf commit ed09a8a

File tree

4 files changed

+143
-27
lines changed

4 files changed

+143
-27
lines changed
 

‎python/core/processing/qgsprocessingparameters.sip

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,40 @@
1111

1212

1313

14+
15+
class QgsProcessingFeatureSourceDefinition
16+
{
17+
%Docstring
18+
19+
Encapsulates settings relating to a feature source input to a processing algorithm.
20+
21+
.. versionadded:: 3.0
22+
%End
23+
24+
%TypeHeaderCode
25+
#include "qgsprocessingparameters.h"
26+
%End
27+
public:
28+
29+
QgsProcessingFeatureSourceDefinition( const QVariant &source = QVariant(), bool selectedFeaturesOnly = false );
30+
%Docstring
31+
Constructor for QgsProcessingFeatureSourceDefinition.
32+
%End
33+
34+
QVariant source;
35+
%Docstring
36+
Source definition. Usually set to a source layer's ID or file name.
37+
%End
38+
39+
bool selectedFeaturesOnly;
40+
%Docstring
41+
True if only selected features in the source should be used by algorithms.
42+
%End
43+
44+
};
45+
46+
47+
1448
class QgsProcessingFeatureSink
1549
{
1650
%Docstring
@@ -52,6 +86,7 @@ class QgsProcessingFeatureSink
5286

5387

5488

89+
5590
class QgsProcessingParameterDefinition
5691
{
5792
%Docstring

‎src/core/processing/qgsprocessingparameters.cpp

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -253,9 +253,31 @@ QgsFeatureSource *QgsProcessingParameters::parameterAsSource( const QgsProcessin
253253
if ( !definition )
254254
return nullptr;
255255

256-
QString layerRef = parameterAsString( definition, parameters, context );
257-
if ( layerRef.isEmpty() )
256+
QVariant val = parameters.value( definition->name() );
257+
258+
bool selectedFeaturesOnly = false;
259+
if ( val.canConvert<QgsProcessingFeatureSourceDefinition>() )
260+
{
261+
// input is a QgsProcessingFeatureSourceDefinition - get extra properties from it
262+
QgsProcessingFeatureSourceDefinition fromVar = qvariant_cast<QgsProcessingFeatureSourceDefinition>( val );
263+
selectedFeaturesOnly = fromVar.selectedFeaturesOnly;
264+
val = fromVar.source;
265+
}
266+
267+
QString layerRef;
268+
if ( val.canConvert<QgsProperty>() )
269+
{
270+
layerRef = val.value< QgsProperty >().valueAsString( context.expressionContext(), definition->defaultValue().toString() );
271+
}
272+
else if ( !val.isValid() || val.toString().isEmpty() )
273+
{
274+
// fall back to default
258275
layerRef = definition->defaultValue().toString();
276+
}
277+
else
278+
{
279+
layerRef = val.toString();
280+
}
259281

260282
if ( layerRef.isEmpty() )
261283
return nullptr;
@@ -264,7 +286,7 @@ QgsFeatureSource *QgsProcessingParameters::parameterAsSource( const QgsProcessin
264286
if ( !vl )
265287
return nullptr;
266288

267-
if ( context.flags() & QgsProcessingContext::UseSelectionIfPresent && vl->selectedFeatureCount() > 0 )
289+
if ( selectedFeaturesOnly )
268290
{
269291
return new QgsProcessingFeatureSource( new QgsVectorLayerSelectedFeatureSource( vl ), context, true );
270292
}

‎src/core/processing/qgsprocessingparameters.h

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,42 @@ class QgsVectorLayer;
3131
class QgsFeatureSink;
3232
class QgsFeatureSource;
3333

34+
35+
/**
36+
* \class QgsProcessingFeatureSourceDefinition
37+
* \ingroup core
38+
*
39+
* Encapsulates settings relating to a feature source input to a processing algorithm.
40+
*
41+
* \since QGIS 3.0
42+
*/
43+
44+
class CORE_EXPORT QgsProcessingFeatureSourceDefinition
45+
{
46+
public:
47+
48+
/**
49+
* Constructor for QgsProcessingFeatureSourceDefinition.
50+
*/
51+
QgsProcessingFeatureSourceDefinition( const QVariant &source = QVariant(), bool selectedFeaturesOnly = false )
52+
: source( source )
53+
, selectedFeaturesOnly( selectedFeaturesOnly )
54+
{}
55+
56+
/**
57+
* Source definition. Usually set to a source layer's ID or file name.
58+
*/
59+
QVariant source;
60+
61+
/**
62+
* True if only selected features in the source should be used by algorithms.
63+
*/
64+
bool selectedFeaturesOnly;
65+
66+
};
67+
68+
Q_DECLARE_METATYPE( QgsProcessingFeatureSourceDefinition )
69+
3470
/**
3571
* \class QgsProcessingFeatureSink
3672
* \ingroup core
@@ -73,6 +109,7 @@ Q_DECLARE_METATYPE( QgsProcessingFeatureSink )
73109

74110

75111

112+
76113
//
77114
// Parameter definitions
78115
//

‎tests/src/core/testqgsprocessing.cpp

Lines changed: 46 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,7 @@ class TestQgsProcessing: public QObject
217217
void parameterOutputVectorLayer();
218218
void checkParamValues();
219219
void combineLayerExtent();
220+
void processingFeatureSource();
220221
void processingFeatureSink();
221222

222223
private:
@@ -452,8 +453,6 @@ void TestQgsProcessing::context()
452453
context.setDefaultEncoding( "my_enc" );
453454
QCOMPARE( context.defaultEncoding(), QStringLiteral( "my_enc" ) );
454455

455-
context.setFlags( QgsProcessingContext::UseSelectionIfPresent );
456-
QCOMPARE( context.flags(), QgsProcessingContext::UseSelectionIfPresent );
457456
context.setFlags( QgsProcessingContext::Flags( 0 ) );
458457
QCOMPARE( context.flags(), QgsProcessingContext::Flags( 0 ) );
459458

@@ -695,9 +694,9 @@ void TestQgsProcessing::features()
695694
return ids;
696695
};
697696

698-
QgsProcessingParameterDefinition *def = new QgsProcessingParameterString( QStringLiteral( "string" ) );
697+
QgsProcessingParameterDefinition *def = new QgsProcessingParameterString( QStringLiteral( "layer" ) );
699698
QVariantMap params;
700-
params.insert( QStringLiteral( "string" ), layer->id() );
699+
params.insert( QStringLiteral( "layer" ), layer->id() );
701700

702701
std::unique_ptr< QgsFeatureSource > source( QgsProcessingParameters::parameterAsSource( def, params, context ) );
703702

@@ -707,32 +706,32 @@ void TestQgsProcessing::features()
707706
QCOMPARE( source->featureCount(), 5L );
708707

709708
// test with selected features
710-
context.setFlags( QgsProcessingContext::UseSelectionIfPresent );
709+
params.insert( QStringLiteral( "layer" ), QVariant::fromValue( QgsProcessingFeatureSourceDefinition( layer->id(), true ) ) );
711710
layer->selectByIds( QgsFeatureIds() << 2 << 4 );
712711
source.reset( QgsProcessingParameters::parameterAsSource( def, params, context ) );
713712
ids = getIds( source->getFeatures() );
714713
QCOMPARE( ids, QgsFeatureIds() << 2 << 4 );
715714
QCOMPARE( source->featureCount(), 2L );
716715

717716
// selection, but not using selected features
718-
context.setFlags( QgsProcessingContext::Flags( 0 ) );
717+
params.insert( QStringLiteral( "layer" ), QVariant::fromValue( QgsProcessingFeatureSourceDefinition( layer->id(), false ) ) );
719718
layer->selectByIds( QgsFeatureIds() << 2 << 4 );
720719
source.reset( QgsProcessingParameters::parameterAsSource( def, params, context ) );
721720
ids = getIds( source->getFeatures() );
722721
QCOMPARE( ids, QgsFeatureIds() << 1 << 2 << 3 << 4 << 5 );
723722
QCOMPARE( source->featureCount(), 5L );
724723

725724
// using selected features, but no selection
726-
context.setFlags( QgsProcessingContext::UseSelectionIfPresent );
725+
params.insert( QStringLiteral( "layer" ), QVariant::fromValue( QgsProcessingFeatureSourceDefinition( layer->id(), true ) ) );
727726
layer->removeSelection();
728727
source.reset( QgsProcessingParameters::parameterAsSource( def, params, context ) );
729728
ids = getIds( source->getFeatures() );
730-
QCOMPARE( ids, QgsFeatureIds() << 1 << 2 << 3 << 4 << 5 );
731-
QCOMPARE( source->featureCount(), 5L );
729+
QVERIFY( ids.isEmpty() );
730+
QCOMPARE( source->featureCount(), 0L );
732731

733732

734733
// test that feature request is honored
735-
context.setFlags( QgsProcessingContext::Flags( 0 ) );
734+
params.insert( QStringLiteral( "layer" ), QVariant::fromValue( QgsProcessingFeatureSourceDefinition( layer->id(), false ) ) );
736735
source.reset( QgsProcessingParameters::parameterAsSource( def, params, context ) );
737736
ids = getIds( source->getFeatures( QgsFeatureRequest().setFilterFids( QgsFeatureIds() << 1 << 3 << 5 ) ) );
738737
QCOMPARE( ids, QgsFeatureIds() << 1 << 3 << 5 );
@@ -741,7 +740,7 @@ void TestQgsProcessing::features()
741740
QCOMPARE( source->featureCount(), 5L );
742741

743742
//test that feature request is honored when using selections
744-
context.setFlags( QgsProcessingContext::UseSelectionIfPresent );
743+
params.insert( QStringLiteral( "layer" ), QVariant::fromValue( QgsProcessingFeatureSourceDefinition( layer->id(), true ) ) );
745744
layer->selectByIds( QgsFeatureIds() << 2 << 4 );
746745
source.reset( QgsProcessingParameters::parameterAsSource( def, params, context ) );
747746
ids = getIds( source->getFeatures( QgsFeatureRequest().setFlags( QgsFeatureRequest::NoGeometry ) ) );
@@ -754,15 +753,14 @@ void TestQgsProcessing::features()
754753
encountered = true;
755754
};
756755

757-
context.setFlags( QgsProcessingContext::Flags( 0 ) );
758756
context.setInvalidGeometryCheck( QgsFeatureRequest::GeometryAbortOnInvalid );
759757
context.setInvalidGeometryCallback( callback );
760758
QgsVectorLayer *polyLayer = new QgsVectorLayer( "Polygon", "v2", "memory" );
761759
QgsFeature f;
762760
f.setGeometry( QgsGeometry::fromWkt( QStringLiteral( "Polygon((0 0, 1 0, 0 1, 1 1, 0 0))" ) ) );
763761
polyLayer->dataProvider()->addFeatures( QgsFeatureList() << f );
764762
p.addMapLayer( polyLayer );
765-
params.insert( QStringLiteral( "string" ), polyLayer->id() );
763+
params.insert( QStringLiteral( "layer" ), polyLayer->id() );
766764

767765
source.reset( QgsProcessingParameters::parameterAsSource( def, params, context ) );
768766
ids = getIds( source->getFeatures() );
@@ -793,9 +791,9 @@ void TestQgsProcessing::uniqueValues()
793791
p.addMapLayer( layer );
794792
context.setProject( &p );
795793

796-
QgsProcessingParameterDefinition *def = new QgsProcessingParameterString( QStringLiteral( "string" ) );
794+
QgsProcessingParameterDefinition *def = new QgsProcessingParameterString( QStringLiteral( "layer" ) );
797795
QVariantMap params;
798-
params.insert( QStringLiteral( "string" ), layer->id() );
796+
params.insert( QStringLiteral( "layer" ), layer->id() );
799797

800798
std::unique_ptr< QgsFeatureSource > source( QgsProcessingParameters::parameterAsSource( def, params, context ) );
801799

@@ -831,7 +829,7 @@ void TestQgsProcessing::uniqueValues()
831829
QVERIFY( vals.contains( QString( "C" ) ) );
832830

833831
// selection and using selection
834-
context.setFlags( QgsProcessingContext::UseSelectionIfPresent );
832+
params.insert( QStringLiteral( "layer" ), QVariant::fromValue( QgsProcessingFeatureSourceDefinition( layer->id(), true ) ) );
835833
source.reset( QgsProcessingParameters::parameterAsSource( def, params, context ) );
836834
QVERIFY( source->uniqueValues( -1 ).isEmpty() );
837835
QVERIFY( source->uniqueValues( 10001 ).isEmpty() );
@@ -860,23 +858,31 @@ void TestQgsProcessing::createIndex()
860858
p.addMapLayer( layer );
861859
context.setProject( &p );
862860

863-
QgsProcessingParameterDefinition *def = new QgsProcessingParameterString( QStringLiteral( "string" ) );
861+
QgsProcessingParameterDefinition *def = new QgsProcessingParameterString( QStringLiteral( "layer" ) );
864862
QVariantMap params;
865-
params.insert( QStringLiteral( "string" ), layer->id() );
863+
params.insert( QStringLiteral( "layer" ), layer->id() );
866864

867865
// disable selected features check
868-
context.setFlags( QgsProcessingContext::Flags( 0 ) );
869866
std::unique_ptr< QgsFeatureSource > source( QgsProcessingParameters::parameterAsSource( def, params, context ) );
867+
QVERIFY( source.get() );
870868
QgsSpatialIndex index( *source.get() );
871869
QList<QgsFeatureId> ids = index.nearestNeighbor( QgsPointXY( 2.1, 2 ), 1 );
872870
QCOMPARE( ids, QList<QgsFeatureId>() << 2 );
873871

874872
// selected features check, but none selected
875-
context.setFlags( QgsProcessingContext::UseSelectionIfPresent );
873+
params.insert( QStringLiteral( "layer" ), QVariant::fromValue( QgsProcessingFeatureSourceDefinition( layer->id(), true ) ) );
876874
source.reset( QgsProcessingParameters::parameterAsSource( def, params, context ) );
877-
index = QgsSpatialIndex( *source.get() );
878-
ids = index.nearestNeighbor( QgsPointXY( 2.1, 2 ), 1 );
879-
QCOMPARE( ids, QList<QgsFeatureId>() << 2 );
875+
bool caught;
876+
try
877+
{
878+
index = QgsSpatialIndex( *source.get() );
879+
ids = index.nearestNeighbor( QgsPointXY( 2.1, 2 ), 1 );
880+
}
881+
catch ( ... )
882+
{
883+
caught = true;
884+
}
885+
QVERIFY( caught );
880886

881887
// create selection
882888
layer->selectByIds( QgsFeatureIds() << 4 << 5 );
@@ -886,7 +892,7 @@ void TestQgsProcessing::createIndex()
886892
QCOMPARE( ids, QList<QgsFeatureId>() << 4 );
887893

888894
// selection but not using selection mode
889-
context.setFlags( QgsProcessingContext::Flags( 0 ) );
895+
params.insert( QStringLiteral( "layer" ), QVariant::fromValue( QgsProcessingFeatureSourceDefinition( layer->id(), false ) ) );
890896
source.reset( QgsProcessingParameters::parameterAsSource( def, params, context ) );
891897
index = QgsSpatialIndex( *source.get() );
892898
ids = index.nearestNeighbor( QgsPointXY( 2.1, 2 ), 1 );
@@ -2305,6 +2311,22 @@ void TestQgsProcessing::combineLayerExtent()
23052311
QGSCOMPARENEAR( ext.yMaximum(), 3536664, 10 );
23062312
}
23072313

2314+
void TestQgsProcessing::processingFeatureSource()
2315+
{
2316+
QVariant source( QStringLiteral( "test.shp" ) );
2317+
QgsProcessingFeatureSourceDefinition fs( source, true );
2318+
QCOMPARE( fs.source, source );
2319+
QVERIFY( fs.selectedFeaturesOnly );
2320+
2321+
// test storing QgsProcessingFeatureSource in variant and retrieving
2322+
QVariant fsInVariant = QVariant::fromValue( fs );
2323+
QVERIFY( fsInVariant.isValid() );
2324+
2325+
QgsProcessingFeatureSourceDefinition fromVar = qvariant_cast<QgsProcessingFeatureSourceDefinition>( fsInVariant );
2326+
QCOMPARE( fromVar.source, source );
2327+
QVERIFY( fromVar.selectedFeaturesOnly );
2328+
}
2329+
23082330
void TestQgsProcessing::processingFeatureSink()
23092331
{
23102332
QVariant sink( QStringLiteral( "test.shp" ) );

0 commit comments

Comments
 (0)
Please sign in to comment.