Branch data Line data Source code
1 : : /***************************************************************************
2 : : qgsprocessingalgorithm.cpp
3 : : --------------------------
4 : : begin : December 2016
5 : : copyright : (C) 2016 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 "qgsprocessingalgorithm.h"
19 : : #include "qgsapplication.h"
20 : : #include "qgsprocessingprovider.h"
21 : : #include "qgsprocessingparameters.h"
22 : : #include "qgsprocessingoutputs.h"
23 : : #include "qgsrectangle.h"
24 : : #include "qgsprocessingcontext.h"
25 : : #include "qgsprocessingutils.h"
26 : : #include "qgsexception.h"
27 : : #include "qgsmessagelog.h"
28 : : #include "qgsvectorlayer.h"
29 : : #include "qgsprocessingfeedback.h"
30 : : #include "qgsmeshlayer.h"
31 : : #include "qgsexpressioncontextutils.h"
32 : :
33 : :
34 : 0 : QgsProcessingAlgorithm::~QgsProcessingAlgorithm()
35 : 0 : {
36 : 0 : qDeleteAll( mParameters );
37 : 0 : qDeleteAll( mOutputs );
38 : 0 : }
39 : :
40 : 0 : QgsProcessingAlgorithm *QgsProcessingAlgorithm::create( const QVariantMap &configuration ) const
41 : : {
42 : 0 : std::unique_ptr< QgsProcessingAlgorithm > creation( createInstance() );
43 : 0 : if ( ! creation )
44 : 0 : throw QgsProcessingException( QObject::tr( "Error creating algorithm from createInstance()" ) );
45 : 0 : creation->setProvider( provider() );
46 : 0 : creation->initAlgorithm( configuration );
47 : 0 : return creation.release();
48 : 0 : }
49 : :
50 : 0 : QString QgsProcessingAlgorithm::id() const
51 : : {
52 : 0 : if ( mProvider )
53 : 0 : return QStringLiteral( "%1:%2" ).arg( mProvider->id(), name() );
54 : : else
55 : 0 : return name();
56 : 0 : }
57 : :
58 : 0 : QString QgsProcessingAlgorithm::shortDescription() const
59 : : {
60 : 0 : return QString();
61 : : }
62 : :
63 : 0 : QString QgsProcessingAlgorithm::shortHelpString() const
64 : : {
65 : 0 : return QString();
66 : : }
67 : :
68 : 0 : QString QgsProcessingAlgorithm::helpString() const
69 : : {
70 : 0 : return QString();
71 : : }
72 : :
73 : 0 : QString QgsProcessingAlgorithm::helpUrl() const
74 : : {
75 : 0 : return QString();
76 : : }
77 : :
78 : 0 : QIcon QgsProcessingAlgorithm::icon() const
79 : : {
80 : 0 : return QgsApplication::getThemeIcon( "/processingAlgorithm.svg" );
81 : 0 : }
82 : :
83 : 0 : QString QgsProcessingAlgorithm::svgIconPath() const
84 : : {
85 : 0 : return QgsApplication::iconPath( QStringLiteral( "processingAlgorithm.svg" ) );
86 : 0 : }
87 : :
88 : 0 : QgsProcessingAlgorithm::Flags QgsProcessingAlgorithm::flags() const
89 : : {
90 : 0 : return FlagSupportsBatch | FlagCanCancel;
91 : : }
92 : :
93 : 0 : bool QgsProcessingAlgorithm::canExecute( QString * ) const
94 : : {
95 : 0 : return true;
96 : : }
97 : :
98 : 0 : bool QgsProcessingAlgorithm::checkParameterValues( const QVariantMap ¶meters, QgsProcessingContext &context, QString *message ) const
99 : : {
100 : 0 : for ( const QgsProcessingParameterDefinition *def : mParameters )
101 : : {
102 : 0 : if ( !def->checkValueIsAcceptable( parameters.value( def->name() ), &context ) )
103 : : {
104 : 0 : if ( message )
105 : : {
106 : : // TODO QGIS 4 - move the message handling to the parameter subclasses (but this
107 : : // requires a change in signature for the virtual checkValueIsAcceptable method)
108 : 0 : if ( def->type() == QgsProcessingParameterFeatureSource::typeName() )
109 : 0 : *message = invalidSourceError( parameters, def->name() );
110 : 0 : else if ( def->type() == QgsProcessingParameterFeatureSink::typeName() )
111 : 0 : *message = invalidSinkError( parameters, def->name() );
112 : 0 : else if ( def->type() == QgsProcessingParameterRasterLayer::typeName() )
113 : 0 : *message = invalidRasterError( parameters, def->name() );
114 : : else
115 : 0 : *message = QObject::tr( "Incorrect parameter value for %1" ).arg( def->name() );
116 : 0 : }
117 : 0 : return false;
118 : : }
119 : : }
120 : 0 : return true;
121 : 0 : }
122 : :
123 : 0 : QVariantMap QgsProcessingAlgorithm::preprocessParameters( const QVariantMap ¶meters )
124 : : {
125 : 0 : return parameters;
126 : : }
127 : :
128 : 0 : QgsProcessingProvider *QgsProcessingAlgorithm::provider() const
129 : : {
130 : 0 : return mProvider;
131 : : }
132 : :
133 : 0 : void QgsProcessingAlgorithm::setProvider( QgsProcessingProvider *provider )
134 : : {
135 : 0 : mProvider = provider;
136 : :
137 : 0 : if ( mProvider && !mProvider->supportsNonFileBasedOutput() )
138 : : {
139 : : // need to update all destination parameters to turn off non file based outputs
140 : 0 : for ( const QgsProcessingParameterDefinition *definition : std::as_const( mParameters ) )
141 : : {
142 : 0 : if ( definition->isDestination() )
143 : : {
144 : 0 : const QgsProcessingDestinationParameter *destParam = static_cast< const QgsProcessingDestinationParameter *>( definition );
145 : 0 : const_cast< QgsProcessingDestinationParameter *>( destParam )->setSupportsNonFileBasedOutput( false );
146 : 0 : }
147 : : }
148 : 0 : }
149 : 0 : }
150 : :
151 : 0 : QWidget *QgsProcessingAlgorithm::createCustomParametersWidget( QWidget * ) const
152 : : {
153 : 0 : return nullptr;
154 : : }
155 : :
156 : 0 : QgsExpressionContext QgsProcessingAlgorithm::createExpressionContext( const QVariantMap ¶meters,
157 : : QgsProcessingContext &context, QgsProcessingFeatureSource *source ) const
158 : : {
159 : : // start with context's expression context
160 : 0 : QgsExpressionContext c = context.expressionContext();
161 : :
162 : : // If there's a source capable of generating a context scope, use it
163 : 0 : if ( source )
164 : : {
165 : 0 : QgsExpressionContextScope *scope = source->createExpressionContextScope();
166 : 0 : if ( scope )
167 : 0 : c << scope;
168 : 0 : }
169 : 0 : else if ( c.scopeCount() == 0 )
170 : : {
171 : : //empty scope, populate with initial scopes
172 : 0 : c << QgsExpressionContextUtils::globalScope()
173 : 0 : << QgsExpressionContextUtils::projectScope( context.project() );
174 : 0 : }
175 : :
176 : 0 : c << QgsExpressionContextUtils::processingAlgorithmScope( this, parameters, context );
177 : 0 : return c;
178 : 0 : }
179 : :
180 : 0 : bool QgsProcessingAlgorithm::validateInputCrs( const QVariantMap ¶meters, QgsProcessingContext &context ) const
181 : : {
182 : 0 : if ( !( flags() & FlagRequiresMatchingCrs ) )
183 : : {
184 : : // I'm a well behaved algorithm - I take work AWAY from users!
185 : 0 : return true;
186 : : }
187 : :
188 : 0 : bool foundCrs = false;
189 : 0 : QgsCoordinateReferenceSystem crs;
190 : 0 : for ( const QgsProcessingParameterDefinition *def : mParameters )
191 : : {
192 : 0 : if ( def->type() == QgsProcessingParameterMapLayer::typeName() || def->type() == QgsProcessingParameterRasterLayer::typeName() )
193 : : {
194 : 0 : QgsMapLayer *layer = QgsProcessingParameters::parameterAsLayer( def, parameters, context );
195 : 0 : if ( layer )
196 : : {
197 : 0 : if ( foundCrs && layer->crs().isValid() && crs != layer->crs() )
198 : : {
199 : 0 : return false;
200 : : }
201 : 0 : else if ( !foundCrs && layer->crs().isValid() )
202 : : {
203 : 0 : foundCrs = true;
204 : 0 : crs = layer->crs();
205 : 0 : }
206 : 0 : }
207 : 0 : }
208 : 0 : else if ( def->type() == QgsProcessingParameterFeatureSource::typeName() )
209 : : {
210 : 0 : std::unique_ptr< QgsFeatureSource > source( QgsProcessingParameters::parameterAsSource( def, parameters, context ) );
211 : 0 : if ( source )
212 : : {
213 : 0 : if ( foundCrs && source->sourceCrs().isValid() && crs != source->sourceCrs() )
214 : : {
215 : 0 : return false;
216 : : }
217 : 0 : else if ( !foundCrs && source->sourceCrs().isValid() )
218 : : {
219 : 0 : foundCrs = true;
220 : 0 : crs = source->sourceCrs();
221 : 0 : }
222 : 0 : }
223 : 0 : }
224 : 0 : else if ( def->type() == QgsProcessingParameterMultipleLayers::typeName() )
225 : : {
226 : 0 : QList< QgsMapLayer *> layers = QgsProcessingParameters::parameterAsLayerList( def, parameters, context );
227 : 0 : const auto constLayers = layers;
228 : 0 : for ( QgsMapLayer *layer : constLayers )
229 : : {
230 : 0 : if ( !layer )
231 : 0 : continue;
232 : :
233 : 0 : if ( foundCrs && layer->crs().isValid() && crs != layer->crs() )
234 : : {
235 : 0 : return false;
236 : : }
237 : 0 : else if ( !foundCrs && layer->crs().isValid() )
238 : : {
239 : 0 : foundCrs = true;
240 : 0 : crs = layer->crs();
241 : 0 : }
242 : : }
243 : 0 : }
244 : 0 : else if ( def->type() == QgsProcessingParameterExtent::typeName() )
245 : : {
246 : 0 : QgsCoordinateReferenceSystem extentCrs = QgsProcessingParameters::parameterAsExtentCrs( def, parameters, context );
247 : 0 : if ( foundCrs && extentCrs.isValid() && crs != extentCrs )
248 : : {
249 : 0 : return false;
250 : : }
251 : 0 : else if ( !foundCrs && extentCrs.isValid() )
252 : : {
253 : 0 : foundCrs = true;
254 : 0 : crs = extentCrs;
255 : 0 : }
256 : 0 : }
257 : 0 : else if ( def->type() == QgsProcessingParameterPoint::typeName() )
258 : : {
259 : 0 : QgsCoordinateReferenceSystem pointCrs = QgsProcessingParameters::parameterAsPointCrs( def, parameters, context );
260 : 0 : if ( foundCrs && pointCrs.isValid() && crs != pointCrs )
261 : : {
262 : 0 : return false;
263 : : }
264 : 0 : else if ( !foundCrs && pointCrs.isValid() )
265 : : {
266 : 0 : foundCrs = true;
267 : 0 : crs = pointCrs;
268 : 0 : }
269 : 0 : }
270 : 0 : else if ( def->type() == QgsProcessingParameterGeometry::typeName() )
271 : : {
272 : 0 : QgsCoordinateReferenceSystem geomCrs = QgsProcessingParameters::parameterAsGeometryCrs( def, parameters, context );
273 : 0 : if ( foundCrs && geomCrs.isValid() && crs != geomCrs )
274 : : {
275 : 0 : return false;
276 : : }
277 : 0 : else if ( !foundCrs && geomCrs.isValid() )
278 : : {
279 : 0 : foundCrs = true;
280 : 0 : crs = geomCrs;
281 : 0 : }
282 : 0 : }
283 : :
284 : : }
285 : 0 : return true;
286 : 0 : }
287 : :
288 : 0 : QString QgsProcessingAlgorithm::asPythonCommand( const QVariantMap ¶meters, QgsProcessingContext &context ) const
289 : : {
290 : 0 : QString s = QStringLiteral( "processing.run(\"%1\"," ).arg( id() );
291 : :
292 : 0 : QStringList parts;
293 : 0 : for ( const QgsProcessingParameterDefinition *def : mParameters )
294 : : {
295 : 0 : if ( def->flags() & QgsProcessingParameterDefinition::FlagHidden )
296 : 0 : continue;
297 : :
298 : 0 : if ( !parameters.contains( def->name() ) )
299 : 0 : continue;
300 : :
301 : 0 : parts << QStringLiteral( "'%1':%2" ).arg( def->name(), def->valueAsPythonString( parameters.value( def->name() ), context ) );
302 : : }
303 : :
304 : 0 : s += QStringLiteral( " {%1})" ).arg( parts.join( ',' ) );
305 : 0 : return s;
306 : 0 : }
307 : :
308 : 0 : bool QgsProcessingAlgorithm::addParameter( QgsProcessingParameterDefinition *definition, bool createOutput )
309 : : {
310 : 0 : if ( !definition )
311 : 0 : return false;
312 : :
313 : : // check for duplicate named parameters
314 : 0 : const QgsProcessingParameterDefinition *existingDef = QgsProcessingAlgorithm::parameterDefinition( definition->name() );
315 : 0 : if ( existingDef && existingDef->name() == definition->name() ) // parameterDefinition is case-insensitive, but we DO allow case-different duplicate names
316 : : {
317 : 0 : QgsMessageLog::logMessage( QObject::tr( "Duplicate parameter %1 registered for alg %2" ).arg( definition->name(), id() ), QObject::tr( "Processing" ) );
318 : 0 : delete definition;
319 : 0 : return false;
320 : : }
321 : :
322 : 0 : if ( definition->isDestination() && mProvider )
323 : : {
324 : 0 : QgsProcessingDestinationParameter *destParam = static_cast< QgsProcessingDestinationParameter *>( definition );
325 : 0 : if ( !mProvider->supportsNonFileBasedOutput() )
326 : 0 : destParam->setSupportsNonFileBasedOutput( false );
327 : 0 : }
328 : :
329 : 0 : mParameters << definition;
330 : 0 : definition->mAlgorithm = this;
331 : :
332 : 0 : if ( createOutput )
333 : 0 : return createAutoOutputForParameter( definition );
334 : : else
335 : 0 : return true;
336 : 0 : }
337 : :
338 : 0 : void QgsProcessingAlgorithm::removeParameter( const QString &name )
339 : : {
340 : 0 : const QgsProcessingParameterDefinition *def = parameterDefinition( name );
341 : 0 : if ( def )
342 : : {
343 : 0 : delete def;
344 : 0 : mParameters.removeAll( def );
345 : :
346 : : // remove output automatically created when adding parameter
347 : 0 : const QgsProcessingOutputDefinition *outputDef = QgsProcessingAlgorithm::outputDefinition( name );
348 : 0 : if ( outputDef && outputDef->autoCreated() )
349 : : {
350 : 0 : delete outputDef;
351 : 0 : mOutputs.removeAll( outputDef );
352 : 0 : }
353 : 0 : }
354 : 0 : }
355 : :
356 : 0 : bool QgsProcessingAlgorithm::addOutput( QgsProcessingOutputDefinition *definition )
357 : : {
358 : 0 : if ( !definition )
359 : 0 : return false;
360 : :
361 : : // check for duplicate named outputs
362 : 0 : if ( QgsProcessingAlgorithm::outputDefinition( definition->name() ) )
363 : : {
364 : 0 : QgsMessageLog::logMessage( QObject::tr( "Duplicate output %1 registered for alg %2" ).arg( definition->name(), id() ), QObject::tr( "Processing" ) );
365 : 0 : delete definition;
366 : 0 : return false;
367 : : }
368 : :
369 : 0 : mOutputs << definition;
370 : 0 : return true;
371 : 0 : }
372 : :
373 : 0 : bool QgsProcessingAlgorithm::prepareAlgorithm( const QVariantMap &, QgsProcessingContext &, QgsProcessingFeedback * )
374 : : {
375 : 0 : return true;
376 : : }
377 : :
378 : 0 : QVariantMap QgsProcessingAlgorithm::postProcessAlgorithm( QgsProcessingContext &, QgsProcessingFeedback * )
379 : : {
380 : 0 : return QVariantMap();
381 : : }
382 : :
383 : 0 : const QgsProcessingParameterDefinition *QgsProcessingAlgorithm::parameterDefinition( const QString &name ) const
384 : : {
385 : : // first pass - case sensitive match
386 : 0 : for ( const QgsProcessingParameterDefinition *def : mParameters )
387 : : {
388 : 0 : if ( def->name() == name )
389 : 0 : return def;
390 : : }
391 : :
392 : : // second pass - case insensitive
393 : 0 : for ( const QgsProcessingParameterDefinition *def : mParameters )
394 : : {
395 : 0 : if ( def->name().compare( name, Qt::CaseInsensitive ) == 0 )
396 : 0 : return def;
397 : : }
398 : 0 : return nullptr;
399 : 0 : }
400 : :
401 : 0 : int QgsProcessingAlgorithm::countVisibleParameters() const
402 : : {
403 : 0 : int count = 0;
404 : 0 : for ( const QgsProcessingParameterDefinition *def : mParameters )
405 : : {
406 : 0 : if ( !( def->flags() & QgsProcessingParameterDefinition::FlagHidden ) )
407 : 0 : count++;
408 : : }
409 : 0 : return count;
410 : : }
411 : :
412 : 0 : QgsProcessingParameterDefinitions QgsProcessingAlgorithm::destinationParameterDefinitions() const
413 : : {
414 : 0 : QgsProcessingParameterDefinitions result;
415 : 0 : for ( const QgsProcessingParameterDefinition *def : mParameters )
416 : : {
417 : 0 : if ( def->isDestination() )
418 : 0 : result << def;
419 : : }
420 : 0 : return result;
421 : 0 : }
422 : :
423 : 0 : const QgsProcessingOutputDefinition *QgsProcessingAlgorithm::outputDefinition( const QString &name ) const
424 : : {
425 : 0 : for ( const QgsProcessingOutputDefinition *def : mOutputs )
426 : : {
427 : 0 : if ( def->name().compare( name, Qt::CaseInsensitive ) == 0 )
428 : 0 : return def;
429 : : }
430 : 0 : return nullptr;
431 : 0 : }
432 : :
433 : 0 : bool QgsProcessingAlgorithm::hasHtmlOutputs() const
434 : : {
435 : 0 : for ( const QgsProcessingOutputDefinition *def : mOutputs )
436 : : {
437 : 0 : if ( def->type() == QLatin1String( "outputHtml" ) )
438 : 0 : return true;
439 : : }
440 : 0 : return false;
441 : 0 : }
442 : :
443 : 0 : QgsProcessingAlgorithm::VectorProperties QgsProcessingAlgorithm::sinkProperties( const QString &, const QVariantMap &, QgsProcessingContext &, const QMap<QString, QgsProcessingAlgorithm::VectorProperties> & ) const
444 : : {
445 : 0 : return VectorProperties();
446 : : }
447 : :
448 : 0 : QVariantMap QgsProcessingAlgorithm::run( const QVariantMap ¶meters, QgsProcessingContext &context, QgsProcessingFeedback *feedback, bool *ok, const QVariantMap &configuration, bool catchExceptions ) const
449 : : {
450 : 0 : std::unique_ptr< QgsProcessingAlgorithm > alg( create( configuration ) );
451 : 0 : if ( ok )
452 : 0 : *ok = false;
453 : :
454 : 0 : bool res = alg->prepare( parameters, context, feedback );
455 : 0 : if ( !res )
456 : 0 : return QVariantMap();
457 : :
458 : 0 : QVariantMap runRes;
459 : : try
460 : : {
461 : 0 : runRes = alg->runPrepared( parameters, context, feedback );
462 : 0 : }
463 : : catch ( QgsProcessingException &e )
464 : : {
465 : 0 : if ( !catchExceptions )
466 : 0 : throw e;
467 : :
468 : 0 : QgsMessageLog::logMessage( e.what(), QObject::tr( "Processing" ), Qgis::Critical );
469 : 0 : feedback->reportError( e.what() );
470 : 0 : return QVariantMap();
471 : 0 : }
472 : :
473 : 0 : if ( ok )
474 : 0 : *ok = true;
475 : :
476 : 0 : QVariantMap ppRes = alg->postProcess( context, feedback );
477 : 0 : if ( !ppRes.isEmpty() )
478 : 0 : return ppRes;
479 : : else
480 : 0 : return runRes;
481 : 0 : }
482 : :
483 : 0 : bool QgsProcessingAlgorithm::prepare( const QVariantMap ¶meters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
484 : : {
485 : : Q_ASSERT_X( QThread::currentThread() == context.temporaryLayerStore()->thread(), "QgsProcessingAlgorithm::prepare", "prepare() must be called from the same thread as context was created in" );
486 : : Q_ASSERT_X( !mHasPrepared, "QgsProcessingAlgorithm::prepare", "prepare() has already been called for the algorithm instance" );
487 : : try
488 : : {
489 : 0 : mHasPrepared = prepareAlgorithm( parameters, context, feedback );
490 : 0 : return mHasPrepared;
491 : 0 : }
492 : : catch ( QgsProcessingException &e )
493 : : {
494 : 0 : QgsMessageLog::logMessage( e.what(), QObject::tr( "Processing" ), Qgis::Critical );
495 : 0 : feedback->reportError( e.what() );
496 : 0 : return false;
497 : 0 : }
498 : 0 : }
499 : :
500 : 0 : QVariantMap QgsProcessingAlgorithm::runPrepared( const QVariantMap ¶meters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
501 : : {
502 : : Q_ASSERT_X( mHasPrepared, "QgsProcessingAlgorithm::runPrepared", QStringLiteral( "prepare() was not called for the algorithm instance %1" ).arg( name() ).toLatin1() );
503 : : Q_ASSERT_X( !mHasExecuted, "QgsProcessingAlgorithm::runPrepared", "runPrepared() was already called for this algorithm instance" );
504 : :
505 : : // Hey kids, let's all be thread safe! It's the fun thing to do!
506 : : //
507 : : // First, let's see if we're going to run into issues.
508 : 0 : QgsProcessingContext *runContext = nullptr;
509 : 0 : if ( context.thread() == QThread::currentThread() )
510 : : {
511 : : // OH. No issues. Seems you're running everything in the same thread, so go about your business. Sorry about
512 : : // the intrusion, we're just making sure everything's nice and safe here. We like to keep a clean and tidy neighbourhood,
513 : : // you know, for the kids and dogs and all.
514 : 0 : runContext = &context;
515 : 0 : }
516 : : else
517 : : {
518 : : // HA! I knew things looked a bit suspicious - seems you're running this algorithm in a different thread
519 : : // from that which the passed context has an affinity for. That's fine and all, but we need to make sure
520 : : // we proceed safely...
521 : :
522 : : // So first we create a temporary local context with affinity for the current thread
523 : 0 : mLocalContext.reset( new QgsProcessingContext() );
524 : : // copy across everything we can safely do from the passed context
525 : 0 : mLocalContext->copyThreadSafeSettings( context );
526 : : // and we'll run the actual algorithm processing using the local thread safe context
527 : 0 : runContext = mLocalContext.get();
528 : : }
529 : :
530 : : try
531 : : {
532 : 0 : QVariantMap runResults = processAlgorithm( parameters, *runContext, feedback );
533 : :
534 : 0 : mHasExecuted = true;
535 : 0 : if ( mLocalContext )
536 : : {
537 : : // ok, time to clean things up. We need to push the temporary context back into
538 : : // the thread that the passed context is associated with (we can only push from the
539 : : // current thread, so we HAVE to do this here)
540 : 0 : mLocalContext->pushToThread( context.thread() );
541 : 0 : }
542 : 0 : return runResults;
543 : 0 : }
544 : : catch ( QgsProcessingException & )
545 : : {
546 : 0 : if ( mLocalContext )
547 : : {
548 : : // see above!
549 : 0 : mLocalContext->pushToThread( context.thread() );
550 : 0 : }
551 : : //rethrow
552 : 0 : throw;
553 : 0 : }
554 : 0 : }
555 : :
556 : 0 : QVariantMap QgsProcessingAlgorithm::postProcess( QgsProcessingContext &context, QgsProcessingFeedback *feedback )
557 : : {
558 : : Q_ASSERT_X( QThread::currentThread() == context.temporaryLayerStore()->thread(), "QgsProcessingAlgorithm::postProcess", "postProcess() must be called from the same thread the context was created in" );
559 : : Q_ASSERT_X( mHasExecuted, "QgsProcessingAlgorithm::postProcess", QStringLiteral( "algorithm instance %1 was not executed" ).arg( name() ).toLatin1() );
560 : : Q_ASSERT_X( !mHasPostProcessed, "QgsProcessingAlgorithm::postProcess", "postProcess() was already called for this algorithm instance" );
561 : :
562 : 0 : if ( mLocalContext )
563 : : {
564 : : // algorithm was processed using a temporary thread safe context. So now we need
565 : : // to take the results from that temporary context, and smash them into the passed
566 : : // context
567 : 0 : context.takeResultsFrom( *mLocalContext );
568 : : // now get lost, we don't need you anymore
569 : 0 : mLocalContext.reset();
570 : 0 : }
571 : :
572 : 0 : mHasPostProcessed = true;
573 : : try
574 : : {
575 : 0 : return postProcessAlgorithm( context, feedback );
576 : 0 : }
577 : : catch ( QgsProcessingException &e )
578 : : {
579 : 0 : QgsMessageLog::logMessage( e.what(), QObject::tr( "Processing" ), Qgis::Critical );
580 : 0 : feedback->reportError( e.what() );
581 : 0 : return QVariantMap();
582 : 0 : }
583 : 0 : }
584 : :
585 : 0 : QString QgsProcessingAlgorithm::parameterAsString( const QVariantMap ¶meters, const QString &name, const QgsProcessingContext &context ) const
586 : : {
587 : 0 : return QgsProcessingParameters::parameterAsString( parameterDefinition( name ), parameters, context );
588 : : }
589 : :
590 : 0 : QString QgsProcessingAlgorithm::parameterAsExpression( const QVariantMap ¶meters, const QString &name, const QgsProcessingContext &context ) const
591 : : {
592 : 0 : return QgsProcessingParameters::parameterAsExpression( parameterDefinition( name ), parameters, context );
593 : : }
594 : :
595 : 0 : double QgsProcessingAlgorithm::parameterAsDouble( const QVariantMap ¶meters, const QString &name, const QgsProcessingContext &context ) const
596 : : {
597 : 0 : return QgsProcessingParameters::parameterAsDouble( parameterDefinition( name ), parameters, context );
598 : : }
599 : :
600 : 0 : int QgsProcessingAlgorithm::parameterAsInt( const QVariantMap ¶meters, const QString &name, const QgsProcessingContext &context ) const
601 : : {
602 : 0 : return QgsProcessingParameters::parameterAsInt( parameterDefinition( name ), parameters, context );
603 : : }
604 : :
605 : 0 : QList<int> QgsProcessingAlgorithm::parameterAsInts( const QVariantMap ¶meters, const QString &name, const QgsProcessingContext &context ) const
606 : : {
607 : 0 : return QgsProcessingParameters::parameterAsInts( parameterDefinition( name ), parameters, context );
608 : : }
609 : :
610 : 0 : int QgsProcessingAlgorithm::parameterAsEnum( const QVariantMap ¶meters, const QString &name, const QgsProcessingContext &context ) const
611 : : {
612 : 0 : return QgsProcessingParameters::parameterAsEnum( parameterDefinition( name ), parameters, context );
613 : : }
614 : :
615 : 0 : QList<int> QgsProcessingAlgorithm::parameterAsEnums( const QVariantMap ¶meters, const QString &name, const QgsProcessingContext &context ) const
616 : : {
617 : 0 : return QgsProcessingParameters::parameterAsEnums( parameterDefinition( name ), parameters, context );
618 : : }
619 : :
620 : 0 : QString QgsProcessingAlgorithm::parameterAsEnumString( const QVariantMap ¶meters, const QString &name, const QgsProcessingContext &context ) const
621 : : {
622 : 0 : return QgsProcessingParameters::parameterAsEnumString( parameterDefinition( name ), parameters, context );
623 : : }
624 : :
625 : 0 : QStringList QgsProcessingAlgorithm::parameterAsEnumStrings( const QVariantMap ¶meters, const QString &name, const QgsProcessingContext &context ) const
626 : : {
627 : 0 : return QgsProcessingParameters::parameterAsEnumStrings( parameterDefinition( name ), parameters, context );
628 : : }
629 : :
630 : 0 : bool QgsProcessingAlgorithm::parameterAsBool( const QVariantMap ¶meters, const QString &name, const QgsProcessingContext &context ) const
631 : : {
632 : 0 : return QgsProcessingParameters::parameterAsBool( parameterDefinition( name ), parameters, context );
633 : : }
634 : :
635 : 0 : bool QgsProcessingAlgorithm::parameterAsBoolean( const QVariantMap ¶meters, const QString &name, const QgsProcessingContext &context ) const
636 : : {
637 : 0 : return QgsProcessingParameters::parameterAsBool( parameterDefinition( name ), parameters, context );
638 : : }
639 : :
640 : 0 : QgsFeatureSink *QgsProcessingAlgorithm::parameterAsSink( const QVariantMap ¶meters, const QString &name, QgsProcessingContext &context, QString &destinationIdentifier, const QgsFields &fields, QgsWkbTypes::Type geometryType, const QgsCoordinateReferenceSystem &crs, QgsFeatureSink::SinkFlags sinkFlags, const QVariantMap &createOptions, const QStringList &datasourceOptions, const QStringList &layerOptions ) const
641 : : {
642 : 0 : if ( !parameterDefinition( name ) )
643 : 0 : throw QgsProcessingException( QObject::tr( "No parameter definition for the sink '%1'" ).arg( name ) );
644 : :
645 : 0 : return QgsProcessingParameters::parameterAsSink( parameterDefinition( name ), parameters, fields, geometryType, crs, context, destinationIdentifier, sinkFlags, createOptions, datasourceOptions, layerOptions );
646 : 0 : }
647 : :
648 : 0 : QgsProcessingFeatureSource *QgsProcessingAlgorithm::parameterAsSource( const QVariantMap ¶meters, const QString &name, QgsProcessingContext &context ) const
649 : : {
650 : 0 : return QgsProcessingParameters::parameterAsSource( parameterDefinition( name ), parameters, context );
651 : : }
652 : :
653 : 0 : QString QgsProcessingAlgorithm::parameterAsCompatibleSourceLayerPath( const QVariantMap ¶meters, const QString &name, QgsProcessingContext &context, const QStringList &compatibleFormats, const QString &preferredFormat, QgsProcessingFeedback *feedback )
654 : : {
655 : 0 : return QgsProcessingParameters::parameterAsCompatibleSourceLayerPath( parameterDefinition( name ), parameters, context, compatibleFormats, preferredFormat, feedback );
656 : : }
657 : :
658 : 0 : QString QgsProcessingAlgorithm::parameterAsCompatibleSourceLayerPathAndLayerName( const QVariantMap ¶meters, const QString &name, QgsProcessingContext &context, const QStringList &compatibleFormats, const QString &preferredFormat, QgsProcessingFeedback *feedback, QString *layerName )
659 : : {
660 : 0 : return QgsProcessingParameters::parameterAsCompatibleSourceLayerPathAndLayerName( parameterDefinition( name ), parameters, context, compatibleFormats, preferredFormat, feedback, layerName );
661 : : }
662 : :
663 : 0 : QgsMapLayer *QgsProcessingAlgorithm::parameterAsLayer( const QVariantMap ¶meters, const QString &name, QgsProcessingContext &context ) const
664 : : {
665 : 0 : return QgsProcessingParameters::parameterAsLayer( parameterDefinition( name ), parameters, context );
666 : : }
667 : :
668 : 0 : QgsRasterLayer *QgsProcessingAlgorithm::parameterAsRasterLayer( const QVariantMap ¶meters, const QString &name, QgsProcessingContext &context ) const
669 : : {
670 : 0 : return QgsProcessingParameters::parameterAsRasterLayer( parameterDefinition( name ), parameters, context );
671 : : }
672 : :
673 : 0 : QgsMeshLayer *QgsProcessingAlgorithm::parameterAsMeshLayer( const QVariantMap ¶meters, const QString &name, QgsProcessingContext &context ) const
674 : : {
675 : 0 : return QgsProcessingParameters::parameterAsMeshLayer( parameterDefinition( name ), parameters, context );
676 : : }
677 : :
678 : 0 : QString QgsProcessingAlgorithm::parameterAsOutputLayer( const QVariantMap ¶meters, const QString &name, QgsProcessingContext &context ) const
679 : : {
680 : 0 : return QgsProcessingParameters::parameterAsOutputLayer( parameterDefinition( name ), parameters, context );
681 : : }
682 : :
683 : 0 : QString QgsProcessingAlgorithm::parameterAsFileOutput( const QVariantMap ¶meters, const QString &name, QgsProcessingContext &context ) const
684 : : {
685 : 0 : return QgsProcessingParameters::parameterAsFileOutput( parameterDefinition( name ), parameters, context );
686 : : }
687 : :
688 : 0 : QgsVectorLayer *QgsProcessingAlgorithm::parameterAsVectorLayer( const QVariantMap ¶meters, const QString &name, QgsProcessingContext &context ) const
689 : : {
690 : 0 : return QgsProcessingParameters::parameterAsVectorLayer( parameterDefinition( name ), parameters, context );
691 : : }
692 : :
693 : 0 : QgsCoordinateReferenceSystem QgsProcessingAlgorithm::parameterAsCrs( const QVariantMap ¶meters, const QString &name, QgsProcessingContext &context ) const
694 : : {
695 : 0 : return QgsProcessingParameters::parameterAsCrs( parameterDefinition( name ), parameters, context );
696 : : }
697 : :
698 : 0 : QgsCoordinateReferenceSystem QgsProcessingAlgorithm::parameterAsExtentCrs( const QVariantMap ¶meters, const QString &name, QgsProcessingContext &context )
699 : : {
700 : 0 : return QgsProcessingParameters::parameterAsExtentCrs( parameterDefinition( name ), parameters, context );
701 : : }
702 : :
703 : 0 : QgsRectangle QgsProcessingAlgorithm::parameterAsExtent( const QVariantMap ¶meters, const QString &name, QgsProcessingContext &context, const QgsCoordinateReferenceSystem &crs ) const
704 : : {
705 : 0 : return QgsProcessingParameters::parameterAsExtent( parameterDefinition( name ), parameters, context, crs );
706 : : }
707 : :
708 : 0 : QgsGeometry QgsProcessingAlgorithm::parameterAsExtentGeometry( const QVariantMap ¶meters, const QString &name, QgsProcessingContext &context, const QgsCoordinateReferenceSystem &crs )
709 : : {
710 : 0 : return QgsProcessingParameters::parameterAsExtentGeometry( parameterDefinition( name ), parameters, context, crs );
711 : : }
712 : :
713 : 0 : QgsPointXY QgsProcessingAlgorithm::parameterAsPoint( const QVariantMap ¶meters, const QString &name, QgsProcessingContext &context, const QgsCoordinateReferenceSystem &crs ) const
714 : : {
715 : 0 : return QgsProcessingParameters::parameterAsPoint( parameterDefinition( name ), parameters, context, crs );
716 : : }
717 : :
718 : 0 : QgsCoordinateReferenceSystem QgsProcessingAlgorithm::parameterAsPointCrs( const QVariantMap ¶meters, const QString &name, QgsProcessingContext &context )
719 : : {
720 : 0 : return QgsProcessingParameters::parameterAsPointCrs( parameterDefinition( name ), parameters, context );
721 : : }
722 : :
723 : 0 : QgsGeometry QgsProcessingAlgorithm::parameterAsGeometry( const QVariantMap ¶meters, const QString &name, QgsProcessingContext &context, const QgsCoordinateReferenceSystem &crs ) const
724 : : {
725 : 0 : return QgsProcessingParameters::parameterAsGeometry( parameterDefinition( name ), parameters, context, crs );
726 : : }
727 : :
728 : 0 : QgsCoordinateReferenceSystem QgsProcessingAlgorithm::parameterAsGeometryCrs( const QVariantMap ¶meters, const QString &name, QgsProcessingContext &context )
729 : : {
730 : 0 : return QgsProcessingParameters::parameterAsGeometryCrs( parameterDefinition( name ), parameters, context );
731 : : }
732 : :
733 : 0 : QString QgsProcessingAlgorithm::parameterAsFile( const QVariantMap ¶meters, const QString &name, QgsProcessingContext &context ) const
734 : : {
735 : 0 : return QgsProcessingParameters::parameterAsFile( parameterDefinition( name ), parameters, context );
736 : : }
737 : :
738 : 0 : QVariantList QgsProcessingAlgorithm::parameterAsMatrix( const QVariantMap ¶meters, const QString &name, QgsProcessingContext &context ) const
739 : : {
740 : 0 : return QgsProcessingParameters::parameterAsMatrix( parameterDefinition( name ), parameters, context );
741 : : }
742 : :
743 : 0 : QList<QgsMapLayer *> QgsProcessingAlgorithm::parameterAsLayerList( const QVariantMap ¶meters, const QString &name, QgsProcessingContext &context ) const
744 : : {
745 : 0 : return QgsProcessingParameters::parameterAsLayerList( parameterDefinition( name ), parameters, context );
746 : : }
747 : :
748 : 0 : QStringList QgsProcessingAlgorithm::parameterAsFileList( const QVariantMap ¶meters, const QString &name, QgsProcessingContext &context ) const
749 : : {
750 : 0 : return QgsProcessingParameters::parameterAsFileList( parameterDefinition( name ), parameters, context );
751 : : }
752 : :
753 : 0 : QList<double> QgsProcessingAlgorithm::parameterAsRange( const QVariantMap ¶meters, const QString &name, QgsProcessingContext &context ) const
754 : : {
755 : 0 : return QgsProcessingParameters::parameterAsRange( parameterDefinition( name ), parameters, context );
756 : : }
757 : :
758 : 0 : QStringList QgsProcessingAlgorithm::parameterAsFields( const QVariantMap ¶meters, const QString &name, QgsProcessingContext &context ) const
759 : : {
760 : 0 : return QgsProcessingParameters::parameterAsFields( parameterDefinition( name ), parameters, context );
761 : : }
762 : :
763 : 0 : QgsPrintLayout *QgsProcessingAlgorithm::parameterAsLayout( const QVariantMap ¶meters, const QString &name, QgsProcessingContext &context )
764 : : {
765 : 0 : return QgsProcessingParameters::parameterAsLayout( parameterDefinition( name ), parameters, context );
766 : : }
767 : :
768 : 0 : QgsLayoutItem *QgsProcessingAlgorithm::parameterAsLayoutItem( const QVariantMap ¶meters, const QString &name, QgsProcessingContext &context, QgsPrintLayout *layout )
769 : : {
770 : 0 : return QgsProcessingParameters::parameterAsLayoutItem( parameterDefinition( name ), parameters, context, layout );
771 : : }
772 : :
773 : 0 : QColor QgsProcessingAlgorithm::parameterAsColor( const QVariantMap ¶meters, const QString &name, QgsProcessingContext &context )
774 : : {
775 : 0 : return QgsProcessingParameters::parameterAsColor( parameterDefinition( name ), parameters, context );
776 : : }
777 : :
778 : 0 : QString QgsProcessingAlgorithm::parameterAsConnectionName( const QVariantMap ¶meters, const QString &name, QgsProcessingContext &context )
779 : : {
780 : 0 : return QgsProcessingParameters::parameterAsConnectionName( parameterDefinition( name ), parameters, context );
781 : : }
782 : :
783 : 0 : QDateTime QgsProcessingAlgorithm::parameterAsDateTime( const QVariantMap ¶meters, const QString &name, QgsProcessingContext &context )
784 : : {
785 : 0 : return QgsProcessingParameters::parameterAsDateTime( parameterDefinition( name ), parameters, context );
786 : : }
787 : :
788 : 0 : QString QgsProcessingAlgorithm::parameterAsSchema( const QVariantMap ¶meters, const QString &name, QgsProcessingContext &context )
789 : : {
790 : 0 : return QgsProcessingParameters::parameterAsSchema( parameterDefinition( name ), parameters, context );
791 : : }
792 : :
793 : 0 : QString QgsProcessingAlgorithm::parameterAsDatabaseTableName( const QVariantMap ¶meters, const QString &name, QgsProcessingContext &context )
794 : : {
795 : 0 : return QgsProcessingParameters::parameterAsDatabaseTableName( parameterDefinition( name ), parameters, context );
796 : : }
797 : :
798 : 0 : QString QgsProcessingAlgorithm::invalidSourceError( const QVariantMap ¶meters, const QString &name )
799 : : {
800 : 0 : if ( !parameters.contains( name ) )
801 : 0 : return QObject::tr( "Could not load source layer for %1: no value specified for parameter" ).arg( name );
802 : : else
803 : : {
804 : 0 : QVariant var = parameters.value( name );
805 : 0 : if ( var.canConvert<QgsProcessingFeatureSourceDefinition>() )
806 : : {
807 : 0 : QgsProcessingFeatureSourceDefinition fromVar = qvariant_cast<QgsProcessingFeatureSourceDefinition>( var );
808 : 0 : var = fromVar.source;
809 : 0 : }
810 : 0 : else if ( var.canConvert<QgsProcessingOutputLayerDefinition>() )
811 : : {
812 : 0 : QgsProcessingOutputLayerDefinition fromVar = qvariant_cast<QgsProcessingOutputLayerDefinition>( var );
813 : 0 : var = fromVar.sink;
814 : 0 : }
815 : 0 : if ( var.canConvert<QgsProperty>() )
816 : : {
817 : 0 : QgsProperty p = var.value< QgsProperty >();
818 : 0 : if ( p.propertyType() == QgsProperty::StaticProperty )
819 : : {
820 : 0 : var = p.staticValue();
821 : 0 : }
822 : 0 : }
823 : 0 : if ( !var.toString().isEmpty() )
824 : 0 : return QObject::tr( "Could not load source layer for %1: %2 not found" ).arg( name, var.toString() );
825 : : else
826 : 0 : return QObject::tr( "Could not load source layer for %1: invalid value" ).arg( name );
827 : 0 : }
828 : 0 : }
829 : :
830 : 0 : QString QgsProcessingAlgorithm::invalidRasterError( const QVariantMap ¶meters, const QString &name )
831 : : {
832 : 0 : if ( !parameters.contains( name ) )
833 : 0 : return QObject::tr( "Could not load source layer for %1: no value specified for parameter" ).arg( name );
834 : : else
835 : : {
836 : 0 : QVariant var = parameters.value( name );
837 : 0 : if ( var.canConvert<QgsProperty>() )
838 : : {
839 : 0 : QgsProperty p = var.value< QgsProperty >();
840 : 0 : if ( p.propertyType() == QgsProperty::StaticProperty )
841 : : {
842 : 0 : var = p.staticValue();
843 : 0 : }
844 : 0 : }
845 : 0 : if ( !var.toString().isEmpty() )
846 : 0 : return QObject::tr( "Could not load source layer for %1: %2 not found" ).arg( name, var.toString() );
847 : : else
848 : 0 : return QObject::tr( "Could not load source layer for %1: invalid value" ).arg( name );
849 : 0 : }
850 : 0 : }
851 : :
852 : 0 : QString QgsProcessingAlgorithm::invalidSinkError( const QVariantMap ¶meters, const QString &name )
853 : : {
854 : 0 : if ( !parameters.contains( name ) )
855 : 0 : return QObject::tr( "Could not create destination layer for %1: no value specified for parameter" ).arg( name );
856 : : else
857 : : {
858 : 0 : QVariant var = parameters.value( name );
859 : 0 : if ( var.canConvert<QgsProcessingOutputLayerDefinition>() )
860 : : {
861 : 0 : QgsProcessingOutputLayerDefinition fromVar = qvariant_cast<QgsProcessingOutputLayerDefinition>( var );
862 : 0 : var = fromVar.sink;
863 : 0 : }
864 : 0 : if ( var.canConvert<QgsProperty>() )
865 : : {
866 : 0 : QgsProperty p = var.value< QgsProperty >();
867 : 0 : if ( p.propertyType() == QgsProperty::StaticProperty )
868 : : {
869 : 0 : var = p.staticValue();
870 : 0 : }
871 : 0 : }
872 : 0 : if ( !var.toString().isEmpty() )
873 : 0 : return QObject::tr( "Could not create destination layer for %1: %2" ).arg( name, var.toString() );
874 : : else
875 : 0 : return QObject::tr( "Could not create destination layer for %1: invalid value" ).arg( name );
876 : 0 : }
877 : 0 : }
878 : :
879 : 0 : bool QgsProcessingAlgorithm::supportInPlaceEdit( const QgsMapLayer *layer ) const
880 : : {
881 : : Q_UNUSED( layer )
882 : 0 : return false;
883 : : }
884 : :
885 : :
886 : 0 : bool QgsProcessingAlgorithm::createAutoOutputForParameter( QgsProcessingParameterDefinition *parameter )
887 : : {
888 : 0 : if ( !parameter->isDestination() )
889 : 0 : return true; // nothing created, but nothing went wrong - so return true
890 : :
891 : 0 : QgsProcessingDestinationParameter *dest = static_cast< QgsProcessingDestinationParameter * >( parameter );
892 : 0 : QgsProcessingOutputDefinition *output( dest->toOutputDefinition() );
893 : 0 : if ( !output )
894 : 0 : return true; // nothing created - but nothing went wrong - so return true
895 : 0 : output->setAutoCreated( true );
896 : :
897 : 0 : if ( !addOutput( output ) )
898 : : {
899 : : // couldn't add output - probably a duplicate name
900 : 0 : return false;
901 : : }
902 : : else
903 : : {
904 : 0 : return true;
905 : : }
906 : 0 : }
907 : :
908 : :
909 : : //
910 : : // QgsProcessingFeatureBasedAlgorithm
911 : : //
912 : :
913 : 0 : QgsProcessingAlgorithm::Flags QgsProcessingFeatureBasedAlgorithm::flags() const
914 : : {
915 : 0 : Flags f = QgsProcessingAlgorithm::flags();
916 : 0 : f |= QgsProcessingAlgorithm::FlagSupportsInPlaceEdits;
917 : 0 : return f;
918 : : }
919 : :
920 : 0 : void QgsProcessingFeatureBasedAlgorithm::initAlgorithm( const QVariantMap &config )
921 : : {
922 : 0 : addParameter( new QgsProcessingParameterFeatureSource( inputParameterName(), inputParameterDescription(), inputLayerTypes() ) );
923 : 0 : initParameters( config );
924 : 0 : addParameter( new QgsProcessingParameterFeatureSink( QStringLiteral( "OUTPUT" ), outputName(), outputLayerType(), QVariant(), false, true, true ) );
925 : 0 : }
926 : :
927 : 0 : QString QgsProcessingFeatureBasedAlgorithm::inputParameterName() const
928 : : {
929 : 0 : return QStringLiteral( "INPUT" );
930 : : }
931 : :
932 : 0 : QString QgsProcessingFeatureBasedAlgorithm::inputParameterDescription() const
933 : : {
934 : 0 : return QObject::tr( "Input layer" );
935 : : }
936 : :
937 : 0 : QList<int> QgsProcessingFeatureBasedAlgorithm::inputLayerTypes() const
938 : : {
939 : 0 : return QList<int>();
940 : : }
941 : :
942 : 0 : QgsProcessing::SourceType QgsProcessingFeatureBasedAlgorithm::outputLayerType() const
943 : : {
944 : 0 : return QgsProcessing::TypeVectorAnyGeometry;
945 : : }
946 : :
947 : 0 : QgsProcessingFeatureSource::Flag QgsProcessingFeatureBasedAlgorithm::sourceFlags() const
948 : : {
949 : 0 : return static_cast<QgsProcessingFeatureSource::Flag>( 0 );
950 : : }
951 : :
952 : 0 : QgsFeatureSink::SinkFlags QgsProcessingFeatureBasedAlgorithm::sinkFlags() const
953 : : {
954 : 0 : return QgsFeatureSink::SinkFlags();
955 : : }
956 : :
957 : 0 : QgsWkbTypes::Type QgsProcessingFeatureBasedAlgorithm::outputWkbType( QgsWkbTypes::Type inputWkbType ) const
958 : : {
959 : 0 : return inputWkbType;
960 : : }
961 : :
962 : 0 : QgsFields QgsProcessingFeatureBasedAlgorithm::outputFields( const QgsFields &inputFields ) const
963 : : {
964 : 0 : return inputFields;
965 : : }
966 : :
967 : 0 : QgsCoordinateReferenceSystem QgsProcessingFeatureBasedAlgorithm::outputCrs( const QgsCoordinateReferenceSystem &inputCrs ) const
968 : : {
969 : 0 : return inputCrs;
970 : : }
971 : :
972 : 0 : void QgsProcessingFeatureBasedAlgorithm::initParameters( const QVariantMap & )
973 : : {
974 : 0 : }
975 : :
976 : 0 : QgsCoordinateReferenceSystem QgsProcessingFeatureBasedAlgorithm::sourceCrs() const
977 : : {
978 : 0 : if ( mSource )
979 : 0 : return mSource->sourceCrs();
980 : : else
981 : 0 : return QgsCoordinateReferenceSystem();
982 : 0 : }
983 : :
984 : 0 : QVariantMap QgsProcessingFeatureBasedAlgorithm::processAlgorithm( const QVariantMap ¶meters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
985 : : {
986 : 0 : prepareSource( parameters, context );
987 : 0 : QString dest;
988 : 0 : std::unique_ptr< QgsFeatureSink > sink( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, dest,
989 : 0 : outputFields( mSource->fields() ),
990 : 0 : outputWkbType( mSource->wkbType() ),
991 : 0 : outputCrs( mSource->sourceCrs() ),
992 : 0 : sinkFlags() ) );
993 : 0 : if ( !sink )
994 : 0 : throw QgsProcessingException( invalidSinkError( parameters, QStringLiteral( "OUTPUT" ) ) );
995 : :
996 : : // prepare expression context for feature iteration
997 : 0 : QgsExpressionContext prevContext = context.expressionContext();
998 : 0 : QgsExpressionContext algContext = prevContext;
999 : :
1000 : 0 : algContext.appendScopes( createExpressionContext( parameters, context, mSource.get() ).takeScopes() );
1001 : 0 : context.setExpressionContext( algContext );
1002 : :
1003 : 0 : long count = mSource->featureCount();
1004 : :
1005 : 0 : QgsFeature f;
1006 : 0 : QgsFeatureIterator it = mSource->getFeatures( request(), sourceFlags() );
1007 : :
1008 : 0 : double step = count > 0 ? 100.0 / count : 1;
1009 : 0 : int current = 0;
1010 : 0 : while ( it.nextFeature( f ) )
1011 : : {
1012 : 0 : if ( feedback->isCanceled() )
1013 : : {
1014 : 0 : break;
1015 : : }
1016 : :
1017 : 0 : context.expressionContext().setFeature( f );
1018 : 0 : const QgsFeatureList transformed = processFeature( f, context, feedback );
1019 : 0 : for ( QgsFeature transformedFeature : transformed )
1020 : 0 : sink->addFeature( transformedFeature, QgsFeatureSink::FastInsert );
1021 : :
1022 : 0 : feedback->setProgress( current * step );
1023 : 0 : current++;
1024 : 0 : }
1025 : :
1026 : 0 : mSource.reset();
1027 : :
1028 : : // probably not necessary - context's aren't usually recycled, but can't hurt
1029 : 0 : context.setExpressionContext( prevContext );
1030 : :
1031 : 0 : QVariantMap outputs;
1032 : 0 : outputs.insert( QStringLiteral( "OUTPUT" ), dest );
1033 : 0 : return outputs;
1034 : 0 : }
1035 : :
1036 : 0 : QgsFeatureRequest QgsProcessingFeatureBasedAlgorithm::request() const
1037 : : {
1038 : 0 : return QgsFeatureRequest();
1039 : : }
1040 : :
1041 : 0 : bool QgsProcessingFeatureBasedAlgorithm::supportInPlaceEdit( const QgsMapLayer *l ) const
1042 : : {
1043 : 0 : const QgsVectorLayer *layer = qobject_cast< const QgsVectorLayer * >( l );
1044 : 0 : if ( !layer )
1045 : 0 : return false;
1046 : :
1047 : 0 : QgsWkbTypes::GeometryType inPlaceGeometryType = layer->geometryType();
1048 : 0 : if ( !inputLayerTypes().empty() &&
1049 : 0 : !inputLayerTypes().contains( QgsProcessing::TypeVector ) &&
1050 : 0 : !inputLayerTypes().contains( QgsProcessing::TypeVectorAnyGeometry ) &&
1051 : 0 : ( ( inPlaceGeometryType == QgsWkbTypes::PolygonGeometry && !inputLayerTypes().contains( QgsProcessing::TypeVectorPolygon ) ) ||
1052 : 0 : ( inPlaceGeometryType == QgsWkbTypes::LineGeometry && !inputLayerTypes().contains( QgsProcessing::TypeVectorLine ) ) ||
1053 : 0 : ( inPlaceGeometryType == QgsWkbTypes::PointGeometry && !inputLayerTypes().contains( QgsProcessing::TypeVectorPoint ) ) ) )
1054 : 0 : return false;
1055 : :
1056 : 0 : QgsWkbTypes::Type type = QgsWkbTypes::Unknown;
1057 : 0 : if ( inPlaceGeometryType == QgsWkbTypes::PointGeometry )
1058 : 0 : type = QgsWkbTypes::Point;
1059 : 0 : else if ( inPlaceGeometryType == QgsWkbTypes::LineGeometry )
1060 : 0 : type = QgsWkbTypes::LineString;
1061 : 0 : else if ( inPlaceGeometryType == QgsWkbTypes::PolygonGeometry )
1062 : 0 : type = QgsWkbTypes::Polygon;
1063 : :
1064 : 0 : if ( QgsWkbTypes::geometryType( outputWkbType( type ) ) != inPlaceGeometryType )
1065 : 0 : return false;
1066 : :
1067 : 0 : return true;
1068 : 0 : }
1069 : :
1070 : 0 : void QgsProcessingFeatureBasedAlgorithm::prepareSource( const QVariantMap ¶meters, QgsProcessingContext &context )
1071 : : {
1072 : 0 : if ( ! mSource )
1073 : : {
1074 : 0 : mSource.reset( parameterAsSource( parameters, inputParameterName(), context ) );
1075 : 0 : if ( !mSource )
1076 : 0 : throw QgsProcessingException( invalidSourceError( parameters, inputParameterName() ) );
1077 : 0 : }
1078 : 0 : }
1079 : :
1080 : :
1081 : 0 : QgsProcessingAlgorithm::VectorProperties QgsProcessingFeatureBasedAlgorithm::sinkProperties( const QString &sink, const QVariantMap ¶meters, QgsProcessingContext &context, const QMap<QString, QgsProcessingAlgorithm::VectorProperties> &sourceProperties ) const
1082 : : {
1083 : 0 : QgsProcessingAlgorithm::VectorProperties result;
1084 : 0 : if ( sink == QLatin1String( "OUTPUT" ) )
1085 : : {
1086 : 0 : if ( sourceProperties.value( QStringLiteral( "INPUT" ) ).availability == QgsProcessingAlgorithm::Available )
1087 : : {
1088 : 0 : const VectorProperties inputProps = sourceProperties.value( QStringLiteral( "INPUT" ) );
1089 : 0 : result.fields = outputFields( inputProps.fields );
1090 : 0 : result.crs = outputCrs( inputProps.crs );
1091 : 0 : result.wkbType = outputWkbType( inputProps.wkbType );
1092 : 0 : result.availability = Available;
1093 : 0 : return result;
1094 : 0 : }
1095 : : else
1096 : : {
1097 : 0 : std::unique_ptr< QgsProcessingFeatureSource > source( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) );
1098 : 0 : if ( source )
1099 : : {
1100 : 0 : result.fields = outputFields( source->fields() );
1101 : 0 : result.crs = outputCrs( source->sourceCrs() );
1102 : 0 : result.wkbType = outputWkbType( source->wkbType() );
1103 : 0 : result.availability = Available;
1104 : 0 : return result;
1105 : : }
1106 : 0 : }
1107 : 0 : }
1108 : 0 : return result;
1109 : 0 : }
1110 : :
|