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