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