33 #include <QTextStream>
34 #include <QRegularExpression>
37 QgsProcessingModelAlgorithm::QgsProcessingModelAlgorithm(
const QString &name,
const QString &group,
const QString &groupId )
38 : mModelName( name.isEmpty() ? QObject::tr(
"model" ) : name )
39 , mModelGroup( group )
40 , mModelGroupId( groupId )
43 void QgsProcessingModelAlgorithm::initAlgorithm(
const QVariantMap & )
47 QString QgsProcessingModelAlgorithm::name()
const
52 QString QgsProcessingModelAlgorithm::displayName()
const
57 QString QgsProcessingModelAlgorithm::group()
const
62 QString QgsProcessingModelAlgorithm::groupId()
const
67 QIcon QgsProcessingModelAlgorithm::icon()
const
72 QString QgsProcessingModelAlgorithm::svgIconPath()
const
77 QString QgsProcessingModelAlgorithm::shortHelpString()
const
79 if ( mHelpContent.empty() )
85 QString QgsProcessingModelAlgorithm::shortDescription()
const
87 return mHelpContent.value( QStringLiteral(
"SHORT_DESCRIPTION" ) ).toString();
90 QString QgsProcessingModelAlgorithm::helpUrl()
const
92 return mHelpContent.value( QStringLiteral(
"HELP_URL" ) ).toString();
95 QVariantMap QgsProcessingModelAlgorithm::parametersForChildAlgorithm(
const QgsProcessingModelChildAlgorithm &child,
const QVariantMap &modelParameters,
const QVariantMap &results,
const QgsExpressionContext &expressionContext, QString &error )
const
100 const QgsProcessingModelChildParameterSources paramSources = child.parameterSources().value( def->name() );
102 QString expressionText;
103 QVariantList paramParts;
104 for (
const QgsProcessingModelChildParameterSource &source : paramSources )
106 switch ( source.source() )
108 case QgsProcessingModelChildParameterSource::StaticValue:
109 paramParts << source.staticValue();
112 case QgsProcessingModelChildParameterSource::ModelParameter:
113 paramParts << modelParameters.value( source.parameterName() );
116 case QgsProcessingModelChildParameterSource::ChildOutput:
118 QVariantMap linkedChildResults = results.value( source.outputChildId() ).toMap();
119 paramParts << linkedChildResults.value( source.outputName() );
123 case QgsProcessingModelChildParameterSource::Expression:
126 paramParts << exp.evaluate( &expressionContext );
127 if ( exp.hasEvalError() )
129 error = QObject::tr(
"Could not evaluate expression for parameter %1 for %2: %3" ).arg( def->name(), child.description(), exp.evalErrorString() );
133 case QgsProcessingModelChildParameterSource::ExpressionText:
139 case QgsProcessingModelChildParameterSource::ModelOutput:
144 if ( ! expressionText.isEmpty() )
146 return expressionText;
148 else if ( paramParts.count() == 1 )
149 return paramParts.at( 0 );
155 QVariantMap childParams;
156 const QList< const QgsProcessingParameterDefinition * > childParameterDefinitions = child.algorithm()->parameterDefinitions();
159 if ( !def->isDestination() )
161 if ( !child.parameterSources().contains( def->name() ) )
164 const QVariant value = evaluateSources( def );
165 childParams.insert( def->name(), value );
172 bool isFinalOutput =
false;
173 QMap<QString, QgsProcessingModelOutput> outputs = child.modelOutputs();
174 QMap<QString, QgsProcessingModelOutput>::const_iterator outputIt = outputs.constBegin();
175 for ( ; outputIt != outputs.constEnd(); ++outputIt )
177 if ( outputIt->childOutputName() == destParam->
name() )
179 QString paramName = child.childId() +
':' + outputIt.key();
180 bool foundParam =
false;
184 if ( modelParameters.contains( paramName ) )
186 value = modelParameters.value( paramName );
195 if ( modelParameters.contains( modelParam->name() ) )
197 value = modelParameters.value( modelParam->name() );
210 value = QVariant::fromValue( fromVar );
213 childParams.insert( destParam->
name(), value );
215 isFinalOutput =
true;
220 bool hasExplicitDefinition =
false;
221 if ( !isFinalOutput && child.parameterSources().contains( def->name() ) )
224 const QVariant value = evaluateSources( def );
225 if ( value.isValid() )
227 childParams.insert( def->name(), value );
228 hasExplicitDefinition =
true;
232 if ( !isFinalOutput && !hasExplicitDefinition )
237 bool required =
true;
240 required = childOutputIsRequired( child.childId(), destParam->
name() );
252 const QgsProcessingParameterDefinition *QgsProcessingModelAlgorithm::modelParameterFromChildIdAndOutputName(
const QString &childId,
const QString &childOutputName )
const
256 if ( !definition->isDestination() )
259 const QString modelChildId = definition->
metadata().value( QStringLiteral(
"_modelChildId" ) ).toString();
260 const QString modelOutputName = definition->metadata().value( QStringLiteral(
"_modelChildOutputName" ) ).toString();
262 if ( modelChildId == childId && modelOutputName == childOutputName )
268 bool QgsProcessingModelAlgorithm::childOutputIsRequired(
const QString &childId,
const QString &outputName )
const
271 QMap< QString, QgsProcessingModelChildAlgorithm >::const_iterator childIt = mChildAlgorithms.constBegin();
272 for ( ; childIt != mChildAlgorithms.constEnd(); ++childIt )
274 if ( childIt->childId() == childId || !childIt->isActive() )
278 QMap<QString, QgsProcessingModelChildParameterSources> candidateChildParams = childIt->parameterSources();
279 QMap<QString, QgsProcessingModelChildParameterSources>::const_iterator childParamIt = candidateChildParams.constBegin();
280 for ( ; childParamIt != candidateChildParams.constEnd(); ++childParamIt )
282 const auto constValue = childParamIt.value();
283 for (
const QgsProcessingModelChildParameterSource &source : constValue )
285 if ( source.source() == QgsProcessingModelChildParameterSource::ChildOutput
286 && source.outputChildId() == childId
287 && source.outputName() == outputName )
299 QSet< QString > toExecute;
300 QMap< QString, QgsProcessingModelChildAlgorithm >::const_iterator childIt = mChildAlgorithms.constBegin();
301 QSet< QString > broken;
302 for ( ; childIt != mChildAlgorithms.constEnd(); ++childIt )
304 if ( childIt->isActive() )
306 if ( childIt->algorithm() )
307 toExecute.insert( childIt->childId() );
309 broken.insert( childIt->childId() );
313 if ( !broken.empty() )
314 throw QgsProcessingException( QCoreApplication::translate(
"QgsProcessingModelAlgorithm",
"Cannot run model, the following algorithms are not available on this system: %1" ).arg( broken.values().join( QLatin1String(
", " ) ) ) );
316 QElapsedTimer totalTime;
322 QVariantMap childResults;
323 QVariantMap childInputs;
327 QVariantMap finalResults;
328 QSet< QString > executed;
329 bool executedAlg =
true;
330 while ( executedAlg && executed.count() < toExecute.count() )
333 for (
const QString &childId : std::as_const( toExecute ) )
338 if ( executed.contains( childId ) )
341 bool canExecute =
true;
342 const QSet< QString > dependencies = dependsOnChildAlgorithms( childId );
343 for (
const QString &dependency : dependencies )
345 if ( !executed.contains( dependency ) )
357 const QgsProcessingModelChildAlgorithm &child = mChildAlgorithms[ childId ];
358 std::unique_ptr< QgsProcessingAlgorithm > childAlg( child.algorithm()->create( child.configuration() ) );
361 if ( feedback && !skipGenericLogging )
362 feedback->
pushDebugInfo( QObject::tr(
"Prepare algorithm: %1" ).arg( childId ) );
366 << createExpressionContextScopeForChildAlgorithm( childId, context, parameters, childResults );
370 QVariantMap childParams = parametersForChildAlgorithm( child, parameters, childResults, expContext, error );
371 if ( !error.isEmpty() )
374 if ( feedback && !skipGenericLogging )
375 feedback->
setProgressText( QObject::tr(
"Running %1 [%2/%3]" ).arg( child.description() ).arg( executed.count() + 1 ).arg( toExecute.count() ) );
379 for (
auto childParamIt = childParams.constBegin(); childParamIt != childParams.constEnd(); ++childParamIt )
381 params << QStringLiteral(
"%1: %2" ).arg( childParamIt.key(),
382 child.algorithm()->parameterDefinition( childParamIt.key() )->valueAsPythonString( childParamIt.value(), context ) );
385 if ( feedback && !skipGenericLogging )
387 feedback->
pushInfo( QObject::tr(
"Input Parameters:" ) );
388 feedback->
pushCommandInfo( QStringLiteral(
"{ %1 }" ).arg( params.join( QLatin1String(
", " ) ) ) );
391 QElapsedTimer childTime;
396 QThread *modelThread = QThread::currentThread();
398 auto prepareOnMainThread = [modelThread, &ok, &childAlg, &childParams, &context, &modelFeedback]
400 Q_ASSERT_X( QThread::currentThread() == qApp->thread(),
"QgsProcessingModelAlgorithm::processAlgorithm",
"childAlg->prepare() must be run on the main thread" );
401 ok = childAlg->prepare( childParams, context, &modelFeedback );
402 context.pushToThread( modelThread );
406 if ( modelThread == qApp->thread() )
407 ok = childAlg->prepare( childParams, context, &modelFeedback );
410 context.pushToThread( qApp->thread() );
411 QMetaObject::invokeMethod( qApp, prepareOnMainThread, Qt::BlockingQueuedConnection );
414 Q_ASSERT_X( QThread::currentThread() == context.thread(),
"QgsProcessingModelAlgorithm::processAlgorithm",
"context was not transferred back to model thread" );
428 auto runOnMainThread = [modelThread, &context, &modelFeedback, &results, &childAlg, &childParams]
430 Q_ASSERT_X( QThread::currentThread() == qApp->thread(),
"QgsProcessingModelAlgorithm::processAlgorithm",
"childAlg->runPrepared() must be run on the main thread" );
431 results = childAlg->runPrepared( childParams, context, &modelFeedback );
432 context.pushToThread( modelThread );
435 if ( feedback && !skipGenericLogging && modelThread != qApp->thread() )
436 feedback->
pushWarning( QObject::tr(
"Algorithm “%1” cannot be run in a background thread, switching to main thread for this step" ).arg( childAlg->displayName() ) );
438 context.pushToThread( qApp->thread() );
439 QMetaObject::invokeMethod( qApp, runOnMainThread, Qt::BlockingQueuedConnection );
444 results = childAlg->runPrepared( childParams, context, &modelFeedback );
453 Q_ASSERT_X( QThread::currentThread() == context.thread(),
"QgsProcessingModelAlgorithm::processAlgorithm",
"context was not transferred back to model thread" );
456 auto postProcessOnMainThread = [modelThread, &ppRes, &childAlg, &context, &modelFeedback]
458 Q_ASSERT_X( QThread::currentThread() == qApp->thread(),
"QgsProcessingModelAlgorithm::processAlgorithm",
"childAlg->postProcess() must be run on the main thread" );
459 ppRes = childAlg->postProcess( context, &modelFeedback );
460 context.pushToThread( modelThread );
464 if ( modelThread == qApp->thread() )
465 ppRes = childAlg->postProcess( context, &modelFeedback );
468 context.pushToThread( qApp->thread() );
469 QMetaObject::invokeMethod( qApp, postProcessOnMainThread, Qt::BlockingQueuedConnection );
472 Q_ASSERT_X( QThread::currentThread() == context.thread(),
"QgsProcessingModelAlgorithm::processAlgorithm",
"context was not transferred back to model thread" );
474 if ( !ppRes.isEmpty() )
477 childResults.insert( childId, results );
481 QMap<QString, QgsProcessingModelOutput> outputs = child.modelOutputs();
482 QMap<QString, QgsProcessingModelOutput>::const_iterator outputIt = outputs.constBegin();
483 for ( ; outputIt != outputs.constEnd(); ++outputIt )
485 switch ( mInternalVersion )
487 case QgsProcessingModelAlgorithm::InternalVersion::Version1:
488 finalResults.insert( childId +
':' + outputIt->name(), results.value( outputIt->childOutputName() ) );
490 case QgsProcessingModelAlgorithm::InternalVersion::Version2:
493 finalResults.insert( modelParam->name(), results.value( outputIt->childOutputName() ) );
499 executed.insert( childId );
501 std::function< void(
const QString &,
const QString & )> pruneAlgorithmBranchRecursive;
502 pruneAlgorithmBranchRecursive = [&](
const QString & id,
const QString &branch = QString() )
504 const QSet<QString> toPrune = dependentChildAlgorithms(
id, branch );
505 for (
const QString &targetId : toPrune )
507 if ( executed.contains( targetId ) )
510 executed.insert( targetId );
511 pruneAlgorithmBranchRecursive( targetId, branch );
521 pruneAlgorithmBranchRecursive( childId, outputDef->name() );
529 for (
const QString &candidateId : std::as_const( toExecute ) )
531 if ( executed.contains( candidateId ) )
536 const QgsProcessingModelChildAlgorithm &candidate = mChildAlgorithms[ candidateId ];
537 const QMap<QString, QgsProcessingModelChildParameterSources> candidateParams = candidate.parameterSources();
538 QMap<QString, QgsProcessingModelChildParameterSources>::const_iterator paramIt = candidateParams.constBegin();
540 for ( ; paramIt != candidateParams.constEnd(); ++paramIt )
542 for (
const QgsProcessingModelChildParameterSource &source : paramIt.value() )
544 if ( source.source() == QgsProcessingModelChildParameterSource::ChildOutput && source.outputChildId() == childId )
547 if ( !results.contains( source.outputName() ) )
552 executed.insert( candidateId );
554 pruneAlgorithmBranchRecursive( candidateId, QString() );
565 childAlg.reset(
nullptr );
566 modelFeedback.setCurrentStep( executed.count() );
567 if ( feedback && !skipGenericLogging )
568 feedback->
pushInfo( QObject::tr(
"OK. Execution took %1 s (%n output(s)).",
nullptr, results.count() ).arg( childTime.elapsed() / 1000.0 ) );
575 feedback->
pushDebugInfo( QObject::tr(
"Model processed OK. Executed %n algorithm(s) total in %1 s.",
nullptr, executed.count() ).arg( totalTime.elapsed() / 1000.0 ) );
577 mResults = finalResults;
578 mResults.insert( QStringLiteral(
"CHILD_RESULTS" ), childResults );
579 mResults.insert( QStringLiteral(
"CHILD_INPUTS" ), childInputs );
583 QString QgsProcessingModelAlgorithm::sourceFilePath()
const
588 void QgsProcessingModelAlgorithm::setSourceFilePath(
const QString &sourceFile )
590 mSourceFile = sourceFile;
593 bool QgsProcessingModelAlgorithm::modelNameMatchesFilePath()
const
595 if ( mSourceFile.isEmpty() )
598 const QFileInfo fi( mSourceFile );
599 return fi.completeBaseName().compare( mModelName, Qt::CaseInsensitive ) == 0;
604 QStringList fileDocString;
605 fileDocString << QStringLiteral(
"\"\"\"" );
606 fileDocString << QStringLiteral(
"Model exported as python." );
607 fileDocString << QStringLiteral(
"Name : %1" ).arg( displayName() );
608 fileDocString << QStringLiteral(
"Group : %1" ).arg( group() );
609 fileDocString << QStringLiteral(
"With QGIS : %1" ).arg(
Qgis::versionInt() );
610 fileDocString << QStringLiteral(
"\"\"\"" );
611 fileDocString << QString();
614 QString indent = QString(
' ' ).repeated( indentSize );
615 QString currentIndent;
617 QMap< QString, QString> friendlyChildNames;
618 QMap< QString, QString> friendlyOutputNames;
619 auto uniqueSafeName = [](
const QString & name,
bool capitalize,
const QMap< QString, QString > &friendlyNames )->QString
621 const QString base = safeName( name, capitalize );
622 QString candidate = base;
624 while ( friendlyNames.contains( candidate ) )
627 candidate = QStringLiteral(
"%1_%2" ).arg( base ).arg( i );
632 const QString algorithmClassName = safeName( name(),
true );
634 QSet< QString > toExecute;
635 for (
auto childIt = mChildAlgorithms.constBegin(); childIt != mChildAlgorithms.constEnd(); ++childIt )
637 if ( childIt->isActive() && childIt->algorithm() )
639 toExecute.insert( childIt->childId() );
640 friendlyChildNames.insert( childIt->childId(), uniqueSafeName( childIt->description().isEmpty() ? childIt->childId() : childIt->description(), !childIt->description().isEmpty(), friendlyChildNames ) );
643 const int totalSteps = toExecute.count();
645 QStringList importLines;
646 switch ( outputType )
651 const auto params = parameterDefinitions();
652 importLines.reserve( params.count() + 3 );
653 importLines << QStringLiteral(
"from qgis.core import QgsProcessing" );
654 importLines << QStringLiteral(
"from qgis.core import QgsProcessingAlgorithm" );
655 importLines << QStringLiteral(
"from qgis.core import QgsProcessingMultiStepFeedback" );
657 bool hasAdvancedParams =
false;
661 hasAdvancedParams =
true;
664 if ( !importString.isEmpty() && !importLines.contains( importString ) )
665 importLines << importString;
668 if ( hasAdvancedParams )
669 importLines << QStringLiteral(
"from qgis.core import QgsProcessingParameterDefinition" );
671 lines << QStringLiteral(
"import processing" );
672 lines << QString() << QString();
674 lines << QStringLiteral(
"class %1(QgsProcessingAlgorithm):" ).arg( algorithmClassName );
678 lines << indent + QStringLiteral(
"def initAlgorithm(self, config=None):" );
679 if ( params.empty() )
681 lines << indent + indent + QStringLiteral(
"pass" );
685 lines.reserve( lines.size() + params.size() );
688 std::unique_ptr< QgsProcessingParameterDefinition > defClone( def->clone() );
690 if ( defClone->isDestination() )
692 const QString uniqueChildName = defClone->metadata().value( QStringLiteral(
"_modelChildId" ) ).toString() +
':' + defClone->metadata().value( QStringLiteral(
"_modelChildOutputName" ) ).toString();
693 const QString friendlyName = !defClone->description().isEmpty() ? uniqueSafeName( defClone->description(),
true, friendlyOutputNames ) : defClone->name();
694 friendlyOutputNames.insert( uniqueChildName, friendlyName );
695 defClone->setName( friendlyName );
699 if ( !mParameterComponents.value( defClone->name() ).comment()->description().isEmpty() )
700 lines << indent + indent + QStringLiteral(
"# %1" ).arg( mParameterComponents.value( defClone->name() ).comment()->description() );
705 lines << indent + indent + QStringLiteral(
"param = %1" ).arg( defClone->asPythonString() );
706 lines << indent + indent + QStringLiteral(
"param.setFlags(param.flags() | QgsProcessingParameterDefinition.FlagAdvanced)" );
707 lines << indent + indent + QStringLiteral(
"self.addParameter(param)" );
711 lines << indent + indent + QStringLiteral(
"self.addParameter(%1)" ).arg( defClone->asPythonString() );
717 lines << indent + QStringLiteral(
"def processAlgorithm(self, parameters, context, model_feedback):" );
718 currentIndent = indent + indent;
720 lines << currentIndent + QStringLiteral(
"# Use a multi-step feedback, so that individual child algorithm progress reports are adjusted for the" );
721 lines << currentIndent + QStringLiteral(
"# overall progress through the model" );
722 lines << currentIndent + QStringLiteral(
"feedback = QgsProcessingMultiStepFeedback(%1, model_feedback)" ).arg( totalSteps );
730 QMap< QString, QgsProcessingModelParameter >::const_iterator paramIt = mParameterComponents.constBegin();
731 for ( ; paramIt != mParameterComponents.constEnd(); ++paramIt )
733 QString name = paramIt.value().parameterName();
734 if ( parameterDefinition( name ) )
737 params.insert( name, parameterDefinition( name )->valueAsPythonString( parameterDefinition( name )->defaultValue(), context ) );
741 if ( !params.isEmpty() )
743 lines << QStringLiteral(
"parameters = {" );
744 for (
auto it = params.constBegin(); it != params.constEnd(); ++it )
746 lines << QStringLiteral(
" '%1':%2," ).arg( it.key(), it.value() );
748 lines << QStringLiteral(
"}" )
752 lines << QStringLiteral(
"context = QgsProcessingContext()" )
753 << QStringLiteral(
"context.setProject(QgsProject.instance())" )
754 << QStringLiteral(
"feedback = QgsProcessingFeedback()" )
763 lines << currentIndent + QStringLiteral(
"results = {}" );
764 lines << currentIndent + QStringLiteral(
"outputs = {}" );
767 QSet< QString > executed;
768 bool executedAlg =
true;
770 while ( executedAlg && executed.count() < toExecute.count() )
773 const auto constToExecute = toExecute;
774 for (
const QString &childId : constToExecute )
776 if ( executed.contains( childId ) )
779 bool canExecute =
true;
780 const auto constDependsOnChildAlgorithms = dependsOnChildAlgorithms( childId );
781 for (
const QString &dependency : constDependsOnChildAlgorithms )
783 if ( !executed.contains( dependency ) )
795 const QgsProcessingModelChildAlgorithm &child = mChildAlgorithms[ childId ];
802 if ( def->isDestination() )
807 bool isFinalOutput =
false;
808 QMap<QString, QgsProcessingModelOutput> outputs = child.modelOutputs();
809 QMap<QString, QgsProcessingModelOutput>::const_iterator outputIt = outputs.constBegin();
810 for ( ; outputIt != outputs.constEnd(); ++outputIt )
812 if ( outputIt->childOutputName() == destParam->
name() )
814 QString paramName = child.childId() +
':' + outputIt.key();
815 paramName = friendlyOutputNames.value( paramName, paramName );
816 childParams.insert( destParam->
name(), QStringLiteral(
"parameters['%1']" ).arg( paramName ) );
817 isFinalOutput =
true;
822 if ( !isFinalOutput )
827 bool required =
true;
830 required = childOutputIsRequired( child.childId(), destParam->
name() );
837 childParams.insert( destParam->
name(), QStringLiteral(
"QgsProcessing.TEMPORARY_OUTPUT" ) );
843 lines << child.asPythonCode( outputType, childParams, currentIndent.size(), indentSize, friendlyChildNames, friendlyOutputNames );
845 if ( currentStep < totalSteps )
848 lines << currentIndent + QStringLiteral(
"feedback.setCurrentStep(%1)" ).arg( currentStep );
849 lines << currentIndent + QStringLiteral(
"if feedback.isCanceled():" );
850 lines << currentIndent + indent + QStringLiteral(
"return {}" );
853 executed.insert( childId );
857 switch ( outputType )
860 lines << currentIndent + QStringLiteral(
"return results" );
864 lines << indent + QStringLiteral(
"def name(self):" );
865 lines << indent + indent + QStringLiteral(
"return '%1'" ).arg( mModelName );
867 lines << indent + QStringLiteral(
"def displayName(self):" );
868 lines << indent + indent + QStringLiteral(
"return '%1'" ).arg( mModelName );
872 lines << indent + QStringLiteral(
"def group(self):" );
873 lines << indent + indent + QStringLiteral(
"return '%1'" ).arg( mModelGroup );
875 lines << indent + QStringLiteral(
"def groupId(self):" );
876 lines << indent + indent + QStringLiteral(
"return '%1'" ).arg( mModelGroupId );
880 if ( !shortHelpString().isEmpty() )
882 lines << indent + QStringLiteral(
"def shortHelpString(self):" );
883 lines << indent + indent + QStringLiteral(
"return \"\"\"%1\"\"\"" ).arg( shortHelpString() );
886 if ( !helpUrl().isEmpty() )
888 lines << indent + QStringLiteral(
"def helpUrl(self):" );
889 lines << indent + indent + QStringLiteral(
"return '%1'" ).arg( helpUrl() );
894 lines << indent + QStringLiteral(
"def createInstance(self):" );
895 lines << indent + indent + QStringLiteral(
"return %1()" ).arg( algorithmClassName );
898 static QMap< QString, QString > sAdditionalImports
900 { QStringLiteral(
"QgsCoordinateReferenceSystem" ), QStringLiteral(
"from qgis.core import QgsCoordinateReferenceSystem" ) },
901 { QStringLiteral(
"QgsExpression" ), QStringLiteral(
"from qgis.core import QgsExpression" ) },
902 { QStringLiteral(
"QgsRectangle" ), QStringLiteral(
"from qgis.core import QgsRectangle" ) },
903 { QStringLiteral(
"QgsReferencedRectangle" ), QStringLiteral(
"from qgis.core import QgsReferencedRectangle" ) },
904 { QStringLiteral(
"QgsPoint" ), QStringLiteral(
"from qgis.core import QgsPoint" ) },
905 { QStringLiteral(
"QgsReferencedPoint" ), QStringLiteral(
"from qgis.core import QgsReferencedPoint" ) },
906 { QStringLiteral(
"QgsProperty" ), QStringLiteral(
"from qgis.core import QgsProperty" ) },
907 { QStringLiteral(
"QgsRasterLayer" ), QStringLiteral(
"from qgis.core import QgsRasterLayer" ) },
908 { QStringLiteral(
"QgsMeshLayer" ), QStringLiteral(
"from qgis.core import QgsMeshLayer" ) },
909 { QStringLiteral(
"QgsVectorLayer" ), QStringLiteral(
"from qgis.core import QgsVectorLayer" ) },
910 { QStringLiteral(
"QgsMapLayer" ), QStringLiteral(
"from qgis.core import QgsMapLayer" ) },
911 { QStringLiteral(
"QgsProcessingFeatureSourceDefinition" ), QStringLiteral(
"from qgis.core import QgsProcessingFeatureSourceDefinition" ) },
912 { QStringLiteral(
"QgsPointXY" ), QStringLiteral(
"from qgis.core import QgsPointXY" ) },
913 { QStringLiteral(
"QgsReferencedPointXY" ), QStringLiteral(
"from qgis.core import QgsReferencedPointXY" ) },
914 { QStringLiteral(
"QgsGeometry" ), QStringLiteral(
"from qgis.core import QgsGeometry" ) },
915 { QStringLiteral(
"QgsProcessingOutputLayerDefinition" ), QStringLiteral(
"from qgis.core import QgsProcessingOutputLayerDefinition" ) },
916 { QStringLiteral(
"QColor" ), QStringLiteral(
"from qgis.PyQt.QtGui import QColor" ) },
917 { QStringLiteral(
"QDateTime" ), QStringLiteral(
"from qgis.PyQt.QtCore import QDateTime" ) },
918 { QStringLiteral(
"QDate" ), QStringLiteral(
"from qgis.PyQt.QtCore import QDate" ) },
919 { QStringLiteral(
"QTime" ), QStringLiteral(
"from qgis.PyQt.QtCore import QTime" ) },
922 for (
auto it = sAdditionalImports.constBegin(); it != sAdditionalImports.constEnd(); ++it )
924 if ( importLines.contains( it.value() ) )
931 for (
const QString &line : std::as_const( lines ) )
933 if ( line.contains( it.key() ) )
941 importLines << it.value();
945 lines = fileDocString + importLines + lines;
954 QMap<QString, QgsProcessingModelAlgorithm::VariableDefinition> QgsProcessingModelAlgorithm::variablesForChildAlgorithm(
const QString &childId,
QgsProcessingContext &context,
const QVariantMap &modelParameters,
const QVariantMap &results )
const
956 QMap<QString, QgsProcessingModelAlgorithm::VariableDefinition> variables;
958 auto safeName = [](
const QString & name )->QString
961 return s.replace( QRegularExpression( QStringLiteral(
"[\\s'\"\\(\\):\\.]" ) ), QStringLiteral(
"_" ) );
995 for (
const QgsProcessingModelChildParameterSource &source : std::as_const( sources ) )
1000 switch ( source.source() )
1002 case QgsProcessingModelChildParameterSource::ModelParameter:
1004 name = source.parameterName();
1005 value = modelParameters.value( source.parameterName() );
1006 description = parameterDefinition( source.parameterName() )->description();
1009 case QgsProcessingModelChildParameterSource::ChildOutput:
1011 const QgsProcessingModelChildAlgorithm &child = mChildAlgorithms.value( source.outputChildId() );
1012 name = QStringLiteral(
"%1_%2" ).arg( child.description().isEmpty() ?
1013 source.outputChildId() : child.description(), source.outputName() );
1016 description = QObject::tr(
"Output '%1' from algorithm '%2'" ).arg( alg->outputDefinition( source.outputName() )->description(),
1017 child.description() );
1019 value = results.value( source.outputChildId() ).toMap().value( source.outputName() );
1023 case QgsProcessingModelChildParameterSource::Expression:
1024 case QgsProcessingModelChildParameterSource::ExpressionText:
1025 case QgsProcessingModelChildParameterSource::StaticValue:
1026 case QgsProcessingModelChildParameterSource::ModelOutput:
1029 variables.insert( safeName( name ), VariableDefinition( value, source, description ) );
1033 sources = availableSourcesForChild( childId, QStringList()
1040 for (
const QgsProcessingModelChildParameterSource &source : std::as_const( sources ) )
1044 QString description;
1046 switch ( source.source() )
1048 case QgsProcessingModelChildParameterSource::ModelParameter:
1050 name = source.parameterName();
1051 value = modelParameters.value( source.parameterName() );
1052 description = parameterDefinition( source.parameterName() )->description();
1055 case QgsProcessingModelChildParameterSource::ChildOutput:
1057 const QgsProcessingModelChildAlgorithm &child = mChildAlgorithms.value( source.outputChildId() );
1058 name = QStringLiteral(
"%1_%2" ).arg( child.description().isEmpty() ?
1059 source.outputChildId() : child.description(), source.outputName() );
1060 value = results.value( source.outputChildId() ).toMap().value( source.outputName() );
1063 description = QObject::tr(
"Output '%1' from algorithm '%2'" ).arg( alg->outputDefinition( source.outputName() )->description(),
1064 child.description() );
1069 case QgsProcessingModelChildParameterSource::Expression:
1070 case QgsProcessingModelChildParameterSource::ExpressionText:
1071 case QgsProcessingModelChildParameterSource::StaticValue:
1072 case QgsProcessingModelChildParameterSource::ModelOutput:
1080 value = fromVar.
sink;
1086 QgsMapLayer *layer = qobject_cast< QgsMapLayer * >( qvariant_cast<QObject *>( value ) );
1090 variables.insert( safeName( name ), VariableDefinition( QVariant::fromValue(
QgsWeakMapLayerPointer( layer ) ), source, description ) );
1091 variables.insert( safeName( QStringLiteral(
"%1_minx" ).arg( name ) ), VariableDefinition( layer ? layer->
extent().
xMinimum() : QVariant(), source, QObject::tr(
"Minimum X of %1" ).arg( description ) ) );
1092 variables.insert( safeName( QStringLiteral(
"%1_miny" ).arg( name ) ), VariableDefinition( layer ? layer->
extent().
yMinimum() : QVariant(), source, QObject::tr(
"Minimum Y of %1" ).arg( description ) ) );
1093 variables.insert( safeName( QStringLiteral(
"%1_maxx" ).arg( name ) ), VariableDefinition( layer ? layer->
extent().
xMaximum() : QVariant(), source, QObject::tr(
"Maximum X of %1" ).arg( description ) ) );
1094 variables.insert( safeName( QStringLiteral(
"%1_maxy" ).arg( name ) ), VariableDefinition( layer ? layer->
extent().
yMaximum() : QVariant(), source, QObject::tr(
"Maximum Y of %1" ).arg( description ) ) );
1097 sources = availableSourcesForChild( childId, QStringList()
1099 for (
const QgsProcessingModelChildParameterSource &source : std::as_const( sources ) )
1103 QString description;
1105 switch ( source.source() )
1107 case QgsProcessingModelChildParameterSource::ModelParameter:
1109 name = source.parameterName();
1110 value = modelParameters.value( source.parameterName() );
1111 description = parameterDefinition( source.parameterName() )->description();
1114 case QgsProcessingModelChildParameterSource::ChildOutput:
1116 const QgsProcessingModelChildAlgorithm &child = mChildAlgorithms.value( source.outputChildId() );
1117 name = QStringLiteral(
"%1_%2" ).arg( child.description().isEmpty() ?
1118 source.outputChildId() : child.description(), source.outputName() );
1119 value = results.value( source.outputChildId() ).toMap().value( source.outputName() );
1122 description = QObject::tr(
"Output '%1' from algorithm '%2'" ).arg( alg->outputDefinition( source.outputName() )->description(),
1123 child.description() );
1128 case QgsProcessingModelChildParameterSource::Expression:
1129 case QgsProcessingModelChildParameterSource::ExpressionText:
1130 case QgsProcessingModelChildParameterSource::StaticValue:
1131 case QgsProcessingModelChildParameterSource::ModelOutput:
1145 value = fromVar.
sink;
1151 if (
QgsVectorLayer *layer = qobject_cast< QgsVectorLayer * >( qvariant_cast<QObject *>( value ) ) )
1153 featureSource = layer;
1155 if ( !featureSource )
1161 variables.insert( safeName( name ), VariableDefinition( value, source, description ) );
1162 variables.insert( safeName( QStringLiteral(
"%1_minx" ).arg( name ) ), VariableDefinition( featureSource ? featureSource->
sourceExtent().
xMinimum() : QVariant(), source, QObject::tr(
"Minimum X of %1" ).arg( description ) ) );
1163 variables.insert( safeName( QStringLiteral(
"%1_miny" ).arg( name ) ), VariableDefinition( featureSource ? featureSource->
sourceExtent().
yMinimum() : QVariant(), source, QObject::tr(
"Minimum Y of %1" ).arg( description ) ) );
1164 variables.insert( safeName( QStringLiteral(
"%1_maxx" ).arg( name ) ), VariableDefinition( featureSource ? featureSource->
sourceExtent().
xMaximum() : QVariant(), source, QObject::tr(
"Maximum X of %1" ).arg( description ) ) );
1165 variables.insert( safeName( QStringLiteral(
"%1_maxy" ).arg( name ) ), VariableDefinition( featureSource ? featureSource->
sourceExtent().
yMaximum() : QVariant(), source, QObject::tr(
"Maximum Y of %1" ).arg( description ) ) );
1171 QgsExpressionContextScope *QgsProcessingModelAlgorithm::createExpressionContextScopeForChildAlgorithm(
const QString &childId,
QgsProcessingContext &context,
const QVariantMap &modelParameters,
const QVariantMap &results )
const
1173 std::unique_ptr< QgsExpressionContextScope > scope(
new QgsExpressionContextScope( QStringLiteral(
"algorithm_inputs" ) ) );
1174 QMap< QString, QgsProcessingModelAlgorithm::VariableDefinition> variables = variablesForChildAlgorithm( childId, context, modelParameters, results );
1175 QMap< QString, QgsProcessingModelAlgorithm::VariableDefinition>::const_iterator varIt = variables.constBegin();
1176 for ( ; varIt != variables.constEnd(); ++varIt )
1180 return scope.release();
1183 QgsProcessingModelChildParameterSources QgsProcessingModelAlgorithm::availableSourcesForChild(
const QString &childId,
const QStringList ¶meterTypes,
const QStringList &outputTypes,
const QList<int> &dataTypes )
const
1185 QgsProcessingModelChildParameterSources sources;
1188 QMap< QString, QgsProcessingModelParameter >::const_iterator paramIt = mParameterComponents.constBegin();
1189 for ( ; paramIt != mParameterComponents.constEnd(); ++paramIt )
1195 if ( parameterTypes.contains( def->
type() ) )
1197 if ( !dataTypes.isEmpty() )
1213 bool ok = sourceDef->
dataTypes().isEmpty();
1214 const auto constDataTypes = sourceDef->
dataTypes();
1215 for (
int type : constDataTypes )
1230 sources << QgsProcessingModelChildParameterSource::fromModelParameter( paramIt->parameterName() );
1234 QSet< QString > dependents;
1235 if ( !childId.isEmpty() )
1237 dependents = dependentChildAlgorithms( childId );
1238 dependents << childId;
1241 QMap< QString, QgsProcessingModelChildAlgorithm >::const_iterator childIt = mChildAlgorithms.constBegin();
1242 for ( ; childIt != mChildAlgorithms.constEnd(); ++childIt )
1244 if ( dependents.contains( childIt->childId() ) )
1254 if ( outputTypes.contains( out->type() ) )
1256 if ( !dataTypes.isEmpty() )
1262 if ( !vectorOutputIsCompatibleType( dataTypes, vectorOut->
dataType() ) )
1269 sources << QgsProcessingModelChildParameterSource::fromChildOutput( childIt->childId(), out->name() );
1277 QVariantMap QgsProcessingModelAlgorithm::helpContent()
const
1279 return mHelpContent;
1282 void QgsProcessingModelAlgorithm::setHelpContent(
const QVariantMap &helpContent )
1284 mHelpContent = helpContent;
1287 void QgsProcessingModelAlgorithm::setName(
const QString &name )
1292 void QgsProcessingModelAlgorithm::setGroup(
const QString &group )
1294 mModelGroup = group;
1297 bool QgsProcessingModelAlgorithm::validate( QStringList &issues )
const
1302 if ( mChildAlgorithms.empty() )
1305 issues << QObject::tr(
"Model does not contain any algorithms" );
1308 for (
auto it = mChildAlgorithms.constBegin(); it != mChildAlgorithms.constEnd(); ++it )
1310 QStringList childIssues;
1311 res = validateChildAlgorithm( it->childId(), childIssues ) && res;
1313 for (
const QString &issue : std::as_const( childIssues ) )
1315 issues << QStringLiteral(
"<b>%1</b>: %2" ).arg( it->description(), issue );
1321 QMap<QString, QgsProcessingModelChildAlgorithm> QgsProcessingModelAlgorithm::childAlgorithms()
const
1323 return mChildAlgorithms;
1326 void QgsProcessingModelAlgorithm::setParameterComponents(
const QMap<QString, QgsProcessingModelParameter> ¶meterComponents )
1328 mParameterComponents = parameterComponents;
1331 void QgsProcessingModelAlgorithm::setParameterComponent(
const QgsProcessingModelParameter &component )
1333 mParameterComponents.insert( component.parameterName(), component );
1336 QgsProcessingModelParameter &QgsProcessingModelAlgorithm::parameterComponent(
const QString &name )
1338 if ( !mParameterComponents.contains( name ) )
1340 QgsProcessingModelParameter &component = mParameterComponents[ name ];
1341 component.setParameterName( name );
1344 return mParameterComponents[ name ];
1347 QList< QgsProcessingModelParameter > QgsProcessingModelAlgorithm::orderedParameters()
const
1349 QList< QgsProcessingModelParameter > res;
1350 QSet< QString > found;
1351 for (
const QString ¶meter : mParameterOrder )
1353 if ( mParameterComponents.contains( parameter ) )
1355 res << mParameterComponents.value( parameter );
1361 for (
auto it = mParameterComponents.constBegin(); it != mParameterComponents.constEnd(); ++it )
1363 if ( !found.contains( it.key() ) )
1371 void QgsProcessingModelAlgorithm::setParameterOrder(
const QStringList &order )
1373 mParameterOrder = order;
1376 void QgsProcessingModelAlgorithm::updateDestinationParameters()
1379 QMutableListIterator<const QgsProcessingParameterDefinition *> it( mParameters );
1380 while ( it.hasNext() )
1390 qDeleteAll( mOutputs );
1394 QSet< QString > usedFriendlyNames;
1395 auto uniqueSafeName = [&usedFriendlyNames ](
const QString & name )->QString
1397 const QString base = safeName( name,
false );
1398 QString candidate = base;
1400 while ( usedFriendlyNames.contains( candidate ) )
1403 candidate = QStringLiteral(
"%1_%2" ).arg( base ).arg( i );
1405 usedFriendlyNames.insert( candidate );
1409 QMap< QString, QgsProcessingModelChildAlgorithm >::const_iterator childIt = mChildAlgorithms.constBegin();
1410 for ( ; childIt != mChildAlgorithms.constEnd(); ++childIt )
1412 QMap<QString, QgsProcessingModelOutput> outputs = childIt->modelOutputs();
1413 QMap<QString, QgsProcessingModelOutput>::const_iterator outputIt = outputs.constBegin();
1414 for ( ; outputIt != outputs.constEnd(); ++outputIt )
1416 if ( !childIt->isActive() || !childIt->algorithm() )
1424 std::unique_ptr< QgsProcessingParameterDefinition > param( source->
clone() );
1428 if ( outputIt->isMandatory() )
1430 if ( mInternalVersion != InternalVersion::Version1 && !outputIt->description().isEmpty() )
1432 QString friendlyName = uniqueSafeName( outputIt->description() );
1433 param->setName( friendlyName );
1437 param->setName( outputIt->childId() +
':' + outputIt->name() );
1440 param->metadata().insert( QStringLiteral(
"_modelChildId" ), outputIt->childId() );
1441 param->metadata().insert( QStringLiteral(
"_modelChildOutputName" ), outputIt->name() );
1442 param->metadata().insert( QStringLiteral(
"_modelChildProvider" ), childIt->algorithm()->provider()->id() );
1444 param->setDescription( outputIt->description() );
1445 param->setDefaultValue( outputIt->defaultValue() );
1448 if ( addParameter( param.release() ) && newDestParam )
1455 newDestParam->mOriginalProvider = provider;
1462 void QgsProcessingModelAlgorithm::addGroupBox(
const QgsProcessingModelGroupBox &groupBox )
1464 mGroupBoxes.insert( groupBox.uuid(), groupBox );
1467 QList<QgsProcessingModelGroupBox> QgsProcessingModelAlgorithm::groupBoxes()
const
1469 return mGroupBoxes.values();
1472 void QgsProcessingModelAlgorithm::removeGroupBox(
const QString &uuid )
1474 mGroupBoxes.remove( uuid );
1477 QVariant QgsProcessingModelAlgorithm::toVariant()
const
1480 map.insert( QStringLiteral(
"model_name" ), mModelName );
1481 map.insert( QStringLiteral(
"model_group" ), mModelGroup );
1482 map.insert( QStringLiteral(
"help" ), mHelpContent );
1483 map.insert( QStringLiteral(
"internal_version" ),
qgsEnumValueToKey( mInternalVersion ) );
1485 QVariantMap childMap;
1486 QMap< QString, QgsProcessingModelChildAlgorithm >::const_iterator childIt = mChildAlgorithms.constBegin();
1487 for ( ; childIt != mChildAlgorithms.constEnd(); ++childIt )
1489 childMap.insert( childIt.key(), childIt.value().toVariant() );
1491 map.insert( QStringLiteral(
"children" ), childMap );
1493 QVariantMap paramMap;
1494 QMap< QString, QgsProcessingModelParameter >::const_iterator paramIt = mParameterComponents.constBegin();
1495 for ( ; paramIt != mParameterComponents.constEnd(); ++paramIt )
1497 paramMap.insert( paramIt.key(), paramIt.value().toVariant() );
1499 map.insert( QStringLiteral(
"parameters" ), paramMap );
1501 QVariantMap paramDefMap;
1506 map.insert( QStringLiteral(
"parameterDefinitions" ), paramDefMap );
1508 QVariantList groupBoxDefs;
1509 for (
auto it = mGroupBoxes.constBegin(); it != mGroupBoxes.constEnd(); ++it )
1511 groupBoxDefs.append( it.value().toVariant() );
1513 map.insert( QStringLiteral(
"groupBoxes" ), groupBoxDefs );
1515 map.insert( QStringLiteral(
"modelVariables" ), mVariables );
1517 map.insert( QStringLiteral(
"designerParameterValues" ), mDesignerParameterValues );
1519 map.insert( QStringLiteral(
"parameterOrder" ), mParameterOrder );
1524 bool QgsProcessingModelAlgorithm::loadVariant(
const QVariant &model )
1526 QVariantMap map = model.toMap();
1528 mModelName = map.value( QStringLiteral(
"model_name" ) ).toString();
1529 mModelGroup = map.value( QStringLiteral(
"model_group" ) ).toString();
1530 mModelGroupId = map.value( QStringLiteral(
"model_group" ) ).toString();
1531 mHelpContent = map.value( QStringLiteral(
"help" ) ).toMap();
1533 mInternalVersion =
qgsEnumKeyToValue( map.value( QStringLiteral(
"internal_version" ) ).toString(), InternalVersion::Version1 );
1535 mVariables = map.value( QStringLiteral(
"modelVariables" ) ).toMap();
1536 mDesignerParameterValues = map.value( QStringLiteral(
"designerParameterValues" ) ).toMap();
1538 mParameterOrder = map.value( QStringLiteral(
"parameterOrder" ) ).toStringList();
1540 mChildAlgorithms.clear();
1541 QVariantMap childMap = map.value( QStringLiteral(
"children" ) ).toMap();
1542 QVariantMap::const_iterator childIt = childMap.constBegin();
1543 for ( ; childIt != childMap.constEnd(); ++childIt )
1545 QgsProcessingModelChildAlgorithm child;
1549 if ( !child.loadVariant( childIt.value() ) )
1552 mChildAlgorithms.insert( child.childId(), child );
1555 mParameterComponents.clear();
1556 QVariantMap paramMap = map.value( QStringLiteral(
"parameters" ) ).toMap();
1557 QVariantMap::const_iterator paramIt = paramMap.constBegin();
1558 for ( ; paramIt != paramMap.constEnd(); ++paramIt )
1560 QgsProcessingModelParameter param;
1561 if ( !param.loadVariant( paramIt.value().toMap() ) )
1564 mParameterComponents.insert( param.parameterName(), param );
1567 qDeleteAll( mParameters );
1568 mParameters.clear();
1569 QVariantMap paramDefMap = map.value( QStringLiteral(
"parameterDefinitions" ) ).toMap();
1571 auto addParam = [ = ](
const QVariant & value )
1579 if ( param->name() == QLatin1String(
"VERBOSE_LOG" ) )
1583 param->setHelp( mHelpContent.value( param->name() ).toString() );
1586 addParameter( param.release() );
1590 QVariantMap map = value.toMap();
1591 QString type = map.value( QStringLiteral(
"parameter_type" ) ).toString();
1592 QString name = map.value( QStringLiteral(
"name" ) ).toString();
1594 QgsMessageLog::logMessage( QCoreApplication::translate(
"Processing",
"Could not load parameter %1 of type %2." ).arg( name, type ), QCoreApplication::translate(
"Processing",
"Processing" ) );
1598 QSet< QString > loadedParams;
1600 for (
const QString &name : std::as_const( mParameterOrder ) )
1602 if ( paramDefMap.contains( name ) )
1604 addParam( paramDefMap.value( name ) );
1605 loadedParams << name;
1609 QVariantMap::const_iterator paramDefIt = paramDefMap.constBegin();
1610 for ( ; paramDefIt != paramDefMap.constEnd(); ++paramDefIt )
1612 if ( !loadedParams.contains( paramDefIt.key() ) )
1613 addParam( paramDefIt.value() );
1616 mGroupBoxes.clear();
1617 const QVariantList groupBoxList = map.value( QStringLiteral(
"groupBoxes" ) ).toList();
1618 for (
const QVariant &groupBoxDef : groupBoxList )
1620 QgsProcessingModelGroupBox groupBox;
1621 groupBox.loadVariant( groupBoxDef.toMap() );
1622 mGroupBoxes.insert( groupBox.uuid(), groupBox );
1625 updateDestinationParameters();
1630 bool QgsProcessingModelAlgorithm::vectorOutputIsCompatibleType(
const QList<int> &acceptableDataTypes,
QgsProcessing::SourceType outputType )
1635 return ( acceptableDataTypes.empty()
1636 || acceptableDataTypes.contains( outputType )
1647 void QgsProcessingModelAlgorithm::reattachAlgorithms()
const
1649 QMap< QString, QgsProcessingModelChildAlgorithm >::const_iterator childIt = mChildAlgorithms.constBegin();
1650 for ( ; childIt != mChildAlgorithms.constEnd(); ++childIt )
1652 if ( !childIt->algorithm() )
1653 childIt->reattach();
1657 bool QgsProcessingModelAlgorithm::toFile(
const QString &path )
const
1659 QDomDocument doc = QDomDocument( QStringLiteral(
"model" ) );
1661 doc.appendChild( elem );
1664 if ( file.open( QFile::WriteOnly | QFile::Truncate ) )
1666 QTextStream stream( &file );
1667 doc.save( stream, 2 );
1674 bool QgsProcessingModelAlgorithm::fromFile(
const QString &path )
1679 if ( file.open( QFile::ReadOnly ) )
1681 if ( !doc.setContent( &file ) )
1692 return loadVariant( props );
1695 void QgsProcessingModelAlgorithm::setChildAlgorithms(
const QMap<QString, QgsProcessingModelChildAlgorithm> &childAlgorithms )
1697 mChildAlgorithms = childAlgorithms;
1698 updateDestinationParameters();
1701 void QgsProcessingModelAlgorithm::setChildAlgorithm(
const QgsProcessingModelChildAlgorithm &
algorithm )
1704 updateDestinationParameters();
1707 QString QgsProcessingModelAlgorithm::addChildAlgorithm( QgsProcessingModelChildAlgorithm &
algorithm )
1709 if (
algorithm.childId().isEmpty() || mChildAlgorithms.contains(
algorithm.childId() ) )
1713 updateDestinationParameters();
1717 QgsProcessingModelChildAlgorithm &QgsProcessingModelAlgorithm::childAlgorithm(
const QString &childId )
1719 return mChildAlgorithms[ childId ];
1722 bool QgsProcessingModelAlgorithm::removeChildAlgorithm(
const QString &
id )
1724 if ( !dependentChildAlgorithms(
id ).isEmpty() )
1727 mChildAlgorithms.remove(
id );
1728 updateDestinationParameters();
1732 void QgsProcessingModelAlgorithm::deactivateChildAlgorithm(
const QString &
id )
1734 const auto constDependentChildAlgorithms = dependentChildAlgorithms(
id );
1735 for (
const QString &child : constDependentChildAlgorithms )
1737 childAlgorithm( child ).setActive(
false );
1739 childAlgorithm(
id ).setActive(
false );
1740 updateDestinationParameters();
1743 bool QgsProcessingModelAlgorithm::activateChildAlgorithm(
const QString &
id )
1745 const auto constDependsOnChildAlgorithms = dependsOnChildAlgorithms(
id );
1746 for (
const QString &child : constDependsOnChildAlgorithms )
1748 if ( !childAlgorithm( child ).isActive() )
1751 childAlgorithm(
id ).setActive(
true );
1752 updateDestinationParameters();
1758 if ( addParameter( definition ) )
1759 mParameterComponents.insert( definition->
name(), component );
1764 removeParameter( definition->
name() );
1765 addParameter( definition );
1768 void QgsProcessingModelAlgorithm::removeModelParameter(
const QString &name )
1770 removeParameter( name );
1771 mParameterComponents.remove( name );
1774 void QgsProcessingModelAlgorithm::changeParameterName(
const QString &oldName,
const QString &newName )
1779 auto replaceExpressionVariable = [oldName, newName, &expressionContext](
const QString & expressionString ) -> std::tuple< bool, QString >
1782 expression.prepare( &expressionContext );
1783 QSet<QString> variables = expression.referencedVariables();
1784 if ( variables.contains( oldName ) )
1786 QString newExpression = expressionString;
1787 newExpression.replace( QStringLiteral(
"@%1" ).arg( oldName ), QStringLiteral(
"@%2" ).arg( newName ) );
1788 return {
true, newExpression };
1790 return {
false, QString() };
1793 QMap< QString, QgsProcessingModelChildAlgorithm >::iterator childIt = mChildAlgorithms.begin();
1794 for ( ; childIt != mChildAlgorithms.end(); ++childIt )
1796 bool changed =
false;
1797 QMap<QString, QgsProcessingModelChildParameterSources> childParams = childIt->parameterSources();
1798 QMap<QString, QgsProcessingModelChildParameterSources>::iterator paramIt = childParams.begin();
1799 for ( ; paramIt != childParams.end(); ++paramIt )
1801 QList< QgsProcessingModelChildParameterSource > &value = paramIt.value();
1802 for (
auto valueIt = value.begin(); valueIt != value.end(); ++valueIt )
1804 switch ( valueIt->source() )
1806 case QgsProcessingModelChildParameterSource::ModelParameter:
1808 if ( valueIt->parameterName() == oldName )
1810 valueIt->setParameterName( newName );
1816 case QgsProcessingModelChildParameterSource::Expression:
1818 bool updatedExpression =
false;
1819 QString newExpression;
1820 std::tie( updatedExpression, newExpression ) = replaceExpressionVariable( valueIt->expression() );
1821 if ( updatedExpression )
1823 valueIt->setExpression( newExpression );
1829 case QgsProcessingModelChildParameterSource::StaticValue:
1831 if ( valueIt->staticValue().canConvert<
QgsProperty >() )
1836 bool updatedExpression =
false;
1837 QString newExpression;
1838 std::tie( updatedExpression, newExpression ) = replaceExpressionVariable( property.expressionString() );
1839 if ( updatedExpression )
1841 property.setExpressionString( newExpression );
1842 valueIt->setStaticValue( property );
1850 case QgsProcessingModelChildParameterSource::ChildOutput:
1851 case QgsProcessingModelChildParameterSource::ExpressionText:
1852 case QgsProcessingModelChildParameterSource::ModelOutput:
1858 childIt->setParameterSources( childParams );
1862 bool QgsProcessingModelAlgorithm::childAlgorithmsDependOnParameter(
const QString &name )
const
1864 QMap< QString, QgsProcessingModelChildAlgorithm >::const_iterator childIt = mChildAlgorithms.constBegin();
1865 for ( ; childIt != mChildAlgorithms.constEnd(); ++childIt )
1868 QMap<QString, QgsProcessingModelChildParameterSources> childParams = childIt->parameterSources();
1869 QMap<QString, QgsProcessingModelChildParameterSources>::const_iterator paramIt = childParams.constBegin();
1870 for ( ; paramIt != childParams.constEnd(); ++paramIt )
1872 const auto constValue = paramIt.value();
1873 for (
const QgsProcessingModelChildParameterSource &source : constValue )
1875 if ( source.source() == QgsProcessingModelChildParameterSource::ModelParameter
1876 && source.parameterName() == name )
1886 bool QgsProcessingModelAlgorithm::otherParametersDependOnParameter(
const QString &name )
const
1888 const auto constMParameters = mParameters;
1891 if ( def->
name() == name )
1900 QMap<QString, QgsProcessingModelParameter> QgsProcessingModelAlgorithm::parameterComponents()
const
1902 return mParameterComponents;
1905 void QgsProcessingModelAlgorithm::dependentChildAlgorithmsRecursive(
const QString &childId, QSet<QString> &depends,
const QString &branch )
const
1907 QMap< QString, QgsProcessingModelChildAlgorithm >::const_iterator childIt = mChildAlgorithms.constBegin();
1908 for ( ; childIt != mChildAlgorithms.constEnd(); ++childIt )
1910 if ( depends.contains( childIt->childId() ) )
1914 const QList< QgsProcessingModelChildDependency > constDependencies = childIt->dependencies();
1915 bool hasDependency =
false;
1916 for (
const QgsProcessingModelChildDependency &dep : constDependencies )
1918 if ( dep.childId == childId && ( branch.isEmpty() || dep.conditionalBranch == branch ) )
1920 hasDependency =
true;
1925 if ( hasDependency )
1927 depends.insert( childIt->childId() );
1928 dependentChildAlgorithmsRecursive( childIt->childId(), depends, branch );
1933 QMap<QString, QgsProcessingModelChildParameterSources> childParams = childIt->parameterSources();
1934 QMap<QString, QgsProcessingModelChildParameterSources>::const_iterator paramIt = childParams.constBegin();
1935 for ( ; paramIt != childParams.constEnd(); ++paramIt )
1937 const auto constValue = paramIt.value();
1938 for (
const QgsProcessingModelChildParameterSource &source : constValue )
1940 if ( source.source() == QgsProcessingModelChildParameterSource::ChildOutput
1941 && source.outputChildId() == childId )
1943 depends.insert( childIt->childId() );
1944 dependentChildAlgorithmsRecursive( childIt->childId(), depends, branch );
1952 QSet<QString> QgsProcessingModelAlgorithm::dependentChildAlgorithms(
const QString &childId,
const QString &conditionalBranch )
const
1954 QSet< QString > algs;
1958 algs.insert( childId );
1960 dependentChildAlgorithmsRecursive( childId, algs, conditionalBranch );
1963 algs.remove( childId );
1969 void QgsProcessingModelAlgorithm::dependsOnChildAlgorithmsRecursive(
const QString &childId, QSet< QString > &depends )
const
1971 const QgsProcessingModelChildAlgorithm &alg = mChildAlgorithms.value( childId );
1974 const QList< QgsProcessingModelChildDependency > constDependencies = alg.dependencies();
1975 for (
const QgsProcessingModelChildDependency &val : constDependencies )
1977 if ( !depends.contains( val.childId ) )
1979 depends.insert( val.childId );
1980 dependsOnChildAlgorithmsRecursive( val.childId, depends );
1985 QMap<QString, QgsProcessingModelChildParameterSources> childParams = alg.parameterSources();
1986 QMap<QString, QgsProcessingModelChildParameterSources>::const_iterator paramIt = childParams.constBegin();
1987 for ( ; paramIt != childParams.constEnd(); ++paramIt )
1989 const auto constValue = paramIt.value();
1990 for (
const QgsProcessingModelChildParameterSource &source : constValue )
1992 if ( source.source() == QgsProcessingModelChildParameterSource::ChildOutput && !depends.contains( source.outputChildId() ) )
1994 depends.insert( source.outputChildId() );
1995 dependsOnChildAlgorithmsRecursive( source.outputChildId(), depends );
2001 QSet< QString > QgsProcessingModelAlgorithm::dependsOnChildAlgorithms(
const QString &childId )
const
2003 QSet< QString > algs;
2007 algs.insert( childId );
2009 dependsOnChildAlgorithmsRecursive( childId, algs );
2012 algs.remove( childId );
2017 QList<QgsProcessingModelChildDependency> QgsProcessingModelAlgorithm::availableDependenciesForChildAlgorithm(
const QString &childId )
const
2019 QSet< QString > dependent;
2020 if ( !childId.isEmpty() )
2022 dependent.unite( dependentChildAlgorithms( childId ) );
2023 dependent.insert( childId );
2026 QList<QgsProcessingModelChildDependency> res;
2027 for (
auto it = mChildAlgorithms.constBegin(); it != mChildAlgorithms.constEnd(); ++it )
2029 if ( !dependent.contains( it->childId() ) )
2032 bool hasBranches =
false;
2033 if ( it->algorithm() )
2041 QgsProcessingModelChildDependency alg;
2042 alg.childId = it->childId();
2043 alg.conditionalBranch = def->
name();
2051 QgsProcessingModelChildDependency alg;
2052 alg.childId = it->childId();
2060 bool QgsProcessingModelAlgorithm::validateChildAlgorithm(
const QString &childId, QStringList &issues )
const
2063 QMap< QString, QgsProcessingModelChildAlgorithm >::const_iterator childIt = mChildAlgorithms.constFind( childId );
2064 if ( childIt != mChildAlgorithms.constEnd() )
2066 if ( !childIt->algorithm() )
2068 issues << QObject::tr(
"Algorithm is not available: <i>%1</i>" ).arg( childIt->algorithmId() );
2077 if ( childIt->parameterSources().contains( def->
name() ) )
2080 const QList< QgsProcessingModelChildParameterSource > sources = childIt->parameterSources().value( def->
name() );
2081 for (
const QgsProcessingModelChildParameterSource &source : sources )
2083 switch ( source.source() )
2085 case QgsProcessingModelChildParameterSource::StaticValue:
2089 issues << QObject::tr(
"Value for <i>%1</i> is not acceptable for this parameter" ).arg( def->
name() );
2093 case QgsProcessingModelChildParameterSource::ModelParameter:
2094 if ( !parameterComponents().contains( source.parameterName() ) )
2097 issues << QObject::tr(
"Model input <i>%1</i> used for parameter <i>%2</i> does not exist" ).arg( source.parameterName(), def->
name() );
2101 case QgsProcessingModelChildParameterSource::ChildOutput:
2102 if ( !childAlgorithms().contains( source.outputChildId() ) )
2105 issues << QObject::tr(
"Child algorithm <i>%1</i> used for parameter <i>%2</i> does not exist" ).arg( source.outputChildId(), def->
name() );
2109 case QgsProcessingModelChildParameterSource::Expression:
2110 case QgsProcessingModelChildParameterSource::ExpressionText:
2111 case QgsProcessingModelChildParameterSource::ModelOutput:
2127 issues << QObject::tr(
"Parameter <i>%1</i> is mandatory" ).arg( def->
name() );
2136 issues << QObject::tr(
"Invalid child ID: <i>%1</i>" ).arg( childId );
2141 bool QgsProcessingModelAlgorithm::canExecute( QString *errorMessage )
const
2143 reattachAlgorithms();
2144 QMap< QString, QgsProcessingModelChildAlgorithm >::const_iterator childIt = mChildAlgorithms.constBegin();
2145 for ( ; childIt != mChildAlgorithms.constEnd(); ++childIt )
2147 if ( !childIt->algorithm() )
2151 *errorMessage = QObject::tr(
"The model you are trying to run contains an algorithm that is not available: <i>%1</i>" ).arg( childIt->algorithmId() );
2159 QString QgsProcessingModelAlgorithm::asPythonCommand(
const QVariantMap ¶meters,
QgsProcessingContext &context )
const
2161 if ( mSourceFile.isEmpty() )
2176 QgsProcessingModelAlgorithm *alg =
new QgsProcessingModelAlgorithm();
2177 alg->loadVariant( toVariant() );
2178 alg->setProvider( provider() );
2179 alg->setSourceFilePath( sourceFilePath() );
2183 QString QgsProcessingModelAlgorithm::safeName(
const QString &name,
bool capitalize )
2185 QString n = name.toLower().trimmed();
2186 const thread_local QRegularExpression rx( QStringLiteral(
"[^\\sa-z_A-Z0-9]" ) );
2187 n.replace( rx, QString() );
2188 const thread_local QRegularExpression rx2( QStringLiteral(
"^\\d*" ) );
2189 n.replace( rx2, QString() );
2191 n = n.replace(
' ',
'_' );
2195 QVariantMap QgsProcessingModelAlgorithm::variables()
const
2200 void QgsProcessingModelAlgorithm::setVariables(
const QVariantMap &variables )
2202 mVariables = variables;
2205 QVariantMap QgsProcessingModelAlgorithm::designerParameterValues()
const
2207 return mDesignerParameterValues;