QGIS API Documentation  3.16.0-Hannover (43b64b13f3)
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  const QVariantMap &createOptions, const QStringList &datasourceOptions, const QStringList &layerOptions )
566 {
567  QVariant val;
568  if ( definition )
569  {
570  val = parameters.value( definition->name() );
571  }
572 
573  return parameterAsSink( definition, val, fields, geometryType, crs, context, destinationIdentifier, sinkFlags, createOptions, datasourceOptions, layerOptions );
574 }
575 
576 QgsFeatureSink *QgsProcessingParameters::parameterAsSink( const QgsProcessingParameterDefinition *definition, const QVariant &value, const QgsFields &fields, QgsWkbTypes::Type geometryType, const QgsCoordinateReferenceSystem &crs, QgsProcessingContext &context, QString &destinationIdentifier, QgsFeatureSink::SinkFlags sinkFlags, const QVariantMap &createOptions, const QStringList &datasourceOptions, const QStringList &layerOptions )
577 {
578  QVariantMap options = createOptions;
579  QVariant val = value;
580 
581  QgsProject *destinationProject = nullptr;
582  QString destName;
583  QgsRemappingSinkDefinition remapDefinition;
584  bool useRemapDefinition = false;
585  if ( val.canConvert<QgsProcessingOutputLayerDefinition>() )
586  {
587  // input is a QgsProcessingOutputLayerDefinition - get extra properties from it
588  QgsProcessingOutputLayerDefinition fromVar = qvariant_cast<QgsProcessingOutputLayerDefinition>( val );
589  destinationProject = fromVar.destinationProject;
590  options = fromVar.createOptions;
591 
592  val = fromVar.sink;
593  destName = fromVar.destinationName;
594  if ( fromVar.useRemapping() )
595  {
596  useRemapDefinition = true;
597  remapDefinition = fromVar.remappingDefinition();
598  }
599  }
600 
601  QString dest;
602  if ( definition && val.canConvert<QgsProperty>() )
603  {
604  dest = val.value< QgsProperty >().valueAsString( context.expressionContext(), definition->defaultValue().toString() );
605  }
606  else if ( !val.isValid() || val.toString().isEmpty() )
607  {
608  if ( definition && definition->flags() & QgsProcessingParameterDefinition::FlagOptional && !definition->defaultValue().isValid() )
609  {
610  // unset, optional sink, no default => no sink
611  return nullptr;
612  }
613  // fall back to default
614  if ( !definition )
615  {
616  throw QgsProcessingException( QObject::tr( "No parameter definition for the sink" ) );
617  }
618  dest = definition->defaultValue().toString();
619  }
620  else
621  {
622  dest = val.toString();
623  }
624  if ( dest == QgsProcessing::TEMPORARY_OUTPUT )
625  {
626  if ( const QgsProcessingDestinationParameter *destParam = dynamic_cast< const QgsProcessingDestinationParameter * >( definition ) )
627  dest = destParam->generateTemporaryDestination();
628  }
629 
630  if ( dest.isEmpty() )
631  return nullptr;
632 
633  std::unique_ptr< QgsFeatureSink > sink( QgsProcessingUtils::createFeatureSink( dest, context, fields, geometryType, crs, options, datasourceOptions, layerOptions, sinkFlags, useRemapDefinition ? &remapDefinition : nullptr ) );
634  destinationIdentifier = dest;
635 
636  if ( destinationProject )
637  {
638  if ( destName.isEmpty() && definition )
639  {
640  destName = definition->description();
641  }
642  QString outputName;
643  if ( definition )
644  outputName = definition->name();
645  context.addLayerToLoadOnCompletion( destinationIdentifier, QgsProcessingContext::LayerDetails( destName, destinationProject, outputName, QgsProcessingUtils::LayerHint::Vector ) );
646  }
647 
648  return sink.release();
649 }
650 
652 {
653  if ( !definition )
654  return nullptr;
655 
656  return parameterAsSource( definition, parameters.value( definition->name() ), context );
657 }
658 
660 {
661  if ( !definition )
662  return nullptr;
663 
664  return QgsProcessingUtils::variantToSource( value, context, definition->defaultValue() );
665 }
666 
667 QString parameterAsCompatibleSourceLayerPathInternal( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context, const QStringList &compatibleFormats, const QString &preferredFormat, QgsProcessingFeedback *feedback, QString *layerName )
668 {
669  if ( !definition )
670  return QString();
671 
672  QVariant val = parameters.value( definition->name() );
673 
674  bool selectedFeaturesOnly = false;
675  long long featureLimit = -1;
676  if ( val.canConvert<QgsProcessingFeatureSourceDefinition>() )
677  {
678  // input is a QgsProcessingFeatureSourceDefinition - get extra properties from it
679  QgsProcessingFeatureSourceDefinition fromVar = qvariant_cast<QgsProcessingFeatureSourceDefinition>( val );
680  selectedFeaturesOnly = fromVar.selectedFeaturesOnly;
681  featureLimit = fromVar.featureLimit;
682  val = fromVar.source;
683  }
684  else if ( val.canConvert<QgsProcessingOutputLayerDefinition>() )
685  {
686  // input is a QgsProcessingOutputLayerDefinition - get extra properties from it
687  QgsProcessingOutputLayerDefinition fromVar = qvariant_cast<QgsProcessingOutputLayerDefinition>( val );
688  val = fromVar.sink;
689  }
690 
691  if ( val.canConvert<QgsProperty>() )
692  {
693  val = val.value< QgsProperty >().valueAsString( context.expressionContext(), definition->defaultValue().toString() );
694  }
695 
696  QgsVectorLayer *vl = nullptr;
697  vl = qobject_cast< QgsVectorLayer * >( qvariant_cast<QObject *>( val ) );
698 
699  if ( !vl )
700  {
701  QString layerRef;
702  if ( val.canConvert<QgsProperty>() )
703  {
704  layerRef = val.value< QgsProperty >().valueAsString( context.expressionContext(), definition->defaultValue().toString() );
705  }
706  else if ( !val.isValid() || val.toString().isEmpty() )
707  {
708  // fall back to default
709  val = definition->defaultValue();
710 
711  // default value may be a vector layer
712  vl = qobject_cast< QgsVectorLayer * >( qvariant_cast<QObject *>( val ) );
713  if ( !vl )
714  layerRef = definition->defaultValue().toString();
715  }
716  else
717  {
718  layerRef = val.toString();
719  }
720 
721  if ( !vl )
722  {
723  if ( layerRef.isEmpty() )
724  return QString();
725 
726  vl = qobject_cast< QgsVectorLayer *>( QgsProcessingUtils::mapLayerFromString( layerRef, context, true, QgsProcessingUtils::LayerHint::Vector ) );
727  }
728  }
729 
730  if ( !vl )
731  return QString();
732 
733  if ( layerName )
734  return QgsProcessingUtils::convertToCompatibleFormatAndLayerName( vl, selectedFeaturesOnly, definition->name(),
735  compatibleFormats, preferredFormat, context, feedback, *layerName, featureLimit );
736  else
737  return QgsProcessingUtils::convertToCompatibleFormat( vl, selectedFeaturesOnly, definition->name(),
738  compatibleFormats, preferredFormat, context, feedback, featureLimit );
739 }
740 
741 QString QgsProcessingParameters::parameterAsCompatibleSourceLayerPath( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context, const QStringList &compatibleFormats, const QString &preferredFormat, QgsProcessingFeedback *feedback )
742 {
743  return parameterAsCompatibleSourceLayerPathInternal( definition, parameters, context, compatibleFormats, preferredFormat, feedback, nullptr );
744 }
745 
746 QString QgsProcessingParameters::parameterAsCompatibleSourceLayerPathAndLayerName( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context, const QStringList &compatibleFormats, const QString &preferredFormat, QgsProcessingFeedback *feedback, QString *layerName )
747 {
748  QString *destLayer = layerName;
749  QString tmp;
750  if ( destLayer )
751  destLayer->clear();
752  else
753  destLayer = &tmp;
754 
755  return parameterAsCompatibleSourceLayerPathInternal( definition, parameters, context, compatibleFormats, preferredFormat, feedback, destLayer );
756 }
757 
758 
760 {
761  if ( !definition )
762  return nullptr;
763 
764  return parameterAsLayer( definition, parameters.value( definition->name() ), context, layerHint );
765 }
766 
768 {
769  if ( !definition )
770  return nullptr;
771 
772  QVariant val = value;
773  if ( val.canConvert<QgsProperty>() )
774  {
775  val = val.value< QgsProperty >().valueAsString( context.expressionContext(), definition->defaultValue().toString() );
776  }
777 
778  if ( QgsMapLayer *layer = qobject_cast< QgsMapLayer * >( qvariant_cast<QObject *>( val ) ) )
779  {
780  return layer;
781  }
782 
783  if ( val.canConvert<QgsProcessingOutputLayerDefinition>() )
784  {
785  // input is a QgsProcessingOutputLayerDefinition - get extra properties from it
786  QgsProcessingOutputLayerDefinition fromVar = qvariant_cast<QgsProcessingOutputLayerDefinition>( val );
787  val = fromVar.sink;
788  }
789 
790  if ( val.canConvert<QgsProperty>() && val.value< QgsProperty >().propertyType() == QgsProperty::StaticProperty )
791  {
792  val = val.value< QgsProperty >().staticValue();
793  }
794 
795  if ( !val.isValid() || val.toString().isEmpty() )
796  {
797  // fall back to default
798  val = definition->defaultValue();
799  }
800 
801  if ( QgsMapLayer *layer = qobject_cast< QgsMapLayer * >( qvariant_cast<QObject *>( val ) ) )
802  {
803  return layer;
804  }
805 
806  QString layerRef = val.toString();
807  if ( layerRef.isEmpty() )
808  layerRef = definition->defaultValue().toString();
809 
810  if ( layerRef.isEmpty() )
811  return nullptr;
812 
813  return QgsProcessingUtils::mapLayerFromString( layerRef, context, true, layerHint );
814 }
815 
817 {
818  return qobject_cast< QgsRasterLayer *>( parameterAsLayer( definition, parameters, context, QgsProcessingUtils::LayerHint::Raster ) );
819 }
820 
822 {
823  return qobject_cast< QgsRasterLayer *>( parameterAsLayer( definition, value, context, QgsProcessingUtils::LayerHint::Raster ) );
824 }
825 
827 {
828  return qobject_cast< QgsMeshLayer *>( parameterAsLayer( definition, parameters, context, QgsProcessingUtils::LayerHint::Mesh ) );
829 }
830 
832 {
833  return qobject_cast< QgsMeshLayer *>( parameterAsLayer( definition, value, context, QgsProcessingUtils::LayerHint::Mesh ) );
834 }
835 
836 QString QgsProcessingParameters::parameterAsOutputLayer( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context )
837 {
838  QVariant val;
839  if ( definition )
840  {
841  val = parameters.value( definition->name() );
842  }
843  return parameterAsOutputLayer( definition, val, context );
844 }
845 
847 {
848  QVariant val = value;
849 
850  QgsProject *destinationProject = nullptr;
851  QString destName;
852  if ( val.canConvert<QgsProcessingOutputLayerDefinition>() )
853  {
854  // input is a QgsProcessingOutputLayerDefinition - get extra properties from it
855  QgsProcessingOutputLayerDefinition fromVar = qvariant_cast<QgsProcessingOutputLayerDefinition>( val );
856  destinationProject = fromVar.destinationProject;
857  val = fromVar.sink;
858  destName = fromVar.destinationName;
859  }
860 
861  QString dest;
862  if ( definition && val.canConvert<QgsProperty>() )
863  {
864  dest = val.value< QgsProperty >().valueAsString( context.expressionContext(), definition->defaultValue().toString() );
865  }
866  else if ( definition && ( !val.isValid() || val.toString().isEmpty() ) )
867  {
868  // fall back to default
869  dest = definition->defaultValue().toString();
870  }
871  else
872  {
873  dest = val.toString();
874  }
875  if ( dest == QgsProcessing::TEMPORARY_OUTPUT )
876  {
877  if ( const QgsProcessingDestinationParameter *destParam = dynamic_cast< const QgsProcessingDestinationParameter * >( definition ) )
878  dest = destParam->generateTemporaryDestination();
879  }
880 
881  if ( destinationProject )
882  {
883  QString outputName;
884  if ( destName.isEmpty() && definition )
885  {
886  destName = definition->description();
887  }
888  if ( definition )
889  outputName = definition->name();
890 
892  if ( definition && definition->type() == QgsProcessingParameterVectorDestination::typeName() )
894  else if ( definition && definition->type() == QgsProcessingParameterRasterDestination::typeName() )
896 
897  context.addLayerToLoadOnCompletion( dest, QgsProcessingContext::LayerDetails( destName, destinationProject, outputName, layerTypeHint ) );
898  }
899 
900  return dest;
901 }
902 
903 QString QgsProcessingParameters::parameterAsFileOutput( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context )
904 {
905  QVariant val;
906  if ( definition )
907  {
908  val = parameters.value( definition->name() );
909  }
910  return parameterAsFileOutput( definition, val, context );
911 }
912 
914 {
915  QVariant val = value;
916 
917  if ( val.canConvert<QgsProcessingOutputLayerDefinition>() )
918  {
919  // input is a QgsProcessingOutputLayerDefinition - get extra properties from it
920  QgsProcessingOutputLayerDefinition fromVar = qvariant_cast<QgsProcessingOutputLayerDefinition>( val );
921  val = fromVar.sink;
922  }
923 
924  QString dest;
925  if ( definition && val.canConvert<QgsProperty>() )
926  {
927  dest = val.value< QgsProperty >().valueAsString( context.expressionContext(), definition->defaultValue().toString() );
928  }
929  else if ( definition && ( !val.isValid() || val.toString().isEmpty() ) )
930  {
931  // fall back to default
932  dest = definition->defaultValue().toString();
933  }
934  else
935  {
936  dest = val.toString();
937  }
938  if ( dest == QgsProcessing::TEMPORARY_OUTPUT )
939  {
940  if ( const QgsProcessingDestinationParameter *destParam = dynamic_cast< const QgsProcessingDestinationParameter * >( definition ) )
941  dest = destParam->generateTemporaryDestination();
942  }
943  return dest;
944 }
945 
947 {
948  return qobject_cast< QgsVectorLayer *>( parameterAsLayer( definition, parameters, context, QgsProcessingUtils::LayerHint::Vector ) );
949 }
950 
952 {
953  return qobject_cast< QgsVectorLayer *>( parameterAsLayer( definition, value, context, QgsProcessingUtils::LayerHint::Vector ) );
954 }
955 
957 {
958  if ( !definition )
960 
961  return parameterAsCrs( definition, parameters.value( definition->name() ), context );
962 }
963 
965 {
966  if ( !definition )
968 
969  return QgsProcessingUtils::variantToCrs( value, context, definition->defaultValue() );
970 }
971 
974 {
975  if ( !definition )
976  return QgsRectangle();
977 
978  return parameterAsExtent( definition, parameters.value( definition->name() ), context, crs );
979 }
980 
982 {
983  if ( !definition )
984  return QgsRectangle();
985 
986  QVariant val = value;
987 
988  if ( val.canConvert< QgsRectangle >() )
989  {
990  return val.value<QgsRectangle>();
991  }
992  if ( val.canConvert< QgsGeometry >() )
993  {
994  const QgsGeometry geom = val.value<QgsGeometry>();
995  if ( !geom.isNull() )
996  return geom.boundingBox();
997  }
998  if ( val.canConvert< QgsReferencedRectangle >() )
999  {
1001  if ( crs.isValid() && rr.crs().isValid() && crs != rr.crs() )
1002  {
1003  QgsCoordinateTransform ct( rr.crs(), crs, context.project() );
1004  try
1005  {
1006  return ct.transformBoundingBox( rr );
1007  }
1008  catch ( QgsCsException & )
1009  {
1010  QgsMessageLog::logMessage( QObject::tr( "Error transforming extent geometry" ) );
1011  }
1012  }
1013  return rr;
1014  }
1015 
1016  if ( val.canConvert<QgsProcessingFeatureSourceDefinition>() )
1017  {
1018  // input is a QgsProcessingFeatureSourceDefinition - get extra properties from it
1019  QgsProcessingFeatureSourceDefinition fromVar = qvariant_cast<QgsProcessingFeatureSourceDefinition>( val );
1020  val = fromVar.source;
1021  }
1022  else if ( val.canConvert<QgsProcessingOutputLayerDefinition>() )
1023  {
1024  // input is a QgsProcessingOutputLayerDefinition - get extra properties from it
1025  QgsProcessingOutputLayerDefinition fromVar = qvariant_cast<QgsProcessingOutputLayerDefinition>( val );
1026  val = fromVar.sink;
1027  }
1028 
1029  if ( val.canConvert<QgsProperty>() && val.value< QgsProperty >().propertyType() == QgsProperty::StaticProperty )
1030  {
1031  val = val.value< QgsProperty >().staticValue();
1032  }
1033 
1034  // maybe parameter is a direct layer value?
1035  QgsMapLayer *layer = qobject_cast< QgsMapLayer * >( qvariant_cast<QObject *>( val ) );
1036 
1037  QString rectText;
1038  if ( val.canConvert<QgsProperty>() )
1039  rectText = val.value< QgsProperty >().valueAsString( context.expressionContext(), definition->defaultValue().toString() );
1040  else
1041  rectText = val.toString();
1042 
1043  if ( rectText.isEmpty() && !layer )
1044  return QgsRectangle();
1045 
1046  QRegularExpression rx( QStringLiteral( "^(.*?)\\s*,\\s*(.*?),\\s*(.*?),\\s*(.*?)\\s*(?:\\[(.*)\\])?\\s*$" ) );
1047  QRegularExpressionMatch match = rx.match( rectText );
1048  if ( match.hasMatch() )
1049  {
1050  bool xMinOk = false;
1051  double xMin = match.captured( 1 ).toDouble( &xMinOk );
1052  bool xMaxOk = false;
1053  double xMax = match.captured( 2 ).toDouble( &xMaxOk );
1054  bool yMinOk = false;
1055  double yMin = match.captured( 3 ).toDouble( &yMinOk );
1056  bool yMaxOk = false;
1057  double yMax = match.captured( 4 ).toDouble( &yMaxOk );
1058  if ( xMinOk && xMaxOk && yMinOk && yMaxOk )
1059  {
1060  QgsRectangle rect( xMin, yMin, xMax, yMax );
1061  QgsCoordinateReferenceSystem rectCrs( match.captured( 5 ) );
1062  if ( crs.isValid() && rectCrs.isValid() && crs != rectCrs )
1063  {
1064  QgsCoordinateTransform ct( rectCrs, crs, context.project() );
1065  try
1066  {
1067  return ct.transformBoundingBox( rect );
1068  }
1069  catch ( QgsCsException & )
1070  {
1071  QgsMessageLog::logMessage( QObject::tr( "Error transforming extent geometry" ) );
1072  }
1073  }
1074  return rect;
1075  }
1076  }
1077 
1078  // try as layer extent
1079  if ( !layer )
1080  layer = QgsProcessingUtils::mapLayerFromString( rectText, context );
1081 
1082  if ( layer )
1083  {
1084  QgsRectangle rect = layer->extent();
1085  if ( crs.isValid() && layer->crs().isValid() && crs != layer->crs() )
1086  {
1087  QgsCoordinateTransform ct( layer->crs(), crs, context.project() );
1088  try
1089  {
1090  return ct.transformBoundingBox( rect );
1091  }
1092  catch ( QgsCsException & )
1093  {
1094  QgsMessageLog::logMessage( QObject::tr( "Error transforming extent geometry" ) );
1095  }
1096  }
1097  return rect;
1098  }
1099  return QgsRectangle();
1100 }
1101 
1103 {
1104  if ( !definition )
1105  return QgsGeometry();
1106 
1107  QVariant val = parameters.value( definition->name() );
1108 
1109  if ( val.canConvert< QgsReferencedRectangle >() )
1110  {
1113  if ( crs.isValid() && rr.crs().isValid() && crs != rr.crs() )
1114  {
1115  g = g.densifyByCount( 20 );
1116  QgsCoordinateTransform ct( rr.crs(), crs, context.project() );
1117  try
1118  {
1119  g.transform( ct );
1120  }
1121  catch ( QgsCsException & )
1122  {
1123  QgsMessageLog::logMessage( QObject::tr( "Error transforming extent geometry" ) );
1124  }
1125  return g;
1126  }
1127  }
1128 
1129  if ( val.canConvert<QgsProcessingFeatureSourceDefinition>() )
1130  {
1131  // input is a QgsProcessingFeatureSourceDefinition - get extra properties from it
1132  QgsProcessingFeatureSourceDefinition fromVar = qvariant_cast<QgsProcessingFeatureSourceDefinition>( val );
1133  val = fromVar.source;
1134  }
1135  else if ( val.canConvert<QgsProcessingOutputLayerDefinition>() )
1136  {
1137  // input is a QgsProcessingOutputLayerDefinition - get extra properties from it
1138  QgsProcessingOutputLayerDefinition fromVar = qvariant_cast<QgsProcessingOutputLayerDefinition>( val );
1139  val = fromVar.sink;
1140  }
1141 
1142  if ( val.canConvert<QgsProperty>() && val.value< QgsProperty >().propertyType() == QgsProperty::StaticProperty )
1143  {
1144  val = val.value< QgsProperty >().staticValue();
1145  }
1146 
1147  QString rectText;
1148  if ( val.canConvert<QgsProperty>() )
1149  rectText = val.value< QgsProperty >().valueAsString( context.expressionContext(), definition->defaultValue().toString() );
1150  else
1151  rectText = val.toString();
1152 
1153  if ( !rectText.isEmpty() )
1154  {
1155  QRegularExpression rx( QStringLiteral( "^(.*?)\\s*,\\s*(.*?),\\s*(.*?),\\s*(.*?)\\s*(?:\\[(.*)\\])?\\s*$" ) );
1156  QRegularExpressionMatch match = rx.match( rectText );
1157  if ( match.hasMatch() )
1158  {
1159  bool xMinOk = false;
1160  double xMin = match.captured( 1 ).toDouble( &xMinOk );
1161  bool xMaxOk = false;
1162  double xMax = match.captured( 2 ).toDouble( &xMaxOk );
1163  bool yMinOk = false;
1164  double yMin = match.captured( 3 ).toDouble( &yMinOk );
1165  bool yMaxOk = false;
1166  double yMax = match.captured( 4 ).toDouble( &yMaxOk );
1167  if ( xMinOk && xMaxOk && yMinOk && yMaxOk )
1168  {
1169  QgsRectangle rect( xMin, yMin, xMax, yMax );
1170  QgsCoordinateReferenceSystem rectCrs( match.captured( 5 ) );
1171  QgsGeometry g = QgsGeometry::fromRect( rect );
1172  if ( crs.isValid() && rectCrs.isValid() && crs != rectCrs )
1173  {
1174  g = g.densifyByCount( 20 );
1175  QgsCoordinateTransform ct( rectCrs, crs, context.project() );
1176  try
1177  {
1178  g.transform( ct );
1179  }
1180  catch ( QgsCsException & )
1181  {
1182  QgsMessageLog::logMessage( QObject::tr( "Error transforming extent geometry" ) );
1183  }
1184  return g;
1185  }
1186  }
1187  }
1188  }
1189 
1190  // try as layer extent
1191 
1192  // maybe parameter is a direct layer value?
1193  QgsMapLayer *layer = qobject_cast< QgsMapLayer * >( qvariant_cast<QObject *>( val ) );
1194  if ( !layer )
1195  layer = QgsProcessingUtils::mapLayerFromString( rectText, context );
1196 
1197  if ( layer )
1198  {
1199  QgsRectangle rect = layer->extent();
1200  QgsGeometry g = QgsGeometry::fromRect( rect );
1201  if ( crs.isValid() && layer->crs().isValid() && crs != layer->crs() )
1202  {
1203  g = g.densifyByCount( 20 );
1204  QgsCoordinateTransform ct( layer->crs(), crs, context.project() );
1205  try
1206  {
1207  g.transform( ct );
1208  }
1209  catch ( QgsCsException & )
1210  {
1211  QgsMessageLog::logMessage( QObject::tr( "Error transforming extent geometry" ) );
1212  }
1213  }
1214  return g;
1215  }
1216 
1217  return QgsGeometry::fromRect( parameterAsExtent( definition, parameters, context, crs ) );
1218 }
1219 
1221 {
1222  QVariant val = parameters.value( definition->name() );
1223  return parameterAsExtentCrs( definition, val, context );
1224 }
1225 
1227 {
1228  QVariant val = value;
1229  if ( val.canConvert< QgsReferencedRectangle >() )
1230  {
1232  if ( rr.crs().isValid() )
1233  {
1234  return rr.crs();
1235  }
1236  }
1237 
1238  if ( val.canConvert<QgsProcessingFeatureSourceDefinition>() )
1239  {
1240  // input is a QgsProcessingFeatureSourceDefinition - get extra properties from it
1241  QgsProcessingFeatureSourceDefinition fromVar = qvariant_cast<QgsProcessingFeatureSourceDefinition>( val );
1242  val = fromVar.source;
1243  }
1244  else if ( val.canConvert<QgsProcessingOutputLayerDefinition>() )
1245  {
1246  // input is a QgsProcessingOutputLayerDefinition - get extra properties from it
1247  QgsProcessingOutputLayerDefinition fromVar = qvariant_cast<QgsProcessingOutputLayerDefinition>( val );
1248  val = fromVar.sink;
1249  }
1250 
1251  if ( val.canConvert<QgsProperty>() && val.value< QgsProperty >().propertyType() == QgsProperty::StaticProperty )
1252  {
1253  val = val.value< QgsProperty >().staticValue();
1254  }
1255 
1256  QString valueAsString;
1257  if ( val.canConvert<QgsProperty>() )
1258  valueAsString = val.value< QgsProperty >().valueAsString( context.expressionContext(), definition->defaultValue().toString() );
1259  else
1260  valueAsString = val.toString();
1261 
1262  QRegularExpression rx( QStringLiteral( "^(.*?)\\s*,\\s*(.*?),\\s*(.*?),\\s*(.*?)\\s*(?:\\[(.*)\\])?\\s*$" ) );
1263 
1264  QRegularExpressionMatch match = rx.match( valueAsString );
1265  if ( match.hasMatch() )
1266  {
1267  QgsCoordinateReferenceSystem crs( match.captured( 5 ) );
1268  if ( crs.isValid() )
1269  return crs;
1270  }
1271 
1272  if ( val.canConvert<QgsProcessingFeatureSourceDefinition>() )
1273  {
1274  // input is a QgsProcessingFeatureSourceDefinition - get extra properties from it
1275  QgsProcessingFeatureSourceDefinition fromVar = qvariant_cast<QgsProcessingFeatureSourceDefinition>( val );
1276  val = fromVar.source;
1277  }
1278  else if ( val.canConvert<QgsProcessingOutputLayerDefinition>() )
1279  {
1280  // input is a QgsProcessingOutputLayerDefinition - get extra properties from it
1281  QgsProcessingOutputLayerDefinition fromVar = qvariant_cast<QgsProcessingOutputLayerDefinition>( val );
1282  val = fromVar.sink;
1283  }
1284 
1285  if ( val.canConvert<QgsProperty>() && val.value< QgsProperty >().propertyType() == QgsProperty::StaticProperty )
1286  {
1287  val = val.value< QgsProperty >().staticValue();
1288  }
1289 
1290  // try as layer crs
1291  if ( QgsMapLayer *layer = qobject_cast< QgsMapLayer * >( qvariant_cast<QObject *>( val ) ) )
1292  return layer->crs();
1293  else if ( QgsMapLayer *layer = QgsProcessingUtils::mapLayerFromString( valueAsString, context ) )
1294  return layer->crs();
1295 
1296  if ( auto *lProject = context.project() )
1297  return lProject->crs();
1298  else
1300 }
1301 
1303 {
1304  if ( !definition )
1305  return QgsPointXY();
1306 
1307  return parameterAsPoint( definition, parameters.value( definition->name() ), context, crs );
1308 }
1309 
1311 {
1312  if ( !definition )
1313  return QgsPointXY();
1314 
1315  QVariant val = value;
1316  if ( val.canConvert< QgsPointXY >() )
1317  {
1318  return val.value<QgsPointXY>();
1319  }
1320  if ( val.canConvert< QgsGeometry >() )
1321  {
1322  const QgsGeometry geom = val.value<QgsGeometry>();
1323  if ( !geom.isNull() )
1324  return geom.centroid().asPoint();
1325  }
1326  if ( val.canConvert< QgsReferencedPointXY >() )
1327  {
1328  QgsReferencedPointXY rp = val.value<QgsReferencedPointXY>();
1329  if ( crs.isValid() && rp.crs().isValid() && crs != rp.crs() )
1330  {
1331  QgsCoordinateTransform ct( rp.crs(), crs, context.project() );
1332  try
1333  {
1334  return ct.transform( rp );
1335  }
1336  catch ( QgsCsException & )
1337  {
1338  QgsMessageLog::logMessage( QObject::tr( "Error transforming point geometry" ) );
1339  }
1340  }
1341  return rp;
1342  }
1343 
1344  QString pointText = parameterAsString( definition, value, context );
1345  if ( pointText.isEmpty() )
1346  pointText = definition->defaultValue().toString();
1347 
1348  if ( pointText.isEmpty() )
1349  return QgsPointXY();
1350 
1351  QRegularExpression rx( QStringLiteral( "^\\s*\\(?\\s*(.*?)\\s*,\\s*(.*?)\\s*(?:\\[(.*)\\])?\\s*\\)?\\s*$" ) );
1352 
1353  QString valueAsString = parameterAsString( definition, value, context );
1354  QRegularExpressionMatch match = rx.match( valueAsString );
1355  if ( match.hasMatch() )
1356  {
1357  bool xOk = false;
1358  double x = match.captured( 1 ).toDouble( &xOk );
1359  bool yOk = false;
1360  double y = match.captured( 2 ).toDouble( &yOk );
1361 
1362  if ( xOk && yOk )
1363  {
1364  QgsPointXY pt( x, y );
1365 
1366  QgsCoordinateReferenceSystem pointCrs( match.captured( 3 ) );
1367  if ( crs.isValid() && pointCrs.isValid() && crs != pointCrs )
1368  {
1369  QgsCoordinateTransform ct( pointCrs, crs, context.project() );
1370  try
1371  {
1372  return ct.transform( pt );
1373  }
1374  catch ( QgsCsException & )
1375  {
1376  QgsMessageLog::logMessage( QObject::tr( "Error transforming point geometry" ) );
1377  }
1378  }
1379  return pt;
1380  }
1381  }
1382 
1383  return QgsPointXY();
1384 }
1385 
1387 {
1388  QVariant val = parameters.value( definition->name() );
1389  return parameterAsPointCrs( definition, val, context );
1390 }
1391 
1393 {
1394  if ( value.canConvert< QgsReferencedPointXY >() )
1395  {
1396  QgsReferencedPointXY rr = value.value<QgsReferencedPointXY>();
1397  if ( rr.crs().isValid() )
1398  {
1399  return rr.crs();
1400  }
1401  }
1402 
1403  QRegularExpression rx( QStringLiteral( "^\\s*\\(?\\s*(.*?)\\s*,\\s*(.*?)\\s*(?:\\[(.*)\\])?\\s*\\)?\\s*$" ) );
1404 
1405  QString valueAsString = parameterAsString( definition, value, context );
1406  QRegularExpressionMatch match = rx.match( valueAsString );
1407  if ( match.hasMatch() )
1408  {
1409  QgsCoordinateReferenceSystem crs( match.captured( 3 ) );
1410  if ( crs.isValid() )
1411  return crs;
1412  }
1413 
1414  if ( auto *lProject = context.project() )
1415  return lProject->crs();
1416  else
1418 }
1419 
1421 {
1422  if ( !definition )
1423  return QgsGeometry();
1424 
1425  return parameterAsGeometry( definition, parameters.value( definition->name() ), context, crs );
1426 }
1427 
1429 {
1430  if ( !definition )
1431  return QgsGeometry();
1432 
1433  QVariant val = value;
1434  if ( val.canConvert< QgsGeometry >() )
1435  {
1436  return val.value<QgsGeometry>();
1437  }
1438 
1439  if ( val.canConvert< QgsPointXY >() )
1440  {
1441  return QgsGeometry::fromPointXY( val.value<QgsPointXY>() );
1442  }
1443 
1444  if ( val.canConvert< QgsRectangle >() )
1445  {
1446  return QgsGeometry::fromRect( val.value<QgsRectangle>() );
1447  }
1448 
1449  if ( val.canConvert< QgsReferencedPointXY >() )
1450  {
1451  QgsReferencedPointXY rp = val.value<QgsReferencedPointXY>();
1452  if ( crs.isValid() && rp.crs().isValid() && crs != rp.crs() )
1453  {
1454  QgsCoordinateTransform ct( rp.crs(), crs, context.project() );
1455  try
1456  {
1457  return QgsGeometry::fromPointXY( ct.transform( rp ) );
1458  }
1459  catch ( QgsCsException & )
1460  {
1461  QgsMessageLog::logMessage( QObject::tr( "Error transforming point geometry" ) );
1462  }
1463  }
1464  return QgsGeometry::fromPointXY( rp );
1465  }
1466 
1467  if ( val.canConvert< QgsReferencedRectangle >() )
1468  {
1471  if ( crs.isValid() && rr.crs().isValid() && crs != rr.crs() )
1472  {
1473  g = g.densifyByCount( 20 );
1474  QgsCoordinateTransform ct( rr.crs(), crs, context.project() );
1475  try
1476  {
1477  g.transform( ct );
1478  }
1479  catch ( QgsCsException & )
1480  {
1481  QgsMessageLog::logMessage( QObject::tr( "Error transforming rectangle geometry" ) );
1482  }
1483  }
1484  return g;
1485  }
1486 
1487  if ( val.canConvert< QgsReferencedGeometry >() )
1488  {
1489  QgsReferencedGeometry rg = val.value<QgsReferencedGeometry>();
1490  if ( crs.isValid() && rg.crs().isValid() && crs != rg.crs() )
1491  {
1492  QgsCoordinateTransform ct( rg.crs(), crs, context.project() );
1493  try
1494  {
1495  rg.transform( ct );
1496  }
1497  catch ( QgsCsException & )
1498  {
1499  QgsMessageLog::logMessage( QObject::tr( "Error transforming geometry" ) );
1500  }
1501  }
1502  return rg;
1503  }
1504 
1505  QString valueAsString = parameterAsString( definition, value, context );
1506  if ( valueAsString.isEmpty() )
1507  valueAsString = definition->defaultValue().toString();
1508 
1509  if ( valueAsString.isEmpty() )
1510  return QgsGeometry();
1511 
1512  QRegularExpression rx( QStringLiteral( "^\\s*(?:CRS=(.*);)?(.*?)$" ) );
1513 
1514  QRegularExpressionMatch match = rx.match( valueAsString );
1515  if ( match.hasMatch() )
1516  {
1517  QgsGeometry g = QgsGeometry::fromWkt( match.captured( 2 ) );
1518  if ( !g.isNull() )
1519  {
1520  QgsCoordinateReferenceSystem geomCrs( match.captured( 1 ) );
1521  if ( crs.isValid() && geomCrs.isValid() && crs != geomCrs )
1522  {
1523  QgsCoordinateTransform ct( geomCrs, crs, context.project() );
1524  try
1525  {
1526  g.transform( ct );
1527  }
1528  catch ( QgsCsException & )
1529  {
1530  QgsMessageLog::logMessage( QObject::tr( "Error transforming geometry" ) );
1531  }
1532  }
1533  return g;
1534  }
1535  }
1536 
1537  return QgsGeometry();
1538 }
1539 
1540 
1542 {
1543  QVariant val = parameters.value( definition->name() );
1544  return parameterAsGeometryCrs( definition, val, context );
1545 }
1546 
1548 {
1549  if ( value.canConvert< QgsReferencedGeometry >() )
1550  {
1551  QgsReferencedGeometry rg = value.value<QgsReferencedGeometry>();
1552  if ( rg.crs().isValid() )
1553  {
1554  return rg.crs();
1555  }
1556  }
1557 
1558  if ( value.canConvert< QgsReferencedPointXY >() )
1559  {
1560  QgsReferencedPointXY rp = value.value<QgsReferencedPointXY>();
1561  if ( rp.crs().isValid() )
1562  {
1563  return rp.crs();
1564  }
1565  }
1566 
1567  if ( value.canConvert< QgsReferencedRectangle >() )
1568  {
1569  QgsReferencedRectangle rr = value.value<QgsReferencedRectangle>();
1570  if ( rr.crs().isValid() )
1571  {
1572  return rr.crs();
1573  }
1574  }
1575 
1576  // Match against EWKT
1577  QRegularExpression rx( QStringLiteral( "^\\s*(?:CRS=(.*);)?(.*?)$" ) );
1578 
1579  QString valueAsString = parameterAsString( definition, value, context );
1580  QRegularExpressionMatch match = rx.match( valueAsString );
1581  if ( match.hasMatch() )
1582  {
1583  QgsCoordinateReferenceSystem crs( match.captured( 1 ) );
1584  if ( crs.isValid() )
1585  return crs;
1586  }
1587 
1588  if ( auto *lProject = context.project() )
1589  return lProject->crs();
1590  else
1592 }
1593 
1594 
1595 
1596 
1597 QString QgsProcessingParameters::parameterAsFile( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context )
1598 {
1599  if ( !definition )
1600  return QString();
1601 
1602  QString fileText = parameterAsString( definition, parameters, context );
1603  if ( fileText.isEmpty() )
1604  fileText = definition->defaultValue().toString();
1605  return fileText;
1606 }
1607 
1608 QString QgsProcessingParameters::parameterAsFile( const QgsProcessingParameterDefinition *definition, const QVariant &value, QgsProcessingContext &context )
1609 {
1610  if ( !definition )
1611  return QString();
1612 
1613  QString fileText = parameterAsString( definition, value, context );
1614  if ( fileText.isEmpty() )
1615  fileText = definition->defaultValue().toString();
1616  return fileText;
1617 }
1618 
1619 QVariantList QgsProcessingParameters::parameterAsMatrix( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context )
1620 {
1621  if ( !definition )
1622  return QVariantList();
1623 
1624  return parameterAsMatrix( definition, parameters.value( definition->name() ), context );
1625 }
1626 
1627 QVariantList QgsProcessingParameters::parameterAsMatrix( const QgsProcessingParameterDefinition *definition, const QVariant &value, QgsProcessingContext &context )
1628 {
1629  if ( !definition )
1630  return QVariantList();
1631 
1632  QString resultString;
1633  QVariant val = value;
1634  if ( val.canConvert<QgsProperty>() )
1635  resultString = val.value< QgsProperty >().valueAsString( context.expressionContext(), definition->defaultValue().toString() );
1636  else if ( val.type() == QVariant::List )
1637  return val.toList();
1638  else
1639  resultString = val.toString();
1640 
1641  if ( resultString.isEmpty() )
1642  {
1643  // check default
1644  if ( definition->defaultValue().type() == QVariant::List )
1645  return definition->defaultValue().toList();
1646  else
1647  resultString = definition->defaultValue().toString();
1648  }
1649 
1650  QVariantList result;
1651  const auto constSplit = resultString.split( ',' );
1652  for ( const QString &s : constSplit )
1653  result << s;
1654 
1655  return result;
1656 }
1657 
1658 QList<QgsMapLayer *> QgsProcessingParameters::parameterAsLayerList( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context )
1659 {
1660  if ( !definition )
1661  return QList<QgsMapLayer *>();
1662 
1663  return parameterAsLayerList( definition, parameters.value( definition->name() ), context );
1664 }
1665 
1666 QList<QgsMapLayer *> QgsProcessingParameters::parameterAsLayerList( const QgsProcessingParameterDefinition *definition, const QVariant &value, QgsProcessingContext &context )
1667 {
1668  if ( !definition )
1669  return QList<QgsMapLayer *>();
1670 
1671  QVariant val = value;
1672  if ( QgsMapLayer *layer = qobject_cast< QgsMapLayer * >( qvariant_cast<QObject *>( val ) ) )
1673  {
1674  return QList<QgsMapLayer *>() << layer;
1675  }
1676 
1677  QList<QgsMapLayer *> layers;
1678 
1679  std::function< void( const QVariant &var ) > processVariant;
1680  processVariant = [ &layers, &context, &definition, &processVariant ]( const QVariant & var )
1681  {
1682  if ( var.type() == QVariant::List )
1683  {
1684  const auto constToList = var.toList();
1685  for ( const QVariant &listVar : constToList )
1686  {
1687  processVariant( listVar );
1688  }
1689  }
1690  else if ( var.type() == QVariant::StringList )
1691  {
1692  const auto constToStringList = var.toStringList();
1693  for ( const QString &s : constToStringList )
1694  {
1695  processVariant( s );
1696  }
1697  }
1698  else if ( var.canConvert<QgsProperty>() )
1699  processVariant( var.value< QgsProperty >().valueAsString( context.expressionContext(), definition->defaultValue().toString() ) );
1700  else if ( var.canConvert<QgsProcessingOutputLayerDefinition>() )
1701  {
1702  // input is a QgsProcessingOutputLayerDefinition - get extra properties from it
1703  QgsProcessingOutputLayerDefinition fromVar = qvariant_cast<QgsProcessingOutputLayerDefinition>( var );
1704  QVariant sink = fromVar.sink;
1705  if ( sink.canConvert<QgsProperty>() )
1706  {
1707  processVariant( sink.value< QgsProperty >().valueAsString( context.expressionContext(), definition->defaultValue().toString() ) );
1708  }
1709  }
1710  else if ( QgsMapLayer *layer = qobject_cast< QgsMapLayer * >( qvariant_cast<QObject *>( var ) ) )
1711  {
1712  layers << layer;
1713  }
1714  else
1715  {
1716  QgsMapLayer *alayer = QgsProcessingUtils::mapLayerFromString( var.toString(), context );
1717  if ( alayer )
1718  layers << alayer;
1719  }
1720  };
1721 
1722  processVariant( val );
1723 
1724  if ( layers.isEmpty() )
1725  {
1726  // check default
1727  if ( QgsMapLayer *layer = qobject_cast< QgsMapLayer * >( qvariant_cast<QObject *>( definition->defaultValue() ) ) )
1728  {
1729  layers << layer;
1730  }
1731  else if ( definition->defaultValue().type() == QVariant::List )
1732  {
1733  const auto constToList = definition->defaultValue().toList();
1734  for ( const QVariant &var : constToList )
1735  {
1736  if ( QgsMapLayer *layer = qobject_cast< QgsMapLayer * >( qvariant_cast<QObject *>( var ) ) )
1737  {
1738  layers << layer;
1739  }
1740  else
1741  {
1742  processVariant( var );
1743  }
1744  }
1745  }
1746  else
1747  processVariant( definition->defaultValue() );
1748  }
1749 
1750  return layers;
1751 }
1752 
1753 QStringList QgsProcessingParameters::parameterAsFileList( const QgsProcessingParameterDefinition *definition, const QVariant &value, QgsProcessingContext &context )
1754 {
1755  if ( !definition )
1756  return QStringList();
1757 
1758  QVariant val = value;
1759 
1760  QStringList files;
1761 
1762  std::function< void( const QVariant &var ) > processVariant;
1763  processVariant = [ &files, &context, &definition, &processVariant ]( const QVariant & var )
1764  {
1765  if ( var.type() == QVariant::List )
1766  {
1767  const auto constToList = var.toList();
1768  for ( const QVariant &listVar : constToList )
1769  {
1770  processVariant( listVar );
1771  }
1772  }
1773  else if ( var.type() == QVariant::StringList )
1774  {
1775  const auto constToStringList = var.toStringList();
1776  for ( const QString &s : constToStringList )
1777  {
1778  processVariant( s );
1779  }
1780  }
1781  else if ( var.canConvert<QgsProperty>() )
1782  processVariant( var.value< QgsProperty >().valueAsString( context.expressionContext(), definition->defaultValue().toString() ) );
1783  else
1784  {
1785  files << var.toString();
1786  }
1787  };
1788 
1789  processVariant( val );
1790 
1791  if ( files.isEmpty() )
1792  {
1793  processVariant( definition->defaultValue() );
1794  }
1795 
1796  return files;
1797 }
1798 
1799 QStringList QgsProcessingParameters::parameterAsFileList( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context )
1800 {
1801  if ( !definition )
1802  return QStringList();
1803 
1804  return parameterAsFileList( definition, parameters.value( definition->name() ), context );
1805 }
1806 
1807 QList<double> QgsProcessingParameters::parameterAsRange( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context )
1808 {
1809  if ( !definition )
1810  return QList<double>();
1811 
1812  return parameterAsRange( definition, parameters.value( definition->name() ), context );
1813 }
1814 
1815 QList<double> QgsProcessingParameters::parameterAsRange( const QgsProcessingParameterDefinition *definition, const QVariant &value, QgsProcessingContext &context )
1816 {
1817  if ( !definition )
1818  return QList<double>();
1819 
1820  QStringList resultStringList;
1821  QVariant val = value;
1822 
1823  if ( val.canConvert<QgsProperty>() )
1824  resultStringList << val.value< QgsProperty >().valueAsString( context.expressionContext(), definition->defaultValue().toString() );
1825  else if ( val.type() == QVariant::List )
1826  {
1827  const auto constToList = val.toList();
1828  for ( const QVariant &var : constToList )
1829  resultStringList << var.toString();
1830  }
1831  else
1832  resultStringList << val.toString();
1833 
1834  if ( ( resultStringList.isEmpty() || ( resultStringList.size() == 1 && resultStringList.at( 0 ).isEmpty() ) ) )
1835  {
1836  resultStringList.clear();
1837  // check default
1838  if ( definition->defaultValue().type() == QVariant::List )
1839  {
1840  const auto constToList = definition->defaultValue().toList();
1841  for ( const QVariant &var : constToList )
1842  resultStringList << var.toString();
1843  }
1844  else
1845  resultStringList << definition->defaultValue().toString();
1846  }
1847 
1848  if ( resultStringList.size() == 1 )
1849  {
1850  resultStringList = resultStringList.at( 0 ).split( ',' );
1851  }
1852 
1853  if ( resultStringList.size() < 2 )
1854  return QList< double >() << std::numeric_limits<double>::quiet_NaN() << std::numeric_limits<double>::quiet_NaN() ;
1855 
1856  QList< double > result;
1857  bool ok = false;
1858  double n = resultStringList.at( 0 ).toDouble( &ok );
1859  if ( ok )
1860  result << n;
1861  else
1862  result << std::numeric_limits<double>::quiet_NaN() ;
1863  ok = false;
1864  n = resultStringList.at( 1 ).toDouble( &ok );
1865  if ( ok )
1866  result << n;
1867  else
1868  result << std::numeric_limits<double>::quiet_NaN() ;
1869 
1870  return result;
1871 }
1872 
1873 QStringList QgsProcessingParameters::parameterAsFields( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context )
1874 {
1875  if ( !definition )
1876  return QStringList();
1877 
1878  QStringList resultStringList;
1879  return parameterAsFields( definition, parameters.value( definition->name() ), context );
1880 }
1881 
1882 QStringList QgsProcessingParameters::parameterAsFields( const QgsProcessingParameterDefinition *definition, const QVariant &value, QgsProcessingContext &context )
1883 {
1884  if ( !definition )
1885  return QStringList();
1886 
1887  QStringList resultStringList;
1888  QVariant val = value;
1889  if ( val.isValid() )
1890  {
1891  if ( val.canConvert<QgsProperty>() )
1892  resultStringList << val.value< QgsProperty >().valueAsString( context.expressionContext(), definition->defaultValue().toString() );
1893  else if ( val.type() == QVariant::List )
1894  {
1895  const auto constToList = val.toList();
1896  for ( const QVariant &var : constToList )
1897  resultStringList << var.toString();
1898  }
1899  else if ( val.type() == QVariant::StringList )
1900  {
1901  resultStringList = val.toStringList();
1902  }
1903  else
1904  resultStringList.append( val.toString().split( ';' ) );
1905  }
1906 
1907  if ( ( resultStringList.isEmpty() || resultStringList.at( 0 ).isEmpty() ) )
1908  {
1909  resultStringList.clear();
1910  // check default
1911  if ( definition->defaultValue().isValid() )
1912  {
1913  if ( definition->defaultValue().type() == QVariant::List )
1914  {
1915  const auto constToList = definition->defaultValue().toList();
1916  for ( const QVariant &var : constToList )
1917  resultStringList << var.toString();
1918  }
1919  else if ( definition->defaultValue().type() == QVariant::StringList )
1920  {
1921  resultStringList = definition->defaultValue().toStringList();
1922  }
1923  else
1924  resultStringList.append( definition->defaultValue().toString().split( ';' ) );
1925  }
1926  }
1927 
1928  return resultStringList;
1929 }
1930 
1932 {
1933  if ( !definition )
1934  return nullptr;
1935 
1936  return parameterAsLayout( definition, parameters.value( definition->name() ), context );
1937 }
1938 
1940 {
1941  const QString layoutName = parameterAsString( definition, value, context );
1942  if ( layoutName.isEmpty() )
1943  return nullptr;
1944 
1945  if ( !context.project() )
1946  return nullptr;
1947 
1948  QgsMasterLayoutInterface *l = context.project()->layoutManager()->layoutByName( layoutName );
1950  return static_cast< QgsPrintLayout * >( l );
1951  else
1952  return nullptr;
1953 }
1954 
1956 {
1957  if ( !definition )
1958  return nullptr;
1959 
1960  return parameterAsLayoutItem( definition, parameters.value( definition->name() ), context, layout );
1961 }
1962 
1964 {
1965  if ( !layout )
1966  return nullptr;
1967 
1968  const QString id = parameterAsString( definition, value, context );
1969  if ( id.isEmpty() )
1970  return nullptr;
1971 
1972  // prefer matching by uuid, since it's guaranteed to be unique.
1973  if ( QgsLayoutItem *item = layout->itemByUuid( id ) )
1974  return item;
1975  else if ( QgsLayoutItem *item = layout->itemById( id ) )
1976  return item;
1977  else
1978  return nullptr;
1979 }
1980 
1981 QColor QgsProcessingParameters::parameterAsColor( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context )
1982 {
1983  if ( !definition )
1984  return QColor();
1985 
1986  return parameterAsColor( definition, parameters.value( definition->name() ), context );
1987 }
1988 
1990 {
1991  if ( !definition )
1992  return QColor();
1993 
1994  QVariant val = value;
1995  if ( val.canConvert<QgsProperty>() )
1996  {
1997  val = val.value< QgsProperty >().value( context.expressionContext(), definition->defaultValue() );
1998  }
1999  if ( val.type() == QVariant::Color )
2000  {
2001  QColor c = val.value< QColor >();
2002  if ( const QgsProcessingParameterColor *colorParam = dynamic_cast< const QgsProcessingParameterColor * >( definition ) )
2003  if ( !colorParam->opacityEnabled() )
2004  c.setAlpha( 255 );
2005  return c;
2006  }
2007 
2008  QString colorText = parameterAsString( definition, value, context );
2009  if ( colorText.isEmpty() && !( definition->flags() & QgsProcessingParameterDefinition::FlagOptional ) )
2010  {
2011  if ( definition->defaultValue().type() == QVariant::Color )
2012  return definition->defaultValue().value< QColor >();
2013  else
2014  colorText = definition->defaultValue().toString();
2015  }
2016 
2017  if ( colorText.isEmpty() )
2018  return QColor();
2019 
2020  bool containsAlpha = false;
2021  QColor c = QgsSymbolLayerUtils::parseColorWithAlpha( colorText, containsAlpha );
2022  if ( const QgsProcessingParameterColor *colorParam = dynamic_cast< const QgsProcessingParameterColor * >( definition ) )
2023  if ( c.isValid() && !colorParam->opacityEnabled() )
2024  c.setAlpha( 255 );
2025  return c;
2026 }
2027 
2028 QString QgsProcessingParameters::parameterAsConnectionName( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, const QgsProcessingContext &context )
2029 {
2030  if ( !definition )
2031  return QString();
2032 
2033  return parameterAsConnectionName( definition, parameters.value( definition->name() ), context );
2034 }
2035 
2036 QString QgsProcessingParameters::parameterAsConnectionName( const QgsProcessingParameterDefinition *definition, const QVariant &value, const QgsProcessingContext &context )
2037 {
2038  // for now it's just treated identical to strings, but in future we may want flexibility to amend this
2039  // (hence the new method)
2040  return parameterAsString( definition, value, context );
2041 }
2042 
2043 QString QgsProcessingParameters::parameterAsSchema( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, const QgsProcessingContext &context )
2044 {
2045  if ( !definition )
2046  return QString();
2047 
2048  return parameterAsSchema( definition, parameters.value( definition->name() ), context );
2049 }
2050 
2051 QString QgsProcessingParameters::parameterAsSchema( const QgsProcessingParameterDefinition *definition, const QVariant &value, const QgsProcessingContext &context )
2052 {
2053  // 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
2054  // parameter values, such as via a delimiter separated string)
2055  return parameterAsString( definition, value, context );
2056 }
2057 
2058 QString QgsProcessingParameters::parameterAsDatabaseTableName( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, const QgsProcessingContext &context )
2059 {
2060  if ( !definition )
2061  return QString();
2062 
2063  return parameterAsDatabaseTableName( definition, parameters.value( definition->name() ), context );
2064 }
2065 
2067 {
2068  // 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
2069  // parameter values, such as via a delimiter separated string)
2070  return parameterAsString( definition, value, context );
2071 }
2072 
2074 {
2075  QString type = map.value( QStringLiteral( "parameter_type" ) ).toString();
2076  QString name = map.value( QStringLiteral( "name" ) ).toString();
2077  std::unique_ptr< QgsProcessingParameterDefinition > def;
2078 
2079  // probably all these hardcoded values aren't required anymore, and we could
2080  // always resort to the registry lookup...
2081  // TODO: confirm
2083  def.reset( new QgsProcessingParameterBoolean( name ) );
2084  else if ( type == QgsProcessingParameterCrs::typeName() )
2085  def.reset( new QgsProcessingParameterCrs( name ) );
2086  else if ( type == QgsProcessingParameterMapLayer::typeName() )
2087  def.reset( new QgsProcessingParameterMapLayer( name ) );
2088  else if ( type == QgsProcessingParameterExtent::typeName() )
2089  def.reset( new QgsProcessingParameterExtent( name ) );
2090  else if ( type == QgsProcessingParameterPoint::typeName() )
2091  def.reset( new QgsProcessingParameterPoint( name ) );
2092  else if ( type == QgsProcessingParameterFile::typeName() )
2093  def.reset( new QgsProcessingParameterFile( name ) );
2094  else if ( type == QgsProcessingParameterMatrix::typeName() )
2095  def.reset( new QgsProcessingParameterMatrix( name ) );
2097  def.reset( new QgsProcessingParameterMultipleLayers( name ) );
2098  else if ( type == QgsProcessingParameterNumber::typeName() )
2099  def.reset( new QgsProcessingParameterNumber( name ) );
2100  else if ( type == QgsProcessingParameterRange::typeName() )
2101  def.reset( new QgsProcessingParameterRange( name ) );
2102  else if ( type == QgsProcessingParameterRasterLayer::typeName() )
2103  def.reset( new QgsProcessingParameterRasterLayer( name ) );
2104  else if ( type == QgsProcessingParameterEnum::typeName() )
2105  def.reset( new QgsProcessingParameterEnum( name ) );
2106  else if ( type == QgsProcessingParameterString::typeName() )
2107  def.reset( new QgsProcessingParameterString( name ) );
2108  else if ( type == QgsProcessingParameterAuthConfig::typeName() )
2109  def.reset( new QgsProcessingParameterAuthConfig( name ) );
2110  else if ( type == QgsProcessingParameterExpression::typeName() )
2111  def.reset( new QgsProcessingParameterExpression( name ) );
2112  else if ( type == QgsProcessingParameterVectorLayer::typeName() )
2113  def.reset( new QgsProcessingParameterVectorLayer( name ) );
2114  else if ( type == QgsProcessingParameterField::typeName() )
2115  def.reset( new QgsProcessingParameterField( name ) );
2116  else if ( type == QgsProcessingParameterFeatureSource::typeName() )
2117  def.reset( new QgsProcessingParameterFeatureSource( name ) );
2118  else if ( type == QgsProcessingParameterFeatureSink::typeName() )
2119  def.reset( new QgsProcessingParameterFeatureSink( name ) );
2121  def.reset( new QgsProcessingParameterVectorDestination( name ) );
2123  def.reset( new QgsProcessingParameterRasterDestination( name ) );
2125  def.reset( new QgsProcessingParameterFileDestination( name ) );
2127  def.reset( new QgsProcessingParameterFolderDestination( name ) );
2128  else if ( type == QgsProcessingParameterBand::typeName() )
2129  def.reset( new QgsProcessingParameterBand( name ) );
2130  else if ( type == QgsProcessingParameterMeshLayer::typeName() )
2131  def.reset( new QgsProcessingParameterMeshLayer( name ) );
2132  else if ( type == QgsProcessingParameterLayout::typeName() )
2133  def.reset( new QgsProcessingParameterLayout( name ) );
2134  else if ( type == QgsProcessingParameterLayoutItem::typeName() )
2135  def.reset( new QgsProcessingParameterLayoutItem( name ) );
2136  else if ( type == QgsProcessingParameterColor::typeName() )
2137  def.reset( new QgsProcessingParameterColor( name ) );
2139  def.reset( new QgsProcessingParameterCoordinateOperation( name ) );
2140  else
2141  {
2143  if ( paramType )
2144  def.reset( paramType->create( name ) );
2145  }
2146 
2147  if ( !def )
2148  return nullptr;
2149 
2150  def->fromVariantMap( map );
2151  return def.release();
2152 }
2153 
2154 QString QgsProcessingParameters::descriptionFromName( const QString &name )
2155 {
2156  QString desc = name;
2157  desc.replace( '_', ' ' );
2158  return desc;
2159 }
2160 
2162 {
2163  bool isOptional = false;
2164  QString name;
2165  QString definition;
2166  QString type;
2167  if ( !parseScriptCodeParameterOptions( code, isOptional, name, type, definition ) )
2168  return nullptr;
2169 
2170  QString description = descriptionFromName( name );
2171 
2172  if ( type == QLatin1String( "boolean" ) )
2173  return QgsProcessingParameterBoolean::fromScriptCode( name, description, isOptional, definition );
2174  else if ( type == QLatin1String( "crs" ) )
2175  return QgsProcessingParameterCrs::fromScriptCode( name, description, isOptional, definition );
2176  else if ( type == QLatin1String( "layer" ) )
2177  return QgsProcessingParameterMapLayer::fromScriptCode( name, description, isOptional, definition );
2178  else if ( type == QLatin1String( "extent" ) )
2179  return QgsProcessingParameterExtent::fromScriptCode( name, description, isOptional, definition );
2180  else if ( type == QLatin1String( "point" ) )
2181  return QgsProcessingParameterPoint::fromScriptCode( name, description, isOptional, definition );
2182  else if ( type == QLatin1String( "geometry" ) )
2183  return QgsProcessingParameterGeometry::fromScriptCode( name, description, isOptional, definition );
2184  else if ( type == QLatin1String( "file" ) )
2185  return QgsProcessingParameterFile::fromScriptCode( name, description, isOptional, definition, QgsProcessingParameterFile::File );
2186  else if ( type == QLatin1String( "folder" ) )
2187  return QgsProcessingParameterFile::fromScriptCode( name, description, isOptional, definition, QgsProcessingParameterFile::Folder );
2188  else if ( type == QLatin1String( "matrix" ) )
2189  return QgsProcessingParameterMatrix::fromScriptCode( name, description, isOptional, definition );
2190  else if ( type == QLatin1String( "multiple" ) )
2191  return QgsProcessingParameterMultipleLayers::fromScriptCode( name, description, isOptional, definition );
2192  else if ( type == QLatin1String( "number" ) )
2193  return QgsProcessingParameterNumber::fromScriptCode( name, description, isOptional, definition );
2194  else if ( type == QLatin1String( "distance" ) )
2195  return QgsProcessingParameterDistance::fromScriptCode( name, description, isOptional, definition );
2196  else if ( type == QLatin1String( "scale" ) )
2197  return QgsProcessingParameterScale::fromScriptCode( name, description, isOptional, definition );
2198  else if ( type == QLatin1String( "range" ) )
2199  return QgsProcessingParameterRange::fromScriptCode( name, description, isOptional, definition );
2200  else if ( type == QLatin1String( "raster" ) )
2201  return QgsProcessingParameterRasterLayer::fromScriptCode( name, description, isOptional, definition );
2202  else if ( type == QLatin1String( "enum" ) )
2203  return QgsProcessingParameterEnum::fromScriptCode( name, description, isOptional, definition );
2204  else if ( type == QLatin1String( "string" ) )
2205  return QgsProcessingParameterString::fromScriptCode( name, description, isOptional, definition );
2206  else if ( type == QLatin1String( "authcfg" ) )
2207  return QgsProcessingParameterAuthConfig::fromScriptCode( name, description, isOptional, definition );
2208  else if ( type == QLatin1String( "expression" ) )
2209  return QgsProcessingParameterExpression::fromScriptCode( name, description, isOptional, definition );
2210  else if ( type == QLatin1String( "field" ) )
2211  return QgsProcessingParameterField::fromScriptCode( name, description, isOptional, definition );
2212  else if ( type == QLatin1String( "vector" ) )
2213  return QgsProcessingParameterVectorLayer::fromScriptCode( name, description, isOptional, definition );
2214  else if ( type == QLatin1String( "source" ) )
2215  return QgsProcessingParameterFeatureSource::fromScriptCode( name, description, isOptional, definition );
2216  else if ( type == QLatin1String( "sink" ) )
2217  return QgsProcessingParameterFeatureSink::fromScriptCode( name, description, isOptional, definition );
2218  else if ( type == QLatin1String( "vectordestination" ) )
2219  return QgsProcessingParameterVectorDestination::fromScriptCode( name, description, isOptional, definition );
2220  else if ( type == QLatin1String( "rasterdestination" ) )
2221  return QgsProcessingParameterRasterDestination::fromScriptCode( name, description, isOptional, definition );
2222  else if ( type == QLatin1String( "filedestination" ) )
2223  return QgsProcessingParameterFileDestination::fromScriptCode( name, description, isOptional, definition );
2224  else if ( type == QLatin1String( "folderdestination" ) )
2225  return QgsProcessingParameterFolderDestination::fromScriptCode( name, description, isOptional, definition );
2226  else if ( type == QLatin1String( "band" ) )
2227  return QgsProcessingParameterBand::fromScriptCode( name, description, isOptional, definition );
2228  else if ( type == QLatin1String( "mesh" ) )
2229  return QgsProcessingParameterMeshLayer::fromScriptCode( name, description, isOptional, definition );
2230  else if ( type == QLatin1String( "layout" ) )
2231  return QgsProcessingParameterLayout::fromScriptCode( name, description, isOptional, definition );
2232  else if ( type == QLatin1String( "layoutitem" ) )
2233  return QgsProcessingParameterLayoutItem::fromScriptCode( name, description, isOptional, definition );
2234  else if ( type == QLatin1String( "color" ) )
2235  return QgsProcessingParameterColor::fromScriptCode( name, description, isOptional, definition );
2236  else if ( type == QLatin1String( "coordinateoperation" ) )
2237  return QgsProcessingParameterCoordinateOperation::fromScriptCode( name, description, isOptional, definition );
2238  else if ( type == QLatin1String( "maptheme" ) )
2239  return QgsProcessingParameterMapTheme::fromScriptCode( name, description, isOptional, definition );
2240  else if ( type == QLatin1String( "datetime" ) )
2241  return QgsProcessingParameterDateTime::fromScriptCode( name, description, isOptional, definition );
2242  else if ( type == QLatin1String( "providerconnection" ) )
2243  return QgsProcessingParameterProviderConnection::fromScriptCode( name, description, isOptional, definition );
2244  else if ( type == QLatin1String( "databaseschema" ) )
2245  return QgsProcessingParameterDatabaseSchema::fromScriptCode( name, description, isOptional, definition );
2246  else if ( type == QLatin1String( "databasetable" ) )
2247  return QgsProcessingParameterDatabaseTable::fromScriptCode( name, description, isOptional, definition );
2248 
2249  return nullptr;
2250 }
2251 
2252 bool QgsProcessingParameters::parseScriptCodeParameterOptions( const QString &code, bool &isOptional, QString &name, QString &type, QString &definition )
2253 {
2254  QRegularExpression re( QStringLiteral( "(?:#*)(.*?)=\\s*(.*)" ) );
2255  QRegularExpressionMatch m = re.match( code );
2256  if ( !m.hasMatch() )
2257  return false;
2258 
2259  name = m.captured( 1 );
2260  QString tokens = m.captured( 2 );
2261  if ( tokens.startsWith( QLatin1String( "optional" ), Qt::CaseInsensitive ) )
2262  {
2263  isOptional = true;
2264  tokens.remove( 0, 8 ); // length "optional" = 8
2265  }
2266  else
2267  {
2268  isOptional = false;
2269  }
2270 
2271  tokens = tokens.trimmed();
2272 
2273  QRegularExpression re2( QStringLiteral( "(.*?)\\s+(.*)" ) );
2274  m = re2.match( tokens );
2275  if ( !m.hasMatch() )
2276  {
2277  type = tokens.toLower().trimmed();
2278  definition.clear();
2279  }
2280  else
2281  {
2282  type = m.captured( 1 ).toLower().trimmed();
2283  definition = m.captured( 2 );
2284  }
2285  return true;
2286 }
2287 
2288 //
2289 // QgsProcessingParameterDefinition
2290 //
2291 
2292 QgsProcessingParameterDefinition::QgsProcessingParameterDefinition( const QString &name, const QString &description, const QVariant &defaultValue, bool optional, const QString &help )
2293  : mName( name )
2294  , mDescription( description )
2295  , mHelp( help )
2296  , mDefault( defaultValue )
2297  , mFlags( optional ? FlagOptional : 0 )
2298 {}
2299 
2301 {
2302  if ( !input.isValid() && !mDefault.isValid() )
2303  return mFlags & FlagOptional;
2304 
2305  if ( ( input.type() == QVariant::String && input.toString().isEmpty() )
2306  || ( !input.isValid() && mDefault.type() == QVariant::String && mDefault.toString().isEmpty() ) )
2307  return mFlags & FlagOptional;
2308 
2309  return true;
2310 }
2311 
2313 {
2314  if ( !value.isValid() )
2315  return QStringLiteral( "None" );
2316 
2317  if ( value.canConvert<QgsProperty>() )
2318  return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
2319 
2320  return QgsProcessingUtils::stringToPythonLiteral( value.toString() );
2321 }
2322 
2324 {
2325  QString code = QStringLiteral( "##%1=" ).arg( mName );
2326  if ( mFlags & FlagOptional )
2327  code += QLatin1String( "optional " );
2328  code += type() + ' ';
2329  code += mDefault.toString();
2330  return code.trimmed();
2331 }
2332 
2334 {
2335  // base class method is probably not much use
2336  if ( QgsProcessingParameterType *t = QgsApplication::processingRegistry()->parameterType( type() ) )
2337  {
2338  switch ( outputType )
2339  {
2341  {
2342  QString code = t->className() + QStringLiteral( "('%1', '%2'" ).arg( name(), description() );
2343  if ( mFlags & FlagOptional )
2344  code += QLatin1String( ", optional=True" );
2345 
2347  code += QStringLiteral( ", defaultValue=%1)" ).arg( valueAsPythonString( mDefault, c ) );
2348  return code;
2349  }
2350  }
2351  }
2352 
2353  // oh well, we tried
2354  return QString();
2355 }
2356 
2358 {
2359  QVariantMap map;
2360  map.insert( QStringLiteral( "parameter_type" ), type() );
2361  map.insert( QStringLiteral( "name" ), mName );
2362  map.insert( QStringLiteral( "description" ), mDescription );
2363  map.insert( QStringLiteral( "help" ), mHelp );
2364  map.insert( QStringLiteral( "default" ), mDefault );
2365  map.insert( QStringLiteral( "flags" ), static_cast< int >( mFlags ) );
2366  map.insert( QStringLiteral( "metadata" ), mMetadata );
2367  return map;
2368 }
2369 
2371 {
2372  mName = map.value( QStringLiteral( "name" ) ).toString();
2373  mDescription = map.value( QStringLiteral( "description" ) ).toString();
2374  mHelp = map.value( QStringLiteral( "help" ) ).toString();
2375  mDefault = map.value( QStringLiteral( "default" ) );
2376  mFlags = static_cast< Flags >( map.value( QStringLiteral( "flags" ) ).toInt() );
2377  mMetadata = map.value( QStringLiteral( "metadata" ) ).toMap();
2378  return true;
2379 }
2380 
2382 {
2383  return mAlgorithm;
2384 }
2385 
2387 {
2388  return mAlgorithm ? mAlgorithm->provider() : nullptr;
2389 }
2390 
2392 {
2393  QString text = QStringLiteral( "<p><b>%1</b></p>" ).arg( description() );
2394  if ( !help().isEmpty() )
2395  {
2396  text += QStringLiteral( "<p>%1</p>" ).arg( help() );
2397  }
2398  text += QStringLiteral( "<p>%1</p>" ).arg( QObject::tr( "Python identifier: ‘%1’" ).arg( QStringLiteral( "<i>%1</i>" ).arg( name() ) ) );
2399  return text;
2400 }
2401 
2402 QgsProcessingParameterBoolean::QgsProcessingParameterBoolean( const QString &name, const QString &description, const QVariant &defaultValue, bool optional )
2403  : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
2404 {}
2405 
2407 {
2408  return new QgsProcessingParameterBoolean( *this );
2409 }
2410 
2412 {
2413  if ( !val.isValid() )
2414  return QStringLiteral( "None" );
2415 
2416  if ( val.canConvert<QgsProperty>() )
2417  return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( val.value< QgsProperty >().asExpression() );
2418  return val.toBool() ? QStringLiteral( "True" ) : QStringLiteral( "False" );
2419 }
2420 
2422 {
2423  QString code = QStringLiteral( "##%1=" ).arg( mName );
2424  if ( mFlags & FlagOptional )
2425  code += QLatin1String( "optional " );
2426  code += type() + ' ';
2427  code += mDefault.toBool() ? QStringLiteral( "true" ) : QStringLiteral( "false" );
2428  return code.trimmed();
2429 }
2430 
2431 QgsProcessingParameterBoolean *QgsProcessingParameterBoolean::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
2432 {
2433  return new QgsProcessingParameterBoolean( name, description, definition.toLower().trimmed() != QStringLiteral( "false" ), isOptional );
2434 }
2435 
2436 QgsProcessingParameterCrs::QgsProcessingParameterCrs( const QString &name, const QString &description, const QVariant &defaultValue, bool optional )
2437  : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
2438 {
2439 
2440 }
2441 
2443 {
2444  return new QgsProcessingParameterCrs( *this );
2445 }
2446 
2448 {
2449  if ( !input.isValid() )
2450  return mFlags & FlagOptional;
2451 
2452  if ( input.canConvert<QgsCoordinateReferenceSystem>() )
2453  {
2454  return true;
2455  }
2456  else if ( input.canConvert<QgsProcessingFeatureSourceDefinition>() )
2457  {
2458  return true;
2459  }
2460  else if ( input.canConvert<QgsProcessingOutputLayerDefinition>() )
2461  {
2462  return true;
2463  }
2464 
2465  if ( input.canConvert<QgsProperty>() )
2466  {
2467  return true;
2468  }
2469 
2470  // direct map layer value
2471  if ( qobject_cast< QgsMapLayer * >( qvariant_cast<QObject *>( input ) ) )
2472  return true;
2473 
2474  if ( input.type() != QVariant::String || input.toString().isEmpty() )
2475  return mFlags & FlagOptional;
2476 
2477  return true;
2478 }
2479 
2480 QString QgsProcessingParameterCrs::valueAsPythonString( const QVariant &value, QgsProcessingContext &context ) const
2481 {
2482  if ( !value.isValid() )
2483  return QStringLiteral( "None" );
2484 
2485  if ( value.canConvert<QgsCoordinateReferenceSystem>() )
2486  {
2487  if ( !value.value< QgsCoordinateReferenceSystem >().isValid() )
2488  return QStringLiteral( "QgsCoordinateReferenceSystem()" );
2489  else
2490  return QStringLiteral( "QgsCoordinateReferenceSystem('%1')" ).arg( value.value< QgsCoordinateReferenceSystem >().authid() );
2491  }
2492 
2493  if ( value.canConvert<QgsProperty>() )
2494  return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
2495 
2496  QVariantMap p;
2497  p.insert( name(), value );
2498  QgsMapLayer *layer = QgsProcessingParameters::parameterAsLayer( this, p, context );
2499  if ( layer )
2501 
2503 }
2504 
2505 QgsProcessingParameterCrs *QgsProcessingParameterCrs::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
2506 {
2507  return new QgsProcessingParameterCrs( name, description, definition.compare( QLatin1String( "none" ), Qt::CaseInsensitive ) == 0 ? QVariant() : definition, isOptional );
2508 }
2509 
2510 QgsProcessingParameterMapLayer::QgsProcessingParameterMapLayer( const QString &name, const QString &description, const QVariant &defaultValue, bool optional, const QList<int> &types )
2511  : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
2513 {
2514 
2515 }
2516 
2518 {
2519  return new QgsProcessingParameterMapLayer( *this );
2520 }
2521 
2523 {
2524  if ( !input.isValid() )
2525  return mFlags & FlagOptional;
2526 
2527  if ( input.canConvert<QgsProperty>() )
2528  {
2529  return true;
2530  }
2531 
2532  if ( qobject_cast< QgsMapLayer * >( qvariant_cast<QObject *>( input ) ) )
2533  {
2534  return true;
2535  }
2536 
2537  if ( input.type() != QVariant::String || input.toString().isEmpty() )
2538  return mFlags & FlagOptional;
2539 
2540  if ( !context )
2541  {
2542  // that's as far as we can get without a context
2543  return true;
2544  }
2545 
2546  // try to load as layer
2547  if ( QgsProcessingUtils::mapLayerFromString( input.toString(), *context ) )
2548  return true;
2549 
2550  return false;
2551 }
2552 
2554 {
2555  if ( !val.isValid() )
2556  return QStringLiteral( "None" );
2557 
2558  if ( val.canConvert<QgsProperty>() )
2559  return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( val.value< QgsProperty >().asExpression() );
2560 
2561  QVariantMap p;
2562  p.insert( name(), val );
2563  QgsMapLayer *layer = QgsProcessingParameters::parameterAsLayer( this, p, context );
2565  : QgsProcessingUtils::stringToPythonLiteral( val.toString() );
2566 }
2567 
2569 {
2570  QStringList vectors = QgsProviderRegistry::instance()->fileVectorFilters().split( QStringLiteral( ";;" ) );
2571  QStringList rasters = QgsProviderRegistry::instance()->fileRasterFilters().split( QStringLiteral( ";;" ) );
2572  for ( const QString &raster : rasters )
2573  {
2574  if ( !vectors.contains( raster ) )
2575  vectors << raster;
2576  }
2577  QStringList meshFilters = QgsProviderRegistry::instance()->fileMeshFilters().split( QStringLiteral( ";;" ) );
2578  for ( const QString &mesh : meshFilters )
2579  {
2580  if ( !vectors.contains( mesh ) )
2581  vectors << mesh;
2582  }
2583  vectors.removeAll( QObject::tr( "All files (*.*)" ) );
2584  std::sort( vectors.begin(), vectors.end() );
2585 
2586  return QObject::tr( "All files (*.*)" ) + QStringLiteral( ";;" ) + vectors.join( QLatin1String( ";;" ) );
2587 }
2588 
2590 {
2591  return createAllMapLayerFileFilter();
2592 }
2593 
2595 {
2596  QString code = QStringLiteral( "##%1=" ).arg( mName );
2597  if ( mFlags & FlagOptional )
2598  code += QLatin1String( "optional " );
2599  code += QLatin1String( "layer " );
2600 
2601  for ( int type : mDataTypes )
2602  {
2603  switch ( type )
2604  {
2606  code += QLatin1String( "hasgeometry " );
2607  break;
2608 
2610  code += QLatin1String( "point " );
2611  break;
2612 
2614  code += QLatin1String( "line " );
2615  break;
2616 
2618  code += QLatin1String( "polygon " );
2619  break;
2620 
2622  code += QLatin1String( "raster " );
2623  break;
2624 
2626  code += QLatin1String( "mesh " );
2627  break;
2628  }
2629  }
2630 
2631  code += mDefault.toString();
2632  return code.trimmed();
2633 }
2634 
2635 QgsProcessingParameterMapLayer *QgsProcessingParameterMapLayer::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
2636 {
2637  QList< int > types;
2638  QString def = definition;
2639  while ( true )
2640  {
2641  if ( def.startsWith( QLatin1String( "hasgeometry" ), Qt::CaseInsensitive ) )
2642  {
2644  def = def.mid( 12 );
2645  continue;
2646  }
2647  else if ( def.startsWith( QLatin1String( "point" ), Qt::CaseInsensitive ) )
2648  {
2650  def = def.mid( 6 );
2651  continue;
2652  }
2653  else if ( def.startsWith( QLatin1String( "line" ), Qt::CaseInsensitive ) )
2654  {
2656  def = def.mid( 5 );
2657  continue;
2658  }
2659  else if ( def.startsWith( QLatin1String( "polygon" ), Qt::CaseInsensitive ) )
2660  {
2662  def = def.mid( 8 );
2663  continue;
2664  }
2665  else if ( def.startsWith( QLatin1String( "raster" ), Qt::CaseInsensitive ) )
2666  {
2667  types << QgsProcessing::TypeRaster;
2668  def = def.mid( 7 );
2669  continue;
2670  }
2671  else if ( def.startsWith( QLatin1String( "mesh" ), Qt::CaseInsensitive ) )
2672  {
2673  types << QgsProcessing::TypeMesh;
2674  def = def.mid( 5 );
2675  continue;
2676  }
2677  break;
2678  }
2679 
2680  return new QgsProcessingParameterMapLayer( name, description, def, isOptional, types );
2681 }
2682 
2684 {
2685  switch ( outputType )
2686  {
2688  {
2689  QString code = QStringLiteral( "QgsProcessingParameterMapLayer('%1', '%2'" ).arg( name(), description() );
2690  if ( mFlags & FlagOptional )
2691  code += QLatin1String( ", optional=True" );
2692 
2694  code += QStringLiteral( ", defaultValue=%1" ).arg( valueAsPythonString( mDefault, c ) );
2695 
2696  if ( !mDataTypes.empty() )
2697  {
2698  QStringList options;
2699  options.reserve( mDataTypes.size() );
2700  for ( int t : mDataTypes )
2701  options << QStringLiteral( "QgsProcessing.%1" ).arg( QgsProcessing::sourceTypeToString( static_cast< QgsProcessing::SourceType >( t ) ) );
2702  code += QStringLiteral( ", types=[%1])" ).arg( options.join( ',' ) );
2703  }
2704  else
2705  {
2706  code += QLatin1Char( ')' );
2707  }
2708 
2709  return code;
2710  }
2711  }
2712  return QString();
2713 }
2714 
2716 {
2718  QVariantList types;
2719  for ( int type : mDataTypes )
2720  {
2721  types << type;
2722  }
2723  map.insert( QStringLiteral( "data_types" ), types );
2724  return map;
2725 }
2726 
2728 {
2730  mDataTypes.clear();
2731  const QVariantList values = map.value( QStringLiteral( "data_types" ) ).toList();
2732  for ( const QVariant &val : values )
2733  {
2734  mDataTypes << val.toInt();
2735  }
2736  return true;
2737 }
2738 
2739 QgsProcessingParameterExtent::QgsProcessingParameterExtent( const QString &name, const QString &description, const QVariant &defaultValue, bool optional )
2740  : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
2741 {
2742 
2743 }
2744 
2746 {
2747  return new QgsProcessingParameterExtent( *this );
2748 }
2749 
2751 {
2752  if ( !input.isValid() )
2753  return mFlags & FlagOptional;
2754 
2755  if ( input.canConvert<QgsProcessingFeatureSourceDefinition>() )
2756  {
2757  return true;
2758  }
2759  else if ( input.canConvert<QgsProcessingOutputLayerDefinition>() )
2760  {
2761  return true;
2762  }
2763 
2764  if ( input.canConvert<QgsProperty>() )
2765  {
2766  return true;
2767  }
2768 
2769  if ( input.canConvert< QgsRectangle >() )
2770  {
2771  QgsRectangle r = input.value<QgsRectangle>();
2772  return !r.isNull();
2773  }
2774  if ( input.canConvert< QgsGeometry >() )
2775  {
2776  return true;
2777  }
2778  if ( input.canConvert< QgsReferencedRectangle >() )
2779  {
2781  return !r.isNull();
2782  }
2783 
2784  // direct map layer value
2785  if ( qobject_cast< QgsMapLayer * >( qvariant_cast<QObject *>( input ) ) )
2786  return true;
2787 
2788  if ( input.type() != QVariant::String || input.toString().isEmpty() )
2789  return mFlags & FlagOptional;
2790 
2791  if ( !context )
2792  {
2793  // that's as far as we can get without a context
2794  return true;
2795  }
2796 
2797  QRegularExpression rx( QStringLiteral( "^(.*?)\\s*,\\s*(.*?)\\s*,\\s*(.*?)\\s*,\\s*(.*?)\\s*(?:\\[(.*)\\])?\\s*$" ) );
2798  QRegularExpressionMatch match = rx.match( input.toString() );
2799  if ( match.hasMatch() )
2800  {
2801  bool xMinOk = false;
2802  ( void )match.captured( 1 ).toDouble( &xMinOk );
2803  bool xMaxOk = false;
2804  ( void )match.captured( 2 ).toDouble( &xMaxOk );
2805  bool yMinOk = false;
2806  ( void )match.captured( 3 ).toDouble( &yMinOk );
2807  bool yMaxOk = false;
2808  ( void )match.captured( 4 ).toDouble( &yMaxOk );
2809  if ( xMinOk && xMaxOk && yMinOk && yMaxOk )
2810  return true;
2811  }
2812 
2813  // try as layer extent
2814  return QgsProcessingUtils::mapLayerFromString( input.toString(), *context );
2815 }
2816 
2817 QString QgsProcessingParameterExtent::valueAsPythonString( const QVariant &value, QgsProcessingContext &context ) const
2818 {
2819  if ( !value.isValid() )
2820  return QStringLiteral( "None" );
2821 
2822  if ( value.canConvert<QgsProperty>() )
2823  return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
2824 
2825  if ( value.canConvert< QgsRectangle >() )
2826  {
2827  QgsRectangle r = value.value<QgsRectangle>();
2828  return QStringLiteral( "'%1, %3, %2, %4'" ).arg( qgsDoubleToString( r.xMinimum() ),
2829  qgsDoubleToString( r.yMinimum() ),
2830  qgsDoubleToString( r.xMaximum() ),
2831  qgsDoubleToString( r.yMaximum() ) );
2832  }
2833  else if ( value.canConvert< QgsReferencedRectangle >() )
2834  {
2836  return QStringLiteral( "'%1, %3, %2, %4 [%5]'" ).arg( qgsDoubleToString( r.xMinimum() ),
2837  qgsDoubleToString( r.yMinimum() ),
2838  qgsDoubleToString( r.xMaximum() ),
2839  qgsDoubleToString( r.yMaximum() ), r.crs().authid() );
2840  }
2841  else if ( value.canConvert< QgsGeometry >() )
2842  {
2843  const QgsGeometry g = value.value<QgsGeometry>();
2844  if ( !g.isNull() )
2845  {
2846  const QString wkt = g.asWkt();
2847  return QStringLiteral( "QgsGeometry.fromWkt('%1')" ).arg( wkt );
2848  }
2849  }
2850 
2851  QVariantMap p;
2852  p.insert( name(), value );
2853  QgsMapLayer *layer = QgsProcessingParameters::parameterAsLayer( this, p, context );
2854  if ( layer )
2856 
2858 }
2859 
2860 QgsProcessingParameterExtent *QgsProcessingParameterExtent::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
2861 {
2862  return new QgsProcessingParameterExtent( name, description, definition, isOptional );
2863 }
2864 
2865 QgsProcessingParameterPoint::QgsProcessingParameterPoint( const QString &name, const QString &description, const QVariant &defaultValue, bool optional )
2866  : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
2867 {
2868 
2869 }
2870 
2872 {
2873  return new QgsProcessingParameterPoint( *this );
2874 }
2875 
2877 {
2878  if ( !input.isValid() )
2879  return mFlags & FlagOptional;
2880 
2881  if ( input.canConvert<QgsProperty>() )
2882  {
2883  return true;
2884  }
2885 
2886  if ( input.canConvert< QgsPointXY >() )
2887  {
2888  return true;
2889  }
2890  if ( input.canConvert< QgsReferencedPointXY >() )
2891  {
2892  return true;
2893  }
2894  if ( input.canConvert< QgsGeometry >() )
2895  {
2896  return true;
2897  }
2898 
2899  if ( input.type() == QVariant::String )
2900  {
2901  if ( input.toString().isEmpty() )
2902  return mFlags & FlagOptional;
2903  }
2904 
2905  QRegularExpression rx( QStringLiteral( "^\\s*\\(?\\s*(.*?)\\s*,\\s*(.*?)\\s*(?:\\[(.*)\\])?\\s*\\)?\\s*$" ) );
2906 
2907  QRegularExpressionMatch match = rx.match( input.toString() );
2908  if ( match.hasMatch() )
2909  {
2910  bool xOk = false;
2911  ( void )match.captured( 1 ).toDouble( &xOk );
2912  bool yOk = false;
2913  ( void )match.captured( 2 ).toDouble( &yOk );
2914  return xOk && yOk;
2915  }
2916  else
2917  return false;
2918 }
2919 
2920 QString QgsProcessingParameterPoint::valueAsPythonString( const QVariant &value, QgsProcessingContext &context ) const
2921 {
2922  if ( !value.isValid() )
2923  return QStringLiteral( "None" );
2924 
2925  if ( value.canConvert<QgsProperty>() )
2926  return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
2927 
2928  if ( value.canConvert< QgsPointXY >() )
2929  {
2930  QgsPointXY r = value.value<QgsPointXY>();
2931  return QStringLiteral( "'%1,%2'" ).arg( qgsDoubleToString( r.x() ),
2932  qgsDoubleToString( r.y() ) );
2933  }
2934  else if ( value.canConvert< QgsReferencedPointXY >() )
2935  {
2936  QgsReferencedPointXY r = value.value<QgsReferencedPointXY>();
2937  return QStringLiteral( "'%1,%2 [%3]'" ).arg( qgsDoubleToString( r.x() ),
2938  qgsDoubleToString( r.y() ),
2939  r.crs().authid() );
2940  }
2941  else if ( value.canConvert< QgsGeometry >() )
2942  {
2943  const QgsGeometry g = value.value<QgsGeometry>();
2944  if ( !g.isNull() )
2945  {
2946  const QString wkt = g.asWkt();
2947  return QStringLiteral( "QgsGeometry.fromWkt('%1')" ).arg( wkt );
2948  }
2949  }
2950 
2952 }
2953 
2954 QgsProcessingParameterPoint *QgsProcessingParameterPoint::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
2955 {
2956  return new QgsProcessingParameterPoint( name, description, definition, isOptional );
2957 }
2958 
2959 QgsProcessingParameterGeometry::QgsProcessingParameterGeometry( const QString &name, const QString &description,
2960  const QVariant &defaultValue, bool optional, const QList<int> &geometryTypes )
2961  : QgsProcessingParameterDefinition( name, description, defaultValue, optional ),
2962  mGeomTypes( geometryTypes )
2963 {
2964 
2965 }
2966 
2968 {
2969  return new QgsProcessingParameterGeometry( *this );
2970 }
2971 
2973 {
2974  if ( !input.isValid() )
2975  return mFlags & FlagOptional;
2976 
2977  if ( input.canConvert<QgsProperty>() )
2978  {
2979  return true;
2980  }
2981 
2982  bool anyTypeAllowed = mGeomTypes.isEmpty() || mGeomTypes.contains( QgsWkbTypes::UnknownGeometry );
2983 
2984  if ( input.canConvert< QgsGeometry >() )
2985  {
2986  return anyTypeAllowed || mGeomTypes.contains( input.value<QgsGeometry>().type() );
2987  }
2988 
2989  if ( input.canConvert< QgsReferencedGeometry >() )
2990  {
2991  return anyTypeAllowed || mGeomTypes.contains( input.value<QgsReferencedGeometry>().type() );
2992  }
2993 
2994  if ( input.canConvert< QgsPointXY >() )
2995  {
2996  return anyTypeAllowed || mGeomTypes.contains( QgsWkbTypes::PointGeometry );
2997  }
2998 
2999  if ( input.canConvert< QgsRectangle >() )
3000  {
3001  return anyTypeAllowed || mGeomTypes.contains( QgsWkbTypes::PolygonGeometry );
3002  }
3003 
3004  if ( input.canConvert< QgsReferencedPointXY >() )
3005  {
3006  return anyTypeAllowed || mGeomTypes.contains( QgsWkbTypes::PointGeometry );
3007  }
3008 
3009  if ( input.canConvert< QgsReferencedRectangle >() )
3010  {
3011  return anyTypeAllowed || mGeomTypes.contains( QgsWkbTypes::PolygonGeometry );
3012  }
3013 
3014  if ( input.type() == QVariant::String )
3015  {
3016  if ( input.toString().isEmpty() )
3017  return mFlags & FlagOptional;
3018  }
3019 
3020  // Match against EWKT
3021  QRegularExpression rx( QStringLiteral( "^\\s*(?:CRS=(.*);)?(.*?)$" ) );
3022 
3023  QRegularExpressionMatch match = rx.match( input.toString() );
3024  if ( match.hasMatch() )
3025  {
3026  QgsGeometry g = QgsGeometry::fromWkt( match.captured( 2 ) );
3027  if ( ! g.isNull() )
3028  {
3029  return anyTypeAllowed || mGeomTypes.contains( g.type() );
3030  }
3031  else
3032  {
3033  QgsMessageLog::logMessage( QObject::tr( "Error creating geometry: \"%1\"" ).arg( g.lastError() ), QObject::tr( "Processing" ) );
3034  }
3035  }
3036  return false;
3037 }
3038 
3039 QString QgsProcessingParameterGeometry::valueAsPythonString( const QVariant &value, QgsProcessingContext &context ) const
3040 {
3042  {
3043  if ( !crs.isValid() )
3045  else
3046  return QgsProcessingUtils::stringToPythonLiteral( QStringLiteral( "CRS=%1;%2" ).arg( crs.authid().isEmpty() ? crs.toWkt( QgsCoordinateReferenceSystem::WKT_PREFERRED ) : crs.authid(), g.asWkt() ) );
3047  };
3048 
3049  if ( !value.isValid() )
3050  return QStringLiteral( "None" );
3051 
3052  if ( value.canConvert<QgsProperty>() )
3053  return QStringLiteral( "QgsProperty.fromExpression(%1)" ).arg( QgsProcessingUtils::stringToPythonLiteral( value.value< QgsProperty >().asExpression() ) );
3054 
3055  if ( value.canConvert< QgsGeometry >() )
3056  {
3057  const QgsGeometry g = value.value<QgsGeometry>();
3058  if ( !g.isNull() )
3059  return asPythonString( g );
3060  }
3061 
3062  if ( value.canConvert< QgsReferencedGeometry >() )
3063  {
3064  const QgsReferencedGeometry g = value.value<QgsReferencedGeometry>();
3065  if ( !g.isNull() )
3066  return asPythonString( g, g.crs() );
3067  }
3068 
3069  if ( value.canConvert< QgsPointXY >() )
3070  {
3071  const QgsGeometry g = QgsGeometry::fromPointXY( value.value<QgsPointXY>() );
3072  if ( !g.isNull() )
3073  return asPythonString( g );
3074  }
3075 
3076  if ( value.canConvert< QgsReferencedPointXY >() )
3077  {
3079  if ( !g.isNull() )
3080  return asPythonString( g, g.crs() );
3081  }
3082 
3083  if ( value.canConvert< QgsRectangle >() )
3084  {
3085  const QgsGeometry g = QgsGeometry::fromRect( value.value<QgsRectangle>() );
3086  if ( !g.isNull() )
3087  return asPythonString( g );
3088  }
3089 
3090  if ( value.canConvert< QgsReferencedRectangle >() )
3091  {
3093  if ( !g.isNull() )
3094  return asPythonString( g, g.crs() );
3095  }
3096 
3098 }
3099 
3101 {
3102  QString code = QStringLiteral( "##%1=" ).arg( mName );
3103  if ( mFlags & FlagOptional )
3104  code += QLatin1String( "optional " );
3105  code += type() + ' ';
3106 
3107  for ( int type : mGeomTypes )
3108  {
3109  switch ( static_cast<QgsWkbTypes::GeometryType>( type ) )
3110  {
3112  code += QLatin1String( "point " );
3113  break;
3114 
3116  code += QLatin1String( "line " );
3117  break;
3118 
3120  code += QLatin1String( "polygon " );
3121  break;
3122 
3123  default:
3124  code += QLatin1String( "unknown" );
3125  break;
3126  }
3127  }
3128 
3129  code += mDefault.toString();
3130  return code.trimmed();
3131 }
3132 
3134 {
3135  switch ( outputType )
3136  {
3138  {
3139  QString code = QStringLiteral( "QgsProcessingParameterGeometry('%1', '%2'" ).arg( name(), description() );
3140  if ( mFlags & FlagOptional )
3141  code += QLatin1String( ", optional=True" );
3142 
3143  if ( !mGeomTypes.empty() )
3144  {
3145  auto geomTypeToString = []( QgsWkbTypes::GeometryType t ) -> QString
3146  {
3147  switch ( t )
3148  {
3150  return QStringLiteral( "PointGeometry" );
3151 
3153  return QStringLiteral( "LineGeometry" );
3154 
3156  return QStringLiteral( "PolygonGeometry" );
3157 
3159  return QStringLiteral( "UnknownGeometry" );
3160 
3162  return QStringLiteral( "NullGeometry" );
3163  }
3164  return QString();
3165  };
3166 
3167  QStringList options;
3168  options.reserve( mGeomTypes.size() );
3169  for ( int type : mGeomTypes )
3170  {
3171  options << QStringLiteral( " QgsWkbTypes.%1" ).arg( geomTypeToString( static_cast<QgsWkbTypes::GeometryType>( type ) ) );
3172  }
3173  code += QStringLiteral( ", geometryTypes=[%1 ]" ).arg( options.join( ',' ) );
3174  }
3175 
3177  code += QStringLiteral( ", defaultValue=%1)" ).arg( valueAsPythonString( mDefault, c ) );
3178  return code;
3179  }
3180  }
3181  return QString();
3182 }
3183 
3185 {
3187  QVariantList types;
3188  for ( int type : mGeomTypes )
3189  {
3190  types << type;
3191  }
3192  map.insert( QStringLiteral( "geometrytypes" ), types );
3193  return map;
3194 }
3195 
3197 {
3199  mGeomTypes.clear();
3200  const QVariantList values = map.value( QStringLiteral( "geometrytypes" ) ).toList();
3201  for ( const QVariant &val : values )
3202  {
3203  mGeomTypes << val.toInt();
3204  }
3205  return true;
3206 }
3207 
3208 QgsProcessingParameterGeometry *QgsProcessingParameterGeometry::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
3209 {
3210  return new QgsProcessingParameterGeometry( name, description, definition, isOptional );
3211 }
3212 
3213 QgsProcessingParameterFile::QgsProcessingParameterFile( const QString &name, const QString &description, Behavior behavior, const QString &extension, const QVariant &defaultValue, bool optional, const QString &fileFilter )
3214  : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
3215  , mBehavior( behavior )
3216  , mExtension( fileFilter.isEmpty() ? extension : QString() )
3217  , mFileFilter( fileFilter.isEmpty() && extension.isEmpty() ? QObject::tr( "All files (*.*)" ) : fileFilter )
3218 {
3219 
3220 }
3221 
3223 {
3224  return new QgsProcessingParameterFile( *this );
3225 }
3226 
3228 {
3229  if ( !input.isValid() )
3230  return mFlags & FlagOptional;
3231 
3232  if ( input.canConvert<QgsProperty>() )
3233  {
3234  return true;
3235  }
3236 
3237  QString string = input.toString().trimmed();
3238 
3239  if ( input.type() != QVariant::String || string.isEmpty() )
3240  return mFlags & FlagOptional;
3241 
3242  switch ( mBehavior )
3243  {
3244  case File:
3245  {
3246  if ( !mExtension.isEmpty() )
3247  {
3248  return string.endsWith( mExtension, Qt::CaseInsensitive );
3249  }
3250  else if ( !mFileFilter.isEmpty() )
3251  {
3252  const QString test = QgsFileUtils::addExtensionFromFilter( string, mFileFilter );
3253  return test == string;
3254  }
3255  else
3256  {
3257  return true;
3258  }
3259  }
3260 
3261  case Folder:
3262  return true;
3263  }
3264  return true;
3265 }
3266 
3268 {
3269  QString code = QStringLiteral( "##%1=" ).arg( mName );
3270  if ( mFlags & FlagOptional )
3271  code += QLatin1String( "optional " );
3272  code += ( mBehavior == File ? QStringLiteral( "file" ) : QStringLiteral( "folder" ) ) + ' ';
3273  code += mDefault.toString();
3274  return code.trimmed();
3275 }
3276 
3278 {
3279  switch ( outputType )
3280  {
3282  {
3283 
3284  QString code = QStringLiteral( "QgsProcessingParameterFile('%1', '%2'" ).arg( name(), description() );
3285  if ( mFlags & FlagOptional )
3286  code += QLatin1String( ", optional=True" );
3287  code += QStringLiteral( ", behavior=%1" ).arg( mBehavior == File ? QStringLiteral( "QgsProcessingParameterFile.File" ) : QStringLiteral( "QgsProcessingParameterFile.Folder" ) );
3288  if ( !mExtension.isEmpty() )
3289  code += QStringLiteral( ", extension='%1'" ).arg( mExtension );
3290  if ( !mFileFilter.isEmpty() )
3291  code += QStringLiteral( ", fileFilter='%1'" ).arg( mFileFilter );
3293  code += QStringLiteral( ", defaultValue=%1)" ).arg( valueAsPythonString( mDefault, c ) );
3294  return code;
3295  }
3296  }
3297  return QString();
3298 }
3299 
3300 void QgsProcessingParameterFile::setExtension( const QString &extension )
3301 {
3302  mExtension = extension;
3303  mFileFilter.clear();
3304 }
3305 
3307 {
3308  return mFileFilter;
3309 }
3310 
3311 void QgsProcessingParameterFile::setFileFilter( const QString &filter )
3312 {
3313  mFileFilter = filter;
3314  mExtension.clear();
3315 }
3316 
3318 {
3320  map.insert( QStringLiteral( "behavior" ), mBehavior );
3321  map.insert( QStringLiteral( "extension" ), mExtension );
3322  map.insert( QStringLiteral( "filefilter" ), mFileFilter );
3323  return map;
3324 }
3325 
3326 bool QgsProcessingParameterFile::fromVariantMap( const QVariantMap &map )
3327 {
3329  mBehavior = static_cast< Behavior >( map.value( QStringLiteral( "behavior" ) ).toInt() );
3330  mExtension = map.value( QStringLiteral( "extension" ) ).toString();
3331  mFileFilter = map.value( QStringLiteral( "filefilter" ) ).toString();
3332  return true;
3333 }
3334 
3335 QgsProcessingParameterFile *QgsProcessingParameterFile::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition, QgsProcessingParameterFile::Behavior behavior )
3336 {
3337  return new QgsProcessingParameterFile( name, description, behavior, QString(), definition, isOptional );
3338 }
3339 
3340 QgsProcessingParameterMatrix::QgsProcessingParameterMatrix( const QString &name, const QString &description, int numberRows, bool fixedNumberRows, const QStringList &headers, const QVariant &defaultValue, bool optional )
3341  : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
3342  , mHeaders( headers )
3343  , mNumberRows( numberRows )
3344  , mFixedNumberRows( fixedNumberRows )
3345 {
3346 
3347 }
3348 
3350 {
3351  return new QgsProcessingParameterMatrix( *this );
3352 }
3353 
3355 {
3356  if ( !input.isValid() )
3357  return mFlags & FlagOptional;
3358 
3359  if ( input.type() == QVariant::String )
3360  {
3361  if ( input.toString().isEmpty() )
3362  return mFlags & FlagOptional;
3363  return true;
3364  }
3365  else if ( input.type() == QVariant::List )
3366  {
3367  if ( input.toList().isEmpty() )
3368  return mFlags & FlagOptional;
3369  return true;
3370  }
3371  else if ( input.type() == QVariant::Double || input.type() == QVariant::Int )
3372  {
3373  return true;
3374  }
3375 
3376  return false;
3377 }
3378 
3379 QString QgsProcessingParameterMatrix::valueAsPythonString( const QVariant &value, QgsProcessingContext &context ) const
3380 {
3381  if ( !value.isValid() )
3382  return QStringLiteral( "None" );
3383 
3384  if ( value.canConvert<QgsProperty>() )
3385  return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
3386 
3387  QVariantMap p;
3388  p.insert( name(), value );
3389  QVariantList list = QgsProcessingParameters::parameterAsMatrix( this, p, context );
3390 
3391  QStringList parts;
3392  const auto constList = list;
3393  for ( const QVariant &v : constList )
3394  {
3395  if ( v.type() == QVariant::List )
3396  {
3397  QStringList parts2;
3398  const auto constToList = v.toList();
3399  for ( const QVariant &v2 : constToList )
3400  {
3401  if ( v2.isNull() || !v2.isValid() )
3402  parts2 << QStringLiteral( "None" );
3403  else if ( v2.toString().isEmpty() )
3404  parts2 << QStringLiteral( "''" );
3405  else
3406  parts2 << v2.toString();
3407  }
3408  parts << parts2.join( ',' ).prepend( '[' ).append( ']' );
3409  }
3410  else
3411  {
3412  if ( v.isNull() || !v.isValid() )
3413  parts << QStringLiteral( "None" );
3414  else if ( v.toString().isEmpty() )
3415  parts << QStringLiteral( "''" );
3416  else
3417  parts << v.toString();
3418  }
3419  }
3420 
3421  return parts.join( ',' ).prepend( '[' ).append( ']' );
3422 }
3423 
3425 {
3426  switch ( outputType )
3427  {
3429  {
3430  QString code = QStringLiteral( "QgsProcessingParameterMatrix('%1', '%2'" ).arg( name(), description() );
3431  if ( mFlags & FlagOptional )
3432  code += QLatin1String( ", optional=True" );
3433  code += QStringLiteral( ", numberRows=" ).arg( mNumberRows );
3434  code += QStringLiteral( ", hasFixedNumberRows=" ).arg( mFixedNumberRows ? QStringLiteral( "True" ) : QStringLiteral( "False" ) );
3435 
3436  QStringList headers;
3437  headers.reserve( mHeaders.size() );
3438  for ( const QString &h : mHeaders )
3440  code += QStringLiteral( ", headers=[%1]" ).arg( headers.join( ',' ) );
3441 
3443  code += QStringLiteral( ", defaultValue=%1)" ).arg( valueAsPythonString( mDefault, c ) );
3444  return code;
3445  }
3446  }
3447  return QString();
3448 }
3449 
3451 {
3452  return mHeaders;
3453 }
3454 
3455 void QgsProcessingParameterMatrix::setHeaders( const QStringList &headers )
3456 {
3457  mHeaders = headers;
3458 }
3459 
3461 {
3462  return mNumberRows;
3463 }
3464 
3466 {
3467  mNumberRows = numberRows;
3468 }
3469 
3471 {
3472  return mFixedNumberRows;
3473 }
3474 
3476 {
3477  mFixedNumberRows = fixedNumberRows;
3478 }
3479 
3481 {
3483  map.insert( QStringLiteral( "headers" ), mHeaders );
3484  map.insert( QStringLiteral( "rows" ), mNumberRows );
3485  map.insert( QStringLiteral( "fixed_number_rows" ), mFixedNumberRows );
3486  return map;
3487 }
3488 
3489 bool QgsProcessingParameterMatrix::fromVariantMap( const QVariantMap &map )
3490 {
3492  mHeaders = map.value( QStringLiteral( "headers" ) ).toStringList();
3493  mNumberRows = map.value( QStringLiteral( "rows" ) ).toInt();
3494  mFixedNumberRows = map.value( QStringLiteral( "fixed_number_rows" ) ).toBool();
3495  return true;
3496 }
3497 
3498 QgsProcessingParameterMatrix *QgsProcessingParameterMatrix::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
3499 {
3500  return new QgsProcessingParameterMatrix( name, description, 0, false, QStringList(), definition.isEmpty() ? QVariant() : definition, isOptional );
3501 }
3502 
3503 QgsProcessingParameterMultipleLayers::QgsProcessingParameterMultipleLayers( const QString &name, const QString &description, QgsProcessing::SourceType layerType, const QVariant &defaultValue, bool optional )
3504  : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
3505  , mLayerType( layerType )
3506 {
3507 
3508 }
3509 
3511 {
3512  return new QgsProcessingParameterMultipleLayers( *this );
3513 }
3514 
3516 {
3517  if ( !input.isValid() )
3518  return mFlags & FlagOptional;
3519 
3520  if ( mLayerType != QgsProcessing::TypeFile )
3521  {
3522  if ( qobject_cast< QgsMapLayer * >( qvariant_cast<QObject *>( input ) ) )
3523  {
3524  return true;
3525  }
3526  }
3527 
3528  if ( input.type() == QVariant::String )
3529  {
3530  if ( input.toString().isEmpty() )
3531  return mFlags & FlagOptional;
3532 
3533  if ( mMinimumNumberInputs > 1 )
3534  return false;
3535 
3536  if ( !context )
3537  return true;
3538 
3539  if ( mLayerType != QgsProcessing::TypeFile )
3540  return QgsProcessingUtils::mapLayerFromString( input.toString(), *context );
3541  else
3542  return true;
3543  }
3544  else if ( input.type() == QVariant::List )
3545  {
3546  if ( input.toList().count() < mMinimumNumberInputs )
3547  return mFlags & FlagOptional;
3548 
3549  if ( mMinimumNumberInputs > input.toList().count() )
3550  return false;
3551 
3552  if ( !context )
3553  return true;
3554 
3555  if ( mLayerType != QgsProcessing::TypeFile )
3556  {
3557  const auto constToList = input.toList();
3558  for ( const QVariant &v : constToList )
3559  {
3560  if ( qobject_cast< QgsMapLayer * >( qvariant_cast<QObject *>( v ) ) )
3561  continue;
3562 
3563  if ( !QgsProcessingUtils::mapLayerFromString( v.toString(), *context ) )
3564  return false;
3565  }
3566  }
3567  return true;
3568  }
3569  else if ( input.type() == QVariant::StringList )
3570  {
3571  if ( input.toStringList().count() < mMinimumNumberInputs )
3572  return mFlags & FlagOptional;
3573 
3574  if ( mMinimumNumberInputs > input.toStringList().count() )
3575  return false;
3576 
3577  if ( !context )
3578  return true;
3579 
3580  if ( mLayerType != QgsProcessing::TypeFile )
3581  {
3582  const auto constToStringList = input.toStringList();
3583  for ( const QString &v : constToStringList )
3584  {
3585  if ( !QgsProcessingUtils::mapLayerFromString( v, *context ) )
3586  return false;
3587  }
3588  }
3589  return true;
3590  }
3591  return false;
3592 }
3593 
3595 {
3596  if ( !value.isValid() )
3597  return QStringLiteral( "None" );
3598 
3599  if ( value.canConvert<QgsProperty>() )
3600  return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
3601 
3602  if ( mLayerType == QgsProcessing::TypeFile )
3603  {
3604  QStringList parts;
3605  if ( value.type() == QVariant::StringList )
3606  {
3607  const QStringList list = value.toStringList();
3608  parts.reserve( list.count() );
3609  for ( const QString &v : list )
3611  }
3612  else if ( value.type() == QVariant::List )
3613  {
3614  const QVariantList list = value.toList();
3615  parts.reserve( list.count() );
3616  for ( const QVariant &v : list )
3617  parts << QgsProcessingUtils::stringToPythonLiteral( v.toString() );
3618  }
3619  if ( !parts.isEmpty() )
3620  return parts.join( ',' ).prepend( '[' ).append( ']' );
3621  }
3622  else
3623  {
3624  QVariantMap p;
3625  p.insert( name(), value );
3626  const QList<QgsMapLayer *> list = QgsProcessingParameters::parameterAsLayerList( this, p, context );
3627  if ( !list.isEmpty() )
3628  {
3629  QStringList parts;
3630  parts.reserve( list.count() );
3631  for ( const QgsMapLayer *layer : list )
3632  {
3634  }
3635  return parts.join( ',' ).prepend( '[' ).append( ']' );
3636  }
3637  }
3638 
3640 }
3641 
3643 {
3644  QString code = QStringLiteral( "##%1=" ).arg( mName );
3645  if ( mFlags & FlagOptional )
3646  code += QLatin1String( "optional " );
3647  switch ( mLayerType )
3648  {
3650  code += QLatin1String( "multiple raster" );
3651  break;
3652 
3654  code += QLatin1String( "multiple file" );
3655  break;
3656 
3657  default:
3658  code += QLatin1String( "multiple vector" );
3659  break;
3660  }
3661  code += ' ';
3662  if ( mDefault.type() == QVariant::List )
3663  {
3664  QStringList parts;
3665  const auto constToList = mDefault.toList();
3666  for ( const QVariant &var : constToList )
3667  {
3668  parts << var.toString();
3669  }
3670  code += parts.join( ',' );
3671  }
3672  else if ( mDefault.type() == QVariant::StringList )
3673  {
3674  code += mDefault.toStringList().join( ',' );
3675  }
3676  else
3677  {
3678  code += mDefault.toString();
3679  }
3680  return code.trimmed();
3681 }
3682 
3684 {
3685  switch ( outputType )
3686  {
3688  {
3689  QString code = QStringLiteral( "QgsProcessingParameterMultipleLayers('%1', '%2'" ).arg( name(), description() );
3690  if ( mFlags & FlagOptional )
3691  code += QLatin1String( ", optional=True" );
3692 
3693  QString layerType = QStringLiteral( "QgsProcessing.%1" ).arg( QgsProcessing::sourceTypeToString( mLayerType ) );
3694 
3695  code += QStringLiteral( ", layerType=%1" ).arg( layerType );
3697  code += QStringLiteral( ", defaultValue=%1)" ).arg( valueAsPythonString( mDefault, c ) );
3698  return code;
3699  }
3700  }
3701  return QString();
3702 }
3703 
3705 {
3706  QStringList exts;
3707  switch ( mLayerType )
3708  {
3710  return QObject::tr( "All files (*.*)" );
3711 
3713  return QgsProviderRegistry::instance()->fileRasterFilters() + QStringLiteral( ";;" ) + QObject::tr( "All files (*.*)" );
3714 
3720  return QgsProviderRegistry::instance()->fileVectorFilters() + QStringLiteral( ";;" ) + QObject::tr( "All files (*.*)" );
3721 
3723  return QgsProviderRegistry::instance()->fileMeshFilters() + QStringLiteral( ";;" ) + QObject::tr( "All files (*.*)" );
3724 
3726  return createAllMapLayerFileFilter();
3727  }
3728  return QString();
3729 }
3730 
3732 {
3733  return mLayerType;
3734 }
3735 
3737 {
3738  mLayerType = type;
3739 }
3740 
3742 {
3743  return mMinimumNumberInputs;
3744 }
3745 
3747 {
3748  if ( mMinimumNumberInputs >= 1 || !( flags() & QgsProcessingParameterDefinition::FlagOptional ) )
3749  mMinimumNumberInputs = minimumNumberInputs;
3750 }
3751 
3753 {
3755  map.insert( QStringLiteral( "layer_type" ), mLayerType );
3756  map.insert( QStringLiteral( "min_inputs" ), mMinimumNumberInputs );
3757  return map;
3758 }
3759 
3761 {
3763  mLayerType = static_cast< QgsProcessing::SourceType >( map.value( QStringLiteral( "layer_type" ) ).toInt() );
3764  mMinimumNumberInputs = map.value( QStringLiteral( "min_inputs" ) ).toInt();
3765  return true;
3766 }
3767 
3768 QgsProcessingParameterMultipleLayers *QgsProcessingParameterMultipleLayers::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
3769 {
3770  QString type = definition;
3771  QString defaultVal;
3772  QRegularExpression re( QStringLiteral( "(.*?)\\s+(.*)" ) );
3773  QRegularExpressionMatch m = re.match( definition );
3774  if ( m.hasMatch() )
3775  {
3776  type = m.captured( 1 ).toLower().trimmed();
3777  defaultVal = m.captured( 2 );
3778  }
3780  if ( type == QLatin1String( "vector" ) )
3782  else if ( type == QLatin1String( "raster" ) )
3784  else if ( type == QLatin1String( "file" ) )
3786  return new QgsProcessingParameterMultipleLayers( name, description, layerType, defaultVal.isEmpty() ? QVariant() : defaultVal, isOptional );
3787 }
3788 
3789 QgsProcessingParameterNumber::QgsProcessingParameterNumber( const QString &name, const QString &description, Type type, const QVariant &defaultValue, bool optional, double minValue, double maxValue )
3790  : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
3791  , mMin( minValue )
3792  , mMax( maxValue )
3793  , mDataType( type )
3794 {
3795  if ( mMin >= mMax )
3796  {
3797  QgsMessageLog::logMessage( QObject::tr( "Invalid number parameter \"%1\": min value %2 is >= max value %3!" ).arg( name ).arg( mMin ).arg( mMax ), QObject::tr( "Processing" ) );
3798  }
3799 }
3800 
3802 {
3803  return new QgsProcessingParameterNumber( *this );
3804 }
3805 
3807 {
3808  QVariant input = value;
3809  if ( !input.isValid() )
3810  {
3811  if ( !defaultValue().isValid() )
3812  return mFlags & FlagOptional;
3813 
3814  input = defaultValue();
3815  }
3816 
3817  if ( input.canConvert<QgsProperty>() )
3818  {
3819  return true;
3820  }
3821 
3822  bool ok = false;
3823  double res = input.toDouble( &ok );
3824  if ( !ok )
3825  return mFlags & FlagOptional;
3826 
3827  return !( res < mMin || res > mMax );
3828 }
3829 
3831 {
3832  if ( !value.isValid() )
3833  return QStringLiteral( "None" );
3834 
3835  if ( value.canConvert<QgsProperty>() )
3836  return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
3837 
3838  return value.toString();
3839 }
3840 
3842 {
3844  QStringList parts;
3845  if ( mMin > std::numeric_limits<double>::lowest() + 1 )
3846  parts << QObject::tr( "Minimum value: %1" ).arg( mMin );
3847  if ( mMax < std::numeric_limits<double>::max() )
3848  parts << QObject::tr( "Maximum value: %1" ).arg( mMax );
3849  if ( mDefault.isValid() )
3850  parts << QObject::tr( "Default value: %1" ).arg( mDataType == Integer ? mDefault.toInt() : mDefault.toDouble() );
3851  QString extra = parts.join( QLatin1String( "<br />" ) );
3852  if ( !extra.isEmpty() )
3853  text += QStringLiteral( "<p>%1</p>" ).arg( extra );
3854  return text;
3855 }
3856 
3858 {
3859  switch ( outputType )
3860  {
3862  {
3863  QString code = QStringLiteral( "QgsProcessingParameterNumber('%1', '%2'" ).arg( name(), description() );
3864  if ( mFlags & FlagOptional )
3865  code += QLatin1String( ", optional=True" );
3866 
3867  code += QStringLiteral( ", type=%1" ).arg( mDataType == Integer ? QStringLiteral( "QgsProcessingParameterNumber.Integer" ) : QStringLiteral( "QgsProcessingParameterNumber.Double" ) );
3868 
3869  if ( mMin != std::numeric_limits<double>::lowest() + 1 )
3870  code += QStringLiteral( ", minValue=%1" ).arg( mMin );
3871  if ( mMax != std::numeric_limits<double>::max() )
3872  code += QStringLiteral( ", maxValue=%1" ).arg( mMax );
3874  code += QStringLiteral( ", defaultValue=%1)" ).arg( valueAsPythonString( mDefault, c ) );
3875  return code;
3876  }
3877  }
3878  return QString();
3879 }
3880 
3882 {
3883  return mMin;
3884 }
3885 
3887 {
3888  mMin = min;
3889 }
3890 
3892 {
3893  return mMax;
3894 }
3895 
3897 {
3898  mMax = max;
3899 }
3900 
3902 {
3903  return mDataType;
3904 }
3905 
3907 {
3908  mDataType = dataType;
3909 }
3910 
3912 {
3914  map.insert( QStringLiteral( "min" ), mMin );
3915  map.insert( QStringLiteral( "max" ), mMax );
3916  map.insert( QStringLiteral( "data_type" ), mDataType );
3917  return map;
3918 }
3919 
3920 bool QgsProcessingParameterNumber::fromVariantMap( const QVariantMap &map )
3921 {
3923  mMin = map.value( QStringLiteral( "min" ) ).toDouble();
3924  mMax = map.value( QStringLiteral( "max" ) ).toDouble();
3925  mDataType = static_cast< Type >( map.value( QStringLiteral( "data_type" ) ).toInt() );
3926  return true;
3927 }
3928 
3929 QgsProcessingParameterNumber *QgsProcessingParameterNumber::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
3930 {
3931  return new QgsProcessingParameterNumber( name, description, Double, definition.isEmpty() ? QVariant()
3932  : ( definition.toLower().trimmed() == QLatin1String( "none" ) ? QVariant() : definition ), isOptional );
3933 }
3934 
3935 QgsProcessingParameterRange::QgsProcessingParameterRange( const QString &name, const QString &description, QgsProcessingParameterNumber::Type type, const QVariant &defaultValue, bool optional )
3936  : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
3937  , mDataType( type )
3938 {
3939 
3940 }
3941 
3943 {
3944  return new QgsProcessingParameterRange( *this );
3945 }
3946 
3948 {
3949  if ( !input.isValid() )
3950  return mFlags & FlagOptional;
3951 
3952  if ( input.canConvert<QgsProperty>() )
3953  {
3954  return true;
3955  }
3956 
3957  if ( input.type() == QVariant::String )
3958  {
3959  QStringList list = input.toString().split( ',' );
3960  if ( list.count() != 2 )
3961  return mFlags & FlagOptional;
3962  bool ok = false;
3963  list.at( 0 ).toDouble( &ok );
3964  bool ok2 = false;
3965  list.at( 1 ).toDouble( &ok2 );
3966  if ( !ok || !ok2 )
3967  return mFlags & FlagOptional;
3968  return true;
3969  }
3970  else if ( input.type() == QVariant::List )
3971  {
3972  if ( input.toList().count() != 2 )
3973  return mFlags & FlagOptional;
3974 
3975  bool ok = false;
3976  input.toList().at( 0 ).toDouble( &ok );
3977  bool ok2 = false;
3978  input.toList().at( 1 ).toDouble( &ok2 );
3979  if ( !ok || !ok2 )
3980  return mFlags & FlagOptional;
3981  return true;
3982  }
3983 
3984  return false;
3985 }
3986 
3987 QString QgsProcessingParameterRange::valueAsPythonString( const QVariant &value, QgsProcessingContext &context ) const
3988 {
3989  if ( !value.isValid() )
3990  return QStringLiteral( "None" );
3991 
3992  if ( value.canConvert<QgsProperty>() )
3993  return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
3994 
3995  QVariantMap p;
3996  p.insert( name(), value );
3997  QList< double > parts = QgsProcessingParameters::parameterAsRange( this, p, context );
3998 
3999  QStringList stringParts;
4000  const auto constParts = parts;
4001  for ( double v : constParts )
4002  {
4003  stringParts << QString::number( v );
4004  }
4005  return stringParts.join( ',' ).prepend( '[' ).append( ']' );
4006 }
4007 
4009 {
4010  switch ( outputType )
4011  {
4013  {
4014  QString code = QStringLiteral( "QgsProcessingParameterRange('%1', '%2'" ).arg( name(), description() );
4015  if ( mFlags & FlagOptional )
4016  code += QLatin1String( ", optional=True" );
4017 
4018  code += QStringLiteral( ", type=%1" ).arg( mDataType == QgsProcessingParameterNumber::Integer ? QStringLiteral( "QgsProcessingParameterNumber.Integer" ) : QStringLiteral( "QgsProcessingParameterNumber.Double" ) );
4019 
4021  code += QStringLiteral( ", defaultValue=%1)" ).arg( valueAsPythonString( mDefault, c ) );
4022  return code;
4023  }
4024  }
4025  return QString();
4026 }
4027 
4029 {
4030  return mDataType;
4031 }
4032 
4034 {
4035  mDataType = dataType;
4036 }
4037 
4039 {
4041  map.insert( QStringLiteral( "data_type" ), mDataType );
4042  return map;
4043 }
4044 
4045 bool QgsProcessingParameterRange::fromVariantMap( const QVariantMap &map )
4046 {
4048  mDataType = static_cast< QgsProcessingParameterNumber::Type >( map.value( QStringLiteral( "data_type" ) ).toInt() );
4049  return true;
4050 }
4051 
4052 QgsProcessingParameterRange *QgsProcessingParameterRange::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
4053 {
4054  return new QgsProcessingParameterRange( name, description, QgsProcessingParameterNumber::Double, definition.isEmpty() ? QVariant()
4055  : ( definition.toLower().trimmed() == QLatin1String( "none" ) ? QVariant() : definition ), isOptional );
4056 }
4057 
4058 QgsProcessingParameterRasterLayer::QgsProcessingParameterRasterLayer( const QString &name, const QString &description, const QVariant &defaultValue, bool optional )
4059  : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
4060 {
4061 
4062 }
4063 
4065 {
4066  return new QgsProcessingParameterRasterLayer( *this );
4067 }
4068 
4070 {
4071  if ( !input.isValid() )
4072  return mFlags & FlagOptional;
4073 
4074  if ( input.canConvert<QgsProperty>() )
4075  {
4076  return true;
4077  }
4078 
4079  if ( qobject_cast< QgsRasterLayer * >( qvariant_cast<QObject *>( input ) ) )
4080  return true;
4081 
4082  if ( input.type() != QVariant::String || input.toString().isEmpty() )
4083  return mFlags & FlagOptional;
4084 
4085  if ( !context )
4086  {
4087  // that's as far as we can get without a context
4088  return true;
4089  }
4090 
4091  // try to load as layer
4092  if ( QgsProcessingUtils::mapLayerFromString( input.toString(), *context, true, QgsProcessingUtils::LayerHint::Raster ) )
4093  return true;
4094 
4095  return false;
4096 }
4097 
4099 {
4100  if ( !val.isValid() )
4101  return QStringLiteral( "None" );
4102 
4103  if ( val.canConvert<QgsProperty>() )
4104  return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( val.value< QgsProperty >().asExpression() );
4105 
4106  QVariantMap p;
4107  p.insert( name(), val );
4110  : QgsProcessingUtils::stringToPythonLiteral( val.toString() );
4111 }
4112 
4114 {
4115  return QgsProviderRegistry::instance()->fileRasterFilters() + QStringLiteral( ";;" ) + QObject::tr( "All files (*.*)" );
4116 }
4117 
4118 QgsProcessingParameterRasterLayer *QgsProcessingParameterRasterLayer::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
4119 {
4120  return new QgsProcessingParameterRasterLayer( name, description, definition.isEmpty() ? QVariant() : definition, isOptional );
4121 }
4122 
4123 QgsProcessingParameterEnum::QgsProcessingParameterEnum( const QString &name, const QString &description, const QStringList &options, bool allowMultiple, const QVariant &defaultValue, bool optional )
4124  : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
4125  , mOptions( options )
4126  , mAllowMultiple( allowMultiple )
4127 {
4128 
4129 }
4130 
4132 {
4133  return new QgsProcessingParameterEnum( *this );
4134 }
4135 
4137 {
4138  QVariant input = value;
4139  if ( !input.isValid() )
4140  {
4141  if ( !defaultValue().isValid() )
4142  return mFlags & FlagOptional;
4143 
4144  input = defaultValue();
4145  }
4146 
4147  if ( input.canConvert<QgsProperty>() )
4148  {
4149  return true;
4150  }
4151 
4152  if ( input.type() == QVariant::List )
4153  {
4154  if ( !mAllowMultiple )
4155  return false;
4156 
4157  const QVariantList values = input.toList();
4158  if ( values.empty() && !( mFlags & FlagOptional ) )
4159  return false;
4160 
4161  for ( const QVariant &val : values )
4162  {
4163  bool ok = false;
4164  int res = val.toInt( &ok );
4165  if ( !ok )
4166  return false;
4167  else if ( res < 0 || res >= mOptions.count() )
4168  return false;
4169  }
4170 
4171  return true;
4172  }
4173  else if ( input.type() == QVariant::String )
4174  {
4175  QStringList parts = input.toString().split( ',' );
4176  if ( parts.count() > 1 && !mAllowMultiple )
4177  return false;
4178 
4179  const auto constParts = parts;
4180  for ( const QString &part : constParts )
4181  {
4182  bool ok = false;
4183  int res = part.toInt( &ok );
4184  if ( !ok )
4185  return false;
4186  else if ( res < 0 || res >= mOptions.count() )
4187  return false;
4188  }
4189  return true;
4190  }
4191  else if ( input.type() == QVariant::Int || input.type() == QVariant::Double )
4192  {
4193  bool ok = false;
4194  int res = input.toInt( &ok );
4195  if ( !ok )
4196  return false;
4197  else if ( res >= 0 && res < mOptions.count() )
4198  return true;
4199  }
4200  return false;
4201 }
4202 
4204 {
4205  if ( !value.isValid() )
4206  return QStringLiteral( "None" );
4207 
4208  if ( value.canConvert<QgsProperty>() )
4209  return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
4210 
4211  if ( value.type() == QVariant::List )
4212  {
4213  QStringList parts;
4214  const auto constToList = value.toList();
4215  for ( const QVariant &val : constToList )
4216  {
4217  parts << QString::number( static_cast< int >( val.toDouble() ) );
4218  }
4219  return parts.join( ',' ).prepend( '[' ).append( ']' );
4220  }
4221  else if ( value.type() == QVariant::String )
4222  {
4223  QStringList parts = value.toString().split( ',' );
4224  if ( parts.count() > 1 )
4225  {
4226  return parts.join( ',' ).prepend( '[' ).append( ']' );
4227  }
4228  }
4229 
4230  return QString::number( static_cast< int >( value.toDouble() ) );
4231 }
4232 
4234 {
4235  QString code = QStringLiteral( "##%1=" ).arg( mName );
4236  if ( mFlags & FlagOptional )
4237  code += QLatin1String( "optional " );
4238  code += QLatin1String( "enum " );
4239 
4240  if ( mAllowMultiple )
4241  code += QLatin1String( "multiple " );
4242 
4243  code += mOptions.join( ';' ) + ' ';
4244 
4245  code += mDefault.toString();
4246  return code.trimmed();
4247 }
4248 
4250 {
4251  switch ( outputType )
4252  {
4254  {
4255  QString code = QStringLiteral( "QgsProcessingParameterEnum('%1', '%2'" ).arg( name(), description() );
4256  if ( mFlags & FlagOptional )
4257  code += QLatin1String( ", optional=True" );
4258 
4259  QStringList options;
4260  options.reserve( mOptions.size() );
4261  for ( const QString &o : mOptions )
4263  code += QStringLiteral( ", options=[%1]" ).arg( options.join( ',' ) );
4264 
4265  code += QStringLiteral( ", allowMultiple=%1" ).arg( mAllowMultiple ? QStringLiteral( "True" ) : QStringLiteral( "False" ) );
4266 
4268  code += QStringLiteral( ", defaultValue=%1)" ).arg( valueAsPythonString( mDefault, c ) );
4269  return code;
4270  }
4271  }
4272  return QString();
4273 }
4274 
4276 {
4277  return mOptions;
4278 }
4279 
4280 void QgsProcessingParameterEnum::setOptions( const QStringList &options )
4281 {
4282  mOptions = options;
4283 }
4284 
4286 {
4287  return mAllowMultiple;
4288 }
4289 
4291 {
4292  mAllowMultiple = allowMultiple;
4293 }
4294 
4296 {
4298  map.insert( QStringLiteral( "options" ), mOptions );
4299  map.insert( QStringLiteral( "allow_multiple" ), mAllowMultiple );
4300  return map;
4301 }
4302 
4303 bool QgsProcessingParameterEnum::fromVariantMap( const QVariantMap &map )
4304 {
4306  mOptions = map.value( QStringLiteral( "options" ) ).toStringList();
4307  mAllowMultiple = map.value( QStringLiteral( "allow_multiple" ) ).toBool();
4308  return true;
4309 }
4310 
4311 QgsProcessingParameterEnum *QgsProcessingParameterEnum::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
4312 {
4313  QString defaultVal;
4314  bool multiple = false;
4315  QString def = definition;
4316  if ( def.startsWith( QLatin1String( "multiple" ), Qt::CaseInsensitive ) )
4317  {
4318  multiple = true;
4319  def = def.mid( 9 );
4320  }
4321 
4322  QRegularExpression re( QStringLiteral( "(.*)\\s+(.*?)$" ) );
4323  QRegularExpressionMatch m = re.match( def );
4324  QString values = def;
4325  if ( m.hasMatch() )
4326  {
4327  values = m.captured( 1 ).trimmed();
4328  defaultVal = m.captured( 2 );
4329  }
4330 
4331  return new QgsProcessingParameterEnum( name, description, values.split( ';' ), multiple, defaultVal.isEmpty() ? QVariant() : defaultVal, isOptional );
4332 }
4333 
4334 QgsProcessingParameterString::QgsProcessingParameterString( const QString &name, const QString &description, const QVariant &defaultValue, bool multiLine, bool optional )
4335  : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
4336  , mMultiLine( multiLine )
4337 {
4338 
4339 }
4340 
4342 {
4343  return new QgsProcessingParameterString( *this );
4344 }
4345 
4347 {
4348  if ( !value.isValid() || value.isNull() )
4349  return QStringLiteral( "None" );
4350 
4351  if ( value.canConvert<QgsProperty>() )
4352  return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
4353 
4354  QString s = value.toString();
4356 }
4357 
4359 {
4360  QString code = QStringLiteral( "##%1=" ).arg( mName );
4361  if ( mFlags & FlagOptional )
4362  code += QLatin1String( "optional " );
4363  code += QLatin1String( "string " );
4364 
4365  if ( mMultiLine )
4366  code += QLatin1String( "long " );
4367 
4368  code += mDefault.toString();
4369  return code.trimmed();
4370 }
4371 
4373 {
4374  switch ( outputType )
4375  {
4377  {
4378  QString code = QStringLiteral( "QgsProcessingParameterString('%1', '%2'" ).arg( name(), description() );
4379  if ( mFlags & FlagOptional )
4380  code += QLatin1String( ", optional=True" );
4381  code += QStringLiteral( ", multiLine=%1" ).arg( mMultiLine ? QStringLiteral( "True" ) : QStringLiteral( "False" ) );
4382 
4384  code += QStringLiteral( ", defaultValue=%1)" ).arg( valueAsPythonString( mDefault, c ) );
4385  return code;
4386  }
4387  }
4388  return QString();
4389 }
4390 
4392 {
4393  return mMultiLine;
4394 }
4395 
4397 {
4398  mMultiLine = multiLine;
4399 }
4400 
4402 {
4404  map.insert( QStringLiteral( "multiline" ), mMultiLine );
4405  return map;
4406 }
4407 
4408 bool QgsProcessingParameterString::fromVariantMap( const QVariantMap &map )
4409 {
4411  mMultiLine = map.value( QStringLiteral( "multiline" ) ).toBool();
4412  return true;
4413 }
4414 
4415 QgsProcessingParameterString *QgsProcessingParameterString::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
4416 {
4417  QString def = definition;
4418  bool multiLine = false;
4419  if ( def.startsWith( QLatin1String( "long" ), Qt::CaseInsensitive ) )
4420  {
4421  multiLine = true;
4422  def = def.mid( 5 );
4423  }
4424 
4425  if ( def.startsWith( '"' ) || def.startsWith( '\'' ) )
4426  def = def.mid( 1 );
4427  if ( def.endsWith( '"' ) || def.endsWith( '\'' ) )
4428  def.chop( 1 );
4429 
4430  QVariant defaultValue = def;
4431  if ( def == QLatin1String( "None" ) )
4432  defaultValue = QVariant();
4433 
4435 }
4436 
4437 //
4438 // QgsProcessingParameterAuthConfig
4439 //
4440 
4441 QgsProcessingParameterAuthConfig::QgsProcessingParameterAuthConfig( const QString &name, const QString &description, const QVariant &defaultValue, bool optional )
4442  : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
4443 {
4444 
4445 }
4446 
4448 {
4449  return new QgsProcessingParameterAuthConfig( *this );
4450 }
4451 
4453 {
4454  if ( !value.isValid() )
4455  return QStringLiteral( "None" );
4456 
4457  QString s = value.toString();
4459 }
4460 
4462 {
4463  QString code = QStringLiteral( "##%1=" ).arg( mName );
4464  if ( mFlags & FlagOptional )
4465  code += QLatin1String( "optional " );
4466  code += QLatin1String( "authcfg " );
4467 
4468  code += mDefault.toString();
4469  return code.trimmed();
4470 }
4471 
4472 QgsProcessingParameterAuthConfig *QgsProcessingParameterAuthConfig::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
4473 {
4474  QString def = definition;
4475 
4476  if ( def.startsWith( '"' ) || def.startsWith( '\'' ) )
4477  def = def.mid( 1 );
4478  if ( def.endsWith( '"' ) || def.endsWith( '\'' ) )
4479  def.chop( 1 );
4480 
4481  QVariant defaultValue = def;
4482  if ( def == QLatin1String( "None" ) )
4483  defaultValue = QVariant();
4484 
4485  return new QgsProcessingParameterAuthConfig( name, description, defaultValue, isOptional );
4486 }
4487 
4488 
4489 //
4490 // QgsProcessingParameterExpression
4491 //
4492 
4493 QgsProcessingParameterExpression::QgsProcessingParameterExpression( const QString &name, const QString &description, const QVariant &defaultValue, const QString &parentLayerParameterName, bool optional )
4494  : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
4495  , mParentLayerParameterName( parentLayerParameterName )
4496 {
4497 
4498 }
4499 
4501 {
4502  return new QgsProcessingParameterExpression( *this );
4503 }
4504 
4506 {
4507  if ( !value.isValid() )
4508  return QStringLiteral( "None" );
4509 
4510  if ( value.canConvert<QgsProperty>() )
4511  return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
4512 
4513  QString s = value.toString();
4515 }
4516 
4518 {
4519  QStringList depends;
4520  if ( !mParentLayerParameterName.isEmpty() )
4521  depends << mParentLayerParameterName;
4522  return depends;
4523 }
4524 
4526 {
4527  switch ( outputType )
4528  {
4530  {
4531  QString code = QStringLiteral( "QgsProcessingParameterExpression('%1', '%2'" ).arg( name(), description() );
4532  if ( mFlags & FlagOptional )
4533  code += QLatin1String( ", optional=True" );
4534 
4535  code += QStringLiteral( ", parentLayerParameterName='%1'" ).arg( mParentLayerParameterName );
4536 
4538  code += QStringLiteral( ", defaultValue=%1)" ).arg( valueAsPythonString( mDefault, c ) );
4539  return code;
4540  }
4541  }
4542  return QString();
4543 }
4544 
4546 {
4547  return mParentLayerParameterName;
4548 }
4549 
4550 void QgsProcessingParameterExpression::setParentLayerParameterName( const QString &parentLayerParameterName )
4551 {
4552  mParentLayerParameterName = parentLayerParameterName;
4553 }
4554 
4556 {
4558  map.insert( QStringLiteral( "parent_layer" ), mParentLayerParameterName );
4559  return map;
4560 }
4561 
4563 {
4565  mParentLayerParameterName = map.value( QStringLiteral( "parent_layer" ) ).toString();
4566  return true;
4567 }
4568 
4569 QgsProcessingParameterExpression *QgsProcessingParameterExpression::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
4570 {
4571  return new QgsProcessingParameterExpression( name, description, definition, QString(), isOptional );
4572 }
4573 
4574 QgsProcessingParameterVectorLayer::QgsProcessingParameterVectorLayer( const QString &name, const QString &description, const QList<int> &types, const QVariant &defaultValue, bool optional )
4575  : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
4577 {
4578 
4579 }
4580 
4582 {
4583  return new QgsProcessingParameterVectorLayer( *this );
4584 }
4585 
4587 {
4588  if ( !v.isValid() )
4589  return mFlags & FlagOptional;
4590 
4591  QVariant var = v;
4592 
4593  if ( var.canConvert<QgsProperty>() )
4594  {
4595  QgsProperty p = var.value< QgsProperty >();
4597  {
4598  var = p.staticValue();
4599  }
4600  else
4601  {
4602  return true;
4603  }
4604  }
4605 
4606  if ( qobject_cast< QgsVectorLayer * >( qvariant_cast<QObject *>( var ) ) )
4607  return true;
4608 
4609  if ( var.type() != QVariant::String || var.toString().isEmpty() )
4610  return mFlags & FlagOptional;
4611 
4612  if ( !context )
4613  {
4614  // that's as far as we can get without a context
4615  return true;
4616  }
4617 
4618  // try to load as layer
4619  if ( QgsProcessingUtils::mapLayerFromString( var.toString(), *context, true, QgsProcessingUtils::LayerHint::Vector ) )
4620  return true;
4621 
4622  return false;
4623 }
4624 
4626 {
4627  if ( !val.isValid() )
4628  return QStringLiteral( "None" );
4629 
4630  if ( val.canConvert<QgsProperty>() )
4631  return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( val.value< QgsProperty >().asExpression() );
4632 
4633  QVariantMap p;
4634  p.insert( name(), val );
4637  : QgsProcessingUtils::stringToPythonLiteral( val.toString() );
4638 }
4639 
4641 {
4642  switch ( outputType )
4643  {
4645  {
4646  QString code = QStringLiteral( "QgsProcessingParameterVectorLayer('%1', '%2'" ).arg( name(), description() );
4647  if ( mFlags & FlagOptional )
4648  code += QLatin1String( ", optional=True" );
4649 
4650  if ( !mDataTypes.empty() )
4651  {
4652  QStringList options;
4653  for ( int t : mDataTypes )
4654  options << QStringLiteral( "QgsProcessing.%1" ).arg( QgsProcessing::sourceTypeToString( static_cast< QgsProcessing::SourceType >( t ) ) );
4655  code += QStringLiteral( ", types=[%1]" ).arg( options.join( ',' ) );
4656  }
4657 
4659  code += QStringLiteral( ", defaultValue=%1)" ).arg( valueAsPythonString( mDefault, c ) );
4660  return code;
4661  }
4662  }
4663  return QString();
4664 }
4665 
4667 {
4668  return QgsProviderRegistry::instance()->fileVectorFilters() + QStringLiteral( ";;" ) + QObject::tr( "All files (*.*)" );
4669 }
4670 
4672 {
4673  return mDataTypes;
4674 }
4675 
4677 {
4678  mDataTypes = types;
4679 }
4680 
4682 {
4684  QVariantList types;
4685  for ( int type : mDataTypes )
4686  {
4687  types << type;
4688  }
4689  map.insert( QStringLiteral( "data_types" ), types );
4690  return map;
4691 }
4692 
4694 {
4696  mDataTypes.clear();
4697  const QVariantList values = map.value( QStringLiteral( "data_types" ) ).toList();
4698  for ( const QVariant &val : values )
4699  {
4700  mDataTypes << val.toInt();
4701  }
4702  return true;
4703 }
4704 
4705 QgsProcessingParameterVectorLayer *QgsProcessingParameterVectorLayer::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
4706 {
4707  return new QgsProcessingParameterVectorLayer( name, description, QList< int>(), definition.isEmpty() ? QVariant() : definition, isOptional );
4708 }
4709 
4711  const QString &description,
4712  const QVariant &defaultValue,
4713  bool optional )
4714  : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
4715 {
4716 
4717 }
4718 
4720 {
4721  return new QgsProcessingParameterMeshLayer( *this );
4722 }
4723 
4725 {
4726  if ( !v.isValid() )
4727  return mFlags & FlagOptional;
4728 
4729  QVariant var = v;
4730 
4731  if ( var.canConvert<QgsProperty>() )
4732  {
4733  QgsProperty p = var.value< QgsProperty >();
4735  {
4736  var = p.staticValue();
4737  }
4738  else
4739  {
4740  return true;
4741  }
4742  }
4743 
4744  if ( qobject_cast< QgsMeshLayer * >( qvariant_cast<QObject *>( var ) ) )
4745  return true;
4746 
4747  if ( var.type() != QVariant::String || var.toString().isEmpty() )
4748  return mFlags & FlagOptional;
4749 
4750  if ( !context )
4751  {
4752  // that's as far as we can get without a context
4753  return true;
4754  }
4755 
4756  // try to load as layer
4757  if ( QgsProcessingUtils::mapLayerFromString( var.toString(), *context, true, QgsProcessingUtils::LayerHint::Mesh ) )
4758  return true;
4759 
4760  return false;
4761 }
4762 
4764 {
4765  if ( !val.isValid() )
4766  return QStringLiteral( "None" );
4767 
4768  if ( val.canConvert<QgsProperty>() )
4769  return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( val.value< QgsProperty >().asExpression() );
4770 
4771  QVariantMap p;
4772  p.insert( name(), val );
4773  QgsMeshLayer *layer = QgsProcessingParameters::parameterAsMeshLayer( this, p, context );
4775  : QgsProcessingUtils::stringToPythonLiteral( val.toString() );
4776 }
4777 
4779 {
4780  return QgsProviderRegistry::instance()->fileMeshFilters() + QStringLiteral( ";;" ) + QObject::tr( "All files (*.*)" );
4781 }
4782 
4783 QgsProcessingParameterMeshLayer *QgsProcessingParameterMeshLayer::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
4784 {
4785  return new QgsProcessingParameterMeshLayer( name, description, definition.isEmpty() ? QVariant() : definition, isOptional );
4786 }
4787 
4788 QgsProcessingParameterField::QgsProcessingParameterField( const QString &name, const QString &description, const QVariant &defaultValue, const QString &parentLayerParameterName, DataType type, bool allowMultiple, bool optional, bool defaultToAllFields )
4789  : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
4790  , mParentLayerParameterName( parentLayerParameterName )
4791  , mDataType( type )
4792  , mAllowMultiple( allowMultiple )
4793  , mDefaultToAllFields( defaultToAllFields )
4794 {
4795 
4796 }
4797 
4798 
4800 {
4801  return new QgsProcessingParameterField( *this );
4802 }
4803 
4805 {
4806  if ( !input.isValid() )
4807  return mFlags & FlagOptional;
4808 
4809  if ( input.canConvert<QgsProperty>() )
4810  {
4811  return true;
4812  }
4813 
4814  if ( input.type() == QVariant::List || input.type() == QVariant::StringList )
4815  {
4816  if ( !mAllowMultiple )
4817  return false;
4818 
4819  if ( input.toList().isEmpty() && !( mFlags & FlagOptional ) )
4820  return false;
4821  }
4822  else if ( input.type() == QVariant::String )
4823  {
4824  if ( input.toString().isEmpty() )
4825  return mFlags & FlagOptional;
4826 
4827  QStringList parts = input.toString().split( ';' );
4828  if ( parts.count() > 1 && !mAllowMultiple )
4829  return false;
4830  }
4831  else
4832  {
4833  if ( input.toString().isEmpty() )
4834  return mFlags & FlagOptional;
4835  }
4836  return true;
4837 }
4838 
4840 {
4841  if ( !value.isValid() )
4842  return QStringLiteral( "None" );
4843 
4844  if ( value.canConvert<QgsProperty>() )
4845  return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
4846 
4847  if ( value.type() == QVariant::List )
4848  {
4849  QStringList parts;
4850  const auto constToList = value.toList();
4851  for ( const QVariant &val : constToList )
4852  {
4853  parts << QgsProcessingUtils::stringToPythonLiteral( val.toString() );
4854  }
4855  return parts.join( ',' ).prepend( '[' ).append( ']' );
4856  }
4857  else if ( value.type() == QVariant::StringList )
4858  {
4859  QStringList parts;
4860  const auto constToStringList = value.toStringList();
4861  for ( QString s : constToStringList )
4862  {
4864  }
4865  return parts.join( ',' ).prepend( '[' ).append( ']' );
4866  }
4867 
4868  return QgsProcessingUtils::stringToPythonLiteral( value.toString() );
4869 }
4870 
4872 {
4873  QString code = QStringLiteral( "##%1=" ).arg( mName );
4874  if ( mFlags & FlagOptional )
4875  code += QLatin1String( "optional " );
4876  code += QLatin1String( "field " );
4877 
4878  switch ( mDataType )
4879  {
4880  case Numeric:
4881  code += QLatin1String( "numeric " );
4882  break;
4883 
4884  case String:
4885  code += QLatin1String( "string " );
4886  break;
4887 
4888  case DateTime:
4889  code += QLatin1String( "datetime " );
4890  break;
4891 
4892  case Any:
4893  break;
4894  }
4895 
4896  if ( mAllowMultiple )
4897  code += QLatin1String( "multiple " );
4898 
4899  if ( mDefaultToAllFields )
4900  code += QLatin1String( "default_to_all_fields " );
4901 
4902  code += mParentLayerParameterName + ' ';
4903 
4904  code += mDefault.toString();
4905  return code.trimmed();
4906 }
4907 
4909 {
4910  switch ( outputType )
4911  {
4913  {
4914  QString code = QStringLiteral( "QgsProcessingParameterField('%1', '%2'" ).arg( name(), description() );
4915  if ( mFlags & FlagOptional )
4916  code += QLatin1String( ", optional=True" );
4917 
4918  QString dataType;
4919  switch ( mDataType )
4920  {
4921  case Any:
4922  dataType = QStringLiteral( "QgsProcessingParameterField.Any" );
4923  break;
4924 
4925  case Numeric:
4926  dataType = QStringLiteral( "QgsProcessingParameterField.Numeric" );
4927  break;
4928 
4929  case String:
4930  dataType = QStringLiteral( "QgsProcessingParameterField.String" );
4931  break;
4932 
4933  case DateTime:
4934  dataType = QStringLiteral( "QgsProcessingParameterField.DateTime" );
4935  break;
4936  }
4937  code += QStringLiteral( ", type=%1" ).arg( dataType );
4938 
4939  code += QStringLiteral( ", parentLayerParameterName='%1'" ).arg( mParentLayerParameterName );
4940  code += QStringLiteral( ", allowMultiple=%1" ).arg( mAllowMultiple ? QStringLiteral( "True" ) : QStringLiteral( "False" ) );
4942  code += QStringLiteral( ", defaultValue=%1" ).arg( valueAsPythonString( mDefault, c ) );
4943 
4944  if ( mDefaultToAllFields )
4945  code += QLatin1String( ", defaultToAllFields=True" );
4946 
4947  code += ')';
4948 
4949  return code;
4950  }
4951  }
4952  return QString();
4953 }
4954 
4956 {
4957  QStringList depends;
4958  if ( !mParentLayerParameterName.isEmpty() )
4959  depends << mParentLayerParameterName;
4960  return depends;
4961 }
4962 
4964 {
4965  return mParentLayerParameterName;
4966 }
4967 
4968 void QgsProcessingParameterField::setParentLayerParameterName( const QString &parentLayerParameterName )
4969 {
4970  mParentLayerParameterName = parentLayerParameterName;
4971 }
4972 
4974 {
4975  return mDataType;
4976 }
4977 
4979 {
4980  mDataType = dataType;
4981 }
4982 
4984 {
4985  return mAllowMultiple;
4986 }
4987 
4989 {
4990  mAllowMultiple = allowMultiple;
4991 }
4992 
4994 {
4995  return mDefaultToAllFields;
4996 }
4997 
4999 {
5000  mDefaultToAllFields = enabled;
5001 }
5002 
5004 {
5006  map.insert( QStringLiteral( "parent_layer" ), mParentLayerParameterName );
5007  map.insert( QStringLiteral( "data_type" ), mDataType );
5008  map.insert( QStringLiteral( "allow_multiple" ), mAllowMultiple );
5009  map.insert( QStringLiteral( "default_to_all_fields" ), mDefaultToAllFields );
5010  return map;
5011 }
5012 
5013 bool QgsProcessingParameterField::fromVariantMap( const QVariantMap &map )
5014 {
5016  mParentLayerParameterName = map.value( QStringLiteral( "parent_layer" ) ).toString();
5017  mDataType = static_cast< DataType >( map.value( QStringLiteral( "data_type" ) ).toInt() );
5018  mAllowMultiple = map.value( QStringLiteral( "allow_multiple" ) ).toBool();
5019  mDefaultToAllFields = map.value( QStringLiteral( "default_to_all_fields" ) ).toBool();
5020  return true;
5021 }
5022 
5023 QgsProcessingParameterField *QgsProcessingParameterField::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
5024 {
5025  QString parent;
5026  DataType type = Any;
5027  bool allowMultiple = false;
5028  bool defaultToAllFields = false;
5029  QString def = definition;
5030 
5031  if ( def.startsWith( QLatin1String( "numeric " ), Qt::CaseInsensitive ) )
5032  {
5033  type = Numeric;
5034  def = def.mid( 8 );
5035  }
5036  else if ( def.startsWith( QLatin1String( "string " ), Qt::CaseInsensitive ) )
5037  {
5038  type = String;
5039  def = def.mid( 7 );
5040  }
5041  else if ( def.startsWith( QLatin1String( "datetime " ), Qt::CaseInsensitive ) )
5042  {
5043  type = DateTime;
5044  def = def.mid( 9 );
5045  }
5046 
5047  if ( def.startsWith( QLatin1String( "multiple" ), Qt::CaseInsensitive ) )
5048  {
5049  allowMultiple = true;
5050  def = def.mid( 8 ).trimmed();
5051  }
5052 
5053  if ( def.startsWith( QLatin1String( "default_to_all_fields" ), Qt::CaseInsensitive ) )
5054  {
5055  defaultToAllFields = true;
5056  def = def.mid( 21 ).trimmed();
5057  }
5058 
5059  QRegularExpression re( QStringLiteral( "(.*?)\\s+(.*)$" ) );
5060  QRegularExpressionMatch m = re.match( def );
5061  if ( m.hasMatch() )
5062  {
5063  parent = m.captured( 1 ).trimmed();
5064  def = m.captured( 2 );
5065  }
5066  else
5067  {
5068  parent = def;
5069  def.clear();
5070  }
5071 
5072  return new QgsProcessingParameterField( name, description, def.isEmpty() ? QVariant() : def, parent, type, allowMultiple, isOptional, defaultToAllFields );
5073 }
5074 
5075 QgsProcessingParameterFeatureSource::QgsProcessingParameterFeatureSource( const QString &name, const QString &description, const QList<int> &types, const QVariant &defaultValue, bool optional )
5076  : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
5078 {
5079 
5080 }
5081 
5083 {
5084  return new QgsProcessingParameterFeatureSource( *this );
5085 }
5086 
5088 {
5089  QVariant var = input;
5090  if ( !var.isValid() )
5091  return mFlags & FlagOptional;
5092 
5093  if ( var.canConvert<QgsProcessingFeatureSourceDefinition>() )
5094  {
5095  QgsProcessingFeatureSourceDefinition fromVar = qvariant_cast<QgsProcessingFeatureSourceDefinition>( var );
5096  var = fromVar.source;
5097  }
5098  else if ( var.canConvert<QgsProcessingOutputLayerDefinition>() )
5099  {
5100  // input is a QgsProcessingOutputLayerDefinition - get extra properties from it
5101  QgsProcessingOutputLayerDefinition fromVar = qvariant_cast<QgsProcessingOutputLayerDefinition>( var );
5102  var = fromVar.sink;
5103  }
5104 
5105  if ( var.canConvert<QgsProperty>() )
5106  {
5107  QgsProperty p = var.value< QgsProperty >();
5109  {
5110  var = p.staticValue();
5111  }
5112  else
5113  {
5114  return true;
5115  }
5116  }
5117  if ( qobject_cast< QgsVectorLayer * >( qvariant_cast<QObject *>( input ) ) )
5118  {
5119  return true;
5120  }
5121 
5122  if ( var.type() != QVariant::String || var.toString().isEmpty() )
5123  return mFlags & FlagOptional;
5124 
5125  if ( !context )
5126  {
5127  // that's as far as we can get without a context
5128  return true;
5129  }
5130 
5131  // try to load as layer
5132  if ( QgsProcessingUtils::mapLayerFromString( var.toString(), *context, true, QgsProcessingUtils::LayerHint::Vector ) )
5133  return true;
5134 
5135  return false;
5136 }
5137 
5139 {
5140  if ( !value.isValid() )
5141  return QStringLiteral( "None" );
5142 
5143  if ( value.canConvert<QgsProperty>() )
5144  return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
5145 
5146  if ( value.canConvert<QgsProcessingFeatureSourceDefinition>() )
5147  {
5148  QgsProcessingFeatureSourceDefinition fromVar = qvariant_cast<QgsProcessingFeatureSourceDefinition>( value );
5149  QString geometryCheckString;
5150  switch ( fromVar.geometryCheck )
5151  {
5153  geometryCheckString = QStringLiteral( "QgsFeatureRequest.GeometryNoCheck" );
5154  break;
5155 
5157  geometryCheckString = QStringLiteral( "QgsFeatureRequest.GeometrySkipInvalid" );
5158  break;
5159 
5161  geometryCheckString = QStringLiteral( "QgsFeatureRequest.GeometryAbortOnInvalid" );
5162  break;
5163  }
5164 
5165  QStringList flags;
5166  QString flagString;
5167  if ( fromVar.flags & QgsProcessingFeatureSourceDefinition::Flag::FlagOverrideDefaultGeometryCheck )
5168  flags << QStringLiteral( "QgsProcessingFeatureSourceDefinition.FlagOverrideDefaultGeometryCheck" );
5169  if ( fromVar.flags & QgsProcessingFeatureSourceDefinition::Flag::FlagCreateIndividualOutputPerInputFeature )
5170  flags << QStringLiteral( "QgsProcessingFeatureSourceDefinition.FlagCreateIndividualOutputPerInputFeature" );
5171  if ( !flags.empty() )
5172  flagString = flags.join( QLatin1String( " | " ) );
5173 
5174  if ( fromVar.source.propertyType() == QgsProperty::StaticProperty )
5175  {
5176  QString layerString = fromVar.source.staticValue().toString();
5177  // prefer to use layer source instead of id if possible (since it's persistent)
5178  if ( QgsVectorLayer *layer = qobject_cast< QgsVectorLayer * >( QgsProcessingUtils::mapLayerFromString( layerString, context, true, QgsProcessingUtils::LayerHint::Vector ) ) )
5179  layerString = layer->source();
5180 
5181  if ( fromVar.selectedFeaturesOnly || fromVar.featureLimit != -1 || fromVar.flags )
5182  {
5183  return QStringLiteral( "QgsProcessingFeatureSourceDefinition('%1', selectedFeaturesOnly=%2, featureLimit=%3%4, geometryCheck=%5)" ).arg( layerString,
5184  fromVar.selectedFeaturesOnly ? QStringLiteral( "True" ) : QStringLiteral( "False" ),
5185  QString::number( fromVar.featureLimit ),
5186  flagString.isEmpty() ? QString() : ( QStringLiteral( ", flags=%1" ).arg( flagString ) ),
5187  geometryCheckString );
5188  }
5189  else
5190  {
5191  return QgsProcessingUtils::stringToPythonLiteral( layerString );
5192  }
5193  }
5194  else
5195  {
5196  if ( fromVar.selectedFeaturesOnly || fromVar.featureLimit != -1 || fromVar.flags )
5197  {
5198  return QStringLiteral( "QgsProcessingFeatureSourceDefinition(QgsProperty.fromExpression('%1'), selectedFeaturesOnly=%2, featureLimit=%3%4, geometryCheck=%5)" )
5199  .arg( fromVar.source.asExpression(),
5200  fromVar.selectedFeaturesOnly ? QStringLiteral( "True" ) : QStringLiteral( "False" ),
5201  QString::number( fromVar.featureLimit ),
5202  flagString.isEmpty() ? QString() : ( QStringLiteral( ", flags=%1" ).arg( flagString ) ),
5203  geometryCheckString );
5204  }
5205  else
5206  {
5207  return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( fromVar.source.asExpression() );
5208  }
5209  }
5210  }
5211  else if ( QgsVectorLayer *layer = qobject_cast< QgsVectorLayer * >( qvariant_cast<QObject *>( value ) ) )
5212  {
5213  return QgsProcessingUtils::stringToPythonLiteral( layer->source() );
5214  }
5215 
5216  QString layerString = value.toString();
5217 
5218  // prefer to use layer source if possible (since it's persistent)
5219  if ( QgsVectorLayer *layer = qobject_cast< QgsVectorLayer * >( QgsProcessingUtils::mapLayerFromString( layerString, context, true, QgsProcessingUtils::LayerHint::Vector ) ) )
5220  layerString = layer->providerType() != QLatin1String( "ogr" ) && layer->providerType() != QLatin1String( "gdal" ) && layer->providerType() != QLatin1String( "mdal" ) ? QgsProcessingUtils::encodeProviderKeyAndUri( layer->providerType(), layer->source() ) : layer->source();
5221 
5222  return QgsProcessingUtils::stringToPythonLiteral( layerString );
5223 }
5224 
5226 {
5227  QString code = QStringLiteral( "##%1=" ).arg( mName );
5228  if ( mFlags & FlagOptional )
5229  code += QLatin1String( "optional " );
5230  code += QLatin1String( "source " );
5231 
5232  for ( int type : mDataTypes )
5233  {
5234  switch ( type )
5235  {
5237  code += QLatin1String( "point " );
5238  break;
5239 
5241  code += QLatin1String( "line " );
5242  break;
5243 
5245  code += QLatin1String( "polygon " );
5246  break;
5247 
5248  }
5249  }
5250 
5251  code += mDefault.toString();
5252  return code.trimmed();
5253 }
5254 
5256 {
5257  switch ( outputType )
5258  {
5260  {
5261  QString code = QStringLiteral( "QgsProcessingParameterFeatureSource('%1', '%2'" ).arg( name(), description() );
5262  if ( mFlags & FlagOptional )
5263  code += QLatin1String( ", optional=True" );
5264 
5265  if ( !mDataTypes.empty() )
5266  {
5267  QStringList options;
5268  options.reserve( mDataTypes.size() );
5269  for ( int t : mDataTypes )
5270  options << QStringLiteral( "QgsProcessing.%1" ).arg( QgsProcessing::sourceTypeToString( static_cast< QgsProcessing::SourceType >( t ) ) );
5271  code += QStringLiteral( ", types=[%1]" ).arg( options.join( ',' ) );
5272  }
5273 
5275  code += QStringLiteral( ", defaultValue=%1)" ).arg( valueAsPythonString( mDefault, c ) );
5276  return code;
5277  }
5278  }
5279  return QString();
5280 }
5281 
5283 {
5284  return QgsProviderRegistry::instance()->fileVectorFilters() + QStringLiteral( ";;" ) + QObject::tr( "All files (*.*)" );
5285 }
5286 
5288  : mDataTypes( types )
5289 {
5290 
5291 }
5292 
5294 {
5296  QVariantList types;
5297  for ( int type : mDataTypes )
5298  {
5299  types << type;
5300  }
5301  map.insert( QStringLiteral( "data_types" ), types );
5302  return map;
5303 }
5304 
5306 {
5308  mDataTypes.clear();
5309  const QVariantList values = map.value( QStringLiteral( "data_types" ) ).toList();
5310  for ( const QVariant &val : values )
5311  {
5312  mDataTypes << val.toInt();
5313  }
5314  return true;
5315 }
5316 
5317 QgsProcessingParameterFeatureSource *QgsProcessingParameterFeatureSource::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
5318 {
5319  QList< int > types;
5320  QString def = definition;
5321  while ( true )
5322  {
5323  if ( def.startsWith( QLatin1String( "point" ), Qt::CaseInsensitive ) )
5324  {
5326  def = def.mid( 6 );
5327  continue;
5328  }
5329  else if ( def.startsWith( QLatin1String( "line" ), Qt::CaseInsensitive ) )
5330  {
5332  def = def.mid( 5 );
5333  continue;
5334  }
5335  else if ( def.startsWith( QLatin1String( "polygon" ), Qt::CaseInsensitive ) )
5336  {
5338  def = def.mid( 8 );
5339  continue;
5340  }
5341  break;
5342  }
5343 
5344  return new QgsProcessingParameterFeatureSource( name, description, types, def, isOptional );
5345 }
5346 
5347 QgsProcessingParameterFeatureSink::QgsProcessingParameterFeatureSink( const QString &name, const QString &description, QgsProcessing::SourceType type, const QVariant &defaultValue, bool optional, bool createByDefault, bool supportsAppend )
5348  : QgsProcessingDestinationParameter( name, description, defaultValue, optional, createByDefault )
5349  , mDataType( type )
5350  , mSupportsAppend( supportsAppend )
5351 {
5352 }
5353 
5355 {
5356  return new QgsProcessingParameterFeatureSink( *this );
5357 }
5358 
5360 {
5361  QVariant var = input;
5362  if ( !var.isValid() )
5363  return mFlags & FlagOptional;
5364 
5365  if ( var.canConvert<QgsProcessingOutputLayerDefinition>() )
5366  {
5367  QgsProcessingOutputLayerDefinition fromVar = qvariant_cast<QgsProcessingOutputLayerDefinition>( var );
5368  var = fromVar.sink;
5369  }
5370 
5371  if ( var.canConvert<QgsProperty>() )
5372  {
5373  QgsProperty p = var.value< QgsProperty >();
5375  {
5376  var = p.staticValue();
5377  }
5378  else
5379  {
5380  return true;
5381  }
5382  }
5383 
5384  if ( var.type() != QVariant::String )
5385  return false;
5386 
5387  if ( var.toString().isEmpty() )
5388  return mFlags & FlagOptional;
5389 
5390  return true;
5391 }
5392 
5394 {
5395  if ( !value.isValid() )
5396  return QStringLiteral( "None" );
5397 
5398  if ( value.canConvert<QgsProperty>() )
5399  return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
5400 
5401  if ( value.canConvert<QgsProcessingOutputLayerDefinition>() )
5402  {
5403  QgsProcessingOutputLayerDefinition fromVar = qvariant_cast<QgsProcessingOutputLayerDefinition>( value );
5404  if ( fromVar.sink.propertyType() == QgsProperty::StaticProperty )
5405  {
5406  return QgsProcessingUtils::stringToPythonLiteral( fromVar.sink.staticValue().toString() );
5407  }
5408  else
5409  {
5410  return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( fromVar.sink.asExpression() );
5411  }
5412  }
5413 
5414  return QgsProcessingUtils::stringToPythonLiteral( value.toString() );
5415 }
5416 
5418 {
5419  QString code = QStringLiteral( "##%1=" ).arg( mName );
5420  if ( mFlags & FlagOptional )
5421  code += QLatin1String( "optional " );
5422  code += QLatin1String( "sink " );
5423 
5424  switch ( mDataType )
5425  {
5427  code += QLatin1String( "point " );
5428  break;
5429 
5431  code += QLatin1String( "line " );
5432  break;
5433 
5435  code += QLatin1String( "polygon " );
5436  break;
5437 
5439  code += QLatin1String( "table " );
5440  break;
5441 
5442  default:
5443  break;
5444  }
5445 
5446  code += mDefault.toString();
5447  return code.trimmed();
5448 }
5449 
5451 {
5452  return new QgsProcessingOutputVectorLayer( name(), description(), mDataType );
5453 }
5454 
5456 {
5457  if ( auto *lOriginalProvider = originalProvider() )
5458  {
5459  return lOriginalProvider->defaultVectorFileExtension( hasGeometry() );
5460  }
5461  else if ( QgsProcessingProvider *p = provider() )
5462  {
5463  return p->defaultVectorFileExtension( hasGeometry() );
5464  }
5465  else
5466  {
5467  if ( hasGeometry() )
5468  {
5470  }
5471  else
5472  {
5473  return QStringLiteral( "dbf" );
5474  }
5475  }
5476 }
5477 
5479 {
5480  switch ( outputType )
5481  {
5483  {
5484  QString code = QStringLiteral( "QgsProcessingParameterFeatureSink('%1', '%2'" ).arg( name(), description() );
5485  if ( mFlags & FlagOptional )
5486  code += QLatin1String( ", optional=True" );
5487 
5488  code += QStringLiteral( ", type=QgsProcessing.%1" ).arg( QgsProcessing::sourceTypeToString( mDataType ) );
5489 
5490  code += QStringLiteral( ", createByDefault=%1" ).arg( createByDefault() ? QStringLiteral( "True" ) : QStringLiteral( "False" ) );
5491  if ( mSupportsAppend )
5492  code += QLatin1String( ", supportsAppend=True" );
5493 
5495  code += QStringLiteral( ", defaultValue=%1)" ).arg( valueAsPythonString( mDefault, c ) );
5496  return code;
5497  }
5498  }
5499  return QString();
5500 }
5501 
5503 {
5504  const QStringList exts = supportedOutputVectorLayerExtensions();
5505  QStringList filters;
5506  for ( const QString &ext : exts )
5507  {
5508  filters << QObject::tr( &