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