QGIS API Documentation 3.32.0-Lima (311a8cb8a6)
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"
22
24
25QgsProcessingModelChildAlgorithm::QgsProcessingModelChildAlgorithm( const QString &algorithmId )
26{
27 setAlgorithmId( algorithmId );
28}
29
30QgsProcessingModelChildAlgorithm::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
43QgsProcessingModelChildAlgorithm &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
57QgsProcessingModelChildAlgorithm *QgsProcessingModelChildAlgorithm::clone() const
58{
59 return new QgsProcessingModelChildAlgorithm( *this );
60}
61
62void 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
102void 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
115bool QgsProcessingModelChildAlgorithm::removeModelOutput( const QString &name )
116{
117 mModelOutputs.remove( name );
118 return true;
119}
120
121QVariant 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
163bool 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
233QStringList 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 {
247 const QStringList parts = mComment.description().split( QStringLiteral( "\n" ) );
248 for ( const QString &part : parts )
249 {
250 lines << baseIndent + QStringLiteral( "# %1" ).arg( part );
251 }
252 }
253
254 QStringList paramParts;
255 QStringList paramComments;
256 for ( auto paramIt = mParams.constBegin(); paramIt != mParams.constEnd(); ++paramIt )
257 {
258 QStringList sourceParts;
259 QStringList sourceComments;
260 const QgsProcessingParameterDefinition *def = algorithm() ? algorithm()->parameterDefinition( paramIt.key() ) : nullptr;
261 const auto parts = paramIt.value();
262 sourceParts.reserve( parts.size() );
263 sourceComments.reserve( parts.size() );
264 for ( const QgsProcessingModelChildParameterSource &source : parts )
265 {
266 QString part = source.asPythonCode( outputType, def, friendlyChildNames );
267 if ( !part.isEmpty() )
268 {
269 sourceParts << part;
270 sourceComments << source.asPythonComment( def );
271 }
272 }
273 if ( sourceParts.count() == 1 )
274 {
275 paramParts << QStringLiteral( "'%1': %2" ).arg( paramIt.key(), sourceParts.at( 0 ) );
276 paramComments << sourceComments.at( 0 );
277 }
278 else
279 {
280 paramParts << QStringLiteral( "'%1': [%2]" ).arg( paramIt.key(), sourceParts.join( ',' ) );
281 paramComments << QString();
282 }
283 }
284
285 lines << baseIndent + QStringLiteral( "alg_params = {" );
286 lines.reserve( lines.size() + paramParts.size() );
287 int i = 0;
288 for ( const QString &p : std::as_const( paramParts ) )
289 {
290 QString line = baseIndent + lineIndent + p + ',';
291 if ( !paramComments.value( i ).isEmpty() )
292 {
293 line += QStringLiteral( " # %1" ).arg( paramComments.value( i ) );
294 }
295 lines << line;
296 i++;
297 }
298 for ( auto it = extraParameters.constBegin(); it != extraParameters.constEnd(); ++it )
299 {
300 lines << baseIndent + lineIndent + QStringLiteral( "%1: %2," ).arg( QgsProcessingUtils::stringToPythonLiteral( it.key() ), it.value() );
301 }
302 if ( lines.constLast().endsWith( ',' ) )
303 {
304 lines[ lines.count() - 1 ].truncate( lines.constLast().length() - 1 );
305 }
306 lines << baseIndent + QStringLiteral( "}" );
307
308 lines << baseIndent + QStringLiteral( "outputs['%1'] = processing.run('%2', alg_params, context=context, feedback=feedback, is_child_algorithm=True)" ).arg( friendlyChildNames.value( mId, mId ), mAlgorithmId );
309
310 for ( auto outputIt = mModelOutputs.constBegin(); outputIt != mModelOutputs.constEnd(); ++outputIt )
311 {
312 QString outputName = QStringLiteral( "%1:%2" ).arg( mId, outputIt.key() );
313 outputName = friendlyOutputNames.value( outputName, outputName );
314 lines << baseIndent + QStringLiteral( "results['%1'] = outputs['%2']['%3']" ).arg( outputName, friendlyChildNames.value( mId, mId ), outputIt.value().childOutputName() );
315 }
316
317 return lines;
318}
319
320QVariantMap QgsProcessingModelChildAlgorithm::configuration() const
321{
322 return mConfiguration;
323}
324
325void QgsProcessingModelChildAlgorithm::setConfiguration( const QVariantMap &configuration )
326{
327 mConfiguration = configuration;
328 mAlgorithm.reset( QgsApplication::processingRegistry()->createAlgorithmById( mAlgorithmId, mConfiguration ) );
329}
330
331void QgsProcessingModelChildAlgorithm::generateChildId( const QgsProcessingModelAlgorithm &model )
332{
333 int i = 1;
334 QString id;
335 while ( true )
336 {
337 id = QStringLiteral( "%1_%2" ).arg( mAlgorithmId ).arg( i );
338 if ( !model.childAlgorithms().contains( id ) )
339 break;
340 i++;
341 }
342 mId = id;
343}
344
345bool QgsProcessingModelChildAlgorithm::setAlgorithmId( const QString &algorithmId )
346{
347 mAlgorithmId = algorithmId;
348 mAlgorithm.reset( QgsApplication::processingRegistry()->createAlgorithmById( mAlgorithmId, mConfiguration ) );
349 return static_cast< bool >( mAlgorithm.get() );
350}
351
352bool QgsProcessingModelChildAlgorithm::reattach() const
353{
354 return const_cast< QgsProcessingModelChildAlgorithm * >( this )->setAlgorithmId( mAlgorithmId );
355}
356
static QgsProcessingRegistry * processingRegistry()
Returns the application's processing registry, used for managing processing providers,...
Abstract base class for processing algorithms.
const QgsProcessingParameterDefinition * parameterDefinition(const QString &name) const
Returns a matching parameter by name.
Base class for the definition of processing parameters.
static QString stringToPythonLiteral(const QString &string)
Converts a string to a Python string literal.
PythonOutputType
Available Python output types.
Definition: qgsprocessing.h:65
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
QMap< QString, QString > QgsStringMap
Definition: qgis.h:4533