Skip to content

Commit

Permalink
Convert model child algorithm parameter sources to a list
Browse files Browse the repository at this point in the history
So that multiple input type parameters are correctly handled,
allowing models with child algorithms like merge to correctly
use any combination of static layers/model inputs/child outputs
as their input parameter
  • Loading branch information
nyalldawson committed Jun 30, 2017
1 parent 8d6d097 commit 77588b9
Show file tree
Hide file tree
Showing 6 changed files with 179 additions and 116 deletions.
23 changes: 12 additions & 11 deletions python/core/processing/qgsprocessingmodelalgorithm.sip
Expand Up @@ -161,6 +161,7 @@ class QgsProcessingModelAlgorithm : QgsProcessingAlgorithm

};


class Component
{
%Docstring
Expand Down Expand Up @@ -415,30 +416,30 @@ Copies are protected to avoid slicing
:rtype: QgsProcessingAlgorithm
%End

QMap< QString, QgsProcessingModelAlgorithm::ChildParameterSource > parameterSources() const;
QMap< QString, QList< QgsProcessingModelAlgorithm::ChildParameterSource > > parameterSources() const;
%Docstring
Returns a map of parameter sources. The keys are the child algorithm
parameter names, the values are the source for that parameter.
parameter names, the values are the sources for that parameter.
.. seealso:: setParameterSources()
.. seealso:: addParameterSource()
:rtype: QMap< str, QgsProcessingModelAlgorithm.ChildParameterSource >
.. seealso:: addParameterSources()
:rtype: QMap< str, QList< QgsProcessingModelAlgorithm.ChildParameterSource > >
%End

void setParameterSources( const QMap< QString, QgsProcessingModelAlgorithm::ChildParameterSource > &sources );
void setParameterSources( const QMap< QString, QList< QgsProcessingModelAlgorithm::ChildParameterSource > > &sources );
%Docstring
Sets the map of parameter ``sources``. The keys are the child algorithm
parameter names, the values are the source for that parameter.
parameter names, the values are the sources for that parameter.
.. seealso:: parameterSources()
.. seealso:: addParameterSource()
.. seealso:: addParameterSources()
%End

void addParameterSource( const QString &name, const QgsProcessingModelAlgorithm::ChildParameterSource &source );
void addParameterSources( const QString &name, const QList< QgsProcessingModelAlgorithm::ChildParameterSource > &source );
%Docstring
Adds a parameter source. The ``name`` argument should match
one of the child algorithm's parameter names, and the ``source``
argument is used to set the source for that parameter.
one of the child algorithm's parameter names, and the ``sources``
argument is used to set the sources for that parameter.

Any existing parameter source with matching name will be replaced.
Any existing parameter sources with matching name will be replaced.
.. seealso:: parameterSources()
.. seealso:: setParameterSources()
%End
Expand Down
8 changes: 6 additions & 2 deletions python/plugins/processing/modeler/ModelerParametersDialog.py
Expand Up @@ -285,6 +285,8 @@ def setPreviousValues(self):
continue
if param.name() in alg.parameterSources():
value = alg.parameterSources()[param.name()]
if isinstance(value, list) and len(value) == 1:
value = value[0]
else:
value = param.defaultValue()

Expand Down Expand Up @@ -325,9 +327,11 @@ def createAlgorithm(self):
if val is None:
continue
elif isinstance(val, QgsProcessingModelAlgorithm.ChildParameterSource):
alg.addParameterSource(param.name(), val)
alg.addParameterSources(param.name(), [val])
elif isinstance(val, list):
alg.addParameterSources(param.name(), val)
else:
alg.addParameterSource(param.name(), QgsProcessingModelAlgorithm.ChildParameterSource.fromStaticValue(val))
alg.addParameterSources(param.name(), [QgsProcessingModelAlgorithm.ChildParameterSource.fromStaticValue(val)])

outputs = {}
for dest in self._alg.destinationParameterDefinitions():
Expand Down
21 changes: 11 additions & 10 deletions python/plugins/processing/modeler/ModelerScene.py
Expand Up @@ -109,17 +109,18 @@ def paintModel(self, model, controls=True):
for parameter in alg.algorithm().parameterDefinitions():
if not parameter.isDestination() and not parameter.flags() & QgsProcessingParameterDefinition.FlagHidden:
if parameter.name() in alg.parameterSources():
value = alg.parameterSources()[parameter.name()]
sources = alg.parameterSources()[parameter.name()]
else:
value = None
sourceItems = self.getItemsFromParamValue(value)
for sourceItem, sourceIdx in sourceItems:
arrow = ModelerArrowItem(sourceItem, sourceIdx, self.algItems[alg.childId()], idx)
sourceItem.addArrow(arrow)
self.algItems[alg.childId()].addArrow(arrow)
arrow.updatePath()
self.addItem(arrow)
idx += 1
sources = []
for source in sources:
sourceItems = self.getItemsFromParamValue(source)
for sourceItem, sourceIdx in sourceItems:
arrow = ModelerArrowItem(sourceItem, sourceIdx, self.algItems[alg.childId()], idx)
sourceItem.addArrow(arrow)
self.algItems[alg.childId()].addArrow(arrow)
arrow.updatePath()
self.addItem(arrow)
idx += 1
for depend in alg.dependencies():
arrow = ModelerArrowItem(self.algItems[depend], -1,
self.algItems[alg.childId()], -1)
Expand Down
141 changes: 90 additions & 51 deletions src/core/processing/qgsprocessingmodelalgorithm.cpp
Expand Up @@ -47,17 +47,17 @@ void QgsProcessingModelAlgorithm::Component::setDescription( const QString &desc
mDescription = description;
}

QMap<QString, QgsProcessingModelAlgorithm::ChildParameterSource> QgsProcessingModelAlgorithm::ChildAlgorithm::parameterSources() const
QMap<QString, QgsProcessingModelAlgorithm::ChildParameterSources> QgsProcessingModelAlgorithm::ChildAlgorithm::parameterSources() const
{
return mParams;
}

void QgsProcessingModelAlgorithm::ChildAlgorithm::setParameterSources( const QMap< QString, QgsProcessingModelAlgorithm::ChildParameterSource > &params )
void QgsProcessingModelAlgorithm::ChildAlgorithm::setParameterSources( const QMap< QString, QgsProcessingModelAlgorithm::ChildParameterSources > &params )
{
mParams = params;
}

void QgsProcessingModelAlgorithm::ChildAlgorithm::addParameterSource( const QString &name, const ChildParameterSource &source )
void QgsProcessingModelAlgorithm::ChildAlgorithm::addParameterSources( const QString &name, const ChildParameterSources &source )
{
mParams.insert( name, source );
}
Expand Down Expand Up @@ -157,10 +157,15 @@ QVariant QgsProcessingModelAlgorithm::ChildAlgorithm::toVariant() const
saveCommonProperties( map );

QVariantMap paramMap;
QMap< QString, QgsProcessingModelAlgorithm::ChildParameterSource >::const_iterator paramIt = mParams.constBegin();
QMap< QString, QgsProcessingModelAlgorithm::ChildParameterSources >::const_iterator paramIt = mParams.constBegin();
for ( ; paramIt != mParams.constEnd(); ++paramIt )
{
paramMap.insert( paramIt.key(), paramIt.value().toVariant() );
QVariantList sources;
Q_FOREACH ( const ChildParameterSource &source, paramIt.value() )
{
sources << source.toVariant();
}
paramMap.insert( paramIt.key(), sources );
}
map.insert( "params", paramMap );

Expand Down Expand Up @@ -193,11 +198,15 @@ bool QgsProcessingModelAlgorithm::ChildAlgorithm::loadVariant( const QVariant &c
QVariantMap::const_iterator paramIt = paramMap.constBegin();
for ( ; paramIt != paramMap.constEnd(); ++paramIt )
{
ChildParameterSource param;
if ( !param.loadVariant( paramIt.value().toMap() ) )
return false;

mParams.insert( paramIt.key(), param );
ChildParameterSources sources;
Q_FOREACH ( const QVariant &sourceVar, paramIt->toList() )
{
ChildParameterSource param;
if ( !param.loadVariant( sourceVar.toMap() ) )
return false;
sources << param;
}
mParams.insert( paramIt.key(), sources );
}

mModelOutputs.clear();
Expand All @@ -223,12 +232,20 @@ QString QgsProcessingModelAlgorithm::ChildAlgorithm::asPythonCode() const
return QString();

QStringList paramParts;
QMap< QString, QgsProcessingModelAlgorithm::ChildParameterSource >::const_iterator paramIt = mParams.constBegin();
QMap< QString, QgsProcessingModelAlgorithm::ChildParameterSources >::const_iterator paramIt = mParams.constBegin();
for ( ; paramIt != mParams.constEnd(); ++paramIt )
{
QString part = paramIt->asPythonCode();
if ( !part.isEmpty() )
paramParts << QStringLiteral( "'%1':%2" ).arg( paramIt.key(), part );
QStringList sourceParts;
Q_FOREACH ( const ChildParameterSource &source, paramIt.value() )
{
QString part = source.asPythonCode();
if ( !part.isEmpty() )
sourceParts << QStringLiteral( "'%1':%2" ).arg( paramIt.key(), part );
}
if ( sourceParts.count() == 1 )
paramParts << sourceParts.at( 0 );
else
paramParts << QStringLiteral( "[%1]" ).arg( paramParts.join( ',' ) );
}

lines << QStringLiteral( "outputs['%1']=processing.run('%2', {%3}, context=context, feedback=feedback)" ).arg( mId, mAlgorithmId, paramParts.join( ',' ) );
Expand Down Expand Up @@ -347,24 +364,34 @@ QVariantMap QgsProcessingModelAlgorithm::parametersForChildAlgorithm( const Chil
if ( !child.parameterSources().contains( def->name() ) )
continue; // use default value

ChildParameterSource paramSource = child.parameterSources().value( def->name() );
switch ( paramSource.source() )
{
case ChildParameterSource::StaticValue:
childParams.insert( def->name(), paramSource.staticValue() );
break;
ChildParameterSources paramSources = child.parameterSources().value( def->name() );

case ChildParameterSource::ModelParameter:
childParams.insert( def->name(), modelParameters.value( paramSource.parameterName() ) );
break;

case ChildParameterSource::ChildOutput:
QVariantList paramParts;
Q_FOREACH ( const ChildParameterSource &source, paramSources )
{
switch ( source.source() )
{
QVariantMap linkedChildResults = results.value( paramSource.outputChildId() );
childParams.insert( def->name(), linkedChildResults.value( paramSource.outputName() ) );
break;
case ChildParameterSource::StaticValue:
paramParts << source.staticValue();
break;

case ChildParameterSource::ModelParameter:
paramParts << modelParameters.value( source.parameterName() );
break;

case ChildParameterSource::ChildOutput:
{
QVariantMap linkedChildResults = results.value( source.outputChildId() );
paramParts << linkedChildResults.value( source.outputName() );
break;
}
}
}
if ( paramParts.count() == 1 )
childParams.insert( def->name(), paramParts.at( 0 ) );
else
childParams.insert( def->name(), paramParts );

}
else
{
Expand Down Expand Up @@ -416,15 +443,18 @@ bool QgsProcessingModelAlgorithm::childOutputIsRequired( const QString &childId,
continue;

// look through all sources for child
QMap<QString, QgsProcessingModelAlgorithm::ChildParameterSource> candidateChildParams = childIt->parameterSources();
QMap<QString, QgsProcessingModelAlgorithm::ChildParameterSource>::const_iterator childParamIt = candidateChildParams.constBegin();
QMap<QString, QgsProcessingModelAlgorithm::ChildParameterSources> candidateChildParams = childIt->parameterSources();
QMap<QString, QgsProcessingModelAlgorithm::ChildParameterSources>::const_iterator childParamIt = candidateChildParams.constBegin();
for ( ; childParamIt != candidateChildParams.constEnd(); ++childParamIt )
{
if ( childParamIt->source() == ChildParameterSource::ChildOutput
&& childParamIt->outputChildId() == childId
&& childParamIt->outputName() == outputName )
Q_FOREACH ( const ChildParameterSource &source, childParamIt.value() )
{
return true;
if ( source.source() == ChildParameterSource::ChildOutput
&& source.outputChildId() == childId
&& source.outputName() == outputName )
{
return true;
}
}
}
}
Expand Down Expand Up @@ -902,14 +932,17 @@ bool QgsProcessingModelAlgorithm::childAlgorithmsDependOnParameter( const QStrin
for ( ; childIt != mChildAlgorithms.constEnd(); ++childIt )
{
// check whether child requires this parameter
QMap<QString, QgsProcessingModelAlgorithm::ChildParameterSource> childParams = childIt->parameterSources();
QMap<QString, QgsProcessingModelAlgorithm::ChildParameterSource>::const_iterator paramIt = childParams.constBegin();
QMap<QString, QgsProcessingModelAlgorithm::ChildParameterSources> childParams = childIt->parameterSources();
QMap<QString, QgsProcessingModelAlgorithm::ChildParameterSources>::const_iterator paramIt = childParams.constBegin();
for ( ; paramIt != childParams.constEnd(); ++paramIt )
{
if ( paramIt->source() == ChildParameterSource::ModelParameter
&& paramIt->parameterName() == name )
Q_FOREACH ( const ChildParameterSource &source, paramIt.value() )
{
return true;
if ( source.source() == ChildParameterSource::ModelParameter
&& source.parameterName() == name )
{
return true;
}
}
}
}
Expand Down Expand Up @@ -938,16 +971,19 @@ void QgsProcessingModelAlgorithm::dependentChildAlgorithmsRecursive( const QStri
}

// check whether child requires any outputs from the target alg
QMap<QString, QgsProcessingModelAlgorithm::ChildParameterSource> childParams = childIt->parameterSources();
QMap<QString, QgsProcessingModelAlgorithm::ChildParameterSource>::const_iterator paramIt = childParams.constBegin();
QMap<QString, QgsProcessingModelAlgorithm::ChildParameterSources> childParams = childIt->parameterSources();
QMap<QString, QgsProcessingModelAlgorithm::ChildParameterSources>::const_iterator paramIt = childParams.constBegin();
for ( ; paramIt != childParams.constEnd(); ++paramIt )
{
if ( paramIt->source() == ChildParameterSource::ChildOutput
&& paramIt->outputChildId() == childId )
Q_FOREACH ( const ChildParameterSource &source, paramIt.value() )
{
depends.insert( childIt->childId() );
dependsOnChildAlgorithmsRecursive( childIt->childId(), depends );
break;
if ( source.source() == ChildParameterSource::ChildOutput
&& source.outputChildId() == childId )
{
depends.insert( childIt->childId() );
dependsOnChildAlgorithmsRecursive( childIt->childId(), depends );
break;
}
}
}
}
Expand Down Expand Up @@ -985,14 +1021,17 @@ void QgsProcessingModelAlgorithm::dependsOnChildAlgorithmsRecursive( const QStri
}

// check through parameter dependencies
QMap<QString, QgsProcessingModelAlgorithm::ChildParameterSource> childParams = alg.parameterSources();
QMap<QString, QgsProcessingModelAlgorithm::ChildParameterSource>::const_iterator paramIt = childParams.constBegin();
QMap<QString, QgsProcessingModelAlgorithm::ChildParameterSources> childParams = alg.parameterSources();
QMap<QString, QgsProcessingModelAlgorithm::ChildParameterSources>::const_iterator paramIt = childParams.constBegin();
for ( ; paramIt != childParams.constEnd(); ++paramIt )
{
if ( paramIt->source() == ChildParameterSource::ChildOutput && !depends.contains( paramIt->outputChildId() ) )
Q_FOREACH ( const ChildParameterSource &source, paramIt.value() )
{
depends.insert( paramIt->outputChildId() );
dependsOnChildAlgorithmsRecursive( paramIt->outputChildId(), depends );
if ( source.source() == ChildParameterSource::ChildOutput && !depends.contains( source.outputChildId() ) )
{
depends.insert( source.outputChildId() );
dependsOnChildAlgorithmsRecursive( source.outputChildId(), depends );
}
}
}
}
Expand Down
27 changes: 16 additions & 11 deletions src/core/processing/qgsprocessingmodelalgorithm.h
Expand Up @@ -168,6 +168,11 @@ class CORE_EXPORT QgsProcessingModelAlgorithm : public QgsProcessingAlgorithm

};

#ifndef SIP_RUN
//! List of child parameter sources
typedef QList< QgsProcessingModelAlgorithm::ChildParameterSource > ChildParameterSources;
#endif

/**
* Represents a component of a model algorithm.
* \since QGIS 3.0
Expand Down Expand Up @@ -413,30 +418,30 @@ class CORE_EXPORT QgsProcessingModelAlgorithm : public QgsProcessingAlgorithm

/**
* Returns a map of parameter sources. The keys are the child algorithm
* parameter names, the values are the source for that parameter.
* parameter names, the values are the sources for that parameter.
* \see setParameterSources()
* \see addParameterSource()
* \see addParameterSources()
*/
QMap< QString, QgsProcessingModelAlgorithm::ChildParameterSource > parameterSources() const;
QMap< QString, QList< QgsProcessingModelAlgorithm::ChildParameterSource > > parameterSources() const;

/**
* Sets the map of parameter \a sources. The keys are the child algorithm
* parameter names, the values are the source for that parameter.
* parameter names, the values are the sources for that parameter.
* \see parameterSources()
* \see addParameterSource()
* \see addParameterSources()
*/
void setParameterSources( const QMap< QString, QgsProcessingModelAlgorithm::ChildParameterSource > &sources );
void setParameterSources( const QMap< QString, QList< QgsProcessingModelAlgorithm::ChildParameterSource > > &sources );

/**
* Adds a parameter source. The \a name argument should match
* one of the child algorithm's parameter names, and the \a source
* argument is used to set the source for that parameter.
* one of the child algorithm's parameter names, and the \a sources
* argument is used to set the sources for that parameter.
*
* Any existing parameter source with matching name will be replaced.
* Any existing parameter sources with matching name will be replaced.
* \see parameterSources()
* \see setParameterSources()
*/
void addParameterSource( const QString &name, const QgsProcessingModelAlgorithm::ChildParameterSource &source );
void addParameterSources( const QString &name, const QList< QgsProcessingModelAlgorithm::ChildParameterSource > &source );

/**
* Returns true if the child algorithm is active.
Expand Down Expand Up @@ -554,7 +559,7 @@ class CORE_EXPORT QgsProcessingModelAlgorithm : public QgsProcessingAlgorithm
QString mAlgorithmId;

//! A map of parameter sources. Keys are algorithm parameter names.
QMap< QString, QgsProcessingModelAlgorithm::ChildParameterSource > mParams;
QMap< QString, QgsProcessingModelAlgorithm::ChildParameterSources > mParams;

//! A map of ModelOutput for final model outputs generated by this child algorithm. Keys are output names from the child algorithm.
QMap< QString, QgsProcessingModelAlgorithm::ModelOutput > mModelOutputs;
Expand Down

0 comments on commit 77588b9

Please sign in to comment.