QGIS API Documentation 3.37.0-Master (fdefdf9c27f)
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() == QMetaType::type( "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() == QMetaType::type( "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() == QMetaType::type( "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() == QMetaType::type( "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() == QMetaType::type( "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() == QMetaType::type( "QgsProperty" ) )
273 resultList << val.value< QgsProperty >().valueAsInt( context.expressionContext(), definition->defaultValue().toInt() );
274 else if ( val.type() == QVariant::List )
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().type() == QVariant::List )
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() == QMetaType::type( "QgsProperty" ) )
326 val = val.value< QgsProperty >().value( context.expressionContext(), definition->defaultValue() );
327
328 QDateTime d = val.toDateTime();
329 if ( !d.isValid() && val.type() == QVariant::String )
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.type() == QVariant::String )
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() == QMetaType::type( "QgsProperty" ) )
363 val = val.value< QgsProperty >().value( context.expressionContext(), definition->defaultValue() );
364
365 QDate d = val.toDate();
366 if ( !d.isValid() && val.type() == QVariant::String )
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.type() == QVariant::String )
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() == QMetaType::type( "QgsProperty" ) )
400 val = val.value< QgsProperty >().value( context.expressionContext(), definition->defaultValue() );
401
402 QTime d;
403
404 if ( val.type() == QVariant::DateTime )
405 d = val.toDateTime().time();
406 else
407 d = val.toTime();
408
409 if ( !d.isValid() && val.type() == QVariant::String )
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.type() == QVariant::String )
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() == QMetaType::type( "QgsProperty" ) )
466 resultList << val.value< QgsProperty >().valueAsString( context.expressionContext(), definition->defaultValue().toString() );
467 else if ( val.type() == QVariant::List )
468 {
469 const auto constToList = val.toList();
470 for ( const QVariant &var : constToList )
471 resultList << var;
472 }
473 else if ( val.type() == QVariant::String )
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().type() == QVariant::List )
490 {
491 const auto constToList = definition->defaultValue().toList();
492 for ( const QVariant &var : constToList )
493 resultList << var;
494 }
495 else if ( definition->defaultValue().type() == QVariant::String )
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.type() == QVariant::List )
561 {
562 const auto constToList = var.toList();
563 for ( const QVariant &listVar : constToList )
564 {
565 processVariant( listVar );
566 }
567 }
568 else if ( var.type() == QVariant::StringList )
569 {
570 const auto constToStringList = var.toStringList();
571 for ( const QString &s : constToStringList )
572 {
573 processVariant( s );
574 }
575 }
576 else if ( var.userType() == QMetaType::type( "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() == QMetaType::type( "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() == QMetaType::type( "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() == QMetaType::type( "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() == QMetaType::type( "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() == QMetaType::type( "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() == QMetaType::type( "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() == QMetaType::type( "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() == QMetaType::type( "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() == QMetaType::type( "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() == QMetaType::type( "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() == QMetaType::type( "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
941{
942 QVariant val = value;
943
944 QgsProject *destinationProject = nullptr;
945 QString destName;
946 if ( val.userType() == QMetaType::type( "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() == QMetaType::type( "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 context.addLayerToLoadOnCompletion( dest, QgsProcessingContext::LayerDetails( destName, destinationProject, outputName, layerTypeHint ) );
996 }
997
998 return dest;
999}
1000
1001QString QgsProcessingParameters::parameterAsFileOutput( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context )
1002{
1003 QVariant val;
1004 if ( definition )
1005 {
1006 val = parameters.value( definition->name() );
1007 }
1008 return parameterAsFileOutput( definition, val, context );
1009}
1010
1012{
1013 QVariant val = value;
1014
1015 if ( val.userType() == QMetaType::type( "QgsProcessingOutputLayerDefinition" ) )
1016 {
1017 // input is a QgsProcessingOutputLayerDefinition - get extra properties from it
1018 const QgsProcessingOutputLayerDefinition fromVar = qvariant_cast<QgsProcessingOutputLayerDefinition>( val );
1019 val = fromVar.sink;
1020 }
1021
1022 QString dest;
1023 if ( definition && val.userType() == QMetaType::type( "QgsProperty" ) )
1024 {
1025 dest = val.value< QgsProperty >().valueAsString( context.expressionContext(), definition->defaultValue().toString() );
1026 }
1027 else if ( definition && ( !val.isValid() || val.toString().isEmpty() ) )
1028 {
1029 // fall back to default
1030 dest = definition->defaultValue().toString();
1031 }
1032 else
1033 {
1034 dest = val.toString();
1035 }
1036 if ( dest == QgsProcessing::TEMPORARY_OUTPUT )
1037 {
1038 if ( const QgsProcessingDestinationParameter *destParam = dynamic_cast< const QgsProcessingDestinationParameter * >( definition ) )
1039 dest = destParam->generateTemporaryDestination( &context );
1040 }
1041 return dest;
1042}
1043
1045{
1046 return qobject_cast< QgsVectorLayer *>( parameterAsLayer( definition, parameters, context, QgsProcessingUtils::LayerHint::Vector ) );
1047}
1048
1050{
1051 return qobject_cast< QgsVectorLayer *>( parameterAsLayer( definition, value, context, QgsProcessingUtils::LayerHint::Vector ) );
1052}
1053
1055{
1056 if ( !definition )
1058
1059 return parameterAsCrs( definition, parameters.value( definition->name() ), context );
1060}
1061
1063{
1064 if ( !definition )
1066
1067 return QgsProcessingUtils::variantToCrs( value, context, definition->defaultValue() );
1068}
1069
1072{
1073 if ( !definition )
1074 return QgsRectangle();
1075
1076 return parameterAsExtent( definition, parameters.value( definition->name() ), context, crs );
1077}
1078
1080{
1081 if ( !definition )
1082 return QgsRectangle();
1083
1084 QVariant val = value;
1085
1086 if ( val.userType() == QMetaType::type( "QgsRectangle" ) )
1087 {
1088 return val.value<QgsRectangle>();
1089 }
1090 if ( val.userType() == QMetaType::type( "QgsGeometry" ) )
1091 {
1092 const QgsGeometry geom = val.value<QgsGeometry>();
1093 if ( !geom.isNull() )
1094 return geom.boundingBox();
1095 }
1096 if ( val.userType() == QMetaType::type( "QgsReferencedRectangle" ) )
1097 {
1098 const QgsReferencedRectangle rr = val.value<QgsReferencedRectangle>();
1099 if ( crs.isValid() && rr.crs().isValid() && crs != rr.crs() )
1100 {
1101 QgsCoordinateTransform ct( rr.crs(), crs, context.project() );
1103 try
1104 {
1105 return ct.transformBoundingBox( rr );
1106 }
1107 catch ( QgsCsException & )
1108 {
1109 QgsMessageLog::logMessage( QObject::tr( "Error transforming extent geometry" ) );
1110 }
1111 }
1112 return rr;
1113 }
1114
1115 if ( val.userType() == QMetaType::type( "QgsProcessingFeatureSourceDefinition" ) )
1116 {
1117 // input is a QgsProcessingFeatureSourceDefinition - get extra properties from it
1118 const QgsProcessingFeatureSourceDefinition fromVar = qvariant_cast<QgsProcessingFeatureSourceDefinition>( val );
1119 val = fromVar.source;
1120 }
1121 else if ( val.userType() == QMetaType::type( "QgsProcessingOutputLayerDefinition" ) )
1122 {
1123 // input is a QgsProcessingOutputLayerDefinition - get extra properties from it
1124 const QgsProcessingOutputLayerDefinition fromVar = qvariant_cast<QgsProcessingOutputLayerDefinition>( val );
1125 val = fromVar.sink;
1126 }
1127
1128 if ( val.userType() == QMetaType::type( "QgsProperty" ) && val.value< QgsProperty >().propertyType() == Qgis::PropertyType::Static )
1129 {
1130 val = val.value< QgsProperty >().staticValue();
1131 }
1132
1133 // maybe parameter is a direct layer value?
1134 QgsMapLayer *layer = qobject_cast< QgsMapLayer * >( qvariant_cast<QObject *>( val ) );
1135
1136 QString rectText;
1137 if ( val.userType() == QMetaType::type( "QgsProperty" ) )
1138 rectText = val.value< QgsProperty >().valueAsString( context.expressionContext(), definition->defaultValue().toString() );
1139 else
1140 rectText = val.toString();
1141
1142 if ( rectText.isEmpty() && !layer )
1143 return QgsRectangle();
1144
1145 const thread_local QRegularExpression rx( QStringLiteral( "^(.*?)\\s*,\\s*(.*?),\\s*(.*?),\\s*(.*?)\\s*(?:\\[(.*)\\])?\\s*$" ) );
1146 const QRegularExpressionMatch match = rx.match( rectText );
1147 if ( match.hasMatch() )
1148 {
1149 bool xMinOk = false;
1150 const double xMin = match.captured( 1 ).toDouble( &xMinOk );
1151 bool xMaxOk = false;
1152 const double xMax = match.captured( 2 ).toDouble( &xMaxOk );
1153 bool yMinOk = false;
1154 const double yMin = match.captured( 3 ).toDouble( &yMinOk );
1155 bool yMaxOk = false;
1156 const double yMax = match.captured( 4 ).toDouble( &yMaxOk );
1157 if ( xMinOk && xMaxOk && yMinOk && yMaxOk )
1158 {
1159 const QgsRectangle rect( xMin, yMin, xMax, yMax );
1160 const QgsCoordinateReferenceSystem rectCrs( match.captured( 5 ) );
1161 if ( crs.isValid() && rectCrs.isValid() && crs != rectCrs )
1162 {
1163 QgsCoordinateTransform ct( rectCrs, crs, context.project() );
1165 try
1166 {
1167 return ct.transformBoundingBox( rect );
1168 }
1169 catch ( QgsCsException & )
1170 {
1171 QgsMessageLog::logMessage( QObject::tr( "Error transforming extent geometry" ) );
1172 }
1173 }
1174 return rect;
1175 }
1176 }
1177
1178 // try as layer extent
1179 if ( !layer )
1180 layer = QgsProcessingUtils::mapLayerFromString( rectText, context );
1181
1182 if ( layer )
1183 {
1184 const QgsRectangle rect = layer->extent();
1185 if ( crs.isValid() && layer->crs().isValid() && crs != layer->crs() )
1186 {
1187 QgsCoordinateTransform ct( layer->crs(), crs, context.project() );
1189 try
1190 {
1191 return ct.transformBoundingBox( rect );
1192 }
1193 catch ( QgsCsException & )
1194 {
1195 QgsMessageLog::logMessage( QObject::tr( "Error transforming extent geometry" ) );
1196 }
1197 }
1198 return rect;
1199 }
1200 return QgsRectangle();
1201}
1202
1204{
1205 if ( !definition )
1206 return QgsGeometry();
1207
1208 QVariant val = parameters.value( definition->name() );
1209
1210 if ( val.userType() == QMetaType::type( "QgsReferencedRectangle" ) )
1211 {
1212 const QgsReferencedRectangle rr = val.value<QgsReferencedRectangle>();
1214 if ( crs.isValid() && rr.crs().isValid() && crs != rr.crs() )
1215 {
1216 g = g.densifyByCount( 20 );
1217 const QgsCoordinateTransform ct( rr.crs(), crs, context.project() );
1218 try
1219 {
1220 g.transform( ct );
1221 }
1222 catch ( QgsCsException & )
1223 {
1224 QgsMessageLog::logMessage( QObject::tr( "Error transforming extent geometry" ) );
1225 }
1226 return g;
1227 }
1228 }
1229
1230 if ( val.userType() == QMetaType::type( "QgsProcessingFeatureSourceDefinition" ) )
1231 {
1232 // input is a QgsProcessingFeatureSourceDefinition - get extra properties from it
1233 const QgsProcessingFeatureSourceDefinition fromVar = qvariant_cast<QgsProcessingFeatureSourceDefinition>( val );
1234 val = fromVar.source;
1235 }
1236 else if ( val.userType() == QMetaType::type( "QgsProcessingOutputLayerDefinition" ) )
1237 {
1238 // input is a QgsProcessingOutputLayerDefinition - get extra properties from it
1239 const QgsProcessingOutputLayerDefinition fromVar = qvariant_cast<QgsProcessingOutputLayerDefinition>( val );
1240 val = fromVar.sink;
1241 }
1242
1243 if ( val.userType() == QMetaType::type( "QgsProperty" ) && val.value< QgsProperty >().propertyType() == Qgis::PropertyType::Static )
1244 {
1245 val = val.value< QgsProperty >().staticValue();
1246 }
1247
1248 QString rectText;
1249 if ( val.userType() == QMetaType::type( "QgsProperty" ) )
1250 rectText = val.value< QgsProperty >().valueAsString( context.expressionContext(), definition->defaultValue().toString() );
1251 else
1252 rectText = val.toString();
1253
1254 if ( !rectText.isEmpty() )
1255 {
1256 const thread_local QRegularExpression rx( QStringLiteral( "^(.*?)\\s*,\\s*(.*?),\\s*(.*?),\\s*(.*?)\\s*(?:\\[(.*)\\])?\\s*$" ) );
1257 const QRegularExpressionMatch match = rx.match( rectText );
1258 if ( match.hasMatch() )
1259 {
1260 bool xMinOk = false;
1261 const double xMin = match.captured( 1 ).toDouble( &xMinOk );
1262 bool xMaxOk = false;
1263 const double xMax = match.captured( 2 ).toDouble( &xMaxOk );
1264 bool yMinOk = false;
1265 const double yMin = match.captured( 3 ).toDouble( &yMinOk );
1266 bool yMaxOk = false;
1267 const double yMax = match.captured( 4 ).toDouble( &yMaxOk );
1268 if ( xMinOk && xMaxOk && yMinOk && yMaxOk )
1269 {
1270 const QgsRectangle rect( xMin, yMin, xMax, yMax );
1271 const QgsCoordinateReferenceSystem rectCrs( match.captured( 5 ) );
1273 if ( crs.isValid() && rectCrs.isValid() && crs != rectCrs )
1274 {
1275 g = g.densifyByCount( 20 );
1276 const QgsCoordinateTransform ct( rectCrs, crs, context.project() );
1277 try
1278 {
1279 g.transform( ct );
1280 }
1281 catch ( QgsCsException & )
1282 {
1283 QgsMessageLog::logMessage( QObject::tr( "Error transforming extent geometry" ) );
1284 }
1285 return g;
1286 }
1287 }
1288 }
1289 }
1290
1291 // try as layer extent
1292
1293 // maybe parameter is a direct layer value?
1294 QgsMapLayer *layer = qobject_cast< QgsMapLayer * >( qvariant_cast<QObject *>( val ) );
1295 if ( !layer )
1296 layer = QgsProcessingUtils::mapLayerFromString( rectText, context );
1297
1298 if ( layer )
1299 {
1300 const QgsRectangle rect = layer->extent();
1302 if ( crs.isValid() && layer->crs().isValid() && crs != layer->crs() )
1303 {
1304 g = g.densifyByCount( 20 );
1305 const QgsCoordinateTransform ct( layer->crs(), crs, context.project() );
1306 try
1307 {
1308 g.transform( ct );
1309 }
1310 catch ( QgsCsException & )
1311 {
1312 QgsMessageLog::logMessage( QObject::tr( "Error transforming extent geometry" ) );
1313 }
1314 }
1315 return g;
1316 }
1317
1318 return QgsGeometry::fromRect( parameterAsExtent( definition, parameters, context, crs ) );
1319}
1320
1322{
1323 const QVariant val = parameters.value( definition->name() );
1324 return parameterAsExtentCrs( definition, val, context );
1325}
1326
1328{
1329 QVariant val = value;
1330 if ( val.userType() == QMetaType::type( "QgsReferencedRectangle" ) )
1331 {
1332 const QgsReferencedRectangle rr = val.value<QgsReferencedRectangle>();
1333 if ( rr.crs().isValid() )
1334 {
1335 return rr.crs();
1336 }
1337 }
1338
1339 if ( val.userType() == QMetaType::type( "QgsProcessingFeatureSourceDefinition" ) )
1340 {
1341 // input is a QgsProcessingFeatureSourceDefinition - get extra properties from it
1342 const QgsProcessingFeatureSourceDefinition fromVar = qvariant_cast<QgsProcessingFeatureSourceDefinition>( val );
1343 val = fromVar.source;
1344 }
1345 else if ( val.userType() == QMetaType::type( "QgsProcessingOutputLayerDefinition" ) )
1346 {
1347 // input is a QgsProcessingOutputLayerDefinition - get extra properties from it
1348 const QgsProcessingOutputLayerDefinition fromVar = qvariant_cast<QgsProcessingOutputLayerDefinition>( val );
1349 val = fromVar.sink;
1350 }
1351
1352 if ( val.userType() == QMetaType::type( "QgsProperty" ) && val.value< QgsProperty >().propertyType() == Qgis::PropertyType::Static )
1353 {
1354 val = val.value< QgsProperty >().staticValue();
1355 }
1356
1357 QString valueAsString;
1358 if ( val.userType() == QMetaType::type( "QgsProperty" ) )
1359 valueAsString = val.value< QgsProperty >().valueAsString( context.expressionContext(), definition->defaultValue().toString() );
1360 else
1361 valueAsString = val.toString();
1362
1363 const thread_local QRegularExpression rx( QStringLiteral( "^(.*?)\\s*,\\s*(.*?),\\s*(.*?),\\s*(.*?)\\s*(?:\\[(.*)\\])?\\s*$" ) );
1364
1365 const QRegularExpressionMatch match = rx.match( valueAsString );
1366 if ( match.hasMatch() )
1367 {
1368 const QgsCoordinateReferenceSystem crs( match.captured( 5 ) );
1369 if ( crs.isValid() )
1370 return crs;
1371 }
1372
1373 if ( val.userType() == QMetaType::type( "QgsProcessingFeatureSourceDefinition" ) )
1374 {
1375 // input is a QgsProcessingFeatureSourceDefinition - get extra properties from it
1376 const QgsProcessingFeatureSourceDefinition fromVar = qvariant_cast<QgsProcessingFeatureSourceDefinition>( val );
1377 val = fromVar.source;
1378 }
1379 else if ( val.userType() == QMetaType::type( "QgsProcessingOutputLayerDefinition" ) )
1380 {
1381 // input is a QgsProcessingOutputLayerDefinition - get extra properties from it
1382 const QgsProcessingOutputLayerDefinition fromVar = qvariant_cast<QgsProcessingOutputLayerDefinition>( val );
1383 val = fromVar.sink;
1384 }
1385
1386 if ( val.userType() == QMetaType::type( "QgsProperty" ) && val.value< QgsProperty >().propertyType() == Qgis::PropertyType::Static )
1387 {
1388 val = val.value< QgsProperty >().staticValue();
1389 }
1390
1391 // try as layer crs
1392 if ( QgsMapLayer *layer = qobject_cast< QgsMapLayer * >( qvariant_cast<QObject *>( val ) ) )
1393 return layer->crs();
1394 else if ( QgsMapLayer *layer = QgsProcessingUtils::mapLayerFromString( valueAsString, context ) )
1395 return layer->crs();
1396
1397 if ( auto *lProject = context.project() )
1398 return lProject->crs();
1399 else
1401}
1402
1404{
1405 if ( !definition )
1406 return QgsPointXY();
1407
1408 return parameterAsPoint( definition, parameters.value( definition->name() ), context, crs );
1409}
1410
1412{
1413 if ( !definition )
1414 return QgsPointXY();
1415
1416 const QVariant val = value;
1417 if ( val.userType() == QMetaType::type( "QgsPointXY" ) )
1418 {
1419 return val.value<QgsPointXY>();
1420 }
1421 if ( val.userType() == QMetaType::type( "QgsGeometry" ) )
1422 {
1423 const QgsGeometry geom = val.value<QgsGeometry>();
1424 if ( !geom.isNull() )
1425 return geom.centroid().asPoint();
1426 }
1427 if ( val.userType() == QMetaType::type( "QgsReferencedPointXY" ) )
1428 {
1429 const QgsReferencedPointXY rp = val.value<QgsReferencedPointXY>();
1430 if ( crs.isValid() && rp.crs().isValid() && crs != rp.crs() )
1431 {
1432 const QgsCoordinateTransform ct( rp.crs(), crs, context.project() );
1433 try
1434 {
1435 return ct.transform( rp );
1436 }
1437 catch ( QgsCsException & )
1438 {
1439 QgsMessageLog::logMessage( QObject::tr( "Error transforming point geometry" ) );
1440 }
1441 }
1442 return rp;
1443 }
1444
1445 QString pointText = parameterAsString( definition, value, context );
1446 if ( pointText.isEmpty() )
1447 pointText = definition->defaultValue().toString();
1448
1449 if ( pointText.isEmpty() )
1450 return QgsPointXY();
1451
1452 const thread_local QRegularExpression rx( QStringLiteral( "^\\s*\\(?\\s*(.*?)\\s*,\\s*(.*?)\\s*(?:\\[(.*)\\])?\\s*\\)?\\s*$" ) );
1453
1454 const QString valueAsString = parameterAsString( definition, value, context );
1455 const QRegularExpressionMatch match = rx.match( valueAsString );
1456 if ( match.hasMatch() )
1457 {
1458 bool xOk = false;
1459 const double x = match.captured( 1 ).toDouble( &xOk );
1460 bool yOk = false;
1461 const double y = match.captured( 2 ).toDouble( &yOk );
1462
1463 if ( xOk && yOk )
1464 {
1465 const QgsPointXY pt( x, y );
1466
1467 const QgsCoordinateReferenceSystem pointCrs( match.captured( 3 ) );
1468 if ( crs.isValid() && pointCrs.isValid() && crs != pointCrs )
1469 {
1470 const QgsCoordinateTransform ct( pointCrs, crs, context.project() );
1471 try
1472 {
1473 return ct.transform( pt );
1474 }
1475 catch ( QgsCsException & )
1476 {
1477 QgsMessageLog::logMessage( QObject::tr( "Error transforming point geometry" ) );
1478 }
1479 }
1480 return pt;
1481 }
1482 }
1483
1484 return QgsPointXY();
1485}
1486
1488{
1489 const QVariant val = parameters.value( definition->name() );
1490 return parameterAsPointCrs( definition, val, context );
1491}
1492
1494{
1495 if ( value.userType() == QMetaType::type( "QgsReferencedPointXY" ) )
1496 {
1497 const QgsReferencedPointXY rr = value.value<QgsReferencedPointXY>();
1498 if ( rr.crs().isValid() )
1499 {
1500 return rr.crs();
1501 }
1502 }
1503
1504 const thread_local QRegularExpression rx( QStringLiteral( "^\\s*\\(?\\s*(.*?)\\s*,\\s*(.*?)\\s*(?:\\[(.*)\\])?\\s*\\)?\\s*$" ) );
1505
1506 const QString valueAsString = parameterAsString( definition, value, context );
1507 const QRegularExpressionMatch match = rx.match( valueAsString );
1508 if ( match.hasMatch() )
1509 {
1510 const QgsCoordinateReferenceSystem crs( match.captured( 3 ) );
1511 if ( crs.isValid() )
1512 return crs;
1513 }
1514
1515 if ( auto *lProject = context.project() )
1516 return lProject->crs();
1517 else
1519}
1520
1522{
1523 if ( !definition )
1524 return QgsGeometry();
1525
1526 return parameterAsGeometry( definition, parameters.value( definition->name() ), context, crs );
1527}
1528
1530{
1531 if ( !definition )
1532 return QgsGeometry();
1533
1534 const QVariant val = value;
1535 if ( val.userType() == QMetaType::type( "QgsGeometry" ) )
1536 {
1537 return val.value<QgsGeometry>();
1538 }
1539
1540 if ( val.userType() == QMetaType::type( "QgsPointXY" ) )
1541 {
1542 return QgsGeometry::fromPointXY( val.value<QgsPointXY>() );
1543 }
1544
1545 if ( val.userType() == QMetaType::type( "QgsRectangle" ) )
1546 {
1547 return QgsGeometry::fromRect( val.value<QgsRectangle>() );
1548 }
1549
1550 if ( val.userType() == QMetaType::type( "QgsReferencedPointXY" ) )
1551 {
1552 const QgsReferencedPointXY rp = val.value<QgsReferencedPointXY>();
1553 if ( crs.isValid() && rp.crs().isValid() && crs != rp.crs() )
1554 {
1555 const QgsCoordinateTransform ct( rp.crs(), crs, context.project() );
1556 try
1557 {
1558 return QgsGeometry::fromPointXY( ct.transform( rp ) );
1559 }
1560 catch ( QgsCsException & )
1561 {
1562 QgsMessageLog::logMessage( QObject::tr( "Error transforming point geometry" ) );
1563 }
1564 }
1565 return QgsGeometry::fromPointXY( rp );
1566 }
1567
1568 if ( val.userType() == QMetaType::type( "QgsReferencedRectangle" ) )
1569 {
1570 const QgsReferencedRectangle rr = val.value<QgsReferencedRectangle>();
1572 if ( crs.isValid() && rr.crs().isValid() && crs != rr.crs() )
1573 {
1574 g = g.densifyByCount( 20 );
1575 const QgsCoordinateTransform ct( rr.crs(), crs, context.project() );
1576 try
1577 {
1578 g.transform( ct );
1579 }
1580 catch ( QgsCsException & )
1581 {
1582 QgsMessageLog::logMessage( QObject::tr( "Error transforming rectangle geometry" ) );
1583 }
1584 }
1585 return g;
1586 }
1587
1588 if ( val.userType() == QMetaType::type( "QgsReferencedGeometry" ) )
1589 {
1591 if ( crs.isValid() && rg.crs().isValid() && crs != rg.crs() )
1592 {
1593 const QgsCoordinateTransform ct( rg.crs(), crs, context.project() );
1594 try
1595 {
1596 rg.transform( ct );
1597 }
1598 catch ( QgsCsException & )
1599 {
1600 QgsMessageLog::logMessage( QObject::tr( "Error transforming geometry" ) );
1601 }
1602 }
1603 return rg;
1604 }
1605
1606 QString valueAsString = parameterAsString( definition, value, context );
1607 if ( valueAsString.isEmpty() )
1608 valueAsString = definition->defaultValue().toString();
1609
1610 if ( valueAsString.isEmpty() )
1611 return QgsGeometry();
1612
1613 const thread_local QRegularExpression rx( QStringLiteral( "^\\s*(?:CRS=(.*);)?(.*?)$" ) );
1614
1615 const QRegularExpressionMatch match = rx.match( valueAsString );
1616 if ( match.hasMatch() )
1617 {
1618 QgsGeometry g = QgsGeometry::fromWkt( match.captured( 2 ) );
1619 if ( !g.isNull() )
1620 {
1621 const QgsCoordinateReferenceSystem geomCrs( match.captured( 1 ) );
1622 if ( crs.isValid() && geomCrs.isValid() && crs != geomCrs )
1623 {
1624 const QgsCoordinateTransform ct( geomCrs, crs, context.project() );
1625 try
1626 {
1627 g.transform( ct );
1628 }
1629 catch ( QgsCsException & )
1630 {
1631 QgsMessageLog::logMessage( QObject::tr( "Error transforming geometry" ) );
1632 }
1633 }
1634 return g;
1635 }
1636 }
1637
1638 return QgsGeometry();
1639}
1640
1642{
1643 const QVariant val = parameters.value( definition->name() );
1644 return parameterAsGeometryCrs( definition, val, context );
1645}
1646
1648{
1649 if ( value.userType() == QMetaType::type( "QgsReferencedGeometry" ) )
1650 {
1651 const QgsReferencedGeometry rg = value.value<QgsReferencedGeometry>();
1652 if ( rg.crs().isValid() )
1653 {
1654 return rg.crs();
1655 }
1656 }
1657
1658 if ( value.userType() == QMetaType::type( "QgsReferencedPointXY" ) )
1659 {
1660 const QgsReferencedPointXY rp = value.value<QgsReferencedPointXY>();
1661 if ( rp.crs().isValid() )
1662 {
1663 return rp.crs();
1664 }
1665 }
1666
1667 if ( value.userType() == QMetaType::type( "QgsReferencedRectangle" ) )
1668 {
1669 const QgsReferencedRectangle rr = value.value<QgsReferencedRectangle>();
1670 if ( rr.crs().isValid() )
1671 {
1672 return rr.crs();
1673 }
1674 }
1675
1676 // Match against EWKT
1677 const QRegularExpression rx( QStringLiteral( "^\\s*(?:CRS=(.*);)?(.*?)$" ) );
1678
1679 const QString valueAsString = parameterAsString( definition, value, context );
1680 const QRegularExpressionMatch match = rx.match( valueAsString );
1681 if ( match.hasMatch() )
1682 {
1683 const QgsCoordinateReferenceSystem crs( match.captured( 1 ) );
1684 if ( crs.isValid() )
1685 return crs;
1686 }
1687
1688 if ( auto *lProject = context.project() )
1689 return lProject->crs();
1690 else
1692}
1693
1694QString QgsProcessingParameters::parameterAsFile( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context )
1695{
1696 if ( !definition )
1697 return QString();
1698
1699 QString fileText = parameterAsString( definition, parameters, context );
1700 if ( fileText.isEmpty() )
1701 fileText = definition->defaultValue().toString();
1702 return fileText;
1703}
1704
1706{
1707 if ( !definition )
1708 return QString();
1709
1710 QString fileText = parameterAsString( definition, value, context );
1711 if ( fileText.isEmpty() )
1712 fileText = definition->defaultValue().toString();
1713 return fileText;
1714}
1715
1716QVariantList QgsProcessingParameters::parameterAsMatrix( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context )
1717{
1718 if ( !definition )
1719 return QVariantList();
1720
1721 return parameterAsMatrix( definition, parameters.value( definition->name() ), context );
1722}
1723
1724QVariantList QgsProcessingParameters::parameterAsMatrix( const QgsProcessingParameterDefinition *definition, const QVariant &value, QgsProcessingContext &context )
1725{
1726 if ( !definition )
1727 return QVariantList();
1728
1729 QString resultString;
1730 const QVariant val = value;
1731 if ( val.userType() == QMetaType::type( "QgsProperty" ) )
1732 resultString = val.value< QgsProperty >().valueAsString( context.expressionContext(), definition->defaultValue().toString() );
1733 else if ( val.type() == QVariant::List )
1734 return val.toList();
1735 else
1736 resultString = val.toString();
1737
1738 if ( resultString.isEmpty() )
1739 {
1740 // check default
1741 if ( definition->defaultValue().type() == QVariant::List )
1742 return definition->defaultValue().toList();
1743 else
1744 resultString = definition->defaultValue().toString();
1745 }
1746
1747 QVariantList result;
1748 const auto constSplit = resultString.split( ',' );
1749 bool ok;
1750 double number;
1751 for ( const QString &s : constSplit )
1752 {
1753 number = s.toDouble( &ok );
1754 result << ( ok ? QVariant( number ) : s );
1755 }
1756
1757 return result;
1758}
1759
1760QList<QgsMapLayer *> QgsProcessingParameters::parameterAsLayerList( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessing::LayerOptionsFlags flags )
1761{
1762 if ( !definition )
1763 return QList<QgsMapLayer *>();
1764
1765 return parameterAsLayerList( definition, parameters.value( definition->name() ), context, flags );
1766}
1767
1769{
1770 if ( !definition )
1771 return QList<QgsMapLayer *>();
1772
1773 const QVariant val = value;
1774 if ( QgsMapLayer *layer = qobject_cast< QgsMapLayer * >( qvariant_cast<QObject *>( val ) ) )
1775 {
1776 return QList<QgsMapLayer *>() << layer;
1777 }
1778
1779 QList<QgsMapLayer *> layers;
1780
1781 std::function< void( const QVariant &var ) > processVariant;
1782 processVariant = [ &layers, &context, &definition, flags, &processVariant]( const QVariant & var )
1783 {
1784 if ( var.type() == QVariant::List )
1785 {
1786 const auto constToList = var.toList();
1787 for ( const QVariant &listVar : constToList )
1788 {
1789 processVariant( listVar );
1790 }
1791 }
1792 else if ( var.type() == QVariant::StringList )
1793 {
1794 const auto constToStringList = var.toStringList();
1795 for ( const QString &s : constToStringList )
1796 {
1797 processVariant( s );
1798 }
1799 }
1800 else if ( var.userType() == QMetaType::type( "QgsProperty" ) )
1801 processVariant( var.value< QgsProperty >().valueAsString( context.expressionContext(), definition->defaultValue().toString() ) );
1802 else if ( var.userType() == QMetaType::type( "QgsProcessingOutputLayerDefinition" ) )
1803 {
1804 // input is a QgsProcessingOutputLayerDefinition - get extra properties from it
1805 const QgsProcessingOutputLayerDefinition fromVar = qvariant_cast<QgsProcessingOutputLayerDefinition>( var );
1806 const QVariant sink = fromVar.sink;
1807 if ( sink.userType() == QMetaType::type( "QgsProperty" ) )
1808 {
1809 processVariant( sink.value< QgsProperty >().valueAsString( context.expressionContext(), definition->defaultValue().toString() ) );
1810 }
1811 }
1812 else if ( QgsMapLayer *layer = qobject_cast< QgsMapLayer * >( qvariant_cast<QObject *>( var ) ) )
1813 {
1814 layers << layer;
1815 }
1816 else
1817 {
1819 if ( alayer )
1820 layers << alayer;
1821 }
1822 };
1823
1824 processVariant( val );
1825
1826 if ( layers.isEmpty() )
1827 {
1828 // check default
1829 if ( QgsMapLayer *layer = qobject_cast< QgsMapLayer * >( qvariant_cast<QObject *>( definition->defaultValue() ) ) )
1830 {
1831 layers << layer;
1832 }
1833 else if ( definition->defaultValue().type() == QVariant::List )
1834 {
1835 const auto constToList = definition->defaultValue().toList();
1836 for ( const QVariant &var : constToList )
1837 {
1838 if ( QgsMapLayer *layer = qobject_cast< QgsMapLayer * >( qvariant_cast<QObject *>( var ) ) )
1839 {
1840 layers << layer;
1841 }
1842 else
1843 {
1844 processVariant( var );
1845 }
1846 }
1847 }
1848 else
1849 processVariant( definition->defaultValue() );
1850 }
1851
1852 return layers;
1853}
1854
1855QStringList QgsProcessingParameters::parameterAsFileList( const QgsProcessingParameterDefinition *definition, const QVariant &value, QgsProcessingContext &context )
1856{
1857 if ( !definition )
1858 return QStringList();
1859
1860 const QVariant val = value;
1861
1862 QStringList files;
1863
1864 std::function< void( const QVariant &var ) > processVariant;
1865 processVariant = [ &files, &context, &definition, &processVariant ]( const QVariant & var )
1866 {
1867 if ( var.type() == QVariant::List )
1868 {
1869 const auto constToList = var.toList();
1870 for ( const QVariant &listVar : constToList )
1871 {
1872 processVariant( listVar );
1873 }
1874 }
1875 else if ( var.type() == QVariant::StringList )
1876 {
1877 const auto constToStringList = var.toStringList();
1878 for ( const QString &s : constToStringList )
1879 {
1880 processVariant( s );
1881 }
1882 }
1883 else if ( var.userType() == QMetaType::type( "QgsProperty" ) )
1884 processVariant( var.value< QgsProperty >().valueAsString( context.expressionContext(), definition->defaultValue().toString() ) );
1885 else
1886 {
1887 files << var.toString();
1888 }
1889 };
1890
1891 processVariant( val );
1892
1893 if ( files.isEmpty() )
1894 {
1895 processVariant( definition->defaultValue() );
1896 }
1897
1898 return files;
1899}
1900
1901QStringList QgsProcessingParameters::parameterAsFileList( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context )
1902{
1903 if ( !definition )
1904 return QStringList();
1905
1906 return parameterAsFileList( definition, parameters.value( definition->name() ), context );
1907}
1908
1909QList<double> QgsProcessingParameters::parameterAsRange( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context )
1910{
1911 if ( !definition )
1912 return QList<double>();
1913
1914 return parameterAsRange( definition, parameters.value( definition->name() ), context );
1915}
1916
1917QList<double> QgsProcessingParameters::parameterAsRange( const QgsProcessingParameterDefinition *definition, const QVariant &value, QgsProcessingContext &context )
1918{
1919 if ( !definition )
1920 return QList<double>();
1921
1922 QStringList resultStringList;
1923 const QVariant val = value;
1924
1925 if ( val.userType() == QMetaType::type( "QgsProperty" ) )
1926 resultStringList << val.value< QgsProperty >().valueAsString( context.expressionContext(), definition->defaultValue().toString() );
1927 else if ( val.type() == QVariant::List )
1928 {
1929 const auto constToList = val.toList();
1930 for ( const QVariant &var : constToList )
1931 resultStringList << var.toString();
1932 }
1933 else
1934 resultStringList << val.toString();
1935
1936 if ( ( resultStringList.isEmpty() || ( resultStringList.size() == 1 && resultStringList.at( 0 ).isEmpty() ) ) )
1937 {
1938 resultStringList.clear();
1939 // check default
1940 if ( definition->defaultValue().type() == QVariant::List )
1941 {
1942 const auto constToList = definition->defaultValue().toList();
1943 for ( const QVariant &var : constToList )
1944 resultStringList << var.toString();
1945 }
1946 else
1947 resultStringList << definition->defaultValue().toString();
1948 }
1949
1950 if ( resultStringList.size() == 1 )
1951 {
1952 resultStringList = resultStringList.at( 0 ).split( ',' );
1953 }
1954
1955 if ( resultStringList.size() < 2 )
1956 return QList< double >() << std::numeric_limits<double>::quiet_NaN() << std::numeric_limits<double>::quiet_NaN() ;
1957
1958 QList< double > result;
1959 bool ok = false;
1960 double n = resultStringList.at( 0 ).toDouble( &ok );
1961 if ( ok )
1962 result << n;
1963 else
1964 result << std::numeric_limits<double>::quiet_NaN() ;
1965 ok = false;
1966 n = resultStringList.at( 1 ).toDouble( &ok );
1967 if ( ok )
1968 result << n;
1969 else
1970 result << std::numeric_limits<double>::quiet_NaN() ;
1971
1972 return result;
1973}
1974
1975QStringList QgsProcessingParameters::parameterAsFields( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context )
1976{
1977 if ( !definition )
1978 return QStringList();
1979
1980 return parameterAsStrings( definition, parameters.value( definition->name() ), context );
1981}
1982
1983QStringList QgsProcessingParameters::parameterAsFields( const QgsProcessingParameterDefinition *definition, const QVariant &value, QgsProcessingContext &context )
1984{
1985 return parameterAsStrings( definition, value, context );
1986}
1987
1988QStringList QgsProcessingParameters::parameterAsStrings( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context )
1989{
1990 if ( !definition )
1991 return QStringList();
1992
1993 return parameterAsStrings( definition, parameters.value( definition->name() ), context );
1994}
1995
1996QStringList QgsProcessingParameters::parameterAsStrings( const QgsProcessingParameterDefinition *definition, const QVariant &value, QgsProcessingContext &context )
1997{
1998 if ( !definition )
1999 return QStringList();
2000
2001 QStringList resultStringList;
2002 const QVariant val = value;
2003 if ( val.isValid() )
2004 {
2005 if ( val.userType() == QMetaType::type( "QgsProperty" ) )
2006 resultStringList << val.value< QgsProperty >().valueAsString( context.expressionContext(), definition->defaultValue().toString() );
2007 else if ( val.type() == QVariant::List )
2008 {
2009 const auto constToList = val.toList();
2010 for ( const QVariant &var : constToList )
2011 resultStringList << var.toString();
2012 }
2013 else if ( val.type() == QVariant::StringList )
2014 {
2015 resultStringList = val.toStringList();
2016 }
2017 else
2018 resultStringList.append( val.toString().split( ';' ) );
2019 }
2020
2021 if ( ( resultStringList.isEmpty() || resultStringList.at( 0 ).isEmpty() ) )
2022 {
2023 resultStringList.clear();
2024 // check default
2025 if ( definition->defaultValue().isValid() )
2026 {
2027 if ( definition->defaultValue().type() == QVariant::List )
2028 {
2029 const auto constToList = definition->defaultValue().toList();
2030 for ( const QVariant &var : constToList )
2031 resultStringList << var.toString();
2032 }
2033 else if ( definition->defaultValue().type() == QVariant::StringList )
2034 {
2035 resultStringList = definition->defaultValue().toStringList();
2036 }
2037 else
2038 resultStringList.append( definition->defaultValue().toString().split( ';' ) );
2039 }
2040 }
2041
2042 return resultStringList;
2043}
2044
2046{
2047 if ( !definition )
2048 return nullptr;
2049
2050 return parameterAsLayout( definition, parameters.value( definition->name() ), context );
2051}
2052
2054{
2055 const QString layoutName = parameterAsString( definition, value, context );
2056 if ( layoutName.isEmpty() )
2057 return nullptr;
2058
2059 if ( !context.project() )
2060 return nullptr;
2061
2062 QgsMasterLayoutInterface *l = context.project()->layoutManager()->layoutByName( layoutName );
2064 return static_cast< QgsPrintLayout * >( l );
2065 else
2066 return nullptr;
2067}
2068
2070{
2071 if ( !definition )
2072 return nullptr;
2073
2074 return parameterAsLayoutItem( definition, parameters.value( definition->name() ), context, layout );
2075}
2076
2078{
2079 if ( !layout )
2080 return nullptr;
2081
2082 const QString id = parameterAsString( definition, value, context );
2083 if ( id.isEmpty() )
2084 return nullptr;
2085
2086 // prefer matching by uuid, since it's guaranteed to be unique.
2087 if ( QgsLayoutItem *item = layout->itemByUuid( id ) )
2088 return item;
2089 else if ( QgsLayoutItem *item = layout->itemById( id ) )
2090 return item;
2091 else
2092 return nullptr;
2093}
2094
2095QColor QgsProcessingParameters::parameterAsColor( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context )
2096{
2097 if ( !definition )
2098 return QColor();
2099
2100 return parameterAsColor( definition, parameters.value( definition->name() ), context );
2101}
2102
2104{
2105 if ( !definition )
2106 return QColor();
2107
2108 QVariant val = value;
2109 if ( val.userType() == QMetaType::type( "QgsProperty" ) )
2110 {
2111 val = val.value< QgsProperty >().value( context.expressionContext(), definition->defaultValue() );
2112 }
2113 if ( val.type() == QVariant::Color )
2114 {
2115 QColor c = val.value< QColor >();
2116 if ( const QgsProcessingParameterColor *colorParam = dynamic_cast< const QgsProcessingParameterColor * >( definition ) )
2117 if ( !colorParam->opacityEnabled() )
2118 c.setAlpha( 255 );
2119 return c;
2120 }
2121
2122 QString colorText = parameterAsString( definition, value, context );
2123 if ( colorText.isEmpty() && !( definition->flags() & Qgis::ProcessingParameterFlag::Optional ) )
2124 {
2125 if ( definition->defaultValue().type() == QVariant::Color )
2126 return definition->defaultValue().value< QColor >();
2127 else
2128 colorText = definition->defaultValue().toString();
2129 }
2130
2131 if ( colorText.isEmpty() )
2132 return QColor();
2133
2134 bool containsAlpha = false;
2135 QColor c = QgsSymbolLayerUtils::parseColorWithAlpha( colorText, containsAlpha );
2136 if ( const QgsProcessingParameterColor *colorParam = dynamic_cast< const QgsProcessingParameterColor * >( definition ) )
2137 if ( c.isValid() && !colorParam->opacityEnabled() )
2138 c.setAlpha( 255 );
2139 return c;
2140}
2141
2142QString QgsProcessingParameters::parameterAsConnectionName( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, const QgsProcessingContext &context )
2143{
2144 if ( !definition )
2145 return QString();
2146
2147 return parameterAsConnectionName( definition, parameters.value( definition->name() ), context );
2148}
2149
2151{
2152 // for now it's just treated identical to strings, but in future we may want flexibility to amend this
2153 // (hence the new method)
2154 return parameterAsString( definition, value, context );
2155}
2156
2157QString QgsProcessingParameters::parameterAsSchema( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, const QgsProcessingContext &context )
2158{
2159 if ( !definition )
2160 return QString();
2161
2162 return parameterAsSchema( definition, parameters.value( definition->name() ), context );
2163}
2164
2165QString QgsProcessingParameters::parameterAsSchema( const QgsProcessingParameterDefinition *definition, const QVariant &value, const QgsProcessingContext &context )
2166{
2167 // 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
2168 // parameter values, such as via a delimiter separated string)
2169 return parameterAsString( definition, value, context );
2170}
2171
2172QString QgsProcessingParameters::parameterAsDatabaseTableName( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, const QgsProcessingContext &context )
2173{
2174 if ( !definition )
2175 return QString();
2176
2177 return parameterAsDatabaseTableName( definition, parameters.value( definition->name() ), context );
2178}
2179
2181{
2182 // 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
2183 // parameter values, such as via a delimiter separated string)
2184 return parameterAsString( definition, value, context );
2185}
2186
2188{
2189 return qobject_cast< QgsPointCloudLayer *>( parameterAsLayer( definition, parameters, context, QgsProcessingUtils::LayerHint::PointCloud, flags ) );
2190}
2191
2193{
2194 return qobject_cast< QgsPointCloudLayer *>( parameterAsLayer( definition, value, context, QgsProcessingUtils::LayerHint::PointCloud, flags ) );
2195}
2196
2198{
2199 return qobject_cast< QgsAnnotationLayer *>( parameterAsLayer( definition, parameters, context, QgsProcessingUtils::LayerHint::Annotation ) );
2200}
2201
2203{
2204 return qobject_cast< QgsAnnotationLayer *>( parameterAsLayer( definition, value, context, QgsProcessingUtils::LayerHint::Annotation ) );
2205}
2206
2208{
2209 const QString type = map.value( QStringLiteral( "parameter_type" ) ).toString();
2210 const QString name = map.value( QStringLiteral( "name" ) ).toString();
2211 std::unique_ptr< QgsProcessingParameterDefinition > def;
2212
2213 // probably all these hardcoded values aren't required anymore, and we could
2214 // always resort to the registry lookup...
2215 // TODO: confirm
2217 def.reset( new QgsProcessingParameterBoolean( name ) );
2218 else if ( type == QgsProcessingParameterCrs::typeName() )
2219 def.reset( new QgsProcessingParameterCrs( name ) );
2220 else if ( type == QgsProcessingParameterMapLayer::typeName() )
2221 def.reset( new QgsProcessingParameterMapLayer( name ) );
2222 else if ( type == QgsProcessingParameterExtent::typeName() )
2223 def.reset( new QgsProcessingParameterExtent( name ) );
2224 else if ( type == QgsProcessingParameterPoint::typeName() )
2225 def.reset( new QgsProcessingParameterPoint( name ) );
2226 else if ( type == QgsProcessingParameterFile::typeName() )
2227 def.reset( new QgsProcessingParameterFile( name ) );
2228 else if ( type == QgsProcessingParameterMatrix::typeName() )
2229 def.reset( new QgsProcessingParameterMatrix( name ) );
2231 def.reset( new QgsProcessingParameterMultipleLayers( name ) );
2232 else if ( type == QgsProcessingParameterNumber::typeName() )
2233 def.reset( new QgsProcessingParameterNumber( name ) );
2234 else if ( type == QgsProcessingParameterRange::typeName() )
2235 def.reset( new QgsProcessingParameterRange( name ) );
2237 def.reset( new QgsProcessingParameterRasterLayer( name ) );
2238 else if ( type == QgsProcessingParameterEnum::typeName() )
2239 def.reset( new QgsProcessingParameterEnum( name ) );
2240 else if ( type == QgsProcessingParameterString::typeName() )
2241 def.reset( new QgsProcessingParameterString( name ) );
2242 else if ( type == QgsProcessingParameterAuthConfig::typeName() )
2243 def.reset( new QgsProcessingParameterAuthConfig( name ) );
2244 else if ( type == QgsProcessingParameterExpression::typeName() )
2245 def.reset( new QgsProcessingParameterExpression( name ) );
2247 def.reset( new QgsProcessingParameterVectorLayer( name ) );
2248 else if ( type == QgsProcessingParameterField::typeName() )
2249 def.reset( new QgsProcessingParameterField( name ) );
2251 def.reset( new QgsProcessingParameterFeatureSource( name ) );
2253 def.reset( new QgsProcessingParameterFeatureSink( name ) );
2255 def.reset( new QgsProcessingParameterVectorDestination( name ) );
2257 def.reset( new QgsProcessingParameterRasterDestination( name ) );
2259 def.reset( new QgsProcessingParameterPointCloudDestination( name ) );
2261 def.reset( new QgsProcessingParameterFileDestination( name ) );
2263 def.reset( new QgsProcessingParameterFolderDestination( name ) );
2264 else if ( type == QgsProcessingParameterBand::typeName() )
2265 def.reset( new QgsProcessingParameterBand( name ) );
2266 else if ( type == QgsProcessingParameterMeshLayer::typeName() )
2267 def.reset( new QgsProcessingParameterMeshLayer( name ) );
2268 else if ( type == QgsProcessingParameterLayout::typeName() )
2269 def.reset( new QgsProcessingParameterLayout( name ) );
2270 else if ( type == QgsProcessingParameterLayoutItem::typeName() )
2271 def.reset( new QgsProcessingParameterLayoutItem( name ) );
2272 else if ( type == QgsProcessingParameterColor::typeName() )
2273 def.reset( new QgsProcessingParameterColor( name ) );
2275 def.reset( new QgsProcessingParameterCoordinateOperation( name ) );
2277 def.reset( new QgsProcessingParameterPointCloudLayer( name ) );
2279 def.reset( new QgsProcessingParameterAnnotationLayer( name ) );
2281 def.reset( new QgsProcessingParameterPointCloudAttribute( name ) );
2283 def.reset( new QgsProcessingParameterVectorTileDestination( name ) );
2284 else
2285 {
2287 if ( paramType )
2288 def.reset( paramType->create( name ) );
2289 }
2290
2291 if ( !def )
2292 return nullptr;
2293
2294 def->fromVariantMap( map );
2295 return def.release();
2296}
2297
2299{
2300 QString desc = name;
2301 desc.replace( '_', ' ' );
2302 return desc;
2303}
2304
2306{
2307 bool isOptional = false;
2308 QString name;
2309 QString definition;
2310 QString type;
2311 if ( !parseScriptCodeParameterOptions( code, isOptional, name, type, definition ) )
2312 return nullptr;
2313
2314 const QString description = descriptionFromName( name );
2315
2316 if ( type == QLatin1String( "boolean" ) )
2317 return QgsProcessingParameterBoolean::fromScriptCode( name, description, isOptional, definition );
2318 else if ( type == QLatin1String( "crs" ) )
2319 return QgsProcessingParameterCrs::fromScriptCode( name, description, isOptional, definition );
2320 else if ( type == QLatin1String( "layer" ) )
2321 return QgsProcessingParameterMapLayer::fromScriptCode( name, description, isOptional, definition );
2322 else if ( type == QLatin1String( "extent" ) )
2323 return QgsProcessingParameterExtent::fromScriptCode( name, description, isOptional, definition );
2324 else if ( type == QLatin1String( "point" ) )
2325 return QgsProcessingParameterPoint::fromScriptCode( name, description, isOptional, definition );
2326 else if ( type == QLatin1String( "geometry" ) )
2327 return QgsProcessingParameterGeometry::fromScriptCode( name, description, isOptional, definition );
2328 else if ( type == QLatin1String( "file" ) )
2329 return QgsProcessingParameterFile::fromScriptCode( name, description, isOptional, definition, Qgis::ProcessingFileParameterBehavior::File );
2330 else if ( type == QLatin1String( "folder" ) )
2331 return QgsProcessingParameterFile::fromScriptCode( name, description, isOptional, definition, Qgis::ProcessingFileParameterBehavior::Folder );
2332 else if ( type == QLatin1String( "matrix" ) )
2333 return QgsProcessingParameterMatrix::fromScriptCode( name, description, isOptional, definition );
2334 else if ( type == QLatin1String( "multiple" ) )
2335 return QgsProcessingParameterMultipleLayers::fromScriptCode( name, description, isOptional, definition );
2336 else if ( type == QLatin1String( "number" ) )
2337 return QgsProcessingParameterNumber::fromScriptCode( name, description, isOptional, definition );
2338 else if ( type == QLatin1String( "distance" ) )
2339 return QgsProcessingParameterDistance::fromScriptCode( name, description, isOptional, definition );
2340 else if ( type == QLatin1String( "duration" ) )
2341 return QgsProcessingParameterDuration::fromScriptCode( name, description, isOptional, definition );
2342 else if ( type == QLatin1String( "scale" ) )
2343 return QgsProcessingParameterScale::fromScriptCode( name, description, isOptional, definition );
2344 else if ( type == QLatin1String( "range" ) )
2345 return QgsProcessingParameterRange::fromScriptCode( name, description, isOptional, definition );
2346 else if ( type == QLatin1String( "raster" ) )
2347 return QgsProcessingParameterRasterLayer::fromScriptCode( name, description, isOptional, definition );
2348 else if ( type == QLatin1String( "enum" ) )
2349 return QgsProcessingParameterEnum::fromScriptCode( name, description, isOptional, definition );
2350 else if ( type == QLatin1String( "string" ) )
2351 return QgsProcessingParameterString::fromScriptCode( name, description, isOptional, definition );
2352 else if ( type == QLatin1String( "authcfg" ) )
2353 return QgsProcessingParameterAuthConfig::fromScriptCode( name, description, isOptional, definition );
2354 else if ( type == QLatin1String( "expression" ) )
2355 return QgsProcessingParameterExpression::fromScriptCode( name, description, isOptional, definition );
2356 else if ( type == QLatin1String( "field" ) )
2357 return QgsProcessingParameterField::fromScriptCode( name, description, isOptional, definition );
2358 else if ( type == QLatin1String( "vector" ) )
2359 return QgsProcessingParameterVectorLayer::fromScriptCode( name, description, isOptional, definition );
2360 else if ( type == QLatin1String( "source" ) )
2361 return QgsProcessingParameterFeatureSource::fromScriptCode( name, description, isOptional, definition );
2362 else if ( type == QLatin1String( "sink" ) )
2363 return QgsProcessingParameterFeatureSink::fromScriptCode( name, description, isOptional, definition );
2364 else if ( type == QLatin1String( "vectordestination" ) )
2365 return QgsProcessingParameterVectorDestination::fromScriptCode( name, description, isOptional, definition );
2366 else if ( type == QLatin1String( "rasterdestination" ) )
2367 return QgsProcessingParameterRasterDestination::fromScriptCode( name, description, isOptional, definition );
2368 else if ( type == QLatin1String( "pointclouddestination" ) )
2369 return QgsProcessingParameterPointCloudDestination::fromScriptCode( name, description, isOptional, definition );
2370 else if ( type == QLatin1String( "filedestination" ) )
2371 return QgsProcessingParameterFileDestination::fromScriptCode( name, description, isOptional, definition );
2372 else if ( type == QLatin1String( "folderdestination" ) )
2373 return QgsProcessingParameterFolderDestination::fromScriptCode( name, description, isOptional, definition );
2374 else if ( type == QLatin1String( "band" ) )
2375 return QgsProcessingParameterBand::fromScriptCode( name, description, isOptional, definition );
2376 else if ( type == QLatin1String( "mesh" ) )
2377 return QgsProcessingParameterMeshLayer::fromScriptCode( name, description, isOptional, definition );
2378 else if ( type == QLatin1String( "layout" ) )
2379 return QgsProcessingParameterLayout::fromScriptCode( name, description, isOptional, definition );
2380 else if ( type == QLatin1String( "layoutitem" ) )
2381 return QgsProcessingParameterLayoutItem::fromScriptCode( name, description, isOptional, definition );
2382 else if ( type == QLatin1String( "color" ) )
2383 return QgsProcessingParameterColor::fromScriptCode( name, description, isOptional, definition );
2384 else if ( type == QLatin1String( "coordinateoperation" ) )
2385 return QgsProcessingParameterCoordinateOperation::fromScriptCode( name, description, isOptional, definition );
2386 else if ( type == QLatin1String( "maptheme" ) )
2387 return QgsProcessingParameterMapTheme::fromScriptCode( name, description, isOptional, definition );
2388 else if ( type == QLatin1String( "datetime" ) )
2389 return QgsProcessingParameterDateTime::fromScriptCode( name, description, isOptional, definition );
2390 else if ( type == QLatin1String( "providerconnection" ) )
2391 return QgsProcessingParameterProviderConnection::fromScriptCode( name, description, isOptional, definition );
2392 else if ( type == QLatin1String( "databaseschema" ) )
2393 return QgsProcessingParameterDatabaseSchema::fromScriptCode( name, description, isOptional, definition );
2394 else if ( type == QLatin1String( "databasetable" ) )
2395 return QgsProcessingParameterDatabaseTable::fromScriptCode( name, description, isOptional, definition );
2396 else if ( type == QLatin1String( "pointcloud" ) )
2397 return QgsProcessingParameterPointCloudLayer::fromScriptCode( name, description, isOptional, definition );
2398 else if ( type == QLatin1String( "annotation" ) )
2399 return QgsProcessingParameterAnnotationLayer::fromScriptCode( name, description, isOptional, definition );
2400 else if ( type == QLatin1String( "attribute" ) )
2401 return QgsProcessingParameterPointCloudAttribute::fromScriptCode( name, description, isOptional, definition );
2402 else if ( type == QLatin1String( "vectortiledestination" ) )
2403 return QgsProcessingParameterVectorTileDestination::fromScriptCode( name, description, isOptional, definition );
2404
2405 return nullptr;
2406}
2407
2408bool QgsProcessingParameters::parseScriptCodeParameterOptions( const QString &code, bool &isOptional, QString &name, QString &type, QString &definition )
2409{
2410 const thread_local QRegularExpression re( QStringLiteral( "(?:#*)(.*?)=\\s*(.*)" ) );
2411 QRegularExpressionMatch m = re.match( code );
2412 if ( !m.hasMatch() )
2413 return false;
2414
2415 name = m.captured( 1 );
2416 QString tokens = m.captured( 2 );
2417 if ( tokens.startsWith( QLatin1String( "optional" ), Qt::CaseInsensitive ) )
2418 {
2419 isOptional = true;
2420 tokens.remove( 0, 8 ); // length "optional" = 8
2421 }
2422 else
2423 {
2424 isOptional = false;
2425 }
2426
2427 tokens = tokens.trimmed();
2428
2429 const thread_local QRegularExpression re2( QStringLiteral( "(.*?)\\s+(.*)" ) );
2430 m = re2.match( tokens );
2431 if ( !m.hasMatch() )
2432 {
2433 type = tokens.toLower().trimmed();
2434 definition.clear();
2435 }
2436 else
2437 {
2438 type = m.captured( 1 ).toLower().trimmed();
2439 definition = m.captured( 2 );
2440 }
2441 return true;
2442}
2443
2444//
2445// QgsProcessingParameterDefinition
2446//
2447
2448QgsProcessingParameterDefinition::QgsProcessingParameterDefinition( const QString &name, const QString &description, const QVariant &defaultValue, bool optional, const QString &help )
2449 : mName( name )
2450 , mDescription( description )
2451 , mHelp( help )
2452 , mDefault( defaultValue )
2453 , mFlags( optional ? Qgis::ProcessingParameterFlag::Optional : Qgis::ProcessingParameterFlag() )
2454{}
2455
2457{
2458 QVariant defaultSettingsValue = defaultGuiValueFromSetting();
2459 if ( defaultSettingsValue.isValid() )
2460 {
2461 return defaultSettingsValue;
2462 }
2463 return mGuiDefault;
2464}
2465
2467{
2468 QVariant defaultSettingsValue = defaultGuiValueFromSetting();
2469 if ( defaultSettingsValue.isValid() )
2470 {
2471 return defaultSettingsValue;
2472 }
2473 return mGuiDefault.isValid() ? mGuiDefault : mDefault;
2474}
2475
2477{
2478 if ( mAlgorithm )
2479 {
2480 QgsSettings s;
2481 QVariant settingValue = s.value( QStringLiteral( "/Processing/DefaultGuiParam/%1/%2" ).arg( mAlgorithm->id() ).arg( mName ) );
2482 if ( settingValue.isValid() )
2483 {
2484 return settingValue;
2485 }
2486 }
2487 return QVariant();
2488}
2489
2491{
2492 if ( !input.isValid() && !mDefault.isValid() )
2494
2495 if ( ( input.type() == QVariant::String && input.toString().isEmpty() )
2496 || ( !input.isValid() && mDefault.type() == QVariant::String && mDefault.toString().isEmpty() ) )
2498
2499 return true;
2500}
2501
2503{
2504 if ( !value.isValid() )
2505 return QStringLiteral( "None" );
2506
2507 if ( value.userType() == QMetaType::type( "QgsProperty" ) )
2508 return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
2509
2510 return QgsProcessingUtils::stringToPythonLiteral( value.toString() );
2511}
2512
2513QVariant QgsProcessingParameterDefinition::valueAsJsonObject( const QVariant &value, QgsProcessingContext &context ) const
2514{
2515 return valueAsJsonObjectPrivate( value, context, ValueAsStringFlags() );
2516}
2517
2519{
2520 if ( !value.isValid() )
2521 return value;
2522
2523 // dive into map and list types and convert each value
2524 if ( value.type() == QVariant::Type::Map )
2525 {
2526 const QVariantMap sourceMap = value.toMap();
2527 QVariantMap resultMap;
2528 for ( auto it = sourceMap.constBegin(); it != sourceMap.constEnd(); it++ )
2529 {
2530 resultMap[ it.key() ] = valueAsJsonObject( it.value(), context );
2531 }
2532 return resultMap;
2533 }
2534 else if ( value.type() == QVariant::Type::List || value.type() == QVariant::Type::StringList )
2535 {
2536 const QVariantList sourceList = value.toList();
2537 QVariantList resultList;
2538 resultList.reserve( sourceList.size() );
2539 for ( const QVariant &v : sourceList )
2540 {
2541 resultList.push_back( valueAsJsonObject( v, context ) );
2542 }
2543 return resultList;
2544 }
2545 else
2546 {
2547 switch ( value.userType() )
2548 {
2549 // simple types which can be directly represented in JSON -- note that strings are NOT handled here yet!
2550 case QMetaType::Bool:
2551 case QMetaType::Char:
2552 case QMetaType::Int:
2553 case QMetaType::Double:
2554 case QMetaType::Float:
2555 case QMetaType::LongLong:
2556 case QMetaType::ULongLong:
2557 case QMetaType::UInt:
2558 case QMetaType::ULong:
2559 case QMetaType::UShort:
2560 return value;
2561
2562 default:
2563 break;
2564 }
2565
2566 if ( value.userType() == QMetaType::type( "QgsProperty" ) )
2567 {
2568 const QgsProperty prop = value.value< QgsProperty >();
2569 switch ( prop.propertyType() )
2570 {
2572 return QVariant();
2574 return valueAsJsonObject( prop.staticValue(), context );
2576 return QVariantMap( {{QStringLiteral( "type" ), QStringLiteral( "data_defined" )}, {QStringLiteral( "field" ), prop.field() }} );
2578 return QVariantMap( {{QStringLiteral( "type" ), QStringLiteral( "data_defined" )}, {QStringLiteral( "expression" ), prop.expressionString() }} );
2579 }
2580 }
2581
2582 // value may be a CRS
2583 if ( value.userType() == QMetaType::type( "QgsCoordinateReferenceSystem" ) )
2584 {
2586 if ( !crs.isValid() )
2587 return QString();
2588 else if ( !crs.authid().isEmpty() )
2589 return crs.authid();
2590 else
2592 }
2593 else if ( value.userType() == QMetaType::type( "QgsRectangle" ) )
2594 {
2595 const QgsRectangle r = value.value<QgsRectangle>();
2596 return QStringLiteral( "%1, %3, %2, %4" ).arg( qgsDoubleToString( r.xMinimum() ),
2599 qgsDoubleToString( r.yMaximum() ) );
2600 }
2601 else if ( value.userType() == QMetaType::type( "QgsReferencedRectangle" ) )
2602 {
2603 const QgsReferencedRectangle r = value.value<QgsReferencedRectangle>();
2604 return QStringLiteral( "%1, %3, %2, %4 [%5]" ).arg( qgsDoubleToString( r.xMinimum() ),
2608 r.crs().authid() );
2609 }
2610 else if ( value.userType() == QMetaType::type( "QgsGeometry" ) )
2611 {
2612 const QgsGeometry g = value.value<QgsGeometry>();
2613 if ( !g.isNull() )
2614 {
2615 return g.asWkt();
2616 }
2617 else
2618 {
2619 return QString();
2620 }
2621 }
2622 else if ( value.userType() == QMetaType::type( "QgsReferencedGeometry" ) )
2623 {
2624 const QgsReferencedGeometry g = value.value<QgsReferencedGeometry>();
2625 if ( !g.isNull() )
2626 {
2627 if ( !g.crs().isValid() )
2628 return g.asWkt();
2629 else
2630 return QStringLiteral( "CRS=%1;%2" ).arg( g.crs().authid().isEmpty() ? g.crs().toWkt( Qgis::CrsWktVariant::Preferred ) : g.crs().authid(), g.asWkt() );
2631 }
2632 else
2633 {
2634 return QString();
2635 }
2636 }
2637 else if ( value.userType() == QMetaType::type( "QgsPointXY" ) )
2638 {
2639 const QgsPointXY r = value.value<QgsPointXY>();
2640 return QStringLiteral( "%1,%2" ).arg( qgsDoubleToString( r.x() ),
2641 qgsDoubleToString( r.y() ) );
2642 }
2643 else if ( value.userType() == QMetaType::type( "QgsReferencedPointXY" ) )
2644 {
2645 const QgsReferencedPointXY r = value.value<QgsReferencedPointXY>();
2646 return QStringLiteral( "%1,%2 [%3]" ).arg( qgsDoubleToString( r.x() ),
2647 qgsDoubleToString( r.y() ),
2648 r.crs().authid() );
2649 }
2650 else if ( value.userType() == QMetaType::type( "QgsProcessingFeatureSourceDefinition" ) )
2651 {
2652 const QgsProcessingFeatureSourceDefinition fromVar = qvariant_cast<QgsProcessingFeatureSourceDefinition>( value );
2653
2654 // TODO -- we could consider also serializating the additional properties like invalid feature handling, limits, etc
2655 return valueAsJsonObject( fromVar.source, context );
2656 }
2657 else if ( value.userType() == QMetaType::type( "QgsProcessingOutputLayerDefinition" ) )
2658 {
2659 const QgsProcessingOutputLayerDefinition fromVar = qvariant_cast<QgsProcessingOutputLayerDefinition>( value );
2660 return valueAsJsonObject( fromVar.sink, context );
2661 }
2662 else if ( value.userType() == QMetaType::type( "QColor" ) )
2663 {
2664 const QColor fromVar = value.value< QColor >();
2665 if ( !fromVar.isValid() )
2666 return QString();
2667
2668 return QStringLiteral( "rgba( %1, %2, %3, %4 )" ).arg( fromVar.red() ).arg( fromVar.green() ).arg( fromVar.blue() ).arg( QString::number( fromVar.alphaF(), 'f', 2 ) );
2669 }
2670 else if ( value.userType() == QMetaType::type( "QDateTime" ) )
2671 {
2672 const QDateTime fromVar = value.toDateTime();
2673 if ( !fromVar.isValid() )
2674 return QString();
2675
2676 return fromVar.toString( Qt::ISODate );
2677 }
2678 else if ( value.userType() == QMetaType::type( "QDate" ) )
2679 {
2680 const QDate fromVar = value.toDate();
2681 if ( !fromVar.isValid() )
2682 return QString();
2683
2684 return fromVar.toString( Qt::ISODate );
2685 }
2686 else if ( value.userType() == QMetaType::type( "QTime" ) )
2687 {
2688 const QTime fromVar = value.toTime();
2689 if ( !fromVar.isValid() )
2690 return QString();
2691
2692 return fromVar.toString( Qt::ISODate );
2693 }
2694
2696 {
2697 // value may be a map layer
2698 QVariantMap p;
2699 p.insert( name(), value );
2700 if ( QgsMapLayer *layer = QgsProcessingParameters::parameterAsLayer( this, p, context ) )
2701 {
2703 }
2704 }
2705
2706 // now we handle strings, after any other specific logic has already been applied
2707 if ( value.userType() == QMetaType::QString )
2708 return value;
2709 }
2710
2711 // unhandled type
2712 Q_ASSERT_X( false, "QgsProcessingParameterDefinition::valueAsJsonObject", QStringLiteral( "unsupported variant type %1" ).arg( QMetaType::typeName( value.userType() ) ).toLocal8Bit() );
2713 return value;
2714}
2715
2716QString QgsProcessingParameterDefinition::valueAsString( const QVariant &value, QgsProcessingContext &context, bool &ok ) const
2717{
2718 return valueAsStringPrivate( value, context, ok, ValueAsStringFlags() );
2719}
2720
2721QString QgsProcessingParameterDefinition::valueAsStringPrivate( const QVariant &value, QgsProcessingContext &context, bool &ok, ValueAsStringFlags flags ) const
2722{
2723 ok = true;
2724
2725 if ( !value.isValid() )
2726 return QString();
2727
2728 switch ( value.userType() )
2729 {
2730 // simple types which can be directly represented in JSON -- note that strings are NOT handled here yet!
2731 case QMetaType::Bool:
2732 case QMetaType::Char:
2733 case QMetaType::Int:
2734 case QMetaType::Double:
2735 case QMetaType::Float:
2736 case QMetaType::LongLong:
2737 case QMetaType::ULongLong:
2738 case QMetaType::UInt:
2739 case QMetaType::ULong:
2740 case QMetaType::UShort:
2741 return value.toString();
2742
2743 default:
2744 break;
2745 }
2746
2747 if ( value.userType() == QMetaType::type( "QgsProperty" ) )
2748 {
2749 const QgsProperty prop = value.value< QgsProperty >();
2750 switch ( prop.propertyType() )
2751 {
2753 return QString();
2755 return valueAsString( prop.staticValue(), context, ok );
2757 return QStringLiteral( "field:%1" ).arg( prop.field() );
2759 return QStringLiteral( "expression:%1" ).arg( prop.expressionString() );
2760 }
2761 }
2762
2763 // value may be a CRS
2764 if ( value.userType() == QMetaType::type( "QgsCoordinateReferenceSystem" ) )
2765 {
2767 if ( !crs.isValid() )
2768 return QString();
2769 else if ( !crs.authid().isEmpty() )
2770 return crs.authid();
2771 else
2773 }
2774 else if ( value.userType() == QMetaType::type( "QgsRectangle" ) )
2775 {
2776 const QgsRectangle r = value.value<QgsRectangle>();
2777 return QStringLiteral( "%1, %3, %2, %4" ).arg( qgsDoubleToString( r.xMinimum() ),
2780 qgsDoubleToString( r.yMaximum() ) );
2781 }
2782 else if ( value.userType() == QMetaType::type( "QgsReferencedRectangle" ) )
2783 {
2784 const QgsReferencedRectangle r = value.value<QgsReferencedRectangle>();
2785 return QStringLiteral( "%1, %3, %2, %4 [%5]" ).arg( qgsDoubleToString( r.xMinimum() ),
2788 qgsDoubleToString( r.yMaximum() ), r.crs().authid() );
2789 }
2790 else if ( value.userType() == QMetaType::type( "QgsGeometry" ) )
2791 {
2792 const QgsGeometry g = value.value<QgsGeometry>();
2793 if ( !g.isNull() )
2794 {
2795 return g.asWkt();
2796 }
2797 else
2798 {
2799 return QString();
2800 }
2801 }
2802 else if ( value.userType() == QMetaType::type( "QgsReferencedGeometry" ) )
2803 {
2804 const QgsReferencedGeometry g = value.value<QgsReferencedGeometry>();
2805 if ( !g.isNull() )
2806 {
2807 if ( !g.crs().isValid() )
2808 return g.asWkt();
2809 else
2810 return QStringLiteral( "CRS=%1;%2" ).arg( g.crs().authid().isEmpty() ? g.crs().toWkt( Qgis::CrsWktVariant::Preferred ) : g.crs().authid(), g.asWkt() );
2811 }
2812 else
2813 {
2814 return QString();
2815 }
2816 }
2817 else if ( value.userType() == QMetaType::type( "QgsPointXY" ) )
2818 {
2819 const QgsPointXY r = value.value<QgsPointXY>();
2820 return QStringLiteral( "%1,%2" ).arg( qgsDoubleToString( r.x() ),
2821 qgsDoubleToString( r.y() ) );
2822 }
2823 else if ( value.userType() == QMetaType::type( "QgsReferencedPointXY" ) )
2824 {
2825 const QgsReferencedPointXY r = value.value<QgsReferencedPointXY>();
2826 return QStringLiteral( "%1,%2 [%3]" ).arg( qgsDoubleToString( r.x() ),
2827 qgsDoubleToString( r.y() ),
2828 r.crs().authid() );
2829 }
2830 else if ( value.userType() == QMetaType::type( "QgsProcessingFeatureSourceDefinition" ) )
2831 {
2832 const QgsProcessingFeatureSourceDefinition fromVar = qvariant_cast<QgsProcessingFeatureSourceDefinition>( value );
2833 return valueAsString( fromVar.source, context, ok );
2834 }
2835 else if ( value.userType() == QMetaType::type( "QgsProcessingOutputLayerDefinition" ) )
2836 {
2837 const QgsProcessingOutputLayerDefinition fromVar = qvariant_cast<QgsProcessingOutputLayerDefinition>( value );
2838 return valueAsString( fromVar.sink, context, ok );
2839 }
2840 else if ( value.userType() == QMetaType::type( "QColor" ) )
2841 {
2842 const QColor fromVar = value.value< QColor >();
2843 if ( !fromVar.isValid() )
2844 return QString();
2845
2846 return QStringLiteral( "rgba( %1, %2, %3, %4 )" ).arg( fromVar.red() ).arg( fromVar.green() ).arg( fromVar.blue() ).arg( QString::number( fromVar.alphaF(), 'f', 2 ) );
2847 }
2848 else if ( value.userType() == QMetaType::type( "QDateTime" ) )
2849 {
2850 const QDateTime fromVar = value.toDateTime();
2851 if ( !fromVar.isValid() )
2852 return QString();
2853
2854 return fromVar.toString( Qt::ISODate );
2855 }
2856 else if ( value.userType() == QMetaType::type( "QDate" ) )
2857 {
2858 const QDate fromVar = value.toDate();
2859 if ( !fromVar.isValid() )
2860 return QString();
2861
2862 return fromVar.toString( Qt::ISODate );
2863 }
2864 else if ( value.userType() == QMetaType::type( "QTime" ) )
2865 {
2866 const QTime fromVar = value.toTime();
2867 if ( !fromVar.isValid() )
2868 return QString();
2869
2870 return fromVar.toString( Qt::ISODate );
2871 }
2872
2874 {
2875 // value may be a map layer
2876 QVariantMap p;
2877 p.insert( name(), value );
2878 if ( QgsMapLayer *layer = QgsProcessingParameters::parameterAsLayer( this, p, context ) )
2879 {
2881 }
2882 }
2883
2884 // now we handle strings, after any other specific logic has already been applied
2885 if ( value.userType() == QMetaType::QString )
2886 return value.toString();
2887
2888 // unhandled type
2889 QgsDebugError( QStringLiteral( "unsupported variant type %1" ).arg( QMetaType::typeName( value.userType() ) ) );
2890 ok = false;
2891 return value.toString();
2892}
2893
2894QStringList QgsProcessingParameterDefinition::valueAsStringList( const QVariant &value, QgsProcessingContext &context, bool &ok ) const
2895{
2896 ok = true;
2897 if ( !value.isValid( ) )
2898 return QStringList();
2899
2900 if ( value.type() == QVariant::Type::List || value.type() == QVariant::Type::StringList )
2901 {
2902 const QVariantList sourceList = value.toList();
2903 QStringList resultList;
2904 resultList.reserve( sourceList.size() );
2905 for ( const QVariant &v : sourceList )
2906 {
2907 resultList.append( valueAsStringList( v, context, ok ) );
2908 }
2909 return resultList;
2910 }
2911
2912 const QString res = valueAsString( value, context, ok );
2913 if ( !ok )
2914 return QStringList();
2915
2916 return {res};
2917}
2918
2920{
2921 return QString();
2922}
2923
2925{
2926 QString code = QStringLiteral( "##%1=" ).arg( mName );
2928 code += QLatin1String( "optional " );
2929 code += type() + ' ';
2930 code += mDefault.toString();
2931 return code.trimmed();
2932}
2933
2935{
2936 // base class method is probably not much use
2938 {
2939 switch ( outputType )
2940 {
2942 {
2943 QString code = t->className() + QStringLiteral( "('%1', %2" )
2946 code += QLatin1String( ", optional=True" );
2947
2949 code += QStringLiteral( ", defaultValue=%1)" ).arg( valueAsPythonString( mDefault, c ) );
2950 return code;
2951 }
2952 }
2953 }
2954
2955 // oh well, we tried
2956 return QString();
2957}
2958
2960{
2961 QVariantMap map;
2962 map.insert( QStringLiteral( "parameter_type" ), type() );
2963 map.insert( QStringLiteral( "name" ), mName );
2964 map.insert( QStringLiteral( "description" ), mDescription );
2965 map.insert( QStringLiteral( "help" ), mHelp );
2966 map.insert( QStringLiteral( "default" ), mDefault );
2967 map.insert( QStringLiteral( "defaultGui" ), mGuiDefault );
2968 map.insert( QStringLiteral( "flags" ), static_cast< int >( mFlags ) );
2969 map.insert( QStringLiteral( "metadata" ), mMetadata );
2970 return map;
2971}
2972
2974{
2975 mName = map.value( QStringLiteral( "name" ) ).toString();
2976 mDescription = map.value( QStringLiteral( "description" ) ).toString();
2977 mHelp = map.value( QStringLiteral( "help" ) ).toString();
2978 mDefault = map.value( QStringLiteral( "default" ) );
2979 mGuiDefault = map.value( QStringLiteral( "defaultGui" ) );
2980 mFlags = static_cast< Qgis::ProcessingParameterFlags >( map.value( QStringLiteral( "flags" ) ).toInt() );
2981 mMetadata = map.value( QStringLiteral( "metadata" ) ).toMap();
2982 return true;
2983}
2984
2986{
2987 return mAlgorithm;
2988}
2989
2991{
2992 return mAlgorithm ? mAlgorithm->provider() : nullptr;
2993}
2994
2996{
2997 QString text = QStringLiteral( "<p><b>%1</b></p>" ).arg( description() );
2998 if ( !help().isEmpty() )
2999 {
3000 text += QStringLiteral( "<p>%1</p>" ).arg( help() );
3001 }
3002 text += QStringLiteral( "<p>%1</p>" ).arg( QObject::tr( "Python identifier: ‘%1’" ).arg( QStringLiteral( "<i>%1</i>" ).arg( name() ) ) );
3003 return text;
3004}
3005
3006QgsProcessingParameterBoolean::QgsProcessingParameterBoolean( const QString &name, const QString &description, const QVariant &defaultValue, bool optional )
3007 : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
3008{}
3009
3011{
3012 return new QgsProcessingParameterBoolean( *this );
3013}
3014
3016{
3017 if ( !val.isValid() )
3018 return QStringLiteral( "None" );
3019
3020 if ( val.userType() == QMetaType::type( "QgsProperty" ) )
3021 return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( val.value< QgsProperty >().asExpression() );
3022 return val.toBool() ? QStringLiteral( "True" ) : QStringLiteral( "False" );
3023}
3024
3026{
3027 QString code = QStringLiteral( "##%1=" ).arg( mName );
3029 code += QLatin1String( "optional " );
3030 code += type() + ' ';
3031 code += mDefault.toBool() ? QStringLiteral( "true" ) : QStringLiteral( "false" );
3032 return code.trimmed();
3033}
3034
3035QgsProcessingParameterBoolean *QgsProcessingParameterBoolean::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
3036{
3037 return new QgsProcessingParameterBoolean( name, description, definition.toLower().trimmed() != QStringLiteral( "false" ), isOptional );
3038}
3039
3040QgsProcessingParameterCrs::QgsProcessingParameterCrs( const QString &name, const QString &description, const QVariant &defaultValue, bool optional )
3041 : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
3042{
3043
3044}
3045
3047{
3048 return new QgsProcessingParameterCrs( *this );
3049}
3050
3052{
3053 QVariant input = v;
3054 if ( !input.isValid() )
3055 {
3056 if ( !defaultValue().isValid() )
3058
3059 input = defaultValue();
3060 }
3061
3062 if ( input.userType() == QMetaType::type( "QgsCoordinateReferenceSystem" ) )
3063 {
3064 return true;
3065 }
3066 else if ( input.userType() == QMetaType::type( "QgsProcessingFeatureSourceDefinition" ) )
3067 {
3068 return true;
3069 }
3070 else if ( input.userType() == QMetaType::type( "QgsProcessingOutputLayerDefinition" ) )
3071 {
3072 return true;
3073 }
3074
3075 if ( input.userType() == QMetaType::type( "QgsProperty" ) )
3076 {
3077 return true;
3078 }
3079
3080 // direct map layer value
3081 if ( qobject_cast< QgsMapLayer * >( qvariant_cast<QObject *>( input ) ) )
3082 return true;
3083
3084 if ( input.type() != QVariant::String || input.toString().isEmpty() )
3086
3087 return true;
3088}
3089
3090QString QgsProcessingParameterCrs::valueAsPythonString( const QVariant &value, QgsProcessingContext &context ) const
3091{
3092 if ( !value.isValid() )
3093 return QStringLiteral( "None" );
3094
3095 if ( value.userType() == QMetaType::type( "QgsCoordinateReferenceSystem" ) )
3096 {
3097 if ( !value.value< QgsCoordinateReferenceSystem >().isValid() )
3098 return QStringLiteral( "QgsCoordinateReferenceSystem()" );
3099 else
3100 return QStringLiteral( "QgsCoordinateReferenceSystem('%1')" ).arg( value.value< QgsCoordinateReferenceSystem >().authid() );
3101 }
3102
3103 if ( value.userType() == QMetaType::type( "QgsProperty" ) )
3104 return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
3105
3106 QVariantMap p;
3107 p.insert( name(), value );
3108 QgsMapLayer *layer = QgsProcessingParameters::parameterAsLayer( this, p, context );
3109 if ( layer )
3111
3113}
3114
3115QString QgsProcessingParameterCrs::valueAsString( const QVariant &value, QgsProcessingContext &context, bool &ok ) const
3116{
3118}
3119
3120QVariant QgsProcessingParameterCrs::valueAsJsonObject( const QVariant &value, QgsProcessingContext &context ) const
3121{
3123}
3124
3125QgsProcessingParameterCrs *QgsProcessingParameterCrs::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
3126{
3127 return new QgsProcessingParameterCrs( name, description, definition.compare( QLatin1String( "none" ), Qt::CaseInsensitive ) == 0 ? QVariant() : definition, isOptional );
3128}
3129
3130QgsProcessingParameterMapLayer::QgsProcessingParameterMapLayer( const QString &name, const QString &description, const QVariant &defaultValue, bool optional, const QList<int> &types )
3131 : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
3133{
3134
3135}
3136
3138{
3139 return new QgsProcessingParameterMapLayer( *this );
3140}
3141
3143{
3144 QVariant input = v;
3145
3146 if ( !input.isValid() )
3147 {
3148 if ( !defaultValue().isValid() )
3150
3151 input = defaultValue();
3152 }
3153
3154 if ( input.userType() == QMetaType::type( "QgsProperty" ) )
3155 {
3156 return true;
3157 }
3158
3159 if ( qobject_cast< QgsMapLayer * >( qvariant_cast<QObject *>( input ) ) )
3160 {
3161 return true;
3162 }
3163
3164 if ( input.type() != QVariant::String || input.toString().isEmpty() )
3166
3167 if ( !context )
3168 {
3169 // that's as far as we can get without a context
3170 return true;
3171 }
3172
3173 // try to load as layer
3174 if ( QgsProcessingUtils::mapLayerFromString( input.toString(), *context ) )
3175 return true;
3176
3177 return false;
3178}
3179
3181{
3182 if ( !val.isValid() )
3183 return QStringLiteral( "None" );
3184
3185 if ( val.userType() == QMetaType::type( "QgsProperty" ) )
3186 return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( val.value< QgsProperty >().asExpression() );
3187
3188 QVariantMap p;
3189 p.insert( name(), val );
3190 QgsMapLayer *layer = QgsProcessingParameters::parameterAsLayer( this, p, context );
3193}
3194
3195QString QgsProcessingParameterMapLayer::valueAsString( const QVariant &value, QgsProcessingContext &context, bool &ok ) const
3196{
3198}
3199
3200QVariant QgsProcessingParameterMapLayer::valueAsJsonObject( const QVariant &value, QgsProcessingContext &context ) const
3201{
3203}
3204
3206{
3207 QStringList vectors = QgsProviderRegistry::instance()->fileVectorFilters().split( QStringLiteral( ";;" ) );
3208 const QStringList rasters = QgsProviderRegistry::instance()->fileRasterFilters().split( QStringLiteral( ";;" ) );
3209 for ( const QString &raster : rasters )
3210 {
3211 if ( !vectors.contains( raster ) )
3212 vectors << raster;
3213 }
3214 const QStringList meshFilters = QgsProviderRegistry::instance()->fileMeshFilters().split( QStringLiteral( ";;" ) );
3215 for ( const QString &mesh : meshFilters )
3216 {
3217 if ( !vectors.contains( mesh ) )
3218 vectors << mesh;
3219 }
3220 const QStringList pointCloudFilters = QgsProviderRegistry::instance()->filePointCloudFilters().split( QStringLiteral( ";;" ) );
3221 for ( const QString &pointCloud : pointCloudFilters )
3222 {
3223 if ( !vectors.contains( pointCloud ) )
3224 vectors << pointCloud;
3225 }
3226 vectors.removeAll( QObject::tr( "All files (*.*)" ) );
3227 std::sort( vectors.begin(), vectors.end() );
3228
3229 return QObject::tr( "All files (*.*)" ) + QStringLiteral( ";;" ) + vectors.join( QLatin1String( ";;" ) );
3230}
3231
3233{
3235}
3236
3238{
3239 QString code = QStringLiteral( "##%1=" ).arg( mName );
3241 code += QLatin1String( "optional " );
3242 code += QLatin1String( "layer " );
3243
3244 for ( const int type : mDataTypes )
3245 {
3246 switch ( static_cast< Qgis::ProcessingSourceType >( type ) )
3247 {
3249 code += QLatin1String( "hasgeometry " );
3250 break;
3251
3253 code += QLatin1String( "point " );
3254 break;
3255
3257 code += QLatin1String( "line " );
3258 break;
3259
3261 code += QLatin1String( "polygon " );
3262 break;
3263
3265 code += QLatin1String( "raster " );
3266 break;
3267
3269 code += QLatin1String( "mesh " );
3270 break;
3271
3273 code += QLatin1String( "plugin " );
3274 break;
3275
3277 code += QLatin1String( "pointcloud " );
3278 break;
3279
3281 code += QLatin1String( "annotation " );
3282 break;
3283
3284 default:
3285 break;
3286 }
3287 }
3288
3289 code += mDefault.toString();
3290 return code.trimmed();
3291}
3292
3293QgsProcessingParameterMapLayer *QgsProcessingParameterMapLayer::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
3294{
3295 QList< int > types;
3296 QString def = definition;
3297 while ( true )
3298 {
3299 if ( def.startsWith( QLatin1String( "hasgeometry" ), Qt::CaseInsensitive ) )
3300 {
3301 types << static_cast< int >( Qgis::ProcessingSourceType::VectorAnyGeometry );
3302 def = def.mid( 12 );
3303 continue;
3304 }
3305 else if ( def.startsWith( QLatin1String( "point" ), Qt::CaseInsensitive ) )
3306 {
3307 types << static_cast< int >( Qgis::ProcessingSourceType::VectorPoint );
3308 def = def.mid( 6 );
3309 continue;
3310 }
3311 else if ( def.startsWith( QLatin1String( "line" ), Qt::CaseInsensitive ) )
3312 {
3313 types << static_cast< int >( Qgis::ProcessingSourceType::VectorLine );
3314 def = def.mid( 5 );
3315 continue;
3316 }
3317 else if ( def.startsWith( QLatin1String( "polygon" ), Qt::CaseInsensitive ) )
3318 {
3319 types << static_cast< int >( Qgis::ProcessingSourceType::VectorPolygon );
3320 def = def.mid( 8 );
3321 continue;
3322 }
3323 else if ( def.startsWith( QLatin1String( "raster" ), Qt::CaseInsensitive ) )
3324 {
3325 types << static_cast< int >( Qgis::ProcessingSourceType::Raster );
3326 def = def.mid( 7 );
3327 continue;
3328 }
3329 else if ( def.startsWith( QLatin1String( "mesh" ), Qt::CaseInsensitive ) )
3330 {
3331 types << static_cast< int >( Qgis::ProcessingSourceType::Mesh );
3332 def = def.mid( 5 );
3333 continue;
3334 }
3335 else if ( def.startsWith( QLatin1String( "plugin" ), Qt::CaseInsensitive ) )
3336 {
3337 types << static_cast< int >( Qgis::ProcessingSourceType::Plugin );
3338 def = def.mid( 7 );
3339 continue;
3340 }
3341 else if ( def.startsWith( QLatin1String( "pointcloud" ), Qt::CaseInsensitive ) )
3342 {
3343 types << static_cast< int >( Qgis::ProcessingSourceType::PointCloud );
3344 def = def.mid( 11 );
3345 continue;
3346 }
3347 else if ( def.startsWith( QLatin1String( "annotation" ), Qt::CaseInsensitive ) )
3348 {
3349 types << static_cast< int >( Qgis::ProcessingSourceType::Annotation );
3350 def = def.mid( 11 );
3351 continue;
3352 }
3353 break;
3354 }
3355
3356 return new QgsProcessingParameterMapLayer( name, description, def.isEmpty() ? QVariant() : def, isOptional, types );
3357}
3358
3360{
3361 switch ( outputType )
3362 {
3364 {
3365 QString code = QStringLiteral( "QgsProcessingParameterMapLayer('%1', %2" )
3368 code += QLatin1String( ", optional=True" );
3369
3371 code += QStringLiteral( ", defaultValue=%1" ).arg( valueAsPythonString( mDefault, c ) );
3372
3373 if ( !mDataTypes.empty() )
3374 {
3375 QStringList options;
3376 options.reserve( mDataTypes.size() );
3377 for ( const int t : mDataTypes )
3378 options << QStringLiteral( "QgsProcessing.%1" ).arg( QgsProcessing::sourceTypeToString( static_cast< Qgis::ProcessingSourceType >( t ) ) );
3379 code += QStringLiteral( ", types=[%1])" ).arg( options.join( ',' ) );
3380 }
3381 else
3382 {
3383 code += QLatin1Char( ')' );
3384 }
3385
3386 return code;
3387 }
3388 }
3389 return QString();
3390}
3391
3393{
3395 QVariantList types;
3396 for ( const int type : mDataTypes )
3397 {
3398 types << type;
3399 }
3400 map.insert( QStringLiteral( "data_types" ), types );
3401 return map;
3402}
3403
3405{
3407 mDataTypes.clear();
3408 const QVariantList values = map.value( QStringLiteral( "data_types" ) ).toList();
3409 for ( const QVariant &val : values )
3410 {
3411 mDataTypes << val.toInt();
3412 }
3413 return true;
3414}
3415
3416QgsProcessingParameterExtent::QgsProcessingParameterExtent( const QString &name, const QString &description, const QVariant &defaultValue, bool optional )
3417 : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
3418{
3419
3420}
3421
3423{
3424 return new QgsProcessingParameterExtent( *this );
3425}
3426
3428{
3429 QVariant input = v;
3430 if ( !input.isValid() )
3431 {
3432 if ( !defaultValue().isValid() )
3434
3435 input = defaultValue();
3436 }
3437
3438 if ( input.userType() == QMetaType::type( "QgsProcessingFeatureSourceDefinition" ) )
3439 {
3440 return true;
3441 }
3442 else if ( input.userType() == QMetaType::type( "QgsProcessingOutputLayerDefinition" ) )
3443 {
3444 return true;
3445 }
3446
3447 if ( input.userType() == QMetaType::type( "QgsProperty" ) )
3448 {
3449 return true;
3450 }
3451
3452 if ( input.userType() == QMetaType::type( "QgsRectangle" ) )
3453 {
3454 const QgsRectangle r = input.value<QgsRectangle>();
3455 return !r.isNull();
3456 }
3457 if ( input.userType() == QMetaType::type( "QgsGeometry" ) )
3458 {
3459 return true;
3460 }
3461 if ( input.userType() == QMetaType::type( "QgsReferencedRectangle" ) )
3462 {
3463 const QgsReferencedRectangle r = input.value<QgsReferencedRectangle>();
3464 return !r.isNull();
3465 }
3466
3467 // direct map layer value
3468 if ( qobject_cast< QgsMapLayer * >( qvariant_cast<QObject *>( input ) ) )
3469 return true;
3470
3471 if ( input.type() != QVariant::String || input.toString().isEmpty() )
3473
3474 if ( !context )
3475 {
3476 // that's as far as we can get without a context
3477 return true;
3478 }
3479
3480 const thread_local QRegularExpression rx( QStringLiteral( "^(.*?)\\s*,\\s*(.*?)\\s*,\\s*(.*?)\\s*,\\s*(.*?)\\s*(?:\\[(.*)\\])?\\s*$" ) );
3481 const QRegularExpressionMatch match = rx.match( input.toString() );
3482 if ( match.hasMatch() )
3483 {
3484 bool xMinOk = false;
3485 ( void )match.captured( 1 ).toDouble( &xMinOk );
3486 bool xMaxOk = false;
3487 ( void )match.captured( 2 ).toDouble( &xMaxOk );
3488 bool yMinOk = false;
3489 ( void )match.captured( 3 ).toDouble( &yMinOk );
3490 bool yMaxOk = false;
3491 ( void )match.captured( 4 ).toDouble( &yMaxOk );
3492 if ( xMinOk && xMaxOk && yMinOk && yMaxOk )
3493 return true;
3494 }
3495
3496 // try as layer extent
3497 return QgsProcessingUtils::mapLayerFromString( input.toString(), *context );
3498}
3499
3500QString QgsProcessingParameterExtent::valueAsPythonString( const QVariant &value, QgsProcessingContext &context ) const
3501{
3502 if ( !value.isValid() )
3503 return QStringLiteral( "None" );
3504
3505 if ( value.userType() == QMetaType::type( "QgsProperty" ) )
3506 return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
3507
3508 if ( value.userType() == QMetaType::type( "QgsRectangle" ) )
3509 {
3510 const QgsRectangle r = value.value<QgsRectangle>();
3511 return QStringLiteral( "'%1, %3, %2, %4'" ).arg( qgsDoubleToString( r.xMinimum() ),
3514 qgsDoubleToString( r.yMaximum() ) );
3515 }
3516 else if ( value.userType() == QMetaType::type( "QgsReferencedRectangle" ) )
3517 {
3518 const QgsReferencedRectangle r = value.value<QgsReferencedRectangle>();
3519 return QStringLiteral( "'%1, %3, %2, %4 [%5]'" ).arg( qgsDoubleToString( r.xMinimum() ),
3522 qgsDoubleToString( r.yMaximum() ), r.crs().authid() );
3523 }
3524 else if ( value.userType() == QMetaType::type( "QgsGeometry" ) )
3525 {
3526 const QgsGeometry g = value.value<QgsGeometry>();
3527 if ( !g.isNull() )
3528 {
3529 const QString wkt = g.asWkt();
3530 return QStringLiteral( "QgsGeometry.fromWkt('%1')" ).arg( wkt );
3531 }
3532 }
3533
3534 QVariantMap p;
3535 p.insert( name(), value );
3536 QgsMapLayer *layer = QgsProcessingParameters::parameterAsLayer( this, p, context );
3537 if ( layer )
3539
3541}
3542
3543QString QgsProcessingParameterExtent::valueAsString( const QVariant &value, QgsProcessingContext &context, bool &ok ) const
3544{
3546}
3547
3548QVariant QgsProcessingParameterExtent::valueAsJsonObject( const QVariant &value, QgsProcessingContext &context ) const
3549{
3551}
3552
3553QgsProcessingParameterExtent *QgsProcessingParameterExtent::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
3554{
3555 return new QgsProcessingParameterExtent( name, description, definition, isOptional );
3556}
3557
3558QgsProcessingParameterPoint::QgsProcessingParameterPoint( const QString &name, const QString &description, const QVariant &defaultValue, bool optional )
3559 : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
3560{
3561
3562}
3563
3565{
3566 return new QgsProcessingParameterPoint( *this );
3567}
3568
3570{
3571 QVariant input = v;
3572 if ( !input.isValid() )
3573 {
3574 if ( !defaultValue().isValid() )
3576
3577 input = defaultValue();
3578 }
3579
3580 if ( input.userType() == QMetaType::type( "QgsProperty" ) )
3581 {
3582 return true;
3583 }
3584
3585 if ( input.userType() == QMetaType::type( "QgsPointXY" ) )
3586 {
3587 return true;
3588 }
3589 if ( input.userType() == QMetaType::type( "QgsReferencedPointXY" ) )
3590 {
3591 return true;
3592 }
3593 if ( input.userType() == QMetaType::type( "QgsGeometry" ) )
3594 {
3595 return true;
3596 }
3597
3598 if ( input.type() == QVariant::String )
3599 {
3600 if ( input.toString().isEmpty() )
3602 }
3603
3604 const thread_local QRegularExpression rx( QStringLiteral( "^\\s*\\(?\\s*(.*?)\\s*,\\s*(.*?)\\s*(?:\\[(.*)\\])?\\s*\\)?\\s*$" ) );
3605
3606 const QRegularExpressionMatch match = rx.match( input.toString() );
3607 if ( match.hasMatch() )
3608 {
3609 bool xOk = false;
3610 ( void )match.captured( 1 ).toDouble( &xOk );
3611 bool yOk = false;
3612 ( void )match.captured( 2 ).toDouble( &yOk );
3613 return xOk && yOk;
3614 }
3615 else
3616 return false;
3617}
3618
3619QString QgsProcessingParameterPoint::valueAsPythonString( const QVariant &value, QgsProcessingContext &context ) const
3620{
3621 if ( !value.isValid() )
3622 return QStringLiteral( "None" );
3623
3624 if ( value.userType() == QMetaType::type( "QgsProperty" ) )
3625 return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
3626
3627 if ( value.userType() == QMetaType::type( "QgsPointXY" ) )
3628 {
3629 const QgsPointXY r = value.value<QgsPointXY>();
3630 return QStringLiteral( "'%1,%2'" ).arg( qgsDoubleToString( r.x() ),
3631 qgsDoubleToString( r.y() ) );
3632 }
3633 else if ( value.userType() == QMetaType::type( "QgsReferencedPointXY" ) )
3634 {
3635 const QgsReferencedPointXY r = value.value<QgsReferencedPointXY>();
3636 return QStringLiteral( "'%1,%2 [%3]'" ).arg( qgsDoubleToString( r.x() ),
3637 qgsDoubleToString( r.y() ),
3638 r.crs().authid() );
3639 }
3640 else if ( value.userType() == QMetaType::type( "QgsGeometry" ) )
3641 {
3642 const QgsGeometry g = value.value<QgsGeometry>();
3643 if ( !g.isNull() )
3644 {
3645 const QString wkt = g.asWkt();
3646 return QStringLiteral( "QgsGeometry.fromWkt('%1')" ).arg( wkt );
3647 }
3648 }
3649
3651}
3652
3653QgsProcessingParameterPoint *QgsProcessingParameterPoint::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
3654{
3655 return new QgsProcessingParameterPoint( name, description, definition, isOptional );
3656}
3657
3658QgsProcessingParameterGeometry::QgsProcessingParameterGeometry( const QString &name, const QString &description,
3659 const QVariant &defaultValue, bool optional, const QList<int> &geometryTypes, bool allowMultipart )
3660 : QgsProcessingParameterDefinition( name, description, defaultValue, optional ),
3661 mGeomTypes( geometryTypes ),
3662 mAllowMultipart( allowMultipart )
3663{
3664
3665}
3666
3668{
3669 return new QgsProcessingParameterGeometry( *this );
3670}
3671
3673{
3674 QVariant input = v;
3675 if ( !input.isValid() )
3676 {
3677 if ( !defaultValue().isValid() )
3679
3680 input = defaultValue();
3681 }
3682
3683 if ( input.userType() == QMetaType::type( "QgsProperty" ) )
3684 {
3685 return true;
3686 }
3687
3688 const bool anyTypeAllowed = mGeomTypes.isEmpty() || mGeomTypes.contains( static_cast< int >( Qgis::GeometryType::Unknown ) );
3689
3690 if ( input.userType() == QMetaType::type( "QgsGeometry" ) )
3691 {
3692 return ( anyTypeAllowed || mGeomTypes.contains( static_cast< int >( input.value<QgsGeometry>().type() ) ) ) &&
3693 ( mAllowMultipart || !input.value<QgsGeometry>().isMultipart() );
3694 }
3695
3696 if ( input.userType() == QMetaType::type( "QgsReferencedGeometry" ) )
3697 {
3698 return ( anyTypeAllowed || mGeomTypes.contains( static_cast<int>( input.value<QgsReferencedGeometry>().type() ) ) ) &&
3699 ( mAllowMultipart || !input.value<QgsReferencedGeometry>().isMultipart() );
3700 }
3701
3702 if ( input.userType() == QMetaType::type( "QgsPointXY" ) )
3703 {
3704 return anyTypeAllowed || mGeomTypes.contains( static_cast< int >( Qgis::GeometryType::Point ) );
3705 }
3706
3707 if ( input.userType() == QMetaType::type( "QgsRectangle" ) )
3708 {
3709 return anyTypeAllowed || mGeomTypes.contains( static_cast< int >( Qgis::GeometryType::Polygon ) );
3710 }
3711
3712 if ( input.userType() == QMetaType::type( "QgsReferencedPointXY" ) )
3713 {
3714 return anyTypeAllowed || mGeomTypes.contains( static_cast< int >( Qgis::GeometryType::Point ) );
3715 }
3716
3717 if ( input.userType() == QMetaType::type( "QgsReferencedRectangle" ) )
3718 {
3719 return anyTypeAllowed || mGeomTypes.contains( static_cast< int >( Qgis::GeometryType::Polygon ) );
3720 }
3721
3722 if ( input.type() == QVariant::String )
3723 {
3724 if ( input.toString().isEmpty() )
3726 }
3727
3728 // Match against EWKT
3729 const thread_local QRegularExpression rx( QStringLiteral( "^\\s*(?:CRS=(.*);)?(.*?)$" ) );
3730
3731 const QRegularExpressionMatch match = rx.match( input.toString() );
3732 if ( match.hasMatch() )
3733 {
3734 const QgsGeometry g = QgsGeometry::fromWkt( match.captured( 2 ) );
3735 if ( ! g.isNull() )
3736 {
3737 return ( anyTypeAllowed || mGeomTypes.contains( static_cast< int >( g.type() ) ) ) && ( mAllowMultipart || !g.isMultipart() );
3738 }
3739 else
3740 {
3741 QgsMessageLog::logMessage( QObject::tr( "Error creating geometry: \"%1\"" ).arg( g.lastError() ), QObject::tr( "Processing" ) );
3742 }
3743 }
3744 return false;
3745}
3746
3748{
3750 {
3751 if ( !crs.isValid() )
3753 else
3754 return QgsProcessingUtils::stringToPythonLiteral( QStringLiteral( "CRS=%1;%2" ).arg( crs.authid().isEmpty() ? crs.toWkt( Qgis::CrsWktVariant::Preferred ) : crs.authid(), g.asWkt() ) );
3755 };
3756
3757 if ( !value.isValid() )
3758 return QStringLiteral( "None" );
3759
3760 if ( value.userType() == QMetaType::type( "QgsProperty" ) )
3761 return QStringLiteral( "QgsProperty.fromExpression(%1)" ).arg( QgsProcessingUtils::stringToPythonLiteral( value.value< QgsProperty >().asExpression() ) );
3762
3763 if ( value.userType() == QMetaType::type( "QgsGeometry" ) )
3764 {
3765 const QgsGeometry g = value.value<QgsGeometry>();
3766 if ( !g.isNull() )
3767 return asPythonString( g );
3768 }
3769
3770 if ( value.userType() == QMetaType::type( "QgsReferencedGeometry" ) )
3771 {
3772 const QgsReferencedGeometry g = value.value<QgsReferencedGeometry>();
3773 if ( !g.isNull() )
3774 return asPythonString( g, g.crs() );
3775 }
3776
3777 if ( value.userType() == QMetaType::type( "QgsPointXY" ) )
3778 {
3779 const QgsGeometry g = QgsGeometry::fromPointXY( value.value<QgsPointXY>() );
3780 if ( !g.isNull() )
3781 return asPythonString( g );
3782 }
3783
3784 if ( value.userType() == QMetaType::type( "QgsReferencedPointXY" ) )
3785 {
3787 if ( !g.isNull() )
3788 return asPythonString( g, g.crs() );
3789 }
3790
3791 if ( value.userType() == QMetaType::type( "QgsRectangle" ) )
3792 {
3793 const QgsGeometry g = QgsGeometry::fromRect( value.value<QgsRectangle>() );
3794 if ( !g.isNull() )
3795 return asPythonString( g );
3796 }
3797
3798 if ( value.userType() == QMetaType::type( "QgsReferencedRectangle" ) )
3799 {
3801 if ( !g.isNull() )
3802 return asPythonString( g, g.crs() );
3803 }
3804
3806}
3807
3809{
3810 QString code = QStringLiteral( "##%1=" ).arg( mName );
3812 code += QLatin1String( "optional " );
3813 code += type() + ' ';
3814
3815 for ( const int type : mGeomTypes )
3816 {
3817 switch ( static_cast<Qgis::GeometryType>( type ) )
3818 {
3820 code += QLatin1String( "point " );
3821 break;
3822
3824 code += QLatin1String( "line " );
3825 break;
3826
3828 code += QLatin1String( "polygon " );
3829 break;
3830
3831 default:
3832 code += QLatin1String( "unknown " );
3833 break;
3834 }
3835 }
3836
3837 code += mDefault.toString();
3838 return code.trimmed();
3839}
3840
3842{
3843 switch ( outputType )
3844 {
3846 {
3847 QString code = QStringLiteral( "QgsProcessingParameterGeometry('%1', %2" )
3850 code += QLatin1String( ", optional=True" );
3851
3852 if ( !mGeomTypes.empty() )
3853 {
3854 auto geomTypeToString = []( Qgis::GeometryType t ) -> QString
3855 {
3856 switch ( t )
3857 {
3859 return QStringLiteral( "PointGeometry" );
3860
3862 return QStringLiteral( "LineGeometry" );
3863
3865 return QStringLiteral( "PolygonGeometry" );
3866
3868 return QStringLiteral( "UnknownGeometry" );
3869
3871 return QStringLiteral( "NullGeometry" );
3872 }
3873 return QString();
3874 };
3875
3876 QStringList options;
3877 options.reserve( mGeomTypes.size() );
3878 for ( const int type : mGeomTypes )
3879 {
3880 options << QStringLiteral( " QgsWkbTypes.%1" ).arg( geomTypeToString( static_cast<Qgis::GeometryType>( type ) ) );
3881 }
3882 code += QStringLiteral( ", geometryTypes=[%1 ]" ).arg( options.join( ',' ) );
3883 }
3884
3885 if ( ! mAllowMultipart )
3886 {
3887 code += QLatin1String( ", allowMultipart=False" );
3888 }
3889
3891 code += QStringLiteral( ", defaultValue=%1)" ).arg( valueAsPythonString( mDefault, c ) );
3892 return code;
3893 }
3894 }
3895 return QString();
3896}
3897
3899{
3901 QVariantList types;
3902 for ( const int type : mGeomTypes )
3903 {
3904 types << type;
3905 }
3906 map.insert( QStringLiteral( "geometrytypes" ), types );
3907 map.insert( QStringLiteral( "multipart" ), mAllowMultipart );
3908 return map;
3909}
3910
3912{
3914 mGeomTypes.clear();
3915 const QVariantList values = map.value( QStringLiteral( "geometrytypes" ) ).toList();
3916 for ( const QVariant &val : values )
3917 {
3918 mGeomTypes << val.toInt();
3919 }
3920 mAllowMultipart = map.value( QStringLiteral( "multipart" ) ).toBool();
3921 return true;
3922}
3923
3924QgsProcessingParameterGeometry *QgsProcessingParameterGeometry::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
3925{
3926 return new QgsProcessingParameterGeometry( name, description, definition, isOptional );
3927}
3928
3929QgsProcessingParameterFile::QgsProcessingParameterFile( const QString &name, const QString &description, Qgis::ProcessingFileParameterBehavior behavior, const QString &extension, const QVariant &defaultValue, bool optional, const QString &fileFilter )
3930 : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
3931 , mBehavior( behavior )
3932 , mExtension( fileFilter.isEmpty() ? extension : QString() )
3933 , mFileFilter( fileFilter.isEmpty() && extension.isEmpty() ? QObject::tr( "All files (*.*)" ) : fileFilter )
3934{
3935
3936}
3937
3939{
3940 return new QgsProcessingParameterFile( *this );
3941}
3942
3944{
3945 QVariant input = v;
3946 if ( !input.isValid() )
3947 {
3948 if ( !defaultValue().isValid() )
3950
3951 input = defaultValue();
3952 }
3953
3954 if ( input.userType() == QMetaType::type( "QgsProperty" ) )
3955 {
3956 return true;
3957 }
3958
3959 const QString string = input.toString().trimmed();
3960
3961 if ( input.type() != QVariant::String || string.isEmpty() )
3963
3964 switch ( mBehavior )
3965 {
3967 {
3968 if ( !mExtension.isEmpty() )
3969 {
3970 return string.endsWith( mExtension, Qt::CaseInsensitive );
3971 }
3972 else if ( !mFileFilter.isEmpty() )
3973 {
3974 return QgsFileUtils::fileMatchesFilter( string, mFileFilter );
3975 }
3976 else
3977 {
3978 return true;
3979 }
3980 }
3981
3983 return true;
3984 }
3985 return true;
3986}
3987
3989{
3990 QString code = QStringLiteral( "##%1=" ).arg( mName );
3992 code += QLatin1String( "optional " );
3993 code += ( mBehavior == Qgis::ProcessingFileParameterBehavior::File ? QStringLiteral( "file" ) : QStringLiteral( "folder" ) ) + ' ';
3994 code += mDefault.toString();
3995 return code.trimmed();
3996}
3997
3999{
4000 switch ( outputType )
4001 {
4003 {
4004
4005 QString code = QStringLiteral( "QgsProcessingParameterFile('%1', %2" )
4008 code += QLatin1String( ", optional=True" );
4009 code += QStringLiteral( ", behavior=%1" ).arg( mBehavior == Qgis::ProcessingFileParameterBehavior::File ? QStringLiteral( "QgsProcessingParameterFile.File" ) : QStringLiteral( "QgsProcessingParameterFile.Folder" ) );
4010 if ( !mExtension.isEmpty() )
4011 code += QStringLiteral( ", extension='%1'" ).arg( mExtension );
4012 if ( !mFileFilter.isEmpty() )
4013 code += QStringLiteral( ", fileFilter='%1'" ).arg( mFileFilter );
4015 code += QStringLiteral( ", defaultValue=%1)" ).arg( valueAsPythonString( mDefault, c ) );
4016 return code;
4017 }
4018 }
4019 return QString();
4020}
4021
4023{
4024 switch ( mBehavior )
4025 {
4027 {
4028 if ( !mFileFilter.isEmpty() )
4029 return mFileFilter != QObject::tr( "All files (*.*)" ) ? mFileFilter + QStringLiteral( ";;" ) + QObject::tr( "All files (*.*)" ) : mFileFilter;
4030 else if ( !mExtension.isEmpty() )
4031 return QObject::tr( "%1 files" ).arg( mExtension.toUpper() ) + QStringLiteral( " (*." ) + mExtension.toLower() + QStringLiteral( ");;" ) + QObject::tr( "All files (*.*)" );
4032 else
4033 return QObject::tr( "All files (*.*)" );
4034 }
4035
4037 return QString();
4038 }
4039 return QString();
4040}
4041
4042void QgsProcessingParameterFile::setExtension( const QString &extension )
4043{
4044 mExtension = extension;
4045 mFileFilter.clear();
4046}
4047
4049{
4050 return mFileFilter;
4051}
4052
4054{
4055 mFileFilter = filter;
4056 mExtension.clear();
4057}
4058
4060{
4062 map.insert( QStringLiteral( "behavior" ), static_cast< int >( mBehavior ) );
4063 map.insert( QStringLiteral( "extension" ), mExtension );
4064 map.insert( QStringLiteral( "filefilter" ), mFileFilter );
4065 return map;
4066}
4067
4069{
4071 mBehavior = static_cast< Qgis::ProcessingFileParameterBehavior >( map.value( QStringLiteral( "behavior" ) ).toInt() );
4072 mExtension = map.value( QStringLiteral( "extension" ) ).toString();
4073 mFileFilter = map.value( QStringLiteral( "filefilter" ) ).toString();
4074 return true;
4075}
4076
4077QgsProcessingParameterFile *QgsProcessingParameterFile::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition, Qgis::ProcessingFileParameterBehavior behavior )
4078{
4079 return new QgsProcessingParameterFile( name, description, behavior, QString(), definition, isOptional );
4080}
4081
4082QgsProcessingParameterMatrix::QgsProcessingParameterMatrix( const QString &name, const QString &description, int numberRows, bool fixedNumberRows, const QStringList &headers, const QVariant &defaultValue, bool optional )
4083 : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
4084 , mHeaders( headers )
4085 , mNumberRows( numberRows )
4086 , mFixedNumberRows( fixedNumberRows )
4087{
4088
4089}
4090
4092{
4093 return new QgsProcessingParameterMatrix( *this );
4094}
4095
4097{
4098 QVariant input = v;
4099 if ( !input.isValid() )
4100 {
4101 if ( !defaultValue().isValid() )
4103
4104 input = defaultValue();
4105 }
4106
4107 if ( input.type() == QVariant::String )
4108 {
4109 if ( input.toString().isEmpty() )
4111 return true;
4112 }
4113 else if ( input.type() == QVariant::List )
4114 {
4115 if ( input.toList().isEmpty() )
4117 return true;
4118 }
4119 else if ( input.type() == QVariant::Double || input.type() == QVariant::Int )
4120 {
4121 return true;
4122 }
4123
4124 return false;
4125}
4126
4127QString QgsProcessingParameterMatrix::valueAsPythonString( const QVariant &value, QgsProcessingContext &context ) const
4128{
4129 if ( !value.isValid() )
4130 return QStringLiteral( "None" );
4131
4132 if ( value.userType() == QMetaType::type( "QgsProperty" ) )
4133 return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
4134
4135 QVariantMap p;
4136 p.insert( name(), value );
4137 const QVariantList list = QgsProcessingParameters::parameterAsMatrix( this, p, context );
4138
4140}
4141
4143{
4144 switch ( outputType )
4145 {
4147 {
4148 QString code = QStringLiteral( "QgsProcessingParameterMatrix('%1', %2" )
4151 code += QLatin1String( ", optional=True" );
4152 code += QStringLiteral( ", numberRows=%1" ).arg( mNumberRows );
4153 code += QStringLiteral( ", hasFixedNumberRows=%1" ).arg( mFixedNumberRows ? QStringLiteral( "True" ) : QStringLiteral( "False" ) );
4154
4155 QStringList headers;
4156 headers.reserve( mHeaders.size() );
4157 for ( const QString &h : mHeaders )
4159 code += QStringLiteral( ", headers=[%1]" ).arg( headers.join( ',' ) );
4160
4162 code += QStringLiteral( ", defaultValue=%1)" ).arg( valueAsPythonString( mDefault, c ) );
4163 return code;
4164 }
4165 }
4166 return QString();
4167}
4168
4170{
4171 return mHeaders;
4172}
4173
4174void QgsProcessingParameterMatrix::setHeaders( const QStringList &headers )
4175{
4176 mHeaders = headers;
4177}
4178
4180{
4181 return mNumberRows;
4182}
4183
4185{
4186 mNumberRows = numberRows;
4187}
4188
4190{
4191 return mFixedNumberRows;
4192}
4193
4195{
4196 mFixedNumberRows = fixedNumberRows;
4197}
4198
4200{
4202 map.insert( QStringLiteral( "headers" ), mHeaders );
4203 map.insert( QStringLiteral( "rows" ), mNumberRows );
4204 map.insert( QStringLiteral( "fixed_number_rows" ), mFixedNumberRows );
4205 return map;
4206}
4207
4209{
4211 mHeaders = map.value( QStringLiteral( "headers" ) ).toStringList();
4212 mNumberRows = map.value( QStringLiteral( "rows" ) ).toInt();
4213 mFixedNumberRows = map.value( QStringLiteral( "fixed_number_rows" ) ).toBool();
4214 return true;
4215}
4216
4217QgsProcessingParameterMatrix *QgsProcessingParameterMatrix::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
4218{
4219 return new QgsProcessingParameterMatrix( name, description, 0, false, QStringList(), definition.isEmpty() ? QVariant() : definition, isOptional );
4220}
4221
4222QgsProcessingParameterMultipleLayers::QgsProcessingParameterMultipleLayers( const QString &name, const QString &description, Qgis::ProcessingSourceType layerType, const QVariant &defaultValue, bool optional )
4223 : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
4224 , mLayerType( layerType )
4225{
4226
4227}
4228
4230{
4231 return new QgsProcessingParameterMultipleLayers( *this );
4232}
4233
4235{
4236 QVariant input = v;
4237 if ( !input.isValid() )
4238 {
4239 if ( !defaultValue().isValid() )
4241
4242 input = defaultValue();
4243 }
4244
4245 if ( mLayerType != Qgis::ProcessingSourceType::File )
4246 {
4247 if ( qobject_cast< QgsMapLayer * >( qvariant_cast<QObject *>( input ) ) )
4248 {
4249 return true;
4250 }
4251 }
4252
4253 if ( input.type() == QVariant::String )
4254 {
4255 if ( input.toString().isEmpty() )
4257
4258 if ( mMinimumNumberInputs > 1 )
4259 return false;
4260
4261 if ( !context )
4262 return true;
4263
4264 if ( mLayerType != Qgis::ProcessingSourceType::File )
4266 else
4267 return true;
4268 }
4269 else if ( input.type() == QVariant::List )
4270 {
4271 if ( input.toList().count() < mMinimumNumberInputs )
4273
4274 if ( mMinimumNumberInputs > input.toList().count() )
4275 return false;
4276
4277 if ( !context )
4278 return true;
4279
4280 if ( mLayerType != Qgis::ProcessingSourceType::File )
4281 {
4282 const auto constToList = input.toList();
4283 for ( const QVariant &v : constToList )
4284 {
4285 if ( qobject_cast< QgsMapLayer * >( qvariant_cast<QObject *>( v ) ) )
4286 continue;
4287
4289 return false;
4290 }
4291 }
4292 return true;
4293 }
4294 else if ( input.type() == QVariant::StringList )
4295 {
4296 if ( input.toStringList().count() < mMinimumNumberInputs )
4298
4299 if ( mMinimumNumberInputs > input.toStringList().count() )
4300 return false;
4301
4302 if ( !context )
4303 return true;
4304
4305 if ( mLayerType != Qgis::ProcessingSourceType::File )
4306 {
4307 const auto constToStringList = input.toStringList();
4308 for ( const QString &v : constToStringList )
4309 {
4311 return false;
4312 }
4313 }
4314 return true;
4315 }
4316 return false;
4317}
4318
4320{
4321 if ( !value.isValid() )
4322 return QStringLiteral( "None" );
4323
4324 if ( value.userType() == QMetaType::type( "QgsProperty" ) )
4325 return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
4326
4327 if ( mLayerType == Qgis::ProcessingSourceType::File )
4328 {
4329 QStringList parts;
4330 if ( value.type() == QVariant::StringList )
4331 {
4332 const QStringList list = value.toStringList();
4333 parts.reserve( list.count() );
4334 for ( const QString &v : list )
4336 }
4337 else if ( value.type() == QVariant::List )
4338 {
4339 const QVariantList list = value.toList();
4340 parts.reserve( list.count() );
4341 for ( const QVariant &v : list )
4342 parts << QgsProcessingUtils::stringToPythonLiteral( v.toString() );
4343 }
4344 if ( !parts.isEmpty() )
4345 return parts.join( ',' ).prepend( '[' ).append( ']' );
4346 }
4347 else
4348 {
4349 QVariantMap p;
4350 p.insert( name(), value );
4352 if ( !list.isEmpty() )
4353 {
4354 QStringList parts;
4355 parts.reserve( list.count() );
4356 for ( const QgsMapLayer *layer : list )
4357 {
4359 }
4360 return parts.join( ',' ).prepend( '[' ).append( ']' );
4361 }
4362 }
4363
4365}
4366
4367QString QgsProcessingParameterMultipleLayers::valueAsString( const QVariant &value, QgsProcessingContext &context, bool &ok ) const
4368{
4370}
4371
4373{
4375}
4376
4378{
4379 QString code = QStringLiteral( "##%1=" ).arg( mName );
4381 code += QLatin1String( "optional " );
4382 switch ( mLayerType )
4383 {
4385 code += QLatin1String( "multiple raster" );
4386 break;
4387
4389 code += QLatin1String( "multiple file" );
4390 break;
4391
4392 default:
4393 code += QLatin1String( "multiple vector" );
4394 break;
4395 }
4396 code += ' ';
4397 if ( mDefault.type() == QVariant::List )
4398 {
4399 QStringList parts;
4400 const auto constToList = mDefault.toList();
4401 for ( const QVariant &var : constToList )
4402 {
4403 parts << var.toString();
4404 }
4405 code += parts.join( ',' );
4406 }
4407 else if ( mDefault.type() == QVariant::StringList )
4408 {
4409 code += mDefault.toStringList().join( ',' );
4410 }
4411 else
4412 {
4413 code += mDefault.toString();
4414 }
4415 return code.trimmed();
4416}
4417
4419{
4420 switch ( outputType )
4421 {
4423 {
4424 QString code = QStringLiteral( "QgsProcessingParameterMultipleLayers('%1', %2" )
4427 code += QLatin1String( ", optional=True" );
4428
4429 const QString layerType = QStringLiteral( "QgsProcessing.%1" ).arg( QgsProcessing::sourceTypeToString( mLayerType ) );
4430
4431 code += QStringLiteral( ", layerType=%1" ).arg( layerType );
4433 code += QStringLiteral( ", defaultValue=%1)" ).arg( valueAsPythonString( mDefault, c ) );
4434 return code;
4435 }
4436 }
4437 return QString();
4438}
4439
4441{
4442 switch ( mLayerType )
4443 {
4445 return QObject::tr( "All files (*.*)" );
4446
4448 return QgsProviderRegistry::instance()->fileRasterFilters() + QStringLiteral( ";;" ) + QObject::tr( "All files (*.*)" );
4449
4455 return QgsProviderRegistry::instance()->fileVectorFilters() + QStringLiteral( ";;" ) + QObject::tr( "All files (*.*)" );
4456
4458 return QgsProviderRegistry::instance()->fileMeshFilters() + QStringLiteral( ";;" ) + QObject::tr( "All files (*.*)" );
4459
4461 return QgsProviderRegistry::instance()->filePointCloudFilters() + QStringLiteral( ";;" ) + QObject::tr( "All files (*.*)" );
4462
4468 }
4469 return QString();
4470}
4471
4473{
4474 return mLayerType;
4475}
4476
4478{
4479 mLayerType = type;
4480}
4481
4483{
4484 return mMinimumNumberInputs;
4485}
4486
4488{
4489 if ( mMinimumNumberInputs >= 1 || !( flags() & Qgis::ProcessingParameterFlag::Optional ) )
4490 mMinimumNumberInputs = minimumNumberInputs;
4491}
4492
4494{
4496 map.insert( QStringLiteral( "layer_type" ), static_cast< int >( mLayerType ) );
4497 map.insert( QStringLiteral( "min_inputs" ), mMinimumNumberInputs );
4498 return map;
4499}
4500
4502{
4504 mLayerType = static_cast< Qgis::ProcessingSourceType >( map.value( QStringLiteral( "layer_type" ) ).toInt() );
4505 mMinimumNumberInputs = map.value( QStringLiteral( "min_inputs" ) ).toInt();
4506 return true;
4507}
4508
4509QgsProcessingParameterMultipleLayers *QgsProcessingParameterMultipleLayers::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
4510{
4511 QString type = definition;
4512 QString defaultVal;
4513 const thread_local QRegularExpression re( QStringLiteral( "(.*?)\\s+(.*)" ) );
4514 const QRegularExpressionMatch m = re.match( definition );
4515 if ( m.hasMatch() )
4516 {
4517 type = m.captured( 1 ).toLower().trimmed();
4518 defaultVal = m.captured( 2 );
4519 }
4521 if ( type == QLatin1String( "vector" ) )
4523 else if ( type == QLatin1String( "raster" ) )
4525 else if ( type == QLatin1String( "file" ) )
4527 return new QgsProcessingParameterMultipleLayers( name, description, layerType, defaultVal.isEmpty() ? QVariant() : defaultVal, isOptional );
4528}
4529
4530QgsProcessingParameterNumber::QgsProcessingParameterNumber( const QString &name, const QString &description, Qgis::ProcessingNumberParameterType type, const QVariant &defaultValue, bool optional, double minValue, double maxValue )
4531 : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
4532 , mMin( minValue )
4533 , mMax( maxValue )
4534 , mDataType( type )
4535{
4536 if ( mMin >= mMax )
4537 {
4538 QgsMessageLog::logMessage( QObject::tr( "Invalid number parameter \"%1\": min value %2 is >= max value %3!" ).arg( name ).arg( mMin ).arg( mMax ), QObject::tr( "Processing" ) );
4539 }
4540}
4541
4543{
4544 return new QgsProcessingParameterNumber( *this );
4545}
4546
4548{
4549 QVariant input = value;
4550 if ( !input.isValid() )
4551 {
4552 if ( !defaultValue().isValid() )
4554
4555 input = defaultValue();
4556 }
4557
4558 if ( input.userType() == QMetaType::type( "QgsProperty" ) )
4559 {
4560 return true;
4561 }
4562
4563 bool ok = false;
4564 const double res = input.toDouble( &ok );
4565 if ( !ok )
4567
4568 return !( res < mMin || res > mMax );
4569}
4570
4572{
4573 if ( !value.isValid() )
4574 return QStringLiteral( "None" );
4575
4576 if ( value.userType() == QMetaType::type( "QgsProperty" ) )
4577 return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
4578
4579 return value.toString();
4580}
4581
4583{
4585 QStringList parts;
4586 if ( mMin > std::numeric_limits<double>::lowest() + 1 )
4587 parts << QObject::tr( "Minimum value: %1" ).arg( mMin );
4588 if ( mMax < std::numeric_limits<double>::max() )
4589 parts << QObject::tr( "Maximum value: %1" ).arg( mMax );
4590 if ( mDefault.isValid() )
4591 parts << QObject::tr( "Default value: %1" ).arg( mDataType == Qgis::ProcessingNumberParameterType::Integer ? mDefault.toInt() : mDefault.toDouble() );
4592 const QString extra = parts.join( QLatin1String( "<br />" ) );
4593 if ( !extra.isEmpty() )
4594 text += QStringLiteral( "<p>%1</p>" ).arg( extra );
4595 return text;
4596}
4597
4599{
4600 switch ( outputType )
4601 {
4603 {
4604 QString code = QStringLiteral( "QgsProcessingParameterNumber('%1', %2" )
4607 code += QLatin1String( ", optional=True" );
4608
4609 code += QStringLiteral( ", type=%1" ).arg( mDataType == Qgis::ProcessingNumberParameterType::Integer ? QStringLiteral( "QgsProcessingParameterNumber.Integer" ) : QStringLiteral( "QgsProcessingParameterNumber.Double" ) );
4610
4611 if ( mMin != std::numeric_limits<double>::lowest() + 1 )
4612 code += QStringLiteral( ", minValue=%1" ).arg( mMin );
4613 if ( mMax != std::numeric_limits<double>::max() )
4614 code += QStringLiteral( ", maxValue=%1" ).arg( mMax );
4616 code += QStringLiteral( ", defaultValue=%1)" ).arg( valueAsPythonString( mDefault, c ) );
4617 return code;
4618 }
4619 }
4620 return QString();
4621}
4622
4624{
4625 return mMin;
4626}
4627
4629{
4630 mMin = min;
4631}
4632
4634{
4635 return mMax;
4636}
4637
4639{
4640 mMax = max;
4641}
4642
4644{
4645 return mDataType;
4646}
4647
4649{
4650 mDataType = dataType;
4651}
4652
4654{
4656 map.insert( QStringLiteral( "min" ), mMin );
4657 map.insert( QStringLiteral( "max" ), mMax );
4658 map.insert( QStringLiteral( "data_type" ), static_cast< int >( mDataType ) );
4659 return map;
4660}
4661
4663{
4665 mMin = map.value( QStringLiteral( "min" ) ).toDouble();
4666 mMax = map.value( QStringLiteral( "max" ) ).toDouble();
4667 mDataType = static_cast< Qgis::ProcessingNumberParameterType >( map.value( QStringLiteral( "data_type" ) ).toInt() );
4668 return true;
4669}
4670
4671QgsProcessingParameterNumber *QgsProcessingParameterNumber::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
4672{
4673 return new QgsProcessingParameterNumber( name, description, Qgis::ProcessingNumberParameterType::Double, definition.isEmpty() ? QVariant()
4674 : ( definition.toLower().trimmed() == QLatin1String( "none" ) ? QVariant() : definition ), isOptional );
4675}
4676
4677QgsProcessingParameterRange::QgsProcessingParameterRange( const QString &name, const QString &description, Qgis::ProcessingNumberParameterType type, const QVariant &defaultValue, bool optional )
4678 : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
4679 , mDataType( type )
4680{
4681
4682}
4683
4685{
4686 return new QgsProcessingParameterRange( *this );
4687}
4688
4690{
4691 QVariant input = v;
4692 if ( !input.isValid() )
4693 {
4694 if ( !defaultValue().isValid() )
4696
4697 input = defaultValue();
4698 }
4699
4700 if ( input.userType() == QMetaType::type( "QgsProperty" ) )
4701 {
4702 return true;
4703 }
4704
4705 if ( input.type() == QVariant::String )
4706 {
4707 const QStringList list = input.toString().split( ',' );
4708 if ( list.count() != 2 )
4710 bool ok = false;
4711 list.at( 0 ).toDouble( &ok );
4712 bool ok2 = false;
4713 list.at( 1 ).toDouble( &ok2 );
4714 if ( !ok || !ok2 )
4716 return true;
4717 }
4718 else if ( input.type() == QVariant::List )
4719 {
4720 if ( input.toList().count() != 2 )
4722
4723 bool ok = false;
4724 input.toList().at( 0 ).toDouble( &ok );
4725 bool ok2 = false;
4726 input.toList().at( 1 ).toDouble( &ok2 );
4727 if ( !ok || !ok2 )
4729 return true;
4730 }
4731
4732 return false;
4733}
4734
4735QString QgsProcessingParameterRange::valueAsPythonString( const QVariant &value, QgsProcessingContext &context ) const
4736{
4737 if ( !value.isValid() )
4738 return QStringLiteral( "None" );
4739
4740 if ( value.userType() == QMetaType::type( "QgsProperty" ) )
4741 return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
4742
4743 QVariantMap p;
4744 p.insert( name(), value );
4745 const QList< double > parts = QgsProcessingParameters::parameterAsRange( this, p, context );
4746
4747 QStringList stringParts;
4748 const auto constParts = parts;
4749 for ( const double v : constParts )
4750 {
4751 stringParts << QString::number( v );
4752 }
4753 return stringParts.join( ',' ).prepend( '[' ).append( ']' );
4754}
4755
4757{
4758 switch ( outputType )
4759 {
4761 {
4762 QString code = QStringLiteral( "QgsProcessingParameterRange('%1', %2" )
4765 code += QLatin1String( ", optional=True" );
4766
4767 code += QStringLiteral( ", type=%1" ).arg( mDataType == Qgis::ProcessingNumberParameterType::Integer ? QStringLiteral( "QgsProcessingParameterNumber.Integer" ) : QStringLiteral( "QgsProcessingParameterNumber.Double" ) );
4768
4770 code += QStringLiteral( ", defaultValue=%1)" ).arg( valueAsPythonString( mDefault, c ) );
4771 return code;
4772 }
4773 }
4774 return QString();
4775}
4776
4778{
4779 return mDataType;
4780}
4781
4783{
4784 mDataType = dataType;
4785}
4786
4788{
4790 map.insert( QStringLiteral( "data_type" ), static_cast< int >( mDataType ) );
4791 return map;
4792}
4793
4795{
4797 mDataType = static_cast< Qgis::ProcessingNumberParameterType >( map.value( QStringLiteral( "data_type" ) ).toInt() );
4798 return true;
4799}
4800
4801QgsProcessingParameterRange *QgsProcessingParameterRange::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
4802{
4803 return new QgsProcessingParameterRange( name, description, Qgis::ProcessingNumberParameterType::Double, definition.isEmpty() ? QVariant()
4804 : ( definition.toLower().trimmed() == QLatin1String( "none" ) ? QVariant() : definition ), isOptional );
4805}
4806
4807QgsProcessingParameterRasterLayer::QgsProcessingParameterRasterLayer( const QString &name, const QString &description, const QVariant &defaultValue, bool optional )
4808 : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
4809{
4810
4811}
4812
4814{
4815 return new QgsProcessingParameterRasterLayer( *this );
4816}
4817
4819{
4820 QVariant input = v;
4821 if ( !input.isValid() )
4822 {
4823 if ( !defaultValue().isValid() )
4825
4826 input = defaultValue();
4827 }
4828
4829 if ( input.userType() == QMetaType::type( "QgsProperty" ) )
4830 {
4831 return true;
4832 }
4833
4834 if ( qobject_cast< QgsRasterLayer * >( qvariant_cast<QObject *>( input ) ) )
4835 return true;
4836
4837 if ( input.type() != QVariant::String || input.toString().isEmpty() )
4839
4840 if ( !context )
4841 {
4842 // that's as far as we can get without a context
4843 return true;
4844 }
4845
4846 // try to load as layer
4847 if ( QgsProcessingUtils::mapLayerFromString( input.toString(), *context, true, QgsProcessingUtils::LayerHint::Raster ) )
4848 return true;
4849
4850 return false;
4851}
4852
4854{
4855 if ( !val.isValid() )
4856 return QStringLiteral( "None" );
4857
4858 if ( val.userType() == QMetaType::type( "QgsProperty" ) )
4859 return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( val.value< QgsProperty >().asExpression() );
4860
4861 QVariantMap p;
4862 p.insert( name(), val );
4866}
4867
4868QString QgsProcessingParameterRasterLayer::valueAsString( const QVariant &value, QgsProcessingContext &context, bool &ok ) const
4869{
4871}
4872
4874{
4876}
4877
4879{
4880 return QgsProviderRegistry::instance()->fileRasterFilters() + QStringLiteral( ";;" ) + QObject::tr( "All files (*.*)" );
4881}
4882
4883QgsProcessingParameterRasterLayer *QgsProcessingParameterRasterLayer::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
4884{
4885 return new QgsProcessingParameterRasterLayer( name, description, definition.isEmpty() ? QVariant() : definition, isOptional );
4886}
4887
4888QgsProcessingParameterEnum::QgsProcessingParameterEnum( const QString &name, const QString &description, const QStringList &options, bool allowMultiple, const QVariant &defaultValue, bool optional, bool usesStaticStrings )
4889 : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
4890 , mOptions( options )
4891 , mAllowMultiple( allowMultiple )
4892 , mUsesStaticStrings( usesStaticStrings )
4893{
4894
4895}
4896
4898{
4899 return new QgsProcessingParameterEnum( *this );
4900}
4901
4903{
4904 QVariant input = value;
4905 if ( !input.isValid() )
4906 {
4907 if ( !defaultValue().isValid() )
4909
4910 input = defaultValue();
4911 }
4912
4913 if ( input.userType() == QMetaType::type( "QgsProperty" ) )
4914 {
4915 return true;
4916 }
4917
4918 if ( mUsesStaticStrings )
4919 {
4920 if ( input.type() == QVariant::List )
4921 {
4922 if ( !mAllowMultiple )
4923 return false;
4924
4925 const QVariantList values = input.toList();
4926 if ( values.empty() && !( mFlags & Qgis::ProcessingParameterFlag::Optional ) )
4927 return false;
4928
4929 for ( const QVariant &val : values )
4930 {
4931 if ( !mOptions.contains( val.toString() ) )
4932 return false;
4933 }
4934
4935 return true;
4936 }
4937 else if ( input.type() == QVariant::StringList )
4938 {
4939 if ( !mAllowMultiple )
4940 return false;
4941
4942 const QStringList values = input.toStringList();
4943
4944 if ( values.empty() && !( mFlags & Qgis::ProcessingParameterFlag::Optional ) )
4945 return false;
4946
4947 if ( values.count() > 1 && !mAllowMultiple )
4948 return false;
4949
4950 for ( const QString &val : values )
4951 {
4952 if ( !mOptions.contains( val ) )
4953 return false;
4954 }
4955 return true;
4956 }
4957 else if ( input.type() == QVariant::String )
4958 {
4959 const QStringList parts = input.toString().split( ',' );
4960 if ( parts.count() > 1 && !mAllowMultiple )
4961 return false;
4962
4963 const auto constParts = parts;
4964 for ( const QString &part : constParts )
4965 {
4966 if ( !mOptions.contains( part ) )
4967 return false;
4968 }
4969 return true;
4970 }
4971 }
4972 else
4973 {
4974 if ( input.type() == QVariant::List )
4975 {
4976 if ( !mAllowMultiple )
4977 return false;
4978
4979 const QVariantList values = input.toList();
4980 if ( values.empty() && !( mFlags & Qgis::ProcessingParameterFlag::Optional ) )
4981 return false;
4982
4983 for ( const QVariant &val : values )
4984 {
4985 bool ok = false;
4986 const int res = val.toInt( &ok );
4987 if ( !ok )
4988 return false;
4989 else if ( res < 0 || res >= mOptions.count() )
4990 return false;
4991 }
4992
4993 return true;
4994 }
4995 else if ( input.type() == QVariant::String )
4996 {
4997 const QStringList parts = input.toString().split( ',' );
4998 if ( parts.count() > 1 && !mAllowMultiple )
4999 return false;
5000
5001 const auto constParts = parts;
5002 for ( const QString &part : constParts )
5003 {
5004 bool ok = false;
5005 const int res = part.toInt( &ok );
5006 if ( !ok )
5007 return false;
5008 else if ( res < 0 || res >= mOptions.count() )
5009 return false;
5010 }
5011 return true;
5012 }
5013 else if ( input.type() == QVariant::Int || input.type() == QVariant::Double )
5014 {
5015 bool ok = false;
5016 const int res = input.toInt( &ok );
5017 if ( !ok )
5018 return false;
5019 else if ( res >= 0 && res < mOptions.count() )
5020 return true;
5021 }
5022 }
5023
5024 return false;
5025}
5026
5028{
5029 if ( !value.isValid() )
5030 return QStringLiteral( "None" );
5031
5032 if ( value.userType() == QMetaType::type( "QgsProperty" ) )
5033 return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
5034
5035 if ( mUsesStaticStrings )
5036 {
5037 if ( value.type() == QVariant::List || value.type() == QVariant::StringList )
5038 {
5039 QStringList parts;
5040 const QStringList constList = value.toStringList();
5041 for ( const QString &val : constList )
5042 {
5044 }
5045 return parts.join( ',' ).prepend( '[' ).append( ']' );
5046 }
5047 else if ( value.type() == QVariant::String )
5048 {
5049 QStringList parts;
5050 const QStringList constList = value.toString().split( ',' );
5051 if ( constList.count() > 1 )
5052 {
5053 for ( const QString &val : constList )
5054 {
5056 }
5057 return parts.join( ',' ).prepend( '[' ).append( ']' );
5058 }
5059 }
5060
5061 return QgsProcessingUtils::stringToPythonLiteral( value.toString() );
5062 }
5063 else
5064 {
5065 if ( value.type() == QVariant::List )
5066 {
5067 QStringList parts;
5068 const auto constToList = value.toList();
5069 for ( const QVariant &val : constToList )
5070 {
5071 parts << QString::number( static_cast< int >( val.toDouble() ) );
5072 }
5073 return parts.join( ',' ).prepend( '[' ).append( ']' );
5074 }
5075 else if ( value.type() == QVariant::String )
5076 {
5077 const QStringList parts = value.toString().split( ',' );
5078 if ( parts.count() > 1 )
5079 {
5080 return parts.join( ',' ).prepend( '[' ).append( ']' );
5081 }
5082 }
5083
5084 return QString::number( static_cast< int >( value.toDouble() ) );
5085 }
5086}
5087
5089{
5090 if ( !value.isValid() )
5091 return QString();
5092
5093 if ( value.userType() == QMetaType::type( "QgsProperty" ) )
5094 return QString();
5095
5096 if ( mUsesStaticStrings )
5097 {
5098 return QString();
5099 }
5100 else
5101 {
5102 if ( value.type() == QVariant::List )
5103 {
5104 QStringList parts;
5105 const QVariantList toList = value.toList();
5106 parts.reserve( toList.size() );
5107 for ( const QVariant &val : toList )
5108 {
5109 parts << mOptions.value( static_cast< int >( val.toDouble() ) );
5110 }
5111 return parts.join( ',' );
5112 }
5113 else if ( value.type() == QVariant::String )
5114 {
5115 const QStringList parts = value.toString().split( ',' );
5116 QStringList comments;
5117 if ( parts.count() > 1 )
5118 {
5119 for ( const QString &part : parts )
5120 {
5121 bool ok = false;
5122 const int val = part.toInt( &ok );
5123 if ( ok )
5124 comments << mOptions.value( val );
5125 }
5126 return comments.join( ',' );
5127 }
5128 }
5129
5130 return mOptions.value( static_cast< int >( value.toDouble() ) );
5131 }
5132}
5133
5135{
5136 QString code = QStringLiteral( "##%1=" ).arg( mNa