QGIS API Documentation  3.26.3-Buenos Aires (65e4edfdad)
qgsprocessingmodelalgorithm.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsprocessingmodelalgorithm.cpp
3  ------------------------------
4  begin : June 2017
5  copyright : (C) 2017 by Nyall Dawson
6  email : nyall dot dawson at gmail dot com
7  ***************************************************************************/
8 
9 /***************************************************************************
10  * *
11  * This program is free software; you can redistribute it and/or modify *
12  * it under the terms of the GNU General Public License as published by *
13  * the Free Software Foundation; either version 2 of the License, or *
14  * (at your option) any later version. *
15  * *
16  ***************************************************************************/
17 
19 #include "qgsprocessingregistry.h"
20 #include "qgsprocessingfeedback.h"
21 #include "qgsprocessingutils.h"
22 #include "qgis.h"
23 #include "qgsxmlutils.h"
24 #include "qgsexception.h"
25 #include "qgsvectorlayer.h"
26 #include "qgsstringutils.h"
27 #include "qgsapplication.h"
31 
32 #include <QFile>
33 #include <QTextStream>
34 #include <QRegularExpression>
36 
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 )
41 {}
42 
43 void QgsProcessingModelAlgorithm::initAlgorithm( const QVariantMap & )
44 {
45 }
46 
47 QString QgsProcessingModelAlgorithm::name() const
48 {
49  return mModelName;
50 }
51 
52 QString QgsProcessingModelAlgorithm::displayName() const
53 {
54  return mModelName;
55 }
56 
57 QString QgsProcessingModelAlgorithm::group() const
58 {
59  return mModelGroup;
60 }
61 
62 QString QgsProcessingModelAlgorithm::groupId() const
63 {
64  return mModelGroupId;
65 }
66 
67 QIcon QgsProcessingModelAlgorithm::icon() const
68 {
69  return QgsApplication::getThemeIcon( QStringLiteral( "/processingModel.svg" ) );
70 }
71 
72 QString QgsProcessingModelAlgorithm::svgIconPath() const
73 {
74  return QgsApplication::iconPath( QStringLiteral( "processingModel.svg" ) );
75 }
76 
77 QString QgsProcessingModelAlgorithm::shortHelpString() const
78 {
79  if ( mHelpContent.empty() )
80  return QString();
81 
82  return QgsProcessingUtils::formatHelpMapAsHtml( mHelpContent, this );
83 }
84 
85 QString QgsProcessingModelAlgorithm::shortDescription() const
86 {
87  return mHelpContent.value( QStringLiteral( "SHORT_DESCRIPTION" ) ).toString();
88 }
89 
90 QString QgsProcessingModelAlgorithm::helpUrl() const
91 {
92  return mHelpContent.value( QStringLiteral( "HELP_URL" ) ).toString();
93 }
94 
95 QVariantMap QgsProcessingModelAlgorithm::parametersForChildAlgorithm( const QgsProcessingModelChildAlgorithm &child, const QVariantMap &modelParameters, const QVariantMap &results, const QgsExpressionContext &expressionContext, QString &error ) const
96 {
97  error.clear();
98  auto evaluateSources = [ =, &error ]( const QgsProcessingParameterDefinition * def )->QVariant
99  {
100  const QgsProcessingModelChildParameterSources paramSources = child.parameterSources().value( def->name() );
101 
102  QString expressionText;
103  QVariantList paramParts;
104  for ( const QgsProcessingModelChildParameterSource &source : paramSources )
105  {
106  switch ( source.source() )
107  {
108  case QgsProcessingModelChildParameterSource::StaticValue:
109  paramParts << source.staticValue();
110  break;
111 
112  case QgsProcessingModelChildParameterSource::ModelParameter:
113  paramParts << modelParameters.value( source.parameterName() );
114  break;
115 
116  case QgsProcessingModelChildParameterSource::ChildOutput:
117  {
118  QVariantMap linkedChildResults = results.value( source.outputChildId() ).toMap();
119  paramParts << linkedChildResults.value( source.outputName() );
120  break;
121  }
122 
123  case QgsProcessingModelChildParameterSource::Expression:
124  {
125  QgsExpression exp( source.expression() );
126  paramParts << exp.evaluate( &expressionContext );
127  if ( exp.hasEvalError() )
128  {
129  error = QObject::tr( "Could not evaluate expression for parameter %1 for %2: %3" ).arg( def->name(), child.description(), exp.evalErrorString() );
130  }
131  break;
132  }
133  case QgsProcessingModelChildParameterSource::ExpressionText:
134  {
135  expressionText = QgsExpression::replaceExpressionText( source.expressionText(), &expressionContext );
136  break;
137  }
138 
139  case QgsProcessingModelChildParameterSource::ModelOutput:
140  break;
141  }
142  }
143 
144  if ( ! expressionText.isEmpty() )
145  {
146  return expressionText;
147  }
148  else if ( paramParts.count() == 1 )
149  return paramParts.at( 0 );
150  else
151  return paramParts;
152  };
153 
154 
155  QVariantMap childParams;
156  const QList< const QgsProcessingParameterDefinition * > childParameterDefinitions = child.algorithm()->parameterDefinitions();
157  for ( const QgsProcessingParameterDefinition *def : childParameterDefinitions )
158  {
159  if ( !def->isDestination() )
160  {
161  if ( !child.parameterSources().contains( def->name() ) )
162  continue; // use default value
163 
164  const QVariant value = evaluateSources( def );
165  childParams.insert( def->name(), value );
166  }
167  else
168  {
169  const QgsProcessingDestinationParameter *destParam = static_cast< const QgsProcessingDestinationParameter * >( def );
170 
171  // is destination linked to one of the final outputs from this model?
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 )
176  {
177  if ( outputIt->childOutputName() == destParam->name() )
178  {
179  QString paramName = child.childId() + ':' + outputIt.key();
180  bool foundParam = false;
181  QVariant value;
182 
183  // if parameter was specified using child_id:child_name directly, take that
184  if ( modelParameters.contains( paramName ) )
185  {
186  value = modelParameters.value( paramName );
187  foundParam = true;
188  }
189 
190  // ...otherwise we need to find the corresponding model parameter which matches this output
191  if ( !foundParam )
192  {
193  if ( const QgsProcessingParameterDefinition *modelParam = modelParameterFromChildIdAndOutputName( child.childId(), outputIt.key() ) )
194  {
195  if ( modelParameters.contains( modelParam->name() ) )
196  {
197  value = modelParameters.value( modelParam->name() );
198  foundParam = true;
199  }
200  }
201  }
202 
203  if ( foundParam )
204  {
205  if ( value.canConvert<QgsProcessingOutputLayerDefinition>() )
206  {
207  // make sure layer output name is correctly set
208  QgsProcessingOutputLayerDefinition fromVar = qvariant_cast<QgsProcessingOutputLayerDefinition>( value );
209  fromVar.destinationName = outputIt.key();
210  value = QVariant::fromValue( fromVar );
211  }
212 
213  childParams.insert( destParam->name(), value );
214  }
215  isFinalOutput = true;
216  break;
217  }
218  }
219 
220  bool hasExplicitDefinition = false;
221  if ( !isFinalOutput && child.parameterSources().contains( def->name() ) )
222  {
223  // explicitly defined source for output
224  const QVariant value = evaluateSources( def );
225  if ( value.isValid() )
226  {
227  childParams.insert( def->name(), value );
228  hasExplicitDefinition = true;
229  }
230  }
231 
232  if ( !isFinalOutput && !hasExplicitDefinition )
233  {
234  // output is temporary
235 
236  // check whether it's optional, and if so - is it required?
237  bool required = true;
239  {
240  required = childOutputIsRequired( child.childId(), destParam->name() );
241  }
242 
243  // not optional, or required elsewhere in model
244  if ( required )
245  childParams.insert( destParam->name(), destParam->generateTemporaryDestination() );
246  }
247  }
248  }
249  return childParams;
250 }
251 
252 const QgsProcessingParameterDefinition *QgsProcessingModelAlgorithm::modelParameterFromChildIdAndOutputName( const QString &childId, const QString &childOutputName ) const
253 {
254  for ( const QgsProcessingParameterDefinition *definition : mParameters )
255  {
256  if ( !definition->isDestination() )
257  continue;
258 
259  const QString modelChildId = definition->metadata().value( QStringLiteral( "_modelChildId" ) ).toString();
260  const QString modelOutputName = definition->metadata().value( QStringLiteral( "_modelChildOutputName" ) ).toString();
261 
262  if ( modelChildId == childId && modelOutputName == childOutputName )
263  return definition;
264  }
265  return nullptr;
266 }
267 
268 bool QgsProcessingModelAlgorithm::childOutputIsRequired( const QString &childId, const QString &outputName ) const
269 {
270  // look through all child algs
271  QMap< QString, QgsProcessingModelChildAlgorithm >::const_iterator childIt = mChildAlgorithms.constBegin();
272  for ( ; childIt != mChildAlgorithms.constEnd(); ++childIt )
273  {
274  if ( childIt->childId() == childId || !childIt->isActive() )
275  continue;
276 
277  // look through all sources for child
278  QMap<QString, QgsProcessingModelChildParameterSources> candidateChildParams = childIt->parameterSources();
279  QMap<QString, QgsProcessingModelChildParameterSources>::const_iterator childParamIt = candidateChildParams.constBegin();
280  for ( ; childParamIt != candidateChildParams.constEnd(); ++childParamIt )
281  {
282  const auto constValue = childParamIt.value();
283  for ( const QgsProcessingModelChildParameterSource &source : constValue )
284  {
285  if ( source.source() == QgsProcessingModelChildParameterSource::ChildOutput
286  && source.outputChildId() == childId
287  && source.outputName() == outputName )
288  {
289  return true;
290  }
291  }
292  }
293  }
294  return false;
295 }
296 
297 QVariantMap QgsProcessingModelAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
298 {
299  QSet< QString > toExecute;
300  QMap< QString, QgsProcessingModelChildAlgorithm >::const_iterator childIt = mChildAlgorithms.constBegin();
301  QSet< QString > broken;
302  for ( ; childIt != mChildAlgorithms.constEnd(); ++childIt )
303  {
304  if ( childIt->isActive() )
305  {
306  if ( childIt->algorithm() )
307  toExecute.insert( childIt->childId() );
308  else
309  broken.insert( childIt->childId() );
310  }
311  }
312 
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( ", " ) ) ) );
315 
316  QElapsedTimer totalTime;
317  totalTime.start();
318 
319  QgsProcessingMultiStepFeedback modelFeedback( toExecute.count(), feedback );
320  QgsExpressionContext baseContext = createExpressionContext( parameters, context );
321 
322  QVariantMap childResults;
323  QVariantMap childInputs;
324 
325  const bool verboseLog = context.logLevel() == QgsProcessingContext::Verbose;
326 
327  QVariantMap finalResults;
328  QSet< QString > executed;
329  bool executedAlg = true;
330  while ( executedAlg && executed.count() < toExecute.count() )
331  {
332  executedAlg = false;
333  for ( const QString &childId : std::as_const( toExecute ) )
334  {
335  if ( feedback && feedback->isCanceled() )
336  break;
337 
338  if ( executed.contains( childId ) )
339  continue;
340 
341  bool canExecute = true;
342  const QSet< QString > dependencies = dependsOnChildAlgorithms( childId );
343  for ( const QString &dependency : dependencies )
344  {
345  if ( !executed.contains( dependency ) )
346  {
347  canExecute = false;
348  break;
349  }
350  }
351 
352  if ( !canExecute )
353  continue;
354 
355  executedAlg = true;
356 
357  const QgsProcessingModelChildAlgorithm &child = mChildAlgorithms[ childId ];
358  std::unique_ptr< QgsProcessingAlgorithm > childAlg( child.algorithm()->create( child.configuration() ) );
359 
360  const bool skipGenericLogging = !verboseLog || childAlg->flags() & QgsProcessingAlgorithm::FlagSkipGenericModelLogging;
361  if ( feedback && !skipGenericLogging )
362  feedback->pushDebugInfo( QObject::tr( "Prepare algorithm: %1" ).arg( childId ) );
363 
364  QgsExpressionContext expContext = baseContext;
365  expContext << QgsExpressionContextUtils::processingAlgorithmScope( child.algorithm(), parameters, context )
366  << createExpressionContextScopeForChildAlgorithm( childId, context, parameters, childResults );
367  context.setExpressionContext( expContext );
368 
369  QString error;
370  QVariantMap childParams = parametersForChildAlgorithm( child, parameters, childResults, expContext, error );
371  if ( !error.isEmpty() )
372  throw QgsProcessingException( error );
373 
374  if ( feedback && !skipGenericLogging )
375  feedback->setProgressText( QObject::tr( "Running %1 [%2/%3]" ).arg( child.description() ).arg( executed.count() + 1 ).arg( toExecute.count() ) );
376 
377  childInputs.insert( childId, QgsProcessingUtils::removePointerValuesFromMap( childParams ) );
378  QStringList params;
379  for ( auto childParamIt = childParams.constBegin(); childParamIt != childParams.constEnd(); ++childParamIt )
380  {
381  params << QStringLiteral( "%1: %2" ).arg( childParamIt.key(),
382  child.algorithm()->parameterDefinition( childParamIt.key() )->valueAsPythonString( childParamIt.value(), context ) );
383  }
384 
385  if ( feedback && !skipGenericLogging )
386  {
387  feedback->pushInfo( QObject::tr( "Input Parameters:" ) );
388  feedback->pushCommandInfo( QStringLiteral( "{ %1 }" ).arg( params.join( QLatin1String( ", " ) ) ) );
389  }
390 
391  QElapsedTimer childTime;
392  childTime.start();
393 
394  bool ok = false;
395 
396  QThread *modelThread = QThread::currentThread();
397 
398  auto prepareOnMainThread = [modelThread, &ok, &childAlg, &childParams, &context, &modelFeedback]
399  {
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 );
403  };
404 
405  // Make sure we only run prepare steps on the main thread!
406  if ( modelThread == qApp->thread() )
407  ok = childAlg->prepare( childParams, context, &modelFeedback );
408  else
409  {
410  context.pushToThread( qApp->thread() );
411  QMetaObject::invokeMethod( qApp, prepareOnMainThread, Qt::BlockingQueuedConnection );
412  }
413 
414  Q_ASSERT_X( QThread::currentThread() == context.thread(), "QgsProcessingModelAlgorithm::processAlgorithm", "context was not transferred back to model thread" );
415 
416  if ( !ok )
417  {
418  const QString error = ( childAlg->flags() & QgsProcessingAlgorithm::FlagCustomException ) ? QString() : QObject::tr( "Error encountered while running %1" ).arg( child.description() );
419  throw QgsProcessingException( error );
420  }
421 
422  QVariantMap results;
423  try
424  {
425  if ( childAlg->flags() & QgsProcessingAlgorithm::FlagNoThreading )
426  {
427  // child algorithm run step must be called on main thread
428  auto runOnMainThread = [modelThread, &context, &modelFeedback, &results, &childAlg, &childParams]
429  {
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 );
433  };
434 
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() ) );
437 
438  context.pushToThread( qApp->thread() );
439  QMetaObject::invokeMethod( qApp, runOnMainThread, Qt::BlockingQueuedConnection );
440  }
441  else
442  {
443  // safe to run on model thread
444  results = childAlg->runPrepared( childParams, context, &modelFeedback );
445  }
446  }
447  catch ( QgsProcessingException & )
448  {
449  const QString error = ( childAlg->flags() & QgsProcessingAlgorithm::FlagCustomException ) ? QString() : QObject::tr( "Error encountered while running %1" ).arg( child.description() );
450  throw QgsProcessingException( error );
451  }
452 
453  Q_ASSERT_X( QThread::currentThread() == context.thread(), "QgsProcessingModelAlgorithm::processAlgorithm", "context was not transferred back to model thread" );
454 
455  QVariantMap ppRes;
456  auto postProcessOnMainThread = [modelThread, &ppRes, &childAlg, &context, &modelFeedback]
457  {
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 );
461  };
462 
463  // Make sure we only run postProcess steps on the main thread!
464  if ( modelThread == qApp->thread() )
465  ppRes = childAlg->postProcess( context, &modelFeedback );
466  else
467  {
468  context.pushToThread( qApp->thread() );
469  QMetaObject::invokeMethod( qApp, postProcessOnMainThread, Qt::BlockingQueuedConnection );
470  }
471 
472  Q_ASSERT_X( QThread::currentThread() == context.thread(), "QgsProcessingModelAlgorithm::processAlgorithm", "context was not transferred back to model thread" );
473 
474  if ( !ppRes.isEmpty() )
475  results = ppRes;
476 
477  childResults.insert( childId, results );
478 
479  // look through child alg's outputs to determine whether any of these should be copied
480  // to the final model outputs
481  QMap<QString, QgsProcessingModelOutput> outputs = child.modelOutputs();
482  QMap<QString, QgsProcessingModelOutput>::const_iterator outputIt = outputs.constBegin();
483  for ( ; outputIt != outputs.constEnd(); ++outputIt )
484  {
485  switch ( mInternalVersion )
486  {
487  case QgsProcessingModelAlgorithm::InternalVersion::Version1:
488  finalResults.insert( childId + ':' + outputIt->name(), results.value( outputIt->childOutputName() ) );
489  break;
490  case QgsProcessingModelAlgorithm::InternalVersion::Version2:
491  if ( const QgsProcessingParameterDefinition *modelParam = modelParameterFromChildIdAndOutputName( child.childId(), outputIt.key() ) )
492  {
493  finalResults.insert( modelParam->name(), results.value( outputIt->childOutputName() ) );
494  }
495  break;
496  }
497  }
498 
499  executed.insert( childId );
500 
501  std::function< void( const QString &, const QString & )> pruneAlgorithmBranchRecursive;
502  pruneAlgorithmBranchRecursive = [&]( const QString & id, const QString &branch = QString() )
503  {
504  const QSet<QString> toPrune = dependentChildAlgorithms( id, branch );
505  for ( const QString &targetId : toPrune )
506  {
507  if ( executed.contains( targetId ) )
508  continue;
509 
510  executed.insert( targetId );
511  pruneAlgorithmBranchRecursive( targetId, branch );
512  }
513  };
514 
515  // prune remaining algorithms if they are dependent on a branch from this child which didn't eventuate
516  const QgsProcessingOutputDefinitions outputDefs = childAlg->outputDefinitions();
517  for ( const QgsProcessingOutputDefinition *outputDef : outputDefs )
518  {
519  if ( outputDef->type() == QgsProcessingOutputConditionalBranch::typeName() && !results.value( outputDef->name() ).toBool() )
520  {
521  pruneAlgorithmBranchRecursive( childId, outputDef->name() );
522  }
523  }
524 
526  {
527  // check if any dependent algorithms should be canceled based on the outputs of this algorithm run
528  // first find all direct dependencies of this algorithm by looking through all remaining child algorithms
529  for ( const QString &candidateId : std::as_const( toExecute ) )
530  {
531  if ( executed.contains( candidateId ) )
532  continue;
533 
534  // a pending algorithm was found..., check it's parameter sources to see if it links to any of the current
535  // algorithm's outputs
536  const QgsProcessingModelChildAlgorithm &candidate = mChildAlgorithms[ candidateId ];
537  const QMap<QString, QgsProcessingModelChildParameterSources> candidateParams = candidate.parameterSources();
538  QMap<QString, QgsProcessingModelChildParameterSources>::const_iterator paramIt = candidateParams.constBegin();
539  bool pruned = false;
540  for ( ; paramIt != candidateParams.constEnd(); ++paramIt )
541  {
542  for ( const QgsProcessingModelChildParameterSource &source : paramIt.value() )
543  {
544  if ( source.source() == QgsProcessingModelChildParameterSource::ChildOutput && source.outputChildId() == childId )
545  {
546  // ok, this one is dependent on the current alg. Did we get a value for it?
547  if ( !results.contains( source.outputName() ) )
548  {
549  // oh no, nothing returned for this parameter. Gotta trim the branch back!
550  pruned = true;
551  // skip the dependent alg..
552  executed.insert( candidateId );
553  //... and everything which depends on it
554  pruneAlgorithmBranchRecursive( candidateId, QString() );
555  break;
556  }
557  }
558  }
559  if ( pruned )
560  break;
561  }
562  }
563  }
564 
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 ) );
569  }
570 
571  if ( feedback && feedback->isCanceled() )
572  break;
573  }
574  if ( feedback )
575  feedback->pushDebugInfo( QObject::tr( "Model processed OK. Executed %n algorithm(s) total in %1 s.", nullptr, executed.count() ).arg( totalTime.elapsed() / 1000.0 ) );
576 
577  mResults = finalResults;
578  mResults.insert( QStringLiteral( "CHILD_RESULTS" ), childResults );
579  mResults.insert( QStringLiteral( "CHILD_INPUTS" ), childInputs );
580  return mResults;
581 }
582 
583 QString QgsProcessingModelAlgorithm::sourceFilePath() const
584 {
585  return mSourceFile;
586 }
587 
588 void QgsProcessingModelAlgorithm::setSourceFilePath( const QString &sourceFile )
589 {
590  mSourceFile = sourceFile;
591 }
592 
593 bool QgsProcessingModelAlgorithm::modelNameMatchesFilePath() const
594 {
595  if ( mSourceFile.isEmpty() )
596  return false;
597 
598  const QFileInfo fi( mSourceFile );
599  return fi.completeBaseName().compare( mModelName, Qt::CaseInsensitive ) == 0;
600 }
601 
602 QStringList QgsProcessingModelAlgorithm::asPythonCode( const QgsProcessing::PythonOutputType outputType, const int indentSize ) const
603 {
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();
612 
613  QStringList lines;
614  QString indent = QString( ' ' ).repeated( indentSize );
615  QString currentIndent;
616 
617  QMap< QString, QString> friendlyChildNames;
618  QMap< QString, QString> friendlyOutputNames;
619  auto uniqueSafeName = []( const QString & name, bool capitalize, const QMap< QString, QString > &friendlyNames )->QString
620  {
621  const QString base = safeName( name, capitalize );
622  QString candidate = base;
623  int i = 1;
624  while ( friendlyNames.contains( candidate ) )
625  {
626  i++;
627  candidate = QStringLiteral( "%1_%2" ).arg( base ).arg( i );
628  }
629  return candidate;
630  };
631 
632  const QString algorithmClassName = safeName( name(), true );
633 
634  QSet< QString > toExecute;
635  for ( auto childIt = mChildAlgorithms.constBegin(); childIt != mChildAlgorithms.constEnd(); ++childIt )
636  {
637  if ( childIt->isActive() && childIt->algorithm() )
638  {
639  toExecute.insert( childIt->childId() );
640  friendlyChildNames.insert( childIt->childId(), uniqueSafeName( childIt->description().isEmpty() ? childIt->childId() : childIt->description(), !childIt->description().isEmpty(), friendlyChildNames ) );
641  }
642  }
643  const int totalSteps = toExecute.count();
644 
645  QStringList importLines; // not a set - we need regular ordering
646  switch ( outputType )
647  {
649  {
650  // add specific parameter type imports
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" );
656 
657  bool hasAdvancedParams = false;
658  for ( const QgsProcessingParameterDefinition *def : params )
659  {
661  hasAdvancedParams = true;
662 
663  const QString importString = QgsApplication::processingRegistry()->parameterType( def->type() )->pythonImportString();
664  if ( !importString.isEmpty() && !importLines.contains( importString ) )
665  importLines << importString;
666  }
667 
668  if ( hasAdvancedParams )
669  importLines << QStringLiteral( "from qgis.core import QgsProcessingParameterDefinition" );
670 
671  lines << QStringLiteral( "import processing" );
672  lines << QString() << QString();
673 
674  lines << QStringLiteral( "class %1(QgsProcessingAlgorithm):" ).arg( algorithmClassName );
675  lines << QString();
676 
677  // initAlgorithm, parameter definitions
678  lines << indent + QStringLiteral( "def initAlgorithm(self, config=None):" );
679  if ( params.empty() )
680  {
681  lines << indent + indent + QStringLiteral( "pass" );
682  }
683  else
684  {
685  lines.reserve( lines.size() + params.size() );
686  for ( const QgsProcessingParameterDefinition *def : params )
687  {
688  std::unique_ptr< QgsProcessingParameterDefinition > defClone( def->clone() );
689 
690  if ( defClone->isDestination() )
691  {
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 );
696  }
697  else
698  {
699  if ( !mParameterComponents.value( defClone->name() ).comment()->description().isEmpty() )
700  lines << indent + indent + QStringLiteral( "# %1" ).arg( mParameterComponents.value( defClone->name() ).comment()->description() );
701  }
702 
703  if ( defClone->flags() & QgsProcessingParameterDefinition::FlagAdvanced )
704  {
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)" );
708  }
709  else
710  {
711  lines << indent + indent + QStringLiteral( "self.addParameter(%1)" ).arg( defClone->asPythonString() );
712  }
713  }
714  }
715 
716  lines << QString();
717  lines << indent + QStringLiteral( "def processAlgorithm(self, parameters, context, model_feedback):" );
718  currentIndent = indent + indent;
719 
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 );
723  break;
724  }
725 #if 0
726  case Script:
727  {
728  QgsStringMap params;
729  QgsProcessingContext context;
730  QMap< QString, QgsProcessingModelParameter >::const_iterator paramIt = mParameterComponents.constBegin();
731  for ( ; paramIt != mParameterComponents.constEnd(); ++paramIt )
732  {
733  QString name = paramIt.value().parameterName();
734  if ( parameterDefinition( name ) )
735  {
736  // TODO - generic value to string method
737  params.insert( name, parameterDefinition( name )->valueAsPythonString( parameterDefinition( name )->defaultValue(), context ) );
738  }
739  }
740 
741  if ( !params.isEmpty() )
742  {
743  lines << QStringLiteral( "parameters = {" );
744  for ( auto it = params.constBegin(); it != params.constEnd(); ++it )
745  {
746  lines << QStringLiteral( " '%1':%2," ).arg( it.key(), it.value() );
747  }
748  lines << QStringLiteral( "}" )
749  << QString();
750  }
751 
752  lines << QStringLiteral( "context = QgsProcessingContext()" )
753  << QStringLiteral( "context.setProject(QgsProject.instance())" )
754  << QStringLiteral( "feedback = QgsProcessingFeedback()" )
755  << QString();
756 
757  break;
758  }
759 #endif
760 
761  }
762 
763  lines << currentIndent + QStringLiteral( "results = {}" );
764  lines << currentIndent + QStringLiteral( "outputs = {}" );
765  lines << QString();
766 
767  QSet< QString > executed;
768  bool executedAlg = true;
769  int currentStep = 0;
770  while ( executedAlg && executed.count() < toExecute.count() )
771  {
772  executedAlg = false;
773  const auto constToExecute = toExecute;
774  for ( const QString &childId : constToExecute )
775  {
776  if ( executed.contains( childId ) )
777  continue;
778 
779  bool canExecute = true;
780  const auto constDependsOnChildAlgorithms = dependsOnChildAlgorithms( childId );
781  for ( const QString &dependency : constDependsOnChildAlgorithms )
782  {
783  if ( !executed.contains( dependency ) )
784  {
785  canExecute = false;
786  break;
787  }
788  }
789 
790  if ( !canExecute )
791  continue;
792 
793  executedAlg = true;
794 
795  const QgsProcessingModelChildAlgorithm &child = mChildAlgorithms[ childId ];
796 
797  // fill in temporary outputs
798  const QgsProcessingParameterDefinitions childDefs = child.algorithm()->parameterDefinitions();
799  QgsStringMap childParams;
800  for ( const QgsProcessingParameterDefinition *def : childDefs )
801  {
802  if ( def->isDestination() )
803  {
804  const QgsProcessingDestinationParameter *destParam = static_cast< const QgsProcessingDestinationParameter * >( def );
805 
806  // is destination linked to one of the final outputs from this model?
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 )
811  {
812  if ( outputIt->childOutputName() == destParam->name() )
813  {
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;
818  break;
819  }
820  }
821 
822  if ( !isFinalOutput )
823  {
824  // output is temporary
825 
826  // check whether it's optional, and if so - is it required?
827  bool required = true;
829  {
830  required = childOutputIsRequired( child.childId(), destParam->name() );
831  }
832 
833  // not optional, or required elsewhere in model
834  if ( required )
835  {
836 
837  childParams.insert( destParam->name(), QStringLiteral( "QgsProcessing.TEMPORARY_OUTPUT" ) );
838  }
839  }
840  }
841  }
842 
843  lines << child.asPythonCode( outputType, childParams, currentIndent.size(), indentSize, friendlyChildNames, friendlyOutputNames );
844  currentStep++;
845  if ( currentStep < totalSteps )
846  {
847  lines << QString();
848  lines << currentIndent + QStringLiteral( "feedback.setCurrentStep(%1)" ).arg( currentStep );
849  lines << currentIndent + QStringLiteral( "if feedback.isCanceled():" );
850  lines << currentIndent + indent + QStringLiteral( "return {}" );
851  lines << QString();
852  }
853  executed.insert( childId );
854  }
855  }
856 
857  switch ( outputType )
858  {
860  lines << currentIndent + QStringLiteral( "return results" );
861  lines << QString();
862 
863  // name, displayName
864  lines << indent + QStringLiteral( "def name(self):" );
865  lines << indent + indent + QStringLiteral( "return '%1'" ).arg( mModelName );
866  lines << QString();
867  lines << indent + QStringLiteral( "def displayName(self):" );
868  lines << indent + indent + QStringLiteral( "return '%1'" ).arg( mModelName );
869  lines << QString();
870 
871  // group, groupId
872  lines << indent + QStringLiteral( "def group(self):" );
873  lines << indent + indent + QStringLiteral( "return '%1'" ).arg( mModelGroup );
874  lines << QString();
875  lines << indent + QStringLiteral( "def groupId(self):" );
876  lines << indent + indent + QStringLiteral( "return '%1'" ).arg( mModelGroupId );
877  lines << QString();
878 
879  // help
880  if ( !shortHelpString().isEmpty() )
881  {
882  lines << indent + QStringLiteral( "def shortHelpString(self):" );
883  lines << indent + indent + QStringLiteral( "return \"\"\"%1\"\"\"" ).arg( shortHelpString() );
884  lines << QString();
885  }
886  if ( !helpUrl().isEmpty() )
887  {
888  lines << indent + QStringLiteral( "def helpUrl(self):" );
889  lines << indent + indent + QStringLiteral( "return '%1'" ).arg( helpUrl() );
890  lines << QString();
891  }
892 
893  // createInstance
894  lines << indent + QStringLiteral( "def createInstance(self):" );
895  lines << indent + indent + QStringLiteral( "return %1()" ).arg( algorithmClassName );
896 
897  // additional import lines
898  static QMap< QString, QString > sAdditionalImports
899  {
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" ) },
920  };
921 
922  for ( auto it = sAdditionalImports.constBegin(); it != sAdditionalImports.constEnd(); ++it )
923  {
924  if ( importLines.contains( it.value() ) )
925  {
926  // already got this import
927  continue;
928  }
929 
930  bool found = false;
931  for ( const QString &line : std::as_const( lines ) )
932  {
933  if ( line.contains( it.key() ) )
934  {
935  found = true;
936  break;
937  }
938  }
939  if ( found )
940  {
941  importLines << it.value();
942  }
943  }
944 
945  lines = fileDocString + importLines + lines;
946  break;
947  }
948 
949  lines << QString();
950 
951  return lines;
952 }
953 
954 QMap<QString, QgsProcessingModelAlgorithm::VariableDefinition> QgsProcessingModelAlgorithm::variablesForChildAlgorithm( const QString &childId, QgsProcessingContext &context, const QVariantMap &modelParameters, const QVariantMap &results ) const
955 {
956  QMap<QString, QgsProcessingModelAlgorithm::VariableDefinition> variables;
957 
958  auto safeName = []( const QString & name )->QString
959  {
960  QString s = name;
961  return s.replace( QRegularExpression( QStringLiteral( "[\\s'\"\\(\\):\\.]" ) ), QStringLiteral( "_" ) );
962  };
963 
964  // "static"/single value sources
965  QgsProcessingModelChildParameterSources sources = availableSourcesForChild( childId, QStringList() << QgsProcessingParameterNumber::typeName()
991  QStringList() << QgsProcessingOutputNumber::typeName()
994 
995  for ( const QgsProcessingModelChildParameterSource &source : std::as_const( sources ) )
996  {
997  QString name;
998  QVariant value;
999  QString description;
1000  switch ( source.source() )
1001  {
1002  case QgsProcessingModelChildParameterSource::ModelParameter:
1003  {
1004  name = source.parameterName();
1005  value = modelParameters.value( source.parameterName() );
1006  description = parameterDefinition( source.parameterName() )->description();
1007  break;
1008  }
1009  case QgsProcessingModelChildParameterSource::ChildOutput:
1010  {
1011  const QgsProcessingModelChildAlgorithm &child = mChildAlgorithms.value( source.outputChildId() );
1012  name = QStringLiteral( "%1_%2" ).arg( child.description().isEmpty() ?
1013  source.outputChildId() : child.description(), source.outputName() );
1014  if ( const QgsProcessingAlgorithm *alg = child.algorithm() )
1015  {
1016  description = QObject::tr( "Output '%1' from algorithm '%2'" ).arg( alg->outputDefinition( source.outputName() )->description(),
1017  child.description() );
1018  }
1019  value = results.value( source.outputChildId() ).toMap().value( source.outputName() );
1020  break;
1021  }
1022 
1023  case QgsProcessingModelChildParameterSource::Expression:
1024  case QgsProcessingModelChildParameterSource::ExpressionText:
1025  case QgsProcessingModelChildParameterSource::StaticValue:
1026  case QgsProcessingModelChildParameterSource::ModelOutput:
1027  continue;
1028  }
1029  variables.insert( safeName( name ), VariableDefinition( value, source, description ) );
1030  }
1031 
1032  // layer sources
1033  sources = availableSourcesForChild( childId, QStringList()
1036  QStringList() << QgsProcessingOutputVectorLayer::typeName()
1039 
1040  for ( const QgsProcessingModelChildParameterSource &source : std::as_const( sources ) )
1041  {
1042  QString name;
1043  QVariant value;
1044  QString description;
1045 
1046  switch ( source.source() )
1047  {
1048  case QgsProcessingModelChildParameterSource::ModelParameter:
1049  {
1050  name = source.parameterName();
1051  value = modelParameters.value( source.parameterName() );
1052  description = parameterDefinition( source.parameterName() )->description();
1053  break;
1054  }
1055  case QgsProcessingModelChildParameterSource::ChildOutput:
1056  {
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() );
1061  if ( const QgsProcessingAlgorithm *alg = child.algorithm() )
1062  {
1063  description = QObject::tr( "Output '%1' from algorithm '%2'" ).arg( alg->outputDefinition( source.outputName() )->description(),
1064  child.description() );
1065  }
1066  break;
1067  }
1068 
1069  case QgsProcessingModelChildParameterSource::Expression:
1070  case QgsProcessingModelChildParameterSource::ExpressionText:
1071  case QgsProcessingModelChildParameterSource::StaticValue:
1072  case QgsProcessingModelChildParameterSource::ModelOutput:
1073  continue;
1074 
1075  }
1076 
1077  if ( value.canConvert<QgsProcessingOutputLayerDefinition>() )
1078  {
1079  QgsProcessingOutputLayerDefinition fromVar = qvariant_cast<QgsProcessingOutputLayerDefinition>( value );
1080  value = fromVar.sink;
1081  if ( value.canConvert<QgsProperty>() )
1082  {
1083  value = value.value< QgsProperty >().valueAsString( context.expressionContext() );
1084  }
1085  }
1086  QgsMapLayer *layer = qobject_cast< QgsMapLayer * >( qvariant_cast<QObject *>( value ) );
1087  if ( !layer )
1088  layer = QgsProcessingUtils::mapLayerFromString( value.toString(), context );
1089 
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 ) ) );
1095  }
1096 
1097  sources = availableSourcesForChild( childId, QStringList()
1099  for ( const QgsProcessingModelChildParameterSource &source : std::as_const( sources ) )
1100  {
1101  QString name;
1102  QVariant value;
1103  QString description;
1104 
1105  switch ( source.source() )
1106  {
1107  case QgsProcessingModelChildParameterSource::ModelParameter:
1108  {
1109  name = source.parameterName();
1110  value = modelParameters.value( source.parameterName() );
1111  description = parameterDefinition( source.parameterName() )->description();
1112  break;
1113  }
1114  case QgsProcessingModelChildParameterSource::ChildOutput:
1115  {
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() );
1120  if ( const QgsProcessingAlgorithm *alg = child.algorithm() )
1121  {
1122  description = QObject::tr( "Output '%1' from algorithm '%2'" ).arg( alg->outputDefinition( source.outputName() )->description(),
1123  child.description() );
1124  }
1125  break;
1126  }
1127 
1128  case QgsProcessingModelChildParameterSource::Expression:
1129  case QgsProcessingModelChildParameterSource::ExpressionText:
1130  case QgsProcessingModelChildParameterSource::StaticValue:
1131  case QgsProcessingModelChildParameterSource::ModelOutput:
1132  continue;
1133 
1134  }
1135 
1136  QgsFeatureSource *featureSource = nullptr;
1137  if ( value.canConvert<QgsProcessingFeatureSourceDefinition>() )
1138  {
1139  QgsProcessingFeatureSourceDefinition fromVar = qvariant_cast<QgsProcessingFeatureSourceDefinition>( value );
1140  value = fromVar.source;
1141  }
1142  else if ( value.canConvert<QgsProcessingOutputLayerDefinition>() )
1143  {
1144  QgsProcessingOutputLayerDefinition fromVar = qvariant_cast<QgsProcessingOutputLayerDefinition>( value );
1145  value = fromVar.sink;
1146  if ( value.canConvert<QgsProperty>() )
1147  {
1148  value = value.value< QgsProperty >().valueAsString( context.expressionContext() );
1149  }
1150  }
1151  if ( QgsVectorLayer *layer = qobject_cast< QgsVectorLayer * >( qvariant_cast<QObject *>( value ) ) )
1152  {
1153  featureSource = layer;
1154  }
1155  if ( !featureSource )
1156  {
1157  if ( QgsVectorLayer *vl = qobject_cast< QgsVectorLayer *>( QgsProcessingUtils::mapLayerFromString( value.toString(), context, true, QgsProcessingUtils::LayerHint::Vector ) ) )
1158  featureSource = vl;
1159  }
1160 
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 ) ) );
1166  }
1167 
1168  return variables;
1169 }
1170 
1171 QgsExpressionContextScope *QgsProcessingModelAlgorithm::createExpressionContextScopeForChildAlgorithm( const QString &childId, QgsProcessingContext &context, const QVariantMap &modelParameters, const QVariantMap &results ) const
1172 {
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 )
1177  {
1178  scope->addVariable( QgsExpressionContextScope::StaticVariable( varIt.key(), varIt->value, true, false, varIt->description ) );
1179  }
1180  return scope.release();
1181 }
1182 
1183 QgsProcessingModelChildParameterSources QgsProcessingModelAlgorithm::availableSourcesForChild( const QString &childId, const QStringList &parameterTypes, const QStringList &outputTypes, const QList<int> &dataTypes ) const
1184 {
1185  QgsProcessingModelChildParameterSources sources;
1186 
1187  // first look through model parameters
1188  QMap< QString, QgsProcessingModelParameter >::const_iterator paramIt = mParameterComponents.constBegin();
1189  for ( ; paramIt != mParameterComponents.constEnd(); ++paramIt )
1190  {
1191  const QgsProcessingParameterDefinition *def = parameterDefinition( paramIt->parameterName() );
1192  if ( !def )
1193  continue;
1194 
1195  if ( parameterTypes.contains( def->type() ) )
1196  {
1197  if ( !dataTypes.isEmpty() )
1198  {
1199  if ( def->type() == QgsProcessingParameterField::typeName() )
1200  {
1201  const QgsProcessingParameterField *fieldDef = static_cast< const QgsProcessingParameterField * >( def );
1202  if ( !( dataTypes.contains( fieldDef->dataType() ) || fieldDef->dataType() == QgsProcessingParameterField::Any ) )
1203  {
1204  continue;
1205  }
1206  }
1208  {
1209  const QgsProcessingParameterLimitedDataTypes *sourceDef = dynamic_cast< const QgsProcessingParameterLimitedDataTypes *>( def );
1210  if ( !sourceDef )
1211  continue;
1212 
1213  bool ok = sourceDef->dataTypes().isEmpty();
1214  const auto constDataTypes = sourceDef->dataTypes();
1215  for ( int type : constDataTypes )
1216  {
1217  if ( dataTypes.contains( type ) || type == QgsProcessing::TypeMapLayer || type == QgsProcessing::TypeVector || type == QgsProcessing::TypeVectorAnyGeometry )
1218  {
1219  ok = true;
1220  break;
1221  }
1222  }
1223  if ( dataTypes.contains( QgsProcessing::TypeMapLayer ) || dataTypes.contains( QgsProcessing::TypeVector ) || dataTypes.contains( QgsProcessing::TypeVectorAnyGeometry ) )
1224  ok = true;
1225 
1226  if ( !ok )
1227  continue;
1228  }
1229  }
1230  sources << QgsProcessingModelChildParameterSource::fromModelParameter( paramIt->parameterName() );
1231  }
1232  }
1233 
1234  QSet< QString > dependents;
1235  if ( !childId.isEmpty() )
1236  {
1237  dependents = dependentChildAlgorithms( childId );
1238  dependents << childId;
1239  }
1240 
1241  QMap< QString, QgsProcessingModelChildAlgorithm >::const_iterator childIt = mChildAlgorithms.constBegin();
1242  for ( ; childIt != mChildAlgorithms.constEnd(); ++childIt )
1243  {
1244  if ( dependents.contains( childIt->childId() ) )
1245  continue;
1246 
1247  const QgsProcessingAlgorithm *alg = childIt->algorithm();
1248  if ( !alg )
1249  continue;
1250 
1251  const auto constOutputDefinitions = alg->outputDefinitions();
1252  for ( const QgsProcessingOutputDefinition *out : constOutputDefinitions )
1253  {
1254  if ( outputTypes.contains( out->type() ) )
1255  {
1256  if ( !dataTypes.isEmpty() )
1257  {
1258  if ( out->type() == QgsProcessingOutputVectorLayer::typeName() )
1259  {
1260  const QgsProcessingOutputVectorLayer *vectorOut = static_cast< const QgsProcessingOutputVectorLayer *>( out );
1261 
1262  if ( !vectorOutputIsCompatibleType( dataTypes, vectorOut->dataType() ) )
1263  {
1264  //unacceptable output
1265  continue;
1266  }
1267  }
1268  }
1269  sources << QgsProcessingModelChildParameterSource::fromChildOutput( childIt->childId(), out->name() );
1270  }
1271  }
1272  }
1273 
1274  return sources;
1275 }
1276 
1277 QVariantMap QgsProcessingModelAlgorithm::helpContent() const
1278 {
1279  return mHelpContent;
1280 }
1281 
1282 void QgsProcessingModelAlgorithm::setHelpContent( const QVariantMap &helpContent )
1283 {
1284  mHelpContent = helpContent;
1285 }
1286 
1287 void QgsProcessingModelAlgorithm::setName( const QString &name )
1288 {
1289  mModelName = name;
1290 }
1291 
1292 void QgsProcessingModelAlgorithm::setGroup( const QString &group )
1293 {
1294  mModelGroup = group;
1295 }
1296 
1297 bool QgsProcessingModelAlgorithm::validate( QStringList &issues ) const
1298 {
1299  issues.clear();
1300  bool res = true;
1301 
1302  if ( mChildAlgorithms.empty() )
1303  {
1304  res = false;
1305  issues << QObject::tr( "Model does not contain any algorithms" );
1306  }
1307 
1308  for ( auto it = mChildAlgorithms.constBegin(); it != mChildAlgorithms.constEnd(); ++it )
1309  {
1310  QStringList childIssues;
1311  res = validateChildAlgorithm( it->childId(), childIssues ) && res;
1312 
1313  for ( const QString &issue : std::as_const( childIssues ) )
1314  {
1315  issues << QStringLiteral( "<b>%1</b>: %2" ).arg( it->description(), issue );
1316  }
1317  }
1318  return res;
1319 }
1320 
1321 QMap<QString, QgsProcessingModelChildAlgorithm> QgsProcessingModelAlgorithm::childAlgorithms() const
1322 {
1323  return mChildAlgorithms;
1324 }
1325 
1326 void QgsProcessingModelAlgorithm::setParameterComponents( const QMap<QString, QgsProcessingModelParameter> &parameterComponents )
1327 {
1328  mParameterComponents = parameterComponents;
1329 }
1330 
1331 void QgsProcessingModelAlgorithm::setParameterComponent( const QgsProcessingModelParameter &component )
1332 {
1333  mParameterComponents.insert( component.parameterName(), component );
1334 }
1335 
1336 QgsProcessingModelParameter &QgsProcessingModelAlgorithm::parameterComponent( const QString &name )
1337 {
1338  if ( !mParameterComponents.contains( name ) )
1339  {
1340  QgsProcessingModelParameter &component = mParameterComponents[ name ];
1341  component.setParameterName( name );
1342  return component;
1343  }
1344  return mParameterComponents[ name ];
1345 }
1346 
1347 QList< QgsProcessingModelParameter > QgsProcessingModelAlgorithm::orderedParameters() const
1348 {
1349  QList< QgsProcessingModelParameter > res;
1350  QSet< QString > found;
1351  for ( const QString &parameter : mParameterOrder )
1352  {
1353  if ( mParameterComponents.contains( parameter ) )
1354  {
1355  res << mParameterComponents.value( parameter );
1356  found << parameter;
1357  }
1358  }
1359 
1360  // add any missing ones to end of list
1361  for ( auto it = mParameterComponents.constBegin(); it != mParameterComponents.constEnd(); ++it )
1362  {
1363  if ( !found.contains( it.key() ) )
1364  {
1365  res << it.value();
1366  }
1367  }
1368  return res;
1369 }
1370 
1371 void QgsProcessingModelAlgorithm::setParameterOrder( const QStringList &order )
1372 {
1373  mParameterOrder = order;
1374 }
1375 
1376 void QgsProcessingModelAlgorithm::updateDestinationParameters()
1377 {
1378  //delete existing destination parameters
1379  QMutableListIterator<const QgsProcessingParameterDefinition *> it( mParameters );
1380  while ( it.hasNext() )
1381  {
1382  const QgsProcessingParameterDefinition *def = it.next();
1383  if ( def->isDestination() )
1384  {
1385  delete def;
1386  it.remove();
1387  }
1388  }
1389  // also delete outputs
1390  qDeleteAll( mOutputs );
1391  mOutputs.clear();
1392 
1393  // rebuild
1394  QSet< QString > usedFriendlyNames;
1395  auto uniqueSafeName = [&usedFriendlyNames ]( const QString & name )->QString
1396  {
1397  const QString base = safeName( name, false );
1398  QString candidate = base;
1399  int i = 1;
1400  while ( usedFriendlyNames.contains( candidate ) )
1401  {
1402  i++;
1403  candidate = QStringLiteral( "%1_%2" ).arg( base ).arg( i );
1404  }
1405  usedFriendlyNames.insert( candidate );
1406  return candidate;
1407  };
1408 
1409  QMap< QString, QgsProcessingModelChildAlgorithm >::const_iterator childIt = mChildAlgorithms.constBegin();
1410  for ( ; childIt != mChildAlgorithms.constEnd(); ++childIt )
1411  {
1412  QMap<QString, QgsProcessingModelOutput> outputs = childIt->modelOutputs();
1413  QMap<QString, QgsProcessingModelOutput>::const_iterator outputIt = outputs.constBegin();
1414  for ( ; outputIt != outputs.constEnd(); ++outputIt )
1415  {
1416  if ( !childIt->isActive() || !childIt->algorithm() )
1417  continue;
1418 
1419  // child algorithm has a destination parameter set, copy it to the model
1420  const QgsProcessingParameterDefinition *source = childIt->algorithm()->parameterDefinition( outputIt->childOutputName() );
1421  if ( !source )
1422  continue;
1423 
1424  std::unique_ptr< QgsProcessingParameterDefinition > param( source->clone() );
1425  // Even if an output was hidden in a child algorithm, we want to show it here for the final
1426  // outputs.
1427  param->setFlags( param->flags() & ~QgsProcessingParameterDefinition::FlagHidden );
1428  if ( outputIt->isMandatory() )
1429  param->setFlags( param->flags() & ~QgsProcessingParameterDefinition::FlagOptional );
1430  if ( mInternalVersion != InternalVersion::Version1 && !outputIt->description().isEmpty() )
1431  {
1432  QString friendlyName = uniqueSafeName( outputIt->description() );
1433  param->setName( friendlyName );
1434  }
1435  else
1436  {
1437  param->setName( outputIt->childId() + ':' + outputIt->name() );
1438  }
1439  // add some metadata so we can easily link this parameter back to the child source
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() );
1443 
1444  param->setDescription( outputIt->description() );
1445  param->setDefaultValue( outputIt->defaultValue() );
1446 
1447  QgsProcessingDestinationParameter *newDestParam = dynamic_cast< QgsProcessingDestinationParameter * >( param.get() );
1448  if ( addParameter( param.release() ) && newDestParam )
1449  {
1450  if ( QgsProcessingProvider *provider = childIt->algorithm()->provider() )
1451  {
1452  // we need to copy the constraints given by the provider which creates this output across
1453  // and replace those which have been set to match the model provider's constraints
1454  newDestParam->setSupportsNonFileBasedOutput( provider->supportsNonFileBasedOutput() );
1455  newDestParam->mOriginalProvider = provider;
1456  }
1457  }
1458  }
1459  }
1460 }
1461 
1462 void QgsProcessingModelAlgorithm::addGroupBox( const QgsProcessingModelGroupBox &groupBox )
1463 {
1464  mGroupBoxes.insert( groupBox.uuid(), groupBox );
1465 }
1466 
1467 QList<QgsProcessingModelGroupBox> QgsProcessingModelAlgorithm::groupBoxes() const
1468 {
1469  return mGroupBoxes.values();
1470 }
1471 
1472 void QgsProcessingModelAlgorithm::removeGroupBox( const QString &uuid )
1473 {
1474  mGroupBoxes.remove( uuid );
1475 }
1476 
1477 QVariant QgsProcessingModelAlgorithm::toVariant() const
1478 {
1479  QVariantMap map;
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 ) );
1484 
1485  QVariantMap childMap;
1486  QMap< QString, QgsProcessingModelChildAlgorithm >::const_iterator childIt = mChildAlgorithms.constBegin();
1487  for ( ; childIt != mChildAlgorithms.constEnd(); ++childIt )
1488  {
1489  childMap.insert( childIt.key(), childIt.value().toVariant() );
1490  }
1491  map.insert( QStringLiteral( "children" ), childMap );
1492 
1493  QVariantMap paramMap;
1494  QMap< QString, QgsProcessingModelParameter >::const_iterator paramIt = mParameterComponents.constBegin();
1495  for ( ; paramIt != mParameterComponents.constEnd(); ++paramIt )
1496  {
1497  paramMap.insert( paramIt.key(), paramIt.value().toVariant() );
1498  }
1499  map.insert( QStringLiteral( "parameters" ), paramMap );
1500 
1501  QVariantMap paramDefMap;
1502  for ( const QgsProcessingParameterDefinition *def : mParameters )
1503  {
1504  paramDefMap.insert( def->name(), def->toVariantMap() );
1505  }
1506  map.insert( QStringLiteral( "parameterDefinitions" ), paramDefMap );
1507 
1508  QVariantList groupBoxDefs;
1509  for ( auto it = mGroupBoxes.constBegin(); it != mGroupBoxes.constEnd(); ++it )
1510  {
1511  groupBoxDefs.append( it.value().toVariant() );
1512  }
1513  map.insert( QStringLiteral( "groupBoxes" ), groupBoxDefs );
1514 
1515  map.insert( QStringLiteral( "modelVariables" ), mVariables );
1516 
1517  map.insert( QStringLiteral( "designerParameterValues" ), mDesignerParameterValues );
1518 
1519  map.insert( QStringLiteral( "parameterOrder" ), mParameterOrder );
1520 
1521  return map;
1522 }
1523 
1524 bool QgsProcessingModelAlgorithm::loadVariant( const QVariant &model )
1525 {
1526  QVariantMap map = model.toMap();
1527 
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();
1532 
1533  mInternalVersion = qgsEnumKeyToValue( map.value( QStringLiteral( "internal_version" ) ).toString(), InternalVersion::Version1 );
1534 
1535  mVariables = map.value( QStringLiteral( "modelVariables" ) ).toMap();
1536  mDesignerParameterValues = map.value( QStringLiteral( "designerParameterValues" ) ).toMap();
1537 
1538  mParameterOrder = map.value( QStringLiteral( "parameterOrder" ) ).toStringList();
1539 
1540  mChildAlgorithms.clear();
1541  QVariantMap childMap = map.value( QStringLiteral( "children" ) ).toMap();
1542  QVariantMap::const_iterator childIt = childMap.constBegin();
1543  for ( ; childIt != childMap.constEnd(); ++childIt )
1544  {
1545  QgsProcessingModelChildAlgorithm child;
1546  // we be lenient here - even if we couldn't load a parameter, don't interrupt the model loading
1547  // otherwise models may become unusable (e.g. due to removed plugins providing algs/parameters)
1548  // with no way for users to repair them
1549  if ( !child.loadVariant( childIt.value() ) )
1550  continue;
1551 
1552  mChildAlgorithms.insert( child.childId(), child );
1553  }
1554 
1555  mParameterComponents.clear();
1556  QVariantMap paramMap = map.value( QStringLiteral( "parameters" ) ).toMap();
1557  QVariantMap::const_iterator paramIt = paramMap.constBegin();
1558  for ( ; paramIt != paramMap.constEnd(); ++paramIt )
1559  {
1560  QgsProcessingModelParameter param;
1561  if ( !param.loadVariant( paramIt.value().toMap() ) )
1562  return false;
1563 
1564  mParameterComponents.insert( param.parameterName(), param );
1565  }
1566 
1567  qDeleteAll( mParameters );
1568  mParameters.clear();
1569  QVariantMap paramDefMap = map.value( QStringLiteral( "parameterDefinitions" ) ).toMap();
1570 
1571  auto addParam = [ = ]( const QVariant & value )
1572  {
1573  std::unique_ptr< QgsProcessingParameterDefinition > param( QgsProcessingParameters::parameterFromVariantMap( value.toMap() ) );
1574  // we be lenient here - even if we couldn't load a parameter, don't interrupt the model loading
1575  // otherwise models may become unusable (e.g. due to removed plugins providing algs/parameters)
1576  // with no way for users to repair them
1577  if ( param )
1578  {
1579  if ( param->name() == QLatin1String( "VERBOSE_LOG" ) )
1580  return; // internal parameter -- some versions of QGIS incorrectly stored this in the model definition file
1581 
1582  // set parameter help from help content
1583  param->setHelp( mHelpContent.value( param->name() ).toString() );
1584 
1585  // add parameter
1586  addParameter( param.release() );
1587  }
1588  else
1589  {
1590  QVariantMap map = value.toMap();
1591  QString type = map.value( QStringLiteral( "parameter_type" ) ).toString();
1592  QString name = map.value( QStringLiteral( "name" ) ).toString();
1593 
1594  QgsMessageLog::logMessage( QCoreApplication::translate( "Processing", "Could not load parameter %1 of type %2." ).arg( name, type ), QCoreApplication::translate( "Processing", "Processing" ) );
1595  }
1596  };
1597 
1598  QSet< QString > loadedParams;
1599  // first add parameters respecting mParameterOrder
1600  for ( const QString &name : std::as_const( mParameterOrder ) )
1601  {
1602  if ( paramDefMap.contains( name ) )
1603  {
1604  addParam( paramDefMap.value( name ) );
1605  loadedParams << name;
1606  }
1607  }
1608  // then load any remaining parameters
1609  QVariantMap::const_iterator paramDefIt = paramDefMap.constBegin();
1610  for ( ; paramDefIt != paramDefMap.constEnd(); ++paramDefIt )
1611  {
1612  if ( !loadedParams.contains( paramDefIt.key() ) )
1613  addParam( paramDefIt.value() );
1614  }
1615 
1616  mGroupBoxes.clear();
1617  const QVariantList groupBoxList = map.value( QStringLiteral( "groupBoxes" ) ).toList();
1618  for ( const QVariant &groupBoxDef : groupBoxList )
1619  {
1620  QgsProcessingModelGroupBox groupBox;
1621  groupBox.loadVariant( groupBoxDef.toMap() );
1622  mGroupBoxes.insert( groupBox.uuid(), groupBox );
1623  }
1624 
1625  updateDestinationParameters();
1626 
1627  return true;
1628 }
1629 
1630 bool QgsProcessingModelAlgorithm::vectorOutputIsCompatibleType( const QList<int> &acceptableDataTypes, QgsProcessing::SourceType outputType )
1631 {
1632  // This method is intended to be "permissive" rather than "restrictive".
1633  // I.e. we only reject outputs which we know can NEVER be acceptable, but
1634  // if there's doubt then we default to returning true.
1635  return ( acceptableDataTypes.empty()
1636  || acceptableDataTypes.contains( outputType )
1637  || outputType == QgsProcessing::TypeMapLayer
1638  || outputType == QgsProcessing::TypeVector
1639  || outputType == QgsProcessing::TypeVectorAnyGeometry
1640  || acceptableDataTypes.contains( QgsProcessing::TypeVector )
1641  || acceptableDataTypes.contains( QgsProcessing::TypeMapLayer )
1642  || ( acceptableDataTypes.contains( QgsProcessing::TypeVectorAnyGeometry ) && ( outputType == QgsProcessing::TypeVectorPoint ||
1643  outputType == QgsProcessing::TypeVectorLine ||
1644  outputType == QgsProcessing::TypeVectorPolygon ) ) );
1645 }
1646 
1647 void QgsProcessingModelAlgorithm::reattachAlgorithms() const
1648 {
1649  QMap< QString, QgsProcessingModelChildAlgorithm >::const_iterator childIt = mChildAlgorithms.constBegin();
1650  for ( ; childIt != mChildAlgorithms.constEnd(); ++childIt )
1651  {
1652  if ( !childIt->algorithm() )
1653  childIt->reattach();
1654  }
1655 }
1656 
1657 bool QgsProcessingModelAlgorithm::toFile( const QString &path ) const
1658 {
1659  QDomDocument doc = QDomDocument( QStringLiteral( "model" ) );
1660  QDomElement elem = QgsXmlUtils::writeVariant( toVariant(), doc );
1661  doc.appendChild( elem );
1662 
1663  QFile file( path );
1664  if ( file.open( QFile::WriteOnly | QFile::Truncate ) )
1665  {
1666  QTextStream stream( &file );
1667  doc.save( stream, 2 );
1668  file.close();
1669  return true;
1670  }
1671  return false;
1672 }
1673 
1674 bool QgsProcessingModelAlgorithm::fromFile( const QString &path )
1675 {
1676  QDomDocument doc;
1677 
1678  QFile file( path );
1679  if ( file.open( QFile::ReadOnly ) )
1680  {
1681  if ( !doc.setContent( &file ) )
1682  return false;
1683 
1684  file.close();
1685  }
1686  else
1687  {
1688  return false;
1689  }
1690 
1691  QVariant props = QgsXmlUtils::readVariant( doc.firstChildElement() );
1692  return loadVariant( props );
1693 }
1694 
1695 void QgsProcessingModelAlgorithm::setChildAlgorithms( const QMap<QString, QgsProcessingModelChildAlgorithm> &childAlgorithms )
1696 {
1697  mChildAlgorithms = childAlgorithms;
1698  updateDestinationParameters();
1699 }
1700 
1701 void QgsProcessingModelAlgorithm::setChildAlgorithm( const QgsProcessingModelChildAlgorithm &algorithm )
1702 {
1703  mChildAlgorithms.insert( algorithm.childId(), algorithm );
1704  updateDestinationParameters();
1705 }
1706 
1707 QString QgsProcessingModelAlgorithm::addChildAlgorithm( QgsProcessingModelChildAlgorithm &algorithm )
1708 {
1709  if ( algorithm.childId().isEmpty() || mChildAlgorithms.contains( algorithm.childId() ) )
1710  algorithm.generateChildId( *this );
1711 
1712  mChildAlgorithms.insert( algorithm.childId(), algorithm );
1713  updateDestinationParameters();
1714  return algorithm.childId();
1715 }
1716 
1717 QgsProcessingModelChildAlgorithm &QgsProcessingModelAlgorithm::childAlgorithm( const QString &childId )
1718 {
1719  return mChildAlgorithms[ childId ];
1720 }
1721 
1722 bool QgsProcessingModelAlgorithm::removeChildAlgorithm( const QString &id )
1723 {
1724  if ( !dependentChildAlgorithms( id ).isEmpty() )
1725  return false;
1726 
1727  mChildAlgorithms.remove( id );
1728  updateDestinationParameters();
1729  return true;
1730 }
1731 
1732 void QgsProcessingModelAlgorithm::deactivateChildAlgorithm( const QString &id )
1733 {
1734  const auto constDependentChildAlgorithms = dependentChildAlgorithms( id );
1735  for ( const QString &child : constDependentChildAlgorithms )
1736  {
1737  childAlgorithm( child ).setActive( false );
1738  }
1739  childAlgorithm( id ).setActive( false );
1740  updateDestinationParameters();
1741 }
1742 
1743 bool QgsProcessingModelAlgorithm::activateChildAlgorithm( const QString &id )
1744 {
1745  const auto constDependsOnChildAlgorithms = dependsOnChildAlgorithms( id );
1746  for ( const QString &child : constDependsOnChildAlgorithms )
1747  {
1748  if ( !childAlgorithm( child ).isActive() )
1749  return false;
1750  }
1751  childAlgorithm( id ).setActive( true );
1752  updateDestinationParameters();
1753  return true;
1754 }
1755 
1756 void QgsProcessingModelAlgorithm::addModelParameter( QgsProcessingParameterDefinition *definition, const QgsProcessingModelParameter &component )
1757 {
1758  if ( addParameter( definition ) )
1759  mParameterComponents.insert( definition->name(), component );
1760 }
1761 
1762 void QgsProcessingModelAlgorithm::updateModelParameter( QgsProcessingParameterDefinition *definition )
1763 {
1764  removeParameter( definition->name() );
1765  addParameter( definition );
1766 }
1767 
1768 void QgsProcessingModelAlgorithm::removeModelParameter( const QString &name )
1769 {
1770  removeParameter( name );
1771  mParameterComponents.remove( name );
1772 }
1773 
1774 void QgsProcessingModelAlgorithm::changeParameterName( const QString &oldName, const QString &newName )
1775 {
1776  QgsProcessingContext context;
1777  QgsExpressionContext expressionContext = createExpressionContext( QVariantMap(), context );
1778 
1779  auto replaceExpressionVariable = [oldName, newName, &expressionContext]( const QString & expressionString ) -> std::tuple< bool, QString >
1780  {
1781  QgsExpression expression( expressionString );
1782  expression.prepare( &expressionContext );
1783  QSet<QString> variables = expression.referencedVariables();
1784  if ( variables.contains( oldName ) )
1785  {
1786  QString newExpression = expressionString;
1787  newExpression.replace( QStringLiteral( "@%1" ).arg( oldName ), QStringLiteral( "@%2" ).arg( newName ) );
1788  return { true, newExpression };
1789  }
1790  return { false, QString() };
1791  };
1792 
1793  QMap< QString, QgsProcessingModelChildAlgorithm >::iterator childIt = mChildAlgorithms.begin();
1794  for ( ; childIt != mChildAlgorithms.end(); ++childIt )
1795  {
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 )
1800  {
1801  QList< QgsProcessingModelChildParameterSource > &value = paramIt.value();
1802  for ( auto valueIt = value.begin(); valueIt != value.end(); ++valueIt )
1803  {
1804  switch ( valueIt->source() )
1805  {
1806  case QgsProcessingModelChildParameterSource::ModelParameter:
1807  {
1808  if ( valueIt->parameterName() == oldName )
1809  {
1810  valueIt->setParameterName( newName );
1811  changed = true;
1812  }
1813  break;
1814  }
1815 
1816  case QgsProcessingModelChildParameterSource::Expression:
1817  {
1818  bool updatedExpression = false;
1819  QString newExpression;
1820  std::tie( updatedExpression, newExpression ) = replaceExpressionVariable( valueIt->expression() );
1821  if ( updatedExpression )
1822  {
1823  valueIt->setExpression( newExpression );
1824  changed = true;
1825  }
1826  break;
1827  }
1828 
1829  case QgsProcessingModelChildParameterSource::StaticValue:
1830  {
1831  if ( valueIt->staticValue().canConvert< QgsProperty >() )
1832  {
1833  QgsProperty property = valueIt->staticValue().value< QgsProperty >();
1834  if ( property.propertyType() == QgsProperty::ExpressionBasedProperty )
1835  {
1836  bool updatedExpression = false;
1837  QString newExpression;
1838  std::tie( updatedExpression, newExpression ) = replaceExpressionVariable( property.expressionString() );
1839  if ( updatedExpression )
1840  {
1841  property.setExpressionString( newExpression );
1842  valueIt->setStaticValue( property );
1843  changed = true;
1844  }
1845  }
1846  }
1847  break;
1848  }
1849 
1850  case QgsProcessingModelChildParameterSource::ChildOutput:
1851  case QgsProcessingModelChildParameterSource::ExpressionText:
1852  case QgsProcessingModelChildParameterSource::ModelOutput:
1853  break;
1854  }
1855  }
1856  }
1857  if ( changed )
1858  childIt->setParameterSources( childParams );
1859  }
1860 }
1861 
1862 bool QgsProcessingModelAlgorithm::childAlgorithmsDependOnParameter( const QString &name ) const
1863 {
1864  QMap< QString, QgsProcessingModelChildAlgorithm >::const_iterator childIt = mChildAlgorithms.constBegin();
1865  for ( ; childIt != mChildAlgorithms.constEnd(); ++childIt )
1866  {
1867  // check whether child requires this parameter
1868  QMap<QString, QgsProcessingModelChildParameterSources> childParams = childIt->parameterSources();
1869  QMap<QString, QgsProcessingModelChildParameterSources>::const_iterator paramIt = childParams.constBegin();
1870  for ( ; paramIt != childParams.constEnd(); ++paramIt )
1871  {
1872  const auto constValue = paramIt.value();
1873  for ( const QgsProcessingModelChildParameterSource &source : constValue )
1874  {
1875  if ( source.source() == QgsProcessingModelChildParameterSource::ModelParameter
1876  && source.parameterName() == name )
1877  {
1878  return true;
1879  }
1880  }
1881  }
1882  }
1883  return false;
1884 }
1885 
1886 bool QgsProcessingModelAlgorithm::otherParametersDependOnParameter( const QString &name ) const
1887 {
1888  const auto constMParameters = mParameters;
1889  for ( const QgsProcessingParameterDefinition *def : constMParameters )
1890  {
1891  if ( def->name() == name )
1892  continue;
1893 
1894  if ( def->dependsOnOtherParameters().contains( name ) )
1895  return true;
1896  }
1897  return false;
1898 }
1899 
1900 QMap<QString, QgsProcessingModelParameter> QgsProcessingModelAlgorithm::parameterComponents() const
1901 {
1902  return mParameterComponents;
1903 }
1904 
1905 void QgsProcessingModelAlgorithm::dependentChildAlgorithmsRecursive( const QString &childId, QSet<QString> &depends, const QString &branch ) const
1906 {
1907  QMap< QString, QgsProcessingModelChildAlgorithm >::const_iterator childIt = mChildAlgorithms.constBegin();
1908  for ( ; childIt != mChildAlgorithms.constEnd(); ++childIt )
1909  {
1910  if ( depends.contains( childIt->childId() ) )
1911  continue;
1912 
1913  // does alg have a direct dependency on this child?
1914  const QList< QgsProcessingModelChildDependency > constDependencies = childIt->dependencies();
1915  bool hasDependency = false;
1916  for ( const QgsProcessingModelChildDependency &dep : constDependencies )
1917  {
1918  if ( dep.childId == childId && ( branch.isEmpty() || dep.conditionalBranch == branch ) )
1919  {
1920  hasDependency = true;
1921  break;
1922  }
1923  }
1924 
1925  if ( hasDependency )
1926  {
1927  depends.insert( childIt->childId() );
1928  dependentChildAlgorithmsRecursive( childIt->childId(), depends, branch );
1929  continue;
1930  }
1931 
1932  // check whether child requires any outputs from the target alg
1933  QMap<QString, QgsProcessingModelChildParameterSources> childParams = childIt->parameterSources();
1934  QMap<QString, QgsProcessingModelChildParameterSources>::const_iterator paramIt = childParams.constBegin();
1935  for ( ; paramIt != childParams.constEnd(); ++paramIt )
1936  {
1937  const auto constValue = paramIt.value();
1938  for ( const QgsProcessingModelChildParameterSource &source : constValue )
1939  {
1940  if ( source.source() == QgsProcessingModelChildParameterSource::ChildOutput
1941  && source.outputChildId() == childId )
1942  {
1943  depends.insert( childIt->childId() );
1944  dependentChildAlgorithmsRecursive( childIt->childId(), depends, branch );
1945  break;
1946  }
1947  }
1948  }
1949  }
1950 }
1951 
1952 QSet<QString> QgsProcessingModelAlgorithm::dependentChildAlgorithms( const QString &childId, const QString &conditionalBranch ) const
1953 {
1954  QSet< QString > algs;
1955 
1956  // temporarily insert the target child algorithm to avoid
1957  // unnecessarily recursion though it
1958  algs.insert( childId );
1959 
1960  dependentChildAlgorithmsRecursive( childId, algs, conditionalBranch );
1961 
1962  // remove temporary target alg
1963  algs.remove( childId );
1964 
1965  return algs;
1966 }
1967 
1968 
1969 void QgsProcessingModelAlgorithm::dependsOnChildAlgorithmsRecursive( const QString &childId, QSet< QString > &depends ) const
1970 {
1971  const QgsProcessingModelChildAlgorithm &alg = mChildAlgorithms.value( childId );
1972 
1973  // add direct dependencies
1974  const QList< QgsProcessingModelChildDependency > constDependencies = alg.dependencies();
1975  for ( const QgsProcessingModelChildDependency &val : constDependencies )
1976  {
1977  if ( !depends.contains( val.childId ) )
1978  {
1979  depends.insert( val.childId );
1980  dependsOnChildAlgorithmsRecursive( val.childId, depends );
1981  }
1982  }
1983 
1984  // check through parameter dependencies
1985  QMap<QString, QgsProcessingModelChildParameterSources> childParams = alg.parameterSources();
1986  QMap<QString, QgsProcessingModelChildParameterSources>::const_iterator paramIt = childParams.constBegin();
1987  for ( ; paramIt != childParams.constEnd(); ++paramIt )
1988  {
1989  const auto constValue = paramIt.value();
1990  for ( const QgsProcessingModelChildParameterSource &source : constValue )
1991  {
1992  if ( source.source() == QgsProcessingModelChildParameterSource::ChildOutput && !depends.contains( source.outputChildId() ) )
1993  {
1994  depends.insert( source.outputChildId() );
1995  dependsOnChildAlgorithmsRecursive( source.outputChildId(), depends );
1996  }
1997  }
1998  }
1999 }
2000 
2001 QSet< QString > QgsProcessingModelAlgorithm::dependsOnChildAlgorithms( const QString &childId ) const
2002 {
2003  QSet< QString > algs;
2004 
2005  // temporarily insert the target child algorithm to avoid
2006  // unnecessarily recursion though it
2007  algs.insert( childId );
2008 
2009  dependsOnChildAlgorithmsRecursive( childId, algs );
2010 
2011  // remove temporary target alg
2012  algs.remove( childId );
2013 
2014  return algs;
2015 }
2016 
2017 QList<QgsProcessingModelChildDependency> QgsProcessingModelAlgorithm::availableDependenciesForChildAlgorithm( const QString &childId ) const
2018 {
2019  QSet< QString > dependent;
2020  if ( !childId.isEmpty() )
2021  {
2022  dependent.unite( dependentChildAlgorithms( childId ) );
2023  dependent.insert( childId );
2024  }
2025 
2026  QList<QgsProcessingModelChildDependency> res;
2027  for ( auto it = mChildAlgorithms.constBegin(); it != mChildAlgorithms.constEnd(); ++it )
2028  {
2029  if ( !dependent.contains( it->childId() ) )
2030  {
2031  // check first if algorithm provides output branches
2032  bool hasBranches = false;
2033  if ( it->algorithm() )
2034  {
2035  const QgsProcessingOutputDefinitions defs = it->algorithm()->outputDefinitions();
2036  for ( const QgsProcessingOutputDefinition *def : defs )
2037  {
2039  {
2040  hasBranches = true;
2041  QgsProcessingModelChildDependency alg;
2042  alg.childId = it->childId();
2043  alg.conditionalBranch = def->name();
2044  res << alg;
2045  }
2046  }
2047  }
2048 
2049  if ( !hasBranches )
2050  {
2051  QgsProcessingModelChildDependency alg;
2052  alg.childId = it->childId();
2053  res << alg;
2054  }
2055  }
2056  }
2057  return res;
2058 }
2059 
2060 bool QgsProcessingModelAlgorithm::validateChildAlgorithm( const QString &childId, QStringList &issues ) const
2061 {
2062  issues.clear();
2063  QMap< QString, QgsProcessingModelChildAlgorithm >::const_iterator childIt = mChildAlgorithms.constFind( childId );
2064  if ( childIt != mChildAlgorithms.constEnd() )
2065  {
2066  if ( !childIt->algorithm() )
2067  {
2068  issues << QObject::tr( "Algorithm is not available: <i>%1</i>" ).arg( childIt->algorithmId() );
2069  return false;
2070  }
2071  bool res = true;
2072 
2073  // loop through child algorithm parameters and check that they are all valid
2074  const QgsProcessingParameterDefinitions defs = childIt->algorithm()->parameterDefinitions();
2075  for ( const QgsProcessingParameterDefinition *def : defs )
2076  {
2077  if ( childIt->parameterSources().contains( def->name() ) )
2078  {
2079  // is the value acceptable?
2080  const QList< QgsProcessingModelChildParameterSource > sources = childIt->parameterSources().value( def->name() );
2081  for ( const QgsProcessingModelChildParameterSource &source : sources )
2082  {
2083  switch ( source.source() )
2084  {
2085  case QgsProcessingModelChildParameterSource::StaticValue:
2086  if ( !def->checkValueIsAcceptable( source.staticValue() ) )
2087  {
2088  res = false;
2089  issues << QObject::tr( "Value for <i>%1</i> is not acceptable for this parameter" ).arg( def->name() );
2090  }
2091  break;
2092 
2093  case QgsProcessingModelChildParameterSource::ModelParameter:
2094  if ( !parameterComponents().contains( source.parameterName() ) )
2095  {
2096  res = false;
2097  issues << QObject::tr( "Model input <i>%1</i> used for parameter <i>%2</i> does not exist" ).arg( source.parameterName(), def->name() );
2098  }
2099  break;
2100 
2101  case QgsProcessingModelChildParameterSource::ChildOutput:
2102  if ( !childAlgorithms().contains( source.outputChildId() ) )
2103  {
2104  res = false;
2105  issues << QObject::tr( "Child algorithm <i>%1</i> used for parameter <i>%2</i> does not exist" ).arg( source.outputChildId(), def->name() );
2106  }
2107  break;
2108 
2109  case QgsProcessingModelChildParameterSource::Expression:
2110  case QgsProcessingModelChildParameterSource::ExpressionText:
2111  case QgsProcessingModelChildParameterSource::ModelOutput:
2112  break;
2113  }
2114  }
2115  }
2116  else
2117  {
2118  // not specified. Is it optional?
2119 
2120  // ignore destination parameters -- they shouldn't ever be mandatory
2121  if ( def->isDestination() )
2122  continue;
2123 
2125  {
2126  res = false;
2127  issues << QObject::tr( "Parameter <i>%1</i> is mandatory" ).arg( def->name() );
2128  }
2129  }
2130  }
2131 
2132  return res;
2133  }
2134  else
2135  {
2136  issues << QObject::tr( "Invalid child ID: <i>%1</i>" ).arg( childId );
2137  return false;
2138  }
2139 }
2140 
2141 bool QgsProcessingModelAlgorithm::canExecute( QString *errorMessage ) const
2142 {
2143  reattachAlgorithms();
2144  QMap< QString, QgsProcessingModelChildAlgorithm >::const_iterator childIt = mChildAlgorithms.constBegin();
2145  for ( ; childIt != mChildAlgorithms.constEnd(); ++childIt )
2146  {
2147  if ( !childIt->algorithm() )
2148  {
2149  if ( errorMessage )
2150  {
2151  *errorMessage = QObject::tr( "The model you are trying to run contains an algorithm that is not available: <i>%1</i>" ).arg( childIt->algorithmId() );
2152  }
2153  return false;
2154  }
2155  }
2156  return true;
2157 }
2158 
2159 QString QgsProcessingModelAlgorithm::asPythonCommand( const QVariantMap &parameters, QgsProcessingContext &context ) const
2160 {
2161  if ( mSourceFile.isEmpty() )
2162  return QString(); // temporary model - can't run as python command
2163 
2164  return QgsProcessingAlgorithm::asPythonCommand( parameters, context );
2165 }
2166 
2167 QgsExpressionContext QgsProcessingModelAlgorithm::createExpressionContext( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeatureSource *source ) const
2168 {
2169  QgsExpressionContext res = QgsProcessingAlgorithm::createExpressionContext( parameters, context, source );
2170  res << QgsExpressionContextUtils::processingModelAlgorithmScope( this, parameters, context );
2171  return res;
2172 }
2173 
2174 QgsProcessingAlgorithm *QgsProcessingModelAlgorithm::createInstance() const
2175 {
2176  QgsProcessingModelAlgorithm *alg = new QgsProcessingModelAlgorithm();
2177  alg->loadVariant( toVariant() );
2178  alg->setProvider( provider() );
2179  alg->setSourceFilePath( sourceFilePath() );
2180  return alg;
2181 }
2182 
2183 QString QgsProcessingModelAlgorithm::safeName( const QString &name, bool capitalize )
2184 {
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*" ) ); // name can't start in a digit
2189  n.replace( rx2, QString() );
2190  if ( !capitalize )
2191  n = n.replace( ' ', '_' );
2193 }
2194 
2195 QVariantMap QgsProcessingModelAlgorithm::variables() const
2196 {
2197  return mVariables;
2198 }
2199 
2200 void QgsProcessingModelAlgorithm::setVariables( const QVariantMap &variables )
2201 {
2202  mVariables = variables;
2203 }
2204 
2205 QVariantMap QgsProcessingModelAlgorithm::designerParameterValues() const
2206 {
2207  return mDesignerParameterValues;
2208 }
2209 
QgsExpressionContext
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
Definition: qgsexpressioncontext.h:406
QgsApplication::processingRegistry
static QgsProcessingRegistry * processingRegistry()
Returns the application's processing registry, used for managing processing providers,...
Definition: qgsapplication.cpp:2455
qgsexpressioncontextutils.h
qgsprocessingparametertype.h
QgsProcessingFeedback::setProgressText
virtual void setProgressText(const QString &text)
Sets a progress report text string.
Definition: qgsprocessingfeedback.cpp:35
QgsProcessingParameterProviderConnection::typeName
static QString typeName()
Returns the type name for the parameter class.
Definition: qgsprocessingparameters.h:4080
qgsEnumValueToKey
QString qgsEnumValueToKey(const T &value, bool *returnOk=nullptr)
Returns the value for the given key of an enum.
Definition: qgis.h:2440
QgsStringUtils::capitalize
static QString capitalize(const QString &string, Qgis::Capitalization capitalization)
Converts a string by applying capitalization rules to the string.
Definition: qgsstringutils.cpp:24
QgsProcessingParameterDefinition::toVariantMap
virtual QVariantMap toVariantMap() const
Saves this parameter to a QVariantMap.
Definition: qgsprocessingparameters.cpp:2895
QgsProperty
A store for object properties.
Definition: qgsproperty.h:230
QgsProcessingFeedback::pushCommandInfo
virtual void pushCommandInfo(const QString &info)
Pushes an informational message containing a command from the algorithm.
Definition: qgsprocessingfeedback.cpp:86
QgsProcessingParameterDuration::typeName
static QString typeName()
Returns the type name for the parameter class.
Definition: qgsprocessingparameters.h:2368
QgsProcessingOutputConditionalBranch::typeName
static QString typeName()
Returns the type name for the output class.
Definition: qgsprocessingoutputs.h:436
QgsProcessingFeedback
Base class for providing feedback from a processing algorithm.
Definition: qgsprocessingfeedback.h:37
algorithm
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into allowing algorithms to be written in pure substantial changes are required in order to port existing x Processing algorithms for QGIS x The most significant changes are outlined not GeoAlgorithm For algorithms which operate on features one by consider subclassing the QgsProcessingFeatureBasedAlgorithm class This class allows much of the boilerplate code for looping over features from a vector layer to be bypassed and instead requires implementation of a processFeature method Ensure that your algorithm(or algorithm 's parent class) implements the new pure virtual createInstance(self) call
qgsstringutils.h
QgsProcessingFeedback::pushInfo
virtual void pushInfo(const QString &info)
Pushes a general informational message from the algorithm.
Definition: qgsprocessingfeedback.cpp:77
QgsProcessingParameterDefinition::flags
Flags flags() const
Returns any flags associated with the parameter.
Definition: qgsprocessingparameters.h:594
QgsProcessingParameterDefinition::metadata
QVariantMap metadata() const
Returns the parameter's freeform metadata.
Definition: qgsprocessingparameters.h:707
QgsProcessingUtils::removePointerValuesFromMap
static QVariantMap removePointerValuesFromMap(const QVariantMap &map)
Removes any raw pointer values from an input map, replacing them with appropriate string values where...
Definition: qgsprocessingutils.cpp:1326
QgsProcessingParameterFile::typeName
static QString typeName()
Returns the type name for the parameter class.
Definition: qgsprocessingparameters.h:1931
QgsProcessing::TypeVectorPolygon
@ TypeVectorPolygon
Vector polygon layers.
Definition: qgsprocessing.h:51
QgsRectangle::yMinimum
double yMinimum() const SIP_HOLDGIL
Returns the y minimum value (bottom side of rectangle).
Definition: qgsrectangle.h:198
QgsProcessingOutputVectorLayer
A vector layer output for processing algorithms.
Definition: qgsprocessingoutputs.h:179
QgsProcessingProvider
Abstract base class for processing providers.
Definition: qgsprocessingprovider.h:35
qgsprocessingmodelalgorithm.h
QgsProcessingParameterLayoutItem::typeName
static QString typeName()
Returns the type name for the parameter class.
Definition: qgsprocessingparameters.h:3676
QgsFeedback::isCanceled
bool isCanceled() const SIP_HOLDGIL
Tells whether the operation has been canceled already.
Definition: qgsfeedback.h:67
QgsFeatureSource
An interface for objects which provide features via a getFeatures method.
Definition: qgsfeaturesource.h:37
QgsProcessingParameterGeometry::typeName
static QString typeName()
Returns the type name for the parameter class.
Definition: qgsprocessingparameters.h:1853
qgis.h
qgsprocessingmodelgroupbox.h
QgsProcessingParameterDefinition::FlagAdvanced
@ FlagAdvanced
Parameter is an advanced parameter which should be hidden from users by default.
Definition: qgsprocessingparameters.h:451
QgsProcessingParameterLimitedDataTypes
Can be inherited by parameters which require limits to their acceptable data types.
Definition: qgsprocessingparameters.h:2793
QgsProcessingParameterDefinition
Base class for the definition of processing parameters.
Definition: qgsprocessingparameters.h:334
QgsProcessing::TypeVectorLine
@ TypeVectorLine
Vector line layers.
Definition: qgsprocessing.h:50
QgsProcessingOutputLayerDefinition
Encapsulates settings relating to a feature sink or output raster layer for a processing algorithm.
Definition: qgsprocessingparameters.h:202
QgsProcessingProvider::algorithm
const QgsProcessingAlgorithm * algorithm(const QString &name) const
Returns the matching algorithm by name, or nullptr if no matching algorithm is contained by this prov...
Definition: qgsprocessingprovider.cpp:90
QgsProcessingAlgorithm::FlagCustomException
@ FlagCustomException
Algorithm raises custom exception notices, don't use the standard ones.
Definition: qgsprocessingalgorithm.h:80
QgsProcessingOutputBoolean::typeName
static QString typeName()
Returns the type name for the output class.
Definition: qgsprocessingoutputs.h:368
QgsApplication::iconPath
static QString iconPath(const QString &iconFile)
Returns path to the desired icon file.
Definition: qgsapplication.cpp:682
QgsProcessingParameterLayout::typeName
static QString typeName()
Returns the type name for the parameter class.
Definition: qgsprocessingparameters.h:3636
QgsProcessing::TypeVectorPoint
@ TypeVectorPoint
Vector point layers.
Definition: qgsprocessing.h:49
QgsProcessingFeatureSourceDefinition::source
QgsProperty source
Source definition.
Definition: qgsprocessingparameters.h:119
QgsProperty::value
QVariant value(const QgsExpressionContext &context, const QVariant &defaultValue=QVariant(), bool *ok=nullptr) const
Calculates the current value of the property, including any transforms which are set for the property...
Definition: qgsproperty.cpp:585
QgsProcessingParameterDefinitions
QList< const QgsProcessingParameterDefinition * > QgsProcessingParameterDefinitions
List of processing parameters.
Definition: qgsprocessingparameters.h:889
QgsProcessingParameterDatabaseTable::typeName
static QString typeName()
Returns the type name for the parameter class.
Definition: qgsprocessingparameters.h:4208
QgsProcessingParameters::parameterFromVariantMap
static QgsProcessingParameterDefinition * parameterFromVariantMap(const QVariantMap &map)
Creates a new QgsProcessingParameterDefinition using the configuration from a supplied variant map.
Definition: qgsprocessingparameters.cpp:2191
QgsProcessingParameterBand::typeName
static QString typeName()
Returns the type name for the parameter class.
Definition: qgsprocessingparameters.h:3563
QgsProcessingOutputRasterLayer::typeName
static QString typeName()
Returns the type name for the output class.
Definition: qgsprocessingoutputs.h:229
QgsProcessingDestinationParameter::setSupportsNonFileBasedOutput
void setSupportsNonFileBasedOutput(bool supportsNonFileBasedOutput)
Sets whether the destination parameter supports non filed-based outputs, such as memory layers or dir...
Definition: qgsprocessingparameters.h:3134
QgsProcessingAlgorithm::FlagPruneModelBranchesBasedOnAlgorithmResults
@ FlagPruneModelBranchesBasedOnAlgorithmResults
Algorithm results will cause remaining model branches to be pruned based on the results of running th...
Definition: qgsprocessingalgorithm.h:81
QgsProcessingDestinationParameter
Base class for all parameter definitions which represent file or layer destinations,...
Definition: qgsprocessingparameters.h:3097
qgsapplication.h
QgsProcessingAlgorithm::outputDefinitions
QgsProcessingOutputDefinitions outputDefinitions() const
Returns an ordered list of output definitions utilized by the algorithm.
Definition: qgsprocessingalgorithm.h:307
QgsProcessingOutputDefinition
Base class for the definition of processing outputs.
Definition: qgsprocessingoutputs.h:41
QgsProcessingFeatureSourceDefinition
Encapsulates settings relating to a feature source input to a processing algorithm.
Definition: qgsprocessingparameters.h:57
QgsRectangle::xMaximum
double xMaximum() const SIP_HOLDGIL
Returns the x maximum value (right side of rectangle).
Definition: qgsrectangle.h:183
QgsProperty::ExpressionBasedProperty
@ ExpressionBasedProperty
Expression based property (QgsExpressionBasedProperty)
Definition: qgsproperty.h:240
QgsProcessingParameterColor::typeName
static QString typeName()
Returns the type name for the parameter class.
Definition: qgsprocessingparameters.h:3751
QgsProcessingParameterRange::typeName
static QString typeName()
Returns the type name for the parameter class.
Definition: qgsprocessingparameters.h:2457
QgsProcessing::TypeMapLayer
@ TypeMapLayer
Any map layer type (raster, vector, mesh, point cloud, annotation or plugin layer)
Definition: qgsprocessing.h:47
QgsProcessing::PythonQgsProcessingAlgorithmSubclass
@ PythonQgsProcessingAlgorithmSubclass
Full Python QgsProcessingAlgorithm subclass.
Definition: qgsprocessing.h:64
QgsProcessing::TypeVector
@ TypeVector
Tables (i.e. vector layers with or without geometry). When used for a sink this indicates the sink ha...
Definition: qgsprocessing.h:54
QgsProcessingMultiStepFeedback
Processing feedback object for multi-step operations.
Definition: qgsprocessingfeedback.h:166
QgsProcessingParameterAuthConfig::typeName
static QString typeName()
Returns the type name for the parameter class.
Definition: qgsprocessingparameters.h:2720
QgsProcessingOutputMapLayer::typeName
static QString typeName()
Returns the type name for the output class.
Definition: qgsprocessingoutputs.h:168
QgsProcessingParameterRasterLayer::typeName
static QString typeName()
Returns the type name for the parameter class.
Definition: qgsprocessingparameters.h:2508
QgsProcessingParameterPoint::typeName
static QString typeName()
Returns the type name for the parameter class.
Definition: qgsprocessingparameters.h:1818
QgsXmlUtils::readVariant
static QVariant readVariant(const QDomElement &element)
Read a QVariant from a QDomElement.
Definition: qgsxmlutils.cpp:251
QgsProcessingContext
Contains information about the context in which a processing algorithm is executed.
Definition: qgsprocessingcontext.h:46
QgsProcessingParameterDefinition::algorithm
QgsProcessingAlgorithm * algorithm() const
Returns a pointer to the algorithm which owns this parameter.
Definition: qgsprocessingparameters.cpp:2921
QgsMapLayer::extent
virtual QgsRectangle extent() const
Returns the extent of the layer.
Definition: qgsmaplayer.cpp:305
QgsProcessingParameterDefinition::name
QString name() const
Returns the name of the parameter.
Definition: qgsprocessingparameters.h:488
QgsProcessingParameterField::typeName
static QString typeName()
Returns the type name for the parameter class.
Definition: qgsprocessingparameters.h:2966
QgsProcessingAlgorithm::asPythonCommand
virtual QString asPythonCommand(const QVariantMap &parameters, QgsProcessingContext &context) const
Returns a Python command string which can be executed to run the algorithm using the specified parame...
Definition: qgsprocessingalgorithm.cpp:290
QgsProcessing::TypeVectorAnyGeometry
@ TypeVectorAnyGeometry
Any vector layer with geometry.
Definition: qgsprocessing.h:48
QgsExpressionContextUtils::processingAlgorithmScope
static QgsExpressionContextScope * processingAlgorithmScope(const QgsProcessingAlgorithm *algorithm, const QVariantMap &parameters, QgsProcessingContext &context)
Creates a new scope which contains variables and functions relating to a processing algorithm,...
Definition: qgsexpressioncontextutils.cpp:850
QgsProcessingParameterString::typeName
static QString typeName()
Returns the type name for the parameter class.
Definition: qgsprocessingparameters.h:2661
QgsProcessingRegistry::parameterType
QgsProcessingParameterType * parameterType(const QString &id) const
Returns the parameter type registered for id.
Definition: qgsprocessingregistry.cpp:227
QgsProcessingParameterEnum::typeName
static QString typeName()
Returns the type name for the parameter class.
Definition: qgsprocessingparameters.h:2556
qgsprocessingfeedback.h
QgsMessageLog::logMessage
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::MessageLevel::Warning, bool notifyUser=true)
Adds a message to the log instance (and creates it if necessary).
Definition: qgsmessagelog.cpp:27
QgsExpressionContextUtils::processingModelAlgorithmScope
static QgsExpressionContextScope * processingModelAlgorithmScope(const QgsProcessingModelAlgorithm *model, const QVariantMap &parameters, QgsProcessingContext &context)
Creates a new scope which contains variables and functions relating to a processing model algorithm,...
Definition: qgsexpressioncontextutils.cpp:867
QgsProcessingContext::setExpressionContext
void setExpressionContext(const QgsExpressionContext &context)
Sets the expression context.
Definition: qgsprocessingcontext.h:159
QgsWeakMapLayerPointer
QPointer< QgsMapLayer > QgsWeakMapLayerPointer
Weak pointer for QgsMapLayer.
Definition: qgsmaplayer.h:2146
QgsProcessingOutputVectorLayer::typeName
static QString typeName()
Returns the type name for the output class.
Definition: qgsprocessingoutputs.h:191
QgsProcessingParameterLimitedDataTypes::dataTypes
QList< int > dataTypes() const
Returns the geometry types for sources acceptable by the parameter.
Definition: qgsprocessingparameters.cpp:5424
QgsRectangle::xMinimum
double xMinimum() const SIP_HOLDGIL
Returns the x minimum value (left side of rectangle).
Definition: qgsrectangle.h:188
QgsProcessingParameterFeatureSource::typeName
static QString typeName()
Returns the type name for the parameter class.
Definition: qgsprocessingparameters.h:3071
QgsFeatureSource::sourceExtent
virtual QgsRectangle sourceExtent() const
Returns the extent of all geometries from the source.
Definition: qgsfeaturesource.cpp:98
QgsProcessingAlgorithm::FlagSkipGenericModelLogging
@ FlagSkipGenericModelLogging
When running as part of a model, the generic algorithm setup and results logging should be skipped.
Definition: qgsprocessingalgorithm.h:82
QgsProcessingParameterFolderDestination::typeName
static QString typeName()
Returns the type name for the parameter class.
Definition: qgsprocessingparameters.h:3528
qgsxmlutils.h
QgsExpressionContextScope
Single scope for storing variables and functions for use within a QgsExpressionContext....
Definition: qgsexpressioncontext.h:113
qgsvectorlayer.h
QgsProcessingFeedback::pushDebugInfo
virtual void pushDebugInfo(const QString &info)
Pushes an informational message containing debugging helpers from the algorithm.
Definition: qgsprocessingfeedback.cpp:95
qgsprocessingutils.h
QgsProcessingUtils::LayerHint::Vector
@ Vector
Vector layer type.
QgsProcessingOutputString::typeName
static QString typeName()
Returns the type name for the output class.
Definition: qgsprocessingoutputs.h:346
QgsStringMap
QMap< QString, QString > QgsStringMap
Definition: qgis.h:2781
QgsRectangle::yMaximum
double yMaximum() const SIP_HOLDGIL
Returns the y maximum value (top side of rectangle).
Definition: qgsrectangle.h:193
QgsProcessingAlgorithm::FlagNoThreading
@ FlagNoThreading
Algorithm is not thread safe and cannot be run in a background thread, e.g. for algorithms which mani...
Definition: qgsprocessingalgorithm.h:76
QgsProcessingAlgorithm
Abstract base class for processing algorithms.
Definition: qgsprocessingalgorithm.h:52
QgsProcessingParameterDefinition::FlagHidden
@ FlagHidden
Parameter is hidden and should not be shown to users.
Definition: qgsprocessingparameters.h:452
QgsProcessingParameterType::pythonImportString
virtual QString pythonImportString() const
Returns a valid Python import string for importing the corresponding parameter type,...
Definition: qgsprocessingparametertype.h:93
QgsVectorLayer
Represents a vector layer which manages a vector based data sets.
Definition: qgsvectorlayer.h:391
QgsProcessingParameterExpression::typeName
static QString typeName()
Returns the type name for the parameter class.
Definition: qgsprocessingparameters.h:2753
QgsMapLayer
Base class for all map layer types. This is the base class for all map layer types (vector,...
Definition: qgsmaplayer.h:72
QgsProcessingUtils::formatHelpMapAsHtml
static QString formatHelpMapAsHtml(const QVariantMap &map, const QgsProcessingAlgorithm *algorithm)
Returns a HTML formatted version of the help text encoded in a variant map for a specified algorithm.
Definition: qgsprocessingutils.cpp:1076
QgsProcessingParameterMapTheme::typeName
static QString typeName()
Returns the type name for the parameter class.
Definition: qgsprocessingparameters.h:3918
QgsProcessingParameterDistance::typeName
static QString typeName()
Returns the type name for the parameter class.
Definition: qgsprocessingparameters.h:2299
QgsProcessingContext::expressionContext
QgsExpressionContext & expressionContext()
Returns the expression context.
Definition: qgsprocessingcontext.h:149
QgsProcessingFeatureSource
QgsFeatureSource subclass which proxies methods to an underlying QgsFeatureSource,...
Definition: qgsprocessingutils.h:577
qgsEnumKeyToValue
T qgsEnumKeyToValue(const QString &key, const T &defaultValue, bool tryValueAsKey=true, bool *returnOk=nullptr)
Returns the value corresponding to the given key of an enum.
Definition: qgis.h:2459
QgsProcessingParameterBoolean::typeName
static QString typeName()
Returns the type name for the parameter class.
Definition: qgsprocessingparameters.h:1722
QgsProcessingAlgorithm::createExpressionContext
virtual QgsExpressionContext createExpressionContext(const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeatureSource *source=nullptr) const
Creates an expression context relating to the algorithm.
Definition: qgsprocessingalgorithm.cpp:158
QgsProcessingParameterDefinition::isDestination
virtual bool isDestination() const
Returns true if this parameter represents a file or layer destination, e.g.
Definition: qgsprocessingparameters.h:481
Qgis::Capitalization::UpperCamelCase
@ UpperCamelCase
Convert the string to upper camel case. Note that this method does not unaccent characters.
QgsProcessingParameterDefinition::clone
virtual QgsProcessingParameterDefinition * clone() const =0
Creates a clone of the parameter definition.
qgsexception.h
QgsProcessingUtils::mapLayerFromString
static QgsMapLayer * mapLayerFromString(const QString &string, QgsProcessingContext &context, bool allowLoadingNewLayers=true, QgsProcessingUtils::LayerHint typeHint=QgsProcessingUtils::LayerHint::UnknownType)
Interprets a string as a map layer within the supplied context.
Definition: qgsprocessingutils.cpp:376
QgsProcessingParameterVectorLayer::typeName
static QString typeName()
Returns the type name for the parameter class.
Definition: qgsprocessingparameters.h:2843
QgsProcessingParameterScale::typeName
static QString typeName()
Returns the type name for the parameter class.
Definition: qgsprocessingparameters.h:2422
QgsProperty::staticValue
QVariant staticValue() const
Returns the current static value for the property.
Definition: qgsproperty.cpp:341
QgsApplication::getThemeIcon
static QIcon getThemeIcon(const QString &name, const QColor &fillColor=QColor(), const QColor &strokeColor=QColor())
Helper to get a theme icon.
Definition: qgsapplication.cpp:693
QgsProcessingParameterCoordinateOperation::typeName
static QString typeName()
Returns the type name for the parameter class.
Definition: qgsprocessingparameters.h:3814
QgsProcessingOutputVectorLayer::dataType
QgsProcessing::SourceType dataType() const
Returns the layer type for the output layer.
Definition: qgsprocessingoutputs.cpp:30
QgsProcessingContext::Verbose
@ Verbose
Verbose logging.
Definition: qgsprocessingcontext.h:66
QgsProcessingOutputNumber::typeName
static QString typeName()
Returns the type name for the output class.
Definition: qgsprocessingoutputs.h:324
QgsProcessingParameterDefinition::type
virtual QString type() const =0
Unique parameter type name.
QgsProcessingOutputLayerDefinition::sink
QgsProperty sink
Sink/layer definition.
Definition: qgsprocessingparameters.h:229
QgsProcessingOutputDefinitions
QList< const QgsProcessingOutputDefinition * > QgsProcessingOutputDefinitions
List of processing parameters.
Definition: qgsprocessingoutputs.h:144
QgsProcessingOutputLayerDefinition::destinationName
QString destinationName
Name to use for sink if it's to be loaded into a destination project.
Definition: qgsprocessingparameters.h:241
QgsProcessingParameterDefinition::FlagOptional
@ FlagOptional
Parameter is optional.
Definition: qgsprocessingparameters.h:453
QgsExpressionContextScope::StaticVariable
Single variable definition for use within a QgsExpressionContextScope.
Definition: qgsexpressioncontext.h:120
QgsProcessingAlgorithm::provider
QgsProcessingProvider * provider() const
Returns the provider to which this algorithm belongs.
Definition: qgsprocessingalgorithm.cpp:130
QgsExpression
Class for parsing and evaluation of expressions (formerly called "search strings")....
Definition: qgsexpression.h:102
QgsProcessingParameterField::Any
@ Any
Accepts any field.
Definition: qgsprocessingparameters.h:2947
QgsProcessing::PythonOutputType
PythonOutputType
Available Python output types.
Definition: qgsprocessing.h:62
QgsXmlUtils::writeVariant
static QDomElement writeVariant(const QVariant &value, QDomDocument &doc)
Write a QVariant to a QDomElement.
Definition: qgsxmlutils.cpp:106
QgsProcessingParameterField::dataType
DataType dataType() const
Returns the acceptable data type for the field.
Definition: qgsprocessingparameters.cpp:5725
QgsProcessingParameterDefinition::dependsOnOtherParameters
virtual QStringList dependsOnOtherParameters() const
Returns a list of other parameter names on which this parameter is dependent (e.g.
Definition: qgsprocessingparameters.h:727
QgsExpression::replaceExpressionText
static QString replaceExpressionText(const QString &action, const QgsExpressionContext *context, const QgsDistanceArea *distanceArea=nullptr)
This function replaces each expression between [% and %] in the string with the result of its evaluat...
Definition: qgsexpression.cpp:434
QgsProcessingParameterDefinition::checkValueIsAcceptable
virtual bool checkValueIsAcceptable(const QVariant &input, QgsProcessingContext *context=nullptr) const
Checks whether the specified input value is acceptable for the parameter.
Definition: qgsprocessingparameters.cpp:2432
qgsprocessingregistry.h
Qgis::versionInt
static int versionInt()
Version number used for comparing versions using the "Check QGIS Version" function.
Definition: qgis.cpp:282
QgsProcessingParameterNumber::typeName
static QString typeName()
Returns the type name for the parameter class.
Definition: qgsprocessingparameters.h:2204
QgsProcessing::SourceType
SourceType
Data source types enum.
Definition: qgsprocessing.h:45
QgsProcessingParameterDateTime::typeName
static QString typeName()
Returns the type name for the parameter class.
Definition: qgsprocessingparameters.h:3974
QgsProcessingException
Custom exception class for processing related exceptions.
Definition: qgsexception.h:82
QgsProcessingParameterField
A vector layer or feature source field parameter for processing algorithms.
Definition: qgsprocessingparameters.h:2940
QgsProcessingParameterCrs::typeName
static QString typeName()
Returns the type name for the parameter class.
Definition: qgsprocessingparameters.h:1753
QgsProcessingDestinationParameter::generateTemporaryDestination
virtual QString generateTemporaryDestination() const
Generates a temporary destination value for this parameter.
Definition: qgsprocessingparameters.cpp:6770
QgsProcessingFeedback::pushWarning
virtual void pushWarning(const QString &warning)
Pushes a warning informational message from the algorithm.
Definition: qgsprocessingfeedback.cpp:68
QgsProcessingAlgorithm::parameterDefinition
const QgsProcessingParameterDefinition * parameterDefinition(const QString &name) const
Returns a matching parameter by name.
Definition: qgsprocessingalgorithm.cpp:461
QgsProcessingParameterDatabaseSchema::typeName
static QString typeName()
Returns the type name for the parameter class.
Definition: qgsprocessingparameters.h:4141
QgsProcessingContext::logLevel
LogLevel logLevel() const
Returns the logging level for algorithms to use when pushing feedback messages to users.
Definition: qgsprocessingcontext.cpp:132