QGIS API Documentation  3.26.3-Buenos Aires (65e4edfdad)
qgsprocessingmodelchildalgorithm.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsprocessingmodelchildalgorithm.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 "qgsapplication.h"
20 #include "qgsprocessingregistry.h"
22 
24 
25 QgsProcessingModelChildAlgorithm::QgsProcessingModelChildAlgorithm( const QString &algorithmId )
26 {
27  setAlgorithmId( algorithmId );
28 }
29 
30 QgsProcessingModelChildAlgorithm::QgsProcessingModelChildAlgorithm( const QgsProcessingModelChildAlgorithm &other )
31  : QgsProcessingModelComponent( other )
32  , mId( other.mId )
33  , mConfiguration( other.mConfiguration )
34  , mParams( other.mParams )
35  , mModelOutputs( other.mModelOutputs )
36  , mActive( other.mActive )
37  , mDependencies( other.mDependencies )
38  , mComment( other.mComment )
39 {
40  setAlgorithmId( other.algorithmId() );
41 }
42 
43 QgsProcessingModelChildAlgorithm &QgsProcessingModelChildAlgorithm::operator=( const QgsProcessingModelChildAlgorithm &other )
44 {
45  QgsProcessingModelComponent::operator =( other );
46  mId = other.mId;
47  mConfiguration = other.mConfiguration;
48  setAlgorithmId( other.algorithmId() );
49  mParams = other.mParams;
50  mModelOutputs = other.mModelOutputs;
51  mActive = other.mActive;
52  mDependencies = other.mDependencies;
53  mComment = other.mComment;
54  return *this;
55 }
56 
57 QgsProcessingModelChildAlgorithm *QgsProcessingModelChildAlgorithm::clone() const
58 {
59  return new QgsProcessingModelChildAlgorithm( *this );
60 }
61 
62 void QgsProcessingModelChildAlgorithm::copyNonDefinitionPropertiesFromModel( QgsProcessingModelAlgorithm *model )
63 {
64  const QgsProcessingModelChildAlgorithm existingChild = model->childAlgorithm( mId );
65  copyNonDefinitionProperties( existingChild );
66 
67  int i = 0;
68  for ( auto it = mModelOutputs.begin(); it != mModelOutputs.end(); ++it )
69  {
70  const QMap<QString, QgsProcessingModelOutput> existingChildModelOutputs = existingChild.modelOutputs();
71  auto existingOutputIt = existingChildModelOutputs.find( it.key() );
72  if ( existingOutputIt == existingChildModelOutputs.end() )
73  continue;
74 
75  if ( !existingOutputIt->position().isNull() )
76  {
77  it.value().setPosition( existingOutputIt->position() );
78  it.value().setSize( existingOutputIt->size() );
79  }
80  else
81  it.value().setPosition( position() + QPointF( size().width(), ( i + 1.5 ) * size().height() ) );
82 
83  if ( QgsProcessingModelComment *comment = it.value().comment() )
84  {
85  if ( const QgsProcessingModelComment *existingComment = existingOutputIt->comment() )
86  {
87  comment->setDescription( existingComment->description() );
88  comment->setSize( existingComment->size() );
89  comment->setPosition( existingComment->position() );
90  comment->setColor( existingComment->color() );
91  }
92  }
93  i++;
94  }
95 }
96 
98 {
99  return mAlgorithm.get();
100 }
101 
102 void QgsProcessingModelChildAlgorithm::setModelOutputs( const QMap<QString, QgsProcessingModelOutput> &modelOutputs )
103 {
104  mModelOutputs = modelOutputs;
105 
106  QMap<QString, QgsProcessingModelOutput>::iterator outputIt = mModelOutputs.begin();
107  for ( ; outputIt != mModelOutputs.end(); ++outputIt )
108  {
109  // make sure values are consistent
110  outputIt->setName( outputIt.key() );
111  outputIt->setChildId( mId );
112  }
113 }
114 
115 bool QgsProcessingModelChildAlgorithm::removeModelOutput( const QString &name )
116 {
117  mModelOutputs.remove( name );
118  return true;
119 }
120 
121 QVariant QgsProcessingModelChildAlgorithm::toVariant() const
122 {
123  QVariantMap map;
124  map.insert( QStringLiteral( "id" ), mId );
125  map.insert( QStringLiteral( "alg_id" ), mAlgorithmId );
126  map.insert( QStringLiteral( "alg_config" ), mConfiguration );
127  map.insert( QStringLiteral( "active" ), mActive );
128 
129  QVariantList dependencies;
130  for ( const QgsProcessingModelChildDependency &dependency : mDependencies )
131  {
132  dependencies << dependency.toVariant();
133  }
134  map.insert( QStringLiteral( "dependencies" ), dependencies );
135 
136  saveCommonProperties( map );
137 
138  QVariantMap paramMap;
139  QMap< QString, QgsProcessingModelChildParameterSources >::const_iterator paramIt = mParams.constBegin();
140  for ( ; paramIt != mParams.constEnd(); ++paramIt )
141  {
142  QVariantList sources;
143  const auto constValue = paramIt.value();
144  for ( const QgsProcessingModelChildParameterSource &source : constValue )
145  {
146  sources << source.toVariant();
147  }
148  paramMap.insert( paramIt.key(), sources );
149  }
150  map.insert( QStringLiteral( "params" ), paramMap );
151 
152  QVariantMap outputMap;
153  QMap< QString, QgsProcessingModelOutput >::const_iterator outputIt = mModelOutputs.constBegin();
154  for ( ; outputIt != mModelOutputs.constEnd(); ++outputIt )
155  {
156  outputMap.insert( outputIt.key(), outputIt.value().toVariant() );
157  }
158  map.insert( QStringLiteral( "outputs" ), outputMap );
159 
160  return map;
161 }
162 
163 bool QgsProcessingModelChildAlgorithm::loadVariant( const QVariant &child )
164 {
165  QVariantMap map = child.toMap();
166 
167  mId = map.value( QStringLiteral( "id" ) ).toString();
168  if ( mId.isEmpty() )
169  return false;
170 
171  mConfiguration = map.value( QStringLiteral( "alg_config" ) ).toMap();
172  setAlgorithmId( map.value( QStringLiteral( "alg_id" ) ).toString() );
173  if ( algorithmId().isEmpty() )
174  return false;
175  mActive = map.value( QStringLiteral( "active" ) ).toBool();
176 
177  mDependencies.clear();
178  if ( map.value( QStringLiteral( "dependencies" ) ).type() == QVariant::StringList )
179  {
180  const QStringList dependencies = map.value( QStringLiteral( "dependencies" ) ).toStringList();
181  for ( const QString &dependency : dependencies )
182  {
183  QgsProcessingModelChildDependency dep;
184  dep.childId = dependency;
185  mDependencies << dep;
186  }
187  }
188  else
189  {
190  const QVariantList dependencies = map.value( QStringLiteral( "dependencies" ) ).toList();
191  for ( const QVariant &dependency : dependencies )
192  {
193  QgsProcessingModelChildDependency dep;
194  dep.loadVariant( dependency.toMap() );
195  mDependencies << dep;
196  }
197  }
198 
199  restoreCommonProperties( map );
200 
201  mParams.clear();
202  QVariantMap paramMap = map.value( QStringLiteral( "params" ) ).toMap();
203  QVariantMap::const_iterator paramIt = paramMap.constBegin();
204  for ( ; paramIt != paramMap.constEnd(); ++paramIt )
205  {
206  QgsProcessingModelChildParameterSources sources;
207  const auto constToList = paramIt->toList();
208  for ( const QVariant &sourceVar : constToList )
209  {
210  QgsProcessingModelChildParameterSource param;
211  if ( !param.loadVariant( sourceVar.toMap() ) )
212  return false;
213  sources << param;
214  }
215  mParams.insert( paramIt.key(), sources );
216  }
217 
218  mModelOutputs.clear();
219  QVariantMap outputMap = map.value( QStringLiteral( "outputs" ) ).toMap();
220  QVariantMap::const_iterator outputIt = outputMap.constBegin();
221  for ( ; outputIt != outputMap.constEnd(); ++outputIt )
222  {
223  QgsProcessingModelOutput output;
224  if ( !output.loadVariant( outputIt.value().toMap() ) )
225  return false;
226 
227  mModelOutputs.insert( outputIt.key(), output );
228  }
229 
230  return true;
231 }
232 
233 QStringList QgsProcessingModelChildAlgorithm::asPythonCode( const QgsProcessing::PythonOutputType outputType, const QgsStringMap &extraParameters,
234  int currentIndent, int indentSize, const QMap<QString, QString> &friendlyChildNames, const QMap<QString, QString> &friendlyOutputNames ) const
235 {
236  QStringList lines;
237  const QString baseIndent = QString( ' ' ).repeated( currentIndent );
238  const QString lineIndent = QString( ' ' ).repeated( indentSize );
239 
240  if ( !algorithm() )
241  return QStringList();
242 
243  if ( !description().isEmpty() )
244  lines << baseIndent + QStringLiteral( "# %1" ).arg( description() );
245  if ( !mComment.description().isEmpty() )
246  lines << baseIndent + QStringLiteral( "# %1" ).arg( mComment.description() );
247 
248  QStringList paramParts;
249  QStringList paramComments;
250  for ( auto paramIt = mParams.constBegin(); paramIt != mParams.constEnd(); ++paramIt )
251  {
252  QStringList sourceParts;
253  QStringList sourceComments;
254  const QgsProcessingParameterDefinition *def = algorithm() ? algorithm()->parameterDefinition( paramIt.key() ) : nullptr;
255  const auto parts = paramIt.value();
256  sourceParts.reserve( parts.size() );
257  sourceComments.reserve( parts.size() );
258  for ( const QgsProcessingModelChildParameterSource &source : parts )
259  {
260  QString part = source.asPythonCode( outputType, def, friendlyChildNames );
261  if ( !part.isEmpty() )
262  {
263  sourceParts << part;
264  sourceComments << source.asPythonComment( def );
265  }
266  }
267  if ( sourceParts.count() == 1 )
268  {
269  paramParts << QStringLiteral( "'%1': %2" ).arg( paramIt.key(), sourceParts.at( 0 ) );
270  paramComments << sourceComments.at( 0 );
271  }
272  else
273  {
274  paramParts << QStringLiteral( "'%1': [%2]" ).arg( paramIt.key(), sourceParts.join( ',' ) );
275  paramComments << QString();
276  }
277  }
278 
279  lines << baseIndent + QStringLiteral( "alg_params = {" );
280  lines.reserve( lines.size() + paramParts.size() );
281  int i = 0;
282  for ( const QString &p : std::as_const( paramParts ) )
283  {
284  QString line = baseIndent + lineIndent + p + ',';
285  if ( !paramComments.value( i ).isEmpty() )
286  {
287  line += QStringLiteral( " # %1" ).arg( paramComments.value( i ) );
288  }
289  lines << line;
290  i++;
291  }
292  for ( auto it = extraParameters.constBegin(); it != extraParameters.constEnd(); ++it )
293  {
294  lines << baseIndent + lineIndent + QStringLiteral( "%1: %2," ).arg( QgsProcessingUtils::stringToPythonLiteral( it.key() ), it.value() );
295  }
296  if ( lines.constLast().endsWith( ',' ) )
297  {
298  lines[ lines.count() - 1 ].truncate( lines.constLast().length() - 1 );
299  }
300  lines << baseIndent + QStringLiteral( "}" );
301 
302  lines << baseIndent + QStringLiteral( "outputs['%1'] = processing.run('%2', alg_params, context=context, feedback=feedback, is_child_algorithm=True)" ).arg( friendlyChildNames.value( mId, mId ), mAlgorithmId );
303 
304  for ( auto outputIt = mModelOutputs.constBegin(); outputIt != mModelOutputs.constEnd(); ++outputIt )
305  {
306  QString outputName = QStringLiteral( "%1:%2" ).arg( mId, outputIt.key() );
307  outputName = friendlyOutputNames.value( outputName, outputName );
308  lines << baseIndent + QStringLiteral( "results['%1'] = outputs['%2']['%3']" ).arg( outputName, friendlyChildNames.value( mId, mId ), outputIt.value().childOutputName() );
309  }
310 
311  return lines;
312 }
313 
314 QVariantMap QgsProcessingModelChildAlgorithm::configuration() const
315 {
316  return mConfiguration;
317 }
318 
319 void QgsProcessingModelChildAlgorithm::setConfiguration( const QVariantMap &configuration )
320 {
321  mConfiguration = configuration;
322  mAlgorithm.reset( QgsApplication::processingRegistry()->createAlgorithmById( mAlgorithmId, mConfiguration ) );
323 }
324 
325 void QgsProcessingModelChildAlgorithm::generateChildId( const QgsProcessingModelAlgorithm &model )
326 {
327  int i = 1;
328  QString id;
329  while ( true )
330  {
331  id = QStringLiteral( "%1_%2" ).arg( mAlgorithmId ).arg( i );
332  if ( !model.childAlgorithms().contains( id ) )
333  break;
334  i++;
335  }
336  mId = id;
337 }
338 
339 bool QgsProcessingModelChildAlgorithm::setAlgorithmId( const QString &algorithmId )
340 {
341  mAlgorithmId = algorithmId;
342  mAlgorithm.reset( QgsApplication::processingRegistry()->createAlgorithmById( mAlgorithmId, mConfiguration ) );
343  return static_cast< bool >( mAlgorithm.get() );
344 }
345 
346 bool QgsProcessingModelChildAlgorithm::reattach() const
347 {
348  return const_cast< QgsProcessingModelChildAlgorithm * >( this )->setAlgorithmId( mAlgorithmId );
349 }
350 
QgsApplication::processingRegistry
static QgsProcessingRegistry * processingRegistry()
Returns the application's processing registry, used for managing processing providers,...
Definition: qgsapplication.cpp:2455
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
qgsprocessingmodelalgorithm.h
QgsProcessingParameterDefinition
Base class for the definition of processing parameters.
Definition: qgsprocessingparameters.h:334
QgsProcessingUtils::stringToPythonLiteral
static QString stringToPythonLiteral(const QString &string)
Converts a string to a Python string literal.
Definition: qgsprocessingutils.cpp:701
qgsapplication.h
qgsprocessingmodelchildalgorithm.h
QgsStringMap
QMap< QString, QString > QgsStringMap
Definition: qgis.h:2781
QgsProcessingAlgorithm
Abstract base class for processing algorithms.
Definition: qgsprocessingalgorithm.h:52
QgsProcessing::PythonOutputType
PythonOutputType
Available Python output types.
Definition: qgsprocessing.h:62
qgsprocessingregistry.h
QgsProcessingAlgorithm::parameterDefinition
const QgsProcessingParameterDefinition * parameterDefinition(const QString &name) const
Returns a matching parameter by name.
Definition: qgsprocessingalgorithm.cpp:461