diff --git a/src/core/processing/models/qgsprocessingmodelalgorithm.cpp b/src/core/processing/models/qgsprocessingmodelalgorithm.cpp index 486d59ebb33..ceb41a0c92d 100644 --- a/src/core/processing/models/qgsprocessingmodelalgorithm.cpp +++ b/src/core/processing/models/qgsprocessingmodelalgorithm.cpp @@ -580,6 +580,11 @@ QMap QgsProcessingMode QgsProcessingFeatureSourceDefinition fromVar = qvariant_cast( value ); value = fromVar.source; } + else if ( value.canConvert() ) + { + QgsProcessingOutputLayerDefinition fromVar = qvariant_cast( value ); + value = fromVar.sink; + } if ( QgsVectorLayer *layer = qobject_cast< QgsVectorLayer * >( qvariant_cast( value ) ) ) { featureSource = layer; diff --git a/src/core/processing/qgsprocessingalgorithm.cpp b/src/core/processing/qgsprocessingalgorithm.cpp index feec5889965..8332f201e6b 100644 --- a/src/core/processing/qgsprocessingalgorithm.cpp +++ b/src/core/processing/qgsprocessingalgorithm.cpp @@ -687,6 +687,11 @@ QString QgsProcessingAlgorithm::invalidSourceError( const QVariantMap ¶meter QgsProcessingFeatureSourceDefinition fromVar = qvariant_cast( var ); var = fromVar.source; } + else if ( var.canConvert() ) + { + QgsProcessingOutputLayerDefinition fromVar = qvariant_cast( var ); + var = fromVar.sink; + } if ( var.canConvert() ) { QgsProperty p = var.value< QgsProperty >(); diff --git a/src/core/processing/qgsprocessingparameters.cpp b/src/core/processing/qgsprocessingparameters.cpp index b61b106b6c7..fb5ed0a4b69 100644 --- a/src/core/processing/qgsprocessingparameters.cpp +++ b/src/core/processing/qgsprocessingparameters.cpp @@ -321,6 +321,12 @@ QString QgsProcessingParameters::parameterAsCompatibleSourceLayerPath( const Qgs selectedFeaturesOnly = fromVar.selectedFeaturesOnly; val = fromVar.source; } + else if ( val.canConvert() ) + { + // input is a QgsProcessingOutputLayerDefinition - get extra properties from it + QgsProcessingOutputLayerDefinition fromVar = qvariant_cast( val ); + val = fromVar.sink; + } if ( val.canConvert() ) { @@ -513,6 +519,12 @@ QgsCoordinateReferenceSystem QgsProcessingParameters::parameterAsCrs( const QgsP QgsProcessingFeatureSourceDefinition fromVar = qvariant_cast( val ); val = fromVar.source; } + else if ( val.canConvert() ) + { + // input is a QgsProcessingOutputLayerDefinition - get extra properties from it + QgsProcessingOutputLayerDefinition fromVar = qvariant_cast( val ); + val = fromVar.sink; + } if ( val.canConvert() && val.value< QgsProperty >().propertyType() == QgsProperty::StaticProperty ) { @@ -589,6 +601,12 @@ QgsRectangle QgsProcessingParameters::parameterAsExtent( const QgsProcessingPara QgsProcessingFeatureSourceDefinition fromVar = qvariant_cast( val ); val = fromVar.source; } + else if ( val.canConvert() ) + { + // input is a QgsProcessingOutputLayerDefinition - get extra properties from it + QgsProcessingOutputLayerDefinition fromVar = qvariant_cast( val ); + val = fromVar.sink; + } if ( val.canConvert() && val.value< QgsProperty >().propertyType() == QgsProperty::StaticProperty ) { @@ -696,6 +714,12 @@ QgsGeometry QgsProcessingParameters::parameterAsExtentGeometry( const QgsProcess QgsProcessingFeatureSourceDefinition fromVar = qvariant_cast( val ); val = fromVar.source; } + else if ( val.canConvert() ) + { + // input is a QgsProcessingOutputLayerDefinition - get extra properties from it + QgsProcessingOutputLayerDefinition fromVar = qvariant_cast( val ); + val = fromVar.sink; + } if ( val.canConvert() && val.value< QgsProperty >().propertyType() == QgsProperty::StaticProperty ) { @@ -794,6 +818,12 @@ QgsCoordinateReferenceSystem QgsProcessingParameters::parameterAsExtentCrs( cons QgsProcessingFeatureSourceDefinition fromVar = qvariant_cast( val ); val = fromVar.source; } + else if ( val.canConvert() ) + { + // input is a QgsProcessingOutputLayerDefinition - get extra properties from it + QgsProcessingOutputLayerDefinition fromVar = qvariant_cast( val ); + val = fromVar.sink; + } if ( val.canConvert() && val.value< QgsProperty >().propertyType() == QgsProperty::StaticProperty ) { @@ -822,6 +852,12 @@ QgsCoordinateReferenceSystem QgsProcessingParameters::parameterAsExtentCrs( cons QgsProcessingFeatureSourceDefinition fromVar = qvariant_cast( val ); val = fromVar.source; } + else if ( val.canConvert() ) + { + // input is a QgsProcessingOutputLayerDefinition - get extra properties from it + QgsProcessingOutputLayerDefinition fromVar = qvariant_cast( val ); + val = fromVar.sink; + } if ( val.canConvert() && val.value< QgsProperty >().propertyType() == QgsProperty::StaticProperty ) { @@ -1451,6 +1487,10 @@ bool QgsProcessingParameterCrs::checkValueIsAcceptable( const QVariant &input, Q { return true; } + else if ( input.canConvert() ) + { + return true; + } if ( input.canConvert() ) { @@ -1567,6 +1607,15 @@ bool QgsProcessingParameterExtent::checkValueIsAcceptable( const QVariant &input if ( !input.isValid() ) return mFlags & FlagOptional; + if ( input.canConvert() ) + { + return true; + } + else if ( input.canConvert() ) + { + return true; + } + if ( input.canConvert() ) { return true; @@ -3097,6 +3146,12 @@ bool QgsProcessingParameterFeatureSource::checkValueIsAcceptable( const QVariant QgsProcessingFeatureSourceDefinition fromVar = qvariant_cast( var ); var = fromVar.source; } + else if ( var.canConvert() ) + { + // input is a QgsProcessingOutputLayerDefinition - get extra properties from it + QgsProcessingOutputLayerDefinition fromVar = qvariant_cast( var ); + var = fromVar.sink; + } if ( var.canConvert() ) { diff --git a/src/core/processing/qgsprocessingutils.cpp b/src/core/processing/qgsprocessingutils.cpp index 953bde61e1b..faca2d0e31e 100644 --- a/src/core/processing/qgsprocessingutils.cpp +++ b/src/core/processing/qgsprocessingutils.cpp @@ -239,6 +239,12 @@ QgsProcessingFeatureSource *QgsProcessingUtils::variantToSource( const QVariant selectedFeaturesOnly = fromVar.selectedFeaturesOnly; val = fromVar.source; } + else if ( val.canConvert() ) + { + // input is a QgsProcessingOutputLayerDefinition (e.g. an output from earlier in a model) - get extra properties from it + QgsProcessingOutputLayerDefinition fromVar = qvariant_cast( val ); + val = fromVar.sink; + } if ( QgsVectorLayer *layer = qobject_cast< QgsVectorLayer * >( qvariant_cast( val ) ) ) { diff --git a/tests/src/analysis/testqgsprocessing.cpp b/tests/src/analysis/testqgsprocessing.cpp index 789fb360d09..fef0e287a84 100644 --- a/tests/src/analysis/testqgsprocessing.cpp +++ b/tests/src/analysis/testqgsprocessing.cpp @@ -2111,6 +2111,7 @@ void TestQgsProcessing::parameterCrs() QVERIFY( !def->checkValueIsAcceptable( QVariant() ) ); QVERIFY( def->checkValueIsAcceptable( QgsProcessingFeatureSourceDefinition( r1->id() ) ) ); QVERIFY( def->checkValueIsAcceptable( QgsProcessingFeatureSourceDefinition( QgsProperty::fromValue( QVariant::fromValue( r1 ) ) ) ) ); + QVERIFY( def->checkValueIsAcceptable( QgsProcessingOutputLayerDefinition( r1->id() ) ) ); // using map layer QVariantMap params; @@ -2149,6 +2150,8 @@ void TestQgsProcessing::parameterCrs() QCOMPARE( QgsProcessingParameters::parameterAsCrs( def.get(), params, context ).authid(), QString( "EPSG:3111" ) ); params.insert( "non_optional", QgsProcessingFeatureSourceDefinition( QgsProperty::fromValue( QVariant::fromValue( v1 ) ) ) ); QCOMPARE( QgsProcessingParameters::parameterAsCrs( def.get(), params, context ).authid(), QString( "EPSG:3111" ) ); + params.insert( "non_optional", QgsProcessingOutputLayerDefinition( v1->id() ) ); + QCOMPARE( QgsProcessingParameters::parameterAsCrs( def.get(), params, context ).authid(), QString( "EPSG:3111" ) ); QCOMPARE( def->valueAsPythonString( QVariant(), context ), QStringLiteral( "None" ) ); QCOMPARE( def->valueAsPythonString( "EPSG:12003", context ), QStringLiteral( "'EPSG:12003'" ) ); @@ -2362,6 +2365,9 @@ void TestQgsProcessing::parameterExtent() QVERIFY( !def->checkValueIsAcceptable( "1,2,3", &context ) ); QVERIFY( !def->checkValueIsAcceptable( "1,2,3,a", &context ) ); + QVERIFY( def->checkValueIsAcceptable( QgsProcessingFeatureSourceDefinition( r1->id() ) ) ); + QVERIFY( def->checkValueIsAcceptable( QgsProcessingOutputLayerDefinition( r1->id() ) ) ); + // using map layer QVariantMap params; params.insert( "non_optional", r1->id() ); @@ -2428,6 +2434,22 @@ void TestQgsProcessing::parameterExtent() QGSCOMPARENEAR( ext.yMinimum(), 5083255, 100 ); QGSCOMPARENEAR( ext.yMaximum(), 5083355, 100 ); + // using output layer definition, e.g. from a previous model child algorithm + params.insert( "non_optional", QgsProcessingOutputLayerDefinition( r1->id() ) ); + QCOMPARE( QgsProcessingParameters::parameterAsExtentCrs( def.get(), params, context ).authid(), QStringLiteral( "EPSG:4326" ) ); + ext = QgsProcessingParameters::parameterAsExtent( def.get(), params, context, QgsCoordinateReferenceSystem( "EPSG:4326" ) ); + QGSCOMPARENEAR( ext.xMinimum(), 1535375, 100 ); + QGSCOMPARENEAR( ext.xMaximum(), 1535475, 100 ); + QGSCOMPARENEAR( ext.yMinimum(), 5083255, 100 ); + QGSCOMPARENEAR( ext.yMaximum(), 5083355, 100 ); + gExt = QgsProcessingParameters::parameterAsExtentGeometry( def.get(), params, context, QgsCoordinateReferenceSystem( "EPSG:4326" ) ); + QCOMPARE( gExt.constGet()->vertexCount(), 5 ); + ext = gExt.boundingBox(); + QGSCOMPARENEAR( ext.xMinimum(), 1535375, 100 ); + QGSCOMPARENEAR( ext.xMaximum(), 1535475, 100 ); + QGSCOMPARENEAR( ext.yMinimum(), 5083255, 100 ); + QGSCOMPARENEAR( ext.yMaximum(), 5083355, 100 ); + // string representing a non-project layer source params.insert( "non_optional", raster2 ); QVERIFY( def->checkValueIsAcceptable( raster2 ) ); @@ -4454,7 +4476,8 @@ void TestQgsProcessing::parameterFeatureSource() QCOMPARE( QgsProcessingAlgorithm::invalidSourceError( params, QStringLiteral( "INPUT" ) ), QStringLiteral( "Could not load source layer for INPUT: my prop layer not found" ) ); params.insert( QStringLiteral( "INPUT" ), QVariant::fromValue( v1 ) ); QCOMPARE( QgsProcessingAlgorithm::invalidSourceError( params, QStringLiteral( "INPUT" ) ), QStringLiteral( "Could not load source layer for INPUT: invalid value" ) ); - + params.insert( QStringLiteral( "INPUT" ), QgsProcessingOutputLayerDefinition( QStringLiteral( "my prop layer" ) ) ); + QCOMPARE( QgsProcessingAlgorithm::invalidSourceError( params, QStringLiteral( "INPUT" ) ), QStringLiteral( "Could not load source layer for INPUT: my prop layer not found" ) ); } void TestQgsProcessing::parameterFeatureSink() @@ -5156,7 +5179,6 @@ void TestQgsProcessing::processingFeatureSource() QVERIFY( source->getFeatures().nextFeature( f2 ) ); QCOMPARE( f2.geometry(), f.geometry() ); - // next using property based definition params.insert( QStringLiteral( "layer" ), QgsProcessingFeatureSourceDefinition( QgsProperty::fromExpression( QStringLiteral( "trim('%1' + ' ')" ).arg( layer->id() ) ), false ) ); source.reset( QgsProcessingParameters::parameterAsSource( def.get(), params, context ) ); @@ -5164,6 +5186,14 @@ void TestQgsProcessing::processingFeatureSource() QVERIFY( source.get() ); QVERIFY( source->getFeatures().nextFeature( f2 ) ); QCOMPARE( f2.geometry(), f.geometry() ); + + // we also must accept QgsProcessingOutputLayerDefinition - e.g. to allow outputs from earlier child algorithms in models + params.insert( QStringLiteral( "layer" ), QgsProcessingOutputLayerDefinition( QgsProperty::fromValue( layer->id() ) ) ); + source.reset( QgsProcessingParameters::parameterAsSource( def.get(), params, context ) ); + // can't directly match it to layer, so instead just get the feature and test that it matches what we expect + QVERIFY( source.get() ); + QVERIFY( source->getFeatures().nextFeature( f2 ) ); + QCOMPARE( f2.geometry(), f.geometry() ); } void TestQgsProcessing::processingFeatureSink() @@ -6584,6 +6614,11 @@ void TestQgsProcessing::convertCompatible() params.remove( QStringLiteral( "source" ) ); out = QgsProcessingParameters::parameterAsCompatibleSourceLayerPath( def.get(), params, context, QStringList() << "shp", QString( "shp" ), &feedback ); QCOMPARE( out, layer->source() ); + + // output layer as input - e.g. from a previous model child + params.insert( QStringLiteral( "source" ), QgsProcessingOutputLayerDefinition( layer->id() ) ); + out = QgsProcessingParameters::parameterAsCompatibleSourceLayerPath( def.get(), params, context, QStringList() << "shp", QString( "shp" ), &feedback ); + QCOMPARE( out, layer->source() ); } void TestQgsProcessing::create()