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