Skip to content

Commit

Permalink
Reimplement getAvailableValuesOfType in QgsProcessingModelAlgorithm
Browse files Browse the repository at this point in the history
  • Loading branch information
nyalldawson committed Jul 7, 2017
1 parent 26cd601 commit 17199c8
Show file tree
Hide file tree
Showing 7 changed files with 206 additions and 0 deletions.
12 changes: 12 additions & 0 deletions python/core/processing/qgsprocessingmodelalgorithm.sip
Original file line number Diff line number Diff line change
Expand Up @@ -865,6 +865,18 @@ Copies are protected to avoid slicing
:rtype: str
%End

QList< QgsProcessingModelAlgorithm::ChildParameterSource > availableSourcesForChild( const QString &childId, const QStringList &parameterTypes = QStringList(),
const QStringList &outputTypes = QStringList(), const QList< int > dataTypes = QList< int >() ) const;
%Docstring
Returns a list of possible sources which can be used for the parameters for a child
algorithm in the model. Returned sources are those which match either one of the
specified ``parameterTypes`` (see QgsProcessingParameterDefinition.type() ) or
on of the specified ``outputTypes`` (see QgsProcessingOutputDefinition.type() ).
If specified, an optional list of ``dataTypes`` can be used to filter the returned
sources to those with compatible data types for the parameter/outputs.
:rtype: list of QgsProcessingModelAlgorithm.ChildParameterSource
%End

protected:

virtual QVariantMap processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback );
Expand Down
7 changes: 7 additions & 0 deletions python/core/qgsexpressioncontext.sip
Original file line number Diff line number Diff line change
Expand Up @@ -874,6 +874,13 @@ class QgsExpressionContextUtils
:rtype: QgsExpressionContextScope
%End

static QgsExpressionContextScope *processingModelResultsScope( const QVariantMap &results, QgsProcessingContext &context ) /Factory/;
%Docstring
Creates a new scope which contains variables and functions relating to processing model results
:rtype: QgsExpressionContextScope
%End


static void registerContextFunctions();
%Docstring
Registers all known core functions provided by QgsExpressionContextScope objects.
Expand Down
84 changes: 84 additions & 0 deletions src/core/processing/qgsprocessingmodelalgorithm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -662,6 +662,90 @@ QString QgsProcessingModelAlgorithm::asPythonCode() const
return lines.join( '\n' );
}

QgsProcessingModelAlgorithm::ChildParameterSources QgsProcessingModelAlgorithm::availableSourcesForChild( const QString &childId, const QStringList &parameterTypes, const QStringList &outputTypes, const QList<int> dataTypes ) const
{
ChildParameterSources sources;

// first look through model parameters
QMap< QString, ModelParameter >::const_iterator paramIt = mParameterComponents.constBegin();
for ( ; paramIt != mParameterComponents.constEnd(); ++paramIt )
{
const QgsProcessingParameterDefinition *def = parameterDefinition( paramIt->parameterName() );
if ( !def )
continue;

if ( parameterTypes.contains( def->type() ) )
{
if ( !dataTypes.isEmpty() )
{
if ( def->type() == QStringLiteral( "field" ) )
{
const QgsProcessingParameterField *fieldDef = static_cast< const QgsProcessingParameterField * >( def );
if ( !( dataTypes.contains( fieldDef->dataType() ) || fieldDef->dataType() == QgsProcessingParameterField::Any ) )
{
continue;
}
}
else if ( def->type() == "source" )
{
const QgsProcessingParameterFeatureSource *sourceDef = static_cast< const QgsProcessingParameterFeatureSource *>( def );
bool ok = !sourceDef->dataTypes().isEmpty();
Q_FOREACH ( int type, sourceDef->dataTypes() )
{
if ( dataTypes.contains( type ) || type == QgsProcessingParameterDefinition::TypeAny )
{
ok = true;
break;
}
}
if ( !ok )
continue;
}
}
sources << ChildParameterSource::fromModelParameter( paramIt->parameterName() );
}
}

QSet< QString > dependents;
if ( !childId.isEmpty() )
{
dependents = dependentChildAlgorithms( childId );
dependents << childId;
}

QMap< QString, ChildAlgorithm >::const_iterator childIt = mChildAlgorithms.constBegin();
for ( ; childIt != mChildAlgorithms.constEnd(); ++childIt )
{
if ( dependents.contains( childIt->childId() ) )
continue;

const QgsProcessingAlgorithm *alg = childIt->algorithm();
if ( !alg )
continue;

Q_FOREACH ( const QgsProcessingOutputDefinition *out, alg->outputDefinitions() )
{
if ( outputTypes.contains( out->type() ) )
{
if ( !dataTypes.isEmpty() )
{
if ( out->type() == QStringLiteral( "outputVector" ) )
{
const QgsProcessingOutputVectorLayer *vectorOut = static_cast< const QgsProcessingOutputVectorLayer *>( out );
if ( !( dataTypes.contains( vectorOut->dataType() ) || vectorOut->dataType() == QgsProcessingParameterDefinition::TypeAny ) )
{
continue;
}
}
}
sources << ChildParameterSource::fromChildOutput( childIt->childId(), out->name() );
}
}
}

return sources;
}

