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