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