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