Skip to content

Commit 6307bc4

Browse files
authored
Merge pull request #4808 from nyalldawson/model_out_layer_names
Fix incorrect layer names used when loading result layers from models
2 parents b57cd0d + bdaba00 commit 6307bc4

File tree

5 files changed

+92
-5
lines changed

5 files changed

+92
-5
lines changed

python/core/processing/qgsprocessingparameters.sip

+5
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,11 @@ class QgsProcessingOutputLayerDefinition
9595
The default behavior is not to load the result into any project (None).
9696
%End
9797

98+
QString destinationName;
99+
%Docstring
100+
Name to use for sink if it's to be loaded into a destination project.
101+
%End
102+
98103
QVariantMap createOptions;
99104
%Docstring
100105
Map of optional sink/layer creation options, which

src/core/processing/qgsprocessingmodelalgorithm.cpp

+12-1
Original file line numberDiff line numberDiff line change
@@ -407,7 +407,18 @@ QVariantMap QgsProcessingModelAlgorithm::parametersForChildAlgorithm( const Chil
407407
{
408408
QString paramName = child.childId() + ':' + outputIt.key();
409409
if ( modelParameters.contains( paramName ) )
410-
childParams.insert( destParam->name(), modelParameters.value( paramName ) );
410+
{
411+
QVariant value = modelParameters.value( paramName );
412+
if ( value.canConvert<QgsProcessingOutputLayerDefinition>() )
413+
{
414+
// make sure layout output name is correctly set
415+
QgsProcessingOutputLayerDefinition fromVar = qvariant_cast<QgsProcessingOutputLayerDefinition>( value );
416+
fromVar.destinationName = outputIt.key();
417+
value = QVariant::fromValue( fromVar );
418+
}
419+
420+
childParams.insert( destParam->name(), value );
421+
}
411422
isFinalOutput = true;
412423
break;
413424
}

src/core/processing/qgsprocessingparameters.cpp

+18-2
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,7 @@ QgsFeatureSink *QgsProcessingParameters::parameterAsSink( const QgsProcessingPar
219219
}
220220

221221
QgsProject *destinationProject = nullptr;
222+
QString destName;
222223
QVariantMap createOptions;
223224
if ( val.canConvert<QgsProcessingOutputLayerDefinition>() )
224225
{
@@ -227,6 +228,7 @@ QgsFeatureSink *QgsProcessingParameters::parameterAsSink( const QgsProcessingPar
227228
destinationProject = fromVar.destinationProject;
228229
createOptions = fromVar.createOptions;
229230
val = fromVar.sink;
231+
destName = fromVar.destinationName;
230232
}
231233

232234
QString dest;
@@ -256,7 +258,13 @@ QgsFeatureSink *QgsProcessingParameters::parameterAsSink( const QgsProcessingPar
256258
destinationIdentifier = dest;
257259

258260
if ( destinationProject )
259-
context.addLayerToLoadOnCompletion( destinationIdentifier, QgsProcessingContext::LayerDetails( definition ? definition->description() : QString(), destinationProject ) );
261+
{
262+
if ( destName.isEmpty() && definition )
263+
{
264+
destName = definition->description();
265+
}
266+
context.addLayerToLoadOnCompletion( destinationIdentifier, QgsProcessingContext::LayerDetails( destName, destinationProject ) );
267+
}
260268

261269
return sink.release();
262270
}
@@ -371,13 +379,15 @@ QString QgsProcessingParameters::parameterAsRasterOutputLayer( const QgsProcessi
371379

372380
QgsProject *destinationProject = nullptr;
373381
QVariantMap createOptions;
382+
QString destName;
374383
if ( val.canConvert<QgsProcessingOutputLayerDefinition>() )
375384
{
376385
// input is a QgsProcessingOutputLayerDefinition - get extra properties from it
377386
QgsProcessingOutputLayerDefinition fromVar = qvariant_cast<QgsProcessingOutputLayerDefinition>( val );
378387
destinationProject = fromVar.destinationProject;
379388
createOptions = fromVar.createOptions;
380389
val = fromVar.sink;
390+
destName = fromVar.destinationName;
381391
}
382392

383393
QString dest;
@@ -396,7 +406,13 @@ QString QgsProcessingParameters::parameterAsRasterOutputLayer( const QgsProcessi
396406
}
397407

398408
if ( destinationProject )
399-
context.addLayerToLoadOnCompletion( dest, QgsProcessingContext::LayerDetails( definition ? definition->description() : QString(), destinationProject ) );
409+
{
410+
if ( destName.isEmpty() && definition )
411+
{
412+
destName = definition->description();
413+
}
414+
context.addLayerToLoadOnCompletion( dest, QgsProcessingContext::LayerDetails( destName, destinationProject ) );
415+
}
400416

401417
return dest;
402418
}

src/core/processing/qgsprocessingparameters.h

+5
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,11 @@ class CORE_EXPORT QgsProcessingOutputLayerDefinition
128128
*/
129129
QgsProject *destinationProject;
130130

131+
/**
132+
* Name to use for sink if it's to be loaded into a destination project.
133+
*/
134+
QString destinationName;
135+
131136
/**
132137
* Map of optional sink/layer creation options, which
133138
* are passed to the underlying provider when creating new layers. Known options also

tests/src/core/testqgsprocessing.cpp

+52-2
Original file line numberDiff line numberDiff line change
@@ -1292,6 +1292,18 @@ void TestQgsProcessing::parameters()
12921292
QCOMPARE( context.layersToLoadOnCompletion().size(), 1 );
12931293
QCOMPARE( context.layersToLoadOnCompletion().keys().at( 0 ), destId );
12941294
QCOMPARE( context.layersToLoadOnCompletion().values().at( 0 ).name, QStringLiteral( "desc" ) );
1295+
1296+
// with name overloading
1297+
QgsProcessingContext context2;
1298+
fs = QgsProcessingOutputLayerDefinition( QStringLiteral( "test.shp" ) );
1299+
fs.destinationProject = &p;
1300+
fs.destinationName = QStringLiteral( "my_dest" );
1301+
params.insert( QStringLiteral( "fs" ), QVariant::fromValue( fs ) );
1302+
sink.reset( QgsProcessingParameters::parameterAsSink( def.get(), params, fields, wkbType, crs, context2, destId ) );
1303+
QVERIFY( sink.get() );
1304+
QCOMPARE( context2.layersToLoadOnCompletion().size(), 1 );
1305+
QCOMPARE( context2.layersToLoadOnCompletion().keys().at( 0 ), destId );
1306+
QCOMPARE( context2.layersToLoadOnCompletion().values().at( 0 ).name, QStringLiteral( "my_dest" ) );
12951307
}
12961308

12971309
void TestQgsProcessing::algorithmParameters()
@@ -3687,6 +3699,29 @@ void TestQgsProcessing::parameterRasterOut()
36873699
QCOMPARE( fromCode->description(), QStringLiteral( "optional" ) );
36883700
QCOMPARE( fromCode->flags(), def->flags() );
36893701
QCOMPARE( fromCode->defaultValue(), def->defaultValue() );
3702+
3703+
// test layers to load on completion
3704+
def.reset( new QgsProcessingParameterRasterOutput( "x", QStringLiteral( "desc" ), QStringLiteral( "default.tif" ), true ) );
3705+
QgsProcessingOutputLayerDefinition fs = QgsProcessingOutputLayerDefinition( QStringLiteral( "test.tif" ) );
3706+
fs.destinationProject = &p;
3707+
params.insert( QStringLiteral( "x" ), QVariant::fromValue( fs ) );
3708+
QCOMPARE( QgsProcessingParameters::parameterAsRasterOutputLayer( def.get(), params, context ), QStringLiteral( "test.tif" ) );
3709+
3710+
// make sure layer was automatically added to list to load on completion
3711+
QCOMPARE( context.layersToLoadOnCompletion().size(), 1 );
3712+
QCOMPARE( context.layersToLoadOnCompletion().keys().at( 0 ), QStringLiteral( "test.tif" ) );
3713+
QCOMPARE( context.layersToLoadOnCompletion().values().at( 0 ).name, QStringLiteral( "desc" ) );
3714+
3715+
// with name overloading
3716+
QgsProcessingContext context2;
3717+
fs = QgsProcessingOutputLayerDefinition( QStringLiteral( "test.tif" ) );
3718+
fs.destinationProject = &p;
3719+
fs.destinationName = QStringLiteral( "my_dest" );
3720+
params.insert( QStringLiteral( "x" ), QVariant::fromValue( fs ) );
3721+
QCOMPARE( QgsProcessingParameters::parameterAsRasterOutputLayer( def.get(), params, context2 ), QStringLiteral( "test.tif" ) );
3722+
QCOMPARE( context2.layersToLoadOnCompletion().size(), 1 );
3723+
QCOMPARE( context2.layersToLoadOnCompletion().keys().at( 0 ), QStringLiteral( "test.tif" ) );
3724+
QCOMPARE( context2.layersToLoadOnCompletion().values().at( 0 ).name, QStringLiteral( "my_dest" ) );
36903725
}
36913726

36923727
void TestQgsProcessing::parameterFileOut()
@@ -4672,6 +4707,9 @@ void TestQgsProcessing::modelExecution()
46724707
modelInputs.insert( "SOURCE_LAYER", "my_layer_id" );
46734708
modelInputs.insert( "DIST", 271 );
46744709
modelInputs.insert( "cx1:MODEL_OUT_LAYER", "dest.shp" );
4710+
QgsProcessingOutputLayerDefinition layerDef( "memory:" );
4711+
layerDef.destinationName = "my_dest";
4712+
modelInputs.insert( "cx3:MY_OUT", QVariant::fromValue( layerDef ) );
46754713
QMap<QString, QVariantMap> childResults;
46764714
QVariantMap params = model2.parametersForChildAlgorithm( model2.childAlgorithm( "cx1" ), modelInputs, childResults );
46774715
QCOMPARE( params.value( "DISSOLVE" ).toBool(), false );
@@ -4704,24 +4742,36 @@ void TestQgsProcessing::modelExecution()
47044742
alg2c3.setAlgorithmId( "native:extractbyexpression" );
47054743
alg2c3.addParameterSources( "INPUT", QgsProcessingModelAlgorithm::ChildParameterSources() << QgsProcessingModelAlgorithm::ChildParameterSource::fromChildOutput( "cx1", "OUTPUT_LAYER" ) );
47064744
alg2c3.addParameterSources( "EXPRESSION", QgsProcessingModelAlgorithm::ChildParameterSources() << QgsProcessingModelAlgorithm::ChildParameterSource::fromStaticValue( "true" ) );
4745+
alg2c3.addParameterSources( "OUTPUT", QgsProcessingModelAlgorithm::ChildParameterSources() << QgsProcessingModelAlgorithm::ChildParameterSource::fromModelParameter( "MY_OUT" ) );
47074746
alg2c3.setDependencies( QStringList() << "cx2" );
4747+
QMap<QString, QgsProcessingModelAlgorithm::ModelOutput> outputs3;
4748+
QgsProcessingModelAlgorithm::ModelOutput out2( "MY_OUT" );
4749+
out2.setChildOutputName( "OUTPUT" );
4750+
outputs3.insert( QStringLiteral( "MY_OUT" ), out2 );
4751+
alg2c3.setModelOutputs( outputs3 );
4752+
47084753
model2.addChildAlgorithm( alg2c3 );
47094754
params = model2.parametersForChildAlgorithm( model2.childAlgorithm( "cx3" ), modelInputs, childResults );
47104755
QCOMPARE( params.value( "INPUT" ).toString(), QStringLiteral( "dest.shp" ) );
47114756
QCOMPARE( params.value( "EXPRESSION" ).toString(), QStringLiteral( "true" ) );
4712-
QCOMPARE( params.value( "OUTPUT" ).toString(), QStringLiteral( "memory:" ) );
4757+
QVERIFY( params.value( "OUTPUT" ).canConvert<QgsProcessingOutputLayerDefinition>() );
4758+
QgsProcessingOutputLayerDefinition outDef = qvariant_cast<QgsProcessingOutputLayerDefinition>( params.value( "OUTPUT" ) );
4759+
QCOMPARE( outDef.destinationName, QStringLiteral( "MY_OUT" ) );
4760+
QCOMPARE( outDef.sink.staticValue().toString(), QStringLiteral( "memory:" ) );
47134761
QCOMPARE( params.count(), 3 ); // don't want FAIL_OUTPUT set!
47144762

47154763
QStringList actualParts = model2.asPythonCode().split( '\n' );
47164764
QStringList expectedParts = QStringLiteral( "##model=name\n"
47174765
"##DIST=number\n"
47184766
"##SOURCE_LAYER=source\n"
47194767
"##model_out_layer=output outputVector\n"
4768+
"##my_out=output outputVector\n"
47204769
"results={}\n"
47214770
"outputs['cx1']=processing.run('native:buffer', {'DISSOLVE':false,'DISTANCE':parameters['DIST'],'END_CAP_STYLE':1,'INPUT':parameters['SOURCE_LAYER'],'JOIN_STYLE':2,'SEGMENTS':16}, context=context, feedback=feedback)\n"
47224771
"results['MODEL_OUT_LAYER']=outputs['cx1']['OUTPUT_LAYER']\n"
47234772
"outputs['cx2']=processing.run('native:centroids', {'INPUT':outputs['cx1']['OUTPUT_LAYER']}, context=context, feedback=feedback)\n"
4724-
"outputs['cx3']=processing.run('native:extractbyexpression', {'EXPRESSION':true,'INPUT':outputs['cx1']['OUTPUT_LAYER']}, context=context, feedback=feedback)\n"
4773+
"outputs['cx3']=processing.run('native:extractbyexpression', {'EXPRESSION':true,'INPUT':outputs['cx1']['OUTPUT_LAYER'],'OUTPUT':parameters['MY_OUT']}, context=context, feedback=feedback)\n"
4774+
"results['MY_OUT']=outputs['cx3']['OUTPUT']\n"
47254775
"return results" ).split( '\n' );
47264776
QCOMPARE( actualParts, expectedParts );
47274777
}

0 commit comments

Comments
 (0)