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