QVariantMap QgsProcessingModelAlgorithm::helpContent() const
{
return mHelpContent;
Expand Down
11 changes: 11 additions & 0 deletions src/core/processing/qgsprocessingmodelalgorithm.h
Original file line number Diff line number Diff line change
Expand Up @@ -855,6 +855,17 @@ class CORE_EXPORT QgsProcessingModelAlgorithm : public QgsProcessingAlgorithm
*/
QString asPythonCode() const;

/**
* Returns a list of possible sources which can be used for the parameters for a child
* algorithm in the model. Returned sources are those which match either one of the
* specified \a parameterTypes (see QgsProcessingParameterDefinition::type() ) or
* on of the specified \a outputTypes (see QgsProcessingOutputDefinition::type() ).
* If specified, an optional list of \a dataTypes can be used to filter the returned
* sources to those with compatible data types for the parameter/outputs.
*/
QList< QgsProcessingModelAlgorithm::ChildParameterSource > availableSourcesForChild( const QString &childId, const QStringList &parameterTypes = QStringList(),
const QStringList &outputTypes = QStringList(), const QList< int > dataTypes = QList< int >() ) const;

protected:

QVariantMap processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
Expand Down
7 changes: 7 additions & 0 deletions src/core/qgsexpressioncontext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1120,6 +1120,13 @@ QgsExpressionContextScope *QgsExpressionContextUtils::processingAlgorithmScope(
return scope.release();
}

QgsExpressionContextScope *QgsExpressionContextUtils::processingModelResultsScope( const QVariantMap &results, QgsProcessingContext &context )
{
std::unique_ptr< QgsExpressionContextScope > scope( new QgsExpressionContextScope( QObject::tr( "Model results" ) ) );

return scope.release();
}

void QgsExpressionContextUtils::registerContextFunctions()
{
QgsExpression::registerFunction( new GetNamedProjectColor( nullptr ) );
Expand Down
6 changes: 6 additions & 0 deletions src/core/qgsexpressioncontext.h
Original file line number Diff line number Diff line change
Expand Up @@ -797,6 +797,12 @@ class CORE_EXPORT QgsExpressionContextUtils
*/
static QgsExpressionContextScope *processingAlgorithmScope( const QgsProcessingAlgorithm *algorithm, const QVariantMap &parameters, QgsProcessingContext &context ) SIP_FACTORY;

/**
* Creates a new scope which contains variables and functions relating to processing model results
*/
static QgsExpressionContextScope *processingModelResultsScope( const QVariantMap &results, QgsProcessingContext &context ) SIP_FACTORY;


/** Registers all known core functions provided by QgsExpressionContextScope objects.
*/
static void registerContextFunctions();
Expand Down
79 changes: 79 additions & 0 deletions tests/src/core/testqgsprocessing.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,7 @@ class TestQgsProcessing: public QObject
void asPythonCommand();
void modelerAlgorithm();
void modelExecution();
void modelAcceptableValues();
void tempUtils();

private:
Expand Down Expand Up @@ -4853,6 +4854,84 @@ void TestQgsProcessing::modelExecution()
QCOMPARE( actualParts, expectedParts );
}

void TestQgsProcessing::modelAcceptableValues()
{
QgsProcessingModelAlgorithm m;
QgsProcessingModelAlgorithm::ModelParameter stringParam1( "string" );
m.addModelParameter( new QgsProcessingParameterString( "string" ), stringParam1 );

QgsProcessingModelAlgorithm::ModelParameter stringParam2( "string2" );
m.addModelParameter( new QgsProcessingParameterString( "string2" ), stringParam2 );

QgsProcessingModelAlgorithm::ModelParameter numParam( "number" );
m.addModelParameter( new QgsProcessingParameterNumber( "number" ), numParam );

QgsProcessingModelAlgorithm::ModelParameter tableFieldParam( "field" );
m.addModelParameter( new QgsProcessingParameterField( "field" ), tableFieldParam );

QgsProcessingModelAlgorithm::ModelParameter fileParam( "file" );
m.addModelParameter( new QgsProcessingParameterFile( "file" ), fileParam );

// test single types
QgsProcessingModelAlgorithm::ChildParameterSources sources = m.availableSourcesForChild( QString(), QStringList() << "number" );
QCOMPARE( sources.count(), 1 );
QCOMPARE( sources.at( 0 ).parameterName(), QStringLiteral( "number" ) );
sources = m.availableSourcesForChild( QString(), QStringList() << "field" );
QCOMPARE( sources.count(), 1 );
QCOMPARE( sources.at( 0 ).parameterName(), QStringLiteral( "field" ) );
sources = m.availableSourcesForChild( QString(), QStringList() << "file" );
QCOMPARE( sources.count(), 1 );
QCOMPARE( sources.at( 0 ).parameterName(), QStringLiteral( "file" ) );

// test multiple types
sources = m.availableSourcesForChild( QString(), QStringList() << "string" << "number" << "file" );
QCOMPARE( sources.count(), 4 );
QSet< QString > res;
res << sources.at( 0 ).parameterName();
res << sources.at( 1 ).parameterName();
res << sources.at( 2 ).parameterName();
res << sources.at( 3 ).parameterName();

QCOMPARE( res, QSet< QString >() << QStringLiteral( "string" )
<< QStringLiteral( "string2" )
<< QStringLiteral( "number" )
<< QStringLiteral( "file" ) );

// check outputs
QgsProcessingModelAlgorithm::ChildAlgorithm alg2c1;
alg2c1.setChildId( "cx1" );
alg2c1.setAlgorithmId( "native:centroids" );
m.addChildAlgorithm( alg2c1 );

sources = m.availableSourcesForChild( QString(), QStringList(), QStringList() << "string" << "outputVector" );
QCOMPARE( sources.count(), 1 );
res.clear();
res << sources.at( 0 ).outputChildId() + ':' + sources.at( 0 ).outputName();
QCOMPARE( res, QSet< QString >() << "cx1:OUTPUT_LAYER" );

// with dependencies between child algs
QgsProcessingModelAlgorithm::ChildAlgorithm alg2c2;
alg2c2.setChildId( "cx2" );
alg2c2.setAlgorithmId( "native:centroids" );
alg2c2.setDependencies( QStringList() << "cx1" );
m.addChildAlgorithm( alg2c2 );
sources = m.availableSourcesForChild( QString(), QStringList(), QStringList() << "string" << "outputVector" );
QCOMPARE( sources.count(), 2 );
res.clear();
res << sources.at( 0 ).outputChildId() + ':' + sources.at( 0 ).outputName();
res << sources.at( 1 ).outputChildId() + ':' + sources.at( 1 ).outputName();
QCOMPARE( res, QSet< QString >() << "cx1:OUTPUT_LAYER" << "cx2:OUTPUT_LAYER" );

sources = m.availableSourcesForChild( QStringLiteral( "cx1" ), QStringList(), QStringList() << "string" << "outputVector" );
QCOMPARE( sources.count(), 0 );

sources = m.availableSourcesForChild( QString( "cx2" ), QStringList(), QStringList() << "string" << "outputVector" );
QCOMPARE( sources.count(), 1 );
res.clear();
res << sources.at( 0 ).outputChildId() + ':' + sources.at( 0 ).outputName();
QCOMPARE( res, QSet< QString >() << "cx1:OUTPUT_LAYER" );
}

void TestQgsProcessing::tempUtils()
{
QString tempFolder = QgsProcessingUtils::tempFolder();
Expand Down

0 comments on commit 17199c8

Please sign in to comment.