QGIS API Documentation 3.27.0-Master (1c05421486)
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 const QStringList resultStringList;
1972 return parameterAsFields( definition, parameters.value( definition->name() ), context );
1973}
1974
1975QStringList QgsProcessingParameters::parameterAsFields( const QgsProcessingParameterDefinition *definition, const QVariant &value, QgsProcessingContext &context )
1976{
1977 if ( !definition )
1978 return QStringList();
1979
1980 QStringList resultStringList;
1981 const QVariant val = value;
1982 if ( val.isValid() )
1983 {
1984 if ( val.userType() == QMetaType::type( "QgsProperty" ) )
1985 resultStringList << val.value< QgsProperty >().valueAsString( context.expressionContext(), definition->defaultValue().toString() );
1986 else if ( val.type() == QVariant::List )
1987 {
1988 const auto constToList = val.toList();
1989 for ( const QVariant &var : constToList )
1990 resultStringList << var.toString();
1991 }
1992 else if ( val.type() == QVariant::StringList )
1993 {
1994 resultStringList = val.toStringList();
1995 }
1996 else
1997 resultStringList.append( val.toString().split( ';' ) );
1998 }
1999
2000 if ( ( resultStringList.isEmpty() || resultStringList.at( 0 ).isEmpty() ) )
2001 {
2002 resultStringList.clear();
2003 // check default
2004 if ( definition->defaultValue().isValid() )
2005 {
2006 if ( definition->defaultValue().type() == QVariant::List )
2007 {
2008 const auto constToList = definition->defaultValue().toList();
2009 for ( const QVariant &var : constToList )
2010 resultStringList << var.toString();
2011 }
2012 else if ( definition->defaultValue().type() == QVariant::StringList )
2013 {
2014 resultStringList = definition->defaultValue().toStringList();
2015 }
2016 else
2017 resultStringList.append( definition->defaultValue().toString().split( ';' ) );
2018 }
2019 }
2020
2021 return resultStringList;
2022}
2023
2025{
2026 if ( !definition )
2027 return nullptr;
2028
2029 return parameterAsLayout( definition, parameters.value( definition->name() ), context );
2030}
2031
2033{
2034 const QString layoutName = parameterAsString( definition, value, context );
2035 if ( layoutName.isEmpty() )
2036 return nullptr;
2037
2038 if ( !context.project() )
2039 return nullptr;
2040
2041 QgsMasterLayoutInterface *l = context.project()->layoutManager()->layoutByName( layoutName );
2043 return static_cast< QgsPrintLayout * >( l );
2044 else
2045 return nullptr;
2046}
2047
2049{
2050 if ( !definition )
2051 return nullptr;
2052
2053 return parameterAsLayoutItem( definition, parameters.value( definition->name() ), context, layout );
2054}
2055
2057{
2058 if ( !layout )
2059 return nullptr;
2060
2061 const QString id = parameterAsString( definition, value, context );
2062 if ( id.isEmpty() )
2063 return nullptr;
2064
2065 // prefer matching by uuid, since it's guaranteed to be unique.
2066 if ( QgsLayoutItem *item = layout->itemByUuid( id ) )
2067 return item;
2068 else if ( QgsLayoutItem *item = layout->itemById( id ) )
2069 return item;
2070 else
2071 return nullptr;
2072}
2073
2074QColor QgsProcessingParameters::parameterAsColor( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context )
2075{
2076 if ( !definition )
2077 return QColor();
2078
2079 return parameterAsColor( definition, parameters.value( definition->name() ), context );
2080}
2081
2083{
2084 if ( !definition )
2085 return QColor();
2086
2087 QVariant val = value;
2088 if ( val.userType() == QMetaType::type( "QgsProperty" ) )
2089 {
2090 val = val.value< QgsProperty >().value( context.expressionContext(), definition->defaultValue() );
2091 }
2092 if ( val.type() == QVariant::Color )
2093 {
2094 QColor c = val.value< QColor >();
2095 if ( const QgsProcessingParameterColor *colorParam = dynamic_cast< const QgsProcessingParameterColor * >( definition ) )
2096 if ( !colorParam->opacityEnabled() )
2097 c.setAlpha( 255 );
2098 return c;
2099 }
2100
2101 QString colorText = parameterAsString( definition, value, context );
2102 if ( colorText.isEmpty() && !( definition->flags() & QgsProcessingParameterDefinition::FlagOptional ) )
2103 {
2104 if ( definition->defaultValue().type() == QVariant::Color )
2105 return definition->defaultValue().value< QColor >();
2106 else
2107 colorText = definition->defaultValue().toString();
2108 }
2109
2110 if ( colorText.isEmpty() )
2111 return QColor();
2112
2113 bool containsAlpha = false;
2114 QColor c = QgsSymbolLayerUtils::parseColorWithAlpha( colorText, containsAlpha );
2115 if ( const QgsProcessingParameterColor *colorParam = dynamic_cast< const QgsProcessingParameterColor * >( definition ) )
2116 if ( c.isValid() && !colorParam->opacityEnabled() )
2117 c.setAlpha( 255 );
2118 return c;
2119}
2120
2121QString QgsProcessingParameters::parameterAsConnectionName( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, const QgsProcessingContext &context )
2122{
2123 if ( !definition )
2124 return QString();
2125
2126 return parameterAsConnectionName( definition, parameters.value( definition->name() ), context );
2127}
2128
2130{
2131 // for now it's just treated identical to strings, but in future we may want flexibility to amend this
2132 // (hence the new method)
2133 return parameterAsString( definition, value, context );
2134}
2135
2136QString QgsProcessingParameters::parameterAsSchema( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, const QgsProcessingContext &context )
2137{
2138 if ( !definition )
2139 return QString();
2140
2141 return parameterAsSchema( definition, parameters.value( definition->name() ), context );
2142}
2143
2144QString QgsProcessingParameters::parameterAsSchema( const QgsProcessingParameterDefinition *definition, const QVariant &value, const QgsProcessingContext &context )
2145{
2146 // 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
2147 // parameter values, such as via a delimiter separated string)
2148 return parameterAsString( definition, value, context );
2149}
2150
2151QString QgsProcessingParameters::parameterAsDatabaseTableName( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, const QgsProcessingContext &context )
2152{
2153 if ( !definition )
2154 return QString();
2155
2156 return parameterAsDatabaseTableName( definition, parameters.value( definition->name() ), context );
2157}
2158
2160{
2161 // 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
2162 // parameter values, such as via a delimiter separated string)
2163 return parameterAsString( definition, value, context );
2164}
2165
2167{
2168 return qobject_cast< QgsPointCloudLayer *>( parameterAsLayer( definition, parameters, context, QgsProcessingUtils::LayerHint::PointCloud ) );
2169}
2170
2172{
2173 return qobject_cast< QgsPointCloudLayer *>( parameterAsLayer( definition, value, context, QgsProcessingUtils::LayerHint::PointCloud ) );
2174}
2175
2177{
2178 return qobject_cast< QgsAnnotationLayer *>( parameterAsLayer( definition, parameters, context, QgsProcessingUtils::LayerHint::Annotation ) );
2179}
2180
2182{
2183 return qobject_cast< QgsAnnotationLayer *>( parameterAsLayer( definition, value, context, QgsProcessingUtils::LayerHint::Annotation ) );
2184}
2185
2187{
2188 const QString type = map.value( QStringLiteral( "parameter_type" ) ).toString();
2189 const QString name = map.value( QStringLiteral( "name" ) ).toString();
2190 std::unique_ptr< QgsProcessingParameterDefinition > def;
2191
2192 // probably all these hardcoded values aren't required anymore, and we could
2193 // always resort to the registry lookup...
2194 // TODO: confirm
2196 def.reset( new QgsProcessingParameterBoolean( name ) );
2197 else if ( type == QgsProcessingParameterCrs::typeName() )
2198 def.reset( new QgsProcessingParameterCrs( name ) );
2199 else if ( type == QgsProcessingParameterMapLayer::typeName() )
2200 def.reset( new QgsProcessingParameterMapLayer( name ) );
2201 else if ( type == QgsProcessingParameterExtent::typeName() )
2202 def.reset( new QgsProcessingParameterExtent( name ) );
2203 else if ( type == QgsProcessingParameterPoint::typeName() )
2204 def.reset( new QgsProcessingParameterPoint( name ) );
2205 else if ( type == QgsProcessingParameterFile::typeName() )
2206 def.reset( new QgsProcessingParameterFile( name ) );
2207 else if ( type == QgsProcessingParameterMatrix::typeName() )
2208 def.reset( new QgsProcessingParameterMatrix( name ) );
2210 def.reset( new QgsProcessingParameterMultipleLayers( name ) );
2211 else if ( type == QgsProcessingParameterNumber::typeName() )
2212 def.reset( new QgsProcessingParameterNumber( name ) );
2213 else if ( type == QgsProcessingParameterRange::typeName() )
2214 def.reset( new QgsProcessingParameterRange( name ) );
2216 def.reset( new QgsProcessingParameterRasterLayer( name ) );
2217 else if ( type == QgsProcessingParameterEnum::typeName() )
2218 def.reset( new QgsProcessingParameterEnum( name ) );
2219 else if ( type == QgsProcessingParameterString::typeName() )
2220 def.reset( new QgsProcessingParameterString( name ) );
2221 else if ( type == QgsProcessingParameterAuthConfig::typeName() )
2222 def.reset( new QgsProcessingParameterAuthConfig( name ) );
2223 else if ( type == QgsProcessingParameterExpression::typeName() )
2224 def.reset( new QgsProcessingParameterExpression( name ) );
2226 def.reset( new QgsProcessingParameterVectorLayer( name ) );
2227 else if ( type == QgsProcessingParameterField::typeName() )
2228 def.reset( new QgsProcessingParameterField( name ) );
2230 def.reset( new QgsProcessingParameterFeatureSource( name ) );
2232 def.reset( new QgsProcessingParameterFeatureSink( name ) );
2234 def.reset( new QgsProcessingParameterVectorDestination( name ) );
2236 def.reset( new QgsProcessingParameterRasterDestination( name ) );
2238 def.reset( new QgsProcessingParameterPointCloudDestination( name ) );
2240 def.reset( new QgsProcessingParameterFileDestination( name ) );
2242 def.reset( new QgsProcessingParameterFolderDestination( name ) );
2243 else if ( type == QgsProcessingParameterBand::typeName() )
2244 def.reset( new QgsProcessingParameterBand( name ) );
2245 else if ( type == QgsProcessingParameterMeshLayer::typeName() )
2246 def.reset( new QgsProcessingParameterMeshLayer( name ) );
2247 else if ( type == QgsProcessingParameterLayout::typeName() )
2248 def.reset( new QgsProcessingParameterLayout( name ) );
2249 else if ( type == QgsProcessingParameterLayoutItem::typeName() )
2250 def.reset( new QgsProcessingParameterLayoutItem( name ) );
2251 else if ( type == QgsProcessingParameterColor::typeName() )
2252 def.reset( new QgsProcessingParameterColor( name ) );
2254 def.reset( new QgsProcessingParameterCoordinateOperation( name ) );
2256 def.reset( new QgsProcessingParameterPointCloudLayer( name ) );
2258 def.reset( new QgsProcessingParameterAnnotationLayer( name ) );
2259 else
2260 {
2262 if ( paramType )
2263 def.reset( paramType->create( name ) );
2264 }
2265
2266 if ( !def )
2267 return nullptr;
2268
2269 def->fromVariantMap( map );
2270 return def.release();
2271}
2272
2274{
2275 QString desc = name;
2276 desc.replace( '_', ' ' );
2277 return desc;
2278}
2279
2281{
2282 bool isOptional = false;
2283 QString name;
2284 QString definition;
2285 QString type;
2286 if ( !parseScriptCodeParameterOptions( code, isOptional, name, type, definition ) )
2287 return nullptr;
2288
2289 const QString description = descriptionFromName( name );
2290
2291 if ( type == QLatin1String( "boolean" ) )
2292 return QgsProcessingParameterBoolean::fromScriptCode( name, description, isOptional, definition );
2293 else if ( type == QLatin1String( "crs" ) )
2294 return QgsProcessingParameterCrs::fromScriptCode( name, description, isOptional, definition );
2295 else if ( type == QLatin1String( "layer" ) )
2296 return QgsProcessingParameterMapLayer::fromScriptCode( name, description, isOptional, definition );
2297 else if ( type == QLatin1String( "extent" ) )
2298 return QgsProcessingParameterExtent::fromScriptCode( name, description, isOptional, definition );
2299 else if ( type == QLatin1String( "point" ) )
2300 return QgsProcessingParameterPoint::fromScriptCode( name, description, isOptional, definition );
2301 else if ( type == QLatin1String( "geometry" ) )
2302 return QgsProcessingParameterGeometry::fromScriptCode( name, description, isOptional, definition );
2303 else if ( type == QLatin1String( "file" ) )
2304 return QgsProcessingParameterFile::fromScriptCode( name, description, isOptional, definition, QgsProcessingParameterFile::File );
2305 else if ( type == QLatin1String( "folder" ) )
2306 return QgsProcessingParameterFile::fromScriptCode( name, description, isOptional, definition, QgsProcessingParameterFile::Folder );
2307 else if ( type == QLatin1String( "matrix" ) )
2308 return QgsProcessingParameterMatrix::fromScriptCode( name, description, isOptional, definition );
2309 else if ( type == QLatin1String( "multiple" ) )
2310 return QgsProcessingParameterMultipleLayers::fromScriptCode( name, description, isOptional, definition );
2311 else if ( type == QLatin1String( "number" ) )
2312 return QgsProcessingParameterNumber::fromScriptCode( name, description, isOptional, definition );
2313 else if ( type == QLatin1String( "distance" ) )
2314 return QgsProcessingParameterDistance::fromScriptCode( name, description, isOptional, definition );
2315 else if ( type == QLatin1String( "duration" ) )
2316 return QgsProcessingParameterDuration::fromScriptCode( name, description, isOptional, definition );
2317 else if ( type == QLatin1String( "scale" ) )
2318 return QgsProcessingParameterScale::fromScriptCode( name, description, isOptional, definition );
2319 else if ( type == QLatin1String( "range" ) )
2320 return QgsProcessingParameterRange::fromScriptCode( name, description, isOptional, definition );
2321 else if ( type == QLatin1String( "raster" ) )
2322 return QgsProcessingParameterRasterLayer::fromScriptCode( name, description, isOptional, definition );
2323 else if ( type == QLatin1String( "enum" ) )
2324 return QgsProcessingParameterEnum::fromScriptCode( name, description, isOptional, definition );
2325 else if ( type == QLatin1String( "string" ) )
2326 return QgsProcessingParameterString::fromScriptCode( name, description, isOptional, definition );
2327 else if ( type == QLatin1String( "authcfg" ) )
2328 return QgsProcessingParameterAuthConfig::fromScriptCode( name, description, isOptional, definition );
2329 else if ( type == QLatin1String( "expression" ) )
2330 return QgsProcessingParameterExpression::fromScriptCode( name, description, isOptional, definition );
2331 else if ( type == QLatin1String( "field" ) )
2332 return QgsProcessingParameterField::fromScriptCode( name, description, isOptional, definition );
2333 else if ( type == QLatin1String( "vector" ) )
2334 return QgsProcessingParameterVectorLayer::fromScriptCode( name, description, isOptional, definition );
2335 else if ( type == QLatin1String( "source" ) )
2336 return QgsProcessingParameterFeatureSource::fromScriptCode( name, description, isOptional, definition );
2337 else if ( type == QLatin1String( "sink" ) )
2338 return QgsProcessingParameterFeatureSink::fromScriptCode( name, description, isOptional, definition );
2339 else if ( type == QLatin1String( "vectordestination" ) )
2340 return QgsProcessingParameterVectorDestination::fromScriptCode( name, description, isOptional, definition );
2341 else if ( type == QLatin1String( "rasterdestination" ) )
2342 return QgsProcessingParameterRasterDestination::fromScriptCode( name, description, isOptional, definition );
2343 else if ( type == QLatin1String( "pointclouddestination" ) )
2344 return QgsProcessingParameterPointCloudDestination::fromScriptCode( name, description, isOptional, definition );
2345 else if ( type == QLatin1String( "filedestination" ) )
2346 return QgsProcessingParameterFileDestination::fromScriptCode( name, description, isOptional, definition );
2347 else if ( type == QLatin1String( "folderdestination" ) )
2348 return QgsProcessingParameterFolderDestination::fromScriptCode( name, description, isOptional, definition );
2349 else if ( type == QLatin1String( "band" ) )
2350 return QgsProcessingParameterBand::fromScriptCode( name, description, isOptional, definition );
2351 else if ( type == QLatin1String( "mesh" ) )
2352 return QgsProcessingParameterMeshLayer::fromScriptCode( name, description, isOptional, definition );
2353 else if ( type == QLatin1String( "layout" ) )
2354 return QgsProcessingParameterLayout::fromScriptCode( name, description, isOptional, definition );
2355 else if ( type == QLatin1String( "layoutitem" ) )
2356 return QgsProcessingParameterLayoutItem::fromScriptCode( name, description, isOptional, definition );
2357 else if ( type == QLatin1String( "color" ) )
2358 return QgsProcessingParameterColor::fromScriptCode( name, description, isOptional, definition );
2359 else if ( type == QLatin1String( "coordinateoperation" ) )
2360 return QgsProcessingParameterCoordinateOperation::fromScriptCode( name, description, isOptional, definition );
2361 else if ( type == QLatin1String( "maptheme" ) )
2362 return QgsProcessingParameterMapTheme::fromScriptCode( name, description, isOptional, definition );
2363 else if ( type == QLatin1String( "datetime" ) )
2364 return QgsProcessingParameterDateTime::fromScriptCode( name, description, isOptional, definition );
2365 else if ( type == QLatin1String( "providerconnection" ) )
2366 return QgsProcessingParameterProviderConnection::fromScriptCode( name, description, isOptional, definition );
2367 else if ( type == QLatin1String( "databaseschema" ) )
2368 return QgsProcessingParameterDatabaseSchema::fromScriptCode( name, description, isOptional, definition );
2369 else if ( type == QLatin1String( "databasetable" ) )
2370 return QgsProcessingParameterDatabaseTable::fromScriptCode( name, description, isOptional, definition );
2371 else if ( type == QLatin1String( "pointcloud" ) )
2372 return QgsProcessingParameterPointCloudLayer::fromScriptCode( name, description, isOptional, definition );
2373 else if ( type == QLatin1String( "annotation" ) )
2374 return QgsProcessingParameterAnnotationLayer::fromScriptCode( name, description, isOptional, definition );
2375
2376 return nullptr;
2377}
2378
2379bool QgsProcessingParameters::parseScriptCodeParameterOptions( const QString &code, bool &isOptional, QString &name, QString &type, QString &definition )
2380{
2381 const QRegularExpression re( QStringLiteral( "(?:#*)(.*?)=\\s*(.*)" ) );
2382 QRegularExpressionMatch m = re.match( code );
2383 if ( !m.hasMatch() )
2384 return false;
2385
2386 name = m.captured( 1 );
2387 QString tokens = m.captured( 2 );
2388 if ( tokens.startsWith( QLatin1String( "optional" ), Qt::CaseInsensitive ) )
2389 {
2390 isOptional = true;
2391 tokens.remove( 0, 8 ); // length "optional" = 8
2392 }
2393 else
2394 {
2395 isOptional = false;
2396 }
2397
2398 tokens = tokens.trimmed();
2399
2400 const QRegularExpression re2( QStringLiteral( "(.*?)\\s+(.*)" ) );
2401 m = re2.match( tokens );
2402 if ( !m.hasMatch() )
2403 {
2404 type = tokens.toLower().trimmed();
2405 definition.clear();
2406 }
2407 else
2408 {
2409 type = m.captured( 1 ).toLower().trimmed();
2410 definition = m.captured( 2 );
2411 }
2412 return true;
2413}
2414
2415//
2416// QgsProcessingParameterDefinition
2417//
2418
2419QgsProcessingParameterDefinition::QgsProcessingParameterDefinition( const QString &name, const QString &description, const QVariant &defaultValue, bool optional, const QString &help )
2420 : mName( name )
2421 , mDescription( description )
2422 , mHelp( help )
2423 , mDefault( defaultValue )
2424 , mFlags( optional ? FlagOptional : 0 )
2425{}
2426
2428{
2429 if ( !input.isValid() && !mDefault.isValid() )
2430 return mFlags & FlagOptional;
2431
2432 if ( ( input.type() == QVariant::String && input.toString().isEmpty() )
2433 || ( !input.isValid() && mDefault.type() == QVariant::String && mDefault.toString().isEmpty() ) )
2434 return mFlags & FlagOptional;
2435
2436 return true;
2437}
2438
2440{
2441 if ( !value.isValid() )
2442 return QStringLiteral( "None" );
2443
2444 if ( value.userType() == QMetaType::type( "QgsProperty" ) )
2445 return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
2446
2447 return QgsProcessingUtils::stringToPythonLiteral( value.toString() );
2448}
2449
2450QVariant QgsProcessingParameterDefinition::valueAsJsonObject( const QVariant &value, QgsProcessingContext &context ) const
2451{
2452 return valueAsJsonObjectPrivate( value, context, ValueAsStringFlags() );
2453}
2454
2455QVariant QgsProcessingParameterDefinition::valueAsJsonObjectPrivate( const QVariant &value, QgsProcessingContext &context, ValueAsStringFlags flags ) const
2456{
2457 if ( !value.isValid() )
2458 return value;
2459
2460 // dive into map and list types and convert each value
2461 if ( value.type() == QVariant::Type::Map )
2462 {
2463 const QVariantMap sourceMap = value.toMap();
2464 QVariantMap resultMap;
2465 for ( auto it = sourceMap.constBegin(); it != sourceMap.constEnd(); it++ )
2466 {
2467 resultMap[ it.key() ] = valueAsJsonObject( it.value(), context );
2468 }
2469 return resultMap;
2470 }
2471 else if ( value.type() == QVariant::Type::List || value.type() == QVariant::Type::StringList )
2472 {
2473 const QVariantList sourceList = value.toList();
2474 QVariantList resultList;
2475 resultList.reserve( sourceList.size() );
2476 for ( const QVariant &v : sourceList )
2477 {
2478 resultList.push_back( valueAsJsonObject( v, context ) );
2479 }
2480 return resultList;
2481 }
2482 else
2483 {
2484 switch ( value.userType() )
2485 {
2486 // simple types which can be directly represented in JSON -- note that strings are NOT handled here yet!
2487 case QMetaType::Bool:
2488 case QMetaType::Char:
2489 case QMetaType::Int:
2490 case QMetaType::Double:
2491 case QMetaType::Float:
2492 case QMetaType::LongLong:
2493 case QMetaType::ULongLong:
2494 case QMetaType::UInt:
2495 case QMetaType::ULong:
2496 case QMetaType::UShort:
2497 return value;
2498
2499 default:
2500 break;
2501 }
2502
2503
2504 if ( value.userType() == QMetaType::type( "QgsProperty" ) )
2505 {
2506 const QgsProperty prop = value.value< QgsProperty >();
2507 switch ( prop.propertyType() )
2508 {
2510 return QVariant();
2512 return valueAsJsonObject( prop.staticValue(), context );
2513
2514 // these are not supported for serialization
2517 QgsDebugMsg( QStringLiteral( "could not convert expression/field based property to JSON object" ) );
2518 return QVariant();
2519 }
2520 }
2521
2522 // value may be a CRS
2523 if ( value.userType() == QMetaType::type( "QgsCoordinateReferenceSystem" ) )
2524 {
2526 if ( !crs.isValid() )
2527 return QString();
2528 else if ( !crs.authid().isEmpty() )
2529 return crs.authid();
2530 else
2532 }
2533 else if ( value.userType() == QMetaType::type( "QgsRectangle" ) )
2534 {
2535 const QgsRectangle r = value.value<QgsRectangle>();
2536 return QStringLiteral( "%1, %3, %2, %4" ).arg( qgsDoubleToString( r.xMinimum() ),
2539 qgsDoubleToString( r.yMaximum() ) );
2540 }
2541 else if ( value.userType() == QMetaType::type( "QgsReferencedRectangle" ) )
2542 {
2543 const QgsReferencedRectangle r = value.value<QgsReferencedRectangle>();
2544 return QStringLiteral( "%1, %3, %2, %4 [%5]" ).arg( qgsDoubleToString( r.xMinimum() ),
2548 r.crs().authid() );
2549 }
2550 else if ( value.userType() == QMetaType::type( "QgsGeometry" ) )
2551 {
2552 const QgsGeometry g = value.value<QgsGeometry>();
2553 if ( !g.isNull() )
2554 {
2555 return g.asWkt();
2556 }
2557 else
2558 {
2559 return QString();
2560 }
2561 }
2562 else if ( value.userType() == QMetaType::type( "QgsReferencedGeometry" ) )
2563 {
2564 const QgsReferencedGeometry g = value.value<QgsReferencedGeometry>();
2565 if ( !g.isNull() )
2566 {
2567 if ( !g.crs().isValid() )
2568 return g.asWkt();
2569 else
2570 return QStringLiteral( "CRS=%1;%2" ).arg( g.crs().authid().isEmpty() ? g.crs().toWkt( QgsCoordinateReferenceSystem::WKT_PREFERRED ) : g.crs().authid(), g.asWkt() );
2571 }
2572 else
2573 {
2574 return QString();
2575 }
2576 }
2577 else if ( value.userType() == QMetaType::type( "QgsPointXY" ) )
2578 {
2579 const QgsPointXY r = value.value<QgsPointXY>();
2580 return QStringLiteral( "%1,%2" ).arg( qgsDoubleToString( r.x() ),
2581 qgsDoubleToString( r.y() ) );
2582 }
2583 else if ( value.userType() == QMetaType::type( "QgsReferencedPointXY" ) )
2584 {
2585 const QgsReferencedPointXY r = value.value<QgsReferencedPointXY>();
2586 return QStringLiteral( "%1,%2 [%3]" ).arg( qgsDoubleToString( r.x() ),
2587 qgsDoubleToString( r.y() ),
2588 r.crs().authid() );
2589 }
2590 else if ( value.userType() == QMetaType::type( "QgsProcessingFeatureSourceDefinition" ) )
2591 {
2592 const QgsProcessingFeatureSourceDefinition fromVar = qvariant_cast<QgsProcessingFeatureSourceDefinition>( value );
2593
2594 // TODO -- we could consider also serializating the additional properties like invalid feature handling, limits, etc
2595 return valueAsJsonObject( fromVar.source, context );
2596 }
2597 else if ( value.userType() == QMetaType::type( "QgsProcessingOutputLayerDefinition" ) )
2598 {
2599 const QgsProcessingOutputLayerDefinition fromVar = qvariant_cast<QgsProcessingOutputLayerDefinition>( value );
2600 return valueAsJsonObject( fromVar.sink, context );
2601 }
2602 else if ( value.userType() == QMetaType::type( "QColor" ) )
2603 {
2604 const QColor fromVar = value.value< QColor >();
2605 if ( !fromVar.isValid() )
2606 return QString();
2607
2608 return QStringLiteral( "rgba( %1, %2, %3, %4 )" ).arg( fromVar.red() ).arg( fromVar.green() ).arg( fromVar.blue() ).arg( QString::number( fromVar.alphaF(), 'f', 2 ) );
2609 }
2610 else if ( value.userType() == QMetaType::type( "QDateTime" ) )
2611 {
2612 const QDateTime fromVar = value.toDateTime();
2613 if ( !fromVar.isValid() )
2614 return QString();
2615
2616 return fromVar.toString( Qt::ISODate );
2617 }
2618 else if ( value.userType() == QMetaType::type( "QDate" ) )
2619 {
2620 const QDate fromVar = value.toDate();
2621 if ( !fromVar.isValid() )
2622 return QString();
2623
2624 return fromVar.toString( Qt::ISODate );
2625 }
2626 else if ( value.userType() == QMetaType::type( "QTime" ) )
2627 {
2628 const QTime fromVar = value.toTime();
2629 if ( !fromVar.isValid() )
2630 return QString();
2631
2632 return fromVar.toString( Qt::ISODate );
2633 }
2634
2636 {
2637 // value may be a map layer
2638 QVariantMap p;
2639 p.insert( name(), value );
2640 if ( QgsMapLayer *layer = QgsProcessingParameters::parameterAsLayer( this, p, context ) )
2641 {
2642 const QString source = QgsProcessingUtils::normalizeLayerSource( layer->source() );
2643 if ( !source.isEmpty() )
2644 return source;
2645 return layer->id();
2646 }
2647 }
2648
2649 // now we handle strings, after any other specific logic has already been applied
2650 if ( value.userType() == QMetaType::QString )
2651 return value;
2652 }
2653
2654 // unhandled type
2655 Q_ASSERT_X( false, "QgsProcessingParameterDefinition::valueAsJsonObject", QStringLiteral( "unsupported variant type %1" ).arg( QMetaType::typeName( value.userType() ) ).toLocal8Bit() );
2656 return value;
2657}
2658
2659QString QgsProcessingParameterDefinition::valueAsString( const QVariant &value, QgsProcessingContext &context, bool &ok ) const
2660{
2661 return valueAsStringPrivate( value, context, ok, ValueAsStringFlags() );
2662}
2663
2664QString QgsProcessingParameterDefinition::valueAsStringPrivate( const QVariant &value, QgsProcessingContext &context, bool &ok, ValueAsStringFlags flags ) const
2665{
2666 ok = true;
2667
2668 if ( !value.isValid() )
2669 return QString();
2670
2671 switch ( value.userType() )
2672 {
2673 // simple types which can be directly represented in JSON -- note that strings are NOT handled here yet!
2674 case QMetaType::Bool:
2675 case QMetaType::Char:
2676 case QMetaType::Int:
2677 case QMetaType::Double:
2678 case QMetaType::Float:
2679 case QMetaType::LongLong:
2680 case QMetaType::ULongLong:
2681 case QMetaType::UInt:
2682 case QMetaType::ULong:
2683 case QMetaType::UShort:
2684 return value.toString();
2685
2686 default:
2687 break;
2688 }
2689
2690 if ( value.userType() == QMetaType::type( "QgsProperty" ) )
2691 {
2692 const QgsProperty prop = value.value< QgsProperty >();
2693 switch ( prop.propertyType() )
2694 {
2696 return QString();
2698 return valueAsString( prop.staticValue(), context, ok );
2699
2700 // these are not supported for serialization
2703 QgsDebugMsg( QStringLiteral( "could not convert expression/field based property to string" ) );
2704 return QString();
2705 }
2706 }
2707
2708 // value may be a CRS
2709 if ( value.userType() == QMetaType::type( "QgsCoordinateReferenceSystem" ) )
2710 {
2712 if ( !crs.isValid() )
2713 return QString();
2714 else if ( !crs.authid().isEmpty() )
2715 return crs.authid();
2716 else
2718 }
2719 else if ( value.userType() == QMetaType::type( "QgsRectangle" ) )
2720 {
2721 const QgsRectangle r = value.value<QgsRectangle>();
2722 return QStringLiteral( "%1, %3, %2, %4" ).arg( qgsDoubleToString( r.xMinimum() ),
2725 qgsDoubleToString( r.yMaximum() ) );
2726 }
2727 else if ( value.userType() == QMetaType::type( "QgsReferencedRectangle" ) )
2728 {
2729 const QgsReferencedRectangle r = value.value<QgsReferencedRectangle>();
2730 return QStringLiteral( "%1, %3, %2, %4 [%5]" ).arg( qgsDoubleToString( r.xMinimum() ),
2733 qgsDoubleToString( r.yMaximum() ), r.crs().authid() );
2734 }
2735 else if ( value.userType() == QMetaType::type( "QgsGeometry" ) )
2736 {
2737 const QgsGeometry g = value.value<QgsGeometry>();
2738 if ( !g.isNull() )
2739 {
2740 return g.asWkt();
2741 }
2742 else
2743 {
2744 return QString();
2745 }
2746 }
2747 else if ( value.userType() == QMetaType::type( "QgsReferencedGeometry" ) )
2748 {
2749 const QgsReferencedGeometry g = value.value<QgsReferencedGeometry>();
2750 if ( !g.isNull() )
2751 {
2752 if ( !g.crs().isValid() )
2753 return g.asWkt();
2754 else
2755 return QStringLiteral( "CRS=%1;%2" ).arg( g.crs().authid().isEmpty() ? g.crs().toWkt( QgsCoordinateReferenceSystem::WKT_PREFERRED ) : g.crs().authid(), g.asWkt() );
2756 }
2757 else
2758 {
2759 return QString();
2760 }
2761 }
2762 else if ( value.userType() == QMetaType::type( "QgsPointXY" ) )
2763 {
2764 const QgsPointXY r = value.value<QgsPointXY>();
2765 return QStringLiteral( "%1,%2" ).arg( qgsDoubleToString( r.x() ),
2766 qgsDoubleToString( r.y() ) );
2767 }
2768 else if ( value.userType() == QMetaType::type( "QgsReferencedPointXY" ) )
2769 {
2770 const QgsReferencedPointXY r = value.value<QgsReferencedPointXY>();
2771 return QStringLiteral( "%1,%2 [%3]" ).arg( qgsDoubleToString( r.x() ),
2772 qgsDoubleToString( r.y() ),
2773 r.crs().authid() );
2774 }
2775 else if ( value.userType() == QMetaType::type( "QgsProcessingFeatureSourceDefinition" ) )
2776 {
2777 const QgsProcessingFeatureSourceDefinition fromVar = qvariant_cast<QgsProcessingFeatureSourceDefinition>( value );
2778 return valueAsString( fromVar.source, context, ok );
2779 }
2780 else if ( value.userType() == QMetaType::type( "QgsProcessingOutputLayerDefinition" ) )
2781 {
2782 const QgsProcessingOutputLayerDefinition fromVar = qvariant_cast<QgsProcessingOutputLayerDefinition>( value );
2783 return valueAsString( fromVar.sink, context, ok );
2784 }
2785 else if ( value.userType() == QMetaType::type( "QColor" ) )
2786 {
2787 const QColor fromVar = value.value< QColor >();
2788 if ( !fromVar.isValid() )
2789 return QString();
2790
2791 return QStringLiteral( "rgba( %1, %2, %3, %4 )" ).arg( fromVar.red() ).arg( fromVar.green() ).arg( fromVar.blue() ).arg( QString::number( fromVar.alphaF(), 'f', 2 ) );
2792 }
2793 else if ( value.userType() == QMetaType::type( "QDateTime" ) )
2794 {
2795 const QDateTime fromVar = value.toDateTime();
2796 if ( !fromVar.isValid() )
2797 return QString();
2798
2799 return fromVar.toString( Qt::ISODate );
2800 }
2801 else if ( value.userType() == QMetaType::type( "QDate" ) )
2802 {
2803 const QDate fromVar = value.toDate();
2804 if ( !fromVar.isValid() )
2805 return QString();
2806
2807 return fromVar.toString( Qt::ISODate );
2808 }
2809 else if ( value.userType() == QMetaType::type( "QTime" ) )
2810 {
2811 const QTime fromVar = value.toTime();
2812 if ( !fromVar.isValid() )
2813 return QString();
2814
2815 return fromVar.toString( Qt::ISODate );
2816 }
2817
2819 {
2820 // value may be a map layer
2821 QVariantMap p;
2822 p.insert( name(), value );
2823 if ( QgsMapLayer *layer = QgsProcessingParameters::parameterAsLayer( this, p, context ) )
2824 {
2825 const QString source = QgsProcessingUtils::normalizeLayerSource( layer->source() );
2826 if ( !source.isEmpty() )
2827 return source;
2828 return layer->id();
2829 }
2830 }
2831
2832 // now we handle strings, after any other specific logic has already been applied
2833 if ( value.userType() == QMetaType::QString )
2834 return value.toString();
2835
2836 // unhandled type
2837 QgsDebugMsg( QStringLiteral( "unsupported variant type %1" ).arg( QMetaType::typeName( value.userType() ) ) );
2838 ok = false;
2839 return value.toString();
2840}
2841
2842QStringList QgsProcessingParameterDefinition::valueAsStringList( const QVariant &value, QgsProcessingContext &context, bool &ok ) const
2843{
2844 ok = true;
2845 if ( !value.isValid( ) )
2846 return QStringList();
2847
2848 if ( value.type() == QVariant::Type::List || value.type() == QVariant::Type::StringList )
2849 {
2850 const QVariantList sourceList = value.toList();
2851 QStringList resultList;
2852 resultList.reserve( sourceList.size() );
2853 for ( const QVariant &v : sourceList )
2854 {
2855 resultList.append( valueAsStringList( v, context, ok ) );
2856 }
2857 return resultList;
2858 }
2859
2860 const QString res = valueAsString( value, context, ok );
2861 if ( !ok )
2862 return QStringList();
2863
2864 return {res};
2865}
2866
2868{
2869 return QString();
2870}
2871
2873{
2874 QString code = QStringLiteral( "##%1=" ).arg( mName );
2875 if ( mFlags & FlagOptional )
2876 code += QLatin1String( "optional " );
2877 code += type() + ' ';
2878 code += mDefault.toString();
2879 return code.trimmed();
2880}
2881
2883{
2884 // base class method is probably not much use
2886 {
2887 switch ( outputType )
2888 {
2890 {
2891 QString code = t->className() + QStringLiteral( "('%1', %2" )
2893 if ( mFlags & FlagOptional )
2894 code += QLatin1String( ", optional=True" );
2895
2897 code += QStringLiteral( ", defaultValue=%1)" ).arg( valueAsPythonString( mDefault, c ) );
2898 return code;
2899 }
2900 }
2901 }
2902
2903 // oh well, we tried
2904 return QString();
2905}
2906
2908{
2909 QVariantMap map;
2910 map.insert( QStringLiteral( "parameter_type" ), type() );
2911 map.insert( QStringLiteral( "name" ), mName );
2912 map.insert( QStringLiteral( "description" ), mDescription );
2913 map.insert( QStringLiteral( "help" ), mHelp );
2914 map.insert( QStringLiteral( "default" ), mDefault );
2915 map.insert( QStringLiteral( "defaultGui" ), mGuiDefault );
2916 map.insert( QStringLiteral( "flags" ), static_cast< int >( mFlags ) );
2917 map.insert( QStringLiteral( "metadata" ), mMetadata );
2918 return map;
2919}
2920
2922{
2923 mName = map.value( QStringLiteral( "name" ) ).toString();
2924 mDescription = map.value( QStringLiteral( "description" ) ).toString();
2925 mHelp = map.value( QStringLiteral( "help" ) ).toString();
2926 mDefault = map.value( QStringLiteral( "default" ) );
2927 mGuiDefault = map.value( QStringLiteral( "defaultGui" ) );
2928 mFlags = static_cast< Flags >( map.value( QStringLiteral( "flags" ) ).toInt() );
2929 mMetadata = map.value( QStringLiteral( "metadata" ) ).toMap();
2930 return true;
2931}
2932
2934{
2935 return mAlgorithm;
2936}
2937
2939{
2940 return mAlgorithm ? mAlgorithm->provider() : nullptr;
2941}
2942
2944{
2945 QString text = QStringLiteral( "<p><b>%1</b></p>" ).arg( description() );
2946 if ( !help().isEmpty() )
2947 {
2948 text += QStringLiteral( "<p>%1</p>" ).arg( help() );
2949 }
2950 text += QStringLiteral( "<p>%1</p>" ).arg( QObject::tr( "Python identifier: ‘%1’" ).arg( QStringLiteral( "<i>%1</i>" ).arg( name() ) ) );
2951 return text;
2952}
2953
2954QgsProcessingParameterBoolean::QgsProcessingParameterBoolean( const QString &name, const QString &description, const QVariant &defaultValue, bool optional )
2955 : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
2956{}
2957
2959{
2960 return new QgsProcessingParameterBoolean( *this );
2961}
2962
2964{
2965 if ( !val.isValid() )
2966 return QStringLiteral( "None" );
2967
2968 if ( val.userType() == QMetaType::type( "QgsProperty" ) )
2969 return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( val.value< QgsProperty >().asExpression() );
2970 return val.toBool() ? QStringLiteral( "True" ) : QStringLiteral( "False" );
2971}
2972
2974{
2975 QString code = QStringLiteral( "##%1=" ).arg( mName );
2976 if ( mFlags & FlagOptional )
2977 code += QLatin1String( "optional " );
2978 code += type() + ' ';
2979 code += mDefault.toBool() ? QStringLiteral( "true" ) : QStringLiteral( "false" );
2980 return code.trimmed();
2981}
2982
2983QgsProcessingParameterBoolean *QgsProcessingParameterBoolean::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
2984{
2985 return new QgsProcessingParameterBoolean( name, description, definition.toLower().trimmed() != QStringLiteral( "false" ), isOptional );
2986}
2987
2988QgsProcessingParameterCrs::QgsProcessingParameterCrs( const QString &name, const QString &description, const QVariant &defaultValue, bool optional )
2989 : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
2990{
2991
2992}
2993
2995{
2996 return new QgsProcessingParameterCrs( *this );
2997}
2998
3000{
3001 if ( !input.isValid() )
3002 return mFlags & FlagOptional;
3003
3004 if ( input.userType() == QMetaType::type( "QgsCoordinateReferenceSystem" ) )
3005 {
3006 return true;
3007 }
3008 else if ( input.userType() == QMetaType::type( "QgsProcessingFeatureSourceDefinition" ) )
3009 {
3010 return true;
3011 }
3012 else if ( input.userType() == QMetaType::type( "QgsProcessingOutputLayerDefinition" ) )
3013 {
3014 return true;
3015 }
3016
3017 if ( input.userType() == QMetaType::type( "QgsProperty" ) )
3018 {
3019 return true;
3020 }
3021
3022 // direct map layer value
3023 if ( qobject_cast< QgsMapLayer * >( qvariant_cast<QObject *>( input ) ) )
3024 return true;
3025
3026 if ( input.type() != QVariant::String || input.toString().isEmpty() )
3027 return mFlags & FlagOptional;
3028
3029 return true;
3030}
3031
3032QString QgsProcessingParameterCrs::valueAsPythonString( const QVariant &value, QgsProcessingContext &context ) const
3033{
3034 if ( !value.isValid() )
3035 return QStringLiteral( "None" );
3036
3037 if ( value.userType() == QMetaType::type( "QgsCoordinateReferenceSystem" ) )
3038 {
3039 if ( !value.value< QgsCoordinateReferenceSystem >().isValid() )
3040 return QStringLiteral( "QgsCoordinateReferenceSystem()" );
3041 else
3042 return QStringLiteral( "QgsCoordinateReferenceSystem('%1')" ).arg( value.value< QgsCoordinateReferenceSystem >().authid() );
3043 }
3044
3045 if ( value.userType() == QMetaType::type( "QgsProperty" ) )
3046 return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
3047
3048 QVariantMap p;
3049 p.insert( name(), value );
3050 QgsMapLayer *layer = QgsProcessingParameters::parameterAsLayer( this, p, context );
3051 if ( layer )
3053
3055}
3056
3057QString QgsProcessingParameterCrs::valueAsString( const QVariant &value, QgsProcessingContext &context, bool &ok ) const
3058{
3060}
3061
3062QVariant QgsProcessingParameterCrs::valueAsJsonObject( const QVariant &value, QgsProcessingContext &context ) const
3063{
3065}
3066
3067QgsProcessingParameterCrs *QgsProcessingParameterCrs::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
3068{
3069 return new QgsProcessingParameterCrs( name, description, definition.compare( QLatin1String( "none" ), Qt::CaseInsensitive ) == 0 ? QVariant() : definition, isOptional );
3070}
3071
3072QgsProcessingParameterMapLayer::QgsProcessingParameterMapLayer( const QString &name, const QString &description, const QVariant &defaultValue, bool optional, const QList<int> &types )
3073 : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
3075{
3076
3077}
3078
3080{
3081 return new QgsProcessingParameterMapLayer( *this );
3082}
3083
3085{
3086 if ( !input.isValid() )
3087 return mFlags & FlagOptional;
3088
3089 if ( input.userType() == QMetaType::type( "QgsProperty" ) )
3090 {
3091 return true;
3092 }
3093
3094 if ( qobject_cast< QgsMapLayer * >( qvariant_cast<QObject *>( input ) ) )
3095 {
3096 return true;
3097 }
3098
3099 if ( input.type() != QVariant::String || input.toString().isEmpty() )
3100 return mFlags & FlagOptional;
3101
3102 if ( !context )
3103 {
3104 // that's as far as we can get without a context
3105 return true;
3106 }
3107
3108 // try to load as layer
3109 if ( QgsProcessingUtils::mapLayerFromString( input.toString(), *context ) )
3110 return true;
3111
3112 return false;
3113}
3114
3116{
3117 if ( !val.isValid() )
3118 return QStringLiteral( "None" );
3119
3120 if ( val.userType() == QMetaType::type( "QgsProperty" ) )
3121 return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( val.value< QgsProperty >().asExpression() );
3122
3123 QVariantMap p;
3124 p.insert( name(), val );
3125 QgsMapLayer *layer = QgsProcessingParameters::parameterAsLayer( this, p, context );
3128}
3129
3130QString QgsProcessingParameterMapLayer::valueAsString( const QVariant &value, QgsProcessingContext &context, bool &ok ) const
3131{
3133}
3134
3135QVariant QgsProcessingParameterMapLayer::valueAsJsonObject( const QVariant &value, QgsProcessingContext &context ) const
3136{
3138}
3139
3141{
3142 QStringList vectors = QgsProviderRegistry::instance()->fileVectorFilters().split( QStringLiteral( ";;" ) );
3143 const QStringList rasters = QgsProviderRegistry::instance()->fileRasterFilters().split( QStringLiteral( ";;" ) );
3144 for ( const QString &raster : rasters )
3145 {
3146 if ( !vectors.contains( raster ) )
3147 vectors << raster;
3148 }
3149 const QStringList meshFilters = QgsProviderRegistry::instance()->fileMeshFilters().split( QStringLiteral( ";;" ) );
3150 for ( const QString &mesh : meshFilters )
3151 {
3152 if ( !vectors.contains( mesh ) )
3153 vectors << mesh;
3154 }
3155 const QStringList pointCloudFilters = QgsProviderRegistry::instance()->filePointCloudFilters().split( QStringLiteral( ";;" ) );
3156 for ( const QString &pointCloud : pointCloudFilters )
3157 {
3158 if ( !vectors.contains( pointCloud ) )
3159 vectors << pointCloud;
3160 }
3161 vectors.removeAll( QObject::tr( "All files (*.*)" ) );
3162 std::sort( vectors.begin(), vectors.end() );
3163
3164 return QObject::tr( "All files (*.*)" ) + QStringLiteral( ";;" ) + vectors.join( QLatin1String( ";;" ) );
3165}
3166
3168{
3170}
3171
3173{
3174 QString code = QStringLiteral( "##%1=" ).arg( mName );
3175 if ( mFlags & FlagOptional )
3176 code += QLatin1String( "optional " );
3177 code += QLatin1String( "layer " );
3178
3179 for ( const int type : mDataTypes )
3180 {
3181 switch ( type )
3182 {
3184 code += QLatin1String( "hasgeometry " );
3185 break;
3186
3188 code += QLatin1String( "point " );
3189 break;
3190
3192 code += QLatin1String( "line " );
3193 break;
3194
3196 code += QLatin1String( "polygon " );
3197 break;
3198
3200 code += QLatin1String( "raster " );
3201 break;
3202
3204 code += QLatin1String( "mesh " );
3205 break;
3206
3208 code += QLatin1String( "plugin " );
3209 break;
3210
3212 code += QLatin1String( "pointcloud " );
3213 break;
3214
3216 code += QLatin1String( "annotation " );
3217 break;
3218 }
3219 }
3220
3221 code += mDefault.toString();
3222 return code.trimmed();
3223}
3224
3225QgsProcessingParameterMapLayer *QgsProcessingParameterMapLayer::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
3226{
3227 QList< int > types;
3228 QString def = definition;
3229 while ( true )
3230 {
3231 if ( def.startsWith( QLatin1String( "hasgeometry" ), Qt::CaseInsensitive ) )
3232 {
3234 def = def.mid( 12 );
3235 continue;
3236 }
3237 else if ( def.startsWith( QLatin1String( "point" ), Qt::CaseInsensitive ) )
3238 {
3240 def = def.mid( 6 );
3241 continue;
3242 }
3243 else if ( def.startsWith( QLatin1String( "line" ), Qt::CaseInsensitive ) )
3244 {
3246 def = def.mid( 5 );
3247 continue;
3248 }
3249 else if ( def.startsWith( QLatin1String( "polygon" ), Qt::CaseInsensitive ) )
3250 {
3252 def = def.mid( 8 );
3253 continue;
3254 }
3255 else if ( def.startsWith( QLatin1String( "raster" ), Qt::CaseInsensitive ) )
3256 {
3258 def = def.mid( 7 );
3259 continue;
3260 }
3261 else if ( def.startsWith( QLatin1String( "mesh" ), Qt::CaseInsensitive ) )
3262 {
3263 types << QgsProcessing::TypeMesh;
3264 def = def.mid( 5 );
3265 continue;
3266 }
3267 else if ( def.startsWith( QLatin1String( "plugin" ), Qt::CaseInsensitive ) )
3268 {
3270 def = def.mid( 7 );
3271 continue;
3272 }
3273 else if ( def.startsWith( QLatin1String( "pointcloud" ), Qt::CaseInsensitive ) )
3274 {
3276 def = def.mid( 11 );
3277 continue;
3278 }
3279 else if ( def.startsWith( QLatin1String( "annotation" ), Qt::CaseInsensitive ) )
3280 {
3282 def = def.mid( 11 );
3283 continue;
3284 }
3285 break;
3286 }
3287
3288 return new QgsProcessingParameterMapLayer( name, description, def, isOptional, types );
3289}
3290
3292{
3293 switch ( outputType )
3294 {
3296 {
3297 QString code = QStringLiteral( "QgsProcessingParameterMapLayer('%1', %2" )
3299 if ( mFlags & FlagOptional )
3300 code += QLatin1String( ", optional=True" );
3301
3303 code += QStringLiteral( ", defaultValue=%1" ).arg( valueAsPythonString( mDefault, c ) );
3304
3305 if ( !mDataTypes.empty() )
3306 {
3307 QStringList options;
3308 options.reserve( mDataTypes.size() );
3309 for ( const int t : mDataTypes )
3310 options << QStringLiteral( "QgsProcessing.%1" ).arg( QgsProcessing::sourceTypeToString( static_cast< QgsProcessing::SourceType >( t ) ) );
3311 code += QStringLiteral( ", types=[%1])" ).arg( options.join( ',' ) );
3312 }
3313 else
3314 {
3315 code += QLatin1Char( ')' );
3316 }
3317
3318 return code;
3319 }
3320 }
3321 return QString();
3322}
3323
3325{
3327 QVariantList types;
3328 for ( const int type : mDataTypes )
3329 {
3330 types << type;
3331 }
3332 map.insert( QStringLiteral( "data_types" ), types );
3333 return map;
3334}
3335
3337{
3339 mDataTypes.clear();
3340 const QVariantList values = map.value( QStringLiteral( "data_types" ) ).toList();
3341 for ( const QVariant &val : values )
3342 {
3343 mDataTypes << val.toInt();
3344 }
3345 return true;
3346}
3347
3348QgsProcessingParameterExtent::QgsProcessingParameterExtent( const QString &name, const QString &description, const QVariant &defaultValue, bool optional )
3349 : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
3350{
3351
3352}
3353
3355{
3356 return new QgsProcessingParameterExtent( *this );
3357}
3358
3360{
3361 if ( !input.isValid() )
3362 return mFlags & FlagOptional;
3363
3364 if ( input.userType() == QMetaType::type( "QgsProcessingFeatureSourceDefinition" ) )
3365 {
3366 return true;
3367 }
3368 else if ( input.userType() == QMetaType::type( "QgsProcessingOutputLayerDefinition" ) )
3369 {
3370 return true;
3371 }
3372
3373 if ( input.userType() == QMetaType::type( "QgsProperty" ) )
3374 {
3375 return true;
3376 }
3377
3378 if ( input.userType() == QMetaType::type( "QgsRectangle" ) )
3379 {
3380 const QgsRectangle r = input.value<QgsRectangle>();
3381 return !r.isNull();
3382 }
3383 if ( input.userType() == QMetaType::type( "QgsGeometry" ) )
3384 {
3385 return true;
3386 }
3387 if ( input.userType() == QMetaType::type( "QgsReferencedRectangle" ) )
3388 {
3389 const QgsReferencedRectangle r = input.value<QgsReferencedRectangle>();
3390 return !r.isNull();
3391 }
3392
3393 // direct map layer value
3394 if ( qobject_cast< QgsMapLayer * >( qvariant_cast<QObject *>( input ) ) )
3395 return true;
3396
3397 if ( input.type() != QVariant::String || input.toString().isEmpty() )
3398 return mFlags & FlagOptional;
3399
3400 if ( !context )
3401 {
3402 // that's as far as we can get without a context
3403 return true;
3404 }
3405
3406 const QRegularExpression rx( QStringLiteral( "^(.*?)\\s*,\\s*(.*?)\\s*,\\s*(.*?)\\s*,\\s*(.*?)\\s*(?:\\[(.*)\\])?\\s*$" ) );
3407 const QRegularExpressionMatch match = rx.match( input.toString() );
3408 if ( match.hasMatch() )
3409 {
3410 bool xMinOk = false;
3411 ( void )match.captured( 1 ).toDouble( &xMinOk );
3412 bool xMaxOk = false;
3413 ( void )match.captured( 2 ).toDouble( &xMaxOk );
3414 bool yMinOk = false;
3415 ( void )match.captured( 3 ).toDouble( &yMinOk );
3416 bool yMaxOk = false;
3417 ( void )match.captured( 4 ).toDouble( &yMaxOk );
3418 if ( xMinOk && xMaxOk && yMinOk && yMaxOk )
3419 return true;
3420 }
3421
3422 // try as layer extent
3423 return QgsProcessingUtils::mapLayerFromString( input.toString(), *context );
3424}
3425
3426QString QgsProcessingParameterExtent::valueAsPythonString( const QVariant &value, QgsProcessingContext &context ) const
3427{
3428 if ( !value.isValid() )
3429 return QStringLiteral( "None" );
3430
3431 if ( value.userType() == QMetaType::type( "QgsProperty" ) )
3432 return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
3433
3434 if ( value.userType() == QMetaType::type( "QgsRectangle" ) )
3435 {
3436 const QgsRectangle r = value.value<QgsRectangle>();
3437 return QStringLiteral( "'%1, %3, %2, %4'" ).arg( qgsDoubleToString( r.xMinimum() ),
3440 qgsDoubleToString( r.yMaximum() ) );
3441 }
3442 else if ( value.userType() == QMetaType::type( "QgsReferencedRectangle" ) )
3443 {
3444 const QgsReferencedRectangle r = value.value<QgsReferencedRectangle>();
3445 return QStringLiteral( "'%1, %3, %2, %4 [%5]'" ).arg( qgsDoubleToString( r.xMinimum() ),
3448 qgsDoubleToString( r.yMaximum() ), r.crs().authid() );
3449 }
3450 else if ( value.userType() == QMetaType::type( "QgsGeometry" ) )
3451 {
3452 const QgsGeometry g = value.value<QgsGeometry>();
3453 if ( !g.isNull() )
3454 {
3455 const QString wkt = g.asWkt();
3456 return QStringLiteral( "QgsGeometry.fromWkt('%1')" ).arg( wkt );
3457 }
3458 }
3459
3460 QVariantMap p;
3461 p.insert( name(), value );
3462 QgsMapLayer *layer = QgsProcessingParameters::parameterAsLayer( this, p, context );
3463 if ( layer )
3465
3467}
3468
3469QString QgsProcessingParameterExtent::valueAsString( const QVariant &value, QgsProcessingContext &context, bool &ok ) const
3470{
3472}
3473
3474QVariant QgsProcessingParameterExtent::valueAsJsonObject( const QVariant &value, QgsProcessingContext &context ) const
3475{
3477}
3478
3479QgsProcessingParameterExtent *QgsProcessingParameterExtent::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
3480{
3481 return new QgsProcessingParameterExtent( name, description, definition, isOptional );
3482}
3483
3484QgsProcessingParameterPoint::QgsProcessingParameterPoint( const QString &name, const QString &description, const QVariant &defaultValue, bool optional )
3485 : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
3486{
3487
3488}
3489
3491{
3492 return new QgsProcessingParameterPoint( *this );
3493}
3494
3496{
3497 if ( !input.isValid() )
3498 return mFlags & FlagOptional;
3499
3500 if ( input.userType() == QMetaType::type( "QgsProperty" ) )
3501 {
3502 return true;
3503 }
3504
3505 if ( input.userType() == QMetaType::type( "QgsPointXY" ) )
3506 {
3507 return true;
3508 }
3509 if ( input.userType() == QMetaType::type( "QgsReferencedPointXY" ) )
3510 {
3511 return true;
3512 }
3513 if ( input.userType() == QMetaType::type( "QgsGeometry" ) )
3514 {
3515 return true;
3516 }
3517
3518 if ( input.type() == QVariant::String )
3519 {
3520 if ( input.toString().isEmpty() )
3521 return mFlags & FlagOptional;
3522 }
3523
3524 const QRegularExpression rx( QStringLiteral( "^\\s*\\(?\\s*(.*?)\\s*,\\s*(.*?)\\s*(?:\\[(.*)\\])?\\s*\\)?\\s*$" ) );
3525
3526 const QRegularExpressionMatch match = rx.match( input.toString() );
3527 if ( match.hasMatch() )
3528 {
3529 bool xOk = false;
3530 ( void )match.captured( 1 ).toDouble( &xOk );
3531 bool yOk = false;
3532 ( void )match.captured( 2 ).toDouble( &yOk );
3533 return xOk && yOk;
3534 }
3535 else
3536 return false;
3537}
3538
3539QString QgsProcessingParameterPoint::valueAsPythonString( const QVariant &value, QgsProcessingContext &context ) const
3540{
3541 if ( !value.isValid() )
3542 return QStringLiteral( "None" );
3543
3544 if ( value.userType() == QMetaType::type( "QgsProperty" ) )
3545 return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
3546
3547 if ( value.userType() == QMetaType::type( "QgsPointXY" ) )
3548 {
3549 const QgsPointXY r = value.value<QgsPointXY>();
3550 return QStringLiteral( "'%1,%2'" ).arg( qgsDoubleToString( r.x() ),
3551 qgsDoubleToString( r.y() ) );
3552 }
3553 else if ( value.userType() == QMetaType::type( "QgsReferencedPointXY" ) )
3554 {
3555 const QgsReferencedPointXY r = value.value<QgsReferencedPointXY>();
3556 return QStringLiteral( "'%1,%2 [%3]'" ).arg( qgsDoubleToString( r.x() ),
3557 qgsDoubleToString( r.y() ),
3558 r.crs().authid() );
3559 }
3560 else if ( value.userType() == QMetaType::type( "QgsGeometry" ) )
3561 {
3562 const QgsGeometry g = value.value<QgsGeometry>();
3563 if ( !g.isNull() )
3564 {
3565 const QString wkt = g.asWkt();
3566 return QStringLiteral( "QgsGeometry.fromWkt('%1')" ).arg( wkt );
3567 }
3568 }
3569
3571}
3572
3573QgsProcessingParameterPoint *QgsProcessingParameterPoint::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
3574{
3575 return new QgsProcessingParameterPoint( name, description, definition, isOptional );
3576}
3577
3578QgsProcessingParameterGeometry::QgsProcessingParameterGeometry( const QString &name, const QString &description,
3579 const QVariant &defaultValue, bool optional, const QList<int> &geometryTypes, bool allowMultipart )
3580 : QgsProcessingParameterDefinition( name, description, defaultValue, optional ),
3581 mGeomTypes( geometryTypes ),
3582 mAllowMultipart( allowMultipart )
3583{
3584
3585}
3586
3588{
3589 return new QgsProcessingParameterGeometry( *this );
3590}
3591
3593{
3594 if ( !input.isValid() )
3595 return mFlags & FlagOptional;
3596
3597 if ( input.userType() == QMetaType::type( "QgsProperty" ) )
3598 {
3599 return true;
3600 }
3601
3602 const bool anyTypeAllowed = mGeomTypes.isEmpty() || mGeomTypes.contains( QgsWkbTypes::UnknownGeometry );
3603
3604 if ( input.userType() == QMetaType::type( "QgsGeometry" ) )
3605 {
3606 return ( anyTypeAllowed || mGeomTypes.contains( input.value<QgsGeometry>().type() ) ) &&
3607 ( mAllowMultipart || !input.value<QgsGeometry>().isMultipart() );
3608 }
3609
3610 if ( input.userType() == QMetaType::type( "QgsReferencedGeometry" ) )
3611 {
3612 return ( anyTypeAllowed || mGeomTypes.contains( input.value<QgsReferencedGeometry>().type() ) ) &&
3613 ( mAllowMultipart || !input.value<QgsReferencedGeometry>().isMultipart() );
3614 }
3615
3616 if ( input.userType() == QMetaType::type( "QgsPointXY" ) )
3617 {
3618 return anyTypeAllowed || mGeomTypes.contains( QgsWkbTypes::PointGeometry );
3619 }
3620
3621 if ( input.userType() == QMetaType::type( "QgsRectangle" ) )
3622 {
3623 return anyTypeAllowed || mGeomTypes.contains( QgsWkbTypes::PolygonGeometry );
3624 }
3625
3626 if ( input.userType() == QMetaType::type( "QgsReferencedPointXY" ) )
3627 {
3628 return anyTypeAllowed || mGeomTypes.contains( QgsWkbTypes::PointGeometry );
3629 }
3630
3631 if ( input.userType() == QMetaType::type( "QgsReferencedRectangle" ) )
3632 {
3633 return anyTypeAllowed || mGeomTypes.contains( QgsWkbTypes::PolygonGeometry );
3634 }
3635
3636 if ( input.type() == QVariant::String )
3637 {
3638 if ( input.toString().isEmpty() )
3639 return mFlags & FlagOptional;
3640 }
3641
3642 // Match against EWKT
3643 const QRegularExpression rx( QStringLiteral( "^\\s*(?:CRS=(.*);)?(.*?)$" ) );
3644
3645 const QRegularExpressionMatch match = rx.match( input.toString() );
3646 if ( match.hasMatch() )
3647 {
3648 const QgsGeometry g = QgsGeometry::fromWkt( match.captured( 2 ) );
3649 if ( ! g.isNull() )
3650 {
3651 return ( anyTypeAllowed || mGeomTypes.contains( g.type() ) ) && ( mAllowMultipart || !g.isMultipart() );
3652 }
3653 else
3654 {
3655 QgsMessageLog::logMessage( QObject::tr( "Error creating geometry: \"%1\"" ).arg( g.lastError() ), QObject::tr( "Processing" ) );
3656 }
3657 }
3658 return false;
3659}
3660
3662{
3664 {
3665 if ( !crs.isValid() )
3667 else
3668 return QgsProcessingUtils::stringToPythonLiteral( QStringLiteral( "CRS=%1;%2" ).arg( crs.authid().isEmpty() ? crs.toWkt( QgsCoordinateReferenceSystem::WKT_PREFERRED ) : crs.authid(), g.asWkt() ) );
3669 };
3670
3671 if ( !value.isValid() )
3672 return QStringLiteral( "None" );
3673
3674 if ( value.userType() == QMetaType::type( "QgsProperty" ) )
3675 return QStringLiteral( "QgsProperty.fromExpression(%1)" ).arg( QgsProcessingUtils::stringToPythonLiteral( value.value< QgsProperty >().asExpression() ) );
3676
3677 if ( value.userType() == QMetaType::type( "QgsGeometry" ) )
3678 {
3679 const QgsGeometry g = value.value<QgsGeometry>();
3680 if ( !g.isNull() )
3681 return asPythonString( g );
3682 }
3683
3684 if ( value.userType() == QMetaType::type( "QgsReferencedGeometry" ) )
3685 {
3686 const QgsReferencedGeometry g = value.value<QgsReferencedGeometry>();
3687 if ( !g.isNull() )
3688 return asPythonString( g, g.crs() );
3689 }
3690
3691 if ( value.userType() == QMetaType::type( "QgsPointXY" ) )
3692 {
3693 const QgsGeometry g = QgsGeometry::fromPointXY( value.value<QgsPointXY>() );
3694 if ( !g.isNull() )
3695 return asPythonString( g );
3696 }
3697
3698 if ( value.userType() == QMetaType::type( "QgsReferencedPointXY" ) )
3699 {
3701 if ( !g.isNull() )
3702 return asPythonString( g, g.crs() );
3703 }
3704
3705 if ( value.userType() == QMetaType::type( "QgsRectangle" ) )
3706 {
3707 const QgsGeometry g = QgsGeometry::fromRect( value.value<QgsRectangle>() );
3708 if ( !g.isNull() )
3709 return asPythonString( g );
3710 }
3711
3712 if ( value.userType() == QMetaType::type( "QgsReferencedRectangle" ) )
3713 {
3715 if ( !g.isNull() )
3716 return asPythonString( g, g.crs() );
3717 }
3718
3720}
3721
3723{
3724 QString code = QStringLiteral( "##%1=" ).arg( mName );
3725 if ( mFlags & FlagOptional )
3726 code += QLatin1String( "optional " );
3727 code += type() + ' ';
3728
3729 for ( const int type : mGeomTypes )
3730 {
3731 switch ( static_cast<QgsWkbTypes::GeometryType>( type ) )
3732 {
3734 code += QLatin1String( "point " );
3735 break;
3736
3738 code += QLatin1String( "line " );
3739 break;
3740
3742 code += QLatin1String( "polygon " );
3743 break;
3744
3745 default:
3746 code += QLatin1String( "unknown " );
3747 break;
3748 }
3749 }
3750
3751 code += mDefault.toString();
3752 return code.trimmed();
3753}
3754
3756{
3757 switch ( outputType )
3758 {
3760 {
3761 QString code = QStringLiteral( "QgsProcessingParameterGeometry('%1', %2" )
3763 if ( mFlags & FlagOptional )
3764 code += QLatin1String( ", optional=True" );
3765
3766 if ( !mGeomTypes.empty() )
3767 {
3768 auto geomTypeToString = []( QgsWkbTypes::GeometryType t ) -> QString
3769 {
3770 switch ( t )
3771 {
3773 return QStringLiteral( "PointGeometry" );
3774
3776 return QStringLiteral( "LineGeometry" );
3777
3779 return QStringLiteral( "PolygonGeometry" );
3780
3782 return QStringLiteral( "UnknownGeometry" );
3783
3785 return QStringLiteral( "NullGeometry" );
3786 }
3787 return QString();
3788 };
3789
3790 QStringList options;
3791 options.reserve( mGeomTypes.size() );
3792 for ( const int type : mGeomTypes )
3793 {
3794 options << QStringLiteral( " QgsWkbTypes.%1" ).arg( geomTypeToString( static_cast<QgsWkbTypes::GeometryType>( type ) ) );
3795 }
3796 code += QStringLiteral( ", geometryTypes=[%1 ]" ).arg( options.join( ',' ) );
3797 }
3798
3799 if ( ! mAllowMultipart )
3800 {
3801 code += QLatin1String( ", allowMultipart=False" );
3802 }
3803
3805 code += QStringLiteral( ", defaultValue=%1)" ).arg( valueAsPythonString( mDefault, c ) );
3806 return code;
3807 }
3808 }
3809 return QString();
3810}
3811
3813{
3815 QVariantList types;
3816 for ( const int type : mGeomTypes )
3817 {
3818 types << type;
3819 }
3820 map.insert( QStringLiteral( "geometrytypes" ), types );
3821 map.insert( QStringLiteral( "multipart" ), mAllowMultipart );
3822 return map;
3823}
3824
3826{
3828 mGeomTypes.clear();
3829 const QVariantList values = map.value( QStringLiteral( "geometrytypes" ) ).toList();
3830 for ( const QVariant &val : values )
3831 {
3832 mGeomTypes << val.toInt();
3833 }
3834 mAllowMultipart = map.value( QStringLiteral( "multipart" ) ).toBool();
3835 return true;
3836}
3837
3838QgsProcessingParameterGeometry *QgsProcessingParameterGeometry::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
3839{
3840 return new QgsProcessingParameterGeometry( name, description, definition, isOptional );
3841}
3842
3843QgsProcessingParameterFile::QgsProcessingParameterFile( const QString &name, const QString &description, Behavior behavior, const QString &extension, const QVariant &defaultValue, bool optional, const QString &fileFilter )
3844 : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
3845 , mBehavior( behavior )
3846 , mExtension( fileFilter.isEmpty() ? extension : QString() )
3847 , mFileFilter( fileFilter.isEmpty() && extension.isEmpty() ? QObject::tr( "All files (*.*)" ) : fileFilter )
3848{
3849
3850}
3851
3853{
3854 return new QgsProcessingParameterFile( *this );
3855}
3856
3858{
3859 if ( !input.isValid() )
3860 return mFlags & FlagOptional;
3861
3862 if ( input.userType() == QMetaType::type( "QgsProperty" ) )
3863 {
3864 return true;
3865 }
3866
3867 const QString string = input.toString().trimmed();
3868
3869 if ( input.type() != QVariant::String || string.isEmpty() )
3870 return mFlags & FlagOptional;
3871
3872 switch ( mBehavior )
3873 {
3874 case File:
3875 {
3876 if ( !mExtension.isEmpty() )
3877 {
3878 return string.endsWith( mExtension, Qt::CaseInsensitive );
3879 }
3880 else if ( !mFileFilter.isEmpty() )
3881 {
3882 return QgsFileUtils::fileMatchesFilter( string, mFileFilter );
3883 }
3884 else
3885 {
3886 return true;
3887 }
3888 }
3889
3890 case Folder:
3891 return true;
3892 }
3893 return true;
3894}
3895
3897{
3898 QString code = QStringLiteral( "##%1=" ).arg( mName );
3899 if ( mFlags & FlagOptional )
3900 code += QLatin1String( "optional " );
3901 code += ( mBehavior == File ? QStringLiteral( "file" ) : QStringLiteral( "folder" ) ) + ' ';
3902 code += mDefault.toString();
3903 return code.trimmed();
3904}
3905
3907{
3908 switch ( outputType )
3909 {
3911 {
3912
3913 QString code = QStringLiteral( "QgsProcessingParameterFile('%1', %2" )
3915 if ( mFlags & FlagOptional )
3916 code += QLatin1String( ", optional=True" );
3917 code += QStringLiteral( ", behavior=%1" ).arg( mBehavior == File ? QStringLiteral( "QgsProcessingParameterFile.File" ) : QStringLiteral( "QgsProcessingParameterFile.Folder" ) );
3918 if ( !mExtension.isEmpty() )
3919 code += QStringLiteral( ", extension='%1'" ).arg( mExtension );
3920 if ( !mFileFilter.isEmpty() )
3921 code += QStringLiteral( ", fileFilter='%1'" ).arg( mFileFilter );
3923 code += QStringLiteral( ", defaultValue=%1)" ).arg( valueAsPythonString( mDefault, c ) );
3924 return code;
3925 }
3926 }
3927 return QString();
3928}
3929
3931{
3932 switch ( mBehavior )
3933 {
3934 case File:
3935 {
3936 if ( !mFileFilter.isEmpty() )
3937 return mFileFilter != QObject::tr( "All files (*.*)" ) ? mFileFilter + QStringLiteral( ";;" ) + QObject::tr( "All files (*.*)" ) : mFileFilter;
3938 else if ( !mExtension.isEmpty() )
3939 return QObject::tr( "%1 files" ).arg( mExtension.toUpper() ) + QStringLiteral( " (*." ) + mExtension.toLower() + QStringLiteral( ");;" ) + QObject::tr( "All files (*.*)" );
3940 else
3941 return QObject::tr( "All files (*.*)" );
3942 }
3943
3944 case Folder:
3945 return QString();
3946 }
3947 return QString();
3948}
3949
3950void QgsProcessingParameterFile::setExtension( const QString &extension )
3951{
3952 mExtension = extension;
3953 mFileFilter.clear();
3954}
3955
3957{
3958 return mFileFilter;
3959}
3960
3962{
3963 mFileFilter = filter;
3964 mExtension.clear();
3965}
3966
3968{
3970 map.insert( QStringLiteral( "behavior" ), mBehavior );
3971 map.insert( QStringLiteral( "extension" ), mExtension );
3972 map.insert( QStringLiteral( "filefilter" ), mFileFilter );
3973 return map;
3974}
3975
3977{
3979 mBehavior = static_cast< Behavior >( map.value( QStringLiteral( "behavior" ) ).toInt() );
3980 mExtension = map.value( QStringLiteral( "extension" ) ).toString();
3981 mFileFilter = map.value( QStringLiteral( "filefilter" ) ).toString();
3982 return true;
3983}
3984
3985QgsProcessingParameterFile *QgsProcessingParameterFile::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition, QgsProcessingParameterFile::Behavior behavior )
3986{
3987 return new QgsProcessingParameterFile( name, description, behavior, QString(), definition, isOptional );
3988}
3989
3990QgsProcessingParameterMatrix::QgsProcessingParameterMatrix( const QString &name, const QString &description, int numberRows, bool fixedNumberRows, const QStringList &headers, const QVariant &defaultValue, bool optional )
3991 : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
3992 , mHeaders( headers )
3993 , mNumberRows( numberRows )
3994 , mFixedNumberRows( fixedNumberRows )
3995{
3996
3997}
3998
4000{
4001 return new QgsProcessingParameterMatrix( *this );
4002}
4003
4005{
4006 if ( !input.isValid() )
4007 return mFlags & FlagOptional;
4008
4009 if ( input.type() == QVariant::String )
4010 {
4011 if ( input.toString().isEmpty() )
4012 return mFlags & FlagOptional;
4013 return true;
4014 }
4015 else if ( input.type() == QVariant::List )
4016 {
4017 if ( input.toList().isEmpty() )
4018 return mFlags & FlagOptional;
4019 return true;
4020 }
4021 else if ( input.type() == QVariant::Double || input.type() == QVariant::Int )
4022 {
4023 return true;
4024 }
4025
4026 return false;
4027}
4028
4029QString QgsProcessingParameterMatrix::valueAsPythonString( const QVariant &value, QgsProcessingContext &context ) const
4030{
4031 if ( !value.isValid() )
4032 return QStringLiteral( "None" );
4033
4034 if ( value.userType() == QMetaType::type( "QgsProperty" ) )
4035 return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
4036
4037 QVariantMap p;
4038 p.insert( name(), value );
4039 const QVariantList list = QgsProcessingParameters::parameterAsMatrix( this, p, context );
4040
4042}
4043
4045{
4046 switch ( outputType )
4047 {
4049 {
4050 QString code = QStringLiteral( "QgsProcessingParameterMatrix('%1', %2" )
4052 if ( mFlags & FlagOptional )
4053 code += QLatin1String( ", optional=True" );
4054 code += QStringLiteral( ", numberRows=%1" ).arg( mNumberRows );
4055 code += QStringLiteral( ", hasFixedNumberRows=%1" ).arg( mFixedNumberRows ? QStringLiteral( "True" ) : QStringLiteral( "False" ) );
4056
4057 QStringList headers;
4058 headers.reserve( mHeaders.size() );
4059 for ( const QString &h : mHeaders )
4061 code += QStringLiteral( ", headers=[%1]" ).arg( headers.join( ',' ) );
4062
4064 code += QStringLiteral( ", defaultValue=%1)" ).arg( valueAsPythonString( mDefault, c ) );
4065 return code;
4066 }
4067 }
4068 return QString();
4069}
4070
4072{
4073 return mHeaders;
4074}
4075
4076void QgsProcessingParameterMatrix::setHeaders( const QStringList &headers )
4077{
4078 mHeaders = headers;
4079}
4080
4082{
4083 return mNumberRows;
4084}
4085
4087{
4088 mNumberRows = numberRows;
4089}
4090
4092{
4093 return mFixedNumberRows;
4094}
4095
4097{
4098 mFixedNumberRows = fixedNumberRows;
4099}
4100
4102{
4104 map.insert( QStringLiteral( "headers" ), mHeaders );
4105 map.insert( QStringLiteral( "rows" ), mNumberRows );
4106 map.insert( QStringLiteral( "fixed_number_rows" ), mFixedNumberRows );
4107 return map;
4108}
4109
4111{
4113 mHeaders = map.value( QStringLiteral( "headers" ) ).toStringList();
4114 mNumberRows = map.value( QStringLiteral( "rows" ) ).toInt();
4115 mFixedNumberRows = map.value( QStringLiteral( "fixed_number_rows" ) ).toBool();
4116 return true;
4117}
4118
4119QgsProcessingParameterMatrix *QgsProcessingParameterMatrix::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
4120{
4121 return new QgsProcessingParameterMatrix( name, description, 0, false, QStringList(), definition.isEmpty() ? QVariant() : definition, isOptional );
4122}
4123
4124QgsProcessingParameterMultipleLayers::QgsProcessingParameterMultipleLayers( const QString &name, const QString &description, QgsProcessing::SourceType layerType, const QVariant &defaultValue, bool optional )
4125 : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
4126 , mLayerType( layerType )
4127{
4128
4129}
4130
4132{
4133 return new QgsProcessingParameterMultipleLayers( *this );
4134}
4135
4137{
4138 if ( !input.isValid() )
4139 return mFlags & FlagOptional;
4140
4141 if ( mLayerType != QgsProcessing::TypeFile )
4142 {
4143 if ( qobject_cast< QgsMapLayer * >( qvariant_cast<QObject *>( input ) ) )
4144 {
4145 return true;
4146 }
4147 }
4148
4149 if ( input.type() == QVariant::String )
4150 {
4151 if ( input.toString().isEmpty() )
4152 return mFlags & FlagOptional;
4153
4154 if ( mMinimumNumberInputs > 1 )
4155 return false;
4156
4157 if ( !context )
4158 return true;
4159
4160 if ( mLayerType != QgsProcessing::TypeFile )
4161 return QgsProcessingUtils::mapLayerFromString( input.toString(), *context );
4162 else
4163 return true;
4164 }
4165 else if ( input.type() == QVariant::List )
4166 {
4167 if ( input.toList().count() < mMinimumNumberInputs )
4168 return mFlags & FlagOptional;
4169
4170 if ( mMinimumNumberInputs > input.toList().count() )
4171 return false;
4172
4173 if ( !context )
4174 return true;
4175
4176 if ( mLayerType != QgsProcessing::TypeFile )
4177 {
4178 const auto constToList = input.toList();
4179 for ( const QVariant &v : constToList )
4180 {
4181 if ( qobject_cast< QgsMapLayer * >( qvariant_cast<QObject *>( v ) ) )
4182 continue;
4183
4184 if ( !QgsProcessingUtils::mapLayerFromString( v.toString(), *context ) )
4185 return false;
4186 }
4187 }
4188 return true;
4189 }
4190 else if ( input.type() == QVariant::StringList )
4191 {
4192 if ( input.toStringList().count() < mMinimumNumberInputs )
4193 return mFlags & FlagOptional;
4194
4195 if ( mMinimumNumberInputs > input.toStringList().count() )
4196 return false;
4197
4198 if ( !context )
4199 return true;
4200
4201 if ( mLayerType != QgsProcessing::TypeFile )
4202 {
4203 const auto constToStringList = input.toStringList();
4204 for ( const QString &v : constToStringList )
4205 {
4206 if ( !QgsProcessingUtils::mapLayerFromString( v, *context ) )
4207 return false;
4208 }
4209 }
4210 return true;
4211 }
4212 return false;
4213}
4214
4216{
4217 if ( !value.isValid() )
4218 return QStringLiteral( "None" );
4219
4220 if ( value.userType() == QMetaType::type( "QgsProperty" ) )
4221 return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
4222
4223 if ( mLayerType == QgsProcessing::TypeFile )
4224 {
4225 QStringList parts;
4226 if ( value.type() == QVariant::StringList )
4227 {
4228 const QStringList list = value.toStringList();
4229 parts.reserve( list.count() );
4230 for ( const QString &v : list )
4232 }
4233 else if ( value.type() == QVariant::List )
4234 {
4235 const QVariantList list = value.toList();
4236 parts.reserve( list.count() );
4237 for ( const QVariant &v : list )
4238 parts << QgsProcessingUtils::stringToPythonLiteral( v.toString() );
4239 }
4240 if ( !parts.isEmpty() )
4241 return parts.join( ',' ).prepend( '[' ).append( ']' );
4242 }
4243 else
4244 {
4245 QVariantMap p;
4246 p.insert( name(), value );
4247 const QList<QgsMapLayer *> list = QgsProcessingParameters::parameterAsLayerList( this, p, context );
4248 if ( !list.isEmpty() )
4249 {
4250 QStringList parts;
4251 parts.reserve( list.count() );
4252 for ( const QgsMapLayer *layer : list )
4253 {
4255 }
4256 return parts.join( ',' ).prepend( '[' ).append( ']' );
4257 }
4258 }
4259
4261}
4262
4263QString QgsProcessingParameterMultipleLayers::valueAsString( const QVariant &value, QgsProcessingContext &context, bool &ok ) const
4264{
4266}
4267
4269{
4271}
4272
4274{
4275 QString code = QStringLiteral( "##%1=" ).arg( mName );
4276 if ( mFlags & FlagOptional )
4277 code += QLatin1String( "optional " );
4278 switch ( mLayerType )
4279 {
4281 code += QLatin1String( "multiple raster" );
4282 break;
4283
4285 code += QLatin1String( "multiple file" );
4286 break;
4287
4288 default:
4289 code += QLatin1String( "multiple vector" );
4290 break;
4291 }
4292 code += ' ';
4293 if ( mDefault.type() == QVariant::List )
4294 {
4295 QStringList parts;
4296 const auto constToList = mDefault.toList();
4297 for ( const QVariant &var : constToList )
4298 {
4299 parts << var.toString();
4300 }
4301 code += parts.join( ',' );
4302 }
4303 else if ( mDefault.type() == QVariant::StringList )
4304 {
4305 code += mDefault.toStringList().join( ',' );
4306 }
4307 else
4308 {
4309 code += mDefault.toString();
4310 }
4311 return code.trimmed();
4312}
4313
4315{
4316 switch ( outputType )
4317 {
4319 {
4320 QString code = QStringLiteral( "QgsProcessingParameterMultipleLayers('%1', %2" )
4322 if ( mFlags & FlagOptional )
4323 code += QLatin1String( ", optional=True" );
4324
4325 const QString layerType = QStringLiteral( "QgsProcessing.%1" ).arg( QgsProcessing::sourceTypeToString( mLayerType ) );
4326
4327 code += QStringLiteral( ", layerType=%1" ).arg( layerType );
4329 code += QStringLiteral( ", defaultValue=%1)" ).arg( valueAsPythonString( mDefault, c ) );
4330 return code;
4331 }
4332 }
4333 return QString();
4334}
4335
4337{
4338 const QStringList exts;
4339 switch ( mLayerType )
4340 {
4342 return QObject::tr( "All files (*.*)" );
4343
4345 return QgsProviderRegistry::instance()->fileRasterFilters() + QStringLiteral( ";;" ) + QObject::tr( "All files (*.*)" );
4346
4352 return QgsProviderRegistry::instance()->fileVectorFilters() + QStringLiteral( ";;" ) + QObject::tr( "All files (*.*)" );
4353
4355 return QgsProviderRegistry::instance()->fileMeshFilters() + QStringLiteral( ";;" ) + QObject::tr( "All files (*.*)" );
4356
4358 return QgsProviderRegistry::instance()->filePointCloudFilters() + QStringLiteral( ";;" ) + QObject::tr( "All files (*.*)" );
4359
4364 }
4365 return QString();
4366}
4367
4369{
4370 return mLayerType;
4371}
4372
4374{
4375 mLayerType = type;
4376}
4377
4379{
4380 return mMinimumNumberInputs;
4381}
4382
4384{
4385 if ( mMinimumNumberInputs >= 1 || !( flags() & QgsProcessingParameterDefinition::FlagOptional ) )
4386 mMinimumNumberInputs = minimumNumberInputs;
4387}
4388
4390{
4392 map.insert( QStringLiteral( "layer_type" ), mLayerType );
4393 map.insert( QStringLiteral( "min_inputs" ), mMinimumNumberInputs );
4394 return map;
4395}
4396
4398{
4400 mLayerType = static_cast< QgsProcessing::SourceType >( map.value( QStringLiteral( "layer_type" ) ).toInt() );
4401 mMinimumNumberInputs = map.value( QStringLiteral( "min_inputs" ) ).toInt();
4402 return true;
4403}
4404
4405QgsProcessingParameterMultipleLayers *QgsProcessingParameterMultipleLayers::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
4406{
4407 QString type = definition;
4408 QString defaultVal;
4409 const QRegularExpression re( QStringLiteral( "(.*?)\\s+(.*)" ) );
4410 const QRegularExpressionMatch m = re.match( definition );
4411 if ( m.hasMatch() )
4412 {
4413 type = m.captured( 1 ).toLower().trimmed();
4414 defaultVal = m.captured( 2 );
4415 }
4417 if ( type == QLatin1String( "vector" ) )
4419 else if ( type == QLatin1String( "raster" ) )
4421 else if ( type == QLatin1String( "file" ) )
4423 return new QgsProcessingParameterMultipleLayers( name, description, layerType, defaultVal.isEmpty() ? QVariant() : defaultVal, isOptional );
4424}
4425
4426QgsProcessingParameterNumber::QgsProcessingParameterNumber( const QString &name, const QString &description, Type type, const QVariant &defaultValue, bool optional, double minValue, double maxValue )
4427 : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
4428 , mMin( minValue )
4429 , mMax( maxValue )
4430 , mDataType( type )
4431{
4432 if ( mMin >= mMax )
4433 {
4434 QgsMessageLog::logMessage( QObject::tr( "Invalid number parameter \"%1\": min value %2 is >= max value %3!" ).arg( name ).arg( mMin ).arg( mMax ), QObject::tr( "Processing" ) );
4435 }
4436}
4437
4439{
4440 return new QgsProcessingParameterNumber( *this );
4441}
4442
4444{
4445 QVariant input = value;
4446 if ( !input.isValid() )
4447 {
4448 if ( !defaultValue().isValid() )
4449 return mFlags & FlagOptional;
4450
4451 input = defaultValue();
4452 }
4453
4454 if ( input.userType() == QMetaType::type( "QgsProperty" ) )
4455 {
4456 return true;
4457 }
4458
4459 bool ok = false;
4460 const double res = input.toDouble( &ok );
4461 if ( !ok )
4462 return mFlags & FlagOptional;
4463
4464 return !( res < mMin || res > mMax );
4465}
4466
4468{
4469 if ( !value.isValid() )
4470 return QStringLiteral( "None" );
4471
4472 if ( value.userType() == QMetaType::type( "QgsProperty" ) )
4473 return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
4474
4475 return value.toString();
4476}
4477
4479{
4481 QStringList parts;
4482 if ( mMin > std::numeric_limits<double>::lowest() + 1 )
4483 parts << QObject::tr( "Minimum value: %1" ).arg( mMin );
4484 if ( mMax < std::numeric_limits<double>::max() )
4485 parts << QObject::tr( "Maximum value: %1" ).arg( mMax );
4486 if ( mDefault.isValid() )
4487 parts << QObject::tr( "Default value: %1" ).arg( mDataType == Integer ? mDefault.toInt() : mDefault.toDouble() );
4488 const QString extra = parts.join( QLatin1String( "<br />" ) );
4489 if ( !extra.isEmpty() )
4490 text += QStringLiteral( "<p>%1</p>" ).arg( extra );
4491 return text;
4492}
4493
4495{
4496 switch ( outputType )
4497 {
4499 {
4500 QString code = QStringLiteral( "QgsProcessingParameterNumber('%1', %2" )
4502 if ( mFlags & FlagOptional )
4503 code += QLatin1String( ", optional=True" );
4504
4505 code += QStringLiteral( ", type=%1" ).arg( mDataType == Integer ? QStringLiteral( "QgsProcessingParameterNumber.Integer" ) : QStringLiteral( "QgsProcessingParameterNumber.Double" ) );
4506
4507 if ( mMin != std::numeric_limits<double>::lowest() + 1 )
4508 code += QStringLiteral( ", minValue=%1" ).arg( mMin );
4509 if ( mMax != std::numeric_limits<double>::max() )
4510 code += QStringLiteral( ", maxValue=%1" ).arg( mMax );
4512 code += QStringLiteral( ", defaultValue=%1)" ).arg( valueAsPythonString( mDefault, c ) );
4513 return code;
4514 }
4515 }
4516 return QString();
4517}
4518
4520{
4521 return mMin;
4522}
4523
4525{
4526 mMin = min;
4527}
4528
4530{
4531 return mMax;
4532}
4533
4535{
4536 mMax = max;
4537}
4538
4540{
4541 return mDataType;
4542}
4543
4545{
4546 mDataType = dataType;
4547}
4548
4550{
4552 map.insert( QStringLiteral( "min" ), mMin );
4553 map.insert( QStringLiteral( "max" ), mMax );
4554 map.insert( QStringLiteral( "data_type" ), mDataType );
4555 return map;
4556}
4557
4559{
4561 mMin = map.value( QStringLiteral( "min" ) ).toDouble();
4562 mMax = map.value( QStringLiteral( "max" ) ).toDouble();
4563 mDataType = static_cast< Type >( map.value( QStringLiteral( "data_type" ) ).toInt() );
4564 return true;
4565}
4566
4567QgsProcessingParameterNumber *QgsProcessingParameterNumber::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
4568{
4569 return new QgsProcessingParameterNumber( name, description, Double, definition.isEmpty() ? QVariant()
4570 : ( definition.toLower().trimmed() == QLatin1String( "none" ) ? QVariant() : definition ), isOptional );
4571}
4572
4573QgsProcessingParameterRange::QgsProcessingParameterRange( const QString &name, const QString &description, QgsProcessingParameterNumber::Type type, const QVariant &defaultValue, bool optional )
4574 : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
4575 , mDataType( type )
4576{
4577
4578}
4579
4581{
4582 return new QgsProcessingParameterRange( *this );
4583}
4584
4586{
4587 if ( !input.isValid() )
4588 return mFlags & FlagOptional;
4589
4590 if ( input.userType() == QMetaType::type( "QgsProperty" ) )
4591 {
4592 return true;
4593 }
4594
4595 if ( input.type() == QVariant::String )
4596 {
4597 const QStringList list = input.toString().split( ',' );
4598 if ( list.count() != 2 )
4599 return mFlags & FlagOptional;
4600 bool ok = false;
4601 list.at( 0 ).toDouble( &ok );
4602 bool ok2 = false;
4603 list.at( 1 ).toDouble( &ok2 );
4604 if ( !ok || !ok2 )
4605 return mFlags & FlagOptional;
4606 return true;
4607 }
4608 else if ( input.type() == QVariant::List )
4609 {
4610 if ( input.toList().count() != 2 )
4611 return mFlags & FlagOptional;
4612
4613 bool ok = false;
4614 input.toList().at( 0 ).toDouble( &ok );
4615 bool ok2 = false;
4616 input.toList().at( 1 ).toDouble( &ok2 );
4617 if ( !ok || !ok2 )
4618 return mFlags & FlagOptional;
4619 return true;
4620 }
4621
4622 return false;
4623}
4624
4625QString QgsProcessingParameterRange::valueAsPythonString( const QVariant &value, QgsProcessingContext &context ) const
4626{
4627 if ( !value.isValid() )
4628 return QStringLiteral( "None" );
4629
4630 if ( value.userType() == QMetaType::type( "QgsProperty" ) )
4631 return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
4632
4633 QVariantMap p;
4634 p.insert( name(), value );
4635 const QList< double > parts = QgsProcessingParameters::parameterAsRange( this, p, context );
4636
4637 QStringList stringParts;
4638 const auto constParts = parts;
4639 for ( const double v : constParts )
4640 {
4641 stringParts << QString::number( v );
4642 }
4643 return stringParts.join( ',' ).prepend( '[' ).append( ']' );
4644}
4645
4647{
4648 switch ( outputType )
4649 {
4651 {
4652 QString code = QStringLiteral( "QgsProcessingParameterRange('%1', %2" )
4654 if ( mFlags & FlagOptional )
4655 code += QLatin1String( ", optional=True" );
4656
4657 code += QStringLiteral( ", type=%1" ).arg( mDataType == QgsProcessingParameterNumber::Integer ? QStringLiteral( "QgsProcessingParameterNumber.Integer" ) : QStringLiteral( "QgsProcessingParameterNumber.Double" ) );
4658
4660 code += QStringLiteral( ", defaultValue=%1)" ).arg( valueAsPythonString( mDefault, c ) );
4661 return code;
4662 }
4663 }
4664 return QString();
4665}
4666
4668{
4669 return mDataType;
4670}
4671
4673{
4674 mDataType = dataType;
4675}
4676
4678{
4680 map.insert( QStringLiteral( "data_type" ), mDataType );
4681 return map;
4682}
4683
4685{
4687 mDataType = static_cast< QgsProcessingParameterNumber::Type >( map.value( QStringLiteral( "data_type" ) ).toInt() );
4688 return true;
4689}
4690
4691QgsProcessingParameterRange *QgsProcessingParameterRange::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
4692{
4693 return new QgsProcessingParameterRange( name, description, QgsProcessingParameterNumber::Double, definition.isEmpty() ? QVariant()
4694 : ( definition.toLower().trimmed() == QLatin1String( "none" ) ? QVariant() : definition ), isOptional );
4695}
4696
4697QgsProcessingParameterRasterLayer::QgsProcessingParameterRasterLayer( const QString &name, const QString &description, const QVariant &defaultValue, bool optional )
4698 : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
4699{
4700
4701}
4702
4704{
4705 return new QgsProcessingParameterRasterLayer( *this );
4706}
4707
4709{
4710 if ( !input.isValid() )
4711 return mFlags & FlagOptional;
4712
4713 if ( input.userType() == QMetaType::type( "QgsProperty" ) )
4714 {
4715 return true;
4716 }
4717
4718 if ( qobject_cast< QgsRasterLayer * >( qvariant_cast<QObject *>( input ) ) )
4719 return true;
4720
4721 if ( input.type() != QVariant::String || input.toString().isEmpty() )
4722 return mFlags & FlagOptional;
4723
4724 if ( !context )
4725 {
4726 // that's as far as we can get without a context
4727 return true;
4728 }
4729
4730 // try to load as layer
4731 if ( QgsProcessingUtils::mapLayerFromString( input.toString(), *context, true, QgsProcessingUtils::LayerHint::Raster ) )
4732 return true;
4733
4734 return false;
4735}
4736
4738{
4739 if ( !val.isValid() )
4740 return QStringLiteral( "None" );
4741
4742 if ( val.userType() == QMetaType::type( "QgsProperty" ) )
4743 return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( val.value< QgsProperty >().asExpression() );
4744
4745 QVariantMap p;
4746 p.insert( name(), val );
4750}
4751
4752QString QgsProcessingParameterRasterLayer::valueAsString( const QVariant &value, QgsProcessingContext &context, bool &ok ) const
4753{
4755}
4756
4758{
4760}
4761
4763{
4764 return QgsProviderRegistry::instance()->fileRasterFilters() + QStringLiteral( ";;" ) + QObject::tr( "All files (*.*)" );
4765}
4766
4767QgsProcessingParameterRasterLayer *QgsProcessingParameterRasterLayer::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
4768{
4769 return new QgsProcessingParameterRasterLayer( name, description, definition.isEmpty() ? QVariant() : definition, isOptional );
4770}
4771
4772QgsProcessingParameterEnum::QgsProcessingParameterEnum( const QString &name, const QString &description, const QStringList &options, bool allowMultiple, const QVariant &defaultValue, bool optional, bool usesStaticStrings )
4773 : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
4774 , mOptions( options )
4775 , mAllowMultiple( allowMultiple )
4776 , mUsesStaticStrings( usesStaticStrings )
4777{
4778
4779}
4780
4782{
4783 return new QgsProcessingParameterEnum( *this );
4784}
4785
4787{
4788 QVariant input = value;
4789 if ( !input.isValid() )
4790 {
4791 if ( !defaultValue().isValid() )
4792 return mFlags & FlagOptional;
4793
4794 input = defaultValue();
4795 }
4796
4797 if ( input.userType() == QMetaType::type( "QgsProperty" ) )
4798 {
4799 return true;
4800 }
4801
4802 if ( mUsesStaticStrings )
4803 {
4804 if ( input.type() == QVariant::List )
4805 {
4806 if ( !mAllowMultiple )
4807 return false;
4808
4809 const QVariantList values = input.toList();
4810 if ( values.empty() && !( mFlags & FlagOptional ) )
4811 return false;
4812
4813 for ( const QVariant &val : values )
4814 {
4815 if ( !mOptions.contains( val.toString() ) )
4816 return false;
4817 }
4818
4819 return true;
4820 }
4821 else if ( input.type() == QVariant::StringList )
4822 {
4823 if ( !mAllowMultiple )
4824 return false;
4825
4826 const QStringList values = input.toStringList();
4827
4828 if ( values.empty() && !( mFlags & FlagOptional ) )
4829 return false;
4830
4831 if ( values.count() > 1 && !mAllowMultiple )
4832 return false;
4833
4834 for ( const QString &val : values )
4835 {
4836 if ( !mOptions.contains( val ) )
4837 return false;
4838 }
4839 return true;
4840 }
4841 else if ( input.type() == QVariant::String )
4842 {
4843 const QStringList parts = input.toString().split( ',' );
4844 if ( parts.count() > 1 && !mAllowMultiple )
4845 return false;
4846
4847 const auto constParts = parts;
4848 for ( const QString &part : constParts )
4849 {
4850 if ( !mOptions.contains( part ) )
4851 return false;
4852 }
4853 return true;
4854 }
4855 }
4856 else
4857 {
4858 if ( input.type() == QVariant::List )
4859 {
4860 if ( !mAllowMultiple )
4861 return false;
4862
4863 const QVariantList values = input.toList();
4864 if ( values.empty() && !( mFlags & FlagOptional ) )
4865 return false;
4866
4867 for ( const QVariant &val : values )
4868 {
4869 bool ok = false;
4870 const int res = val.toInt( &ok );
4871 if ( !ok )
4872 return false;
4873 else if ( res < 0 || res >= mOptions.count() )
4874 return false;
4875 }
4876
4877 return true;
4878 }
4879 else if ( input.type() == QVariant::String )
4880 {
4881 const QStringList parts = input.toString().split( ',' );
4882 if ( parts.count() > 1 && !mAllowMultiple )
4883 return false;
4884
4885 const auto constParts = parts;
4886 for ( const QString &part : constParts )
4887 {
4888 bool ok = false;
4889 const int res = part.toInt( &ok );
4890 if ( !ok )
4891 return false;
4892 else if ( res < 0 || res >= mOptions.count() )
4893 return false;
4894 }
4895 return true;
4896 }
4897 else if ( input.type() == QVariant::Int || input.type() == QVariant::Double )
4898 {
4899 bool ok = false;
4900 const int res = input.toInt( &ok );
4901 if ( !ok )
4902 return false;
4903 else if ( res >= 0 && res < mOptions.count() )
4904 return true;
4905 }
4906 }
4907
4908 return false;
4909}
4910
4912{
4913 if ( !value.isValid() )
4914 return QStringLiteral( "None" );
4915
4916 if ( value.userType() == QMetaType::type( "QgsProperty" ) )
4917 return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
4918
4919 if ( mUsesStaticStrings )
4920 {
4921 if ( value.type() == QVariant::StringList )
4922 {
4923 QStringList parts;
4924 const QStringList constList = value.toStringList();
4925 for ( const QString &val : constList )
4926 {
4928 }
4929 return parts.join( ',' ).prepend( '[' ).append( ']' );
4930 }
4931 else if ( value.type() == QVariant::String )
4932 {
4933 QStringList parts;
4934 const QStringList constList = value.toString().split( ',' );
4935 if ( constList.count() > 1 )
4936 {
4937 for ( const QString &val : constList )
4938 {
4940 }
4941 return parts.join( ',' ).prepend( '[' ).append( ']' );
4942 }
4943 }
4944
4945 return QgsProcessingUtils::stringToPythonLiteral( value.toString() );
4946 }
4947 else
4948 {
4949 if ( value.type() == QVariant::List )
4950 {
4951 QStringList parts;
4952 const auto constToList = value.toList();
4953 for ( const QVariant &val : constToList )
4954 {
4955 parts << QString::number( static_cast< int >( val.toDouble() ) );
4956 }
4957 return parts.join( ',' ).prepend( '[' ).append( ']' );
4958 }
4959 else if ( value.type() == QVariant::String )
4960 {
4961 const QStringList parts = value.toString().split( ',' );
4962 if ( parts.count() > 1 )
4963 {
4964 return parts.join( ',' ).prepend( '[' ).append( ']' );
4965 }
4966 }
4967
4968 return QString::number( static_cast< int >( value.toDouble() ) );
4969 }
4970}
4971
4973{
4974 if ( !value.isValid() )
4975 return QString();
4976
4977 if ( value.userType() == QMetaType::type( "QgsProperty" ) )
4978 return QString();
4979
4980 if ( mUsesStaticStrings )
4981 {
4982 return QString();
4983 }
4984 else
4985 {
4986 if ( value.type() == QVariant::List )
4987 {
4988 QStringList parts;
4989 const QVariantList toList = value.toList();
4990 parts.reserve( toList.size() );
4991 for ( const QVariant &val : toList )
4992 {
4993 parts << mOptions.value( static_cast< int >( val.toDouble() ) );
4994 }
4995 return parts.join( ',' );
4996 }
4997 else if ( value.type() == QVariant::String )
4998 {
4999 const QStringList parts = value.toString().split( ',' );
5000 QStringList comments;
5001 if ( parts.count() > 1 )
5002 {
5003 for ( const QString &part : parts )
5004 {
5005 bool ok = false;
5006 const int val = part.toInt( &ok );
5007 if ( ok )
5008 comments << mOptions.value( val );
5009 }
5010 return comments.join( ',' );
5011 }
5012 }
5013
5014 return mOptions.value( static_cast< int >( value.toDouble() ) );
5015 }
5016}
5017
5019{
5020 QString code = QStringLiteral( "##%1=" ).arg( mName );
5021 if ( mFlags & FlagOptional )
5022 code += QLatin1String( "optional " );
5023 code += QLatin1String( "enum " );
5024
5025 if ( mAllowMultiple )
5026 code += QLatin1String( "multiple " );
5027
5028 if ( mUsesStaticStrings )
5029 code += QLatin1String( "static " );
5030
5031 code += mOptions.join( ';' ) + ' ';
5032
5033 code += mDefault.toString();
5034 return code.trimmed();
5035}
5036
5038{
5039 switch ( outputType )
5040 {
5042 {
5043 QString code = QStringLiteral( "QgsProcessingParameterEnum('%1', %2" )
5045 if ( mFlags & FlagOptional )
5046 code += QLatin1String( ", optional=True" );
5047
5048 QStringList options;
5049 options.reserve( mOptions.size() );
5050 for ( const QString &o : mOptions )
5052 code += QStringLiteral( ", options=[%1]" ).arg( options.join( ',' ) );
5053
5054 code += QStringLiteral( ", allowMultiple=%1" ).arg( mAllowMultiple ? QStringLiteral( "True" ) : QStringLiteral( "False" ) );
5055
5056 code += QStringLiteral( ", usesStaticStrings=%1" ).arg( mUsesStaticStrings ? QStringLiteral( "True" ) : QStringLiteral( "False" ) );
5057
5059 code += QStringLiteral( ", defaultValue=%1)" ).arg( valueAsPythonString( mDefault, c ) );
5060
5061 return code;
5062 }
5063 }
5064 return QString();
5065}
5066
5068{
5069 return mOptions;
5070}
5071
5072void QgsProcessingParameterEnum::setOptions( const QStringList &options )
5073{
5074 mOptions = options;
5075}
5076
5078{
5079 return mAllowMultiple;
5080}
5081
5083{
5084 mAllowMultiple = allowMultiple;
5085}
5086
5088{
5089 return mUsesStaticStrings;
5090}
5091
5093{
5094 mUsesStaticStrings = usesStaticStrings;
5095}
5096
5098{
5100 map.insert( QStringLiteral( "options" ), mOptions );
5101 map.insert( QStringLiteral( "allow_multiple" ), mAllowMultiple );
5102 map.insert( QStringLiteral( "uses_static_strings" ), mUsesStaticStrings );
5103 return map;
5104}
5105
5107{
5109 mOptions = map.value( QStringLiteral( "options" ) ).toStringList();
5110 mAllowMultiple = map.value( QStringLiteral( "allow_multiple" ) ).toBool();
5111 mUsesStaticStrings = map.value( QStringLiteral( "uses_static_strings" ) ).toBool();
5112 return true;
5113}
5114
5115QgsProcessingParameterEnum *QgsProcessingParameterEnum::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
5116{
5117 QString defaultVal;
5118 QString def = definition;
5119
5120 bool multiple = false;
5121 if ( def.startsWith( QLatin1String( "multiple" ), Qt::CaseInsensitive ) )
5122 {
5123 multiple = true;
5124 def = def.mid( 9 );
5125 }
5126
5127 bool staticStrings = false;
5128 if ( def.startsWith( QLatin1String( "static" ), Qt::CaseInsensitive ) )
5129 {
5130 staticStrings = true;
5131 def = def.mid( 7 );
5132 }
5133
5134 const QRegularExpression re( QStringLiteral( "(.*)\\s+(.*?)$" ) );
5135 const QRegularExpressionMatch m = re.match( def );
5136 QString values = def;
5137 if ( m.hasMatch() )
5138 {
5139 values = m.captured( 1 ).trimmed();
5140 defaultVal = m.captured( 2 );
5141 }
5142
5143 return new QgsProcessingParameterEnum( name, description, values.split( ';' ), multiple, defaultVal.isEmpty() ? QVariant() : defaultVal, isOptional, staticStrings );
5144}
5145
5146QgsProcessingParameterString::QgsProcessingParameterString( const QString &name, const QString &description, const QVariant &defaultValue, bool multiLine, bool optional )
5147 : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
5148 , mMultiLine( multiLine )
5149{
5150
5151}
5152
5154{
5155 return new QgsProcessingParameterString( *this );
5156}
5157
5159{
5160 if ( QgsVariantUtils::isNull( value ) )
5161 return QStringLiteral( "None" );
5162
5163 if ( value.userType() == QMetaType::type( "QgsProperty" ) )
5164 return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
5165
5166 const QString s = value.toString();
5168}
5169