QGIS API Documentation 4.0.0-Norrköping (1ddcee3d0e4)
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(
245 const QgsProcessing::PythonOutputType outputType,
246 const QgsStringMap &extraParameters,
247 int currentIndent,
248 int indentSize,
249 const QMap<QString, QString> &friendlyChildNames,
250 const QMap<QString, QString> &friendlyOutputNames
251) const
252{
253 QStringList lines;
254 const QString baseIndent = QString( ' ' ).repeated( currentIndent );
255 const QString lineIndent = QString( ' ' ).repeated( indentSize );
256
257 if ( !algorithm() )
258 return QStringList();
259
260 if ( !description().isEmpty() )
261 lines << baseIndent + u"# %1"_s.arg( description() );
262 if ( !mComment.description().isEmpty() )
263 {
264 const QStringList parts = mComment.description().split( u"\n"_s );
265 for ( const QString &part : parts )
266 {
267 lines << baseIndent + u"# %1"_s.arg( part );
268 }
269 }
270
271 QStringList paramParts;
272 QStringList paramComments;
273 for ( auto paramIt = mParams.constBegin(); paramIt != mParams.constEnd(); ++paramIt )
274 {
275 QStringList sourceParts;
276 QStringList sourceComments;
277 const QgsProcessingParameterDefinition *def = algorithm() ? algorithm()->parameterDefinition( paramIt.key() ) : nullptr;
278 const auto parts = paramIt.value();
279 sourceParts.reserve( parts.size() );
280 sourceComments.reserve( parts.size() );
281 for ( const QgsProcessingModelChildParameterSource &source : parts )
282 {
283 QString part = source.asPythonCode( outputType, def, friendlyChildNames );
284 if ( !part.isEmpty() )
285 {
286 sourceParts << part;
287 sourceComments << source.asPythonComment( def );
288 }
289 }
290 if ( sourceParts.count() == 1 )
291 {
292 paramParts << u"'%1': %2"_s.arg( paramIt.key(), sourceParts.at( 0 ) );
293 paramComments << sourceComments.at( 0 );
294 }
295 else
296 {
297 paramParts << u"'%1': [%2]"_s.arg( paramIt.key(), sourceParts.join( ',' ) );
298 paramComments << QString();
299 }
300 }
301
302 lines << baseIndent + u"alg_params = {"_s;
303 lines.reserve( lines.size() + paramParts.size() );
304 int i = 0;
305 for ( const QString &p : std::as_const( paramParts ) )
306 {
307 QString line = baseIndent + lineIndent + p + ',';
308 if ( !paramComments.value( i ).isEmpty() )
309 {
310 line += u" # %1"_s.arg( paramComments.value( i ) );
311 }
312 lines << line;
313 i++;
314 }
315 for ( auto it = extraParameters.constBegin(); it != extraParameters.constEnd(); ++it )
316 {
317 lines << baseIndent + lineIndent + u"%1: %2,"_s.arg( QgsProcessingUtils::stringToPythonLiteral( it.key() ), it.value() );
318 }
319 if ( lines.constLast().endsWith( ',' ) )
320 {
321 lines[lines.count() - 1].truncate( lines.constLast().length() - 1 );
322 }
323 lines << baseIndent + u"}"_s;
324
325 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 );
326
327 for ( auto outputIt = mModelOutputs.constBegin(); outputIt != mModelOutputs.constEnd(); ++outputIt )
328 {
329 QString outputName = u"%1:%2"_s.arg( mId, outputIt.key() );
330 outputName = friendlyOutputNames.value( outputName, outputName );
331 lines << baseIndent + u"results['%1'] = outputs['%2']['%3']"_s.arg( outputName, friendlyChildNames.value( mId, mId ), outputIt.value().childOutputName() );
332 }
333
334 return lines;
335}
336
337QVariantMap QgsProcessingModelChildAlgorithm::configuration() const
338{
339 return mConfiguration;
340}
341
342void QgsProcessingModelChildAlgorithm::setConfiguration( const QVariantMap &configuration )
343{
344 mConfiguration = configuration;
345 mAlgorithm.reset( QgsApplication::processingRegistry()->createAlgorithmById( mAlgorithmId, mConfiguration ) );
346}
347
348void QgsProcessingModelChildAlgorithm::generateChildId( const QgsProcessingModelAlgorithm &model )
349{
350 int i = 1;
351 QString id;
352 while ( true )
353 {
354 id = u"%1_%2"_s.arg( mAlgorithmId ).arg( i );
355 if ( !model.childAlgorithms().contains( id ) )
356 break;
357 i++;
358 }
359 mId = id;
360}
361
362bool QgsProcessingModelChildAlgorithm::setAlgorithmId( const QString &algorithmId )
363{
364 mAlgorithmId = algorithmId;
365 mAlgorithm.reset( QgsApplication::processingRegistry()->createAlgorithmById( mAlgorithmId, mConfiguration ) );
366 return static_cast< bool >( mAlgorithm.get() );
367}
368
369bool QgsProcessingModelChildAlgorithm::reattach() const
370{
371 return const_cast< QgsProcessingModelChildAlgorithm * >( this )->setAlgorithmId( mAlgorithmId );
372}
373
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:7475