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