1 /***************************************************************************
2                          qgsprocessingparameters.cpp
3                          ---------------------------
4     begin                : April 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 "qgsprocessingparameters.h"
19 #include "qgsprocessingprovider.h"
20 #include "qgsprocessingcontext.h"
21 #include "qgsprocessingutils.h"
22 #include "qgsprocessingalgorithm.h"
23 #include "qgsvectorlayerfeatureiterator.h"
24 #include "qgsprocessingoutputs.h"
25 #include "qgssettings.h"
26 #include "qgsvectorfilewriter.h"
27 #include "qgsreferencedgeometry.h"
28 #include "qgsprocessingregistry.h"
29 #include "qgsprocessingparametertype.h"
30 #include "qgsrasterfilewriter.h"
31 #include "qgsvectorlayer.h"
32 #include "qgsmeshlayer.h"
33 #include "qgsapplication.h"
34 #include "qgslayoutmanager.h"
35 #include "qgsprintlayout.h"
36 #include "qgssymbollayerutils.h"
37 #include "qgsfileutils.h"
38 #include "qgsproviderregistry.h"
39 #include <functional>
40 
41 
toVariant() const42 QVariant QgsProcessingFeatureSourceDefinition::toVariant() const
43 {
44   QVariantMap map;
45   map.insert( QStringLiteral( "source" ), source.toVariant() );
46   map.insert( QStringLiteral( "selected_only" ), selectedFeaturesOnly );
47   map.insert( QStringLiteral( "feature_limit" ), featureLimit );
48   map.insert( QStringLiteral( "flags" ), static_cast< int >( flags ) );
49   map.insert( QStringLiteral( "geometry_check" ), static_cast< int >( geometryCheck ) );
50   return map;
51 }
52 
loadVariant(const QVariantMap & map)53 bool QgsProcessingFeatureSourceDefinition::loadVariant( const QVariantMap &map )
54 {
55   source.loadVariant( map.value( QStringLiteral( "source" ) ) );
56   selectedFeaturesOnly = map.value( QStringLiteral( "selected_only" ), false ).toBool();
57   featureLimit = map.value( QStringLiteral( "feature_limit" ), -1 ).toLongLong();
58   flags = static_cast< Flags >( map.value( QStringLiteral( "flags" ), 0 ).toInt() );
59   geometryCheck = static_cast< QgsFeatureRequest::InvalidGeometryCheck >( map.value( QStringLiteral( "geometry_check" ), QgsFeatureRequest::GeometryAbortOnInvalid ).toInt() );
60   return true;
61 }
62 
63 
64 //
65 // QgsProcessingOutputLayerDefinition
66 //
67 
setRemappingDefinition(const QgsRemappingSinkDefinition & definition)68 void QgsProcessingOutputLayerDefinition::setRemappingDefinition( const QgsRemappingSinkDefinition &definition )
69 {
70   mUseRemapping = true;
71   mRemappingDefinition = definition;
72 }
73 
toVariant() const74 QVariant QgsProcessingOutputLayerDefinition::toVariant() const
75 {
76   QVariantMap map;
77   map.insert( QStringLiteral( "sink" ), sink.toVariant() );
78   map.insert( QStringLiteral( "create_options" ), createOptions );
79   if ( mUseRemapping )
80     map.insert( QStringLiteral( "remapping" ), QVariant::fromValue( mRemappingDefinition ) );
81   return map;
82 }
83 
loadVariant(const QVariantMap & map)84 bool QgsProcessingOutputLayerDefinition::loadVariant( const QVariantMap &map )
85 {
86   sink.loadVariant( map.value( QStringLiteral( "sink" ) ) );
87   createOptions = map.value( QStringLiteral( "create_options" ) ).toMap();
88   if ( map.contains( QStringLiteral( "remapping" ) ) )
89   {
90     mUseRemapping = true;
91     mRemappingDefinition = map.value( QStringLiteral( "remapping" ) ).value< QgsRemappingSinkDefinition >();
92   }
93   else
94   {
95     mUseRemapping = false;
96   }
97   return true;
98 }
99 
operator ==(const QgsProcessingOutputLayerDefinition & other) const100 bool QgsProcessingOutputLayerDefinition::operator==( const QgsProcessingOutputLayerDefinition &other ) const
101 {
102   return sink == other.sink && destinationProject == other.destinationProject && destinationName == other.destinationName && createOptions == other.createOptions
103          && mUseRemapping == other.mUseRemapping && mRemappingDefinition == other.mRemappingDefinition;
104 }
105 
operator !=(const QgsProcessingOutputLayerDefinition & other) const106 bool QgsProcessingOutputLayerDefinition::operator!=( const QgsProcessingOutputLayerDefinition &other ) const
107 {
108   return !( *this == other );
109 }
110 
isDynamic(const QVariantMap & parameters,const QString & name)111 bool QgsProcessingParameters::isDynamic( const QVariantMap &parameters, const QString &name )
112 {
113   QVariant val = parameters.value( name );
114   if ( val.canConvert<QgsProperty>() )
115     return val.value< QgsProperty >().propertyType() != QgsProperty::StaticProperty;
116   else
117     return false;
118 }
119 
parameterAsString(const QgsProcessingParameterDefinition * definition,const QVariantMap & parameters,const QgsProcessingContext & context)120 QString QgsProcessingParameters::parameterAsString( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, const QgsProcessingContext &context )
121 {
122   if ( !definition )
123     return QString();
124 
125   return parameterAsString( definition, parameters.value( definition->name() ), context );
126 }
127 
parameterAsString(const QgsProcessingParameterDefinition * definition,const QVariant & value,const QgsProcessingContext & context)128 QString QgsProcessingParameters::parameterAsString( const QgsProcessingParameterDefinition *definition, const QVariant &value, const QgsProcessingContext &context )
129 {
130   if ( !definition )
131     return QString();
132 
133   QVariant val = value;
134   if ( val.canConvert<QgsProperty>() )
135     return val.value< QgsProperty >().valueAsString( context.expressionContext(), definition->defaultValue().toString() );
136 
137   if ( !val.isValid() )
138   {
139     // fall back to default
140     val = definition->defaultValue();
141   }
142 
143   if ( val == QgsProcessing::TEMPORARY_OUTPUT )
144   {
145     if ( const QgsProcessingDestinationParameter *destParam = dynamic_cast< const QgsProcessingDestinationParameter * >( definition ) )
146       return destParam->generateTemporaryDestination();
147   }
148 
149   return val.toString();
150 }
151 
parameterAsExpression(const QgsProcessingParameterDefinition * definition,const QVariantMap & parameters,const QgsProcessingContext & context)152 QString QgsProcessingParameters::parameterAsExpression( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, const QgsProcessingContext &context )
153 {
154   if ( !definition )
155     return QString();
156 
157   return parameterAsExpression( definition, parameters.value( definition->name() ), context );
158 }
159 
parameterAsExpression(const QgsProcessingParameterDefinition * definition,const QVariant & value,const QgsProcessingContext & context)160 QString QgsProcessingParameters::parameterAsExpression( const QgsProcessingParameterDefinition *definition, const QVariant &value, const QgsProcessingContext &context )
161 {
162   if ( !definition )
163     return QString();
164 
165   QVariant val = value;
166   if ( val.canConvert<QgsProperty>() )
167     return val.value< QgsProperty >().valueAsString( context.expressionContext(), definition->defaultValue().toString() );
168 
169   if ( val.isValid() && !val.toString().isEmpty() )
170   {
171     QgsExpression e( val.toString() );
172     if ( e.isValid() )
173       return val.toString();
174   }
175 
176   // fall back to default
177   return definition->defaultValue().toString();
178 }
179 
parameterAsDouble(const QgsProcessingParameterDefinition * definition,const QVariantMap & parameters,const QgsProcessingContext & context)180 double QgsProcessingParameters::parameterAsDouble( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, const QgsProcessingContext &context )
181 {
182   if ( !definition )
183     return 0;
184 
185   return parameterAsDouble( definition, parameters.value( definition->name() ), context );
186 }
187 
parameterAsDouble(const QgsProcessingParameterDefinition * definition,const QVariant & value,const QgsProcessingContext & context)188 double QgsProcessingParameters::parameterAsDouble( const QgsProcessingParameterDefinition *definition, const QVariant &value, const QgsProcessingContext &context )
189 {
190   if ( !definition )
191     return 0;
192 
193   QVariant val = value;
194   if ( val.canConvert<QgsProperty>() )
195     return val.value< QgsProperty >().valueAsDouble( context.expressionContext(), definition->defaultValue().toDouble() );
196 
197   bool ok = false;
198   double res = val.toDouble( &ok );
199   if ( ok )
200     return res;
201 
202   // fall back to default
203   val = definition->defaultValue();
204   return val.toDouble();
205 }
206 
parameterAsInt(const QgsProcessingParameterDefinition * definition,const QVariantMap & parameters,const QgsProcessingContext & context)207 int QgsProcessingParameters::parameterAsInt( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, const QgsProcessingContext &context )
208 {
209   if ( !definition )
210     return 0;
211 
212   return parameterAsInt( definition, parameters.value( definition->name() ), context );
213 }
214 
parameterAsInt(const QgsProcessingParameterDefinition * definition,const QVariant & value,const QgsProcessingContext & context)215 int QgsProcessingParameters::parameterAsInt( const QgsProcessingParameterDefinition *definition, const QVariant &value, const QgsProcessingContext &context )
216 {
217   if ( !definition )
218     return 0;
219 
220   QVariant val = value;
221   if ( val.canConvert<QgsProperty>() )
222     return val.value< QgsProperty >().valueAsInt( context.expressionContext(), definition->defaultValue().toInt() );
223 
224   bool ok = false;
225   double dbl = val.toDouble( &ok );
226   if ( !ok )
227   {
228     // fall back to default
229     val = definition->defaultValue();
230     dbl = val.toDouble( &ok );
231   }
232 
233   //String representations of doubles in QVariant will not convert to int
234   //work around this by first converting to double, and then checking whether the double is convertible to int
235   if ( ok )
236   {
237     double round = std::round( dbl );
238     if ( round  > std::numeric_limits<int>::max() || round < -std::numeric_limits<int>::max() )
239     {
240       //double too large to fit in int
241       return 0;
242     }
243     return static_cast< int >( std::round( dbl ) );
244   }
245 
246   return val.toInt();
247 }
248 
parameterAsInts(const QgsProcessingParameterDefinition * definition,const QVariantMap & parameters,const QgsProcessingContext & context)249 QList< int > QgsProcessingParameters::parameterAsInts( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, const QgsProcessingContext &context )
250 {
251   if ( !definition )
252     return QList< int >();
253 
254   return parameterAsInts( definition, parameters.value( definition->name() ), context );
255 }
256 
parameterAsInts(const QgsProcessingParameterDefinition * definition,const QVariant & value,const QgsProcessingContext & context)257 QList< int > QgsProcessingParameters::parameterAsInts( const QgsProcessingParameterDefinition *definition, const QVariant &value, const QgsProcessingContext &context )
258 {
259   if ( !definition )
260     return QList< int >();
261 
262   QList< int > resultList;
263   QVariant val = value;
264   if ( val.isValid() )
265   {
266     if ( val.canConvert<QgsProperty>() )
267       resultList << val.value< QgsProperty >().valueAsInt( context.expressionContext(), definition->defaultValue().toInt() );
268     else if ( val.type() == QVariant::List )
269     {
270       QVariantList list = val.toList();
271       for ( auto it = list.constBegin(); it != list.constEnd(); ++it )
272         resultList << it->toInt();
273     }
274     else
275     {
276       QStringList parts = val.toString().split( ';' );
277       for ( auto it = parts.constBegin(); it != parts.constEnd(); ++it )
278         resultList << it->toInt();
279     }
280   }
281 
282   if ( ( resultList.isEmpty() || resultList.at( 0 ) == 0 ) )
283   {
284     resultList.clear();
285     // check default
286     if ( definition->defaultValue().isValid() )
287     {
288       if ( definition->defaultValue().type() == QVariant::List )
289       {
290         QVariantList list = definition->defaultValue().toList();
291         for ( auto it = list.constBegin(); it != list.constEnd(); ++it )
292           resultList << it->toInt();
293       }
294       else
295       {
296         QStringList parts = definition->defaultValue().toString().split( ';' );
297         for ( auto it = parts.constBegin(); it != parts.constEnd(); ++it )
298           resultList << it->toInt();
299       }
300     }
301   }
302 
303   return resultList;
304 }
305 
parameterAsDateTime(const QgsProcessingParameterDefinition * definition,const QVariantMap & parameters,const QgsProcessingContext & context)306 QDateTime QgsProcessingParameters::parameterAsDateTime( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, const QgsProcessingContext &context )
307 {
308   if ( !definition )
309     return QDateTime();
310 
311   return parameterAsDateTime( definition, parameters.value( definition->name() ), context );
312 }
313 
parameterAsDateTime(const QgsProcessingParameterDefinition * definition,const QVariant & value,const QgsProcessingContext & context)314 QDateTime QgsProcessingParameters::parameterAsDateTime( const QgsProcessingParameterDefinition *definition, const QVariant &value, const QgsProcessingContext &context )
315 {
316   if ( !definition )
317     return QDateTime();
318 
319   QVariant val = value;
320   if ( val.canConvert<QgsProperty>() )
321     val = val.value< QgsProperty >().value( context.expressionContext(), definition->defaultValue() );
322 
323   QDateTime d = val.toDateTime();
324   if ( !d.isValid() && val.type() == QVariant::String )
325   {
326     d = QDateTime::fromString( val.toString() );
327   }
328 
329   if ( !d.isValid() )
330   {
331     // fall back to default
332     val = definition->defaultValue();
333     d = val.toDateTime();
334   }
335   if ( !d.isValid() && val.type() == QVariant::String )
336   {
337     d = QDateTime::fromString( val.toString() );
338   }
339 
340   return d;
341 }
342 
parameterAsDate(const QgsProcessingParameterDefinition * definition,const QVariantMap & parameters,const QgsProcessingContext & context)343 QDate QgsProcessingParameters::parameterAsDate( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, const QgsProcessingContext &context )
344 {
345   if ( !definition )
346     return QDate();
347 
348   return parameterAsDate( definition, parameters.value( definition->name() ), context );
349 }
350 
parameterAsDate(const QgsProcessingParameterDefinition * definition,const QVariant & value,const QgsProcessingContext & context)351 QDate QgsProcessingParameters::parameterAsDate( const QgsProcessingParameterDefinition *definition, const QVariant &value, const QgsProcessingContext &context )
352 {
353   if ( !definition )
354     return QDate();
355 
356   QVariant val = value;
357   if ( val.canConvert<QgsProperty>() )
358     val = val.value< QgsProperty >().value( context.expressionContext(), definition->defaultValue() );
359 
360   QDate d = val.toDate();
361   if ( !d.isValid() && val.type() == QVariant::String )
362   {
363     d = QDate::fromString( val.toString() );
364   }
365 
366   if ( !d.isValid() )
367   {
368     // fall back to default
369     val = definition->defaultValue();
370     d = val.toDate();
371   }
372   if ( !d.isValid() && val.type() == QVariant::String )
373   {
374     d = QDate::fromString( val.toString() );
375   }
376 
377   return d;
378 }
379 
parameterAsTime(const QgsProcessingParameterDefinition * definition,const QVariantMap & parameters,const QgsProcessingContext & context)380 QTime QgsProcessingParameters::parameterAsTime( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, const QgsProcessingContext &context )
381 {
382   if ( !definition )
383     return QTime();
384 
385   return parameterAsTime( definition, parameters.value( definition->name() ), context );
386 }
387 
parameterAsTime(const QgsProcessingParameterDefinition * definition,const QVariant & value,const QgsProcessingContext & context)388 QTime QgsProcessingParameters::parameterAsTime( const QgsProcessingParameterDefinition *definition, const QVariant &value, const QgsProcessingContext &context )
389 {
390   if ( !definition )
391     return QTime();
392 
393   QVariant val = value;
394   if ( val.canConvert<QgsProperty>() )
395     val = val.value< QgsProperty >().value( context.expressionContext(), definition->defaultValue() );
396 
397   QTime d;
398 
399   if ( val.type() == QVariant::DateTime )
400     d = val.toDateTime().time();
401   else
402     d = val.toTime();
403 
404   if ( !d.isValid() && val.type() == QVariant::String )
405   {
406     d = QTime::fromString( val.toString() );
407   }
408 
409   if ( !d.isValid() )
410   {
411     // fall back to default
412     val = definition->defaultValue();
413     d = val.toTime();
414   }
415   if ( !d.isValid() && val.type() == QVariant::String )
416   {
417     d = QTime::fromString( val.toString() );
418   }
419 
420   return d;
421 }
422 
parameterAsEnum(const QgsProcessingParameterDefinition * definition,const QVariantMap & parameters,const QgsProcessingContext & context)423 int QgsProcessingParameters::parameterAsEnum( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, const QgsProcessingContext &context )
424 {
425   if ( !definition )
426     return 0;
427 
428   return parameterAsEnum( definition, parameters.value( definition->name() ), context );
429 }
430 
parameterAsEnum(const QgsProcessingParameterDefinition * definition,const QVariant & value,const QgsProcessingContext & context)431 int QgsProcessingParameters::parameterAsEnum( const QgsProcessingParameterDefinition *definition, const QVariant &value, const QgsProcessingContext &context )
432 {
433   if ( !definition )
434     return 0;
435 
436   int val = parameterAsInt( definition, value, context );
437   const QgsProcessingParameterEnum *enumDef = dynamic_cast< const QgsProcessingParameterEnum *>( definition );
438   if ( enumDef && val >= enumDef->options().size() )
439   {
440     return enumDef->defaultValue().toInt();
441   }
442   return val;
443 }
444 
parameterAsEnums(const QgsProcessingParameterDefinition * definition,const QVariantMap & parameters,const QgsProcessingContext & context)445 QList<int> QgsProcessingParameters::parameterAsEnums( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, const QgsProcessingContext &context )
446 {
447   if ( !definition )
448     return QList<int>();
449 
450   return parameterAsEnums( definition, parameters.value( definition->name() ), context );
451 }
452 
parameterAsEnums(const QgsProcessingParameterDefinition * definition,const QVariant & value,const QgsProcessingContext & context)453 QList<int> QgsProcessingParameters::parameterAsEnums( const QgsProcessingParameterDefinition *definition, const QVariant &value, const QgsProcessingContext &context )
454 {
455   if ( !definition )
456     return QList<int>();
457 
458   QVariantList resultList;
459   QVariant val = value;
460   if ( val.canConvert<QgsProperty>() )
461     resultList << val.value< QgsProperty >().valueAsString( context.expressionContext(), definition->defaultValue().toString() );
462   else if ( val.type() == QVariant::List )
463   {
464     const auto constToList = val.toList();
465     for ( const QVariant &var : constToList )
466       resultList << var;
467   }
468   else if ( val.type() == QVariant::String )
469   {
470     const auto constSplit = val.toString().split( ',' );
471     for ( const QString &var : constSplit )
472       resultList << var;
473   }
474   else
475     resultList << val;
476 
477   if ( resultList.isEmpty() )
478     return QList< int >();
479 
480   if ( ( !val.isValid() || !resultList.at( 0 ).isValid() ) && definition )
481   {
482     resultList.clear();
483     // check default
484     if ( definition->defaultValue().type() == QVariant::List )
485     {
486       const auto constToList = definition->defaultValue().toList();
487       for ( const QVariant &var : constToList )
488         resultList << var;
489     }
490     else if ( definition->defaultValue().type() == QVariant::String )
491     {
492       const auto constSplit = definition->defaultValue().toString().split( ',' );
493       for ( const QString &var : constSplit )
494         resultList << var;
495     }
496     else
497       resultList << definition->defaultValue();
498   }
499 
500   QList< int > result;
501   const QgsProcessingParameterEnum *enumDef = dynamic_cast< const QgsProcessingParameterEnum *>( definition );
502   const auto constResultList = resultList;
503   for ( const QVariant &var : constResultList )
504   {
505     int resInt = var.toInt();
506     if ( !enumDef || resInt < enumDef->options().size() )
507     {
508       result << resInt;
509     }
510   }
511   return result;
512 }
513 
parameterAsBool(const QgsProcessingParameterDefinition * definition,const QVariantMap & parameters,const QgsProcessingContext & context)514 bool QgsProcessingParameters::parameterAsBool( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, const QgsProcessingContext &context )
515 {
516   if ( !definition )
517     return false;
518 
519   return parameterAsBool( definition, parameters.value( definition->name() ), context );
520 }
521 
parameterAsBoolean(const QgsProcessingParameterDefinition * definition,const QVariantMap & parameters,const QgsProcessingContext & context)522 bool QgsProcessingParameters::parameterAsBoolean( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, const QgsProcessingContext &context )
523 {
524   if ( !definition )
525     return false;
526 
527   return parameterAsBoolean( definition, parameters.value( definition->name() ), context );
528 }
529 
parameterAsBool(const QgsProcessingParameterDefinition * definition,const QVariant & value,const QgsProcessingContext & context)530 bool QgsProcessingParameters::parameterAsBool( const QgsProcessingParameterDefinition *definition, const QVariant &value, const QgsProcessingContext &context )
531 {
532   if ( !definition )
533     return false;
534 
535   QVariant def = definition->defaultValue();
536 
537   QVariant val = value;
538   if ( val.canConvert<QgsProperty>() )
539     return val.value< QgsProperty >().valueAsBool( context.expressionContext(), def.toBool() );
540   else if ( val.isValid() )
541     return val.toBool();
542   else
543     return def.toBool();
544 }
545 
parameterAsBoolean(const QgsProcessingParameterDefinition * definition,const QVariant & value,const QgsProcessingContext & context)546 bool QgsProcessingParameters::parameterAsBoolean( const QgsProcessingParameterDefinition *definition, const QVariant &value, const QgsProcessingContext &context )
547 {
548   if ( !definition )
549     return false;
550 
551   QVariant def = definition->defaultValue();
552 
553   QVariant val = value;
554   if ( val.canConvert<QgsProperty>() )
555     return val.value< QgsProperty >().valueAsBool( context.expressionContext(), def.toBool() );
556   else if ( val.isValid() )
557     return val.toBool();
558   else
559     return def.toBool();
560 }
561 
parameterAsSink(const QgsProcessingParameterDefinition * definition,const QVariantMap & parameters,const QgsFields & fields,QgsWkbTypes::Type geometryType,const QgsCoordinateReferenceSystem & crs,QgsProcessingContext & context,QString & destinationIdentifier,QgsFeatureSink::SinkFlags sinkFlags,const QVariantMap & createOptions,const QStringList & datasourceOptions,const QStringList & layerOptions)562 QgsFeatureSink *QgsProcessingParameters::parameterAsSink( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, const QgsFields &fields,
563     QgsWkbTypes::Type geometryType, const QgsCoordinateReferenceSystem &crs,
564     QgsProcessingContext &context, QString &destinationIdentifier, QgsFeatureSink::SinkFlags sinkFlags,
565     const QVariantMap &createOptions, const QStringList &datasourceOptions, const QStringList &layerOptions )
566 {
567   QVariant val;
568   if ( definition )
569   {
570     val = parameters.value( definition->name() );
571   }
572 
573   return parameterAsSink( definition, val, fields, geometryType, crs, context, destinationIdentifier, sinkFlags, createOptions, datasourceOptions, layerOptions );
574 }
575 
parameterAsSink(const QgsProcessingParameterDefinition * definition,const QVariant & value,const QgsFields & fields,QgsWkbTypes::Type geometryType,const QgsCoordinateReferenceSystem & crs,QgsProcessingContext & context,QString & destinationIdentifier,QgsFeatureSink::SinkFlags sinkFlags,const QVariantMap & createOptions,const QStringList & datasourceOptions,const QStringList & layerOptions)576 QgsFeatureSink *QgsProcessingParameters::parameterAsSink( const QgsProcessingParameterDefinition *definition, const QVariant &value, const QgsFields &fields, QgsWkbTypes::Type geometryType, const QgsCoordinateReferenceSystem &crs, QgsProcessingContext &context, QString &destinationIdentifier, QgsFeatureSink::SinkFlags sinkFlags, const QVariantMap &createOptions, const QStringList &datasourceOptions, const QStringList &layerOptions )
577 {
578   QVariantMap options = createOptions;
579   QVariant val = value;
580 
581   QgsProject *destinationProject = nullptr;
582   QString destName;
583   QgsRemappingSinkDefinition remapDefinition;
584   bool useRemapDefinition = false;
585   if ( val.canConvert<QgsProcessingOutputLayerDefinition>() )
586   {
587     // input is a QgsProcessingOutputLayerDefinition - get extra properties from it
588     QgsProcessingOutputLayerDefinition fromVar = qvariant_cast<QgsProcessingOutputLayerDefinition>( val );
589     destinationProject = fromVar.destinationProject;
590     options = fromVar.createOptions;
591 
592     val = fromVar.sink;
593     destName = fromVar.destinationName;
594     if ( fromVar.useRemapping() )
595     {
596       useRemapDefinition = true;
597       remapDefinition = fromVar.remappingDefinition();
598     }
599   }
600 
601   QString dest;
602   if ( definition && val.canConvert<QgsProperty>() )
603   {
604     dest = val.value< QgsProperty >().valueAsString( context.expressionContext(), definition->defaultValue().toString() );
605   }
606   else if ( !val.isValid() || val.toString().isEmpty() )
607   {
608     if ( definition && definition->flags() & QgsProcessingParameterDefinition::FlagOptional && !definition->defaultValue().isValid() )
609     {
610       // unset, optional sink, no default => no sink
611       return nullptr;
612     }
613     // fall back to default
614     if ( !definition )
615     {
616       throw QgsProcessingException( QObject::tr( "No parameter definition for the sink" ) );
617     }
618     dest = definition->defaultValue().toString();
619   }
620   else
621   {
622     dest = val.toString();
623   }
624   if ( dest == QgsProcessing::TEMPORARY_OUTPUT )
625   {
626     if ( const QgsProcessingDestinationParameter *destParam = dynamic_cast< const QgsProcessingDestinationParameter * >( definition ) )
627       dest = destParam->generateTemporaryDestination();
628   }
629 
630   if ( dest.isEmpty() )
631     return nullptr;
632 
633   std::unique_ptr< QgsFeatureSink > sink( QgsProcessingUtils::createFeatureSink( dest, context, fields, geometryType, crs, options, datasourceOptions, layerOptions, sinkFlags, useRemapDefinition ? &remapDefinition : nullptr ) );
634   destinationIdentifier = dest;
635 
636   if ( destinationProject )
637   {
638     if ( destName.isEmpty() && definition )
639     {
640       destName = definition->description();
641     }
642     QString outputName;
643     if ( definition )
644       outputName = definition->name();
645     context.addLayerToLoadOnCompletion( destinationIdentifier, QgsProcessingContext::LayerDetails( destName, destinationProject, outputName, QgsProcessingUtils::LayerHint::Vector ) );
646   }
647 
648   return sink.release();
649 }
650 
parameterAsSource(const QgsProcessingParameterDefinition * definition,const QVariantMap & parameters,QgsProcessingContext & context)651 QgsProcessingFeatureSource *QgsProcessingParameters::parameterAsSource( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context )
652 {
653   if ( !definition )
654     return nullptr;
655 
656   return parameterAsSource( definition, parameters.value( definition->name() ), context );
657 }
658 
parameterAsSource(const QgsProcessingParameterDefinition * definition,const QVariant & value,QgsProcessingContext & context)659 QgsProcessingFeatureSource *QgsProcessingParameters::parameterAsSource( const QgsProcessingParameterDefinition *definition, const QVariant &value, QgsProcessingContext &context )
660 {
661   if ( !definition )
662     return nullptr;
663 
664   return QgsProcessingUtils::variantToSource( value, context, definition->defaultValue() );
665 }
666 
parameterAsCompatibleSourceLayerPathInternal(const QgsProcessingParameterDefinition * definition,const QVariantMap & parameters,QgsProcessingContext & context,const QStringList & compatibleFormats,const QString & preferredFormat,QgsProcessingFeedback * feedback,QString * layerName)667 QString parameterAsCompatibleSourceLayerPathInternal( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context, const QStringList &compatibleFormats, const QString &preferredFormat, QgsProcessingFeedback *feedback, QString *layerName )
668 {
669   if ( !definition )
670     return QString();
671 
672   QVariant val = parameters.value( definition->name() );
673 
674   bool selectedFeaturesOnly = false;
675   long long featureLimit = -1;
676   if ( val.canConvert<QgsProcessingFeatureSourceDefinition>() )
677   {
678     // input is a QgsProcessingFeatureSourceDefinition - get extra properties from it
679     QgsProcessingFeatureSourceDefinition fromVar = qvariant_cast<QgsProcessingFeatureSourceDefinition>( val );
680     selectedFeaturesOnly = fromVar.selectedFeaturesOnly;
681     featureLimit = fromVar.featureLimit;
682     val = fromVar.source;
683   }
684   else if ( val.canConvert<QgsProcessingOutputLayerDefinition>() )
685   {
686     // input is a QgsProcessingOutputLayerDefinition - get extra properties from it
687     QgsProcessingOutputLayerDefinition fromVar = qvariant_cast<QgsProcessingOutputLayerDefinition>( val );
688     val = fromVar.sink;
689   }
690 
691   if ( val.canConvert<QgsProperty>() )
692   {
693     val = val.value< QgsProperty >().valueAsString( context.expressionContext(), definition->defaultValue().toString() );
694   }
695 
696   QgsVectorLayer *vl = nullptr;
697   vl = qobject_cast< QgsVectorLayer * >( qvariant_cast<QObject *>( val ) );
698 
699   if ( !vl )
700   {
701     QString layerRef;
702     if ( val.canConvert<QgsProperty>() )
703     {
704       layerRef = val.value< QgsProperty >().valueAsString( context.expressionContext(), definition->defaultValue().toString() );
705     }
706     else if ( !val.isValid() || val.toString().isEmpty() )
707     {
708       // fall back to default
709       val = definition->defaultValue();
710 
711       // default value may be a vector layer
712       vl = qobject_cast< QgsVectorLayer * >( qvariant_cast<QObject *>( val ) );
713       if ( !vl )
714         layerRef = definition->defaultValue().toString();
715     }
716     else
717     {
718       layerRef = val.toString();
719     }
720 
721     if ( !vl )
722     {
723       if ( layerRef.isEmpty() )
724         return QString();
725 
726       vl = qobject_cast< QgsVectorLayer *>( QgsProcessingUtils::mapLayerFromString( layerRef, context, true, QgsProcessingUtils::LayerHint::Vector ) );
727     }
728   }
729 
730   if ( !vl )
731     return QString();
732 
733   if ( layerName )
734     return QgsProcessingUtils::convertToCompatibleFormatAndLayerName( vl, selectedFeaturesOnly, definition->name(),
735            compatibleFormats, preferredFormat, context, feedback, *layerName, featureLimit );
736   else
737     return QgsProcessingUtils::convertToCompatibleFormat( vl, selectedFeaturesOnly, definition->name(),
738            compatibleFormats, preferredFormat, context, feedback, featureLimit );
739 }
740 
parameterAsCompatibleSourceLayerPath(const QgsProcessingParameterDefinition * definition,const QVariantMap & parameters,QgsProcessingContext & context,const QStringList & compatibleFormats,const QString & preferredFormat,QgsProcessingFeedback * feedback)741 QString QgsProcessingParameters::parameterAsCompatibleSourceLayerPath( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context, const QStringList &compatibleFormats, const QString &preferredFormat, QgsProcessingFeedback *feedback )
742 {
743   return parameterAsCompatibleSourceLayerPathInternal( definition, parameters, context, compatibleFormats, preferredFormat, feedback, nullptr );
744 }
745 
parameterAsCompatibleSourceLayerPathAndLayerName(const QgsProcessingParameterDefinition * definition,const QVariantMap & parameters,QgsProcessingContext & context,const QStringList & compatibleFormats,const QString & preferredFormat,QgsProcessingFeedback * feedback,QString * layerName)746 QString QgsProcessingParameters::parameterAsCompatibleSourceLayerPathAndLayerName( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context, const QStringList &compatibleFormats, const QString &preferredFormat, QgsProcessingFeedback *feedback, QString *layerName )
747 {
748   QString *destLayer = layerName;
749   QString tmp;
750   if ( destLayer )
751     destLayer->clear();
752   else
753     destLayer = &tmp;
754 
755   return parameterAsCompatibleSourceLayerPathInternal( definition, parameters, context, compatibleFormats, preferredFormat, feedback, destLayer );
756 }
757 
758 
parameterAsLayer(const QgsProcessingParameterDefinition * definition,const QVariantMap & parameters,QgsProcessingContext & context,QgsProcessingUtils::LayerHint layerHint)759 QgsMapLayer *QgsProcessingParameters::parameterAsLayer( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingUtils::LayerHint layerHint )
760 {
761   if ( !definition )
762     return nullptr;
763 
764   return parameterAsLayer( definition, parameters.value( definition->name() ), context, layerHint );
765 }
766 
parameterAsLayer(const QgsProcessingParameterDefinition * definition,const QVariant & value,QgsProcessingContext & context,QgsProcessingUtils::LayerHint layerHint)767 QgsMapLayer *QgsProcessingParameters::parameterAsLayer( const QgsProcessingParameterDefinition *definition, const QVariant &value, QgsProcessingContext &context, QgsProcessingUtils::LayerHint layerHint )
768 {
769   if ( !definition )
770     return nullptr;
771 
772   QVariant val = value;
773   if ( val.canConvert<QgsProperty>() )
774   {
775     val = val.value< QgsProperty >().valueAsString( context.expressionContext(), definition->defaultValue().toString() );
776   }
777 
778   if ( QgsMapLayer *layer = qobject_cast< QgsMapLayer * >( qvariant_cast<QObject *>( val ) ) )
779   {
780     return layer;
781   }
782 
783   if ( val.canConvert<QgsProcessingOutputLayerDefinition>() )
784   {
785     // input is a QgsProcessingOutputLayerDefinition - get extra properties from it
786     QgsProcessingOutputLayerDefinition fromVar = qvariant_cast<QgsProcessingOutputLayerDefinition>( val );
787     val = fromVar.sink;
788   }
789 
790   if ( val.canConvert<QgsProperty>() && val.value< QgsProperty >().propertyType() == QgsProperty::StaticProperty )
791   {
792     val = val.value< QgsProperty >().staticValue();
793   }
794 
795   if ( !val.isValid() || val.toString().isEmpty() )
796   {
797     // fall back to default
798     val = definition->defaultValue();
799   }
800 
801   if ( QgsMapLayer *layer = qobject_cast< QgsMapLayer * >( qvariant_cast<QObject *>( val ) ) )
802   {
803     return layer;
804   }
805 
806   QString layerRef = val.toString();
807   if ( layerRef.isEmpty() )
808     layerRef = definition->defaultValue().toString();
809 
810   if ( layerRef.isEmpty() )
811     return nullptr;
812 
813   return QgsProcessingUtils::mapLayerFromString( layerRef, context, true, layerHint );
814 }
815 
parameterAsRasterLayer(const QgsProcessingParameterDefinition * definition,const QVariantMap & parameters,QgsProcessingContext & context)816 QgsRasterLayer *QgsProcessingParameters::parameterAsRasterLayer( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context )
817 {
818   return qobject_cast< QgsRasterLayer *>( parameterAsLayer( definition, parameters, context, QgsProcessingUtils::LayerHint::Raster ) );
819 }
820 
parameterAsRasterLayer(const QgsProcessingParameterDefinition * definition,const QVariant & value,QgsProcessingContext & context)821 QgsRasterLayer *QgsProcessingParameters::parameterAsRasterLayer( const QgsProcessingParameterDefinition *definition, const QVariant &value, QgsProcessingContext &context )
822 {
823   return qobject_cast< QgsRasterLayer *>( parameterAsLayer( definition, value, context, QgsProcessingUtils::LayerHint::Raster ) );
824 }
825 
parameterAsMeshLayer(const QgsProcessingParameterDefinition * definition,const QVariantMap & parameters,QgsProcessingContext & context)826 QgsMeshLayer *QgsProcessingParameters::parameterAsMeshLayer( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context )
827 {
828   return qobject_cast< QgsMeshLayer *>( parameterAsLayer( definition, parameters, context, QgsProcessingUtils::LayerHint::Mesh ) );
829 }
830 
parameterAsMeshLayer(const QgsProcessingParameterDefinition * definition,const QVariant & value,QgsProcessingContext & context)831 QgsMeshLayer *QgsProcessingParameters::parameterAsMeshLayer( const QgsProcessingParameterDefinition *definition, const QVariant &value, QgsProcessingContext &context )
832 {
833   return qobject_cast< QgsMeshLayer *>( parameterAsLayer( definition, value, context, QgsProcessingUtils::LayerHint::Mesh ) );
834 }
835 
parameterAsOutputLayer(const QgsProcessingParameterDefinition * definition,const QVariantMap & parameters,QgsProcessingContext & context)836 QString QgsProcessingParameters::parameterAsOutputLayer( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context )
837 {
838   QVariant val;
839   if ( definition )
840   {
841     val = parameters.value( definition->name() );
842   }
843   return parameterAsOutputLayer( definition, val, context );
844 }
845 
parameterAsOutputLayer(const QgsProcessingParameterDefinition * definition,const QVariant & value,QgsProcessingContext & context)846 QString QgsProcessingParameters::parameterAsOutputLayer( const QgsProcessingParameterDefinition *definition, const QVariant &value, QgsProcessingContext &context )
847 {
848   QVariant val = value;
849 
850   QgsProject *destinationProject = nullptr;
851   QString destName;
852   if ( val.canConvert<QgsProcessingOutputLayerDefinition>() )
853   {
854     // input is a QgsProcessingOutputLayerDefinition - get extra properties from it
855     QgsProcessingOutputLayerDefinition fromVar = qvariant_cast<QgsProcessingOutputLayerDefinition>( val );
856     destinationProject = fromVar.destinationProject;
857     val = fromVar.sink;
858     destName = fromVar.destinationName;
859   }
860 
861   QString dest;
862   if ( definition && val.canConvert<QgsProperty>() )
863   {
864     dest = val.value< QgsProperty >().valueAsString( context.expressionContext(), definition->defaultValue().toString() );
865   }
866   else if ( definition && ( !val.isValid() || val.toString().isEmpty() ) )
867   {
868     // fall back to default
869     dest = definition->defaultValue().toString();
870   }
871   else
872   {
873     dest = val.toString();
874   }
875   if ( dest == QgsProcessing::TEMPORARY_OUTPUT )
876   {
877     if ( const QgsProcessingDestinationParameter *destParam = dynamic_cast< const QgsProcessingDestinationParameter * >( definition ) )
878       dest = destParam->generateTemporaryDestination();
879   }
880 
881   if ( destinationProject )
882   {
883     QString outputName;
884     if ( destName.isEmpty() && definition )
885     {
886       destName = definition->description();
887     }
888     if ( definition )
889       outputName = definition->name();
890 
891     QgsProcessingUtils::LayerHint layerTypeHint = QgsProcessingUtils::LayerHint::UnknownType;
892     if ( definition && definition->type() == QgsProcessingParameterVectorDestination::typeName() )
893       layerTypeHint = QgsProcessingUtils::LayerHint::Vector;
894     else if ( definition && definition->type() == QgsProcessingParameterRasterDestination::typeName() )
895       layerTypeHint = QgsProcessingUtils::LayerHint::Raster;
896 
897     context.addLayerToLoadOnCompletion( dest, QgsProcessingContext::LayerDetails( destName, destinationProject, outputName, layerTypeHint ) );
898   }
899 
900   return dest;
901 }
902 
parameterAsFileOutput(const QgsProcessingParameterDefinition * definition,const QVariantMap & parameters,QgsProcessingContext & context)903 QString QgsProcessingParameters::parameterAsFileOutput( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context )
904 {
905   QVariant val;
906   if ( definition )
907   {
908     val = parameters.value( definition->name() );
909   }
910   return parameterAsFileOutput( definition, val, context );
911 }
912 
parameterAsFileOutput(const QgsProcessingParameterDefinition * definition,const QVariant & value,QgsProcessingContext & context)913 QString QgsProcessingParameters::parameterAsFileOutput( const QgsProcessingParameterDefinition *definition, const QVariant &value, QgsProcessingContext &context )
914 {
915   QVariant val = value;
916 
917   if ( val.canConvert<QgsProcessingOutputLayerDefinition>() )
918   {
919     // input is a QgsProcessingOutputLayerDefinition - get extra properties from it
920     QgsProcessingOutputLayerDefinition fromVar = qvariant_cast<QgsProcessingOutputLayerDefinition>( val );
921     val = fromVar.sink;
922   }
923 
924   QString dest;
925   if ( definition && val.canConvert<QgsProperty>() )
926   {
927     dest = val.value< QgsProperty >().valueAsString( context.expressionContext(), definition->defaultValue().toString() );
928   }
929   else if ( definition && ( !val.isValid() || val.toString().isEmpty() ) )
930   {
931     // fall back to default
932     dest = definition->defaultValue().toString();
933   }
934   else
935   {
936     dest = val.toString();
937   }
938   if ( dest == QgsProcessing::TEMPORARY_OUTPUT )
939   {
940     if ( const QgsProcessingDestinationParameter *destParam = dynamic_cast< const QgsProcessingDestinationParameter * >( definition ) )
941       dest = destParam->generateTemporaryDestination();
942   }
943   return dest;
944 }
945 
parameterAsVectorLayer(const QgsProcessingParameterDefinition * definition,const QVariantMap & parameters,QgsProcessingContext & context)946 QgsVectorLayer *QgsProcessingParameters::parameterAsVectorLayer( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context )
947 {
948   return qobject_cast< QgsVectorLayer *>( parameterAsLayer( definition, parameters, context, QgsProcessingUtils::LayerHint::Vector ) );
949 }
950 
parameterAsVectorLayer(const QgsProcessingParameterDefinition * definition,const QVariant & value,QgsProcessingContext & context)951 QgsVectorLayer *QgsProcessingParameters::parameterAsVectorLayer( const QgsProcessingParameterDefinition *definition, const QVariant &value, QgsProcessingContext &context )
952 {
953   return qobject_cast< QgsVectorLayer *>( parameterAsLayer( definition, value, context, QgsProcessingUtils::LayerHint::Vector ) );
954 }
955 
parameterAsCrs(const QgsProcessingParameterDefinition * definition,const QVariantMap & parameters,QgsProcessingContext & context)956 QgsCoordinateReferenceSystem QgsProcessingParameters::parameterAsCrs( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context )
957 {
958   if ( !definition )
959     return QgsCoordinateReferenceSystem();
960 
961   return parameterAsCrs( definition, parameters.value( definition->name() ), context );
962 }
963 
parameterAsCrs(const QgsProcessingParameterDefinition * definition,const QVariant & value,QgsProcessingContext & context)964 QgsCoordinateReferenceSystem QgsProcessingParameters::parameterAsCrs( const QgsProcessingParameterDefinition *definition, const QVariant &value, QgsProcessingContext &context )
965 {
966   if ( !definition )
967     return QgsCoordinateReferenceSystem();
968 
969   return QgsProcessingUtils::variantToCrs( value, context, definition->defaultValue() );
970 }
971 
parameterAsExtent(const QgsProcessingParameterDefinition * definition,const QVariantMap & parameters,QgsProcessingContext & context,const QgsCoordinateReferenceSystem & crs)972 QgsRectangle QgsProcessingParameters::parameterAsExtent( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context,
973     const QgsCoordinateReferenceSystem &crs )
974 {
975   if ( !definition )
976     return QgsRectangle();
977 
978   return parameterAsExtent( definition, parameters.value( definition->name() ), context, crs );
979 }
980 
parameterAsExtent(const QgsProcessingParameterDefinition * definition,const QVariant & value,QgsProcessingContext & context,const QgsCoordinateReferenceSystem & crs)981 QgsRectangle QgsProcessingParameters::parameterAsExtent( const QgsProcessingParameterDefinition *definition, const QVariant &value, QgsProcessingContext &context, const QgsCoordinateReferenceSystem &crs )
982 {
983   if ( !definition )
984     return QgsRectangle();
985 
986   QVariant val = value;
987 
988   if ( val.canConvert< QgsRectangle >() )
989   {
990     return val.value<QgsRectangle>();
991   }
992   if ( val.canConvert< QgsGeometry >() )
993   {
994     const QgsGeometry geom = val.value<QgsGeometry>();
995     if ( !geom.isNull() )
996       return geom.boundingBox();
997   }
998   if ( val.canConvert< QgsReferencedRectangle >() )
999   {
1000     QgsReferencedRectangle rr = val.value<QgsReferencedRectangle>();
1001     if ( crs.isValid() && rr.crs().isValid() && crs != rr.crs() )
1002     {
1003       QgsCoordinateTransform ct( rr.crs(), crs, context.project() );
1004       try
1005       {
1006         return ct.transformBoundingBox( rr );
1007       }
1008       catch ( QgsCsException & )
1009       {
1010         QgsMessageLog::logMessage( QObject::tr( "Error transforming extent geometry" ) );
1011       }
1012     }
1013     return rr;
1014   }
1015 
1016   if ( val.canConvert<QgsProcessingFeatureSourceDefinition>() )
1017   {
1018     // input is a QgsProcessingFeatureSourceDefinition - get extra properties from it
1019     QgsProcessingFeatureSourceDefinition fromVar = qvariant_cast<QgsProcessingFeatureSourceDefinition>( val );
1020     val = fromVar.source;
1021   }
1022   else if ( val.canConvert<QgsProcessingOutputLayerDefinition>() )
1023   {
1024     // input is a QgsProcessingOutputLayerDefinition - get extra properties from it
1025     QgsProcessingOutputLayerDefinition fromVar = qvariant_cast<QgsProcessingOutputLayerDefinition>( val );
1026     val = fromVar.sink;
1027   }
1028 
1029   if ( val.canConvert<QgsProperty>() && val.value< QgsProperty >().propertyType() == QgsProperty::StaticProperty )
1030   {
1031     val = val.value< QgsProperty >().staticValue();
1032   }
1033 
1034   // maybe parameter is a direct layer value?
1035   QgsMapLayer *layer = qobject_cast< QgsMapLayer * >( qvariant_cast<QObject *>( val ) );
1036 
1037   QString rectText;
1038   if ( val.canConvert<QgsProperty>() )
1039     rectText = val.value< QgsProperty >().valueAsString( context.expressionContext(), definition->defaultValue().toString() );
1040   else
1041     rectText = val.toString();
1042 
1043   if ( rectText.isEmpty() && !layer )
1044     return QgsRectangle();
1045 
1046   QRegularExpression rx( QStringLiteral( "^(.*?)\\s*,\\s*(.*?),\\s*(.*?),\\s*(.*?)\\s*(?:\\[(.*)\\])?\\s*$" ) );
1047   QRegularExpressionMatch match = rx.match( rectText );
1048   if ( match.hasMatch() )
1049   {
1050     bool xMinOk = false;
1051     double xMin = match.captured( 1 ).toDouble( &xMinOk );
1052     bool xMaxOk = false;
1053     double xMax = match.captured( 2 ).toDouble( &xMaxOk );
1054     bool yMinOk = false;
1055     double yMin = match.captured( 3 ).toDouble( &yMinOk );
1056     bool yMaxOk = false;
1057     double yMax = match.captured( 4 ).toDouble( &yMaxOk );
1058     if ( xMinOk && xMaxOk && yMinOk && yMaxOk )
1059     {
1060       QgsRectangle rect( xMin, yMin, xMax, yMax );
1061       QgsCoordinateReferenceSystem rectCrs( match.captured( 5 ) );
1062       if ( crs.isValid() && rectCrs.isValid() && crs != rectCrs )
1063       {
1064         QgsCoordinateTransform ct( rectCrs, crs, context.project() );
1065         try
1066         {
1067           return ct.transformBoundingBox( rect );
1068         }
1069         catch ( QgsCsException & )
1070         {
1071           QgsMessageLog::logMessage( QObject::tr( "Error transforming extent geometry" ) );
1072         }
1073       }
1074       return rect;
1075     }
1076   }
1077 
1078   // try as layer extent
1079   if ( !layer )
1080     layer = QgsProcessingUtils::mapLayerFromString( rectText, context );
1081 
1082   if ( layer )
1083   {
1084     QgsRectangle rect = layer->extent();
1085     if ( crs.isValid() && layer->crs().isValid() && crs != layer->crs() )
1086     {
1087       QgsCoordinateTransform ct( layer->crs(), crs, context.project() );
1088       try
1089       {
1090         return ct.transformBoundingBox( rect );
1091       }
1092       catch ( QgsCsException & )
1093       {
1094         QgsMessageLog::logMessage( QObject::tr( "Error transforming extent geometry" ) );
1095       }
1096     }
1097     return rect;
1098   }
1099   return QgsRectangle();
1100 }
1101 
parameterAsExtentGeometry(const QgsProcessingParameterDefinition * definition,const QVariantMap & parameters,QgsProcessingContext & context,const QgsCoordinateReferenceSystem & crs)1102 QgsGeometry QgsProcessingParameters::parameterAsExtentGeometry( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context, const QgsCoordinateReferenceSystem &crs )
1103 {
1104   if ( !definition )
1105     return QgsGeometry();
1106 
1107   QVariant val = parameters.value( definition->name() );
1108 
1109   if ( val.canConvert< QgsReferencedRectangle >() )
1110   {
1111     QgsReferencedRectangle rr = val.value<QgsReferencedRectangle>();
1112     QgsGeometry g = QgsGeometry::fromRect( rr );
1113     if ( crs.isValid() && rr.crs().isValid() && crs != rr.crs() )
1114     {
1115       g = g.densifyByCount( 20 );
1116       QgsCoordinateTransform ct( rr.crs(), crs, context.project() );
1117       try
1118       {
1119         g.transform( ct );
1120       }
1121       catch ( QgsCsException & )
1122       {
1123         QgsMessageLog::logMessage( QObject::tr( "Error transforming extent geometry" ) );
1124       }
1125       return g;
1126     }
1127   }
1128 
1129   if ( val.canConvert<QgsProcessingFeatureSourceDefinition>() )
1130   {
1131     // input is a QgsProcessingFeatureSourceDefinition - get extra properties from it
1132     QgsProcessingFeatureSourceDefinition fromVar = qvariant_cast<QgsProcessingFeatureSourceDefinition>( val );
1133     val = fromVar.source;
1134   }
1135   else if ( val.canConvert<QgsProcessingOutputLayerDefinition>() )
1136   {
1137     // input is a QgsProcessingOutputLayerDefinition - get extra properties from it
1138     QgsProcessingOutputLayerDefinition fromVar = qvariant_cast<QgsProcessingOutputLayerDefinition>( val );
1139     val = fromVar.sink;
1140   }
1141 
1142   if ( val.canConvert<QgsProperty>() && val.value< QgsProperty >().propertyType() == QgsProperty::StaticProperty )
1143   {
1144     val = val.value< QgsProperty >().staticValue();
1145   }
1146 
1147   QString rectText;
1148   if ( val.canConvert<QgsProperty>() )
1149     rectText = val.value< QgsProperty >().valueAsString( context.expressionContext(), definition->defaultValue().toString() );
1150   else
1151     rectText = val.toString();
1152 
1153   if ( !rectText.isEmpty() )
1154   {
1155     QRegularExpression rx( QStringLiteral( "^(.*?)\\s*,\\s*(.*?),\\s*(.*?),\\s*(.*?)\\s*(?:\\[(.*)\\])?\\s*$" ) );
1156     QRegularExpressionMatch match = rx.match( rectText );
1157     if ( match.hasMatch() )
1158     {
1159       bool xMinOk = false;
1160       double xMin = match.captured( 1 ).toDouble( &xMinOk );
1161       bool xMaxOk = false;
1162       double xMax = match.captured( 2 ).toDouble( &xMaxOk );
1163       bool yMinOk = false;
1164       double yMin = match.captured( 3 ).toDouble( &yMinOk );
1165       bool yMaxOk = false;
1166       double yMax = match.captured( 4 ).toDouble( &yMaxOk );
1167       if ( xMinOk && xMaxOk && yMinOk && yMaxOk )
1168       {
1169         QgsRectangle rect( xMin, yMin, xMax, yMax );
1170         QgsCoordinateReferenceSystem rectCrs( match.captured( 5 ) );
1171         QgsGeometry g = QgsGeometry::fromRect( rect );
1172         if ( crs.isValid() && rectCrs.isValid() && crs != rectCrs )
1173         {
1174           g = g.densifyByCount( 20 );
1175           QgsCoordinateTransform ct( rectCrs, crs, context.project() );
1176           try
1177           {
1178             g.transform( ct );
1179           }
1180           catch ( QgsCsException & )
1181           {
1182             QgsMessageLog::logMessage( QObject::tr( "Error transforming extent geometry" ) );
1183           }
1184           return g;
1185         }
1186       }
1187     }
1188   }
1189 
1190   // try as layer extent
1191 
1192   // maybe parameter is a direct layer value?
1193   QgsMapLayer *layer = qobject_cast< QgsMapLayer * >( qvariant_cast<QObject *>( val ) );
1194   if ( !layer )
1195     layer = QgsProcessingUtils::mapLayerFromString( rectText, context );
1196 
1197   if ( layer )
1198   {
1199     QgsRectangle rect = layer->extent();
1200     QgsGeometry g = QgsGeometry::fromRect( rect );
1201     if ( crs.isValid() && layer->crs().isValid() && crs != layer->crs() )
1202     {
1203       g = g.densifyByCount( 20 );
1204       QgsCoordinateTransform ct( layer->crs(), crs, context.project() );
1205       try
1206       {
1207         g.transform( ct );
1208       }
1209       catch ( QgsCsException & )
1210       {
1211         QgsMessageLog::logMessage( QObject::tr( "Error transforming extent geometry" ) );
1212       }
1213     }
1214     return g;
1215   }
1216 
1217   return QgsGeometry::fromRect( parameterAsExtent( definition, parameters, context, crs ) );
1218 }
1219 
parameterAsExtentCrs(const QgsProcessingParameterDefinition * definition,const QVariantMap & parameters,QgsProcessingContext & context)1220 QgsCoordinateReferenceSystem QgsProcessingParameters::parameterAsExtentCrs( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context )
1221 {
1222   QVariant val = parameters.value( definition->name() );
1223   return parameterAsExtentCrs( definition, val, context );
1224 }
1225 
parameterAsExtentCrs(const QgsProcessingParameterDefinition * definition,const QVariant & value,QgsProcessingContext & context)1226 QgsCoordinateReferenceSystem QgsProcessingParameters::parameterAsExtentCrs( const QgsProcessingParameterDefinition *definition, const QVariant &value, QgsProcessingContext &context )
1227 {
1228   QVariant val = value;
1229   if ( val.canConvert< QgsReferencedRectangle >() )
1230   {
1231     QgsReferencedRectangle rr = val.value<QgsReferencedRectangle>();
1232     if ( rr.crs().isValid() )
1233     {
1234       return rr.crs();
1235     }
1236   }
1237 
1238   if ( val.canConvert<QgsProcessingFeatureSourceDefinition>() )
1239   {
1240     // input is a QgsProcessingFeatureSourceDefinition - get extra properties from it
1241     QgsProcessingFeatureSourceDefinition fromVar = qvariant_cast<QgsProcessingFeatureSourceDefinition>( val );
1242     val = fromVar.source;
1243   }
1244   else if ( val.canConvert<QgsProcessingOutputLayerDefinition>() )
1245   {
1246     // input is a QgsProcessingOutputLayerDefinition - get extra properties from it
1247     QgsProcessingOutputLayerDefinition fromVar = qvariant_cast<QgsProcessingOutputLayerDefinition>( val );
1248     val = fromVar.sink;
1249   }
1250 
1251   if ( val.canConvert<QgsProperty>() && val.value< QgsProperty >().propertyType() == QgsProperty::StaticProperty )
1252   {
1253     val = val.value< QgsProperty >().staticValue();
1254   }
1255 
1256   QString valueAsString;
1257   if ( val.canConvert<QgsProperty>() )
1258     valueAsString = val.value< QgsProperty >().valueAsString( context.expressionContext(), definition->defaultValue().toString() );
1259   else
1260     valueAsString = val.toString();
1261 
1262   QRegularExpression rx( QStringLiteral( "^(.*?)\\s*,\\s*(.*?),\\s*(.*?),\\s*(.*?)\\s*(?:\\[(.*)\\])?\\s*$" ) );
1263 
1264   QRegularExpressionMatch match = rx.match( valueAsString );
1265   if ( match.hasMatch() )
1266   {
1267     QgsCoordinateReferenceSystem crs( match.captured( 5 ) );
1268     if ( crs.isValid() )
1269       return crs;
1270   }
1271 
1272   if ( val.canConvert<QgsProcessingFeatureSourceDefinition>() )
1273   {
1274     // input is a QgsProcessingFeatureSourceDefinition - get extra properties from it
1275     QgsProcessingFeatureSourceDefinition fromVar = qvariant_cast<QgsProcessingFeatureSourceDefinition>( val );
1276     val = fromVar.source;
1277   }
1278   else if ( val.canConvert<QgsProcessingOutputLayerDefinition>() )
1279   {
1280     // input is a QgsProcessingOutputLayerDefinition - get extra properties from it
1281     QgsProcessingOutputLayerDefinition fromVar = qvariant_cast<QgsProcessingOutputLayerDefinition>( val );
1282     val = fromVar.sink;
1283   }
1284 
1285   if ( val.canConvert<QgsProperty>() && val.value< QgsProperty >().propertyType() == QgsProperty::StaticProperty )
1286   {
1287     val = val.value< QgsProperty >().staticValue();
1288   }
1289 
1290   // try as layer crs
1291   if ( QgsMapLayer *layer = qobject_cast< QgsMapLayer * >( qvariant_cast<QObject *>( val ) ) )
1292     return layer->crs();
1293   else if ( QgsMapLayer *layer = QgsProcessingUtils::mapLayerFromString( valueAsString, context ) )
1294     return layer->crs();
1295 
1296   if ( auto *lProject = context.project() )
1297     return lProject->crs();
1298   else
1299     return QgsCoordinateReferenceSystem();
1300 }
1301 
parameterAsPoint(const QgsProcessingParameterDefinition * definition,const QVariantMap & parameters,QgsProcessingContext & context,const QgsCoordinateReferenceSystem & crs)1302 QgsPointXY QgsProcessingParameters::parameterAsPoint( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context, const QgsCoordinateReferenceSystem &crs )
1303 {
1304   if ( !definition )
1305     return QgsPointXY();
1306 
1307   return parameterAsPoint( definition, parameters.value( definition->name() ), context, crs );
1308 }
1309 
parameterAsPoint(const QgsProcessingParameterDefinition * definition,const QVariant & value,QgsProcessingContext & context,const QgsCoordinateReferenceSystem & crs)1310 QgsPointXY QgsProcessingParameters::parameterAsPoint( const QgsProcessingParameterDefinition *definition, const QVariant &value, QgsProcessingContext &context, const QgsCoordinateReferenceSystem &crs )
1311 {
1312   if ( !definition )
1313     return QgsPointXY();
1314 
1315   QVariant val = value;
1316   if ( val.canConvert< QgsPointXY >() )
1317   {
1318     return val.value<QgsPointXY>();
1319   }
1320   if ( val.canConvert< QgsGeometry >() )
1321   {
1322     const QgsGeometry geom = val.value<QgsGeometry>();
1323     if ( !geom.isNull() )
1324       return geom.centroid().asPoint();
1325   }
1326   if ( val.canConvert< QgsReferencedPointXY >() )
1327   {
1328     QgsReferencedPointXY rp = val.value<QgsReferencedPointXY>();
1329     if ( crs.isValid() && rp.crs().isValid() && crs != rp.crs() )
1330     {
1331       QgsCoordinateTransform ct( rp.crs(), crs, context.project() );
1332       try
1333       {
1334         return ct.transform( rp );
1335       }
1336       catch ( QgsCsException & )
1337       {
1338         QgsMessageLog::logMessage( QObject::tr( "Error transforming point geometry" ) );
1339       }
1340     }
1341     return rp;
1342   }
1343 
1344   QString pointText = parameterAsString( definition, value, context );
1345   if ( pointText.isEmpty() )
1346     pointText = definition->defaultValue().toString();
1347 
1348   if ( pointText.isEmpty() )
1349     return QgsPointXY();
1350 
1351   QRegularExpression rx( QStringLiteral( "^\\s*\\(?\\s*(.*?)\\s*,\\s*(.*?)\\s*(?:\\[(.*)\\])?\\s*\\)?\\s*$" ) );
1352 
1353   QString valueAsString = parameterAsString( definition, value, context );
1354   QRegularExpressionMatch match = rx.match( valueAsString );
1355   if ( match.hasMatch() )
1356   {
1357     bool xOk = false;
1358     double x = match.captured( 1 ).toDouble( &xOk );
1359     bool yOk = false;
1360     double y = match.captured( 2 ).toDouble( &yOk );
1361 
1362     if ( xOk && yOk )
1363     {
1364       QgsPointXY pt( x, y );
1365 
1366       QgsCoordinateReferenceSystem pointCrs( match.captured( 3 ) );
1367       if ( crs.isValid() && pointCrs.isValid() && crs != pointCrs )
1368       {
1369         QgsCoordinateTransform ct( pointCrs, crs, context.project() );
1370         try
1371         {
1372           return ct.transform( pt );
1373         }
1374         catch ( QgsCsException & )
1375         {
1376           QgsMessageLog::logMessage( QObject::tr( "Error transforming point geometry" ) );
1377         }
1378       }
1379       return pt;
1380     }
1381   }
1382 
1383   return QgsPointXY();
1384 }
1385 
parameterAsPointCrs(const QgsProcessingParameterDefinition * definition,const QVariantMap & parameters,QgsProcessingContext & context)1386 QgsCoordinateReferenceSystem QgsProcessingParameters::parameterAsPointCrs( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context )
1387 {
1388   QVariant val = parameters.value( definition->name() );
1389   return parameterAsPointCrs( definition, val, context );
1390 }
1391 
parameterAsPointCrs(const QgsProcessingParameterDefinition * definition,const QVariant & value,QgsProcessingContext & context)1392 QgsCoordinateReferenceSystem QgsProcessingParameters::parameterAsPointCrs( const QgsProcessingParameterDefinition *definition, const QVariant &value, QgsProcessingContext &context )
1393 {
1394   if ( value.canConvert< QgsReferencedPointXY >() )
1395   {
1396     QgsReferencedPointXY rr = value.value<QgsReferencedPointXY>();
1397     if ( rr.crs().isValid() )
1398     {
1399       return rr.crs();
1400     }
1401   }
1402 
1403   QRegularExpression rx( QStringLiteral( "^\\s*\\(?\\s*(.*?)\\s*,\\s*(.*?)\\s*(?:\\[(.*)\\])?\\s*\\)?\\s*$" ) );
1404 
1405   QString valueAsString = parameterAsString( definition, value, context );
1406   QRegularExpressionMatch match = rx.match( valueAsString );
1407   if ( match.hasMatch() )
1408   {
1409     QgsCoordinateReferenceSystem crs( match.captured( 3 ) );
1410     if ( crs.isValid() )
1411       return crs;
1412   }
1413 
1414   if ( auto *lProject = context.project() )
1415     return lProject->crs();
1416   else
1417     return QgsCoordinateReferenceSystem();
1418 }
1419 
parameterAsGeometry(const QgsProcessingParameterDefinition * definition,const QVariantMap & parameters,QgsProcessingContext & context,const QgsCoordinateReferenceSystem & crs)1420 QgsGeometry QgsProcessingParameters::parameterAsGeometry( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context, const QgsCoordinateReferenceSystem &crs )
1421 {
1422   if ( !definition )
1423     return QgsGeometry();
1424 
1425   return parameterAsGeometry( definition, parameters.value( definition->name() ), context, crs );
1426 }
1427 
parameterAsGeometry(const QgsProcessingParameterDefinition * definition,const QVariant & value,QgsProcessingContext & context,const QgsCoordinateReferenceSystem & crs)1428 QgsGeometry QgsProcessingParameters::parameterAsGeometry( const QgsProcessingParameterDefinition *definition, const QVariant &value, QgsProcessingContext &context, const QgsCoordinateReferenceSystem &crs )
1429 {
1430   if ( !definition )
1431     return QgsGeometry();
1432 
1433   QVariant val = value;
1434   if ( val.canConvert< QgsGeometry >() )
1435   {
1436     return val.value<QgsGeometry>();
1437   }
1438 
1439   if ( val.canConvert< QgsPointXY >() )
1440   {
1441     return QgsGeometry::fromPointXY( val.value<QgsPointXY>() );
1442   }
1443 
1444   if ( val.canConvert< QgsRectangle >() )
1445   {
1446     return QgsGeometry::fromRect( val.value<QgsRectangle>() );
1447   }
1448 
1449   if ( val.canConvert< QgsReferencedPointXY >() )
1450   {
1451     QgsReferencedPointXY rp = val.value<QgsReferencedPointXY>();
1452     if ( crs.isValid() && rp.crs().isValid() && crs != rp.crs() )
1453     {
1454       QgsCoordinateTransform ct( rp.crs(), crs, context.project() );
1455       try
1456       {
1457         return QgsGeometry::fromPointXY( ct.transform( rp ) );
1458       }
1459       catch ( QgsCsException & )
1460       {
1461         QgsMessageLog::logMessage( QObject::tr( "Error transforming point geometry" ) );
1462       }
1463     }
1464     return QgsGeometry::fromPointXY( rp );
1465   }
1466 
1467   if ( val.canConvert< QgsReferencedRectangle >() )
1468   {
1469     QgsReferencedRectangle rr = val.value<QgsReferencedRectangle>();
1470     QgsGeometry g = QgsGeometry::fromRect( rr );
1471     if ( crs.isValid() && rr.crs().isValid() && crs != rr.crs() )
1472     {
1473       g = g.densifyByCount( 20 );
1474       QgsCoordinateTransform ct( rr.crs(), crs, context.project() );
1475       try
1476       {
1477         g.transform( ct );
1478       }
1479       catch ( QgsCsException & )
1480       {
1481         QgsMessageLog::logMessage( QObject::tr( "Error transforming rectangle geometry" ) );
1482       }
1483     }
1484     return g;
1485   }
1486 
1487   if ( val.canConvert< QgsReferencedGeometry >() )
1488   {
1489     QgsReferencedGeometry rg = val.value<QgsReferencedGeometry>();
1490     if ( crs.isValid() && rg.crs().isValid() && crs != rg.crs() )
1491     {
1492       QgsCoordinateTransform ct( rg.crs(), crs, context.project() );
1493       try
1494       {
1495         rg.transform( ct );
1496       }
1497       catch ( QgsCsException & )
1498       {
1499         QgsMessageLog::logMessage( QObject::tr( "Error transforming geometry" ) );
1500       }
1501     }
1502     return rg;
1503   }
1504 
1505   QString valueAsString = parameterAsString( definition, value, context );
1506   if ( valueAsString.isEmpty() )
1507     valueAsString = definition->defaultValue().toString();
1508 
1509   if ( valueAsString.isEmpty() )
1510     return QgsGeometry();
1511 
1512   QRegularExpression rx( QStringLiteral( "^\\s*(?:CRS=(.*);)?(.*?)$" ) );
1513 
1514   QRegularExpressionMatch match = rx.match( valueAsString );
1515   if ( match.hasMatch() )
1516   {
1517     QgsGeometry g =  QgsGeometry::fromWkt( match.captured( 2 ) );
1518     if ( !g.isNull() )
1519     {
1520       QgsCoordinateReferenceSystem geomCrs( match.captured( 1 ) );
1521       if ( crs.isValid() && geomCrs.isValid() && crs != geomCrs )
1522       {
1523         QgsCoordinateTransform ct( geomCrs, crs, context.project() );
1524         try
1525         {
1526           g.transform( ct );
1527         }
1528         catch ( QgsCsException & )
1529         {
1530           QgsMessageLog::logMessage( QObject::tr( "Error transforming geometry" ) );
1531         }
1532       }
1533       return g;
1534     }
1535   }
1536 
1537   return QgsGeometry();
1538 }
1539 
1540 
parameterAsGeometryCrs(const QgsProcessingParameterDefinition * definition,const QVariantMap & parameters,QgsProcessingContext & context)1541 QgsCoordinateReferenceSystem QgsProcessingParameters::parameterAsGeometryCrs( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context )
1542 {
1543   QVariant val = parameters.value( definition->name() );
1544   return parameterAsGeometryCrs( definition, val, context );
1545 }
1546 
parameterAsGeometryCrs(const QgsProcessingParameterDefinition * definition,const QVariant & value,QgsProcessingContext & context)1547 QgsCoordinateReferenceSystem QgsProcessingParameters::parameterAsGeometryCrs( const QgsProcessingParameterDefinition *definition, const QVariant &value, QgsProcessingContext &context )
1548 {
1549   if ( value.canConvert< QgsReferencedGeometry >() )
1550   {
1551     QgsReferencedGeometry rg = value.value<QgsReferencedGeometry>();
1552     if ( rg.crs().isValid() )
1553     {
1554       return rg.crs();
1555     }
1556   }
1557 
1558   if ( value.canConvert< QgsReferencedPointXY >() )
1559   {
1560     QgsReferencedPointXY rp = value.value<QgsReferencedPointXY>();
1561     if ( rp.crs().isValid() )
1562     {
1563       return rp.crs();
1564     }
1565   }
1566 
1567   if ( value.canConvert< QgsReferencedRectangle >() )
1568   {
1569     QgsReferencedRectangle rr = value.value<QgsReferencedRectangle>();
1570     if ( rr.crs().isValid() )
1571     {
1572       return rr.crs();
1573     }
1574   }
1575 
1576   // Match against EWKT
1577   QRegularExpression rx( QStringLiteral( "^\\s*(?:CRS=(.*);)?(.*?)$" ) );
1578 
1579   QString valueAsString = parameterAsString( definition, value, context );
1580   QRegularExpressionMatch match = rx.match( valueAsString );
1581   if ( match.hasMatch() )
1582   {
1583     QgsCoordinateReferenceSystem crs( match.captured( 1 ) );
1584     if ( crs.isValid() )
1585       return crs;
1586   }
1587 
1588   if ( auto *lProject = context.project() )
1589     return lProject->crs();
1590   else
1591     return QgsCoordinateReferenceSystem();
1592 }
1593 
1594 
1595 
1596 
parameterAsFile(const QgsProcessingParameterDefinition * definition,const QVariantMap & parameters,QgsProcessingContext & context)1597 QString QgsProcessingParameters::parameterAsFile( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context )
1598 {
1599   if ( !definition )
1600     return QString();
1601 
1602   QString fileText = parameterAsString( definition, parameters, context );
1603   if ( fileText.isEmpty() )
1604     fileText = definition->defaultValue().toString();
1605   return fileText;
1606 }
1607 
parameterAsFile(const QgsProcessingParameterDefinition * definition,const QVariant & value,QgsProcessingContext & context)1608 QString QgsProcessingParameters::parameterAsFile( const QgsProcessingParameterDefinition *definition, const QVariant &value, QgsProcessingContext &context )
1609 {
1610   if ( !definition )
1611     return QString();
1612 
1613   QString fileText = parameterAsString( definition, value, context );
1614   if ( fileText.isEmpty() )
1615     fileText = definition->defaultValue().toString();
1616   return fileText;
1617 }
1618 
parameterAsMatrix(const QgsProcessingParameterDefinition * definition,const QVariantMap & parameters,QgsProcessingContext & context)1619 QVariantList QgsProcessingParameters::parameterAsMatrix( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context )
1620 {
1621   if ( !definition )
1622     return QVariantList();
1623 
1624   return parameterAsMatrix( definition, parameters.value( definition->name() ), context );
1625 }
1626 
parameterAsMatrix(const QgsProcessingParameterDefinition * definition,const QVariant & value,QgsProcessingContext & context)1627 QVariantList QgsProcessingParameters::parameterAsMatrix( const QgsProcessingParameterDefinition *definition, const QVariant &value, QgsProcessingContext &context )
1628 {
1629   if ( !definition )
1630     return QVariantList();
1631 
1632   QString resultString;
1633   QVariant val = value;
1634   if ( val.canConvert<QgsProperty>() )
1635     resultString = val.value< QgsProperty >().valueAsString( context.expressionContext(), definition->defaultValue().toString() );
1636   else if ( val.type() == QVariant::List )
1637     return val.toList();
1638   else
1639     resultString = val.toString();
1640 
1641   if ( resultString.isEmpty() )
1642   {
1643     // check default
1644     if ( definition->defaultValue().type() == QVariant::List )
1645       return definition->defaultValue().toList();
1646     else
1647       resultString = definition->defaultValue().toString();
1648   }
1649 
1650   QVariantList result;
1651   const auto constSplit = resultString.split( ',' );
1652   bool ok;
1653   double number;
1654   for ( const QString &s : constSplit )
1655   {
1656     number = s.toDouble( &ok );
1657     result << ( ok ? QVariant( number ) : s );
1658   }
1659 
1660   return result;
1661 }
1662 
parameterAsLayerList(const QgsProcessingParameterDefinition * definition,const QVariantMap & parameters,QgsProcessingContext & context)1663 QList<QgsMapLayer *> QgsProcessingParameters::parameterAsLayerList( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context )
1664 {
1665   if ( !definition )
1666     return QList<QgsMapLayer *>();
1667 
1668   return parameterAsLayerList( definition, parameters.value( definition->name() ), context );
1669 }
1670 
parameterAsLayerList(const QgsProcessingParameterDefinition * definition,const QVariant & value,QgsProcessingContext & context)1671 QList<QgsMapLayer *> QgsProcessingParameters::parameterAsLayerList( const QgsProcessingParameterDefinition *definition, const QVariant &value, QgsProcessingContext &context )
1672 {
1673   if ( !definition )
1674     return QList<QgsMapLayer *>();
1675 
1676   QVariant val = value;
1677   if ( QgsMapLayer *layer = qobject_cast< QgsMapLayer * >( qvariant_cast<QObject *>( val ) ) )
1678   {
1679     return QList<QgsMapLayer *>() << layer;
1680   }
1681 
1682   QList<QgsMapLayer *> layers;
1683 
1684   std::function< void( const QVariant &var ) > processVariant;
1685   processVariant = [ &layers, &context, &definition, &processVariant ]( const QVariant & var )
1686   {
1687     if ( var.type() == QVariant::List )
1688     {
1689       const auto constToList = var.toList();
1690       for ( const QVariant &listVar : constToList )
1691       {
1692         processVariant( listVar );
1693       }
1694     }
1695     else if ( var.type() == QVariant::StringList )
1696     {
1697       const auto constToStringList = var.toStringList();
1698       for ( const QString &s : constToStringList )
1699       {
1700         processVariant( s );
1701       }
1702     }
1703     else if ( var.canConvert<QgsProperty>() )
1704       processVariant( var.value< QgsProperty >().valueAsString( context.expressionContext(), definition->defaultValue().toString() ) );
1705     else if ( var.canConvert<QgsProcessingOutputLayerDefinition>() )
1706     {
1707       // input is a QgsProcessingOutputLayerDefinition - get extra properties from it
1708       QgsProcessingOutputLayerDefinition fromVar = qvariant_cast<QgsProcessingOutputLayerDefinition>( var );
1709       QVariant sink = fromVar.sink;
1710       if ( sink.canConvert<QgsProperty>() )
1711       {
1712         processVariant( sink.value< QgsProperty >().valueAsString( context.expressionContext(), definition->defaultValue().toString() ) );
1713       }
1714     }
1715     else if ( QgsMapLayer *layer = qobject_cast< QgsMapLayer * >( qvariant_cast<QObject *>( var ) ) )
1716     {
1717       layers << layer;
1718     }
1719     else
1720     {
1721       QgsMapLayer *alayer = QgsProcessingUtils::mapLayerFromString( var.toString(), context );
1722       if ( alayer )
1723         layers << alayer;
1724     }
1725   };
1726 
1727   processVariant( val );
1728 
1729   if ( layers.isEmpty() )
1730   {
1731     // check default
1732     if ( QgsMapLayer *layer = qobject_cast< QgsMapLayer * >( qvariant_cast<QObject *>( definition->defaultValue() ) ) )
1733     {
1734       layers << layer;
1735     }
1736     else if ( definition->defaultValue().type() == QVariant::List )
1737     {
1738       const auto constToList = definition->defaultValue().toList();
1739       for ( const QVariant &var : constToList )
1740       {
1741         if ( QgsMapLayer *layer = qobject_cast< QgsMapLayer * >( qvariant_cast<QObject *>( var ) ) )
1742         {
1743           layers << layer;
1744         }
1745         else
1746         {
1747           processVariant( var );
1748         }
1749       }
1750     }
1751     else
1752       processVariant( definition->defaultValue() );
1753   }
1754 
1755   return layers;
1756 }
1757 
parameterAsFileList(const QgsProcessingParameterDefinition * definition,const QVariant & value,QgsProcessingContext & context)1758 QStringList QgsProcessingParameters::parameterAsFileList( const QgsProcessingParameterDefinition *definition, const QVariant &value, QgsProcessingContext &context )
1759 {
1760   if ( !definition )
1761     return QStringList();
1762 
1763   QVariant val = value;
1764 
1765   QStringList files;
1766 
1767   std::function< void( const QVariant &var ) > processVariant;
1768   processVariant = [ &files, &context, &definition, &processVariant ]( const QVariant & var )
1769   {
1770     if ( var.type() == QVariant::List )
1771     {
1772       const auto constToList = var.toList();
1773       for ( const QVariant &listVar : constToList )
1774       {
1775         processVariant( listVar );
1776       }
1777     }
1778     else if ( var.type() == QVariant::StringList )
1779     {
1780       const auto constToStringList = var.toStringList();
1781       for ( const QString &s : constToStringList )
1782       {
1783         processVariant( s );
1784       }
1785     }
1786     else if ( var.canConvert<QgsProperty>() )
1787       processVariant( var.value< QgsProperty >().valueAsString( context.expressionContext(), definition->defaultValue().toString() ) );
1788     else
1789     {
1790       files << var.toString();
1791     }
1792   };
1793 
1794   processVariant( val );
1795 
1796   if ( files.isEmpty() )
1797   {
1798     processVariant( definition->defaultValue() );
1799   }
1800 
1801   return files;
1802 }
1803 
parameterAsFileList(const QgsProcessingParameterDefinition * definition,const QVariantMap & parameters,QgsProcessingContext & context)1804 QStringList QgsProcessingParameters::parameterAsFileList( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context )
1805 {
1806   if ( !definition )
1807     return QStringList();
1808 
1809   return parameterAsFileList( definition, parameters.value( definition->name() ), context );
1810 }
1811 
parameterAsRange(const QgsProcessingParameterDefinition * definition,const QVariantMap & parameters,QgsProcessingContext & context)1812 QList<double> QgsProcessingParameters::parameterAsRange( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context )
1813 {
1814   if ( !definition )
1815     return QList<double>();
1816 
1817   return parameterAsRange( definition, parameters.value( definition->name() ), context );
1818 }
1819 
parameterAsRange(const QgsProcessingParameterDefinition * definition,const QVariant & value,QgsProcessingContext & context)1820 QList<double> QgsProcessingParameters::parameterAsRange( const QgsProcessingParameterDefinition *definition, const QVariant &value, QgsProcessingContext &context )
1821 {
1822   if ( !definition )
1823     return QList<double>();
1824 
1825   QStringList resultStringList;
1826   QVariant val = value;
1827 
1828   if ( val.canConvert<QgsProperty>() )
1829     resultStringList << val.value< QgsProperty >().valueAsString( context.expressionContext(), definition->defaultValue().toString() );
1830   else if ( val.type() == QVariant::List )
1831   {
1832     const auto constToList = val.toList();
1833     for ( const QVariant &var : constToList )
1834       resultStringList << var.toString();
1835   }
1836   else
1837     resultStringList << val.toString();
1838 
1839   if ( ( resultStringList.isEmpty() || ( resultStringList.size() == 1 && resultStringList.at( 0 ).isEmpty() ) ) )
1840   {
1841     resultStringList.clear();
1842     // check default
1843     if ( definition->defaultValue().type() == QVariant::List )
1844     {
1845       const auto constToList = definition->defaultValue().toList();
1846       for ( const QVariant &var : constToList )
1847         resultStringList << var.toString();
1848     }
1849     else
1850       resultStringList << definition->defaultValue().toString();
1851   }
1852 
1853   if ( resultStringList.size() == 1 )
1854   {
1855     resultStringList = resultStringList.at( 0 ).split( ',' );
1856   }
1857 
1858   if ( resultStringList.size() < 2 )
1859     return QList< double >() << std::numeric_limits<double>::quiet_NaN()  << std::numeric_limits<double>::quiet_NaN() ;
1860 
1861   QList< double > result;
1862   bool ok = false;
1863   double n = resultStringList.at( 0 ).toDouble( &ok );
1864   if ( ok )
1865     result << n;
1866   else
1867     result << std::numeric_limits<double>::quiet_NaN() ;
1868   ok = false;
1869   n = resultStringList.at( 1 ).toDouble( &ok );
1870   if ( ok )
1871     result << n;
1872   else
1873     result << std::numeric_limits<double>::quiet_NaN() ;
1874 
1875   return result;
1876 }
1877 
parameterAsFields(const QgsProcessingParameterDefinition * definition,const QVariantMap & parameters,QgsProcessingContext & context)1878 QStringList QgsProcessingParameters::parameterAsFields( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context )
1879 {
1880   if ( !definition )
1881     return QStringList();
1882 
1883   QStringList resultStringList;
1884   return parameterAsFields( definition, parameters.value( definition->name() ), context );
1885 }
1886 
parameterAsFields(const QgsProcessingParameterDefinition * definition,const QVariant & value,QgsProcessingContext & context)1887 QStringList QgsProcessingParameters::parameterAsFields( const QgsProcessingParameterDefinition *definition, const QVariant &value, QgsProcessingContext &context )
1888 {
1889   if ( !definition )
1890     return QStringList();
1891 
1892   QStringList resultStringList;
1893   QVariant val = value;
1894   if ( val.isValid() )
1895   {
1896     if ( val.canConvert<QgsProperty>() )
1897       resultStringList << val.value< QgsProperty >().valueAsString( context.expressionContext(), definition->defaultValue().toString() );
1898     else if ( val.type() == QVariant::List )
1899     {
1900       const auto constToList = val.toList();
1901       for ( const QVariant &var : constToList )
1902         resultStringList << var.toString();
1903     }
1904     else if ( val.type() == QVariant::StringList )
1905     {
1906       resultStringList = val.toStringList();
1907     }
1908     else
1909       resultStringList.append( val.toString().split( ';' ) );
1910   }
1911 
1912   if ( ( resultStringList.isEmpty() || resultStringList.at( 0 ).isEmpty() ) )
1913   {
1914     resultStringList.clear();
1915     // check default
1916     if ( definition->defaultValue().isValid() )
1917     {
1918       if ( definition->defaultValue().type() == QVariant::List )
1919       {
1920         const auto constToList = definition->defaultValue().toList();
1921         for ( const QVariant &var : constToList )
1922           resultStringList << var.toString();
1923       }
1924       else if ( definition->defaultValue().type() == QVariant::StringList )
1925       {
1926         resultStringList = definition->defaultValue().toStringList();
1927       }
1928       else
1929         resultStringList.append( definition->defaultValue().toString().split( ';' ) );
1930     }
1931   }
1932 
1933   return resultStringList;
1934 }
1935 
parameterAsLayout(const QgsProcessingParameterDefinition * definition,const QVariantMap & parameters,QgsProcessingContext & context)1936 QgsPrintLayout *QgsProcessingParameters::parameterAsLayout( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context )
1937 {
1938   if ( !definition )
1939     return nullptr;
1940 
1941   return parameterAsLayout( definition, parameters.value( definition->name() ), context );
1942 }
1943 
parameterAsLayout(const QgsProcessingParameterDefinition * definition,const QVariant & value,QgsProcessingContext & context)1944 QgsPrintLayout *QgsProcessingParameters::parameterAsLayout( const QgsProcessingParameterDefinition *definition, const QVariant &value, QgsProcessingContext &context )
1945 {
1946   const QString layoutName = parameterAsString( definition, value, context );
1947   if ( layoutName.isEmpty() )
1948     return nullptr;
1949 
1950   if ( !context.project() )
1951     return nullptr;
1952 
1953   QgsMasterLayoutInterface *l = context.project()->layoutManager()->layoutByName( layoutName );
1954   if ( l && l->layoutType() == QgsMasterLayoutInterface::PrintLayout )
1955     return static_cast< QgsPrintLayout * >( l );
1956   else
1957     return nullptr;
1958 }
1959 
parameterAsLayoutItem(const QgsProcessingParameterDefinition * definition,const QVariantMap & parameters,QgsProcessingContext & context,QgsPrintLayout * layout)1960 QgsLayoutItem *QgsProcessingParameters::parameterAsLayoutItem( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context, QgsPrintLayout *layout )
1961 {
1962   if ( !definition )
1963     return nullptr;
1964 
1965   return parameterAsLayoutItem( definition, parameters.value( definition->name() ), context, layout );
1966 }
1967 
parameterAsLayoutItem(const QgsProcessingParameterDefinition * definition,const QVariant & value,QgsProcessingContext & context,QgsPrintLayout * layout)1968 QgsLayoutItem *QgsProcessingParameters::parameterAsLayoutItem( const QgsProcessingParameterDefinition *definition, const QVariant &value, QgsProcessingContext &context, QgsPrintLayout *layout )
1969 {
1970   if ( !layout )
1971     return nullptr;
1972 
1973   const QString id = parameterAsString( definition, value, context );
1974   if ( id.isEmpty() )
1975     return nullptr;
1976 
1977   // prefer matching by uuid, since it's guaranteed to be unique.
1978   if ( QgsLayoutItem *item = layout->itemByUuid( id ) )
1979     return item;
1980   else if ( QgsLayoutItem *item = layout->itemById( id ) )
1981     return item;
1982   else
1983     return nullptr;
1984 }
1985 
parameterAsColor(const QgsProcessingParameterDefinition * definition,const QVariantMap & parameters,QgsProcessingContext & context)1986 QColor QgsProcessingParameters::parameterAsColor( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context )
1987 {
1988   if ( !definition )
1989     return QColor();
1990 
1991   return parameterAsColor( definition, parameters.value( definition->name() ), context );
1992 }
1993 
parameterAsColor(const QgsProcessingParameterDefinition * definition,const QVariant & value,QgsProcessingContext & context)1994 QColor QgsProcessingParameters::parameterAsColor( const QgsProcessingParameterDefinition *definition, const QVariant &value, QgsProcessingContext &context )
1995 {
1996   if ( !definition )
1997     return QColor();
1998 
1999   QVariant val = value;
2000   if ( val.canConvert<QgsProperty>() )
2001   {
2002     val = val.value< QgsProperty >().value( context.expressionContext(), definition->defaultValue() );
2003   }
2004   if ( val.type() == QVariant::Color )
2005   {
2006     QColor c = val.value< QColor >();
2007     if ( const QgsProcessingParameterColor *colorParam = dynamic_cast< const QgsProcessingParameterColor * >( definition ) )
2008       if ( !colorParam->opacityEnabled() )
2009         c.setAlpha( 255 );
2010     return c;
2011   }
2012 
2013   QString colorText = parameterAsString( definition, value, context );
2014   if ( colorText.isEmpty() && !( definition->flags() & QgsProcessingParameterDefinition::FlagOptional ) )
2015   {
2016     if ( definition->defaultValue().type() == QVariant::Color )
2017       return definition->defaultValue().value< QColor >();
2018     else
2019       colorText = definition->defaultValue().toString();
2020   }
2021 
2022   if ( colorText.isEmpty() )
2023     return QColor();
2024 
2025   bool containsAlpha = false;
2026   QColor c = QgsSymbolLayerUtils::parseColorWithAlpha( colorText, containsAlpha );
2027   if ( const QgsProcessingParameterColor *colorParam = dynamic_cast< const QgsProcessingParameterColor * >( definition ) )
2028     if ( c.isValid() && !colorParam->opacityEnabled() )
2029       c.setAlpha( 255 );
2030   return c;
2031 }
2032 
parameterAsConnectionName(const QgsProcessingParameterDefinition * definition,const QVariantMap & parameters,const QgsProcessingContext & context)2033 QString QgsProcessingParameters::parameterAsConnectionName( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, const QgsProcessingContext &context )
2034 {
2035   if ( !definition )
2036     return QString();
2037 
2038   return parameterAsConnectionName( definition, parameters.value( definition->name() ), context );
2039 }
2040 
parameterAsConnectionName(const QgsProcessingParameterDefinition * definition,const QVariant & value,const QgsProcessingContext & context)2041 QString QgsProcessingParameters::parameterAsConnectionName( const QgsProcessingParameterDefinition *definition, const QVariant &value, const QgsProcessingContext &context )
2042 {
2043   // for now it's just treated identical to strings, but in future we may want flexibility to amend this
2044   // (hence the new method)
2045   return parameterAsString( definition, value, context );
2046 }
2047 
parameterAsSchema(const QgsProcessingParameterDefinition * definition,const QVariantMap & parameters,const QgsProcessingContext & context)2048 QString QgsProcessingParameters::parameterAsSchema( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, const QgsProcessingContext &context )
2049 {
2050   if ( !definition )
2051     return QString();
2052 
2053   return parameterAsSchema( definition, parameters.value( definition->name() ), context );
2054 }
2055 
parameterAsSchema(const QgsProcessingParameterDefinition * definition,const QVariant & value,const QgsProcessingContext & context)2056 QString QgsProcessingParameters::parameterAsSchema( const QgsProcessingParameterDefinition *definition, const QVariant &value, const QgsProcessingContext &context )
2057 {
2058   // for now it's just treated identical to strings, but in future we may want flexibility to amend this (e.g. if we want to embed connection details into the schema
2059   // parameter values, such as via a delimiter separated string)
2060   return parameterAsString( definition, value, context );
2061 }
2062 
parameterAsDatabaseTableName(const QgsProcessingParameterDefinition * definition,const QVariantMap & parameters,const QgsProcessingContext & context)2063 QString QgsProcessingParameters::parameterAsDatabaseTableName( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, const QgsProcessingContext &context )
2064 {
2065   if ( !definition )
2066     return QString();
2067 
2068   return parameterAsDatabaseTableName( definition, parameters.value( definition->name() ), context );
2069 }
2070 
parameterAsDatabaseTableName(const QgsProcessingParameterDefinition * definition,const QVariant & value,const QgsProcessingContext & context)2071 QString QgsProcessingParameters::parameterAsDatabaseTableName( const QgsProcessingParameterDefinition *definition, const QVariant &value, const QgsProcessingContext &context )
2072 {
2073   // for now it's just treated identical to strings, but in future we may want flexibility to amend this (e.g. if we want to embed connection details into the table name
2074   // parameter values, such as via a delimiter separated string)
2075   return parameterAsString( definition, value, context );
2076 }
2077 
parameterFromVariantMap(const QVariantMap & map)2078 QgsProcessingParameterDefinition *QgsProcessingParameters::parameterFromVariantMap( const QVariantMap &map )
2079 {
2080   QString type = map.value( QStringLiteral( "parameter_type" ) ).toString();
2081   QString name = map.value( QStringLiteral( "name" ) ).toString();
2082   std::unique_ptr< QgsProcessingParameterDefinition > def;
2083 
2084   // probably all these hardcoded values aren't required anymore, and we could
2085   // always resort to the registry lookup...
2086   // TODO: confirm
2087   if ( type == QgsProcessingParameterBoolean::typeName() )
2088     def.reset( new QgsProcessingParameterBoolean( name ) );
2089   else if ( type == QgsProcessingParameterCrs::typeName() )
2090     def.reset( new QgsProcessingParameterCrs( name ) );
2091   else if ( type == QgsProcessingParameterMapLayer::typeName() )
2092     def.reset( new QgsProcessingParameterMapLayer( name ) );
2093   else if ( type == QgsProcessingParameterExtent::typeName() )
2094     def.reset( new QgsProcessingParameterExtent( name ) );
2095   else if ( type == QgsProcessingParameterPoint::typeName() )
2096     def.reset( new QgsProcessingParameterPoint( name ) );
2097   else if ( type == QgsProcessingParameterFile::typeName() )
2098     def.reset( new QgsProcessingParameterFile( name ) );
2099   else if ( type == QgsProcessingParameterMatrix::typeName() )
2100     def.reset( new QgsProcessingParameterMatrix( name ) );
2101   else if ( type == QgsProcessingParameterMultipleLayers::typeName() )
2102     def.reset( new QgsProcessingParameterMultipleLayers( name ) );
2103   else if ( type == QgsProcessingParameterNumber::typeName() )
2104     def.reset( new QgsProcessingParameterNumber( name ) );
2105   else if ( type == QgsProcessingParameterRange::typeName() )
2106     def.reset( new QgsProcessingParameterRange( name ) );
2107   else if ( type == QgsProcessingParameterRasterLayer::typeName() )
2108     def.reset( new QgsProcessingParameterRasterLayer( name ) );
2109   else if ( type == QgsProcessingParameterEnum::typeName() )
2110     def.reset( new QgsProcessingParameterEnum( name ) );
2111   else if ( type == QgsProcessingParameterString::typeName() )
2112     def.reset( new QgsProcessingParameterString( name ) );
2113   else if ( type == QgsProcessingParameterAuthConfig::typeName() )
2114     def.reset( new QgsProcessingParameterAuthConfig( name ) );
2115   else if ( type == QgsProcessingParameterExpression::typeName() )
2116     def.reset( new QgsProcessingParameterExpression( name ) );
2117   else if ( type == QgsProcessingParameterVectorLayer::typeName() )
2118     def.reset( new QgsProcessingParameterVectorLayer( name ) );
2119   else if ( type == QgsProcessingParameterField::typeName() )
2120     def.reset( new QgsProcessingParameterField( name ) );
2121   else if ( type == QgsProcessingParameterFeatureSource::typeName() )
2122     def.reset( new QgsProcessingParameterFeatureSource( name ) );
2123   else if ( type == QgsProcessingParameterFeatureSink::typeName() )
2124     def.reset( new QgsProcessingParameterFeatureSink( name ) );
2125   else if ( type == QgsProcessingParameterVectorDestination::typeName() )
2126     def.reset( new QgsProcessingParameterVectorDestination( name ) );
2127   else if ( type == QgsProcessingParameterRasterDestination::typeName() )
2128     def.reset( new QgsProcessingParameterRasterDestination( name ) );
2129   else if ( type == QgsProcessingParameterFileDestination::typeName() )
2130     def.reset( new QgsProcessingParameterFileDestination( name ) );
2131   else if ( type == QgsProcessingParameterFolderDestination::typeName() )
2132     def.reset( new QgsProcessingParameterFolderDestination( name ) );
2133   else if ( type == QgsProcessingParameterBand::typeName() )
2134     def.reset( new QgsProcessingParameterBand( name ) );
2135   else if ( type == QgsProcessingParameterMeshLayer::typeName() )
2136     def.reset( new QgsProcessingParameterMeshLayer( name ) );
2137   else if ( type == QgsProcessingParameterLayout::typeName() )
2138     def.reset( new QgsProcessingParameterLayout( name ) );
2139   else if ( type == QgsProcessingParameterLayoutItem::typeName() )
2140     def.reset( new QgsProcessingParameterLayoutItem( name ) );
2141   else if ( type == QgsProcessingParameterColor::typeName() )
2142     def.reset( new QgsProcessingParameterColor( name ) );
2143   else if ( type == QgsProcessingParameterCoordinateOperation::typeName() )
2144     def.reset( new QgsProcessingParameterCoordinateOperation( name ) );
2145   else
2146   {
2147     QgsProcessingParameterType *paramType = QgsApplication::instance()->processingRegistry()->parameterType( type );
2148     if ( paramType )
2149       def.reset( paramType->create( name ) );
2150   }
2151 
2152   if ( !def )
2153     return nullptr;
2154 
2155   def->fromVariantMap( map );
2156   return def.release();
2157 }
2158 
descriptionFromName(const QString & name)2159 QString QgsProcessingParameters::descriptionFromName( const QString &name )
2160 {
2161   QString desc = name;
2162   desc.replace( '_', ' ' );
2163   return desc;
2164 }
2165 
parameterFromScriptCode(const QString & code)2166 QgsProcessingParameterDefinition *QgsProcessingParameters::parameterFromScriptCode( const QString &code )
2167 {
2168   bool isOptional = false;
2169   QString name;
2170   QString definition;
2171   QString type;
2172   if ( !parseScriptCodeParameterOptions( code, isOptional, name, type, definition ) )
2173     return nullptr;
2174 
2175   QString description = descriptionFromName( name );
2176 
2177   if ( type == QLatin1String( "boolean" ) )
2178     return QgsProcessingParameterBoolean::fromScriptCode( name, description, isOptional, definition );
2179   else if ( type == QLatin1String( "crs" ) )
2180     return QgsProcessingParameterCrs::fromScriptCode( name, description, isOptional, definition );
2181   else if ( type == QLatin1String( "layer" ) )
2182     return QgsProcessingParameterMapLayer::fromScriptCode( name, description, isOptional, definition );
2183   else if ( type == QLatin1String( "extent" ) )
2184     return QgsProcessingParameterExtent::fromScriptCode( name, description, isOptional, definition );
2185   else if ( type == QLatin1String( "point" ) )
2186     return QgsProcessingParameterPoint::fromScriptCode( name, description, isOptional, definition );
2187   else if ( type == QLatin1String( "geometry" ) )
2188     return QgsProcessingParameterGeometry::fromScriptCode( name, description, isOptional, definition );
2189   else if ( type == QLatin1String( "file" ) )
2190     return QgsProcessingParameterFile::fromScriptCode( name, description, isOptional, definition, QgsProcessingParameterFile::File );
2191   else if ( type == QLatin1String( "folder" ) )
2192     return QgsProcessingParameterFile::fromScriptCode( name, description, isOptional, definition, QgsProcessingParameterFile::Folder );
2193   else if ( type == QLatin1String( "matrix" ) )
2194     return QgsProcessingParameterMatrix::fromScriptCode( name, description, isOptional, definition );
2195   else if ( type == QLatin1String( "multiple" ) )
2196     return QgsProcessingParameterMultipleLayers::fromScriptCode( name, description, isOptional, definition );
2197   else if ( type == QLatin1String( "number" ) )
2198     return QgsProcessingParameterNumber::fromScriptCode( name, description, isOptional, definition );
2199   else if ( type == QLatin1String( "distance" ) )
2200     return QgsProcessingParameterDistance::fromScriptCode( name, description, isOptional, definition );
2201   else if ( type == QLatin1String( "scale" ) )
2202     return QgsProcessingParameterScale::fromScriptCode( name, description, isOptional, definition );
2203   else if ( type == QLatin1String( "range" ) )
2204     return QgsProcessingParameterRange::fromScriptCode( name, description, isOptional, definition );
2205   else if ( type == QLatin1String( "raster" ) )
2206     return QgsProcessingParameterRasterLayer::fromScriptCode( name, description, isOptional, definition );
2207   else if ( type == QLatin1String( "enum" ) )
2208     return QgsProcessingParameterEnum::fromScriptCode( name, description, isOptional, definition );
2209   else if ( type == QLatin1String( "string" ) )
2210     return QgsProcessingParameterString::fromScriptCode( name, description, isOptional, definition );
2211   else if ( type == QLatin1String( "authcfg" ) )
2212     return QgsProcessingParameterAuthConfig::fromScriptCode( name, description, isOptional, definition );
2213   else if ( type == QLatin1String( "expression" ) )
2214     return QgsProcessingParameterExpression::fromScriptCode( name, description, isOptional, definition );
2215   else if ( type == QLatin1String( "field" ) )
2216     return QgsProcessingParameterField::fromScriptCode( name, description, isOptional, definition );
2217   else if ( type == QLatin1String( "vector" ) )
2218     return QgsProcessingParameterVectorLayer::fromScriptCode( name, description, isOptional, definition );
2219   else if ( type == QLatin1String( "source" ) )
2220     return QgsProcessingParameterFeatureSource::fromScriptCode( name, description, isOptional, definition );
2221   else if ( type == QLatin1String( "sink" ) )
2222     return QgsProcessingParameterFeatureSink::fromScriptCode( name, description, isOptional, definition );
2223   else if ( type == QLatin1String( "vectordestination" ) )
2224     return QgsProcessingParameterVectorDestination::fromScriptCode( name, description, isOptional, definition );
2225   else if ( type == QLatin1String( "rasterdestination" ) )
2226     return QgsProcessingParameterRasterDestination::fromScriptCode( name, description, isOptional, definition );
2227   else if ( type == QLatin1String( "filedestination" ) )
2228     return QgsProcessingParameterFileDestination::fromScriptCode( name, description, isOptional, definition );
2229   else if ( type == QLatin1String( "folderdestination" ) )
2230     return QgsProcessingParameterFolderDestination::fromScriptCode( name, description, isOptional, definition );
2231   else if ( type == QLatin1String( "band" ) )
2232     return QgsProcessingParameterBand::fromScriptCode( name, description, isOptional, definition );
2233   else if ( type == QLatin1String( "mesh" ) )
2234     return QgsProcessingParameterMeshLayer::fromScriptCode( name, description, isOptional, definition );
2235   else if ( type == QLatin1String( "layout" ) )
2236     return QgsProcessingParameterLayout::fromScriptCode( name, description, isOptional, definition );
2237   else if ( type == QLatin1String( "layoutitem" ) )
2238     return QgsProcessingParameterLayoutItem::fromScriptCode( name, description, isOptional, definition );
2239   else if ( type == QLatin1String( "color" ) )
2240     return QgsProcessingParameterColor::fromScriptCode( name, description, isOptional, definition );
2241   else if ( type == QLatin1String( "coordinateoperation" ) )
2242     return QgsProcessingParameterCoordinateOperation::fromScriptCode( name, description, isOptional, definition );
2243   else if ( type == QLatin1String( "maptheme" ) )
2244     return QgsProcessingParameterMapTheme::fromScriptCode( name, description, isOptional, definition );
2245   else if ( type == QLatin1String( "datetime" ) )
2246     return QgsProcessingParameterDateTime::fromScriptCode( name, description, isOptional, definition );
2247   else if ( type == QLatin1String( "providerconnection" ) )
2248     return QgsProcessingParameterProviderConnection::fromScriptCode( name, description, isOptional, definition );
2249   else if ( type == QLatin1String( "databaseschema" ) )
2250     return QgsProcessingParameterDatabaseSchema::fromScriptCode( name, description, isOptional, definition );
2251   else if ( type == QLatin1String( "databasetable" ) )
2252     return QgsProcessingParameterDatabaseTable::fromScriptCode( name, description, isOptional, definition );
2253 
2254   return nullptr;
2255 }
2256 
parseScriptCodeParameterOptions(const QString & code,bool & isOptional,QString & name,QString & type,QString & definition)2257 bool QgsProcessingParameters::parseScriptCodeParameterOptions( const QString &code, bool &isOptional, QString &name, QString &type, QString &definition )
2258 {
2259   QRegularExpression re( QStringLiteral( "(?:#*)(.*?)=\\s*(.*)" ) );
2260   QRegularExpressionMatch m = re.match( code );
2261   if ( !m.hasMatch() )
2262     return false;
2263 
2264   name = m.captured( 1 );
2265   QString tokens = m.captured( 2 );
2266   if ( tokens.startsWith( QLatin1String( "optional" ), Qt::CaseInsensitive ) )
2267   {
2268     isOptional = true;
2269     tokens.remove( 0, 8 ); // length "optional" = 8
2270   }
2271   else
2272   {
2273     isOptional = false;
2274   }
2275 
2276   tokens = tokens.trimmed();
2277 
2278   QRegularExpression re2( QStringLiteral( "(.*?)\\s+(.*)" ) );
2279   m = re2.match( tokens );
2280   if ( !m.hasMatch() )
2281   {
2282     type = tokens.toLower().trimmed();
2283     definition.clear();
2284   }
2285   else
2286   {
2287     type = m.captured( 1 ).toLower().trimmed();
2288     definition = m.captured( 2 );
2289   }
2290   return true;
2291 }
2292 
2293 //
2294 // QgsProcessingParameterDefinition
2295 //
2296 
QgsProcessingParameterDefinition(const QString & name,const QString & description,const QVariant & defaultValue,bool optional,const QString & help)2297 QgsProcessingParameterDefinition::QgsProcessingParameterDefinition( const QString &name, const QString &description, const QVariant &defaultValue, bool optional, const QString &help )
2298   : mName( name )
2299   , mDescription( description )
2300   , mHelp( help )
2301   , mDefault( defaultValue )
2302   , mFlags( optional ? FlagOptional : 0 )
2303 {}
2304 
checkValueIsAcceptable(const QVariant & input,QgsProcessingContext *) const2305 bool QgsProcessingParameterDefinition::checkValueIsAcceptable( const QVariant &input, QgsProcessingContext * ) const
2306 {
2307   if ( !input.isValid() && !mDefault.isValid() )
2308     return mFlags & FlagOptional;
2309 
2310   if ( ( input.type() == QVariant::String && input.toString().isEmpty() )
2311        || ( !input.isValid() && mDefault.type() == QVariant::String && mDefault.toString().isEmpty() ) )
2312     return mFlags & FlagOptional;
2313 
2314   return true;
2315 }
2316 
valueAsPythonString(const QVariant & value,QgsProcessingContext &) const2317 QString QgsProcessingParameterDefinition::valueAsPythonString( const QVariant &value, QgsProcessingContext & ) const
2318 {
2319   if ( !value.isValid() )
2320     return QStringLiteral( "None" );
2321 
2322   if ( value.canConvert<QgsProperty>() )
2323     return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
2324 
2325   return QgsProcessingUtils::stringToPythonLiteral( value.toString() );
2326 }
2327 
asScriptCode() const2328 QString QgsProcessingParameterDefinition::asScriptCode() const
2329 {
2330   QString code = QStringLiteral( "##%1=" ).arg( mName );
2331   if ( mFlags & FlagOptional )
2332     code += QLatin1String( "optional " );
2333   code += type() + ' ';
2334   code += mDefault.toString();
2335   return code.trimmed();
2336 }
2337 
asPythonString(const QgsProcessing::PythonOutputType outputType) const2338 QString QgsProcessingParameterDefinition::asPythonString( const QgsProcessing::PythonOutputType outputType ) const
2339 {
2340   // base class method is probably not much use
2341   if ( QgsProcessingParameterType *t = QgsApplication::processingRegistry()->parameterType( type() ) )
2342   {
2343     switch ( outputType )
2344     {
2345       case QgsProcessing::PythonQgsProcessingAlgorithmSubclass:
2346       {
2347         QString code = t->className() + QStringLiteral( "('%1', '%2'" ).arg( name(), description() );
2348         if ( mFlags & FlagOptional )
2349           code += QLatin1String( ", optional=True" );
2350 
2351         QgsProcessingContext c;
2352         code += QStringLiteral( ", defaultValue=%1)" ).arg( valueAsPythonString( mDefault, c ) );
2353         return code;
2354       }
2355     }
2356   }
2357 
2358   // oh well, we tried
2359   return QString();
2360 }
2361 
toVariantMap() const2362 QVariantMap QgsProcessingParameterDefinition::toVariantMap() const
2363 {
2364   QVariantMap map;
2365   map.insert( QStringLiteral( "parameter_type" ), type() );
2366   map.insert( QStringLiteral( "name" ), mName );
2367   map.insert( QStringLiteral( "description" ), mDescription );
2368   map.insert( QStringLiteral( "help" ), mHelp );
2369   map.insert( QStringLiteral( "default" ), mDefault );
2370   map.insert( QStringLiteral( "defaultGui" ), mGuiDefault );
2371   map.insert( QStringLiteral( "flags" ), static_cast< int >( mFlags ) );
2372   map.insert( QStringLiteral( "metadata" ), mMetadata );
2373   return map;
2374 }
2375 
fromVariantMap(const QVariantMap & map)2376 bool QgsProcessingParameterDefinition::fromVariantMap( const QVariantMap &map )
2377 {
2378   mName = map.value( QStringLiteral( "name" ) ).toString();
2379   mDescription = map.value( QStringLiteral( "description" ) ).toString();
2380   mHelp = map.value( QStringLiteral( "help" ) ).toString();
2381   mDefault = map.value( QStringLiteral( "default" ) );
2382   mGuiDefault = map.value( QStringLiteral( "defaultGui" ) );
2383   mFlags = static_cast< Flags >( map.value( QStringLiteral( "flags" ) ).toInt() );
2384   mMetadata = map.value( QStringLiteral( "metadata" ) ).toMap();
2385   return true;
2386 }
2387 
algorithm() const2388 QgsProcessingAlgorithm *QgsProcessingParameterDefinition::algorithm() const
2389 {
2390   return mAlgorithm;
2391 }
2392 
provider() const2393 QgsProcessingProvider *QgsProcessingParameterDefinition::provider() const
2394 {
2395   return mAlgorithm ? mAlgorithm->provider() : nullptr;
2396 }
2397 
toolTip() const2398 QString QgsProcessingParameterDefinition::toolTip() const
2399 {
2400   QString text = QStringLiteral( "<p><b>%1</b></p>" ).arg( description() );
2401   if ( !help().isEmpty() )
2402   {
2403     text += QStringLiteral( "<p>%1</p>" ).arg( help() );
2404   }
2405   text += QStringLiteral( "<p>%1</p>" ).arg( QObject::tr( "Python identifier: ‘%1’" ).arg( QStringLiteral( "<i>%1</i>" ).arg( name() ) ) );
2406   return text;
2407 }
2408 
QgsProcessingParameterBoolean(const QString & name,const QString & description,const QVariant & defaultValue,bool optional)2409 QgsProcessingParameterBoolean::QgsProcessingParameterBoolean( const QString &name, const QString &description, const QVariant &defaultValue, bool optional )
2410   : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
2411 {}
2412 
clone() const2413 QgsProcessingParameterDefinition *QgsProcessingParameterBoolean::clone() const
2414 {
2415   return new QgsProcessingParameterBoolean( *this );
2416 }
2417 
valueAsPythonString(const QVariant & val,QgsProcessingContext &) const2418 QString QgsProcessingParameterBoolean::valueAsPythonString( const QVariant &val, QgsProcessingContext & ) const
2419 {
2420   if ( !val.isValid() )
2421     return QStringLiteral( "None" );
2422 
2423   if ( val.canConvert<QgsProperty>() )
2424     return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( val.value< QgsProperty >().asExpression() );
2425   return val.toBool() ? QStringLiteral( "True" ) : QStringLiteral( "False" );
2426 }
2427 
asScriptCode() const2428 QString QgsProcessingParameterBoolean::asScriptCode() const
2429 {
2430   QString code = QStringLiteral( "##%1=" ).arg( mName );
2431   if ( mFlags & FlagOptional )
2432     code += QLatin1String( "optional " );
2433   code += type() + ' ';
2434   code += mDefault.toBool() ? QStringLiteral( "true" ) : QStringLiteral( "false" );
2435   return code.trimmed();
2436 }
2437 
fromScriptCode(const QString & name,const QString & description,bool isOptional,const QString & definition)2438 QgsProcessingParameterBoolean *QgsProcessingParameterBoolean::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
2439 {
2440   return new QgsProcessingParameterBoolean( name, description, definition.toLower().trimmed() != QStringLiteral( "false" ), isOptional );
2441 }
2442 
QgsProcessingParameterCrs(const QString & name,const QString & description,const QVariant & defaultValue,bool optional)2443 QgsProcessingParameterCrs::QgsProcessingParameterCrs( const QString &name, const QString &description, const QVariant &defaultValue, bool optional )
2444   : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
2445 {
2446 
2447 }
2448 
clone() const2449 QgsProcessingParameterDefinition *QgsProcessingParameterCrs::clone() const
2450 {
2451   return new QgsProcessingParameterCrs( *this );
2452 }
2453 
checkValueIsAcceptable(const QVariant & input,QgsProcessingContext *) const2454 bool QgsProcessingParameterCrs::checkValueIsAcceptable( const QVariant &input, QgsProcessingContext * ) const
2455 {
2456   if ( !input.isValid() )
2457     return mFlags & FlagOptional;
2458 
2459   if ( input.canConvert<QgsCoordinateReferenceSystem>() )
2460   {
2461     return true;
2462   }
2463   else if ( input.canConvert<QgsProcessingFeatureSourceDefinition>() )
2464   {
2465     return true;
2466   }
2467   else if ( input.canConvert<QgsProcessingOutputLayerDefinition>() )
2468   {
2469     return true;
2470   }
2471 
2472   if ( input.canConvert<QgsProperty>() )
2473   {
2474     return true;
2475   }
2476 
2477   // direct map layer value
2478   if ( qobject_cast< QgsMapLayer * >( qvariant_cast<QObject *>( input ) ) )
2479     return true;
2480 
2481   if ( input.type() != QVariant::String || input.toString().isEmpty() )
2482     return mFlags & FlagOptional;
2483 
2484   return true;
2485 }
2486 
valueAsPythonString(const QVariant & value,QgsProcessingContext & context) const2487 QString QgsProcessingParameterCrs::valueAsPythonString( const QVariant &value, QgsProcessingContext &context ) const
2488 {
2489   if ( !value.isValid() )
2490     return QStringLiteral( "None" );
2491 
2492   if ( value.canConvert<QgsCoordinateReferenceSystem>() )
2493   {
2494     if ( !value.value< QgsCoordinateReferenceSystem >().isValid() )
2495       return QStringLiteral( "QgsCoordinateReferenceSystem()" );
2496     else
2497       return QStringLiteral( "QgsCoordinateReferenceSystem('%1')" ).arg( value.value< QgsCoordinateReferenceSystem >().authid() );
2498   }
2499 
2500   if ( value.canConvert<QgsProperty>() )
2501     return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
2502 
2503   QVariantMap p;
2504   p.insert( name(), value );
2505   QgsMapLayer *layer = QgsProcessingParameters::parameterAsLayer( this, p, context );
2506   if ( layer )
2507     return QgsProcessingUtils::stringToPythonLiteral( QgsProcessingUtils::normalizeLayerSource( layer->source() ) );
2508 
2509   return QgsProcessingParameterDefinition::valueAsPythonString( value, context );
2510 }
2511 
fromScriptCode(const QString & name,const QString & description,bool isOptional,const QString & definition)2512 QgsProcessingParameterCrs *QgsProcessingParameterCrs::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
2513 {
2514   return new QgsProcessingParameterCrs( name, description, definition.compare( QLatin1String( "none" ), Qt::CaseInsensitive ) == 0 ? QVariant() : definition, isOptional );
2515 }
2516 
QgsProcessingParameterMapLayer(const QString & name,const QString & description,const QVariant & defaultValue,bool optional,const QList<int> & types)2517 QgsProcessingParameterMapLayer::QgsProcessingParameterMapLayer( const QString &name, const QString &description, const QVariant &defaultValue, bool optional, const QList<int> &types )
2518   : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
2519   , QgsProcessingParameterLimitedDataTypes( types )
2520 {
2521 
2522 }
2523 
clone() const2524 QgsProcessingParameterDefinition *QgsProcessingParameterMapLayer::clone() const
2525 {
2526   return new QgsProcessingParameterMapLayer( *this );
2527 }
2528 
checkValueIsAcceptable(const QVariant & input,QgsProcessingContext * context) const2529 bool QgsProcessingParameterMapLayer::checkValueIsAcceptable( const QVariant &input, QgsProcessingContext *context ) const
2530 {
2531   if ( !input.isValid() )
2532     return mFlags & FlagOptional;
2533 
2534   if ( input.canConvert<QgsProperty>() )
2535   {
2536     return true;
2537   }
2538 
2539   if ( qobject_cast< QgsMapLayer * >( qvariant_cast<QObject *>( input ) ) )
2540   {
2541     return true;
2542   }
2543 
2544   if ( input.type() != QVariant::String || input.toString().isEmpty() )
2545     return mFlags & FlagOptional;
2546 
2547   if ( !context )
2548   {
2549     // that's as far as we can get without a context
2550     return true;
2551   }
2552 
2553   // try to load as layer
2554   if ( QgsProcessingUtils::mapLayerFromString( input.toString(), *context ) )
2555     return true;
2556 
2557   return false;
2558 }
2559 
valueAsPythonString(const QVariant & val,QgsProcessingContext & context) const2560 QString QgsProcessingParameterMapLayer::valueAsPythonString( const QVariant &val, QgsProcessingContext &context ) const
2561 {
2562   if ( !val.isValid() )
2563     return QStringLiteral( "None" );
2564 
2565   if ( val.canConvert<QgsProperty>() )
2566     return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( val.value< QgsProperty >().asExpression() );
2567 
2568   QVariantMap p;
2569   p.insert( name(), val );
2570   QgsMapLayer *layer = QgsProcessingParameters::parameterAsLayer( this, p, context );
2571   return layer ? QgsProcessingUtils::stringToPythonLiteral( QgsProcessingUtils::normalizeLayerSource( layer->source() ) )
2572          : QgsProcessingUtils::stringToPythonLiteral( val.toString() );
2573 }
2574 
createAllMapLayerFileFilter()2575 QString createAllMapLayerFileFilter()
2576 {
2577   QStringList vectors = QgsProviderRegistry::instance()->fileVectorFilters().split( QStringLiteral( ";;" ) );
2578   QStringList rasters = QgsProviderRegistry::instance()->fileRasterFilters().split( QStringLiteral( ";;" ) );
2579   for ( const QString &raster : rasters )
2580   {
2581     if ( !vectors.contains( raster ) )
2582       vectors << raster;
2583   }
2584   QStringList meshFilters = QgsProviderRegistry::instance()->fileMeshFilters().split( QStringLiteral( ";;" ) );
2585   for ( const QString &mesh : meshFilters )
2586   {
2587     if ( !vectors.contains( mesh ) )
2588       vectors << mesh;
2589   }
2590   vectors.removeAll( QObject::tr( "All files (*.*)" ) );
2591   std::sort( vectors.begin(), vectors.end() );
2592 
2593   return QObject::tr( "All files (*.*)" ) + QStringLiteral( ";;" ) + vectors.join( QLatin1String( ";;" ) );
2594 }
2595 
createFileFilter() const2596 QString QgsProcessingParameterMapLayer::createFileFilter() const
2597 {
2598   return createAllMapLayerFileFilter();
2599 }
2600 
asScriptCode() const2601 QString QgsProcessingParameterMapLayer::asScriptCode() const
2602 {
2603   QString code = QStringLiteral( "##%1=" ).arg( mName );
2604   if ( mFlags & FlagOptional )
2605     code += QLatin1String( "optional " );
2606   code += QLatin1String( "layer " );
2607 
2608   for ( int type : mDataTypes )
2609   {
2610     switch ( type )
2611     {
2612       case QgsProcessing::TypeVectorAnyGeometry:
2613         code += QLatin1String( "hasgeometry " );
2614         break;
2615 
2616       case QgsProcessing::TypeVectorPoint:
2617         code += QLatin1String( "point " );
2618         break;
2619 
2620       case QgsProcessing::TypeVectorLine:
2621         code += QLatin1String( "line " );
2622         break;
2623 
2624       case QgsProcessing::TypeVectorPolygon:
2625         code += QLatin1String( "polygon " );
2626         break;
2627 
2628       case QgsProcessing::TypeRaster:
2629         code += QLatin1String( "raster " );
2630         break;
2631 
2632       case QgsProcessing::TypeMesh:
2633         code += QLatin1String( "mesh " );
2634         break;
2635     }
2636   }
2637 
2638   code += mDefault.toString();
2639   return code.trimmed();
2640 }
2641 
fromScriptCode(const QString & name,const QString & description,bool isOptional,const QString & definition)2642 QgsProcessingParameterMapLayer *QgsProcessingParameterMapLayer::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
2643 {
2644   QList< int > types;
2645   QString def = definition;
2646   while ( true )
2647   {
2648     if ( def.startsWith( QLatin1String( "hasgeometry" ), Qt::CaseInsensitive ) )
2649     {
2650       types << QgsProcessing::TypeVectorAnyGeometry;
2651       def = def.mid( 12 );
2652       continue;
2653     }
2654     else if ( def.startsWith( QLatin1String( "point" ), Qt::CaseInsensitive ) )
2655     {
2656       types << QgsProcessing::TypeVectorPoint;
2657       def = def.mid( 6 );
2658       continue;
2659     }
2660     else if ( def.startsWith( QLatin1String( "line" ), Qt::CaseInsensitive ) )
2661     {
2662       types << QgsProcessing::TypeVectorLine;
2663       def = def.mid( 5 );
2664       continue;
2665     }
2666     else if ( def.startsWith( QLatin1String( "polygon" ), Qt::CaseInsensitive ) )
2667     {
2668       types << QgsProcessing::TypeVectorPolygon;
2669       def = def.mid( 8 );
2670       continue;
2671     }
2672     else if ( def.startsWith( QLatin1String( "raster" ), Qt::CaseInsensitive ) )
2673     {
2674       types << QgsProcessing::TypeRaster;
2675       def = def.mid( 7 );
2676       continue;
2677     }
2678     else if ( def.startsWith( QLatin1String( "mesh" ), Qt::CaseInsensitive ) )
2679     {
2680       types << QgsProcessing::TypeMesh;
2681       def = def.mid( 5 );
2682       continue;
2683     }
2684     break;
2685   }
2686 
2687   return new QgsProcessingParameterMapLayer( name, description, def, isOptional, types );
2688 }
2689 
asPythonString(const QgsProcessing::PythonOutputType outputType) const2690 QString QgsProcessingParameterMapLayer::asPythonString( const QgsProcessing::PythonOutputType outputType ) const
2691 {
2692   switch ( outputType )
2693   {
2694     case QgsProcessing::PythonQgsProcessingAlgorithmSubclass:
2695     {
2696       QString code = QStringLiteral( "QgsProcessingParameterMapLayer('%1', '%2'" ).arg( name(), description() );
2697       if ( mFlags & FlagOptional )
2698         code += QLatin1String( ", optional=True" );
2699 
2700       QgsProcessingContext c;
2701       code += QStringLiteral( ", defaultValue=%1" ).arg( valueAsPythonString( mDefault, c ) );
2702 
2703       if ( !mDataTypes.empty() )
2704       {
2705         QStringList options;
2706         options.reserve( mDataTypes.size() );
2707         for ( int t : mDataTypes )
2708           options << QStringLiteral( "QgsProcessing.%1" ).arg( QgsProcessing::sourceTypeToString( static_cast< QgsProcessing::SourceType >( t ) ) );
2709         code += QStringLiteral( ", types=[%1])" ).arg( options.join( ',' ) );
2710       }
2711       else
2712       {
2713         code += QLatin1Char( ')' );
2714       }
2715 
2716       return code;
2717     }
2718   }
2719   return QString();
2720 }
2721 
toVariantMap() const2722 QVariantMap QgsProcessingParameterMapLayer::toVariantMap() const
2723 {
2724   QVariantMap map = QgsProcessingParameterDefinition::toVariantMap();
2725   QVariantList types;
2726   for ( int type : mDataTypes )
2727   {
2728     types << type;
2729   }
2730   map.insert( QStringLiteral( "data_types" ), types );
2731   return map;
2732 }
2733 
fromVariantMap(const QVariantMap & map)2734 bool QgsProcessingParameterMapLayer::fromVariantMap( const QVariantMap &map )
2735 {
2736   QgsProcessingParameterDefinition::fromVariantMap( map );
2737   mDataTypes.clear();
2738   const QVariantList values = map.value( QStringLiteral( "data_types" ) ).toList();
2739   for ( const QVariant &val : values )
2740   {
2741     mDataTypes << val.toInt();
2742   }
2743   return true;
2744 }
2745 
QgsProcessingParameterExtent(const QString & name,const QString & description,const QVariant & defaultValue,bool optional)2746 QgsProcessingParameterExtent::QgsProcessingParameterExtent( const QString &name, const QString &description, const QVariant &defaultValue, bool optional )
2747   : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
2748 {
2749 
2750 }
2751 
clone() const2752 QgsProcessingParameterDefinition *QgsProcessingParameterExtent::clone() const
2753 {
2754   return new QgsProcessingParameterExtent( *this );
2755 }
2756 
checkValueIsAcceptable(const QVariant & input,QgsProcessingContext * context) const2757 bool QgsProcessingParameterExtent::checkValueIsAcceptable( const QVariant &input, QgsProcessingContext *context ) const
2758 {
2759   if ( !input.isValid() )
2760     return mFlags & FlagOptional;
2761 
2762   if ( input.canConvert<QgsProcessingFeatureSourceDefinition>() )
2763   {
2764     return true;
2765   }
2766   else if ( input.canConvert<QgsProcessingOutputLayerDefinition>() )
2767   {
2768     return true;
2769   }
2770 
2771   if ( input.canConvert<QgsProperty>() )
2772   {
2773     return true;
2774   }
2775 
2776   if ( input.canConvert< QgsRectangle >() )
2777   {
2778     QgsRectangle r = input.value<QgsRectangle>();
2779     return !r.isNull();
2780   }
2781   if ( input.canConvert< QgsGeometry >() )
2782   {
2783     return true;
2784   }
2785   if ( input.canConvert< QgsReferencedRectangle >() )
2786   {
2787     QgsReferencedRectangle r = input.value<QgsReferencedRectangle>();
2788     return !r.isNull();
2789   }
2790 
2791   // direct map layer value
2792   if ( qobject_cast< QgsMapLayer * >( qvariant_cast<QObject *>( input ) ) )
2793     return true;
2794 
2795   if ( input.type() != QVariant::String || input.toString().isEmpty() )
2796     return mFlags & FlagOptional;
2797 
2798   if ( !context )
2799   {
2800     // that's as far as we can get without a context
2801     return true;
2802   }
2803 
2804   QRegularExpression rx( QStringLiteral( "^(.*?)\\s*,\\s*(.*?)\\s*,\\s*(.*?)\\s*,\\s*(.*?)\\s*(?:\\[(.*)\\])?\\s*$" ) );
2805   QRegularExpressionMatch match = rx.match( input.toString() );
2806   if ( match.hasMatch() )
2807   {
2808     bool xMinOk = false;
2809     ( void )match.captured( 1 ).toDouble( &xMinOk );
2810     bool xMaxOk = false;
2811     ( void )match.captured( 2 ).toDouble( &xMaxOk );
2812     bool yMinOk = false;
2813     ( void )match.captured( 3 ).toDouble( &yMinOk );
2814     bool yMaxOk = false;
2815     ( void )match.captured( 4 ).toDouble( &yMaxOk );
2816     if ( xMinOk && xMaxOk && yMinOk && yMaxOk )
2817       return true;
2818   }
2819 
2820   // try as layer extent
2821   return QgsProcessingUtils::mapLayerFromString( input.toString(), *context );
2822 }
2823 
valueAsPythonString(const QVariant & value,QgsProcessingContext & context) const2824 QString QgsProcessingParameterExtent::valueAsPythonString( const QVariant &value, QgsProcessingContext &context ) const
2825 {
2826   if ( !value.isValid() )
2827     return QStringLiteral( "None" );
2828 
2829   if ( value.canConvert<QgsProperty>() )
2830     return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
2831 
2832   if ( value.canConvert< QgsRectangle >() )
2833   {
2834     QgsRectangle r = value.value<QgsRectangle>();
2835     return QStringLiteral( "'%1, %3, %2, %4'" ).arg( qgsDoubleToString( r.xMinimum() ),
2836            qgsDoubleToString( r.yMinimum() ),
2837            qgsDoubleToString( r.xMaximum() ),
2838            qgsDoubleToString( r.yMaximum() ) );
2839   }
2840   else if ( value.canConvert< QgsReferencedRectangle >() )
2841   {
2842     QgsReferencedRectangle r = value.value<QgsReferencedRectangle>();
2843     return QStringLiteral( "'%1, %3, %2, %4 [%5]'" ).arg( qgsDoubleToString( r.xMinimum() ),
2844            qgsDoubleToString( r.yMinimum() ),
2845            qgsDoubleToString( r.xMaximum() ),
2846            qgsDoubleToString( r.yMaximum() ),                                                                                                                             r.crs().authid() );
2847   }
2848   else if ( value.canConvert< QgsGeometry >() )
2849   {
2850     const QgsGeometry g = value.value<QgsGeometry>();
2851     if ( !g.isNull() )
2852     {
2853       const QString wkt = g.asWkt();
2854       return QStringLiteral( "QgsGeometry.fromWkt('%1')" ).arg( wkt );
2855     }
2856   }
2857 
2858   QVariantMap p;
2859   p.insert( name(), value );
2860   QgsMapLayer *layer = QgsProcessingParameters::parameterAsLayer( this, p, context );
2861   if ( layer )
2862     return QgsProcessingUtils::stringToPythonLiteral( QgsProcessingUtils::normalizeLayerSource( layer->source() ) );
2863 
2864   return QgsProcessingParameterDefinition::valueAsPythonString( value, context );
2865 }
2866 
fromScriptCode(const QString & name,const QString & description,bool isOptional,const QString & definition)2867 QgsProcessingParameterExtent *QgsProcessingParameterExtent::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
2868 {
2869   return new QgsProcessingParameterExtent( name, description, definition, isOptional );
2870 }
2871 
QgsProcessingParameterPoint(const QString & name,const QString & description,const QVariant & defaultValue,bool optional)2872 QgsProcessingParameterPoint::QgsProcessingParameterPoint( const QString &name, const QString &description, const QVariant &defaultValue, bool optional )
2873   : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
2874 {
2875 
2876 }
2877 
clone() const2878 QgsProcessingParameterDefinition *QgsProcessingParameterPoint::clone() const
2879 {
2880   return new QgsProcessingParameterPoint( *this );
2881 }
2882 
checkValueIsAcceptable(const QVariant & input,QgsProcessingContext *) const2883 bool QgsProcessingParameterPoint::checkValueIsAcceptable( const QVariant &input, QgsProcessingContext * ) const
2884 {
2885   if ( !input.isValid() )
2886     return mFlags & FlagOptional;
2887 
2888   if ( input.canConvert<QgsProperty>() )
2889   {
2890     return true;
2891   }
2892 
2893   if ( input.canConvert< QgsPointXY >() )
2894   {
2895     return true;
2896   }
2897   if ( input.canConvert< QgsReferencedPointXY >() )
2898   {
2899     return true;
2900   }
2901   if ( input.canConvert< QgsGeometry >() )
2902   {
2903     return true;
2904   }
2905 
2906   if ( input.type() == QVariant::String )
2907   {
2908     if ( input.toString().isEmpty() )
2909       return mFlags & FlagOptional;
2910   }
2911 
2912   QRegularExpression rx( QStringLiteral( "^\\s*\\(?\\s*(.*?)\\s*,\\s*(.*?)\\s*(?:\\[(.*)\\])?\\s*\\)?\\s*$" ) );
2913 
2914   QRegularExpressionMatch match = rx.match( input.toString() );
2915   if ( match.hasMatch() )
2916   {
2917     bool xOk = false;
2918     ( void )match.captured( 1 ).toDouble( &xOk );
2919     bool yOk = false;
2920     ( void )match.captured( 2 ).toDouble( &yOk );
2921     return xOk && yOk;
2922   }
2923   else
2924     return false;
2925 }
2926 
valueAsPythonString(const QVariant & value,QgsProcessingContext & context) const2927 QString QgsProcessingParameterPoint::valueAsPythonString( const QVariant &value, QgsProcessingContext &context ) const
2928 {
2929   if ( !value.isValid() )
2930     return QStringLiteral( "None" );
2931 
2932   if ( value.canConvert<QgsProperty>() )
2933     return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
2934 
2935   if ( value.canConvert< QgsPointXY >() )
2936   {
2937     QgsPointXY r = value.value<QgsPointXY>();
2938     return QStringLiteral( "'%1,%2'" ).arg( qgsDoubleToString( r.x() ),
2939                                             qgsDoubleToString( r.y() ) );
2940   }
2941   else if ( value.canConvert< QgsReferencedPointXY >() )
2942   {
2943     QgsReferencedPointXY r = value.value<QgsReferencedPointXY>();
2944     return QStringLiteral( "'%1,%2 [%3]'" ).arg( qgsDoubleToString( r.x() ),
2945            qgsDoubleToString( r.y() ),
2946            r.crs().authid() );
2947   }
2948   else if ( value.canConvert< QgsGeometry >() )
2949   {
2950     const QgsGeometry g = value.value<QgsGeometry>();
2951     if ( !g.isNull() )
2952     {
2953       const QString wkt = g.asWkt();
2954       return QStringLiteral( "QgsGeometry.fromWkt('%1')" ).arg( wkt );
2955     }
2956   }
2957 
2958   return QgsProcessingParameterDefinition::valueAsPythonString( value, context );
2959 }
2960 
fromScriptCode(const QString & name,const QString & description,bool isOptional,const QString & definition)2961 QgsProcessingParameterPoint *QgsProcessingParameterPoint::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
2962 {
2963   return new QgsProcessingParameterPoint( name, description, definition, isOptional );
2964 }
2965 
QgsProcessingParameterGeometry(const QString & name,const QString & description,const QVariant & defaultValue,bool optional,const QList<int> & geometryTypes,bool allowMultipart)2966 QgsProcessingParameterGeometry::QgsProcessingParameterGeometry( const QString &name, const QString &description,
2967     const QVariant &defaultValue, bool optional, const QList<int> &geometryTypes, bool allowMultipart )
2968   : QgsProcessingParameterDefinition( name, description, defaultValue, optional ),
2969     mGeomTypes( geometryTypes ),
2970     mAllowMultipart( allowMultipart )
2971 {
2972 
2973 }
2974 
clone() const2975 QgsProcessingParameterDefinition *QgsProcessingParameterGeometry::clone() const
2976 {
2977   return new QgsProcessingParameterGeometry( *this );
2978 }
2979 
checkValueIsAcceptable(const QVariant & input,QgsProcessingContext *) const2980 bool QgsProcessingParameterGeometry::checkValueIsAcceptable( const QVariant &input, QgsProcessingContext * ) const
2981 {
2982   if ( !input.isValid() )
2983     return mFlags & FlagOptional;
2984 
2985   if ( input.canConvert<QgsProperty>() )
2986   {
2987     return true;
2988   }
2989 
2990   bool anyTypeAllowed = mGeomTypes.isEmpty() || mGeomTypes.contains( QgsWkbTypes::UnknownGeometry );
2991 
2992   if ( input.canConvert< QgsGeometry >() )
2993   {
2994     return ( anyTypeAllowed || mGeomTypes.contains( input.value<QgsGeometry>().type() ) ) &&
2995            ( mAllowMultipart || !input.value<QgsGeometry>().isMultipart() );
2996   }
2997 
2998   if ( input.canConvert< QgsReferencedGeometry >() )
2999   {
3000     return ( anyTypeAllowed || mGeomTypes.contains( input.value<QgsReferencedGeometry>().type() ) ) &&
3001            ( mAllowMultipart || !input.value<QgsReferencedGeometry>().isMultipart() );
3002   }
3003 
3004   if ( input.canConvert< QgsPointXY >() )
3005   {
3006     return anyTypeAllowed || mGeomTypes.contains( QgsWkbTypes::PointGeometry );
3007   }
3008 
3009   if ( input.canConvert< QgsRectangle >() )
3010   {
3011     return anyTypeAllowed || mGeomTypes.contains( QgsWkbTypes::PolygonGeometry );
3012   }
3013 
3014   if ( input.canConvert< QgsReferencedPointXY >() )
3015   {
3016     return anyTypeAllowed || mGeomTypes.contains( QgsWkbTypes::PointGeometry );
3017   }
3018 
3019   if ( input.canConvert< QgsReferencedRectangle >() )
3020   {
3021     return anyTypeAllowed || mGeomTypes.contains( QgsWkbTypes::PolygonGeometry );
3022   }
3023 
3024   if ( input.type() == QVariant::String )
3025   {
3026     if ( input.toString().isEmpty() )
3027       return mFlags & FlagOptional;
3028   }
3029 
3030   // Match against EWKT
3031   QRegularExpression rx( QStringLiteral( "^\\s*(?:CRS=(.*);)?(.*?)$" ) );
3032 
3033   QRegularExpressionMatch match = rx.match( input.toString() );
3034   if ( match.hasMatch() )
3035   {
3036     QgsGeometry g = QgsGeometry::fromWkt( match.captured( 2 ) );
3037     if ( ! g.isNull() )
3038     {
3039       return ( anyTypeAllowed || mGeomTypes.contains( g.type() ) ) && ( mAllowMultipart || !g.isMultipart() );
3040     }
3041     else
3042     {
3043       QgsMessageLog::logMessage( QObject::tr( "Error creating geometry: \"%1\"" ).arg( g.lastError() ), QObject::tr( "Processing" ) );
3044     }
3045   }
3046   return false;
3047 }
3048 
valueAsPythonString(const QVariant & value,QgsProcessingContext & context) const3049 QString QgsProcessingParameterGeometry::valueAsPythonString( const QVariant &value, QgsProcessingContext &context ) const
3050 {
3051   auto asPythonString = []( const QgsGeometry & g, const QgsCoordinateReferenceSystem &crs = QgsCoordinateReferenceSystem() )
3052   {
3053     if ( !crs.isValid() )
3054       return QgsProcessingUtils::stringToPythonLiteral( g.asWkt() );
3055     else
3056       return QgsProcessingUtils::stringToPythonLiteral( QStringLiteral( "CRS=%1;%2" ).arg( crs.authid().isEmpty() ? crs.toWkt( QgsCoordinateReferenceSystem::WKT_PREFERRED ) : crs.authid(), g.asWkt() ) );
3057   };
3058 
3059   if ( !value.isValid() )
3060     return QStringLiteral( "None" );
3061 
3062   if ( value.canConvert<QgsProperty>() )
3063     return QStringLiteral( "QgsProperty.fromExpression(%1)" ).arg( QgsProcessingUtils::stringToPythonLiteral( value.value< QgsProperty >().asExpression() ) );
3064 
3065   if ( value.canConvert< QgsGeometry >() )
3066   {
3067     const QgsGeometry g = value.value<QgsGeometry>();
3068     if ( !g.isNull() )
3069       return asPythonString( g );
3070   }
3071 
3072   if ( value.canConvert< QgsReferencedGeometry >() )
3073   {
3074     const QgsReferencedGeometry g = value.value<QgsReferencedGeometry>();
3075     if ( !g.isNull() )
3076       return asPythonString( g, g.crs() );
3077   }
3078 
3079   if ( value.canConvert< QgsPointXY >() )
3080   {
3081     const QgsGeometry g = QgsGeometry::fromPointXY( value.value<QgsPointXY>() );
3082     if ( !g.isNull() )
3083       return asPythonString( g );
3084   }
3085 
3086   if ( value.canConvert< QgsReferencedPointXY >() )
3087   {
3088     const QgsReferencedGeometry g = QgsReferencedGeometry::fromReferencedPointXY( value.value<QgsReferencedPointXY>() );
3089     if ( !g.isNull() )
3090       return asPythonString( g, g.crs() );
3091   }
3092 
3093   if ( value.canConvert< QgsRectangle >() )
3094   {
3095     const QgsGeometry g = QgsGeometry::fromRect( value.value<QgsRectangle>() );
3096     if ( !g.isNull() )
3097       return asPythonString( g );
3098   }
3099 
3100   if ( value.canConvert< QgsReferencedRectangle >() )
3101   {
3102     const QgsReferencedGeometry g = QgsReferencedGeometry::fromReferencedRect( value.value<QgsReferencedRectangle>() );
3103     if ( !g.isNull() )
3104       return asPythonString( g, g.crs() );
3105   }
3106 
3107   return QgsProcessingParameterDefinition::valueAsPythonString( value, context );
3108 }
3109 
asScriptCode() const3110 QString QgsProcessingParameterGeometry::asScriptCode() const
3111 {
3112   QString code = QStringLiteral( "##%1=" ).arg( mName );
3113   if ( mFlags & FlagOptional )
3114     code += QLatin1String( "optional " );
3115   code += type() + ' ';
3116 
3117   for ( int type : mGeomTypes )
3118   {
3119     switch ( static_cast<QgsWkbTypes::GeometryType>( type ) )
3120     {
3121       case QgsWkbTypes::PointGeometry:
3122         code += QLatin1String( "point " );
3123         break;
3124 
3125       case QgsWkbTypes::LineGeometry:
3126         code += QLatin1String( "line " );
3127         break;
3128 
3129       case QgsWkbTypes::PolygonGeometry:
3130         code += QLatin1String( "polygon " );
3131         break;
3132 
3133       default:
3134         code += QLatin1String( "unknown " );
3135         break;
3136     }
3137   }
3138 
3139   code += mDefault.toString();
3140   return code.trimmed();
3141 }
3142 
asPythonString(const QgsProcessing::PythonOutputType outputType) const3143 QString QgsProcessingParameterGeometry::asPythonString( const QgsProcessing::PythonOutputType outputType ) const
3144 {
3145   switch ( outputType )
3146   {
3147     case QgsProcessing::PythonQgsProcessingAlgorithmSubclass:
3148     {
3149       QString code = QStringLiteral( "QgsProcessingParameterGeometry('%1', '%2'" ).arg( name(), description() );
3150       if ( mFlags & FlagOptional )
3151         code += QLatin1String( ", optional=True" );
3152 
3153       if ( !mGeomTypes.empty() )
3154       {
3155         auto geomTypeToString = []( QgsWkbTypes::GeometryType t ) -> QString
3156         {
3157           switch ( t )
3158           {
3159             case QgsWkbTypes::PointGeometry:
3160               return QStringLiteral( "PointGeometry" );
3161 
3162             case QgsWkbTypes::LineGeometry:
3163               return QStringLiteral( "LineGeometry" );
3164 
3165             case QgsWkbTypes::PolygonGeometry:
3166               return QStringLiteral( "PolygonGeometry" );
3167 
3168             case QgsWkbTypes::UnknownGeometry:
3169               return QStringLiteral( "UnknownGeometry" );
3170 
3171             case QgsWkbTypes::NullGeometry:
3172               return QStringLiteral( "NullGeometry" );
3173           }
3174           return QString();
3175         };
3176 
3177         QStringList options;
3178         options.reserve( mGeomTypes.size() );
3179         for ( int type : mGeomTypes )
3180         {
3181           options << QStringLiteral( " QgsWkbTypes.%1" ).arg( geomTypeToString( static_cast<QgsWkbTypes::GeometryType>( type ) ) );
3182         }
3183         code += QStringLiteral( ", geometryTypes=[%1 ]" ).arg( options.join( ',' ) );
3184       }
3185 
3186       if ( ! mAllowMultipart )
3187       {
3188         code += QStringLiteral( ", allowMultipart=False" );
3189       }
3190 
3191       QgsProcessingContext c;
3192       code += QStringLiteral( ", defaultValue=%1)" ).arg( valueAsPythonString( mDefault, c ) );
3193       return code;
3194     }
3195   }
3196   return QString();
3197 }
3198 
toVariantMap() const3199 QVariantMap QgsProcessingParameterGeometry::toVariantMap() const
3200 {
3201   QVariantMap map = QgsProcessingParameterDefinition::toVariantMap();
3202   QVariantList types;
3203   for ( int type : mGeomTypes )
3204   {
3205     types << type;
3206   }
3207   map.insert( QStringLiteral( "geometrytypes" ), types );
3208   map.insert( QStringLiteral( "multipart" ), mAllowMultipart );
3209   return map;
3210 }
3211 
fromVariantMap(const QVariantMap & map)3212 bool QgsProcessingParameterGeometry::fromVariantMap( const QVariantMap &map )
3213 {
3214   QgsProcessingParameterDefinition::fromVariantMap( map );
3215   mGeomTypes.clear();
3216   const QVariantList values = map.value( QStringLiteral( "geometrytypes" ) ).toList();
3217   for ( const QVariant &val : values )
3218   {
3219     mGeomTypes << val.toInt();
3220   }
3221   mAllowMultipart = map.value( QStringLiteral( "multipart" ) ).toBool();
3222   return true;
3223 }
3224 
fromScriptCode(const QString & name,const QString & description,bool isOptional,const QString & definition)3225 QgsProcessingParameterGeometry *QgsProcessingParameterGeometry::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
3226 {
3227   return new QgsProcessingParameterGeometry( name, description, definition, isOptional );
3228 }
3229 
QgsProcessingParameterFile(const QString & name,const QString & description,Behavior behavior,const QString & extension,const QVariant & defaultValue,bool optional,const QString & fileFilter)3230 QgsProcessingParameterFile::QgsProcessingParameterFile( const QString &name, const QString &description, Behavior behavior, const QString &extension, const QVariant &defaultValue, bool optional, const QString &fileFilter )
3231   : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
3232   , mBehavior( behavior )
3233   , mExtension( fileFilter.isEmpty() ? extension : QString() )
3234   , mFileFilter( fileFilter.isEmpty() && extension.isEmpty() ? QObject::tr( "All files (*.*)" ) : fileFilter )
3235 {
3236 
3237 }
3238 
clone() const3239 QgsProcessingParameterDefinition *QgsProcessingParameterFile::clone() const
3240 {
3241   return new QgsProcessingParameterFile( *this );
3242 }
3243 
checkValueIsAcceptable(const QVariant & input,QgsProcessingContext *) const3244 bool QgsProcessingParameterFile::checkValueIsAcceptable( const QVariant &input, QgsProcessingContext * ) const
3245 {
3246   if ( !input.isValid() )
3247     return mFlags & FlagOptional;
3248 
3249   if ( input.canConvert<QgsProperty>() )
3250   {
3251     return true;
3252   }
3253 
3254   QString string = input.toString().trimmed();
3255 
3256   if ( input.type() != QVariant::String || string.isEmpty() )
3257     return mFlags & FlagOptional;
3258 
3259   switch ( mBehavior )
3260   {
3261     case File:
3262     {
3263       if ( !mExtension.isEmpty() )
3264       {
3265         return string.endsWith( mExtension, Qt::CaseInsensitive );
3266       }
3267       else if ( !mFileFilter.isEmpty() )
3268       {
3269         const QString test = QgsFileUtils::addExtensionFromFilter( string, mFileFilter );
3270         return test == string;
3271       }
3272       else
3273       {
3274         return true;
3275       }
3276     }
3277 
3278     case Folder:
3279       return true;
3280   }
3281   return true;
3282 }
3283 
asScriptCode() const3284 QString QgsProcessingParameterFile::asScriptCode() const
3285 {
3286   QString code = QStringLiteral( "##%1=" ).arg( mName );
3287   if ( mFlags & FlagOptional )
3288     code += QLatin1String( "optional " );
3289   code += ( mBehavior == File ? QStringLiteral( "file" ) : QStringLiteral( "folder" ) ) + ' ';
3290   code += mDefault.toString();
3291   return code.trimmed();
3292 }
3293 
asPythonString(const QgsProcessing::PythonOutputType outputType) const3294 QString QgsProcessingParameterFile::asPythonString( const QgsProcessing::PythonOutputType outputType ) const
3295 {
3296   switch ( outputType )
3297   {
3298     case QgsProcessing::PythonQgsProcessingAlgorithmSubclass:
3299     {
3300 
3301       QString code = QStringLiteral( "QgsProcessingParameterFile('%1', '%2'" ).arg( name(), description() );
3302       if ( mFlags & FlagOptional )
3303         code += QLatin1String( ", optional=True" );
3304       code += QStringLiteral( ", behavior=%1" ).arg( mBehavior == File ? QStringLiteral( "QgsProcessingParameterFile.File" ) : QStringLiteral( "QgsProcessingParameterFile.Folder" ) );
3305       if ( !mExtension.isEmpty() )
3306         code += QStringLiteral( ", extension='%1'" ).arg( mExtension );
3307       if ( !mFileFilter.isEmpty() )
3308         code += QStringLiteral( ", fileFilter='%1'" ).arg( mFileFilter );
3309       QgsProcessingContext c;
3310       code += QStringLiteral( ", defaultValue=%1)" ).arg( valueAsPythonString( mDefault, c ) );
3311       return code;
3312     }
3313   }
3314   return QString();
3315 }
3316 
createFileFilter() const3317 QString QgsProcessingParameterFile::createFileFilter() const
3318 {
3319   switch ( mBehavior )
3320   {
3321     case File:
3322     {
3323       if ( !mFileFilter.isEmpty() )
3324         return mFileFilter != QObject::tr( "All files (*.*)" ) ? mFileFilter + QStringLiteral( ";;" ) + QObject::tr( "All files (*.*)" ) : mFileFilter;
3325       else if ( !mExtension.isEmpty() )
3326         return QObject::tr( "%1 files" ).arg( mExtension.toUpper() ) + QStringLiteral( " (*." ) + mExtension.toLower() +  QStringLiteral( ");;" ) + QObject::tr( "All files (*.*)" );
3327       else
3328         return QObject::tr( "All files (*.*)" );
3329     }
3330 
3331     case Folder:
3332       return QString();
3333   }
3334   return QString();
3335 }
3336 
setExtension(const QString & extension)3337 void QgsProcessingParameterFile::setExtension( const QString &extension )
3338 {
3339   mExtension = extension;
3340   mFileFilter.clear();
3341 }
3342 
fileFilter() const3343 QString QgsProcessingParameterFile::fileFilter() const
3344 {
3345   return mFileFilter;
3346 }
3347 
setFileFilter(const QString & filter)3348 void QgsProcessingParameterFile::setFileFilter( const QString &filter )
3349 {
3350   mFileFilter = filter;
3351   mExtension.clear();
3352 }
3353 
toVariantMap() const3354 QVariantMap QgsProcessingParameterFile::toVariantMap() const
3355 {
3356   QVariantMap map = QgsProcessingParameterDefinition::toVariantMap();
3357   map.insert( QStringLiteral( "behavior" ), mBehavior );
3358   map.insert( QStringLiteral( "extension" ), mExtension );
3359   map.insert( QStringLiteral( "filefilter" ), mFileFilter );
3360   return map;
3361 }
3362 
fromVariantMap(const QVariantMap & map)3363 bool QgsProcessingParameterFile::fromVariantMap( const QVariantMap &map )
3364 {
3365   QgsProcessingParameterDefinition::fromVariantMap( map );
3366   mBehavior = static_cast< Behavior >( map.value( QStringLiteral( "behavior" ) ).toInt() );
3367   mExtension = map.value( QStringLiteral( "extension" ) ).toString();
3368   mFileFilter = map.value( QStringLiteral( "filefilter" ) ).toString();
3369   return true;
3370 }
3371 
fromScriptCode(const QString & name,const QString & description,bool isOptional,const QString & definition,QgsProcessingParameterFile::Behavior behavior)3372 QgsProcessingParameterFile *QgsProcessingParameterFile::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition, QgsProcessingParameterFile::Behavior behavior )
3373 {
3374   return new QgsProcessingParameterFile( name, description, behavior, QString(), definition, isOptional );
3375 }
3376 
QgsProcessingParameterMatrix(const QString & name,const QString & description,int numberRows,bool fixedNumberRows,const QStringList & headers,const QVariant & defaultValue,bool optional)3377 QgsProcessingParameterMatrix::QgsProcessingParameterMatrix( const QString &name, const QString &description, int numberRows, bool fixedNumberRows, const QStringList &headers, const QVariant &defaultValue, bool optional )
3378   : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
3379   , mHeaders( headers )
3380   , mNumberRows( numberRows )
3381   , mFixedNumberRows( fixedNumberRows )
3382 {
3383 
3384 }
3385 
clone() const3386 QgsProcessingParameterDefinition *QgsProcessingParameterMatrix::clone() const
3387 {
3388   return new QgsProcessingParameterMatrix( *this );
3389 }
3390 
checkValueIsAcceptable(const QVariant & input,QgsProcessingContext *) const3391 bool QgsProcessingParameterMatrix::checkValueIsAcceptable( const QVariant &input, QgsProcessingContext * ) const
3392 {
3393   if ( !input.isValid() )
3394     return mFlags & FlagOptional;
3395 
3396   if ( input.type() == QVariant::String )
3397   {
3398     if ( input.toString().isEmpty() )
3399       return mFlags & FlagOptional;
3400     return true;
3401   }
3402   else if ( input.type() == QVariant::List )
3403   {
3404     if ( input.toList().isEmpty() )
3405       return mFlags & FlagOptional;
3406     return true;
3407   }
3408   else if ( input.type() == QVariant::Double || input.type() == QVariant::Int )
3409   {
3410     return true;
3411   }
3412 
3413   return false;
3414 }
3415 
valueAsPythonString(const QVariant & value,QgsProcessingContext & context) const3416 QString QgsProcessingParameterMatrix::valueAsPythonString( const QVariant &value, QgsProcessingContext &context ) const
3417 {
3418   if ( !value.isValid() )
3419     return QStringLiteral( "None" );
3420 
3421   if ( value.canConvert<QgsProperty>() )
3422     return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
3423 
3424   QVariantMap p;
3425   p.insert( name(), value );
3426   QVariantList list = QgsProcessingParameters::parameterAsMatrix( this, p, context );
3427 
3428   return QgsProcessingUtils::variantToPythonLiteral( list );
3429 }
3430 
asPythonString(const QgsProcessing::PythonOutputType outputType) const3431 QString QgsProcessingParameterMatrix::asPythonString( const QgsProcessing::PythonOutputType outputType ) const
3432 {
3433   switch ( outputType )
3434   {
3435     case QgsProcessing::PythonQgsProcessingAlgorithmSubclass:
3436     {
3437       QString code = QStringLiteral( "QgsProcessingParameterMatrix('%1', '%2'" ).arg( name(), description() );
3438       if ( mFlags & FlagOptional )
3439         code += QLatin1String( ", optional=True" );
3440       code += QStringLiteral( ", numberRows=%1" ).arg( mNumberRows );
3441       code += QStringLiteral( ", hasFixedNumberRows=%1" ).arg( mFixedNumberRows ? QStringLiteral( "True" ) : QStringLiteral( "False" ) );
3442 
3443       QStringList headers;
3444       headers.reserve( mHeaders.size() );
3445       for ( const QString &h : mHeaders )
3446         headers << QgsProcessingUtils::stringToPythonLiteral( h );
3447       code += QStringLiteral( ", headers=[%1]" ).arg( headers.join( ',' ) );
3448 
3449       QgsProcessingContext c;
3450       code += QStringLiteral( ", defaultValue=%1)" ).arg( valueAsPythonString( mDefault, c ) );
3451       return code;
3452     }
3453   }
3454   return QString();
3455 }
3456 
headers() const3457 QStringList QgsProcessingParameterMatrix::headers() const
3458 {
3459   return mHeaders;
3460 }
3461 
setHeaders(const QStringList & headers)3462 void QgsProcessingParameterMatrix::setHeaders( const QStringList &headers )
3463 {
3464   mHeaders = headers;
3465 }
3466 
numberRows() const3467 int QgsProcessingParameterMatrix::numberRows() const
3468 {
3469   return mNumberRows;
3470 }
3471 
setNumberRows(int numberRows)3472 void QgsProcessingParameterMatrix::setNumberRows( int numberRows )
3473 {
3474   mNumberRows = numberRows;
3475 }
3476 
hasFixedNumberRows() const3477 bool QgsProcessingParameterMatrix::hasFixedNumberRows() const
3478 {
3479   return mFixedNumberRows;
3480 }
3481 
setHasFixedNumberRows(bool fixedNumberRows)3482 void QgsProcessingParameterMatrix::setHasFixedNumberRows( bool fixedNumberRows )
3483 {
3484   mFixedNumberRows = fixedNumberRows;
3485 }
3486 
toVariantMap() const3487 QVariantMap QgsProcessingParameterMatrix::toVariantMap() const
3488 {
3489   QVariantMap map = QgsProcessingParameterDefinition::toVariantMap();
3490   map.insert( QStringLiteral( "headers" ), mHeaders );
3491   map.insert( QStringLiteral( "rows" ), mNumberRows );
3492   map.insert( QStringLiteral( "fixed_number_rows" ), mFixedNumberRows );
3493   return map;
3494 }
3495 
fromVariantMap(const QVariantMap & map)3496 bool QgsProcessingParameterMatrix::fromVariantMap( const QVariantMap &map )
3497 {
3498   QgsProcessingParameterDefinition::fromVariantMap( map );
3499   mHeaders = map.value( QStringLiteral( "headers" ) ).toStringList();
3500   mNumberRows = map.value( QStringLiteral( "rows" ) ).toInt();
3501   mFixedNumberRows = map.value( QStringLiteral( "fixed_number_rows" ) ).toBool();
3502   return true;
3503 }
3504 
fromScriptCode(const QString & name,const QString & description,bool isOptional,const QString & definition)3505 QgsProcessingParameterMatrix *QgsProcessingParameterMatrix::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
3506 {
3507   return new QgsProcessingParameterMatrix( name, description, 0, false, QStringList(), definition.isEmpty() ? QVariant() : definition, isOptional );
3508 }
3509 
QgsProcessingParameterMultipleLayers(const QString & name,const QString & description,QgsProcessing::SourceType layerType,const QVariant & defaultValue,bool optional)3510 QgsProcessingParameterMultipleLayers::QgsProcessingParameterMultipleLayers( const QString &name, const QString &description, QgsProcessing::SourceType layerType, const QVariant &defaultValue, bool optional )
3511   : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
3512   , mLayerType( layerType )
3513 {
3514 
3515 }
3516 
clone() const3517 QgsProcessingParameterDefinition *QgsProcessingParameterMultipleLayers::clone() const
3518 {
3519   return new QgsProcessingParameterMultipleLayers( *this );
3520 }
3521 
checkValueIsAcceptable(const QVariant & input,QgsProcessingContext * context) const3522 bool QgsProcessingParameterMultipleLayers::checkValueIsAcceptable( const QVariant &input, QgsProcessingContext *context ) const
3523 {
3524   if ( !input.isValid() )
3525     return mFlags & FlagOptional;
3526 
3527   if ( mLayerType != QgsProcessing::TypeFile )
3528   {
3529     if ( qobject_cast< QgsMapLayer * >( qvariant_cast<QObject *>( input ) ) )
3530     {
3531       return true;
3532     }
3533   }
3534 
3535   if ( input.type() == QVariant::String )
3536   {
3537     if ( input.toString().isEmpty() )
3538       return mFlags & FlagOptional;
3539 
3540     if ( mMinimumNumberInputs > 1 )
3541       return false;
3542 
3543     if ( !context )
3544       return true;
3545 
3546     if ( mLayerType != QgsProcessing::TypeFile )
3547       return QgsProcessingUtils::mapLayerFromString( input.toString(), *context );
3548     else
3549       return true;
3550   }
3551   else if ( input.type() == QVariant::List )
3552   {
3553     if ( input.toList().count() < mMinimumNumberInputs )
3554       return mFlags & FlagOptional;
3555 
3556     if ( mMinimumNumberInputs > input.toList().count() )
3557       return false;
3558 
3559     if ( !context )
3560       return true;
3561 
3562     if ( mLayerType != QgsProcessing::TypeFile )
3563     {
3564       const auto constToList = input.toList();
3565       for ( const QVariant &v : constToList )
3566       {
3567         if ( qobject_cast< QgsMapLayer * >( qvariant_cast<QObject *>( v ) ) )
3568           continue;
3569 
3570         if ( !QgsProcessingUtils::mapLayerFromString( v.toString(), *context ) )
3571           return false;
3572       }
3573     }
3574     return true;
3575   }
3576   else if ( input.type() == QVariant::StringList )
3577   {
3578     if ( input.toStringList().count() < mMinimumNumberInputs )
3579       return mFlags & FlagOptional;
3580 
3581     if ( mMinimumNumberInputs > input.toStringList().count() )
3582       return false;
3583 
3584     if ( !context )
3585       return true;
3586 
3587     if ( mLayerType != QgsProcessing::TypeFile )
3588     {
3589       const auto constToStringList = input.toStringList();
3590       for ( const QString &v : constToStringList )
3591       {
3592         if ( !QgsProcessingUtils::mapLayerFromString( v, *context ) )
3593           return false;
3594       }
3595     }
3596     return true;
3597   }
3598   return false;
3599 }
3600 
valueAsPythonString(const QVariant & value,QgsProcessingContext & context) const3601 QString QgsProcessingParameterMultipleLayers::valueAsPythonString( const QVariant &value, QgsProcessingContext &context ) const
3602 {
3603   if ( !value.isValid() )
3604     return QStringLiteral( "None" );
3605 
3606   if ( value.canConvert<QgsProperty>() )
3607     return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
3608 
3609   if ( mLayerType == QgsProcessing::TypeFile )
3610   {
3611     QStringList parts;
3612     if ( value.type() == QVariant::StringList )
3613     {
3614       const QStringList list = value.toStringList();
3615       parts.reserve( list.count() );
3616       for ( const QString &v : list )
3617         parts <<  QgsProcessingUtils::stringToPythonLiteral( v );
3618     }
3619     else if ( value.type() == QVariant::List )
3620     {
3621       const QVariantList list = value.toList();
3622       parts.reserve( list.count() );
3623       for ( const QVariant &v : list )
3624         parts <<  QgsProcessingUtils::stringToPythonLiteral( v.toString() );
3625     }
3626     if ( !parts.isEmpty() )
3627       return parts.join( ',' ).prepend( '[' ).append( ']' );
3628   }
3629   else
3630   {
3631     QVariantMap p;
3632     p.insert( name(), value );
3633     const QList<QgsMapLayer *> list = QgsProcessingParameters::parameterAsLayerList( this, p, context );
3634     if ( !list.isEmpty() )
3635     {
3636       QStringList parts;
3637       parts.reserve( list.count() );
3638       for ( const QgsMapLayer *layer : list )
3639       {
3640         parts << QgsProcessingUtils::stringToPythonLiteral( QgsProcessingUtils::normalizeLayerSource( layer->source() ) );
3641       }
3642       return parts.join( ',' ).prepend( '[' ).append( ']' );
3643     }
3644   }
3645 
3646   return QgsProcessingParameterDefinition::valueAsPythonString( value, context );
3647 }
3648 
asScriptCode() const3649 QString QgsProcessingParameterMultipleLayers::asScriptCode() const
3650 {
3651   QString code = QStringLiteral( "##%1=" ).arg( mName );
3652   if ( mFlags & FlagOptional )
3653     code += QLatin1String( "optional " );
3654   switch ( mLayerType )
3655   {
3656     case QgsProcessing::TypeRaster:
3657       code += QLatin1String( "multiple raster" );
3658       break;
3659 
3660     case QgsProcessing::TypeFile:
3661       code += QLatin1String( "multiple file" );
3662       break;
3663 
3664     default:
3665       code += QLatin1String( "multiple vector" );
3666       break;
3667   }
3668   code += ' ';
3669   if ( mDefault.type() == QVariant::List )
3670   {
3671     QStringList parts;
3672     const auto constToList = mDefault.toList();
3673     for ( const QVariant &var : constToList )
3674     {
3675       parts << var.toString();
3676     }
3677     code += parts.join( ',' );
3678   }
3679   else if ( mDefault.type() == QVariant::StringList )
3680   {
3681     code += mDefault.toStringList().join( ',' );
3682   }
3683   else
3684   {
3685     code += mDefault.toString();
3686   }
3687   return code.trimmed();
3688 }
3689 
asPythonString(const QgsProcessing::PythonOutputType outputType) const3690 QString QgsProcessingParameterMultipleLayers::asPythonString( const QgsProcessing::PythonOutputType outputType ) const
3691 {
3692   switch ( outputType )
3693   {
3694     case QgsProcessing::PythonQgsProcessingAlgorithmSubclass:
3695     {
3696       QString code = QStringLiteral( "QgsProcessingParameterMultipleLayers('%1', '%2'" ).arg( name(), description() );
3697       if ( mFlags & FlagOptional )
3698         code += QLatin1String( ", optional=True" );
3699 
3700       QString layerType = QStringLiteral( "QgsProcessing.%1" ).arg( QgsProcessing::sourceTypeToString( mLayerType ) );
3701 
3702       code += QStringLiteral( ", layerType=%1" ).arg( layerType );
3703       QgsProcessingContext c;
3704       code += QStringLiteral( ", defaultValue=%1)" ).arg( valueAsPythonString( mDefault, c ) );
3705       return code;
3706     }
3707   }
3708   return QString();
3709 }
3710 
createFileFilter() const3711 QString QgsProcessingParameterMultipleLayers::createFileFilter() const
3712 {
3713   QStringList exts;
3714   switch ( mLayerType )
3715   {
3716     case QgsProcessing::TypeFile:
3717       return QObject::tr( "All files (*.*)" );
3718 
3719     case QgsProcessing::TypeRaster:
3720       return QgsProviderRegistry::instance()->fileRasterFilters() + QStringLiteral( ";;" ) + QObject::tr( "All files (*.*)" );
3721 
3722     case QgsProcessing::TypeVector:
3723     case QgsProcessing::TypeVectorAnyGeometry:
3724     case QgsProcessing::TypeVectorPoint:
3725     case QgsProcessing::TypeVectorLine:
3726     case QgsProcessing::TypeVectorPolygon:
3727       return QgsProviderRegistry::instance()->fileVectorFilters() + QStringLiteral( ";;" ) + QObject::tr( "All files (*.*)" );
3728 
3729     case QgsProcessing::TypeMesh:
3730       return QgsProviderRegistry::instance()->fileMeshFilters() + QStringLiteral( ";;" ) + QObject::tr( "All files (*.*)" );
3731 
3732     case QgsProcessing::TypeMapLayer:
3733       return createAllMapLayerFileFilter();
3734   }
3735   return QString();
3736 }
3737 
layerType() const3738 QgsProcessing::SourceType QgsProcessingParameterMultipleLayers::layerType() const
3739 {
3740   return mLayerType;
3741 }
3742 
setLayerType(QgsProcessing::SourceType type)3743 void QgsProcessingParameterMultipleLayers::setLayerType( QgsProcessing::SourceType type )
3744 {
3745   mLayerType = type;
3746 }
3747 
minimumNumberInputs() const3748 int QgsProcessingParameterMultipleLayers::minimumNumberInputs() const
3749 {
3750   return mMinimumNumberInputs;
3751 }
3752 
setMinimumNumberInputs(int minimumNumberInputs)3753 void QgsProcessingParameterMultipleLayers::setMinimumNumberInputs( int minimumNumberInputs )
3754 {
3755   if ( mMinimumNumberInputs >= 1 || !( flags() & QgsProcessingParameterDefinition::FlagOptional ) )
3756     mMinimumNumberInputs = minimumNumberInputs;
3757 }
3758 
toVariantMap() const3759 QVariantMap QgsProcessingParameterMultipleLayers::toVariantMap() const
3760 {
3761   QVariantMap map = QgsProcessingParameterDefinition::toVariantMap();
3762   map.insert( QStringLiteral( "layer_type" ), mLayerType );
3763   map.insert( QStringLiteral( "min_inputs" ), mMinimumNumberInputs );
3764   return map;
3765 }
3766 
fromVariantMap(const QVariantMap & map)3767 bool QgsProcessingParameterMultipleLayers::fromVariantMap( const QVariantMap &map )
3768 {
3769   QgsProcessingParameterDefinition::fromVariantMap( map );
3770   mLayerType = static_cast< QgsProcessing::SourceType >( map.value( QStringLiteral( "layer_type" ) ).toInt() );
3771   mMinimumNumberInputs = map.value( QStringLiteral( "min_inputs" ) ).toInt();
3772   return true;
3773 }
3774 
fromScriptCode(const QString & name,const QString & description,bool isOptional,const QString & definition)3775 QgsProcessingParameterMultipleLayers *QgsProcessingParameterMultipleLayers::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
3776 {
3777   QString type = definition;
3778   QString defaultVal;
3779   QRegularExpression re( QStringLiteral( "(.*?)\\s+(.*)" ) );
3780   QRegularExpressionMatch m = re.match( definition );
3781   if ( m.hasMatch() )
3782   {
3783     type = m.captured( 1 ).toLower().trimmed();
3784     defaultVal = m.captured( 2 );
3785   }
3786   QgsProcessing::SourceType layerType = QgsProcessing::TypeVectorAnyGeometry;
3787   if ( type == QLatin1String( "vector" ) )
3788     layerType = QgsProcessing::TypeVectorAnyGeometry;
3789   else if ( type == QLatin1String( "raster" ) )
3790     layerType = QgsProcessing::TypeRaster;
3791   else if ( type == QLatin1String( "file" ) )
3792     layerType = QgsProcessing::TypeFile;
3793   return new QgsProcessingParameterMultipleLayers( name, description, layerType, defaultVal.isEmpty() ? QVariant() : defaultVal, isOptional );
3794 }
3795 
QgsProcessingParameterNumber(const QString & name,const QString & description,Type type,const QVariant & defaultValue,bool optional,double minValue,double maxValue)3796 QgsProcessingParameterNumber::QgsProcessingParameterNumber( const QString &name, const QString &description, Type type, const QVariant &defaultValue, bool optional, double minValue, double maxValue )
3797   : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
3798   , mMin( minValue )
3799   , mMax( maxValue )
3800   , mDataType( type )
3801 {
3802   if ( mMin >= mMax )
3803   {
3804     QgsMessageLog::logMessage( QObject::tr( "Invalid number parameter \"%1\": min value %2 is >= max value %3!" ).arg( name ).arg( mMin ).arg( mMax ), QObject::tr( "Processing" ) );
3805   }
3806 }
3807 
clone() const3808 QgsProcessingParameterDefinition *QgsProcessingParameterNumber::clone() const
3809 {
3810   return new QgsProcessingParameterNumber( *this );
3811 }
3812 
checkValueIsAcceptable(const QVariant & value,QgsProcessingContext *) const3813 bool QgsProcessingParameterNumber::checkValueIsAcceptable( const QVariant &value, QgsProcessingContext * ) const
3814 {
3815   QVariant input = value;
3816   if ( !input.isValid() )
3817   {
3818     if ( !defaultValue().isValid() )
3819       return mFlags & FlagOptional;
3820 
3821     input = defaultValue();
3822   }
3823 
3824   if ( input.canConvert<QgsProperty>() )
3825   {
3826     return true;
3827   }
3828 
3829   bool ok = false;
3830   double res = input.toDouble( &ok );
3831   if ( !ok )
3832     return mFlags & FlagOptional;
3833 
3834   return !( res < mMin || res > mMax );
3835 }
3836 
valueAsPythonString(const QVariant & value,QgsProcessingContext &) const3837 QString QgsProcessingParameterNumber::valueAsPythonString( const QVariant &value, QgsProcessingContext & ) const
3838 {
3839   if ( !value.isValid() )
3840     return QStringLiteral( "None" );
3841 
3842   if ( value.canConvert<QgsProperty>() )
3843     return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
3844 
3845   return value.toString();
3846 }
3847 
toolTip() const3848 QString QgsProcessingParameterNumber::toolTip() const
3849 {
3850   QString text = QgsProcessingParameterDefinition::toolTip();
3851   QStringList parts;
3852   if ( mMin > std::numeric_limits<double>::lowest() + 1 )
3853     parts << QObject::tr( "Minimum value: %1" ).arg( mMin );
3854   if ( mMax < std::numeric_limits<double>::max() )
3855     parts << QObject::tr( "Maximum value: %1" ).arg( mMax );
3856   if ( mDefault.isValid() )
3857     parts << QObject::tr( "Default value: %1" ).arg( mDataType == Integer ? mDefault.toInt() : mDefault.toDouble() );
3858   QString extra = parts.join( QLatin1String( "<br />" ) );
3859   if ( !extra.isEmpty() )
3860     text += QStringLiteral( "<p>%1</p>" ).arg( extra );
3861   return text;
3862 }
3863 
asPythonString(const QgsProcessing::PythonOutputType outputType) const3864 QString QgsProcessingParameterNumber::asPythonString( const QgsProcessing::PythonOutputType outputType ) const
3865 {
3866   switch ( outputType )
3867   {
3868     case QgsProcessing::PythonQgsProcessingAlgorithmSubclass:
3869     {
3870       QString code = QStringLiteral( "QgsProcessingParameterNumber('%1', '%2'" ).arg( name(), description() );
3871       if ( mFlags & FlagOptional )
3872         code += QLatin1String( ", optional=True" );
3873 
3874       code += QStringLiteral( ", type=%1" ).arg( mDataType == Integer ? QStringLiteral( "QgsProcessingParameterNumber.Integer" ) : QStringLiteral( "QgsProcessingParameterNumber.Double" ) );
3875 
3876       if ( mMin != std::numeric_limits<double>::lowest() + 1 )
3877         code += QStringLiteral( ", minValue=%1" ).arg( mMin );
3878       if ( mMax != std::numeric_limits<double>::max() )
3879         code += QStringLiteral( ", maxValue=%1" ).arg( mMax );
3880       QgsProcessingContext c;
3881       code += QStringLiteral( ", defaultValue=%1)" ).arg( valueAsPythonString( mDefault, c ) );
3882       return code;
3883     }
3884   }
3885   return QString();
3886 }
3887 
minimum() const3888 double QgsProcessingParameterNumber::minimum() const
3889 {
3890   return mMin;
3891 }
3892 
setMinimum(double min)3893 void QgsProcessingParameterNumber::setMinimum( double min )
3894 {
3895   mMin = min;
3896 }
3897 
maximum() const3898 double QgsProcessingParameterNumber::maximum() const
3899 {
3900   return mMax;
3901 }
3902 
setMaximum(double max)3903 void QgsProcessingParameterNumber::setMaximum( double max )
3904 {
3905   mMax = max;
3906 }
3907 
dataType() const3908 QgsProcessingParameterNumber::Type QgsProcessingParameterNumber::dataType() const
3909 {
3910   return mDataType;
3911 }
3912 
setDataType(Type dataType)3913 void QgsProcessingParameterNumber::setDataType( Type dataType )
3914 {
3915   mDataType = dataType;
3916 }
3917 
toVariantMap() const3918 QVariantMap QgsProcessingParameterNumber::toVariantMap() const
3919 {
3920   QVariantMap map = QgsProcessingParameterDefinition::toVariantMap();
3921   map.insert( QStringLiteral( "min" ), mMin );
3922   map.insert( QStringLiteral( "max" ), mMax );
3923   map.insert( QStringLiteral( "data_type" ), mDataType );
3924   return map;
3925 }
3926 
fromVariantMap(const QVariantMap & map)3927 bool QgsProcessingParameterNumber::fromVariantMap( const QVariantMap &map )
3928 {
3929   QgsProcessingParameterDefinition::fromVariantMap( map );
3930   mMin = map.value( QStringLiteral( "min" ) ).toDouble();
3931   mMax = map.value( QStringLiteral( "max" ) ).toDouble();
3932   mDataType = static_cast< Type >( map.value( QStringLiteral( "data_type" ) ).toInt() );
3933   return true;
3934 }
3935 
fromScriptCode(const QString & name,const QString & description,bool isOptional,const QString & definition)3936 QgsProcessingParameterNumber *QgsProcessingParameterNumber::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
3937 {
3938   return new QgsProcessingParameterNumber( name, description, Double, definition.isEmpty() ? QVariant()
3939          : ( definition.toLower().trimmed() == QLatin1String( "none" ) ? QVariant() : definition ), isOptional );
3940 }
3941 
QgsProcessingParameterRange(const QString & name,const QString & description,QgsProcessingParameterNumber::Type type,const QVariant & defaultValue,bool optional)3942 QgsProcessingParameterRange::QgsProcessingParameterRange( const QString &name, const QString &description, QgsProcessingParameterNumber::Type type, const QVariant &defaultValue, bool optional )
3943   : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
3944   , mDataType( type )
3945 {
3946 
3947 }
3948 
clone() const3949 QgsProcessingParameterDefinition *QgsProcessingParameterRange::clone() const
3950 {
3951   return new QgsProcessingParameterRange( *this );
3952 }
3953 
checkValueIsAcceptable(const QVariant & input,QgsProcessingContext *) const3954 bool QgsProcessingParameterRange::checkValueIsAcceptable( const QVariant &input, QgsProcessingContext * ) const
3955 {
3956   if ( !input.isValid() )
3957     return mFlags & FlagOptional;
3958 
3959   if ( input.canConvert<QgsProperty>() )
3960   {
3961     return true;
3962   }
3963 
3964   if ( input.type() == QVariant::String )
3965   {
3966     QStringList list = input.toString().split( ',' );
3967     if ( list.count() != 2 )
3968       return mFlags & FlagOptional;
3969     bool ok = false;
3970     list.at( 0 ).toDouble( &ok );
3971     bool ok2 = false;
3972     list.at( 1 ).toDouble( &ok2 );
3973     if ( !ok || !ok2 )
3974       return mFlags & FlagOptional;
3975     return true;
3976   }
3977   else if ( input.type() == QVariant::List )
3978   {
3979     if ( input.toList().count() != 2 )
3980       return mFlags & FlagOptional;
3981 
3982     bool ok = false;
3983     input.toList().at( 0 ).toDouble( &ok );
3984     bool ok2 = false;
3985     input.toList().at( 1 ).toDouble( &ok2 );
3986     if ( !ok || !ok2 )
3987       return mFlags & FlagOptional;
3988     return true;
3989   }
3990 
3991   return false;
3992 }
3993 
valueAsPythonString(const QVariant & value,QgsProcessingContext & context) const3994 QString QgsProcessingParameterRange::valueAsPythonString( const QVariant &value, QgsProcessingContext &context ) const
3995 {
3996   if ( !value.isValid() )
3997     return QStringLiteral( "None" );
3998 
3999   if ( value.canConvert<QgsProperty>() )
4000     return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
4001 
4002   QVariantMap p;
4003   p.insert( name(), value );
4004   QList< double > parts = QgsProcessingParameters::parameterAsRange( this, p, context );
4005 
4006   QStringList stringParts;
4007   const auto constParts = parts;
4008   for ( double v : constParts )
4009   {
4010     stringParts << QString::number( v );
4011   }
4012   return stringParts.join( ',' ).prepend( '[' ).append( ']' );
4013 }
4014 
asPythonString(const QgsProcessing::PythonOutputType outputType) const4015 QString QgsProcessingParameterRange::asPythonString( const QgsProcessing::PythonOutputType outputType ) const
4016 {
4017   switch ( outputType )
4018   {
4019     case QgsProcessing::PythonQgsProcessingAlgorithmSubclass:
4020     {
4021       QString code = QStringLiteral( "QgsProcessingParameterRange('%1', '%2'" ).arg( name(), description() );
4022       if ( mFlags & FlagOptional )
4023         code += QLatin1String( ", optional=True" );
4024 
4025       code += QStringLiteral( ", type=%1" ).arg( mDataType == QgsProcessingParameterNumber::Integer ? QStringLiteral( "QgsProcessingParameterNumber.Integer" ) : QStringLiteral( "QgsProcessingParameterNumber.Double" ) );
4026 
4027       QgsProcessingContext c;
4028       code += QStringLiteral( ", defaultValue=%1)" ).arg( valueAsPythonString( mDefault, c ) );
4029       return code;
4030     }
4031   }
4032   return QString();
4033 }
4034 
dataType() const4035 QgsProcessingParameterNumber::Type QgsProcessingParameterRange::dataType() const
4036 {
4037   return mDataType;
4038 }
4039 
setDataType(QgsProcessingParameterNumber::Type dataType)4040 void QgsProcessingParameterRange::setDataType( QgsProcessingParameterNumber::Type dataType )
4041 {
4042   mDataType = dataType;
4043 }
4044 
toVariantMap() const4045 QVariantMap QgsProcessingParameterRange::toVariantMap() const
4046 {
4047   QVariantMap map = QgsProcessingParameterDefinition::toVariantMap();
4048   map.insert( QStringLiteral( "data_type" ), mDataType );
4049   return map;
4050 }
4051 
fromVariantMap(const QVariantMap & map)4052 bool QgsProcessingParameterRange::fromVariantMap( const QVariantMap &map )
4053 {
4054   QgsProcessingParameterDefinition::fromVariantMap( map );
4055   mDataType = static_cast< QgsProcessingParameterNumber::Type >( map.value( QStringLiteral( "data_type" ) ).toInt() );
4056   return true;
4057 }
4058 
fromScriptCode(const QString & name,const QString & description,bool isOptional,const QString & definition)4059 QgsProcessingParameterRange *QgsProcessingParameterRange::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
4060 {
4061   return new QgsProcessingParameterRange( name, description, QgsProcessingParameterNumber::Double, definition.isEmpty() ? QVariant()
4062                                           : ( definition.toLower().trimmed() == QLatin1String( "none" ) ? QVariant() : definition ), isOptional );
4063 }
4064 
QgsProcessingParameterRasterLayer(const QString & name,const QString & description,const QVariant & defaultValue,bool optional)4065 QgsProcessingParameterRasterLayer::QgsProcessingParameterRasterLayer( const QString &name, const QString &description, const QVariant &defaultValue, bool optional )
4066   : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
4067 {
4068 
4069 }
4070 
clone() const4071 QgsProcessingParameterDefinition *QgsProcessingParameterRasterLayer::clone() const
4072 {
4073   return new QgsProcessingParameterRasterLayer( *this );
4074 }
4075 
checkValueIsAcceptable(const QVariant & input,QgsProcessingContext * context) const4076 bool QgsProcessingParameterRasterLayer::checkValueIsAcceptable( const QVariant &input, QgsProcessingContext *context ) const
4077 {
4078   if ( !input.isValid() )
4079     return mFlags & FlagOptional;
4080 
4081   if ( input.canConvert<QgsProperty>() )
4082   {
4083     return true;
4084   }
4085 
4086   if ( qobject_cast< QgsRasterLayer * >( qvariant_cast<QObject *>( input ) ) )
4087     return true;
4088 
4089   if ( input.type() != QVariant::String || input.toString().isEmpty() )
4090     return mFlags & FlagOptional;
4091 
4092   if ( !context )
4093   {
4094     // that's as far as we can get without a context
4095     return true;
4096   }
4097 
4098   // try to load as layer
4099   if ( QgsProcessingUtils::mapLayerFromString( input.toString(), *context, true, QgsProcessingUtils::LayerHint::Raster ) )
4100     return true;
4101 
4102   return false;
4103 }
4104 
valueAsPythonString(const QVariant & val,QgsProcessingContext & context) const4105 QString QgsProcessingParameterRasterLayer::valueAsPythonString( const QVariant &val, QgsProcessingContext &context ) const
4106 {
4107   if ( !val.isValid() )
4108     return QStringLiteral( "None" );
4109 
4110   if ( val.canConvert<QgsProperty>() )
4111     return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( val.value< QgsProperty >().asExpression() );
4112 
4113   QVariantMap p;
4114   p.insert( name(), val );
4115   QgsRasterLayer *layer = QgsProcessingParameters::parameterAsRasterLayer( this, p, context );
4116   return layer ? QgsProcessingUtils::stringToPythonLiteral( QgsProcessingUtils::normalizeLayerSource( layer->source() ) )
4117          : QgsProcessingUtils::stringToPythonLiteral( val.toString() );
4118 }
4119 
createFileFilter() const4120 QString QgsProcessingParameterRasterLayer::createFileFilter() const
4121 {
4122   return QgsProviderRegistry::instance()->fileRasterFilters() + QStringLiteral( ";;" ) + QObject::tr( "All files (*.*)" );
4123 }
4124 
fromScriptCode(const QString & name,const QString & description,bool isOptional,const QString & definition)4125 QgsProcessingParameterRasterLayer *QgsProcessingParameterRasterLayer::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
4126 {
4127   return new QgsProcessingParameterRasterLayer( name, description, definition.isEmpty() ? QVariant() : definition, isOptional );
4128 }
4129 
QgsProcessingParameterEnum(const QString & name,const QString & description,const QStringList & options,bool allowMultiple,const QVariant & defaultValue,bool optional)4130 QgsProcessingParameterEnum::QgsProcessingParameterEnum( const QString &name, const QString &description, const QStringList &options, bool allowMultiple, const QVariant &defaultValue, bool optional )
4131   : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
4132   , mOptions( options )
4133   , mAllowMultiple( allowMultiple )
4134 {
4135 
4136 }
4137 
clone() const4138 QgsProcessingParameterDefinition *QgsProcessingParameterEnum::clone() const
4139 {
4140   return new QgsProcessingParameterEnum( *this );
4141 }
4142 
checkValueIsAcceptable(const QVariant & value,QgsProcessingContext *) const4143 bool QgsProcessingParameterEnum::checkValueIsAcceptable( const QVariant &value, QgsProcessingContext * ) const
4144 {
4145   QVariant input = value;
4146   if ( !input.isValid() )
4147   {
4148     if ( !defaultValue().isValid() )
4149       return mFlags & FlagOptional;
4150 
4151     input = defaultValue();
4152   }
4153 
4154   if ( input.canConvert<QgsProperty>() )
4155   {
4156     return true;
4157   }
4158 
4159   if ( input.type() == QVariant::List )
4160   {
4161     if ( !mAllowMultiple )
4162       return false;
4163 
4164     const QVariantList values = input.toList();
4165     if ( values.empty() && !( mFlags & FlagOptional ) )
4166       return false;
4167 
4168     for ( const QVariant &val : values )
4169     {
4170       bool ok = false;
4171       int res = val.toInt( &ok );
4172       if ( !ok )
4173         return false;
4174       else if ( res < 0 || res >= mOptions.count() )
4175         return false;
4176     }
4177 
4178     return true;
4179   }
4180   else if ( input.type() == QVariant::String )
4181   {
4182     QStringList parts = input.toString().split( ',' );
4183     if ( parts.count() > 1 && !mAllowMultiple )
4184       return false;
4185 
4186     const auto constParts = parts;
4187     for ( const QString &part : constParts )
4188     {
4189       bool ok = false;
4190       int res = part.toInt( &ok );
4191       if ( !ok )
4192         return false;
4193       else if ( res < 0 || res >= mOptions.count() )
4194         return false;
4195     }
4196     return true;
4197   }
4198   else if ( input.type() == QVariant::Int || input.type() == QVariant::Double )
4199   {
4200     bool ok = false;
4201     int res = input.toInt( &ok );
4202     if ( !ok )
4203       return false;
4204     else if ( res >= 0 && res < mOptions.count() )
4205       return true;
4206   }
4207   return false;
4208 }
4209 
valueAsPythonString(const QVariant & value,QgsProcessingContext &) const4210 QString QgsProcessingParameterEnum::valueAsPythonString( const QVariant &value, QgsProcessingContext & ) const
4211 {
4212   if ( !value.isValid() )
4213     return QStringLiteral( "None" );
4214 
4215   if ( value.canConvert<QgsProperty>() )
4216     return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
4217 
4218   if ( value.type() == QVariant::List )
4219   {
4220     QStringList parts;
4221     const auto constToList = value.toList();
4222     for ( const QVariant &val : constToList )
4223     {
4224       parts << QString::number( static_cast< int >( val.toDouble() ) );
4225     }
4226     return parts.join( ',' ).prepend( '[' ).append( ']' );
4227   }
4228   else if ( value.type() == QVariant::String )
4229   {
4230     QStringList parts = value.toString().split( ',' );
4231     if ( parts.count() > 1 )
4232     {
4233       return parts.join( ',' ).prepend( '[' ).append( ']' );
4234     }
4235   }
4236 
4237   return QString::number( static_cast< int >( value.toDouble() ) );
4238 }
4239 
asScriptCode() const4240 QString QgsProcessingParameterEnum::asScriptCode() const
4241 {
4242   QString code = QStringLiteral( "##%1=" ).arg( mName );
4243   if ( mFlags & FlagOptional )
4244     code += QLatin1String( "optional " );
4245   code += QLatin1String( "enum " );
4246 
4247   if ( mAllowMultiple )
4248     code += QLatin1String( "multiple " );
4249 
4250   code += mOptions.join( ';' ) + ' ';
4251 
4252   code += mDefault.toString();
4253   return code.trimmed();
4254 }
4255 
asPythonString(const QgsProcessing::PythonOutputType outputType) const4256 QString QgsProcessingParameterEnum::asPythonString( const QgsProcessing::PythonOutputType outputType ) const
4257 {
4258   switch ( outputType )
4259   {
4260     case QgsProcessing::PythonQgsProcessingAlgorithmSubclass:
4261     {
4262       QString code = QStringLiteral( "QgsProcessingParameterEnum('%1', '%2'" ).arg( name(), description() );
4263       if ( mFlags & FlagOptional )
4264         code += QLatin1String( ", optional=True" );
4265 
4266       QStringList options;
4267       options.reserve( mOptions.size() );
4268       for ( const QString &o : mOptions )
4269         options << QgsProcessingUtils::stringToPythonLiteral( o );
4270       code += QStringLiteral( ", options=[%1]" ).arg( options.join( ',' ) );
4271 
4272       code += QStringLiteral( ", allowMultiple=%1" ).arg( mAllowMultiple ? QStringLiteral( "True" ) : QStringLiteral( "False" ) );
4273 
4274       QgsProcessingContext c;
4275       code += QStringLiteral( ", defaultValue=%1)" ).arg( valueAsPythonString( mDefault, c ) );
4276       return code;
4277     }
4278   }
4279   return QString();
4280 }
4281 
options() const4282 QStringList QgsProcessingParameterEnum::options() const
4283 {
4284   return mOptions;
4285 }
4286 
setOptions(const QStringList & options)4287 void QgsProcessingParameterEnum::setOptions( const QStringList &options )
4288 {
4289   mOptions = options;
4290 }
4291 
allowMultiple() const4292 bool QgsProcessingParameterEnum::allowMultiple() const
4293 {
4294   return mAllowMultiple;
4295 }
4296 
setAllowMultiple(bool allowMultiple)4297 void QgsProcessingParameterEnum::setAllowMultiple( bool allowMultiple )
4298 {
4299   mAllowMultiple = allowMultiple;
4300 }
4301 
toVariantMap() const4302 QVariantMap QgsProcessingParameterEnum::toVariantMap() const
4303 {
4304   QVariantMap map = QgsProcessingParameterDefinition::toVariantMap();
4305   map.insert( QStringLiteral( "options" ), mOptions );
4306   map.insert( QStringLiteral( "allow_multiple" ), mAllowMultiple );
4307   return map;
4308 }
4309 
fromVariantMap(const QVariantMap & map)4310 bool QgsProcessingParameterEnum::fromVariantMap( const QVariantMap &map )
4311 {
4312   QgsProcessingParameterDefinition::fromVariantMap( map );
4313   mOptions = map.value( QStringLiteral( "options" ) ).toStringList();
4314   mAllowMultiple = map.value( QStringLiteral( "allow_multiple" ) ).toBool();
4315   return true;
4316 }
4317 
fromScriptCode(const QString & name,const QString & description,bool isOptional,const QString & definition)4318 QgsProcessingParameterEnum *QgsProcessingParameterEnum::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
4319 {
4320   QString defaultVal;
4321   bool multiple = false;
4322   QString def = definition;
4323   if ( def.startsWith( QLatin1String( "multiple" ), Qt::CaseInsensitive ) )
4324   {
4325     multiple = true;
4326     def = def.mid( 9 );
4327   }
4328 
4329   QRegularExpression re( QStringLiteral( "(.*)\\s+(.*?)$" ) );
4330   QRegularExpressionMatch m = re.match( def );
4331   QString values = def;
4332   if ( m.hasMatch() )
4333   {
4334     values = m.captured( 1 ).trimmed();
4335     defaultVal = m.captured( 2 );
4336   }
4337 
4338   return new QgsProcessingParameterEnum( name, description, values.split( ';' ), multiple, defaultVal.isEmpty() ? QVariant() : defaultVal, isOptional );
4339 }
4340 
QgsProcessingParameterString(const QString & name,const QString & description,const QVariant & defaultValue,bool multiLine,bool optional)4341 QgsProcessingParameterString::QgsProcessingParameterString( const QString &name, const QString &description, const QVariant &defaultValue, bool multiLine, bool optional )
4342   : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
4343   , mMultiLine( multiLine )
4344 {
4345 
4346 }
4347 
clone() const4348 QgsProcessingParameterDefinition *QgsProcessingParameterString::clone() const
4349 {
4350   return new QgsProcessingParameterString( *this );
4351 }
4352 
valueAsPythonString(const QVariant & value,QgsProcessingContext &) const4353 QString QgsProcessingParameterString::valueAsPythonString( const QVariant &value, QgsProcessingContext & ) const
4354 {
4355   if ( !value.isValid() || value.isNull() )
4356     return QStringLiteral( "None" );
4357 
4358   if ( value.canConvert<QgsProperty>() )
4359     return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
4360 
4361   QString s = value.toString();
4362   return QgsProcessingUtils::stringToPythonLiteral( s );
4363 }
4364 
asScriptCode() const4365 QString QgsProcessingParameterString::asScriptCode() const
4366 {
4367   QString code = QStringLiteral( "##%1=" ).arg( mName );
4368   if ( mFlags & FlagOptional )
4369     code += QLatin1String( "optional " );
4370   code += QLatin1String( "string " );
4371 
4372   if ( mMultiLine )
4373     code += QLatin1String( "long " );
4374 
4375   code += mDefault.toString();
4376   return code.trimmed();
4377 }
4378 
asPythonString(const QgsProcessing::PythonOutputType outputType) const4379 QString QgsProcessingParameterString::asPythonString( const QgsProcessing::PythonOutputType outputType ) const
4380 {
4381   switch ( outputType )
4382   {
4383     case QgsProcessing::PythonQgsProcessingAlgorithmSubclass:
4384     {
4385       QString code = QStringLiteral( "QgsProcessingParameterString('%1', '%2'" ).arg( name(), description() );
4386       if ( mFlags & FlagOptional )
4387         code += QLatin1String( ", optional=True" );
4388       code += QStringLiteral( ", multiLine=%1" ).arg( mMultiLine ? QStringLiteral( "True" ) : QStringLiteral( "False" ) );
4389 
4390       QgsProcessingContext c;
4391       code += QStringLiteral( ", defaultValue=%1)" ).arg( valueAsPythonString( mDefault, c ) );
4392       return code;
4393     }
4394   }
4395   return QString();
4396 }
4397 
multiLine() const4398 bool QgsProcessingParameterString::multiLine() const
4399 {
4400   return mMultiLine;
4401 }
4402 
setMultiLine(bool multiLine)4403 void QgsProcessingParameterString::setMultiLine( bool multiLine )
4404 {
4405   mMultiLine = multiLine;
4406 }
4407 
toVariantMap() const4408 QVariantMap QgsProcessingParameterString::toVariantMap() const
4409 {
4410   QVariantMap map = QgsProcessingParameterDefinition::toVariantMap();
4411   map.insert( QStringLiteral( "multiline" ), mMultiLine );
4412   return map;
4413 }
4414 
fromVariantMap(const QVariantMap & map)4415 bool QgsProcessingParameterString::fromVariantMap( const QVariantMap &map )
4416 {
4417   QgsProcessingParameterDefinition::fromVariantMap( map );
4418   mMultiLine = map.value( QStringLiteral( "multiline" ) ).toBool();
4419   return true;
4420 }
4421 
fromScriptCode(const QString & name,const QString & description,bool isOptional,const QString & definition)4422 QgsProcessingParameterString *QgsProcessingParameterString::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
4423 {
4424   QString def = definition;
4425   bool multiLine = false;
4426   if ( def.startsWith( QLatin1String( "long" ), Qt::CaseInsensitive ) )
4427   {
4428     multiLine = true;
4429     def = def.mid( 5 );
4430   }
4431 
4432   if ( def.startsWith( '"' ) || def.startsWith( '\'' ) )
4433     def = def.mid( 1 );
4434   if ( def.endsWith( '"' ) || def.endsWith( '\'' ) )
4435     def.chop( 1 );
4436 
4437   QVariant defaultValue = def;
4438   if ( def == QLatin1String( "None" ) )
4439     defaultValue = QVariant();
4440 
4441   return new QgsProcessingParameterString( name, description, defaultValue, multiLine, isOptional );
4442 }
4443 
4444 //
4445 // QgsProcessingParameterAuthConfig
4446 //
4447 
QgsProcessingParameterAuthConfig(const QString & name,const QString & description,const QVariant & defaultValue,bool optional)4448 QgsProcessingParameterAuthConfig::QgsProcessingParameterAuthConfig( const QString &name, const QString &description, const QVariant &defaultValue, bool optional )
4449   : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
4450 {
4451 
4452 }
4453 
clone() const4454 QgsProcessingParameterDefinition *QgsProcessingParameterAuthConfig::clone() const
4455 {
4456   return new QgsProcessingParameterAuthConfig( *this );
4457 }
4458 
valueAsPythonString(const QVariant & value,QgsProcessingContext &) const4459 QString QgsProcessingParameterAuthConfig::valueAsPythonString( const QVariant &value, QgsProcessingContext & ) const
4460 {
4461   if ( !value.isValid() )
4462     return QStringLiteral( "None" );
4463 
4464   QString s = value.toString();
4465   return QgsProcessingUtils::stringToPythonLiteral( s );
4466 }
4467 
asScriptCode() const4468 QString QgsProcessingParameterAuthConfig::asScriptCode() const
4469 {
4470   QString code = QStringLiteral( "##%1=" ).arg( mName );
4471   if ( mFlags & FlagOptional )
4472     code += QLatin1String( "optional " );
4473   code += QLatin1String( "authcfg " );
4474 
4475   code += mDefault.toString();
4476   return code.trimmed();
4477 }
4478 
fromScriptCode(const QString & name,const QString & description,bool isOptional,const QString & definition)4479 QgsProcessingParameterAuthConfig *QgsProcessingParameterAuthConfig::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
4480 {
4481   QString def = definition;
4482 
4483   if ( def.startsWith( '"' ) || def.startsWith( '\'' ) )
4484     def = def.mid( 1 );
4485   if ( def.endsWith( '"' ) || def.endsWith( '\'' ) )
4486     def.chop( 1 );
4487 
4488   QVariant defaultValue = def;
4489   if ( def == QLatin1String( "None" ) )
4490     defaultValue = QVariant();
4491 
4492   return new QgsProcessingParameterAuthConfig( name, description, defaultValue, isOptional );
4493 }
4494 
4495 
4496 //
4497 // QgsProcessingParameterExpression
4498 //
4499 
QgsProcessingParameterExpression(const QString & name,const QString & description,const QVariant & defaultValue,const QString & parentLayerParameterName,bool optional)4500 QgsProcessingParameterExpression::QgsProcessingParameterExpression( const QString &name, const QString &description, const QVariant &defaultValue, const QString &parentLayerParameterName, bool optional )
4501   : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
4502   , mParentLayerParameterName( parentLayerParameterName )
4503 {
4504 
4505 }
4506 
clone() const4507 QgsProcessingParameterDefinition *QgsProcessingParameterExpression::clone() const
4508 {
4509   return new QgsProcessingParameterExpression( *this );
4510 }
4511 
valueAsPythonString(const QVariant & value,QgsProcessingContext &) const4512 QString QgsProcessingParameterExpression::valueAsPythonString( const QVariant &value, QgsProcessingContext & ) const
4513 {
4514   if ( !value.isValid() )
4515     return QStringLiteral( "None" );
4516 
4517   if ( value.canConvert<QgsProperty>() )
4518     return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
4519 
4520   QString s = value.toString();
4521   return QgsProcessingUtils::stringToPythonLiteral( s );
4522 }
4523 
dependsOnOtherParameters() const4524 QStringList QgsProcessingParameterExpression::dependsOnOtherParameters() const
4525 {
4526   QStringList depends;
4527   if ( !mParentLayerParameterName.isEmpty() )
4528     depends << mParentLayerParameterName;
4529   return depends;
4530 }
4531 
asPythonString(const QgsProcessing::PythonOutputType outputType) const4532 QString QgsProcessingParameterExpression::asPythonString( const QgsProcessing::PythonOutputType outputType ) const
4533 {
4534   switch ( outputType )
4535   {
4536     case QgsProcessing::PythonQgsProcessingAlgorithmSubclass:
4537     {
4538       QString code = QStringLiteral( "QgsProcessingParameterExpression('%1', '%2'" ).arg( name(), description() );
4539       if ( mFlags & FlagOptional )
4540         code += QLatin1String( ", optional=True" );
4541 
4542       code += QStringLiteral( ", parentLayerParameterName='%1'" ).arg( mParentLayerParameterName );
4543 
4544       QgsProcessingContext c;
4545       code += QStringLiteral( ", defaultValue=%1)" ).arg( valueAsPythonString( mDefault, c ) );
4546       return code;
4547     }
4548   }
4549   return QString();
4550 }
4551 
parentLayerParameterName() const4552 QString QgsProcessingParameterExpression::parentLayerParameterName() const
4553 {
4554   return mParentLayerParameterName;
4555 }
4556 
setParentLayerParameterName(const QString & parentLayerParameterName)4557 void QgsProcessingParameterExpression::setParentLayerParameterName( const QString &parentLayerParameterName )
4558 {
4559   mParentLayerParameterName = parentLayerParameterName;
4560 }
4561 
toVariantMap() const4562 QVariantMap QgsProcessingParameterExpression::toVariantMap() const
4563 {
4564   QVariantMap map = QgsProcessingParameterDefinition::toVariantMap();
4565   map.insert( QStringLiteral( "parent_layer" ), mParentLayerParameterName );
4566   return map;
4567 }
4568 
fromVariantMap(const QVariantMap & map)4569 bool QgsProcessingParameterExpression::fromVariantMap( const QVariantMap &map )
4570 {
4571   QgsProcessingParameterDefinition::fromVariantMap( map );
4572   mParentLayerParameterName = map.value( QStringLiteral( "parent_layer" ) ).toString();
4573   return true;
4574 }
4575 
fromScriptCode(const QString & name,const QString & description,bool isOptional,const QString & definition)4576 QgsProcessingParameterExpression *QgsProcessingParameterExpression::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
4577 {
4578   return new QgsProcessingParameterExpression( name, description, definition, QString(), isOptional );
4579 }
4580 
QgsProcessingParameterVectorLayer(const QString & name,const QString & description,const QList<int> & types,const QVariant & defaultValue,bool optional)4581 QgsProcessingParameterVectorLayer::QgsProcessingParameterVectorLayer( const QString &name, const QString &description, const QList<int> &types, const QVariant &defaultValue, bool optional )
4582   : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
4583   , QgsProcessingParameterLimitedDataTypes( types )
4584 {
4585 
4586 }
4587 
clone() const4588 QgsProcessingParameterDefinition *QgsProcessingParameterVectorLayer::clone() const
4589 {
4590   return new QgsProcessingParameterVectorLayer( *this );
4591 }
4592 
checkValueIsAcceptable(const QVariant & v,QgsProcessingContext * context) const4593 bool QgsProcessingParameterVectorLayer::checkValueIsAcceptable( const QVariant &v, QgsProcessingContext *context ) const
4594 {
4595   if ( !v.isValid() )
4596     return mFlags & FlagOptional;
4597 
4598   QVariant var = v;
4599 
4600   if ( var.canConvert<QgsProperty>() )
4601   {
4602     QgsProperty p = var.value< QgsProperty >();
4603     if ( p.propertyType() == QgsProperty::StaticProperty )
4604     {
4605       var = p.staticValue();
4606     }
4607     else
4608     {
4609       return true;
4610     }
4611   }
4612 
4613   if ( qobject_cast< QgsVectorLayer * >( qvariant_cast<QObject *>( var ) ) )
4614     return true;
4615 
4616   if ( var.type() != QVariant::String || var.toString().isEmpty() )
4617     return mFlags & FlagOptional;
4618 
4619   if ( !context )
4620   {
4621     // that's as far as we can get without a context
4622     return true;
4623   }
4624 
4625   // try to load as layer
4626   if ( QgsProcessingUtils::mapLayerFromString( var.toString(), *context, true, QgsProcessingUtils::LayerHint::Vector ) )
4627     return true;
4628 
4629   return false;
4630 }
4631 
valueAsPythonString(const QVariant & val,QgsProcessingContext & context) const4632 QString QgsProcessingParameterVectorLayer::valueAsPythonString( const QVariant &val, QgsProcessingContext &context ) const
4633 {
4634   if ( !val.isValid() )
4635     return QStringLiteral( "None" );
4636 
4637   if ( val.canConvert<QgsProperty>() )
4638     return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( val.value< QgsProperty >().asExpression() );
4639 
4640   QVariantMap p;
4641   p.insert( name(), val );
4642   QgsVectorLayer *layer = QgsProcessingParameters::parameterAsVectorLayer( this, p, context );
4643   return layer ? QgsProcessingUtils::stringToPythonLiteral( QgsProcessingUtils::normalizeLayerSource( layer->source() ) )
4644          : QgsProcessingUtils::stringToPythonLiteral( val.toString() );
4645 }
4646 
asPythonString(const QgsProcessing::PythonOutputType outputType) const4647 QString QgsProcessingParameterVectorLayer::asPythonString( const QgsProcessing::PythonOutputType outputType ) const
4648 {
4649   switch ( outputType )
4650   {
4651     case QgsProcessing::PythonQgsProcessingAlgorithmSubclass:
4652     {
4653       QString code = QStringLiteral( "QgsProcessingParameterVectorLayer('%1', '%2'" ).arg( name(), description() );
4654       if ( mFlags & FlagOptional )
4655         code += QLatin1String( ", optional=True" );
4656 
4657       if ( !mDataTypes.empty() )
4658       {
4659         QStringList options;
4660         for ( int t : mDataTypes )
4661           options << QStringLiteral( "QgsProcessing.%1" ).arg( QgsProcessing::sourceTypeToString( static_cast< QgsProcessing::SourceType >( t ) ) );
4662         code += QStringLiteral( ", types=[%1]" ).arg( options.join( ',' ) );
4663       }
4664 
4665       QgsProcessingContext c;
4666       code += QStringLiteral( ", defaultValue=%1)" ).arg( valueAsPythonString( mDefault, c ) );
4667       return code;
4668     }
4669   }
4670   return QString();
4671 }
4672 
createFileFilter() const4673 QString QgsProcessingParameterVectorLayer::createFileFilter() const
4674 {
4675   return QgsProviderRegistry::instance()->fileVectorFilters() + QStringLiteral( ";;" ) + QObject::tr( "All files (*.*)" );
4676 }
4677 
dataTypes() const4678 QList<int> QgsProcessingParameterLimitedDataTypes::dataTypes() const
4679 {
4680   return mDataTypes;
4681 }
4682 
setDataTypes(const QList<int> & types)4683 void QgsProcessingParameterLimitedDataTypes::setDataTypes( const QList<int> &types )
4684 {
4685   mDataTypes = types;
4686 }
4687 
toVariantMap() const4688 QVariantMap QgsProcessingParameterVectorLayer::toVariantMap() const
4689 {
4690   QVariantMap map = QgsProcessingParameterDefinition::toVariantMap();
4691   QVariantList types;
4692   for ( int type : mDataTypes )
4693   {
4694     types << type;
4695   }
4696   map.insert( QStringLiteral( "data_types" ), types );
4697   return map;
4698 }
4699 
fromVariantMap(const QVariantMap & map)4700 bool QgsProcessingParameterVectorLayer::fromVariantMap( const QVariantMap &map )
4701 {
4702   QgsProcessingParameterDefinition::fromVariantMap( map );
4703   mDataTypes.clear();
4704   const QVariantList values = map.value( QStringLiteral( "data_types" ) ).toList();
4705   for ( const QVariant &val : values )
4706   {
4707     mDataTypes << val.toInt();
4708   }
4709   return true;
4710 }
4711 
fromScriptCode(const QString & name,const QString & description,bool isOptional,const QString & definition)4712 QgsProcessingParameterVectorLayer *QgsProcessingParameterVectorLayer::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
4713 {
4714   return new QgsProcessingParameterVectorLayer( name, description, QList< int>(),  definition.isEmpty() ? QVariant() : definition, isOptional );
4715 }
4716 
QgsProcessingParameterMeshLayer(const QString & name,const QString & description,const QVariant & defaultValue,bool optional)4717 QgsProcessingParameterMeshLayer::QgsProcessingParameterMeshLayer( const QString &name,
4718     const QString &description,
4719     const QVariant &defaultValue,
4720     bool optional )
4721   : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
4722 {
4723 
4724 }
4725 
clone() const4726 QgsProcessingParameterDefinition *QgsProcessingParameterMeshLayer::clone() const
4727 {
4728   return new QgsProcessingParameterMeshLayer( *this );
4729 }
4730 
checkValueIsAcceptable(const QVariant & v,QgsProcessingContext * context) const4731 bool QgsProcessingParameterMeshLayer::checkValueIsAcceptable( const QVariant &v, QgsProcessingContext *context ) const
4732 {
4733   if ( !v.isValid() )
4734     return mFlags & FlagOptional;
4735 
4736   QVariant var = v;
4737 
4738   if ( var.canConvert<QgsProperty>() )
4739   {
4740     QgsProperty p = var.value< QgsProperty >();
4741     if ( p.propertyType() == QgsProperty::StaticProperty )
4742     {
4743       var = p.staticValue();
4744     }
4745     else
4746     {
4747       return true;
4748     }
4749   }
4750 
4751   if ( qobject_cast< QgsMeshLayer * >( qvariant_cast<QObject *>( var ) ) )
4752     return true;
4753 
4754   if ( var.type() != QVariant::String || var.toString().isEmpty() )
4755     return mFlags & FlagOptional;
4756 
4757   if ( !context )
4758   {
4759     // that's as far as we can get without a context
4760     return true;
4761   }
4762 
4763   // try to load as layer
4764   if ( QgsProcessingUtils::mapLayerFromString( var.toString(), *context, true, QgsProcessingUtils::LayerHint::Mesh ) )
4765     return true;
4766 
4767   return false;
4768 }
4769 
valueAsPythonString(const QVariant & val,QgsProcessingContext & context) const4770 QString QgsProcessingParameterMeshLayer::valueAsPythonString( const QVariant &val, QgsProcessingContext &context ) const
4771 {
4772   if ( !val.isValid() )
4773     return QStringLiteral( "None" );
4774 
4775   if ( val.canConvert<QgsProperty>() )
4776     return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( val.value< QgsProperty >().asExpression() );
4777 
4778   QVariantMap p;
4779   p.insert( name(), val );
4780   QgsMeshLayer *layer = QgsProcessingParameters::parameterAsMeshLayer( this, p, context );
4781   return layer ? QgsProcessingUtils::stringToPythonLiteral( QgsProcessingUtils::normalizeLayerSource( layer->source() ) )
4782          : QgsProcessingUtils::stringToPythonLiteral( val.toString() );
4783 }
4784 
createFileFilter() const4785 QString QgsProcessingParameterMeshLayer::createFileFilter() const
4786 {
4787   return QgsProviderRegistry::instance()->fileMeshFilters() + QStringLiteral( ";;" ) + QObject::tr( "All files (*.*)" );
4788 }
4789 
fromScriptCode(const QString & name,const QString & description,bool isOptional,const QString & definition)4790 QgsProcessingParameterMeshLayer *QgsProcessingParameterMeshLayer::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
4791 {
4792   return new QgsProcessingParameterMeshLayer( name, description,  definition.isEmpty() ? QVariant() : definition, isOptional );
4793 }
4794 
QgsProcessingParameterField(const QString & name,const QString & description,const QVariant & defaultValue,const QString & parentLayerParameterName,DataType type,bool allowMultiple,bool optional,bool defaultToAllFields)4795 QgsProcessingParameterField::QgsProcessingParameterField( const QString &name, const QString &description, const QVariant &defaultValue, const QString &parentLayerParameterName, DataType type, bool allowMultiple, bool optional, bool defaultToAllFields )
4796   : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
4797   , mParentLayerParameterName( parentLayerParameterName )
4798   , mDataType( type )
4799   , mAllowMultiple( allowMultiple )
4800   , mDefaultToAllFields( defaultToAllFields )
4801 {
4802 
4803 }
4804 
4805 
clone() const4806 QgsProcessingParameterDefinition *QgsProcessingParameterField::clone() const
4807 {
4808   return new QgsProcessingParameterField( *this );
4809 }
4810 
checkValueIsAcceptable(const QVariant & input,QgsProcessingContext *) const4811 bool QgsProcessingParameterField::checkValueIsAcceptable( const QVariant &input, QgsProcessingContext * ) const
4812 {
4813   if ( !input.isValid() )
4814     return mFlags & FlagOptional;
4815 
4816   if ( input.canConvert<QgsProperty>() )
4817   {
4818     return true;
4819   }
4820 
4821   if ( input.type() == QVariant::List || input.type() == QVariant::StringList )
4822   {
4823     if ( !mAllowMultiple )
4824       return false;
4825 
4826     if ( input.toList().isEmpty() && !( mFlags & FlagOptional ) )
4827       return false;
4828   }
4829   else if ( input.type() == QVariant::String )
4830   {
4831     if ( input.toString().isEmpty() )
4832       return mFlags & FlagOptional;
4833 
4834     QStringList parts = input.toString().split( ';' );
4835     if ( parts.count() > 1 && !mAllowMultiple )
4836       return false;
4837   }
4838   else
4839   {
4840     if ( input.toString().isEmpty() )
4841       return mFlags & FlagOptional;
4842   }
4843   return true;
4844 }
4845 
valueAsPythonString(const QVariant & value,QgsProcessingContext &) const4846 QString QgsProcessingParameterField::valueAsPythonString( const QVariant &value, QgsProcessingContext & ) const
4847 {
4848   if ( !value.isValid() )
4849     return QStringLiteral( "None" );
4850 
4851   if ( value.canConvert<QgsProperty>() )
4852     return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
4853 
4854   if ( value.type() == QVariant::List )
4855   {
4856     QStringList parts;
4857     const auto constToList = value.toList();
4858     for ( const QVariant &val : constToList )
4859     {
4860       parts << QgsProcessingUtils::stringToPythonLiteral( val.toString() );
4861     }
4862     return parts.join( ',' ).prepend( '[' ).append( ']' );
4863   }
4864   else if ( value.type() == QVariant::StringList )
4865   {
4866     QStringList parts;
4867     const auto constToStringList = value.toStringList();
4868     for ( QString s : constToStringList )
4869     {
4870       parts << QgsProcessingUtils::stringToPythonLiteral( s );
4871     }
4872     return parts.join( ',' ).prepend( '[' ).append( ']' );
4873   }
4874 
4875   return QgsProcessingUtils::stringToPythonLiteral( value.toString() );
4876 }
4877 
asScriptCode() const4878 QString QgsProcessingParameterField::asScriptCode() const
4879 {
4880   QString code = QStringLiteral( "##%1=" ).arg( mName );
4881   if ( mFlags & FlagOptional )
4882     code += QLatin1String( "optional " );
4883   code += QLatin1String( "field " );
4884 
4885   switch ( mDataType )
4886   {
4887     case Numeric:
4888       code += QLatin1String( "numeric " );
4889       break;
4890 
4891     case String:
4892       code += QLatin1String( "string " );
4893       break;
4894 
4895     case DateTime:
4896       code += QLatin1String( "datetime " );
4897       break;
4898 
4899     case Any:
4900       break;
4901   }
4902 
4903   if ( mAllowMultiple )
4904     code += QLatin1String( "multiple " );
4905 
4906   if ( mDefaultToAllFields )
4907     code += QLatin1String( "default_to_all_fields " );
4908 
4909   code += mParentLayerParameterName + ' ';
4910 
4911   code += mDefault.toString();
4912   return code.trimmed();
4913 }
4914 
asPythonString(const QgsProcessing::PythonOutputType outputType) const4915 QString QgsProcessingParameterField::asPythonString( const QgsProcessing::PythonOutputType outputType ) const
4916 {
4917   switch ( outputType )
4918   {
4919     case QgsProcessing::PythonQgsProcessingAlgorithmSubclass:
4920     {
4921       QString code = QStringLiteral( "QgsProcessingParameterField('%1', '%2'" ).arg( name(), description() );
4922       if ( mFlags & FlagOptional )
4923         code += QLatin1String( ", optional=True" );
4924 
4925       QString dataType;
4926       switch ( mDataType )
4927       {
4928         case Any:
4929           dataType = QStringLiteral( "QgsProcessingParameterField.Any" );
4930           break;
4931 
4932         case Numeric:
4933           dataType = QStringLiteral( "QgsProcessingParameterField.Numeric" );
4934           break;
4935 
4936         case String:
4937           dataType = QStringLiteral( "QgsProcessingParameterField.String" );
4938           break;
4939 
4940         case DateTime:
4941           dataType = QStringLiteral( "QgsProcessingParameterField.DateTime" );
4942           break;
4943       }
4944       code += QStringLiteral( ", type=%1" ).arg( dataType );
4945 
4946       code += QStringLiteral( ", parentLayerParameterName='%1'" ).arg( mParentLayerParameterName );
4947       code += QStringLiteral( ", allowMultiple=%1" ).arg( mAllowMultiple ? QStringLiteral( "True" ) : QStringLiteral( "False" ) );
4948       QgsProcessingContext c;
4949       code += QStringLiteral( ", defaultValue=%1" ).arg( valueAsPythonString( mDefault, c ) );
4950 
4951       if ( mDefaultToAllFields )
4952         code += QLatin1String( ", defaultToAllFields=True" );
4953 
4954       code += ')';
4955 
4956       return code;
4957     }
4958   }
4959   return QString();
4960 }
4961 
dependsOnOtherParameters() const4962 QStringList QgsProcessingParameterField::dependsOnOtherParameters() const
4963 {
4964   QStringList depends;
4965   if ( !mParentLayerParameterName.isEmpty() )
4966     depends << mParentLayerParameterName;
4967   return depends;
4968 }
4969 
parentLayerParameterName() const4970 QString QgsProcessingParameterField::parentLayerParameterName() const
4971 {
4972   return mParentLayerParameterName;
4973 }
4974 
setParentLayerParameterName(const QString & parentLayerParameterName)4975 void QgsProcessingParameterField::setParentLayerParameterName( const QString &parentLayerParameterName )
4976 {
4977   mParentLayerParameterName = parentLayerParameterName;
4978 }
4979 
dataType() const4980 QgsProcessingParameterField::DataType QgsProcessingParameterField::dataType() const
4981 {
4982   return mDataType;
4983 }
4984 
setDataType(DataType dataType)4985 void QgsProcessingParameterField::setDataType( DataType dataType )
4986 {
4987   mDataType = dataType;
4988 }
4989 
allowMultiple() const4990 bool QgsProcessingParameterField::allowMultiple() const
4991 {
4992   return mAllowMultiple;
4993 }
4994 
setAllowMultiple(bool allowMultiple)4995 void QgsProcessingParameterField::setAllowMultiple( bool allowMultiple )
4996 {
4997   mAllowMultiple = allowMultiple;
4998 }
4999 
defaultToAllFields() const5000 bool QgsProcessingParameterField::defaultToAllFields() const
5001 {
5002   return mDefaultToAllFields;
5003 }
5004 
setDefaultToAllFields(bool enabled)5005 void QgsProcessingParameterField::setDefaultToAllFields( bool enabled )
5006 {
5007   mDefaultToAllFields = enabled;
5008 }
5009 
toVariantMap() const5010 QVariantMap QgsProcessingParameterField::toVariantMap() const
5011 {
5012   QVariantMap map = QgsProcessingParameterDefinition::toVariantMap();
5013   map.insert( QStringLiteral( "parent_layer" ), mParentLayerParameterName );
5014   map.insert( QStringLiteral( "data_type" ), mDataType );
5015   map.insert( QStringLiteral( "allow_multiple" ), mAllowMultiple );
5016   map.insert( QStringLiteral( "default_to_all_fields" ), mDefaultToAllFields );
5017   return map;
5018 }
5019 
fromVariantMap(const QVariantMap & map)5020 bool QgsProcessingParameterField::fromVariantMap( const QVariantMap &map )
5021 {
5022   QgsProcessingParameterDefinition::fromVariantMap( map );
5023   mParentLayerParameterName = map.value( QStringLiteral( "parent_layer" ) ).toString();
5024   mDataType = static_cast< DataType >( map.value( QStringLiteral( "data_type" ) ).toInt() );
5025   mAllowMultiple = map.value( QStringLiteral( "allow_multiple" ) ).toBool();
5026   mDefaultToAllFields = map.value( QStringLiteral( "default_to_all_fields" ) ).toBool();
5027   return true;
5028 }
5029 
fromScriptCode(const QString & name,const QString & description,bool isOptional,const QString & definition)5030 QgsProcessingParameterField *QgsProcessingParameterField::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
5031 {
5032   QString parent;
5033   DataType type = Any;
5034   bool allowMultiple = false;
5035   bool defaultToAllFields = false;
5036   QString def = definition;
5037 
5038   if ( def.startsWith( QLatin1String( "numeric " ), Qt::CaseInsensitive ) )
5039   {
5040     type = Numeric;
5041     def = def.mid( 8 );
5042   }
5043   else if ( def.startsWith( QLatin1String( "string " ), Qt::CaseInsensitive ) )
5044   {
5045     type = String;
5046     def = def.mid( 7 );
5047   }
5048   else if ( def.startsWith( QLatin1String( "datetime " ), Qt::CaseInsensitive ) )
5049   {
5050     type = DateTime;
5051     def = def.mid( 9 );
5052   }
5053 
5054   if ( def.startsWith( QLatin1String( "multiple" ), Qt::CaseInsensitive ) )
5055   {
5056     allowMultiple = true;
5057     def = def.mid( 8 ).trimmed();
5058   }
5059 
5060   if ( def.startsWith( QLatin1String( "default_to_all_fields" ), Qt::CaseInsensitive ) )
5061   {
5062     defaultToAllFields = true;
5063     def = def.mid( 21 ).trimmed();
5064   }
5065 
5066   QRegularExpression re( QStringLiteral( "(.*?)\\s+(.*)$" ) );
5067   QRegularExpressionMatch m = re.match( def );
5068   if ( m.hasMatch() )
5069   {
5070     parent = m.captured( 1 ).trimmed();
5071     def = m.captured( 2 );
5072   }
5073   else
5074   {
5075     parent = def;
5076     def.clear();
5077   }
5078 
5079   return new QgsProcessingParameterField( name, description, def.isEmpty() ? QVariant() : def, parent, type, allowMultiple, isOptional, defaultToAllFields );
5080 }
5081 
QgsProcessingParameterFeatureSource(const QString & name,const QString & description,const QList<int> & types,const QVariant & defaultValue,bool optional)5082 QgsProcessingParameterFeatureSource::QgsProcessingParameterFeatureSource( const QString &name, const QString &description, const QList<int> &types, const QVariant &defaultValue, bool optional )
5083   : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
5084   , QgsProcessingParameterLimitedDataTypes( types )
5085 {
5086 
5087 }
5088 
clone() const5089 QgsProcessingParameterDefinition *QgsProcessingParameterFeatureSource::clone() const
5090 {
5091   return new QgsProcessingParameterFeatureSource( *this );
5092 }
5093 
checkValueIsAcceptable(const QVariant & input,QgsProcessingContext * context) const5094 bool QgsProcessingParameterFeatureSource::checkValueIsAcceptable( const QVariant &input, QgsProcessingContext *context ) const
5095 {
5096   QVariant var = input;
5097   if ( !var.isValid() )
5098     return mFlags & FlagOptional;
5099 
5100   if ( var.canConvert<QgsProcessingFeatureSourceDefinition>() )
5101   {
5102     QgsProcessingFeatureSourceDefinition fromVar = qvariant_cast<QgsProcessingFeatureSourceDefinition>( var );
5103     var = fromVar.source;
5104   }
5105   else if ( var.canConvert<QgsProcessingOutputLayerDefinition>() )
5106   {
5107     // input is a QgsProcessingOutputLayerDefinition - get extra properties from it
5108     QgsProcessingOutputLayerDefinition fromVar = qvariant_cast<QgsProcessingOutputLayerDefinition>( var );
5109     var = fromVar.sink;
5110   }
5111 
5112   if ( var.canConvert<QgsProperty>() )
5113   {
5114     QgsProperty p = var.value< QgsProperty >();
5115     if ( p.propertyType() == QgsProperty::StaticProperty )
5116     {
5117       var = p.staticValue();
5118     }
5119     else
5120     {
5121       return true;
5122     }
5123   }
5124   if ( qobject_cast< QgsVectorLayer * >( qvariant_cast<QObject *>( input ) ) )
5125   {
5126     return true;
5127   }
5128 
5129   if ( var.type() != QVariant::String || var.toString().isEmpty() )
5130     return mFlags & FlagOptional;
5131 
5132   if ( !context )
5133   {
5134     // that's as far as we can get without a context
5135     return true;
5136   }
5137 
5138   // try to load as layer
5139   if ( QgsProcessingUtils::mapLayerFromString( var.toString(), *context, true, QgsProcessingUtils::LayerHint::Vector ) )
5140     return true;
5141 
5142   return false;
5143 }
5144 
valueAsPythonString(const QVariant & value,QgsProcessingContext & context) const5145 QString QgsProcessingParameterFeatureSource::valueAsPythonString( const QVariant &value, QgsProcessingContext &context ) const
5146 {
5147   if ( !value.isValid() )
5148     return QStringLiteral( "None" );
5149 
5150   if ( value.canConvert<QgsProperty>() )
5151     return QStringLiteral( "QgsProperty.fromExpression(%1)" ).arg( QgsProcessingUtils::stringToPythonLiteral( value.value< QgsProperty >().asExpression() ) );
5152 
5153   if ( value.canConvert<QgsProcessingFeatureSourceDefinition>() )
5154   {
5155     QgsProcessingFeatureSourceDefinition fromVar = qvariant_cast<QgsProcessingFeatureSourceDefinition>( value );
5156     QString geometryCheckString;
5157     switch ( fromVar.geometryCheck )
5158     {
5159       case QgsFeatureRequest::GeometryNoCheck:
5160         geometryCheckString = QStringLiteral( "QgsFeatureRequest.GeometryNoCheck" );
5161         break;
5162 
5163       case QgsFeatureRequest::GeometrySkipInvalid:
5164         geometryCheckString = QStringLiteral( "QgsFeatureRequest.GeometrySkipInvalid" );
5165         break;
5166 
5167       case QgsFeatureRequest::GeometryAbortOnInvalid:
5168         geometryCheckString = QStringLiteral( "QgsFeatureRequest.GeometryAbortOnInvalid" );
5169         break;
5170     }
5171 
5172     QStringList flags;
5173     QString flagString;
5174     if ( fromVar.flags & QgsProcessingFeatureSourceDefinition::Flag::FlagOverrideDefaultGeometryCheck )
5175       flags << QStringLiteral( "QgsProcessingFeatureSourceDefinition.FlagOverrideDefaultGeometryCheck" );
5176     if ( fromVar.flags & QgsProcessingFeatureSourceDefinition::Flag::FlagCreateIndividualOutputPerInputFeature )
5177       flags << QStringLiteral( "QgsProcessingFeatureSourceDefinition.FlagCreateIndividualOutputPerInputFeature" );
5178     if ( !flags.empty() )
5179       flagString = flags.join( QLatin1String( " | " ) );
5180 
5181     if ( fromVar.source.propertyType() == QgsProperty::StaticProperty )
5182     {
5183       QString layerString = fromVar.source.staticValue().toString();
5184       // prefer to use layer source instead of id if possible (since it's persistent)
5185       if ( QgsVectorLayer *layer = qobject_cast< QgsVectorLayer * >( QgsProcessingUtils::mapLayerFromString( layerString, context, true, QgsProcessingUtils::LayerHint::Vector ) ) )
5186         layerString = layer->source();
5187 
5188       if ( fromVar.selectedFeaturesOnly || fromVar.featureLimit != -1 || fromVar.flags )
5189       {
5190         return QStringLiteral( "QgsProcessingFeatureSourceDefinition(%1, selectedFeaturesOnly=%2, featureLimit=%3%4, geometryCheck=%5)" ).arg( QgsProcessingUtils::stringToPythonLiteral( layerString ),
5191                fromVar.selectedFeaturesOnly ? QStringLiteral( "True" ) : QStringLiteral( "False" ),
5192                QString::number( fromVar.featureLimit ),
5193                flagString.isEmpty() ? QString() : ( QStringLiteral( ", flags=%1" ).arg( flagString ) ),
5194                geometryCheckString );
5195       }
5196       else
5197       {
5198         return QgsProcessingUtils::stringToPythonLiteral( layerString );
5199       }
5200     }
5201     else
5202     {
5203       if ( fromVar.selectedFeaturesOnly || fromVar.featureLimit != -1 || fromVar.flags )
5204       {
5205         return QStringLiteral( "QgsProcessingFeatureSourceDefinition(QgsProperty.fromExpression(%1), selectedFeaturesOnly=%2, featureLimit=%3%4, geometryCheck=%5)" )
5206                .arg( QgsProcessingUtils::stringToPythonLiteral( fromVar.source.asExpression() ),
5207                      fromVar.selectedFeaturesOnly ? QStringLiteral( "True" ) : QStringLiteral( "False" ),
5208                      QString::number( fromVar.featureLimit ),
5209                      flagString.isEmpty() ? QString() : ( QStringLiteral( ", flags=%1" ).arg( flagString ) ),
5210                      geometryCheckString );
5211       }
5212       else
5213       {
5214         return QStringLiteral( "QgsProperty.fromExpression(%1)" ).arg( QgsProcessingUtils::stringToPythonLiteral( fromVar.source.asExpression() ) );
5215       }
5216     }
5217   }
5218   else if ( QgsVectorLayer *layer = qobject_cast< QgsVectorLayer * >( qvariant_cast<QObject *>( value ) ) )
5219   {
5220     return QgsProcessingUtils::stringToPythonLiteral( layer->source() );
5221   }
5222 
5223   QString layerString = value.toString();
5224 
5225   // prefer to use layer source if possible (since it's persistent)
5226   if ( QgsVectorLayer *layer = qobject_cast< QgsVectorLayer * >( QgsProcessingUtils::mapLayerFromString( layerString, context, true, QgsProcessingUtils::LayerHint::Vector ) ) )
5227     layerString = layer->providerType() != QLatin1String( "ogr" ) && layer->providerType() != QLatin1String( "gdal" ) && layer->providerType() != QLatin1String( "mdal" ) ? QgsProcessingUtils::encodeProviderKeyAndUri( layer->providerType(), layer->source() ) : layer->source();
5228 
5229   return QgsProcessingUtils::stringToPythonLiteral( layerString );
5230 }
5231 
asScriptCode() const5232 QString QgsProcessingParameterFeatureSource::asScriptCode() const
5233 {
5234   QString code = QStringLiteral( "##%1=" ).arg( mName );
5235   if ( mFlags & FlagOptional )
5236     code += QLatin1String( "optional " );
5237   code += QLatin1String( "source " );
5238 
5239   for ( int type : mDataTypes )
5240   {
5241     switch ( type )
5242     {
5243       case QgsProcessing::TypeVectorPoint:
5244         code += QLatin1String( "point " );
5245         break;
5246 
5247       case QgsProcessing::TypeVectorLine:
5248         code += QLatin1String( "line " );
5249         break;
5250 
5251       case QgsProcessing::TypeVectorPolygon:
5252         code += QLatin1String( "polygon " );
5253         break;
5254 
5255     }
5256   }
5257 
5258   code += mDefault.toString();
5259   return code.trimmed();
5260 }
5261 
asPythonString(const QgsProcessing::PythonOutputType outputType) const5262 QString QgsProcessingParameterFeatureSource::asPythonString( const QgsProcessing::PythonOutputType outputType ) const
5263 {
5264   switch ( outputType )
5265   {
5266     case QgsProcessing::PythonQgsProcessingAlgorithmSubclass:
5267     {
5268       QString code = QStringLiteral( "QgsProcessingParameterFeatureSource('%1', '%2'" ).arg( name(), description() );
5269       if ( mFlags & FlagOptional )
5270         code += QLatin1String( ", optional=True" );
5271 
5272       if ( !mDataTypes.empty() )
5273       {
5274         QStringList options;
5275         options.reserve( mDataTypes.size() );
5276         for ( int t : mDataTypes )
5277           options << QStringLiteral( "QgsProcessing.%1" ).arg( QgsProcessing::sourceTypeToString( static_cast< QgsProcessing::SourceType >( t ) ) );
5278         code += QStringLiteral( ", types=[%1]" ).arg( options.join( ',' ) );
5279       }
5280 
5281       QgsProcessingContext c;
5282       code += QStringLiteral( ", defaultValue=%1)" ).arg( valueAsPythonString( mDefault, c ) );
5283       return code;
5284     }
5285   }
5286   return QString();
5287 }
5288 
createFileFilter() const5289 QString QgsProcessingParameterFeatureSource::createFileFilter() const
5290 {
5291   return QgsProviderRegistry::instance()->fileVectorFilters() + QStringLiteral( ";;" ) + QObject::tr( "All files (*.*)" );
5292 }
5293 
QgsProcessingParameterLimitedDataTypes(const QList<int> & types)5294 QgsProcessingParameterLimitedDataTypes::QgsProcessingParameterLimitedDataTypes( const QList<int> &types )
5295   : mDataTypes( types )
5296 {
5297 
5298 }
5299 
toVariantMap() const5300 QVariantMap QgsProcessingParameterFeatureSource::toVariantMap() const
5301 {
5302   QVariantMap map = QgsProcessingParameterDefinition::toVariantMap();
5303   QVariantList types;
5304   for ( int type : mDataTypes )
5305   {
5306     types << type;
5307   }
5308   map.insert( QStringLiteral( "data_types" ), types );
5309   return map;
5310 }
5311 
fromVariantMap(const QVariantMap & map)5312 bool QgsProcessingParameterFeatureSource::fromVariantMap( const QVariantMap &map )
5313 {
5314   QgsProcessingParameterDefinition::fromVariantMap( map );
5315   mDataTypes.clear();
5316   const QVariantList values = map.value( QStringLiteral( "data_types" ) ).toList();
5317   for ( const QVariant &val : values )
5318   {
5319     mDataTypes << val.toInt();
5320   }
5321   return true;
5322 }
5323 
fromScriptCode(const QString & name,const QString & description,bool isOptional,const QString & definition)5324 QgsProcessingParameterFeatureSource *QgsProcessingParameterFeatureSource::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
5325 {
5326   QList< int > types;
5327   QString def = definition;
5328   while ( true )
5329   {
5330     if ( def.startsWith( QLatin1String( "point" ), Qt::CaseInsensitive ) )
5331     {
5332       types << QgsProcessing::TypeVectorPoint;
5333       def = def.mid( 6 );
5334       continue;
5335     }
5336     else if ( def.startsWith( QLatin1String( "line" ), Qt::CaseInsensitive ) )
5337     {
5338       types << QgsProcessing::TypeVectorLine;
5339       def = def.mid( 5 );
5340       continue;
5341     }
5342     else if ( def.startsWith( QLatin1String( "polygon" ), Qt::CaseInsensitive ) )
5343     {
5344       types << QgsProcessing::TypeVectorPolygon;
5345       def = def.mid( 8 );
5346       continue;
5347     }
5348     break;
5349   }
5350 
5351   return new QgsProcessingParameterFeatureSource( name, description, types, def, isOptional );
5352 }
5353 
QgsProcessingParameterFeatureSink(const QString & name,const QString & description,QgsProcessing::SourceType type,const QVariant & defaultValue,bool optional,bool createByDefault,bool supportsAppend)5354 QgsProcessingParameterFeatureSink::QgsProcessingParameterFeatureSink( const QString &name, const QString &description, QgsProcessing::SourceType type, const QVariant &defaultValue, bool optional, bool createByDefault, bool supportsAppend )
5355   : QgsProcessingDestinationParameter( name, description, defaultValue, optional, createByDefault )
5356   , mDataType( type )
5357   , mSupportsAppend( supportsAppend )
5358 {
5359 }
5360 
clone() const5361 QgsProcessingParameterDefinition *QgsProcessingParameterFeatureSink::clone() const
5362 {
5363   return new QgsProcessingParameterFeatureSink( *this );
5364 }
5365 
checkValueIsAcceptable(const QVariant & input,QgsProcessingContext *) const5366 bool QgsProcessingParameterFeatureSink::checkValueIsAcceptable( const QVariant &input, QgsProcessingContext * ) const
5367 {
5368   QVariant var = input;
5369   if ( !var.isValid() )
5370     return mFlags & FlagOptional;
5371 
5372   if ( var.canConvert<QgsProcessingOutputLayerDefinition>() )
5373   {
5374     QgsProcessingOutputLayerDefinition fromVar = qvariant_cast<QgsProcessingOutputLayerDefinition>( var );
5375     var = fromVar.sink;
5376   }
5377 
5378   if ( var.canConvert<QgsProperty>() )
5379   {
5380     QgsProperty p = var.value< QgsProperty >();
5381     if ( p.propertyType() == QgsProperty::StaticProperty )
5382     {
5383       var = p.staticValue();
5384     }
5385     else
5386     {
5387       return true;
5388     }
5389   }
5390 
5391   if ( var.type() != QVariant::String )
5392     return false;
5393 
5394   if ( var.toString().isEmpty() )
5395     return mFlags & FlagOptional;
5396 
5397   return true;
5398 }
5399 
valueAsPythonString(const QVariant & value,QgsProcessingContext &) const5400 QString QgsProcessingParameterFeatureSink::valueAsPythonString( const QVariant &value, QgsProcessingContext & ) const
5401 {
5402   if ( !value.isValid() )
5403     return QStringLiteral( "None" );
5404 
5405   if ( value.canConvert<QgsProperty>() )
5406     return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
5407 
5408   if ( value.canConvert<QgsProcessingOutputLayerDefinition>() )
5409   {
5410     QgsProcessingOutputLayerDefinition fromVar = qvariant_cast<QgsProcessingOutputLayerDefinition>( value );
5411     if ( fromVar.sink.propertyType() == QgsProperty::StaticProperty )
5412     {
5413       return QgsProcessingUtils::stringToPythonLiteral( fromVar.sink.staticValue().toString() );
5414     }
5415     else
5416     {
5417       return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( fromVar.sink.asExpression() );
5418     }
5419   }
5420 
5421   return QgsProcessingUtils::stringToPythonLiteral( value.toString() );
5422 }
5423 
asScriptCode() const5424 QString QgsProcessingParameterFeatureSink::asScriptCode() const
5425 {
5426   QString code = QStringLiteral( "##%1=" ).arg( mName );
5427   if ( mFlags & FlagOptional )
5428     code += QLatin1String( "optional " );
5429   code += QLatin1String( "sink " );
5430 
5431   switch ( mDataType )
5432   {
5433     case QgsProcessing::TypeVectorPoint:
5434       code += QLatin1String( "point " );
5435       break;
5436 
5437     case QgsProcessing::TypeVectorLine:
5438       code += QLatin1String( "line " );
5439       break;
5440 
5441     case QgsProcessing::TypeVectorPolygon:
5442       code += QLatin1String( "polygon " );
5443       break;
5444 
5445     case QgsProcessing::TypeVector:
5446       code += QLatin1String( "table " );
5447       break;
5448 
5449     default:
5450       break;
5451   }
5452 
5453   code += mDefault.toString();
5454   return code.trimmed();
5455 }
5456 
toOutputDefinition() const5457 QgsProcessingOutputDefinition *QgsProcessingParameterFeatureSink::toOutputDefinition() const
5458 {
5459   return new QgsProcessingOutputVectorLayer( name(), description(), mDataType );
5460 }
5461 
defaultFileExtension() const5462 QString QgsProcessingParameterFeatureSink::defaultFileExtension() const
5463 {
5464   if ( auto *lOriginalProvider = originalProvider() )
5465   {
5466     return lOriginalProvider->defaultVectorFileExtension( hasGeometry() );
5467   }
5468   else if ( QgsProcessingProvider *p = provider() )
5469   {
5470     return p->defaultVectorFileExtension( hasGeometry() );
5471   }
5472   else
5473   {
5474     if ( hasGeometry() )
5475     {
5476       return QgsProcessingUtils::defaultVectorExtension();
5477     }
5478     else
5479     {
5480       return QStringLiteral( "dbf" );
5481     }
5482   }
5483 }
5484 
asPythonString(const QgsProcessing::PythonOutputType outputType) const5485 QString QgsProcessingParameterFeatureSink::asPythonString( const QgsProcessing::PythonOutputType outputType ) const
5486 {
5487   switch ( outputType )
5488   {
5489     case QgsProcessing::PythonQgsProcessingAlgorithmSubclass:
5490     {
5491       QString code = QStringLiteral( "QgsProcessingParameterFeatureSink('%1', '%2'" ).arg( name(), description() );
5492       if ( mFlags & FlagOptional )
5493         code += QLatin1String( ", optional=True" );
5494 
5495       code += QStringLiteral( ", type=QgsProcessing.%1" ).arg( QgsProcessing::sourceTypeToString( mDataType ) );
5496 
5497       code += QStringLiteral( ", createByDefault=%1" ).arg( createByDefault() ? QStringLiteral( "True" ) : QStringLiteral( "False" ) );
5498       if ( mSupportsAppend )
5499         code += QLatin1String( ", supportsAppend=True" );
5500 
5501       QgsProcessingContext c;
5502       code += QStringLiteral( ", defaultValue=%1)" ).arg( valueAsPythonString( mDefault, c ) );
5503       return code;
5504     }
5505   }
5506   return QString();
5507 }
5508 
createFileFilter() const5509 QString QgsProcessingParameterFeatureSink::createFileFilter() const
5510 {
5511   const QStringList exts = supportedOutputVectorLayerExtensions();
5512   QStringList filters;
5513   for ( const QString &ext : exts )
5514   {
5515     filters << QObject::tr( "%1 files (*.%2)" ).arg( ext.toUpper(), ext.toLower() );
5516   }
5517   return filters.join( QLatin1String( ";;" ) ) + QStringLiteral( ";;" ) + QObject::tr( "All files (*.*)" );
5518 
5519 }
5520 
supportedOutputVectorLayerExtensions() const5521 QStringList QgsProcessingParameterFeatureSink::supportedOutputVectorLayerExtensions() const
5522 {
5523   if ( auto *lOriginalProvider = originalProvider() )
5524   {
5525     if ( hasGeometry() )
5526       return lOriginalProvider->supportedOutputVectorLayerExtensions();
5527     else
5528       return lOriginalProvider->supportedOutputTableExtensions();
5529   }
5530   else if ( QgsProcessingProvider *p = provider() )
5531   {
5532     if ( hasGeometry() )
5533       return p->supportedOutputVectorLayerExtensions();
5534     else
5535       return p->supportedOutputTableExtensions();
5536   }
5537   else
5538   {
5539     return QgsVectorFileWriter::supportedFormatExtensions();
5540   }
5541 }
5542 
dataType() const5543 QgsProcessing::SourceType QgsProcessingParameterFeatureSink::dataType() const
5544 {
5545   return mDataType;
5546 }
5547 
hasGeometry() const5548 bool QgsProcessingParameterFeatureSink::hasGeometry() const
5549 {
5550   switch ( mDataType )
5551   {
5552     case QgsProcessing::TypeMapLayer:
5553     case QgsProcessing::TypeVectorAnyGeometry:
5554     case QgsProcessing::TypeVectorPoint:
5555     case QgsProcessing::TypeVectorLine:
5556     case QgsProcessing::TypeVectorPolygon:
5557       return true;
5558 
5559     case QgsProcessing::TypeRaster:
5560     case QgsProcessing::TypeFile:
5561     case QgsProcessing::TypeVector:
5562     case QgsProcessing::TypeMesh:
5563       return false;
5564   }
5565   return true;
5566 }
5567 
setDataType(QgsProcessing::SourceType type)5568 void QgsProcessingParameterFeatureSink::setDataType( QgsProcessing::SourceType type )
5569 {
5570   mDataType = type;
5571 }
5572 
toVariantMap() const5573 QVariantMap QgsProcessingParameterFeatureSink::toVariantMap() const
5574 {
5575   QVariantMap map = QgsProcessingDestinationParameter::toVariantMap();
5576   map.insert( QStringLiteral( "data_type" ), mDataType );
5577   map.insert( QStringLiteral( "supports_append" ), mSupportsAppend );
5578   return map;
5579 }
5580 
fromVariantMap(const QVariantMap & map)5581 bool QgsProcessingParameterFeatureSink::fromVariantMap( const QVariantMap &map )
5582 {
5583   QgsProcessingDestinationParameter::fromVariantMap( map );
5584   mDataType = static_cast< QgsProcessing::SourceType >( map.value( QStringLiteral( "data_type" ) ).toInt() );
5585   mSupportsAppend = map.value( QStringLiteral( "supports_append" ), false ).toBool();
5586   return true;
5587 }
5588 
generateTemporaryDestination() const5589 QString QgsProcessingParameterFeatureSink::generateTemporaryDestination() const
5590 {
5591   if ( supportsNonFileBasedOutput() )
5592     return QStringLiteral( "memory:%1" ).arg( description() );
5593   else
5594     return QgsProcessingDestinationParameter::generateTemporaryDestination();
5595 }
5596 
fromScriptCode(const QString & name,const QString & description,bool isOptional,const QString & definition)5597 QgsProcessingParameterFeatureSink *QgsProcessingParameterFeatureSink::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
5598 {
5599   QgsProcessing::SourceType type = QgsProcessing::TypeVectorAnyGeometry;
5600   QString def = definition;
5601   if ( def.startsWith( QLatin1String( "point" ), Qt::CaseInsensitive ) )
5602   {
5603     type = QgsProcessing::TypeVectorPoint;
5604     def = def.mid( 6 );
5605   }
5606   else if ( def.startsWith( QLatin1String( "line" ), Qt::CaseInsensitive ) )
5607   {
5608     type = QgsProcessing::TypeVectorLine;
5609     def = def.mid( 5 );
5610   }
5611   else if ( def.startsWith( QLatin1String( "polygon" ), Qt::CaseInsensitive ) )
5612   {
5613     type = QgsProcessing::TypeVectorPolygon;
5614     def = def.mid( 8 );
5615   }
5616   else if ( def.startsWith( QLatin1String( "table" ), Qt::CaseInsensitive ) )
5617   {
5618     type = QgsProcessing::TypeVector;
5619     def = def.mid( 6 );
5620   }
5621 
5622   return new QgsProcessingParameterFeatureSink( name, description, type, definition, isOptional );
5623 }
5624 
supportsAppend() const5625 bool QgsProcessingParameterFeatureSink::supportsAppend() const
5626 {
5627   return mSupportsAppend;
5628 }
5629 
setSupportsAppend(bool supportsAppend)5630 void QgsProcessingParameterFeatureSink::setSupportsAppend( bool supportsAppend )
5631 {
5632   mSupportsAppend = supportsAppend;
5633 }
5634 
QgsProcessingParameterRasterDestination(const QString & name,const QString & description,const QVariant & defaultValue,bool optional,bool createByDefault)5635 QgsProcessingParameterRasterDestination::QgsProcessingParameterRasterDestination( const QString &name, const QString &description, const QVariant &defaultValue, bool optional, bool createByDefault )
5636   : QgsProcessingDestinationParameter( name, description, defaultValue, optional, createByDefault )
5637 {
5638 }
5639 
clone() const5640 QgsProcessingParameterDefinition *QgsProcessingParameterRasterDestination::clone() const
5641 {
5642   return new QgsProcessingParameterRasterDestination( *this );
5643 }
5644 
checkValueIsAcceptable(const QVariant & input,QgsProcessingContext *) const5645 bool QgsProcessingParameterRasterDestination::checkValueIsAcceptable( const QVariant &input, QgsProcessingContext * ) const
5646 {
5647   QVariant var = input;
5648   if ( !var.isValid() )
5649     return mFlags & FlagOptional;
5650 
5651   if ( var.canConvert<QgsProcessingOutputLayerDefinition>() )
5652   {
5653     QgsProcessingOutputLayerDefinition fromVar = qvariant_cast<QgsProcessingOutputLayerDefinition>( var );
5654     var = fromVar.sink;
5655   }
5656 
5657   if ( var.canConvert<QgsProperty>() )
5658   {
5659     QgsProperty p = var.value< QgsProperty >();
5660     if ( p.propertyType() == QgsProperty::StaticProperty )
5661     {
5662       var = p.staticValue();
5663     }
5664     else
5665     {
5666       return true;
5667     }
5668   }
5669 
5670   if ( var.type() != QVariant::String )
5671     return false;
5672 
5673   if ( var.toString().isEmpty() )
5674     return mFlags & FlagOptional;
5675 
5676   return true;
5677 }
5678 
valueAsPythonString(const QVariant & value,QgsProcessingContext &) const5679 QString QgsProcessingParameterRasterDestination::valueAsPythonString( const QVariant &value, QgsProcessingContext & ) const
5680 {
5681   if ( !value.isValid() )
5682     return QStringLiteral( "None" );
5683 
5684   if ( value.canConvert<QgsProperty>() )
5685     return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
5686 
5687   if ( value.canConvert<QgsProcessingOutputLayerDefinition>() )
5688   {
5689     QgsProcessingOutputLayerDefinition fromVar = qvariant_cast<QgsProcessingOutputLayerDefinition>( value );
5690     if ( fromVar.sink.propertyType() == QgsProperty::StaticProperty )
5691     {
5692       return QgsProcessingUtils::stringToPythonLiteral( fromVar.sink.staticValue().toString() );
5693     }
5694     else
5695     {
5696       return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( fromVar.sink.asExpression() );
5697     }
5698   }
5699 
5700   return QgsProcessingUtils::stringToPythonLiteral( value.toString() );
5701 }
5702 
toOutputDefinition() const5703 QgsProcessingOutputDefinition *QgsProcessingParameterRasterDestination::toOutputDefinition() const
5704 {
5705   return new QgsProcessingOutputRasterLayer( name(), description() );
5706 }
5707 
defaultFileExtension() const5708 QString QgsProcessingParameterRasterDestination::defaultFileExtension() const
5709 {
5710   if ( auto *lOriginalProvider = originalProvider() )
5711   {
5712     return lOriginalProvider->defaultRasterFileExtension();
5713   }
5714   else if ( QgsProcessingProvider *p = provider() )
5715   {
5716     return p->defaultRasterFileExtension();
5717   }
5718   else
5719   {
5720     return QgsProcessingUtils::defaultRasterExtension();
5721   }
5722 }
5723 
createFileFilter() const5724 QString QgsProcessingParameterRasterDestination::createFileFilter() const
5725 {
5726   const QStringList exts = supportedOutputRasterLayerExtensions();
5727   QStringList filters;
5728   for ( const QString &ext : exts )
5729   {
5730     filters << QObject::tr( "%1 files (*.%2)" ).arg( ext.toUpper(), ext.toLower() );
5731   }
5732   return filters.join( QLatin1String( ";;" ) ) + QStringLiteral( ";;" ) + QObject::tr( "All files (*.*)" );
5733 }
5734 
supportedOutputRasterLayerExtensions() const5735 QStringList QgsProcessingParameterRasterDestination::supportedOutputRasterLayerExtensions() const
5736 {
5737   if ( auto *lOriginalProvider = originalProvider() )
5738   {
5739     return lOriginalProvider->supportedOutputRasterLayerExtensions();
5740   }
5741   else if ( QgsProcessingProvider *p = provider() )
5742   {
5743     return p->supportedOutputRasterLayerExtensions();
5744   }
5745   else
5746   {
5747     return QgsRasterFileWriter::supportedFormatExtensions();
5748   }
5749 }
5750 
fromScriptCode(const QString & name,const QString & description,bool isOptional,const QString & definition)5751 QgsProcessingParameterRasterDestination *QgsProcessingParameterRasterDestination::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
5752 {
5753   return new QgsProcessingParameterRasterDestination( name, description, definition.isEmpty() ? QVariant() : definition, isOptional );
5754 }
5755 
5756 
QgsProcessingParameterFileDestination(const QString & name,const QString & description,const QString & fileFilter,const QVariant & defaultValue,bool optional,bool createByDefault)5757 QgsProcessingParameterFileDestination::QgsProcessingParameterFileDestination( const QString &name, const QString &description, const QString &fileFilter, const QVariant &defaultValue, bool optional, bool createByDefault )
5758   : QgsProcessingDestinationParameter( name, description, defaultValue, optional, createByDefault )
5759   , mFileFilter( fileFilter.isEmpty() ? QObject::tr( "All files (*.*)" ) : fileFilter )
5760 {
5761 
5762 }
5763 
clone() const5764 QgsProcessingParameterDefinition *QgsProcessingParameterFileDestination::clone() const
5765 {
5766   return new QgsProcessingParameterFileDestination( *this );
5767 }
5768 
checkValueIsAcceptable(const QVariant & input,QgsProcessingContext *) const5769 bool QgsProcessingParameterFileDestination::checkValueIsAcceptable( const QVariant &input, QgsProcessingContext * ) const
5770 {
5771   QVariant var = input;
5772   if ( !var.isValid() )
5773     return mFlags & FlagOptional;
5774 
5775   if ( var.canConvert<QgsProcessingOutputLayerDefinition>() )
5776   {
5777     QgsProcessingOutputLayerDefinition fromVar = qvariant_cast<QgsProcessingOutputLayerDefinition>( var );
5778     var = fromVar.sink;
5779   }
5780 
5781   if ( var.canConvert<QgsProperty>() )
5782   {
5783     QgsProperty p = var.value< QgsProperty >();
5784     if ( p.propertyType() == QgsProperty::StaticProperty )
5785     {
5786       var = p.staticValue();
5787     }
5788     else
5789     {
5790       return true;
5791     }
5792   }
5793 
5794   if ( var.type() != QVariant::String )
5795     return false;
5796 
5797   if ( var.toString().isEmpty() )
5798     return mFlags & FlagOptional;
5799 
5800   // possible enhancement - check that value is compatible with file filter?
5801 
5802   return true;
5803 }
5804 
valueAsPythonString(const QVariant & value,QgsProcessingContext &) const5805 QString QgsProcessingParameterFileDestination::valueAsPythonString( const QVariant &value, QgsProcessingContext & ) const
5806 {
5807   if ( !value.isValid() )
5808     return QStringLiteral( "None" );
5809 
5810   if ( value.canConvert<QgsProperty>() )
5811     return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
5812 
5813   if ( value.canConvert<QgsProcessingOutputLayerDefinition>() )
5814   {
5815     QgsProcessingOutputLayerDefinition fromVar = qvariant_cast<QgsProcessingOutputLayerDefinition>( value );
5816     if ( fromVar.sink.propertyType() == QgsProperty::StaticProperty )
5817     {
5818       return QgsProcessingUtils::stringToPythonLiteral( fromVar.sink.staticValue().toString() );
5819     }
5820     else
5821     {
5822       return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( fromVar.sink.asExpression() );
5823     }
5824   }
5825 
5826   return QgsProcessingUtils::stringToPythonLiteral( value.toString() );
5827 }
5828 
toOutputDefinition() const5829 QgsProcessingOutputDefinition *QgsProcessingParameterFileDestination::toOutputDefinition() const
5830 {
5831   if ( !mFileFilter.isEmpty() && mFileFilter.contains( QStringLiteral( "htm" ), Qt::CaseInsensitive ) )
5832   {
5833     return new QgsProcessingOutputHtml( name(), description() );
5834   }
5835   else
5836   {
5837     return new QgsProcessingOutputFile( name(), description() );
5838   }
5839 }
5840 
defaultFileExtension() const5841 QString QgsProcessingParameterFileDestination::defaultFileExtension() const
5842 {
5843   if ( mFileFilter.isEmpty() || mFileFilter == QObject::tr( "All files (*.*)" ) )
5844     return QStringLiteral( "file" );
5845 
5846   // get first extension from filter
5847   QRegularExpression rx( QStringLiteral( ".*?\\(\\*\\.([a-zA-Z0-9._]+).*" ) );
5848   QRegularExpressionMatch match = rx.match( mFileFilter );
5849   if ( !match.hasMatch() )
5850     return QStringLiteral( "file" );
5851 
5852   return match.captured( 1 );
5853 }
5854 
asPythonString(const QgsProcessing::PythonOutputType outputType) const5855 QString QgsProcessingParameterFileDestination::asPythonString( const QgsProcessing::PythonOutputType outputType ) const
5856 {
5857   switch ( outputType )
5858   {
5859     case QgsProcessing::PythonQgsProcessingAlgorithmSubclass:
5860     {
5861       QString code = QStringLiteral( "QgsProcessingParameterFileDestination('%1', '%2'" ).arg( name(), description() );
5862       if ( mFlags & FlagOptional )
5863         code += QLatin1String( ", optional=True" );
5864 
5865       code += QStringLiteral( ", fileFilter=%1" ).arg( QgsProcessingUtils::stringToPythonLiteral( mFileFilter ) );
5866 
5867       code += QStringLiteral( ", createByDefault=%1" ).arg( createByDefault() ? QStringLiteral( "True" ) : QStringLiteral( "False" ) );
5868 
5869       QgsProcessingContext c;
5870       code += QStringLiteral( ", defaultValue=%1)" ).arg( valueAsPythonString( mDefault, c ) );
5871       return code;
5872     }
5873   }
5874   return QString();
5875 }
5876 
createFileFilter() const5877 QString QgsProcessingParameterFileDestination::createFileFilter() const
5878 {
5879   return ( fileFilter().isEmpty() ? QString() : fileFilter() + QStringLiteral( ";;" ) ) + QObject::tr( "All files (*.*)" );
5880 }
5881 
fileFilter() const5882 QString QgsProcessingParameterFileDestination::fileFilter() const
5883 {
5884   return mFileFilter;
5885 }
5886 
setFileFilter(const QString & fileFilter)5887 void QgsProcessingParameterFileDestination::setFileFilter( const QString &fileFilter )
5888 {
5889   mFileFilter = fileFilter;
5890 }
5891 
toVariantMap() const5892 QVariantMap QgsProcessingParameterFileDestination::toVariantMap() const
5893 {
5894   QVariantMap map = QgsProcessingDestinationParameter::toVariantMap();
5895   map.insert( QStringLiteral( "file_filter" ), mFileFilter );
5896   return map;
5897 }
5898 
fromVariantMap(const QVariantMap & map)5899 bool QgsProcessingParameterFileDestination::fromVariantMap( const QVariantMap &map )
5900 {
5901   QgsProcessingDestinationParameter::fromVariantMap( map );
5902   mFileFilter = map.value( QStringLiteral( "file_filter" ) ).toString();
5903   return true;
5904 
5905 }
5906 
fromScriptCode(const QString & name,const QString & description,bool isOptional,const QString & definition)5907 QgsProcessingParameterFileDestination *QgsProcessingParameterFileDestination::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
5908 {
5909   return new QgsProcessingParameterFileDestination( name, description, QString(), definition.isEmpty() ? QVariant() : definition, isOptional );
5910 }
5911 
QgsProcessingParameterFolderDestination(const QString & name,const QString & description,const QVariant & defaultValue,bool optional,bool createByDefault)5912 QgsProcessingParameterFolderDestination::QgsProcessingParameterFolderDestination( const QString &name, const QString &description, const QVariant &defaultValue, bool optional, bool createByDefault )
5913   : QgsProcessingDestinationParameter( name, description, defaultValue, optional, createByDefault )
5914 {}
5915 
clone() const5916 QgsProcessingParameterDefinition *QgsProcessingParameterFolderDestination::clone() const
5917 {
5918   return new QgsProcessingParameterFolderDestination( *this );
5919 }
5920 
checkValueIsAcceptable(const QVariant & input,QgsProcessingContext *) const5921 bool QgsProcessingParameterFolderDestination::checkValueIsAcceptable( const QVariant &input, QgsProcessingContext * ) const
5922 {
5923   QVariant var = input;
5924   if ( !var.isValid() )
5925     return mFlags & FlagOptional;
5926 
5927   if ( var.canConvert<QgsProperty>() )
5928   {
5929     QgsProperty p = var.value< QgsProperty >();
5930     if ( p.propertyType() == QgsProperty::StaticProperty )
5931     {
5932       var = p.staticValue();
5933     }
5934     else
5935     {
5936       return true;
5937     }
5938   }
5939 
5940   if ( var.type() != QVariant::String )
5941     return false;
5942 
5943   if ( var.toString().isEmpty() )
5944     return mFlags & FlagOptional;
5945 
5946   return true;
5947 }
5948 
toOutputDefinition() const5949 QgsProcessingOutputDefinition *QgsProcessingParameterFolderDestination::toOutputDefinition() const
5950 {
5951   return new QgsProcessingOutputFolder( name(), description() );
5952 }
5953 
defaultFileExtension() const5954 QString QgsProcessingParameterFolderDestination::defaultFileExtension() const
5955 {
5956   return QString();
5957 }
5958 
fromScriptCode(const QString & name,const QString & description,bool isOptional,const QString & definition)5959 QgsProcessingParameterFolderDestination *QgsProcessingParameterFolderDestination::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
5960 {
5961   return new QgsProcessingParameterFolderDestination( name, description, definition.isEmpty() ? QVariant() : definition, isOptional );
5962 }
5963 
QgsProcessingDestinationParameter(const QString & name,const QString & description,const QVariant & defaultValue,bool optional,bool createByDefault)5964 QgsProcessingDestinationParameter::QgsProcessingDestinationParameter( const QString &name, const QString &description, const QVariant &defaultValue, bool optional, bool createByDefault )
5965   : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
5966   , mCreateByDefault( createByDefault )
5967 {
5968 
5969 }
5970 
toVariantMap() const5971 QVariantMap QgsProcessingDestinationParameter::toVariantMap() const
5972 {
5973   QVariantMap map = QgsProcessingParameterDefinition::toVariantMap();
5974   map.insert( QStringLiteral( "supports_non_file_outputs" ), mSupportsNonFileBasedOutputs );
5975   map.insert( QStringLiteral( "create_by_default" ), mCreateByDefault );
5976   return map;
5977 }
5978 
fromVariantMap(const QVariantMap & map)5979 bool QgsProcessingDestinationParameter::fromVariantMap( const QVariantMap &map )
5980 {
5981   QgsProcessingParameterDefinition::fromVariantMap( map );
5982   mSupportsNonFileBasedOutputs = map.value( QStringLiteral( "supports_non_file_outputs" ) ).toBool();
5983   mCreateByDefault = map.value( QStringLiteral( "create_by_default" ), QStringLiteral( "1" ) ).toBool();
5984   return true;
5985 }
5986 
asPythonString(const QgsProcessing::PythonOutputType outputType) const5987 QString QgsProcessingDestinationParameter::asPythonString( const QgsProcessing::PythonOutputType outputType ) const
5988 {
5989   switch ( outputType )
5990   {
5991     case QgsProcessing::PythonQgsProcessingAlgorithmSubclass:
5992     {
5993       // base class method is probably not much use
5994       if ( QgsProcessingParameterType *t = QgsApplication::processingRegistry()->parameterType( type() ) )
5995       {
5996         QString code = t->className() + QStringLiteral( "('%1', '%2'" ).arg( name(), description() );
5997         if ( mFlags & FlagOptional )
5998           code += QLatin1String( ", optional=True" );
5999 
6000         code += QStringLiteral( ", createByDefault=%1" ).arg( mCreateByDefault ? QStringLiteral( "True" ) : QStringLiteral( "False" ) );
6001 
6002         QgsProcessingContext c;
6003         code += QStringLiteral( ", defaultValue=%1)" ).arg( valueAsPythonString( mDefault, c ) );
6004         return code;
6005       }
6006       break;
6007     }
6008   }
6009   // oh well, we tried
6010   return QString();
6011 }
6012 
createFileFilter() const6013 QString QgsProcessingDestinationParameter::createFileFilter() const
6014 {
6015   return QObject::tr( "Default extension" ) + QStringLiteral( " (*." ) + defaultFileExtension() + ')';
6016 }
6017 
generateTemporaryDestination() const6018 QString QgsProcessingDestinationParameter::generateTemporaryDestination() const
6019 {
6020   // sanitize name to avoid multiple . in the filename. E.g. when name() contain
6021   // backend command name having a "." inside as in case of grass commands
6022   QRegularExpression rx( QStringLiteral( "[.]" ) );
6023   QString sanitizedName = name();
6024   sanitizedName.replace( rx, QStringLiteral( "_" ) );
6025 
6026   if ( defaultFileExtension().isEmpty() )
6027   {
6028     return QgsProcessingUtils::generateTempFilename( sanitizedName );
6029   }
6030   else
6031   {
6032     return QgsProcessingUtils::generateTempFilename( sanitizedName + '.' + defaultFileExtension() );
6033   }
6034 }
6035 
isSupportedOutputValue(const QVariant & value,QgsProcessingContext & context,QString & error) const6036 bool QgsProcessingDestinationParameter::isSupportedOutputValue( const QVariant &value, QgsProcessingContext &context, QString &error ) const
6037 {
6038   if ( auto *lOriginalProvider = originalProvider() )
6039     return lOriginalProvider->isSupportedOutputValue( value, this, context, error );
6040   else if ( provider() )
6041     return provider()->isSupportedOutputValue( value, this, context, error );
6042 
6043   return true;
6044 }
6045 
createByDefault() const6046 bool QgsProcessingDestinationParameter::createByDefault() const
6047 {
6048   return mCreateByDefault;
6049 }
6050 
setCreateByDefault(bool createByDefault)6051 void QgsProcessingDestinationParameter::setCreateByDefault( bool createByDefault )
6052 {
6053   mCreateByDefault = createByDefault;
6054 }
6055 
QgsProcessingParameterVectorDestination(const QString & name,const QString & description,QgsProcessing::SourceType type,const QVariant & defaultValue,bool optional,bool createByDefault)6056 QgsProcessingParameterVectorDestination::QgsProcessingParameterVectorDestination( const QString &name, const QString &description, QgsProcessing::SourceType type, const QVariant &defaultValue, bool optional, bool createByDefault )
6057   : QgsProcessingDestinationParameter( name, description, defaultValue, optional, createByDefault )
6058   , mDataType( type )
6059 {
6060 
6061 }
6062 
clone() const6063 QgsProcessingParameterDefinition *QgsProcessingParameterVectorDestination::clone() const
6064 {
6065   return new QgsProcessingParameterVectorDestination( *this );
6066 }
6067 
checkValueIsAcceptable(const QVariant & input,QgsProcessingContext *) const6068 bool QgsProcessingParameterVectorDestination::checkValueIsAcceptable( const QVariant &input, QgsProcessingContext * ) const
6069 {
6070   QVariant var = input;
6071   if ( !var.isValid() )
6072     return mFlags & FlagOptional;
6073 
6074   if ( var.canConvert<QgsProcessingOutputLayerDefinition>() )
6075   {
6076     QgsProcessingOutputLayerDefinition fromVar = qvariant_cast<QgsProcessingOutputLayerDefinition>( var );
6077     var = fromVar.sink;
6078   }
6079 
6080   if ( var.canConvert<QgsProperty>() )
6081   {
6082     QgsProperty p = var.value< QgsProperty >();
6083     if ( p.propertyType() == QgsProperty::StaticProperty )
6084     {
6085       var = p.staticValue();
6086     }
6087     else
6088     {
6089       return true;
6090     }
6091   }
6092 
6093   if ( var.type() != QVariant::String )
6094     return false;
6095 
6096   if ( var.toString().isEmpty() )
6097     return mFlags & FlagOptional;
6098 
6099   return true;
6100 }
6101 
valueAsPythonString(const QVariant & value,QgsProcessingContext &) const6102 QString QgsProcessingParameterVectorDestination::valueAsPythonString( const QVariant &value, QgsProcessingContext & ) const
6103 {
6104   if ( !value.isValid() )
6105     return QStringLiteral( "None" );
6106 
6107   if ( value.canConvert<QgsProperty>() )
6108     return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
6109 
6110   if ( value.canConvert<QgsProcessingOutputLayerDefinition>() )
6111   {
6112     QgsProcessingOutputLayerDefinition fromVar = qvariant_cast<QgsProcessingOutputLayerDefinition>( value );
6113     if ( fromVar.sink.propertyType() == QgsProperty::StaticProperty )
6114     {
6115       return QgsProcessingUtils::stringToPythonLiteral( fromVar.sink.staticValue().toString() );
6116     }
6117     else
6118     {
6119       return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( fromVar.sink.asExpression() );
6120     }
6121   }
6122 
6123   return QgsProcessingUtils::stringToPythonLiteral( value.toString() );
6124 }
6125 
asScriptCode() const6126 QString QgsProcessingParameterVectorDestination::asScriptCode() const
6127 {
6128   QString code = QStringLiteral( "##%1=" ).arg( mName );
6129   if ( mFlags & FlagOptional )
6130     code += QLatin1String( "optional " );
6131   code += QLatin1String( "vectorDestination " );
6132 
6133   switch ( mDataType )
6134   {
6135     case QgsProcessing::TypeVectorPoint:
6136       code += QLatin1String( "point " );
6137       break;
6138 
6139     case QgsProcessing::TypeVectorLine:
6140       code += QLatin1String( "line " );
6141       break;
6142 
6143     case QgsProcessing::TypeVectorPolygon:
6144       code += QLatin1String( "polygon " );
6145       break;
6146 
6147     default:
6148       break;
6149   }
6150 
6151   code += mDefault.toString();
6152   return code.trimmed();
6153 }
6154 
toOutputDefinition() const6155 QgsProcessingOutputDefinition *QgsProcessingParameterVectorDestination::toOutputDefinition() const
6156 {
6157   return new QgsProcessingOutputVectorLayer( name(), description(), mDataType );
6158 }
6159 
defaultFileExtension() const6160 QString QgsProcessingParameterVectorDestination::defaultFileExtension() const
6161 {
6162   if ( auto *lOriginalProvider = originalProvider() )
6163   {
6164     return lOriginalProvider->defaultVectorFileExtension( hasGeometry() );
6165   }
6166   else if ( QgsProcessingProvider *p = provider() )
6167   {
6168     return p->defaultVectorFileExtension( hasGeometry() );
6169   }
6170   else
6171   {
6172     if ( hasGeometry() )
6173     {
6174       return QgsProcessingUtils::defaultVectorExtension();
6175     }
6176     else
6177     {
6178       return QStringLiteral( "dbf" );
6179     }
6180   }
6181 }
6182 
asPythonString(const QgsProcessing::PythonOutputType outputType) const6183 QString QgsProcessingParameterVectorDestination::asPythonString( const QgsProcessing::PythonOutputType outputType ) const
6184 {
6185   switch ( outputType )
6186   {
6187     case QgsProcessing::PythonQgsProcessingAlgorithmSubclass:
6188     {
6189       QString code = QStringLiteral( "QgsProcessingParameterVectorDestination('%1', '%2'" ).arg( name(), description() );
6190       if ( mFlags & FlagOptional )
6191         code += QLatin1String( ", optional=True" );
6192 
6193       code += QStringLiteral( ", type=QgsProcessing.%1" ).arg( QgsProcessing::sourceTypeToString( mDataType ) );
6194 
6195       code += QStringLiteral( ", createByDefault=%1" ).arg( createByDefault() ? QStringLiteral( "True" ) : QStringLiteral( "False" ) );
6196 
6197       QgsProcessingContext c;
6198       code += QStringLiteral( ", defaultValue=%1)" ).arg( valueAsPythonString( mDefault, c ) );
6199       return code;
6200     }
6201   }
6202   return QString();
6203 }
6204 
createFileFilter() const6205 QString QgsProcessingParameterVectorDestination::createFileFilter() const
6206 {
6207   const QStringList exts = supportedOutputVectorLayerExtensions();
6208   QStringList filters;
6209   for ( const QString &ext : exts )
6210   {
6211     filters << QObject::tr( "%1 files (*.%2)" ).arg( ext.toUpper(), ext.toLower() );
6212   }
6213   return filters.join( QLatin1String( ";;" ) ) + QStringLiteral( ";;" ) + QObject::tr( "All files (*.*)" );
6214 }
6215 
supportedOutputVectorLayerExtensions() const6216 QStringList QgsProcessingParameterVectorDestination::supportedOutputVectorLayerExtensions() const
6217 {
6218   if ( auto *lOriginalProvider = originalProvider() )
6219   {
6220     if ( hasGeometry() )
6221       return lOriginalProvider->supportedOutputVectorLayerExtensions();
6222     else
6223       return lOriginalProvider->supportedOutputTableExtensions();
6224   }
6225   else if ( QgsProcessingProvider *p = provider() )
6226   {
6227     if ( hasGeometry() )
6228       return p->supportedOutputVectorLayerExtensions();
6229     else
6230       return p->supportedOutputTableExtensions();
6231   }
6232   else
6233   {
6234     return QgsVectorFileWriter::supportedFormatExtensions();
6235   }
6236 }
6237 
dataType() const6238 QgsProcessing::SourceType QgsProcessingParameterVectorDestination::dataType() const
6239 {
6240   return mDataType;
6241 }
6242 
hasGeometry() const6243 bool QgsProcessingParameterVectorDestination::hasGeometry() const
6244 {
6245   switch ( mDataType )
6246   {
6247     case QgsProcessing::TypeMapLayer:
6248     case QgsProcessing::TypeVectorAnyGeometry:
6249     case QgsProcessing::TypeVectorPoint:
6250     case QgsProcessing::TypeVectorLine:
6251     case QgsProcessing::TypeVectorPolygon:
6252       return true;
6253 
6254     case QgsProcessing::TypeRaster:
6255     case QgsProcessing::TypeFile:
6256     case QgsProcessing::TypeVector:
6257     case QgsProcessing::TypeMesh:
6258       return false;
6259   }
6260   return true;
6261 }
6262 
setDataType(QgsProcessing::SourceType type)6263 void QgsProcessingParameterVectorDestination::setDataType( QgsProcessing::SourceType type )
6264 {
6265   mDataType = type;
6266 }
6267 
toVariantMap() const6268 QVariantMap QgsProcessingParameterVectorDestination::toVariantMap() const
6269 {
6270   QVariantMap map = QgsProcessingDestinationParameter::toVariantMap();
6271   map.insert( QStringLiteral( "data_type" ), mDataType );
6272   return map;
6273 }
6274 
fromVariantMap(const QVariantMap & map)6275 bool QgsProcessingParameterVectorDestination::fromVariantMap( const QVariantMap &map )
6276 {
6277   QgsProcessingDestinationParameter::fromVariantMap( map );
6278   mDataType = static_cast< QgsProcessing::SourceType >( map.value( QStringLiteral( "data_type" ) ).toInt() );
6279   return true;
6280 }
6281 
fromScriptCode(const QString & name,const QString & description,bool isOptional,const QString & definition)6282 QgsProcessingParameterVectorDestination *QgsProcessingParameterVectorDestination::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
6283 {
6284   QgsProcessing::SourceType type = QgsProcessing::TypeVectorAnyGeometry;
6285   QString def = definition;
6286   if ( def.startsWith( QLatin1String( "point" ), Qt::CaseInsensitive ) )
6287   {
6288     type = QgsProcessing::TypeVectorPoint;
6289     def = def.mid( 6 );
6290   }
6291   else if ( def.startsWith( QLatin1String( "line" ), Qt::CaseInsensitive ) )
6292   {
6293     type = QgsProcessing::TypeVectorLine;
6294     def = def.mid( 5 );
6295   }
6296   else if ( def.startsWith( QLatin1String( "polygon" ), Qt::CaseInsensitive ) )
6297   {
6298     type = QgsProcessing::TypeVectorPolygon;
6299     def = def.mid( 8 );
6300   }
6301 
6302   return new QgsProcessingParameterVectorDestination( name, description, type, definition, isOptional );
6303 }
6304 
QgsProcessingParameterBand(const QString & name,const QString & description,const QVariant & defaultValue,const QString & parentLayerParameterName,bool optional,bool allowMultiple)6305 QgsProcessingParameterBand::QgsProcessingParameterBand( const QString &name, const QString &description, const QVariant &defaultValue, const QString &parentLayerParameterName, bool optional, bool allowMultiple )
6306   : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
6307   , mParentLayerParameterName( parentLayerParameterName )
6308   , mAllowMultiple( allowMultiple )
6309 {
6310 
6311 }
6312 
clone() const6313 QgsProcessingParameterDefinition *QgsProcessingParameterBand::clone() const
6314 {
6315   return new QgsProcessingParameterBand( *this );
6316 }
6317 
checkValueIsAcceptable(const QVariant & input,QgsProcessingContext *) const6318 bool QgsProcessingParameterBand::checkValueIsAcceptable( const QVariant &input, QgsProcessingContext * ) const
6319 {
6320   if ( !input.isValid() )
6321     return mFlags & FlagOptional;
6322 
6323   if ( input.canConvert<QgsProperty>() )
6324   {
6325     return true;
6326   }
6327 
6328   if ( input.type() == QVariant::List || input.type() == QVariant::StringList )
6329   {
6330     if ( !mAllowMultiple )
6331       return false;
6332 
6333     if ( input.toList().isEmpty() && !( mFlags & FlagOptional ) )
6334       return false;
6335   }
6336   else
6337   {
6338     bool ok = false;
6339     double res = input.toInt( &ok );
6340     Q_UNUSED( res )
6341     if ( !ok )
6342       return mFlags & FlagOptional;
6343   }
6344   return true;
6345 }
6346 
allowMultiple() const6347 bool QgsProcessingParameterBand::allowMultiple() const
6348 {
6349   return mAllowMultiple;
6350 }
6351 
setAllowMultiple(bool allowMultiple)6352 void QgsProcessingParameterBand::setAllowMultiple( bool allowMultiple )
6353 {
6354   mAllowMultiple = allowMultiple;
6355 }
6356 
valueAsPythonString(const QVariant & value,QgsProcessingContext &) const6357 QString QgsProcessingParameterBand::valueAsPythonString( const QVariant &value, QgsProcessingContext & ) const
6358 {
6359   if ( !value.isValid() )
6360     return QStringLiteral( "None" );
6361 
6362   if ( value.canConvert<QgsProperty>() )
6363     return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
6364 
6365   if ( value.type() == QVariant::List )
6366   {
6367     QStringList parts;
6368     QVariantList values = value.toList();
6369     for ( auto it = values.constBegin(); it != values.constEnd(); ++it )
6370     {
6371       parts << QString::number( static_cast< int >( it->toDouble() ) );
6372     }
6373     return parts.join( ',' ).prepend( '[' ).append( ']' );
6374   }
6375   else if ( value.type() == QVariant::StringList )
6376   {
6377     QStringList parts;
6378     QStringList values = value.toStringList();
6379     for ( auto it = values.constBegin(); it != values.constEnd(); ++it )
6380     {
6381       parts << QString::number( static_cast< int >( it->toDouble() ) );
6382     }
6383     return parts.join( ',' ).prepend( '[' ).append( ']' );
6384   }
6385 
6386   return value.toString();
6387 }
6388 
asScriptCode() const6389 QString QgsProcessingParameterBand::asScriptCode() const
6390 {
6391   QString code = QStringLiteral( "##%1=" ).arg( mName );
6392   if ( mFlags & FlagOptional )
6393     code += QLatin1String( "optional " );
6394   code += QLatin1String( "band " );
6395 
6396   if ( mAllowMultiple )
6397     code += QLatin1String( "multiple " );
6398 
6399   code += mParentLayerParameterName + ' ';
6400 
6401   code += mDefault.toString();
6402   return code.trimmed();
6403 }
6404 
dependsOnOtherParameters() const6405 QStringList QgsProcessingParameterBand::dependsOnOtherParameters() const
6406 {
6407   QStringList depends;
6408   if ( !mParentLayerParameterName.isEmpty() )
6409     depends << mParentLayerParameterName;
6410   return depends;
6411 }
6412 
asPythonString(const QgsProcessing::PythonOutputType outputType) const6413 QString QgsProcessingParameterBand::asPythonString( const QgsProcessing::PythonOutputType outputType ) const
6414 {
6415   switch ( outputType )
6416   {
6417     case QgsProcessing::PythonQgsProcessingAlgorithmSubclass:
6418     {
6419       QString code = QStringLiteral( "QgsProcessingParameterBand('%1', '%2'" ).arg( name(), description() );
6420       if ( mFlags & FlagOptional )
6421         code += QLatin1String( ", optional=True" );
6422 
6423       code += QStringLiteral( ", parentLayerParameterName='%1'" ).arg( mParentLayerParameterName );
6424       code += QStringLiteral( ", allowMultiple=%1" ).arg( mAllowMultiple ? QStringLiteral( "True" ) : QStringLiteral( "False" ) );
6425 
6426       QgsProcessingContext c;
6427       code += QStringLiteral( ", defaultValue=%1)" ).arg( valueAsPythonString( mDefault, c ) );
6428       return code;
6429     }
6430   }
6431   return QString();
6432 }
6433 
parentLayerParameterName() const6434 QString QgsProcessingParameterBand::parentLayerParameterName() const
6435 {
6436   return mParentLayerParameterName;
6437 }
6438 
setParentLayerParameterName(const QString & parentLayerParameterName)6439 void QgsProcessingParameterBand::setParentLayerParameterName( const QString &parentLayerParameterName )
6440 {
6441   mParentLayerParameterName = parentLayerParameterName;
6442 }
6443 
toVariantMap() const6444 QVariantMap QgsProcessingParameterBand::toVariantMap() const
6445 {
6446   QVariantMap map = QgsProcessingParameterDefinition::toVariantMap();
6447   map.insert( QStringLiteral( "parent_layer" ), mParentLayerParameterName );
6448   map.insert( QStringLiteral( "allow_multiple" ), mAllowMultiple );
6449   return map;
6450 }
6451 
fromVariantMap(const QVariantMap & map)6452 bool QgsProcessingParameterBand::fromVariantMap( const QVariantMap &map )
6453 {
6454   QgsProcessingParameterDefinition::fromVariantMap( map );
6455   mParentLayerParameterName = map.value( QStringLiteral( "parent_layer" ) ).toString();
6456   mAllowMultiple = map.value( QStringLiteral( "allow_multiple" ) ).toBool();
6457   return true;
6458 }
6459 
fromScriptCode(const QString & name,const QString & description,bool isOptional,const QString & definition)6460 QgsProcessingParameterBand *QgsProcessingParameterBand::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
6461 {
6462   QString parent;
6463   QString def = definition;
6464   bool allowMultiple = false;
6465 
6466   if ( def.startsWith( QLatin1String( "multiple" ), Qt::CaseInsensitive ) )
6467   {
6468     allowMultiple = true;
6469     def = def.mid( 8 ).trimmed();
6470   }
6471 
6472   QRegularExpression re( QStringLiteral( "(.*?)\\s+(.*)$" ) );
6473   QRegularExpressionMatch m = re.match( def );
6474   if ( m.hasMatch() )
6475   {
6476     parent = m.captured( 1 ).trimmed();
6477     def = m.captured( 2 );
6478   }
6479   else
6480   {
6481     parent = def;
6482     def.clear();
6483   }
6484 
6485   return new QgsProcessingParameterBand( name, description, def.isEmpty() ? QVariant() : def, parent, isOptional, allowMultiple );
6486 }
6487 
6488 //
6489 // QgsProcessingParameterDistance
6490 //
6491 
QgsProcessingParameterDistance(const QString & name,const QString & description,const QVariant & defaultValue,const QString & parentParameterName,bool optional,double minValue,double maxValue)6492 QgsProcessingParameterDistance::QgsProcessingParameterDistance( const QString &name, const QString &description, const QVariant &defaultValue, const QString &parentParameterName, bool optional, double minValue, double maxValue )
6493   : QgsProcessingParameterNumber( name, description, Double, defaultValue, optional, minValue, maxValue )
6494   , mParentParameterName( parentParameterName )
6495 {
6496 
6497 }
6498 
clone() const6499 QgsProcessingParameterDistance *QgsProcessingParameterDistance::clone() const
6500 {
6501   return new QgsProcessingParameterDistance( *this );
6502 }
6503 
type() const6504 QString QgsProcessingParameterDistance::type() const
6505 {
6506   return typeName();
6507 }
6508 
dependsOnOtherParameters() const6509 QStringList QgsProcessingParameterDistance::dependsOnOtherParameters() const
6510 {
6511   QStringList depends;
6512   if ( !mParentParameterName.isEmpty() )
6513     depends << mParentParameterName;
6514   return depends;
6515 }
6516 
asPythonString(const QgsProcessing::PythonOutputType outputType) const6517 QString QgsProcessingParameterDistance::asPythonString( const QgsProcessing::PythonOutputType outputType ) const
6518 {
6519   switch ( outputType )
6520   {
6521     case QgsProcessing::PythonQgsProcessingAlgorithmSubclass:
6522     {
6523       QString code = QStringLiteral( "QgsProcessingParameterDistance('%1', '%2'" ).arg( name(), description() );
6524       if ( mFlags & FlagOptional )
6525         code += QLatin1String( ", optional=True" );
6526 
6527       code += QStringLiteral( ", parentParameterName='%1'" ).arg( mParentParameterName );
6528 
6529       if ( minimum() != std::numeric_limits<double>::lowest() + 1 )
6530         code += QStringLiteral( ", minValue=%1" ).arg( minimum() );
6531       if ( maximum() != std::numeric_limits<double>::max() )
6532         code += QStringLiteral( ", maxValue=%1" ).arg( maximum() );
6533       QgsProcessingContext c;
6534       code += QStringLiteral( ", defaultValue=%1)" ).arg( valueAsPythonString( mDefault, c ) );
6535       return code;
6536     }
6537   }
6538   return QString();
6539 }
6540 
parentParameterName() const6541 QString QgsProcessingParameterDistance::parentParameterName() const
6542 {
6543   return mParentParameterName;
6544 }
6545 
setParentParameterName(const QString & parentParameterName)6546 void QgsProcessingParameterDistance::setParentParameterName( const QString &parentParameterName )
6547 {
6548   mParentParameterName = parentParameterName;
6549 }
6550 
toVariantMap() const6551 QVariantMap QgsProcessingParameterDistance::toVariantMap() const
6552 {
6553   QVariantMap map = QgsProcessingParameterNumber::toVariantMap();
6554   map.insert( QStringLiteral( "parent" ), mParentParameterName );
6555   map.insert( QStringLiteral( "default_unit" ), static_cast< int >( mDefaultUnit ) );
6556   return map;
6557 }
6558 
fromVariantMap(const QVariantMap & map)6559 bool QgsProcessingParameterDistance::fromVariantMap( const QVariantMap &map )
6560 {
6561   QgsProcessingParameterNumber::fromVariantMap( map );
6562   mParentParameterName = map.value( QStringLiteral( "parent" ) ).toString();
6563   mDefaultUnit = static_cast< QgsUnitTypes::DistanceUnit>( map.value( QStringLiteral( "default_unit" ), QgsUnitTypes::DistanceUnknownUnit ).toInt() );
6564   return true;
6565 }
6566 
6567 
6568 //
6569 // QgsProcessingParameterScale
6570 //
6571 
QgsProcessingParameterScale(const QString & name,const QString & description,const QVariant & defaultValue,bool optional)6572 QgsProcessingParameterScale::QgsProcessingParameterScale( const QString &name, const QString &description, const QVariant &defaultValue, bool optional )
6573   : QgsProcessingParameterNumber( name, description, Double, defaultValue, optional )
6574 {
6575 
6576 }
6577 
clone() const6578 QgsProcessingParameterScale *QgsProcessingParameterScale::clone() const
6579 {
6580   return new QgsProcessingParameterScale( *this );
6581 }
6582 
type() const6583 QString QgsProcessingParameterScale::type() const
6584 {
6585   return typeName();
6586 }
6587 
asPythonString(const QgsProcessing::PythonOutputType outputType) const6588 QString QgsProcessingParameterScale::asPythonString( const QgsProcessing::PythonOutputType outputType ) const
6589 {
6590   switch ( outputType )
6591   {
6592     case QgsProcessing::PythonQgsProcessingAlgorithmSubclass:
6593     {
6594       QString code = QStringLiteral( "QgsProcessingParameterScale('%1', '%2'" ).arg( name(), description() );
6595       if ( mFlags & FlagOptional )
6596         code += QLatin1String( ", optional=True" );
6597       QgsProcessingContext c;
6598       code += QStringLiteral( ", defaultValue=%1)" ).arg( valueAsPythonString( mDefault, c ) );
6599       return code;
6600     }
6601   }
6602   return QString();
6603 }
6604 
fromScriptCode(const QString & name,const QString & description,bool isOptional,const QString & definition)6605 QgsProcessingParameterScale *QgsProcessingParameterScale::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
6606 {
6607   return new QgsProcessingParameterScale( name, description, definition.isEmpty() ? QVariant()
6608                                           : ( definition.toLower().trimmed() == QLatin1String( "none" ) ? QVariant() : definition ), isOptional );
6609 }
6610 
6611 
6612 //
6613 // QgsProcessingParameterLayout
6614 //
6615 
QgsProcessingParameterLayout(const QString & name,const QString & description,const QVariant & defaultValue,bool optional)6616 QgsProcessingParameterLayout::QgsProcessingParameterLayout( const QString &name, const QString &description, const QVariant &defaultValue, bool optional )
6617   : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
6618 {}
6619 
clone() const6620 QgsProcessingParameterDefinition *QgsProcessingParameterLayout::clone() const
6621 {
6622   return new QgsProcessingParameterLayout( *this );
6623 }
6624 
valueAsPythonString(const QVariant & value,QgsProcessingContext &) const6625 QString QgsProcessingParameterLayout::valueAsPythonString( const QVariant &value, QgsProcessingContext & ) const
6626 {
6627   if ( !value.isValid() || value.isNull() )
6628     return QStringLiteral( "None" );
6629 
6630   if ( value.canConvert<QgsProperty>() )
6631     return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
6632 
6633   QString s = value.toString();
6634   return QgsProcessingUtils::stringToPythonLiteral( s );
6635 }
6636 
asScriptCode() const6637 QString QgsProcessingParameterLayout::asScriptCode() const
6638 {
6639   QString code = QStringLiteral( "##%1=" ).arg( mName );
6640   if ( mFlags & FlagOptional )
6641     code += QLatin1String( "optional " );
6642   code += QLatin1String( "layout " );
6643 
6644   code += mDefault.toString();
6645   return code.trimmed();
6646 }
6647 
asPythonString(const QgsProcessing::PythonOutputType outputType) const6648 QString QgsProcessingParameterLayout::asPythonString( const QgsProcessing::PythonOutputType outputType ) const
6649 {
6650   switch ( outputType )
6651   {
6652     case QgsProcessing::PythonQgsProcessingAlgorithmSubclass:
6653     {
6654       QString code = QStringLiteral( "QgsProcessingParameterLayout('%1', '%2'" ).arg( name(), description() );
6655       if ( mFlags & FlagOptional )
6656         code += QLatin1String( ", optional=True" );
6657       QgsProcessingContext c;
6658       code += QStringLiteral( ", defaultValue=%1)" ).arg( valueAsPythonString( mDefault, c ) );
6659       return code;
6660     }
6661   }
6662   return QString();
6663 }
6664 
fromScriptCode(const QString & name,const QString & description,bool isOptional,const QString & definition)6665 QgsProcessingParameterLayout *QgsProcessingParameterLayout::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
6666 {
6667   QString def = definition;
6668 
6669   if ( def.startsWith( '"' ) || def.startsWith( '\'' ) )
6670     def = def.mid( 1 );
6671   if ( def.endsWith( '"' ) || def.endsWith( '\'' ) )
6672     def.chop( 1 );
6673 
6674   QVariant defaultValue = def;
6675   if ( def == QLatin1String( "None" ) )
6676     defaultValue = QVariant();
6677 
6678   return new QgsProcessingParameterLayout( name, description, defaultValue, isOptional );
6679 }
6680 
6681 
6682 //
6683 // QString mParentLayerParameterName;
6684 //
6685 
QgsProcessingParameterLayoutItem(const QString & name,const QString & description,const QVariant & defaultValue,const QString & parentLayoutParameterName,int itemType,bool optional)6686 QgsProcessingParameterLayoutItem::QgsProcessingParameterLayoutItem( const QString &name, const QString &description, const QVariant &defaultValue, const QString &parentLayoutParameterName, int itemType, bool optional )
6687   : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
6688   , mParentLayoutParameterName( parentLayoutParameterName )
6689   , mItemType( itemType )
6690 {
6691 
6692 }
6693 
clone() const6694 QgsProcessingParameterDefinition *QgsProcessingParameterLayoutItem::clone() const
6695 {
6696   return new QgsProcessingParameterLayoutItem( *this );
6697 }
6698 
valueAsPythonString(const QVariant & value,QgsProcessingContext &) const6699 QString QgsProcessingParameterLayoutItem::valueAsPythonString( const QVariant &value, QgsProcessingContext & ) const
6700 {
6701   if ( !value.isValid() || value.isNull() )
6702     return QStringLiteral( "None" );
6703 
6704   if ( value.canConvert<QgsProperty>() )
6705     return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
6706 
6707   QString s = value.toString();
6708   return QgsProcessingUtils::stringToPythonLiteral( s );
6709 }
6710 
asScriptCode() const6711 QString QgsProcessingParameterLayoutItem::asScriptCode() const
6712 {
6713   QString code = QStringLiteral( "##%1=" ).arg( mName );
6714   if ( mFlags & FlagOptional )
6715     code += QLatin1String( "optional " );
6716   code += QLatin1String( "layoutitem " );
6717   if ( mItemType >= 0 )
6718     code += QString::number( mItemType ) + ' ';
6719 
6720   code += mParentLayoutParameterName + ' ';
6721 
6722   code += mDefault.toString();
6723   return code.trimmed();
6724 }
6725 
asPythonString(QgsProcessing::PythonOutputType outputType) const6726 QString QgsProcessingParameterLayoutItem::asPythonString( QgsProcessing::PythonOutputType outputType ) const
6727 {
6728   switch ( outputType )
6729   {
6730     case QgsProcessing::PythonQgsProcessingAlgorithmSubclass:
6731     {
6732       QString code = QStringLiteral( "QgsProcessingParameterLayoutItem('%1', '%2'" ).arg( name(), description() );
6733       if ( mFlags & FlagOptional )
6734         code += QLatin1String( ", optional=True" );
6735 
6736       if ( mItemType >= 0 )
6737         code += QStringLiteral( ", itemType=%1" ).arg( mItemType );
6738 
6739       code += QStringLiteral( ", parentLayoutParameterName='%1'" ).arg( mParentLayoutParameterName );
6740 
6741       QgsProcessingContext c;
6742       code += QStringLiteral( ", defaultValue=%1)" ).arg( valueAsPythonString( mDefault, c ) );
6743       return code;
6744     }
6745   }
6746   return QString();
6747 }
6748 
toVariantMap() const6749 QVariantMap QgsProcessingParameterLayoutItem::toVariantMap() const
6750 {
6751   QVariantMap map = QgsProcessingParameterDefinition::toVariantMap();
6752   map.insert( QStringLiteral( "parent_layout" ), mParentLayoutParameterName );
6753   map.insert( QStringLiteral( "item_type" ), mItemType );
6754   return map;
6755 }
6756 
fromVariantMap(const QVariantMap & map)6757 bool QgsProcessingParameterLayoutItem::fromVariantMap( const QVariantMap &map )
6758 {
6759   QgsProcessingParameterDefinition::fromVariantMap( map );
6760   mParentLayoutParameterName = map.value( QStringLiteral( "parent_layout" ) ).toString();
6761   mItemType = map.value( QStringLiteral( "item_type" ) ).toInt();
6762   return true;
6763 }
6764 
dependsOnOtherParameters() const6765 QStringList QgsProcessingParameterLayoutItem::dependsOnOtherParameters() const
6766 {
6767   QStringList depends;
6768   if ( !mParentLayoutParameterName.isEmpty() )
6769     depends << mParentLayoutParameterName;
6770   return depends;
6771 }
6772 
fromScriptCode(const QString & name,const QString & description,bool isOptional,const QString & definition)6773 QgsProcessingParameterLayoutItem *QgsProcessingParameterLayoutItem::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
6774 {
6775   QString parent;
6776   QString def = definition;
6777   int itemType = -1;
6778   QRegularExpression re( QStringLiteral( "(\\d+)?\\s*(.*?)\\s+(.*)$" ) );
6779   QRegularExpressionMatch m = re.match( def );
6780   if ( m.hasMatch() )
6781   {
6782     itemType = m.captured( 1 ).trimmed().isEmpty() ? -1 : m.captured( 1 ).trimmed().toInt();
6783     parent = m.captured( 2 ).trimmed().isEmpty() ? m.captured( 3 ).trimmed() : m.captured( 2 ).trimmed();
6784     def = !m.captured( 2 ).trimmed().isEmpty() ? m.captured( 3 ) : QString();
6785   }
6786   else
6787   {
6788     parent = def;
6789     def.clear();
6790   }
6791 
6792   return new QgsProcessingParameterLayoutItem( name, description, def.isEmpty() ? QVariant() : def, parent, itemType, isOptional );
6793 }
6794 
parentLayoutParameterName() const6795 QString QgsProcessingParameterLayoutItem::parentLayoutParameterName() const
6796 {
6797   return mParentLayoutParameterName;
6798 }
6799 
setParentLayoutParameterName(const QString & name)6800 void QgsProcessingParameterLayoutItem::setParentLayoutParameterName( const QString &name )
6801 {
6802   mParentLayoutParameterName = name;
6803 }
6804 
itemType() const6805 int QgsProcessingParameterLayoutItem::itemType() const
6806 {
6807   return mItemType;
6808 }
6809 
setItemType(int type)6810 void QgsProcessingParameterLayoutItem::setItemType( int type )
6811 {
6812   mItemType = type;
6813 }
6814 
6815 //
6816 // QgsProcessingParameterColor
6817 //
6818 
QgsProcessingParameterColor(const QString & name,const QString & description,const QVariant & defaultValue,bool opacityEnabled,bool optional)6819 QgsProcessingParameterColor::QgsProcessingParameterColor( const QString &name, const QString &description, const QVariant &defaultValue, bool opacityEnabled, bool optional )
6820   : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
6821   , mAllowOpacity( opacityEnabled )
6822 {
6823 
6824 }
6825 
clone() const6826 QgsProcessingParameterDefinition *QgsProcessingParameterColor::clone() const
6827 {
6828   return new QgsProcessingParameterColor( *this );
6829 }
6830 
valueAsPythonString(const QVariant & value,QgsProcessingContext &) const6831 QString QgsProcessingParameterColor::valueAsPythonString( const QVariant &value, QgsProcessingContext & ) const
6832 {
6833   if ( !value.isValid() || value.isNull() )
6834     return QStringLiteral( "None" );
6835 
6836   if ( value.canConvert<QgsProperty>() )
6837     return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
6838 
6839   if ( value.canConvert< QColor >() && !value.value< QColor >().isValid() )
6840     return QStringLiteral( "QColor()" );
6841 
6842   if ( value.canConvert< QColor >() )
6843   {
6844     QColor c = value.value< QColor >();
6845     if ( !mAllowOpacity || c.alpha() == 255 )
6846       return QStringLiteral( "QColor(%1, %2, %3)" ).arg( c.red() ).arg( c.green() ).arg( c.blue() );
6847     else
6848       return QStringLiteral( "QColor(%1, %2, %3, %4)" ).arg( c.red() ).arg( c.green() ).arg( c.blue() ).arg( c.alpha() );
6849   }
6850 
6851   QString s = value.toString();
6852   return QgsProcessingUtils::stringToPythonLiteral( s );
6853 }
6854 
asScriptCode() const6855 QString QgsProcessingParameterColor::asScriptCode() const
6856 {
6857   QString code = QStringLiteral( "##%1=" ).arg( mName );
6858   if ( mFlags & FlagOptional )
6859     code += QLatin1String( "optional " );
6860   code += QLatin1String( "color " );
6861 
6862   if ( mAllowOpacity )
6863     code += QLatin1String( "withopacity " );
6864 
6865   code += mDefault.toString();
6866   return code.trimmed();
6867 }
6868 
asPythonString(const QgsProcessing::PythonOutputType outputType) const6869 QString QgsProcessingParameterColor::asPythonString( const QgsProcessing::PythonOutputType outputType ) const
6870 {
6871   switch ( outputType )
6872   {
6873     case QgsProcessing::PythonQgsProcessingAlgorithmSubclass:
6874     {
6875       QString code = QStringLiteral( "QgsProcessingParameterColor('%1', '%2'" ).arg( name(), description() );
6876       if ( mFlags & FlagOptional )
6877         code += QLatin1String( ", optional=True" );
6878 
6879       code += QStringLiteral( ", opacityEnabled=%1" ).arg( mAllowOpacity ? QStringLiteral( "True" ) : QStringLiteral( "False" ) );
6880 
6881       QgsProcessingContext c;
6882       code += QStringLiteral( ", defaultValue=%1)" ).arg( valueAsPythonString( mDefault, c ) );
6883       return code;
6884     }
6885   }
6886   return QString();
6887 }
6888 
checkValueIsAcceptable(const QVariant & input,QgsProcessingContext *) const6889 bool QgsProcessingParameterColor::checkValueIsAcceptable( const QVariant &input, QgsProcessingContext * ) const
6890 {
6891   if ( !input.isValid() && ( mDefault.isValid() && ( !mDefault.toString().isEmpty() || mDefault.value< QColor >().isValid() ) ) )
6892     return true;
6893 
6894   if ( !input.isValid() )
6895     return mFlags & FlagOptional;
6896 
6897   if ( input.type() == QVariant::Color )
6898   {
6899     return true;
6900   }
6901   else if ( input.canConvert<QgsProperty>() )
6902   {
6903     return true;
6904   }
6905 
6906   if ( input.type() != QVariant::String || input.toString().isEmpty() )
6907     return mFlags & FlagOptional;
6908 
6909   bool containsAlpha = false;
6910   return QgsSymbolLayerUtils::parseColorWithAlpha( input.toString(), containsAlpha ).isValid();
6911 }
6912 
toVariantMap() const6913 QVariantMap QgsProcessingParameterColor::toVariantMap() const
6914 {
6915   QVariantMap map = QgsProcessingParameterDefinition::toVariantMap();
6916   map.insert( QStringLiteral( "opacityEnabled" ), mAllowOpacity );
6917   return map;
6918 }
6919 
fromVariantMap(const QVariantMap & map)6920 bool QgsProcessingParameterColor::fromVariantMap( const QVariantMap &map )
6921 {
6922   QgsProcessingParameterDefinition::fromVariantMap( map );
6923   mAllowOpacity = map.value( QStringLiteral( "opacityEnabled" ) ).toBool();
6924   return true;
6925 }
6926 
opacityEnabled() const6927 bool QgsProcessingParameterColor::opacityEnabled() const
6928 {
6929   return mAllowOpacity;
6930 }
6931 
setOpacityEnabled(bool enabled)6932 void QgsProcessingParameterColor::setOpacityEnabled( bool enabled )
6933 {
6934   mAllowOpacity = enabled;
6935 }
6936 
fromScriptCode(const QString & name,const QString & description,bool isOptional,const QString & definition)6937 QgsProcessingParameterColor *QgsProcessingParameterColor::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
6938 {
6939   QString def = definition;
6940 
6941   bool allowOpacity = false;
6942   if ( def.startsWith( QLatin1String( "withopacity" ), Qt::CaseInsensitive ) )
6943   {
6944     allowOpacity = true;
6945     def = def.mid( 12 );
6946   }
6947 
6948   if ( def.startsWith( '"' ) || def.startsWith( '\'' ) )
6949     def = def.mid( 1 );
6950   if ( def.endsWith( '"' ) || def.endsWith( '\'' ) )
6951     def.chop( 1 );
6952 
6953   QVariant defaultValue = def;
6954   if ( def == QLatin1String( "None" ) )
6955     defaultValue = QVariant();
6956 
6957   return new QgsProcessingParameterColor( name, description, defaultValue, allowOpacity, isOptional );
6958 }
6959 
6960 //
6961 // QgsProcessingParameterCoordinateOperation
6962 //
QgsProcessingParameterCoordinateOperation(const QString & name,const QString & description,const QVariant & defaultValue,const QString & sourceCrsParameterName,const QString & destinationCrsParameterName,const QVariant & staticSourceCrs,const QVariant & staticDestinationCrs,bool optional)6963 QgsProcessingParameterCoordinateOperation::QgsProcessingParameterCoordinateOperation( const QString &name, const QString &description, const QVariant &defaultValue, const QString &sourceCrsParameterName, const QString &destinationCrsParameterName, const QVariant &staticSourceCrs, const QVariant &staticDestinationCrs, bool optional )
6964   : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
6965   , mSourceParameterName( sourceCrsParameterName )
6966   , mDestParameterName( destinationCrsParameterName )
6967   , mSourceCrs( staticSourceCrs )
6968   , mDestCrs( staticDestinationCrs )
6969 {
6970 
6971 }
6972 
clone() const6973 QgsProcessingParameterDefinition *QgsProcessingParameterCoordinateOperation::clone() const
6974 {
6975   return new QgsProcessingParameterCoordinateOperation( * this );
6976 }
6977 
valueAsPythonString(const QVariant & value,QgsProcessingContext & context) const6978 QString QgsProcessingParameterCoordinateOperation::valueAsPythonString( const QVariant &value, QgsProcessingContext &context ) const
6979 {
6980   if ( !value.isValid() || value.isNull() )
6981     return QStringLiteral( "None" );
6982 
6983   if ( value.canConvert<QgsCoordinateReferenceSystem>() )
6984   {
6985     if ( !value.value< QgsCoordinateReferenceSystem >().isValid() )
6986       return QStringLiteral( "QgsCoordinateReferenceSystem()" );
6987     else
6988       return QStringLiteral( "QgsCoordinateReferenceSystem('%1')" ).arg( value.value< QgsCoordinateReferenceSystem >().authid() );
6989   }
6990 
6991   if ( value.canConvert<QgsProperty>() )
6992     return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
6993 
6994   QVariantMap p;
6995   p.insert( name(), value );
6996   QgsMapLayer *layer = QgsProcessingParameters::parameterAsLayer( this, p, context );
6997   if ( layer )
6998     return QgsProcessingUtils::stringToPythonLiteral( QgsProcessingUtils::normalizeLayerSource( layer->source() ) );
6999 
7000   QString s = value.toString();
7001   return QgsProcessingUtils::stringToPythonLiteral( s );
7002 }
7003 
asScriptCode() const7004 QString QgsProcessingParameterCoordinateOperation::asScriptCode() const
7005 {
7006   QString code = QStringLiteral( "##%1=" ).arg( mName );
7007   if ( mFlags & FlagOptional )
7008     code += QLatin1String( "optional " );
7009   code += QLatin1String( "coordinateoperation " );
7010 
7011   code += mDefault.toString();
7012   return code.trimmed();
7013 }
7014 
asPythonString(QgsProcessing::PythonOutputType outputType) const7015 QString QgsProcessingParameterCoordinateOperation::asPythonString( QgsProcessing::PythonOutputType outputType ) const
7016 {
7017   switch ( outputType )
7018   {
7019     case QgsProcessing::PythonQgsProcessingAlgorithmSubclass:
7020     {
7021       QgsProcessingContext c;
7022       QString code = QStringLiteral( "QgsProcessingParameterCoordinateOperation('%1', '%2'" ).arg( name(), description() );
7023       if ( mFlags & FlagOptional )
7024         code += QLatin1String( ", optional=True" );
7025       if ( !mSourceParameterName.isEmpty() )
7026         code += QStringLiteral( ", sourceCrsParameterName=%1" ).arg( valueAsPythonString( mSourceParameterName, c ) );
7027       if ( !mDestParameterName.isEmpty() )
7028         code += QStringLiteral( ", destinationCrsParameterName=%1" ).arg( valueAsPythonString( mDestParameterName, c ) );
7029 
7030       if ( mSourceCrs.isValid() )
7031         code += QStringLiteral( ", staticSourceCrs=%1" ).arg( valueAsPythonString( mSourceCrs, c ) );
7032       if ( mDestCrs.isValid() )
7033         code += QStringLiteral( ", staticDestinationCrs=%1" ).arg( valueAsPythonString( mDestCrs, c ) );
7034 
7035       code += QStringLiteral( ", defaultValue=%1)" ).arg( valueAsPythonString( mDefault, c ) );
7036       return code;
7037     }
7038   }
7039   return QString();
7040 }
7041 
dependsOnOtherParameters() const7042 QStringList QgsProcessingParameterCoordinateOperation::dependsOnOtherParameters() const
7043 {
7044   QStringList res;
7045   if ( !mSourceParameterName.isEmpty() )
7046     res << mSourceParameterName;
7047   if ( !mDestParameterName.isEmpty() )
7048     res << mDestParameterName;
7049   return res;
7050 }
7051 
toVariantMap() const7052 QVariantMap QgsProcessingParameterCoordinateOperation::toVariantMap() const
7053 {
7054   QVariantMap map = QgsProcessingParameterDefinition::toVariantMap();
7055   map.insert( QStringLiteral( "source_crs_parameter_name" ), mSourceParameterName );
7056   map.insert( QStringLiteral( "dest_crs_parameter_name" ), mDestParameterName );
7057   map.insert( QStringLiteral( "static_source_crs" ), mSourceCrs );
7058   map.insert( QStringLiteral( "static_dest_crs" ), mDestCrs );
7059   return map;
7060 }
7061 
fromVariantMap(const QVariantMap & map)7062 bool QgsProcessingParameterCoordinateOperation::fromVariantMap( const QVariantMap &map )
7063 {
7064   QgsProcessingParameterDefinition::fromVariantMap( map );
7065   mSourceParameterName = map.value( QStringLiteral( "source_crs_parameter_name" ) ).toString();
7066   mDestParameterName = map.value( QStringLiteral( "dest_crs_parameter_name" ) ).toString();
7067   mSourceCrs = map.value( QStringLiteral( "static_source_crs" ) );
7068   mDestCrs = map.value( QStringLiteral( "static_dest_crs" ) );
7069   return true;
7070 }
7071 
fromScriptCode(const QString & name,const QString & description,bool isOptional,const QString & definition)7072 QgsProcessingParameterCoordinateOperation *QgsProcessingParameterCoordinateOperation::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
7073 {
7074   QString def = definition;
7075 
7076   if ( def.startsWith( '"' ) || def.startsWith( '\'' ) )
7077     def = def.mid( 1 );
7078   if ( def.endsWith( '"' ) || def.endsWith( '\'' ) )
7079     def.chop( 1 );
7080 
7081   QVariant defaultValue = def;
7082   if ( def == QLatin1String( "None" ) )
7083     defaultValue = QVariant();
7084 
7085   return new QgsProcessingParameterCoordinateOperation( name, description, defaultValue, QString(), QString(), QVariant(), QVariant(), isOptional );
7086 }
7087 
7088 
7089 //
7090 // QgsProcessingParameterMapTheme
7091 //
7092 
QgsProcessingParameterMapTheme(const QString & name,const QString & description,const QVariant & defaultValue,bool optional)7093 QgsProcessingParameterMapTheme::QgsProcessingParameterMapTheme( const QString &name, const QString &description, const QVariant &defaultValue, bool optional )
7094   : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
7095 {
7096 
7097 }
7098 
7099 
clone() const7100 QgsProcessingParameterDefinition *QgsProcessingParameterMapTheme::clone() const
7101 {
7102   return new QgsProcessingParameterMapTheme( *this );
7103 }
7104 
checkValueIsAcceptable(const QVariant & input,QgsProcessingContext *) const7105 bool QgsProcessingParameterMapTheme::checkValueIsAcceptable( const QVariant &input, QgsProcessingContext * ) const
7106 {
7107   if ( !input.isValid() && !mDefault.isValid() )
7108     return mFlags & FlagOptional;
7109 
7110   if ( ( input.type() == QVariant::String && input.toString().isEmpty() )
7111        || ( !input.isValid() && mDefault.type() == QVariant::String && mDefault.toString().isEmpty() ) )
7112     return mFlags & FlagOptional;
7113 
7114   return true;
7115 }
7116 
valueAsPythonString(const QVariant & value,QgsProcessingContext &) const7117 QString QgsProcessingParameterMapTheme::valueAsPythonString( const QVariant &value, QgsProcessingContext & ) const
7118 {
7119   if ( !value.isValid() )
7120     return QStringLiteral( "None" );
7121 
7122   if ( value.canConvert<QgsProperty>() )
7123     return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
7124 
7125   return QgsProcessingUtils::stringToPythonLiteral( value.toString() );
7126 }
7127 
asScriptCode() const7128 QString QgsProcessingParameterMapTheme::asScriptCode() const
7129 {
7130   QString code = QStringLiteral( "##%1=" ).arg( mName );
7131   if ( mFlags & FlagOptional )
7132     code += QLatin1String( "optional " );
7133   code += QLatin1String( "maptheme " );
7134 
7135   code += mDefault.toString();
7136   return code.trimmed();
7137 }
7138 
asPythonString(const QgsProcessing::PythonOutputType outputType) const7139 QString QgsProcessingParameterMapTheme::asPythonString( const QgsProcessing::PythonOutputType outputType ) const
7140 {
7141   switch ( outputType )
7142   {
7143     case QgsProcessing::PythonQgsProcessingAlgorithmSubclass:
7144     {
7145       QString code = QStringLiteral( "QgsProcessingParameterMapTheme('%1', '%2'" ).arg( name(), description() );
7146       if ( mFlags & FlagOptional )
7147         code += QLatin1String( ", optional=True" );
7148 
7149       QgsProcessingContext c;
7150       code += QStringLiteral( ", defaultValue=%1)" ).arg( valueAsPythonString( mDefault, c ) );
7151 
7152       return code;
7153     }
7154   }
7155   return QString();
7156 }
7157 
toVariantMap() const7158 QVariantMap QgsProcessingParameterMapTheme::toVariantMap() const
7159 {
7160   QVariantMap map = QgsProcessingParameterDefinition::toVariantMap();
7161   return map;
7162 }
7163 
fromVariantMap(const QVariantMap & map)7164 bool QgsProcessingParameterMapTheme::fromVariantMap( const QVariantMap &map )
7165 {
7166   QgsProcessingParameterDefinition::fromVariantMap( map );
7167   return true;
7168 }
7169 
fromScriptCode(const QString & name,const QString & description,bool isOptional,const QString & definition)7170 QgsProcessingParameterMapTheme *QgsProcessingParameterMapTheme::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
7171 {
7172   QString parent;
7173 
7174   QString def = definition;
7175   if ( def.startsWith( '"' ) || def.startsWith( '\'' ) )
7176     def = def.mid( 1 );
7177   if ( def.endsWith( '"' ) || def.endsWith( '\'' ) )
7178     def.chop( 1 );
7179 
7180   QVariant defaultValue = def;
7181 
7182   if ( defaultValue == QLatin1String( "None" ) || defaultValue.toString().isEmpty() )
7183     defaultValue = QVariant();
7184 
7185   return new QgsProcessingParameterMapTheme( name, description, defaultValue, isOptional );
7186 }
7187 
7188 
7189 //
7190 // QgsProcessingParameterDateTime
7191 //
7192 
QgsProcessingParameterDateTime(const QString & name,const QString & description,Type type,const QVariant & defaultValue,bool optional,const QDateTime & minValue,const QDateTime & maxValue)7193 QgsProcessingParameterDateTime::QgsProcessingParameterDateTime( const QString &name, const QString &description, Type type, const QVariant &defaultValue, bool optional, const QDateTime &minValue, const QDateTime &maxValue )
7194   : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
7195   , mMin( minValue )
7196   , mMax( maxValue )
7197   , mDataType( type )
7198 {
7199   if ( mMin.isValid() && mMax.isValid() && mMin >= mMax )
7200   {
7201     QgsMessageLog::logMessage( QObject::tr( "Invalid datetime parameter \"%1\": min value %2 is >= max value %3!" ).arg( name, mMin.toString(), mMax.toString() ), QObject::tr( "Processing" ) );
7202   }
7203 }
7204 
clone() const7205 QgsProcessingParameterDefinition *QgsProcessingParameterDateTime::clone() const
7206 {
7207   return new QgsProcessingParameterDateTime( *this );
7208 }
7209 
checkValueIsAcceptable(const QVariant & value,QgsProcessingContext *) const7210 bool QgsProcessingParameterDateTime::checkValueIsAcceptable( const QVariant &value, QgsProcessingContext * ) const
7211 {
7212   QVariant input = value;
7213   if ( !input.isValid() )
7214   {
7215     if ( !defaultValue().isValid() )
7216       return mFlags & FlagOptional;
7217 
7218     input = defaultValue();
7219   }
7220 
7221   if ( input.canConvert<QgsProperty>() )
7222   {
7223     return true;
7224   }
7225 
7226   if ( input.type() != QVariant::DateTime && input.type() != QVariant::Date && input.type() != QVariant::Time && input.type() != QVariant::String )
7227     return false;
7228 
7229   if ( ( input.type() == QVariant::DateTime || input.type() == QVariant::Date ) && mDataType == Time )
7230     return false;
7231 
7232   if ( input.type() == QVariant::String )
7233   {
7234     QString s = input.toString();
7235     if ( s.isEmpty() )
7236       return mFlags & FlagOptional;
7237 
7238     input = QDateTime::fromString( s, Qt::ISODate );
7239     if ( mDataType == Time )
7240     {
7241       if ( !input.toDateTime().isValid() )
7242         input = QTime::fromString( s );
7243       else
7244         input = input.toDateTime().time();
7245     }
7246   }
7247 
7248   if ( mDataType != Time )
7249   {
7250     QDateTime res = input.toDateTime();
7251     return res.isValid() && ( res >= mMin || !mMin.isValid() ) && ( res <= mMax || !mMax.isValid() );
7252   }
7253   else
7254   {
7255     QTime res = input.toTime();
7256     return res.isValid() && ( res >= mMin.time() || !mMin.isValid() ) && ( res <= mMax.time() || !mMax.isValid() );
7257   }
7258 }
7259 
valueAsPythonString(const QVariant & value,QgsProcessingContext &) const7260 QString QgsProcessingParameterDateTime::valueAsPythonString( const QVariant &value, QgsProcessingContext & ) const
7261 {
7262   if ( !value.isValid() )
7263     return QStringLiteral( "None" );
7264 
7265   if ( value.canConvert<QgsProperty>() )
7266     return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
7267 
7268   if ( value.type() == QVariant::DateTime )
7269   {
7270     const QDateTime dt = value.toDateTime();
7271     if ( !dt.isValid() )
7272       return QStringLiteral( "QDateTime()" );
7273     else
7274       return QStringLiteral( "QDateTime(QDate(%1, %2, %3), QTime(%4, %5, %6))" ).arg( dt.date().year() )
7275              .arg( dt.date().month() )
7276              .arg( dt.date().day() )
7277              .arg( dt.time().hour() )
7278              .arg( dt.time().minute() )
7279              .arg( dt.time().second() );
7280   }
7281   else if ( value.type() == QVariant::Date )
7282   {
7283     const QDate dt = value.toDate();
7284     if ( !dt.isValid() )
7285       return QStringLiteral( "QDate()" );
7286     else
7287       return QStringLiteral( "QDate(%1, %2, %3)" ).arg( dt.year() )
7288              .arg( dt.month() )
7289              .arg( dt.day() );
7290   }
7291   else if ( value.type() == QVariant::Time )
7292   {
7293     const QTime dt = value.toTime();
7294     if ( !dt.isValid() )
7295       return QStringLiteral( "QTime()" );
7296     else
7297       return QStringLiteral( "QTime(%4, %5, %6)" )
7298              .arg( dt.hour() )
7299              .arg( dt.minute() )
7300              .arg( dt.second() );
7301   }
7302   return value.toString();
7303 }
7304 
toolTip() const7305 QString QgsProcessingParameterDateTime::toolTip() const
7306 {
7307   QString text = QgsProcessingParameterDefinition::toolTip();
7308   QStringList parts;
7309   if ( mMin.isValid() )
7310     parts << QObject::tr( "Minimum value: %1" ).arg( mMin.toString( Qt::ISODate ) );
7311   if ( mMax.isValid() )
7312     parts << QObject::tr( "Maximum value: %1" ).arg( mMax.toString( Qt::ISODate ) );
7313   if ( mDefault.isValid() )
7314     parts << QObject::tr( "Default value: %1" ).arg( mDataType == DateTime ? mDefault.toDateTime().toString( Qt::ISODate ) :
7315           ( mDataType == Date ? mDefault.toDate().toString( Qt::ISODate ) : mDefault.toTime( ).toString() ) );
7316   QString extra = parts.join( QLatin1String( "<br />" ) );
7317   if ( !extra.isEmpty() )
7318     text += QStringLiteral( "<p>%1</p>" ).arg( extra );
7319   return text;
7320 }
7321 
asPythonString(const QgsProcessing::PythonOutputType outputType) const7322 QString QgsProcessingParameterDateTime::asPythonString( const QgsProcessing::PythonOutputType outputType ) const
7323 {
7324   switch ( outputType )
7325   {
7326     case QgsProcessing::PythonQgsProcessingAlgorithmSubclass:
7327     {
7328       QString code = QStringLiteral( "QgsProcessingParameterDateTime('%1', '%2'" ).arg( name(), description() );
7329       if ( mFlags & FlagOptional )
7330         code += QLatin1String( ", optional=True" );
7331 
7332       code += QStringLiteral( ", type=%1" ).arg( mDataType == DateTime ? QStringLiteral( "QgsProcessingParameterDateTime.DateTime" )
7333               : mDataType == Date ? QStringLiteral( "QgsProcessingParameterDateTime.Date" )
7334               : QStringLiteral( "QgsProcessingParameterDateTime.Time" ) );
7335 
7336       QgsProcessingContext c;
7337       if ( mMin.isValid() )
7338         code += QStringLiteral( ", minValue=%1" ).arg( valueAsPythonString( mMin, c ) );
7339       if ( mMax.isValid() )
7340         code += QStringLiteral( ", maxValue=%1" ).arg( valueAsPythonString( mMax, c ) );
7341       code += QStringLiteral( ", defaultValue=%1)" ).arg( valueAsPythonString( mDefault, c ) );
7342       return code;
7343     }
7344   }
7345   return QString();
7346 }
7347 
minimum() const7348 QDateTime QgsProcessingParameterDateTime::minimum() const
7349 {
7350   return mMin;
7351 }
7352 
setMinimum(const QDateTime & min)7353 void QgsProcessingParameterDateTime::setMinimum( const QDateTime &min )
7354 {
7355   mMin = min;
7356 }
7357 
maximum() const7358 QDateTime QgsProcessingParameterDateTime::maximum() const
7359 {
7360   return mMax;
7361 }
7362 
setMaximum(const QDateTime & max)7363 void QgsProcessingParameterDateTime::setMaximum( const QDateTime &max )
7364 {
7365   mMax = max;
7366 }
7367 
dataType() const7368 QgsProcessingParameterDateTime::Type QgsProcessingParameterDateTime::dataType() const
7369 {
7370   return mDataType;
7371 }
7372 
setDataType(Type dataType)7373 void QgsProcessingParameterDateTime::setDataType( Type dataType )
7374 {
7375   mDataType = dataType;
7376 }
7377 
toVariantMap() const7378 QVariantMap QgsProcessingParameterDateTime::toVariantMap() const
7379 {
7380   QVariantMap map = QgsProcessingParameterDefinition::toVariantMap();
7381   map.insert( QStringLiteral( "min" ), mMin );
7382   map.insert( QStringLiteral( "max" ), mMax );
7383   map.insert( QStringLiteral( "data_type" ), mDataType );
7384   return map;
7385 }
7386 
fromVariantMap(const QVariantMap & map)7387 bool QgsProcessingParameterDateTime::fromVariantMap( const QVariantMap &map )
7388 {
7389   QgsProcessingParameterDefinition::fromVariantMap( map );
7390   mMin = map.value( QStringLiteral( "min" ) ).toDateTime();
7391   mMax = map.value( QStringLiteral( "max" ) ).toDateTime();
7392   mDataType = static_cast< Type >( map.value( QStringLiteral( "data_type" ) ).toInt() );
7393   return true;
7394 }
7395 
fromScriptCode(const QString & name,const QString & description,bool isOptional,const QString & definition)7396 QgsProcessingParameterDateTime *QgsProcessingParameterDateTime::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
7397 {
7398   return new QgsProcessingParameterDateTime( name, description, DateTime, definition.isEmpty() ? QVariant()
7399          : ( definition.toLower().trimmed() == QLatin1String( "none" ) ? QVariant() : definition ), isOptional );
7400 }
7401 
7402 
7403 
7404 //
7405 // QgsProcessingParameterProviderConnection
7406 //
7407 
QgsProcessingParameterProviderConnection(const QString & name,const QString & description,const QString & provider,const QVariant & defaultValue,bool optional)7408 QgsProcessingParameterProviderConnection::QgsProcessingParameterProviderConnection( const QString &name, const QString &description, const QString &provider, const QVariant &defaultValue, bool optional )
7409   : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
7410   , mProviderId( provider )
7411 {
7412 
7413 }
7414 
7415 
clone() const7416 QgsProcessingParameterDefinition *QgsProcessingParameterProviderConnection::clone() const
7417 {
7418   return new QgsProcessingParameterProviderConnection( *this );
7419 }
7420 
checkValueIsAcceptable(const QVariant & input,QgsProcessingContext *) const7421 bool QgsProcessingParameterProviderConnection::checkValueIsAcceptable( const QVariant &input, QgsProcessingContext * ) const
7422 {
7423   if ( !input.isValid() && !mDefault.isValid() )
7424     return mFlags & FlagOptional;
7425 
7426   if ( ( input.type() == QVariant::String && input.toString().isEmpty() )
7427        || ( !input.isValid() && mDefault.type() == QVariant::String && mDefault.toString().isEmpty() ) )
7428     return mFlags & FlagOptional;
7429 
7430   return true;
7431 }
7432 
valueAsPythonString(const QVariant & value,QgsProcessingContext &) const7433 QString QgsProcessingParameterProviderConnection::valueAsPythonString( const QVariant &value, QgsProcessingContext & ) const
7434 {
7435   if ( !value.isValid() )
7436     return QStringLiteral( "None" );
7437 
7438   if ( value.canConvert<QgsProperty>() )
7439     return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
7440 
7441   return QgsProcessingUtils::stringToPythonLiteral( value.toString() );
7442 }
7443 
asScriptCode() const7444 QString QgsProcessingParameterProviderConnection::asScriptCode() const
7445 {
7446   QString code = QStringLiteral( "##%1=" ).arg( mName );
7447   if ( mFlags & FlagOptional )
7448     code += QLatin1String( "optional " );
7449   code += QLatin1String( "providerconnection " );
7450   code += mProviderId + ' ';
7451 
7452   code += mDefault.toString();
7453   return code.trimmed();
7454 }
7455 
asPythonString(const QgsProcessing::PythonOutputType outputType) const7456 QString QgsProcessingParameterProviderConnection::asPythonString( const QgsProcessing::PythonOutputType outputType ) const
7457 {
7458   switch ( outputType )
7459   {
7460     case QgsProcessing::PythonQgsProcessingAlgorithmSubclass:
7461     {
7462       QString code = QStringLiteral( "QgsProcessingParameterProviderConnection('%1', '%2', '%3'" ).arg( name(), description(), mProviderId );
7463       if ( mFlags & FlagOptional )
7464         code += QLatin1String( ", optional=True" );
7465 
7466       QgsProcessingContext c;
7467       code += QStringLiteral( ", defaultValue=%1)" ).arg( valueAsPythonString( mDefault, c ) );
7468 
7469       return code;
7470     }
7471   }
7472   return QString();
7473 }
7474 
toVariantMap() const7475 QVariantMap QgsProcessingParameterProviderConnection::toVariantMap() const
7476 {
7477   QVariantMap map = QgsProcessingParameterDefinition::toVariantMap();
7478   map.insert( QStringLiteral( "provider" ), mProviderId );
7479   return map;
7480 }
7481 
fromVariantMap(const QVariantMap & map)7482 bool QgsProcessingParameterProviderConnection::fromVariantMap( const QVariantMap &map )
7483 {
7484   QgsProcessingParameterDefinition::fromVariantMap( map );
7485   mProviderId = map.value( QStringLiteral( "provider" ) ).toString();
7486   return true;
7487 }
7488 
fromScriptCode(const QString & name,const QString & description,bool isOptional,const QString & definition)7489 QgsProcessingParameterProviderConnection *QgsProcessingParameterProviderConnection::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
7490 {
7491   QString parent;
7492 
7493   QString def = definition;
7494   QString provider;
7495   if ( def.contains( ' ' ) )
7496   {
7497     provider = def.left( def.indexOf( ' ' ) );
7498     def = def.mid( def.indexOf( ' ' ) + 1 );
7499   }
7500   else
7501   {
7502     provider = def;
7503     def.clear();
7504   }
7505 
7506   if ( def.startsWith( '"' ) || def.startsWith( '\'' ) )
7507     def = def.mid( 1 );
7508   if ( def.endsWith( '"' ) || def.endsWith( '\'' ) )
7509     def.chop( 1 );
7510 
7511   QVariant defaultValue = def;
7512 
7513   if ( defaultValue == QLatin1String( "None" ) || defaultValue.toString().isEmpty() )
7514     defaultValue = QVariant();
7515 
7516   return new QgsProcessingParameterProviderConnection( name, description, provider, defaultValue, isOptional );
7517 }
7518 
7519 
7520 //
7521 // QgsProcessingParameterDatabaseSchema
7522 //
7523 
QgsProcessingParameterDatabaseSchema(const QString & name,const QString & description,const QString & parentLayerParameterName,const QVariant & defaultValue,bool optional)7524 QgsProcessingParameterDatabaseSchema::QgsProcessingParameterDatabaseSchema( const QString &name, const QString &description, const QString &parentLayerParameterName, const QVariant &defaultValue, bool optional )
7525   : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
7526   , mParentConnectionParameterName( parentLayerParameterName )
7527 {
7528 
7529 }
7530 
7531 
clone() const7532 QgsProcessingParameterDefinition *QgsProcessingParameterDatabaseSchema::clone() const
7533 {
7534   return new QgsProcessingParameterDatabaseSchema( *this );
7535 }
7536 
checkValueIsAcceptable(const QVariant & input,QgsProcessingContext *) const7537 bool QgsProcessingParameterDatabaseSchema::checkValueIsAcceptable( const QVariant &input, QgsProcessingContext * ) const
7538 {
7539   if ( !input.isValid() && !mDefault.isValid() )
7540     return mFlags & FlagOptional;
7541 
7542   if ( ( input.type() == QVariant::String && input.toString().isEmpty() )
7543        || ( !input.isValid() && mDefault.type() == QVariant::String && mDefault.toString().isEmpty() ) )
7544     return mFlags & FlagOptional;
7545 
7546   return true;
7547 }
7548 
valueAsPythonString(const QVariant & value,QgsProcessingContext &) const7549 QString QgsProcessingParameterDatabaseSchema::valueAsPythonString( const QVariant &value, QgsProcessingContext & ) const
7550 {
7551   if ( !value.isValid() )
7552     return QStringLiteral( "None" );
7553 
7554   if ( value.canConvert<QgsProperty>() )
7555     return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
7556 
7557   return QgsProcessingUtils::stringToPythonLiteral( value.toString() );
7558 }
7559 
asScriptCode() const7560 QString QgsProcessingParameterDatabaseSchema::asScriptCode() const
7561 {
7562   QString code = QStringLiteral( "##%1=" ).arg( mName );
7563   if ( mFlags & FlagOptional )
7564     code += QLatin1String( "optional " );
7565   code += QLatin1String( "databaseschema " );
7566 
7567   code += mParentConnectionParameterName + ' ';
7568 
7569   code += mDefault.toString();
7570   return code.trimmed();
7571 }
7572 
asPythonString(const QgsProcessing::PythonOutputType outputType) const7573 QString QgsProcessingParameterDatabaseSchema::asPythonString( const QgsProcessing::PythonOutputType outputType ) const
7574 {
7575   switch ( outputType )
7576   {
7577     case QgsProcessing::PythonQgsProcessingAlgorithmSubclass:
7578     {
7579       QString code = QStringLiteral( "QgsProcessingParameterDatabaseSchema('%1', '%2'" ).arg( name(), description() );
7580       if ( mFlags & FlagOptional )
7581         code += QLatin1String( ", optional=True" );
7582 
7583       code += QStringLiteral( ", connectionParameterName='%1'" ).arg( mParentConnectionParameterName );
7584       QgsProcessingContext c;
7585       code += QStringLiteral( ", defaultValue=%1" ).arg( valueAsPythonString( mDefault, c ) );
7586 
7587       code += ')';
7588 
7589       return code;
7590     }
7591   }
7592   return QString();
7593 }
7594 
dependsOnOtherParameters() const7595 QStringList QgsProcessingParameterDatabaseSchema::dependsOnOtherParameters() const
7596 {
7597   QStringList depends;
7598   if ( !mParentConnectionParameterName.isEmpty() )
7599     depends << mParentConnectionParameterName;
7600   return depends;
7601 }
7602 
parentConnectionParameterName() const7603 QString QgsProcessingParameterDatabaseSchema::parentConnectionParameterName() const
7604 {
7605   return mParentConnectionParameterName;
7606 }
7607 
setParentConnectionParameterName(const QString & name)7608 void QgsProcessingParameterDatabaseSchema::setParentConnectionParameterName( const QString &name )
7609 {
7610   mParentConnectionParameterName = name;
7611 }
7612 
toVariantMap() const7613 QVariantMap QgsProcessingParameterDatabaseSchema::toVariantMap() const
7614 {
7615   QVariantMap map = QgsProcessingParameterDefinition::toVariantMap();
7616   map.insert( QStringLiteral( "mParentConnectionParameterName" ), mParentConnectionParameterName );
7617   return map;
7618 }
7619 
fromVariantMap(const QVariantMap & map)7620 bool QgsProcessingParameterDatabaseSchema::fromVariantMap( const QVariantMap &map )
7621 {
7622   QgsProcessingParameterDefinition::fromVariantMap( map );
7623   mParentConnectionParameterName = map.value( QStringLiteral( "mParentConnectionParameterName" ) ).toString();
7624   return true;
7625 }
7626 
fromScriptCode(const QString & name,const QString & description,bool isOptional,const QString & definition)7627 QgsProcessingParameterDatabaseSchema *QgsProcessingParameterDatabaseSchema::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
7628 {
7629   QString parent;
7630   QString def = definition;
7631 
7632   QRegularExpression re( QStringLiteral( "(.*?)\\s+(.*)$" ) );
7633   QRegularExpressionMatch m = re.match( def );
7634   if ( m.hasMatch() )
7635   {
7636     parent = m.captured( 1 ).trimmed();
7637     def = m.captured( 2 );
7638   }
7639   else
7640   {
7641     parent = def;
7642     def.clear();
7643   }
7644 
7645   return new QgsProcessingParameterDatabaseSchema( name, description, parent, def.isEmpty() ? QVariant() : def, isOptional );
7646 }
7647 
7648 //
7649 // QgsProcessingParameterDatabaseTable
7650 //
7651 
QgsProcessingParameterDatabaseTable(const QString & name,const QString & description,const QString & connectionParameterName,const QString & schemaParameterName,const QVariant & defaultValue,bool optional,bool allowNewTableNames)7652 QgsProcessingParameterDatabaseTable::QgsProcessingParameterDatabaseTable( const QString &name, const QString &description,
7653     const QString &connectionParameterName,
7654     const QString &schemaParameterName,
7655     const QVariant &defaultValue, bool optional, bool allowNewTableNames )
7656   : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
7657   , mParentConnectionParameterName( connectionParameterName )
7658   , mParentSchemaParameterName( schemaParameterName )
7659   , mAllowNewTableNames( allowNewTableNames )
7660 {
7661 
7662 }
7663 
7664 
clone() const7665 QgsProcessingParameterDefinition *QgsProcessingParameterDatabaseTable::clone() const
7666 {
7667   return new QgsProcessingParameterDatabaseTable( *this );
7668 }
7669 
checkValueIsAcceptable(const QVariant & input,QgsProcessingContext *) const7670 bool QgsProcessingParameterDatabaseTable::checkValueIsAcceptable( const QVariant &input, QgsProcessingContext * ) const
7671 {
7672   if ( !input.isValid() && !mDefault.isValid() )
7673     return mFlags & FlagOptional;
7674 
7675   if ( ( input.type() == QVariant::String && input.toString().isEmpty() )
7676        || ( !input.isValid() && mDefault.type() == QVariant::String && mDefault.toString().isEmpty() ) )
7677     return mFlags & FlagOptional;
7678 
7679   return true;
7680 }
7681 
valueAsPythonString(const QVariant & value,QgsProcessingContext &) const7682 QString QgsProcessingParameterDatabaseTable::valueAsPythonString( const QVariant &value, QgsProcessingContext & ) const
7683 {
7684   if ( !value.isValid() )
7685     return QStringLiteral( "None" );
7686 
7687   if ( value.canConvert<QgsProperty>() )
7688     return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
7689 
7690   return QgsProcessingUtils::stringToPythonLiteral( value.toString() );
7691 }
7692 
asScriptCode() const7693 QString QgsProcessingParameterDatabaseTable::asScriptCode() const
7694 {
7695   QString code = QStringLiteral( "##%1=" ).arg( mName );
7696   if ( mFlags & FlagOptional )
7697     code += QLatin1String( "optional " );
7698   code += QLatin1String( "databasetable " );
7699 
7700   code += ( mParentConnectionParameterName.isEmpty() ? QStringLiteral( "none" ) : mParentConnectionParameterName ) + ' ';
7701   code += ( mParentSchemaParameterName.isEmpty() ? QStringLiteral( "none" ) : mParentSchemaParameterName ) + ' ';
7702 
7703   code += mDefault.toString();
7704   return code.trimmed();
7705 }
7706 
asPythonString(const QgsProcessing::PythonOutputType outputType) const7707 QString QgsProcessingParameterDatabaseTable::asPythonString( const QgsProcessing::PythonOutputType outputType ) const
7708 {
7709   switch ( outputType )
7710   {
7711     case QgsProcessing::PythonQgsProcessingAlgorithmSubclass:
7712     {
7713       QString code = QStringLiteral( "QgsProcessingParameterDatabaseTable('%1', '%2'" ).arg( name(), description() );
7714       if ( mFlags & FlagOptional )
7715         code += QLatin1String( ", optional=True" );
7716 
7717       if ( mAllowNewTableNames )
7718         code += QLatin1String( ", allowNewTableNames=True" );
7719 
7720       code += QStringLiteral( ", connectionParameterName='%1'" ).arg( mParentConnectionParameterName );
7721       code += QStringLiteral( ", schemaParameterName='%1'" ).arg( mParentSchemaParameterName );
7722       QgsProcessingContext c;
7723       code += QStringLiteral( ", defaultValue=%1" ).arg( valueAsPythonString( mDefault, c ) );
7724 
7725       code += ')';
7726 
7727       return code;
7728     }
7729   }
7730   return QString();
7731 }
7732 
dependsOnOtherParameters() const7733 QStringList QgsProcessingParameterDatabaseTable::dependsOnOtherParameters() const
7734 {
7735   QStringList depends;
7736   if ( !mParentConnectionParameterName.isEmpty() )
7737     depends << mParentConnectionParameterName;
7738   if ( !mParentSchemaParameterName.isEmpty() )
7739     depends << mParentSchemaParameterName;
7740   return depends;
7741 }
7742 
parentConnectionParameterName() const7743 QString QgsProcessingParameterDatabaseTable::parentConnectionParameterName() const
7744 {
7745   return mParentConnectionParameterName;
7746 }
7747 
setParentConnectionParameterName(const QString & name)7748 void QgsProcessingParameterDatabaseTable::setParentConnectionParameterName( const QString &name )
7749 {
7750   mParentConnectionParameterName = name;
7751 }
7752 
parentSchemaParameterName() const7753 QString QgsProcessingParameterDatabaseTable::parentSchemaParameterName() const
7754 {
7755   return mParentSchemaParameterName;
7756 }
7757 
setParentSchemaParameterName(const QString & name)7758 void QgsProcessingParameterDatabaseTable::setParentSchemaParameterName( const QString &name )
7759 {
7760   mParentSchemaParameterName = name;
7761 }
7762 
toVariantMap() const7763 QVariantMap QgsProcessingParameterDatabaseTable::toVariantMap() const
7764 {
7765   QVariantMap map = QgsProcessingParameterDefinition::toVariantMap();
7766   map.insert( QStringLiteral( "mParentConnectionParameterName" ), mParentConnectionParameterName );
7767   map.insert( QStringLiteral( "mParentSchemaParameterName" ), mParentSchemaParameterName );
7768   map.insert( QStringLiteral( "mAllowNewTableNames" ), mAllowNewTableNames );
7769   return map;
7770 }
7771 
fromVariantMap(const QVariantMap & map)7772 bool QgsProcessingParameterDatabaseTable::fromVariantMap( const QVariantMap &map )
7773 {
7774   QgsProcessingParameterDefinition::fromVariantMap( map );
7775   mParentConnectionParameterName = map.value( QStringLiteral( "mParentConnectionParameterName" ) ).toString();
7776   mParentSchemaParameterName = map.value( QStringLiteral( "mParentSchemaParameterName" ) ).toString();
7777   mAllowNewTableNames = map.value( QStringLiteral( "mAllowNewTableNames" ), false ).toBool();
7778   return true;
7779 }
7780 
fromScriptCode(const QString & name,const QString & description,bool isOptional,const QString & definition)7781 QgsProcessingParameterDatabaseTable *QgsProcessingParameterDatabaseTable::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
7782 {
7783   QString connection;
7784   QString schema;
7785   QString def = definition;
7786 
7787   QRegularExpression re( QStringLiteral( "(.*?)\\s+(.*+)\\b\\s*(.*)$" ) );
7788   QRegularExpressionMatch m = re.match( def );
7789   if ( m.hasMatch() )
7790   {
7791     connection = m.captured( 1 ).trimmed();
7792     if ( connection == QLatin1String( "none" ) )
7793       connection.clear();
7794     schema = m.captured( 2 ).trimmed();
7795     if ( schema == QLatin1String( "none" ) )
7796       schema.clear();
7797     def = m.captured( 3 );
7798   }
7799 
7800   return new QgsProcessingParameterDatabaseTable( name, description, connection, schema, def.isEmpty() ? QVariant() : def, isOptional );
7801 }
7802 
allowNewTableNames() const7803 bool QgsProcessingParameterDatabaseTable::allowNewTableNames() const
7804 {
7805   return mAllowNewTableNames;
7806 }
7807 
setAllowNewTableNames(bool allowNewTableNames)7808 void QgsProcessingParameterDatabaseTable::setAllowNewTableNames( bool allowNewTableNames )
7809 {
7810   mAllowNewTableNames = allowNewTableNames;
7811 }
7812