QGIS API Documentation  3.23.0-Master (eb871beae0)
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  const QgsCoordinateTransform ct( rr.crs(), crs, context.project() );
1098  try
1099  {
1100  return ct.transformBoundingBox( rr );
1101  }
1102  catch ( QgsCsException & )
1103  {
1104  QgsMessageLog::logMessage( QObject::tr( "Error transforming extent geometry" ) );
1105  }
1106  }
1107  return rr;
1108  }
1109 
1110  if ( val.canConvert<QgsProcessingFeatureSourceDefinition>() )
1111  {
1112  // input is a QgsProcessingFeatureSourceDefinition - get extra properties from it
1113  const QgsProcessingFeatureSourceDefinition fromVar = qvariant_cast<QgsProcessingFeatureSourceDefinition>( val );
1114  val = fromVar.source;
1115  }
1116  else if ( val.canConvert<QgsProcessingOutputLayerDefinition>() )
1117  {
1118  // input is a QgsProcessingOutputLayerDefinition - get extra properties from it
1119  const QgsProcessingOutputLayerDefinition fromVar = qvariant_cast<QgsProcessingOutputLayerDefinition>( val );
1120  val = fromVar.sink;
1121  }
1122 
1123  if ( val.canConvert<QgsProperty>() && val.value< QgsProperty >().propertyType() == QgsProperty::StaticProperty )
1124  {
1125  val = val.value< QgsProperty >().staticValue();
1126  }
1127 
1128  // maybe parameter is a direct layer value?
1129  QgsMapLayer *layer = qobject_cast< QgsMapLayer * >( qvariant_cast<QObject *>( val ) );
1130 
1131  QString rectText;
1132  if ( val.canConvert<QgsProperty>() )
1133  rectText = val.value< QgsProperty >().valueAsString( context.expressionContext(), definition->defaultValue().toString() );
1134  else
1135  rectText = val.toString();
1136 
1137  if ( rectText.isEmpty() && !layer )
1138  return QgsRectangle();
1139 
1140  const QRegularExpression rx( QStringLiteral( "^(.*?)\\s*,\\s*(.*?),\\s*(.*?),\\s*(.*?)\\s*(?:\\[(.*)\\])?\\s*$" ) );
1141  const QRegularExpressionMatch match = rx.match( rectText );
1142  if ( match.hasMatch() )
1143  {
1144  bool xMinOk = false;
1145  const double xMin = match.captured( 1 ).toDouble( &xMinOk );
1146  bool xMaxOk = false;
1147  const double xMax = match.captured( 2 ).toDouble( &xMaxOk );
1148  bool yMinOk = false;
1149  const double yMin = match.captured( 3 ).toDouble( &yMinOk );
1150  bool yMaxOk = false;
1151  const double yMax = match.captured( 4 ).toDouble( &yMaxOk );
1152  if ( xMinOk && xMaxOk && yMinOk && yMaxOk )
1153  {
1154  const QgsRectangle rect( xMin, yMin, xMax, yMax );
1155  const QgsCoordinateReferenceSystem rectCrs( match.captured( 5 ) );
1156  if ( crs.isValid() && rectCrs.isValid() && crs != rectCrs )
1157  {
1158  const QgsCoordinateTransform ct( rectCrs, crs, context.project() );
1159  try
1160  {
1161  return ct.transformBoundingBox( rect );
1162  }
1163  catch ( QgsCsException & )
1164  {
1165  QgsMessageLog::logMessage( QObject::tr( "Error transforming extent geometry" ) );
1166  }
1167  }
1168  return rect;
1169  }
1170  }
1171 
1172  // try as layer extent
1173  if ( !layer )
1174  layer = QgsProcessingUtils::mapLayerFromString( rectText, context );
1175 
1176  if ( layer )
1177  {
1178  const QgsRectangle rect = layer->extent();
1179  if ( crs.isValid() && layer->crs().isValid() && crs != layer->crs() )
1180  {
1181  const QgsCoordinateTransform ct( layer->crs(), crs, context.project() );
1182  try
1183  {
1184  return ct.transformBoundingBox( rect );
1185  }
1186  catch ( QgsCsException & )
1187  {
1188  QgsMessageLog::logMessage( QObject::tr( "Error transforming extent geometry" ) );
1189  }
1190  }
1191  return rect;
1192  }
1193  return QgsRectangle();
1194 }
1195 
1197 {
1198  if ( !definition )
1199  return QgsGeometry();
1200 
1201  QVariant val = parameters.value( definition->name() );
1202 
1203  if ( val.canConvert< QgsReferencedRectangle >() )
1204  {
1205  const QgsReferencedRectangle rr = val.value<QgsReferencedRectangle>();
1207  if ( crs.isValid() && rr.crs().isValid() && crs != rr.crs() )
1208  {
1209  g = g.densifyByCount( 20 );
1210  const QgsCoordinateTransform ct( rr.crs(), crs, context.project() );
1211  try
1212  {
1213  g.transform( ct );
1214  }
1215  catch ( QgsCsException & )
1216  {
1217  QgsMessageLog::logMessage( QObject::tr( "Error transforming extent geometry" ) );
1218  }
1219  return g;
1220  }
1221  }
1222 
1223  if ( val.canConvert<QgsProcessingFeatureSourceDefinition>() )
1224  {
1225  // input is a QgsProcessingFeatureSourceDefinition - get extra properties from it
1226  const QgsProcessingFeatureSourceDefinition fromVar = qvariant_cast<QgsProcessingFeatureSourceDefinition>( val );
1227  val = fromVar.source;
1228  }
1229  else if ( val.canConvert<QgsProcessingOutputLayerDefinition>() )
1230  {
1231  // input is a QgsProcessingOutputLayerDefinition - get extra properties from it
1232  const QgsProcessingOutputLayerDefinition fromVar = qvariant_cast<QgsProcessingOutputLayerDefinition>( val );
1233  val = fromVar.sink;
1234  }
1235 
1236  if ( val.canConvert<QgsProperty>() && val.value< QgsProperty >().propertyType() == QgsProperty::StaticProperty )
1237  {
1238  val = val.value< QgsProperty >().staticValue();
1239  }
1240 
1241  QString rectText;
1242  if ( val.canConvert<QgsProperty>() )
1243  rectText = val.value< QgsProperty >().valueAsString( context.expressionContext(), definition->defaultValue().toString() );
1244  else
1245  rectText = val.toString();
1246 
1247  if ( !rectText.isEmpty() )
1248  {
1249  const QRegularExpression rx( QStringLiteral( "^(.*?)\\s*,\\s*(.*?),\\s*(.*?),\\s*(.*?)\\s*(?:\\[(.*)\\])?\\s*$" ) );
1250  const QRegularExpressionMatch match = rx.match( rectText );
1251  if ( match.hasMatch() )
1252  {
1253  bool xMinOk = false;
1254  const double xMin = match.captured( 1 ).toDouble( &xMinOk );
1255  bool xMaxOk = false;
1256  const double xMax = match.captured( 2 ).toDouble( &xMaxOk );
1257  bool yMinOk = false;
1258  const double yMin = match.captured( 3 ).toDouble( &yMinOk );
1259  bool yMaxOk = false;
1260  const double yMax = match.captured( 4 ).toDouble( &yMaxOk );
1261  if ( xMinOk && xMaxOk && yMinOk && yMaxOk )
1262  {
1263  const QgsRectangle rect( xMin, yMin, xMax, yMax );
1264  const QgsCoordinateReferenceSystem rectCrs( match.captured( 5 ) );
1265  QgsGeometry g = QgsGeometry::fromRect( rect );
1266  if ( crs.isValid() && rectCrs.isValid() && crs != rectCrs )
1267  {
1268  g = g.densifyByCount( 20 );
1269  const QgsCoordinateTransform ct( rectCrs, crs, context.project() );
1270  try
1271  {
1272  g.transform( ct );
1273  }
1274  catch ( QgsCsException & )
1275  {
1276  QgsMessageLog::logMessage( QObject::tr( "Error transforming extent geometry" ) );
1277  }
1278  return g;
1279  }
1280  }
1281  }
1282  }
1283 
1284  // try as layer extent
1285 
1286  // maybe parameter is a direct layer value?
1287  QgsMapLayer *layer = qobject_cast< QgsMapLayer * >( qvariant_cast<QObject *>( val ) );
1288  if ( !layer )
1289  layer = QgsProcessingUtils::mapLayerFromString( rectText, context );
1290 
1291  if ( layer )
1292  {
1293  const QgsRectangle rect = layer->extent();
1294  QgsGeometry g = QgsGeometry::fromRect( rect );
1295  if ( crs.isValid() && layer->crs().isValid() && crs != layer->crs() )
1296  {
1297  g = g.densifyByCount( 20 );
1298  const QgsCoordinateTransform ct( layer->crs(), crs, context.project() );
1299  try
1300  {
1301  g.transform( ct );
1302  }
1303  catch ( QgsCsException & )
1304  {
1305  QgsMessageLog::logMessage( QObject::tr( "Error transforming extent geometry" ) );
1306  }
1307  }
1308  return g;
1309  }
1310 
1311  return QgsGeometry::fromRect( parameterAsExtent( definition, parameters, context, crs ) );
1312 }
1313 
1315 {
1316  const QVariant val = parameters.value( definition->name() );
1317  return parameterAsExtentCrs( definition, val, context );
1318 }
1319 
1321 {
1322  QVariant val = value;
1323  if ( val.canConvert< QgsReferencedRectangle >() )
1324  {
1325  const QgsReferencedRectangle rr = val.value<QgsReferencedRectangle>();
1326  if ( rr.crs().isValid() )
1327  {
1328  return rr.crs();
1329  }
1330  }
1331 
1332  if ( val.canConvert<QgsProcessingFeatureSourceDefinition>() )
1333  {
1334  // input is a QgsProcessingFeatureSourceDefinition - get extra properties from it
1335  const QgsProcessingFeatureSourceDefinition fromVar = qvariant_cast<QgsProcessingFeatureSourceDefinition>( val );
1336  val = fromVar.source;
1337  }
1338  else if ( val.canConvert<QgsProcessingOutputLayerDefinition>() )
1339  {
1340  // input is a QgsProcessingOutputLayerDefinition - get extra properties from it
1341  const QgsProcessingOutputLayerDefinition fromVar = qvariant_cast<QgsProcessingOutputLayerDefinition>( val );
1342  val = fromVar.sink;
1343  }
1344 
1345  if ( val.canConvert<QgsProperty>() && val.value< QgsProperty >().propertyType() == QgsProperty::StaticProperty )
1346  {
1347  val = val.value< QgsProperty >().staticValue();
1348  }
1349 
1350  QString valueAsString;
1351  if ( val.canConvert<QgsProperty>() )
1352  valueAsString = val.value< QgsProperty >().valueAsString( context.expressionContext(), definition->defaultValue().toString() );
1353  else
1354  valueAsString = val.toString();
1355 
1356  const QRegularExpression rx( QStringLiteral( "^(.*?)\\s*,\\s*(.*?),\\s*(.*?),\\s*(.*?)\\s*(?:\\[(.*)\\])?\\s*$" ) );
1357 
1358  const QRegularExpressionMatch match = rx.match( valueAsString );
1359  if ( match.hasMatch() )
1360  {
1361  const QgsCoordinateReferenceSystem crs( match.captured( 5 ) );
1362  if ( crs.isValid() )
1363  return crs;
1364  }
1365 
1366  if ( val.canConvert<QgsProcessingFeatureSourceDefinition>() )
1367  {
1368  // input is a QgsProcessingFeatureSourceDefinition - get extra properties from it
1369  const QgsProcessingFeatureSourceDefinition fromVar = qvariant_cast<QgsProcessingFeatureSourceDefinition>( val );
1370  val = fromVar.source;
1371  }
1372  else if ( val.canConvert<QgsProcessingOutputLayerDefinition>() )
1373  {
1374  // input is a QgsProcessingOutputLayerDefinition - get extra properties from it
1375  const QgsProcessingOutputLayerDefinition fromVar = qvariant_cast<QgsProcessingOutputLayerDefinition>( val );
1376  val = fromVar.sink;
1377  }
1378 
1379  if ( val.canConvert<QgsProperty>() && val.value< QgsProperty >().propertyType() == QgsProperty::StaticProperty )
1380  {
1381  val = val.value< QgsProperty >().staticValue();
1382  }
1383 
1384  // try as layer crs
1385  if ( QgsMapLayer *layer = qobject_cast< QgsMapLayer * >( qvariant_cast<QObject *>( val ) ) )
1386  return layer->crs();
1387  else if ( QgsMapLayer *layer = QgsProcessingUtils::mapLayerFromString( valueAsString, context ) )
1388  return layer->crs();
1389 
1390  if ( auto *lProject = context.project() )
1391  return lProject->crs();
1392  else
1394 }
1395 
1397 {
1398  if ( !definition )
1399  return QgsPointXY();
1400 
1401  return parameterAsPoint( definition, parameters.value( definition->name() ), context, crs );
1402 }
1403 
1405 {
1406  if ( !definition )
1407  return QgsPointXY();
1408 
1409  const QVariant val = value;
1410  if ( val.canConvert< QgsPointXY >() )
1411  {
1412  return val.value<QgsPointXY>();
1413  }
1414  if ( val.canConvert< QgsGeometry >() )
1415  {
1416  const QgsGeometry geom = val.value<QgsGeometry>();
1417  if ( !geom.isNull() )
1418  return geom.centroid().asPoint();
1419  }
1420  if ( val.canConvert< QgsReferencedPointXY >() )
1421  {
1422  const QgsReferencedPointXY rp = val.value<QgsReferencedPointXY>();
1423  if ( crs.isValid() && rp.crs().isValid() && crs != rp.crs() )
1424  {
1425  const QgsCoordinateTransform ct( rp.crs(), crs, context.project() );
1426  try
1427  {
1428  return ct.transform( rp );
1429  }
1430  catch ( QgsCsException & )
1431  {
1432  QgsMessageLog::logMessage( QObject::tr( "Error transforming point geometry" ) );
1433  }
1434  }
1435  return rp;
1436  }
1437 
1438  QString pointText = parameterAsString( definition, value, context );
1439  if ( pointText.isEmpty() )
1440  pointText = definition->defaultValue().toString();
1441 
1442  if ( pointText.isEmpty() )
1443  return QgsPointXY();
1444 
1445  const QRegularExpression rx( QStringLiteral( "^\\s*\\(?\\s*(.*?)\\s*,\\s*(.*?)\\s*(?:\\[(.*)\\])?\\s*\\)?\\s*$" ) );
1446 
1447  const QString valueAsString = parameterAsString( definition, value, context );
1448  const QRegularExpressionMatch match = rx.match( valueAsString );
1449  if ( match.hasMatch() )
1450  {
1451  bool xOk = false;
1452  const double x = match.captured( 1 ).toDouble( &xOk );
1453  bool yOk = false;
1454  const double y = match.captured( 2 ).toDouble( &yOk );
1455 
1456  if ( xOk && yOk )
1457  {
1458  const QgsPointXY pt( x, y );
1459 
1460  const QgsCoordinateReferenceSystem pointCrs( match.captured( 3 ) );
1461  if ( crs.isValid() && pointCrs.isValid() && crs != pointCrs )
1462  {
1463  const QgsCoordinateTransform ct( pointCrs, crs, context.project() );
1464  try
1465  {
1466  return ct.transform( pt );
1467  }
1468  catch ( QgsCsException & )
1469  {
1470  QgsMessageLog::logMessage( QObject::tr( "Error transforming point geometry" ) );
1471  }
1472  }
1473  return pt;
1474  }
1475  }
1476 
1477  return QgsPointXY();
1478 }
1479 
1481 {
1482  const QVariant val = parameters.value( definition->name() );
1483  return parameterAsPointCrs( definition, val, context );
1484 }
1485 
1487 {
1488  if ( value.canConvert< QgsReferencedPointXY >() )
1489  {
1490  const QgsReferencedPointXY rr = value.value<QgsReferencedPointXY>();
1491  if ( rr.crs().isValid() )
1492  {
1493  return rr.crs();
1494  }
1495  }
1496 
1497  const QRegularExpression rx( QStringLiteral( "^\\s*\\(?\\s*(.*?)\\s*,\\s*(.*?)\\s*(?:\\[(.*)\\])?\\s*\\)?\\s*$" ) );
1498 
1499  const QString valueAsString = parameterAsString( definition, value, context );
1500  const QRegularExpressionMatch match = rx.match( valueAsString );
1501  if ( match.hasMatch() )
1502  {
1503  const QgsCoordinateReferenceSystem crs( match.captured( 3 ) );
1504  if ( crs.isValid() )
1505  return crs;
1506  }
1507 
1508  if ( auto *lProject = context.project() )
1509  return lProject->crs();
1510  else
1512 }
1513 
1515 {
1516  if ( !definition )
1517  return QgsGeometry();
1518 
1519  return parameterAsGeometry( definition, parameters.value( definition->name() ), context, crs );
1520 }
1521 
1523 {
1524  if ( !definition )
1525  return QgsGeometry();
1526 
1527  const QVariant val = value;
1528  if ( val.canConvert< QgsGeometry >() )
1529  {
1530  return val.value<QgsGeometry>();
1531  }
1532 
1533  if ( val.canConvert< QgsPointXY >() )
1534  {
1535  return QgsGeometry::fromPointXY( val.value<QgsPointXY>() );
1536  }
1537 
1538  if ( val.canConvert< QgsRectangle >() )
1539  {
1540  return QgsGeometry::fromRect( val.value<QgsRectangle>() );
1541  }
1542 
1543  if ( val.canConvert< QgsReferencedPointXY >() )
1544  {
1545  const QgsReferencedPointXY rp = val.value<QgsReferencedPointXY>();
1546  if ( crs.isValid() && rp.crs().isValid() && crs != rp.crs() )
1547  {
1548  const QgsCoordinateTransform ct( rp.crs(), crs, context.project() );
1549  try
1550  {
1551  return QgsGeometry::fromPointXY( ct.transform( rp ) );
1552  }
1553  catch ( QgsCsException & )
1554  {
1555  QgsMessageLog::logMessage( QObject::tr( "Error transforming point geometry" ) );
1556  }
1557  }
1558  return QgsGeometry::fromPointXY( rp );
1559  }
1560 
1561  if ( val.canConvert< QgsReferencedRectangle >() )
1562  {
1563  const QgsReferencedRectangle rr = val.value<QgsReferencedRectangle>();
1565  if ( crs.isValid() && rr.crs().isValid() && crs != rr.crs() )
1566  {
1567  g = g.densifyByCount( 20 );
1568  const QgsCoordinateTransform ct( rr.crs(), crs, context.project() );
1569  try
1570  {
1571  g.transform( ct );
1572  }
1573  catch ( QgsCsException & )
1574  {
1575  QgsMessageLog::logMessage( QObject::tr( "Error transforming rectangle geometry" ) );
1576  }
1577  }
1578  return g;
1579  }
1580 
1581  if ( val.canConvert< QgsReferencedGeometry >() )
1582  {
1583  QgsReferencedGeometry rg = val.value<QgsReferencedGeometry>();
1584  if ( crs.isValid() && rg.crs().isValid() && crs != rg.crs() )
1585  {
1586  const QgsCoordinateTransform ct( rg.crs(), crs, context.project() );
1587  try
1588  {
1589  rg.transform( ct );
1590  }
1591  catch ( QgsCsException & )
1592  {
1593  QgsMessageLog::logMessage( QObject::tr( "Error transforming geometry" ) );
1594  }
1595  }
1596  return rg;
1597  }
1598 
1599  QString valueAsString = parameterAsString( definition, value, context );
1600  if ( valueAsString.isEmpty() )
1601  valueAsString = definition->defaultValue().toString();
1602 
1603  if ( valueAsString.isEmpty() )
1604  return QgsGeometry();
1605 
1606  const QRegularExpression rx( QStringLiteral( "^\\s*(?:CRS=(.*);)?(.*?)$" ) );
1607 
1608  const QRegularExpressionMatch match = rx.match( valueAsString );
1609  if ( match.hasMatch() )
1610  {
1611  QgsGeometry g = QgsGeometry::fromWkt( match.captured( 2 ) );
1612  if ( !g.isNull() )
1613  {
1614  const QgsCoordinateReferenceSystem geomCrs( match.captured( 1 ) );
1615  if ( crs.isValid() && geomCrs.isValid() && crs != geomCrs )
1616  {
1617  const QgsCoordinateTransform ct( geomCrs, crs, context.project() );
1618  try
1619  {
1620  g.transform( ct );
1621  }
1622  catch ( QgsCsException & )
1623  {
1624  QgsMessageLog::logMessage( QObject::tr( "Error transforming geometry" ) );
1625  }
1626  }
1627  return g;
1628  }
1629  }
1630 
1631  return QgsGeometry();
1632 }
1633 
1635 {
1636  const QVariant val = parameters.value( definition->name() );
1637  return parameterAsGeometryCrs( definition, val, context );
1638 }
1639 
1641 {
1642  if ( value.canConvert< QgsReferencedGeometry >() )
1643  {
1644  const QgsReferencedGeometry rg = value.value<QgsReferencedGeometry>();
1645  if ( rg.crs().isValid() )
1646  {
1647  return rg.crs();
1648  }
1649  }
1650 
1651  if ( value.canConvert< QgsReferencedPointXY >() )
1652  {
1653  const QgsReferencedPointXY rp = value.value<QgsReferencedPointXY>();
1654  if ( rp.crs().isValid() )
1655  {
1656  return rp.crs();
1657  }
1658  }
1659 
1660  if ( value.canConvert< QgsReferencedRectangle >() )
1661  {
1662  const QgsReferencedRectangle rr = value.value<QgsReferencedRectangle>();
1663  if ( rr.crs().isValid() )
1664  {
1665  return rr.crs();
1666  }
1667  }
1668 
1669  // Match against EWKT
1670  const QRegularExpression rx( QStringLiteral( "^\\s*(?:CRS=(.*);)?(.*?)$" ) );
1671 
1672  const QString valueAsString = parameterAsString( definition, value, context );
1673  const QRegularExpressionMatch match = rx.match( valueAsString );
1674  if ( match.hasMatch() )
1675  {
1676  const QgsCoordinateReferenceSystem crs( match.captured( 1 ) );
1677  if ( crs.isValid() )
1678  return crs;
1679  }
1680 
1681  if ( auto *lProject = context.project() )
1682  return lProject->crs();
1683  else
1685 }
1686 
1687 QString QgsProcessingParameters::parameterAsFile( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context )
1688 {
1689  if ( !definition )
1690  return QString();
1691 
1692  QString fileText = parameterAsString( definition, parameters, context );
1693  if ( fileText.isEmpty() )
1694  fileText = definition->defaultValue().toString();
1695  return fileText;
1696 }
1697 
1698 QString QgsProcessingParameters::parameterAsFile( const QgsProcessingParameterDefinition *definition, const QVariant &value, QgsProcessingContext &context )
1699 {
1700  if ( !definition )
1701  return QString();
1702 
1703  QString fileText = parameterAsString( definition, value, context );
1704  if ( fileText.isEmpty() )
1705  fileText = definition->defaultValue().toString();
1706  return fileText;
1707 }
1708 
1709 QVariantList QgsProcessingParameters::parameterAsMatrix( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context )
1710 {
1711  if ( !definition )
1712  return QVariantList();
1713 
1714  return parameterAsMatrix( definition, parameters.value( definition->name() ), context );
1715 }
1716 
1717 QVariantList QgsProcessingParameters::parameterAsMatrix( const QgsProcessingParameterDefinition *definition, const QVariant &value, QgsProcessingContext &context )
1718 {
1719  if ( !definition )
1720  return QVariantList();
1721 
1722  QString resultString;
1723  const QVariant val = value;
1724  if ( val.canConvert<QgsProperty>() )
1725  resultString = val.value< QgsProperty >().valueAsString( context.expressionContext(), definition->defaultValue().toString() );
1726  else if ( val.type() == QVariant::List )
1727  return val.toList();
1728  else
1729  resultString = val.toString();
1730 
1731  if ( resultString.isEmpty() )
1732  {
1733  // check default
1734  if ( definition->defaultValue().type() == QVariant::List )
1735  return definition->defaultValue().toList();
1736  else
1737  resultString = definition->defaultValue().toString();
1738  }
1739 
1740  QVariantList result;
1741  const auto constSplit = resultString.split( ',' );
1742  bool ok;
1743  double number;
1744  for ( const QString &s : constSplit )
1745  {
1746  number = s.toDouble( &ok );
1747  result << ( ok ? QVariant( number ) : s );
1748  }
1749 
1750  return result;
1751 }
1752 
1753 QList<QgsMapLayer *> QgsProcessingParameters::parameterAsLayerList( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context )
1754 {
1755  if ( !definition )
1756  return QList<QgsMapLayer *>();
1757 
1758  return parameterAsLayerList( definition, parameters.value( definition->name() ), context );
1759 }
1760 
1761 QList<QgsMapLayer *> QgsProcessingParameters::parameterAsLayerList( const QgsProcessingParameterDefinition *definition, const QVariant &value, QgsProcessingContext &context )
1762 {
1763  if ( !definition )
1764  return QList<QgsMapLayer *>();
1765 
1766  const QVariant val = value;
1767  if ( QgsMapLayer *layer = qobject_cast< QgsMapLayer * >( qvariant_cast<QObject *>( val ) ) )
1768  {
1769  return QList<QgsMapLayer *>() << layer;
1770  }
1771 
1772  QList<QgsMapLayer *> layers;
1773 
1774  std::function< void( const QVariant &var ) > processVariant;
1775  processVariant = [ &layers, &context, &definition, &processVariant ]( const QVariant & var )
1776  {
1777  if ( var.type() == QVariant::List )
1778  {
1779  const auto constToList = var.toList();
1780  for ( const QVariant &listVar : constToList )
1781  {
1782  processVariant( listVar );
1783  }
1784  }
1785  else if ( var.type() == QVariant::StringList )
1786  {
1787  const auto constToStringList = var.toStringList();
1788  for ( const QString &s : constToStringList )
1789  {
1790  processVariant( s );
1791  }
1792  }
1793  else if ( var.canConvert<QgsProperty>() )
1794  processVariant( var.value< QgsProperty >().valueAsString( context.expressionContext(), definition->defaultValue().toString() ) );
1795  else if ( var.canConvert<QgsProcessingOutputLayerDefinition>() )
1796  {
1797  // input is a QgsProcessingOutputLayerDefinition - get extra properties from it
1798  const QgsProcessingOutputLayerDefinition fromVar = qvariant_cast<QgsProcessingOutputLayerDefinition>( var );
1799  const QVariant sink = fromVar.sink;
1800  if ( sink.canConvert<QgsProperty>() )
1801  {
1802  processVariant( sink.value< QgsProperty >().valueAsString( context.expressionContext(), definition->defaultValue().toString() ) );
1803  }
1804  }
1805  else if ( QgsMapLayer *layer = qobject_cast< QgsMapLayer * >( qvariant_cast<QObject *>( var ) ) )
1806  {
1807  layers << layer;
1808  }
1809  else
1810  {
1811  QgsMapLayer *alayer = QgsProcessingUtils::mapLayerFromString( var.toString(), context );
1812  if ( alayer )
1813  layers << alayer;
1814  }
1815  };
1816 
1817  processVariant( val );
1818 
1819  if ( layers.isEmpty() )
1820  {
1821  // check default
1822  if ( QgsMapLayer *layer = qobject_cast< QgsMapLayer * >( qvariant_cast<QObject *>( definition->defaultValue() ) ) )
1823  {
1824  layers << layer;
1825  }
1826  else if ( definition->defaultValue().type() == QVariant::List )
1827  {
1828  const auto constToList = definition->defaultValue().toList();
1829  for ( const QVariant &var : constToList )
1830  {
1831  if ( QgsMapLayer *layer = qobject_cast< QgsMapLayer * >( qvariant_cast<QObject *>( var ) ) )
1832  {
1833  layers << layer;
1834  }
1835  else
1836  {
1837  processVariant( var );
1838  }
1839  }
1840  }
1841  else
1842  processVariant( definition->defaultValue() );
1843  }
1844 
1845  return layers;
1846 }
1847 
1848 QStringList QgsProcessingParameters::parameterAsFileList( const QgsProcessingParameterDefinition *definition, const QVariant &value, QgsProcessingContext &context )
1849 {
1850  if ( !definition )
1851  return QStringList();
1852 
1853  const QVariant val = value;
1854 
1855  QStringList files;
1856 
1857  std::function< void( const QVariant &var ) > processVariant;
1858  processVariant = [ &files, &context, &definition, &processVariant ]( const QVariant & var )
1859  {
1860  if ( var.type() == QVariant::List )
1861  {
1862  const auto constToList = var.toList();
1863  for ( const QVariant &listVar : constToList )
1864  {
1865  processVariant( listVar );
1866  }
1867  }
1868  else if ( var.type() == QVariant::StringList )
1869  {
1870  const auto constToStringList = var.toStringList();
1871  for ( const QString &s : constToStringList )
1872  {
1873  processVariant( s );
1874  }
1875  }
1876  else if ( var.canConvert<QgsProperty>() )
1877  processVariant( var.value< QgsProperty >().valueAsString( context.expressionContext(), definition->defaultValue().toString() ) );
1878  else
1879  {
1880  files << var.toString();
1881  }
1882  };
1883 
1884  processVariant( val );
1885 
1886  if ( files.isEmpty() )
1887  {
1888  processVariant( definition->defaultValue() );
1889  }
1890 
1891  return files;
1892 }
1893 
1894 QStringList QgsProcessingParameters::parameterAsFileList( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context )
1895 {
1896  if ( !definition )
1897  return QStringList();
1898 
1899  return parameterAsFileList( definition, parameters.value( definition->name() ), context );
1900 }
1901 
1902 QList<double> QgsProcessingParameters::parameterAsRange( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context )
1903 {
1904  if ( !definition )
1905  return QList<double>();
1906 
1907  return parameterAsRange( definition, parameters.value( definition->name() ), context );
1908 }
1909 
1910 QList<double> QgsProcessingParameters::parameterAsRange( const QgsProcessingParameterDefinition *definition, const QVariant &value, QgsProcessingContext &context )
1911 {
1912  if ( !definition )
1913  return QList<double>();
1914 
1915  QStringList resultStringList;
1916  const QVariant val = value;
1917 
1918  if ( val.canConvert<QgsProperty>() )
1919  resultStringList << val.value< QgsProperty >().valueAsString( context.expressionContext(), definition->defaultValue().toString() );
1920  else if ( val.type() == QVariant::List )
1921  {
1922  const auto constToList = val.toList();
1923  for ( const QVariant &var : constToList )
1924  resultStringList << var.toString();
1925  }
1926  else
1927  resultStringList << val.toString();
1928 
1929  if ( ( resultStringList.isEmpty() || ( resultStringList.size() == 1 && resultStringList.at( 0 ).isEmpty() ) ) )
1930  {
1931  resultStringList.clear();
1932  // check default
1933  if ( definition->defaultValue().type() == QVariant::List )
1934  {
1935  const auto constToList = definition->defaultValue().toList();
1936  for ( const QVariant &var : constToList )
1937  resultStringList << var.toString();
1938  }
1939  else
1940  resultStringList << definition->defaultValue().toString();
1941  }
1942 
1943  if ( resultStringList.size() == 1 )
1944  {
1945  resultStringList = resultStringList.at( 0 ).split( ',' );
1946  }
1947 
1948  if ( resultStringList.size() < 2 )
1949  return QList< double >() << std::numeric_limits<double>::quiet_NaN() << std::numeric_limits<double>::quiet_NaN() ;
1950 
1951  QList< double > result;
1952  bool ok = false;
1953  double n = resultStringList.at( 0 ).toDouble( &ok );
1954  if ( ok )
1955  result << n;
1956  else
1957  result << std::numeric_limits<double>::quiet_NaN() ;
1958  ok = false;
1959  n = resultStringList.at( 1 ).toDouble( &ok );
1960  if ( ok )
1961  result << n;
1962  else
1963  result << std::numeric_limits<double>::quiet_NaN() ;
1964 
1965  return result;
1966 }
1967 
1968 QStringList QgsProcessingParameters::parameterAsFields( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context )
1969 {
1970  if ( !definition )
1971  return QStringList();
1972 
1973  const QStringList resultStringList;
1974  return parameterAsFields( definition, parameters.value( definition->name() ), context );
1975 }
1976 
1977 QStringList QgsProcessingParameters::parameterAsFields( const QgsProcessingParameterDefinition *definition, const QVariant &value, QgsProcessingContext &context )
1978 {
1979  if ( !definition )
1980  return QStringList();
1981 
1982  QStringList resultStringList;
1983  const QVariant val = value;
1984  if ( val.isValid() )
1985  {
1986  if ( val.canConvert<QgsProperty>() )
1987  resultStringList << val.value< QgsProperty >().valueAsString( context.expressionContext(), definition->defaultValue().toString() );
1988  else if ( val.type() == QVariant::List )
1989  {
1990  const auto constToList = val.toList();
1991  for ( const QVariant &var : constToList )
1992  resultStringList << var.toString();
1993  }
1994  else if ( val.type() == QVariant::StringList )
1995  {
1996  resultStringList = val.toStringList();
1997  }
1998  else
1999  resultStringList.append( val.toString().split( ';' ) );
2000  }
2001 
2002  if ( ( resultStringList.isEmpty() || resultStringList.at( 0 ).isEmpty() ) )
2003  {
2004  resultStringList.clear();
2005  // check default
2006  if ( definition->defaultValue().isValid() )
2007  {
2008  if ( definition->defaultValue().type() == QVariant::List )
2009  {
2010  const auto constToList = definition->defaultValue().toList();
2011  for ( const QVariant &var : constToList )
2012  resultStringList << var.toString();
2013  }
2014  else if ( definition->defaultValue().type() == QVariant::StringList )
2015  {
2016  resultStringList = definition->defaultValue().toStringList();
2017  }
2018  else
2019  resultStringList.append( definition->defaultValue().toString().split( ';' ) );
2020  }
2021  }
2022 
2023  return resultStringList;
2024 }
2025 
2027 {
2028  if ( !definition )
2029  return nullptr;
2030 
2031  return parameterAsLayout( definition, parameters.value( definition->name() ), context );
2032 }
2033 
2035 {
2036  const QString layoutName = parameterAsString( definition, value, context );
2037  if ( layoutName.isEmpty() )
2038  return nullptr;
2039 
2040  if ( !context.project() )
2041  return nullptr;
2042 
2043  QgsMasterLayoutInterface *l = context.project()->layoutManager()->layoutByName( layoutName );
2045  return static_cast< QgsPrintLayout * >( l );
2046  else
2047  return nullptr;
2048 }
2049 
2051 {
2052  if ( !definition )
2053  return nullptr;
2054 
2055  return parameterAsLayoutItem( definition, parameters.value( definition->name() ), context, layout );
2056 }
2057 
2059 {
2060  if ( !layout )
2061  return nullptr;
2062 
2063  const QString id = parameterAsString( definition, value, context );
2064  if ( id.isEmpty() )
2065  return nullptr;
2066 
2067  // prefer matching by uuid, since it's guaranteed to be unique.
2068  if ( QgsLayoutItem *item = layout->itemByUuid( id ) )
2069  return item;
2070  else if ( QgsLayoutItem *item = layout->itemById( id ) )
2071  return item;
2072  else
2073  return nullptr;
2074 }
2075 
2076 QColor QgsProcessingParameters::parameterAsColor( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context )
2077 {
2078  if ( !definition )
2079  return QColor();
2080 
2081  return parameterAsColor( definition, parameters.value( definition->name() ), context );
2082 }
2083 
2085 {
2086  if ( !definition )
2087  return QColor();
2088 
2089  QVariant val = value;
2090  if ( val.canConvert<QgsProperty>() )
2091  {
2092  val = val.value< QgsProperty >().value( context.expressionContext(), definition->defaultValue() );
2093  }
2094  if ( val.type() == QVariant::Color )
2095  {
2096  QColor c = val.value< QColor >();
2097  if ( const QgsProcessingParameterColor *colorParam = dynamic_cast< const QgsProcessingParameterColor * >( definition ) )
2098  if ( !colorParam->opacityEnabled() )
2099  c.setAlpha( 255 );
2100  return c;
2101  }
2102 
2103  QString colorText = parameterAsString( definition, value, context );
2104  if ( colorText.isEmpty() && !( definition->flags() & QgsProcessingParameterDefinition::FlagOptional ) )
2105  {
2106  if ( definition->defaultValue().type() == QVariant::Color )
2107  return definition->defaultValue().value< QColor >();
2108  else
2109  colorText = definition->defaultValue().toString();
2110  }
2111 
2112  if ( colorText.isEmpty() )
2113  return QColor();
2114 
2115  bool containsAlpha = false;
2116  QColor c = QgsSymbolLayerUtils::parseColorWithAlpha( colorText, containsAlpha );
2117  if ( const QgsProcessingParameterColor *colorParam = dynamic_cast< const QgsProcessingParameterColor * >( definition ) )
2118  if ( c.isValid() && !colorParam->opacityEnabled() )
2119  c.setAlpha( 255 );
2120  return c;
2121 }
2122 
2123 QString QgsProcessingParameters::parameterAsConnectionName( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, const QgsProcessingContext &context )
2124 {
2125  if ( !definition )
2126  return QString();
2127 
2128  return parameterAsConnectionName( definition, parameters.value( definition->name() ), context );
2129 }
2130 
2131 QString QgsProcessingParameters::parameterAsConnectionName( const QgsProcessingParameterDefinition *definition, const QVariant &value, const QgsProcessingContext &context )
2132 {
2133  // for now it's just treated identical to strings, but in future we may want flexibility to amend this
2134  // (hence the new method)
2135  return parameterAsString( definition, value, context );
2136 }
2137 
2138 QString QgsProcessingParameters::parameterAsSchema( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, const QgsProcessingContext &context )
2139 {
2140  if ( !definition )
2141  return QString();
2142 
2143  return parameterAsSchema( definition, parameters.value( definition->name() ), context );
2144 }
2145 
2146 QString QgsProcessingParameters::parameterAsSchema( const QgsProcessingParameterDefinition *definition, const QVariant &value, const QgsProcessingContext &context )
2147 {
2148  // 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
2149  // parameter values, such as via a delimiter separated string)
2150  return parameterAsString( definition, value, context );
2151 }
2152 
2153 QString QgsProcessingParameters::parameterAsDatabaseTableName( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, const QgsProcessingContext &context )
2154 {
2155  if ( !definition )
2156  return QString();
2157 
2158  return parameterAsDatabaseTableName( definition, parameters.value( definition->name() ), context );
2159 }
2160 
2162 {
2163  // 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
2164  // parameter values, such as via a delimiter separated string)
2165  return parameterAsString( definition, value, context );
2166 }
2167 
2169 {
2170  return qobject_cast< QgsPointCloudLayer *>( parameterAsLayer( definition, parameters, context, QgsProcessingUtils::LayerHint::PointCloud ) );
2171 }
2172 
2174 {
2175  return qobject_cast< QgsPointCloudLayer *>( parameterAsLayer( definition, value, context, QgsProcessingUtils::LayerHint::PointCloud ) );
2176 }
2177 
2179 {
2180  return qobject_cast< QgsAnnotationLayer *>( parameterAsLayer( definition, parameters, context, QgsProcessingUtils::LayerHint::Annotation ) );
2181 }
2182 
2184 {
2185  return qobject_cast< QgsAnnotationLayer *>( parameterAsLayer( definition, value, context, QgsProcessingUtils::LayerHint::Annotation ) );
2186 }
2187 
2189 {
2190  const QString type = map.value( QStringLiteral( "parameter_type" ) ).toString();
2191  const QString name = map.value( QStringLiteral( "name" ) ).toString();
2192  std::unique_ptr< QgsProcessingParameterDefinition > def;
2193 
2194  // probably all these hardcoded values aren't required anymore, and we could
2195  // always resort to the registry lookup...
2196  // TODO: confirm
2198  def.reset( new QgsProcessingParameterBoolean( name ) );
2199  else if ( type == QgsProcessingParameterCrs::typeName() )
2200  def.reset( new QgsProcessingParameterCrs( name ) );
2201  else if ( type == QgsProcessingParameterMapLayer::typeName() )
2202  def.reset( new QgsProcessingParameterMapLayer( name ) );
2203  else if ( type == QgsProcessingParameterExtent::typeName() )
2204  def.reset( new QgsProcessingParameterExtent( name ) );
2205  else if ( type == QgsProcessingParameterPoint::typeName() )
2206  def.reset( new QgsProcessingParameterPoint( name ) );
2207  else if ( type == QgsProcessingParameterFile::typeName() )
2208  def.reset( new QgsProcessingParameterFile( name ) );
2209  else if ( type == QgsProcessingParameterMatrix::typeName() )
2210  def.reset( new QgsProcessingParameterMatrix( name ) );
2212  def.reset( new QgsProcessingParameterMultipleLayers( name ) );
2213  else if ( type == QgsProcessingParameterNumber::typeName() )
2214  def.reset( new QgsProcessingParameterNumber( name ) );
2215  else if ( type == QgsProcessingParameterRange::typeName() )
2216  def.reset( new QgsProcessingParameterRange( name ) );
2217  else if ( type == QgsProcessingParameterRasterLayer::typeName() )
2218  def.reset( new QgsProcessingParameterRasterLayer( name ) );
2219  else if ( type == QgsProcessingParameterEnum::typeName() )
2220  def.reset( new QgsProcessingParameterEnum( name ) );
2221  else if ( type == QgsProcessingParameterString::typeName() )
2222  def.reset( new QgsProcessingParameterString( name ) );
2223  else if ( type == QgsProcessingParameterAuthConfig::typeName() )
2224  def.reset( new QgsProcessingParameterAuthConfig( name ) );
2225  else if ( type == QgsProcessingParameterExpression::typeName() )
2226  def.reset( new QgsProcessingParameterExpression( name ) );
2227  else if ( type == QgsProcessingParameterVectorLayer::typeName() )
2228  def.reset( new QgsProcessingParameterVectorLayer( name ) );
2229  else if ( type == QgsProcessingParameterField::typeName() )
2230  def.reset( new QgsProcessingParameterField( name ) );
2231  else if ( type == QgsProcessingParameterFeatureSource::typeName() )
2232  def.reset( new QgsProcessingParameterFeatureSource( name ) );
2233  else if ( type == QgsProcessingParameterFeatureSink::typeName() )
2234  def.reset( new QgsProcessingParameterFeatureSink( name ) );
2236  def.reset( new QgsProcessingParameterVectorDestination( name ) );
2238  def.reset( new QgsProcessingParameterRasterDestination( name ) );
2240  def.reset( new QgsProcessingParameterPointCloudDestination( name ) );
2242  def.reset( new QgsProcessingParameterFileDestination( name ) );
2244  def.reset( new QgsProcessingParameterFolderDestination( name ) );
2245  else if ( type == QgsProcessingParameterBand::typeName() )
2246  def.reset( new QgsProcessingParameterBand( name ) );
2247  else if ( type == QgsProcessingParameterMeshLayer::typeName() )
2248  def.reset( new QgsProcessingParameterMeshLayer( name ) );
2249  else if ( type == QgsProcessingParameterLayout::typeName() )
2250  def.reset( new QgsProcessingParameterLayout( name ) );
2251  else if ( type == QgsProcessingParameterLayoutItem::typeName() )
2252  def.reset( new QgsProcessingParameterLayoutItem( name ) );
2253  else if ( type == QgsProcessingParameterColor::typeName() )
2254  def.reset( new QgsProcessingParameterColor( name ) );
2256  def.reset( new QgsProcessingParameterCoordinateOperation( name ) );
2258  def.reset( new QgsProcessingParameterPointCloudLayer( name ) );
2260  def.reset( new QgsProcessingParameterAnnotationLayer( name ) );
2261  else
2262  {
2264  if ( paramType )
2265  def.reset( paramType->create( name ) );
2266  }
2267 
2268  if ( !def )
2269  return nullptr;
2270 
2271  def->fromVariantMap( map );
2272  return def.release();
2273 }
2274 
2275 QString QgsProcessingParameters::descriptionFromName( const QString &name )
2276 {
2277  QString desc = name;
2278  desc.replace( '_', ' ' );
2279  return desc;
2280 }
2281 
2283 {
2284  bool isOptional = false;
2285  QString name;
2286  QString definition;
2287  QString type;
2288  if ( !parseScriptCodeParameterOptions( code, isOptional, name, type, definition ) )
2289  return nullptr;
2290 
2291  const QString description = descriptionFromName( name );
2292 
2293  if ( type == QLatin1String( "boolean" ) )
2294  return QgsProcessingParameterBoolean::fromScriptCode( name, description, isOptional, definition );
2295  else if ( type == QLatin1String( "crs" ) )
2296  return QgsProcessingParameterCrs::fromScriptCode( name, description, isOptional, definition );
2297  else if ( type == QLatin1String( "layer" ) )
2298  return QgsProcessingParameterMapLayer::fromScriptCode( name, description, isOptional, definition );
2299  else if ( type == QLatin1String( "extent" ) )
2300  return QgsProcessingParameterExtent::fromScriptCode( name, description, isOptional, definition );
2301  else if ( type == QLatin1String( "point" ) )
2302  return QgsProcessingParameterPoint::fromScriptCode( name, description, isOptional, definition );
2303  else if ( type == QLatin1String( "geometry" ) )
2304  return QgsProcessingParameterGeometry::fromScriptCode( name, description, isOptional, definition );
2305  else if ( type == QLatin1String( "file" ) )
2306  return QgsProcessingParameterFile::fromScriptCode( name, description, isOptional, definition, QgsProcessingParameterFile::File );
2307  else if ( type == QLatin1String( "folder" ) )
2308  return QgsProcessingParameterFile::fromScriptCode( name, description, isOptional, definition, QgsProcessingParameterFile::Folder );
2309  else if ( type == QLatin1String( "matrix" ) )
2310  return QgsProcessingParameterMatrix::fromScriptCode( name, description, isOptional, definition );
2311  else if ( type == QLatin1String( "multiple" ) )
2312  return QgsProcessingParameterMultipleLayers::fromScriptCode( name, description, isOptional, definition );
2313  else if ( type == QLatin1String( "number" ) )
2314  return QgsProcessingParameterNumber::fromScriptCode( name, description, isOptional, definition );
2315  else if ( type == QLatin1String( "distance" ) )
2316  return QgsProcessingParameterDistance::fromScriptCode( name, description, isOptional, definition );
2317  else if ( type == QLatin1String( "duration" ) )
2318  return QgsProcessingParameterDuration::fromScriptCode( name, description, isOptional, definition );
2319  else if ( type == QLatin1String( "scale" ) )
2320  return QgsProcessingParameterScale::fromScriptCode( name, description, isOptional, definition );
2321  else if ( type == QLatin1String( "range" ) )
2322  return QgsProcessingParameterRange::fromScriptCode( name, description, isOptional, definition );
2323  else if ( type == QLatin1String( "raster" ) )
2324  return QgsProcessingParameterRasterLayer::fromScriptCode( name, description, isOptional, definition );
2325  else if ( type == QLatin1String( "enum" ) )
2326  return QgsProcessingParameterEnum::fromScriptCode( name, description, isOptional, definition );
2327  else if ( type == QLatin1String( "string" ) )
2328  return QgsProcessingParameterString::fromScriptCode( name, description, isOptional, definition );
2329  else if ( type == QLatin1String( "authcfg" ) )
2330  return QgsProcessingParameterAuthConfig::fromScriptCode( name, description, isOptional, definition );
2331  else if ( type == QLatin1String( "expression" ) )
2332  return QgsProcessingParameterExpression::fromScriptCode( name, description, isOptional, definition );
2333  else if ( type == QLatin1String( "field" ) )
2334  return QgsProcessingParameterField::fromScriptCode( name, description, isOptional, definition );
2335  else if ( type == QLatin1String( "vector" ) )
2336  return QgsProcessingParameterVectorLayer::fromScriptCode( name, description, isOptional, definition );
2337  else if ( type == QLatin1String( "source" ) )
2338  return QgsProcessingParameterFeatureSource::fromScriptCode( name, description, isOptional, definition );
2339  else if ( type == QLatin1String( "sink" ) )
2340  return QgsProcessingParameterFeatureSink::fromScriptCode( name, description, isOptional, definition );
2341  else if ( type == QLatin1String( "vectordestination" ) )
2342  return QgsProcessingParameterVectorDestination::fromScriptCode( name, description, isOptional, definition );
2343  else if ( type == QLatin1String( "rasterdestination" ) )
2344  return QgsProcessingParameterRasterDestination::fromScriptCode( name, description, isOptional, definition );
2345  else if ( type == QLatin1String( "pointclouddestination" ) )
2346  return QgsProcessingParameterPointCloudDestination::fromScriptCode( name, description, isOptional, definition );
2347  else if ( type == QLatin1String( "filedestination" ) )
2348  return QgsProcessingParameterFileDestination::fromScriptCode( name, description, isOptional, definition );
2349  else if ( type == QLatin1String( "folderdestination" ) )
2350  return QgsProcessingParameterFolderDestination::fromScriptCode( name, description, isOptional, definition );
2351  else if ( type == QLatin1String( "band" ) )
2352  return QgsProcessingParameterBand::fromScriptCode( name, description, isOptional, definition );
2353  else if ( type == QLatin1String( "mesh" ) )
2354  return QgsProcessingParameterMeshLayer::fromScriptCode( name, description, isOptional, definition );
2355  else if ( type == QLatin1String( "layout" ) )
2356  return QgsProcessingParameterLayout::fromScriptCode( name, description, isOptional, definition );
2357  else if ( type == QLatin1String( "layoutitem" ) )
2358  return QgsProcessingParameterLayoutItem::fromScriptCode( name, description, isOptional, definition );
2359  else if ( type == QLatin1String( "color" ) )
2360  return QgsProcessingParameterColor::fromScriptCode( name, description, isOptional, definition );
2361  else if ( type == QLatin1String( "coordinateoperation" ) )
2362  return QgsProcessingParameterCoordinateOperation::fromScriptCode( name, description, isOptional, definition );
2363  else if ( type == QLatin1String( "maptheme" ) )
2364  return QgsProcessingParameterMapTheme::fromScriptCode( name, description, isOptional, definition );
2365  else if ( type == QLatin1String( "datetime" ) )
2366  return QgsProcessingParameterDateTime::fromScriptCode( name, description, isOptional, definition );
2367  else if ( type == QLatin1String( "providerconnection" ) )
2368  return QgsProcessingParameterProviderConnection::fromScriptCode( name, description, isOptional, definition );
2369  else if ( type == QLatin1String( "databaseschema" ) )
2370  return QgsProcessingParameterDatabaseSchema::fromScriptCode( name, description, isOptional, definition );
2371  else if ( type == QLatin1String( "databasetable" ) )
2372  return QgsProcessingParameterDatabaseTable::fromScriptCode( name, description, isOptional, definition );
2373  else if ( type == QLatin1String( "pointcloud" ) )
2374  return QgsProcessingParameterPointCloudLayer::fromScriptCode( name, description, isOptional, definition );
2375  else if ( type == QLatin1String( "annotation" ) )
2376  return QgsProcessingParameterAnnotationLayer::fromScriptCode( name, description, isOptional, definition );
2377 
2378  return nullptr;
2379 }
2380 
2381 bool QgsProcessingParameters::parseScriptCodeParameterOptions( const QString &code, bool &isOptional, QString &name, QString &type, QString &definition )
2382 {
2383  const QRegularExpression re( QStringLiteral( "(?:#*)(.*?)=\\s*(.*)" ) );
2384  QRegularExpressionMatch m = re.match( code );
2385  if ( !m.hasMatch() )
2386  return false;
2387 
2388  name = m.captured( 1 );
2389  QString tokens = m.captured( 2 );
2390  if ( tokens.startsWith( QLatin1String( "optional" ), Qt::CaseInsensitive ) )
2391  {
2392  isOptional = true;
2393  tokens.remove( 0, 8 ); // length "optional" = 8
2394  }
2395  else
2396  {
2397  isOptional = false;
2398  }
2399 
2400  tokens = tokens.trimmed();
2401 
2402  const QRegularExpression re2( QStringLiteral( "(.*?)\\s+(.*)" ) );
2403  m = re2.match( tokens );
2404  if ( !m.hasMatch() )
2405  {
2406  type = tokens.toLower().trimmed();
2407  definition.clear();
2408  }
2409  else
2410  {
2411  type = m.captured( 1 ).toLower().trimmed();
2412  definition = m.captured( 2 );
2413  }
2414  return true;
2415 }
2416 
2417 //
2418 // QgsProcessingParameterDefinition
2419 //
2420 
2421 QgsProcessingParameterDefinition::QgsProcessingParameterDefinition( const QString &name, const QString &description, const QVariant &defaultValue, bool optional, const QString &help )
2422  : mName( name )
2423  , mDescription( description )
2424  , mHelp( help )
2425  , mDefault( defaultValue )
2426  , mFlags( optional ? FlagOptional : 0 )
2427 {}
2428 
2430 {
2431  if ( !input.isValid() && !mDefault.isValid() )
2432  return mFlags & FlagOptional;
2433 
2434  if ( ( input.type() == QVariant::String && input.toString().isEmpty() )
2435  || ( !input.isValid() && mDefault.type() == QVariant::String && mDefault.toString().isEmpty() ) )
2436  return mFlags & FlagOptional;
2437 
2438  return true;
2439 }
2440 
2442 {
2443  if ( !value.isValid() )
2444  return QStringLiteral( "None" );
2445 
2446  if ( value.canConvert<QgsProperty>() )
2447  return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
2448 
2449  return QgsProcessingUtils::stringToPythonLiteral( value.toString() );
2450 }
2451 
2453 {
2454  return QString();
2455 }
2456 
2458 {
2459  QString code = QStringLiteral( "##%1=" ).arg( mName );
2460  if ( mFlags & FlagOptional )
2461  code += QLatin1String( "optional " );
2462  code += type() + ' ';
2463  code += mDefault.toString();
2464  return code.trimmed();
2465 }
2466 
2468 {
2469  // base class method is probably not much use
2470  if ( QgsProcessingParameterType *t = QgsApplication::processingRegistry()->parameterType( type() ) )
2471  {
2472  switch ( outputType )
2473  {
2475  {
2476  QString code = t->className() + QStringLiteral( "('%1', %2" )
2478  if ( mFlags & FlagOptional )
2479  code += QLatin1String( ", optional=True" );
2480 
2482  code += QStringLiteral( ", defaultValue=%1)" ).arg( valueAsPythonString( mDefault, c ) );
2483  return code;
2484  }
2485  }
2486  }
2487 
2488  // oh well, we tried
2489  return QString();
2490 }
2491 
2493 {
2494  QVariantMap map;
2495  map.insert( QStringLiteral( "parameter_type" ), type() );
2496  map.insert( QStringLiteral( "name" ), mName );
2497  map.insert( QStringLiteral( "description" ), mDescription );
2498  map.insert( QStringLiteral( "help" ), mHelp );
2499  map.insert( QStringLiteral( "default" ), mDefault );
2500  map.insert( QStringLiteral( "defaultGui" ), mGuiDefault );
2501  map.insert( QStringLiteral( "flags" ), static_cast< int >( mFlags ) );
2502  map.insert( QStringLiteral( "metadata" ), mMetadata );
2503  return map;
2504 }
2505 
2507 {
2508  mName = map.value( QStringLiteral( "name" ) ).toString();
2509  mDescription = map.value( QStringLiteral( "description" ) ).toString();
2510  mHelp = map.value( QStringLiteral( "help" ) ).toString();
2511  mDefault = map.value( QStringLiteral( "default" ) );
2512  mGuiDefault = map.value( QStringLiteral( "defaultGui" ) );
2513  mFlags = static_cast< Flags >( map.value( QStringLiteral( "flags" ) ).toInt() );
2514  mMetadata = map.value( QStringLiteral( "metadata" ) ).toMap();
2515  return true;
2516 }
2517 
2519 {
2520  return mAlgorithm;
2521 }
2522 
2524 {
2525  return mAlgorithm ? mAlgorithm->provider() : nullptr;
2526 }
2527 
2529 {
2530  QString text = QStringLiteral( "<p><b>%1</b></p>" ).arg( description() );
2531  if ( !help().isEmpty() )
2532  {
2533  text += QStringLiteral( "<p>%1</p>" ).arg( help() );
2534  }
2535  text += QStringLiteral( "<p>%1</p>" ).arg( QObject::tr( "Python identifier: ‘%1’" ).arg( QStringLiteral( "<i>%1</i>" ).arg( name() ) ) );
2536  return text;
2537 }
2538 
2539 QgsProcessingParameterBoolean::QgsProcessingParameterBoolean( const QString &name, const QString &description, const QVariant &defaultValue, bool optional )
2540  : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
2541 {}
2542 
2544 {
2545  return new QgsProcessingParameterBoolean( *this );
2546 }
2547 
2549 {
2550  if ( !val.isValid() )
2551  return QStringLiteral( "None" );
2552 
2553  if ( val.canConvert<QgsProperty>() )
2554  return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( val.value< QgsProperty >().asExpression() );
2555  return val.toBool() ? QStringLiteral( "True" ) : QStringLiteral( "False" );
2556 }
2557 
2559 {
2560  QString code = QStringLiteral( "##%1=" ).arg( mName );
2561  if ( mFlags & FlagOptional )
2562  code += QLatin1String( "optional " );
2563  code += type() + ' ';
2564  code += mDefault.toBool() ? QStringLiteral( "true" ) : QStringLiteral( "false" );
2565  return code.trimmed();
2566 }
2567 
2568 QgsProcessingParameterBoolean *QgsProcessingParameterBoolean::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
2569 {
2570  return new QgsProcessingParameterBoolean( name, description, definition.toLower().trimmed() != QStringLiteral( "false" ), isOptional );
2571 }
2572 
2573 QgsProcessingParameterCrs::QgsProcessingParameterCrs( const QString &name, const QString &description, const QVariant &defaultValue, bool optional )
2574  : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
2575 {
2576 
2577 }
2578 
2580 {
2581  return new QgsProcessingParameterCrs( *this );
2582 }
2583 
2585 {
2586  if ( !input.isValid() )
2587  return mFlags & FlagOptional;
2588 
2589  if ( input.canConvert<QgsCoordinateReferenceSystem>() )
2590  {
2591  return true;
2592  }
2593  else if ( input.canConvert<QgsProcessingFeatureSourceDefinition>() )
2594  {
2595  return true;
2596  }
2597  else if ( input.canConvert<QgsProcessingOutputLayerDefinition>() )
2598  {
2599  return true;
2600  }
2601 
2602  if ( input.canConvert<QgsProperty>() )
2603  {
2604  return true;
2605  }
2606 
2607  // direct map layer value
2608  if ( qobject_cast< QgsMapLayer * >( qvariant_cast<QObject *>( input ) ) )
2609  return true;
2610 
2611  if ( input.type() != QVariant::String || input.toString().isEmpty() )
2612  return mFlags & FlagOptional;
2613 
2614  return true;
2615 }
2616 
2617 QString QgsProcessingParameterCrs::valueAsPythonString( const QVariant &value, QgsProcessingContext &context ) const
2618 {
2619  if ( !value.isValid() )
2620  return QStringLiteral( "None" );
2621 
2622  if ( value.canConvert<QgsCoordinateReferenceSystem>() )
2623  {
2624  if ( !value.value< QgsCoordinateReferenceSystem >().isValid() )
2625  return QStringLiteral( "QgsCoordinateReferenceSystem()" );
2626  else
2627  return QStringLiteral( "QgsCoordinateReferenceSystem('%1')" ).arg( value.value< QgsCoordinateReferenceSystem >().authid() );
2628  }
2629 
2630  if ( value.canConvert<QgsProperty>() )
2631  return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
2632 
2633  QVariantMap p;
2634  p.insert( name(), value );
2635  QgsMapLayer *layer = QgsProcessingParameters::parameterAsLayer( this, p, context );
2636  if ( layer )
2638 
2640 }
2641 
2642 QgsProcessingParameterCrs *QgsProcessingParameterCrs::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
2643 {
2644  return new QgsProcessingParameterCrs( name, description, definition.compare( QLatin1String( "none" ), Qt::CaseInsensitive ) == 0 ? QVariant() : definition, isOptional );
2645 }
2646 
2647 QgsProcessingParameterMapLayer::QgsProcessingParameterMapLayer( const QString &name, const QString &description, const QVariant &defaultValue, bool optional, const QList<int> &types )
2648  : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
2650 {
2651 
2652 }
2653 
2655 {
2656  return new QgsProcessingParameterMapLayer( *this );
2657 }
2658 
2660 {
2661  if ( !input.isValid() )
2662  return mFlags & FlagOptional;
2663 
2664  if ( input.canConvert<QgsProperty>() )
2665  {
2666  return true;
2667  }
2668 
2669  if ( qobject_cast< QgsMapLayer * >( qvariant_cast<QObject *>( input ) ) )
2670  {
2671  return true;
2672  }
2673 
2674  if ( input.type() != QVariant::String || input.toString().isEmpty() )
2675  return mFlags & FlagOptional;
2676 
2677  if ( !context )
2678  {
2679  // that's as far as we can get without a context
2680  return true;
2681  }
2682 
2683  // try to load as layer
2684  if ( QgsProcessingUtils::mapLayerFromString( input.toString(), *context ) )
2685  return true;
2686 
2687  return false;
2688 }
2689 
2691 {
2692  if ( !val.isValid() )
2693  return QStringLiteral( "None" );
2694 
2695  if ( val.canConvert<QgsProperty>() )
2696  return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( val.value< QgsProperty >().asExpression() );
2697 
2698  QVariantMap p;
2699  p.insert( name(), val );
2700  QgsMapLayer *layer = QgsProcessingParameters::parameterAsLayer( this, p, context );
2702  : QgsProcessingUtils::stringToPythonLiteral( val.toString() );
2703 }
2704 
2706 {
2707  QStringList vectors = QgsProviderRegistry::instance()->fileVectorFilters().split( QStringLiteral( ";;" ) );
2708  const QStringList rasters = QgsProviderRegistry::instance()->fileRasterFilters().split( QStringLiteral( ";;" ) );
2709  for ( const QString &raster : rasters )
2710  {
2711  if ( !vectors.contains( raster ) )
2712  vectors << raster;
2713  }
2714  const QStringList meshFilters = QgsProviderRegistry::instance()->fileMeshFilters().split( QStringLiteral( ";;" ) );
2715  for ( const QString &mesh : meshFilters )
2716  {
2717  if ( !vectors.contains( mesh ) )
2718  vectors << mesh;
2719  }
2720  const QStringList pointCloudFilters = QgsProviderRegistry::instance()->filePointCloudFilters().split( QStringLiteral( ";;" ) );
2721  for ( const QString &pointCloud : pointCloudFilters )
2722  {
2723  if ( !vectors.contains( pointCloud ) )
2724  vectors << pointCloud;
2725  }
2726  vectors.removeAll( QObject::tr( "All files (*.*)" ) );
2727  std::sort( vectors.begin(), vectors.end() );
2728 
2729  return QObject::tr( "All files (*.*)" ) + QStringLiteral( ";;" ) + vectors.join( QLatin1String( ";;" ) );
2730 }
2731 
2733 {
2734  return createAllMapLayerFileFilter();
2735 }
2736 
2738 {
2739  QString code = QStringLiteral( "##%1=" ).arg( mName );
2740  if ( mFlags & FlagOptional )
2741  code += QLatin1String( "optional " );
2742  code += QLatin1String( "layer " );
2743 
2744  for ( const int type : mDataTypes )
2745  {
2746  switch ( type )
2747  {
2749  code += QLatin1String( "hasgeometry " );
2750  break;
2751 
2753  code += QLatin1String( "point " );
2754  break;
2755 
2757  code += QLatin1String( "line " );
2758  break;
2759 
2761  code += QLatin1String( "polygon " );
2762  break;
2763 
2765  code += QLatin1String( "raster " );
2766  break;
2767 
2769  code += QLatin1String( "mesh " );
2770  break;
2771 
2773  code += QLatin1String( "plugin " );
2774  break;
2775 
2777  code += QLatin1String( "pointcloud " );
2778  break;
2779 
2781  code += QLatin1String( "annotation " );
2782  break;
2783  }
2784  }
2785 
2786  code += mDefault.toString();
2787  return code.trimmed();
2788 }
2789 
2790 QgsProcessingParameterMapLayer *QgsProcessingParameterMapLayer::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
2791 {
2792  QList< int > types;
2793  QString def = definition;
2794  while ( true )
2795  {
2796  if ( def.startsWith( QLatin1String( "hasgeometry" ), Qt::CaseInsensitive ) )
2797  {
2799  def = def.mid( 12 );
2800  continue;
2801  }
2802  else if ( def.startsWith( QLatin1String( "point" ), Qt::CaseInsensitive ) )
2803  {
2805  def = def.mid( 6 );
2806  continue;
2807  }
2808  else if ( def.startsWith( QLatin1String( "line" ), Qt::CaseInsensitive ) )
2809  {
2811  def = def.mid( 5 );
2812  continue;
2813  }
2814  else if ( def.startsWith( QLatin1String( "polygon" ), Qt::CaseInsensitive ) )
2815  {
2817  def = def.mid( 8 );
2818  continue;
2819  }
2820  else if ( def.startsWith( QLatin1String( "raster" ), Qt::CaseInsensitive ) )
2821  {
2822  types << QgsProcessing::TypeRaster;
2823  def = def.mid( 7 );
2824  continue;
2825  }
2826  else if ( def.startsWith( QLatin1String( "mesh" ), Qt::CaseInsensitive ) )
2827  {
2828  types << QgsProcessing::TypeMesh;
2829  def = def.mid( 5 );
2830  continue;
2831  }
2832  else if ( def.startsWith( QLatin1String( "plugin" ), Qt::CaseInsensitive ) )
2833  {
2834  types << QgsProcessing::TypePlugin;
2835  def = def.mid( 7 );
2836  continue;
2837  }
2838  else if ( def.startsWith( QLatin1String( "pointcloud" ), Qt::CaseInsensitive ) )
2839  {
2841  def = def.mid( 11 );
2842  continue;
2843  }
2844  else if ( def.startsWith( QLatin1String( "annotation" ), Qt::CaseInsensitive ) )
2845  {
2847  def = def.mid( 11 );
2848  continue;
2849  }
2850  break;
2851  }
2852 
2853  return new QgsProcessingParameterMapLayer( name, description, def, isOptional, types );
2854 }
2855 
2857 {
2858  switch ( outputType )
2859  {
2861  {
2862  QString code = QStringLiteral( "QgsProcessingParameterMapLayer('%1', %2" )
2864  if ( mFlags & FlagOptional )
2865  code += QLatin1String( ", optional=True" );
2866 
2868  code += QStringLiteral( ", defaultValue=%1" ).arg( valueAsPythonString( mDefault, c ) );
2869 
2870  if ( !mDataTypes.empty() )
2871  {
2872  QStringList options;
2873  options.reserve( mDataTypes.size() );
2874  for ( const int t : mDataTypes )
2875  options << QStringLiteral( "QgsProcessing.%1" ).arg( QgsProcessing::sourceTypeToString( static_cast< QgsProcessing::SourceType >( t ) ) );
2876  code += QStringLiteral( ", types=[%1])" ).arg( options.join( ',' ) );
2877  }
2878  else
2879  {
2880  code += QLatin1Char( ')' );
2881  }
2882 
2883  return code;
2884  }
2885  }
2886  return QString();
2887 }
2888 
2890 {
2892  QVariantList types;
2893  for ( const int type : mDataTypes )
2894  {
2895  types << type;
2896  }
2897  map.insert( QStringLiteral( "data_types" ), types );
2898  return map;
2899 }
2900 
2902 {
2904  mDataTypes.clear();
2905  const QVariantList values = map.value( QStringLiteral( "data_types" ) ).toList();
2906  for ( const QVariant &val : values )
2907  {
2908  mDataTypes << val.toInt();
2909  }
2910  return true;
2911 }
2912 
2913 QgsProcessingParameterExtent::QgsProcessingParameterExtent( const QString &name, const QString &description, const QVariant &defaultValue, bool optional )
2914  : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
2915 {
2916 
2917 }
2918 
2920 {
2921  return new QgsProcessingParameterExtent( *this );
2922 }
2923 
2925 {
2926  if ( !input.isValid() )
2927  return mFlags & FlagOptional;
2928 
2929  if ( input.canConvert<QgsProcessingFeatureSourceDefinition>() )
2930  {
2931  return true;
2932  }
2933  else if ( input.canConvert<QgsProcessingOutputLayerDefinition>() )
2934  {
2935  return true;
2936  }
2937 
2938  if ( input.canConvert<QgsProperty>() )
2939  {
2940  return true;
2941  }
2942 
2943  if ( input.canConvert< QgsRectangle >() )
2944  {
2945  const QgsRectangle r = input.value<QgsRectangle>();
2946  return !r.isNull();
2947  }
2948  if ( input.canConvert< QgsGeometry >() )
2949  {
2950  return true;
2951  }
2952  if ( input.canConvert< QgsReferencedRectangle >() )
2953  {
2954  const QgsReferencedRectangle r = input.value<QgsReferencedRectangle>();
2955  return !r.isNull();
2956  }
2957 
2958  // direct map layer value
2959  if ( qobject_cast< QgsMapLayer * >( qvariant_cast<QObject *>( input ) ) )
2960  return true;
2961 
2962  if ( input.type() != QVariant::String || input.toString().isEmpty() )
2963  return mFlags & FlagOptional;
2964 
2965  if ( !context )
2966  {
2967  // that's as far as we can get without a context
2968  return true;
2969  }
2970 
2971  const QRegularExpression rx( QStringLiteral( "^(.*?)\\s*,\\s*(.*?)\\s*,\\s*(.*?)\\s*,\\s*(.*?)\\s*(?:\\[(.*)\\])?\\s*$" ) );
2972  const QRegularExpressionMatch match = rx.match( input.toString() );
2973  if ( match.hasMatch() )
2974  {
2975  bool xMinOk = false;
2976  ( void )match.captured( 1 ).toDouble( &xMinOk );
2977  bool xMaxOk = false;
2978  ( void )match.captured( 2 ).toDouble( &xMaxOk );
2979  bool yMinOk = false;
2980  ( void )match.captured( 3 ).toDouble( &yMinOk );
2981  bool yMaxOk = false;
2982  ( void )match.captured( 4 ).toDouble( &yMaxOk );
2983  if ( xMinOk && xMaxOk && yMinOk && yMaxOk )
2984  return true;
2985  }
2986 
2987  // try as layer extent
2988  return QgsProcessingUtils::mapLayerFromString( input.toString(), *context );
2989 }
2990 
2991 QString QgsProcessingParameterExtent::valueAsPythonString( const QVariant &value, QgsProcessingContext &context ) const
2992 {
2993  if ( !value.isValid() )
2994  return QStringLiteral( "None" );
2995 
2996  if ( value.canConvert<QgsProperty>() )
2997  return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
2998 
2999  if ( value.canConvert< QgsRectangle >() )
3000  {
3001  const QgsRectangle r = value.value<QgsRectangle>();
3002  return QStringLiteral( "'%1, %3, %2, %4'" ).arg( qgsDoubleToString( r.xMinimum() ),
3003  qgsDoubleToString( r.yMinimum() ),
3004  qgsDoubleToString( r.xMaximum() ),
3005  qgsDoubleToString( r.yMaximum() ) );
3006  }
3007  else if ( value.canConvert< QgsReferencedRectangle >() )
3008  {
3009  const QgsReferencedRectangle r = value.value<QgsReferencedRectangle>();
3010  return QStringLiteral( "'%1, %3, %2, %4 [%5]'" ).arg( qgsDoubleToString( r.xMinimum() ),
3011  qgsDoubleToString( r.yMinimum() ),
3012  qgsDoubleToString( r.xMaximum() ),
3013  qgsDoubleToString( r.yMaximum() ), r.crs().authid() );
3014  }
3015  else if ( value.canConvert< QgsGeometry >() )
3016  {
3017  const QgsGeometry g = value.value<QgsGeometry>();
3018  if ( !g.isNull() )
3019  {
3020  const QString wkt = g.asWkt();
3021  return QStringLiteral( "QgsGeometry.fromWkt('%1')" ).arg( wkt );
3022  }
3023  }
3024 
3025  QVariantMap p;
3026  p.insert( name(), value );
3027  QgsMapLayer *layer = QgsProcessingParameters::parameterAsLayer( this, p, context );
3028  if ( layer )
3030 
3032 }
3033 
3034 QgsProcessingParameterExtent *QgsProcessingParameterExtent::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
3035 {
3036  return new QgsProcessingParameterExtent( name, description, definition, isOptional );
3037 }
3038 
3039 QgsProcessingParameterPoint::QgsProcessingParameterPoint( const QString &name, const QString &description, const QVariant &defaultValue, bool optional )
3040  : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
3041 {
3042 
3043 }
3044 
3046 {
3047  return new QgsProcessingParameterPoint( *this );
3048 }
3049 
3051 {
3052  if ( !input.isValid() )
3053  return mFlags & FlagOptional;
3054 
3055  if ( input.canConvert<QgsProperty>() )
3056  {
3057  return true;
3058  }
3059 
3060  if ( input.canConvert< QgsPointXY >() )
3061  {
3062  return true;
3063  }
3064  if ( input.canConvert< QgsReferencedPointXY >() )
3065  {
3066  return true;
3067  }
3068  if ( input.canConvert< QgsGeometry >() )
3069  {
3070  return true;
3071  }
3072 
3073  if ( input.type() == QVariant::String )
3074  {
3075  if ( input.toString().isEmpty() )
3076  return mFlags & FlagOptional;
3077  }
3078 
3079  const QRegularExpression rx( QStringLiteral( "^\\s*\\(?\\s*(.*?)\\s*,\\s*(.*?)\\s*(?:\\[(.*)\\])?\\s*\\)?\\s*$" ) );
3080 
3081  const QRegularExpressionMatch match = rx.match( input.toString() );
3082  if ( match.hasMatch() )
3083  {
3084  bool xOk = false;
3085  ( void )match.captured( 1 ).toDouble( &xOk );
3086  bool yOk = false;
3087  ( void )match.captured( 2 ).toDouble( &yOk );
3088  return xOk && yOk;
3089  }
3090  else
3091  return false;
3092 }
3093 
3094 QString QgsProcessingParameterPoint::valueAsPythonString( const QVariant &value, QgsProcessingContext &context ) const
3095 {
3096  if ( !value.isValid() )
3097  return QStringLiteral( "None" );
3098 
3099  if ( value.canConvert<QgsProperty>() )
3100  return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
3101 
3102  if ( value.canConvert< QgsPointXY >() )
3103  {
3104  const QgsPointXY r = value.value<QgsPointXY>();
3105  return QStringLiteral( "'%1,%2'" ).arg( qgsDoubleToString( r.x() ),
3106  qgsDoubleToString( r.y() ) );
3107  }
3108  else if ( value.canConvert< QgsReferencedPointXY >() )
3109  {
3110  const QgsReferencedPointXY r = value.value<QgsReferencedPointXY>();
3111  return QStringLiteral( "'%1,%2 [%3]'" ).arg( qgsDoubleToString( r.x() ),
3112  qgsDoubleToString( r.y() ),
3113  r.crs().authid() );
3114  }
3115  else if ( value.canConvert< QgsGeometry >() )
3116  {
3117  const QgsGeometry g = value.value<QgsGeometry>();
3118  if ( !g.isNull() )
3119  {
3120  const QString wkt = g.asWkt();
3121  return QStringLiteral( "QgsGeometry.fromWkt('%1')" ).arg( wkt );
3122  }
3123  }
3124 
3126 }
3127 
3128 QgsProcessingParameterPoint *QgsProcessingParameterPoint::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
3129 {
3130  return new QgsProcessingParameterPoint( name, description, definition, isOptional );
3131 }
3132 
3133 QgsProcessingParameterGeometry::QgsProcessingParameterGeometry( const QString &name, const QString &description,
3134  const QVariant &defaultValue, bool optional, const QList<int> &geometryTypes, bool allowMultipart )
3135  : QgsProcessingParameterDefinition( name, description, defaultValue, optional ),
3136  mGeomTypes( geometryTypes ),
3137  mAllowMultipart( allowMultipart )
3138 {
3139 
3140 }
3141 
3143 {
3144  return new QgsProcessingParameterGeometry( *this );
3145 }
3146 
3148 {
3149  if ( !input.isValid() )
3150  return mFlags & FlagOptional;
3151 
3152  if ( input.canConvert<QgsProperty>() )
3153  {
3154  return true;
3155  }
3156 
3157  const bool anyTypeAllowed = mGeomTypes.isEmpty() || mGeomTypes.contains( QgsWkbTypes::UnknownGeometry );
3158 
3159  if ( input.canConvert< QgsGeometry >() )
3160  {
3161  return ( anyTypeAllowed || mGeomTypes.contains( input.value<QgsGeometry>().type() ) ) &&
3162  ( mAllowMultipart || !input.value<QgsGeometry>().isMultipart() );
3163  }
3164 
3165  if ( input.canConvert< QgsReferencedGeometry >() )
3166  {
3167  return ( anyTypeAllowed || mGeomTypes.contains( input.value<QgsReferencedGeometry>().type() ) ) &&
3168  ( mAllowMultipart || !input.value<QgsReferencedGeometry>().isMultipart() );
3169  }
3170 
3171  if ( input.canConvert< QgsPointXY >() )
3172  {
3173  return anyTypeAllowed || mGeomTypes.contains( QgsWkbTypes::PointGeometry );
3174  }
3175 
3176  if ( input.canConvert< QgsRectangle >() )
3177  {
3178  return anyTypeAllowed || mGeomTypes.contains( QgsWkbTypes::PolygonGeometry );
3179  }
3180 
3181  if ( input.canConvert< QgsReferencedPointXY >() )
3182  {
3183  return anyTypeAllowed || mGeomTypes.contains( QgsWkbTypes::PointGeometry );
3184  }
3185 
3186  if ( input.canConvert< QgsReferencedRectangle >() )
3187  {
3188  return anyTypeAllowed || mGeomTypes.contains( QgsWkbTypes::PolygonGeometry );
3189  }
3190 
3191  if ( input.type() == QVariant::String )
3192  {
3193  if ( input.toString().isEmpty() )
3194  return mFlags & FlagOptional;
3195  }
3196 
3197  // Match against EWKT
3198  const QRegularExpression rx( QStringLiteral( "^\\s*(?:CRS=(.*);)?(.*?)$" ) );
3199 
3200  const QRegularExpressionMatch match = rx.match( input.toString() );
3201  if ( match.hasMatch() )
3202  {
3203  const QgsGeometry g = QgsGeometry::fromWkt( match.captured( 2 ) );
3204  if ( ! g.isNull() )
3205  {
3206  return ( anyTypeAllowed || mGeomTypes.contains( g.type() ) ) && ( mAllowMultipart || !g.isMultipart() );
3207  }
3208  else
3209  {
3210  QgsMessageLog::logMessage( QObject::tr( "Error creating geometry: \"%1\"" ).arg( g.lastError() ), QObject::tr( "Processing" ) );
3211  }
3212  }
3213  return false;
3214 }
3215 
3216 QString QgsProcessingParameterGeometry::valueAsPythonString( const QVariant &value, QgsProcessingContext &context ) const
3217 {
3219  {
3220  if ( !crs.isValid() )
3222  else
3223  return QgsProcessingUtils::stringToPythonLiteral( QStringLiteral( "CRS=%1;%2" ).arg( crs.authid().isEmpty() ? crs.toWkt( QgsCoordinateReferenceSystem::WKT_PREFERRED ) : crs.authid(), g.asWkt() ) );
3224  };
3225 
3226  if ( !value.isValid() )
3227  return QStringLiteral( "None" );
3228 
3229  if ( value.canConvert<QgsProperty>() )
3230  return QStringLiteral( "QgsProperty.fromExpression(%1)" ).arg( QgsProcessingUtils::stringToPythonLiteral( value.value< QgsProperty >().asExpression() ) );
3231 
3232  if ( value.canConvert< QgsGeometry >() )
3233  {
3234  const QgsGeometry g = value.value<QgsGeometry>();
3235  if ( !g.isNull() )
3236  return asPythonString( g );
3237  }
3238 
3239  if ( value.canConvert< QgsReferencedGeometry >() )
3240  {
3241  const QgsReferencedGeometry g = value.value<QgsReferencedGeometry>();
3242  if ( !g.isNull() )
3243  return asPythonString( g, g.crs() );
3244  }
3245 
3246  if ( value.canConvert< QgsPointXY >() )
3247  {
3248  const QgsGeometry g = QgsGeometry::fromPointXY( value.value<QgsPointXY>() );
3249  if ( !g.isNull() )
3250  return asPythonString( g );
3251  }
3252 
3253  if ( value.canConvert< QgsReferencedPointXY >() )
3254  {
3256  if ( !g.isNull() )
3257  return asPythonString( g, g.crs() );
3258  }
3259 
3260  if ( value.canConvert< QgsRectangle >() )
3261  {
3262  const QgsGeometry g = QgsGeometry::fromRect( value.value<QgsRectangle>() );
3263  if ( !g.isNull() )
3264  return asPythonString( g );
3265  }
3266 
3267  if ( value.canConvert< QgsReferencedRectangle >() )
3268  {
3270  if ( !g.isNull() )
3271  return asPythonString( g, g.crs() );
3272  }
3273 
3275 }
3276 
3278 {
3279  QString code = QStringLiteral( "##%1=" ).arg( mName );
3280  if ( mFlags & FlagOptional )
3281  code += QLatin1String( "optional " );
3282  code += type() + ' ';
3283 
3284  for ( const int type : mGeomTypes )
3285  {
3286  switch ( static_cast<QgsWkbTypes::GeometryType>( type ) )
3287  {
3289  code += QLatin1String( "point " );
3290  break;
3291 
3293  code += QLatin1String( "line " );
3294  break;
3295 
3297  code += QLatin1String( "polygon " );
3298  break;
3299 
3300  default:
3301  code += QLatin1String( "unknown " );
3302  break;
3303  }
3304  }
3305 
3306  code += mDefault.toString();
3307  return code.trimmed();
3308 }
3309 
3311 {
3312  switch ( outputType )
3313  {
3315  {
3316  QString code = QStringLiteral( "QgsProcessingParameterGeometry('%1', %2" )
3318  if ( mFlags & FlagOptional )
3319  code += QLatin1String( ", optional=True" );
3320 
3321  if ( !mGeomTypes.empty() )
3322  {
3323  auto geomTypeToString = []( QgsWkbTypes::GeometryType t ) -> QString
3324  {
3325  switch ( t )
3326  {
3328  return QStringLiteral( "PointGeometry" );
3329 
3331  return QStringLiteral( "LineGeometry" );
3332 
3334  return QStringLiteral( "PolygonGeometry" );
3335 
3337  return QStringLiteral( "UnknownGeometry" );
3338 
3340  return QStringLiteral( "NullGeometry" );
3341  }
3342  return QString();
3343  };
3344 
3345  QStringList options;
3346  options.reserve( mGeomTypes.size() );
3347  for ( const int type : mGeomTypes )
3348  {
3349  options << QStringLiteral( " QgsWkbTypes.%1" ).arg( geomTypeToString( static_cast<QgsWkbTypes::GeometryType>( type ) ) );
3350  }
3351  code += QStringLiteral( ", geometryTypes=[%1 ]" ).arg( options.join( ',' ) );
3352  }
3353 
3354  if ( ! mAllowMultipart )
3355  {
3356  code += QLatin1String( ", allowMultipart=False" );
3357  }
3358 
3360  code += QStringLiteral( ", defaultValue=%1)" ).arg( valueAsPythonString( mDefault, c ) );
3361  return code;
3362  }
3363  }
3364  return QString();
3365 }
3366 
3368 {
3370  QVariantList types;
3371  for ( const int type : mGeomTypes )
3372  {
3373  types << type;
3374  }
3375  map.insert( QStringLiteral( "geometrytypes" ), types );
3376  map.insert( QStringLiteral( "multipart" ), mAllowMultipart );
3377  return map;
3378 }
3379 
3381 {
3383  mGeomTypes.clear();
3384  const QVariantList values = map.value( QStringLiteral( "geometrytypes" ) ).toList();
3385  for ( const QVariant &val : values )
3386  {
3387  mGeomTypes << val.toInt();
3388  }
3389  mAllowMultipart = map.value( QStringLiteral( "multipart" ) ).toBool();
3390  return true;
3391 }
3392 
3393 QgsProcessingParameterGeometry *QgsProcessingParameterGeometry::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
3394 {
3395  return new QgsProcessingParameterGeometry( name, description, definition, isOptional );
3396 }
3397 
3398 QgsProcessingParameterFile::QgsProcessingParameterFile( const QString &name, const QString &description, Behavior behavior, const QString &extension, const QVariant &defaultValue, bool optional, const QString &fileFilter )
3399  : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
3400  , mBehavior( behavior )
3401  , mExtension( fileFilter.isEmpty() ? extension : QString() )
3402  , mFileFilter( fileFilter.isEmpty() && extension.isEmpty() ? QObject::tr( "All files (*.*)" ) : fileFilter )
3403 {
3404 
3405 }
3406 
3408 {
3409  return new QgsProcessingParameterFile( *this );
3410 }
3411 
3413 {
3414  if ( !input.isValid() )
3415  return mFlags & FlagOptional;
3416 
3417  if ( input.canConvert<QgsProperty>() )
3418  {
3419  return true;
3420  }
3421 
3422  const QString string = input.toString().trimmed();
3423 
3424  if ( input.type() != QVariant::String || string.isEmpty() )
3425  return mFlags & FlagOptional;
3426 
3427  switch ( mBehavior )
3428  {
3429  case File:
3430  {
3431  if ( !mExtension.isEmpty() )
3432  {
3433  return string.endsWith( mExtension, Qt::CaseInsensitive );
3434  }
3435  else if ( !mFileFilter.isEmpty() )
3436  {
3437  return QgsFileUtils::fileMatchesFilter( string, mFileFilter );
3438  }
3439  else
3440  {
3441  return true;
3442  }
3443  }
3444 
3445  case Folder:
3446  return true;
3447  }
3448  return true;
3449 }
3450 
3452 {
3453  QString code = QStringLiteral( "##%1=" ).arg( mName );
3454  if ( mFlags & FlagOptional )
3455  code += QLatin1String( "optional " );
3456  code += ( mBehavior == File ? QStringLiteral( "file" ) : QStringLiteral( "folder" ) ) + ' ';
3457  code += mDefault.toString();
3458  return code.trimmed();
3459 }
3460 
3462 {
3463  switch ( outputType )
3464  {
3466  {
3467 
3468  QString code = QStringLiteral( "QgsProcessingParameterFile('%1', %2" )
3470  if ( mFlags & FlagOptional )
3471  code += QLatin1String( ", optional=True" );
3472  code += QStringLiteral( ", behavior=%1" ).arg( mBehavior == File ? QStringLiteral( "QgsProcessingParameterFile.File" ) : QStringLiteral( "QgsProcessingParameterFile.Folder" ) );
3473  if ( !mExtension.isEmpty() )
3474  code += QStringLiteral( ", extension='%1'" ).arg( mExtension );
3475  if ( !mFileFilter.isEmpty() )
3476  code += QStringLiteral( ", fileFilter='%1'" ).arg( mFileFilter );
3478  code += QStringLiteral( ", defaultValue=%1)" ).arg( valueAsPythonString( mDefault, c ) );
3479  return code;
3480  }
3481  }
3482  return QString();
3483 }
3484 
3486 {
3487  switch ( mBehavior )
3488  {
3489  case File:
3490  {
3491  if ( !mFileFilter.isEmpty() )
3492  return mFileFilter != QObject::tr( "All files (*.*)" ) ? mFileFilter + QStringLiteral( ";;" ) + QObject::tr( "All files (*.*)" ) : mFileFilter;
3493  else if ( !mExtension.isEmpty() )
3494  return QObject::tr( "%1 files" ).arg( mExtension.toUpper() ) + QStringLiteral( " (*." ) + mExtension.toLower() + QStringLiteral( ");;" ) + QObject::tr( "All files (*.*)" );
3495  else
3496  return QObject::tr( "All files (*.*)" );
3497  }
3498 
3499  case Folder:
3500  return QString();
3501  }
3502  return QString();
3503 }
3504 
3505 void QgsProcessingParameterFile::setExtension( const QString &extension )
3506 {
3507  mExtension = extension;
3508  mFileFilter.clear();
3509 }
3510 
3512 {
3513  return mFileFilter;
3514 }
3515 
3516 void QgsProcessingParameterFile::setFileFilter( const QString &filter )
3517 {
3518  mFileFilter = filter;
3519  mExtension.clear();
3520 }
3521 
3523 {
3525  map.insert( QStringLiteral( "behavior" ), mBehavior );
3526  map.insert( QStringLiteral( "extension" ), mExtension );
3527  map.insert( QStringLiteral( "filefilter" ), mFileFilter );
3528  return map;
3529 }
3530 
3531 bool QgsProcessingParameterFile::fromVariantMap( const QVariantMap &map )
3532 {
3534  mBehavior = static_cast< Behavior >( map.value( QStringLiteral( "behavior" ) ).toInt() );
3535  mExtension = map.value( QStringLiteral( "extension" ) ).toString();
3536  mFileFilter = map.value( QStringLiteral( "filefilter" ) ).toString();
3537  return true;
3538 }
3539 
3540 QgsProcessingParameterFile *QgsProcessingParameterFile::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition, QgsProcessingParameterFile::Behavior behavior )
3541 {
3542  return new QgsProcessingParameterFile( name, description, behavior, QString(), definition, isOptional );
3543 }
3544 
3545 QgsProcessingParameterMatrix::QgsProcessingParameterMatrix( const QString &name, const QString &description, int numberRows, bool fixedNumberRows, const QStringList &headers, const QVariant &defaultValue, bool optional )
3546  : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
3547  , mHeaders( headers )
3548  , mNumberRows( numberRows )
3549  , mFixedNumberRows( fixedNumberRows )
3550 {
3551 
3552 }
3553 
3555 {
3556  return new QgsProcessingParameterMatrix( *this );
3557 }
3558 
3560 {
3561  if ( !input.isValid() )
3562  return mFlags & FlagOptional;
3563 
3564  if ( input.type() == QVariant::String )
3565  {
3566  if ( input.toString().isEmpty() )
3567  return mFlags & FlagOptional;
3568  return true;
3569  }
3570  else if ( input.type() == QVariant::List )
3571  {
3572  if ( input.toList().isEmpty() )
3573  return mFlags & FlagOptional;
3574  return true;
3575  }
3576  else if ( input.type() == QVariant::Double || input.type() == QVariant::Int )
3577  {
3578  return true;
3579  }
3580 
3581  return false;
3582 }
3583 
3584 QString QgsProcessingParameterMatrix::valueAsPythonString( const QVariant &value, QgsProcessingContext &context ) const
3585 {
3586  if ( !value.isValid() )
3587  return QStringLiteral( "None" );
3588 
3589  if ( value.canConvert<QgsProperty>() )
3590  return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
3591 
3592  QVariantMap p;
3593  p.insert( name(), value );
3594  const QVariantList list = QgsProcessingParameters::parameterAsMatrix( this, p, context );
3595 
3597 }
3598 
3600 {
3601  switch ( outputType )
3602  {
3604  {
3605  QString code = QStringLiteral( "QgsProcessingParameterMatrix('%1', %2" )
3607  if ( mFlags & FlagOptional )
3608  code += QLatin1String( ", optional=True" );
3609  code += QStringLiteral( ", numberRows=%1" ).arg( mNumberRows );
3610  code += QStringLiteral( ", hasFixedNumberRows=%1" ).arg( mFixedNumberRows ? QStringLiteral( "True" ) : QStringLiteral( "False" ) );
3611 
3612  QStringList headers;
3613  headers.reserve( mHeaders.size() );
3614  for ( const QString &h : mHeaders )
3616  code += QStringLiteral( ", headers=[%1]" ).arg( headers.join( ',' ) );
3617 
3619  code += QStringLiteral( ", defaultValue=%1)" ).arg( valueAsPythonString( mDefault, c ) );
3620  return code;
3621  }
3622  }
3623  return QString();
3624 }
3625 
3627 {
3628  return mHeaders;
3629 }
3630 
3631 void QgsProcessingParameterMatrix::setHeaders( const QStringList &headers )
3632 {
3633  mHeaders = headers;
3634 }
3635 
3637 {
3638  return mNumberRows;
3639 }
3640 
3642 {
3643  mNumberRows = numberRows;
3644 }
3645 
3647 {
3648  return mFixedNumberRows;
3649 }
3650 
3652 {
3653  mFixedNumberRows = fixedNumberRows;
3654 }
3655 
3657 {
3659  map.insert( QStringLiteral( "headers" ), mHeaders );
3660  map.insert( QStringLiteral( "rows" ), mNumberRows );
3661  map.insert( QStringLiteral( "fixed_number_rows" ), mFixedNumberRows );
3662  return map;
3663 }
3664 
3665 bool QgsProcessingParameterMatrix::fromVariantMap( const QVariantMap &map )
3666 {
3668  mHeaders = map.value( QStringLiteral( "headers" ) ).toStringList();
3669  mNumberRows = map.value( QStringLiteral( "rows" ) ).toInt();
3670  mFixedNumberRows = map.value( QStringLiteral( "fixed_number_rows" ) ).toBool();
3671  return true;
3672 }
3673 
3674 QgsProcessingParameterMatrix *QgsProcessingParameterMatrix::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
3675 {
3676  return new QgsProcessingParameterMatrix( name, description, 0, false, QStringList(), definition.isEmpty() ? QVariant() : definition, isOptional );
3677 }
3678 
3679 QgsProcessingParameterMultipleLayers::QgsProcessingParameterMultipleLayers( const QString &name, const QString &description, QgsProcessing::SourceType layerType, const QVariant &defaultValue, bool optional )
3680  : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
3681  , mLayerType( layerType )
3682 {
3683 
3684 }
3685 
3687 {
3688  return new QgsProcessingParameterMultipleLayers( *this );
3689 }
3690 
3692 {
3693  if ( !input.isValid() )
3694  return mFlags & FlagOptional;
3695 
3696  if ( mLayerType != QgsProcessing::TypeFile )
3697  {
3698  if ( qobject_cast< QgsMapLayer * >( qvariant_cast<QObject *>( input ) ) )
3699  {
3700  return true;
3701  }
3702  }
3703 
3704  if ( input.type() == QVariant::String )
3705  {
3706  if ( input.toString().isEmpty() )
3707  return mFlags & FlagOptional;
3708 
3709  if ( mMinimumNumberInputs > 1 )
3710  return false;
3711 
3712  if ( !context )
3713  return true;
3714 
3715  if ( mLayerType != QgsProcessing::TypeFile )
3716  return QgsProcessingUtils::mapLayerFromString( input.toString(), *context );
3717  else
3718  return true;
3719  }
3720  else if ( input.type() == QVariant::List )
3721  {
3722  if ( input.toList().count() < mMinimumNumberInputs )
3723  return mFlags & FlagOptional;
3724 
3725  if ( mMinimumNumberInputs > input.toList().count() )
3726  return false;
3727 
3728  if ( !context )
3729  return true;
3730 
3731  if ( mLayerType != QgsProcessing::TypeFile )
3732  {
3733  const auto constToList = input.toList();
3734  for ( const QVariant &v : constToList )
3735  {
3736  if ( qobject_cast< QgsMapLayer * >( qvariant_cast<QObject *>( v ) ) )
3737  continue;
3738 
3739  if ( !QgsProcessingUtils::mapLayerFromString( v.toString(), *context ) )
3740  return false;
3741  }
3742  }
3743  return true;
3744  }
3745  else if ( input.type() == QVariant::StringList )
3746  {
3747  if ( input.toStringList().count() < mMinimumNumberInputs )
3748  return mFlags & FlagOptional;
3749 
3750  if ( mMinimumNumberInputs > input.toStringList().count() )
3751  return false;
3752 
3753  if ( !context )
3754  return true;
3755 
3756  if ( mLayerType != QgsProcessing::TypeFile )
3757  {
3758  const auto constToStringList = input.toStringList();
3759  for ( const QString &v : constToStringList )
3760  {
3761  if ( !QgsProcessingUtils::mapLayerFromString( v, *context ) )
3762  return false;
3763  }
3764  }
3765  return true;
3766  }
3767  return false;
3768 }
3769 
3771 {
3772  if ( !value.isValid() )
3773  return QStringLiteral( "None" );
3774 
3775  if ( value.canConvert<QgsProperty>() )
3776  return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
3777 
3778  if ( mLayerType == QgsProcessing::TypeFile )
3779  {
3780  QStringList parts;
3781  if ( value.type() == QVariant::StringList )
3782  {
3783  const QStringList list = value.toStringList();
3784  parts.reserve( list.count() );
3785  for ( const QString &v : list )
3787  }
3788  else if ( value.type() == QVariant::List )
3789  {
3790  const QVariantList list = value.toList();
3791  parts.reserve( list.count() );
3792  for ( const QVariant &v : list )
3793  parts << QgsProcessingUtils::stringToPythonLiteral( v.toString() );
3794  }
3795  if ( !parts.isEmpty() )
3796  return parts.join( ',' ).prepend( '[' ).append( ']' );
3797  }
3798  else
3799  {
3800  QVariantMap p;
3801  p.insert( name(), value );
3802  const QList<QgsMapLayer *> list = QgsProcessingParameters::parameterAsLayerList( this, p, context );
3803  if ( !list.isEmpty() )
3804  {
3805  QStringList parts;
3806  parts.reserve( list.count() );
3807  for ( const QgsMapLayer *layer : list )
3808  {
3810  }
3811  return parts.join( ',' ).prepend( '[' ).append( ']' );
3812  }
3813  }
3814 
3816 }
3817 
3819 {
3820  QString code = QStringLiteral( "##%1=" ).arg( mName );
3821  if ( mFlags & FlagOptional )
3822  code += QLatin1String( "optional " );
3823  switch ( mLayerType )
3824  {
3826  code += QLatin1String( "multiple raster" );
3827  break;
3828 
3830  code += QLatin1String( "multiple file" );
3831  break;
3832 
3833  default:
3834  code += QLatin1String( "multiple vector" );
3835  break;
3836  }
3837  code += ' ';
3838  if ( mDefault.type() == QVariant::List )
3839  {
3840  QStringList parts;
3841  const auto constToList = mDefault.toList();
3842  for ( const QVariant &var : constToList )
3843  {
3844  parts << var.toString();
3845  }
3846  code += parts.join( ',' );
3847  }
3848  else if ( mDefault.type() == QVariant::StringList )
3849  {
3850  code += mDefault.toStringList().join( ',' );
3851  }
3852  else
3853  {
3854  code += mDefault.toString();
3855  }
3856  return code.trimmed();
3857 }
3858 
3860 {
3861  switch ( outputType )
3862  {
3864  {
3865  QString code = QStringLiteral( "QgsProcessingParameterMultipleLayers('%1', %2" )
3867  if ( mFlags & FlagOptional )
3868  code += QLatin1String( ", optional=True" );
3869 
3870  const QString layerType = QStringLiteral( "QgsProcessing.%1" ).arg( QgsProcessing::sourceTypeToString( mLayerType ) );
3871 
3872  code += QStringLiteral( ", layerType=%1" ).arg( layerType );
3874  code += QStringLiteral( ", defaultValue=%1)" ).arg( valueAsPythonString( mDefault, c ) );
3875  return code;
3876  }
3877  }
3878  return QString();
3879 }
3880 
3882 {
3883  const QStringList exts;
3884  switch ( mLayerType )
3885  {
3887  return QObject::tr( "All files (*.*)" );
3888 
3890  return QgsProviderRegistry::instance()->fileRasterFilters() + QStringLiteral( ";;" ) + QObject::tr( "All files (*.*)" );
3891 
3897  return QgsProviderRegistry::instance()->fileVectorFilters() + QStringLiteral( ";;" ) + QObject::tr( "All files (*.*)" );
3898 
3900  return QgsProviderRegistry::instance()->fileMeshFilters() + QStringLiteral( ";;" ) + QObject::tr( "All files (*.*)" );
3901 
3903  return QgsProviderRegistry::instance()->filePointCloudFilters() + QStringLiteral( ";;" ) + QObject::tr( "All files (*.*)" );
3904 
3908  return createAllMapLayerFileFilter();
3909  }
3910  return QString();
3911 }
3912 
3914 {
3915  return mLayerType;
3916 }
3917 
3919 {
3920  mLayerType = type;
3921 }
3922 
3924 {
3925  return mMinimumNumberInputs;
3926 }
3927 
3929 {
3930  if ( mMinimumNumberInputs >= 1 || !( flags() & QgsProcessingParameterDefinition::FlagOptional ) )
3931  mMinimumNumberInputs = minimumNumberInputs;
3932 }
3933 
3935 {
3937  map.insert( QStringLiteral( "layer_type" ), mLayerType );
3938  map.insert( QStringLiteral( "min_inputs" ), mMinimumNumberInputs );
3939  return map;
3940 }
3941 
3943 {
3945  mLayerType = static_cast< QgsProcessing::SourceType >( map.value( QStringLiteral( "layer_type" ) ).toInt() );
3946  mMinimumNumberInputs = map.value( QStringLiteral( "min_inputs" ) ).toInt();
3947  return true;
3948 }
3949 
3950 QgsProcessingParameterMultipleLayers *QgsProcessingParameterMultipleLayers::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
3951 {
3952  QString type = definition;
3953  QString defaultVal;
3954  const QRegularExpression re( QStringLiteral( "(.*?)\\s+(.*)" ) );
3955  const QRegularExpressionMatch m = re.match( definition );
3956  if ( m.hasMatch() )
3957  {
3958  type = m.captured( 1 ).toLower().trimmed();
3959  defaultVal = m.captured( 2 );
3960  }
3962  if ( type == QLatin1String( "vector" ) )
3964  else if ( type == QLatin1String( "raster" ) )
3966  else if ( type == QLatin1String( "file" ) )
3968  return new QgsProcessingParameterMultipleLayers( name, description, layerType, defaultVal.isEmpty() ? QVariant() : defaultVal, isOptional );
3969 }
3970 
3971 QgsProcessingParameterNumber::QgsProcessingParameterNumber( const QString &name, const QString &description, Type type, const QVariant &defaultValue, bool optional, double minValue, double maxValue )
3972  : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
3973  , mMin( minValue )
3974  , mMax( maxValue )
3975  , mDataType( type )
3976 {
3977  if ( mMin >= mMax )
3978  {
3979  QgsMessageLog::logMessage( QObject::tr( "Invalid number parameter \"%1\": min value %2 is >= max value %3!" ).arg( name ).arg( mMin ).arg( mMax ), QObject::tr( "Processing" ) );
3980  }
3981 }
3982 
3984 {
3985  return new QgsProcessingParameterNumber( *this );
3986 }
3987 
3989 {
3990  QVariant input = value;
3991  if ( !input.isValid() )
3992  {
3993  if ( !defaultValue().isValid() )
3994  return mFlags & FlagOptional;
3995 
3996  input = defaultValue();
3997  }
3998 
3999  if ( input.canConvert<QgsProperty>() )
4000  {
4001  return true;
4002  }
4003 
4004  bool ok = false;
4005  const double res = input.toDouble( &ok );
4006  if ( !ok )
4007  return mFlags & FlagOptional;
4008 
4009  return !( res < mMin || res > mMax );
4010 }
4011 
4013 {
4014  if ( !value.isValid() )
4015  return QStringLiteral( "None" );
4016 
4017  if ( value.canConvert<QgsProperty>() )
4018  return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
4019 
4020  return value.toString();
4021 }
4022 
4024 {
4026  QStringList parts;
4027  if ( mMin > std::numeric_limits<double>::lowest() + 1 )
4028  parts << QObject::tr( "Minimum value: %1" ).arg( mMin );
4029  if ( mMax < std::numeric_limits<double>::max() )
4030  parts << QObject::tr( "Maximum value: %1" ).arg( mMax );
4031  if ( mDefault.isValid() )
4032  parts << QObject::tr( "Default value: %1" ).arg( mDataType == Integer ? mDefault.toInt() : mDefault.toDouble() );
4033  const QString extra = parts.join( QLatin1String( "<br />" ) );
4034  if ( !extra.isEmpty() )
4035  text += QStringLiteral( "<p>%1</p>" ).arg( extra );
4036  return text;
4037 }
4038 
4040 {
4041  switch ( outputType )
4042  {
4044  {
4045  QString code = QStringLiteral( "QgsProcessingParameterNumber('%1', %2" )
4047  if ( mFlags & FlagOptional )
4048  code += QLatin1String( ", optional=True" );
4049 
4050  code += QStringLiteral( ", type=%1" ).arg( mDataType == Integer ? QStringLiteral( "QgsProcessingParameterNumber.Integer" ) : QStringLiteral( "QgsProcessingParameterNumber.Double" ) );
4051 
4052  if ( mMin != std::numeric_limits<double>::lowest() + 1 )
4053  code += QStringLiteral( ", minValue=%1" ).arg( mMin );
4054  if ( mMax != std::numeric_limits<double>::max() )
4055  code += QStringLiteral( ", maxValue=%1" ).arg( mMax );
4057  code += QStringLiteral( ", defaultValue=%1)" ).arg( valueAsPythonString( mDefault, c ) );
4058  return code;
4059  }
4060  }
4061  return QString();
4062 }
4063 
4065 {
4066  return mMin;
4067 }
4068 
4070 {
4071  mMin = min;
4072 }
4073 
4075 {
4076  return mMax;
4077 }
4078 
4080 {
4081  mMax = max;
4082 }
4083 
4085 {
4086  return mDataType;
4087 }
4088 
4090 {
4091  mDataType = dataType;
4092 }
4093 
4095 {
4097  map.insert( QStringLiteral( "min" ), mMin );
4098  map.insert( QStringLiteral( "max" ), mMax );
4099  map.insert( QStringLiteral( "data_type" ), mDataType );
4100  return map;
4101 }
4102 
4103 bool QgsProcessingParameterNumber::fromVariantMap( const QVariantMap &map )
4104 {
4106  mMin = map.value( QStringLiteral( "min" ) ).toDouble();
4107  mMax = map.value( QStringLiteral( "max" ) ).toDouble();
4108  mDataType = static_cast< Type >( map.value( QStringLiteral( "data_type" ) ).toInt() );
4109  return true;
4110 }
4111 
4112 QgsProcessingParameterNumber *QgsProcessingParameterNumber::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
4113 {
4114  return new QgsProcessingParameterNumber( name, description, Double, definition.isEmpty() ? QVariant()
4115  : ( definition.toLower().trimmed() == QLatin1String( "none" ) ? QVariant() : definition ), isOptional );
4116 }
4117 
4118 QgsProcessingParameterRange::QgsProcessingParameterRange( const QString &name, const QString &description, QgsProcessingParameterNumber::Type type, const QVariant &defaultValue, bool optional )
4119  : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
4120  , mDataType( type )
4121 {
4122 
4123 }
4124 
4126 {
4127  return new QgsProcessingParameterRange( *this );
4128 }
4129 
4131 {
4132  if ( !input.isValid() )
4133  return mFlags & FlagOptional;
4134 
4135  if ( input.canConvert<QgsProperty>() )
4136  {
4137  return true;
4138  }
4139 
4140  if ( input.type() == QVariant::String )
4141  {
4142  const QStringList list = input.toString().split( ',' );
4143  if ( list.count() != 2 )
4144  return mFlags & FlagOptional;
4145  bool ok = false;
4146  list.at( 0 ).toDouble( &ok );
4147  bool ok2 = false;
4148  list.at( 1 ).toDouble( &ok2 );
4149  if ( !ok || !ok2 )
4150  return mFlags & FlagOptional;
4151  return true;
4152  }
4153  else if ( input.type() == QVariant::List )
4154  {
4155  if ( input.toList().count() != 2 )
4156  return mFlags & FlagOptional;
4157 
4158  bool ok = false;
4159  input.toList().at( 0 ).toDouble( &ok );
4160  bool ok2 = false;
4161  input.toList().at( 1 ).toDouble( &ok2 );
4162  if ( !ok || !ok2 )
4163  return mFlags & FlagOptional;
4164  return true;
4165  }
4166 
4167  return false;
4168 }
4169 
4170 QString QgsProcessingParameterRange::valueAsPythonString( const QVariant &value, QgsProcessingContext &context ) const
4171 {
4172  if ( !value.isValid() )
4173  return QStringLiteral( "None" );
4174 
4175  if ( value.canConvert<QgsProperty>() )
4176  return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
4177 
4178  QVariantMap p;
4179  p.insert( name(), value );
4180  const QList< double > parts = QgsProcessingParameters::parameterAsRange( this, p, context );
4181 
4182  QStringList stringParts;
4183  const auto constParts = parts;
4184  for ( const double v : constParts )
4185  {
4186  stringParts << QString::number( v );
4187  }
4188  return stringParts.join( ',' ).prepend( '[' ).append( ']' );
4189 }
4190 
4192 {
4193  switch ( outputType )
4194  {
4196  {
4197  QString code = QStringLiteral( "QgsProcessingParameterRange('%1', %2" )
4199  if ( mFlags & FlagOptional )
4200  code += QLatin1String( ", optional=True" );
4201 
4202  code += QStringLiteral( ", type=%1" ).arg( mDataType == QgsProcessingParameterNumber::Integer ? QStringLiteral( "QgsProcessingParameterNumber.Integer" ) : QStringLiteral( "QgsProcessingParameterNumber.Double" ) );
4203 
4205  code += QStringLiteral( ", defaultValue=%1)" ).arg( valueAsPythonString( mDefault, c ) );
4206  return code;
4207  }
4208  }
4209  return QString();
4210 }
4211 
4213 {
4214  return mDataType;
4215 }
4216 
4218 {
4219  mDataType = dataType;
4220 }
4221 
4223 {
4225  map.insert( QStringLiteral( "data_type" ), mDataType );
4226  return map;
4227 }
4228 
4229 bool QgsProcessingParameterRange::fromVariantMap( const QVariantMap &map )
4230 {
4232  mDataType = static_cast< QgsProcessingParameterNumber::Type >( map.value( QStringLiteral( "data_type" ) ).toInt() );
4233  return true;
4234 }
4235 
4236 QgsProcessingParameterRange *QgsProcessingParameterRange::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
4237 {
4238  return new QgsProcessingParameterRange( name, description, QgsProcessingParameterNumber::Double, definition.isEmpty() ? QVariant()
4239  : ( definition.toLower().trimmed() == QLatin1String( "none" ) ? QVariant() : definition ), isOptional );
4240 }
4241 
4242 QgsProcessingParameterRasterLayer::QgsProcessingParameterRasterLayer( const QString &name, const QString &description, const QVariant &defaultValue, bool optional )
4243  : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
4244 {
4245 
4246 }
4247 
4249 {
4250  return new QgsProcessingParameterRasterLayer( *this );
4251 }
4252 
4254 {
4255  if ( !input.isValid() )
4256  return mFlags & FlagOptional;
4257 
4258  if ( input.canConvert<QgsProperty>() )
4259  {
4260  return true;
4261  }
4262 
4263  if ( qobject_cast< QgsRasterLayer * >( qvariant_cast<QObject *>( input ) ) )
4264  return true;
4265 
4266  if ( input.type() != QVariant::String || input.toString().isEmpty() )
4267  return mFlags & FlagOptional;
4268 
4269  if ( !context )
4270  {
4271  // that's as far as we can get without a context
4272  return true;
4273  }
4274 
4275  // try to load as layer
4276  if ( QgsProcessingUtils::mapLayerFromString( input.toString(), *context, true, QgsProcessingUtils::LayerHint::Raster ) )
4277  return true;
4278 
4279  return false;
4280 }
4281 
4283 {
4284  if ( !val.isValid() )
4285  return QStringLiteral( "None" );
4286 
4287  if ( val.canConvert<QgsProperty>() )
4288  return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( val.value< QgsProperty >().asExpression() );
4289 
4290  QVariantMap p;
4291  p.insert( name(), val );
4294  : QgsProcessingUtils::stringToPythonLiteral( val.toString() );
4295 }
4296 
4298 {
4299  return QgsProviderRegistry::instance()->fileRasterFilters() + QStringLiteral( ";;" ) + QObject::tr( "All files (*.*)" );
4300 }
4301 
4302 QgsProcessingParameterRasterLayer *QgsProcessingParameterRasterLayer::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
4303 {
4304  return new QgsProcessingParameterRasterLayer( name, description, definition.isEmpty() ? QVariant() : definition, isOptional );
4305 }
4306 
4307 QgsProcessingParameterEnum::QgsProcessingParameterEnum( const QString &name, const QString &description, const QStringList &options, bool allowMultiple, const QVariant &defaultValue, bool optional, bool usesStaticStrings )
4308  : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
4309  , mOptions( options )
4310  , mAllowMultiple( allowMultiple )
4311  , mUsesStaticStrings( usesStaticStrings )
4312 {
4313 
4314 }
4315 
4317 {
4318  return new QgsProcessingParameterEnum( *this );
4319 }
4320 
4322 {
4323  QVariant input = value;
4324  if ( !input.isValid() )
4325  {
4326  if ( !defaultValue().isValid() )
4327  return mFlags & FlagOptional;
4328 
4329  input = defaultValue();
4330  }
4331 
4332  if ( input.canConvert<QgsProperty>() )
4333  {
4334  return true;
4335  }
4336 
4337  if ( mUsesStaticStrings )
4338  {
4339  if ( input.type() == QVariant::List )
4340  {
4341  if ( !mAllowMultiple )
4342  return false;
4343 
4344  const QVariantList values = input.toList();
4345  if ( values.empty() && !( mFlags & FlagOptional ) )
4346  return false;
4347 
4348  for ( const QVariant &val : values )
4349  {
4350  if ( !mOptions.contains( val.toString() ) )
4351  return false;
4352  }
4353 
4354  return true;
4355  }
4356  else if ( input.type() == QVariant::StringList )
4357  {
4358  if ( !mAllowMultiple )
4359  return false;
4360 
4361  const QStringList values = input.toStringList();
4362 
4363  if ( values.empty() && !( mFlags & FlagOptional ) )
4364  return false;
4365 
4366  if ( values.count() > 1 && !mAllowMultiple )
4367  return false;
4368 
4369  for ( const QString &val : values )
4370  {
4371  if ( !mOptions.contains( val ) )
4372  return false;
4373  }
4374  return true;
4375  }
4376  else if ( input.type() == QVariant::String )
4377  {
4378  const QStringList parts = input.toString().split( ',' );
4379  if ( parts.count() > 1 && !mAllowMultiple )
4380  return false;
4381 
4382  const auto constParts = parts;
4383  for ( const QString &part : constParts )
4384  {
4385  if ( !mOptions.contains( part ) )
4386  return false;
4387  }
4388  return true;
4389  }
4390  }
4391  else
4392  {
4393  if ( input.type() == QVariant::List )
4394  {
4395  if ( !mAllowMultiple )
4396  return false;
4397 
4398  const QVariantList values = input.toList();
4399  if ( values.empty() && !( mFlags & FlagOptional ) )
4400  return false;
4401 
4402  for ( const QVariant &val : values )
4403  {
4404  bool ok = false;
4405  const int res = val.toInt( &ok );
4406  if ( !ok )
4407  return false;
4408  else if ( res < 0 || res >= mOptions.count() )
4409  return false;
4410  }
4411 
4412  return true;
4413  }
4414  else if ( input.type() == QVariant::String )
4415  {
4416  const QStringList parts = input.toString().split( ',' );
4417  if ( parts.count() > 1 && !mAllowMultiple )
4418  return false;
4419 
4420  const auto constParts = parts;
4421  for ( const QString &part : constParts )
4422  {
4423  bool ok = false;
4424  const int res = part.toInt( &ok );
4425  if ( !ok )
4426  return false;
4427  else if ( res < 0 || res >= mOptions.count() )
4428  return false;
4429  }
4430  return true;
4431  }
4432  else if ( input.type() == QVariant::Int || input.type() == QVariant::Double )
4433  {
4434  bool ok = false;
4435  const int res = input.toInt( &ok );
4436  if ( !ok )
4437  return false;
4438  else if ( res >= 0 && res < mOptions.count() )
4439  return true;
4440  }
4441  }
4442 
4443  return false;
4444 }
4445 
4447 {
4448  if ( !value.isValid() )
4449  return QStringLiteral( "None" );
4450 
4451  if ( value.canConvert<QgsProperty>() )
4452  return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
4453 
4454  if ( mUsesStaticStrings )
4455  {
4456  if ( value.type() == QVariant::StringList )
4457  {
4458  QStringList parts;
4459  const QStringList constList = value.toStringList();
4460  for ( const QString &val : constList )
4461  {
4463  }
4464  return parts.join( ',' ).prepend( '[' ).append( ']' );
4465  }
4466  else if ( value.type() == QVariant::String )
4467  {
4468  QStringList parts;
4469  const QStringList constList = value.toString().split( ',' );
4470  if ( constList.count() > 1 )
4471  {
4472  for ( const QString &val : constList )
4473  {
4475  }
4476  return parts.join( ',' ).prepend( '[' ).append( ']' );
4477  }
4478  }
4479 
4480  return QgsProcessingUtils::stringToPythonLiteral( value.toString() );
4481  }
4482  else
4483  {
4484  if ( value.type() == QVariant::List )
4485  {
4486  QStringList parts;
4487  const auto constToList = value.toList();
4488  for ( const QVariant &val : constToList )
4489  {
4490  parts << QString::number( static_cast< int >( val.toDouble() ) );
4491  }
4492  return parts.join( ',' ).prepend( '[' ).append( ']' );
4493  }
4494  else if ( value.type() == QVariant::String )
4495  {
4496  const QStringList parts = value.toString().split( ',' );
4497  if ( parts.count() > 1 )
4498  {
4499  return parts.join( ',' ).prepend( '[' ).append( ']' );
4500  }
4501  }
4502 
4503  return QString::number( static_cast< int >( value.toDouble() ) );
4504  }
4505 }
4506 
4508 {
4509  if ( !value.isValid() )
4510  return QString();
4511 
4512  if ( value.canConvert<QgsProperty>() )
4513  return QString();
4514 
4515  if ( mUsesStaticStrings )
4516  {
4517  return QString();
4518  }
4519  else
4520  {
4521  if ( value.type() == QVariant::List )
4522  {
4523  QStringList parts;
4524  const QVariantList toList = value.toList();
4525  parts.reserve( toList.size() );
4526  for ( const QVariant &val : toList )
4527  {
4528  parts << mOptions.value( static_cast< int >( val.toDouble() ) );
4529  }
4530  return parts.join( ',' );
4531  }
4532  else if ( value.type() == QVariant::String )
4533  {
4534  const QStringList parts = value.toString().split( ',' );
4535  QStringList comments;
4536  if ( parts.count() > 1 )
4537  {
4538  for ( const QString &part : parts )
4539  {
4540  bool ok = false;
4541  const int val = part.toInt( &ok );
4542  if ( ok )
4543  comments << mOptions.value( val );
4544  }
4545  return comments.join( ',' );
4546  }
4547  }
4548 
4549  return mOptions.value( static_cast< int >( value.toDouble() ) );
4550  }
4551 }
4552 
4554 {
4555  QString code = QStringLiteral( "##%1=" ).arg( mName );
4556  if ( mFlags & FlagOptional )
4557  code += QLatin1String( "optional " );
4558  code += QLatin1String( "enum " );
4559 
4560  if ( mAllowMultiple )
4561  code += QLatin1String( "multiple " );
4562 
4563  if ( mUsesStaticStrings )
4564  code += QLatin1String( "static " );
4565 
4566  code += mOptions.join( ';' ) + ' ';
4567 
4568  code += mDefault.toString();
4569  return code.trimmed();
4570 }
4571 
4573 {
4574  switch ( outputType )
4575  {
4577  {
4578  QString code = QStringLiteral( "QgsProcessingParameterEnum('%1', %2" )
4580  if ( mFlags & FlagOptional )
4581  code += QLatin1String( ", optional=True" );
4582 
4583  QStringList options;
4584  options.reserve( mOptions.size() );
4585  for ( const QString &o : mOptions )
4587  code += QStringLiteral( ", options=[%1]" ).arg( options.join( ',' ) );
4588 
4589  code += QStringLiteral( ", allowMultiple=%1" ).arg( mAllowMultiple ? QStringLiteral( "True" ) : QStringLiteral( "False" ) );
4590 
4591  code += QStringLiteral( ", usesStaticStrings=%1" ).arg( mUsesStaticStrings ? QStringLiteral( "True" ) : QStringLiteral( "False" ) );
4592 
4594  code += QStringLiteral( ", defaultValue=%1)" ).arg( valueAsPythonString( mDefault, c ) );
4595 
4596  return code;
4597  }
4598  }
4599  return QString();
4600 }
4601 
4603 {
4604  return mOptions;
4605 }
4606 
4607 void QgsProcessingParameterEnum::setOptions( const QStringList &options )
4608 {
4609  mOptions = options;
4610 }
4611 
4613 {
4614  return mAllowMultiple;
4615 }
4616 
4618 {
4619  mAllowMultiple = allowMultiple;
4620 }
4621 
4623 {
4624  return mUsesStaticStrings;
4625 }
4626 
4628 {
4629  mUsesStaticStrings = usesStaticStrings;
4630 }
4631 
4633 {
4635  map.insert( QStringLiteral( "options" ), mOptions );
4636  map.insert( QStringLiteral( "allow_multiple" ), mAllowMultiple );
4637  map.insert( QStringLiteral( "uses_static_strings" ), mUsesStaticStrings );
4638  return map;
4639 }
4640 
4641 bool QgsProcessingParameterEnum::fromVariantMap( const QVariantMap &map )
4642 {
4644  mOptions = map.value( QStringLiteral( "options" ) ).toStringList();
4645  mAllowMultiple = map.value( QStringLiteral( "allow_multiple" ) ).toBool();
4646  mUsesStaticStrings = map.value( QStringLiteral( "uses_static_strings" ) ).toBool();
4647  return true;
4648 }
4649 
4650 QgsProcessingParameterEnum *QgsProcessingParameterEnum::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
4651 {
4652  QString defaultVal;
4653  QString def = definition;
4654 
4655  bool multiple = false;
4656  if ( def.startsWith( QLatin1String( "multiple" ), Qt::CaseInsensitive ) )
4657  {
4658  multiple = true;
4659  def = def.mid( 9 );
4660  }
4661 
4662  bool staticStrings = false;
4663  if ( def.startsWith( QLatin1String( "static" ), Qt::CaseInsensitive ) )
4664  {
4665  staticStrings = true;
4666  def = def.mid( 7 );
4667  }
4668 
4669  const QRegularExpression re( QStringLiteral( "(.*)\\s+(.*?)$" ) );
4670  const QRegularExpressionMatch m = re.match( def );
4671  QString values = def;
4672  if ( m.hasMatch() )
4673  {
4674  values = m.captured( 1 ).trimmed();
4675  defaultVal = m.captured( 2 );
4676  }
4677 
4678  return new QgsProcessingParameterEnum( name, description, values.split( ';' ), multiple, defaultVal.isEmpty() ? QVariant() : defaultVal, isOptional, staticStrings );
4679 }
4680 
4681 QgsProcessingParameterString::QgsProcessingParameterString( const QString &name, const QString &description, const QVariant &defaultValue, bool multiLine, bool optional )
4682  : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
4683  , mMultiLine( multiLine )
4684 {
4685 
4686 }
4687 
4689 {
4690  return new QgsProcessingParameterString( *this );
4691 }
4692 
4694 {
4695  if ( !value.isValid() || value.isNull() )
4696  return QStringLiteral( "None" );
4697 
4698  if ( value.canConvert<QgsProperty>() )
4699  return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
4700 
4701  const QString s = value.toString();
4703 }
4704 
4706 {
4707  QString code = QStringLiteral( "##%1=" ).arg( mName );
4708  if ( mFlags & FlagOptional )
4709  code += QLatin1String( "optional " );
4710  code += QLatin1String( "string " );
4711 
4712  if ( mMultiLine )
4713  code += QLatin1String( "long " );
4714 
4715  code += mDefault.toString();
4716  return code.trimmed();
4717 }
4718 
4720 {
4721  switch ( outputType )
4722  {
4724  {
4725  QString code = QStringLiteral( "QgsProcessingParameterString('%1', %2" )
4727  if ( mFlags & FlagOptional )
4728  code += QLatin1String( ", optional=True" );
4729  code += QStringLiteral( ", multiLine=%1" ).arg( mMultiLine ? QStringLiteral( "True" ) : QStringLiteral( "False" ) );
4730 
4732  code += QStringLiteral( ", defaultValue=%1)" ).arg( valueAsPythonString( mDefault, c ) );
4733  return code;
4734  }
4735  }
4736  return QString();
4737 }
4738 
4740 {
4741  return mMultiLine;
4742 }
4743 
4745 {
4746  mMultiLine = multiLine;
4747 }
4748 
4750 {
4752  map.insert( QStringLiteral( "multiline" ), mMultiLine );
4753  return map;
4754 }
4755 
4756 bool QgsProcessingParameterString::fromVariantMap( const QVariantMap &map )
4757 {
4759  mMultiLine = map.value( QStringLiteral( "multiline" ) ).toBool();
4760  return true;
4761 }
4762 
4763 QgsProcessingParameterString *QgsProcessingParameterString::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
4764 {
4765  QString def = definition;
4766  bool multiLine = false;
4767  if ( def.startsWith( QLatin1String( "long" ), Qt::CaseInsensitive ) )
4768  {
4769  multiLine = true;
4770  def = def.mid( 5 );
4771  }
4772 
4773  if ( def.startsWith( '"' ) || def.startsWith( '\'' ) )
4774  def = def.mid( 1 );
4775  if ( def.endsWith( '"' ) || def.endsWith( '\'' ) )
4776  def.chop( 1 );
4777 
4778  QVariant defaultValue = def;
4779  if ( def == QLatin1String( "None" ) )
4780  defaultValue = QVariant();
4781 
4783 }
4784 
4785 //
4786 // QgsProcessingParameterAuthConfig
4787 //
4788 
4789 QgsProcessingParameterAuthConfig::QgsProcessingParameterAuthConfig( const QString &name, const QString &description, const QVariant &defaultValue, bool optional )
4790  : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
4791 {
4792 
4793 }
4794 
4796 {
4797  return new QgsProcessingParameterAuthConfig( *this );
4798 }
4799 
4801 {
4802  if ( !value.isValid() )
4803  return QStringLiteral( "None" );
4804 
4805  const QString s = value.toString();
4807 }
4808 
4810 {
4811  QString code = QStringLiteral( "##%1=" ).arg( mName );
4812  if ( mFlags & FlagOptional )
4813  code += QLatin1String( "optional " );
4814  code += QLatin1String( "authcfg " );
4815 
4816  code += mDefault.toString();
4817  return code.trimmed();
4818 }
4819 
4820 QgsProcessingParameterAuthConfig *QgsProcessingParameterAuthConfig::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
4821 {
4822  QString def = definition;
4823 
4824  if ( def.startsWith( '"' ) || def.startsWith( '\'' ) )
4825  def = def.mid( 1 );
4826  if ( def.endsWith( '"' ) || def.endsWith( '\'' ) )
4827  def.chop( 1 );
4828 
4829  QVariant defaultValue = def;
4830  if ( def == QLatin1String( "None" ) )
4831  defaultValue = QVariant();
4832 
4833  return new QgsProcessingParameterAuthConfig( name, description, defaultValue, isOptional );
4834 }
4835 
4836 
4837 //
4838 // QgsProcessingParameterExpression
4839 //
4840 
4841 QgsProcessingParameterExpression::QgsProcessingParameterExpression( const QString &name, const QString &description, const QVariant &defaultValue, const QString &parentLayerParameterName, bool optional )
4842  : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
4843  , mParentLayerParameterName( parentLayerParameterName )
4844 {
4845 
4846 }
4847 
4849 {
4850  return new QgsProcessingParameterExpression( *this );
4851 }
4852 
4854 {
4855  if ( !value.isValid() )
4856  return QStringLiteral( "None" );
4857 
4858  if ( value.canConvert<QgsProperty>() )
4859  return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
4860 
4861  const QString s = value.toString();
4863 }
4864 
4866 {
4867  QStringList depends;
4868  if ( !mParentLayerParameterName.isEmpty() )
4869  depends << mParentLayerParameterName;
4870  return depends;
4871 }
4872 
4874 {
4875  switch ( outputType )
4876  {
4878  {
4879  QString code = QStringLiteral( "QgsProcessingParameterExpression('%1', %2" )
4881  if ( mFlags & FlagOptional )
4882  code += QLatin1String( ", optional=True" );
4883 
4884  code += QStringLiteral( ", parentLayerParameterName='%1'" ).arg( mParentLayerParameterName );
4885 
4887  code += QStringLiteral( ", defaultValue=%1)" ).arg( valueAsPythonString( mDefault, c ) );
4888  return code;
4889  }
4890  }
4891  return QString();
4892 }
4893 
4895 {
4896  return mParentLayerParameterName;
4897 }
4898 
4899 void QgsProcessingParameterExpression::setParentLayerParameterName( const QString &parentLayerParameterName )
4900 {
4901  mParentLayerParameterName = parentLayerParameterName;
4902 }
4903 
4905 {
4907  map.insert( QStringLiteral( "parent_layer" ), mParentLayerParameterName );
4908  return map;
4909 }
4910 
4912 {
4914  mParentLayerParameterName = map.value( QStringLiteral( "parent_layer" ) ).toString();
4915  return true;
4916 }
4917 
4918 QgsProcessingParameterExpression *QgsProcessingParameterExpression::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
4919 {
4920  return new QgsProcessingParameterExpression( name, description, definition, QString(), isOptional );
4921 }
4922 
4923 QgsProcessingParameterVectorLayer::QgsProcessingParameterVectorLayer( const QString &name, const QString &description, const QList<int> &types, const QVariant &defaultValue, bool optional )
4924  : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
4926 {
4927 
4928 }
4929 
4931 {
4932  return new QgsProcessingParameterVectorLayer( *this );
4933 }
4934 
4936 {
4937  if ( !v.isValid() )
4938  return mFlags & FlagOptional;
4939 
4940  QVariant var = v;
4941 
4942  if ( var.canConvert<QgsProperty>() )
4943  {
4944  const QgsProperty p = var.value< QgsProperty >();
4946  {
4947  var = p.staticValue();
4948  }
4949  else
4950  {
4951  return true;
4952  }
4953  }
4954 
4955  if ( qobject_cast< QgsVectorLayer * >( qvariant_cast<QObject *>( var ) ) )
4956  return true;
4957 
4958  if ( var.type() != QVariant::String || var.toString().isEmpty() )
4959  return mFlags & FlagOptional;
4960 
4961  if ( !context )
4962  {
4963  // that's as far as we can get without a context
4964  return true;
4965  }
4966 
4967  // try to load as layer
4968  if ( QgsProcessingUtils::mapLayerFromString( var.toString(), *context, true, QgsProcessingUtils::LayerHint::Vector ) )
4969  return true;
4970 
4971  return false;
4972 }
4973 
4975 {
4976  if ( !val.isValid() )
4977  return QStringLiteral( "None" );
4978 
4979  if ( val.canConvert<QgsProperty>() )
4980  return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( val.value< QgsProperty >().asExpression() );
4981 
4982  QVariantMap p;
4983  p.insert( name(), val );
4986  : QgsProcessingUtils::stringToPythonLiteral( val.toString() );
4987 }
4988 
4990 {
4991  switch ( outputType )
4992  {
4994  {
4995  QString code = QStringLiteral( "QgsProcessingParameterVectorLayer('%1', %2" )
4997  if ( mFlags & FlagOptional )
4998  code += QLatin1String( ", optional=True" );
4999 
5000  if ( !mDataTypes.empty() )
5001  {
5002  QStringList options;
5003  for ( const int t : mDataTypes )
5004  options << QStringLiteral( "QgsProcessing.%1" ).arg( QgsProcessing::sourceTypeToString( static_cast< QgsProcessing::SourceType >( t ) ) );
5005  code += QStringLiteral( ", types=[%1]" ).arg( options.join( ',' ) );
5006  }
5007 
5009  code += QStringLiteral( ", defaultValue=%1)" ).arg( valueAsPythonString( mDefault, c ) );
5010  return code;
5011  }
5012  }
5013  return QString();
5014 }
5015 
5017 {
5018  return QgsProviderRegistry::instance()->fileVectorFilters() + QStringLiteral( ";;" ) + QObject::tr( "All files (*.*)" );
5019 }
5020 
5022 {
5023  return mDataTypes;
5024 }
5025 
5027 {
5028  mDataTypes = types;
5029 }
5030 
5032 {
5034  QVariantList types;
5035  for ( const int type : mDataTypes )
5036  {
5037  types << type;
5038  }
5039  map.insert( QStringLiteral( "data_types" ), types );
5040  return map;
5041 }
5042 
5044 {
5046  mDataTypes.clear();
5047  const QVariantList values = map.value( QStringLiteral( "data_types" ) ).toList();
5048  for ( const QVariant &val : values )
5049  {
5050  mDataTypes << val.toInt();
5051  }
5052  return true;
5053 }
5054 
5055 QgsProcessingParameterVectorLayer *QgsProcessingParameterVectorLayer::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
5056 {
5057  return new QgsProcessingParameterVectorLayer( name, description, QList< int>(), definition.isEmpty() ? QVariant() : definition, isOptional );
5058 }
5059 
5060 QgsProcessingParameterMeshLayer::QgsProcessingParameterMeshLayer( const QString &name, const QString &description,
5061  const QVariant &defaultValue, bool optional )
5062  : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
5063 {
5064 
5065 }
5066 
5068 {
5069  return new QgsProcessingParameterMeshLayer( *this );
5070 }
5071 
5073 {
5074  if ( !v.isValid() )
5075  return mFlags & FlagOptional;
5076 
5077  QVariant var = v;
5078 
5079  if ( var.canConvert<QgsProperty>() )
5080  {
5081  const QgsProperty p = var.value< QgsProperty >();
5083  {
5084  var = p.staticValue();
5085  }
5086  else
5087  {
5088  return true;
5089  }
5090  }
5091 
5092  if ( qobject_cast< QgsMeshLayer * >( qvariant_cast<QObject *>( var ) ) )
5093  return true;
5094 
5095  if ( var.type() != QVariant::String || var.toString().isEmpty() )
5096  return mFlags & FlagOptional;
5097 
5098  if ( !context )
5099  {
5100  // that's as far as we can get without a context
5101  return true;
5102  }
5103 
5104  // try to load as layer
5105  if ( QgsProcessingUtils::mapLayerFromString( var.toString(), *context, true, QgsProcessingUtils::LayerHint::Mesh ) )
5106  return true;
5107 
5108  return false;
5109 }
5110 
5112 {
5113  if ( !val.isValid() )
5114  return QStringLiteral( "None" );
5115 
5116  if ( val.canConvert<QgsProperty>() )
5117  return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( val.value< QgsProperty >().asExpression() );
5118 
5119  QVariantMap p;
5120  p.insert( name(), val );
5121  QgsMeshLayer *layer = QgsProcessingParameters::parameterAsMeshLayer( this, p, context );
5123  : QgsProcessingUtils::stringToPythonLiteral( val.toString() );
5124 }
5125 
5127 {
5128  return QgsProviderRegistry::instance()->fileMeshFilters() + QStringLiteral( ";;" ) + QObject::tr( "All files (*.*)" );
5129 }
5130 
5131 QgsProcessingParameterMeshLayer *QgsProcessingParameterMeshLayer::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
5132 {
5133  return new QgsProcessingParameterMeshLayer( name, description, definition.isEmpty() ? QVariant() : definition, isOptional );
5134 }
5135 
5136 QgsProcessingParameterField::QgsProcessingParameterField( const QString &name, const QString &description, const QVariant &defaultValue, const QString &parentLayerParameterName, DataType type, bool allowMultiple, bool optional, bool defaultToAllFields )
5137  : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
5138  , mParentLayerParameterName( parentLayerParameterName )
5139  , mDataType( type )
5140  , mAllowMultiple( allowMultiple )
5141  , mDefaultToAllFields( defaultToAllFields )
5142 {
5143 
5144 }
5145 
5146 
5148 {
5149  return new QgsProcessingParameterField( *this );
5150 }
5151 
5153 {
5154  if ( !input.isValid() )
5155  return mFlags & FlagOptional;
5156 
5157  if ( input.canConvert<QgsProperty>() )
5158  {
5159  return true;
5160  }
5161 
5162  if ( input.type() == QVariant::List || input.type() == QVariant::StringList )
5163  {
5164  if ( !mAllowMultiple )
5165  return false;
5166 
5167  if ( input.toList().isEmpty() && !( mFlags & FlagOptional ) )
5168  return false;
5169  }
5170  else if ( input.type() == QVariant::String )
5171  {
5172  if ( input.toString().isEmpty() )
5173  return mFlags & FlagOptional;
5174 
5175  const QStringList parts = input.toString().split( ';' );
5176  if ( parts.count() > 1 && !mAllowMultiple )
5177  return false;
5178  }
5179  else
5180  {
5181  if ( input.toString().isEmpty() )
5182  return mFlags & FlagOptional;
5183  }
5184  return true;
5185 }
5186 
5188 {
5189  if ( !value.isValid() )
5190  return QStringLiteral( "None" );
5191 
5192  if ( value.canConvert<QgsProperty>() )
5193  return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
5194 
5195  if ( value.type() == QVariant::List )
5196  {
5197  QStringList parts;
5198  const auto constToList = value.toList();
5199  for ( const QVariant &val : constToList )
5200  {
5201  parts << QgsProcessingUtils::stringToPythonLiteral( val.toString() );
5202  }
5203  return parts.join( ',' ).prepend( '[' ).append( ']' );
5204  }
5205  else if ( value.type() == QVariant::StringList )
5206  {
5207  QStringList parts;
5208  const auto constToStringList = value.toStringList();
5209  for ( const QString &s : constToStringList )
5210  {
5212  }
5213  return parts.join( ',' ).prepend( '[' ).append( ']' );
5214  }
5215 
5216  return QgsProcessingUtils::stringToPythonLiteral( value.toString() );
5217 }
5218 
5220 {
5221  QString code = QStringLiteral( "##%1=" ).arg( mName );
5222  if ( mFlags & FlagOptional )
5223  code += QLatin1String( "optional " );
5224  code += QLatin1String( "field " );
5225 
5226  switch ( mDataType )
5227  {
5228  case Numeric:
5229  code += QLatin1String( "numeric " );
5230  break;
5231 
5232  case String:
5233  code += QLatin1String( "string " );
5234  break;
5235 
5236  case DateTime:
5237  code += QLatin1String( "datetime " );
5238  break;
5239 
5240  case Any:
5241  break;
5242  }
5243 
5244  if ( mAllowMultiple )
5245  code += QLatin1String( "multiple " );
5246 
5247  if ( mDefaultToAllFields )
5248  code += QLatin1String( "default_to_all_fields " );
5249 
5250  code += mParentLayerParameterName + ' ';
5251 
5252  code += mDefault.toString();
5253  return code.trimmed();
5254 }
5255 
5257 {
5258  switch ( outputType )
5259  {
5261  {
5262  QString code = QStringLiteral( "QgsProcessingParameterField('%1', %2" )
5264  if ( mFlags & FlagOptional )
5265  code += QLatin1String( ", optional=True" );
5266 
5267  QString dataType;
5268  switch ( mDataType )
5269  {
5270  case Any:
5271  dataType = QStringLiteral( "QgsProcessingParameterField.Any" );
5272  break;
5273 
5274  case Numeric:
5275  dataType = QStringLiteral( "QgsProcessingParameterField.Numeric" );
5276  break;
5277 
5278  case String:
5279  dataType = QStringLiteral( "QgsProcessingParameterField.String" );
5280  break;
5281 
5282  case DateTime:
5283  dataType = QStringLiteral( "QgsProcessingParameterField.DateTime" );
5284  break;
5285  }
5286  code += QStringLiteral( ", type=%1" ).arg( dataType );
5287 
5288  code += QStringLiteral( ", parentLayerParameterName='%1'" ).arg( mParentLayerParameterName );
5289  code += QStringLiteral( ", allowMultiple=%1" ).arg( mAllowMultiple ? QStringLiteral( "True" ) : QStringLiteral( "False" ) );
5291  code += QStringLiteral( ", defaultValue=%1" ).arg( valueAsPythonString( mDefault, c ) );
5292 
5293  if ( mDefaultToAllFields )
5294  code += QLatin1String( ", defaultToAllFields=True" );
5295 
5296  code += ')';
5297 
5298  return code;
5299  }
5300  }
5301  return QString();
5302 }
5303 
5305 {
5306  QStringList depends;
5307  if ( !mParentLayerParameterName.isEmpty() )
5308  depends << mParentLayerParameterName;
5309  return depends;
5310 }
5311 
5313 {
5314  return mParentLayerParameterName;
5315 }
5316 
5317 void QgsProcessingParameterField::setParentLayerParameterName( const QString &parentLayerParameterName )
5318 {
5319  mParentLayerParameterName = parentLayerParameterName;
5320 }
5321 
5323 {
5324  return mDataType;
5325 }
5326 
5328 {
5329  mDataType = dataType;
5330 }
5331 
5333 {
5334  return mAllowMultiple;
5335 }
5336 
5338 {
5339  mAllowMultiple = allowMultiple;
5340 }
5341 
5343 {
5344  return mDefaultToAllFields;
5345 }
5346 
5348 {
5349  mDefaultToAllFields = enabled;
5350 }
5351 
5353 {
5355  map.insert( QStringLiteral( "parent_layer" ), mParentLayerParameterName );
5356  map.insert( QStringLiteral( "data_type" ), mDataType );
5357  map.insert( QStringLiteral( "allow_multiple" ), mAllowMultiple );
5358  map.insert( QStringLiteral( "default_to_all_fields" ), mDefaultToAllFields );
5359  return map;
5360 }
5361 
5362 bool QgsProcessingParameterField::fromVariantMap( const QVariantMap &map )
5363 {
5365  mParentLayerParameterName = map.value( QStringLiteral( "parent_layer" ) ).toString();
5366  mDataType = static_cast< DataType >( map.value( QStringLiteral( "data_type" ) ).toInt() );
5367  mAllowMultiple = map.value( QStringLiteral( "allow_multiple" ) ).toBool();
5368  mDefaultToAllFields = map.value( QStringLiteral( "default_to_all_fields" ) ).toBool();
5369  return true;
5370 }
5371 
5372 QgsProcessingParameterField *QgsProcessingParameterField::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
5373 {
5374  QString parent;
5375  DataType type = Any;
5376  bool allowMultiple = false;
5377  bool defaultToAllFields = false;
5378  QString def = definition;
5379 
5380  if ( def.startsWith( QLatin1String( "numeric " ), Qt::CaseInsensitive ) )
5381  {
5382  type = Numeric;
5383  def = def.mid( 8 );
5384  }
5385  else if ( def.startsWith( QLatin1String( "string " ), Qt::CaseInsensitive ) )
5386  {
5387  type = String;
5388  def = def.mid( 7 );
5389  }
5390  else if ( def.startsWith( QLatin1String( "datetime " ), Qt::CaseInsensitive ) )
5391  {
5392  type = DateTime;
5393  def = def.mid( 9 );
5394  }
5395 
5396  if ( def.startsWith( QLatin1String( "multiple" ), Qt::CaseInsensitive ) )
5397  {
5398  allowMultiple = true;
5399  def = def.mid( 8 ).trimmed();
5400  }
5401 
5402  if ( def.startsWith( QLatin1String( "default_to_all_fields" ), Qt::CaseInsensitive ) )
5403  {
5404  defaultToAllFields = true;
5405  def = def.mid( 21 ).trimmed();
5406  }
5407 
5408  const QRegularExpression re( QStringLiteral( "(.*?)\\s+(.*)$" ) );
5409  const QRegularExpressionMatch m = re.match( def );
5410  if ( m.hasMatch() )
5411  {
5412  parent = m.captured( 1 ).trimmed();
5413  def = m.captured( 2 );
5414  }
5415  else
5416  {
5417  parent = def;
5418  def.clear();
5419  }
5420 
5421  return new QgsProcessingParameterField( name, description, def.isEmpty() ? QVariant() : def, parent, type, allowMultiple, isOptional, defaultToAllFields );
5422 }
5423 
5424 QgsProcessingParameterFeatureSource::QgsProcessingParameterFeatureSource( const QString &name, const QString &description, const QList<int> &types, const QVariant &defaultValue, bool optional )
5425  : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
5427 {
5428 
5429 }
5430 
5432 {
5433  return new QgsProcessingParameterFeatureSource( *this );
5434 }
5435 
5437 {
5438  QVariant var = input;
5439  if ( !var.isValid() )
5440  return mFlags & FlagOptional;
5441 
5442  if ( var.canConvert<QgsProcessingFeatureSourceDefinition>() )
5443  {
5444  const QgsProcessingFeatureSourceDefinition fromVar = qvariant_cast<QgsProcessingFeatureSourceDefinition>( var );
5445  var = fromVar.source;
5446  }
5447  else if ( var.canConvert<QgsProcessingOutputLayerDefinition>() )
5448  {
5449  // input is a QgsProcessingOutputLayerDefinition - get extra properties from it
5450  const QgsProcessingOutputLayerDefinition fromVar = qvariant_cast<QgsProcessingOutputLayerDefinition>( var );
5451  var = fromVar.sink;
5452  }
5453 
5454  if ( var.canConvert<QgsProperty>() )
5455  {
5456  const QgsProperty p = var.value< QgsProperty >();
5458  {
5459  var = p.staticValue();
5460  }
5461  else
5462  {
5463  return true;
5464  }
5465  }
5466  if ( qobject_cast< QgsVectorLayer * >( qvariant_cast<QObject *>( input ) ) )
5467  {
5468  return true;
5469  }
5470 
5471  if ( var.type() != QVariant::String || var.toString().isEmpty() )
5472  return mFlags & FlagOptional;
5473 
5474  if ( !context )
5475  {
5476  // that's as far as we can get without a context
5477  return true;
5478  }
5479 
5480  // try to load as layer
5481  if ( QgsProcessingUtils::mapLayerFromString( var.toString(), *context, true, QgsProcessingUtils::LayerHint::Vector ) )
5482  return true;
5483 
5484  return false;
5485 }
5486 
5488 {
5489  if ( !value.isValid() )
5490  return QStringLiteral(