QGIS API Documentation  3.10.0-A Coruña (6c816b4204)
qgsprocessingparameters.cpp
Go to the documentation of this file.
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 
19 #include "qgsprocessingprovider.h"
20 #include "qgsprocessingcontext.h"
21 #include "qgsprocessingutils.h"
22 #include "qgsprocessingalgorithm.h"
24 #include "qgsprocessingoutputs.h"
25 #include "qgssettings.h"
26 #include "qgsvectorfilewriter.h"
27 #include "qgsreferencedgeometry.h"
28 #include "qgsprocessingregistry.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 <functional>
39 
40 
42 {
43  QVariantMap map;
44  map.insert( QStringLiteral( "sink" ), sink.toVariant() );
45  map.insert( QStringLiteral( "create_options" ), createOptions );
46  return map;
47 }
48 
50 {
51  sink.loadVariant( map.value( QStringLiteral( "sink" ) ) );
52  createOptions = map.value( QStringLiteral( "create_options" ) ).toMap();
53  return true;
54 }
55 
56 bool QgsProcessingParameters::isDynamic( const QVariantMap &parameters, const QString &name )
57 {
58  QVariant val = parameters.value( name );
59  if ( val.canConvert<QgsProperty>() )
60  return val.value< QgsProperty >().propertyType() != QgsProperty::StaticProperty;
61  else
62  return false;
63 }
64 
65 QString QgsProcessingParameters::parameterAsString( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, const QgsProcessingContext &context )
66 {
67  if ( !definition )
68  return QString();
69 
70  return parameterAsString( definition, parameters.value( definition->name() ), context );
71 }
72 
73 QString QgsProcessingParameters::parameterAsString( const QgsProcessingParameterDefinition *definition, const QVariant &value, const QgsProcessingContext &context )
74 {
75  if ( !definition )
76  return QString();
77 
78  QVariant val = value;
79  if ( val.canConvert<QgsProperty>() )
80  return val.value< QgsProperty >().valueAsString( context.expressionContext(), definition->defaultValue().toString() );
81 
82  if ( !val.isValid() )
83  {
84  // fall back to default
85  val = definition->defaultValue();
86  }
87 
89  {
90  if ( const QgsProcessingDestinationParameter *destParam = dynamic_cast< const QgsProcessingDestinationParameter * >( definition ) )
91  return destParam->generateTemporaryDestination();
92  }
93 
94  return val.toString();
95 }
96 
97 QString QgsProcessingParameters::parameterAsExpression( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, const QgsProcessingContext &context )
98 {
99  if ( !definition )
100  return QString();
101 
102  return parameterAsExpression( definition, parameters.value( definition->name() ), context );
103 }
104 
105 QString QgsProcessingParameters::parameterAsExpression( const QgsProcessingParameterDefinition *definition, const QVariant &value, const QgsProcessingContext &context )
106 {
107  if ( !definition )
108  return QString();
109 
110  QVariant val = value;
111  if ( val.canConvert<QgsProperty>() )
112  return val.value< QgsProperty >().valueAsString( context.expressionContext(), definition->defaultValue().toString() );
113 
114  if ( val.isValid() && !val.toString().isEmpty() )
115  {
116  QgsExpression e( val.toString() );
117  if ( e.isValid() )
118  return val.toString();
119  }
120 
121  // fall back to default
122  return definition->defaultValue().toString();
123 }
124 
125 double QgsProcessingParameters::parameterAsDouble( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, const QgsProcessingContext &context )
126 {
127  if ( !definition )
128  return 0;
129 
130  return parameterAsDouble( definition, parameters.value( definition->name() ), context );
131 }
132 
133 double QgsProcessingParameters::parameterAsDouble( const QgsProcessingParameterDefinition *definition, const QVariant &value, const QgsProcessingContext &context )
134 {
135  if ( !definition )
136  return 0;
137 
138  QVariant val = value;
139  if ( val.canConvert<QgsProperty>() )
140  return val.value< QgsProperty >().valueAsDouble( context.expressionContext(), definition->defaultValue().toDouble() );
141 
142  bool ok = false;
143  double res = val.toDouble( &ok );
144  if ( ok )
145  return res;
146 
147  // fall back to default
148  val = definition->defaultValue();
149  return val.toDouble();
150 }
151 
152 int QgsProcessingParameters::parameterAsInt( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, const QgsProcessingContext &context )
153 {
154  if ( !definition )
155  return 0;
156 
157  return parameterAsInt( definition, parameters.value( definition->name() ), context );
158 }
159 
160 int QgsProcessingParameters::parameterAsInt( const QgsProcessingParameterDefinition *definition, const QVariant &value, const QgsProcessingContext &context )
161 {
162  if ( !definition )
163  return 0;
164 
165  QVariant val = value;
166  if ( val.canConvert<QgsProperty>() )
167  return val.value< QgsProperty >().valueAsInt( context.expressionContext(), definition->defaultValue().toInt() );
168 
169  bool ok = false;
170  double dbl = val.toDouble( &ok );
171  if ( !ok )
172  {
173  // fall back to default
174  val = definition->defaultValue();
175  dbl = val.toDouble( &ok );
176  }
177 
178  //String representations of doubles in QVariant will not convert to int
179  //work around this by first converting to double, and then checking whether the double is convertible to int
180  if ( ok )
181  {
182  double round = std::round( dbl );
183  if ( round > std::numeric_limits<int>::max() || round < -std::numeric_limits<int>::max() )
184  {
185  //double too large to fit in int
186  return 0;
187  }
188  return static_cast< int >( std::round( dbl ) );
189  }
190 
191  return val.toInt();
192 }
193 
194 QList< int > QgsProcessingParameters::parameterAsInts( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, const QgsProcessingContext &context )
195 {
196  if ( !definition )
197  return QList< int >();
198 
199  return parameterAsInts( definition, parameters.value( definition->name() ), context );
200 }
201 
202 QList< int > QgsProcessingParameters::parameterAsInts( const QgsProcessingParameterDefinition *definition, const QVariant &value, const QgsProcessingContext &context )
203 {
204  if ( !definition )
205  return QList< int >();
206 
207  QList< int > resultList;
208  QVariant val = value;
209  if ( val.isValid() )
210  {
211  if ( val.canConvert<QgsProperty>() )
212  resultList << val.value< QgsProperty >().valueAsInt( context.expressionContext(), definition->defaultValue().toInt() );
213  else if ( val.type() == QVariant::List )
214  {
215  QVariantList list = val.toList();
216  for ( auto it = list.constBegin(); it != list.constEnd(); ++it )
217  resultList << it->toInt();
218  }
219  else
220  {
221  QStringList parts = val.toString().split( ';' );
222  for ( auto it = parts.constBegin(); it != parts.constEnd(); ++it )
223  resultList << it->toInt();
224  }
225  }
226 
227  if ( ( resultList.isEmpty() || resultList.at( 0 ) == 0 ) )
228  {
229  resultList.clear();
230  // check default
231  if ( definition->defaultValue().isValid() )
232  {
233  if ( definition->defaultValue().type() == QVariant::List )
234  {
235  QVariantList list = definition->defaultValue().toList();
236  for ( auto it = list.constBegin(); it != list.constEnd(); ++it )
237  resultList << it->toInt();
238  }
239  else
240  {
241  QStringList parts = definition->defaultValue().toString().split( ';' );
242  for ( auto it = parts.constBegin(); it != parts.constEnd(); ++it )
243  resultList << it->toInt();
244  }
245  }
246  }
247 
248  return resultList;
249 }
250 
251 int QgsProcessingParameters::parameterAsEnum( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, const QgsProcessingContext &context )
252 {
253  if ( !definition )
254  return 0;
255 
256  return parameterAsEnum( definition, parameters.value( definition->name() ), context );
257 }
258 
259 int QgsProcessingParameters::parameterAsEnum( const QgsProcessingParameterDefinition *definition, const QVariant &value, const QgsProcessingContext &context )
260 {
261  if ( !definition )
262  return 0;
263 
264  int val = parameterAsInt( definition, value, context );
265  const QgsProcessingParameterEnum *enumDef = dynamic_cast< const QgsProcessingParameterEnum *>( definition );
266  if ( enumDef && val >= enumDef->options().size() )
267  {
268  return enumDef->defaultValue().toInt();
269  }
270  return val;
271 }
272 
273 QList<int> QgsProcessingParameters::parameterAsEnums( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, const QgsProcessingContext &context )
274 {
275  if ( !definition )
276  return QList<int>();
277 
278  return parameterAsEnums( definition, parameters.value( definition->name() ), context );
279 }
280 
281 QList<int> QgsProcessingParameters::parameterAsEnums( const QgsProcessingParameterDefinition *definition, const QVariant &value, const QgsProcessingContext &context )
282 {
283  if ( !definition )
284  return QList<int>();
285 
286  QVariantList resultList;
287  QVariant val = value;
288  if ( val.canConvert<QgsProperty>() )
289  resultList << val.value< QgsProperty >().valueAsString( context.expressionContext(), definition->defaultValue().toString() );
290  else if ( val.type() == QVariant::List )
291  {
292  const auto constToList = val.toList();
293  for ( const QVariant &var : constToList )
294  resultList << var;
295  }
296  else if ( val.type() == QVariant::String )
297  {
298  const auto constSplit = val.toString().split( ',' );
299  for ( const QString &var : constSplit )
300  resultList << var;
301  }
302  else
303  resultList << val;
304 
305  if ( resultList.isEmpty() )
306  return QList< int >();
307 
308  if ( ( !val.isValid() || !resultList.at( 0 ).isValid() ) && definition )
309  {
310  resultList.clear();
311  // check default
312  if ( definition->defaultValue().type() == QVariant::List )
313  {
314  const auto constToList = definition->defaultValue().toList();
315  for ( const QVariant &var : constToList )
316  resultList << var;
317  }
318  else if ( definition->defaultValue().type() == QVariant::String )
319  {
320  const auto constSplit = definition->defaultValue().toString().split( ',' );
321  for ( const QString &var : constSplit )
322  resultList << var;
323  }
324  else
325  resultList << definition->defaultValue();
326  }
327 
328  QList< int > result;
329  const QgsProcessingParameterEnum *enumDef = dynamic_cast< const QgsProcessingParameterEnum *>( definition );
330  const auto constResultList = resultList;
331  for ( const QVariant &var : constResultList )
332  {
333  int resInt = var.toInt();
334  if ( !enumDef || resInt < enumDef->options().size() )
335  {
336  result << resInt;
337  }
338  }
339  return result;
340 }
341 
342 bool QgsProcessingParameters::parameterAsBool( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, const QgsProcessingContext &context )
343 {
344  if ( !definition )
345  return false;
346 
347  return parameterAsBool( definition, parameters.value( definition->name() ), context );
348 }
349 
350 bool QgsProcessingParameters::parameterAsBoolean( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, const QgsProcessingContext &context )
351 {
352  if ( !definition )
353  return false;
354 
355  return parameterAsBoolean( definition, parameters.value( definition->name() ), context );
356 }
357 
358 bool QgsProcessingParameters::parameterAsBool( const QgsProcessingParameterDefinition *definition, const QVariant &value, const QgsProcessingContext &context )
359 {
360  if ( !definition )
361  return false;
362 
363  QVariant def = definition->defaultValue();
364 
365  QVariant val = value;
366  if ( val.canConvert<QgsProperty>() )
367  return val.value< QgsProperty >().valueAsBool( context.expressionContext(), def.toBool() );
368  else if ( val.isValid() )
369  return val.toBool();
370  else
371  return def.toBool();
372 }
373 
374 bool QgsProcessingParameters::parameterAsBoolean( const QgsProcessingParameterDefinition *definition, const QVariant &value, const QgsProcessingContext &context )
375 {
376  if ( !definition )
377  return false;
378 
379  QVariant def = definition->defaultValue();
380 
381  QVariant val = value;
382  if ( val.canConvert<QgsProperty>() )
383  return val.value< QgsProperty >().valueAsBool( context.expressionContext(), def.toBool() );
384  else if ( val.isValid() )
385  return val.toBool();
386  else
387  return def.toBool();
388 }
389 
390 QgsFeatureSink *QgsProcessingParameters::parameterAsSink( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, const QgsFields &fields,
392  QgsProcessingContext &context, QString &destinationIdentifier, QgsFeatureSink::SinkFlags sinkFlags )
393 {
394  QVariant val;
395  if ( definition )
396  {
397  val = parameters.value( definition->name() );
398  }
399 
400  return parameterAsSink( definition, val, fields, geometryType, crs, context, destinationIdentifier, sinkFlags );
401 }
402 
403 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 )
404 {
405  QVariant val = value;
406 
407  QgsProject *destinationProject = nullptr;
408  QString destName;
409  QVariantMap createOptions;
410  if ( val.canConvert<QgsProcessingOutputLayerDefinition>() )
411  {
412  // input is a QgsProcessingOutputLayerDefinition - get extra properties from it
414  destinationProject = fromVar.destinationProject;
415  createOptions = fromVar.createOptions;
416 
417  val = fromVar.sink;
418  destName = fromVar.destinationName;
419  }
420 
421  QString dest;
422  if ( val.canConvert<QgsProperty>() )
423  {
424  dest = val.value< QgsProperty >().valueAsString( context.expressionContext(), definition->defaultValue().toString() );
425  }
426  else if ( !val.isValid() || val.toString().isEmpty() )
427  {
428  if ( definition && definition->flags() & QgsProcessingParameterDefinition::FlagOptional && !definition->defaultValue().isValid() )
429  {
430  // unset, optional sink, no default => no sink
431  return nullptr;
432  }
433  // fall back to default
434  dest = definition->defaultValue().toString();
435  }
436  else
437  {
438  dest = val.toString();
439  }
440  if ( dest == QgsProcessing::TEMPORARY_OUTPUT )
441  {
442  if ( const QgsProcessingDestinationParameter *destParam = dynamic_cast< const QgsProcessingDestinationParameter * >( definition ) )
443  dest = destParam->generateTemporaryDestination();
444  }
445 
446  if ( dest.isEmpty() )
447  return nullptr;
448 
449  std::unique_ptr< QgsFeatureSink > sink( QgsProcessingUtils::createFeatureSink( dest, context, fields, geometryType, crs, createOptions, sinkFlags ) );
450  destinationIdentifier = dest;
451 
452  if ( destinationProject )
453  {
454  if ( destName.isEmpty() && definition )
455  {
456  destName = definition->description();
457  }
458  QString outputName;
459  if ( definition )
460  outputName = definition->name();
461  context.addLayerToLoadOnCompletion( destinationIdentifier, QgsProcessingContext::LayerDetails( destName, destinationProject, outputName, QgsProcessingUtils::LayerHint::Vector ) );
462  }
463 
464  return sink.release();
465 }
466 
468 {
469  if ( !definition )
470  return nullptr;
471 
472  return parameterAsSource( definition, parameters.value( definition->name() ), context );
473 }
474 
476 {
477  if ( !definition )
478  return nullptr;
479 
480  return QgsProcessingUtils::variantToSource( value, context, definition->defaultValue() );
481 }
482 
483 QString parameterAsCompatibleSourceLayerPathInternal( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context, const QStringList &compatibleFormats, const QString &preferredFormat, QgsProcessingFeedback *feedback, QString *layerName )
484 {
485  if ( !definition )
486  return QString();
487 
488  QVariant val = parameters.value( definition->name() );
489 
490  bool selectedFeaturesOnly = false;
491  if ( val.canConvert<QgsProcessingFeatureSourceDefinition>() )
492  {
493  // input is a QgsProcessingFeatureSourceDefinition - get extra properties from it
495  selectedFeaturesOnly = fromVar.selectedFeaturesOnly;
496  val = fromVar.source;
497  }
498  else if ( val.canConvert<QgsProcessingOutputLayerDefinition>() )
499  {
500  // input is a QgsProcessingOutputLayerDefinition - get extra properties from it
502  val = fromVar.sink;
503  }
504 
505  if ( val.canConvert<QgsProperty>() )
506  {
507  val = val.value< QgsProperty >().valueAsString( context.expressionContext(), definition->defaultValue().toString() );
508  }
509 
510  QgsVectorLayer *vl = nullptr;
511  vl = qobject_cast< QgsVectorLayer * >( qvariant_cast<QObject *>( val ) );
512 
513  if ( !vl )
514  {
515  QString layerRef;
516  if ( val.canConvert<QgsProperty>() )
517  {
518  layerRef = val.value< QgsProperty >().valueAsString( context.expressionContext(), definition->defaultValue().toString() );
519  }
520  else if ( !val.isValid() || val.toString().isEmpty() )
521  {
522  // fall back to default
523  val = definition->defaultValue();
524 
525  // default value may be a vector layer
526  vl = qobject_cast< QgsVectorLayer * >( qvariant_cast<QObject *>( val ) );
527  if ( !vl )
528  layerRef = definition->defaultValue().toString();
529  }
530  else
531  {
532  layerRef = val.toString();
533  }
534 
535  if ( !vl )
536  {
537  if ( layerRef.isEmpty() )
538  return QString();
539 
540  vl = qobject_cast< QgsVectorLayer *>( QgsProcessingUtils::mapLayerFromString( layerRef, context, true, QgsProcessingUtils::LayerHint::Vector ) );
541  }
542  }
543 
544  if ( !vl )
545  return QString();
546 
547  if ( layerName )
548  return QgsProcessingUtils::convertToCompatibleFormatAndLayerName( vl, selectedFeaturesOnly, definition->name(),
549  compatibleFormats, preferredFormat, context, feedback, *layerName );
550  else
551  return QgsProcessingUtils::convertToCompatibleFormat( vl, selectedFeaturesOnly, definition->name(),
552  compatibleFormats, preferredFormat, context, feedback );
553 }
554 
555 QString QgsProcessingParameters::parameterAsCompatibleSourceLayerPath( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context, const QStringList &compatibleFormats, const QString &preferredFormat, QgsProcessingFeedback *feedback )
556 {
557  return parameterAsCompatibleSourceLayerPathInternal( definition, parameters, context, compatibleFormats, preferredFormat, feedback, nullptr );
558 }
559 
560 QString QgsProcessingParameters::parameterAsCompatibleSourceLayerPathAndLayerName( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context, const QStringList &compatibleFormats, const QString &preferredFormat, QgsProcessingFeedback *feedback, QString *layerName )
561 {
562  QString *destLayer = layerName;
563  QString tmp;
564  if ( destLayer )
565  destLayer->clear();
566  else
567  destLayer = &tmp;
568 
569  return parameterAsCompatibleSourceLayerPathInternal( definition, parameters, context, compatibleFormats, preferredFormat, feedback, destLayer );
570 }
571 
572 
574 {
575  if ( !definition )
576  return nullptr;
577 
578  return parameterAsLayer( definition, parameters.value( definition->name() ), context );
579 }
580 
582 {
583  if ( !definition )
584  return nullptr;
585 
586  QVariant val = value;
587  if ( val.canConvert<QgsProperty>() )
588  {
589  val = val.value< QgsProperty >().valueAsString( context.expressionContext(), definition->defaultValue().toString() );
590  }
591 
592  if ( QgsMapLayer *layer = qobject_cast< QgsMapLayer * >( qvariant_cast<QObject *>( val ) ) )
593  {
594  return layer;
595  }
596 
597  if ( val.canConvert<QgsProcessingOutputLayerDefinition>() )
598  {
599  // input is a QgsProcessingOutputLayerDefinition - get extra properties from it
601  val = fromVar.sink;
602  }
603 
604  if ( val.canConvert<QgsProperty>() && val.value< QgsProperty >().propertyType() == QgsProperty::StaticProperty )
605  {
606  val = val.value< QgsProperty >().staticValue();
607  }
608 
609  if ( !val.isValid() || val.toString().isEmpty() )
610  {
611  // fall back to default
612  val = definition->defaultValue();
613  }
614 
615  if ( QgsMapLayer *layer = qobject_cast< QgsMapLayer * >( qvariant_cast<QObject *>( val ) ) )
616  {
617  return layer;
618  }
619 
620  QString layerRef = val.toString();
621  if ( layerRef.isEmpty() )
622  layerRef = definition->defaultValue().toString();
623 
624  if ( layerRef.isEmpty() )
625  return nullptr;
626 
627  return QgsProcessingUtils::mapLayerFromString( layerRef, context );
628 }
629 
631 {
632  return qobject_cast< QgsRasterLayer *>( parameterAsLayer( definition, parameters, context ) );
633 }
634 
636 {
637  return qobject_cast< QgsRasterLayer *>( parameterAsLayer( definition, value, context ) );
638 }
639 
641 {
642  return qobject_cast< QgsMeshLayer *>( parameterAsLayer( definition, parameters, context ) );
643 }
644 
646 {
647  return qobject_cast< QgsMeshLayer *>( parameterAsLayer( definition, value, context ) );
648 }
649 
650 QString QgsProcessingParameters::parameterAsOutputLayer( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context )
651 {
652  QVariant val;
653  if ( definition )
654  {
655  val = parameters.value( definition->name() );
656  }
657  return parameterAsOutputLayer( definition, val, context );
658 }
659 
661 {
662  QVariant val = value;
663 
664  QgsProject *destinationProject = nullptr;
665  QVariantMap createOptions;
666  QString destName;
667  if ( val.canConvert<QgsProcessingOutputLayerDefinition>() )
668  {
669  // input is a QgsProcessingOutputLayerDefinition - get extra properties from it
671  destinationProject = fromVar.destinationProject;
672  createOptions = fromVar.createOptions;
673  val = fromVar.sink;
674  destName = fromVar.destinationName;
675  }
676 
677  QString dest;
678  if ( val.canConvert<QgsProperty>() )
679  {
680  dest = val.value< QgsProperty >().valueAsString( context.expressionContext(), definition->defaultValue().toString() );
681  }
682  else if ( definition && ( !val.isValid() || val.toString().isEmpty() ) )
683  {
684  // fall back to default
685  dest = definition->defaultValue().toString();
686  }
687  else
688  {
689  dest = val.toString();
690  }
691  if ( dest == QgsProcessing::TEMPORARY_OUTPUT )
692  {
693  if ( const QgsProcessingDestinationParameter *destParam = dynamic_cast< const QgsProcessingDestinationParameter * >( definition ) )
694  dest = destParam->generateTemporaryDestination();
695  }
696 
697  if ( destinationProject )
698  {
699  QString outputName;
700  if ( destName.isEmpty() && definition )
701  {
702  destName = definition->description();
703  }
704  if ( definition )
705  outputName = definition->name();
706 
710  else if ( definition->type() == QgsProcessingParameterRasterDestination::typeName() )
712 
713  context.addLayerToLoadOnCompletion( dest, QgsProcessingContext::LayerDetails( destName, destinationProject, outputName, layerTypeHint ) );
714  }
715 
716  return dest;
717 }
718 
719 QString QgsProcessingParameters::parameterAsFileOutput( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context )
720 {
721  QVariant val;
722  if ( definition )
723  {
724  val = parameters.value( definition->name() );
725  }
726  return parameterAsFileOutput( definition, val, context );
727 }
728 
730 {
731  QVariant val = value;
732 
733  if ( val.canConvert<QgsProcessingOutputLayerDefinition>() )
734  {
735  // input is a QgsProcessingOutputLayerDefinition - get extra properties from it
737  val = fromVar.sink;
738  }
739 
740  QString dest;
741  if ( val.canConvert<QgsProperty>() )
742  {
743  dest = val.value< QgsProperty >().valueAsString( context.expressionContext(), definition->defaultValue().toString() );
744  }
745  else if ( !val.isValid() || val.toString().isEmpty() )
746  {
747  // fall back to default
748  dest = definition->defaultValue().toString();
749  }
750  else
751  {
752  dest = val.toString();
753  }
754  if ( dest == QgsProcessing::TEMPORARY_OUTPUT )
755  {
756  if ( const QgsProcessingDestinationParameter *destParam = dynamic_cast< const QgsProcessingDestinationParameter * >( definition ) )
757  dest = destParam->generateTemporaryDestination();
758  }
759  return dest;
760 }
761 
763 {
764  return qobject_cast< QgsVectorLayer *>( parameterAsLayer( definition, parameters, context ) );
765 }
766 
768 {
769  return qobject_cast< QgsVectorLayer *>( parameterAsLayer( definition, value, context ) );
770 }
771 
773 {
774  if ( !definition )
776 
777  return parameterAsCrs( definition, parameters.value( definition->name() ), context );
778 }
779 
781 {
782  if ( !definition )
784 
785  QVariant val = value;
786 
787  if ( val.canConvert<QgsCoordinateReferenceSystem>() )
788  {
789  // input is a QgsCoordinateReferenceSystem - done!
790  return val.value< QgsCoordinateReferenceSystem >();
791  }
792  else if ( val.canConvert<QgsProcessingFeatureSourceDefinition>() )
793  {
794  // input is a QgsProcessingFeatureSourceDefinition - get extra properties from it
796  val = fromVar.source;
797  }
798  else if ( val.canConvert<QgsProcessingOutputLayerDefinition>() )
799  {
800  // input is a QgsProcessingOutputLayerDefinition - get extra properties from it
802  val = fromVar.sink;
803  }
804 
805  if ( val.canConvert<QgsProperty>() && val.value< QgsProperty >().propertyType() == QgsProperty::StaticProperty )
806  {
807  val = val.value< QgsProperty >().staticValue();
808  }
809 
810  // maybe a map layer
811  if ( QgsMapLayer *layer = qobject_cast< QgsMapLayer * >( qvariant_cast<QObject *>( val ) ) )
812  return layer->crs();
813 
814  if ( val.canConvert<QgsProperty>() )
815  val = val.value< QgsProperty >().valueAsString( context.expressionContext(), definition->defaultValue().toString() );
816 
817  if ( !val.isValid() )
818  {
819  // fall back to default
820  val = definition->defaultValue();
821  }
822 
823  QString crsText = val.toString();
824  if ( crsText.isEmpty() )
825  crsText = definition->defaultValue().toString();
826 
827  if ( crsText.isEmpty() )
829 
830  // maybe special string
831  if ( context.project() && crsText.compare( QLatin1String( "ProjectCrs" ), Qt::CaseInsensitive ) == 0 )
832  return context.project()->crs();
833 
834  // maybe a map layer reference
835  if ( QgsMapLayer *layer = QgsProcessingUtils::mapLayerFromString( crsText, context ) )
836  return layer->crs();
837 
838  // else CRS from string
840  crs.createFromString( crsText );
841  return crs;
842 }
843 
846 {
847  if ( !definition )
848  return QgsRectangle();
849 
850  return parameterAsExtent( definition, parameters.value( definition->name() ), context, crs );
851 }
852 
854 {
855  if ( !definition )
856  return QgsRectangle();
857 
858  QVariant val = value;
859 
860  if ( val.canConvert< QgsRectangle >() )
861  {
862  return val.value<QgsRectangle>();
863  }
864  if ( val.canConvert< QgsReferencedRectangle >() )
865  {
867  if ( crs.isValid() && rr.crs().isValid() && crs != rr.crs() )
868  {
869  QgsCoordinateTransform ct( rr.crs(), crs, context.project() );
870  try
871  {
872  return ct.transformBoundingBox( rr );
873  }
874  catch ( QgsCsException & )
875  {
876  QgsMessageLog::logMessage( QObject::tr( "Error transforming extent geometry" ) );
877  }
878  }
879  return rr;
880  }
881 
882  if ( val.canConvert<QgsProcessingFeatureSourceDefinition>() )
883  {
884  // input is a QgsProcessingFeatureSourceDefinition - get extra properties from it
886  val = fromVar.source;
887  }
888  else if ( val.canConvert<QgsProcessingOutputLayerDefinition>() )
889  {
890  // input is a QgsProcessingOutputLayerDefinition - get extra properties from it
892  val = fromVar.sink;
893  }
894 
895  if ( val.canConvert<QgsProperty>() && val.value< QgsProperty >().propertyType() == QgsProperty::StaticProperty )
896  {
897  val = val.value< QgsProperty >().staticValue();
898  }
899 
900  // maybe parameter is a direct layer value?
901  QgsMapLayer *layer = qobject_cast< QgsMapLayer * >( qvariant_cast<QObject *>( val ) );
902 
903  QString rectText;
904  if ( val.canConvert<QgsProperty>() )
905  rectText = val.value< QgsProperty >().valueAsString( context.expressionContext(), definition->defaultValue().toString() );
906  else
907  rectText = val.toString();
908 
909  if ( rectText.isEmpty() && !layer )
910  return QgsRectangle();
911 
912  QRegularExpression rx( QStringLiteral( "^(.*?)\\s*,\\s*(.*?),\\s*(.*?),\\s*(.*?)\\s*(?:\\[(.*)\\])?\\s*$" ) );
913  QRegularExpressionMatch match = rx.match( rectText );
914  if ( match.hasMatch() )
915  {
916  bool xMinOk = false;
917  double xMin = match.captured( 1 ).toDouble( &xMinOk );
918  bool xMaxOk = false;
919  double xMax = match.captured( 2 ).toDouble( &xMaxOk );
920  bool yMinOk = false;
921  double yMin = match.captured( 3 ).toDouble( &yMinOk );
922  bool yMaxOk = false;
923  double yMax = match.captured( 4 ).toDouble( &yMaxOk );
924  if ( xMinOk && xMaxOk && yMinOk && yMaxOk )
925  {
926  QgsRectangle rect( xMin, yMin, xMax, yMax );
927  QgsCoordinateReferenceSystem rectCrs( match.captured( 5 ) );
928  if ( crs.isValid() && rectCrs.isValid() && crs != rectCrs )
929  {
930  QgsCoordinateTransform ct( rectCrs, crs, context.project() );
931  try
932  {
933  return ct.transformBoundingBox( rect );
934  }
935  catch ( QgsCsException & )
936  {
937  QgsMessageLog::logMessage( QObject::tr( "Error transforming extent geometry" ) );
938  }
939  }
940  return rect;
941  }
942  }
943 
944  // try as layer extent
945  if ( !layer )
946  layer = QgsProcessingUtils::mapLayerFromString( rectText, context );
947 
948  if ( layer )
949  {
950  QgsRectangle rect = layer->extent();
951  if ( crs.isValid() && layer->crs().isValid() && crs != layer->crs() )
952  {
953  QgsCoordinateTransform ct( layer->crs(), crs, context.project() );
954  try
955  {
956  return ct.transformBoundingBox( rect );
957  }
958  catch ( QgsCsException & )
959  {
960  QgsMessageLog::logMessage( QObject::tr( "Error transforming extent geometry" ) );
961  }
962  }
963  return rect;
964  }
965  return QgsRectangle();
966 }
967 
969 {
970  if ( !definition )
971  return QgsGeometry();
972 
973  QVariant val = parameters.value( definition->name() );
974 
975  if ( val.canConvert< QgsReferencedRectangle >() )
976  {
979  if ( crs.isValid() && rr.crs().isValid() && crs != rr.crs() )
980  {
981  g = g.densifyByCount( 20 );
982  QgsCoordinateTransform ct( rr.crs(), crs, context.project() );
983  try
984  {
985  g.transform( ct );
986  }
987  catch ( QgsCsException & )
988  {
989  QgsMessageLog::logMessage( QObject::tr( "Error transforming extent geometry" ) );
990  }
991  return g;
992  }
993  }
994 
995  if ( val.canConvert<QgsProcessingFeatureSourceDefinition>() )
996  {
997  // input is a QgsProcessingFeatureSourceDefinition - get extra properties from it
999  val = fromVar.source;
1000  }
1001  else if ( val.canConvert<QgsProcessingOutputLayerDefinition>() )
1002  {
1003  // input is a QgsProcessingOutputLayerDefinition - get extra properties from it
1005  val = fromVar.sink;
1006  }
1007 
1008  if ( val.canConvert<QgsProperty>() && val.value< QgsProperty >().propertyType() == QgsProperty::StaticProperty )
1009  {
1010  val = val.value< QgsProperty >().staticValue();
1011  }
1012 
1013  QString rectText;
1014  if ( val.canConvert<QgsProperty>() )
1015  rectText = val.value< QgsProperty >().valueAsString( context.expressionContext(), definition->defaultValue().toString() );
1016  else
1017  rectText = val.toString();
1018 
1019  if ( !rectText.isEmpty() )
1020  {
1021  QRegularExpression rx( QStringLiteral( "^(.*?)\\s*,\\s*(.*?),\\s*(.*?),\\s*(.*?)\\s*(?:\\[(.*)\\])?\\s*$" ) );
1022  QRegularExpressionMatch match = rx.match( rectText );
1023  if ( match.hasMatch() )
1024  {
1025  bool xMinOk = false;
1026  double xMin = match.captured( 1 ).toDouble( &xMinOk );
1027  bool xMaxOk = false;
1028  double xMax = match.captured( 2 ).toDouble( &xMaxOk );
1029  bool yMinOk = false;
1030  double yMin = match.captured( 3 ).toDouble( &yMinOk );
1031  bool yMaxOk = false;
1032  double yMax = match.captured( 4 ).toDouble( &yMaxOk );
1033  if ( xMinOk && xMaxOk && yMinOk && yMaxOk )
1034  {
1035  QgsRectangle rect( xMin, yMin, xMax, yMax );
1036  QgsCoordinateReferenceSystem rectCrs( match.captured( 5 ) );
1037  QgsGeometry g = QgsGeometry::fromRect( rect );
1038  if ( crs.isValid() && rectCrs.isValid() && crs != rectCrs )
1039  {
1040  g = g.densifyByCount( 20 );
1041  QgsCoordinateTransform ct( rectCrs, crs, context.project() );
1042  try
1043  {
1044  g.transform( ct );
1045  }
1046  catch ( QgsCsException & )
1047  {
1048  QgsMessageLog::logMessage( QObject::tr( "Error transforming extent geometry" ) );
1049  }
1050  return g;
1051  }
1052  }
1053  }
1054  }
1055 
1056  // try as layer extent
1057 
1058  // maybe parameter is a direct layer value?
1059  QgsMapLayer *layer = qobject_cast< QgsMapLayer * >( qvariant_cast<QObject *>( val ) );
1060  if ( !layer )
1061  layer = QgsProcessingUtils::mapLayerFromString( rectText, context );
1062 
1063  if ( layer )
1064  {
1065  QgsRectangle rect = layer->extent();
1066  QgsGeometry g = QgsGeometry::fromRect( rect );
1067  if ( crs.isValid() && layer->crs().isValid() && crs != layer->crs() )
1068  {
1069  g = g.densifyByCount( 20 );
1070  QgsCoordinateTransform ct( layer->crs(), crs, context.project() );
1071  try
1072  {
1073  g.transform( ct );
1074  }
1075  catch ( QgsCsException & )
1076  {
1077  QgsMessageLog::logMessage( QObject::tr( "Error transforming extent geometry" ) );
1078  }
1079  }
1080  return g;
1081  }
1082 
1083  return QgsGeometry::fromRect( parameterAsExtent( definition, parameters, context, crs ) );
1084 }
1085 
1087 {
1088  QVariant val = parameters.value( definition->name() );
1089 
1090  if ( val.canConvert< QgsReferencedRectangle >() )
1091  {
1093  if ( rr.crs().isValid() )
1094  {
1095  return rr.crs();
1096  }
1097  }
1098 
1099  if ( val.canConvert<QgsProcessingFeatureSourceDefinition>() )
1100  {
1101  // input is a QgsProcessingFeatureSourceDefinition - get extra properties from it
1103  val = fromVar.source;
1104  }
1105  else if ( val.canConvert<QgsProcessingOutputLayerDefinition>() )
1106  {
1107  // input is a QgsProcessingOutputLayerDefinition - get extra properties from it
1109  val = fromVar.sink;
1110  }
1111 
1112  if ( val.canConvert<QgsProperty>() && val.value< QgsProperty >().propertyType() == QgsProperty::StaticProperty )
1113  {
1114  val = val.value< QgsProperty >().staticValue();
1115  }
1116 
1117  QString valueAsString;
1118  if ( val.canConvert<QgsProperty>() )
1119  valueAsString = val.value< QgsProperty >().valueAsString( context.expressionContext(), definition->defaultValue().toString() );
1120  else
1121  valueAsString = val.toString();
1122 
1123  QRegularExpression rx( QStringLiteral( "^(.*?)\\s*,\\s*(.*?),\\s*(.*?),\\s*(.*?)\\s*(?:\\[(.*)\\])?\\s*$" ) );
1124 
1125  QRegularExpressionMatch match = rx.match( valueAsString );
1126  if ( match.hasMatch() )
1127  {
1128  QgsCoordinateReferenceSystem crs( match.captured( 5 ) );
1129  if ( crs.isValid() )
1130  return crs;
1131  }
1132 
1133  if ( val.canConvert<QgsProcessingFeatureSourceDefinition>() )
1134  {
1135  // input is a QgsProcessingFeatureSourceDefinition - get extra properties from it
1137  val = fromVar.source;
1138  }
1139  else if ( val.canConvert<QgsProcessingOutputLayerDefinition>() )
1140  {
1141  // input is a QgsProcessingOutputLayerDefinition - get extra properties from it
1143  val = fromVar.sink;
1144  }
1145 
1146  if ( val.canConvert<QgsProperty>() && val.value< QgsProperty >().propertyType() == QgsProperty::StaticProperty )
1147  {
1148  val = val.value< QgsProperty >().staticValue();
1149  }
1150 
1151  // try as layer crs
1152  if ( QgsMapLayer *layer = qobject_cast< QgsMapLayer * >( qvariant_cast<QObject *>( val ) ) )
1153  return layer->crs();
1154  else if ( QgsMapLayer *layer = QgsProcessingUtils::mapLayerFromString( valueAsString, context ) )
1155  return layer->crs();
1156 
1157  if ( context.project() )
1158  return context.project()->crs();
1159  else
1161 }
1162 
1164 {
1165  if ( !definition )
1166  return QgsPointXY();
1167 
1168  return parameterAsPoint( definition, parameters.value( definition->name() ), context, crs );
1169 }
1170 
1172 {
1173  if ( !definition )
1174  return QgsPointXY();
1175 
1176  QVariant val = value;
1177  if ( val.canConvert< QgsPointXY >() )
1178  {
1179  return val.value<QgsPointXY>();
1180  }
1181  if ( val.canConvert< QgsGeometry >() )
1182  {
1183  const QgsGeometry geom = val.value<QgsGeometry>();
1184  if ( !geom.isNull() )
1185  return geom.centroid().asPoint();
1186  }
1187  if ( val.canConvert< QgsReferencedPointXY >() )
1188  {
1189  QgsReferencedPointXY rp = val.value<QgsReferencedPointXY>();
1190  if ( crs.isValid() && rp.crs().isValid() && crs != rp.crs() )
1191  {
1192  QgsCoordinateTransform ct( rp.crs(), crs, context.project() );
1193  try
1194  {
1195  return ct.transform( rp );
1196  }
1197  catch ( QgsCsException & )
1198  {
1199  QgsMessageLog::logMessage( QObject::tr( "Error transforming point geometry" ) );
1200  }
1201  }
1202  return rp;
1203  }
1204 
1205  QString pointText = parameterAsString( definition, value, context );
1206  if ( pointText.isEmpty() )
1207  pointText = definition->defaultValue().toString();
1208 
1209  if ( pointText.isEmpty() )
1210  return QgsPointXY();
1211 
1212  QRegularExpression rx( QStringLiteral( "^\\s*\\(?\\s*(.*?)\\s*,\\s*(.*?)\\s*(?:\\[(.*)\\])?\\s*\\)?\\s*$" ) );
1213 
1214  QString valueAsString = parameterAsString( definition, value, context );
1215  QRegularExpressionMatch match = rx.match( valueAsString );
1216  if ( match.hasMatch() )
1217  {
1218  bool xOk = false;
1219  double x = match.captured( 1 ).toDouble( &xOk );
1220  bool yOk = false;
1221  double y = match.captured( 2 ).toDouble( &yOk );
1222 
1223  if ( xOk && yOk )
1224  {
1225  QgsPointXY pt( x, y );
1226 
1227  QgsCoordinateReferenceSystem pointCrs( match.captured( 3 ) );
1228  if ( crs.isValid() && pointCrs.isValid() && crs != pointCrs )
1229  {
1230  QgsCoordinateTransform ct( pointCrs, crs, context.project() );
1231  try
1232  {
1233  return ct.transform( pt );
1234  }
1235  catch ( QgsCsException & )
1236  {
1237  QgsMessageLog::logMessage( QObject::tr( "Error transforming point geometry" ) );
1238  }
1239  }
1240  return pt;
1241  }
1242  }
1243 
1244  return QgsPointXY();
1245 }
1246 
1248 {
1249  QVariant val = parameters.value( definition->name() );
1250  return parameterAsPointCrs( definition, val, context );
1251 }
1252 
1254 {
1255  if ( value.canConvert< QgsReferencedPointXY >() )
1256  {
1257  QgsReferencedPointXY rr = value.value<QgsReferencedPointXY>();
1258  if ( rr.crs().isValid() )
1259  {
1260  return rr.crs();
1261  }
1262  }
1263 
1264  QRegularExpression rx( QStringLiteral( "^\\s*\\(?\\s*(.*?)\\s*,\\s*(.*?)\\s*(?:\\[(.*)\\])?\\s*\\)?\\s*$" ) );
1265 
1266  QString valueAsString = parameterAsString( definition, value, context );
1267  QRegularExpressionMatch match = rx.match( valueAsString );
1268  if ( match.hasMatch() )
1269  {
1270  QgsCoordinateReferenceSystem crs( match.captured( 3 ) );
1271  if ( crs.isValid() )
1272  return crs;
1273  }
1274 
1275  if ( context.project() )
1276  return context.project()->crs();
1277  else
1279 }
1280 
1281 QString QgsProcessingParameters::parameterAsFile( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context )
1282 {
1283  if ( !definition )
1284  return QString();
1285 
1286  QString fileText = parameterAsString( definition, parameters, context );
1287  if ( fileText.isEmpty() )
1288  fileText = definition->defaultValue().toString();
1289  return fileText;
1290 }
1291 
1292 QString QgsProcessingParameters::parameterAsFile( const QgsProcessingParameterDefinition *definition, const QVariant &value, QgsProcessingContext &context )
1293 {
1294  if ( !definition )
1295  return QString();
1296 
1297  QString fileText = parameterAsString( definition, value, context );
1298  if ( fileText.isEmpty() )
1299  fileText = definition->defaultValue().toString();
1300  return fileText;
1301 }
1302 
1303 QVariantList QgsProcessingParameters::parameterAsMatrix( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context )
1304 {
1305  if ( !definition )
1306  return QVariantList();
1307 
1308  return parameterAsMatrix( definition, parameters.value( definition->name() ), context );
1309 }
1310 
1311 QVariantList QgsProcessingParameters::parameterAsMatrix( const QgsProcessingParameterDefinition *definition, const QVariant &value, QgsProcessingContext &context )
1312 {
1313  if ( !definition )
1314  return QVariantList();
1315 
1316  QString resultString;
1317  QVariant val = value;
1318  if ( val.canConvert<QgsProperty>() )
1319  resultString = val.value< QgsProperty >().valueAsString( context.expressionContext(), definition->defaultValue().toString() );
1320  else if ( val.type() == QVariant::List )
1321  return val.toList();
1322  else
1323  resultString = val.toString();
1324 
1325  if ( resultString.isEmpty() )
1326  {
1327  // check default
1328  if ( definition->defaultValue().type() == QVariant::List )
1329  return definition->defaultValue().toList();
1330  else
1331  resultString = definition->defaultValue().toString();
1332  }
1333 
1334  QVariantList result;
1335  const auto constSplit = resultString.split( ',' );
1336  for ( const QString &s : constSplit )
1337  result << s;
1338 
1339  return result;
1340 }
1341 
1342 QList<QgsMapLayer *> QgsProcessingParameters::parameterAsLayerList( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context )
1343 {
1344  if ( !definition )
1345  return QList<QgsMapLayer *>();
1346 
1347  return parameterAsLayerList( definition, parameters.value( definition->name() ), context );
1348 }
1349 
1350 QList<QgsMapLayer *> QgsProcessingParameters::parameterAsLayerList( const QgsProcessingParameterDefinition *definition, const QVariant &value, QgsProcessingContext &context )
1351 {
1352  if ( !definition )
1353  return QList<QgsMapLayer *>();
1354 
1355  QVariant val = value;
1356  if ( QgsMapLayer *layer = qobject_cast< QgsMapLayer * >( qvariant_cast<QObject *>( val ) ) )
1357  {
1358  return QList<QgsMapLayer *>() << layer;
1359  }
1360 
1361  QList<QgsMapLayer *> layers;
1362 
1363  std::function< void( const QVariant &var ) > processVariant;
1364  processVariant = [ &layers, &context, &definition, &processVariant ]( const QVariant & var )
1365  {
1366  if ( var.type() == QVariant::List )
1367  {
1368  const auto constToList = var.toList();
1369  for ( const QVariant &listVar : constToList )
1370  {
1371  processVariant( listVar );
1372  }
1373  }
1374  else if ( var.type() == QVariant::StringList )
1375  {
1376  const auto constToStringList = var.toStringList();
1377  for ( const QString &s : constToStringList )
1378  {
1379  processVariant( s );
1380  }
1381  }
1382  else if ( var.canConvert<QgsProperty>() )
1383  processVariant( var.value< QgsProperty >().valueAsString( context.expressionContext(), definition->defaultValue().toString() ) );
1384  else if ( var.canConvert<QgsProcessingOutputLayerDefinition>() )
1385  {
1386  // input is a QgsProcessingOutputLayerDefinition - get extra properties from it
1388  QVariant sink = fromVar.sink;
1389  if ( sink.canConvert<QgsProperty>() )
1390  {
1391  processVariant( sink.value< QgsProperty >().valueAsString( context.expressionContext(), definition->defaultValue().toString() ) );
1392  }
1393  }
1394  else if ( QgsMapLayer *layer = qobject_cast< QgsMapLayer * >( qvariant_cast<QObject *>( var ) ) )
1395  {
1396  layers << layer;
1397  }
1398  else
1399  {
1400  QgsMapLayer *alayer = QgsProcessingUtils::mapLayerFromString( var.toString(), context );
1401  if ( alayer )
1402  layers << alayer;
1403  }
1404  };
1405 
1406  processVariant( val );
1407 
1408  if ( layers.isEmpty() )
1409  {
1410  // check default
1411  if ( QgsMapLayer *layer = qobject_cast< QgsMapLayer * >( qvariant_cast<QObject *>( definition->defaultValue() ) ) )
1412  {
1413  layers << layer;
1414  }
1415  else if ( definition->defaultValue().type() == QVariant::List )
1416  {
1417  const auto constToList = definition->defaultValue().toList();
1418  for ( const QVariant &var : constToList )
1419  {
1420  if ( QgsMapLayer *layer = qobject_cast< QgsMapLayer * >( qvariant_cast<QObject *>( var ) ) )
1421  {
1422  layers << layer;
1423  }
1424  else
1425  {
1426  processVariant( var );
1427  }
1428  }
1429  }
1430  else
1431  processVariant( definition->defaultValue() );
1432  }
1433 
1434  return layers;
1435 }
1436 
1437 QStringList QgsProcessingParameters::parameterAsFileList( const QgsProcessingParameterDefinition *definition, const QVariant &value, QgsProcessingContext &context )
1438 {
1439  if ( !definition )
1440  return QStringList();
1441 
1442  QVariant val = value;
1443 
1444  QStringList files;
1445 
1446  std::function< void( const QVariant &var ) > processVariant;
1447  processVariant = [ &files, &context, &definition, &processVariant ]( const QVariant & var )
1448  {
1449  if ( var.type() == QVariant::List )
1450  {
1451  const auto constToList = var.toList();
1452  for ( const QVariant &listVar : constToList )
1453  {
1454  processVariant( listVar );
1455  }
1456  }
1457  else if ( var.type() == QVariant::StringList )
1458  {
1459  const auto constToStringList = var.toStringList();
1460  for ( const QString &s : constToStringList )
1461  {
1462  processVariant( s );
1463  }
1464  }
1465  else if ( var.canConvert<QgsProperty>() )
1466  processVariant( var.value< QgsProperty >().valueAsString( context.expressionContext(), definition->defaultValue().toString() ) );
1467  else
1468  {
1469  files << var.toString();
1470  }
1471  };
1472 
1473  processVariant( val );
1474 
1475  if ( files.isEmpty() )
1476  {
1477  processVariant( definition->defaultValue() );
1478  }
1479 
1480  return files;
1481 }
1482 
1483 QStringList QgsProcessingParameters::parameterAsFileList( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context )
1484 {
1485  if ( !definition )
1486  return QStringList();
1487 
1488  return parameterAsFileList( definition, parameters.value( definition->name() ), context );
1489 }
1490 
1491 QList<double> QgsProcessingParameters::parameterAsRange( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context )
1492 {
1493  if ( !definition )
1494  return QList<double>();
1495 
1496  return parameterAsRange( definition, parameters.value( definition->name() ), context );
1497 }
1498 
1499 QList<double> QgsProcessingParameters::parameterAsRange( const QgsProcessingParameterDefinition *definition, const QVariant &value, QgsProcessingContext &context )
1500 {
1501  if ( !definition )
1502  return QList<double>();
1503 
1504  QStringList resultStringList;
1505  QVariant val = value;
1506  if ( val.canConvert<QgsProperty>() )
1507  resultStringList << val.value< QgsProperty >().valueAsString( context.expressionContext(), definition->defaultValue().toString() );
1508  else if ( val.type() == QVariant::List )
1509  {
1510  const auto constToList = val.toList();
1511  for ( const QVariant &var : constToList )
1512  resultStringList << var.toString();
1513  }
1514  else
1515  resultStringList << val.toString();
1516 
1517  if ( ( resultStringList.isEmpty() || ( resultStringList.size() == 1 && resultStringList.at( 0 ).isEmpty() ) ) )
1518  {
1519  resultStringList.clear();
1520  // check default
1521  if ( definition->defaultValue().type() == QVariant::List )
1522  {
1523  const auto constToList = definition->defaultValue().toList();
1524  for ( const QVariant &var : constToList )
1525  resultStringList << var.toString();
1526  }
1527  else
1528  resultStringList << definition->defaultValue().toString();
1529  }
1530 
1531  if ( resultStringList.size() == 1 )
1532  {
1533  resultStringList = resultStringList.at( 0 ).split( ',' );
1534  }
1535 
1536  if ( resultStringList.size() < 2 )
1537  return QList< double >() << 0.0 << 0.0;
1538 
1539  return QList< double >() << resultStringList.at( 0 ).toDouble() << resultStringList.at( 1 ).toDouble();
1540 }
1541 
1542 QStringList QgsProcessingParameters::parameterAsFields( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context )
1543 {
1544  if ( !definition )
1545  return QStringList();
1546 
1547  QStringList resultStringList;
1548  return parameterAsFields( definition, parameters.value( definition->name() ), context );
1549 }
1550 
1551 QStringList QgsProcessingParameters::parameterAsFields( const QgsProcessingParameterDefinition *definition, const QVariant &value, QgsProcessingContext &context )
1552 {
1553  if ( !definition )
1554  return QStringList();
1555 
1556  QStringList resultStringList;
1557  QVariant val = value;
1558  if ( val.isValid() )
1559  {
1560  if ( val.canConvert<QgsProperty>() )
1561  resultStringList << val.value< QgsProperty >().valueAsString( context.expressionContext(), definition->defaultValue().toString() );
1562  else if ( val.type() == QVariant::List )
1563  {
1564  const auto constToList = val.toList();
1565  for ( const QVariant &var : constToList )
1566  resultStringList << var.toString();
1567  }
1568  else
1569  resultStringList.append( val.toString().split( ';' ) );
1570  }
1571 
1572  if ( ( resultStringList.isEmpty() || resultStringList.at( 0 ).isEmpty() ) )
1573  {
1574  resultStringList.clear();
1575  // check default
1576  if ( definition->defaultValue().isValid() )
1577  {
1578  if ( definition->defaultValue().type() == QVariant::List )
1579  {
1580  const auto constToList = definition->defaultValue().toList();
1581  for ( const QVariant &var : constToList )
1582  resultStringList << var.toString();
1583  }
1584  else
1585  resultStringList.append( definition->defaultValue().toString().split( ';' ) );
1586  }
1587  }
1588 
1589  return resultStringList;
1590 }
1591 
1593 {
1594  if ( !definition )
1595  return nullptr;
1596 
1597  return parameterAsLayout( definition, parameters.value( definition->name() ), context );
1598 }
1599 
1601 {
1602  const QString layoutName = parameterAsString( definition, value, context );
1603  if ( layoutName.isEmpty() )
1604  return nullptr;
1605 
1606  if ( !context.project() )
1607  return nullptr;
1608 
1609  QgsMasterLayoutInterface *l = context.project()->layoutManager()->layoutByName( layoutName );
1611  return static_cast< QgsPrintLayout * >( l );
1612  else
1613  return nullptr;
1614 }
1615 
1617 {
1618  if ( !definition )
1619  return nullptr;
1620 
1621  return parameterAsLayoutItem( definition, parameters.value( definition->name() ), context, layout );
1622 }
1623 
1625 {
1626  if ( !layout )
1627  return nullptr;
1628 
1629  const QString id = parameterAsString( definition, value, context );
1630  if ( id.isEmpty() )
1631  return nullptr;
1632 
1633  // prefer matching by uuid, since it's guaranteed to be unique.
1634  if ( QgsLayoutItem *item = layout->itemByUuid( id ) )
1635  return item;
1636  else if ( QgsLayoutItem *item = layout->itemById( id ) )
1637  return item;
1638  else
1639  return nullptr;
1640 }
1641 
1642 QColor QgsProcessingParameters::parameterAsColor( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context )
1643 {
1644  if ( !definition )
1645  return QColor();
1646 
1647  return parameterAsColor( definition, parameters.value( definition->name() ), context );
1648 }
1649 
1651 {
1652  if ( !definition )
1653  return QColor();
1654 
1655  QVariant val = value;
1656  if ( val.canConvert<QgsProperty>() )
1657  {
1658  val = val.value< QgsProperty >().value( context.expressionContext(), definition->defaultValue() );
1659  }
1660  if ( val.type() == QVariant::Color )
1661  {
1662  QColor c = val.value< QColor >();
1663  if ( const QgsProcessingParameterColor *colorParam = dynamic_cast< const QgsProcessingParameterColor * >( definition ) )
1664  if ( !colorParam->opacityEnabled() )
1665  c.setAlpha( 255 );
1666  return c;
1667  }
1668 
1669  QString colorText = parameterAsString( definition, value, context );
1670  if ( colorText.isEmpty() && !( definition->flags() & QgsProcessingParameterDefinition::FlagOptional ) )
1671  {
1672  if ( definition->defaultValue().type() == QVariant::Color )
1673  return definition->defaultValue().value< QColor >();
1674  else
1675  colorText = definition->defaultValue().toString();
1676  }
1677 
1678  if ( colorText.isEmpty() )
1679  return QColor();
1680 
1681  bool containsAlpha = false;
1682  QColor c = QgsSymbolLayerUtils::parseColorWithAlpha( colorText, containsAlpha );
1683  if ( const QgsProcessingParameterColor *colorParam = dynamic_cast< const QgsProcessingParameterColor * >( definition ) )
1684  if ( c.isValid() && !colorParam->opacityEnabled() )
1685  c.setAlpha( 255 );
1686  return c;
1687 }
1688 
1690 {
1691  QString type = map.value( QStringLiteral( "parameter_type" ) ).toString();
1692  QString name = map.value( QStringLiteral( "name" ) ).toString();
1693  std::unique_ptr< QgsProcessingParameterDefinition > def;
1695  def.reset( new QgsProcessingParameterBoolean( name ) );
1696  else if ( type == QgsProcessingParameterCrs::typeName() )
1697  def.reset( new QgsProcessingParameterCrs( name ) );
1698  else if ( type == QgsProcessingParameterMapLayer::typeName() )
1699  def.reset( new QgsProcessingParameterMapLayer( name ) );
1700  else if ( type == QgsProcessingParameterExtent::typeName() )
1701  def.reset( new QgsProcessingParameterExtent( name ) );
1702  else if ( type == QgsProcessingParameterPoint::typeName() )
1703  def.reset( new QgsProcessingParameterPoint( name ) );
1704  else if ( type == QgsProcessingParameterFile::typeName() )
1705  def.reset( new QgsProcessingParameterFile( name ) );
1706  else if ( type == QgsProcessingParameterMatrix::typeName() )
1707  def.reset( new QgsProcessingParameterMatrix( name ) );
1709  def.reset( new QgsProcessingParameterMultipleLayers( name ) );
1710  else if ( type == QgsProcessingParameterNumber::typeName() )
1711  def.reset( new QgsProcessingParameterNumber( name ) );
1712  else if ( type == QgsProcessingParameterRange::typeName() )
1713  def.reset( new QgsProcessingParameterRange( name ) );
1714  else if ( type == QgsProcessingParameterRasterLayer::typeName() )
1715  def.reset( new QgsProcessingParameterRasterLayer( name ) );
1716  else if ( type == QgsProcessingParameterEnum::typeName() )
1717  def.reset( new QgsProcessingParameterEnum( name ) );
1718  else if ( type == QgsProcessingParameterString::typeName() )
1719  def.reset( new QgsProcessingParameterString( name ) );
1720  else if ( type == QgsProcessingParameterAuthConfig::typeName() )
1721  def.reset( new QgsProcessingParameterAuthConfig( name ) );
1722  else if ( type == QgsProcessingParameterExpression::typeName() )
1723  def.reset( new QgsProcessingParameterExpression( name ) );
1724  else if ( type == QgsProcessingParameterVectorLayer::typeName() )
1725  def.reset( new QgsProcessingParameterVectorLayer( name ) );
1726  else if ( type == QgsProcessingParameterField::typeName() )
1727  def.reset( new QgsProcessingParameterField( name ) );
1728  else if ( type == QgsProcessingParameterFeatureSource::typeName() )
1729  def.reset( new QgsProcessingParameterFeatureSource( name ) );
1730  else if ( type == QgsProcessingParameterFeatureSink::typeName() )
1731  def.reset( new QgsProcessingParameterFeatureSink( name ) );
1733  def.reset( new QgsProcessingParameterVectorDestination( name ) );
1735  def.reset( new QgsProcessingParameterRasterDestination( name ) );
1737  def.reset( new QgsProcessingParameterFileDestination( name ) );
1739  def.reset( new QgsProcessingParameterFolderDestination( name ) );
1740  else if ( type == QgsProcessingParameterBand::typeName() )
1741  def.reset( new QgsProcessingParameterBand( name ) );
1742  else if ( type == QgsProcessingParameterMeshLayer::typeName() )
1743  def.reset( new QgsProcessingParameterMeshLayer( name ) );
1744  else if ( type == QgsProcessingParameterLayout::typeName() )
1745  def.reset( new QgsProcessingParameterLayout( name ) );
1746  else if ( type == QgsProcessingParameterLayoutItem::typeName() )
1747  def.reset( new QgsProcessingParameterLayoutItem( name ) );
1748  else if ( type == QgsProcessingParameterColor::typeName() )
1749  def.reset( new QgsProcessingParameterColor( name ) );
1750  else
1751  {
1753  if ( paramType )
1754  def.reset( paramType->create( name ) );
1755  }
1756 
1757  if ( !def )
1758  return nullptr;
1759 
1760  def->fromVariantMap( map );
1761  return def.release();
1762 }
1763 
1764 QString QgsProcessingParameters::descriptionFromName( const QString &name )
1765 {
1766  QString desc = name;
1767  desc.replace( '_', ' ' );
1768  return desc;
1769 }
1770 
1772 {
1773  bool isOptional = false;
1774  QString name;
1775  QString definition;
1776  QString type;
1777  if ( !parseScriptCodeParameterOptions( code, isOptional, name, type, definition ) )
1778  return nullptr;
1779 
1780  QString description = descriptionFromName( name );
1781 
1782  if ( type == QStringLiteral( "boolean" ) )
1783  return QgsProcessingParameterBoolean::fromScriptCode( name, description, isOptional, definition );
1784  else if ( type == QStringLiteral( "crs" ) )
1785  return QgsProcessingParameterCrs::fromScriptCode( name, description, isOptional, definition );
1786  else if ( type == QStringLiteral( "layer" ) )
1787  return QgsProcessingParameterMapLayer::fromScriptCode( name, description, isOptional, definition );
1788  else if ( type == QStringLiteral( "extent" ) )
1789  return QgsProcessingParameterExtent::fromScriptCode( name, description, isOptional, definition );
1790  else if ( type == QStringLiteral( "point" ) )
1791  return QgsProcessingParameterPoint::fromScriptCode( name, description, isOptional, definition );
1792  else if ( type == QStringLiteral( "file" ) )
1793  return QgsProcessingParameterFile::fromScriptCode( name, description, isOptional, definition, QgsProcessingParameterFile::File );
1794  else if ( type == QStringLiteral( "folder" ) )
1795  return QgsProcessingParameterFile::fromScriptCode( name, description, isOptional, definition, QgsProcessingParameterFile::Folder );
1796  else if ( type == QStringLiteral( "matrix" ) )
1797  return QgsProcessingParameterMatrix::fromScriptCode( name, description, isOptional, definition );
1798  else if ( type == QStringLiteral( "multiple" ) )
1799  return QgsProcessingParameterMultipleLayers::fromScriptCode( name, description, isOptional, definition );
1800  else if ( type == QStringLiteral( "number" ) )
1801  return QgsProcessingParameterNumber::fromScriptCode( name, description, isOptional, definition );
1802  else if ( type == QStringLiteral( "distance" ) )
1803  return QgsProcessingParameterDistance::fromScriptCode( name, description, isOptional, definition );
1804  else if ( type == QStringLiteral( "scale" ) )
1805  return QgsProcessingParameterScale::fromScriptCode( name, description, isOptional, definition );
1806  else if ( type == QStringLiteral( "range" ) )
1807  return QgsProcessingParameterRange::fromScriptCode( name, description, isOptional, definition );
1808  else if ( type == QStringLiteral( "raster" ) )
1809  return QgsProcessingParameterRasterLayer::fromScriptCode( name, description, isOptional, definition );
1810  else if ( type == QStringLiteral( "enum" ) )
1811  return QgsProcessingParameterEnum::fromScriptCode( name, description, isOptional, definition );
1812  else if ( type == QStringLiteral( "string" ) )
1813  return QgsProcessingParameterString::fromScriptCode( name, description, isOptional, definition );
1814  else if ( type == QStringLiteral( "authcfg" ) )
1815  return QgsProcessingParameterAuthConfig::fromScriptCode( name, description, isOptional, definition );
1816  else if ( type == QStringLiteral( "expression" ) )
1817  return QgsProcessingParameterExpression::fromScriptCode( name, description, isOptional, definition );
1818  else if ( type == QStringLiteral( "field" ) )
1819  return QgsProcessingParameterField::fromScriptCode( name, description, isOptional, definition );
1820  else if ( type == QStringLiteral( "vector" ) )
1821  return QgsProcessingParameterVectorLayer::fromScriptCode( name, description, isOptional, definition );
1822  else if ( type == QStringLiteral( "source" ) )
1823  return QgsProcessingParameterFeatureSource::fromScriptCode( name, description, isOptional, definition );
1824  else if ( type == QStringLiteral( "sink" ) )
1825  return QgsProcessingParameterFeatureSink::fromScriptCode( name, description, isOptional, definition );
1826  else if ( type == QStringLiteral( "vectordestination" ) )
1827  return QgsProcessingParameterVectorDestination::fromScriptCode( name, description, isOptional, definition );
1828  else if ( type == QStringLiteral( "rasterdestination" ) )
1829  return QgsProcessingParameterRasterDestination::fromScriptCode( name, description, isOptional, definition );
1830  else if ( type == QStringLiteral( "filedestination" ) )
1831  return QgsProcessingParameterFileDestination::fromScriptCode( name, description, isOptional, definition );
1832  else if ( type == QStringLiteral( "folderdestination" ) )
1833  return QgsProcessingParameterFolderDestination::fromScriptCode( name, description, isOptional, definition );
1834  else if ( type == QStringLiteral( "band" ) )
1835  return QgsProcessingParameterBand::fromScriptCode( name, description, isOptional, definition );
1836  else if ( type == QStringLiteral( "mesh" ) )
1837  return QgsProcessingParameterMeshLayer::fromScriptCode( name, description, isOptional, definition );
1838  else if ( type == QStringLiteral( "layout" ) )
1839  return QgsProcessingParameterLayout::fromScriptCode( name, description, isOptional, definition );
1840  else if ( type == QStringLiteral( "layoutitem" ) )
1841  return QgsProcessingParameterLayoutItem::fromScriptCode( name, description, isOptional, definition );
1842  else if ( type == QStringLiteral( "color" ) )
1843  return QgsProcessingParameterColor::fromScriptCode( name, description, isOptional, definition );
1844 
1845  return nullptr;
1846 }
1847 
1848 bool QgsProcessingParameters::parseScriptCodeParameterOptions( const QString &code, bool &isOptional, QString &name, QString &type, QString &definition )
1849 {
1850  QRegularExpression re( QStringLiteral( "(?:#*)(.*?)=\\s*(.*)" ) );
1851  QRegularExpressionMatch m = re.match( code );
1852  if ( !m.hasMatch() )
1853  return false;
1854 
1855  name = m.captured( 1 );
1856  QString tokens = m.captured( 2 );
1857  if ( tokens.startsWith( QLatin1String( "optional" ), Qt::CaseInsensitive ) )
1858  {
1859  isOptional = true;
1860  tokens.remove( 0, 8 ); // length "optional" = 8
1861  }
1862  else
1863  {
1864  isOptional = false;
1865  }
1866 
1867  tokens = tokens.trimmed();
1868 
1869  QRegularExpression re2( QStringLiteral( "(.*?)\\s+(.*)" ) );
1870  m = re2.match( tokens );
1871  if ( !m.hasMatch() )
1872  {
1873  type = tokens.toLower().trimmed();
1874  definition.clear();
1875  }
1876  else
1877  {
1878  type = m.captured( 1 ).toLower().trimmed();
1879  definition = m.captured( 2 );
1880  }
1881  return true;
1882 }
1883 
1884 //
1885 // QgsProcessingParameterDefinition
1886 //
1887 
1888 QgsProcessingParameterDefinition::QgsProcessingParameterDefinition( const QString &name, const QString &description, const QVariant &defaultValue, bool optional )
1889  : mName( name )
1890  , mDescription( description )
1891  , mDefault( defaultValue )
1892  , mFlags( optional ? FlagOptional : 0 )
1893 {}
1894 
1896 {
1897  if ( !input.isValid() && !mDefault.isValid() )
1898  return mFlags & FlagOptional;
1899 
1900  if ( ( input.type() == QVariant::String && input.toString().isEmpty() )
1901  || ( !input.isValid() && mDefault.type() == QVariant::String && mDefault.toString().isEmpty() ) )
1902  return mFlags & FlagOptional;
1903 
1904  return true;
1905 }
1906 
1908 {
1909  if ( !value.isValid() )
1910  return QStringLiteral( "None" );
1911 
1912  if ( value.canConvert<QgsProperty>() )
1913  return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
1914 
1915  return QgsProcessingUtils::stringToPythonLiteral( value.toString() );
1916 }
1917 
1919 {
1920  QString code = QStringLiteral( "##%1=" ).arg( mName );
1921  if ( mFlags & FlagOptional )
1922  code += QStringLiteral( "optional " );
1923  code += type() + ' ';
1924  code += mDefault.toString();
1925  return code.trimmed();
1926 }
1927 
1929 {
1930  // base class method is probably not much use
1931  if ( QgsProcessingParameterType *t = QgsApplication::processingRegistry()->parameterType( type() ) )
1932  {
1933  switch ( outputType )
1934  {
1936  {
1937  QString code = t->className() + QStringLiteral( "('%1', '%2'" ).arg( name(), description() );
1938  if ( mFlags & FlagOptional )
1939  code += QStringLiteral( ", optional=True" );
1940 
1942  code += QStringLiteral( ", defaultValue=%1)" ).arg( valueAsPythonString( mDefault, c ) );
1943  return code;
1944  }
1945  }
1946  }
1947 
1948  // oh well, we tried
1949  return QString();
1950 }
1951 
1953 {
1954  QVariantMap map;
1955  map.insert( QStringLiteral( "parameter_type" ), type() );
1956  map.insert( QStringLiteral( "name" ), mName );
1957  map.insert( QStringLiteral( "description" ), mDescription );
1958  map.insert( QStringLiteral( "default" ), mDefault );
1959  map.insert( QStringLiteral( "flags" ), static_cast< int >( mFlags ) );
1960  map.insert( QStringLiteral( "metadata" ), mMetadata );
1961  return map;
1962 }
1963 
1965 {
1966  mName = map.value( QStringLiteral( "name" ) ).toString();
1967  mDescription = map.value( QStringLiteral( "description" ) ).toString();
1968  mDefault = map.value( QStringLiteral( "default" ) );
1969  mFlags = static_cast< Flags >( map.value( QStringLiteral( "flags" ) ).toInt() );
1970  mMetadata = map.value( QStringLiteral( "metadata" ) ).toMap();
1971  return true;
1972 }
1973 
1975 {
1976  return mAlgorithm;
1977 }
1978 
1980 {
1981  return mAlgorithm ? mAlgorithm->provider() : nullptr;
1982 }
1983 
1985 {
1986  return QStringLiteral( "<p><b>%1</b></p><p>%2</p>" ).arg(
1987  description(),
1988  QObject::tr( "Python identifier: ‘%1’" ).arg( QStringLiteral( "<i>%1</i>" ).arg( name() ) ) );
1989 }
1990 
1991 QgsProcessingParameterBoolean::QgsProcessingParameterBoolean( const QString &name, const QString &description, const QVariant &defaultValue, bool optional )
1992  : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
1993 {}
1994 
1996 {
1997  return new QgsProcessingParameterBoolean( *this );
1998 }
1999 
2001 {
2002  if ( !val.isValid() )
2003  return QStringLiteral( "None" );
2004 
2005  if ( val.canConvert<QgsProperty>() )
2006  return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( val.value< QgsProperty >().asExpression() );
2007  return val.toBool() ? QStringLiteral( "True" ) : QStringLiteral( "False" );
2008 }
2009 
2011 {
2012  QString code = QStringLiteral( "##%1=" ).arg( mName );
2013  if ( mFlags & FlagOptional )
2014  code += QStringLiteral( "optional " );
2015  code += type() + ' ';
2016  code += mDefault.toBool() ? QStringLiteral( "true" ) : QStringLiteral( "false" );
2017  return code.trimmed();
2018 }
2019 
2020 QgsProcessingParameterBoolean *QgsProcessingParameterBoolean::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
2021 {
2022  return new QgsProcessingParameterBoolean( name, description, definition.toLower().trimmed() != QStringLiteral( "false" ), isOptional );
2023 }
2024 
2025 QgsProcessingParameterCrs::QgsProcessingParameterCrs( const QString &name, const QString &description, const QVariant &defaultValue, bool optional )
2026  : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
2027 {
2028 
2029 }
2030 
2032 {
2033  return new QgsProcessingParameterCrs( *this );
2034 }
2035 
2037 {
2038  if ( !input.isValid() )
2039  return mFlags & FlagOptional;
2040 
2041  if ( input.canConvert<QgsCoordinateReferenceSystem>() )
2042  {
2043  return true;
2044  }
2045  else if ( input.canConvert<QgsProcessingFeatureSourceDefinition>() )
2046  {
2047  return true;
2048  }
2049  else if ( input.canConvert<QgsProcessingOutputLayerDefinition>() )
2050  {
2051  return true;
2052  }
2053 
2054  if ( input.canConvert<QgsProperty>() )
2055  {
2056  return true;
2057  }
2058 
2059  // direct map layer value
2060  if ( qobject_cast< QgsMapLayer * >( qvariant_cast<QObject *>( input ) ) )
2061  return true;
2062 
2063  if ( input.type() != QVariant::String || input.toString().isEmpty() )
2064  return mFlags & FlagOptional;
2065 
2066  return true;
2067 }
2068 
2069 QString QgsProcessingParameterCrs::valueAsPythonString( const QVariant &value, QgsProcessingContext &context ) const
2070 {
2071  if ( !value.isValid() )
2072  return QStringLiteral( "None" );
2073 
2074  if ( value.canConvert<QgsCoordinateReferenceSystem>() )
2075  {
2076  if ( !value.value< QgsCoordinateReferenceSystem >().isValid() )
2077  return QStringLiteral( "QgsCoordinateReferenceSystem()" );
2078  else
2079  return QStringLiteral( "QgsCoordinateReferenceSystem('%1')" ).arg( value.value< QgsCoordinateReferenceSystem >().authid() );
2080  }
2081 
2082  if ( value.canConvert<QgsProperty>() )
2083  return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
2084 
2085  QVariantMap p;
2086  p.insert( name(), value );
2087  QgsMapLayer *layer = QgsProcessingParameters::parameterAsLayer( this, p, context );
2088  if ( layer )
2090 
2092 }
2093 
2094 QgsProcessingParameterCrs *QgsProcessingParameterCrs::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
2095 {
2096  return new QgsProcessingParameterCrs( name, description, definition.compare( QLatin1String( "none" ), Qt::CaseInsensitive ) == 0 ? QVariant() : definition, isOptional );
2097 }
2098 
2099 QgsProcessingParameterMapLayer::QgsProcessingParameterMapLayer( const QString &name, const QString &description, const QVariant &defaultValue, bool optional )
2100  : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
2101 {
2102 
2103 }
2104 
2106 {
2107  return new QgsProcessingParameterMapLayer( *this );
2108 }
2109 
2111 {
2112  if ( !input.isValid() )
2113  return mFlags & FlagOptional;
2114 
2115  if ( input.canConvert<QgsProperty>() )
2116  {
2117  return true;
2118  }
2119 
2120  if ( qobject_cast< QgsMapLayer * >( qvariant_cast<QObject *>( input ) ) )
2121  {
2122  return true;
2123  }
2124 
2125  if ( input.type() != QVariant::String || input.toString().isEmpty() )
2126  return mFlags & FlagOptional;
2127 
2128  if ( !context )
2129  {
2130  // that's as far as we can get without a context
2131  return true;
2132  }
2133 
2134  // try to load as layer
2135  if ( QgsProcessingUtils::mapLayerFromString( input.toString(), *context ) )
2136  return true;
2137 
2138  return false;
2139 }
2140 
2142 {
2143  if ( !val.isValid() )
2144  return QStringLiteral( "None" );
2145 
2146  if ( val.canConvert<QgsProperty>() )
2147  return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( val.value< QgsProperty >().asExpression() );
2148 
2149  QVariantMap p;
2150  p.insert( name(), val );
2151  QgsMapLayer *layer = QgsProcessingParameters::parameterAsLayer( this, p, context );
2153  : QgsProcessingUtils::stringToPythonLiteral( val.toString() );
2154 }
2155 
2156 QgsProcessingParameterMapLayer *QgsProcessingParameterMapLayer::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
2157 {
2158  return new QgsProcessingParameterMapLayer( name, description, definition, isOptional );
2159 }
2160 
2161 QgsProcessingParameterExtent::QgsProcessingParameterExtent( const QString &name, const QString &description, const QVariant &defaultValue, bool optional )
2162  : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
2163 {
2164 
2165 }
2166 
2168 {
2169  return new QgsProcessingParameterExtent( *this );
2170 }
2171 
2173 {
2174  if ( !input.isValid() )
2175  return mFlags & FlagOptional;
2176 
2177  if ( input.canConvert<QgsProcessingFeatureSourceDefinition>() )
2178  {
2179  return true;
2180  }
2181  else if ( input.canConvert<QgsProcessingOutputLayerDefinition>() )
2182  {
2183  return true;
2184  }
2185 
2186  if ( input.canConvert<QgsProperty>() )
2187  {
2188  return true;
2189  }
2190 
2191  if ( input.canConvert< QgsRectangle >() )
2192  {
2193  QgsRectangle r = input.value<QgsRectangle>();
2194  return !r.isNull();
2195  }
2196  if ( input.canConvert< QgsReferencedRectangle >() )
2197  {
2199  return !r.isNull();
2200  }
2201 
2202  // direct map layer value
2203  if ( qobject_cast< QgsMapLayer * >( qvariant_cast<QObject *>( input ) ) )
2204  return true;
2205 
2206  if ( input.type() != QVariant::String || input.toString().isEmpty() )
2207  return mFlags & FlagOptional;
2208 
2209  if ( !context )
2210  {
2211  // that's as far as we can get without a context
2212  return true;
2213  }
2214 
2215  QRegularExpression rx( QStringLiteral( "^(.*?)\\s*,\\s*(.*?)\\s*,\\s*(.*?)\\s*,\\s*(.*?)\\s*(?:\\[(.*)\\])?\\s*$" ) );
2216  QRegularExpressionMatch match = rx.match( input.toString() );
2217  if ( match.hasMatch() )
2218  {
2219  bool xMinOk = false;
2220  ( void )match.captured( 1 ).toDouble( &xMinOk );
2221  bool xMaxOk = false;
2222  ( void )match.captured( 2 ).toDouble( &xMaxOk );
2223  bool yMinOk = false;
2224  ( void )match.captured( 3 ).toDouble( &yMinOk );
2225  bool yMaxOk = false;
2226  ( void )match.captured( 4 ).toDouble( &yMaxOk );
2227  if ( xMinOk && xMaxOk && yMinOk && yMaxOk )
2228  return true;
2229  }
2230 
2231  // try as layer extent
2232  return QgsProcessingUtils::mapLayerFromString( input.toString(), *context );
2233 }
2234 
2235 QString QgsProcessingParameterExtent::valueAsPythonString( const QVariant &value, QgsProcessingContext &context ) const
2236 {
2237  if ( !value.isValid() )
2238  return QStringLiteral( "None" );
2239 
2240  if ( value.canConvert<QgsProperty>() )
2241  return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
2242 
2243  if ( value.canConvert< QgsRectangle >() )
2244  {
2245  QgsRectangle r = value.value<QgsRectangle>();
2246  return QStringLiteral( "'%1, %3, %2, %4'" ).arg( qgsDoubleToString( r.xMinimum() ),
2247  qgsDoubleToString( r.yMinimum() ),
2248  qgsDoubleToString( r.xMaximum() ),
2249  qgsDoubleToString( r.yMaximum() ) );
2250  }
2251  if ( value.canConvert< QgsReferencedRectangle >() )
2252  {
2254  return QStringLiteral( "'%1, %3, %2, %4 [%5]'" ).arg( qgsDoubleToString( r.xMinimum() ),
2255  qgsDoubleToString( r.yMinimum() ),
2256  qgsDoubleToString( r.xMaximum() ),
2257  qgsDoubleToString( r.yMaximum() ), r.crs().authid() );
2258  }
2259 
2260  QVariantMap p;
2261  p.insert( name(), value );
2262  QgsMapLayer *layer = QgsProcessingParameters::parameterAsLayer( this, p, context );
2263  if ( layer )
2265 
2267 }
2268 
2269 QgsProcessingParameterExtent *QgsProcessingParameterExtent::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
2270 {
2271  return new QgsProcessingParameterExtent( name, description, definition, isOptional );
2272 }
2273 
2274 QgsProcessingParameterPoint::QgsProcessingParameterPoint( const QString &name, const QString &description, const QVariant &defaultValue, bool optional )
2275  : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
2276 {
2277 
2278 }
2279 
2281 {
2282  return new QgsProcessingParameterPoint( *this );
2283 }
2284 
2286 {
2287  if ( !input.isValid() )
2288  return mFlags & FlagOptional;
2289 
2290  if ( input.canConvert<QgsProperty>() )
2291  {
2292  return true;
2293  }
2294 
2295  if ( input.canConvert< QgsPointXY >() )
2296  {
2297  return true;
2298  }
2299  if ( input.canConvert< QgsReferencedPointXY >() )
2300  {
2301  return true;
2302  }
2303  if ( input.canConvert< QgsGeometry >() )
2304  {
2305  return true;
2306  }
2307 
2308  if ( input.type() == QVariant::String )
2309  {
2310  if ( input.toString().isEmpty() )
2311  return mFlags & FlagOptional;
2312  }
2313 
2314  QRegularExpression rx( QStringLiteral( "^\\s*\\(?\\s*(.*?)\\s*,\\s*(.*?)\\s*(?:\\[(.*)\\])?\\s*\\)?\\s*$" ) );
2315 
2316  QRegularExpressionMatch match = rx.match( input.toString() );
2317  if ( match.hasMatch() )
2318  {
2319  bool xOk = false;
2320  ( void )match.captured( 1 ).toDouble( &xOk );
2321  bool yOk = false;
2322  ( void )match.captured( 2 ).toDouble( &yOk );
2323  return xOk && yOk;
2324  }
2325  else
2326  return false;
2327 }
2328 
2329 QString QgsProcessingParameterPoint::valueAsPythonString( const QVariant &value, QgsProcessingContext &context ) const
2330 {
2331  if ( !value.isValid() )
2332  return QStringLiteral( "None" );
2333 
2334  if ( value.canConvert<QgsProperty>() )
2335  return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
2336 
2337  if ( value.canConvert< QgsPointXY >() )
2338  {
2339  QgsPointXY r = value.value<QgsPointXY>();
2340  return QStringLiteral( "'%1,%2'" ).arg( qgsDoubleToString( r.x() ),
2341  qgsDoubleToString( r.y() ) );
2342  }
2343  else if ( value.canConvert< QgsReferencedPointXY >() )
2344  {
2345  QgsReferencedPointXY r = value.value<QgsReferencedPointXY>();
2346  return QStringLiteral( "'%1,%2 [%3]'" ).arg( qgsDoubleToString( r.x() ),
2347  qgsDoubleToString( r.y() ),
2348  r.crs().authid() );
2349  }
2350  else if ( value.canConvert< QgsGeometry >() )
2351  {
2352  const QgsGeometry g = value.value<QgsGeometry>();
2353  if ( !g.isNull() )
2354  {
2355  const QString wkt = g.asWkt();
2356  return QStringLiteral( "QgsGeometry.fromWkt('%1')" ).arg( wkt );
2357  }
2358  }
2359 
2361 }
2362 
2363 QgsProcessingParameterPoint *QgsProcessingParameterPoint::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
2364 {
2365  return new QgsProcessingParameterPoint( name, description, definition, isOptional );
2366 }
2367 
2368 QgsProcessingParameterFile::QgsProcessingParameterFile( const QString &name, const QString &description, Behavior behavior, const QString &extension, const QVariant &defaultValue, bool optional, const QString &fileFilter )
2369  : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
2370  , mBehavior( behavior )
2371  , mExtension( fileFilter.isEmpty() ? extension : QString() )
2372  , mFileFilter( fileFilter.isEmpty() && extension.isEmpty() ? QObject::tr( "All files (*.*)" ) : fileFilter )
2373 {
2374 
2375 }
2376 
2378 {
2379  return new QgsProcessingParameterFile( *this );
2380 }
2381 
2383 {
2384  if ( !input.isValid() )
2385  return mFlags & FlagOptional;
2386 
2387  if ( input.canConvert<QgsProperty>() )
2388  {
2389  return true;
2390  }
2391 
2392  QString string = input.toString().trimmed();
2393 
2394  if ( input.type() != QVariant::String || string.isEmpty() )
2395  return mFlags & FlagOptional;
2396 
2397  switch ( mBehavior )
2398  {
2399  case File:
2400  {
2401  if ( !mExtension.isEmpty() )
2402  {
2403  return string.endsWith( mExtension, Qt::CaseInsensitive );
2404  }
2405  else if ( !mFileFilter.isEmpty() )
2406  {
2407  const QString test = QgsFileUtils::addExtensionFromFilter( string, mFileFilter );
2408  return test == string;
2409  }
2410  else
2411  {
2412  return true;
2413  }
2414  }
2415 
2416  case Folder:
2417  return true;
2418  }
2419  return true;
2420 }
2421 
2423 {
2424  QString code = QStringLiteral( "##%1=" ).arg( mName );
2425  if ( mFlags & FlagOptional )
2426  code += QStringLiteral( "optional " );
2427  code += ( mBehavior == File ? QStringLiteral( "file" ) : QStringLiteral( "folder" ) ) + ' ';
2428  code += mDefault.toString();
2429  return code.trimmed();
2430 }
2431 
2433 {
2434  switch ( outputType )
2435  {
2437  {
2438 
2439  QString code = QStringLiteral( "QgsProcessingParameterFile('%1', '%2'" ).arg( name(), description() );
2440  if ( mFlags & FlagOptional )
2441  code += QStringLiteral( ", optional=True" );
2442  code += QStringLiteral( ", behavior=%1" ).arg( mBehavior == File ? QStringLiteral( "QgsProcessingParameterFile.File" ) : QStringLiteral( "QgsProcessingParameterFile.Folder" ) );
2443  if ( !mExtension.isEmpty() )
2444  code += QStringLiteral( ", extension='%1'" ).arg( mExtension );
2445  if ( !mFileFilter.isEmpty() )
2446  code += QStringLiteral( ", fileFilter='%1'" ).arg( mFileFilter );
2448  code += QStringLiteral( ", defaultValue=%1)" ).arg( valueAsPythonString( mDefault, c ) );
2449  return code;
2450  }
2451  }
2452  return QString();
2453 }
2454 
2456 {
2457  mExtension = extension;
2458  mFileFilter.clear();
2459 }
2460 
2462 {
2463  return mFileFilter;
2464 }
2465 
2466 void QgsProcessingParameterFile::setFileFilter( const QString &filter )
2467 {
2468  mFileFilter = filter;
2469  mExtension.clear();
2470 }
2471 
2473 {
2475  map.insert( QStringLiteral( "behavior" ), mBehavior );
2476  map.insert( QStringLiteral( "extension" ), mExtension );
2477  map.insert( QStringLiteral( "filefilter" ), mFileFilter );
2478  return map;
2479 }
2480 
2481 bool QgsProcessingParameterFile::fromVariantMap( const QVariantMap &map )
2482 {
2484  mBehavior = static_cast< Behavior >( map.value( QStringLiteral( "behavior" ) ).toInt() );
2485  mExtension = map.value( QStringLiteral( "extension" ) ).toString();
2486  mFileFilter = map.value( QStringLiteral( "filefilter" ) ).toString();
2487  return true;
2488 }
2489 
2491 {
2492  return new QgsProcessingParameterFile( name, description, behavior, QString(), definition, isOptional );
2493 }
2494 
2495 QgsProcessingParameterMatrix::QgsProcessingParameterMatrix( const QString &name, const QString &description, int numberRows, bool fixedNumberRows, const QStringList &headers, const QVariant &defaultValue, bool optional )
2496  : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
2497  , mHeaders( headers )
2498  , mNumberRows( numberRows )
2499  , mFixedNumberRows( fixedNumberRows )
2500 {
2501 
2502 }
2503 
2505 {
2506  return new QgsProcessingParameterMatrix( *this );
2507 }
2508 
2510 {
2511  if ( !input.isValid() )
2512  return mFlags & FlagOptional;
2513 
2514  if ( input.type() == QVariant::String )
2515  {
2516  if ( input.toString().isEmpty() )
2517  return mFlags & FlagOptional;
2518  return true;
2519  }
2520  else if ( input.type() == QVariant::List )
2521  {
2522  if ( input.toList().isEmpty() )
2523  return mFlags & FlagOptional;
2524  return true;
2525  }
2526  else if ( input.type() == QVariant::Double || input.type() == QVariant::Int )
2527  {
2528  return true;
2529  }
2530 
2531  return false;
2532 }
2533 
2534 QString QgsProcessingParameterMatrix::valueAsPythonString( const QVariant &value, QgsProcessingContext &context ) const
2535 {
2536  if ( !value.isValid() )
2537  return QStringLiteral( "None" );
2538 
2539  if ( value.canConvert<QgsProperty>() )
2540  return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
2541 
2542  QVariantMap p;
2543  p.insert( name(), value );
2544  QVariantList list = QgsProcessingParameters::parameterAsMatrix( this, p, context );
2545 
2546  QStringList parts;
2547  const auto constList = list;
2548  for ( const QVariant &v : constList )
2549  {
2550  if ( v.type() == QVariant::List )
2551  {
2552  QStringList parts2;
2553  const auto constToList = v.toList();
2554  for ( const QVariant &v2 : constToList )
2555  {
2556  if ( v2.isNull() || !v2.isValid() )
2557  parts2 << QStringLiteral( "None" );
2558  else if ( v2.toString().isEmpty() )
2559  parts2 << QStringLiteral( "''" );
2560  else
2561  parts2 << v2.toString();
2562  }
2563  parts << parts2.join( ',' ).prepend( '[' ).append( ']' );
2564  }
2565  else
2566  {
2567  if ( v.isNull() || !v.isValid() )
2568  parts << QStringLiteral( "None" );
2569  else if ( v.toString().isEmpty() )
2570  parts << QStringLiteral( "''" );
2571  else
2572  parts << v.toString();
2573  }
2574  }
2575 
2576  return parts.join( ',' ).prepend( '[' ).append( ']' );
2577 }
2578 
2580 {
2581  switch ( outputType )
2582  {
2584  {
2585  QString code = QStringLiteral( "QgsProcessingParameterMatrix('%1', '%2'" ).arg( name(), description() );
2586  if ( mFlags & FlagOptional )
2587  code += QStringLiteral( ", optional=True" );
2588  code += QStringLiteral( ", numberRows=" ).arg( mNumberRows );
2589  code += QStringLiteral( ", hasFixedNumberRows=" ).arg( mFixedNumberRows ? QStringLiteral( "True" ) : QStringLiteral( "False" ) );
2590 
2591  QStringList headers;
2592  headers.reserve( mHeaders.size() );
2593  for ( const QString &h : mHeaders )
2595  code += QStringLiteral( ", headers=[%1]" ).arg( headers.join( ',' ) );
2596 
2598  code += QStringLiteral( ", defaultValue=%1)" ).arg( valueAsPythonString( mDefault, c ) );
2599  return code;
2600  }
2601  }
2602  return QString();
2603 }
2604 
2606 {
2607  return mHeaders;
2608 }
2609 
2611 {
2612  mHeaders = headers;
2613 }
2614 
2616 {
2617  return mNumberRows;
2618 }
2619 
2621 {
2622  mNumberRows = numberRows;
2623 }
2624 
2626 {
2627  return mFixedNumberRows;
2628 }
2629 
2631 {
2632  mFixedNumberRows = fixedNumberRows;
2633 }
2634 
2636 {
2638  map.insert( QStringLiteral( "headers" ), mHeaders );
2639  map.insert( QStringLiteral( "rows" ), mNumberRows );
2640  map.insert( QStringLiteral( "fixed_number_rows" ), mFixedNumberRows );
2641  return map;
2642 }
2643 
2644 bool QgsProcessingParameterMatrix::fromVariantMap( const QVariantMap &map )
2645 {
2647  mHeaders = map.value( QStringLiteral( "headers" ) ).toStringList();
2648  mNumberRows = map.value( QStringLiteral( "rows" ) ).toInt();
2649  mFixedNumberRows = map.value( QStringLiteral( "fixed_number_rows" ) ).toBool();
2650  return true;
2651 }
2652 
2653 QgsProcessingParameterMatrix *QgsProcessingParameterMatrix::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
2654 {
2655  return new QgsProcessingParameterMatrix( name, description, 0, false, QStringList(), definition.isEmpty() ? QVariant() : definition, isOptional );
2656 }
2657 
2659  : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
2660  , mLayerType( layerType )
2661 {
2662 
2663 }
2664 
2666 {
2667  return new QgsProcessingParameterMultipleLayers( *this );
2668 }
2669 
2671 {
2672  if ( !input.isValid() )
2673  return mFlags & FlagOptional;
2674 
2675  if ( mLayerType != QgsProcessing::TypeFile )
2676  {
2677  if ( qobject_cast< QgsMapLayer * >( qvariant_cast<QObject *>( input ) ) )
2678  {
2679  return true;
2680  }
2681  }
2682 
2683  if ( input.type() == QVariant::String )
2684  {
2685  if ( input.toString().isEmpty() )
2686  return mFlags & FlagOptional;
2687 
2688  if ( mMinimumNumberInputs > 1 )
2689  return false;
2690 
2691  if ( !context )
2692  return true;
2693 
2694  if ( mLayerType != QgsProcessing::TypeFile )
2695  return QgsProcessingUtils::mapLayerFromString( input.toString(), *context );
2696  else
2697  return true;
2698  }
2699  else if ( input.type() == QVariant::List )
2700  {
2701  if ( input.toList().count() < mMinimumNumberInputs )
2702  return mFlags & FlagOptional;
2703 
2704  if ( mMinimumNumberInputs > input.toList().count() )
2705  return false;
2706 
2707  if ( !context )
2708  return true;
2709 
2710  if ( mLayerType != QgsProcessing::TypeFile )
2711  {
2712  const auto constToList = input.toList();
2713  for ( const QVariant &v : constToList )
2714  {
2715  if ( qobject_cast< QgsMapLayer * >( qvariant_cast<QObject *>( v ) ) )
2716  continue;
2717 
2718  if ( !QgsProcessingUtils::mapLayerFromString( v.toString(), *context ) )
2719  return false;
2720  }
2721  }
2722  return true;
2723  }
2724  else if ( input.type() == QVariant::StringList )
2725  {
2726  if ( input.toStringList().count() < mMinimumNumberInputs )
2727  return mFlags & FlagOptional;
2728 
2729  if ( mMinimumNumberInputs > input.toStringList().count() )
2730  return false;
2731 
2732  if ( !context )
2733  return true;
2734 
2735  if ( mLayerType != QgsProcessing::TypeFile )
2736  {
2737  const auto constToStringList = input.toStringList();
2738  for ( const QString &v : constToStringList )
2739  {
2740  if ( !QgsProcessingUtils::mapLayerFromString( v, *context ) )
2741  return false;
2742  }
2743  }
2744  return true;
2745  }
2746  return false;
2747 }
2748 
2750 {
2751  if ( !value.isValid() )
2752  return QStringLiteral( "None" );
2753 
2754  if ( value.canConvert<QgsProperty>() )
2755  return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
2756 
2757  if ( mLayerType == QgsProcessing::TypeFile )
2758  {
2759  QStringList parts;
2760  if ( value.type() == QVariant::StringList )
2761  {
2762  const QStringList list = value.toStringList();
2763  parts.reserve( list.count() );
2764  for ( const QString &v : list )
2766  }
2767  else if ( value.type() == QVariant::List )
2768  {
2769  const QVariantList list = value.toList();
2770  parts.reserve( list.count() );
2771  for ( const QVariant &v : list )
2772  parts << QgsProcessingUtils::stringToPythonLiteral( v.toString() );
2773  }
2774  if ( !parts.isEmpty() )
2775  return parts.join( ',' ).prepend( '[' ).append( ']' );
2776  }
2777  else
2778  {
2779  QVariantMap p;
2780  p.insert( name(), value );
2781  const QList<QgsMapLayer *> list = QgsProcessingParameters::parameterAsLayerList( this, p, context );
2782  if ( !list.isEmpty() )
2783  {
2784  QStringList parts;
2785  parts.reserve( list.count() );
2786  for ( const QgsMapLayer *layer : list )
2787  {
2789  }
2790  return parts.join( ',' ).prepend( '[' ).append( ']' );
2791  }
2792  }
2793 
2795 }
2796 
2798 {
2799  QString code = QStringLiteral( "##%1=" ).arg( mName );
2800  if ( mFlags & FlagOptional )
2801  code += QStringLiteral( "optional " );
2802  switch ( mLayerType )
2803  {
2805  code += QStringLiteral( "multiple raster" );
2806  break;
2807 
2809  code += QStringLiteral( "multiple file" );
2810  break;
2811 
2812  default:
2813  code += QStringLiteral( "multiple vector" );
2814  break;
2815  }
2816  code += ' ';
2817  if ( mDefault.type() == QVariant::List )
2818  {
2819  QStringList parts;
2820  const auto constToList = mDefault.toList();
2821  for ( const QVariant &var : constToList )
2822  {
2823  parts << var.toString();
2824  }
2825  code += parts.join( ',' );
2826  }
2827  else if ( mDefault.type() == QVariant::StringList )
2828  {
2829  code += mDefault.toStringList().join( ',' );
2830  }
2831  else
2832  {
2833  code += mDefault.toString();
2834  }
2835  return code.trimmed();
2836 }
2837 
2839 {
2840  switch ( outputType )
2841  {
2843  {
2844  QString code = QStringLiteral( "QgsProcessingParameterMultipleLayers('%1', '%2'" ).arg( name(), description() );
2845  if ( mFlags & FlagOptional )
2846  code += QStringLiteral( ", optional=True" );
2847 
2848  QString layerType = QStringLiteral( "QgsProcessing.%1" ).arg( QgsProcessing::sourceTypeToString( mLayerType ) );
2849 
2850  code += QStringLiteral( ", layerType=%1" ).arg( layerType );
2852  code += QStringLiteral( ", defaultValue=%1)" ).arg( valueAsPythonString( mDefault, c ) );
2853  return code;
2854  }
2855  }
2856  return QString();
2857 }
2858 
2860 {
2861  return mLayerType;
2862 }
2863 
2865 {
2866  mLayerType = type;
2867 }
2868 
2870 {
2871  return mMinimumNumberInputs;
2872 }
2873 
2875 {
2876  if ( mMinimumNumberInputs >= 1 || !( flags() & QgsProcessingParameterDefinition::FlagOptional ) )
2877  mMinimumNumberInputs = minimumNumberInputs;
2878 }
2879 
2881 {
2883  map.insert( QStringLiteral( "layer_type" ), mLayerType );
2884  map.insert( QStringLiteral( "min_inputs" ), mMinimumNumberInputs );
2885  return map;
2886 }
2887 
2889 {
2891  mLayerType = static_cast< QgsProcessing::SourceType >( map.value( QStringLiteral( "layer_type" ) ).toInt() );
2892  mMinimumNumberInputs = map.value( QStringLiteral( "min_inputs" ) ).toInt();
2893  return true;
2894 }
2895 
2896 QgsProcessingParameterMultipleLayers *QgsProcessingParameterMultipleLayers::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
2897 {
2898  QString type = definition;
2899  QString defaultVal;
2900  QRegularExpression re( QStringLiteral( "(.*?)\\s+(.*)" ) );
2901  QRegularExpressionMatch m = re.match( definition );
2902  if ( m.hasMatch() )
2903  {
2904  type = m.captured( 1 ).toLower().trimmed();
2905  defaultVal = m.captured( 2 );
2906  }
2908  if ( type == QStringLiteral( "vector" ) )
2910  else if ( type == QStringLiteral( "raster" ) )
2911  layerType = QgsProcessing::TypeRaster;
2912  else if ( type == QStringLiteral( "file" ) )
2913  layerType = QgsProcessing::TypeFile;
2914  return new QgsProcessingParameterMultipleLayers( name, description, layerType, defaultVal.isEmpty() ? QVariant() : defaultVal, isOptional );
2915 }
2916 
2917 QgsProcessingParameterNumber::QgsProcessingParameterNumber( const QString &name, const QString &description, Type type, const QVariant &defaultValue, bool optional, double minValue, double maxValue )
2918  : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
2919  , mMin( minValue )
2920  , mMax( maxValue )
2921  , mDataType( type )
2922 {
2923  if ( mMin >= mMax )
2924  {
2925  QgsMessageLog::logMessage( QObject::tr( "Invalid number parameter \"%1\": min value %2 is >= max value %3!" ).arg( name ).arg( mMin ).arg( mMax ), QObject::tr( "Processing" ) );
2926  }
2927 }
2928 
2930 {
2931  return new QgsProcessingParameterNumber( *this );
2932 }
2933 
2935 {
2936  QVariant input = value;
2937  if ( !input.isValid() )
2938  {
2939  if ( !defaultValue().isValid() )
2940  return mFlags & FlagOptional;
2941 
2942  input = defaultValue();
2943  }
2944 
2945  if ( input.canConvert<QgsProperty>() )
2946  {
2947  return true;
2948  }
2949 
2950  bool ok = false;
2951  double res = input.toDouble( &ok );
2952  if ( !ok )
2953  return mFlags & FlagOptional;
2954 
2955  return !( res < mMin || res > mMax );
2956 }
2957 
2959 {
2960  if ( !value.isValid() )
2961  return QStringLiteral( "None" );
2962 
2963  if ( value.canConvert<QgsProperty>() )
2964  return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
2965 
2966  return value.toString();
2967 }
2968 
2970 {
2972  QStringList parts;
2973  if ( mMin > std::numeric_limits<double>::lowest() + 1 )
2974  parts << QObject::tr( "Minimum value: %1" ).arg( mMin );
2975  if ( mMax < std::numeric_limits<double>::max() )
2976  parts << QObject::tr( "Maximum value: %1" ).arg( mMax );
2977  if ( mDefault.isValid() )
2978  parts << QObject::tr( "Default value: %1" ).arg( mDataType == Integer ? mDefault.toInt() : mDefault.toDouble() );
2979  QString extra = parts.join( QStringLiteral( "<br />" ) );
2980  if ( !extra.isEmpty() )
2981  text += QStringLiteral( "<p>%1</p>" ).arg( extra );
2982  return text;
2983 }
2984 
2986 {
2987  switch ( outputType )
2988  {
2990  {
2991  QString code = QStringLiteral( "QgsProcessingParameterNumber('%1', '%2'" ).arg( name(), description() );
2992  if ( mFlags & FlagOptional )
2993  code += QStringLiteral( ", optional=True" );
2994 
2995  code += QStringLiteral( ", type=%1" ).arg( mDataType == Integer ? QStringLiteral( "QgsProcessingParameterNumber.Integer" ) : QStringLiteral( "QgsProcessingParameterNumber.Double" ) );
2996 
2997  if ( mMin != std::numeric_limits<double>::lowest() + 1 )
2998  code += QStringLiteral( ", minValue=%1" ).arg( mMin );
2999  if ( mMax != std::numeric_limits<double>::max() )
3000  code += QStringLiteral( ", maxValue=%1" ).arg( mMax );
3002  code += QStringLiteral( ", defaultValue=%1)" ).arg( valueAsPythonString( mDefault, c ) );
3003  return code;
3004  }
3005  }
3006  return QString();
3007 }
3008 
3010 {
3011  return mMin;
3012 }
3013 
3015 {
3016  mMin = min;
3017 }
3018 
3020 {
3021  return mMax;
3022 }
3023 
3025 {
3026  mMax = max;
3027 }
3028 
3030 {
3031  return mDataType;
3032 }
3033 
3035 {
3036  mDataType = dataType;
3037 }
3038 
3040 {
3042  map.insert( QStringLiteral( "min" ), mMin );
3043  map.insert( QStringLiteral( "max" ), mMax );
3044  map.insert( QStringLiteral( "data_type" ), mDataType );
3045  return map;
3046 }
3047 
3048 bool QgsProcessingParameterNumber::fromVariantMap( const QVariantMap &map )
3049 {
3051  mMin = map.value( QStringLiteral( "min" ) ).toDouble();
3052  mMax = map.value( QStringLiteral( "max" ) ).toDouble();
3053  mDataType = static_cast< Type >( map.value( QStringLiteral( "data_type" ) ).toInt() );
3054  return true;
3055 }
3056 
3057 QgsProcessingParameterNumber *QgsProcessingParameterNumber::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
3058 {
3059  return new QgsProcessingParameterNumber( name, description, Double, definition.isEmpty() ? QVariant()
3060  : ( definition.toLower().trimmed() == QStringLiteral( "none" ) ? QVariant() : definition ), isOptional );
3061 }
3062 
3064  : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
3065  , mDataType( type )
3066 {
3067 
3068 }
3069 
3071 {
3072  return new QgsProcessingParameterRange( *this );
3073 }
3074 
3076 {
3077  if ( !input.isValid() )
3078  return mFlags & FlagOptional;
3079 
3080  if ( input.canConvert<QgsProperty>() )
3081  {
3082  return true;
3083  }
3084 
3085  if ( input.type() == QVariant::String )
3086  {
3087  QStringList list = input.toString().split( ',' );
3088  if ( list.count() != 2 )
3089  return mFlags & FlagOptional;
3090  bool ok = false;
3091  list.at( 0 ).toDouble( &ok );
3092  bool ok2 = false;
3093  list.at( 1 ).toDouble( &ok2 );
3094  if ( !ok || !ok2 )
3095  return mFlags & FlagOptional;
3096  return true;
3097  }
3098  else if ( input.type() == QVariant::List )
3099  {
3100  if ( input.toList().count() != 2 )
3101  return mFlags & FlagOptional;
3102 
3103  bool ok = false;
3104  input.toList().at( 0 ).toDouble( &ok );
3105  bool ok2 = false;
3106  input.toList().at( 1 ).toDouble( &ok2 );
3107  if ( !ok || !ok2 )
3108  return mFlags & FlagOptional;
3109  return true;
3110  }
3111 
3112  return false;
3113 }
3114 
3115 QString QgsProcessingParameterRange::valueAsPythonString( const QVariant &value, QgsProcessingContext &context ) const
3116 {
3117  if ( !value.isValid() )
3118  return QStringLiteral( "None" );
3119 
3120  if ( value.canConvert<QgsProperty>() )
3121  return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
3122 
3123  QVariantMap p;
3124  p.insert( name(), value );
3125  QList< double > parts = QgsProcessingParameters::parameterAsRange( this, p, context );
3126 
3127  QStringList stringParts;
3128  const auto constParts = parts;
3129  for ( double v : constParts )
3130  {
3131  stringParts << QString::number( v );
3132  }
3133  return stringParts.join( ',' ).prepend( '[' ).append( ']' );
3134 }
3135 
3137 {
3138  switch ( outputType )
3139  {
3141  {
3142  QString code = QStringLiteral( "QgsProcessingParameterRange('%1', '%2'" ).arg( name(), description() );
3143  if ( mFlags & FlagOptional )
3144  code += QStringLiteral( ", optional=True" );
3145 
3146  code += QStringLiteral( ", type=%1" ).arg( mDataType == QgsProcessingParameterNumber::Integer ? QStringLiteral( "QgsProcessingParameterNumber.Integer" ) : QStringLiteral( "QgsProcessingParameterNumber.Double" ) );
3147 
3149  code += QStringLiteral( ", defaultValue=%1)" ).arg( valueAsPythonString( mDefault, c ) );
3150  return code;
3151  }
3152  }
3153  return QString();
3154 }
3155 
3157 {
3158  return mDataType;
3159 }
3160 
3162 {
3163  mDataType = dataType;
3164 }
3165 
3167 {
3169  map.insert( QStringLiteral( "data_type" ), mDataType );
3170  return map;
3171 }
3172 
3173 bool QgsProcessingParameterRange::fromVariantMap( const QVariantMap &map )
3174 {
3176  mDataType = static_cast< QgsProcessingParameterNumber::Type >( map.value( QStringLiteral( "data_type" ) ).toInt() );
3177  return true;
3178 }
3179 
3180 QgsProcessingParameterRange *QgsProcessingParameterRange::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
3181 {
3182  return new QgsProcessingParameterRange( name, description, QgsProcessingParameterNumber::Double, definition.isEmpty() ? QVariant() : definition, isOptional );
3183 }
3184 
3185 QgsProcessingParameterRasterLayer::QgsProcessingParameterRasterLayer( const QString &name, const QString &description, const QVariant &defaultValue, bool optional )
3186  : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
3187 {
3188 
3189 }
3190 
3192 {
3193  return new QgsProcessingParameterRasterLayer( *this );
3194 }
3195 
3197 {
3198  if ( !input.isValid() )
3199  return mFlags & FlagOptional;
3200 
3201  if ( input.canConvert<QgsProperty>() )
3202  {
3203  return true;
3204  }
3205 
3206  if ( qobject_cast< QgsRasterLayer * >( qvariant_cast<QObject *>( input ) ) )
3207  return true;
3208 
3209  if ( input.type() != QVariant::String || input.toString().isEmpty() )
3210  return mFlags & FlagOptional;
3211 
3212  if ( !context )
3213  {
3214  // that's as far as we can get without a context
3215  return true;
3216  }
3217 
3218  // try to load as layer
3219  if ( QgsProcessingUtils::mapLayerFromString( input.toString(), *context, true, QgsProcessingUtils::LayerHint::Raster ) )
3220  return true;
3221 
3222  return false;
3223 }
3224 
3226 {
3227  if ( !val.isValid() )
3228  return QStringLiteral( "None" );
3229 
3230  if ( val.canConvert<QgsProperty>() )
3231  return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( val.value< QgsProperty >().asExpression() );
3232 
3233  QVariantMap p;
3234  p.insert( name(), val );
3237  : QgsProcessingUtils::stringToPythonLiteral( val.toString() );
3238 }
3239 
3240 QgsProcessingParameterRasterLayer *QgsProcessingParameterRasterLayer::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
3241 {
3242  return new QgsProcessingParameterRasterLayer( name, description, definition.isEmpty() ? QVariant() : definition, isOptional );
3243 }
3244 
3245 QgsProcessingParameterEnum::QgsProcessingParameterEnum( const QString &name, const QString &description, const QStringList &options, bool allowMultiple, const QVariant &defaultValue, bool optional )
3246  : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
3247  , mOptions( options )
3248  , mAllowMultiple( allowMultiple )
3249 {
3250 
3251 }
3252 
3254 {
3255  return new QgsProcessingParameterEnum( *this );
3256 }
3257 
3259 {
3260  QVariant input = value;
3261  if ( !input.isValid() )
3262  {
3263  if ( !defaultValue().isValid() )
3264  return mFlags & FlagOptional;
3265 
3266  input = defaultValue();
3267  }
3268 
3269  if ( input.canConvert<QgsProperty>() )
3270  {
3271  return true;
3272  }
3273 
3274  if ( input.type() == QVariant::List )
3275  {
3276  if ( !mAllowMultiple )
3277  return false;
3278 
3279  const QVariantList values = input.toList();
3280  if ( values.empty() && !( mFlags & FlagOptional ) )
3281  return false;
3282 
3283  for ( const QVariant &val : values )
3284  {
3285  bool ok = false;
3286  int res = val.toInt( &ok );
3287  if ( !ok )
3288  return false;
3289  else if ( res < 0 || res >= mOptions.count() )
3290  return false;
3291  }
3292 
3293  return true;
3294  }
3295  else if ( input.type() == QVariant::String )
3296  {
3297  QStringList parts = input.toString().split( ',' );
3298  if ( parts.count() > 1 && !mAllowMultiple )
3299  return false;
3300 
3301  const auto constParts = parts;
3302  for ( const QString &part : constParts )
3303  {
3304  bool ok = false;
3305  int res = part.toInt( &ok );
3306  if ( !ok )
3307  return false;
3308  else if ( res < 0 || res >= mOptions.count() )
3309  return false;
3310  }
3311  return true;
3312  }
3313  else if ( input.type() == QVariant::Int || input.type() == QVariant::Double )
3314  {
3315  bool ok = false;
3316  int res = input.toInt( &ok );
3317  if ( !ok )
3318  return false;
3319  else if ( res >= 0 && res < mOptions.count() )
3320  return true;
3321  }
3322  return false;
3323 }
3324 
3326 {
3327  if ( !value.isValid() )
3328  return QStringLiteral( "None" );
3329 
3330  if ( value.canConvert<QgsProperty>() )
3331  return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
3332 
3333  if ( value.type() == QVariant::List )
3334  {
3335  QStringList parts;
3336  const auto constToList = value.toList();
3337  for ( const QVariant &val : constToList )
3338  {
3339  parts << QString::number( static_cast< int >( val.toDouble() ) );
3340  }
3341  return parts.join( ',' ).prepend( '[' ).append( ']' );
3342  }
3343  else if ( value.type() == QVariant::String )
3344  {
3345  QStringList parts = value.toString().split( ',' );
3346  if ( parts.count() > 1 )
3347  {
3348  return parts.join( ',' ).prepend( '[' ).append( ']' );
3349  }
3350  }
3351 
3352  return QString::number( static_cast< int >( value.toDouble() ) );
3353 }
3354 
3356 {
3357  QString code = QStringLiteral( "##%1=" ).arg( mName );
3358  if ( mFlags & FlagOptional )
3359  code += QStringLiteral( "optional " );
3360  code += QStringLiteral( "enum " );
3361 
3362  if ( mAllowMultiple )
3363  code += QStringLiteral( "multiple " );
3364 
3365  code += mOptions.join( ';' ) + ' ';
3366 
3367  code += mDefault.toString();
3368  return code.trimmed();
3369 }
3370 
3372 {
3373  switch ( outputType )
3374  {
3376  {
3377  QString code = QStringLiteral( "QgsProcessingParameterEnum('%1', '%2'" ).arg( name(), description() );
3378  if ( mFlags & FlagOptional )
3379  code += QStringLiteral( ", optional=True" );
3380 
3381  QStringList options;
3382  options.reserve( mOptions.size() );
3383  for ( const QString &o : mOptions )
3385  code += QStringLiteral( ", options=[%1]" ).arg( options.join( ',' ) );
3386 
3387  code += QStringLiteral( ", allowMultiple=%1" ).arg( mAllowMultiple ? QStringLiteral( "True" ) : QStringLiteral( "False" ) );
3388 
3390  code += QStringLiteral( ", defaultValue=%1)" ).arg( valueAsPythonString( mDefault, c ) );
3391  return code;
3392  }
3393  }
3394  return QString();
3395 }
3396 
3398 {
3399  return mOptions;
3400 }
3401 
3403 {
3404  mOptions = options;
3405 }
3406 
3408 {
3409  return mAllowMultiple;
3410 }
3411 
3413 {
3414  mAllowMultiple = allowMultiple;
3415 }
3416 
3418 {
3420  map.insert( QStringLiteral( "options" ), mOptions );
3421  map.insert( QStringLiteral( "allow_multiple" ), mAllowMultiple );
3422  return map;
3423 }
3424 
3425 bool QgsProcessingParameterEnum::fromVariantMap( const QVariantMap &map )
3426 {
3428  mOptions = map.value( QStringLiteral( "options" ) ).toStringList();
3429  mAllowMultiple = map.value( QStringLiteral( "allow_multiple" ) ).toBool();
3430  return true;
3431 }
3432 
3433 QgsProcessingParameterEnum *QgsProcessingParameterEnum::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
3434 {
3435  QString defaultVal;
3436  bool multiple = false;
3437  QString def = definition;
3438  if ( def.startsWith( QLatin1String( "multiple" ), Qt::CaseInsensitive ) )
3439  {
3440  multiple = true;
3441  def = def.mid( 9 );
3442  }
3443 
3444  QRegularExpression re( QStringLiteral( "(.*)\\s+(.*?)$" ) );
3445  QRegularExpressionMatch m = re.match( def );
3446  QString values = def;
3447  if ( m.hasMatch() )
3448  {
3449  values = m.captured( 1 ).trimmed();
3450  defaultVal = m.captured( 2 );
3451  }
3452 
3453  return new QgsProcessingParameterEnum( name, description, values.split( ';' ), multiple, defaultVal.isEmpty() ? QVariant() : defaultVal, isOptional );
3454 }
3455 
3456 QgsProcessingParameterString::QgsProcessingParameterString( const QString &name, const QString &description, const QVariant &defaultValue, bool multiLine, bool optional )
3457  : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
3458  , mMultiLine( multiLine )
3459 {
3460 
3461 }
3462 
3464 {
3465  return new QgsProcessingParameterString( *this );
3466 }
3467 
3469 {
3470  if ( !value.isValid() || value.isNull() )
3471  return QStringLiteral( "None" );
3472 
3473  if ( value.canConvert<QgsProperty>() )
3474  return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
3475 
3476  QString s = value.toString();
3478 }
3479 
3481 {
3482  QString code = QStringLiteral( "##%1=" ).arg( mName );
3483  if ( mFlags & FlagOptional )
3484  code += QStringLiteral( "optional " );
3485  code += QStringLiteral( "string " );
3486 
3487  if ( mMultiLine )
3488  code += QStringLiteral( "long " );
3489 
3490  code += mDefault.toString();
3491  return code.trimmed();
3492 }
3493 
3495 {
3496  switch ( outputType )
3497  {
3499  {
3500  QString code = QStringLiteral( "QgsProcessingParameterString('%1', '%2'" ).arg( name(), description() );
3501  if ( mFlags & FlagOptional )
3502  code += QStringLiteral( ", optional=True" );
3503  code += QStringLiteral( ", multiLine=%1" ).arg( mMultiLine ? QStringLiteral( "True" ) : QStringLiteral( "False" ) );
3504 
3506  code += QStringLiteral( ", defaultValue=%1)" ).arg( valueAsPythonString( mDefault, c ) );
3507  return code;
3508  }
3509  }
3510  return QString();
3511 }
3512 
3514 {
3515  return mMultiLine;
3516 }
3517 
3519 {
3520  mMultiLine = multiLine;
3521 }
3522 
3524 {
3526  map.insert( QStringLiteral( "multiline" ), mMultiLine );
3527  return map;
3528 }
3529 
3530 bool QgsProcessingParameterString::fromVariantMap( const QVariantMap &map )
3531 {
3533  mMultiLine = map.value( QStringLiteral( "multiline" ) ).toBool();
3534  return true;
3535 }
3536 
3537 QgsProcessingParameterString *QgsProcessingParameterString::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
3538 {
3539  QString def = definition;
3540  bool multiLine = false;
3541  if ( def.startsWith( QLatin1String( "long" ), Qt::CaseInsensitive ) )
3542  {
3543  multiLine = true;
3544  def = def.mid( 5 );
3545  }
3546 
3547  if ( def.startsWith( '"' ) || def.startsWith( '\'' ) )
3548  def = def.mid( 1 );
3549  if ( def.endsWith( '"' ) || def.endsWith( '\'' ) )
3550  def.chop( 1 );
3551 
3552  QVariant defaultValue = def;
3553  if ( def == QStringLiteral( "None" ) )
3554  defaultValue = QVariant();
3555 
3556  return new QgsProcessingParameterString( name, description, defaultValue, multiLine, isOptional );
3557 }
3558 
3559 //
3560 // QgsProcessingParameterAuthConfig
3561 //
3562 
3563 QgsProcessingParameterAuthConfig::QgsProcessingParameterAuthConfig( const QString &name, const QString &description, const QVariant &defaultValue, bool optional )
3564  : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
3565 {
3566 
3567 }
3568 
3570 {
3571  return new QgsProcessingParameterAuthConfig( *this );
3572 }
3573 
3575 {
3576  if ( !value.isValid() )
3577  return QStringLiteral( "None" );
3578 
3579  QString s = value.toString();
3581 }
3582 
3584 {
3585  QString code = QStringLiteral( "##%1=" ).arg( mName );
3586  if ( mFlags & FlagOptional )
3587  code += QStringLiteral( "optional " );
3588  code += QStringLiteral( "authcfg " );
3589 
3590  code += mDefault.toString();
3591  return code.trimmed();
3592 }
3593 
3594 QgsProcessingParameterAuthConfig *QgsProcessingParameterAuthConfig::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
3595 {
3596  QString def = definition;
3597 
3598  if ( def.startsWith( '"' ) || def.startsWith( '\'' ) )
3599  def = def.mid( 1 );
3600  if ( def.endsWith( '"' ) || def.endsWith( '\'' ) )
3601  def.chop( 1 );
3602 
3603  QVariant defaultValue = def;
3604  if ( def == QStringLiteral( "None" ) )
3605  defaultValue = QVariant();
3606 
3607  return new QgsProcessingParameterAuthConfig( name, description, defaultValue, isOptional );
3608 }
3609 
3610 
3611 //
3612 // QgsProcessingParameterExpression
3613 //
3614 
3615 QgsProcessingParameterExpression::QgsProcessingParameterExpression( const QString &name, const QString &description, const QVariant &defaultValue, const QString &parentLayerParameterName, bool optional )
3616  : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
3617  , mParentLayerParameterName( parentLayerParameterName )
3618 {
3619 
3620 }
3621 
3623 {
3624  return new QgsProcessingParameterExpression( *this );
3625 }
3626 
3628 {
3629  if ( !value.isValid() )
3630  return QStringLiteral( "None" );
3631 
3632  if ( value.canConvert<QgsProperty>() )
3633  return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
3634 
3635  QString s = value.toString();
3637 }
3638 
3640 {
3641  QStringList depends;
3642  if ( !mParentLayerParameterName.isEmpty() )
3643  depends << mParentLayerParameterName;
3644  return depends;
3645 }
3646 
3648 {
3649  switch ( outputType )
3650  {
3652  {
3653  QString code = QStringLiteral( "QgsProcessingParameterExpression('%1', '%2'" ).arg( name(), description() );
3654  if ( mFlags & FlagOptional )
3655  code += QStringLiteral( ", optional=True" );
3656 
3657  code += QStringLiteral( ", parentLayerParameterName='%1'" ).arg( mParentLayerParameterName );
3658 
3660  code += QStringLiteral( ", defaultValue=%1)" ).arg( valueAsPythonString( mDefault, c ) );
3661  return code;
3662  }
3663  }
3664  return QString();
3665 }
3666 
3668 {
3669  return mParentLayerParameterName;
3670 }
3671 
3673 {
3674  mParentLayerParameterName = parentLayerParameterName;
3675 }
3676 
3678 {
3680  map.insert( QStringLiteral( "parent_layer" ), mParentLayerParameterName );
3681  return map;
3682 }
3683 
3685 {
3687  mParentLayerParameterName = map.value( QStringLiteral( "parent_layer" ) ).toString();
3688  return true;
3689 }
3690 
3691 QgsProcessingParameterExpression *QgsProcessingParameterExpression::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
3692 {
3693  return new QgsProcessingParameterExpression( name, description, definition, QString(), isOptional );
3694 }
3695 
3696 QgsProcessingParameterVectorLayer::QgsProcessingParameterVectorLayer( const QString &name, const QString &description, const QList<int> &types, const QVariant &defaultValue, bool optional )
3697  : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
3699 {
3700 
3701 }
3702 
3704 {
3705  return new QgsProcessingParameterVectorLayer( *this );
3706 }
3707 
3709 {
3710  if ( !v.isValid() )
3711  return mFlags & FlagOptional;
3712 
3713  QVariant var = v;
3714 
3715  if ( var.canConvert<QgsProperty>() )
3716  {
3717  QgsProperty p = var.value< QgsProperty >();
3719  {
3720  var = p.staticValue();
3721  }
3722  else
3723  {
3724  return true;
3725  }
3726  }
3727 
3728  if ( qobject_cast< QgsVectorLayer * >( qvariant_cast<QObject *>( var ) ) )
3729  return true;
3730 
3731  if ( var.type() != QVariant::String || var.toString().isEmpty() )
3732  return mFlags & FlagOptional;
3733 
3734  if ( !context )
3735  {
3736  // that's as far as we can get without a context
3737  return true;
3738  }
3739 
3740  // try to load as layer
3741  if ( QgsProcessingUtils::mapLayerFromString( var.toString(), *context, true, QgsProcessingUtils::LayerHint::Vector ) )
3742  return true;
3743 
3744  return false;
3745 }
3746 
3748 {
3749  if ( !val.isValid() )
3750  return QStringLiteral( "None" );
3751 
3752  if ( val.canConvert<QgsProperty>() )
3753  return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( val.value< QgsProperty >().asExpression() );
3754 
3755  QVariantMap p;
3756  p.insert( name(), val );
3759  : QgsProcessingUtils::stringToPythonLiteral( val.toString() );
3760 }
3761 
3763 {
3764  switch ( outputType )
3765  {
3767  {
3768  QString code = QStringLiteral( "QgsProcessingParameterVectorLayer('%1', '%2'" ).arg( name(), description() );
3769  if ( mFlags & FlagOptional )
3770  code += QStringLiteral( ", optional=True" );
3771 
3772  if ( !mDataTypes.empty() )
3773  {
3774  QStringList options;
3775  for ( int t : mDataTypes )
3776  options << QStringLiteral( "QgsProcessing.%1" ).arg( QgsProcessing::sourceTypeToString( static_cast< QgsProcessing::SourceType >( t ) ) );
3777  code += QStringLiteral( ", types=[%1]" ).arg( options.join( ',' ) );
3778  }
3779 
3781  code += QStringLiteral( ", defaultValue=%1)" ).arg( valueAsPythonString( mDefault, c ) );
3782  return code;
3783  }
3784  }
3785  return QString();
3786 }
3787 
3789 {
3790  return mDataTypes;
3791 }
3792 
3794 {
3795  mDataTypes = types;
3796 }
3797 
3799 {
3801  QVariantList types;
3802  const auto constMDataTypes = mDataTypes;
3803  for ( int type : constMDataTypes )
3804  {
3805  types << type;
3806  }
3807  map.insert( QStringLiteral( "data_types" ), types );
3808  return map;
3809 }
3810 
3812 {
3814  mDataTypes.clear();
3815  QVariantList values = map.value( QStringLiteral( "data_types" ) ).toList();
3816  const auto constValues = values;
3817  for ( const QVariant &val : constValues )
3818  {
3819  mDataTypes << val.toInt();
3820  }
3821  return true;
3822 }
3823 
3824 QgsProcessingParameterVectorLayer *QgsProcessingParameterVectorLayer::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
3825 {
3826  return new QgsProcessingParameterVectorLayer( name, description, QList< int>(), definition.isEmpty() ? QVariant() : definition, isOptional );
3827 }
3828 
3830  const QString &description,
3831  const QVariant &defaultValue,
3832  bool optional )
3833  : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
3834 {
3835 
3836 }
3837 
3839 {
3840  return new QgsProcessingParameterMeshLayer( *this );
3841 }
3842 
3844 {
3845  if ( !v.isValid() )
3846  return mFlags & FlagOptional;
3847 
3848  QVariant var = v;
3849 
3850  if ( var.canConvert<QgsProperty>() )
3851  {
3852  QgsProperty p = var.value< QgsProperty >();
3854  {
3855  var = p.staticValue();
3856  }
3857  else
3858  {
3859  return true;
3860  }
3861  }
3862 
3863  if ( qobject_cast< QgsMeshLayer * >( qvariant_cast<QObject *>( var ) ) )
3864  return true;
3865 
3866  if ( var.type() != QVariant::String || var.toString().isEmpty() )
3867  return mFlags & FlagOptional;
3868 
3869  if ( !context )
3870  {
3871  // that's as far as we can get without a context
3872  return true;
3873  }
3874 
3875  // try to load as layer
3876  if ( QgsProcessingUtils::mapLayerFromString( var.toString(), *context, true, QgsProcessingUtils::LayerHint::Mesh ) )
3877  return true;
3878 
3879  return false;
3880 }
3881 
3883 {
3884  if ( !val.isValid() )
3885  return QStringLiteral( "None" );
3886 
3887  if ( val.canConvert<QgsProperty>() )
3888  return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( val.value< QgsProperty >().asExpression() );
3889 
3890  QVariantMap p;
3891  p.insert( name(), val );
3892  QgsMeshLayer *layer = QgsProcessingParameters::parameterAsMeshLayer( this, p, context );
3894  : QgsProcessingUtils::stringToPythonLiteral( val.toString() );
3895 }
3896 
3897 QgsProcessingParameterMeshLayer *QgsProcessingParameterMeshLayer::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
3898 {
3899  return new QgsProcessingParameterMeshLayer( name, description, definition.isEmpty() ? QVariant() : definition, isOptional );
3900 }
3901 
3902 QgsProcessingParameterField::QgsProcessingParameterField( const QString &name, const QString &description, const QVariant &defaultValue, const QString &parentLayerParameterName, DataType type, bool allowMultiple, bool optional )
3903  : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
3904  , mParentLayerParameterName( parentLayerParameterName )
3905  , mDataType( type )
3906  , mAllowMultiple( allowMultiple )
3907 {
3908 
3909 }
3910 
3911 
3913 {
3914  return new QgsProcessingParameterField( *this );
3915 }
3916 
3918 {
3919  if ( !input.isValid() )
3920  return mFlags & FlagOptional;
3921 
3922  if ( input.canConvert<QgsProperty>() )
3923  {
3924  return true;
3925  }
3926 
3927  if ( input.type() == QVariant::List || input.type() == QVariant::StringList )
3928  {
3929  if ( !mAllowMultiple )
3930  return false;
3931 
3932  if ( input.toList().isEmpty() && !( mFlags & FlagOptional ) )
3933  return false;
3934  }
3935  else if ( input.type() == QVariant::String )
3936  {
3937  if ( input.toString().isEmpty() )
3938  return mFlags & FlagOptional;
3939 
3940  QStringList parts = input.toString().split( ';' );
3941  if ( parts.count() > 1 && !mAllowMultiple )
3942  return false;
3943  }
3944  else
3945  {
3946  if ( input.toString().isEmpty() )
3947  return mFlags & FlagOptional;
3948  }
3949  return true;
3950 }
3951 
3953 {
3954  if ( !value.isValid() )
3955  return QStringLiteral( "None" );
3956 
3957  if ( value.canConvert<QgsProperty>() )
3958  return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
3959 
3960  if ( value.type() == QVariant::List )
3961  {
3962  QStringList parts;
3963  const auto constToList = value.toList();
3964  for ( const QVariant &val : constToList )
3965  {
3966  parts << QgsProcessingUtils::stringToPythonLiteral( val.toString() );
3967  }
3968  return parts.join( ',' ).prepend( '[' ).append( ']' );
3969  }
3970  else if ( value.type() == QVariant::StringList )
3971  {
3972  QStringList parts;
3973  const auto constToStringList = value.toStringList();
3974  for ( QString s : constToStringList )
3975  {
3977  }
3978  return parts.join( ',' ).prepend( '[' ).append( ']' );
3979  }
3980 
3981  return QgsProcessingUtils::stringToPythonLiteral( value.toString() );
3982 }
3983 
3985 {
3986  QString code = QStringLiteral( "##%1=" ).arg( mName );
3987  if ( mFlags & FlagOptional )
3988  code += QStringLiteral( "optional " );
3989  code += QStringLiteral( "field " );
3990 
3991  switch ( mDataType )
3992  {
3993  case Numeric:
3994  code += QStringLiteral( "numeric " );
3995  break;
3996 
3997  case String:
3998  code += QStringLiteral( "string " );
3999  break;
4000 
4001  case DateTime:
4002  code += QStringLiteral( "datetime " );
4003  break;
4004 
4005  case Any:
4006  break;
4007  }
4008 
4009  if ( mAllowMultiple )
4010  code += QStringLiteral( "multiple " );
4011 
4012  code += mParentLayerParameterName + ' ';
4013 
4014  code += mDefault.toString();
4015  return code.trimmed();
4016 }
4017 
4019 {
4020  switch ( outputType )
4021  {
4023  {
4024  QString code = QStringLiteral( "QgsProcessingParameterField('%1', '%2'" ).arg( name(), description() );
4025  if ( mFlags & FlagOptional )
4026  code += QStringLiteral( ", optional=True" );
4027 
4028  QString dataType;
4029  switch ( mDataType )
4030  {
4031  case Any:
4032  dataType = QStringLiteral( "QgsProcessingParameterField.Any" );
4033  break;
4034 
4035  case Numeric:
4036  dataType = QStringLiteral( "QgsProcessingParameterField.Numeric" );
4037  break;
4038 
4039  case String:
4040  dataType = QStringLiteral( "QgsProcessingParameterField.String" );
4041  break;
4042 
4043  case DateTime:
4044  dataType = QStringLiteral( "QgsProcessingParameterField.DateTime" );
4045  break;
4046  }
4047  code += QStringLiteral( ", type=%1" ).arg( dataType );
4048 
4049  code += QStringLiteral( ", parentLayerParameterName='%1'" ).arg( mParentLayerParameterName );
4050  code += QStringLiteral( ", allowMultiple=%1" ).arg( mAllowMultiple ? QStringLiteral( "True" ) : QStringLiteral( "False" ) );
4051 
4053  code += QStringLiteral( ", defaultValue=%1)" ).arg( valueAsPythonString( mDefault, c ) );
4054  return code;
4055  }
4056  }
4057  return QString();
4058 }
4059 
4061 {
4062  QStringList depends;
4063  if ( !mParentLayerParameterName.isEmpty() )
4064  depends << mParentLayerParameterName;
4065  return depends;
4066 }
4067 
4069 {
4070  return mParentLayerParameterName;
4071 }
4072 
4074 {
4075  mParentLayerParameterName = parentLayerParameterName;
4076 }
4077 
4079 {
4080  return mDataType;
4081 }
4082 
4084 {
4085  mDataType = dataType;
4086 }
4087 
4089 {
4090  return mAllowMultiple;
4091 }
4092 
4094 {
4095  mAllowMultiple = allowMultiple;
4096 }
4097 
4099 {
4101  map.insert( QStringLiteral( "parent_layer" ), mParentLayerParameterName );
4102  map.insert( QStringLiteral( "data_type" ), mDataType );
4103  map.insert( QStringLiteral( "allow_multiple" ), mAllowMultiple );
4104  return map;
4105 }
4106 
4107 bool QgsProcessingParameterField::fromVariantMap( const QVariantMap &map )
4108 {
4110  mParentLayerParameterName = map.value( QStringLiteral( "parent_layer" ) ).toString();
4111  mDataType = static_cast< DataType >( map.value( QStringLiteral( "data_type" ) ).toInt() );
4112  mAllowMultiple = map.value( QStringLiteral( "allow_multiple" ) ).toBool();
4113  return true;
4114 }
4115 
4116 QgsProcessingParameterField *QgsProcessingParameterField::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
4117 {
4118  QString parent;
4119  DataType type = Any;
4120  bool allowMultiple = false;
4121  QString def = definition;
4122 
4123  if ( def.startsWith( QLatin1String( "numeric " ), Qt::CaseInsensitive ) )
4124  {
4125  type = Numeric;
4126  def = def.mid( 8 );
4127  }
4128  else if ( def.startsWith( QLatin1String( "string " ), Qt::CaseInsensitive ) )
4129  {
4130  type = String;
4131  def = def.mid( 7 );
4132  }
4133  else if ( def.startsWith( QLatin1String( "datetime " ), Qt::CaseInsensitive ) )
4134  {
4135  type = DateTime;
4136  def = def.mid( 9 );
4137  }
4138 
4139  if ( def.startsWith( QLatin1String( "multiple" ), Qt::CaseInsensitive ) )
4140  {
4141  allowMultiple = true;
4142  def = def.mid( 8 ).trimmed();
4143  }
4144 
4145  QRegularExpression re( QStringLiteral( "(.*?)\\s+(.*)$" ) );
4146  QRegularExpressionMatch m = re.match( def );
4147  if ( m.hasMatch() )
4148  {
4149  parent = m.captured( 1 ).trimmed();
4150  def = m.captured( 2 );
4151  }
4152  else
4153  {
4154  parent = def;
4155  def.clear();
4156  }
4157 
4158  return new QgsProcessingParameterField( name, description, def.isEmpty() ? QVariant() : def, parent, type, allowMultiple, isOptional );
4159 }
4160 
4161 QgsProcessingParameterFeatureSource::QgsProcessingParameterFeatureSource( const QString &name, const QString &description, const QList<int> &types, const QVariant &defaultValue, bool optional )
4162  : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
4164 {
4165 
4166 }
4167 
4169 {
4170  return new QgsProcessingParameterFeatureSource( *this );
4171 }
4172 
4174 {
4175  QVariant var = input;
4176  if ( !var.isValid() )
4177  return mFlags & FlagOptional;
4178 
4179  if ( var.canConvert<QgsProcessingFeatureSourceDefinition>() )
4180  {
4182  var = fromVar.source;
4183  }
4184  else if ( var.canConvert<QgsProcessingOutputLayerDefinition>() )
4185  {
4186  // input is a QgsProcessingOutputLayerDefinition - get extra properties from it
4188  var = fromVar.sink;
4189  }
4190 
4191  if ( var.canConvert<QgsProperty>() )
4192  {
4193  QgsProperty p = var.value< QgsProperty >();
4195  {
4196  var = p.staticValue();
4197  }
4198  else
4199  {
4200  return true;
4201  }
4202  }
4203  if ( qobject_cast< QgsVectorLayer * >( qvariant_cast<QObject *>( input ) ) )
4204  {
4205  return true;
4206  }
4207 
4208  if ( var.type() != QVariant::String || var.toString().isEmpty() )
4209  return mFlags & FlagOptional;
4210 
4211  if ( !context )
4212  {
4213  // that's as far as we can get without a context
4214  return true;
4215  }
4216 
4217  // try to load as layer
4218  if ( QgsProcessingUtils::mapLayerFromString( var.toString(), *context, true, QgsProcessingUtils::LayerHint::Vector ) )
4219  return true;
4220 
4221  return false;
4222 }
4223 
4225 {
4226  if ( !value.isValid() )
4227  return QStringLiteral( "None" );
4228 
4229  if ( value.canConvert<QgsProperty>() )
4230  return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
4231 
4232  if ( value.canConvert<QgsProcessingFeatureSourceDefinition>() )
4233  {
4235  if ( fromVar.source.propertyType() == QgsProperty::StaticProperty )
4236  {
4237  if ( fromVar.selectedFeaturesOnly )
4238  {
4239  return QStringLiteral( "QgsProcessingFeatureSourceDefinition('%1', True)" ).arg( fromVar.source.staticValue().toString() );
4240  }
4241  else
4242  {
4243  QString layerString = fromVar.source.staticValue().toString();
4244  // prefer to use layer source instead of id if possible (since it's persistent)
4245  if ( QgsVectorLayer *layer = qobject_cast< QgsVectorLayer * >( QgsProcessingUtils::mapLayerFromString( layerString, context, true, QgsProcessingUtils::LayerHint::Vector ) ) )
4246  layerString = layer->source();
4247  return QgsProcessingUtils::stringToPythonLiteral( layerString );
4248  }
4249  }
4250  else
4251  {
4252  if ( fromVar.selectedFeaturesOnly )
4253  {
4254  return QStringLiteral( "QgsProcessingFeatureSourceDefinition(QgsProperty.fromExpression('%1'), True)" ).arg( fromVar.source.asExpression() );
4255  }
4256  else
4257  {
4258  return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( fromVar.source.asExpression() );
4259  }
4260  }
4261  }
4262  else if ( QgsVectorLayer *layer = qobject_cast< QgsVectorLayer * >( qvariant_cast<QObject *>( value ) ) )
4263  {
4264  return QgsProcessingUtils::stringToPythonLiteral( layer->source() );
4265  }
4266 
4267  QString layerString = value.toString();
4268 
4269  // prefer to use layer source if possible (since it's persistent)
4270  if ( QgsVectorLayer *layer = qobject_cast< QgsVectorLayer * >( QgsProcessingUtils::mapLayerFromString( layerString, context, true, QgsProcessingUtils::LayerHint::Vector ) ) )
4271  layerString = layer->source();
4272 
4273  return QgsProcessingUtils::stringToPythonLiteral( layerString );
4274 }
4275 
4277 {
4278  QString code = QStringLiteral( "##%1=" ).arg( mName );
4279  if ( mFlags & FlagOptional )
4280  code += QStringLiteral( "optional " );
4281  code += QStringLiteral( "source " );
4282 
4283  const auto constMDataTypes = mDataTypes;
4284  for ( int type : constMDataTypes )
4285  {
4286  switch ( type )
4287  {
4289  code += QStringLiteral( "point " );
4290  break;
4291 
4293  code += QStringLiteral( "line " );
4294  break;
4295 
4297  code += QStringLiteral( "polygon " );
4298  break;
4299 
4300  }
4301  }
4302 
4303  code += mDefault.toString();
4304  return code.trimmed();
4305 }
4306 
4308 {
4309  switch ( outputType )
4310  {
4312  {
4313  QString code = QStringLiteral( "QgsProcessingParameterFeatureSource('%1', '%2'" ).arg( name(), description() );
4314  if ( mFlags & FlagOptional )
4315  code += QStringLiteral( ", optional=True" );
4316 
4317  if ( !mDataTypes.empty() )
4318  {
4319  QStringList options;
4320  options.reserve( mDataTypes.size() );
4321  for ( int t : mDataTypes )
4322  options << QStringLiteral( "QgsProcessing.%1" ).arg( QgsProcessing::sourceTypeToString( static_cast< QgsProcessing::SourceType >( t ) ) );
4323  code += QStringLiteral( ", types=[%1]" ).arg( options.join( ',' ) );
4324  }
4325 
4327  code += QStringLiteral( ", defaultValue=%1)" ).arg( valueAsPythonString( mDefault, c ) );
4328  return code;
4329  }
4330  }
4331  return QString();
4332 }
4333 
4335  : mDataTypes( types )
4336 {
4337 
4338 }
4339 
4341 {
4343  QVariantList types;
4344  const auto constMDataTypes = mDataTypes;
4345  for ( int type : constMDataTypes )
4346  {
4347  types << type;
4348  }
4349  map.insert( QStringLiteral( "data_types" ), types );
4350  return map;
4351 }
4352 
4354 {
4356  mDataTypes.clear();
4357  QVariantList values = map.value( QStringLiteral( "data_types" ) ).toList();
4358  const auto constValues = values;
4359  for ( const QVariant &val : constValues )
4360  {
4361  mDataTypes << val.toInt();
4362  }
4363  return true;
4364 }
4365 
4366 QgsProcessingParameterFeatureSource *QgsProcessingParameterFeatureSource::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
4367 {
4368  QList< int > types;
4369  QString def = definition;
4370  while ( true )
4371  {
4372  if ( def.startsWith( QLatin1String( "point" ), Qt::CaseInsensitive ) )
4373  {
4375  def = def.mid( 6 );
4376  continue;
4377  }
4378  else if ( def.startsWith( QLatin1String( "line" ), Qt::CaseInsensitive ) )
4379  {
4381  def = def.mid( 5 );
4382  continue;
4383  }
4384  else if ( def.startsWith( QLatin1String( "polygon" ), Qt::CaseInsensitive ) )
4385  {
4387  def = def.mid( 8 );
4388  continue;
4389  }
4390  break;
4391  }
4392 
4393  return new QgsProcessingParameterFeatureSource( name, description, types, def, isOptional );
4394 }
4395 
4396 QgsProcessingParameterFeatureSink::QgsProcessingParameterFeatureSink( const QString &name, const QString &description, QgsProcessing::SourceType type, const QVariant &defaultValue, bool optional, bool createByDefault )
4397  : QgsProcessingDestinationParameter( name, description, defaultValue, optional, createByDefault )
4398  , mDataType( type )
4399 {
4400 }
4401 
4403 {
4404  return new QgsProcessingParameterFeatureSink( *this );
4405 }
4406 
4408 {
4409  QVariant var = input;
4410  if ( !var.isValid() )
4411  return mFlags & FlagOptional;
4412 
4413  if ( var.canConvert<QgsProcessingOutputLayerDefinition>() )
4414  {
4416  var = fromVar.sink;
4417  }
4418 
4419  if ( var.canConvert<QgsProperty>() )
4420  {
4421  QgsProperty p = var.value< QgsProperty >();
4423  {
4424  var = p.staticValue();
4425  }
4426  else
4427  {
4428  return true;
4429  }
4430  }
4431 
4432  if ( var.type() != QVariant::String )
4433  return false;
4434 
4435  if ( var.toString().isEmpty() )
4436  return mFlags & FlagOptional;
4437 
4438  return true;
4439 }
4440 
4442 {
4443  if ( !value.isValid() )
4444  return QStringLiteral( "None" );
4445 
4446  if ( value.canConvert<QgsProperty>() )
4447  return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
4448 
4449  if ( value.canConvert<QgsProcessingOutputLayerDefinition>() )
4450  {
4452  if ( fromVar.sink.propertyType() == QgsProperty::StaticProperty )
4453  {
4454  return QgsProcessingUtils::stringToPythonLiteral( fromVar.sink.staticValue().toString() );
4455  }
4456  else
4457  {
4458  return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( fromVar.sink.asExpression() );
4459  }
4460  }
4461 
4462  return QgsProcessingUtils::stringToPythonLiteral( value.toString() );
4463 }
4464 
4466 {
4467  QString code = QStringLiteral( "##%1=" ).arg( mName );
4468  if ( mFlags & FlagOptional )
4469  code += QStringLiteral( "optional " );
4470  code += QStringLiteral( "sink " );
4471 
4472  switch ( mDataType )
4473  {
4475  code += QStringLiteral( "point " );
4476  break;
4477 
4479  code += QStringLiteral( "line " );
4480  break;
4481 
4483  code += QStringLiteral( "polygon " );
4484  break;
4485 
4487  code += QStringLiteral( "table " );
4488  break;
4489 
4490  default:
4491  break;
4492  }
4493 
4494  code += mDefault.toString();
4495  return code.trimmed();
4496 }
4497 
4499 {
4500  return new QgsProcessingOutputVectorLayer( name(), description(), mDataType );
4501 }
4502 
4504 {
4505  if ( originalProvider() )
4506  {
4508  }
4509  else if ( QgsProcessingProvider *p = provider() )
4510  {
4511  return p->defaultVectorFileExtension( hasGeometry() );
4512  }
4513  else
4514  {
4515  if ( hasGeometry() )
4516  {
4518  }
4519  else
4520  {
4521  return QStringLiteral( "dbf" );
4522  }
4523  }
4524 }
4525 
4527 {
4528  switch ( outputType )
4529  {
4531  {
4532  QString code = QStringLiteral( "QgsProcessingParameterFeatureSink('%1', '%2'" ).arg( name(), description() );
4533  if ( mFlags & FlagOptional )
4534  code += QStringLiteral( ", optional=True" );
4535 
4536  code += QStringLiteral( ", type=QgsProcessing.%1" ).arg( QgsProcessing::sourceTypeToString( mDataType ) );
4537 
4538  code += QStringLiteral( ", createByDefault=%1" ).arg( createByDefault() ? QStringLiteral( "True" ) : QStringLiteral( "False" ) );
4539 
4541  code += QStringLiteral( ", defaultValue=%1)" ).arg( valueAsPythonString( mDefault, c ) );
4542  return code;
4543  }
4544  }
4545  return QString();
4546 }
4547 
4549 {
4550  if ( originalProvider() )
4551  {
4552  if ( hasGeometry() )
4554  else
4556  }
4557  else if ( QgsProcessingProvider *p = provider() )
4558  {
4559  if ( hasGeometry() )
4560  return p->supportedOutputVectorLayerExtensions();
4561  else
4562  return p->supportedOutputTableExtensions();
4563  }
4564  else
4565  {
4567  }
4568 }
4569 
4571 {
4572  return mDataType;
4573 }
4574 
4576 {
4577  switch ( mDataType )
4578  {
4584  return true;
4585 
4590  return false;
4591  }
4592  return true;
4593 }
4594 
4596 {
4597  mDataType = type;
4598 }
4599 
4601 {
4603  map.insert( QStringLiteral( "data_type" ), mDataType );
4604  return map;
4605 }
4606 
4608 {
4610  mDataType = static_cast< QgsProcessing::SourceType >( map.value( QStringLiteral( "data_type" ) ).toInt() );
4611  return true;
4612 }
4613 
4615 {
4617  return QStringLiteral( "memory:%1" ).arg( description() );
4618  else
4620 }
4621 
4622 QgsProcessingParameterFeatureSink *QgsProcessingParameterFeatureSink::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
4623 {
4625  QString def = definition;
4626  if ( def.startsWith( QLatin1String( "point" ), Qt::CaseInsensitive ) )
4627  {
4629  def = def.mid( 6 );
4630  }
4631  else if ( def.startsWith( QLatin1String( "line" ), Qt::CaseInsensitive ) )
4632  {
4634  def = def.mid( 5 );
4635  }
4636  else if ( def.startsWith( QLatin1String( "polygon" ), Qt::CaseInsensitive ) )
4637  {
4639  def = def.mid( 8 );
4640  }
4641  else if ( def.startsWith( QLatin1String( "table" ), Qt::CaseInsensitive ) )
4642  {
4644  def = def.mid( 6 );
4645  }
4646 
4647  return new QgsProcessingParameterFeatureSink( name, description, type, definition, isOptional );
4648 }
4649 
4651  : QgsProcessingDestinationParameter( name, description, defaultValue, optional, createByDefault )
4652 {
4653 }
4654 
4656 {
4657  return new QgsProcessingParameterRasterDestination( *this );
4658 }
4659 
4661 {
4662  QVariant var = input;
4663  if ( !var.isValid() )
4664  return mFlags & FlagOptional;
4665 
4666  if ( var.canConvert<QgsProcessingOutputLayerDefinition>() )
4667  {
4669  var = fromVar.sink;
4670  }
4671 
4672  if ( var.canConvert<QgsProperty>() )
4673  {
4674  QgsProperty p = var.value< QgsProperty >();
4676  {
4677  var = p.staticValue();
4678  }
4679  else
4680  {
4681  return true;
4682  }
4683  }
4684 
4685  if ( var.type() != QVariant::String )
4686  return false;
4687 
4688  if ( var.toString().isEmpty() )
4689  return mFlags & FlagOptional;
4690 
4691  return true;
4692 }
4693 
4695 {
4696  if ( !value.isValid() )
4697  return QStringLiteral( "None" );
4698 
4699  if ( value.canConvert<QgsProperty>() )
4700  return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
4701 
4702  if ( value.canConvert<QgsProcessingOutputLayerDefinition>() )
4703  {
4705  if ( fromVar.sink.propertyType() == QgsProperty::StaticProperty )
4706  {
4707  return QgsProcessingUtils::stringToPythonLiteral( fromVar.sink.staticValue().toString() );
4708  }
4709  else
4710  {
4711  return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( fromVar.sink.asExpression() );
4712  }
4713  }
4714 
4715  return QgsProcessingUtils::stringToPythonLiteral( value.toString() );
4716 }
4717 
4719 {
4720  return new QgsProcessingOutputRasterLayer( name(), description() );
4721 }
4722 
4724 {
4725  if ( originalProvider() )
4726  {
4728  }
4729  else if ( QgsProcessingProvider *p = provider() )
4730  {
4731  return p->defaultRasterFileExtension();
4732  }
4733  else
4734  {
4736  }
4737 }
4738 
4740 {
4741  if ( originalProvider() )
4742  {
4744  }
4745  else if ( QgsProcessingProvider *p = provider() )
4746  {
4747  return p->supportedOutputRasterLayerExtensions();
4748  }
4749  else
4750  {
4752  }
4753 }
4754 
4755 QgsProcessingParameterRasterDestination *QgsProcessingParameterRasterDestination::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
4756 {
4757  return new QgsProcessingParameterRasterDestination( name, description, definition.isEmpty() ? QVariant() : definition, isOptional );
4758 }
4759 
4760 
4761 QgsProcessingParameterFileDestination::QgsProcessingParameterFileDestination( const QString &name, const QString &description, const QString &fileFilter, const QVariant &defaultValue, bool optional, bool createByDefault )
4762  : QgsProcessingDestinationParameter( name, description, defaultValue, optional, createByDefault )
4763  , mFileFilter( fileFilter.isEmpty() ? QObject::tr( "All files (*.*)" ) : fileFilter )
4764 {
4765 
4766 }
4767 
4769 {
4770  return new QgsProcessingParameterFileDestination( *this );
4771 }
4772 
4774 {
4775  QVariant var = input;
4776  if ( !var.isValid() )
4777  return mFlags & FlagOptional;
4778 
4779  if ( var.canConvert<QgsProcessingOutputLayerDefinition>() )
4780  {
4782  var = fromVar.sink;
4783  }
4784 
4785  if ( var.canConvert<QgsProperty>() )
4786  {
4787  QgsProperty p = var.value< QgsProperty >();
4789  {
4790  var = p.staticValue();
4791  }
4792  else
4793  {
4794  return true;
4795  }
4796  }
4797 
4798  if ( var.type() != QVariant::String )
4799  return false;
4800 
4801  if ( var.toString().isEmpty() )
4802  return mFlags & FlagOptional;
4803 
4804  // possible enhancement - check that value is compatible with file filter?
4805 
4806  return true;
4807 }
4808 
4810 {
4811  if ( !value.isValid() )
4812  return QStringLiteral( "None" );
4813 
4814  if ( value.canConvert<QgsProperty>() )
4815  return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
4816 
4817  if ( value.canConvert<QgsProcessingOutputLayerDefinition>() )
4818  {
4820  if ( fromVar.sink.propertyType() == QgsProperty::StaticProperty )
4821  {
4822  return QgsProcessingUtils::stringToPythonLiteral( fromVar.sink.staticValue().toString() );
4823  }
4824  else
4825  {
4826  return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( fromVar.sink.asExpression() );
4827  }
4828  }
4829 
4830  return QgsProcessingUtils::stringToPythonLiteral( value.toString() );
4831 }
4832 
4834 {
4835  if ( !mFileFilter.isEmpty() && mFileFilter.contains( QStringLiteral( "htm" ), Qt::CaseInsensitive ) )
4836  {
4837  return new QgsProcessingOutputHtml( name(), description() );
4838  }
4839  else
4840  {
4841  return new QgsProcessingOutputFile( name(), description() );
4842  }
4843 }
4844 
4846 {
4847  if ( mFileFilter.isEmpty() || mFileFilter == QObject::tr( "All files (*.*)" ) )
4848  return QStringLiteral( "file" );
4849 
4850  // get first extension from filter
4851  QRegularExpression rx( QStringLiteral( ".*?\\(\\*\\.([a-zA-Z0-9._]+).*" ) );
4852  QRegularExpressionMatch match = rx.match( mFileFilter );
4853  if ( !match.hasMatch() )
4854  return QStringLiteral( "file" );
4855 
4856  return match.captured( 1 );
4857 }
4858 
4860 {
4861  switch ( outputType )
4862  {
4864  {
4865  QString code = QStringLiteral( "QgsProcessingParameterFileDestination('%1', '%2'" ).arg( name(), description() );
4866  if ( mFlags & FlagOptional )
4867  code += QStringLiteral( ", optional=True" );
4868 
4869  code += QStringLiteral( ", fileFilter=%1" ).arg( QgsProcessingUtils::stringToPythonLiteral( mFileFilter ) );
4870 
4871  code += QStringLiteral( ", createByDefault=%1" ).arg( createByDefault() ? QStringLiteral( "True" ) : QStringLiteral( "False" ) );
4872 
4874  code += QStringLiteral( ", defaultValue=%1)" ).arg( valueAsPythonString( mDefault, c ) );
4875  return code;
4876  }
4877  }
4878  return QString();
4879 }
4880 
4882 {
4883  return mFileFilter;
4884 }
4885 
4887 {
4888  mFileFilter = fileFilter;
4889 }
4890 
4892 {
4894  map.insert( QStringLiteral( "file_filter" ), mFileFilter );
4895  return map;
4896 }
4897 
4899 {
4901  mFileFilter = map.value( QStringLiteral( "file_filter" ) ).toString();
4902  return true;
4903 
4904 }
4905 
4906 QgsProcessingParameterFileDestination *QgsProcessingParameterFileDestination::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
4907 {
4908  return new QgsProcessingParameterFileDestination( name, description, QString(), definition.isEmpty() ? QVariant() : definition, isOptional );
4909 }
4910 
4912  : QgsProcessingDestinationParameter( name, description, defaultValue, optional, createByDefault )
4913 {}
4914 
4916 {
4917  return new QgsProcessingParameterFolderDestination( *this );
4918 }
4919 
4921 {
4922  QVariant var = input;
4923  if ( !var.isValid() )
4924  return mFlags & FlagOptional;
4925 
4926  if ( var.canConvert<QgsProperty>() )
4927  {
4928  QgsProperty p = var.value< QgsProperty >();
4930  {
4931  var = p.staticValue();
4932  }
4933  else
4934  {
4935  return true;
4936  }
4937  }
4938 
4939  if ( var.type() != QVariant::String )
4940  return false;
4941 
4942  if ( var.toString().isEmpty() )
4943  return mFlags & FlagOptional;
4944 
4945  return true;
4946 }
4947 
4949 {
4950  return new QgsProcessingOutputFolder( name(), description() );
4951 }
4952 
4954 {
4955  return QString();
4956 }
4957 
4958 QgsProcessingParameterFolderDestination *QgsProcessingParameterFolderDestination::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
4959 {
4960  return new QgsProcessingParameterFolderDestination( name, description, definition.isEmpty() ? QVariant() : definition, isOptional );
4961 }
4962 
4963 QgsProcessingDestinationParameter::QgsProcessingDestinationParameter( const QString &name, const QString &description, const QVariant &defaultValue, bool optional, bool createByDefault )
4964  : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
4965  , mCreateByDefault( createByDefault )
4966 {
4967 
4968 }
4969 
4971 {
4973  map.insert( QStringLiteral( "supports_non_file_outputs" ), mSupportsNonFileBasedOutputs );
4974  map.insert( QStringLiteral( "create_by_default" ), mCreateByDefault );
4975  return map;
4976 }
4977 
4979 {
4981  mSupportsNonFileBasedOutputs = map.value( QStringLiteral( "supports_non_file_outputs" ) ).toBool();
4982  mCreateByDefault = map.value( QStringLiteral( "create_by_default" ), QStringLiteral( "1" ) ).toBool();
4983  return true;
4984 }
4985 
4987 {
4988  switch ( outputType )
4989  {
4991  {
4992  // base class method is probably not much use
4993  if ( QgsProcessingParameterType *t = QgsApplication::processingRegistry()->parameterType( type() ) )
4994  {
4995  QString code = t->className() + QStringLiteral( "('%1', '%2'" ).arg( name(), description() );
4996  if ( mFlags & FlagOptional )
4997  code += QStringLiteral( ", optional=True" );
4998 
4999  code += QStringLiteral( ", createByDefault=%1" ).arg( mCreateByDefault ? QStringLiteral( "True" ) : QStringLiteral( "False" ) );
5000 
5002  code += QStringLiteral( ", defaultValue=%1)" ).arg( valueAsPythonString( mDefault, c ) );
5003  return code;
5004  }
5005  break;
5006  }
5007  }
5008  // oh well, we tried
5009  return QString();
5010 }
5011 
5013 {
5014  if ( defaultFileExtension().isEmpty() )
5015  {
5017  }
5018  else
5019  {
5021  }
5022 }
5023 
5025 {
5026  return mCreateByDefault;
5027 }
5028 
5030 {
5031  mCreateByDefault = createByDefault;
5032 }
5033 
5035  : QgsProcessingDestinationParameter( name, description, defaultValue, optional, createByDefault )
5036  , mDataType( type )
5037 {
5038 
5039 }
5040 
5042 {
5043  return new QgsProcessingParameterVectorDestination( *this );
5044 }
5045 
5047 {
5048  QVariant var = input;
5049  if ( !var.isValid() )
5050  return mFlags & FlagOptional;
5051 
5052  if ( var.canConvert<QgsProcessingOutputLayerDefinition>() )
5053  {
5055  var = fromVar.sink;
5056  }
5057 
5058  if ( var.canConvert<QgsProperty>() )
5059  {
5060  QgsProperty p = var.value< QgsProperty >();
5062  {
5063  var = p.staticValue();
5064  }
5065  else
5066  {
5067  return true;
5068  }
5069  }
5070 
5071  if ( var.type() != QVariant::String )
5072  return false;
5073 
5074  if ( var.toString().isEmpty() )
5075  return mFlags & FlagOptional;
5076 
5077  return true;
5078 }
5079 
5081 {
5082  if ( !value.isValid() )
5083  return QStringLiteral( "None" );
5084 
5085  if ( value.canConvert<QgsProperty>() )
5086  return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
5087 
5088  if ( value.canConvert<QgsProcessingOutputLayerDefinition>() )
5089  {
5091  if ( fromVar.sink.propertyType() == QgsProperty::StaticProperty )
5092  {
5093  return QgsProcessingUtils::stringToPythonLiteral( fromVar.sink.staticValue().toString() );
5094  }
5095  else
5096  {
5097  return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( fromVar.sink.asExpression() );
5098  }
5099  }
5100 
5101  return QgsProcessingUtils::stringToPythonLiteral( value.toString() );
5102 }
5103 
5105 {
5106  QString code = QStringLiteral( "##%1=" ).arg( mName );
5107  if ( mFlags & FlagOptional )
5108  code += QStringLiteral( "optional " );
5109  code += QStringLiteral( "vectorDestination " );
5110 
5111  switch ( mDataType )
5112  {
5114  code += QStringLiteral( "point " );
5115  break;
5116 
5118  code += QStringLiteral( "line " );
5119  break;
5120 
5122  code += QStringLiteral( "polygon " );
5123  break;
5124 
5125  default:
5126  break;
5127  }
5128 
5129  code += mDefault.toString();
5130  return code.trimmed();
5131 }
5132 
5134 {
5135  return new QgsProcessingOutputVectorLayer( name(), description(), mDataType );
5136 }
5137 
5139 {
5140  if ( originalProvider() )
5141  {
5143  }
5144  else if ( QgsProcessingProvider *p = provider() )
5145  {
5146  return p->defaultVectorFileExtension( hasGeometry() );
5147  }
5148  else
5149  {
5150  if ( hasGeometry() )
5151  {
5153  }
5154  else
5155  {
5156  return QStringLiteral( "dbf" );
5157  }
5158  }
5159 }
5160 
5162 {
5163  switch ( outputType )
5164  {
5166  {
5167  QString code = QStringLiteral( "QgsProcessingParameterVectorDestination('%1', '%2'" ).arg( name(), description() );
5168  if ( mFlags & FlagOptional )
5169  code += QStringLiteral( ", optional=True" );
5170 
5171  code += QStringLiteral( ", type=QgsProcessing.%1" ).arg( QgsProcessing::sourceTypeToString( mDataType ) );
5172 
5173  code += QStringLiteral( ", createByDefault=%1" ).arg( createByDefault() ? QStringLiteral( "True" ) : QStringLiteral( "False" ) );
5174 
5176  code += QStringLiteral( ", defaultValue=%1)" ).arg( valueAsPythonString( mDefault, c ) );
5177  return code;
5178  }
5179  }
5180  return QString();
5181 }
5182 
5184 {
5185  if ( originalProvider() )
5186  {
5187  if ( hasGeometry() )
5189  else
5191  }
5192  else if ( QgsProcessingProvider *p = provider() )
5193  {
5194  if ( hasGeometry() )
5195  return p->supportedOutputVectorLayerExtensions();
5196  else
5197  return p->supportedOutputTableExtensions();
5198  }
5199  else
5200  {
5202  }
5203 }
5204 
5206 {
5207  return mDataType;
5208 }
5209 
5211 {
5212  switch ( mDataType )
5213  {
5219  return true;
5220 
5225  return false;
5226  }
5227  return true;
5228 }
5229 
5231 {
5232  mDataType = type;
5233 }
5234 
5236 {
5238  map.insert( QStringLiteral( "data_type" ), mDataType );
5239  return map;
5240 }
5241 
5243 {
5245  mDataType = static_cast< QgsProcessing::SourceType >( map.value( QStringLiteral( "data_type" ) ).toInt() );
5246  return true;
5247 }
5248 
5249 QgsProcessingParameterVectorDestination *QgsProcessingParameterVectorDestination::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
5250 {
5252  QString def = definition;
5253  if ( def.startsWith( QLatin1String( "point" ), Qt::CaseInsensitive ) )
5254  {
5256  def = def.mid( 6 );
5257  }
5258  else if ( def.startsWith( QLatin1String( "line" ), Qt::CaseInsensitive ) )
5259  {
5261  def = def.mid( 5 );
5262  }
5263  else if ( def.startsWith( QLatin1String( "polygon" ), Qt::CaseInsensitive ) )
5264  {
5266  def = def.mid( 8 );
5267  }
5268 
5269  return new QgsProcessingParameterVectorDestination( name, description, type, definition, isOptional );
5270 }
5271 
5272 QgsProcessingParameterBand::QgsProcessingParameterBand( const QString &name, const QString &description, const QVariant &defaultValue, const QString &parentLayerParameterName, bool optional, bool allowMultiple )
5273  : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
5274  , mParentLayerParameterName( parentLayerParameterName )
5275  , mAllowMultiple( allowMultiple )
5276 {
5277 
5278 }
5279 
5281 {
5282  return new QgsProcessingParameterBand( *this );
5283 }
5284 
5286 {
5287  if ( !input.isValid() )
5288  return mFlags & FlagOptional;
5289 
5290  if ( input.canConvert<QgsProperty>() )
5291  {
5292  return true;
5293  }
5294 
5295  if ( input.type() == QVariant::List || input.type() == QVariant::StringList )
5296  {
5297  if ( !mAllowMultiple )
5298  return false;
5299 
5300  if ( input.toList().isEmpty() && !( mFlags & FlagOptional ) )
5301  return false;
5302  }
5303  else
5304  {
5305  bool ok = false;
5306  double res = input.toInt( &ok );
5307  Q_UNUSED( res )
5308  if ( !ok )
5309  return mFlags & FlagOptional;
5310  }
5311  return true;
5312 }
5313 
5315 {
5316  return mAllowMultiple;
5317 }
5318 
5320 {
5321  mAllowMultiple = allowMultiple;
5322 }
5323 
5325 {
5326  if ( !value.isValid() )
5327  return QStringLiteral( "None" );
5328 
5329  if ( value.canConvert<QgsProperty>() )
5330  return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
5331 
5332  if ( value.type() == QVariant::List )
5333  {
5334  QStringList parts;
5335  QVariantList values = value.toList();
5336  for ( auto it = values.constBegin(); it != values.constEnd(); ++it )
5337  {
5338  parts << QString::number( static_cast< int >( it->toDouble() ) );
5339  }
5340  return parts.join( ',' ).prepend( '[' ).append( ']' );
5341  }
5342  else if ( value.type() == QVariant::StringList )
5343  {
5344  QStringList parts;
5345  QStringList values = value.toStringList();
5346  for ( auto it = values.constBegin(); it != values.constEnd(); ++it )
5347  {
5348  parts << QString::number( static_cast< int >( it->toDouble() ) );
5349  }
5350  return parts.join( ',' ).prepend( '[' ).append( ']' );
5351  }
5352 
5353  return value.toString();
5354 }
5355 
5357 {
5358  QString code = QStringLiteral( "##%1=" ).arg( mName );
5359  if ( mFlags & FlagOptional )
5360  code += QStringLiteral( "optional " );
5361  code += QStringLiteral( "band " );
5362 
5363  if ( mAllowMultiple )
5364  code += QStringLiteral( "multiple " );
5365 
5366  code += mParentLayerParameterName + ' ';
5367 
5368  code += mDefault.toString();
5369  return code.trimmed();
5370 }
5371 
5373 {
5374  QStringList depends;
5375  if ( !mParentLayerParameterName.isEmpty() )
5376  depends << mParentLayerParameterName;
5377  return depends;
5378 }
5379 
5381 {
5382  switch ( outputType )
5383  {
5385  {
5386  QString code = QStringLiteral( "QgsProcessingParameterBand('%1', '%2'" ).arg( name(), description() );
5387  if ( mFlags & FlagOptional )
5388  code += QStringLiteral( ", optional=True" );
5389 
5390  code += QStringLiteral( ", parentLayerParameterName='%1'" ).arg( mParentLayerParameterName );
5391  code += QStringLiteral( ", allowMultiple=%1" ).arg( mAllowMultiple ? QStringLiteral( "True" ) : QStringLiteral( "False" ) );
5392 
5394  code += QStringLiteral( ", defaultValue=%1)" ).arg( valueAsPythonString( mDefault, c ) );
5395  return code;
5396  }
5397  }
5398  return QString();
5399 }
5400 
5402 {
5403  return mParentLayerParameterName;
5404 }
5405 
5407 {
5408  mParentLayerParameterName = parentLayerParameterName;
5409 }
5410 
5412 {
5414  map.insert( QStringLiteral( "parent_layer" ), mParentLayerParameterName );
5415  map.insert( QStringLiteral( "allow_multiple" ), mAllowMultiple );
5416  return map;
5417 }
5418 
5419 bool QgsProcessingParameterBand::fromVariantMap( const QVariantMap &map )
5420 {
5422  mParentLayerParameterName = map.value( QStringLiteral( "parent_layer" ) ).toString();
5423  mAllowMultiple = map.value( QStringLiteral( "allow_multiple" ) ).toBool();
5424  return true;
5425 }
5426 
5427 QgsProcessingParameterBand *QgsProcessingParameterBand::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
5428 {
5429  QString parent;
5430  QString def = definition;
5431  bool allowMultiple = false;
5432 
5433  if ( def.startsWith( QLatin1String( "multiple" ), Qt::CaseInsensitive ) )
5434  {
5435  allowMultiple = true;
5436  def = def.mid( 8 ).trimmed();
5437  }
5438 
5439  QRegularExpression re( QStringLiteral( "(.*?)\\s+(.*)$" ) );
5440  QRegularExpressionMatch m = re.match( def );
5441  if ( m.hasMatch() )
5442  {
5443  parent = m.captured( 1 ).trimmed();
5444  def = m.captured( 2 );
5445  }
5446  else
5447  {
5448  parent = def;
5449  def.clear();
5450  }
5451 
5452  return new QgsProcessingParameterBand( name, description, def.isEmpty() ? QVariant() : def, parent, isOptional, allowMultiple );
5453 }
5454 
5455 //
5456 // QgsProcessingParameterDistance
5457 //
5458 
5459 QgsProcessingParameterDistance::QgsProcessingParameterDistance( const QString &name, const QString &description, const QVariant &defaultValue, const QString &parentParameterName, bool optional, double minValue, double maxValue )
5460  : QgsProcessingParameterNumber( name, description, Double, defaultValue, optional, minValue, maxValue )
5461  , mParentParameterName( parentParameterName )
5462 {
5463 
5464 }
5465 
5467 {
5468  return new QgsProcessingParameterDistance( *this );
5469 }
5470 
5472 {
5473  return typeName();
5474 }
5475 
5477 {
5478  QStringList depends;
5479  if ( !mParentParameterName.isEmpty() )
5480  depends << mParentParameterName;
5481  return depends;
5482 }
5483 
5485 {
5486  switch ( outputType )
5487  {
5489  {
5490  QString code = QStringLiteral( "QgsProcessingParameterDistance('%1', '%2'" ).arg( name(), description() );
5491  if ( mFlags & FlagOptional )
5492  code += QStringLiteral( ", optional=True" );
5493 
5494  code += QStringLiteral( ", parentParameterName='%1'" ).arg( mParentParameterName );
5495 
5496  if ( minimum() != std::numeric_limits<double>::lowest() + 1 )
5497  code += QStringLiteral( ", minValue=%1" ).arg( minimum() );
5498  if ( maximum() != std::numeric_limits<double>::max() )
5499  code += QStringLiteral( ", maxValue=%1" ).arg( maximum() );
5501  code += QStringLiteral( ", defaultValue=%1)" ).arg( valueAsPythonString( mDefault, c ) );
5502  return code;
5503  }
5504  }
5505  return QString();
5506 }
5507 
5509 {
5510  return mParentParameterName;
5511 }
5512 
5514 {
5515  mParentParameterName = parentParameterName;
5516 }
5517 
5519 {
5520  QVariantMap map = QgsProcessingParameterNumber::toVariantMap();
5521  map.insert( QStringLiteral( "parent" ), mParentParameterName );
5522  map.insert( QStringLiteral( "default_unit" ), static_cast< int >( mDefaultUnit ) );
5523  return map;
5524 }
5525 
5527 {
5529  mParentParameterName = map.value( QStringLiteral( "parent" ) ).toString();
5530  mDefaultUnit = static_cast< QgsUnitTypes::DistanceUnit>( map.value( QStringLiteral( "default_unit" ), QgsUnitTypes::DistanceUnknownUnit ).toInt() );
5531  return true;
5532 }
5533 
5534 
5535 //
5536 // QgsProcessingParameterScale
5537 //
5538 
5539 QgsProcessingParameterScale::QgsProcessingParameterScale( const QString &name, const QString &description, const QVariant &defaultValue, bool optional )
5540  : QgsProcessingParameterNumber( name, description, Double, defaultValue, optional )
5541 {
5542 
5543 }