QGIS API Documentation 3.99.0-Master (09f76ad7019)
Loading...
Searching...
No Matches
qgsprocessingwidgetwrapperimpl.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsprocessingwidgetwrapperimpl.cpp
3 ---------------------
4 begin : August 2018
5 copyright : (C) 2018 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
19
20#include <memory>
21
23#include "qgsannotationlayer.h"
24#include "qgsapplication.h"
25#include "qgsauthconfigselect.h"
27#include "qgscolorbutton.h"
31#include "qgsdatetimeedit.h"
33#include "qgsdoublespinbox.h"
34#include "qgsdoublevalidator.h"
38#include "qgsextentwidget.h"
39#include "qgsfieldcombobox.h"
41#include "qgsfilewidget.h"
42#include "qgsfilterlineedit.h"
43#include "qgsgeometrywidget.h"
44#include "qgslayoutcombobox.h"
46#include "qgslayoutmanager.h"
47#include "qgsmapcanvas.h"
48#include "qgsmaplayercombobox.h"
49#include "qgsmapmouseevent.h"
51#include "qgsmessagebar.h"
53#include "qgspointcloudlayer.h"
54#include "qgsprintlayout.h"
66#include "qgsproject.h"
70#include "qgsscalewidget.h"
71#include "qgssettings.h"
72#include "qgssnapindicator.h"
73#include "qgsspinbox.h"
74#include "qgsunittypes.h"
75
76#include <QButtonGroup>
77#include <QCheckBox>
78#include <QComboBox>
79#include <QFileDialog>
80#include <QHBoxLayout>
81#include <QLabel>
82#include <QLineEdit>
83#include <QMenu>
84#include <QPlainTextEdit>
85#include <QRadioButton>
86#include <QString>
87#include <QToolButton>
88#include <QVBoxLayout>
89
90#include "moc_qgsprocessingwidgetwrapperimpl.cpp"
91
92using namespace Qt::StringLiterals;
93
95
96//
97// QgsProcessingBooleanWidgetWrapper
98//
99
100
101QgsProcessingBooleanParameterDefinitionWidget::QgsProcessingBooleanParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
102 : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
103{
104 QVBoxLayout *vlayout = new QVBoxLayout();
105 vlayout->setContentsMargins( 0, 0, 0, 0 );
106
107 mDefaultCheckBox = new QCheckBox( tr( "Checked" ) );
108 if ( const QgsProcessingParameterBoolean *boolParam = dynamic_cast<const QgsProcessingParameterBoolean *>( definition ) )
109 mDefaultCheckBox->setChecked( QgsProcessingParameters::parameterAsBool( boolParam, boolParam->defaultValueForGui(), context ) );
110 else
111 mDefaultCheckBox->setChecked( false );
112 vlayout->addWidget( mDefaultCheckBox );
113 setLayout( vlayout );
114}
115
116QgsProcessingParameterDefinition *QgsProcessingBooleanParameterDefinitionWidget::createParameter( const QString &name, const QString &description, Qgis::ProcessingParameterFlags flags ) const
117{
118 auto param = std::make_unique<QgsProcessingParameterBoolean>( name, description, mDefaultCheckBox->isChecked() );
119 param->setFlags( flags );
120 return param.release();
121}
122
123
124QgsProcessingBooleanWidgetWrapper::QgsProcessingBooleanWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type, QWidget *parent )
125 : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
126{
127}
128
129QWidget *QgsProcessingBooleanWidgetWrapper::createWidget()
130{
131 switch ( type() )
132 {
134 {
135 QString description = parameterDefinition()->description();
136 if ( parameterDefinition()->flags() & Qgis::ProcessingParameterFlag::Optional )
137 description = QObject::tr( "%1 [optional]" ).arg( description );
138
139 mCheckBox = new QCheckBox( description );
140 mCheckBox->setToolTip( parameterDefinition()->toolTip() );
141
142 connect( mCheckBox, &QCheckBox::toggled, this, [this] {
143 emit widgetValueHasChanged( this );
144 } );
145 return mCheckBox;
146 }
147
150 {
151 mComboBox = new QComboBox();
152 mComboBox->addItem( tr( "Yes" ), true );
153 mComboBox->addItem( tr( "No" ), false );
154 mComboBox->setToolTip( parameterDefinition()->toolTip() );
155
156 connect( mComboBox, qOverload<int>( &QComboBox::currentIndexChanged ), this, [this] {
157 emit widgetValueHasChanged( this );
158 } );
159
160 return mComboBox;
161 }
162 }
163 return nullptr;
164}
165
166QLabel *QgsProcessingBooleanWidgetWrapper::createLabel()
167{
168 // avoid creating labels in standard dialogs
169 if ( type() == Qgis::ProcessingMode::Standard )
170 return nullptr;
171 else
173}
174
175void QgsProcessingBooleanWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
176{
177 switch ( type() )
178 {
180 {
181 const bool v = QgsProcessingParameters::parameterAsBool( parameterDefinition(), value, context );
182 mCheckBox->setChecked( v );
183 break;
184 }
185
188 {
189 const bool v = QgsProcessingParameters::parameterAsBool( parameterDefinition(), value, context );
190 mComboBox->setCurrentIndex( mComboBox->findData( v ) );
191 break;
192 }
193 }
194}
195
196QVariant QgsProcessingBooleanWidgetWrapper::widgetValue() const
197{
198 switch ( type() )
199 {
201 return mCheckBox->isChecked();
202
205 return mComboBox->currentData();
206 }
207 return QVariant();
208}
209
210QString QgsProcessingBooleanWidgetWrapper::parameterType() const
211{
213}
214
215QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingBooleanWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type )
216{
217 return new QgsProcessingBooleanWidgetWrapper( parameter, type );
218}
219
220QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingBooleanWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
221{
222 return new QgsProcessingBooleanParameterDefinitionWidget( context, widgetContext, definition, algorithm );
223}
224
225
226//
227// QgsProcessingCrsWidgetWrapper
228//
229
230QgsProcessingCrsParameterDefinitionWidget::QgsProcessingCrsParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
231 : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
232{
233 QVBoxLayout *vlayout = new QVBoxLayout();
234 vlayout->setContentsMargins( 0, 0, 0, 0 );
235
236 vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
237
238 mCrsSelector = new QgsProjectionSelectionWidget();
239
240 // possibly we should expose this for parameter by parameter control
241 mCrsSelector->setShowAccuracyWarnings( true );
242
243 if ( const QgsProcessingParameterCrs *crsParam = dynamic_cast<const QgsProcessingParameterCrs *>( definition ) )
244 mCrsSelector->setCrs( QgsProcessingParameters::parameterAsCrs( crsParam, crsParam->defaultValueForGui(), context ) );
245 else
246 mCrsSelector->setCrs( QgsCoordinateReferenceSystem( u"EPSG:4326"_s ) );
247
248 vlayout->addWidget( mCrsSelector );
249 setLayout( vlayout );
250}
251
252QgsProcessingParameterDefinition *QgsProcessingCrsParameterDefinitionWidget::createParameter( const QString &name, const QString &description, Qgis::ProcessingParameterFlags flags ) const
253{
254 auto param = std::make_unique<QgsProcessingParameterCrs>( name, description, mCrsSelector->crs().authid() );
255 param->setFlags( flags );
256 return param.release();
257}
258
259QgsProcessingCrsWidgetWrapper::QgsProcessingCrsWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type, QWidget *parent )
260 : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
261{
262}
263
264QWidget *QgsProcessingCrsWidgetWrapper::createWidget()
265{
266 Q_ASSERT( mProjectionSelectionWidget == nullptr );
267 mProjectionSelectionWidget = new QgsProjectionSelectionWidget();
268 mProjectionSelectionWidget->setToolTip( parameterDefinition()->toolTip() );
269
270 if ( parameterDefinition()->flags() & Qgis::ProcessingParameterFlag::Optional )
271 mProjectionSelectionWidget->setOptionVisible( QgsProjectionSelectionWidget::CrsNotSet, true );
272 else
273 mProjectionSelectionWidget->setOptionVisible( QgsProjectionSelectionWidget::CrsNotSet, false );
274
275 connect( mProjectionSelectionWidget, &QgsProjectionSelectionWidget::crsChanged, this, [this] {
276 emit widgetValueHasChanged( this );
277 } );
278
279 switch ( type() )
280 {
283 {
284 return mProjectionSelectionWidget;
285 }
286
288 {
289 QWidget *w = new QWidget();
290 w->setToolTip( parameterDefinition()->toolTip() );
291
292 QVBoxLayout *vl = new QVBoxLayout();
293 vl->setContentsMargins( 0, 0, 0, 0 );
294 w->setLayout( vl );
295
296 mUseProjectCrsCheckBox = new QCheckBox( tr( "Use project CRS" ) );
297 mUseProjectCrsCheckBox->setToolTip( tr( "Always use the current project CRS when running the model" ) );
298 vl->addWidget( mUseProjectCrsCheckBox );
299 connect( mUseProjectCrsCheckBox, &QCheckBox::toggled, mProjectionSelectionWidget, &QgsProjectionSelectionWidget::setDisabled );
300 connect( mUseProjectCrsCheckBox, &QCheckBox::toggled, this, [this] {
301 emit widgetValueHasChanged( this );
302 } );
303
304 vl->addWidget( mProjectionSelectionWidget );
305
306 return w;
307 }
308 }
309 return nullptr;
310}
311
312void QgsProcessingCrsWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
313{
314 if ( mUseProjectCrsCheckBox )
315 {
316 if ( value.toString().compare( "ProjectCrs"_L1, Qt::CaseInsensitive ) == 0 )
317 {
318 mUseProjectCrsCheckBox->setChecked( true );
319 return;
320 }
321 else
322 {
323 mUseProjectCrsCheckBox->setChecked( false );
324 }
325 }
326
327 const QgsCoordinateReferenceSystem v = QgsProcessingParameters::parameterAsCrs( parameterDefinition(), value, context );
328 if ( mProjectionSelectionWidget )
329 mProjectionSelectionWidget->setCrs( v );
330}
331
332QVariant QgsProcessingCrsWidgetWrapper::widgetValue() const
333{
334 if ( mUseProjectCrsCheckBox && mUseProjectCrsCheckBox->isChecked() )
335 return u"ProjectCrs"_s;
336 else if ( mProjectionSelectionWidget )
337 return mProjectionSelectionWidget->crs().isValid() ? mProjectionSelectionWidget->crs() : QVariant();
338 else
339 return QVariant();
340}
341
342QString QgsProcessingCrsWidgetWrapper::modelerExpressionFormatString() const
343{
344 return tr( "string as EPSG code, WKT or PROJ format, or a string identifying a map layer" );
345}
346
347QString QgsProcessingCrsWidgetWrapper::parameterType() const
348{
350}
351
352QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingCrsWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type )
353{
354 return new QgsProcessingCrsWidgetWrapper( parameter, type );
355}
356
357QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingCrsWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
358{
359 return new QgsProcessingCrsParameterDefinitionWidget( context, widgetContext, definition, algorithm );
360}
361
362
363//
364// QgsProcessingStringWidgetWrapper
365//
366
367
368QgsProcessingStringParameterDefinitionWidget::QgsProcessingStringParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
369 : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
370{
371 QVBoxLayout *vlayout = new QVBoxLayout();
372 vlayout->setContentsMargins( 0, 0, 0, 0 );
373
374 vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
375
376 mDefaultLineEdit = new QLineEdit();
377 if ( const QgsProcessingParameterString *stringParam = dynamic_cast<const QgsProcessingParameterString *>( definition ) )
378 mDefaultLineEdit->setText( QgsProcessingParameters::parameterAsString( stringParam, stringParam->defaultValueForGui(), context ) );
379 vlayout->addWidget( mDefaultLineEdit );
380
381 mMultiLineCheckBox = new QCheckBox( tr( "Multiline input" ) );
382 if ( const QgsProcessingParameterString *stringParam = dynamic_cast<const QgsProcessingParameterString *>( definition ) )
383 mMultiLineCheckBox->setChecked( stringParam->multiLine() );
384 vlayout->addWidget( mMultiLineCheckBox );
385
386 setLayout( vlayout );
387}
388
389QgsProcessingParameterDefinition *QgsProcessingStringParameterDefinitionWidget::createParameter( const QString &name, const QString &description, Qgis::ProcessingParameterFlags flags ) const
390{
391 auto param = std::make_unique<QgsProcessingParameterString>( name, description, mDefaultLineEdit->text(), mMultiLineCheckBox->isChecked() );
392 param->setFlags( flags );
393 return param.release();
394}
395
396
397QgsProcessingStringWidgetWrapper::QgsProcessingStringWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type, QWidget *parent )
398 : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
399{
400}
401
402QWidget *QgsProcessingStringWidgetWrapper::createWidget()
403{
404 const QVariantMap metadata = parameterDefinition()->metadata();
405 const QVariant valueHintsVariant = metadata.value( u"widget_wrapper"_s ).toMap().value( u"value_hints"_s );
406
407 if ( valueHintsVariant.isValid() )
408 {
409 const QVariantList valueList = valueHintsVariant.toList();
410 mComboBox = new QComboBox();
411 mComboBox->setToolTip( parameterDefinition()->toolTip() );
412
413 if ( parameterDefinition()->flags() & Qgis::ProcessingParameterFlag::Optional )
414 {
415 mComboBox->addItem( QString() );
416 }
417 for ( const QVariant &entry : valueList )
418 {
419 mComboBox->addItem( entry.toString(), entry.toString() );
420 }
421 mComboBox->setCurrentIndex( 0 );
422
423 connect( mComboBox, qOverload<int>( &QComboBox::currentIndexChanged ), this, [this]( int ) {
424 emit widgetValueHasChanged( this );
425 } );
426 return mComboBox;
427 }
428 else
429 {
430 switch ( type() )
431 {
434 {
435 if ( static_cast<const QgsProcessingParameterString *>( parameterDefinition() )->multiLine() )
436 {
437 mPlainTextEdit = new QPlainTextEdit();
438 mPlainTextEdit->setToolTip( parameterDefinition()->toolTip() );
439
440 connect( mPlainTextEdit, &QPlainTextEdit::textChanged, this, [this] {
441 emit widgetValueHasChanged( this );
442 } );
443 return mPlainTextEdit;
444 }
445 else
446 {
447 mLineEdit = new QLineEdit();
448 mLineEdit->setToolTip( parameterDefinition()->toolTip() );
449
450 connect( mLineEdit, &QLineEdit::textChanged, this, [this] {
451 emit widgetValueHasChanged( this );
452 } );
453 return mLineEdit;
454 }
455 }
456
458 {
459 mLineEdit = new QLineEdit();
460 mLineEdit->setToolTip( parameterDefinition()->toolTip() );
461
462 connect( mLineEdit, &QLineEdit::textChanged, this, [this] {
463 emit widgetValueHasChanged( this );
464 } );
465 return mLineEdit;
466 }
467 }
468 }
469
470 return nullptr;
471}
472
473void QgsProcessingStringWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
474{
475 const QString v = QgsProcessingParameters::parameterAsString( parameterDefinition(), value, context );
476 if ( mLineEdit )
477 mLineEdit->setText( v );
478 if ( mPlainTextEdit )
479 mPlainTextEdit->setPlainText( v );
480 if ( mComboBox )
481 {
482 int index = -1;
483 if ( !value.isValid() )
484 index = mComboBox->findData( QVariant() );
485 else
486 index = mComboBox->findData( v );
487
488 if ( index >= 0 )
489 mComboBox->setCurrentIndex( index );
490 else
491 mComboBox->setCurrentIndex( 0 );
492 }
493}
494
495QVariant QgsProcessingStringWidgetWrapper::widgetValue() const
496{
497 if ( mLineEdit )
498 return mLineEdit->text();
499 else if ( mPlainTextEdit )
500 return mPlainTextEdit->toPlainText();
501 else if ( mComboBox )
502 return mComboBox->currentData();
503 else
504 return QVariant();
505}
506
507QString QgsProcessingStringWidgetWrapper::parameterType() const
508{
510}
511
512QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingStringWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type )
513{
514 return new QgsProcessingStringWidgetWrapper( parameter, type );
515}
516
517QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingStringWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
518{
519 return new QgsProcessingStringParameterDefinitionWidget( context, widgetContext, definition, algorithm );
520}
521
522
523//
524// QgsProcessingAuthConfigWidgetWrapper
525//
526
527QgsProcessingAuthConfigWidgetWrapper::QgsProcessingAuthConfigWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type, QWidget *parent )
528 : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
529{
530}
531
532QWidget *QgsProcessingAuthConfigWidgetWrapper::createWidget()
533{
534 switch ( type() )
535 {
539 {
540 mAuthConfigSelect = new QgsAuthConfigSelect();
541 mAuthConfigSelect->setToolTip( parameterDefinition()->toolTip() );
542
543 connect( mAuthConfigSelect, &QgsAuthConfigSelect::selectedConfigIdChanged, this, [this] {
544 emit widgetValueHasChanged( this );
545 } );
546 return mAuthConfigSelect;
547 }
548 }
549 return nullptr;
550}
551
552void QgsProcessingAuthConfigWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
553{
554 const QString v = QgsProcessingParameters::parameterAsString( parameterDefinition(), value, context );
555 if ( mAuthConfigSelect )
556 mAuthConfigSelect->setConfigId( v );
557}
558
559QVariant QgsProcessingAuthConfigWidgetWrapper::widgetValue() const
560{
561 if ( mAuthConfigSelect )
562 return mAuthConfigSelect->configId();
563 else
564 return QVariant();
565}
566
567QString QgsProcessingAuthConfigWidgetWrapper::parameterType() const
568{
570}
571
572QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingAuthConfigWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type )
573{
574 return new QgsProcessingAuthConfigWidgetWrapper( parameter, type );
575}
576
577//
578// QgsProcessingNumericWidgetWrapper
579//
580
581QgsProcessingNumberParameterDefinitionWidget::QgsProcessingNumberParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
582 : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
583{
584 QVBoxLayout *vlayout = new QVBoxLayout();
585 vlayout->setContentsMargins( 0, 0, 0, 0 );
586
587 vlayout->addWidget( new QLabel( tr( "Number type" ) ) );
588
589 mTypeComboBox = new QComboBox();
590 mTypeComboBox->addItem( tr( "Float" ), static_cast<int>( Qgis::ProcessingNumberParameterType::Double ) );
591 mTypeComboBox->addItem( tr( "Integer" ), static_cast<int>( Qgis::ProcessingNumberParameterType::Integer ) );
592 vlayout->addWidget( mTypeComboBox );
593
594 vlayout->addWidget( new QLabel( tr( "Minimum value" ) ) );
595 mMinLineEdit = new QLineEdit();
596 vlayout->addWidget( mMinLineEdit );
597
598 vlayout->addWidget( new QLabel( tr( "Maximum value" ) ) );
599 mMaxLineEdit = new QLineEdit();
600 vlayout->addWidget( mMaxLineEdit );
601
602 vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
603 mDefaultLineEdit = new QLineEdit();
604 vlayout->addWidget( mDefaultLineEdit );
605
606 if ( const QgsProcessingParameterNumber *numberParam = dynamic_cast<const QgsProcessingParameterNumber *>( definition ) )
607 {
608 mTypeComboBox->setCurrentIndex( mTypeComboBox->findData( static_cast<int>( numberParam->dataType() ) ) );
609
610 if ( !qgsDoubleNear( numberParam->maximum(), std::numeric_limits<double>::max() ) )
611 {
612 mMaxLineEdit->setText( QLocale().toString( numberParam->maximum() ) );
613 }
614 else
615 {
616 mMaxLineEdit->clear();
617 }
618
619 if ( !qgsDoubleNear( numberParam->minimum(), std::numeric_limits<double>::lowest() ) )
620 {
621 mMinLineEdit->setText( QLocale().toString( numberParam->minimum() ) );
622 }
623 else
624 {
625 mMinLineEdit->clear();
626 }
627
628 mDefaultLineEdit->setText( numberParam->defaultValueForGui().toString() );
629 }
630
631 setLayout( vlayout );
632}
633
634QgsProcessingParameterDefinition *QgsProcessingNumberParameterDefinitionWidget::createParameter( const QString &name, const QString &description, Qgis::ProcessingParameterFlags flags ) const
635{
636 bool ok;
637 double val = QgsDoubleValidator::toDouble( mDefaultLineEdit->text(), &ok );
638
639 Qgis::ProcessingNumberParameterType dataType = static_cast<Qgis::ProcessingNumberParameterType>( mTypeComboBox->currentData().toInt() );
640 auto param = std::make_unique<QgsProcessingParameterNumber>( name, description, dataType, ok ? val : QVariant() );
641
642 if ( !mMinLineEdit->text().trimmed().isEmpty() )
643 {
644 val = QgsDoubleValidator::toDouble( mMinLineEdit->text(), &ok );
645 if ( ok )
646 {
647 param->setMinimum( val );
648 }
649 }
650
651 if ( !mMaxLineEdit->text().trimmed().isEmpty() )
652 {
653 val = QgsDoubleValidator::toDouble( mMaxLineEdit->text(), &ok );
654 if ( ok )
655 {
656 param->setMaximum( val );
657 }
658 }
659
660 param->setFlags( flags );
661 return param.release();
662}
663
664QgsProcessingNumericWidgetWrapper::QgsProcessingNumericWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type, QWidget *parent )
665 : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
666{
667}
668
669QWidget *QgsProcessingNumericWidgetWrapper::createWidget()
670{
671 const QgsProcessingParameterNumber *numberDef = static_cast<const QgsProcessingParameterNumber *>( parameterDefinition() );
672 const QVariantMap metadata = numberDef->metadata();
673 const int decimals = metadata.value( u"widget_wrapper"_s ).toMap().value( u"decimals"_s, 6 ).toInt();
674 switch ( type() )
675 {
679 {
680 // lots of duplicate code here -- but there's no common interface between QSpinBox/QDoubleSpinBox which would allow us to avoid this
681 QAbstractSpinBox *spinBox = nullptr;
682 switch ( numberDef->dataType() )
683 {
685 mDoubleSpinBox = new QgsDoubleSpinBox();
686 mDoubleSpinBox->setExpressionsEnabled( true );
687 mDoubleSpinBox->setDecimals( decimals );
688
689 // guess reasonable step value for double spin boxes
690 if ( !qgsDoubleNear( numberDef->maximum(), std::numeric_limits<double>::max() ) && !qgsDoubleNear( numberDef->minimum(), std::numeric_limits<double>::lowest() + 1 ) )
691 {
692 double singleStep = calculateStep( numberDef->minimum(), numberDef->maximum() );
693 singleStep = std::max( singleStep, std::pow( 10, -decimals ) );
694 mDoubleSpinBox->setSingleStep( singleStep );
695 }
696
697 spinBox = mDoubleSpinBox;
698 break;
699
701 mSpinBox = new QgsSpinBox();
702 mSpinBox->setExpressionsEnabled( true );
703 spinBox = mSpinBox;
704 break;
705 }
706 spinBox->setToolTip( parameterDefinition()->toolTip() );
707
708 double max = 999999999;
709 if ( !qgsDoubleNear( numberDef->maximum(), std::numeric_limits<double>::max() ) )
710 {
711 max = numberDef->maximum();
712 }
713 double min = -999999999;
714 if ( !qgsDoubleNear( numberDef->minimum(), std::numeric_limits<double>::lowest() ) )
715 {
716 min = numberDef->minimum();
717 }
718 if ( mDoubleSpinBox )
719 {
720 mDoubleSpinBox->setMinimum( min );
721 mDoubleSpinBox->setMaximum( max );
722 }
723 else
724 {
725 mSpinBox->setMinimum( static_cast<int>( min ) );
726 mSpinBox->setMaximum( static_cast<int>( max ) );
727 }
728
730 {
731 mAllowingNull = true;
732 if ( mDoubleSpinBox )
733 {
734 mDoubleSpinBox->setShowClearButton( true );
735 const double min = mDoubleSpinBox->minimum() - mDoubleSpinBox->singleStep();
736 mDoubleSpinBox->setMinimum( min );
737 mDoubleSpinBox->setValue( min );
738 }
739 else
740 {
741 mSpinBox->setShowClearButton( true );
742 const int min = mSpinBox->minimum() - 1;
743 mSpinBox->setMinimum( min );
744 mSpinBox->setValue( min );
745 }
746 spinBox->setSpecialValueText( tr( "Not set" ) );
747 }
748 else
749 {
750 if ( numberDef->defaultValueForGui().isValid() )
751 {
752 // if default value for parameter, we clear to that
753 bool ok = false;
754 if ( mDoubleSpinBox )
755 {
756 double defaultVal = numberDef->defaultValueForGui().toDouble( &ok );
757 if ( ok )
758 mDoubleSpinBox->setClearValue( defaultVal );
759 }
760 else
761 {
762 int intVal = numberDef->defaultValueForGui().toInt( &ok );
763 if ( ok )
764 mSpinBox->setClearValue( intVal );
765 }
766 }
767 else if ( !qgsDoubleNear( numberDef->minimum(), std::numeric_limits<double>::lowest() ) )
768 {
769 // otherwise we clear to the minimum, if it's set
770 if ( mDoubleSpinBox )
771 mDoubleSpinBox->setClearValue( numberDef->minimum() );
772 else
773 mSpinBox->setClearValue( static_cast<int>( numberDef->minimum() ) );
774 }
775 else
776 {
777 // last resort, we clear to 0
778 if ( mDoubleSpinBox )
779 {
780 mDoubleSpinBox->setValue( 0 );
781 mDoubleSpinBox->setClearValue( 0 );
782 }
783 else
784 {
785 mSpinBox->setValue( 0 );
786 mSpinBox->setClearValue( 0 );
787 }
788 }
789 }
790
791 if ( mDoubleSpinBox )
792 connect( mDoubleSpinBox, qOverload<double>( &QgsDoubleSpinBox::valueChanged ), this, [this] { emit widgetValueHasChanged( this ); } );
793 else if ( mSpinBox )
794 connect( mSpinBox, qOverload<int>( &QgsSpinBox::valueChanged ), this, [this] { emit widgetValueHasChanged( this ); } );
795
796 return spinBox;
797 }
798 }
799 return nullptr;
800}
801
802void QgsProcessingNumericWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
803{
804 if ( mDoubleSpinBox )
805 {
806 if ( mAllowingNull && !value.isValid() )
807 mDoubleSpinBox->clear();
808 else
809 {
810 const double v = QgsProcessingParameters::parameterAsDouble( parameterDefinition(), value, context );
811 mDoubleSpinBox->setValue( v );
812 }
813 }
814 else if ( mSpinBox )
815 {
816 if ( mAllowingNull && !value.isValid() )
817 mSpinBox->clear();
818 else
819 {
820 const int v = QgsProcessingParameters::parameterAsInt( parameterDefinition(), value, context );
821 mSpinBox->setValue( v );
822 }
823 }
824}
825
826QVariant QgsProcessingNumericWidgetWrapper::widgetValue() const
827{
828 if ( mDoubleSpinBox )
829 {
830 if ( mAllowingNull && qgsDoubleNear( mDoubleSpinBox->value(), mDoubleSpinBox->minimum() ) )
831 return QVariant();
832 else
833 return mDoubleSpinBox->value();
834 }
835 else if ( mSpinBox )
836 {
837 if ( mAllowingNull && mSpinBox->value() == mSpinBox->minimum() )
838 return QVariant();
839 else
840 return mSpinBox->value();
841 }
842 else
843 return QVariant();
844}
845
846double QgsProcessingNumericWidgetWrapper::calculateStep( const double minimum, const double maximum )
847{
848 const double valueRange = maximum - minimum;
849 if ( valueRange <= 1.0 )
850 {
851 const double step = valueRange / 10.0;
852 // round to 1 significant figure
853 return qgsRound( step, -std::floor( std::log( step ) ) );
854 }
855 else
856 {
857 return 1.0;
858 }
859}
860
861QString QgsProcessingNumericWidgetWrapper::parameterType() const
862{
864}
865
866QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingNumericWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type )
867{
868 return new QgsProcessingNumericWidgetWrapper( parameter, type );
869}
870
871QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingNumericWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
872{
873 return new QgsProcessingNumberParameterDefinitionWidget( context, widgetContext, definition, algorithm );
874}
875
876//
877// QgsProcessingDistanceWidgetWrapper
878//
879
880QgsProcessingDistanceParameterDefinitionWidget::QgsProcessingDistanceParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
881 : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
882{
883 QVBoxLayout *vlayout = new QVBoxLayout();
884 vlayout->setContentsMargins( 0, 0, 0, 0 );
885
886 vlayout->addWidget( new QLabel( tr( "Linked input" ) ) );
887
888 mParentLayerComboBox = new QComboBox();
889
890 QString initialParent;
891 if ( const QgsProcessingParameterDistance *distParam = dynamic_cast<const QgsProcessingParameterDistance *>( definition ) )
892 initialParent = distParam->parentParameterName();
893
894 if ( auto *lModel = widgetContext.model() )
895 {
896 // populate combo box with other model input choices
897 const QMap<QString, QgsProcessingModelParameter> components = lModel->parameterComponents();
898 for ( auto it = components.constBegin(); it != components.constEnd(); ++it )
899 {
900 if ( const QgsProcessingParameterFeatureSource *definition = dynamic_cast<const QgsProcessingParameterFeatureSource *>( lModel->parameterDefinition( it.value().parameterName() ) ) )
901 {
902 mParentLayerComboBox->addItem( definition->description(), definition->name() );
903 if ( !initialParent.isEmpty() && initialParent == definition->name() )
904 {
905 mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
906 }
907 }
908 else if ( const QgsProcessingParameterVectorLayer *definition = dynamic_cast<const QgsProcessingParameterVectorLayer *>( lModel->parameterDefinition( it.value().parameterName() ) ) )
909 {
910 mParentLayerComboBox->addItem( definition->description(), definition->name() );
911 if ( !initialParent.isEmpty() && initialParent == definition->name() )
912 {
913 mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
914 }
915 }
916 else if ( const QgsProcessingParameterMapLayer *definition = dynamic_cast<const QgsProcessingParameterMapLayer *>( lModel->parameterDefinition( it.value().parameterName() ) ) )
917 {
918 mParentLayerComboBox->addItem( definition->description(), definition->name() );
919 if ( !initialParent.isEmpty() && initialParent == definition->name() )
920 {
921 mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
922 }
923 }
924 else if ( const QgsProcessingParameterCrs *definition = dynamic_cast<const QgsProcessingParameterCrs *>( lModel->parameterDefinition( it.value().parameterName() ) ) )
925 {
926 mParentLayerComboBox->addItem( definition->description(), definition->name() );
927 if ( !initialParent.isEmpty() && initialParent == definition->name() )
928 {
929 mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
930 }
931 }
932 }
933 }
934
935 if ( mParentLayerComboBox->count() == 0 && !initialParent.isEmpty() )
936 {
937 // if no parent candidates found, we just add the existing one as a placeholder
938 mParentLayerComboBox->addItem( initialParent, initialParent );
939 mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
940 }
941
942 vlayout->addWidget( mParentLayerComboBox );
943
944 vlayout->addWidget( new QLabel( tr( "Minimum value" ) ) );
945 mMinLineEdit = new QLineEdit();
946 vlayout->addWidget( mMinLineEdit );
947
948 vlayout->addWidget( new QLabel( tr( "Maximum value" ) ) );
949 mMaxLineEdit = new QLineEdit();
950 vlayout->addWidget( mMaxLineEdit );
951
952 vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
953 mDefaultLineEdit = new QLineEdit();
954 vlayout->addWidget( mDefaultLineEdit );
955
956 if ( const QgsProcessingParameterDistance *distParam = dynamic_cast<const QgsProcessingParameterDistance *>( definition ) )
957 {
958 mMinLineEdit->setText( QLocale().toString( distParam->minimum() ) );
959 mMaxLineEdit->setText( QLocale().toString( distParam->maximum() ) );
960 mDefaultLineEdit->setText( distParam->defaultValueForGui().toString() );
961 }
962
963 setLayout( vlayout );
964}
965
966QgsProcessingParameterDefinition *QgsProcessingDistanceParameterDefinitionWidget::createParameter( const QString &name, const QString &description, Qgis::ProcessingParameterFlags flags ) const
967{
968 bool ok;
969 double val = QgsDoubleValidator::toDouble( mDefaultLineEdit->text(), &ok );
970
971 auto param = std::make_unique<QgsProcessingParameterDistance>( name, description, ok ? val : QVariant(), mParentLayerComboBox->currentData().toString() );
972
973 val = QgsDoubleValidator::toDouble( mMinLineEdit->text(), &ok );
974 if ( ok )
975 {
976 param->setMinimum( val );
977 }
978
979 val = QgsDoubleValidator::toDouble( mMaxLineEdit->text(), &ok );
980 if ( ok )
981 {
982 param->setMaximum( val );
983 }
984
985 param->setFlags( flags );
986 return param.release();
987}
988
989QgsProcessingDistanceWidgetWrapper::QgsProcessingDistanceWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type, QWidget *parent )
990 : QgsProcessingNumericWidgetWrapper( parameter, type, parent )
991{
992}
993
994QString QgsProcessingDistanceWidgetWrapper::parameterType() const
995{
997}
998
999QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingDistanceWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type )
1000{
1001 return new QgsProcessingDistanceWidgetWrapper( parameter, type );
1002}
1003
1004QWidget *QgsProcessingDistanceWidgetWrapper::createWidget()
1005{
1006 const QgsProcessingParameterDistance *distanceDef = static_cast<const QgsProcessingParameterDistance *>( parameterDefinition() );
1007
1008 QWidget *spin = QgsProcessingNumericWidgetWrapper::createWidget();
1009 switch ( type() )
1010 {
1012 {
1013 mLabel = new QLabel();
1014 mUnitsCombo = new QComboBox();
1015
1016 mUnitsCombo->addItem( QgsUnitTypes::toString( Qgis::DistanceUnit::Meters ), static_cast<int>( Qgis::DistanceUnit::Meters ) );
1017 mUnitsCombo->addItem( QgsUnitTypes::toString( Qgis::DistanceUnit::Kilometers ), static_cast<int>( Qgis::DistanceUnit::Kilometers ) );
1018 mUnitsCombo->addItem( QgsUnitTypes::toString( Qgis::DistanceUnit::Feet ), static_cast<int>( Qgis::DistanceUnit::Feet ) );
1019 mUnitsCombo->addItem( QgsUnitTypes::toString( Qgis::DistanceUnit::Yards ), static_cast<int>( Qgis::DistanceUnit::Yards ) );
1020 mUnitsCombo->addItem( QgsUnitTypes::toString( Qgis::DistanceUnit::Miles ), static_cast<int>( Qgis::DistanceUnit::Miles ) );
1022 mUnitsCombo->addItem( QgsUnitTypes::toString( Qgis::DistanceUnit::Centimeters ), static_cast<int>( Qgis::DistanceUnit::Centimeters ) );
1023 mUnitsCombo->addItem( QgsUnitTypes::toString( Qgis::DistanceUnit::Millimeters ), static_cast<int>( Qgis::DistanceUnit::Millimeters ) );
1024 mUnitsCombo->addItem( QgsUnitTypes::toString( Qgis::DistanceUnit::Inches ), static_cast<int>( Qgis::DistanceUnit::Inches ) );
1025
1026 const int labelMargin = static_cast<int>( std::round( mUnitsCombo->fontMetrics().horizontalAdvance( 'X' ) ) );
1027 QHBoxLayout *layout = new QHBoxLayout();
1028 layout->addWidget( spin, 1 );
1029 layout->insertSpacing( 1, labelMargin / 2 );
1030 layout->insertWidget( 2, mLabel );
1031 layout->insertWidget( 3, mUnitsCombo );
1032
1033 // bit of fiddlyness here -- we want the initial spacing to only be visible
1034 // when the warning label is shown, so it's embedded inside mWarningLabel
1035 // instead of outside it
1036 mWarningLabel = new QWidget();
1037 QHBoxLayout *warningLayout = new QHBoxLayout();
1038 warningLayout->setContentsMargins( 0, 0, 0, 0 );
1039 QLabel *warning = new QLabel();
1040 QIcon icon = QgsApplication::getThemeIcon( u"mIconWarning.svg"_s );
1041 const int size = static_cast<int>( std::max( 24.0, spin->minimumSize().height() * 0.5 ) );
1042 warning->setPixmap( icon.pixmap( icon.actualSize( QSize( size, size ) ) ) );
1043 warning->setToolTip( tr( "Distance is in geographic degrees. Consider reprojecting to a projected local coordinate system for accurate results." ) );
1044 warningLayout->insertSpacing( 0, labelMargin / 2 );
1045 warningLayout->insertWidget( 1, warning );
1046 mWarningLabel->setLayout( warningLayout );
1047 layout->insertWidget( 4, mWarningLabel );
1048
1049 QWidget *w = new QWidget();
1050 layout->setContentsMargins( 0, 0, 0, 0 );
1051 w->setLayout( layout );
1052
1053 setUnits( distanceDef->defaultUnit() );
1054
1055 return w;
1056 }
1057
1060 return spin;
1061 }
1062 return nullptr;
1063}
1064
1065void QgsProcessingDistanceWidgetWrapper::postInitialize( const QList<QgsAbstractProcessingParameterWidgetWrapper *> &wrappers )
1066{
1067 QgsProcessingNumericWidgetWrapper::postInitialize( wrappers );
1068 switch ( type() )
1069 {
1071 {
1072 for ( const QgsAbstractProcessingParameterWidgetWrapper *wrapper : wrappers )
1073 {
1074 if ( wrapper->parameterDefinition()->name() == static_cast<const QgsProcessingParameterDistance *>( parameterDefinition() )->parentParameterName() )
1075 {
1076 setUnitParameterValue( wrapper->parameterValue(), wrapper );
1077 connect( wrapper, &QgsAbstractProcessingParameterWidgetWrapper::widgetValueHasChanged, this, [this, wrapper] {
1078 setUnitParameterValue( wrapper->parameterValue(), wrapper );
1079 } );
1080 break;
1081 }
1082 }
1083 break;
1084 }
1085
1088 break;
1089 }
1090}
1091
1092void QgsProcessingDistanceWidgetWrapper::setUnitParameterValue( const QVariant &value, const QgsAbstractProcessingParameterWidgetWrapper *wrapper )
1093{
1095
1096 // evaluate value to layer
1097 QgsProcessingContext *context = nullptr;
1098 std::unique_ptr<QgsProcessingContext> tmpContext;
1099 if ( mProcessingContextGenerator )
1100 context = mProcessingContextGenerator->processingContext();
1101
1102 if ( !context )
1103 {
1104 tmpContext = std::make_unique<QgsProcessingContext>();
1105 context = tmpContext.get();
1106 }
1107
1108 const QgsCoordinateReferenceSystem crs = wrapper
1110 : QgsProcessingUtils::variantToCrs( value, *context );
1111 if ( crs.isValid() )
1112 {
1113 units = crs.mapUnits();
1114 }
1115
1116 setUnits( units );
1117}
1118
1119void QgsProcessingDistanceWidgetWrapper::setUnits( Qgis::DistanceUnit units )
1120{
1121 mLabel->setText( QgsUnitTypes::toString( units ) );
1123 {
1124 mUnitsCombo->hide();
1125 mLabel->show();
1126 }
1127 else
1128 {
1129 // Only reset the combo if the base units have changed
1130 // or we might loose any user-set unit when changing layer.
1131 // See issue #61470
1132 if ( mBaseUnit != units )
1133 {
1134 mUnitsCombo->setCurrentIndex( mUnitsCombo->findData( static_cast<int>( units ) ) );
1135 }
1136
1137 mUnitsCombo->show();
1138 mLabel->hide();
1139 }
1140 mWarningLabel->setVisible( units == Qgis::DistanceUnit::Degrees );
1141 mBaseUnit = units;
1142}
1143
1144QVariant QgsProcessingDistanceWidgetWrapper::widgetValue() const
1145{
1146 const QVariant val = QgsProcessingNumericWidgetWrapper::widgetValue();
1147 if ( val.userType() == QMetaType::Type::Double && mUnitsCombo && mUnitsCombo->isVisible() )
1148 {
1149 Qgis::DistanceUnit displayUnit = static_cast<Qgis::DistanceUnit>( mUnitsCombo->currentData().toInt() );
1150 return val.toDouble() * QgsUnitTypes::fromUnitToUnitFactor( displayUnit, mBaseUnit );
1151 }
1152 else
1153 {
1154 return val;
1155 }
1156}
1157
1158QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingDistanceWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
1159{
1160 return new QgsProcessingDistanceParameterDefinitionWidget( context, widgetContext, definition, algorithm );
1161}
1162
1163
1164//
1165// QgsProcessingAreaParameterDefinitionWidget
1166//
1167
1168QgsProcessingAreaParameterDefinitionWidget::QgsProcessingAreaParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
1169 : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
1170{
1171 QVBoxLayout *vlayout = new QVBoxLayout();
1172 vlayout->setContentsMargins( 0, 0, 0, 0 );
1173
1174 vlayout->addWidget( new QLabel( tr( "Linked input" ) ) );
1175
1176 mParentLayerComboBox = new QComboBox();
1177
1178 QString initialParent;
1179 if ( const QgsProcessingParameterArea *areaParam = dynamic_cast<const QgsProcessingParameterArea *>( definition ) )
1180 initialParent = areaParam->parentParameterName();
1181
1182 if ( auto *lModel = widgetContext.model() )
1183 {
1184 // populate combo box with other model input choices
1185 const QMap<QString, QgsProcessingModelParameter> components = lModel->parameterComponents();
1186 for ( auto it = components.constBegin(); it != components.constEnd(); ++it )
1187 {
1188 if ( const QgsProcessingParameterFeatureSource *definition = dynamic_cast<const QgsProcessingParameterFeatureSource *>( lModel->parameterDefinition( it.value().parameterName() ) ) )
1189 {
1190 mParentLayerComboBox->addItem( definition->description(), definition->name() );
1191 if ( !initialParent.isEmpty() && initialParent == definition->name() )
1192 {
1193 mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
1194 }
1195 }
1196 else if ( const QgsProcessingParameterVectorLayer *definition = dynamic_cast<const QgsProcessingParameterVectorLayer *>( lModel->parameterDefinition( it.value().parameterName() ) ) )
1197 {
1198 mParentLayerComboBox->addItem( definition->description(), definition->name() );
1199 if ( !initialParent.isEmpty() && initialParent == definition->name() )
1200 {
1201 mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
1202 }
1203 }
1204 else if ( const QgsProcessingParameterMapLayer *definition = dynamic_cast<const QgsProcessingParameterMapLayer *>( lModel->parameterDefinition( it.value().parameterName() ) ) )
1205 {
1206 mParentLayerComboBox->addItem( definition->description(), definition->name() );
1207 if ( !initialParent.isEmpty() && initialParent == definition->name() )
1208 {
1209 mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
1210 }
1211 }
1212 else if ( const QgsProcessingParameterCrs *definition = dynamic_cast<const QgsProcessingParameterCrs *>( lModel->parameterDefinition( it.value().parameterName() ) ) )
1213 {
1214 mParentLayerComboBox->addItem( definition->description(), definition->name() );
1215 if ( !initialParent.isEmpty() && initialParent == definition->name() )
1216 {
1217 mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
1218 }
1219 }
1220 }
1221 }
1222
1223 if ( mParentLayerComboBox->count() == 0 && !initialParent.isEmpty() )
1224 {
1225 // if no parent candidates found, we just add the existing one as a placeholder
1226 mParentLayerComboBox->addItem( initialParent, initialParent );
1227 mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
1228 }
1229
1230 vlayout->addWidget( mParentLayerComboBox );
1231
1232 vlayout->addWidget( new QLabel( tr( "Minimum value" ) ) );
1233 mMinLineEdit = new QLineEdit();
1234 vlayout->addWidget( mMinLineEdit );
1235
1236 vlayout->addWidget( new QLabel( tr( "Maximum value" ) ) );
1237 mMaxLineEdit = new QLineEdit();
1238 vlayout->addWidget( mMaxLineEdit );
1239
1240 vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
1241 mDefaultLineEdit = new QLineEdit();
1242 vlayout->addWidget( mDefaultLineEdit );
1243
1244 if ( const QgsProcessingParameterArea *areaParam = dynamic_cast<const QgsProcessingParameterArea *>( definition ) )
1245 {
1246 mMinLineEdit->setText( QLocale().toString( areaParam->minimum() ) );
1247 mMaxLineEdit->setText( QLocale().toString( areaParam->maximum() ) );
1248 mDefaultLineEdit->setText( areaParam->defaultValueForGui().toString() );
1249 }
1250
1251 setLayout( vlayout );
1252}
1253
1254QgsProcessingParameterDefinition *QgsProcessingAreaParameterDefinitionWidget::createParameter( const QString &name, const QString &description, Qgis::ProcessingParameterFlags flags ) const
1255{
1256 bool ok;
1257 double val = QgsDoubleValidator::toDouble( mDefaultLineEdit->text(), &ok );
1258
1259 auto param = std::make_unique<QgsProcessingParameterArea>( name, description, ok ? val : QVariant(), mParentLayerComboBox->currentData().toString() );
1260
1261 val = QgsDoubleValidator::toDouble( mMinLineEdit->text(), &ok );
1262 if ( ok )
1263 {
1264 param->setMinimum( val );
1265 }
1266
1267 val = QgsDoubleValidator::toDouble( mMaxLineEdit->text(), &ok );
1268 if ( ok )
1269 {
1270 param->setMaximum( val );
1271 }
1272
1273 param->setFlags( flags );
1274 return param.release();
1275}
1276
1277
1278//
1279// QgsProcessingAreaWidgetWrapper
1280//
1281
1282QgsProcessingAreaWidgetWrapper::QgsProcessingAreaWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type, QWidget *parent )
1283 : QgsProcessingNumericWidgetWrapper( parameter, type, parent )
1284{
1285}
1286
1287QString QgsProcessingAreaWidgetWrapper::parameterType() const
1288{
1290}
1291
1292QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingAreaWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type )
1293{
1294 return new QgsProcessingAreaWidgetWrapper( parameter, type );
1295}
1296
1297QWidget *QgsProcessingAreaWidgetWrapper::createWidget()
1298{
1299 const QgsProcessingParameterArea *areaDef = static_cast<const QgsProcessingParameterArea *>( parameterDefinition() );
1300
1301 QWidget *spin = QgsProcessingNumericWidgetWrapper::createWidget();
1302 switch ( type() )
1303 {
1305 {
1306 mLabel = new QLabel();
1307 mUnitsCombo = new QComboBox();
1308
1309 mUnitsCombo->addItem( QgsUnitTypes::toString( Qgis::AreaUnit::SquareMeters ), QVariant::fromValue( Qgis::AreaUnit::SquareMeters ) );
1310 mUnitsCombo->addItem( QgsUnitTypes::toString( Qgis::AreaUnit::SquareKilometers ), QVariant::fromValue( Qgis::AreaUnit::SquareKilometers ) );
1311 mUnitsCombo->addItem( QgsUnitTypes::toString( Qgis::AreaUnit::SquareFeet ), QVariant::fromValue( Qgis::AreaUnit::SquareFeet ) );
1312 mUnitsCombo->addItem( QgsUnitTypes::toString( Qgis::AreaUnit::SquareYards ), QVariant::fromValue( Qgis::AreaUnit::SquareYards ) );
1313 mUnitsCombo->addItem( QgsUnitTypes::toString( Qgis::AreaUnit::SquareMiles ), QVariant::fromValue( Qgis::AreaUnit::SquareMiles ) );
1314 mUnitsCombo->addItem( QgsUnitTypes::toString( Qgis::AreaUnit::Hectares ), QVariant::fromValue( Qgis::AreaUnit::Hectares ) );
1315 mUnitsCombo->addItem( QgsUnitTypes::toString( Qgis::AreaUnit::Acres ), QVariant::fromValue( Qgis::AreaUnit::Acres ) );
1317 mUnitsCombo->addItem( QgsUnitTypes::toString( Qgis::AreaUnit::SquareDegrees ), QVariant::fromValue( Qgis::AreaUnit::SquareDegrees ) );
1318 mUnitsCombo->addItem( QgsUnitTypes::toString( Qgis::AreaUnit::SquareCentimeters ), QVariant::fromValue( Qgis::AreaUnit::SquareCentimeters ) );
1319 mUnitsCombo->addItem( QgsUnitTypes::toString( Qgis::AreaUnit::SquareMillimeters ), QVariant::fromValue( Qgis::AreaUnit::SquareMillimeters ) );
1320 mUnitsCombo->addItem( QgsUnitTypes::toString( Qgis::AreaUnit::SquareInches ), QVariant::fromValue( Qgis::AreaUnit::SquareInches ) );
1321
1322 const int labelMargin = static_cast<int>( std::round( mUnitsCombo->fontMetrics().horizontalAdvance( 'X' ) ) );
1323 QHBoxLayout *layout = new QHBoxLayout();
1324 layout->addWidget( spin, 1 );
1325 layout->insertSpacing( 1, labelMargin / 2 );
1326 layout->insertWidget( 2, mLabel );
1327 layout->insertWidget( 3, mUnitsCombo );
1328
1329 // bit of fiddlyness here -- we want the initial spacing to only be visible
1330 // when the warning label is shown, so it's embedded inside mWarningLabel
1331 // instead of outside it
1332 mWarningLabel = new QWidget();
1333 QHBoxLayout *warningLayout = new QHBoxLayout();
1334 warningLayout->setContentsMargins( 0, 0, 0, 0 );
1335 QLabel *warning = new QLabel();
1336 QIcon icon = QgsApplication::getThemeIcon( u"mIconWarning.svg"_s );
1337 const int size = static_cast<int>( std::max( 24.0, spin->minimumSize().height() * 0.5 ) );
1338 warning->setPixmap( icon.pixmap( icon.actualSize( QSize( size, size ) ) ) );
1339 warning->setToolTip( tr( "Area is in geographic degrees. Consider reprojecting to a projected local coordinate system for accurate results." ) );
1340 warningLayout->insertSpacing( 0, labelMargin / 2 );
1341 warningLayout->insertWidget( 1, warning );
1342 mWarningLabel->setLayout( warningLayout );
1343 layout->insertWidget( 4, mWarningLabel );
1344
1345 QWidget *w = new QWidget();
1346 layout->setContentsMargins( 0, 0, 0, 0 );
1347 w->setLayout( layout );
1348
1349 setUnits( areaDef->defaultUnit() );
1350
1351 return w;
1352 }
1353
1356 return spin;
1357 }
1358 return nullptr;
1359}
1360
1361void QgsProcessingAreaWidgetWrapper::postInitialize( const QList<QgsAbstractProcessingParameterWidgetWrapper *> &wrappers )
1362{
1363 QgsProcessingNumericWidgetWrapper::postInitialize( wrappers );
1364 switch ( type() )
1365 {
1367 {
1368 for ( const QgsAbstractProcessingParameterWidgetWrapper *wrapper : wrappers )
1369 {
1370 if ( wrapper->parameterDefinition()->name() == static_cast<const QgsProcessingParameterArea *>( parameterDefinition() )->parentParameterName() )
1371 {
1372 setUnitParameterValue( wrapper->parameterValue(), wrapper );
1373 connect( wrapper, &QgsAbstractProcessingParameterWidgetWrapper::widgetValueHasChanged, this, [this, wrapper] {
1374 setUnitParameterValue( wrapper->parameterValue(), wrapper );
1375 } );
1376 break;
1377 }
1378 }
1379 break;
1380 }
1381
1384 break;
1385 }
1386}
1387
1388void QgsProcessingAreaWidgetWrapper::setUnitParameterValue( const QVariant &value, const QgsAbstractProcessingParameterWidgetWrapper *wrapper )
1389{
1391
1392 // evaluate value to layer
1393 QgsProcessingContext *context = nullptr;
1394 std::unique_ptr<QgsProcessingContext> tmpContext;
1395 if ( mProcessingContextGenerator )
1396 context = mProcessingContextGenerator->processingContext();
1397
1398 if ( !context )
1399 {
1400 tmpContext = std::make_unique<QgsProcessingContext>();
1401 context = tmpContext.get();
1402 }
1403
1404 const QgsCoordinateReferenceSystem crs = wrapper
1406 : QgsProcessingUtils::variantToCrs( value, *context );
1407 if ( crs.isValid() )
1408 {
1409 units = QgsUnitTypes::distanceToAreaUnit( crs.mapUnits() );
1410 }
1411
1412 setUnits( units );
1413}
1414
1415void QgsProcessingAreaWidgetWrapper::setUnits( Qgis::AreaUnit units )
1416{
1417 mLabel->setText( QgsUnitTypes::toString( units ) );
1419 {
1420 mUnitsCombo->hide();
1421 mLabel->show();
1422 }
1423 else
1424 {
1425 mUnitsCombo->setCurrentIndex( mUnitsCombo->findData( QVariant::fromValue( units ) ) );
1426 mUnitsCombo->show();
1427 mLabel->hide();
1428 }
1429 mWarningLabel->setVisible( units == Qgis::AreaUnit::SquareDegrees );
1430 mBaseUnit = units;
1431}
1432
1433QVariant QgsProcessingAreaWidgetWrapper::widgetValue() const
1434{
1435 const QVariant val = QgsProcessingNumericWidgetWrapper::widgetValue();
1436 if ( val.userType() == QMetaType::Type::Double && mUnitsCombo && mUnitsCombo->isVisible() )
1437 {
1438 const Qgis::AreaUnit displayUnit = mUnitsCombo->currentData().value<Qgis::AreaUnit>();
1439 return val.toDouble() * QgsUnitTypes::fromUnitToUnitFactor( displayUnit, mBaseUnit );
1440 }
1441 else
1442 {
1443 return val;
1444 }
1445}
1446
1447QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingAreaWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
1448{
1449 return new QgsProcessingAreaParameterDefinitionWidget( context, widgetContext, definition, algorithm );
1450}
1451
1452
1453//
1454// QgsProcessingVolumeParameterDefinitionWidget
1455//
1456
1457QgsProcessingVolumeParameterDefinitionWidget::QgsProcessingVolumeParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
1458 : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
1459{
1460 QVBoxLayout *vlayout = new QVBoxLayout();
1461 vlayout->setContentsMargins( 0, 0, 0, 0 );
1462
1463 vlayout->addWidget( new QLabel( tr( "Linked input" ) ) );
1464
1465 mParentLayerComboBox = new QComboBox();
1466
1467 QString initialParent;
1468 if ( const QgsProcessingParameterVolume *volumeParam = dynamic_cast<const QgsProcessingParameterVolume *>( definition ) )
1469 initialParent = volumeParam->parentParameterName();
1470
1471 if ( auto *lModel = widgetContext.model() )
1472 {
1473 // populate combo box with other model input choices
1474 const QMap<QString, QgsProcessingModelParameter> components = lModel->parameterComponents();
1475 for ( auto it = components.constBegin(); it != components.constEnd(); ++it )
1476 {
1477 if ( const QgsProcessingParameterFeatureSource *definition = dynamic_cast<const QgsProcessingParameterFeatureSource *>( lModel->parameterDefinition( it.value().parameterName() ) ) )
1478 {
1479 mParentLayerComboBox->addItem( definition->description(), definition->name() );
1480 if ( !initialParent.isEmpty() && initialParent == definition->name() )
1481 {
1482 mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
1483 }
1484 }
1485 else if ( const QgsProcessingParameterVectorLayer *definition = dynamic_cast<const QgsProcessingParameterVectorLayer *>( lModel->parameterDefinition( it.value().parameterName() ) ) )
1486 {
1487 mParentLayerComboBox->addItem( definition->description(), definition->name() );
1488 if ( !initialParent.isEmpty() && initialParent == definition->name() )
1489 {
1490 mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
1491 }
1492 }
1493 else if ( const QgsProcessingParameterMapLayer *definition = dynamic_cast<const QgsProcessingParameterMapLayer *>( lModel->parameterDefinition( it.value().parameterName() ) ) )
1494 {
1495 mParentLayerComboBox->addItem( definition->description(), definition->name() );
1496 if ( !initialParent.isEmpty() && initialParent == definition->name() )
1497 {
1498 mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
1499 }
1500 }
1501 else if ( const QgsProcessingParameterCrs *definition = dynamic_cast<const QgsProcessingParameterCrs *>( lModel->parameterDefinition( it.value().parameterName() ) ) )
1502 {
1503 mParentLayerComboBox->addItem( definition->description(), definition->name() );
1504 if ( !initialParent.isEmpty() && initialParent == definition->name() )
1505 {
1506 mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
1507 }
1508 }
1509 }
1510 }
1511
1512 if ( mParentLayerComboBox->count() == 0 && !initialParent.isEmpty() )
1513 {
1514 // if no parent candidates found, we just add the existing one as a placeholder
1515 mParentLayerComboBox->addItem( initialParent, initialParent );
1516 mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
1517 }
1518
1519 vlayout->addWidget( mParentLayerComboBox );
1520
1521 vlayout->addWidget( new QLabel( tr( "Minimum value" ) ) );
1522 mMinLineEdit = new QLineEdit();
1523 vlayout->addWidget( mMinLineEdit );
1524
1525 vlayout->addWidget( new QLabel( tr( "Maximum value" ) ) );
1526 mMaxLineEdit = new QLineEdit();
1527 vlayout->addWidget( mMaxLineEdit );
1528
1529 vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
1530 mDefaultLineEdit = new QLineEdit();
1531 vlayout->addWidget( mDefaultLineEdit );
1532
1533 if ( const QgsProcessingParameterVolume *volumeParam = dynamic_cast<const QgsProcessingParameterVolume *>( definition ) )
1534 {
1535 mMinLineEdit->setText( QLocale().toString( volumeParam->minimum() ) );
1536 mMaxLineEdit->setText( QLocale().toString( volumeParam->maximum() ) );
1537 mDefaultLineEdit->setText( volumeParam->defaultValueForGui().toString() );
1538 }
1539
1540 setLayout( vlayout );
1541}
1542
1543QgsProcessingParameterDefinition *QgsProcessingVolumeParameterDefinitionWidget::createParameter( const QString &name, const QString &description, Qgis::ProcessingParameterFlags flags ) const
1544{
1545 bool ok;
1546 double val = QgsDoubleValidator::toDouble( mDefaultLineEdit->text(), &ok );
1547
1548 auto param = std::make_unique<QgsProcessingParameterVolume>( name, description, ok ? val : QVariant(), mParentLayerComboBox->currentData().toString() );
1549
1550 val = QgsDoubleValidator::toDouble( mMinLineEdit->text(), &ok );
1551 if ( ok )
1552 {
1553 param->setMinimum( val );
1554 }
1555
1556 val = QgsDoubleValidator::toDouble( mMaxLineEdit->text(), &ok );
1557 if ( ok )
1558 {
1559 param->setMaximum( val );
1560 }
1561
1562 param->setFlags( flags );
1563 return param.release();
1564}
1565
1566
1567//
1568// QgsProcessingVolumeWidgetWrapper
1569//
1570
1571QgsProcessingVolumeWidgetWrapper::QgsProcessingVolumeWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type, QWidget *parent )
1572 : QgsProcessingNumericWidgetWrapper( parameter, type, parent )
1573{
1574}
1575
1576QString QgsProcessingVolumeWidgetWrapper::parameterType() const
1577{
1579}
1580
1581QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingVolumeWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type )
1582{
1583 return new QgsProcessingVolumeWidgetWrapper( parameter, type );
1584}
1585
1586QWidget *QgsProcessingVolumeWidgetWrapper::createWidget()
1587{
1588 const QgsProcessingParameterVolume *volumeDef = static_cast<const QgsProcessingParameterVolume *>( parameterDefinition() );
1589
1590 QWidget *spin = QgsProcessingNumericWidgetWrapper::createWidget();
1591 switch ( type() )
1592 {
1594 {
1595 mLabel = new QLabel();
1596 mUnitsCombo = new QComboBox();
1597
1598 mUnitsCombo->addItem( QgsUnitTypes::toString( Qgis::VolumeUnit::CubicMeters ), QVariant::fromValue( Qgis::VolumeUnit::CubicMeters ) );
1599 mUnitsCombo->addItem( QgsUnitTypes::toString( Qgis::VolumeUnit::CubicFeet ), QVariant::fromValue( Qgis::VolumeUnit::CubicFeet ) );
1600 mUnitsCombo->addItem( QgsUnitTypes::toString( Qgis::VolumeUnit::CubicYards ), QVariant::fromValue( Qgis::VolumeUnit::CubicYards ) );
1601 mUnitsCombo->addItem( QgsUnitTypes::toString( Qgis::VolumeUnit::Barrel ), QVariant::fromValue( Qgis::VolumeUnit::Barrel ) );
1602 mUnitsCombo->addItem( QgsUnitTypes::toString( Qgis::VolumeUnit::CubicDecimeter ), QVariant::fromValue( Qgis::VolumeUnit::CubicDecimeter ) );
1603 mUnitsCombo->addItem( QgsUnitTypes::toString( Qgis::VolumeUnit::Liters ), QVariant::fromValue( Qgis::VolumeUnit::Liters ) );
1604 mUnitsCombo->addItem( QgsUnitTypes::toString( Qgis::VolumeUnit::GallonUS ), QVariant::fromValue( Qgis::VolumeUnit::GallonUS ) );
1605 mUnitsCombo->addItem( QgsUnitTypes::toString( Qgis::VolumeUnit::CubicInch ), QVariant::fromValue( Qgis::VolumeUnit::CubicInch ) );
1606 mUnitsCombo->addItem( QgsUnitTypes::toString( Qgis::VolumeUnit::CubicCentimeter ), QVariant::fromValue( Qgis::VolumeUnit::CubicCentimeter ) );
1607 mUnitsCombo->addItem( QgsUnitTypes::toString( Qgis::VolumeUnit::CubicDegrees ), QVariant::fromValue( Qgis::VolumeUnit::CubicDegrees ) );
1608
1609 const int labelMargin = static_cast<int>( std::round( mUnitsCombo->fontMetrics().horizontalAdvance( 'X' ) ) );
1610 QHBoxLayout *layout = new QHBoxLayout();
1611 layout->addWidget( spin, 1 );
1612 layout->insertSpacing( 1, labelMargin / 2 );
1613 layout->insertWidget( 2, mLabel );
1614 layout->insertWidget( 3, mUnitsCombo );
1615
1616 // bit of fiddlyness here -- we want the initial spacing to only be visible
1617 // when the warning label is shown, so it's embedded inside mWarningLabel
1618 // instead of outside it
1619 mWarningLabel = new QWidget();
1620 QHBoxLayout *warningLayout = new QHBoxLayout();
1621 warningLayout->setContentsMargins( 0, 0, 0, 0 );
1622 QLabel *warning = new QLabel();
1623 QIcon icon = QgsApplication::getThemeIcon( u"mIconWarning.svg"_s );
1624 const int size = static_cast<int>( std::max( 24.0, spin->minimumSize().height() * 0.5 ) );
1625 warning->setPixmap( icon.pixmap( icon.actualSize( QSize( size, size ) ) ) );
1626 warning->setToolTip( tr( "Volume is in geographic degrees. Consider reprojecting to a projected local coordinate system for accurate results." ) );
1627 warningLayout->insertSpacing( 0, labelMargin / 2 );
1628 warningLayout->insertWidget( 1, warning );
1629 mWarningLabel->setLayout( warningLayout );
1630 layout->insertWidget( 4, mWarningLabel );
1631
1632 QWidget *w = new QWidget();
1633 layout->setContentsMargins( 0, 0, 0, 0 );
1634 w->setLayout( layout );
1635
1636 setUnits( volumeDef->defaultUnit() );
1637
1638 return w;
1639 }
1640
1643 return spin;
1644 }
1645 return nullptr;
1646}
1647
1648void QgsProcessingVolumeWidgetWrapper::postInitialize( const QList<QgsAbstractProcessingParameterWidgetWrapper *> &wrappers )
1649{
1650 QgsProcessingNumericWidgetWrapper::postInitialize( wrappers );
1651 switch ( type() )
1652 {
1654 {
1655 for ( const QgsAbstractProcessingParameterWidgetWrapper *wrapper : wrappers )
1656 {
1657 if ( wrapper->parameterDefinition()->name() == static_cast<const QgsProcessingParameterVolume *>( parameterDefinition() )->parentParameterName() )
1658 {
1659 setUnitParameterValue( wrapper->parameterValue(), wrapper );
1660 connect( wrapper, &QgsAbstractProcessingParameterWidgetWrapper::widgetValueHasChanged, this, [this, wrapper] {
1661 setUnitParameterValue( wrapper->parameterValue(), wrapper );
1662 } );
1663 break;
1664 }
1665 }
1666 break;
1667 }
1668
1671 break;
1672 }
1673}
1674
1675void QgsProcessingVolumeWidgetWrapper::setUnitParameterValue( const QVariant &value, const QgsAbstractProcessingParameterWidgetWrapper *wrapper )
1676{
1678
1679 // evaluate value to layer
1680 QgsProcessingContext *context = nullptr;
1681 std::unique_ptr<QgsProcessingContext> tmpContext;
1682 if ( mProcessingContextGenerator )
1683 context = mProcessingContextGenerator->processingContext();
1684
1685 if ( !context )
1686 {
1687 tmpContext = std::make_unique<QgsProcessingContext>();
1688 context = tmpContext.get();
1689 }
1690
1691 const QgsCoordinateReferenceSystem crs = wrapper
1693 : QgsProcessingUtils::variantToCrs( value, *context );
1694 if ( crs.isValid() )
1695 {
1696 units = QgsUnitTypes::distanceToVolumeUnit( crs.mapUnits() );
1697 }
1698
1699 setUnits( units );
1700}
1701
1702void QgsProcessingVolumeWidgetWrapper::setUnits( Qgis::VolumeUnit units )
1703{
1704 mLabel->setText( QgsUnitTypes::toString( units ) );
1706 {
1707 mUnitsCombo->hide();
1708 mLabel->show();
1709 }
1710 else
1711 {
1712 mUnitsCombo->setCurrentIndex( mUnitsCombo->findData( QVariant::fromValue( units ) ) );
1713 mUnitsCombo->show();
1714 mLabel->hide();
1715 }
1716 mWarningLabel->setVisible( units == Qgis::VolumeUnit::CubicDegrees );
1717 mBaseUnit = units;
1718}
1719
1720QVariant QgsProcessingVolumeWidgetWrapper::widgetValue() const
1721{
1722 const QVariant val = QgsProcessingNumericWidgetWrapper::widgetValue();
1723 if ( val.userType() == QMetaType::Type::Double && mUnitsCombo && mUnitsCombo->isVisible() )
1724 {
1725 const Qgis::VolumeUnit displayUnit = mUnitsCombo->currentData().value<Qgis::VolumeUnit>();
1726 return val.toDouble() * QgsUnitTypes::fromUnitToUnitFactor( displayUnit, mBaseUnit );
1727 }
1728 else
1729 {
1730 return val;
1731 }
1732}
1733
1734QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingVolumeWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
1735{
1736 return new QgsProcessingVolumeParameterDefinitionWidget( context, widgetContext, definition, algorithm );
1737}
1738
1739
1740//
1741// QgsProcessingDurationWidgetWrapper
1742//
1743
1744QgsProcessingDurationParameterDefinitionWidget::QgsProcessingDurationParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
1745 : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
1746{
1747 QVBoxLayout *vlayout = new QVBoxLayout();
1748 vlayout->setContentsMargins( 0, 0, 0, 0 );
1749
1750 vlayout->addWidget( new QLabel( tr( "Minimum value" ) ) );
1751 mMinLineEdit = new QLineEdit();
1752 vlayout->addWidget( mMinLineEdit );
1753
1754 vlayout->addWidget( new QLabel( tr( "Maximum value" ) ) );
1755 mMaxLineEdit = new QLineEdit();
1756 vlayout->addWidget( mMaxLineEdit );
1757
1758 vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
1759 mDefaultLineEdit = new QLineEdit();
1760 vlayout->addWidget( mDefaultLineEdit );
1761
1762 vlayout->addWidget( new QLabel( tr( "Default unit type" ) ) );
1763
1764 mUnitsCombo = new QComboBox();
1766 mUnitsCombo->addItem( QgsUnitTypes::toString( Qgis::TemporalUnit::Seconds ), static_cast<int>( Qgis::TemporalUnit::Seconds ) );
1767 mUnitsCombo->addItem( QgsUnitTypes::toString( Qgis::TemporalUnit::Minutes ), static_cast<int>( Qgis::TemporalUnit::Minutes ) );
1768 mUnitsCombo->addItem( QgsUnitTypes::toString( Qgis::TemporalUnit::Hours ), static_cast<int>( Qgis::TemporalUnit::Hours ) );
1769 mUnitsCombo->addItem( QgsUnitTypes::toString( Qgis::TemporalUnit::Days ), static_cast<int>( Qgis::TemporalUnit::Days ) );
1770 mUnitsCombo->addItem( QgsUnitTypes::toString( Qgis::TemporalUnit::Weeks ), static_cast<int>( Qgis::TemporalUnit::Weeks ) );
1771 mUnitsCombo->addItem( tr( "years (365.25 days)" ), static_cast<int>( Qgis::TemporalUnit::Years ) );
1772 mUnitsCombo->addItem( QgsUnitTypes::toString( Qgis::TemporalUnit::Decades ), static_cast<int>( Qgis::TemporalUnit::Decades ) );
1773 mUnitsCombo->addItem( QgsUnitTypes::toString( Qgis::TemporalUnit::Centuries ), static_cast<int>( Qgis::TemporalUnit::Centuries ) );
1774 vlayout->addWidget( mUnitsCombo );
1775
1776 if ( const QgsProcessingParameterDuration *durationParam = dynamic_cast<const QgsProcessingParameterDuration *>( definition ) )
1777 {
1778 mMinLineEdit->setText( QLocale().toString( durationParam->minimum() ) );
1779 mMaxLineEdit->setText( QLocale().toString( durationParam->maximum() ) );
1780 mDefaultLineEdit->setText( durationParam->defaultValueForGui().toString() );
1781 mUnitsCombo->setCurrentIndex( mUnitsCombo->findData( static_cast<int>( durationParam->defaultUnit() ) ) );
1782 }
1783
1784 setLayout( vlayout );
1785}
1786
1787QgsProcessingParameterDefinition *QgsProcessingDurationParameterDefinitionWidget::createParameter( const QString &name, const QString &description, Qgis::ProcessingParameterFlags flags ) const
1788{
1789 bool ok;
1790 double val = QgsDoubleValidator::toDouble( mDefaultLineEdit->text(), &ok );
1791
1792 auto param = std::make_unique<QgsProcessingParameterDuration>( name, description, ok ? val : QVariant() );
1793
1794 val = QgsDoubleValidator::toDouble( mMinLineEdit->text(), &ok );
1795 if ( ok )
1796 {
1797 param->setMinimum( val );
1798 }
1799
1800 val = QgsDoubleValidator::toDouble( mMaxLineEdit->text(), &ok );
1801 if ( ok )
1802 {
1803 param->setMaximum( val );
1804 }
1805
1806 param->setDefaultUnit( static_cast<Qgis::TemporalUnit>( mUnitsCombo->currentData().toInt() ) );
1807
1808 param->setFlags( flags );
1809 return param.release();
1810}
1811
1812QgsProcessingDurationWidgetWrapper::QgsProcessingDurationWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type, QWidget *parent )
1813 : QgsProcessingNumericWidgetWrapper( parameter, type, parent )
1814{
1815}
1816
1817QString QgsProcessingDurationWidgetWrapper::parameterType() const
1818{
1820}
1821
1822QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingDurationWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type )
1823{
1824 return new QgsProcessingDurationWidgetWrapper( parameter, type );
1825}
1826
1827QWidget *QgsProcessingDurationWidgetWrapper::createWidget()
1828{
1829 const QgsProcessingParameterDuration *durationDef = static_cast<const QgsProcessingParameterDuration *>( parameterDefinition() );
1830
1831 QWidget *spin = QgsProcessingNumericWidgetWrapper::createWidget();
1832 switch ( type() )
1833 {
1835 {
1836 mUnitsCombo = new QComboBox();
1837
1839 mUnitsCombo->addItem( QgsUnitTypes::toString( Qgis::TemporalUnit::Seconds ), static_cast<int>( Qgis::TemporalUnit::Seconds ) );
1840 mUnitsCombo->addItem( QgsUnitTypes::toString( Qgis::TemporalUnit::Minutes ), static_cast<int>( Qgis::TemporalUnit::Minutes ) );
1841 mUnitsCombo->addItem( QgsUnitTypes::toString( Qgis::TemporalUnit::Hours ), static_cast<int>( Qgis::TemporalUnit::Hours ) );
1842 mUnitsCombo->addItem( QgsUnitTypes::toString( Qgis::TemporalUnit::Days ), static_cast<int>( Qgis::TemporalUnit::Days ) );
1843 mUnitsCombo->addItem( QgsUnitTypes::toString( Qgis::TemporalUnit::Weeks ), static_cast<int>( Qgis::TemporalUnit::Weeks ) );
1844 mUnitsCombo->addItem( tr( "years (365.25 days)" ), static_cast<int>( Qgis::TemporalUnit::Years ) );
1845 mUnitsCombo->addItem( QgsUnitTypes::toString( Qgis::TemporalUnit::Decades ), static_cast<int>( Qgis::TemporalUnit::Decades ) );
1846 mUnitsCombo->addItem( QgsUnitTypes::toString( Qgis::TemporalUnit::Centuries ), static_cast<int>( Qgis::TemporalUnit::Centuries ) );
1847
1848 QHBoxLayout *layout = new QHBoxLayout();
1849 layout->addWidget( spin, 1 );
1850 layout->insertWidget( 1, mUnitsCombo );
1851
1852 QWidget *w = new QWidget();
1853 layout->setContentsMargins( 0, 0, 0, 0 );
1854 w->setLayout( layout );
1855
1856 mUnitsCombo->setCurrentIndex( mUnitsCombo->findData( static_cast<int>( durationDef->defaultUnit() ) ) );
1857 mUnitsCombo->show();
1858
1859 return w;
1860 }
1861
1864 return spin;
1865 }
1866 return nullptr;
1867}
1868
1869QLabel *QgsProcessingDurationWidgetWrapper::createLabel()
1870{
1872
1873 if ( type() == Qgis::ProcessingMode::Modeler )
1874 {
1875 label->setText( u"%1 [%2]"_s.arg( label->text(), QgsUnitTypes::toString( mBaseUnit ) ) );
1876 }
1877
1878 return label;
1879}
1880
1881QVariant QgsProcessingDurationWidgetWrapper::widgetValue() const
1882{
1883 const QVariant val = QgsProcessingNumericWidgetWrapper::widgetValue();
1884 if ( val.userType() == QMetaType::Type::Double && mUnitsCombo )
1885 {
1886 Qgis::TemporalUnit displayUnit = static_cast<Qgis::TemporalUnit>( mUnitsCombo->currentData().toInt() );
1887 return val.toDouble() * QgsUnitTypes::fromUnitToUnitFactor( displayUnit, mBaseUnit );
1888 }
1889 else
1890 {
1891 return val;
1892 }
1893}
1894
1895void QgsProcessingDurationWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
1896{
1897 if ( mUnitsCombo )
1898 {
1899 Qgis::TemporalUnit displayUnit = static_cast<Qgis::TemporalUnit>( mUnitsCombo->currentData().toInt() );
1900 const QVariant val = value.toDouble() * QgsUnitTypes::fromUnitToUnitFactor( mBaseUnit, displayUnit );
1901 QgsProcessingNumericWidgetWrapper::setWidgetValue( val, context );
1902 }
1903 else
1904 {
1905 QgsProcessingNumericWidgetWrapper::setWidgetValue( value, context );
1906 }
1907}
1908
1909QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingDurationWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
1910{
1911 return new QgsProcessingDurationParameterDefinitionWidget( context, widgetContext, definition, algorithm );
1912}
1913
1914//
1915// QgsProcessingScaleWidgetWrapper
1916//
1917
1918QgsProcessingScaleParameterDefinitionWidget::QgsProcessingScaleParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
1919 : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
1920{
1921 QVBoxLayout *vlayout = new QVBoxLayout();
1922 vlayout->setContentsMargins( 0, 0, 0, 0 );
1923
1924 vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
1925
1926 mDefaultLineEdit = new QLineEdit();
1927
1928 if ( const QgsProcessingParameterScale *scaleParam = dynamic_cast<const QgsProcessingParameterScale *>( definition ) )
1929 {
1930 mDefaultLineEdit->setText( scaleParam->defaultValueForGui().toString() );
1931 }
1932
1933 vlayout->addWidget( mDefaultLineEdit );
1934
1935 setLayout( vlayout );
1936}
1937
1938QgsProcessingParameterDefinition *QgsProcessingScaleParameterDefinitionWidget::createParameter( const QString &name, const QString &description, Qgis::ProcessingParameterFlags flags ) const
1939{
1940 bool ok;
1941 double val = mDefaultLineEdit->text().toDouble( &ok );
1942 auto param = std::make_unique<QgsProcessingParameterScale>( name, description, ok ? val : QVariant() );
1943 param->setFlags( flags );
1944 return param.release();
1945}
1946
1947QgsProcessingScaleWidgetWrapper::QgsProcessingScaleWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type, QWidget *parent )
1948 : QgsProcessingNumericWidgetWrapper( parameter, type, parent )
1949{
1950}
1951
1952QString QgsProcessingScaleWidgetWrapper::parameterType() const
1953{
1955}
1956
1957QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingScaleWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type )
1958{
1959 return new QgsProcessingScaleWidgetWrapper( parameter, type );
1960}
1961
1962QWidget *QgsProcessingScaleWidgetWrapper::createWidget()
1963{
1964 const QgsProcessingParameterScale *scaleDef = static_cast<const QgsProcessingParameterScale *>( parameterDefinition() );
1965
1966 switch ( type() )
1967 {
1971 {
1972 mScaleWidget = new QgsScaleWidget( nullptr );
1974 mScaleWidget->setAllowNull( true );
1975
1976 mScaleWidget->setMapCanvas( widgetContext().mapCanvas() );
1977 mScaleWidget->setShowCurrentScaleButton( true );
1978
1979 mScaleWidget->setToolTip( parameterDefinition()->toolTip() );
1980 connect( mScaleWidget, &QgsScaleWidget::scaleChanged, this, [this]( double ) {
1981 emit widgetValueHasChanged( this );
1982 } );
1983 return mScaleWidget;
1984 }
1985 }
1986 return nullptr;
1987}
1988
1989void QgsProcessingScaleWidgetWrapper::setWidgetContext( const QgsProcessingParameterWidgetContext &context )
1990{
1991 if ( mScaleWidget )
1992 mScaleWidget->setMapCanvas( context.mapCanvas() );
1994}
1995
1996
1997QVariant QgsProcessingScaleWidgetWrapper::widgetValue() const
1998{
1999 return mScaleWidget && !mScaleWidget->isNull() ? QVariant( mScaleWidget->scale() ) : QVariant();
2000}
2001
2002void QgsProcessingScaleWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
2003{
2004 if ( mScaleWidget )
2005 {
2006 if ( mScaleWidget->allowNull() && !value.isValid() )
2007 mScaleWidget->setNull();
2008 else
2009 {
2010 const double v = QgsProcessingParameters::parameterAsDouble( parameterDefinition(), value, context );
2011 mScaleWidget->setScale( v );
2012 }
2013 }
2014}
2015
2016QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingScaleWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
2017{
2018 return new QgsProcessingScaleParameterDefinitionWidget( context, widgetContext, definition, algorithm );
2019}
2020
2021
2022//
2023// QgsProcessingRangeWidgetWrapper
2024//
2025
2026QgsProcessingRangeParameterDefinitionWidget::QgsProcessingRangeParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
2027 : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
2028{
2029 QVBoxLayout *vlayout = new QVBoxLayout();
2030 vlayout->setContentsMargins( 0, 0, 0, 0 );
2031
2032 vlayout->addWidget( new QLabel( tr( "Number type" ) ) );
2033
2034 mTypeComboBox = new QComboBox();
2035 mTypeComboBox->addItem( tr( "Float" ), static_cast<int>( Qgis::ProcessingNumberParameterType::Double ) );
2036 mTypeComboBox->addItem( tr( "Integer" ), static_cast<int>( Qgis::ProcessingNumberParameterType::Integer ) );
2037 vlayout->addWidget( mTypeComboBox );
2038
2039 vlayout->addWidget( new QLabel( tr( "Minimum value" ) ) );
2040 mMinLineEdit = new QLineEdit();
2041 vlayout->addWidget( mMinLineEdit );
2042
2043 vlayout->addWidget( new QLabel( tr( "Maximum value" ) ) );
2044 mMaxLineEdit = new QLineEdit();
2045 vlayout->addWidget( mMaxLineEdit );
2046
2047 if ( const QgsProcessingParameterRange *rangeParam = dynamic_cast<const QgsProcessingParameterRange *>( definition ) )
2048 {
2049 mTypeComboBox->setCurrentIndex( mTypeComboBox->findData( static_cast<int>( rangeParam->dataType() ) ) );
2050 const QList<double> range = QgsProcessingParameters::parameterAsRange( rangeParam, rangeParam->defaultValueForGui(), context );
2051 mMinLineEdit->setText( QLocale().toString( range.at( 0 ) ) );
2052 mMaxLineEdit->setText( QLocale().toString( range.at( 1 ) ) );
2053 }
2054
2055 setLayout( vlayout );
2056}
2057
2058QgsProcessingParameterDefinition *QgsProcessingRangeParameterDefinitionWidget::createParameter( const QString &name, const QString &description, Qgis::ProcessingParameterFlags flags ) const
2059{
2060 QString defaultValue;
2061 if ( mMinLineEdit->text().isEmpty() )
2062 {
2063 defaultValue = u"None"_s;
2064 }
2065 else
2066 {
2067 bool ok;
2068 defaultValue = QString::number( QgsDoubleValidator::toDouble( mMinLineEdit->text(), &ok ) );
2069 if ( !ok )
2070 {
2071 defaultValue = u"None"_s;
2072 }
2073 }
2074
2075 if ( mMaxLineEdit->text().isEmpty() )
2076 {
2077 defaultValue += ",None"_L1;
2078 }
2079 else
2080 {
2081 bool ok;
2082 const double val { QgsDoubleValidator::toDouble( mMaxLineEdit->text(), &ok ) };
2083 defaultValue += u",%1"_s.arg( ok ? QString::number( val ) : "None"_L1 );
2084 }
2085
2086 Qgis::ProcessingNumberParameterType dataType = static_cast<Qgis::ProcessingNumberParameterType>( mTypeComboBox->currentData().toInt() );
2087 auto param = std::make_unique<QgsProcessingParameterRange>( name, description, dataType, defaultValue );
2088 param->setFlags( flags );
2089 return param.release();
2090}
2091
2092
2093QgsProcessingRangeWidgetWrapper::QgsProcessingRangeWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type, QWidget *parent )
2094 : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
2095{
2096}
2097
2098QWidget *QgsProcessingRangeWidgetWrapper::createWidget()
2099{
2100 const QgsProcessingParameterRange *rangeDef = static_cast<const QgsProcessingParameterRange *>( parameterDefinition() );
2101 switch ( type() )
2102 {
2106 {
2107 QHBoxLayout *layout = new QHBoxLayout();
2108
2109 mMinSpinBox = new QgsDoubleSpinBox();
2110 mMaxSpinBox = new QgsDoubleSpinBox();
2111
2112 mMinSpinBox->setExpressionsEnabled( true );
2113 mMinSpinBox->setShowClearButton( false );
2114 mMaxSpinBox->setExpressionsEnabled( true );
2115 mMaxSpinBox->setShowClearButton( false );
2116
2117 QLabel *minLabel = new QLabel( tr( "Min" ) );
2118 layout->addWidget( minLabel );
2119 layout->addWidget( mMinSpinBox, 1 );
2120
2121 QLabel *maxLabel = new QLabel( tr( "Max" ) );
2122 layout->addWidget( maxLabel );
2123 layout->addWidget( mMaxSpinBox, 1 );
2124
2125 QWidget *w = new QWidget();
2126 layout->setContentsMargins( 0, 0, 0, 0 );
2127 w->setLayout( layout );
2128
2130 {
2131 mMinSpinBox->setDecimals( 6 );
2132 mMaxSpinBox->setDecimals( 6 );
2133 }
2134 else
2135 {
2136 mMinSpinBox->setDecimals( 0 );
2137 mMaxSpinBox->setDecimals( 0 );
2138 }
2139
2140 mMinSpinBox->setMinimum( -99999999.999999 );
2141 mMaxSpinBox->setMinimum( -99999999.999999 );
2142 mMinSpinBox->setMaximum( 99999999.999999 );
2143 mMaxSpinBox->setMaximum( 99999999.999999 );
2144
2146 {
2147 mAllowingNull = true;
2148
2149 const double min = mMinSpinBox->minimum() - 1;
2150 mMinSpinBox->setMinimum( min );
2151 mMaxSpinBox->setMinimum( min );
2152 mMinSpinBox->setValue( min );
2153 mMaxSpinBox->setValue( min );
2154
2155 mMinSpinBox->setShowClearButton( true );
2156 mMaxSpinBox->setShowClearButton( true );
2157 mMinSpinBox->setSpecialValueText( tr( "Not set" ) );
2158 mMaxSpinBox->setSpecialValueText( tr( "Not set" ) );
2159 }
2160
2161 w->setToolTip( parameterDefinition()->toolTip() );
2162
2163 connect( mMinSpinBox, qOverload<double>( &QgsDoubleSpinBox::valueChanged ), this, [this]( const double v ) {
2164 mBlockChangedSignal++;
2165 if ( !mAllowingNull && v > mMaxSpinBox->value() )
2166 mMaxSpinBox->setValue( v );
2167 mBlockChangedSignal--;
2168
2169 if ( !mBlockChangedSignal )
2170 emit widgetValueHasChanged( this );
2171 } );
2172 connect( mMaxSpinBox, qOverload<double>( &QgsDoubleSpinBox::valueChanged ), this, [this]( const double v ) {
2173 mBlockChangedSignal++;
2174 if ( !mAllowingNull && v < mMinSpinBox->value() )
2175 mMinSpinBox->setValue( v );
2176 mBlockChangedSignal--;
2177
2178 if ( !mBlockChangedSignal )
2179 emit widgetValueHasChanged( this );
2180 } );
2181
2182 return w;
2183 }
2184 }
2185 return nullptr;
2186}
2187
2188void QgsProcessingRangeWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
2189{
2190 const QList<double> v = QgsProcessingParameters::parameterAsRange( parameterDefinition(), value, context );
2191 if ( mAllowingNull && v.empty() )
2192 {
2193 mMinSpinBox->clear();
2194 mMaxSpinBox->clear();
2195 }
2196 else
2197 {
2198 if ( v.empty() )
2199 return;
2200
2201 if ( mAllowingNull )
2202 {
2203 mBlockChangedSignal++;
2204 if ( std::isnan( v.at( 0 ) ) )
2205 mMinSpinBox->clear();
2206 else
2207 mMinSpinBox->setValue( v.at( 0 ) );
2208
2209 if ( v.count() >= 2 )
2210 {
2211 if ( std::isnan( v.at( 1 ) ) )
2212 mMaxSpinBox->clear();
2213 else
2214 mMaxSpinBox->setValue( v.at( 1 ) );
2215 }
2216 mBlockChangedSignal--;
2217 }
2218 else
2219 {
2220 mBlockChangedSignal++;
2221 mMinSpinBox->setValue( v.at( 0 ) );
2222 if ( v.count() >= 2 )
2223 mMaxSpinBox->setValue( v.at( 1 ) );
2224 mBlockChangedSignal--;
2225 }
2226 }
2227
2228 if ( !mBlockChangedSignal )
2229 emit widgetValueHasChanged( this );
2230}
2231
2232QVariant QgsProcessingRangeWidgetWrapper::widgetValue() const
2233{
2234 if ( mAllowingNull )
2235 {
2236 QString value;
2237 if ( qgsDoubleNear( mMinSpinBox->value(), mMinSpinBox->minimum() ) )
2238 value = u"None"_s;
2239 else
2240 value = QString::number( mMinSpinBox->value() );
2241
2242 if ( qgsDoubleNear( mMaxSpinBox->value(), mMaxSpinBox->minimum() ) )
2243 value += ",None"_L1;
2244 else
2245 value += u",%1"_s.arg( mMaxSpinBox->value() );
2246
2247 return value;
2248 }
2249 else
2250 return u"%1,%2"_s.arg( mMinSpinBox->value() ).arg( mMaxSpinBox->value() );
2251}
2252
2253QString QgsProcessingRangeWidgetWrapper::modelerExpressionFormatString() const
2254{
2255 return tr( "string as two comma delimited floats, e.g. '1,10'" );
2256}
2257
2258QString QgsProcessingRangeWidgetWrapper::parameterType() const
2259{
2261}
2262
2263QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingRangeWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type )
2264{
2265 return new QgsProcessingRangeWidgetWrapper( parameter, type );
2266}
2267
2268QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingRangeWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
2269{
2270 return new QgsProcessingRangeParameterDefinitionWidget( context, widgetContext, definition, algorithm );
2271}
2272
2273
2274//
2275// QgsProcessingMatrixWidgetWrapper
2276//
2277
2278QgsProcessingMatrixParameterDefinitionWidget::QgsProcessingMatrixParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
2279 : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
2280{
2281 QVBoxLayout *vlayout = new QVBoxLayout();
2282 vlayout->setContentsMargins( 0, 0, 0, 0 );
2283
2284 mMatrixWidget = new QgsProcessingMatrixModelerWidget();
2285 if ( const QgsProcessingParameterMatrix *matrixParam = dynamic_cast<const QgsProcessingParameterMatrix *>( definition ) )
2286 {
2287 mMatrixWidget->setValue( matrixParam->headers(), matrixParam->defaultValueForGui() );
2288 mMatrixWidget->setFixedRows( matrixParam->hasFixedNumberRows() );
2289 }
2290 vlayout->addWidget( mMatrixWidget );
2291 setLayout( vlayout );
2292}
2293
2294QgsProcessingParameterDefinition *QgsProcessingMatrixParameterDefinitionWidget::createParameter( const QString &name, const QString &description, Qgis::ProcessingParameterFlags flags ) const
2295{
2296 auto param = std::make_unique<QgsProcessingParameterMatrix>( name, description, 1, mMatrixWidget->fixedRows(), mMatrixWidget->headers(), mMatrixWidget->value() );
2297 param->setFlags( flags );
2298 return param.release();
2299}
2300
2301
2302QgsProcessingMatrixWidgetWrapper::QgsProcessingMatrixWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type, QWidget *parent )
2303 : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
2304{
2305}
2306
2307QWidget *QgsProcessingMatrixWidgetWrapper::createWidget()
2308{
2309 mMatrixWidget = new QgsProcessingMatrixParameterPanel( nullptr, dynamic_cast<const QgsProcessingParameterMatrix *>( parameterDefinition() ) );
2310 mMatrixWidget->setToolTip( parameterDefinition()->toolTip() );
2311
2312 connect( mMatrixWidget, &QgsProcessingMatrixParameterPanel::changed, this, [this] {
2313 emit widgetValueHasChanged( this );
2314 } );
2315
2316 switch ( type() )
2317 {
2321 {
2322 return mMatrixWidget;
2323 }
2324 }
2325 return nullptr;
2326}
2327
2328void QgsProcessingMatrixWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
2329{
2330 const QVariantList v = QgsProcessingParameters::parameterAsMatrix( parameterDefinition(), value, context );
2331 if ( mMatrixWidget )
2332 mMatrixWidget->setValue( v );
2333}
2334
2335QVariant QgsProcessingMatrixWidgetWrapper::widgetValue() const
2336{
2337 if ( mMatrixWidget )
2338 return mMatrixWidget->value().isEmpty() ? QVariant() : mMatrixWidget->value();
2339 else
2340 return QVariant();
2341}
2342
2343QString QgsProcessingMatrixWidgetWrapper::modelerExpressionFormatString() const
2344{
2345 return tr( "comma delimited string of values, or an array of values" );
2346}
2347
2348QString QgsProcessingMatrixWidgetWrapper::parameterType() const
2349{
2351}
2352
2353QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingMatrixWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type )
2354{
2355 return new QgsProcessingMatrixWidgetWrapper( parameter, type );
2356}
2357
2358QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingMatrixWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
2359{
2360 return new QgsProcessingMatrixParameterDefinitionWidget( context, widgetContext, definition, algorithm );
2361}
2362
2363
2364//
2365// QgsProcessingFileWidgetWrapper
2366//
2367
2368
2369QgsProcessingFileParameterDefinitionWidget::QgsProcessingFileParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
2370 : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
2371{
2372 QVBoxLayout *vlayout = new QVBoxLayout();
2373 vlayout->setContentsMargins( 0, 0, 0, 0 );
2374
2375 vlayout->addWidget( new QLabel( tr( "Type" ) ) );
2376
2377 mTypeComboBox = new QComboBox();
2378 mTypeComboBox->addItem( tr( "File" ), static_cast<int>( Qgis::ProcessingFileParameterBehavior::File ) );
2379 mTypeComboBox->addItem( tr( "Folder" ), static_cast<int>( Qgis::ProcessingFileParameterBehavior::Folder ) );
2380 if ( const QgsProcessingParameterFile *fileParam = dynamic_cast<const QgsProcessingParameterFile *>( definition ) )
2381 mTypeComboBox->setCurrentIndex( mTypeComboBox->findData( static_cast<int>( fileParam->behavior() ) ) );
2382 else
2383 mTypeComboBox->setCurrentIndex( 0 );
2384 vlayout->addWidget( mTypeComboBox );
2385
2386 vlayout->addWidget( new QLabel( tr( "File filter" ) ) );
2387
2388 mFilterComboBox = new QComboBox();
2389 mFilterComboBox->setEditable( true );
2390 // add some standard ones -- these also act as a demonstration of the required format
2391 mFilterComboBox->addItem( tr( "All Files (*.*)" ) );
2392 mFilterComboBox->addItem( tr( "CSV Files (*.csv)" ) );
2393 mFilterComboBox->addItem( tr( "HTML Files (*.html *.htm)" ) );
2394 mFilterComboBox->addItem( tr( "Text Files (*.txt)" ) );
2395 if ( const QgsProcessingParameterFile *fileParam = dynamic_cast<const QgsProcessingParameterFile *>( definition ) )
2396 mFilterComboBox->setCurrentText( fileParam->fileFilter() );
2397 else
2398 mFilterComboBox->setCurrentIndex( 0 );
2399 vlayout->addWidget( mFilterComboBox );
2400
2401 vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
2402
2403 mDefaultFileWidget = new QgsFileWidget();
2404 mDefaultFileWidget->lineEdit()->setShowClearButton( true );
2405 if ( const QgsProcessingParameterFile *fileParam = dynamic_cast<const QgsProcessingParameterFile *>( definition ) )
2406 {
2407 mDefaultFileWidget->setStorageMode( fileParam->behavior() == Qgis::ProcessingFileParameterBehavior::File ? QgsFileWidget::GetFile : QgsFileWidget::GetDirectory );
2408 mDefaultFileWidget->setFilePath( fileParam->defaultValueForGui().toString() );
2409 }
2410 else
2411 mDefaultFileWidget->setStorageMode( QgsFileWidget::GetFile );
2412 vlayout->addWidget( mDefaultFileWidget );
2413
2414 connect( mTypeComboBox, qOverload<int>( &QComboBox::currentIndexChanged ), this, [this] {
2415 Qgis::ProcessingFileParameterBehavior behavior = static_cast<Qgis::ProcessingFileParameterBehavior>( mTypeComboBox->currentData().toInt() );
2416 mFilterComboBox->setEnabled( behavior == Qgis::ProcessingFileParameterBehavior::File );
2417 mDefaultFileWidget->setStorageMode( behavior == Qgis::ProcessingFileParameterBehavior::File ? QgsFileWidget::GetFile : QgsFileWidget::GetDirectory );
2418 } );
2419 mFilterComboBox->setEnabled( static_cast<Qgis::ProcessingFileParameterBehavior>( mTypeComboBox->currentData().toInt() ) == Qgis::ProcessingFileParameterBehavior::File );
2420
2421
2422 setLayout( vlayout );
2423}
2424
2425QgsProcessingParameterDefinition *QgsProcessingFileParameterDefinitionWidget::createParameter( const QString &name, const QString &description, Qgis::ProcessingParameterFlags flags ) const
2426{
2427 auto param = std::make_unique<QgsProcessingParameterFile>( name, description );
2428 param->setBehavior( static_cast<Qgis::ProcessingFileParameterBehavior>( mTypeComboBox->currentData().toInt() ) );
2429 if ( param->behavior() == Qgis::ProcessingFileParameterBehavior::File )
2430 param->setFileFilter( mFilterComboBox->currentText() );
2431 if ( !mDefaultFileWidget->filePath().isEmpty() )
2432 param->setDefaultValue( mDefaultFileWidget->filePath() );
2433 param->setFlags( flags );
2434 return param.release();
2435}
2436
2437
2438QgsProcessingFileWidgetWrapper::QgsProcessingFileWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type, QWidget *parent )
2439 : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
2440{
2441}
2442
2443QWidget *QgsProcessingFileWidgetWrapper::createWidget()
2444{
2445 const QgsProcessingParameterFile *fileParam = dynamic_cast<const QgsProcessingParameterFile *>( parameterDefinition() );
2446 if ( !fileParam )
2447 return nullptr;
2448
2449 switch ( type() )
2450 {
2454 {
2455 mFileWidget = new QgsFileWidget();
2456 mFileWidget->setToolTip( parameterDefinition()->toolTip() );
2457 mFileWidget->setDialogTitle( parameterDefinition()->description() );
2458
2459 mFileWidget->setDefaultRoot( QgsSettings().value( u"/Processing/LastInputPath"_s, QDir::homePath() ).toString() );
2460
2461 switch ( fileParam->behavior() )
2462 {
2464 mFileWidget->setStorageMode( QgsFileWidget::GetFile );
2465 if ( !fileParam->fileFilter().isEmpty() )
2466 mFileWidget->setFilter( fileParam->fileFilter() );
2467 else if ( !fileParam->extension().isEmpty() )
2468 mFileWidget->setFilter( tr( "%1 files" ).arg( fileParam->extension().toUpper() ) + u" (*."_s + fileParam->extension().toLower() + ')' );
2469 break;
2470
2472 mFileWidget->setStorageMode( QgsFileWidget::GetDirectory );
2473 break;
2474 }
2475
2476 connect( mFileWidget, &QgsFileWidget::fileChanged, this, [this]( const QString &path ) {
2477 QgsSettings().setValue( u"/Processing/LastInputPath"_s, QFileInfo( path ).canonicalPath() );
2478 emit widgetValueHasChanged( this );
2479 } );
2480 return mFileWidget;
2481 }
2482 }
2483 return nullptr;
2484}
2485
2486void QgsProcessingFileWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
2487{
2488 const QString v = QgsProcessingParameters::parameterAsString( parameterDefinition(), value, context );
2489 if ( mFileWidget )
2490 mFileWidget->setFilePath( v );
2491}
2492
2493QVariant QgsProcessingFileWidgetWrapper::widgetValue() const
2494{
2495 if ( mFileWidget )
2496 return mFileWidget->filePath();
2497 else
2498 return QVariant();
2499}
2500
2501QString QgsProcessingFileWidgetWrapper::modelerExpressionFormatString() const
2502{
2503 return tr( "string representing a path to a file or folder" );
2504}
2505
2506QString QgsProcessingFileWidgetWrapper::parameterType() const
2507{
2509}
2510
2511QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingFileWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type )
2512{
2513 return new QgsProcessingFileWidgetWrapper( parameter, type );
2514}
2515
2516QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingFileWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
2517{
2518 return new QgsProcessingFileParameterDefinitionWidget( context, widgetContext, definition, algorithm );
2519}
2520
2521
2522//
2523// QgsProcessingExpressionWidgetWrapper
2524//
2525
2526QgsProcessingExpressionParameterDefinitionWidget::QgsProcessingExpressionParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
2527 : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
2528{
2529 QVBoxLayout *vlayout = new QVBoxLayout();
2530 vlayout->setContentsMargins( 0, 0, 0, 0 );
2531 vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
2532
2533 mDefaultQgisLineEdit = new QgsExpressionLineEdit();
2534 mDefaultQgisLineEdit->registerExpressionContextGenerator( this );
2535
2536 mDefaultPointCloudLineEdit = new QgsProcessingPointCloudExpressionLineEdit();
2537 mDefaultRasterCalculatorLineEdit = new QgsProcessingRasterCalculatorExpressionLineEdit();
2538
2539 QStackedWidget *stackedWidget = new QStackedWidget();
2540 stackedWidget->addWidget( mDefaultQgisLineEdit );
2541 stackedWidget->addWidget( mDefaultPointCloudLineEdit );
2542 stackedWidget->addWidget( mDefaultRasterCalculatorLineEdit );
2543 vlayout->addWidget( stackedWidget );
2544
2545 if ( const QgsProcessingParameterExpression *expParam = dynamic_cast<const QgsProcessingParameterExpression *>( definition ) )
2546 {
2547 const QString expr = QgsProcessingParameters::parameterAsExpression( expParam, expParam->defaultValueForGui(), context );
2548 mDefaultQgisLineEdit->setExpression( expr );
2549 mDefaultPointCloudLineEdit->setExpression( expr );
2550 }
2551
2552 vlayout->addWidget( new QLabel( tr( "Parent layer" ) ) );
2553
2554 mParentLayerComboBox = new QComboBox();
2555 vlayout->addWidget( mParentLayerComboBox );
2556
2557 vlayout->addWidget( new QLabel( tr( "Expression type" ) ) );
2558 mExpressionTypeComboBox = new QComboBox();
2559 mExpressionTypeComboBox->addItem( tr( "QGIS" ), static_cast<int>( Qgis::ExpressionType::Qgis ) );
2560 mExpressionTypeComboBox->addItem( tr( "Point Cloud" ), static_cast<int>( Qgis::ExpressionType::PointCloud ) );
2561 mExpressionTypeComboBox->addItem( tr( "Raster Calculator" ), static_cast<int>( Qgis::ExpressionType::RasterCalculator ) );
2562
2563 connect( mExpressionTypeComboBox, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, [this, stackedWidget, definition, widgetContext]( int ) {
2564 mParentLayerComboBox->clear();
2565 mParentLayerComboBox->addItem( tr( "None" ), QVariant() );
2566
2567 stackedWidget->setCurrentIndex( mExpressionTypeComboBox->currentIndex() > 0 ? mExpressionTypeComboBox->currentIndex() : 0 );
2568
2569 QString initialParent;
2570 if ( const QgsProcessingParameterExpression *expParam = dynamic_cast<const QgsProcessingParameterExpression *>( definition ) )
2571 initialParent = expParam->parentLayerParameterName();
2572
2573 Qgis::ExpressionType exprType = static_cast<Qgis::ExpressionType>( mExpressionTypeComboBox->currentData().toInt() );
2574
2575 if ( QgsProcessingModelAlgorithm *model = widgetContext.model() )
2576 {
2577 // populate combo box with other model input choices
2578 const QMap<QString, QgsProcessingModelParameter> components = model->parameterComponents();
2579 for ( auto it = components.constBegin(); it != components.constEnd(); ++it )
2580 {
2581 switch ( exprType )
2582 {
2584 if ( const QgsProcessingParameterFeatureSource *definition = dynamic_cast<const QgsProcessingParameterFeatureSource *>( model->parameterDefinition( it.value().parameterName() ) ) )
2585 {
2586 mParentLayerComboBox->addItem( definition->description(), definition->name() );
2587 if ( !initialParent.isEmpty() && initialParent == definition->name() )
2588 {
2589 mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
2590 }
2591 }
2592 else if ( const QgsProcessingParameterVectorLayer *definition = dynamic_cast<const QgsProcessingParameterVectorLayer *>( model->parameterDefinition( it.value().parameterName() ) ) )
2593 {
2594 mParentLayerComboBox->addItem( definition->description(), definition->name() );
2595 if ( !initialParent.isEmpty() && initialParent == definition->name() )
2596 {
2597 mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
2598 }
2599 }
2600 break;
2602 if ( const QgsProcessingParameterPointCloudLayer *definition = dynamic_cast<const QgsProcessingParameterPointCloudLayer *>( model->parameterDefinition( it.value().parameterName() ) ) )
2603 {
2604 mParentLayerComboBox->addItem( definition->description(), definition->name() );
2605 if ( !initialParent.isEmpty() && initialParent == definition->name() )
2606 {
2607 mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
2608 }
2609 }
2610 break;
2612 if ( const QgsProcessingParameterMultipleLayers *definition = dynamic_cast<const QgsProcessingParameterMultipleLayers *>( model->parameterDefinition( it.value().parameterName() ) ) )
2613 {
2614 if ( definition->layerType() != Qgis::ProcessingSourceType::Raster )
2615 {
2616 continue;
2617 }
2618 mParentLayerComboBox->addItem( definition->description(), definition->name() );
2619 if ( !initialParent.isEmpty() && initialParent == definition->name() )
2620 {
2621 mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
2622 }
2623 }
2624 break;
2625 }
2626 }
2627 }
2628
2629 if ( mParentLayerComboBox->count() == 1 && !initialParent.isEmpty() )
2630 {
2631 // if no parent candidates found, we just add the existing one as a placeholder
2632 mParentLayerComboBox->addItem( initialParent, initialParent );
2633 mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
2634 }
2635 } );
2636
2637 mExpressionTypeComboBox->setCurrentIndex( -1 );
2638 if ( const QgsProcessingParameterExpression *expParam = dynamic_cast<const QgsProcessingParameterExpression *>( definition ) )
2639 mExpressionTypeComboBox->setCurrentIndex( mExpressionTypeComboBox->findData( static_cast<int>( expParam->expressionType() ) ) );
2640 else
2641 mExpressionTypeComboBox->setCurrentIndex( 0 );
2642
2643 vlayout->addWidget( mExpressionTypeComboBox );
2644
2645 setLayout( vlayout );
2646}
2647
2648QgsProcessingParameterDefinition *QgsProcessingExpressionParameterDefinitionWidget::createParameter( const QString &name, const QString &description, Qgis::ProcessingParameterFlags flags ) const
2649{
2650 Qgis::ExpressionType expressionType = static_cast<Qgis::ExpressionType>( mExpressionTypeComboBox->currentData().toInt() );
2651 QString expression;
2652 switch ( expressionType )
2653 {
2655 expression = mDefaultQgisLineEdit->expression();
2656 break;
2658 expression = mDefaultPointCloudLineEdit->expression();
2659 break;
2661 expression = mDefaultRasterCalculatorLineEdit->expression();
2662 break;
2663 }
2664 auto param = std::make_unique<QgsProcessingParameterExpression>( name, description, expression, mParentLayerComboBox->currentData().toString(), false, expressionType );
2665 param->setFlags( flags );
2666 return param.release();
2667}
2668
2669QgsProcessingExpressionWidgetWrapper::QgsProcessingExpressionWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type, QWidget *parent )
2670 : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
2671{
2672}
2673
2674QWidget *QgsProcessingExpressionWidgetWrapper::createWidget()
2675{
2676 const QgsProcessingParameterExpression *expParam = dynamic_cast<const QgsProcessingParameterExpression *>( parameterDefinition() );
2677 if ( !expParam )
2678 return nullptr;
2679
2680 switch ( type() )
2681 {
2685 {
2686 if ( expParam->parentLayerParameterName().isEmpty() )
2687 {
2688 mExpLineEdit = new QgsExpressionLineEdit();
2689 mExpLineEdit->setToolTip( parameterDefinition()->toolTip() );
2690 mExpLineEdit->setExpressionDialogTitle( parameterDefinition()->description() );
2691 mExpLineEdit->registerExpressionContextGenerator( this );
2692 connect( mExpLineEdit, &QgsExpressionLineEdit::expressionChanged, this, [this]( const QString & ) {
2693 emit widgetValueHasChanged( this );
2694 } );
2695 return mExpLineEdit;
2696 }
2697 else
2698 {
2700 {
2701 mPointCloudExpLineEdit = new QgsProcessingPointCloudExpressionLineEdit();
2702 mPointCloudExpLineEdit->setToolTip( parameterDefinition()->toolTip() );
2703 connect( mPointCloudExpLineEdit, &QgsProcessingPointCloudExpressionLineEdit::expressionChanged, this, [this]( const QString & ) {
2704 emit widgetValueHasChanged( this );
2705 } );
2706 return mPointCloudExpLineEdit;
2707 }
2708
2710 {
2711 mRasterCalculatorExpLineEdit = new QgsProcessingRasterCalculatorExpressionLineEdit();
2712 mRasterCalculatorExpLineEdit->setToolTip( parameterDefinition()->toolTip() );
2713 if ( type() == Qgis::ProcessingMode::Modeler )
2714 {
2715 mRasterCalculatorExpLineEdit->setLayers( QVariantList() << "A" << "B" << "C" << "D" << "E" << "F" << "G" );
2716 }
2717 connect( mRasterCalculatorExpLineEdit, &QgsProcessingRasterCalculatorExpressionLineEdit::expressionChanged, this, [this]( const QString & ) {
2718 emit widgetValueHasChanged( this );
2719 } );
2720 return mRasterCalculatorExpLineEdit;
2721 }
2722
2723 // native QGIS expression
2724 if ( expParam->metadata().value( u"inlineEditor"_s ).toBool() )
2725 {
2726 mExpBuilderWidget = new QgsExpressionBuilderWidget();
2727 mExpBuilderWidget->setToolTip( parameterDefinition()->toolTip() );
2728 mExpBuilderWidget->init( createExpressionContext() );
2729 connect( mExpBuilderWidget, &QgsExpressionBuilderWidget::expressionParsed, this, [this]( bool changed ) {
2730 Q_UNUSED( changed );
2731 emit widgetValueHasChanged( this );
2732 } );
2733 return mExpBuilderWidget;
2734 }
2735 else
2736 {
2737 mFieldExpWidget = new QgsFieldExpressionWidget();
2738 mFieldExpWidget->setToolTip( parameterDefinition()->toolTip() );
2739 mFieldExpWidget->setExpressionDialogTitle( parameterDefinition()->description() );
2740 mFieldExpWidget->registerExpressionContextGenerator( this );
2742 mFieldExpWidget->setAllowEmptyFieldName( true );
2743
2744 connect( mFieldExpWidget, static_cast<void ( QgsFieldExpressionWidget::* )( const QString & )>( &QgsFieldExpressionWidget::fieldChanged ), this, [this]( const QString & ) {
2745 emit widgetValueHasChanged( this );
2746 } );
2747 return mFieldExpWidget;
2748 }
2749 }
2750 }
2751 }
2752 return nullptr;
2753}
2754
2755void QgsProcessingExpressionWidgetWrapper::postInitialize( const QList<QgsAbstractProcessingParameterWidgetWrapper *> &wrappers )
2756{
2758 switch ( type() )
2759 {
2762 {
2763 for ( const QgsAbstractProcessingParameterWidgetWrapper *wrapper : wrappers )
2764 {
2765 if ( wrapper->parameterDefinition()->name() == static_cast<const QgsProcessingParameterExpression *>( parameterDefinition() )->parentLayerParameterName() )
2766 {
2767 setParentLayerWrapperValue( wrapper );
2768 connect( wrapper, &QgsAbstractProcessingParameterWidgetWrapper::widgetValueHasChanged, this, [this, wrapper] {
2769 setParentLayerWrapperValue( wrapper );
2770 } );
2771 break;
2772 }
2773 }
2774 break;
2775 }
2776
2778 break;
2779 }
2780}
2781
2782void QgsProcessingExpressionWidgetWrapper::registerProcessingContextGenerator( QgsProcessingContextGenerator *generator )
2783{
2785 if ( mExpBuilderWidget )
2786 {
2787 // we need to regenerate the expression context for use by this widget -- it doesn't fetch automatically on demand
2788 mExpBuilderWidget->setExpressionContext( createExpressionContext() );
2789 }
2790}
2791
2792void QgsProcessingExpressionWidgetWrapper::setParentLayerWrapperValue( const QgsAbstractProcessingParameterWidgetWrapper *parentWrapper )
2793{
2794 // evaluate value to layer
2795 QgsProcessingContext *context = nullptr;
2796 std::unique_ptr<QgsProcessingContext> tmpContext;
2797 if ( mProcessingContextGenerator )
2798 context = mProcessingContextGenerator->processingContext();
2799
2800 if ( !context )
2801 {
2802 tmpContext = std::make_unique<QgsProcessingContext>();
2803 context = tmpContext.get();
2804 }
2805
2806 QVariant val = parentWrapper->parameterValue();
2807
2808 const QgsProcessingParameterExpression *expParam = dynamic_cast<const QgsProcessingParameterExpression *>( parameterDefinition() );
2809 if ( !expParam )
2810 return;
2811
2812 switch ( expParam->expressionType() )
2813 {
2815 {
2816 if ( val.userType() == qMetaTypeId<QgsProcessingFeatureSourceDefinition>() )
2817 {
2818 // input is a QgsProcessingFeatureSourceDefinition - get extra properties from it
2819 QgsProcessingFeatureSourceDefinition fromVar = qvariant_cast<QgsProcessingFeatureSourceDefinition>( val );
2820 val = fromVar.source;
2821 }
2822
2824 if ( !layer )
2825 {
2826 if ( mFieldExpWidget )
2827 mFieldExpWidget->setLayer( nullptr );
2828 else if ( mExpBuilderWidget )
2829 mExpBuilderWidget->setLayer( nullptr );
2830 else if ( mExpLineEdit )
2831 mExpLineEdit->setLayer( nullptr );
2832 return;
2833 }
2834
2835 // need to grab ownership of layer if required - otherwise layer may be deleted when context
2836 // goes out of scope
2837 std::unique_ptr<QgsMapLayer> ownedLayer( context->takeResultLayer( layer->id() ) );
2838 if ( ownedLayer && ownedLayer->type() == Qgis::LayerType::Vector )
2839 {
2840 mParentLayer = std::move( ownedLayer );
2841 layer = static_cast<QgsVectorLayer *>( mParentLayer.get() );
2842 }
2843 else
2844 {
2845 // don't need ownership of this layer - it wasn't owned by context (so e.g. is owned by the project)
2846 }
2847
2848 if ( mFieldExpWidget )
2849 mFieldExpWidget->setLayer( layer );
2850 if ( mExpBuilderWidget )
2851 mExpBuilderWidget->setLayer( layer );
2852 else if ( mExpLineEdit )
2853 mExpLineEdit->setLayer( layer );
2854
2855 break;
2856 }
2858 {
2860 if ( !layer )
2861 {
2862 if ( mPointCloudExpLineEdit )
2863 mPointCloudExpLineEdit->setLayer( nullptr );
2864 return;
2865 }
2866
2867 // need to grab ownership of layer if required - otherwise layer may be deleted when context
2868 // goes out of scope
2869 std::unique_ptr<QgsMapLayer> ownedLayer( context->takeResultLayer( layer->id() ) );
2870 if ( ownedLayer && ownedLayer->type() == Qgis::LayerType::PointCloud )
2871 {
2872 mParentLayer = std::move( ownedLayer );
2873 layer = static_cast<QgsPointCloudLayer *>( mParentLayer.get() );
2874 }
2875 else
2876 {
2877 // don't need ownership of this layer - it wasn't owned by context (so e.g. is owned by the project)
2878 }
2879
2880 if ( mPointCloudExpLineEdit )
2881 mPointCloudExpLineEdit->setLayer( layer );
2882
2883 break;
2884 }
2886 {
2888 if ( layers.isEmpty() )
2889 {
2890 if ( mRasterCalculatorExpLineEdit )
2891 {
2892 mRasterCalculatorExpLineEdit->setLayers( val.userType() == QMetaType::Type::QVariantList ? val.toList() : QVariantList() << val );
2893 }
2894 return;
2895 }
2896
2897 if ( mRasterCalculatorExpLineEdit )
2898 {
2899 QVariantList layersList;
2900 for ( QgsMapLayer *layer : layers )
2901 {
2902 layersList << layer->name();
2903 }
2904 mRasterCalculatorExpLineEdit->setLayers( layersList );
2905 }
2906
2907 break;
2908 }
2909 }
2910}
2911
2912void QgsProcessingExpressionWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
2913{
2914 const QString v = QgsProcessingParameters::parameterAsString( parameterDefinition(), value, context );
2915 if ( mFieldExpWidget )
2916 mFieldExpWidget->setExpression( v );
2917 else if ( mExpBuilderWidget )
2918 mExpBuilderWidget->setExpressionText( v );
2919 else if ( mExpLineEdit )
2920 mExpLineEdit->setExpression( v );
2921 else if ( mPointCloudExpLineEdit )
2922 mPointCloudExpLineEdit->setExpression( v );
2923 else if ( mRasterCalculatorExpLineEdit )
2924 mRasterCalculatorExpLineEdit->setExpression( v );
2925}
2926
2927QVariant QgsProcessingExpressionWidgetWrapper::widgetValue() const
2928{
2929 if ( mFieldExpWidget )
2930 return mFieldExpWidget->expression();
2931 if ( mExpBuilderWidget )
2932 return mExpBuilderWidget->expressionText();
2933 else if ( mExpLineEdit )
2934 return mExpLineEdit->expression();
2935 else if ( mPointCloudExpLineEdit )
2936 return mPointCloudExpLineEdit->expression();
2937 else if ( mRasterCalculatorExpLineEdit )
2938 return mRasterCalculatorExpLineEdit->expression();
2939 else
2940 return QVariant();
2941}
2942
2943QString QgsProcessingExpressionWidgetWrapper::modelerExpressionFormatString() const
2944{
2945 return tr( "string representation of an expression" );
2946}
2947
2948const QgsVectorLayer *QgsProcessingExpressionWidgetWrapper::linkedVectorLayer() const
2949{
2950 if ( mFieldExpWidget && mFieldExpWidget->layer() )
2951 return mFieldExpWidget->layer();
2952
2953 if ( mExpBuilderWidget && mExpBuilderWidget->layer() )
2954 return mExpBuilderWidget->layer();
2955
2957}
2958
2959QString QgsProcessingExpressionWidgetWrapper::parameterType() const
2960{
2962}
2963
2964QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingExpressionWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type )
2965{
2966 return new QgsProcessingExpressionWidgetWrapper( parameter, type );
2967}
2968
2969QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingExpressionWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
2970{
2971 return new QgsProcessingExpressionParameterDefinitionWidget( context, widgetContext, definition, algorithm );
2972}
2973
2974
2975//
2976// QgsProcessingEnumPanelWidget
2977//
2978
2979QgsProcessingEnumPanelWidget::QgsProcessingEnumPanelWidget( QWidget *parent, const QgsProcessingParameterEnum *param )
2980 : QWidget( parent )
2981 , mParam( param )
2982{
2983 QHBoxLayout *hl = new QHBoxLayout();
2984 hl->setContentsMargins( 0, 0, 0, 0 );
2985
2986 mLineEdit = new QLineEdit();
2987 mLineEdit->setEnabled( false );
2988 hl->addWidget( mLineEdit, 1 );
2989
2990 mToolButton = new QToolButton();
2991 mToolButton->setText( QString( QChar( 0x2026 ) ) );
2992 hl->addWidget( mToolButton );
2993
2994 setLayout( hl );
2995
2996 if ( mParam )
2997 {
2998 mLineEdit->setText( tr( "%1 options selected" ).arg( 0 ) );
2999 }
3000
3001 connect( mToolButton, &QToolButton::clicked, this, &QgsProcessingEnumPanelWidget::showDialog );
3002}
3003
3004void QgsProcessingEnumPanelWidget::setValue( const QVariant &value )
3005{
3006 if ( value.isValid() )
3007 {
3008 mValue = value.userType() == QMetaType::Type::QVariantList ? value.toList() : QVariantList() << value;
3009
3010 if ( mParam->usesStaticStrings() && mValue.count() == 1 && mValue.at( 0 ).toString().isEmpty() )
3011 mValue.clear();
3012 }
3013 else
3014 mValue.clear();
3015
3016 updateSummaryText();
3017 emit changed();
3018}
3019
3020void QgsProcessingEnumPanelWidget::showDialog()
3021{
3022 QVariantList availableOptions;
3023 if ( mParam )
3024 {
3025 availableOptions.reserve( mParam->options().size() );
3026
3027 if ( mParam->usesStaticStrings() )
3028 {
3029 for ( QString o : mParam->options() )
3030 {
3031 availableOptions << o;
3032 }
3033 }
3034 else
3035 {
3036 for ( int i = 0; i < mParam->options().count(); ++i )
3037 availableOptions << i;
3038 }
3039 }
3040
3041 const QStringList options = mParam ? mParam->options() : QStringList();
3043 if ( panel && panel->dockMode() )
3044 {
3045 QgsProcessingMultipleSelectionPanelWidget *widget = new QgsProcessingMultipleSelectionPanelWidget( availableOptions, mValue );
3046 widget->setPanelTitle( mParam->description() );
3047
3048 if ( mParam->usesStaticStrings() )
3049 {
3050 widget->setValueFormatter( [options]( const QVariant &v ) -> QString {
3051 const QString i = v.toString();
3052 return options.contains( i ) ? i : QString();
3053 } );
3054 }
3055 else
3056 {
3057 widget->setValueFormatter( [options]( const QVariant &v ) -> QString {
3058 const int i = v.toInt();
3059 return options.size() > i ? options.at( i ) : QString();
3060 } );
3061 }
3062
3063 connect( widget, &QgsProcessingMultipleSelectionPanelWidget::selectionChanged, this, [this, widget]() {
3064 setValue( widget->selectedOptions() );
3065 } );
3066 connect( widget, &QgsProcessingMultipleSelectionPanelWidget::acceptClicked, widget, &QgsPanelWidget::acceptPanel );
3067 panel->openPanel( widget );
3068 }
3069 else
3070 {
3071 QgsProcessingMultipleSelectionDialog dlg( availableOptions, mValue, this, Qt::WindowFlags() );
3072
3073 dlg.setValueFormatter( [options]( const QVariant &v ) -> QString {
3074 const int i = v.toInt();
3075 return options.size() > i ? options.at( i ) : QString();
3076 } );
3077 if ( dlg.exec() )
3078 {
3079 setValue( dlg.selectedOptions() );
3080 }
3081 }
3082}
3083
3084void QgsProcessingEnumPanelWidget::updateSummaryText()
3085{
3086 if ( !mParam )
3087 return;
3088
3089 if ( mValue.empty() )
3090 {
3091 mLineEdit->setText( tr( "%1 options selected" ).arg( 0 ) );
3092 }
3093 else
3094 {
3095 QStringList values;
3096 values.reserve( mValue.size() );
3097 if ( mParam->usesStaticStrings() )
3098 {
3099 for ( const QVariant &val : std::as_const( mValue ) )
3100 {
3101 values << val.toString();
3102 }
3103 }
3104 else
3105 {
3106 const QStringList options = mParam->options();
3107 for ( const QVariant &val : std::as_const( mValue ) )
3108 {
3109 const int i = val.toInt();
3110 values << ( options.size() > i ? options.at( i ) : QString() );
3111 }
3112 }
3113
3114 const QString concatenated = values.join( tr( "," ) );
3115 if ( concatenated.length() < 100 )
3116 mLineEdit->setText( concatenated );
3117 else
3118 mLineEdit->setText( tr( "%n option(s) selected", nullptr, mValue.count() ) );
3119 }
3120}
3121
3122
3123//
3124// QgsProcessingEnumCheckboxPanelWidget
3125//
3126QgsProcessingEnumCheckboxPanelWidget::QgsProcessingEnumCheckboxPanelWidget( QWidget *parent, const QgsProcessingParameterEnum *param, int columns )
3127 : QWidget( parent )
3128 , mParam( param )
3129 , mButtonGroup( new QButtonGroup( this ) )
3130 , mColumns( columns )
3131{
3132 mButtonGroup->setExclusive( !mParam->allowMultiple() );
3133
3134 QGridLayout *l = new QGridLayout();
3135 l->setContentsMargins( 0, 0, 0, 0 );
3136
3137 int rows = static_cast<int>( std::ceil( mParam->options().count() / static_cast<double>( mColumns ) ) );
3138 for ( int i = 0; i < mParam->options().count(); ++i )
3139 {
3140 QAbstractButton *button = nullptr;
3141 if ( mParam->allowMultiple() )
3142 button = new QCheckBox( mParam->options().at( i ) );
3143 else
3144 button = new QRadioButton( mParam->options().at( i ) );
3145
3146 connect( button, &QAbstractButton::toggled, this, [this] {
3147 if ( !mBlockChangedSignal )
3148 emit changed();
3149 } );
3150
3151 mButtons.insert( i, button );
3152
3153 mButtonGroup->addButton( button, i );
3154 l->addWidget( button, i % rows, i / rows );
3155 }
3156 l->addItem( new QSpacerItem( 0, 0, QSizePolicy::Expanding, QSizePolicy::Minimum ), 0, mColumns );
3157 setLayout( l );
3158
3159 if ( mParam->allowMultiple() )
3160 {
3161 setContextMenuPolicy( Qt::CustomContextMenu );
3162 connect( this, &QWidget::customContextMenuRequested, this, &QgsProcessingEnumCheckboxPanelWidget::showPopupMenu );
3163 }
3164}
3165
3166QVariant QgsProcessingEnumCheckboxPanelWidget::value() const
3167{
3168 if ( mParam->allowMultiple() )
3169 {
3170 QVariantList value;
3171 for ( auto it = mButtons.constBegin(); it != mButtons.constEnd(); ++it )
3172 {
3173 if ( it.value()->isChecked() )
3174 value.append( mParam->usesStaticStrings() ? mParam->options().at( it.key().toInt() ) : it.key() );
3175 }
3176 return value;
3177 }
3178 else
3179 {
3180 if ( mParam->usesStaticStrings() )
3181 return mButtonGroup->checkedId() >= 0 ? mParam->options().at( mButtonGroup->checkedId() ) : QVariant();
3182 else
3183 return mButtonGroup->checkedId() >= 0 ? mButtonGroup->checkedId() : QVariant();
3184 }
3185}
3186
3187void QgsProcessingEnumCheckboxPanelWidget::setValue( const QVariant &value )
3188{
3189 mBlockChangedSignal = true;
3190 if ( mParam->allowMultiple() )
3191 {
3192 QVariantList selected;
3193 if ( value.isValid() )
3194 selected = value.userType() == QMetaType::Type::QVariantList ? value.toList() : QVariantList() << value;
3195 for ( auto it = mButtons.constBegin(); it != mButtons.constEnd(); ++it )
3196 {
3197 QVariant v = mParam->usesStaticStrings() ? mParam->options().at( it.key().toInt() ) : it.key();
3198 it.value()->setChecked( selected.contains( v ) );
3199 }
3200 }
3201 else
3202 {
3203 QVariant v = value;
3204 if ( v.userType() == QMetaType::Type::QVariantList )
3205 v = v.toList().value( 0 );
3206
3207 v = mParam->usesStaticStrings() ? static_cast< int >( mParam->options().indexOf( v.toString() ) ) : v;
3208 if ( mButtons.contains( v ) )
3209 mButtons.value( v )->setChecked( true );
3210 }
3211 mBlockChangedSignal = false;
3212 emit changed();
3213}
3214
3215void QgsProcessingEnumCheckboxPanelWidget::showPopupMenu()
3216{
3217 QMenu popupMenu;
3218 QAction *selectAllAction = new QAction( tr( "Select All" ), &popupMenu );
3219 connect( selectAllAction, &QAction::triggered, this, &QgsProcessingEnumCheckboxPanelWidget::selectAll );
3220 QAction *clearAllAction = new QAction( tr( "Clear Selection" ), &popupMenu );
3221 connect( clearAllAction, &QAction::triggered, this, &QgsProcessingEnumCheckboxPanelWidget::deselectAll );
3222 popupMenu.addAction( selectAllAction );
3223 popupMenu.addAction( clearAllAction );
3224 popupMenu.exec( QCursor::pos() );
3225}
3226
3227void QgsProcessingEnumCheckboxPanelWidget::selectAll()
3228{
3229 mBlockChangedSignal = true;
3230 for ( auto it = mButtons.constBegin(); it != mButtons.constEnd(); ++it )
3231 it.value()->setChecked( true );
3232 mBlockChangedSignal = false;
3233 emit changed();
3234}
3235
3236void QgsProcessingEnumCheckboxPanelWidget::deselectAll()
3237{
3238 mBlockChangedSignal = true;
3239 for ( auto it = mButtons.constBegin(); it != mButtons.constEnd(); ++it )
3240 it.value()->setChecked( false );
3241 mBlockChangedSignal = false;
3242 emit changed();
3243}
3244
3245
3246//
3247// QgsProcessingEnumWidgetWrapper
3248//
3249
3250QgsProcessingEnumParameterDefinitionWidget::QgsProcessingEnumParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
3251 : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
3252{
3253 QVBoxLayout *vlayout = new QVBoxLayout();
3254 vlayout->setContentsMargins( 0, 0, 0, 0 );
3255
3256 mEnumWidget = new QgsProcessingEnumModelerWidget();
3257 if ( const QgsProcessingParameterEnum *enumParam = dynamic_cast<const QgsProcessingParameterEnum *>( definition ) )
3258 {
3259 mEnumWidget->setAllowMultiple( enumParam->allowMultiple() );
3260 mEnumWidget->setOptions( enumParam->options() );
3261 mEnumWidget->setDefaultOptions( enumParam->defaultValueForGui() );
3262 }
3263 vlayout->addWidget( mEnumWidget );
3264 setLayout( vlayout );
3265}
3266
3267QgsProcessingParameterDefinition *QgsProcessingEnumParameterDefinitionWidget::createParameter( const QString &name, const QString &description, Qgis::ProcessingParameterFlags flags ) const
3268{
3269 auto param = std::make_unique<QgsProcessingParameterEnum>( name, description, mEnumWidget->options(), mEnumWidget->allowMultiple(), mEnumWidget->defaultOptions() );
3270 param->setFlags( flags );
3271 return param.release();
3272}
3273
3274
3275QgsProcessingEnumWidgetWrapper::QgsProcessingEnumWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type, QWidget *parent )
3276 : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
3277{
3278}
3279
3280QWidget *QgsProcessingEnumWidgetWrapper::createWidget()
3281{
3282 const QgsProcessingParameterEnum *expParam = dynamic_cast<const QgsProcessingParameterEnum *>( parameterDefinition() );
3283 if ( !expParam )
3284 return nullptr;
3285
3286 switch ( type() )
3287 {
3289 {
3290 // checkbox panel only for use outside in standard gui!
3291 if ( expParam->metadata().value( u"widget_wrapper"_s ).toMap().value( u"useCheckBoxes"_s, false ).toBool() )
3292 {
3293 const int columns = expParam->metadata().value( u"widget_wrapper"_s ).toMap().value( u"columns"_s, 2 ).toInt();
3294 mCheckboxPanel = new QgsProcessingEnumCheckboxPanelWidget( nullptr, expParam, columns );
3295 mCheckboxPanel->setToolTip( parameterDefinition()->toolTip() );
3296 connect( mCheckboxPanel, &QgsProcessingEnumCheckboxPanelWidget::changed, this, [this] {
3297 emit widgetValueHasChanged( this );
3298 } );
3299 return mCheckboxPanel;
3300 }
3301 }
3302 [[fallthrough]];
3305 {
3306 if ( expParam->allowMultiple() )
3307 {
3308 mPanel = new QgsProcessingEnumPanelWidget( nullptr, expParam );
3309 mPanel->setToolTip( parameterDefinition()->toolTip() );
3310 connect( mPanel, &QgsProcessingEnumPanelWidget::changed, this, [this] {
3311 emit widgetValueHasChanged( this );
3312 } );
3313 return mPanel;
3314 }
3315 else
3316 {
3317 mComboBox = new QComboBox();
3318
3320 mComboBox->addItem( tr( "[Not selected]" ), QVariant() );
3321 const QStringList options = expParam->options();
3322 const QVariantList iconList = expParam->metadata().value( u"widget_wrapper"_s ).toMap().value( u"icons"_s ).toList();
3323 for ( int i = 0; i < options.count(); ++i )
3324 {
3325 const QIcon icon = iconList.value( i ).value<QIcon>();
3326
3327 if ( expParam->usesStaticStrings() )
3328 mComboBox->addItem( icon, options.at( i ), options.at( i ) );
3329 else
3330 mComboBox->addItem( icon, options.at( i ), i );
3331 }
3332
3333 mComboBox->setToolTip( parameterDefinition()->toolTip() );
3334 mComboBox->setSizeAdjustPolicy( QComboBox::AdjustToMinimumContentsLengthWithIcon );
3335 connect( mComboBox, qOverload<int>( &QComboBox::currentIndexChanged ), this, [this]( int ) {
3336 emit widgetValueHasChanged( this );
3337 } );
3338 return mComboBox;
3339 }
3340 }
3341 }
3342 return nullptr;
3343}
3344
3345void QgsProcessingEnumWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
3346{
3347 if ( mComboBox )
3348 {
3349 if ( !value.isValid() )
3350 mComboBox->setCurrentIndex( mComboBox->findData( QVariant() ) );
3351 else
3352 {
3353 if ( auto *enumDef = dynamic_cast<const QgsProcessingParameterEnum *>( parameterDefinition() ); enumDef && enumDef->usesStaticStrings() )
3354 {
3355 const QString v = QgsProcessingParameters::parameterAsEnumString( parameterDefinition(), value, context );
3356 mComboBox->setCurrentIndex( mComboBox->findData( v ) );
3357 }
3358 else
3359 {
3360 const int v = QgsProcessingParameters::parameterAsEnum( parameterDefinition(), value, context );
3361 mComboBox->setCurrentIndex( mComboBox->findData( v ) );
3362 }
3363 }
3364 }
3365 else if ( mPanel || mCheckboxPanel )
3366 {
3367 QVariantList opts;
3368 if ( value.isValid() )
3369 {
3370 if ( auto *enumDef = dynamic_cast<const QgsProcessingParameterEnum *>( parameterDefinition() ); enumDef && enumDef->usesStaticStrings() )
3371 {
3372 const QStringList v = QgsProcessingParameters::parameterAsEnumStrings( parameterDefinition(), value, context );
3373 opts.reserve( v.size() );
3374 for ( QString i : v )
3375 opts << i;
3376 }
3377 else
3378 {
3379 const QList<int> v = QgsProcessingParameters::parameterAsEnums( parameterDefinition(), value, context );
3380 opts.reserve( v.size() );
3381 for ( int i : v )
3382 opts << i;
3383 }
3384 }
3385 if ( mPanel )
3386 mPanel->setValue( opts );
3387 else if ( mCheckboxPanel )
3388 mCheckboxPanel->setValue( opts );
3389 }
3390}
3391
3392QVariant QgsProcessingEnumWidgetWrapper::widgetValue() const
3393{
3394 if ( mComboBox )
3395 return mComboBox->currentData();
3396 else if ( mPanel )
3397 return mPanel->value();
3398 else if ( mCheckboxPanel )
3399 return mCheckboxPanel->value();
3400 else
3401 return QVariant();
3402}
3403
3404QString QgsProcessingEnumWidgetWrapper::modelerExpressionFormatString() const
3405{
3406 return tr( "selected option index (starting from 0), array of indices, or comma separated string of options (e.g. '1,3')" );
3407}
3408
3409QString QgsProcessingEnumWidgetWrapper::parameterType() const
3410{
3412}
3413
3414QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingEnumWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type )
3415{
3416 return new QgsProcessingEnumWidgetWrapper( parameter, type );
3417}
3418
3419QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingEnumWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
3420{
3421 return new QgsProcessingEnumParameterDefinitionWidget( context, widgetContext, definition, algorithm );
3422}
3423
3424//
3425// QgsProcessingLayoutWidgetWrapper
3426//
3427
3428QgsProcessingLayoutWidgetWrapper::QgsProcessingLayoutWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type, QWidget *parent )
3429 : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
3430{
3431}
3432
3433QWidget *QgsProcessingLayoutWidgetWrapper::createWidget()
3434{
3435 const QgsProcessingParameterLayout *layoutParam = dynamic_cast<const QgsProcessingParameterLayout *>( parameterDefinition() );
3436 if ( !layoutParam )
3437 return nullptr;
3438
3439 switch ( type() )
3440 {
3443 {
3444 // combobox only for use outside modeler!
3445 mComboBox = new QgsLayoutComboBox( nullptr, widgetContext().project() ? widgetContext().project()->layoutManager() : nullptr );
3446 if ( layoutParam->flags() & Qgis::ProcessingParameterFlag::Optional )
3447 mComboBox->setAllowEmptyLayout( true );
3448 mComboBox->setFilters( QgsLayoutManagerProxyModel::FilterPrintLayouts );
3449
3450 mComboBox->setToolTip( parameterDefinition()->toolTip() );
3451 connect( mComboBox, &QgsLayoutComboBox::layoutChanged, this, [this]( QgsMasterLayoutInterface * ) {
3452 emit widgetValueHasChanged( this );
3453 } );
3454 return mComboBox;
3455 }
3456
3458 {
3459 mPlainComboBox = new QComboBox();
3460 mPlainComboBox->setEditable( true );
3461 mPlainComboBox->setToolTip( tr( "Name of an existing print layout" ) );
3462 if ( widgetContext().project() )
3463 {
3464 const QList<QgsPrintLayout *> layouts = widgetContext().project()->layoutManager()->printLayouts();
3465 for ( const QgsPrintLayout *layout : layouts )
3466 mPlainComboBox->addItem( layout->name() );
3467 }
3468
3469 connect( mPlainComboBox, &QComboBox::currentTextChanged, this, [this]( const QString & ) {
3470 emit widgetValueHasChanged( this );
3471 } );
3472 return mPlainComboBox;
3473 }
3474 }
3475 return nullptr;
3476}
3477
3478void QgsProcessingLayoutWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
3479{
3480 if ( mComboBox )
3481 {
3482 if ( !value.isValid() )
3483 mComboBox->setCurrentLayout( nullptr );
3484 else
3485 {
3486 if ( QgsPrintLayout *l = QgsProcessingParameters::parameterAsLayout( parameterDefinition(), value, context ) )
3487 mComboBox->setCurrentLayout( l );
3488 else
3489 mComboBox->setCurrentLayout( nullptr );
3490 }
3491 }
3492 else if ( mPlainComboBox )
3493 {
3494 const QString v = QgsProcessingParameters::parameterAsString( parameterDefinition(), value, context );
3495 mPlainComboBox->setCurrentText( v );
3496 }
3497}
3498
3499QVariant QgsProcessingLayoutWidgetWrapper::widgetValue() const
3500{
3501 if ( mComboBox )
3502 {
3503 const QgsMasterLayoutInterface *l = mComboBox->currentLayout();
3504 return l ? l->name() : QVariant();
3505 }
3506 else if ( mPlainComboBox )
3507 return mPlainComboBox->currentText().isEmpty() ? QVariant() : mPlainComboBox->currentText();
3508 else
3509 return QVariant();
3510}
3511
3512void QgsProcessingLayoutWidgetWrapper::setWidgetContext( const QgsProcessingParameterWidgetContext &context )
3513{
3515 if ( mPlainComboBox && context.project() )
3516 {
3517 const QList<QgsPrintLayout *> layouts = widgetContext().project()->layoutManager()->printLayouts();
3518 for ( const QgsPrintLayout *layout : layouts )
3519 mPlainComboBox->addItem( layout->name() );
3520 }
3521}
3522
3523QString QgsProcessingLayoutWidgetWrapper::modelerExpressionFormatString() const
3524{
3525 return tr( "string representing the name of an existing print layout" );
3526}
3527
3528QString QgsProcessingLayoutWidgetWrapper::parameterType() const
3529{
3531}
3532
3533QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingLayoutWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type )
3534{
3535 return new QgsProcessingLayoutWidgetWrapper( parameter, type );
3536}
3537
3538
3539//
3540// QgsProcessingLayoutItemWidgetWrapper
3541//
3542
3543
3544QgsProcessingLayoutItemParameterDefinitionWidget::QgsProcessingLayoutItemParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
3545 : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
3546{
3547 QVBoxLayout *vlayout = new QVBoxLayout();
3548 vlayout->setContentsMargins( 0, 0, 0, 0 );
3549
3550 vlayout->addWidget( new QLabel( tr( "Parent layout" ) ) );
3551
3552 mParentLayoutComboBox = new QComboBox();
3553 QString initialParent;
3554 if ( const QgsProcessingParameterLayoutItem *itemParam = dynamic_cast<const QgsProcessingParameterLayoutItem *>( definition ) )
3555 initialParent = itemParam->parentLayoutParameterName();
3556
3557 if ( auto *lModel = widgetContext.model() )
3558 {
3559 // populate combo box with other model input choices
3560 const QMap<QString, QgsProcessingModelParameter> components = lModel->parameterComponents();
3561 for ( auto it = components.constBegin(); it != components.constEnd(); ++it )
3562 {
3563 if ( const QgsProcessingParameterLayout *definition = dynamic_cast<const QgsProcessingParameterLayout *>( lModel->parameterDefinition( it.value().parameterName() ) ) )
3564 {
3565 mParentLayoutComboBox->addItem( definition->description(), definition->name() );
3566 if ( !initialParent.isEmpty() && initialParent == definition->name() )
3567 {
3568 mParentLayoutComboBox->setCurrentIndex( mParentLayoutComboBox->count() - 1 );
3569 }
3570 }
3571 }
3572 }
3573
3574 if ( mParentLayoutComboBox->count() == 0 && !initialParent.isEmpty() )
3575 {
3576 // if no parent candidates found, we just add the existing one as a placeholder
3577 mParentLayoutComboBox->addItem( initialParent, initialParent );
3578 mParentLayoutComboBox->setCurrentIndex( mParentLayoutComboBox->count() - 1 );
3579 }
3580
3581 vlayout->addWidget( mParentLayoutComboBox );
3582 setLayout( vlayout );
3583}
3584QgsProcessingParameterDefinition *QgsProcessingLayoutItemParameterDefinitionWidget::createParameter( const QString &name, const QString &description, Qgis::ProcessingParameterFlags flags ) const
3585{
3586 auto param = std::make_unique<QgsProcessingParameterLayoutItem>( name, description, QVariant(), mParentLayoutComboBox->currentData().toString() );
3587 param->setFlags( flags );
3588 return param.release();
3589}
3590
3591
3592QgsProcessingLayoutItemWidgetWrapper::QgsProcessingLayoutItemWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type, QWidget *parent )
3593 : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
3594{
3595}
3596
3597QWidget *QgsProcessingLayoutItemWidgetWrapper::createWidget()
3598{
3599 const QgsProcessingParameterLayoutItem *layoutParam = dynamic_cast<const QgsProcessingParameterLayoutItem *>( parameterDefinition() );
3600 if ( !layoutParam )
3601 return nullptr;
3602
3603 switch ( type() )
3604 {
3607 {
3608 // combobox only for use outside modeler!
3609 mComboBox = new QgsLayoutItemComboBox( nullptr, nullptr );
3610 if ( layoutParam->flags() & Qgis::ProcessingParameterFlag::Optional )
3611 mComboBox->setAllowEmptyItem( true );
3612 if ( layoutParam->itemType() >= 0 )
3613 mComboBox->setItemType( static_cast<QgsLayoutItemRegistry::ItemType>( layoutParam->itemType() ) );
3614
3615 mComboBox->setToolTip( parameterDefinition()->toolTip() );
3616 connect( mComboBox, &QgsLayoutItemComboBox::itemChanged, this, [this]( QgsLayoutItem * ) {
3617 emit widgetValueHasChanged( this );
3618 } );
3619 return mComboBox;
3620 }
3621
3623 {
3624 mLineEdit = new QLineEdit();
3625 mLineEdit->setToolTip( tr( "UUID or ID of an existing print layout item" ) );
3626 connect( mLineEdit, &QLineEdit::textChanged, this, [this]( const QString & ) {
3627 emit widgetValueHasChanged( this );
3628 } );
3629 return mLineEdit;
3630 }
3631 }
3632 return nullptr;
3633}
3634
3635void QgsProcessingLayoutItemWidgetWrapper::postInitialize( const QList<QgsAbstractProcessingParameterWidgetWrapper *> &wrappers )
3636{
3638 switch ( type() )
3639 {
3642 {
3643 for ( const QgsAbstractProcessingParameterWidgetWrapper *wrapper : wrappers )
3644 {
3645 if ( wrapper->parameterDefinition()->name() == static_cast<const QgsProcessingParameterLayoutItem *>( parameterDefinition() )->parentLayoutParameterName() )
3646 {
3647 setLayoutParameterValue( wrapper->parameterValue() );
3648 connect( wrapper, &QgsAbstractProcessingParameterWidgetWrapper::widgetValueHasChanged, this, [this, wrapper] {
3649 setLayoutParameterValue( wrapper->parameterValue() );
3650 } );
3651 break;
3652 }
3653 }
3654 break;
3655 }
3656
3658 break;
3659 }
3660}
3661
3662void QgsProcessingLayoutItemWidgetWrapper::setLayoutParameterValue( const QVariant &value )
3663{
3664 QgsPrintLayout *layout = nullptr;
3665
3666 // evaluate value to layout
3667 QgsProcessingContext *context = nullptr;
3668 std::unique_ptr<QgsProcessingContext> tmpContext;
3669 if ( mProcessingContextGenerator )
3670 context = mProcessingContextGenerator->processingContext();
3671
3672 if ( !context )
3673 {
3674 tmpContext = std::make_unique<QgsProcessingContext>();
3675 context = tmpContext.get();
3676 }
3677
3678 layout = QgsProcessingParameters::parameterAsLayout( parameterDefinition(), value, *context );
3679 setLayout( layout );
3680}
3681
3682void QgsProcessingLayoutItemWidgetWrapper::setLayout( QgsPrintLayout *layout )
3683{
3684 if ( mComboBox )
3685 mComboBox->setCurrentLayout( layout );
3686}
3687
3688void QgsProcessingLayoutItemWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
3689{
3690 if ( mComboBox )
3691 {
3692 if ( !value.isValid() )
3693 mComboBox->setItem( nullptr );
3694 else
3695 {
3696 QgsLayoutItem *item = QgsProcessingParameters::parameterAsLayoutItem( parameterDefinition(), value, context, qobject_cast<QgsPrintLayout *>( mComboBox->currentLayout() ) );
3697 mComboBox->setItem( item );
3698 }
3699 }
3700 else if ( mLineEdit )
3701 {
3702 const QString v = QgsProcessingParameters::parameterAsString( parameterDefinition(), value, context );
3703 mLineEdit->setText( v );
3704 }
3705}
3706
3707QVariant QgsProcessingLayoutItemWidgetWrapper::widgetValue() const
3708{
3709 if ( mComboBox )
3710 {
3711 const QgsLayoutItem *i = mComboBox->currentItem();
3712 return i ? i->uuid() : QVariant();
3713 }
3714 else if ( mLineEdit )
3715 return mLineEdit->text().isEmpty() ? QVariant() : mLineEdit->text();
3716 else
3717 return QVariant();
3718}
3719
3720
3721QString QgsProcessingLayoutItemWidgetWrapper::modelerExpressionFormatString() const
3722{
3723 return tr( "string representing the UUID or ID of an existing print layout item" );
3724}
3725
3726QString QgsProcessingLayoutItemWidgetWrapper::parameterType() const
3727{
3729}
3730
3731QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingLayoutItemWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type )
3732{
3733 return new QgsProcessingLayoutItemWidgetWrapper( parameter, type );
3734}
3735
3736QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingLayoutItemWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
3737{
3738 return new QgsProcessingLayoutItemParameterDefinitionWidget( context, widgetContext, definition, algorithm );
3739}
3740
3741//
3742// QgsProcessingPointMapTool
3743//
3744
3745QgsProcessingPointMapTool::QgsProcessingPointMapTool( QgsMapCanvas *canvas )
3746 : QgsMapTool( canvas )
3747{
3749 mSnapIndicator = std::make_unique<QgsSnapIndicator>( canvas );
3750}
3751
3752QgsProcessingPointMapTool::~QgsProcessingPointMapTool() = default;
3753
3754void QgsProcessingPointMapTool::deactivate()
3755{
3756 mSnapIndicator->setMatch( QgsPointLocator::Match() );
3758}
3759
3760void QgsProcessingPointMapTool::canvasMoveEvent( QgsMapMouseEvent *e )
3761{
3762 e->snapPoint();
3763 mSnapIndicator->setMatch( e->mapPointMatch() );
3764}
3765
3766void QgsProcessingPointMapTool::canvasPressEvent( QgsMapMouseEvent *e )
3767{
3768 if ( e->button() == Qt::LeftButton )
3769 {
3770 QgsPointXY point = e->snapPoint();
3771 emit clicked( point );
3772 emit complete();
3773 }
3774}
3775
3776void QgsProcessingPointMapTool::keyPressEvent( QKeyEvent *e )
3777{
3778 if ( e->key() == Qt::Key_Escape )
3779 {
3780 // Override default shortcut management in MapCanvas
3781 e->ignore();
3782 emit complete();
3783 }
3784}
3785
3786
3787//
3788// QgsProcessingPointPanel
3789//
3790
3791QgsProcessingPointPanel::QgsProcessingPointPanel( QWidget *parent )
3792 : QWidget( parent )
3793{
3794 QHBoxLayout *l = new QHBoxLayout();
3795 l->setContentsMargins( 0, 0, 0, 0 );
3796 mLineEdit = new QgsFilterLineEdit();
3797 mLineEdit->setShowClearButton( false );
3798 l->addWidget( mLineEdit, 1 );
3799 mButton = new QToolButton();
3800 mButton->setText( QString( QChar( 0x2026 ) ) );
3801 l->addWidget( mButton );
3802 setLayout( l );
3803
3804 connect( mLineEdit, &QLineEdit::textChanged, this, &QgsProcessingPointPanel::changed );
3805 connect( mLineEdit, &QLineEdit::textChanged, this, &QgsProcessingPointPanel::textChanged );
3806 connect( mButton, &QToolButton::clicked, this, &QgsProcessingPointPanel::selectOnCanvas );
3807 mButton->setVisible( false );
3808}
3809
3810void QgsProcessingPointPanel::setMapCanvas( QgsMapCanvas *canvas )
3811{
3812 mCanvas = canvas;
3813 if ( mAllowSelectOnCanvas )
3814 {
3815 mButton->setVisible( true );
3816
3817 mCrs = canvas->mapSettings().destinationCrs();
3818 mTool = std::make_unique<QgsProcessingPointMapTool>( mCanvas );
3819 connect( mTool.get(), &QgsProcessingPointMapTool::clicked, this, &QgsProcessingPointPanel::updatePoint );
3820 connect( mTool.get(), &QgsProcessingPointMapTool::complete, this, &QgsProcessingPointPanel::pointPicked );
3821 }
3822}
3823
3824void QgsProcessingPointPanel::setAllowNull( bool allowNull )
3825{
3826 mLineEdit->setShowClearButton( allowNull );
3827}
3828
3829void QgsProcessingPointPanel::setShowPointOnCanvas( bool show )
3830{
3831 if ( mShowPointOnCanvas == show )
3832 return;
3833
3834 mShowPointOnCanvas = show;
3835 if ( mShowPointOnCanvas )
3836 {
3837 updateRubberBand();
3838 }
3839 else
3840 {
3841 mMapPointRubberBand.reset();
3842 }
3843}
3844
3845void QgsProcessingPointPanel::setAllowSelectOnCanvas( bool allow )
3846{
3847 mAllowSelectOnCanvas = allow;
3848 mButton->setVisible( mAllowSelectOnCanvas && static_cast<bool>( mTool ) );
3849}
3850
3851QVariant QgsProcessingPointPanel::value() const
3852{
3853 return mLineEdit->showClearButton() && mLineEdit->text().trimmed().isEmpty() ? QVariant() : QVariant( mLineEdit->text() );
3854}
3855
3856void QgsProcessingPointPanel::clear()
3857{
3858 mLineEdit->clear();
3859}
3860
3861void QgsProcessingPointPanel::setValue( const QgsPointXY &point, const QgsCoordinateReferenceSystem &crs )
3862{
3863 mPoint = point;
3864 QString newText = u"%1,%2"_s
3865 .arg( QString::number( point.x(), 'f' ), QString::number( point.y(), 'f' ) );
3866
3867 mCrs = crs;
3868 if ( mCrs.isValid() )
3869 {
3870 newText += u" [%1]"_s.arg( mCrs.authid() );
3871 }
3872 mLineEdit->setText( newText );
3873 updateRubberBand();
3874}
3875
3876void QgsProcessingPointPanel::showEvent( QShowEvent * )
3877{
3878 if ( mFirstShow )
3879 {
3880 // we don't support select on canvas if the dialog is modal
3881 if ( QWidget *parentWindow = window() )
3882 {
3883 setAllowSelectOnCanvas( !parentWindow->isModal() );
3884 }
3885 mFirstShow = false;
3886 }
3887}
3888
3889void QgsProcessingPointPanel::selectOnCanvas()
3890{
3891 if ( !mCanvas )
3892 return;
3893
3894 mPrevTool = mCanvas->mapTool();
3895 mCanvas->setMapTool( mTool.get() );
3896
3897 emit toggleDialogVisibility( false );
3898}
3899
3900void QgsProcessingPointPanel::updatePoint( const QgsPointXY &point )
3901{
3902 setValue( point, mCanvas->mapSettings().destinationCrs() );
3903}
3904
3905void QgsProcessingPointPanel::pointPicked()
3906{
3907 if ( !mCanvas )
3908 return;
3909
3910 mCanvas->setMapTool( mPrevTool );
3911
3912 emit toggleDialogVisibility( true );
3913}
3914
3915void QgsProcessingPointPanel::textChanged( const QString &text )
3916{
3917 const thread_local QRegularExpression rx( u"^\\s*\\(?\\s*(.*?)\\s*,\\s*(.*?)\\s*(?:\\[(.*)\\])?\\s*\\)?\\s*$"_s );
3918
3919 const QRegularExpressionMatch match = rx.match( text );
3920 if ( match.hasMatch() )
3921 {
3922 bool xOk = false;
3923 const double x = match.captured( 1 ).toDouble( &xOk );
3924 bool yOk = false;
3925 const double y = match.captured( 2 ).toDouble( &yOk );
3926
3927 if ( xOk && yOk )
3928 {
3929 mPoint = QgsPointXY( x, y );
3930
3931 const QgsCoordinateReferenceSystem pointCrs( match.captured( 3 ) );
3932 if ( pointCrs.isValid() )
3933 {
3934 mCrs = pointCrs;
3935 }
3936 }
3937 else
3938 {
3939 mPoint = QgsPointXY();
3940 }
3941 }
3942 else
3943 {
3944 mPoint = QgsPointXY();
3945 }
3946
3947 updateRubberBand();
3948}
3949
3950void QgsProcessingPointPanel::updateRubberBand()
3951{
3952 if ( !mShowPointOnCanvas || !mCanvas )
3953 return;
3954
3955 if ( mPoint.isEmpty() )
3956 {
3957 mMapPointRubberBand.reset();
3958 return;
3959 }
3960
3961 if ( !mMapPointRubberBand )
3962 {
3963 mMapPointRubberBand.reset( new QgsRubberBand( mCanvas, Qgis::GeometryType::Point ) );
3964 mMapPointRubberBand->setZValue( 1000 );
3965 mMapPointRubberBand->setIcon( QgsRubberBand::ICON_X );
3966
3967 const double scaleFactor = mCanvas->fontMetrics().xHeight() * .4;
3968 mMapPointRubberBand->setWidth( scaleFactor );
3969 mMapPointRubberBand->setIconSize( scaleFactor * 5 );
3970
3971 mMapPointRubberBand->setSecondaryStrokeColor( QColor( 255, 255, 255, 100 ) );
3972 mMapPointRubberBand->setColor( QColor( 200, 0, 200 ) );
3973 }
3974
3975 mMapPointRubberBand->setToGeometry( QgsGeometry::fromPointXY( mPoint ), mCrs );
3976}
3977
3978
3979//
3980// QgsProcessingPointWidgetWrapper
3981//
3982
3983QgsProcessingPointParameterDefinitionWidget::QgsProcessingPointParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
3984 : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
3985{
3986 QVBoxLayout *vlayout = new QVBoxLayout();
3987 vlayout->setContentsMargins( 0, 0, 0, 0 );
3988
3989 vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
3990
3991 mDefaultLineEdit = new QLineEdit();
3992 mDefaultLineEdit->setToolTip( tr( "Point as 'x,y'" ) );
3993 mDefaultLineEdit->setPlaceholderText( tr( "Point as 'x,y'" ) );
3994 if ( const QgsProcessingParameterPoint *pointParam = dynamic_cast<const QgsProcessingParameterPoint *>( definition ) )
3995 {
3996 QgsPointXY point = QgsProcessingParameters::parameterAsPoint( pointParam, pointParam->defaultValueForGui(), context );
3997 mDefaultLineEdit->setText( u"%1,%2"_s.arg( QString::number( point.x(), 'f' ), QString::number( point.y(), 'f' ) ) );
3998 }
3999
4000 vlayout->addWidget( mDefaultLineEdit );
4001 setLayout( vlayout );
4002}
4003
4004QgsProcessingParameterDefinition *QgsProcessingPointParameterDefinitionWidget::createParameter( const QString &name, const QString &description, Qgis::ProcessingParameterFlags flags ) const
4005{
4006 auto param = std::make_unique<QgsProcessingParameterPoint>( name, description, mDefaultLineEdit->text() );
4007 param->setFlags( flags );
4008 return param.release();
4009}
4010
4011QgsProcessingPointWidgetWrapper::QgsProcessingPointWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type, QWidget *parent )
4012 : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
4013{
4014}
4015
4016QWidget *QgsProcessingPointWidgetWrapper::createWidget()
4017{
4018 const QgsProcessingParameterPoint *pointParam = dynamic_cast<const QgsProcessingParameterPoint *>( parameterDefinition() );
4019 if ( !pointParam )
4020 return nullptr;
4021
4022 switch ( type() )
4023 {
4026 {
4027 mPanel = new QgsProcessingPointPanel( nullptr );
4028 if ( widgetContext().mapCanvas() )
4029 mPanel->setMapCanvas( widgetContext().mapCanvas() );
4030
4031 if ( pointParam->flags() & Qgis::ProcessingParameterFlag::Optional )
4032 mPanel->setAllowNull( true );
4033
4034 if ( type() == Qgis::ProcessingMode::Standard )
4035 mPanel->setShowPointOnCanvas( true );
4036
4037 mPanel->setToolTip( parameterDefinition()->toolTip() );
4038
4039 connect( mPanel, &QgsProcessingPointPanel::changed, this, [this] {
4040 emit widgetValueHasChanged( this );
4041 } );
4042
4043 if ( mDialog )
4044 setDialog( mDialog ); // setup connections to panel - dialog was previously set before the widget was created
4045 return mPanel;
4046 }
4047
4049 {
4050 mLineEdit = new QLineEdit();
4051 mLineEdit->setToolTip( tr( "Point as 'x,y'" ) );
4052 connect( mLineEdit, &QLineEdit::textChanged, this, [this]( const QString & ) {
4053 emit widgetValueHasChanged( this );
4054 } );
4055 return mLineEdit;
4056 }
4057 }
4058 return nullptr;
4059}
4060
4061void QgsProcessingPointWidgetWrapper::setWidgetContext( const QgsProcessingParameterWidgetContext &context )
4062{
4064 if ( mPanel && context.mapCanvas() )
4065 mPanel->setMapCanvas( context.mapCanvas() );
4066}
4067
4068void QgsProcessingPointWidgetWrapper::setDialog( QDialog *dialog )
4069{
4070 mDialog = dialog;
4071 if ( mPanel )
4072 {
4073 connect( mPanel, &QgsProcessingPointPanel::toggleDialogVisibility, mDialog, [this]( bool visible ) {
4074 if ( !visible )
4075 mDialog->showMinimized();
4076 else
4077 {
4078 mDialog->showNormal();
4079 mDialog->raise();
4080 mDialog->activateWindow();
4081 }
4082 } );
4083 }
4085}
4086
4087void QgsProcessingPointWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
4088{
4089 if ( mPanel )
4090 {
4091 if ( !value.isValid() || ( value.userType() == QMetaType::Type::QString && value.toString().isEmpty() ) )
4092 mPanel->clear();
4093 else
4094 {
4095 QgsPointXY p = QgsProcessingParameters::parameterAsPoint( parameterDefinition(), value, context );
4096 QgsCoordinateReferenceSystem crs = QgsProcessingParameters::parameterAsPointCrs( parameterDefinition(), value, context );
4097 mPanel->setValue( p, crs );
4098 }
4099 }
4100 else if ( mLineEdit )
4101 {
4102 const QString v = QgsProcessingParameters::parameterAsString( parameterDefinition(), value, context );
4103 mLineEdit->setText( v );
4104 }
4105}
4106
4107QVariant QgsProcessingPointWidgetWrapper::widgetValue() const
4108{
4109 if ( mPanel )
4110 {
4111 return mPanel->value();
4112 }
4113 else if ( mLineEdit )
4114 return mLineEdit->text().isEmpty() ? QVariant() : mLineEdit->text();
4115 else
4116 return QVariant();
4117}
4118
4119QString QgsProcessingPointWidgetWrapper::modelerExpressionFormatString() const
4120{
4121 return tr( "string of the format 'x,y' or a geometry value (centroid is used)" );
4122}
4123
4124QString QgsProcessingPointWidgetWrapper::parameterType() const
4125{
4127}
4128
4129QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingPointWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type )
4130{
4131 return new QgsProcessingPointWidgetWrapper( parameter, type );
4132}
4133
4134QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingPointWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
4135{
4136 return new QgsProcessingPointParameterDefinitionWidget( context, widgetContext, definition, algorithm );
4137}
4138
4139
4140//
4141// QgsProcessingGeometryWidgetWrapper
4142//
4143
4144
4145QgsProcessingGeometryParameterDefinitionWidget::QgsProcessingGeometryParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
4146 : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
4147{
4148 QVBoxLayout *vlayout = new QVBoxLayout();
4149 vlayout->setContentsMargins( 0, 0, 0, 0 );
4150
4151 vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
4152
4153 mGeometryWidget = new QgsGeometryWidget();
4154 if ( const QgsProcessingParameterGeometry *geometryParam = dynamic_cast<const QgsProcessingParameterGeometry *>( definition ) )
4155 {
4156 QgsGeometry g = QgsProcessingParameters::parameterAsGeometry( geometryParam, geometryParam->defaultValueForGui(), context );
4157 if ( !g.isNull() )
4158 {
4159 mGeometryWidget->setGeometryValue( QgsReferencedGeometry( g, QgsCoordinateReferenceSystem() ) );
4160 }
4161 }
4162
4163 vlayout->addWidget( mGeometryWidget );
4164 setLayout( vlayout );
4165}
4166
4167QgsProcessingParameterDefinition *QgsProcessingGeometryParameterDefinitionWidget::createParameter( const QString &name, const QString &description, Qgis::ProcessingParameterFlags flags ) const
4168{
4169 const QgsReferencedGeometry geometry = mGeometryWidget->geometryValue();
4170 auto param = std::make_unique<QgsProcessingParameterGeometry>( name, description, geometry.isEmpty() ? QVariant() : geometry.asWkt() );
4171 param->setFlags( flags );
4172 return param.release();
4173}
4174
4175QgsProcessingGeometryWidgetWrapper::QgsProcessingGeometryWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type, QWidget *parent )
4176 : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
4177{
4178}
4179
4180QWidget *QgsProcessingGeometryWidgetWrapper::createWidget()
4181{
4182 switch ( type() )
4183 {
4187 {
4188 mGeometryWidget = new QgsGeometryWidget();
4189 mGeometryWidget->setToolTip( parameterDefinition()->toolTip() );
4190 connect( mGeometryWidget, &QgsGeometryWidget::geometryValueChanged, this, [this]( const QgsReferencedGeometry & ) {
4191 emit widgetValueHasChanged( this );
4192 } );
4193 return mGeometryWidget;
4194 }
4195 }
4196 return nullptr;
4197}
4198
4199void QgsProcessingGeometryWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
4200{
4201 if ( mGeometryWidget )
4202 {
4203 QgsGeometry g = QgsProcessingParameters::parameterAsGeometry( parameterDefinition(), value, context );
4204 if ( !g.isNull() )
4205 {
4206 mGeometryWidget->setGeometryValue( QgsReferencedGeometry( g, QgsCoordinateReferenceSystem() ) );
4207 }
4208 else
4209 {
4210 mGeometryWidget->clearGeometry();
4211 }
4212 }
4213}
4214
4215QVariant QgsProcessingGeometryWidgetWrapper::widgetValue() const
4216{
4217 if ( mGeometryWidget )
4218 {
4219 const QgsReferencedGeometry geometry = mGeometryWidget->geometryValue();
4220 return geometry.isEmpty() ? QVariant() : geometry.asWkt();
4221 }
4222 else
4223 {
4224 return QVariant();
4225 }
4226}
4227
4228QString QgsProcessingGeometryWidgetWrapper::modelerExpressionFormatString() const
4229{
4230 return tr( "string in the Well-Known-Text format or a geometry value" );
4231}
4232
4233QString QgsProcessingGeometryWidgetWrapper::parameterType() const
4234{
4236}
4237
4238QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingGeometryWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type )
4239{
4240 return new QgsProcessingGeometryWidgetWrapper( parameter, type );
4241}
4242
4243QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingGeometryWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
4244{
4245 return new QgsProcessingGeometryParameterDefinitionWidget( context, widgetContext, definition, algorithm );
4246}
4247
4248
4249//
4250// QgsProcessingColorWidgetWrapper
4251//
4252
4253
4254QgsProcessingColorParameterDefinitionWidget::QgsProcessingColorParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
4255 : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
4256{
4257 QVBoxLayout *vlayout = new QVBoxLayout();
4258 vlayout->setContentsMargins( 0, 0, 0, 0 );
4259
4260 vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
4261
4262 mDefaultColorButton = new QgsColorButton();
4263 mDefaultColorButton->setShowNull( true );
4264 mAllowOpacity = new QCheckBox( tr( "Allow opacity control" ) );
4265
4266 if ( const QgsProcessingParameterColor *colorParam = dynamic_cast<const QgsProcessingParameterColor *>( definition ) )
4267 {
4268 const QColor c = QgsProcessingParameters::parameterAsColor( colorParam, colorParam->defaultValueForGui(), context );
4269 if ( !c.isValid() )
4270 mDefaultColorButton->setToNull();
4271 else
4272 mDefaultColorButton->setColor( c );
4273 mAllowOpacity->setChecked( colorParam->opacityEnabled() );
4274 }
4275 else
4276 {
4277 mDefaultColorButton->setToNull();
4278 mAllowOpacity->setChecked( true );
4279 }
4280
4281 vlayout->addWidget( mDefaultColorButton );
4282 vlayout->addWidget( mAllowOpacity );
4283 setLayout( vlayout );
4284}
4285
4286QgsProcessingParameterDefinition *QgsProcessingColorParameterDefinitionWidget::createParameter( const QString &name, const QString &description, Qgis::ProcessingParameterFlags flags ) const
4287{
4288 auto param = std::make_unique<QgsProcessingParameterColor>( name, description, mDefaultColorButton->color(), mAllowOpacity->isChecked() );
4289 param->setFlags( flags );
4290 return param.release();
4291}
4292
4293QgsProcessingColorWidgetWrapper::QgsProcessingColorWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type, QWidget *parent )
4294 : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
4295{
4296}
4297
4298QWidget *QgsProcessingColorWidgetWrapper::createWidget()
4299{
4300 const QgsProcessingParameterColor *colorParam = dynamic_cast<const QgsProcessingParameterColor *>( parameterDefinition() );
4301 if ( !colorParam )
4302 return nullptr;
4303
4304 switch ( type() )
4305 {
4309 {
4310 mColorButton = new QgsColorButton( nullptr );
4311 mColorButton->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed );
4312
4313 if ( colorParam->flags() & Qgis::ProcessingParameterFlag::Optional )
4314 mColorButton->setShowNull( true );
4315
4316 mColorButton->setAllowOpacity( colorParam->opacityEnabled() );
4317 mColorButton->setToolTip( parameterDefinition()->toolTip() );
4318 mColorButton->setColorDialogTitle( parameterDefinition()->description() );
4319 if ( colorParam->defaultValueForGui().value<QColor>().isValid() )
4320 {
4321 mColorButton->setDefaultColor( colorParam->defaultValueForGui().value<QColor>() );
4322 }
4323
4324 connect( mColorButton, &QgsColorButton::colorChanged, this, [this] {
4325 emit widgetValueHasChanged( this );
4326 } );
4327
4328 return mColorButton;
4329 }
4330 }
4331 return nullptr;
4332}
4333
4334void QgsProcessingColorWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
4335{
4336 if ( mColorButton )
4337 {
4338 if ( !value.isValid() || ( value.userType() == QMetaType::Type::QString && value.toString().isEmpty() )
4339 || ( value.userType() == QMetaType::Type::QColor && !value.value<QColor>().isValid() ) )
4340 mColorButton->setToNull();
4341 else
4342 {
4343 const QColor c = QgsProcessingParameters::parameterAsColor( parameterDefinition(), value, context );
4344 if ( !c.isValid() && mColorButton->showNull() )
4345 mColorButton->setToNull();
4346 else
4347 mColorButton->setColor( c );
4348 }
4349 }
4350}
4351
4352QVariant QgsProcessingColorWidgetWrapper::widgetValue() const
4353{
4354 if ( mColorButton )
4355 return mColorButton->isNull() ? QVariant() : mColorButton->color();
4356 else
4357 return QVariant();
4358}
4359
4360QString QgsProcessingColorWidgetWrapper::modelerExpressionFormatString() const
4361{
4362 return tr( "color style string, e.g. #ff0000 or 255,0,0" );
4363}
4364
4365QString QgsProcessingColorWidgetWrapper::parameterType() const
4366{
4368}
4369
4370QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingColorWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type )
4371{
4372 return new QgsProcessingColorWidgetWrapper( parameter, type );
4373}
4374
4375QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingColorWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
4376{
4377 return new QgsProcessingColorParameterDefinitionWidget( context, widgetContext, definition, algorithm );
4378}
4379
4380
4381//
4382// QgsProcessingCoordinateOperationWidgetWrapper
4383//
4384
4385QgsProcessingCoordinateOperationParameterDefinitionWidget::QgsProcessingCoordinateOperationParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
4386 : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
4387{
4388 QVBoxLayout *vlayout = new QVBoxLayout();
4389 vlayout->setContentsMargins( 0, 0, 0, 0 );
4390
4391 vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
4392
4393 mDefaultLineEdit = new QLineEdit();
4394 if ( const QgsProcessingParameterCoordinateOperation *coordParam = dynamic_cast<const QgsProcessingParameterCoordinateOperation *>( definition ) )
4395 mDefaultLineEdit->setText( QgsProcessingParameters::parameterAsString( coordParam, coordParam->defaultValueForGui(), context ) );
4396 vlayout->addWidget( mDefaultLineEdit );
4397
4398 mSourceParamComboBox = new QComboBox();
4399 mDestParamComboBox = new QComboBox();
4400 QString initialSource;
4401 QString initialDest;
4404 if ( const QgsProcessingParameterCoordinateOperation *itemParam = dynamic_cast<const QgsProcessingParameterCoordinateOperation *>( definition ) )
4405 {
4406 initialSource = itemParam->sourceCrsParameterName();
4407 initialDest = itemParam->destinationCrsParameterName();
4408 sourceCrs = QgsProcessingUtils::variantToCrs( itemParam->sourceCrs(), context );
4409 destCrs = QgsProcessingUtils::variantToCrs( itemParam->destinationCrs(), context );
4410 }
4411
4412 mSourceParamComboBox->addItem( QString(), QString() );
4413 mDestParamComboBox->addItem( QString(), QString() );
4414 if ( auto *lModel = widgetContext.model() )
4415 {
4416 // populate combo box with other model input choices
4417 const QMap<QString, QgsProcessingModelParameter> components = lModel->parameterComponents();
4418 for ( auto it = components.constBegin(); it != components.constEnd(); ++it )
4419 {
4420 if ( definition && it->parameterName() == definition->name() )
4421 continue;
4422
4423 // TODO - we should probably filter this list?
4424 mSourceParamComboBox->addItem( it->parameterName(), it->parameterName() );
4425 mDestParamComboBox->addItem( it->parameterName(), it->parameterName() );
4426 if ( !initialSource.isEmpty() && initialSource == it->parameterName() )
4427 {
4428 mSourceParamComboBox->setCurrentIndex( mSourceParamComboBox->count() - 1 );
4429 }
4430 if ( !initialDest.isEmpty() && initialDest == it->parameterName() )
4431 {
4432 mDestParamComboBox->setCurrentIndex( mDestParamComboBox->count() - 1 );
4433 }
4434 }
4435 }
4436
4437 if ( mSourceParamComboBox->count() == 1 && !initialSource.isEmpty() )
4438 {
4439 // if no source candidates found, we just add the existing one as a placeholder
4440 mSourceParamComboBox->addItem( initialSource, initialSource );
4441 mSourceParamComboBox->setCurrentIndex( mSourceParamComboBox->count() - 1 );
4442 }
4443 if ( mDestParamComboBox->count() == 1 && !initialDest.isEmpty() )
4444 {
4445 // if no dest candidates found, we just add the existing one as a placeholder
4446 mDestParamComboBox->addItem( initialDest, initialDest );
4447 mDestParamComboBox->setCurrentIndex( mDestParamComboBox->count() - 1 );
4448 }
4449
4450 vlayout->addWidget( new QLabel( tr( "Source CRS parameter" ) ) );
4451 vlayout->addWidget( mSourceParamComboBox );
4452 vlayout->addWidget( new QLabel( tr( "Destination CRS parameter" ) ) );
4453 vlayout->addWidget( mDestParamComboBox );
4454
4455 mStaticSourceWidget = new QgsProjectionSelectionWidget();
4456 mStaticSourceWidget->setOptionVisible( QgsProjectionSelectionWidget::CrsNotSet, true );
4457 mStaticSourceWidget->setCrs( sourceCrs );
4458 mStaticDestWidget = new QgsProjectionSelectionWidget();
4459 mStaticDestWidget->setOptionVisible( QgsProjectionSelectionWidget::CrsNotSet, true );
4460 mStaticDestWidget->setCrs( destCrs );
4461
4462 vlayout->addWidget( new QLabel( tr( "Static source CRS" ) ) );
4463 vlayout->addWidget( mStaticSourceWidget );
4464 vlayout->addWidget( new QLabel( tr( "Static destination CRS" ) ) );
4465 vlayout->addWidget( mStaticDestWidget );
4466
4467 setLayout( vlayout );
4468}
4469
4470QgsProcessingParameterDefinition *QgsProcessingCoordinateOperationParameterDefinitionWidget::createParameter( const QString &name, const QString &description, Qgis::ProcessingParameterFlags flags ) const
4471{
4472 auto param = std::make_unique<QgsProcessingParameterCoordinateOperation>( name, description, mDefaultLineEdit->text(), mSourceParamComboBox->currentText(), mDestParamComboBox->currentText(), mStaticSourceWidget->crs().isValid() ? QVariant::fromValue( mStaticSourceWidget->crs() ) : QVariant(), mStaticDestWidget->crs().isValid() ? QVariant::fromValue( mStaticDestWidget->crs() ) : QVariant() );
4473 param->setFlags( flags );
4474 return param.release();
4475}
4476
4477QgsProcessingCoordinateOperationWidgetWrapper::QgsProcessingCoordinateOperationWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type, QWidget *parent )
4478 : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
4479{
4480}
4481
4482QWidget *QgsProcessingCoordinateOperationWidgetWrapper::createWidget()
4483{
4484 const QgsProcessingParameterCoordinateOperation *coordParam = dynamic_cast<const QgsProcessingParameterCoordinateOperation *>( parameterDefinition() );
4485 if ( !coordParam )
4486 return nullptr;
4487
4489 mSourceCrs = QgsProcessingUtils::variantToCrs( coordParam->sourceCrs(), c );
4490 mDestCrs = QgsProcessingUtils::variantToCrs( coordParam->destinationCrs(), c );
4491 switch ( type() )
4492 {
4494 {
4495 mOperationWidget = new QgsCoordinateOperationWidget( nullptr );
4496 mOperationWidget->setShowMakeDefault( false );
4497 mOperationWidget->setShowFallbackOption( false );
4498 mOperationWidget->setToolTip( parameterDefinition()->toolTip() );
4499 mOperationWidget->setSourceCrs( mSourceCrs );
4500 mOperationWidget->setDestinationCrs( mDestCrs );
4501 mOperationWidget->setMapCanvas( mCanvas );
4502 if ( !coordParam->defaultValueForGui().toString().isEmpty() )
4503 {
4505 deets.proj = coordParam->defaultValueForGui().toString();
4506 mOperationWidget->setSelectedOperation( deets );
4507 }
4508
4509 connect( mOperationWidget, &QgsCoordinateOperationWidget::operationChanged, this, [this] {
4510 emit widgetValueHasChanged( this );
4511 } );
4512
4513 return mOperationWidget;
4514 }
4515
4518 {
4519 mLineEdit = new QLineEdit();
4520 QHBoxLayout *layout = new QHBoxLayout();
4521 layout->addWidget( mLineEdit, 1 );
4522 connect( mLineEdit, &QLineEdit::textChanged, this, [this] {
4523 emit widgetValueHasChanged( this );
4524 } );
4525
4526 QToolButton *button = new QToolButton();
4527 button->setText( QString( QChar( 0x2026 ) ) );
4528 connect( button, &QToolButton::clicked, this, [this, button] {
4529 QgsDatumTransformDialog dlg( mSourceCrs, mDestCrs, false, false, false, qMakePair( -1, -1 ), button, Qt::WindowFlags(), mLineEdit->text(), mCanvas );
4530 if ( dlg.exec() )
4531 {
4532 mLineEdit->setText( dlg.selectedDatumTransform().proj );
4533 emit widgetValueHasChanged( this );
4534 }
4535 } );
4536 layout->addWidget( button );
4537
4538 QWidget *w = new QWidget();
4539 layout->setContentsMargins( 0, 0, 0, 0 );
4540 w->setLayout( layout );
4541 return w;
4542 }
4543 }
4544 return nullptr;
4545}
4546
4547void QgsProcessingCoordinateOperationWidgetWrapper::postInitialize( const QList<QgsAbstractProcessingParameterWidgetWrapper *> &wrappers )
4548{
4550 switch ( type() )
4551 {
4554 {
4555 for ( const QgsAbstractProcessingParameterWidgetWrapper *wrapper : wrappers )
4556 {
4557 if ( wrapper->parameterDefinition()->name() == static_cast<const QgsProcessingParameterCoordinateOperation *>( parameterDefinition() )->sourceCrsParameterName() )
4558 {
4559 setSourceCrsParameterValue( wrapper->parameterValue() );
4560 connect( wrapper, &QgsAbstractProcessingParameterWidgetWrapper::widgetValueHasChanged, this, [this, wrapper] {
4561 setSourceCrsParameterValue( wrapper->parameterValue() );
4562 } );
4563 }
4564 if ( wrapper->parameterDefinition()->name() == static_cast<const QgsProcessingParameterCoordinateOperation *>( parameterDefinition() )->destinationCrsParameterName() )
4565 {
4566 setDestinationCrsParameterValue( wrapper->parameterValue() );
4567 connect( wrapper, &QgsAbstractProcessingParameterWidgetWrapper::widgetValueHasChanged, this, [this, wrapper] {
4568 setDestinationCrsParameterValue( wrapper->parameterValue() );
4569 } );
4570 }
4571 }
4572 break;
4573 }
4574
4576 break;
4577 }
4578}
4579
4580void QgsProcessingCoordinateOperationWidgetWrapper::setWidgetContext( const QgsProcessingParameterWidgetContext &context )
4581{
4582 mCanvas = context.mapCanvas();
4583 if ( mOperationWidget )
4584 mOperationWidget->setMapCanvas( context.mapCanvas() );
4585}
4586
4587void QgsProcessingCoordinateOperationWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext & )
4588{
4589 if ( mOperationWidget )
4590 {
4591 if ( !value.isValid() || ( value.userType() == QMetaType::Type::QString ) )
4592 {
4594 deets.proj = value.toString();
4595 mOperationWidget->setSelectedOperation( deets );
4596 }
4597 }
4598 if ( mLineEdit )
4599 {
4600 if ( !value.isValid() || ( value.userType() == QMetaType::Type::QString ) )
4601 {
4602 mLineEdit->setText( value.toString() );
4603 }
4604 }
4605}
4606
4607QVariant QgsProcessingCoordinateOperationWidgetWrapper::widgetValue() const
4608{
4609 if ( mOperationWidget )
4610 return mOperationWidget->selectedOperation().proj;
4611 else if ( mLineEdit )
4612 return mLineEdit->text();
4613 else
4614 return QVariant();
4615}
4616
4617QString QgsProcessingCoordinateOperationWidgetWrapper::modelerExpressionFormatString() const
4618{
4619 return tr( "Proj coordinate operation string, e.g. '+proj=pipeline +step +inv...'" );
4620}
4621
4622void QgsProcessingCoordinateOperationWidgetWrapper::setSourceCrsParameterValue( const QVariant &value )
4623{
4624 QgsProcessingContext *context = nullptr;
4625 std::unique_ptr<QgsProcessingContext> tmpContext;
4626 if ( mProcessingContextGenerator )
4627 context = mProcessingContextGenerator->processingContext();
4628
4629 if ( !context )
4630 {
4631 tmpContext = std::make_unique<QgsProcessingContext>();
4632 context = tmpContext.get();
4633 }
4634
4635 mSourceCrs = QgsProcessingUtils::variantToCrs( value, *context );
4636 if ( mOperationWidget )
4637 {
4638 mOperationWidget->setSourceCrs( mSourceCrs );
4639 mOperationWidget->setSelectedOperationUsingContext( context->transformContext() );
4640 }
4641}
4642
4643void QgsProcessingCoordinateOperationWidgetWrapper::setDestinationCrsParameterValue( const QVariant &value )
4644{
4645 QgsProcessingContext *context = nullptr;
4646 std::unique_ptr<QgsProcessingContext> tmpContext;
4647 if ( mProcessingContextGenerator )
4648 context = mProcessingContextGenerator->processingContext();
4649
4650 if ( !context )
4651 {
4652 tmpContext = std::make_unique<QgsProcessingContext>();
4653 context = tmpContext.get();
4654 }
4655
4656 mDestCrs = QgsProcessingUtils::variantToCrs( value, *context );
4657 if ( mOperationWidget )
4658 {
4659 mOperationWidget->setDestinationCrs( mDestCrs );
4660 mOperationWidget->setSelectedOperationUsingContext( context->transformContext() );
4661 }
4662}
4663
4664QString QgsProcessingCoordinateOperationWidgetWrapper::parameterType() const
4665{
4667}
4668
4669QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingCoordinateOperationWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type )
4670{
4671 return new QgsProcessingCoordinateOperationWidgetWrapper( parameter, type );
4672}
4673
4674QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingCoordinateOperationWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
4675{
4676 return new QgsProcessingCoordinateOperationParameterDefinitionWidget( context, widgetContext, definition, algorithm );
4677}
4678
4679
4680//
4681// QgsProcessingFieldPanelWidget
4682//
4683
4684QgsProcessingFieldPanelWidget::QgsProcessingFieldPanelWidget( QWidget *parent, const QgsProcessingParameterField *param )
4685 : QWidget( parent )
4686 , mParam( param )
4687{
4688 QHBoxLayout *hl = new QHBoxLayout();
4689 hl->setContentsMargins( 0, 0, 0, 0 );
4690
4691 mLineEdit = new QLineEdit();
4692 mLineEdit->setEnabled( false );
4693 hl->addWidget( mLineEdit, 1 );
4694
4695 mToolButton = new QToolButton();
4696 mToolButton->setText( QString( QChar( 0x2026 ) ) );
4697 hl->addWidget( mToolButton );
4698
4699 setLayout( hl );
4700
4701 if ( mParam )
4702 {
4703 mLineEdit->setText( tr( "%n field(s) selected", nullptr, 0 ) );
4704 }
4705
4706 connect( mToolButton, &QToolButton::clicked, this, &QgsProcessingFieldPanelWidget::showDialog );
4707}
4708
4709void QgsProcessingFieldPanelWidget::setFields( const QgsFields &fields )
4710{
4711 mFields = fields;
4712
4713 // ensure that after setting new fields the value does not contain fields
4714 // which are not available anymore, see https://github.com/qgis/QGIS/issues/39351
4715 QVariantList availableFields;
4716 for ( const QgsField &field : std::as_const( mFields ) )
4717 {
4718 availableFields << field.name();
4719 }
4720 QList<QVariant>::iterator it = std::remove_if( mValue.begin(), mValue.end(), [&availableFields]( const QVariant &value ) { return !availableFields.contains( value ); } );
4721 mValue.erase( it, mValue.end() );
4722
4723 updateSummaryText();
4724 emit changed();
4725}
4726
4727void QgsProcessingFieldPanelWidget::setValue( const QVariant &value )
4728{
4729 if ( value.isValid() )
4730 mValue = value.userType() == QMetaType::Type::QVariantList ? value.toList() : QVariantList() << value;
4731 else
4732 mValue.clear();
4733
4734 updateSummaryText();
4735 emit changed();
4736}
4737
4738void QgsProcessingFieldPanelWidget::showDialog()
4739{
4740 QVariantList availableOptions;
4741 availableOptions.reserve( mFields.size() );
4742 for ( const QgsField &field : std::as_const( mFields ) )
4743 {
4744 availableOptions << field.name();
4745 }
4746
4748 if ( panel && panel->dockMode() )
4749 {
4750 QgsProcessingMultipleSelectionPanelWidget *widget = new QgsProcessingMultipleSelectionPanelWidget( availableOptions, mValue );
4751 widget->setPanelTitle( mParam->description() );
4752
4753 widget->setValueFormatter( []( const QVariant &v ) -> QString {
4754 return v.toString();
4755 } );
4756
4757 connect( widget, &QgsProcessingMultipleSelectionPanelWidget::selectionChanged, this, [this, widget]() {
4758 setValue( widget->selectedOptions() );
4759 } );
4760 connect( widget, &QgsProcessingMultipleSelectionPanelWidget::acceptClicked, widget, &QgsPanelWidget::acceptPanel );
4761 panel->openPanel( widget );
4762 }
4763 else
4764 {
4765 QgsProcessingMultipleSelectionDialog dlg( availableOptions, mValue, this, Qt::WindowFlags() );
4766
4767 dlg.setValueFormatter( []( const QVariant &v ) -> QString {
4768 return v.toString();
4769 } );
4770 if ( dlg.exec() )
4771 {
4772 setValue( dlg.selectedOptions() );
4773 }
4774 }
4775}
4776
4777void QgsProcessingFieldPanelWidget::updateSummaryText()
4778{
4779 if ( !mParam )
4780 return;
4781
4782 if ( mValue.empty() )
4783 {
4784 mLineEdit->setText( tr( "%n field(s) selected", nullptr, 0 ) );
4785 }
4786 else
4787 {
4788 QStringList values;
4789 values.reserve( mValue.size() );
4790 for ( const QVariant &val : std::as_const( mValue ) )
4791 {
4792 values << val.toString();
4793 }
4794
4795 const QString concatenated = values.join( tr( "," ) );
4796 if ( concatenated.length() < 100 )
4797 mLineEdit->setText( concatenated );
4798 else
4799 mLineEdit->setText( tr( "%n field(s) selected", nullptr, mValue.count() ) );
4800 }
4801}
4802
4803
4804//
4805// QgsProcessingFieldWidgetWrapper
4806//
4807
4808QgsProcessingFieldParameterDefinitionWidget::QgsProcessingFieldParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
4809 : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
4810{
4811 QVBoxLayout *vlayout = new QVBoxLayout();
4812 vlayout->setContentsMargins( 0, 0, 0, 0 );
4813
4814 vlayout->addWidget( new QLabel( tr( "Parent layer" ) ) );
4815 mParentLayerComboBox = new QComboBox();
4816
4817 QString initialParent;
4818 if ( const QgsProcessingParameterField *fieldParam = dynamic_cast<const QgsProcessingParameterField *>( definition ) )
4819 initialParent = fieldParam->parentLayerParameterName();
4820
4821 if ( auto *lModel = widgetContext.model() )
4822 {
4823 // populate combo box with other model input choices
4824 const QMap<QString, QgsProcessingModelParameter> components = lModel->parameterComponents();
4825 for ( auto it = components.constBegin(); it != components.constEnd(); ++it )
4826 {
4827 if ( const QgsProcessingParameterFeatureSource *definition = dynamic_cast<const QgsProcessingParameterFeatureSource *>( lModel->parameterDefinition( it.value().parameterName() ) ) )
4828 {
4829 mParentLayerComboBox->addItem( definition->description(), definition->name() );
4830 if ( !initialParent.isEmpty() && initialParent == definition->name() )
4831 {
4832 mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
4833 }
4834 }
4835 else if ( const QgsProcessingParameterVectorLayer *definition = dynamic_cast<const QgsProcessingParameterVectorLayer *>( lModel->parameterDefinition( it.value().parameterName() ) ) )
4836 {
4837 mParentLayerComboBox->addItem( definition->description(), definition->name() );
4838 if ( !initialParent.isEmpty() && initialParent == definition->name() )
4839 {
4840 mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
4841 }
4842 }
4843 else if ( const QgsProcessingParameterMultipleLayers *definition = dynamic_cast<const QgsProcessingParameterMultipleLayers *>( lModel->parameterDefinition( it.value().parameterName() ) ) )
4844 {
4845 if ( definition->layerType() == Qgis::ProcessingSourceType::Vector )
4846 {
4847 mParentLayerComboBox->addItem( definition->description(), definition->name() );
4848 if ( !initialParent.isEmpty() && initialParent == definition->name() )
4849 {
4850 mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
4851 }
4852 }
4853 }
4854 }
4855 }
4856
4857 if ( mParentLayerComboBox->count() == 0 && !initialParent.isEmpty() )
4858 {
4859 // if no parent candidates found, we just add the existing one as a placeholder
4860 mParentLayerComboBox->addItem( initialParent, initialParent );
4861 mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
4862 }
4863
4864 vlayout->addWidget( mParentLayerComboBox );
4865
4866 vlayout->addWidget( new QLabel( tr( "Allowed data type" ) ) );
4867 mDataTypeComboBox = new QComboBox();
4868 mDataTypeComboBox->addItem( tr( "Any" ), static_cast<int>( Qgis::ProcessingFieldParameterDataType::Any ) );
4869 mDataTypeComboBox->addItem( tr( "Number" ), static_cast<int>( Qgis::ProcessingFieldParameterDataType::Numeric ) );
4870 mDataTypeComboBox->addItem( tr( "String" ), static_cast<int>( Qgis::ProcessingFieldParameterDataType::String ) );
4871 mDataTypeComboBox->addItem( tr( "Date/time" ), static_cast<int>( Qgis::ProcessingFieldParameterDataType::DateTime ) );
4872 mDataTypeComboBox->addItem( tr( "Binary" ), static_cast<int>( Qgis::ProcessingFieldParameterDataType::Binary ) );
4873 mDataTypeComboBox->addItem( tr( "Boolean" ), static_cast<int>( Qgis::ProcessingFieldParameterDataType::Boolean ) );
4874 if ( const QgsProcessingParameterField *fieldParam = dynamic_cast<const QgsProcessingParameterField *>( definition ) )
4875 mDataTypeComboBox->setCurrentIndex( mDataTypeComboBox->findData( static_cast<int>( fieldParam->dataType() ) ) );
4876
4877 vlayout->addWidget( mDataTypeComboBox );
4878
4879 mAllowMultipleCheckBox = new QCheckBox( tr( "Accept multiple fields" ) );
4880 if ( const QgsProcessingParameterField *fieldParam = dynamic_cast<const QgsProcessingParameterField *>( definition ) )
4881 mAllowMultipleCheckBox->setChecked( fieldParam->allowMultiple() );
4882
4883 vlayout->addWidget( mAllowMultipleCheckBox );
4884
4885 mDefaultToAllCheckBox = new QCheckBox( tr( "Select all fields by default" ) );
4886 mDefaultToAllCheckBox->setEnabled( mAllowMultipleCheckBox->isChecked() );
4887 if ( const QgsProcessingParameterField *fieldParam = dynamic_cast<const QgsProcessingParameterField *>( definition ) )
4888 mDefaultToAllCheckBox->setChecked( fieldParam->defaultToAllFields() );
4889
4890 vlayout->addWidget( mDefaultToAllCheckBox );
4891
4892 connect( mAllowMultipleCheckBox, &QCheckBox::stateChanged, this, [this] {
4893 mDefaultToAllCheckBox->setEnabled( mAllowMultipleCheckBox->isChecked() );
4894 } );
4895
4896 vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
4897
4898 mDefaultLineEdit = new QLineEdit();
4899 mDefaultLineEdit->setToolTip( tr( "Default field name, or ; separated list of field names for multiple field parameters" ) );
4900 if ( const QgsProcessingParameterField *fieldParam = dynamic_cast<const QgsProcessingParameterField *>( definition ) )
4901 {
4902 const QStringList fields = QgsProcessingParameters::parameterAsStrings( fieldParam, fieldParam->defaultValueForGui(), context );
4903 mDefaultLineEdit->setText( fields.join( ';' ) );
4904 }
4905 vlayout->addWidget( mDefaultLineEdit );
4906
4907 setLayout( vlayout );
4908}
4909
4910QgsProcessingParameterDefinition *QgsProcessingFieldParameterDefinitionWidget::createParameter( const QString &name, const QString &description, Qgis::ProcessingParameterFlags flags ) const
4911{
4912 Qgis::ProcessingFieldParameterDataType dataType = static_cast<Qgis::ProcessingFieldParameterDataType>( mDataTypeComboBox->currentData().toInt() );
4913
4914 QVariant defaultValue;
4915 if ( !mDefaultLineEdit->text().trimmed().isEmpty() )
4916 {
4917 defaultValue = mDefaultLineEdit->text();
4918 }
4919 auto param = std::make_unique<QgsProcessingParameterField>( name, description, defaultValue, mParentLayerComboBox->currentData().toString(), dataType, mAllowMultipleCheckBox->isChecked(), false, mDefaultToAllCheckBox->isChecked() );
4920 param->setFlags( flags );
4921 return param.release();
4922}
4923
4924QgsProcessingFieldWidgetWrapper::QgsProcessingFieldWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type, QWidget *parent )
4925 : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
4926{
4927}
4928
4929QWidget *QgsProcessingFieldWidgetWrapper::createWidget()
4930{
4931 const QgsProcessingParameterField *fieldParam = dynamic_cast<const QgsProcessingParameterField *>( parameterDefinition() );
4932 if ( !fieldParam )
4933 return nullptr;
4934
4935 switch ( type() )
4936 {
4939 {
4940 if ( fieldParam->allowMultiple() )
4941 {
4942 mPanel = new QgsProcessingFieldPanelWidget( nullptr, fieldParam );
4943 mPanel->setToolTip( parameterDefinition()->toolTip() );
4944 connect( mPanel, &QgsProcessingFieldPanelWidget::changed, this, [this] {
4945 emit widgetValueHasChanged( this );
4946 } );
4947 return mPanel;
4948 }
4949 else
4950 {
4951 mComboBox = new QgsFieldComboBox();
4952 mComboBox->setAllowEmptyFieldName( fieldParam->flags() & Qgis::ProcessingParameterFlag::Optional );
4953
4955 mComboBox->setFilters( QgsFieldProxyModel::Numeric );
4956 else if ( fieldParam->dataType() == Qgis::ProcessingFieldParameterDataType::String )
4957 mComboBox->setFilters( QgsFieldProxyModel::String );
4960 else if ( fieldParam->dataType() == Qgis::ProcessingFieldParameterDataType::Binary )
4961 mComboBox->setFilters( QgsFieldProxyModel::Binary );
4963 mComboBox->setFilters( QgsFieldProxyModel::Boolean );
4964
4965 mComboBox->setToolTip( parameterDefinition()->toolTip() );
4966 connect( mComboBox, &QgsFieldComboBox::fieldChanged, this, [this]( const QString & ) {
4967 emit widgetValueHasChanged( this );
4968 } );
4969 return mComboBox;
4970 }
4971 }
4972
4974 {
4975 mLineEdit = new QLineEdit();
4976 mLineEdit->setToolTip( QObject::tr( "Name of field (separate field names with ; for multiple field parameters)" ) );
4977 connect( mLineEdit, &QLineEdit::textChanged, this, [this] {
4978 emit widgetValueHasChanged( this );
4979 } );
4980 return mLineEdit;
4981 }
4982 }
4983 return nullptr;
4984}
4985
4986void QgsProcessingFieldWidgetWrapper::postInitialize( const QList<QgsAbstractProcessingParameterWidgetWrapper *> &wrappers )
4987{
4989 switch ( type() )
4990 {
4993 {
4994 for ( const QgsAbstractProcessingParameterWidgetWrapper *wrapper : wrappers )
4995 {
4996 if ( wrapper->parameterDefinition()->name() == static_cast<const QgsProcessingParameterField *>( parameterDefinition() )->parentLayerParameterName() )
4997 {
4998 setParentLayerWrapperValue( wrapper );
4999 connect( wrapper, &QgsAbstractProcessingParameterWidgetWrapper::widgetValueHasChanged, this, [this, wrapper] {
5000 setParentLayerWrapperValue( wrapper );
5001 } );
5002 break;
5003 }
5004 }
5005 break;
5006 }
5007
5009 break;
5010 }
5011}
5012
5013void QgsProcessingFieldWidgetWrapper::setParentLayerWrapperValue( const QgsAbstractProcessingParameterWidgetWrapper *parentWrapper )
5014{
5015 // evaluate value to layer
5016 QgsProcessingContext *context = nullptr;
5017 std::unique_ptr<QgsProcessingContext> tmpContext;
5018 if ( mProcessingContextGenerator )
5019 context = mProcessingContextGenerator->processingContext();
5020
5021 if ( !context )
5022 {
5023 tmpContext = std::make_unique<QgsProcessingContext>();
5024 context = tmpContext.get();
5025 }
5026
5027 QVariant value = parentWrapper->parameterValue();
5028
5029 if ( value.userType() == qMetaTypeId<QgsProcessingFeatureSourceDefinition>() )
5030 {
5031 // input is a QgsProcessingFeatureSourceDefinition - source from it.
5032 // this is normally discouraged, and algorithms should NEVER do this -- but in this case we can make
5033 // certain assumptions due to the fact that we're calling this outside of algorithm/model execution and all sources
5034 // should be real map layers at this stage
5035 QgsProcessingFeatureSourceDefinition fromVar = qvariant_cast<QgsProcessingFeatureSourceDefinition>( value );
5036 value = fromVar.source;
5037 }
5038
5039 bool valueSet = false;
5040 const QList<QgsMapLayer *> layers = QgsProcessingParameters::parameterAsLayerList( parentWrapper->parameterDefinition(), value, *context );
5041
5042 // several layers, populate with intersection of layers fields
5043 if ( layers.count() > 1 )
5044 {
5045 QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( layers.at( 0 ) );
5046 QgsFields fields = vlayer && vlayer->isValid() ? vlayer->fields() : QgsFields();
5047 const QList<QgsMapLayer *> remainingLayers = layers.mid( 1 );
5048 for ( QgsMapLayer *layer : remainingLayers )
5049 {
5050 if ( fields.isEmpty() )
5051 break;
5052
5053 QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( layer );
5054 if ( !vlayer || !vlayer->isValid() )
5055 {
5056 fields = QgsFields();
5057 break;
5058 }
5059
5060 for ( int fieldIdx = fields.count() - 1; fieldIdx >= 0; fieldIdx-- )
5061 {
5062 if ( vlayer->fields().lookupField( fields.at( fieldIdx ).name() ) < 0 )
5063 fields.remove( fieldIdx );
5064 }
5065 }
5066
5067 if ( mComboBox )
5068 mComboBox->setFields( fields );
5069 else if ( mPanel )
5070 mPanel->setFields( filterFields( fields ) );
5071
5072 valueSet = true;
5073 }
5074
5075 // only one layer
5076 if ( !valueSet && !layers.isEmpty() && layers.at( 0 )->isValid() )
5077 {
5078 QgsVectorLayer *layer = qobject_cast<QgsVectorLayer *>( layers.at( 0 ) );
5079
5080 // need to grab ownership of layer if required - otherwise layer may be deleted when context
5081 // goes out of scope
5082 std::unique_ptr<QgsMapLayer> ownedLayer( context->takeResultLayer( layer->id() ) );
5083 if ( ownedLayer && ownedLayer->type() == Qgis::LayerType::Vector )
5084 {
5085 mParentLayer.reset( qobject_cast<QgsVectorLayer *>( ownedLayer.release() ) );
5086 layer = mParentLayer.get();
5087 }
5088 else
5089 {
5090 // don't need ownership of this layer - it wasn't owned by context (so e.g. is owned by the project)
5091 }
5092
5093 if ( mComboBox )
5094 mComboBox->setLayer( layer );
5095 else if ( mPanel )
5096 mPanel->setFields( filterFields( layer->fields() ) );
5097
5098 valueSet = true;
5099 }
5100
5101 if ( !valueSet )
5102 {
5103 std::unique_ptr<QgsProcessingFeatureSource> source( QgsProcessingParameters::parameterAsSource( parentWrapper->parameterDefinition(), value, *context ) );
5104 if ( source )
5105 {
5106 const QgsFields fields = source->fields();
5107 if ( mComboBox )
5108 mComboBox->setFields( fields );
5109 else if ( mPanel )
5110 mPanel->setFields( filterFields( fields ) );
5111
5112 valueSet = true;
5113 }
5114 }
5115
5116 if ( !valueSet )
5117 {
5118 if ( mComboBox )
5119 mComboBox->setLayer( nullptr );
5120 else if ( mPanel )
5121 mPanel->setFields( QgsFields() );
5122
5123 if ( value.isValid() && widgetContext().messageBar() )
5124 {
5125 widgetContext().messageBar()->clearWidgets();
5126 widgetContext().messageBar()->pushMessage( QString(), QObject::tr( "Could not load selected layer/table. Dependent field could not be populated" ), Qgis::MessageLevel::Info );
5127 }
5128 return;
5129 }
5130
5131 const QgsProcessingParameterField *fieldParam = static_cast<const QgsProcessingParameterField *>( parameterDefinition() );
5132 if ( mPanel && fieldParam->defaultToAllFields() )
5133 {
5134 QVariantList val;
5135 val.reserve( mPanel->fields().size() );
5136 for ( const QgsField &field : mPanel->fields() )
5137 val << field.name();
5138 setWidgetValue( val, *context );
5139 }
5140 else if ( fieldParam->defaultValueForGui().isValid() )
5141 setWidgetValue( parameterDefinition()->defaultValueForGui(), *context );
5142}
5143
5144void QgsProcessingFieldWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
5145{
5146 if ( mComboBox )
5147 {
5148 if ( !value.isValid() )
5149 mComboBox->setField( QString() );
5150 else
5151 {
5152 const QString v = QgsProcessingParameters::parameterAsString( parameterDefinition(), value, context );
5153 mComboBox->setField( v );
5154 }
5155 }
5156 else if ( mPanel )
5157 {
5158 QVariantList opts;
5159 if ( value.isValid() )
5160 {
5161 const QStringList v = QgsProcessingParameters::parameterAsStrings( parameterDefinition(), value, context );
5162 opts.reserve( v.size() );
5163 for ( const QString &i : v )
5164 opts << i;
5165 }
5166 if ( mPanel )
5167 mPanel->setValue( opts );
5168 }
5169 else if ( mLineEdit )
5170 {
5171 const QgsProcessingParameterField *fieldParam = static_cast<const QgsProcessingParameterField *>( parameterDefinition() );
5172 if ( fieldParam->allowMultiple() )
5173 {
5174 const QStringList v = QgsProcessingParameters::parameterAsStrings( parameterDefinition(), value, context );
5175 mLineEdit->setText( v.join( ';' ) );
5176 }
5177 else
5178 {
5179 mLineEdit->setText( QgsProcessingParameters::parameterAsString( parameterDefinition(), value, context ) );
5180 }
5181 }
5182}
5183
5184QVariant QgsProcessingFieldWidgetWrapper::widgetValue() const
5185{
5186 if ( mComboBox )
5187 return mComboBox->currentField();
5188 else if ( mPanel )
5189 return mPanel->value();
5190 else if ( mLineEdit )
5191 {
5192 const QgsProcessingParameterField *fieldParam = static_cast<const QgsProcessingParameterField *>( parameterDefinition() );
5193 if ( fieldParam->allowMultiple() )
5194 {
5195 return mLineEdit->text().split( ';' );
5196 }
5197 else
5198 return mLineEdit->text();
5199 }
5200 else
5201 return QVariant();
5202}
5203
5204QString QgsProcessingFieldWidgetWrapper::modelerExpressionFormatString() const
5205{
5206 return tr( "selected field names as an array of names, or semicolon separated string of options (e.g. 'fid;place_name')" );
5207}
5208
5209const QgsVectorLayer *QgsProcessingFieldWidgetWrapper::linkedVectorLayer() const
5210{
5211 if ( mComboBox && mComboBox->layer() )
5212 return mComboBox->layer();
5213
5215}
5216
5217QgsFields QgsProcessingFieldWidgetWrapper::filterFields( const QgsFields &fields ) const
5218{
5219 const QgsProcessingParameterField *fieldParam = static_cast<const QgsProcessingParameterField *>( parameterDefinition() );
5220 QgsFields res;
5221 for ( const QgsField &f : fields )
5222 {
5223 switch ( fieldParam->dataType() )
5224 {
5226 res.append( f );
5227 break;
5228
5230 if ( f.isNumeric() )
5231 res.append( f );
5232 break;
5233
5235 if ( f.type() == QMetaType::Type::QString )
5236 res.append( f );
5237 break;
5238
5240 if ( f.type() == QMetaType::Type::QDate || f.type() == QMetaType::Type::QTime || f.type() == QMetaType::Type::QDateTime )
5241 res.append( f );
5242 break;
5243
5245 if ( f.type() == QMetaType::Type::QByteArray )
5246 res.append( f );
5247 break;
5248
5250 if ( f.type() == QMetaType::Type::Bool )
5251 res.append( f );
5252 break;
5253 }
5254 }
5255
5256 return res;
5257}
5258
5259QString QgsProcessingFieldWidgetWrapper::parameterType() const
5260{
5262}
5263
5264QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingFieldWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type )
5265{
5266 return new QgsProcessingFieldWidgetWrapper( parameter, type );
5267}
5268
5269QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingFieldWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
5270{
5271 return new QgsProcessingFieldParameterDefinitionWidget( context, widgetContext, definition, algorithm );
5272}
5273
5274//
5275// QgsProcessingMapThemeWidgetWrapper
5276//
5277
5278
5279QgsProcessingMapThemeParameterDefinitionWidget::QgsProcessingMapThemeParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
5280 : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
5281{
5282 QVBoxLayout *vlayout = new QVBoxLayout();
5283 vlayout->setContentsMargins( 0, 0, 0, 0 );
5284
5285 vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
5286
5287 mDefaultComboBox = new QComboBox();
5288 mDefaultComboBox->addItem( QString(), QVariant( -1 ) );
5289
5290 const QStringList mapThemes = widgetContext.project() ? widgetContext.project()->mapThemeCollection()->mapThemes() : QgsProject::instance()->mapThemeCollection()->mapThemes();
5291 for ( const QString &theme : mapThemes )
5292 {
5293 mDefaultComboBox->addItem( QgsApplication::getThemeIcon( u"/mActionShowAllLayers.svg"_s ), theme, theme );
5294 }
5295 mDefaultComboBox->setEditable( true );
5296
5297 if ( const QgsProcessingParameterMapTheme *themeParam = dynamic_cast<const QgsProcessingParameterMapTheme *>( definition ) )
5298 {
5299 if ( themeParam->defaultValueForGui().isValid() )
5300 mDefaultComboBox->setCurrentText( QgsProcessingParameters::parameterAsString( themeParam, themeParam->defaultValueForGui(), context ) );
5301 else
5302 mDefaultComboBox->setCurrentIndex( mDefaultComboBox->findData( -1 ) );
5303 }
5304 else
5305 mDefaultComboBox->setCurrentIndex( mDefaultComboBox->findData( -1 ) );
5306
5307 vlayout->addWidget( mDefaultComboBox );
5308
5309 setLayout( vlayout );
5310}
5311
5312QgsProcessingParameterDefinition *QgsProcessingMapThemeParameterDefinitionWidget::createParameter( const QString &name, const QString &description, Qgis::ProcessingParameterFlags flags ) const
5313{
5314 QVariant defaultVal;
5315 if ( mDefaultComboBox->currentText().isEmpty() )
5316 defaultVal = QVariant();
5317 else
5318 defaultVal = mDefaultComboBox->currentText();
5319 auto param = std::make_unique<QgsProcessingParameterMapTheme>( name, description, defaultVal );
5320 param->setFlags( flags );
5321 return param.release();
5322}
5323
5324
5325QgsProcessingMapThemeWidgetWrapper::QgsProcessingMapThemeWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type, QWidget *parent )
5326 : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
5327{
5328}
5329
5330QWidget *QgsProcessingMapThemeWidgetWrapper::createWidget()
5331{
5332 const QgsProcessingParameterMapTheme *themeParam = dynamic_cast<const QgsProcessingParameterMapTheme *>( parameterDefinition() );
5333 if ( !themeParam )
5334 return nullptr;
5335
5336 mComboBox = new QComboBox();
5337
5338 if ( themeParam->flags() & Qgis::ProcessingParameterFlag::Optional )
5339 mComboBox->addItem( tr( "[Not selected]" ), QVariant( -1 ) );
5340
5341 const QStringList mapThemes = widgetContext().project() ? widgetContext().project()->mapThemeCollection()->mapThemes() : QgsProject::instance()->mapThemeCollection()->mapThemes();
5342 for ( const QString &theme : mapThemes )
5343 {
5344 mComboBox->addItem( QgsApplication::getThemeIcon( u"/mActionShowAllLayers.svg"_s ), theme, theme );
5345 }
5346
5347 switch ( type() )
5348 {
5351 break;
5352
5354 mComboBox->setEditable( true );
5355 break;
5356 }
5357
5358 mComboBox->setToolTip( parameterDefinition()->toolTip() );
5359 connect( mComboBox, qOverload<int>( &QComboBox::currentIndexChanged ), this, [this]( int ) {
5360 emit widgetValueHasChanged( this );
5361 } );
5362
5363 return mComboBox;
5364}
5365
5366void QgsProcessingMapThemeWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
5367{
5368 const QString v = QgsProcessingParameters::parameterAsString( parameterDefinition(), value, context );
5369
5370 if ( !value.isValid() )
5371 mComboBox->setCurrentIndex( mComboBox->findData( QVariant( -1 ) ) );
5372 else
5373 {
5374 if ( mComboBox->isEditable() && mComboBox->findData( v ) == -1 )
5375 {
5376 const QString prev = mComboBox->currentText();
5377 mComboBox->setCurrentText( v );
5378 if ( prev != v )
5379 emit widgetValueHasChanged( this );
5380 }
5381 else
5382 mComboBox->setCurrentIndex( mComboBox->findData( v ) );
5383 }
5384}
5385
5386QVariant QgsProcessingMapThemeWidgetWrapper::widgetValue() const
5387{
5388 if ( mComboBox )
5389 return mComboBox->currentData().toInt() == -1 ? QVariant() : !mComboBox->currentData().isValid() && mComboBox->isEditable() ? mComboBox->currentText().isEmpty() ? QVariant() : QVariant( mComboBox->currentText() )
5390 : mComboBox->currentData();
5391 else
5392 return QVariant();
5393}
5394
5395QString QgsProcessingMapThemeWidgetWrapper::modelerExpressionFormatString() const
5396{
5397 return tr( "map theme as a string value (e.g. 'base maps')" );
5398}
5399
5400QString QgsProcessingMapThemeWidgetWrapper::parameterType() const
5401{
5403}
5404
5405QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingMapThemeWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type )
5406{
5407 return new QgsProcessingMapThemeWidgetWrapper( parameter, type );
5408}
5409
5410QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingMapThemeWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
5411{
5412 return new QgsProcessingMapThemeParameterDefinitionWidget( context, widgetContext, definition, algorithm );
5413}
5414
5415
5416//
5417// QgsProcessingDateTimeWidgetWrapper
5418//
5419
5420
5421QgsProcessingDateTimeParameterDefinitionWidget::QgsProcessingDateTimeParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
5422 : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
5423{
5424 QVBoxLayout *vlayout = new QVBoxLayout();
5425 vlayout->setContentsMargins( 0, 0, 0, 0 );
5426
5427 vlayout->addWidget( new QLabel( tr( "Type" ) ) );
5428
5429 mTypeComboBox = new QComboBox();
5430 mTypeComboBox->addItem( tr( "Date and Time" ), static_cast<int>( Qgis::ProcessingDateTimeParameterDataType::DateTime ) );
5431 mTypeComboBox->addItem( tr( "Date" ), static_cast<int>( Qgis::ProcessingDateTimeParameterDataType::Date ) );
5432 mTypeComboBox->addItem( tr( "Time" ), static_cast<int>( Qgis::ProcessingDateTimeParameterDataType::Time ) );
5433 if ( const QgsProcessingParameterDateTime *datetimeParam = dynamic_cast<const QgsProcessingParameterDateTime *>( definition ) )
5434 mTypeComboBox->setCurrentIndex( mTypeComboBox->findData( static_cast<int>( datetimeParam->dataType() ) ) );
5435 else
5436 mTypeComboBox->setCurrentIndex( 0 );
5437 vlayout->addWidget( mTypeComboBox );
5438
5439 setLayout( vlayout );
5440}
5441
5442QgsProcessingParameterDefinition *QgsProcessingDateTimeParameterDefinitionWidget::createParameter( const QString &name, const QString &description, Qgis::ProcessingParameterFlags flags ) const
5443{
5444 auto param = std::make_unique<QgsProcessingParameterDateTime>( name, description );
5445 param->setDataType( static_cast<Qgis::ProcessingDateTimeParameterDataType>( mTypeComboBox->currentData().toInt() ) );
5446 param->setFlags( flags );
5447 return param.release();
5448}
5449
5450
5451QgsProcessingDateTimeWidgetWrapper::QgsProcessingDateTimeWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type, QWidget *parent )
5452 : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
5453{
5454}
5455
5456QWidget *QgsProcessingDateTimeWidgetWrapper::createWidget()
5457{
5458 const QgsProcessingParameterDateTime *dateTimeParam = dynamic_cast<const QgsProcessingParameterDateTime *>( parameterDefinition() );
5459 if ( !dateTimeParam )
5460 return nullptr;
5461
5462 QgsDateTimeEdit *widget = nullptr;
5463 switch ( dateTimeParam->dataType() )
5464 {
5466 mDateTimeEdit = new QgsDateTimeEdit();
5467 widget = mDateTimeEdit;
5468 break;
5469
5471 mDateEdit = new QgsDateEdit();
5472 widget = mDateEdit;
5473 break;
5474
5476 mTimeEdit = new QgsTimeEdit();
5477 widget = mTimeEdit;
5478 break;
5479 }
5480 if ( !widget )
5481 return nullptr;
5482
5483 if ( dateTimeParam->flags() & Qgis::ProcessingParameterFlag::Optional )
5484 {
5485 widget->setNullRepresentation( tr( "[Not selected]" ) );
5486 widget->setAllowNull( true );
5487 }
5488 else
5489 {
5490 widget->setAllowNull( false );
5491 }
5492 widget->setToolTip( parameterDefinition()->toolTip() );
5493
5494 if ( mDateTimeEdit )
5495 {
5496 connect( mDateTimeEdit, &QgsDateTimeEdit::valueChanged, this, [this]( const QDateTime & ) {
5497 emit widgetValueHasChanged( this );
5498 } );
5499 }
5500 else if ( mDateEdit )
5501 {
5502 connect( mDateEdit, &QgsDateEdit::dateValueChanged, this, [this]( const QDate & ) {
5503 emit widgetValueHasChanged( this );
5504 } );
5505 }
5506 else if ( mTimeEdit )
5507 {
5508 connect( mTimeEdit, &QgsTimeEdit::timeValueChanged, this, [this]( const QTime & ) {
5509 emit widgetValueHasChanged( this );
5510 } );
5511 }
5512
5513 return widget;
5514}
5515
5516QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingDateTimeWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
5517{
5518 return new QgsProcessingDateTimeParameterDefinitionWidget( context, widgetContext, definition, algorithm );
5519}
5520
5521void QgsProcessingDateTimeWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
5522{
5523 if ( mDateTimeEdit )
5524 {
5525 mDateTimeEdit->setDateTime( QgsProcessingParameters::parameterAsDateTime( parameterDefinition(), value, context ) );
5526 }
5527 else if ( mDateEdit )
5528 {
5529 mDateEdit->setDate( QgsProcessingParameters::parameterAsDate( parameterDefinition(), value, context ) );
5530 }
5531 else if ( mTimeEdit )
5532 {
5533 mTimeEdit->setTime( QgsProcessingParameters::parameterAsTime( parameterDefinition(), value, context ) );
5534 }
5535}
5536
5537QVariant QgsProcessingDateTimeWidgetWrapper::widgetValue() const
5538{
5539 if ( mDateTimeEdit )
5540 return !mDateTimeEdit->dateTime().isNull() && mDateTimeEdit->dateTime().isValid() ? QVariant( mDateTimeEdit->dateTime() ) : QVariant();
5541 else if ( mDateEdit )
5542 return !mDateEdit->date().isNull() && mDateEdit->date().isValid() ? QVariant( mDateEdit->date() ) : QVariant();
5543 else if ( mTimeEdit )
5544 return !mTimeEdit->time().isNull() && mTimeEdit->time().isValid() ? QVariant( mTimeEdit->time() ) : QVariant();
5545 else
5546 return QVariant();
5547}
5548
5549QString QgsProcessingDateTimeWidgetWrapper::modelerExpressionFormatString() const
5550{
5551 const QgsProcessingParameterDateTime *dateTimeParam = dynamic_cast<const QgsProcessingParameterDateTime *>( parameterDefinition() );
5552 if ( dateTimeParam )
5553 {
5554 switch ( dateTimeParam->dataType() )
5555 {
5557 return tr( "datetime value, or a ISO string representation of a datetime" );
5558
5560 return tr( "date value, or a ISO string representation of a date" );
5561
5563 return tr( "time value, or a ISO string representation of a time" );
5564 }
5565 }
5566 return QString();
5567}
5568
5569QString QgsProcessingDateTimeWidgetWrapper::parameterType() const
5570{
5572}
5573
5574QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingDateTimeWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type )
5575{
5576 return new QgsProcessingDateTimeWidgetWrapper( parameter, type );
5577}
5578
5579
5580//
5581// QgsProcessingProviderConnectionWidgetWrapper
5582//
5583
5584QgsProcessingProviderConnectionParameterDefinitionWidget::QgsProcessingProviderConnectionParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
5585 : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
5586{
5587 const QgsProcessingParameterProviderConnection *connectionParam = dynamic_cast<const QgsProcessingParameterProviderConnection *>( definition );
5588
5589 QVBoxLayout *vlayout = new QVBoxLayout();
5590 vlayout->setContentsMargins( 0, 0, 0, 0 );
5591
5592 vlayout->addWidget( new QLabel( tr( "Provider" ) ) );
5593 mProviderComboBox = new QComboBox();
5594 mProviderComboBox->addItem( QObject::tr( "Postgres" ), u"postgres"_s );
5595 mProviderComboBox->addItem( QObject::tr( "GeoPackage" ), u"ogr"_s );
5596 mProviderComboBox->addItem( QObject::tr( "Spatialite" ), u"spatialite"_s );
5597
5598 vlayout->addWidget( mProviderComboBox );
5599
5600 vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
5601
5602 mDefaultEdit = new QLineEdit();
5603 vlayout->addWidget( mDefaultEdit );
5604 setLayout( vlayout );
5605
5606 if ( connectionParam )
5607 {
5608 mProviderComboBox->setCurrentIndex( mProviderComboBox->findData( connectionParam->providerId() ) );
5609 mDefaultEdit->setText( connectionParam->defaultValueForGui().toString() );
5610 }
5611}
5612
5613QgsProcessingParameterDefinition *QgsProcessingProviderConnectionParameterDefinitionWidget::createParameter( const QString &name, const QString &description, Qgis::ProcessingParameterFlags flags ) const
5614{
5615 QVariant defaultVal;
5616 if ( mDefaultEdit->text().isEmpty() )
5617 defaultVal = QVariant();
5618 else
5619 defaultVal = mDefaultEdit->text();
5620 auto param = std::make_unique<QgsProcessingParameterProviderConnection>( name, description, mProviderComboBox->currentData().toString(), defaultVal );
5621 param->setFlags( flags );
5622 return param.release();
5623}
5624
5625
5626QgsProcessingProviderConnectionWidgetWrapper::QgsProcessingProviderConnectionWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type, QWidget *parent )
5627 : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
5628{
5629}
5630
5631QWidget *QgsProcessingProviderConnectionWidgetWrapper::createWidget()
5632{
5633 const QgsProcessingParameterProviderConnection *connectionParam = dynamic_cast<const QgsProcessingParameterProviderConnection *>( parameterDefinition() );
5634 if ( !connectionParam )
5635 return nullptr;
5636
5637 mProviderComboBox = new QgsProviderConnectionComboBox( connectionParam->providerId() );
5638 if ( connectionParam->flags() & Qgis::ProcessingParameterFlag::Optional )
5639 mProviderComboBox->setAllowEmptyConnection( true );
5640
5641 switch ( type() )
5642 {
5645 break;
5647 mProviderComboBox->setEditable( true );
5648 break;
5649 }
5650
5651 mProviderComboBox->setToolTip( parameterDefinition()->toolTip() );
5652 connect( mProviderComboBox, &QgsProviderConnectionComboBox::currentTextChanged, this, [this]( const QString & ) {
5653 if ( mBlockSignals )
5654 return;
5655
5656 emit widgetValueHasChanged( this );
5657 } );
5658
5659 return mProviderComboBox;
5660}
5661
5662QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingProviderConnectionWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
5663{
5664 return new QgsProcessingProviderConnectionParameterDefinitionWidget( context, widgetContext, definition, algorithm );
5665}
5666
5667void QgsProcessingProviderConnectionWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
5668{
5669 const QString v = QgsProcessingParameters::parameterAsConnectionName( parameterDefinition(), value, context );
5670
5671 if ( !value.isValid() )
5672 mProviderComboBox->setCurrentIndex( -1 );
5673 else
5674 {
5675 if ( mProviderComboBox->isEditable() )
5676 {
5677 const QString prev = mProviderComboBox->currentText();
5678 mBlockSignals++;
5679 mProviderComboBox->setConnection( v );
5680 mProviderComboBox->setCurrentText( v );
5681
5682 mBlockSignals--;
5683 if ( prev != v )
5684 emit widgetValueHasChanged( this );
5685 }
5686 else
5687 mProviderComboBox->setConnection( v );
5688 }
5689}
5690
5691QVariant QgsProcessingProviderConnectionWidgetWrapper::widgetValue() const
5692{
5693 if ( mProviderComboBox )
5694 if ( mProviderComboBox->isEditable() )
5695 return mProviderComboBox->currentText().isEmpty() ? QVariant() : QVariant( mProviderComboBox->currentText() );
5696 else
5697 return mProviderComboBox->currentConnection().isEmpty() ? QVariant() : QVariant( mProviderComboBox->currentConnection() );
5698 else
5699 return QVariant();
5700}
5701
5702QString QgsProcessingProviderConnectionWidgetWrapper::modelerExpressionFormatString() const
5703{
5704 return tr( "connection name as a string value" );
5705}
5706
5707QString QgsProcessingProviderConnectionWidgetWrapper::parameterType() const
5708{
5710}
5711
5712QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingProviderConnectionWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type )
5713{
5714 return new QgsProcessingProviderConnectionWidgetWrapper( parameter, type );
5715}
5716
5717
5718//
5719// QgsProcessingDatabaseSchemaWidgetWrapper
5720//
5721
5722QgsProcessingDatabaseSchemaParameterDefinitionWidget::QgsProcessingDatabaseSchemaParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
5723 : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
5724{
5725 const QgsProcessingParameterDatabaseSchema *schemaParam = dynamic_cast<const QgsProcessingParameterDatabaseSchema *>( definition );
5726
5727 QVBoxLayout *vlayout = new QVBoxLayout();
5728 vlayout->setContentsMargins( 0, 0, 0, 0 );
5729
5730 mConnectionParamComboBox = new QComboBox();
5731 QString initialConnection;
5732 if ( schemaParam )
5733 {
5734 initialConnection = schemaParam->parentConnectionParameterName();
5735 }
5736
5737 if ( auto *lModel = widgetContext.model() )
5738 {
5739 // populate combo box with other model input choices
5740 const QMap<QString, QgsProcessingModelParameter> components = lModel->parameterComponents();
5741 for ( auto it = components.constBegin(); it != components.constEnd(); ++it )
5742 {
5743 if ( definition && it->parameterName() == definition->name() )
5744 continue;
5745
5746 if ( !dynamic_cast<const QgsProcessingParameterProviderConnection *>( lModel->parameterDefinition( it->parameterName() ) ) )
5747 continue;
5748
5749 mConnectionParamComboBox->addItem( it->parameterName(), it->parameterName() );
5750 if ( !initialConnection.isEmpty() && initialConnection == it->parameterName() )
5751 {
5752 mConnectionParamComboBox->setCurrentIndex( mConnectionParamComboBox->count() - 1 );
5753 }
5754 }
5755 }
5756
5757 if ( mConnectionParamComboBox->count() == 0 && !initialConnection.isEmpty() )
5758 {
5759 // if no candidates found, we just add the existing one as a placeholder
5760 mConnectionParamComboBox->addItem( initialConnection, initialConnection );
5761 mConnectionParamComboBox->setCurrentIndex( mConnectionParamComboBox->count() - 1 );
5762 }
5763
5764 vlayout->addWidget( new QLabel( tr( "Provider connection parameter" ) ) );
5765 vlayout->addWidget( mConnectionParamComboBox );
5766
5767 vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
5768
5769 mDefaultEdit = new QLineEdit();
5770 vlayout->addWidget( mDefaultEdit );
5771 setLayout( vlayout );
5772
5773 if ( schemaParam )
5774 {
5775 mDefaultEdit->setText( schemaParam->defaultValueForGui().toString() );
5776 }
5777}
5778
5779QgsProcessingParameterDefinition *QgsProcessingDatabaseSchemaParameterDefinitionWidget::createParameter( const QString &name, const QString &description, Qgis::ProcessingParameterFlags flags ) const
5780{
5781 QVariant defaultVal;
5782 if ( mDefaultEdit->text().isEmpty() )
5783 defaultVal = QVariant();
5784 else
5785 defaultVal = mDefaultEdit->text();
5786 auto param = std::make_unique<QgsProcessingParameterDatabaseSchema>( name, description, mConnectionParamComboBox->currentData().toString(), defaultVal );
5787 param->setFlags( flags );
5788 return param.release();
5789}
5790
5791
5792QgsProcessingDatabaseSchemaWidgetWrapper::QgsProcessingDatabaseSchemaWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type, QWidget *parent )
5793 : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
5794{
5795}
5796
5797QWidget *QgsProcessingDatabaseSchemaWidgetWrapper::createWidget()
5798{
5799 const QgsProcessingParameterDatabaseSchema *schemaParam = dynamic_cast<const QgsProcessingParameterDatabaseSchema *>( parameterDefinition() );
5800 if ( !schemaParam )
5801 return nullptr;
5802
5803 mSchemaComboBox = new QgsDatabaseSchemaComboBox( QString(), QString() );
5804 if ( schemaParam->flags() & Qgis::ProcessingParameterFlag::Optional )
5805 mSchemaComboBox->setAllowEmptySchema( true );
5806
5807 switch ( type() )
5808 {
5811 break;
5813 mSchemaComboBox->comboBox()->setEditable( true );
5814 break;
5815 }
5816
5817 mSchemaComboBox->setToolTip( parameterDefinition()->toolTip() );
5818 connect( mSchemaComboBox->comboBox(), &QComboBox::currentTextChanged, this, [this]( const QString & ) {
5819 if ( mBlockSignals )
5820 return;
5821
5822 emit widgetValueHasChanged( this );
5823 } );
5824
5825 return mSchemaComboBox;
5826}
5827
5828QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingDatabaseSchemaWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
5829{
5830 return new QgsProcessingDatabaseSchemaParameterDefinitionWidget( context, widgetContext, definition, algorithm );
5831}
5832
5833void QgsProcessingDatabaseSchemaWidgetWrapper::setParentConnectionWrapperValue( const QgsAbstractProcessingParameterWidgetWrapper *parentWrapper )
5834{
5835 // evaluate value to connection
5836 QgsProcessingContext *context = nullptr;
5837 std::unique_ptr<QgsProcessingContext> tmpContext;
5838 if ( mProcessingContextGenerator )
5839 context = mProcessingContextGenerator->processingContext();
5840
5841 if ( !context )
5842 {
5843 tmpContext = std::make_unique<QgsProcessingContext>();
5844 context = tmpContext.get();
5845 }
5846
5847 const QVariant value = parentWrapper->parameterValue();
5848 const QString connection = value.isValid() ? QgsProcessingParameters::parameterAsConnectionName( parentWrapper->parameterDefinition(), value, *context ) : QString();
5849
5850 if ( mSchemaComboBox )
5851 mSchemaComboBox->setConnectionName( connection, qgis::down_cast<const QgsProcessingParameterProviderConnection *>( parentWrapper->parameterDefinition() )->providerId() );
5852
5853 const QgsProcessingParameterDatabaseSchema *schemaParam = qgis::down_cast<const QgsProcessingParameterDatabaseSchema *>( parameterDefinition() );
5854 if ( schemaParam->defaultValueForGui().isValid() )
5855 setWidgetValue( parameterDefinition()->defaultValueForGui(), *context );
5856}
5857
5858void QgsProcessingDatabaseSchemaWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
5859{
5860 const QString v = QgsProcessingParameters::parameterAsSchema( parameterDefinition(), value, context );
5861
5862 if ( !value.isValid() )
5863 mSchemaComboBox->comboBox()->setCurrentIndex( -1 );
5864 else
5865 {
5866 if ( mSchemaComboBox->comboBox()->isEditable() )
5867 {
5868 const QString prev = mSchemaComboBox->comboBox()->currentText();
5869 mBlockSignals++;
5870 mSchemaComboBox->setSchema( v );
5871 mSchemaComboBox->comboBox()->setCurrentText( v );
5872
5873 mBlockSignals--;
5874 if ( prev != v )
5875 emit widgetValueHasChanged( this );
5876 }
5877 else
5878 mSchemaComboBox->setSchema( v );
5879 }
5880}
5881
5882QVariant QgsProcessingDatabaseSchemaWidgetWrapper::widgetValue() const
5883{
5884 if ( mSchemaComboBox )
5885 if ( mSchemaComboBox->comboBox()->isEditable() )
5886 return mSchemaComboBox->comboBox()->currentText().isEmpty() ? QVariant() : QVariant( mSchemaComboBox->comboBox()->currentText() );
5887 else
5888 return mSchemaComboBox->currentSchema().isEmpty() ? QVariant() : QVariant( mSchemaComboBox->currentSchema() );
5889 else
5890 return QVariant();
5891}
5892
5893QString QgsProcessingDatabaseSchemaWidgetWrapper::modelerExpressionFormatString() const
5894{
5895 return tr( "database schema name as a string value" );
5896}
5897
5898QString QgsProcessingDatabaseSchemaWidgetWrapper::parameterType() const
5899{
5901}
5902
5903QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingDatabaseSchemaWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type )
5904{
5905 return new QgsProcessingDatabaseSchemaWidgetWrapper( parameter, type );
5906}
5907
5908void QgsProcessingDatabaseSchemaWidgetWrapper::postInitialize( const QList<QgsAbstractProcessingParameterWidgetWrapper *> &wrappers )
5909{
5911 switch ( type() )
5912 {
5915 {
5916 for ( const QgsAbstractProcessingParameterWidgetWrapper *wrapper : wrappers )
5917 {
5918 if ( wrapper->parameterDefinition()->name() == static_cast<const QgsProcessingParameterDatabaseSchema *>( parameterDefinition() )->parentConnectionParameterName() )
5919 {
5920 setParentConnectionWrapperValue( wrapper );
5921 connect( wrapper, &QgsAbstractProcessingParameterWidgetWrapper::widgetValueHasChanged, this, [this, wrapper] {
5922 setParentConnectionWrapperValue( wrapper );
5923 } );
5924 break;
5925 }
5926 }
5927 break;
5928 }
5929
5931 break;
5932 }
5933}
5934
5935
5936//
5937// QgsProcessingDatabaseTableWidgetWrapper
5938//
5939
5940QgsProcessingDatabaseTableParameterDefinitionWidget::QgsProcessingDatabaseTableParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
5941 : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
5942{
5943 const QgsProcessingParameterDatabaseTable *tableParam = dynamic_cast<const QgsProcessingParameterDatabaseTable *>( definition );
5944
5945 QVBoxLayout *vlayout = new QVBoxLayout();
5946 vlayout->setContentsMargins( 0, 0, 0, 0 );
5947
5948 mConnectionParamComboBox = new QComboBox();
5949 mSchemaParamComboBox = new QComboBox();
5950 QString initialConnection;
5951 QString initialSchema;
5952 if ( tableParam )
5953 {
5954 initialConnection = tableParam->parentConnectionParameterName();
5955 initialSchema = tableParam->parentSchemaParameterName();
5956 }
5957
5958 if ( auto *lModel = widgetContext.model() )
5959 {
5960 // populate combo box with other model input choices
5961 const QMap<QString, QgsProcessingModelParameter> components = lModel->parameterComponents();
5962 for ( auto it = components.constBegin(); it != components.constEnd(); ++it )
5963 {
5964 if ( definition && it->parameterName() == definition->name() )
5965 continue;
5966
5967 if ( dynamic_cast<const QgsProcessingParameterProviderConnection *>( lModel->parameterDefinition( it->parameterName() ) ) )
5968 {
5969 mConnectionParamComboBox->addItem( it->parameterName(), it->parameterName() );
5970 if ( !initialConnection.isEmpty() && initialConnection == it->parameterName() )
5971 {
5972 mConnectionParamComboBox->setCurrentIndex( mConnectionParamComboBox->count() - 1 );
5973 }
5974 }
5975 else if ( dynamic_cast<const QgsProcessingParameterDatabaseSchema *>( lModel->parameterDefinition( it->parameterName() ) ) )
5976 {
5977 mSchemaParamComboBox->addItem( it->parameterName(), it->parameterName() );
5978 if ( !initialConnection.isEmpty() && initialConnection == it->parameterName() )
5979 {
5980 mSchemaParamComboBox->setCurrentIndex( mSchemaParamComboBox->count() - 1 );
5981 }
5982 }
5983 }
5984 }
5985
5986 if ( mConnectionParamComboBox->count() == 0 && !initialConnection.isEmpty() )
5987 {
5988 // if no candidates found, we just add the existing one as a placeholder
5989 mConnectionParamComboBox->addItem( initialConnection, initialConnection );
5990 mConnectionParamComboBox->setCurrentIndex( mConnectionParamComboBox->count() - 1 );
5991 }
5992
5993 if ( mSchemaParamComboBox->count() == 0 && !initialSchema.isEmpty() )
5994 {
5995 // if no candidates found, we just add the existing one as a placeholder
5996 mSchemaParamComboBox->addItem( initialSchema, initialSchema );
5997 mSchemaParamComboBox->setCurrentIndex( mSchemaParamComboBox->count() - 1 );
5998 }
5999
6000 vlayout->addWidget( new QLabel( tr( "Provider connection parameter" ) ) );
6001 vlayout->addWidget( mConnectionParamComboBox );
6002
6003 vlayout->addWidget( new QLabel( tr( "Database schema parameter" ) ) );
6004 vlayout->addWidget( mSchemaParamComboBox );
6005
6006 vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
6007
6008 mDefaultEdit = new QLineEdit();
6009 vlayout->addWidget( mDefaultEdit );
6010 setLayout( vlayout );
6011
6012 if ( tableParam )
6013 {
6014 mDefaultEdit->setText( tableParam->defaultValueForGui().toString() );
6015 }
6016}
6017
6018QgsProcessingParameterDefinition *QgsProcessingDatabaseTableParameterDefinitionWidget::createParameter( const QString &name, const QString &description, Qgis::ProcessingParameterFlags flags ) const
6019{
6020 QVariant defaultVal;
6021 if ( mDefaultEdit->text().isEmpty() )
6022 defaultVal = QVariant();
6023 else
6024 defaultVal = mDefaultEdit->text();
6025 auto param = std::make_unique<QgsProcessingParameterDatabaseTable>( name, description, mConnectionParamComboBox->currentData().toString(), mSchemaParamComboBox->currentData().toString(), defaultVal );
6026 param->setFlags( flags );
6027 return param.release();
6028}
6029
6030
6031QgsProcessingDatabaseTableWidgetWrapper::QgsProcessingDatabaseTableWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type, QWidget *parent )
6032 : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
6033{
6034}
6035
6036QWidget *QgsProcessingDatabaseTableWidgetWrapper::createWidget()
6037{
6038 const QgsProcessingParameterDatabaseTable *tableParam = dynamic_cast<const QgsProcessingParameterDatabaseTable *>( parameterDefinition() );
6039 if ( !tableParam )
6040 return nullptr;
6041
6042 mTableComboBox = new QgsDatabaseTableComboBox( QString(), QString() );
6043 if ( tableParam->flags() & Qgis::ProcessingParameterFlag::Optional )
6044 mTableComboBox->setAllowEmptyTable( true );
6045
6046 if ( type() == Qgis::ProcessingMode::Modeler || tableParam->allowNewTableNames() )
6047 mTableComboBox->comboBox()->setEditable( true );
6048
6049 mTableComboBox->setToolTip( parameterDefinition()->toolTip() );
6050 connect( mTableComboBox->comboBox(), &QComboBox::currentTextChanged, this, [this]( const QString & ) {
6051 if ( mBlockSignals )
6052 return;
6053
6054 emit widgetValueHasChanged( this );
6055 } );
6056
6057 return mTableComboBox;
6058}
6059
6060QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingDatabaseTableWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
6061{
6062 return new QgsProcessingDatabaseTableParameterDefinitionWidget( context, widgetContext, definition, algorithm );
6063}
6064
6065void QgsProcessingDatabaseTableWidgetWrapper::setParentConnectionWrapperValue( const QgsAbstractProcessingParameterWidgetWrapper *parentWrapper )
6066{
6067 // evaluate value to connection
6068 QgsProcessingContext *context = nullptr;
6069 std::unique_ptr<QgsProcessingContext> tmpContext;
6070 if ( mProcessingContextGenerator )
6071 context = mProcessingContextGenerator->processingContext();
6072
6073 if ( !context )
6074 {
6075 tmpContext = std::make_unique<QgsProcessingContext>();
6076 context = tmpContext.get();
6077 }
6078
6079 QVariant value = parentWrapper->parameterValue();
6080 mConnection = value.isValid() ? QgsProcessingParameters::parameterAsConnectionName( parentWrapper->parameterDefinition(), value, *context ) : QString();
6081 mProvider = qgis::down_cast<const QgsProcessingParameterProviderConnection *>( parentWrapper->parameterDefinition() )->providerId();
6082 if ( mTableComboBox && !mSchema.isEmpty() )
6083 {
6084 mTableComboBox->setSchema( mSchema );
6085 mTableComboBox->setConnectionName( mConnection, mProvider );
6086
6087 const QgsProcessingParameterDatabaseTable *tableParam = qgis::down_cast<const QgsProcessingParameterDatabaseTable *>( parameterDefinition() );
6088 if ( tableParam->defaultValueForGui().isValid() )
6089 setWidgetValue( parameterDefinition()->defaultValueForGui(), *context );
6090 }
6091}
6092
6093void QgsProcessingDatabaseTableWidgetWrapper::setParentSchemaWrapperValue( const QgsAbstractProcessingParameterWidgetWrapper *parentWrapper )
6094{
6095 // evaluate value to schema
6096 QgsProcessingContext *context = nullptr;
6097 std::unique_ptr<QgsProcessingContext> tmpContext;
6098 if ( mProcessingContextGenerator )
6099 context = mProcessingContextGenerator->processingContext();
6100
6101 if ( !context )
6102 {
6103 tmpContext = std::make_unique<QgsProcessingContext>();
6104 context = tmpContext.get();
6105 }
6106
6107 QVariant value = parentWrapper->parameterValue();
6108 mSchema = value.isValid() ? QgsProcessingParameters::parameterAsSchema( parentWrapper->parameterDefinition(), value, *context ) : QString();
6109
6110 if ( mTableComboBox && !mSchema.isEmpty() && !mConnection.isEmpty() )
6111 {
6112 mTableComboBox->setSchema( mSchema );
6113 mTableComboBox->setConnectionName( mConnection, mProvider );
6114
6115 const QgsProcessingParameterDatabaseTable *tableParam = static_cast<const QgsProcessingParameterDatabaseTable *>( parameterDefinition() );
6116 if ( tableParam->defaultValueForGui().isValid() )
6117 setWidgetValue( parameterDefinition()->defaultValueForGui(), *context );
6118 }
6119}
6120
6121void QgsProcessingDatabaseTableWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
6122{
6123 const QString v = QgsProcessingParameters::parameterAsDatabaseTableName( parameterDefinition(), value, context );
6124
6125 if ( !value.isValid() )
6126 mTableComboBox->comboBox()->setCurrentIndex( -1 );
6127 else
6128 {
6129 if ( mTableComboBox->comboBox()->isEditable() )
6130 {
6131 const QString prev = mTableComboBox->comboBox()->currentText();
6132 mBlockSignals++;
6133 mTableComboBox->setTable( v );
6134 mTableComboBox->comboBox()->setCurrentText( v );
6135
6136 mBlockSignals--;
6137 if ( prev != v )
6138 emit widgetValueHasChanged( this );
6139 }
6140 else
6141 mTableComboBox->setTable( v );
6142 }
6143}
6144
6145QVariant QgsProcessingDatabaseTableWidgetWrapper::widgetValue() const
6146{
6147 if ( mTableComboBox )
6148 if ( mTableComboBox->comboBox()->isEditable() )
6149 return mTableComboBox->comboBox()->currentText().isEmpty() ? QVariant() : QVariant( mTableComboBox->comboBox()->currentText() );
6150 else
6151 return mTableComboBox->currentTable().isEmpty() ? QVariant() : QVariant( mTableComboBox->currentTable() );
6152 else
6153 return QVariant();
6154}
6155
6156QString QgsProcessingDatabaseTableWidgetWrapper::modelerExpressionFormatString() const
6157{
6158 return tr( "database table name as a string value" );
6159}
6160
6161QString QgsProcessingDatabaseTableWidgetWrapper::parameterType() const
6162{
6164}
6165
6166QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingDatabaseTableWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type )
6167{
6168 return new QgsProcessingDatabaseTableWidgetWrapper( parameter, type );
6169}
6170
6171void QgsProcessingDatabaseTableWidgetWrapper::postInitialize( const QList<QgsAbstractProcessingParameterWidgetWrapper *> &wrappers )
6172{
6174 switch ( type() )
6175 {
6178 {
6179 for ( const QgsAbstractProcessingParameterWidgetWrapper *wrapper : wrappers )
6180 {
6181 if ( wrapper->parameterDefinition()->name() == static_cast<const QgsProcessingParameterDatabaseTable *>( parameterDefinition() )->parentConnectionParameterName() )
6182 {
6183 setParentConnectionWrapperValue( wrapper );
6184 connect( wrapper, &QgsAbstractProcessingParameterWidgetWrapper::widgetValueHasChanged, this, [this, wrapper] {
6185 setParentConnectionWrapperValue( wrapper );
6186 } );
6187 }
6188 else if ( wrapper->parameterDefinition()->name() == static_cast<const QgsProcessingParameterDatabaseTable *>( parameterDefinition() )->parentSchemaParameterName() )
6189 {
6190 setParentSchemaWrapperValue( wrapper );
6191 connect( wrapper, &QgsAbstractProcessingParameterWidgetWrapper::widgetValueHasChanged, this, [this, wrapper] {
6192 setParentSchemaWrapperValue( wrapper );
6193 } );
6194 }
6195 }
6196 break;
6197 }
6198
6200 break;
6201 }
6202}
6203
6204
6205//
6206// QgsProcessingExtentWidgetWrapper
6207//
6208
6209QgsProcessingExtentParameterDefinitionWidget::QgsProcessingExtentParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
6210 : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
6211{
6212 QVBoxLayout *vlayout = new QVBoxLayout();
6213 vlayout->setContentsMargins( 0, 0, 0, 0 );
6214
6215 vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
6216
6217 mDefaultWidget = new QgsExtentWidget();
6218 mDefaultWidget->setNullValueAllowed( true, tr( "Not set" ) );
6219 if ( const QgsProcessingParameterExtent *extentParam = dynamic_cast<const QgsProcessingParameterExtent *>( definition ) )
6220 {
6221 if ( extentParam->defaultValueForGui().isValid() )
6222 {
6223 QgsRectangle rect = QgsProcessingParameters::parameterAsExtent( extentParam, extentParam->defaultValueForGui(), context );
6224 QgsCoordinateReferenceSystem crs = QgsProcessingParameters::parameterAsExtentCrs( extentParam, extentParam->defaultValueForGui(), context );
6225 mDefaultWidget->setCurrentExtent( rect, crs );
6226 mDefaultWidget->setOutputExtentFromCurrent();
6227 }
6228 else
6229 {
6230 mDefaultWidget->clear();
6231 }
6232 }
6233
6234 vlayout->addWidget( mDefaultWidget );
6235 setLayout( vlayout );
6236}
6237
6238QgsProcessingParameterDefinition *QgsProcessingExtentParameterDefinitionWidget::createParameter( const QString &name, const QString &description, Qgis::ProcessingParameterFlags flags ) const
6239{
6240 const QString defaultVal = mDefaultWidget->isValid() ? u"%1,%2,%3,%4%5"_s.arg( QString::number( mDefaultWidget->outputExtent().xMinimum(), 'f', 9 ), QString::number( mDefaultWidget->outputExtent().xMaximum(), 'f', 9 ), QString::number( mDefaultWidget->outputExtent().yMinimum(), 'f', 9 ), QString::number( mDefaultWidget->outputExtent().yMaximum(), 'f', 9 ), mDefaultWidget->outputCrs().isValid() ? u" [%1]"_s.arg( mDefaultWidget->outputCrs().authid() ) : QString() ) : QString();
6241 auto param = std::make_unique<QgsProcessingParameterExtent>( name, description, !defaultVal.isEmpty() ? QVariant( defaultVal ) : QVariant() );
6242 param->setFlags( flags );
6243 return param.release();
6244}
6245
6246
6247QgsProcessingExtentWidgetWrapper::QgsProcessingExtentWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type, QWidget *parent )
6248 : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
6249{
6250}
6251
6252QWidget *QgsProcessingExtentWidgetWrapper::createWidget()
6253{
6254 const QgsProcessingParameterExtent *extentParam = dynamic_cast<const QgsProcessingParameterExtent *>( parameterDefinition() );
6255 if ( !extentParam )
6256 return nullptr;
6257
6258 switch ( type() )
6259 {
6263 {
6264 mExtentWidget = new QgsExtentWidget( nullptr );
6265 if ( widgetContext().mapCanvas() )
6266 mExtentWidget->setMapCanvas( widgetContext().mapCanvas() );
6267
6268 if ( extentParam->flags() & Qgis::ProcessingParameterFlag::Optional )
6269 mExtentWidget->setNullValueAllowed( true, tr( "Not set" ) );
6270
6271 mExtentWidget->setToolTip( parameterDefinition()->toolTip() );
6272
6273 connect( mExtentWidget, &QgsExtentWidget::extentChanged, this, [this] {
6274 emit widgetValueHasChanged( this );
6275 } );
6276
6277 if ( mDialog && type() != Qgis::ProcessingMode::Modeler )
6278 setDialog( mDialog ); // setup connections to panel - dialog was previously set before the widget was created
6279
6280 return mExtentWidget;
6281 }
6282 }
6283 return nullptr;
6284}
6285
6286void QgsProcessingExtentWidgetWrapper::setWidgetContext( const QgsProcessingParameterWidgetContext &context )
6287{
6289 if ( mExtentWidget && context.mapCanvas() && type() != Qgis::ProcessingMode::Modeler )
6290 mExtentWidget->setMapCanvas( context.mapCanvas() );
6291}
6292
6293void QgsProcessingExtentWidgetWrapper::setDialog( QDialog *dialog )
6294{
6295 mDialog = dialog;
6296 if ( mExtentWidget && mDialog && type() != Qgis::ProcessingMode::Modeler )
6297 {
6298 connect( mExtentWidget, &QgsExtentWidget::toggleDialogVisibility, mDialog, [this]( bool visible ) {
6299 if ( !visible )
6300 mDialog->showMinimized();
6301 else
6302 {
6303 mDialog->showNormal();
6304 mDialog->raise();
6305 mDialog->activateWindow();
6306 }
6307 } );
6308 }
6310}
6311
6312void QgsProcessingExtentWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
6313{
6314 if ( mExtentWidget )
6315 {
6316 if ( !value.isValid() || ( value.userType() == QMetaType::Type::QString && value.toString().isEmpty() ) )
6317 mExtentWidget->clear();
6318 else
6319 {
6320 QgsRectangle r = QgsProcessingParameters::parameterAsExtent( parameterDefinition(), value, context );
6321 QgsCoordinateReferenceSystem crs = QgsProcessingParameters::parameterAsPointCrs( parameterDefinition(), value, context );
6322 mExtentWidget->setCurrentExtent( r, crs );
6323 mExtentWidget->setOutputExtentFromUser( r, crs );
6324 }
6325 }
6326}
6327
6328QVariant QgsProcessingExtentWidgetWrapper::widgetValue() const
6329{
6330 if ( mExtentWidget )
6331 {
6332 const QString val = mExtentWidget->isValid() ? u"%1,%2,%3,%4%5"_s.arg( QString::number( mExtentWidget->outputExtent().xMinimum(), 'f', 9 ), QString::number( mExtentWidget->outputExtent().xMaximum(), 'f', 9 ), QString::number( mExtentWidget->outputExtent().yMinimum(), 'f', 9 ), QString::number( mExtentWidget->outputExtent().yMaximum(), 'f', 9 ), mExtentWidget->outputCrs().isValid() ? u" [%1]"_s.arg( mExtentWidget->outputCrs().authid() ) : QString() ) : QString();
6333
6334 return val.isEmpty() ? QVariant() : QVariant( val );
6335 }
6336 else
6337 return QVariant();
6338}
6339
6340QString QgsProcessingExtentWidgetWrapper::modelerExpressionFormatString() const
6341{
6342 return tr( "string of the format 'x min,x max,y min,y max' or a geometry value (bounding box is used)" );
6343}
6344
6345QString QgsProcessingExtentWidgetWrapper::parameterType() const
6346{
6348}
6349
6350QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingExtentWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type )
6351{
6352 return new QgsProcessingExtentWidgetWrapper( parameter, type );
6353}
6354
6355QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingExtentWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
6356{
6357 return new QgsProcessingExtentParameterDefinitionWidget( context, widgetContext, definition, algorithm );
6358}
6359
6360
6361//
6362// QgsProcessingMapLayerWidgetWrapper
6363//
6364
6365QgsProcessingMapLayerParameterDefinitionWidget::QgsProcessingMapLayerParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
6366 : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
6367{
6368 QVBoxLayout *vlayout = new QVBoxLayout();
6369 vlayout->setContentsMargins( 0, 0, 0, 0 );
6370
6371 vlayout->addWidget( new QLabel( tr( "Layer type" ) ) );
6372 mLayerTypeComboBox = new QgsCheckableComboBox();
6373 mLayerTypeComboBox->addItem( tr( "Any Map Layer" ), static_cast<int>( Qgis::ProcessingSourceType::MapLayer ) );
6374 mLayerTypeComboBox->addItem( tr( "Vector (Point)" ), static_cast<int>( Qgis::ProcessingSourceType::VectorPoint ) );
6375 mLayerTypeComboBox->addItem( tr( "Vector (Line)" ), static_cast<int>( Qgis::ProcessingSourceType::VectorLine ) );
6376 mLayerTypeComboBox->addItem( tr( "Vector (Polygon)" ), static_cast<int>( Qgis::ProcessingSourceType::VectorPolygon ) );
6377 mLayerTypeComboBox->addItem( tr( "Vector (Any Geometry Type)" ), static_cast<int>( Qgis::ProcessingSourceType::VectorAnyGeometry ) );
6378 mLayerTypeComboBox->addItem( tr( "Vector (No Geometry Required)" ), static_cast<int>( Qgis::ProcessingSourceType::Vector ) );
6379 mLayerTypeComboBox->addItem( tr( "Raster" ), static_cast<int>( Qgis::ProcessingSourceType::Raster ) );
6380 mLayerTypeComboBox->addItem( tr( "Mesh" ), static_cast<int>( Qgis::ProcessingSourceType::Mesh ) );
6381 mLayerTypeComboBox->addItem( tr( "Plugin" ), static_cast<int>( Qgis::ProcessingSourceType::Plugin ) );
6382 mLayerTypeComboBox->addItem( tr( "Point Cloud" ), static_cast<int>( Qgis::ProcessingSourceType::PointCloud ) );
6383 mLayerTypeComboBox->addItem( tr( "Annotation" ), static_cast<int>( Qgis::ProcessingSourceType::Annotation ) );
6384
6385 if ( const QgsProcessingParameterMapLayer *layerParam = dynamic_cast<const QgsProcessingParameterMapLayer *>( definition ) )
6386 {
6387 for ( int i : layerParam->dataTypes() )
6388 {
6389 mLayerTypeComboBox->setItemCheckState( mLayerTypeComboBox->findData( i ), Qt::Checked );
6390 }
6391 }
6392
6393 vlayout->addWidget( mLayerTypeComboBox );
6394
6395 setLayout( vlayout );
6396}
6397
6398QgsProcessingParameterDefinition *QgsProcessingMapLayerParameterDefinitionWidget::createParameter( const QString &name, const QString &description, Qgis::ProcessingParameterFlags flags ) const
6399{
6400 QList<int> dataTypes;
6401 for ( const QVariant &v : mLayerTypeComboBox->checkedItemsData() )
6402 dataTypes << v.toInt();
6403
6404 auto param = std::make_unique<QgsProcessingParameterMapLayer>( name, description );
6405 param->setDataTypes( dataTypes );
6406 param->setFlags( flags );
6407 return param.release();
6408}
6409
6410QgsProcessingMapLayerWidgetWrapper::QgsProcessingMapLayerWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type, QWidget *parent )
6411 : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
6412{
6413}
6414
6415QWidget *QgsProcessingMapLayerWidgetWrapper::createWidget()
6416{
6417 mComboBox = new QgsProcessingMapLayerComboBox( parameterDefinition(), type() );
6418
6419 switch ( type() )
6420 {
6423 break;
6425 mComboBox->setEditable( true );
6426 break;
6427 }
6428
6429 mComboBox->setToolTip( parameterDefinition()->toolTip() );
6430
6431 connect( mComboBox, &QgsProcessingMapLayerComboBox::valueChanged, this, [this]() {
6432 if ( mBlockSignals )
6433 return;
6434
6435 emit widgetValueHasChanged( this );
6436 } );
6437
6438 setWidgetContext( widgetContext() );
6439 return mComboBox;
6440}
6441
6442void QgsProcessingMapLayerWidgetWrapper::setWidgetContext( const QgsProcessingParameterWidgetContext &context )
6443{
6445 if ( mComboBox )
6446 {
6447 mComboBox->setWidgetContext( context );
6448
6449 if ( !( parameterDefinition()->flags() & Qgis::ProcessingParameterFlag::Optional ) )
6450 {
6451 // non optional parameter -- if no default value set, default to active layer
6452 if ( !parameterDefinition()->defaultValueForGui().isValid() )
6453 mComboBox->setLayer( context.activeLayer() );
6454 }
6455 }
6456}
6457
6458void QgsProcessingMapLayerWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
6459{
6460 if ( mComboBox )
6461 mComboBox->setValue( value, context );
6462}
6463
6464QVariant QgsProcessingMapLayerWidgetWrapper::widgetValue() const
6465{
6466 return mComboBox ? mComboBox->value() : QVariant();
6467}
6468
6469QString QgsProcessingMapLayerWidgetWrapper::modelerExpressionFormatString() const
6470{
6471 return tr( "path to a map layer" );
6472}
6473
6474Qgis::ProcessingModelChildParameterSource QgsProcessingMapLayerWidgetWrapper::defaultModelSource( const QgsProcessingParameterDefinition *parameter ) const
6475{
6476 // non-optional layer sources default to a matching model input layer, but optional layer parameters
6477 // should default to static values. We don't want all optional layer parameters to have values set by default!
6478 if ( !( parameter->flags() & Qgis::ProcessingParameterFlag::Optional ) )
6479 {
6481 }
6482 else
6483 {
6485 }
6486}
6487
6488QString QgsProcessingMapLayerWidgetWrapper::parameterType() const
6489{
6491}
6492
6493QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingMapLayerWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type )
6494{
6495 return new QgsProcessingMapLayerWidgetWrapper( parameter, type );
6496}
6497
6498QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingMapLayerWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
6499{
6500 return new QgsProcessingMapLayerParameterDefinitionWidget( context, widgetContext, definition, algorithm );
6501}
6502
6503
6504//
6505// QgsProcessingRasterLayerWidgetWrapper
6506//
6507
6508QgsProcessingRasterLayerWidgetWrapper::QgsProcessingRasterLayerWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type, QWidget *parent )
6509 : QgsProcessingMapLayerWidgetWrapper( parameter, type, parent )
6510{
6511}
6512
6513QString QgsProcessingRasterLayerWidgetWrapper::modelerExpressionFormatString() const
6514{
6515 return tr( "path to a raster layer" );
6516}
6517
6518QString QgsProcessingRasterLayerWidgetWrapper::parameterType() const
6519{
6521}
6522
6523QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingRasterLayerWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type )
6524{
6525 return new QgsProcessingRasterLayerWidgetWrapper( parameter, type );
6526}
6527
6528QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingRasterLayerWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
6529{
6530 Q_UNUSED( context );
6531 Q_UNUSED( widgetContext );
6532 Q_UNUSED( definition );
6533 Q_UNUSED( algorithm );
6534
6535 return nullptr;
6536}
6537
6538
6539//
6540// QgsProcessingVectorLayerWidgetWrapper
6541//
6542
6543QgsProcessingVectorLayerParameterDefinitionWidget::QgsProcessingVectorLayerParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
6544 : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
6545{
6546 QVBoxLayout *vlayout = new QVBoxLayout();
6547 vlayout->setContentsMargins( 0, 0, 0, 0 );
6548
6549 vlayout->addWidget( new QLabel( tr( "Geometry type" ) ) );
6550 mGeometryTypeComboBox = new QgsCheckableComboBox();
6551 mGeometryTypeComboBox->addItem( tr( "Geometry Not Required" ), static_cast<int>( Qgis::ProcessingSourceType::Vector ) );
6552 mGeometryTypeComboBox->addItem( tr( "Point" ), static_cast<int>( Qgis::ProcessingSourceType::VectorPoint ) );
6553 mGeometryTypeComboBox->addItem( tr( "Line" ), static_cast<int>( Qgis::ProcessingSourceType::VectorLine ) );
6554 mGeometryTypeComboBox->addItem( tr( "Polygon" ), static_cast<int>( Qgis::ProcessingSourceType::VectorPolygon ) );
6555 mGeometryTypeComboBox->addItem( tr( "Any Geometry Type" ), static_cast<int>( Qgis::ProcessingSourceType::VectorAnyGeometry ) );
6556
6557 if ( const QgsProcessingParameterVectorLayer *vectorParam = dynamic_cast<const QgsProcessingParameterVectorLayer *>( definition ) )
6558 {
6559 for ( int i : vectorParam->dataTypes() )
6560 {
6561 mGeometryTypeComboBox->setItemCheckState( mGeometryTypeComboBox->findData( i ), Qt::Checked );
6562 }
6563 }
6564
6565 vlayout->addWidget( mGeometryTypeComboBox );
6566
6567 setLayout( vlayout );
6568}
6569
6570QgsProcessingParameterDefinition *QgsProcessingVectorLayerParameterDefinitionWidget::createParameter( const QString &name, const QString &description, Qgis::ProcessingParameterFlags flags ) const
6571{
6572 QList<int> dataTypes;
6573 for ( const QVariant &v : mGeometryTypeComboBox->checkedItemsData() )
6574 dataTypes << v.toInt();
6575
6576 auto param = std::make_unique<QgsProcessingParameterVectorLayer>( name, description, dataTypes );
6577 param->setFlags( flags );
6578 return param.release();
6579}
6580
6581
6582QgsProcessingVectorLayerWidgetWrapper::QgsProcessingVectorLayerWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type, QWidget *parent )
6583 : QgsProcessingMapLayerWidgetWrapper( parameter, type, parent )
6584{
6585}
6586
6587QString QgsProcessingVectorLayerWidgetWrapper::modelerExpressionFormatString() const
6588{
6589 return tr( "path to a vector layer" );
6590}
6591
6592QString QgsProcessingVectorLayerWidgetWrapper::parameterType() const
6593{
6595}
6596
6597QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingVectorLayerWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type )
6598{
6599 return new QgsProcessingVectorLayerWidgetWrapper( parameter, type );
6600}
6601
6602QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingVectorLayerWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
6603{
6604 return new QgsProcessingVectorLayerParameterDefinitionWidget( context, widgetContext, definition, algorithm );
6605}
6606
6607
6608//
6609// QgsProcessingFeatureSourceLayerWidgetWrapper
6610//
6611
6612QgsProcessingFeatureSourceParameterDefinitionWidget::QgsProcessingFeatureSourceParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
6613 : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
6614{
6615 QVBoxLayout *vlayout = new QVBoxLayout();
6616 vlayout->setContentsMargins( 0, 0, 0, 0 );
6617
6618 vlayout->addWidget( new QLabel( tr( "Geometry type" ) ) );
6619 mGeometryTypeComboBox = new QgsCheckableComboBox();
6620 mGeometryTypeComboBox->addItem( tr( "Geometry Not Required" ), static_cast<int>( Qgis::ProcessingSourceType::Vector ) );
6621 mGeometryTypeComboBox->addItem( tr( "Point" ), static_cast<int>( Qgis::ProcessingSourceType::VectorPoint ) );
6622 mGeometryTypeComboBox->addItem( tr( "Line" ), static_cast<int>( Qgis::ProcessingSourceType::VectorLine ) );
6623 mGeometryTypeComboBox->addItem( tr( "Polygon" ), static_cast<int>( Qgis::ProcessingSourceType::VectorPolygon ) );
6624 mGeometryTypeComboBox->addItem( tr( "Any Geometry Type" ), static_cast<int>( Qgis::ProcessingSourceType::VectorAnyGeometry ) );
6625
6626 if ( const QgsProcessingParameterFeatureSource *sourceParam = dynamic_cast<const QgsProcessingParameterFeatureSource *>( definition ) )
6627 {
6628 for ( int i : sourceParam->dataTypes() )
6629 {
6630 mGeometryTypeComboBox->setItemCheckState( mGeometryTypeComboBox->findData( i ), Qt::Checked );
6631 }
6632 }
6633 else
6634 {
6635 mGeometryTypeComboBox->setItemCheckState( mGeometryTypeComboBox->findData( static_cast<int>( Qgis::ProcessingSourceType::VectorAnyGeometry ) ), Qt::Checked );
6636 }
6637
6638 vlayout->addWidget( mGeometryTypeComboBox );
6639
6640 setLayout( vlayout );
6641}
6642
6643QgsProcessingParameterDefinition *QgsProcessingFeatureSourceParameterDefinitionWidget::createParameter( const QString &name, const QString &description, Qgis::ProcessingParameterFlags flags ) const
6644{
6645 QList<int> dataTypes;
6646 for ( const QVariant &v : mGeometryTypeComboBox->checkedItemsData() )
6647 dataTypes << v.toInt();
6648
6649 auto param = std::make_unique<QgsProcessingParameterFeatureSource>( name, description, dataTypes );
6650 param->setFlags( flags );
6651 return param.release();
6652}
6653
6654QgsProcessingFeatureSourceWidgetWrapper::QgsProcessingFeatureSourceWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type, QWidget *parent )
6655 : QgsProcessingMapLayerWidgetWrapper( parameter, type, parent )
6656{
6657}
6658
6659QString QgsProcessingFeatureSourceWidgetWrapper::modelerExpressionFormatString() const
6660{
6661 return tr( "path to a vector layer" );
6662}
6663
6664QString QgsProcessingFeatureSourceWidgetWrapper::parameterType() const
6665{
6667}
6668
6669QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingFeatureSourceWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type )
6670{
6671 return new QgsProcessingFeatureSourceWidgetWrapper( parameter, type );
6672}
6673
6674QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingFeatureSourceWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
6675{
6676 return new QgsProcessingFeatureSourceParameterDefinitionWidget( context, widgetContext, definition, algorithm );
6677}
6678
6679//
6680// QgsProcessingMeshLayerWidgetWrapper
6681//
6682
6683QgsProcessingMeshLayerWidgetWrapper::QgsProcessingMeshLayerWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type, QWidget *parent )
6684 : QgsProcessingMapLayerWidgetWrapper( parameter, type, parent )
6685{
6686}
6687
6688QString QgsProcessingMeshLayerWidgetWrapper::modelerExpressionFormatString() const
6689{
6690 return tr( "path to a mesh layer" );
6691}
6692
6693QString QgsProcessingMeshLayerWidgetWrapper::parameterType() const
6694{
6696}
6697
6698QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingMeshLayerWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type )
6699{
6700 return new QgsProcessingMeshLayerWidgetWrapper( parameter, type );
6701}
6702
6703QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingMeshLayerWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
6704{
6705 Q_UNUSED( context );
6706 Q_UNUSED( widgetContext );
6707 Q_UNUSED( definition );
6708 Q_UNUSED( algorithm );
6709
6710 return nullptr;
6711}
6712
6713
6714//
6715// QgsProcessingRasterBandPanelWidget
6716//
6717
6718QgsProcessingRasterBandPanelWidget::QgsProcessingRasterBandPanelWidget( QWidget *parent, const QgsProcessingParameterBand *param )
6719 : QWidget( parent )
6720 , mParam( param )
6721{
6722 QHBoxLayout *hl = new QHBoxLayout();
6723 hl->setContentsMargins( 0, 0, 0, 0 );
6724
6725 mLineEdit = new QLineEdit();
6726 mLineEdit->setEnabled( false );
6727 hl->addWidget( mLineEdit, 1 );
6728
6729 mToolButton = new QToolButton();
6730 mToolButton->setText( QString( QChar( 0x2026 ) ) );
6731 hl->addWidget( mToolButton );
6732
6733 setLayout( hl );
6734
6735 if ( mParam )
6736 {
6737 mLineEdit->setText( tr( "%n band(s) selected", nullptr, 0 ) );
6738 }
6739
6740 connect( mToolButton, &QToolButton::clicked, this, &QgsProcessingRasterBandPanelWidget::showDialog );
6741}
6742
6743void QgsProcessingRasterBandPanelWidget::setBands( const QList<int> &bands )
6744{
6745 mBands = bands;
6746}
6747
6748void QgsProcessingRasterBandPanelWidget::setBandNames( const QHash<int, QString> &names )
6749{
6750 mBandNames = names;
6751}
6752
6753void QgsProcessingRasterBandPanelWidget::setValue( const QVariant &value )
6754{
6755 if ( value.isValid() )
6756 mValue = value.userType() == QMetaType::Type::QVariantList ? value.toList() : QVariantList() << value;
6757 else
6758 mValue.clear();
6759
6760 updateSummaryText();
6761 emit changed();
6762}
6763
6764void QgsProcessingRasterBandPanelWidget::showDialog()
6765{
6766 QVariantList availableOptions;
6767 availableOptions.reserve( mBands.size() );
6768 for ( int band : std::as_const( mBands ) )
6769 {
6770 availableOptions << band;
6771 }
6772
6774 if ( panel && panel->dockMode() )
6775 {
6776 QgsProcessingMultipleSelectionPanelWidget *widget = new QgsProcessingMultipleSelectionPanelWidget( availableOptions, mValue );
6777 widget->setPanelTitle( mParam->description() );
6778
6779 widget->setValueFormatter( [this]( const QVariant &v ) -> QString {
6780 int band = v.toInt();
6781 return mBandNames.contains( band ) ? mBandNames.value( band ) : v.toString();
6782 } );
6783
6784 connect( widget, &QgsProcessingMultipleSelectionPanelWidget::selectionChanged, this, [this, widget]() {
6785 setValue( widget->selectedOptions() );
6786 } );
6787 connect( widget, &QgsProcessingMultipleSelectionPanelWidget::acceptClicked, widget, &QgsPanelWidget::acceptPanel );
6788 panel->openPanel( widget );
6789 }
6790 else
6791 {
6792 QgsProcessingMultipleSelectionDialog dlg( availableOptions, mValue, this, Qt::WindowFlags() );
6793
6794 dlg.setValueFormatter( [this]( const QVariant &v ) -> QString {
6795 int band = v.toInt();
6796 return mBandNames.contains( band ) ? mBandNames.value( band ) : v.toString();
6797 } );
6798 if ( dlg.exec() )
6799 {
6800 setValue( dlg.selectedOptions() );
6801 }
6802 }
6803}
6804
6805void QgsProcessingRasterBandPanelWidget::updateSummaryText()
6806{
6807 if ( mParam )
6808 mLineEdit->setText( tr( "%n band(s) selected", nullptr, mValue.count() ) );
6809}
6810
6811
6812//
6813// QgsProcessingBandWidgetWrapper
6814//
6815
6816QgsProcessingBandParameterDefinitionWidget::QgsProcessingBandParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
6817 : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
6818{
6819 QVBoxLayout *vlayout = new QVBoxLayout();
6820 vlayout->setContentsMargins( 0, 0, 0, 0 );
6821
6822 vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
6823
6824 mDefaultLineEdit = new QLineEdit();
6825 mDefaultLineEdit->setToolTip( tr( "Band number (separate bands with ; for multiple band parameters)" ) );
6826 if ( const QgsProcessingParameterBand *bandParam = dynamic_cast<const QgsProcessingParameterBand *>( definition ) )
6827 {
6828 const QList<int> bands = QgsProcessingParameters::parameterAsInts( bandParam, bandParam->defaultValueForGui(), context );
6829 QStringList defVal;
6830 for ( int b : bands )
6831 {
6832 defVal << QString::number( b );
6833 }
6834
6835 mDefaultLineEdit->setText( defVal.join( ';' ) );
6836 }
6837 vlayout->addWidget( mDefaultLineEdit );
6838
6839 vlayout->addWidget( new QLabel( tr( "Parent layer" ) ) );
6840 mParentLayerComboBox = new QComboBox();
6841
6842 QString initialParent;
6843 if ( const QgsProcessingParameterBand *bandParam = dynamic_cast<const QgsProcessingParameterBand *>( definition ) )
6844 initialParent = bandParam->parentLayerParameterName();
6845
6846 if ( auto *lModel = widgetContext.model() )
6847 {
6848 // populate combo box with other model input choices
6849 const QMap<QString, QgsProcessingModelParameter> components = lModel->parameterComponents();
6850 for ( auto it = components.constBegin(); it != components.constEnd(); ++it )
6851 {
6852 if ( const QgsProcessingParameterRasterLayer *definition = dynamic_cast<const QgsProcessingParameterRasterLayer *>( lModel->parameterDefinition( it.value().parameterName() ) ) )
6853 {
6854 mParentLayerComboBox->addItem( definition->description(), definition->name() );
6855 if ( !initialParent.isEmpty() && initialParent == definition->name() )
6856 {
6857 mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
6858 }
6859 }
6860 }
6861 }
6862
6863 if ( mParentLayerComboBox->count() == 0 && !initialParent.isEmpty() )
6864 {
6865 // if no parent candidates found, we just add the existing one as a placeholder
6866 mParentLayerComboBox->addItem( initialParent, initialParent );
6867 mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
6868 }
6869
6870 vlayout->addWidget( mParentLayerComboBox );
6871
6872 mAllowMultipleCheckBox = new QCheckBox( tr( "Allow multiple" ) );
6873 if ( const QgsProcessingParameterBand *bandParam = dynamic_cast<const QgsProcessingParameterBand *>( definition ) )
6874 mAllowMultipleCheckBox->setChecked( bandParam->allowMultiple() );
6875
6876 vlayout->addWidget( mAllowMultipleCheckBox );
6877 setLayout( vlayout );
6878}
6879
6880QgsProcessingParameterDefinition *QgsProcessingBandParameterDefinitionWidget::createParameter( const QString &name, const QString &description, Qgis::ProcessingParameterFlags flags ) const
6881{
6882 auto param = std::make_unique<QgsProcessingParameterBand>( name, description, mDefaultLineEdit->text().split( ';' ), mParentLayerComboBox->currentData().toString(), false, mAllowMultipleCheckBox->isChecked() );
6883 param->setFlags( flags );
6884 return param.release();
6885}
6886
6887QgsProcessingBandWidgetWrapper::QgsProcessingBandWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type, QWidget *parent )
6888 : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
6889{
6890}
6891
6892QWidget *QgsProcessingBandWidgetWrapper::createWidget()
6893{
6894 const QgsProcessingParameterBand *bandParam = dynamic_cast<const QgsProcessingParameterBand *>( parameterDefinition() );
6895 if ( !bandParam )
6896 return nullptr;
6897
6898 switch ( type() )
6899 {
6902 {
6903 if ( bandParam->allowMultiple() )
6904 {
6905 mPanel = new QgsProcessingRasterBandPanelWidget( nullptr, bandParam );
6906 mPanel->setToolTip( parameterDefinition()->toolTip() );
6907 connect( mPanel, &QgsProcessingRasterBandPanelWidget::changed, this, [this] {
6908 emit widgetValueHasChanged( this );
6909 } );
6910 return mPanel;
6911 }
6912 else
6913 {
6914 mComboBox = new QgsRasterBandComboBox();
6915 mComboBox->setShowNotSetOption( bandParam->flags() & Qgis::ProcessingParameterFlag::Optional );
6916
6917 mComboBox->setToolTip( parameterDefinition()->toolTip() );
6918 connect( mComboBox, &QgsRasterBandComboBox::bandChanged, this, [this]( int ) {
6919 emit widgetValueHasChanged( this );
6920 } );
6921 return mComboBox;
6922 }
6923 }
6924
6926 {
6927 mLineEdit = new QLineEdit();
6928 mLineEdit->setToolTip( QObject::tr( "Band number (separate bands with ; for multiple band parameters)" ) );
6929 connect( mLineEdit, &QLineEdit::textChanged, this, [this] {
6930 emit widgetValueHasChanged( this );
6931 } );
6932 return mLineEdit;
6933 }
6934 }
6935 return nullptr;
6936}
6937
6938void QgsProcessingBandWidgetWrapper::postInitialize( const QList<QgsAbstractProcessingParameterWidgetWrapper *> &wrappers )
6939{
6941 switch ( type() )
6942 {
6945 {
6946 for ( const QgsAbstractProcessingParameterWidgetWrapper *wrapper : wrappers )
6947 {
6948 if ( wrapper->parameterDefinition()->name() == static_cast<const QgsProcessingParameterBand *>( parameterDefinition() )->parentLayerParameterName() )
6949 {
6950 setParentLayerWrapperValue( wrapper );
6951 connect( wrapper, &QgsAbstractProcessingParameterWidgetWrapper::widgetValueHasChanged, this, [this, wrapper] {
6952 setParentLayerWrapperValue( wrapper );
6953 } );
6954 break;
6955 }
6956 }
6957 break;
6958 }
6959
6961 break;
6962 }
6963}
6964
6965void QgsProcessingBandWidgetWrapper::setParentLayerWrapperValue( const QgsAbstractProcessingParameterWidgetWrapper *parentWrapper )
6966{
6967 // evaluate value to layer
6968 QgsProcessingContext *context = nullptr;
6969 std::unique_ptr<QgsProcessingContext> tmpContext;
6970 if ( mProcessingContextGenerator )
6971 context = mProcessingContextGenerator->processingContext();
6972
6973 if ( !context )
6974 {
6975 tmpContext = std::make_unique<QgsProcessingContext>();
6976 context = tmpContext.get();
6977 }
6978
6979 QVariant value = parentWrapper->parameterValue();
6980
6981 QgsRasterLayer *layer = QgsProcessingParameters::parameterAsRasterLayer( parentWrapper->parameterDefinition(), value, *context );
6982 if ( layer && layer->isValid() )
6983 {
6984 // need to grab ownership of layer if required - otherwise layer may be deleted when context
6985 // goes out of scope
6986 std::unique_ptr<QgsMapLayer> ownedLayer( context->takeResultLayer( layer->id() ) );
6987 if ( ownedLayer && ownedLayer->type() == Qgis::LayerType::Raster )
6988 {
6989 mParentLayer.reset( qobject_cast<QgsRasterLayer *>( ownedLayer.release() ) );
6990 layer = mParentLayer.get();
6991 }
6992 else
6993 {
6994 // don't need ownership of this layer - it wasn't owned by context (so e.g. is owned by the project)
6995 }
6996
6997 if ( mComboBox )
6998 mComboBox->setLayer( layer );
6999 else if ( mPanel )
7000 {
7001 QgsRasterDataProvider *provider = layer->dataProvider();
7002 if ( provider && layer->isValid() )
7003 {
7004 //fill available bands
7005 int nBands = provider->bandCount();
7006 QList<int> bands;
7007 QHash<int, QString> bandNames;
7008 for ( int i = 1; i <= nBands; ++i )
7009 {
7010 bandNames.insert( i, QgsRasterBandComboBox::displayBandName( provider, i ) );
7011 bands << i;
7012 }
7013 mPanel->setBands( bands );
7014 mPanel->setBandNames( bandNames );
7015 }
7016 }
7017 }
7018 else
7019 {
7020 if ( mComboBox )
7021 mComboBox->setLayer( nullptr );
7022 else if ( mPanel )
7023 mPanel->setBands( QList<int>() );
7024
7025 if ( value.isValid() && widgetContext().messageBar() )
7026 {
7027 widgetContext().messageBar()->clearWidgets();
7028 widgetContext().messageBar()->pushMessage( QString(), QObject::tr( "Could not load selected layer/table. Dependent bands could not be populated" ), Qgis::MessageLevel::Info );
7029 }
7030 }
7031
7032 if ( parameterDefinition()->defaultValueForGui().isValid() )
7033 setWidgetValue( parameterDefinition()->defaultValueForGui(), *context );
7034}
7035
7036void QgsProcessingBandWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
7037{
7038 if ( mComboBox )
7039 {
7040 if ( !value.isValid() )
7041 mComboBox->setBand( -1 );
7042 else
7043 {
7044 const int v = QgsProcessingParameters::parameterAsInt( parameterDefinition(), value, context );
7045 mComboBox->setBand( v );
7046 }
7047 }
7048 else if ( mPanel )
7049 {
7050 QVariantList opts;
7051 if ( value.isValid() )
7052 {
7053 const QList<int> v = QgsProcessingParameters::parameterAsInts( parameterDefinition(), value, context );
7054 opts.reserve( v.size() );
7055 for ( int i : v )
7056 opts << i;
7057 }
7058 if ( mPanel )
7059 mPanel->setValue( value.isValid() ? opts : QVariant() );
7060 }
7061 else if ( mLineEdit )
7062 {
7063 const QgsProcessingParameterBand *bandParam = static_cast<const QgsProcessingParameterBand *>( parameterDefinition() );
7064 if ( bandParam->allowMultiple() )
7065 {
7066 const QList<int> v = QgsProcessingParameters::parameterAsInts( parameterDefinition(), value, context );
7067 QStringList opts;
7068 opts.reserve( v.size() );
7069 for ( int i : v )
7070 opts << QString::number( i );
7071 mLineEdit->setText( value.isValid() && !opts.empty() ? opts.join( ';' ) : QString() );
7072 }
7073 else
7074 {
7075 if ( value.isValid() )
7076 mLineEdit->setText( QString::number( QgsProcessingParameters::parameterAsInt( parameterDefinition(), value, context ) ) );
7077 else
7078 mLineEdit->clear();
7079 }
7080 }
7081}
7082
7083QVariant QgsProcessingBandWidgetWrapper::widgetValue() const
7084{
7085 if ( mComboBox )
7086 return mComboBox->currentBand() == -1 ? QVariant() : mComboBox->currentBand();
7087 else if ( mPanel )
7088 return !mPanel->value().toList().isEmpty() ? mPanel->value() : QVariant();
7089 else if ( mLineEdit )
7090 {
7091 const QgsProcessingParameterBand *bandParam = static_cast<const QgsProcessingParameterBand *>( parameterDefinition() );
7092 if ( bandParam->allowMultiple() )
7093 {
7094 const QStringList parts = mLineEdit->text().split( ';', Qt::SkipEmptyParts );
7095 QVariantList res;
7096 res.reserve( parts.count() );
7097 for ( const QString &s : parts )
7098 {
7099 bool ok = false;
7100 int band = s.toInt( &ok );
7101 if ( ok )
7102 res << band;
7103 }
7104 return res.isEmpty() ? QVariant() : res;
7105 }
7106 else
7107 {
7108 return mLineEdit->text().isEmpty() ? QVariant() : mLineEdit->text();
7109 }
7110 }
7111 else
7112 return QVariant();
7113}
7114
7115QString QgsProcessingBandWidgetWrapper::modelerExpressionFormatString() const
7116{
7117 return tr( "selected band numbers as an array of numbers, or semicolon separated string of options (e.g. '1;3')" );
7118}
7119
7120QString QgsProcessingBandWidgetWrapper::parameterType() const
7121{
7123}
7124
7125QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingBandWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type )
7126{
7127 return new QgsProcessingBandWidgetWrapper( parameter, type );
7128}
7129
7130QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingBandWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
7131{
7132 return new QgsProcessingBandParameterDefinitionWidget( context, widgetContext, definition, algorithm );
7133}
7134
7135//
7136// QgsProcessingMultipleLayerLineEdit
7137//
7138
7139QgsProcessingMultipleLayerLineEdit::QgsProcessingMultipleLayerLineEdit( QWidget *parent, const QgsProcessingParameterMultipleLayers *param )
7140 : QgsHighlightableLineEdit( parent )
7141 , mParam( param )
7142{
7143 setAcceptDrops( true );
7144}
7145
7146void QgsProcessingMultipleLayerLineEdit::dragEnterEvent( QDragEnterEvent *event )
7147{
7148 const QStringList uris = QgsProcessingMultipleInputPanelWidget::compatibleUrisFromMimeData( mParam, event->mimeData(), {} );
7149 if ( !uris.isEmpty() )
7150 {
7151 event->setDropAction( Qt::CopyAction );
7152 event->accept();
7153 setHighlighted( true );
7154 }
7155 else
7156 {
7157 event->ignore();
7158 }
7159}
7160
7161void QgsProcessingMultipleLayerLineEdit::dragLeaveEvent( QDragLeaveEvent *event )
7162{
7163 QgsHighlightableLineEdit::dragLeaveEvent( event );
7164 event->accept();
7165 setHighlighted( false );
7166}
7167
7168void QgsProcessingMultipleLayerLineEdit::dropEvent( QDropEvent *event )
7169{
7170 const QStringList uris = QgsProcessingMultipleInputPanelWidget::compatibleUrisFromMimeData( mParam, event->mimeData(), {} );
7171 if ( !uris.isEmpty() )
7172 {
7173 event->setDropAction( Qt::CopyAction );
7174 event->accept();
7175 QVariantList uriList;
7176 uriList.reserve( uris.size() );
7177 for ( const QString &uri : uris )
7178 uriList.append( QVariant( uri ) );
7179 emit layersDropped( uriList );
7180 }
7181
7182 setHighlighted( false );
7183}
7184
7185//
7186// QgsProcessingMultipleLayerPanelWidget
7187//
7188
7189QgsProcessingMultipleLayerPanelWidget::QgsProcessingMultipleLayerPanelWidget( QWidget *parent, const QgsProcessingParameterMultipleLayers *param )
7190 : QWidget( parent )
7191 , mParam( param )
7192{
7193 QHBoxLayout *hl = new QHBoxLayout();
7194 hl->setContentsMargins( 0, 0, 0, 0 );
7195
7196 mLineEdit = new QgsProcessingMultipleLayerLineEdit( nullptr, param );
7197 mLineEdit->setEnabled( true );
7198 mLineEdit->setReadOnly( true );
7199
7200 hl->addWidget( mLineEdit, 1 );
7201 connect( mLineEdit, &QgsProcessingMultipleLayerLineEdit::layersDropped, this, &QgsProcessingMultipleLayerPanelWidget::setValue );
7202
7203 mToolButton = new QToolButton();
7204 mToolButton->setText( QString( QChar( 0x2026 ) ) );
7205 hl->addWidget( mToolButton );
7206
7207 setLayout( hl );
7208
7209 if ( mParam )
7210 {
7211 mLineEdit->setText( tr( "%n input(s) selected", nullptr, 0 ) );
7212 }
7213
7214 connect( mToolButton, &QToolButton::clicked, this, &QgsProcessingMultipleLayerPanelWidget::showDialog );
7215}
7216
7217void QgsProcessingMultipleLayerPanelWidget::setValue( const QVariant &value )
7218{
7219 if ( value.isValid() )
7220 mValue = value.userType() == QMetaType::Type::QVariantList ? value.toList() : QVariantList() << value;
7221 else
7222 mValue.clear();
7223
7224 updateSummaryText();
7225 emit changed();
7226}
7227
7228void QgsProcessingMultipleLayerPanelWidget::setProject( QgsProject *project )
7229{
7230 mProject = project;
7231 if ( mProject )
7232 {
7233 connect( mProject, &QgsProject::layerRemoved, this, [&]( const QString &layerId ) {
7234 if ( mValue.removeAll( layerId ) )
7235 {
7236 updateSummaryText();
7237 emit changed();
7238 }
7239 } );
7240 }
7241}
7242
7243void QgsProcessingMultipleLayerPanelWidget::setModel( QgsProcessingModelAlgorithm *model, const QString &modelChildAlgorithmID )
7244{
7245 mModel = model;
7246 if ( !model )
7247 return;
7248
7249 switch ( mParam->layerType() )
7250 {
7252 mModelSources = model->availableSourcesForChild( modelChildAlgorithmID, QStringList() << QgsProcessingParameterFile::typeName(), QStringList() << QgsProcessingOutputFile::typeName() );
7253 break;
7254
7256 {
7258 break;
7259 }
7260
7262 {
7264 break;
7265 }
7266
7268 {
7270 break;
7271 }
7272
7274 {
7276 break;
7277 }
7278
7280 {
7281 mModelSources = model->availableSourcesForChild( modelChildAlgorithmID, QStringList() << QgsProcessingParameterAnnotationLayer::typeName() << QgsProcessingParameterMultipleLayers::typeName(), QStringList() << QgsProcessingOutputMapLayer::typeName() << QgsProcessingOutputMultipleLayers::typeName() );
7282 break;
7283 }
7284
7286 {
7287 mModelSources = model->availableSourcesForChild( modelChildAlgorithmID, QStringList() << QgsProcessingParameterMapLayer::typeName() << QgsProcessingParameterMultipleLayers::typeName(), QStringList() << QgsProcessingOutputMapLayer::typeName() << QgsProcessingOutputMultipleLayers::typeName() );
7288 break;
7289 }
7290
7292 {
7293 mModelSources = model->availableSourcesForChild( modelChildAlgorithmID, QStringList() << QgsProcessingParameterMapLayer::typeName() << QgsProcessingParameterMultipleLayers::typeName(), QStringList() << QgsProcessingOutputMapLayer::typeName() << QgsProcessingOutputMultipleLayers::typeName() );
7294 break;
7295 }
7296
7298 {
7300 break;
7301 }
7302
7304 {
7306 break;
7307 }
7308
7310 {
7312 break;
7313 }
7314
7316 {
7318 break;
7319 }
7320
7322 {
7324 break;
7325 }
7326
7328 {
7330 // << QgsProcessingOutputMeshLayer::typeName()
7332 break;
7333 }
7334 }
7335}
7336
7337void QgsProcessingMultipleLayerPanelWidget::showDialog()
7338{
7340 if ( panel && panel->dockMode() )
7341 {
7342 QgsProcessingMultipleInputPanelWidget *widget = new QgsProcessingMultipleInputPanelWidget( mParam, mValue, mModelSources, mModel, nullptr );
7343 widget->setPanelTitle( mParam->description() );
7344 widget->setProject( mProject );
7345 connect( widget, &QgsProcessingMultipleSelectionPanelWidget::selectionChanged, this, [this, widget]() {
7346 setValue( widget->selectedOptions() );
7347 } );
7348 connect( widget, &QgsProcessingMultipleSelectionPanelWidget::acceptClicked, widget, &QgsPanelWidget::acceptPanel );
7349 panel->openPanel( widget );
7350 }
7351 else
7352 {
7353 QgsProcessingMultipleInputDialog dlg( mParam, mValue, mModelSources, mModel, this, Qt::WindowFlags() );
7354 dlg.setProject( mProject );
7355 if ( dlg.exec() )
7356 {
7357 setValue( dlg.selectedOptions() );
7358 }
7359 }
7360}
7361
7362void QgsProcessingMultipleLayerPanelWidget::updateSummaryText()
7363{
7364 if ( mParam )
7365 mLineEdit->setText( tr( "%n input(s) selected", nullptr, mValue.count() ) );
7366}
7367
7368//
7369// QgsProcessingMultipleLayerWidgetWrapper
7370//
7371
7372QgsProcessingMultipleLayerParameterDefinitionWidget::QgsProcessingMultipleLayerParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
7373 : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
7374{
7375 QVBoxLayout *vlayout = new QVBoxLayout();
7376 vlayout->setContentsMargins( 0, 0, 0, 0 );
7377
7378 vlayout->addWidget( new QLabel( tr( "Allowed layer type" ) ) );
7379 mLayerTypeComboBox = new QComboBox();
7380 mLayerTypeComboBox->addItem( tr( "Any Map Layer" ), static_cast<int>( Qgis::ProcessingSourceType::MapLayer ) );
7381 mLayerTypeComboBox->addItem( tr( "Vector (No Geometry Required)" ), static_cast<int>( Qgis::ProcessingSourceType::Vector ) );
7382 mLayerTypeComboBox->addItem( tr( "Vector (Point)" ), static_cast<int>( Qgis::ProcessingSourceType::VectorPoint ) );
7383 mLayerTypeComboBox->addItem( tr( "Vector (Line)" ), static_cast<int>( Qgis::ProcessingSourceType::VectorLine ) );
7384 mLayerTypeComboBox->addItem( tr( "Vector (Polygon)" ), static_cast<int>( Qgis::ProcessingSourceType::VectorPolygon ) );
7385 mLayerTypeComboBox->addItem( tr( "Any Geometry Type" ), static_cast<int>( Qgis::ProcessingSourceType::VectorAnyGeometry ) );
7386 mLayerTypeComboBox->addItem( tr( "Raster" ), static_cast<int>( Qgis::ProcessingSourceType::Raster ) );
7387 mLayerTypeComboBox->addItem( tr( "File" ), static_cast<int>( Qgis::ProcessingSourceType::File ) );
7388 mLayerTypeComboBox->addItem( tr( "Mesh" ), static_cast<int>( Qgis::ProcessingSourceType::Mesh ) );
7389 mLayerTypeComboBox->addItem( tr( "Plugin" ), static_cast<int>( Qgis::ProcessingSourceType::Plugin ) );
7390 mLayerTypeComboBox->addItem( tr( "Point Cloud" ), static_cast<int>( Qgis::ProcessingSourceType::PointCloud ) );
7391 mLayerTypeComboBox->addItem( tr( "Annotation" ), static_cast<int>( Qgis::ProcessingSourceType::Annotation ) );
7392 if ( const QgsProcessingParameterMultipleLayers *layersParam = dynamic_cast<const QgsProcessingParameterMultipleLayers *>( definition ) )
7393 mLayerTypeComboBox->setCurrentIndex( mLayerTypeComboBox->findData( static_cast<int>( layersParam->layerType() ) ) );
7394
7395 vlayout->addWidget( mLayerTypeComboBox );
7396 setLayout( vlayout );
7397}
7398
7399QgsProcessingParameterDefinition *QgsProcessingMultipleLayerParameterDefinitionWidget::createParameter( const QString &name, const QString &description, Qgis::ProcessingParameterFlags flags ) const
7400{
7401 auto param = std::make_unique<QgsProcessingParameterMultipleLayers>( name, description, static_cast<Qgis::ProcessingSourceType>( mLayerTypeComboBox->currentData().toInt() ) );
7402 param->setFlags( flags );
7403 return param.release();
7404}
7405
7406QgsProcessingMultipleLayerWidgetWrapper::QgsProcessingMultipleLayerWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type, QWidget *parent )
7407 : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
7408{
7409}
7410
7411QWidget *QgsProcessingMultipleLayerWidgetWrapper::createWidget()
7412{
7413 const QgsProcessingParameterMultipleLayers *layerParam = dynamic_cast<const QgsProcessingParameterMultipleLayers *>( parameterDefinition() );
7414
7415 mPanel = new QgsProcessingMultipleLayerPanelWidget( nullptr, layerParam );
7416 mPanel->setToolTip( parameterDefinition()->toolTip() );
7417 mPanel->setProject( widgetContext().project() );
7418 if ( type() == Qgis::ProcessingMode::Modeler )
7419 mPanel->setModel( widgetContext().model(), widgetContext().modelChildAlgorithmId() );
7420 connect( mPanel, &QgsProcessingMultipleLayerPanelWidget::changed, this, [this] {
7421 emit widgetValueHasChanged( this );
7422 } );
7423 return mPanel;
7424}
7425
7426void QgsProcessingMultipleLayerWidgetWrapper::setWidgetContext( const QgsProcessingParameterWidgetContext &context )
7427{
7429 if ( mPanel )
7430 {
7431 mPanel->setProject( context.project() );
7432 if ( type() == Qgis::ProcessingMode::Modeler )
7433 mPanel->setModel( widgetContext().model(), widgetContext().modelChildAlgorithmId() );
7434 }
7435}
7436
7437void QgsProcessingMultipleLayerWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
7438{
7439 if ( mPanel )
7440 {
7441 QVariantList opts;
7442 if ( value.isValid() )
7443 {
7444 const QList<QgsMapLayer *> v = QgsProcessingParameters::parameterAsLayerList( parameterDefinition(), value, context );
7445 opts.reserve( v.size() );
7446 for ( const QgsMapLayer *l : v )
7447 opts << l->source();
7448 }
7449
7450 for ( const QVariant &v : value.toList() )
7451 {
7452 if ( v.userType() == qMetaTypeId<QgsProcessingModelChildParameterSource>() )
7453 {
7454 const QgsProcessingModelChildParameterSource source = v.value<QgsProcessingModelChildParameterSource>();
7455 opts << QVariant::fromValue( source );
7456 }
7457 }
7458
7459 if ( mPanel )
7460 mPanel->setValue( value.isValid() ? opts : QVariant() );
7461 }
7462}
7463
7464QVariant QgsProcessingMultipleLayerWidgetWrapper::widgetValue() const
7465{
7466 if ( mPanel )
7467 return !mPanel->value().toList().isEmpty() ? mPanel->value() : QVariant();
7468 else
7469 return QVariant();
7470}
7471
7472QString QgsProcessingMultipleLayerWidgetWrapper::modelerExpressionFormatString() const
7473{
7474 return tr( "an array of layer paths, or semicolon separated string of layer paths" );
7475}
7476
7477QString QgsProcessingMultipleLayerWidgetWrapper::parameterType() const
7478{
7480}
7481
7482QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingMultipleLayerWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type )
7483{
7484 return new QgsProcessingMultipleLayerWidgetWrapper( parameter, type );
7485}
7486
7487QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingMultipleLayerWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
7488{
7489 return new QgsProcessingMultipleLayerParameterDefinitionWidget( context, widgetContext, definition, algorithm );
7490}
7491
7492
7493//
7494// QgsProcessingPointCloudLayerWidgetWrapper
7495//
7496
7497QgsProcessingPointCloudLayerWidgetWrapper::QgsProcessingPointCloudLayerWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type, QWidget *parent )
7498 : QgsProcessingMapLayerWidgetWrapper( parameter, type, parent )
7499{
7500}
7501
7502QString QgsProcessingPointCloudLayerWidgetWrapper::modelerExpressionFormatString() const
7503{
7504 return tr( "path to a point cloud layer" );
7505}
7506
7507QString QgsProcessingPointCloudLayerWidgetWrapper::parameterType() const
7508{
7510}
7511
7512QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingPointCloudLayerWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type )
7513{
7514 return new QgsProcessingPointCloudLayerWidgetWrapper( parameter, type );
7515}
7516
7517QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingPointCloudLayerWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
7518{
7519 Q_UNUSED( context );
7520 Q_UNUSED( widgetContext );
7521 Q_UNUSED( definition );
7522 Q_UNUSED( algorithm );
7523
7524 return nullptr;
7525}
7526
7527
7528//
7529// QgsProcessingAnnotationLayerWidgetWrapper
7530//
7531
7532QgsProcessingAnnotationLayerWidgetWrapper::QgsProcessingAnnotationLayerWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type, QWidget *parent )
7533 : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
7534{
7535}
7536
7537QString QgsProcessingAnnotationLayerWidgetWrapper::modelerExpressionFormatString() const
7538{
7539 return tr( "name of an annotation layer, or \"main\" for the main annotation layer" );
7540}
7541
7542QString QgsProcessingAnnotationLayerWidgetWrapper::parameterType() const
7543{
7545}
7546
7547QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingAnnotationLayerWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type )
7548{
7549 return new QgsProcessingAnnotationLayerWidgetWrapper( parameter, type );
7550}
7551
7552QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingAnnotationLayerWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
7553{
7554 Q_UNUSED( context );
7555 Q_UNUSED( widgetContext );
7556 Q_UNUSED( definition );
7557 Q_UNUSED( algorithm );
7558
7559 return nullptr;
7560}
7561
7562void QgsProcessingAnnotationLayerWidgetWrapper::setWidgetContext( const QgsProcessingParameterWidgetContext &context )
7563{
7565 if ( mComboBox )
7566 {
7567 if ( mWidgetContext.project() )
7568 mComboBox->setAdditionalLayers( { mWidgetContext.project()->mainAnnotationLayer() } );
7569 }
7570}
7571
7572QWidget *QgsProcessingAnnotationLayerWidgetWrapper::createWidget()
7573{
7574 mComboBox = new QgsMapLayerComboBox();
7575 mComboBox->setFilters( Qgis::LayerFilter::AnnotationLayer );
7576
7577 switch ( type() )
7578 {
7581 break;
7583 mComboBox->setEditable( true );
7584 break;
7585 }
7586
7587 mComboBox->setToolTip( parameterDefinition()->toolTip() );
7588
7589 if ( mWidgetContext.project() )
7590 mComboBox->setAdditionalLayers( { mWidgetContext.project()->mainAnnotationLayer() } );
7591
7592 if ( parameterDefinition()->flags() & Qgis::ProcessingParameterFlag::Optional )
7593 mComboBox->setAllowEmptyLayer( true );
7594
7595 connect( mComboBox, &QgsMapLayerComboBox::layerChanged, this, [this]() {
7596 if ( mBlockSignals )
7597 return;
7598
7599 emit widgetValueHasChanged( this );
7600 } );
7601
7602 setWidgetContext( widgetContext() );
7603 return mComboBox;
7604}
7605
7606void QgsProcessingAnnotationLayerWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
7607{
7608 if ( mComboBox )
7609 {
7610 if ( !value.isValid() && parameterDefinition()->flags() & Qgis::ProcessingParameterFlag::Optional )
7611 {
7612 mComboBox->setLayer( nullptr );
7613 return;
7614 }
7615
7616 QVariant val = value;
7617 if ( val.userType() == qMetaTypeId<QgsProperty>() )
7618 {
7619 if ( val.value<QgsProperty>().propertyType() == Qgis::PropertyType::Static )
7620 {
7621 val = val.value<QgsProperty>().staticValue();
7622 }
7623 else
7624 {
7625 val = val.value<QgsProperty>().valueAsString( context.expressionContext(), parameterDefinition()->defaultValueForGui().toString() );
7626 }
7627 }
7628
7629 QgsMapLayer *layer = qobject_cast<QgsMapLayer *>( val.value<QObject *>() );
7630 if ( !layer && val.userType() == QMetaType::Type::QString )
7631 {
7633 }
7634
7635 if ( layer )
7636 {
7637 mComboBox->setLayer( layer );
7638 }
7639 }
7640}
7641
7642QVariant QgsProcessingAnnotationLayerWidgetWrapper::widgetValue() const
7643{
7644 return mComboBox && mComboBox->currentLayer() ? ( mWidgetContext.project() ? ( mComboBox->currentLayer() == mWidgetContext.project()->mainAnnotationLayer() ? u"main"_s : mComboBox->currentLayer()->id() ) : mComboBox->currentLayer()->id() )
7645 : QVariant();
7646}
7647
7648
7649//
7650// QgsProcessingPointCloudAttributePanelWidget
7651//
7652
7653QgsProcessingPointCloudAttributePanelWidget::QgsProcessingPointCloudAttributePanelWidget( QWidget *parent, const QgsProcessingParameterPointCloudAttribute *param )
7654 : QWidget( parent )
7655 , mParam( param )
7656{
7657 QHBoxLayout *hl = new QHBoxLayout();
7658 hl->setContentsMargins( 0, 0, 0, 0 );
7659
7660 mLineEdit = new QLineEdit();
7661 mLineEdit->setEnabled( false );
7662 hl->addWidget( mLineEdit, 1 );
7663
7664 mToolButton = new QToolButton();
7665 mToolButton->setText( QString( QChar( 0x2026 ) ) );
7666 hl->addWidget( mToolButton );
7667
7668 setLayout( hl );
7669
7670 if ( mParam )
7671 {
7672 mLineEdit->setText( tr( "%n attribute(s) selected", nullptr, 0 ) );
7673 }
7674
7675 connect( mToolButton, &QToolButton::clicked, this, &QgsProcessingPointCloudAttributePanelWidget::showDialog );
7676}
7677
7678void QgsProcessingPointCloudAttributePanelWidget::setAttributes( const QgsPointCloudAttributeCollection &attributes )
7679{
7680 mAttributes = attributes;
7681}
7682
7683void QgsProcessingPointCloudAttributePanelWidget::setValue( const QVariant &value )
7684{
7685 if ( value.isValid() )
7686 mValue = value.userType() == QMetaType::Type::QVariantList ? value.toList() : QVariantList() << value;
7687 else
7688 mValue.clear();
7689
7690 updateSummaryText();
7691 emit changed();
7692}
7693
7694void QgsProcessingPointCloudAttributePanelWidget::showDialog()
7695{
7696 QVariantList availableOptions;
7697 availableOptions.reserve( mAttributes.count() );
7698 const QVector<QgsPointCloudAttribute> attributes = mAttributes.attributes();
7699 for ( const QgsPointCloudAttribute &attr : attributes )
7700 {
7701 availableOptions << attr.name();
7702 }
7703
7705 if ( panel && panel->dockMode() )
7706 {
7707 QgsProcessingMultipleSelectionPanelWidget *widget = new QgsProcessingMultipleSelectionPanelWidget( availableOptions, mValue );
7708 widget->setPanelTitle( mParam->description() );
7709
7710 widget->setValueFormatter( []( const QVariant &v ) -> QString {
7711 return v.toString();
7712 } );
7713
7714 connect( widget, &QgsProcessingMultipleSelectionPanelWidget::selectionChanged, this, [this, widget]() {
7715 setValue( widget->selectedOptions() );
7716 } );
7717 connect( widget, &QgsProcessingMultipleSelectionPanelWidget::acceptClicked, widget, &QgsPanelWidget::acceptPanel );
7718 panel->openPanel( widget );
7719 }
7720 else
7721 {
7722 QgsProcessingMultipleSelectionDialog dlg( availableOptions, mValue, this, Qt::WindowFlags() );
7723
7724 dlg.setValueFormatter( []( const QVariant &v ) -> QString {
7725 return v.toString();
7726 } );
7727 if ( dlg.exec() )
7728 {
7729 setValue( dlg.selectedOptions() );
7730 }
7731 }
7732}
7733
7734void QgsProcessingPointCloudAttributePanelWidget::updateSummaryText()
7735{
7736 if ( !mParam )
7737 return;
7738
7739 if ( mValue.empty() )
7740 {
7741 mLineEdit->setText( tr( "%n attribute(s) selected", nullptr, 0 ) );
7742 }
7743 else
7744 {
7745 QStringList values;
7746 values.reserve( mValue.size() );
7747 for ( const QVariant &val : std::as_const( mValue ) )
7748 {
7749 values << val.toString();
7750 }
7751
7752 const QString concatenated = values.join( tr( "," ) );
7753 if ( concatenated.length() < 100 )
7754 mLineEdit->setText( concatenated );
7755 else
7756 mLineEdit->setText( tr( "%n attribute(s) selected", nullptr, mValue.count() ) );
7757 }
7758}
7759
7760
7761//
7762// QgsProcessingPointCloudAttributeWidgetWrapper
7763//
7764
7765QgsProcessingPointCloudAttributeParameterDefinitionWidget::QgsProcessingPointCloudAttributeParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
7766 : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
7767{
7768 QVBoxLayout *vlayout = new QVBoxLayout();
7769 vlayout->setContentsMargins( 0, 0, 0, 0 );
7770
7771 vlayout->addWidget( new QLabel( tr( "Parent layer" ) ) );
7772 mParentLayerComboBox = new QComboBox();
7773
7774 QString initialParent;
7775 if ( const QgsProcessingParameterPointCloudAttribute *attrParam = dynamic_cast<const QgsProcessingParameterPointCloudAttribute *>( definition ) )
7776 initialParent = attrParam->parentLayerParameterName();
7777
7778 if ( auto *lModel = widgetContext.model() )
7779 {
7780 // populate combo box with other model input choices
7781 const QMap<QString, QgsProcessingModelParameter> components = lModel->parameterComponents();
7782 for ( auto it = components.constBegin(); it != components.constEnd(); ++it )
7783 {
7784 if ( const QgsProcessingParameterPointCloudLayer *definition = dynamic_cast<const QgsProcessingParameterPointCloudLayer *>( lModel->parameterDefinition( it.value().parameterName() ) ) )
7785 {
7786 mParentLayerComboBox->addItem( definition->description(), definition->name() );
7787 if ( !initialParent.isEmpty() && initialParent == definition->name() )
7788 {
7789 mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
7790 }
7791 }
7792 }
7793 }
7794
7795 if ( mParentLayerComboBox->count() == 0 && !initialParent.isEmpty() )
7796 {
7797 // if no parent candidates found, we just add the existing one as a placeholder
7798 mParentLayerComboBox->addItem( initialParent, initialParent );
7799 mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
7800 }
7801
7802 vlayout->addWidget( mParentLayerComboBox );
7803
7804 mAllowMultipleCheckBox = new QCheckBox( tr( "Accept multiple attributes" ) );
7805 if ( const QgsProcessingParameterPointCloudAttribute *attrParam = dynamic_cast<const QgsProcessingParameterPointCloudAttribute *>( definition ) )
7806 mAllowMultipleCheckBox->setChecked( attrParam->allowMultiple() );
7807
7808 vlayout->addWidget( mAllowMultipleCheckBox );
7809
7810 mDefaultToAllCheckBox = new QCheckBox( tr( "Select all attributes by default" ) );
7811 mDefaultToAllCheckBox->setEnabled( mAllowMultipleCheckBox->isChecked() );
7812 if ( const QgsProcessingParameterPointCloudAttribute *attrParam = dynamic_cast<const QgsProcessingParameterPointCloudAttribute *>( definition ) )
7813 mDefaultToAllCheckBox->setChecked( attrParam->defaultToAllAttributes() );
7814
7815 vlayout->addWidget( mDefaultToAllCheckBox );
7816
7817 connect( mAllowMultipleCheckBox, &QCheckBox::stateChanged, this, [this] {
7818 mDefaultToAllCheckBox->setEnabled( mAllowMultipleCheckBox->isChecked() );
7819 } );
7820
7821 vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
7822
7823 mDefaultLineEdit = new QLineEdit();
7824 mDefaultLineEdit->setToolTip( tr( "Default attribute name, or ; separated list of attribute names for multiple attribute parameters" ) );
7825 if ( const QgsProcessingParameterPointCloudAttribute *attrParam = dynamic_cast<const QgsProcessingParameterPointCloudAttribute *>( definition ) )
7826 {
7827 const QStringList attributes = QgsProcessingParameters::parameterAsStrings( attrParam, attrParam->defaultValueForGui(), context );
7828 mDefaultLineEdit->setText( attributes.join( ';' ) );
7829 }
7830 vlayout->addWidget( mDefaultLineEdit );
7831
7832 setLayout( vlayout );
7833}
7834
7835QgsProcessingParameterDefinition *QgsProcessingPointCloudAttributeParameterDefinitionWidget::createParameter( const QString &name, const QString &description, Qgis::ProcessingParameterFlags flags ) const
7836{
7837 QVariant defaultValue;
7838 if ( !mDefaultLineEdit->text().trimmed().isEmpty() )
7839 {
7840 defaultValue = mDefaultLineEdit->text();
7841 }
7842 auto param = std::make_unique<QgsProcessingParameterPointCloudAttribute>( name, description, defaultValue, mParentLayerComboBox->currentData().toString(), mAllowMultipleCheckBox->isChecked(), false, mDefaultToAllCheckBox->isChecked() );
7843 param->setFlags( flags );
7844 return param.release();
7845}
7846
7847QgsProcessingPointCloudAttributeWidgetWrapper::QgsProcessingPointCloudAttributeWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type, QWidget *parent )
7848 : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
7849{
7850}
7851
7852QWidget *QgsProcessingPointCloudAttributeWidgetWrapper::createWidget()
7853{
7854 const QgsProcessingParameterPointCloudAttribute *attrParam = dynamic_cast<const QgsProcessingParameterPointCloudAttribute *>( parameterDefinition() );
7855 if ( !attrParam )
7856 return nullptr;
7857
7858 switch ( type() )
7859 {
7862 {
7863 if ( attrParam->allowMultiple() )
7864 {
7865 mPanel = new QgsProcessingPointCloudAttributePanelWidget( nullptr, attrParam );
7866 mPanel->setToolTip( parameterDefinition()->toolTip() );
7867 connect( mPanel, &QgsProcessingPointCloudAttributePanelWidget::changed, this, [this] {
7868 emit widgetValueHasChanged( this );
7869 } );
7870 return mPanel;
7871 }
7872 else
7873 {
7874 mComboBox = new QgsPointCloudAttributeComboBox();
7875 mComboBox->setAllowEmptyAttributeName( attrParam->flags() & Qgis::ProcessingParameterFlag::Optional );
7876 mComboBox->setToolTip( parameterDefinition()->toolTip() );
7877 connect( mComboBox, &QgsPointCloudAttributeComboBox::attributeChanged, this, [this]( const QString & ) {
7878 emit widgetValueHasChanged( this );
7879 } );
7880 return mComboBox;
7881 }
7882 }
7883
7885 {
7886 mLineEdit = new QLineEdit();
7887 mLineEdit->setToolTip( QObject::tr( "Name of attribute (separate attribute names with ; for multiple attribute parameters)" ) );
7888 connect( mLineEdit, &QLineEdit::textChanged, this, [this] {
7889 emit widgetValueHasChanged( this );
7890 } );
7891 return mLineEdit;
7892 }
7893 }
7894 return nullptr;
7895}
7896
7897void QgsProcessingPointCloudAttributeWidgetWrapper::postInitialize( const QList<QgsAbstractProcessingParameterWidgetWrapper *> &wrappers )
7898{
7900 switch ( type() )
7901 {
7904 {
7905 for ( const QgsAbstractProcessingParameterWidgetWrapper *wrapper : wrappers )
7906 {
7907 if ( wrapper->parameterDefinition()->name() == static_cast<const QgsProcessingParameterPointCloudAttribute *>( parameterDefinition() )->parentLayerParameterName() )
7908 {
7909 setParentLayerWrapperValue( wrapper );
7910 connect( wrapper, &QgsAbstractProcessingParameterWidgetWrapper::widgetValueHasChanged, this, [this, wrapper] {
7911 setParentLayerWrapperValue( wrapper );
7912 } );
7913 break;
7914 }
7915 }
7916 break;
7917 }
7918
7920 break;
7921 }
7922}
7923
7924void QgsProcessingPointCloudAttributeWidgetWrapper::setParentLayerWrapperValue( const QgsAbstractProcessingParameterWidgetWrapper *parentWrapper )
7925{
7926 // evaluate value to layer
7927 QgsProcessingContext *context = nullptr;
7928 std::unique_ptr<QgsProcessingContext> tmpContext;
7929 if ( mProcessingContextGenerator )
7930 context = mProcessingContextGenerator->processingContext();
7931
7932 if ( !context )
7933 {
7934 tmpContext = std::make_unique<QgsProcessingContext>();
7935 context = tmpContext.get();
7936 }
7937
7938 QVariant value = parentWrapper->parameterValue();
7939
7941 if ( layer && layer->isValid() )
7942 {
7943 // need to grab ownership of layer if required - otherwise layer may be deleted when context
7944 // goes out of scope
7945 std::unique_ptr<QgsMapLayer> ownedLayer( context->takeResultLayer( layer->id() ) );
7946 if ( ownedLayer && ownedLayer->type() == Qgis::LayerType::PointCloud )
7947 {
7948 mParentLayer.reset( qobject_cast<QgsPointCloudLayer *>( ownedLayer.release() ) );
7949 layer = mParentLayer.get();
7950 }
7951 else
7952 {
7953 // don't need ownership of this layer - it wasn't owned by context (so e.g. is owned by the project)
7954 }
7955
7956 if ( mComboBox )
7957 mComboBox->setLayer( layer );
7958 else if ( mPanel )
7959 {
7960 mPanel->setAttributes( layer->attributes() );
7961 }
7962 }
7963 else
7964 {
7965 if ( mComboBox )
7966 {
7967 mComboBox->setLayer( nullptr );
7968 }
7969 else if ( mPanel )
7970 mPanel->setAttributes( QgsPointCloudAttributeCollection() );
7971
7972 if ( value.isValid() && widgetContext().messageBar() )
7973 {
7974 widgetContext().messageBar()->clearWidgets();
7975 widgetContext().messageBar()->pushMessage( QString(), QObject::tr( "Could not load selected layer/table. Dependent attributes could not be populated" ), Qgis::MessageLevel::Info );
7976 }
7977 }
7978
7979 const QgsProcessingParameterPointCloudAttribute *attrParam = static_cast<const QgsProcessingParameterPointCloudAttribute *>( parameterDefinition() );
7980 if ( mPanel && attrParam->defaultToAllAttributes() )
7981 {
7982 QVariantList val;
7983 val.reserve( mPanel->attributes().attributes().size() );
7984 for ( const QgsPointCloudAttribute &attr : mPanel->attributes().attributes() )
7985 val << attr.name();
7986 setWidgetValue( val, *context );
7987 }
7988 else if ( attrParam->defaultValueForGui().isValid() )
7989 setWidgetValue( parameterDefinition()->defaultValueForGui(), *context );
7990}
7991
7992void QgsProcessingPointCloudAttributeWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
7993{
7994 if ( mComboBox )
7995 {
7996 if ( !value.isValid() )
7997 mComboBox->setAttribute( QString() );
7998 else
7999 {
8000 const QString v = QgsProcessingParameters::parameterAsString( parameterDefinition(), value, context );
8001 mComboBox->setAttribute( v );
8002 }
8003 }
8004 else if ( mPanel )
8005 {
8006 QVariantList opts;
8007 if ( value.isValid() )
8008 {
8009 const QStringList v = QgsProcessingParameters::parameterAsStrings( parameterDefinition(), value, context );
8010 opts.reserve( v.size() );
8011 for ( const QString &i : v )
8012 opts << i;
8013 }
8014 if ( mPanel )
8015 mPanel->setValue( opts );
8016 }
8017 else if ( mLineEdit )
8018 {
8019 const QgsProcessingParameterPointCloudAttribute *attrParam = static_cast<const QgsProcessingParameterPointCloudAttribute *>( parameterDefinition() );
8020 if ( attrParam->allowMultiple() )
8021 {
8022 const QStringList v = QgsProcessingParameters::parameterAsStrings( parameterDefinition(), value, context );
8023 mLineEdit->setText( v.join( ';' ) );
8024 }
8025 else
8026 {
8027 mLineEdit->setText( QgsProcessingParameters::parameterAsString( parameterDefinition(), value, context ) );
8028 }
8029 }
8030}
8031
8032QVariant QgsProcessingPointCloudAttributeWidgetWrapper::widgetValue() const
8033{
8034 if ( mComboBox )
8035 return mComboBox->currentAttribute();
8036 else if ( mPanel )
8037 return mPanel->value();
8038 else if ( mLineEdit )
8039 {
8040 const QgsProcessingParameterPointCloudAttribute *attrParam = static_cast<const QgsProcessingParameterPointCloudAttribute *>( parameterDefinition() );
8041 if ( attrParam->allowMultiple() )
8042 {
8043 return mLineEdit->text().split( ';' );
8044 }
8045 else
8046 return mLineEdit->text();
8047 }
8048 else
8049 return QVariant();
8050}
8051
8052QString QgsProcessingPointCloudAttributeWidgetWrapper::modelerExpressionFormatString() const
8053{
8054 return tr( "selected attribute names as an array of names, or semicolon separated string of options (e.g. 'X;Intensity')" );
8055}
8056
8057QString QgsProcessingPointCloudAttributeWidgetWrapper::parameterType() const
8058{
8060}
8061
8062QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingPointCloudAttributeWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type )
8063{
8064 return new QgsProcessingPointCloudAttributeWidgetWrapper( parameter, type );
8065}
8066
8067QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingPointCloudAttributeWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
8068{
8069 return new QgsProcessingPointCloudAttributeParameterDefinitionWidget( context, widgetContext, definition, algorithm );
8070}
8071
8072
8073//
8074// QgsProcessingOutputWidgetWrapper
8075//
8076
8077QgsProcessingOutputWidgetWrapper::QgsProcessingOutputWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type, QWidget *parent )
8078 : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
8079{
8080}
8081
8082QWidget *QgsProcessingOutputWidgetWrapper::createWidget()
8083{
8084 const QgsProcessingDestinationParameter *destParam = dynamic_cast<const QgsProcessingDestinationParameter *>( parameterDefinition() );
8085 switch ( type() )
8086 {
8089 {
8090 mOutputWidget = new QgsProcessingLayerOutputDestinationWidget( destParam, false );
8091 if ( mProcessingContextGenerator )
8092 mOutputWidget->setContext( mProcessingContextGenerator->processingContext() );
8093 if ( mParametersGenerator )
8094 mOutputWidget->registerProcessingParametersGenerator( mParametersGenerator );
8095 mOutputWidget->setToolTip( parameterDefinition()->toolTip() );
8096
8097 connect( mOutputWidget, &QgsProcessingLayerOutputDestinationWidget::destinationChanged, this, [this]() {
8098 if ( mBlockSignals )
8099 return;
8100
8101 emit widgetValueHasChanged( this );
8102 } );
8103
8104 if ( type() == Qgis::ProcessingMode::Standard
8106 mOutputWidget->addOpenAfterRunningOption();
8107
8108 return mOutputWidget;
8109 }
8111 break;
8112 }
8113
8114 return nullptr;
8115}
8116
8117
8118void QgsProcessingOutputWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext & )
8119{
8120 if ( mOutputWidget )
8121 mOutputWidget->setValue( value );
8122}
8123
8124QVariant QgsProcessingOutputWidgetWrapper::widgetValue() const
8125{
8126 if ( mOutputWidget )
8127 return mOutputWidget->value();
8128
8129 return QVariant();
8130}
8131
8132QVariantMap QgsProcessingOutputWidgetWrapper::customProperties() const
8133{
8134 QVariantMap res;
8135 if ( mOutputWidget )
8136 res.insert( u"OPEN_AFTER_RUNNING"_s, mOutputWidget->openAfterRunning() );
8137 return res;
8138}
8139
8140//
8141// QgsProcessingFeatureSinkWidgetWrapper
8142//
8143
8144QgsProcessingFeatureSinkWidgetWrapper::QgsProcessingFeatureSinkWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type, QWidget *parent )
8145 : QgsProcessingOutputWidgetWrapper( parameter, type, parent )
8146{
8147}
8148
8149QString QgsProcessingFeatureSinkWidgetWrapper::parameterType() const
8150{
8152}
8153
8154QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingFeatureSinkWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type )
8155{
8156 return new QgsProcessingFeatureSinkWidgetWrapper( parameter, type );
8157}
8158
8159QString QgsProcessingFeatureSinkWidgetWrapper::modelerExpressionFormatString() const
8160{
8161 return tr( "path to layer destination" );
8162}
8163
8164//
8165// QgsProcessingFeatureSinkWidgetWrapper
8166//
8167
8168QgsProcessingVectorDestinationWidgetWrapper::QgsProcessingVectorDestinationWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type, QWidget *parent )
8169 : QgsProcessingOutputWidgetWrapper( parameter, type, parent )
8170{
8171}
8172
8173QString QgsProcessingVectorDestinationWidgetWrapper::parameterType() const
8174{
8176}
8177
8178QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingVectorDestinationWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type )
8179{
8180 return new QgsProcessingVectorDestinationWidgetWrapper( parameter, type );
8181}
8182
8183QString QgsProcessingVectorDestinationWidgetWrapper::modelerExpressionFormatString() const
8184{
8185 return tr( "path to layer destination" );
8186}
8187
8188//
8189// QgsProcessingRasterDestinationWidgetWrapper
8190//
8191
8192QgsProcessingRasterDestinationWidgetWrapper::QgsProcessingRasterDestinationWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type, QWidget *parent )
8193 : QgsProcessingOutputWidgetWrapper( parameter, type, parent )
8194{
8195}
8196
8197QString QgsProcessingRasterDestinationWidgetWrapper::parameterType() const
8198{
8200}
8201
8202QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingRasterDestinationWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type )
8203{
8204 return new QgsProcessingRasterDestinationWidgetWrapper( parameter, type );
8205}
8206
8207QString QgsProcessingRasterDestinationWidgetWrapper::modelerExpressionFormatString() const
8208{
8209 return tr( "path to layer destination" );
8210}
8211
8212//
8213// QgsProcessingPointCloudDestinationWidgetWrapper
8214//
8215
8216QgsProcessingPointCloudDestinationWidgetWrapper::QgsProcessingPointCloudDestinationWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type, QWidget *parent )
8217 : QgsProcessingOutputWidgetWrapper( parameter, type, parent )
8218{
8219}
8220
8221QString QgsProcessingPointCloudDestinationWidgetWrapper::parameterType() const
8222{
8224}
8225
8226QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingPointCloudDestinationWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type )
8227{
8228 return new QgsProcessingPointCloudDestinationWidgetWrapper( parameter, type );
8229}
8230
8231QString QgsProcessingPointCloudDestinationWidgetWrapper::modelerExpressionFormatString() const
8232{
8233 return tr( "path to layer destination" );
8234}
8235
8236//
8237// QgsProcessingFileDestinationWidgetWrapper
8238//
8239
8240QgsProcessingFileDestinationWidgetWrapper::QgsProcessingFileDestinationWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type, QWidget *parent )
8241 : QgsProcessingOutputWidgetWrapper( parameter, type, parent )
8242{
8243}
8244
8245QString QgsProcessingFileDestinationWidgetWrapper::parameterType() const
8246{
8248}
8249
8250QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingFileDestinationWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type )
8251{
8252 return new QgsProcessingFileDestinationWidgetWrapper( parameter, type );
8253}
8254
8255
8256QString QgsProcessingFileDestinationWidgetWrapper::modelerExpressionFormatString() const
8257{
8258 return tr( "path to file destination" );
8259}
8260
8261//
8262// QgsProcessingFolderDestinationWidgetWrapper
8263//
8264
8265QgsProcessingFolderDestinationWidgetWrapper::QgsProcessingFolderDestinationWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type, QWidget *parent )
8266 : QgsProcessingOutputWidgetWrapper( parameter, type, parent )
8267{
8268}
8269
8270QString QgsProcessingFolderDestinationWidgetWrapper::parameterType() const
8271{
8273}
8274
8275QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingFolderDestinationWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type )
8276{
8277 return new QgsProcessingFolderDestinationWidgetWrapper( parameter, type );
8278}
8279
8280
8281QString QgsProcessingFolderDestinationWidgetWrapper::modelerExpressionFormatString() const
8282{
8283 return tr( "path to folder destination" );
8284}
8285
8286//
8287// QgsProcessingVectorTileDestinationWidgetWrapper
8288//
8289
8290QgsProcessingVectorTileDestinationWidgetWrapper::QgsProcessingVectorTileDestinationWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type, QWidget *parent )
8291 : QgsProcessingOutputWidgetWrapper( parameter, type, parent )
8292{
8293}
8294
8295QString QgsProcessingVectorTileDestinationWidgetWrapper::parameterType() const
8296{
8298}
8299
8300QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingVectorTileDestinationWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type )
8301{
8302 return new QgsProcessingPointCloudDestinationWidgetWrapper( parameter, type );
8303}
8304
8305QString QgsProcessingVectorTileDestinationWidgetWrapper::modelerExpressionFormatString() const
8306{
8307 return tr( "path to layer destination" );
8308}
8309
@ Standard
Unit is a standard measurement unit.
Definition qgis.h:5183
ProcessingSourceType
Processing data source types.
Definition qgis.h:3602
@ File
Files (i.e. non map layer sources, such as text files).
Definition qgis.h:3609
@ Plugin
Plugin layers.
Definition qgis.h:3612
@ TiledScene
Tiled scene layers.
Definition qgis.h:3616
@ Annotation
Annotation layers.
Definition qgis.h:3614
@ Vector
Tables (i.e. vector layers with or without geometry). When used for a sink this indicates the sink ha...
Definition qgis.h:3610
@ VectorTile
Vector tile layers.
Definition qgis.h:3615
@ MapLayer
Any map layer type (raster, vector, mesh, point cloud, annotation or plugin layer).
Definition qgis.h:3603
@ Mesh
Mesh layers.
Definition qgis.h:3611
@ Raster
Raster layers.
Definition qgis.h:3608
@ VectorAnyGeometry
Any vector layer with geometry.
Definition qgis.h:3604
@ VectorPoint
Vector point layers.
Definition qgis.h:3605
@ VectorPolygon
Vector polygon layers.
Definition qgis.h:3607
@ VectorLine
Vector line layers.
Definition qgis.h:3606
@ PointCloud
Point cloud layers.
Definition qgis.h:3613
ProcessingFileParameterBehavior
Flags which dictate the behavior of QgsProcessingParameterFile.
Definition qgis.h:3859
@ File
Parameter is a single file.
Definition qgis.h:3860
@ Folder
Parameter is a folder.
Definition qgis.h:3861
ExpressionType
Expression types.
Definition qgis.h:5843
@ RasterCalculator
Raster calculator expression.
Definition qgis.h:5846
@ Qgis
Native QGIS expression.
Definition qgis.h:5844
@ PointCloud
Point cloud expression.
Definition qgis.h:5845
ProcessingMode
Types of modes which Processing widgets can be created for.
Definition qgis.h:3742
@ Batch
Batch processing mode.
Definition qgis.h:3744
@ Modeler
Modeler mode.
Definition qgis.h:3745
@ Standard
Standard (single-run) algorithm mode.
Definition qgis.h:3743
DistanceUnit
Units of distance.
Definition qgis.h:5120
@ Feet
Imperial feet.
Definition qgis.h:5123
@ Centimeters
Centimeters.
Definition qgis.h:5128
@ Millimeters
Millimeters.
Definition qgis.h:5129
@ Miles
Terrestrial miles.
Definition qgis.h:5126
@ Meters
Meters.
Definition qgis.h:5121
@ Unknown
Unknown distance unit.
Definition qgis.h:5170
@ Yards
Imperial yards.
Definition qgis.h:5125
@ Degrees
Degrees, for planar geographic CRS distance measurements.
Definition qgis.h:5127
@ Inches
Inches.
Definition qgis.h:5130
@ NauticalMiles
Nautical miles.
Definition qgis.h:5124
@ Kilometers
Kilometers.
Definition qgis.h:5122
ProcessingFieldParameterDataType
Processing field parameter data types.
Definition qgis.h:3887
@ String
Accepts string fields.
Definition qgis.h:3890
@ Boolean
Accepts boolean fields, since QGIS 3.34.
Definition qgis.h:3893
@ Binary
Accepts binary fields, since QGIS 3.34.
Definition qgis.h:3892
@ Numeric
Accepts numeric fields.
Definition qgis.h:3889
@ DateTime
Accepts datetime fields.
Definition qgis.h:3891
AreaUnit
Units of area.
Definition qgis.h:5197
@ Acres
Acres.
Definition qgis.h:5204
@ SquareFeet
Square feet.
Definition qgis.h:5200
@ SquareCentimeters
Square centimeters.
Definition qgis.h:5207
@ SquareInches
Square inches.
Definition qgis.h:5209
@ SquareNauticalMiles
Square nautical miles.
Definition qgis.h:5205
@ SquareMillimeters
Square millimeters.
Definition qgis.h:5208
@ SquareYards
Square yards.
Definition qgis.h:5201
@ Hectares
Hectares.
Definition qgis.h:5203
@ SquareKilometers
Square kilometers.
Definition qgis.h:5199
@ SquareMeters
Square meters.
Definition qgis.h:5198
@ Unknown
Unknown areal unit.
Definition qgis.h:5210
@ SquareDegrees
Square degrees, for planar geographic CRS area measurements.
Definition qgis.h:5206
@ SquareMiles
Square miles.
Definition qgis.h:5202
@ Info
Information message.
Definition qgis.h:160
@ Static
Static property.
Definition qgis.h:703
@ AnnotationLayer
QgsAnnotationLayer.
Definition qgis.h:225
TemporalUnit
Temporal units.
Definition qgis.h:5266
@ Milliseconds
Milliseconds.
Definition qgis.h:5267
@ Hours
Hours.
Definition qgis.h:5270
@ Centuries
Centuries.
Definition qgis.h:5276
@ Seconds
Seconds.
Definition qgis.h:5268
@ Weeks
Weeks.
Definition qgis.h:5272
@ Years
Years.
Definition qgis.h:5274
@ Decades
Decades.
Definition qgis.h:5275
@ Minutes
Minutes.
Definition qgis.h:5269
@ Point
Points.
Definition qgis.h:366
@ Vector
Vector layer.
Definition qgis.h:194
@ Raster
Raster layer.
Definition qgis.h:195
@ PointCloud
Point cloud layer. Added in QGIS 3.18.
Definition qgis.h:200
QFlags< ProcessingParameterFlag > ProcessingParameterFlags
Flags which dictate the behavior of Processing parameters.
Definition qgis.h:3848
VolumeUnit
Units of volume.
Definition qgis.h:5222
@ CubicMeters
Cubic meters.
Definition qgis.h:5223
@ Barrel
Barrels.
Definition qgis.h:5226
@ CubicYards
Cubic yards.
Definition qgis.h:5225
@ CubicFeet
Cubic feet.
Definition qgis.h:5224
@ CubicDegrees
Cubic degrees, for planar geographic CRS volume measurements.
Definition qgis.h:5232
@ CubicDecimeter
Cubic decimeters.
Definition qgis.h:5227
@ Unknown
Unknown volume unit.
Definition qgis.h:5233
@ CubicInch
Cubic inches.
Definition qgis.h:5230
@ GallonUS
US Gallons.
Definition qgis.h:5229
@ Liters
Litres.
Definition qgis.h:5228
@ CubicCentimeter
Cubic Centimeters.
Definition qgis.h:5231
ProcessingModelChildParameterSource
Processing model child parameter sources.
Definition qgis.h:3918
@ ModelParameter
Parameter value is taken from a parent model parameter.
Definition qgis.h:3919
@ StaticValue
Parameter value is a static value.
Definition qgis.h:3921
@ Optional
Parameter is optional.
Definition qgis.h:3836
ProcessingDateTimeParameterDataType
Processing date time parameter data types.
Definition qgis.h:3905
ProcessingNumberParameterType
Processing numeric parameter data types.
Definition qgis.h:3873
@ Double
Double/float values.
Definition qgis.h:3875
A widget wrapper for Processing parameter value widgets.
QVariant parameterValue() const
Returns the current value of the parameter.
virtual QLabel * createLabel()
Creates a new label to accompany widgets created by the wrapper.
virtual void registerProcessingContextGenerator(QgsProcessingContextGenerator *generator)
Registers a Processing context generator class that will be used to retrieve a Processing context for...
void widgetValueHasChanged(QgsAbstractProcessingParameterWidgetWrapper *wrapper)
Emitted whenever the parameter value (as defined by the wrapped widget) is changed.
virtual void postInitialize(const QList< QgsAbstractProcessingParameterWidgetWrapper * > &wrappers)
Called after all wrappers have been created within a particular dialog or context,...
virtual const QgsVectorLayer * linkedVectorLayer() const
Returns the optional vector layer associated with this widget wrapper, or nullptr if no vector layer ...
const QgsProcessingParameterDefinition * parameterDefinition() const
Returns the parameter definition associated with this wrapper.
virtual void setDialog(QDialog *dialog)
Sets the parent dialog in which the wrapper is shown.
virtual void setWidgetContext(const QgsProcessingParameterWidgetContext &context)
Sets the context in which the Processing parameter widget is shown, e.g., the parent model algorithm,...
static QCursor getThemeCursor(Cursor cursor)
Helper to get a theme cursor.
static QIcon getThemeIcon(const QString &name, const QColor &fillColor=QColor(), const QColor &strokeColor=QColor())
Helper to get a theme icon.
@ CapturePoint
Select and capture a point or a feature.
Selector widget for authentication configs.
void selectedConfigIdChanged(const QString &authcfg)
Emitted when authentication config is changed or missing.
QComboBox subclass which allows selecting multiple items.
A cross platform button subclass for selecting colors.
void colorChanged(const QColor &color)
Emitted whenever a new color is set for the button.
A widget for selecting the coordinate operation to use when transforming between a source and destina...
void operationChanged()
Emitted when the operation selected in the dialog is changed.
Represents a coordinate reference system (CRS).
bool isValid() const
Returns whether this CRS is correctly initialized and usable.
A combo box which displays the list of schemas for a specific database connection.
A combobox which displays the list of tables for a specific database connection.
A QDateEdit widget with the capability of setting/reading null dates.
void dateValueChanged(const QDate &date)
Signal emitted whenever the date changes.
A QDateTimeEdit with the capability of setting/reading null date/times.
void setAllowNull(bool allowNull)
Determines if the widget allows setting null date/time.
void setNullRepresentation(const QString &null)
Sets the widget's null representation, which defaults to QgsApplication::nullRepresentation().
void valueChanged(const QDateTime &date)
Signal emitted whenever the value changes.
A dialog for configuring transform operations between coordinate reference systems.
The QgsSpinBox is a spin box with a clear button that will set the value to the defined clear value.
static double toDouble(const QString &input, bool *ok)
Converts input string to double value.
A reusable widget that can be used to build an expression string.
void expressionParsed(bool isValid)
Emitted when the user changes the expression in the widget.
A widget which includes a line edit for entering expressions together with a button to open the expre...
void expressionChanged(const QString &expression)
Emitted when the expression is changed.
A widget for configuration of a map extent.
void toggleDialogVisibility(bool visible)
Emitted when the parent dialog visibility must be changed (e.g.
void extentChanged(const QgsRectangle &r)
Emitted when the widget's extent is changed.
A combobox which displays the list of fields of a given layer.
void fieldChanged(const QString &fieldName)
Emitted when the currently selected field changes.
A widget for selection of layer fields or expression creation.
void fieldChanged(const QString &fieldName)
Emitted when the currently selected field changes.
@ DateTime
Datetime fields.
@ Date
Date or datetime fields.
@ Binary
Binary fields, since QGIS 3.34.
@ String
String fields.
@ Boolean
Boolean fields, since QGIS 3.34.
@ Numeric
All numeric fields.
Encapsulate a field in an attribute table or data source.
Definition qgsfield.h:56
QString name
Definition qgsfield.h:65
Container of fields for a vector layer.
Definition qgsfields.h:46
bool append(const QgsField &field, Qgis::FieldOrigin origin=Qgis::FieldOrigin::Provider, int originIndex=-1)
Appends a field.
Definition qgsfields.cpp:76
int count
Definition qgsfields.h:50
bool isEmpty
Definition qgsfields.h:49
void remove(int fieldIdx)
Removes the field with the given index.
QgsField at(int i) const
Returns the field at particular index (must be in range 0..N-1).
Q_INVOKABLE int lookupField(const QString &fieldName) const
Looks up field's index from the field name.
A widget for selecting a file or a folder.
@ GetFile
Select a single file.
@ GetDirectory
Select a directory.
void fileChanged(const QString &path)
Emitted whenever the current file or directory path is changed.
QLineEdit subclass with built in support for clearing the widget's value and handling custom null val...
A widget for storing and interacting with a QgsGeometry object.
void geometryValueChanged(const QgsReferencedGeometry &value)
Emitted whenever the geometry value of the widget is changed.
A geometry is the spatial representation of a feature.
static QgsGeometry fromPointXY(const QgsPointXY &point)
Creates a new geometry from a QgsPointXY object.
bool isEmpty() const
Returns true if the geometry is empty (eg a linestring with no vertices, or a collection with no geom...
Q_INVOKABLE QString asWkt(int precision=17) const
Exports the geometry to WKT.
A QgsFilterLineEdit subclass with the ability to "highlight" the edges of the widget.
A combobox which displays available layouts from a QgsLayoutManager.
void layoutChanged(QgsMasterLayoutInterface *layout)
Emitted whenever the currently selected layout changes.
A combo box which displays items of a matching type from a layout.
void itemChanged(QgsLayoutItem *item)
Emitted whenever the currently selected item changes.
Base class for graphical items within a QgsLayout.
virtual QString uuid() const
Returns the item identification string.
@ FilterPrintLayouts
Includes print layouts.
QList< QgsPrintLayout * > printLayouts() const
Returns a list of all print layouts contained in the manager.
Map canvas is a class for displaying all GIS data types on a canvas.
const QgsMapSettings & mapSettings() const
Gets access to properties used for map rendering.
A combobox which displays a dynamic list of layers from a QGIS project.
void layerChanged(QgsMapLayer *layer)
Emitted whenever the currently selected layer changes.
Base class for all map layer types.
Definition qgsmaplayer.h:83
QString name
Definition qgsmaplayer.h:87
QString id
Definition qgsmaplayer.h:86
A mouse event which is the result of a user interaction with a QgsMapCanvas.
QgsPointLocator::Match mapPointMatch() const
Returns the matching data from the most recently snapped point.
QgsPointXY snapPoint()
snapPoint will snap the points using the map canvas snapping utils configuration
QgsCoordinateReferenceSystem destinationCrs() const
Returns the destination coordinate reference system for the map render.
Abstract base class for all map tools.
Definition qgsmaptool.h:72
virtual void deactivate()
called when map tool is being deactivated
Interface for master layout type objects, such as print layouts and reports.
virtual QString name() const =0
Returns the layout's name.
void pushMessage(const QString &text, Qgis::MessageLevel level=Qgis::MessageLevel::Info, int duration=-1)
A convenience method for pushing a message with the specified text to the bar.
bool clearWidgets()
Removes all items from the bar.
Base class for any widget that can be shown as an inline panel.
void openPanel(QgsPanelWidget *panel)
Open a panel or dialog depending on dock mode setting If dock mode is true this method will emit the ...
bool dockMode() const
Returns the dock mode state.
void acceptPanel()
Accept the panel.
static QgsPanelWidget * findParentPanel(QWidget *widget)
Traces through the parents of a widget to find if it is contained within a QgsPanelWidget widget.
A collection of point cloud attributes.
A combobox which displays the list of attributes of a given point cloud layer.
void attributeChanged(const QString &name)
Emitted when the currently selected attribute changes.
Attribute for point cloud data pair of name and size in bytes.
Represents a map layer supporting display of point clouds.
QgsPointCloudAttributeCollection attributes() const
Returns the attributes available from the layer.
Represents a 2D point.
Definition qgspointxy.h:62
double y
Definition qgspointxy.h:66
double x
Definition qgspointxy.h:65
Print layout, a QgsLayout subclass for static or atlas-based layouts.
Abstract base class for widgets which allow users to specify the properties of a Processing parameter...
Abstract base class for processing algorithms.
An interface for objects which can create Processing contexts.
Contains information about the context in which a processing algorithm is executed.
QgsExpressionContext & expressionContext()
Returns the expression context.
QgsCoordinateTransformContext transformContext() const
Returns the coordinate transform context.
QgsMapLayer * takeResultLayer(const QString &id)
Takes the result map layer with matching id from the context and transfers ownership of it back to th...
Base class for all parameter definitions which represent file or layer destinations,...
Encapsulates settings relating to a feature source input to a processing algorithm.
static QString typeName()
Returns the type name for the output class.
static QString typeName()
Returns the type name for the output class.
static QString typeName()
Returns the type name for the output class.
static QString typeName()
Returns the type name for the output class.
static QString typeName()
Returns the type name for the output class.
static QString typeName()
Returns the type name for the parameter class.
A double numeric parameter for area values.
Qgis::AreaUnit defaultUnit() const
Returns the default area unit for the parameter.
static QString typeName()
Returns the type name for the parameter class.
static QString typeName()
Returns the type name for the parameter class.
A raster band parameter for Processing algorithms.
static QString typeName()
Returns the type name for the parameter class.
bool allowMultiple() const
Returns whether multiple band selections are permitted.
A boolean parameter for processing algorithms.
static QString typeName()
Returns the type name for the parameter class.
A color parameter for processing algorithms.
bool opacityEnabled() const
Returns true if the parameter allows opacity control.
static QString typeName()
Returns the type name for the parameter class.
A coordinate operation parameter for processing algorithms.
static QString typeName()
Returns the type name for the parameter class.
QVariant sourceCrs() const
Returns the static source CRS, or an invalid value if this is not set.
QVariant destinationCrs() const
Returns the static destination CRS, or an invalid value if this is not set.
A coordinate reference system parameter for processing algorithms.
static QString typeName()
Returns the type name for the parameter class.
A database schema parameter for processing algorithms, allowing users to select from existing schemas...
static QString typeName()
Returns the type name for the parameter class.
QString parentConnectionParameterName() const
Returns the name of the parent connection parameter, or an empty string if this is not set.
A database table name parameter for processing algorithms.
static QString typeName()
Returns the type name for the parameter class.
QString parentConnectionParameterName() const
Returns the name of the parent connection parameter, or an empty string if this is not set.
QString parentSchemaParameterName() const
Returns the name of the parent schema parameter, or an empty string if this is not set.
bool allowNewTableNames() const
Returns true if the parameter allows users to enter names for a new (non-existing) tables.
A datetime (or pure date or time) parameter for processing algorithms.
static QString typeName()
Returns the type name for the parameter class.
Qgis::ProcessingDateTimeParameterDataType dataType() const
Returns the acceptable data type for the parameter.
Base class for the definition of processing parameters.
void setFlags(Qgis::ProcessingParameterFlags flags)
Sets the flags associated with the parameter.
QVariantMap metadata() const
Returns the parameter's freeform metadata.
QString description() const
Returns the description for the parameter.
QVariant defaultValueForGui() const
Returns the default value to use for the parameter in a GUI.
virtual QString type() const =0
Unique parameter type name.
QString name() const
Returns the name of the parameter.
Qgis::ProcessingParameterFlags flags() const
Returns any flags associated with the parameter.
A double numeric parameter for distance values.
static QString typeName()
Returns the type name for the parameter class.
Qgis::DistanceUnit defaultUnit() const
Returns the default distance unit for the parameter.
A double numeric parameter for duration values.
Qgis::TemporalUnit defaultUnit() const
Returns the default duration unit for the parameter.
static QString typeName()
Returns the type name for the parameter class.
An enum based parameter for processing algorithms, allowing for selection from predefined values.
bool allowMultiple() const
Returns true if the parameter allows multiple selected values.
QStringList options() const
Returns the list of acceptable options for the parameter.
bool usesStaticStrings() const
Returns true if the parameter uses static (non-translated) string values for its enumeration choice l...
static QString typeName()
Returns the type name for the parameter class.
An expression parameter for processing algorithms.
QString parentLayerParameterName() const
Returns the name of the parent layer parameter, or an empty string if this is not set.
static QString typeName()
Returns the type name for the parameter class.
Qgis::ExpressionType expressionType() const
Returns the parameter's expression type.
A rectangular map extent parameter for processing algorithms.
static QString typeName()
Returns the type name for the parameter class.
static QString typeName()
Returns the type name for the parameter class.
An input feature source (such as vector layers) parameter for processing algorithms.
static QString typeName()
Returns the type name for the parameter class.
A vector layer or feature source field parameter for processing algorithms.
Qgis::ProcessingFieldParameterDataType dataType() const
Returns the acceptable data type for the field.
bool allowMultiple() const
Returns whether multiple field selections are permitted.
bool defaultToAllFields() const
Returns whether a parameter which allows multiple selections (see allowMultiple()) should automatical...
static QString typeName()
Returns the type name for the parameter class.
void setDataType(Qgis::ProcessingFieldParameterDataType type)
Sets the acceptable data type for the field.
static QString typeName()
Returns the type name for the parameter class.
An input file or folder parameter for processing algorithms.
QString extension() const
Returns any specified file extension for the parameter.
static QString typeName()
Returns the type name for the parameter class.
QString fileFilter() const
Returns the file filter string for file destinations compatible with this parameter.
Qgis::ProcessingFileParameterBehavior behavior() const
Returns the parameter behavior (e.g.
static QString typeName()
Returns the type name for the parameter class.
A geometry parameter for processing algorithms.
static QString typeName()
Returns the type name for the parameter class.
A print layout item parameter, allowing users to select a particular item from a print layout.
static QString typeName()
Returns the type name for the parameter class.
int itemType() const
Returns the acceptable item type, or -1 if any item type is allowed.
A print layout parameter, allowing users to select a print layout.
static QString typeName()
Returns the type name for the parameter class.
A map layer parameter for processing algorithms.
static QString typeName()
Returns the type name for the parameter class.
A map theme parameter for processing algorithms, allowing users to select an existing map theme from ...
static QString typeName()
Returns the type name for the parameter class.
A table (matrix) parameter for processing algorithms.
static QString typeName()
Returns the type name for the parameter class.
static QString typeName()
Returns the type name for the parameter class.
A parameter for processing algorithms which accepts multiple map layers.
static QString typeName()
Returns the type name for the parameter class.
A numeric parameter for processing algorithms.
double minimum() const
Returns the minimum value acceptable by the parameter.
double maximum() const
Returns the maximum value acceptable by the parameter.
Qgis::ProcessingNumberParameterType dataType() const
Returns the acceptable data type for the parameter.
static QString typeName()
Returns the type name for the parameter class.
A point cloud layer attribute parameter for Processing algorithms.
static QString typeName()
Returns the type name for the parameter class.
bool allowMultiple() const
Returns whether multiple field selections are permitted.
bool defaultToAllAttributes() const
Returns whether a parameter which allows multiple selections (see allowMultiple()) should automatical...
static QString typeName()
Returns the type name for the parameter class.
A point cloud layer parameter for processing algorithms.
static QString typeName()
Returns the type name for the parameter class.
A point parameter for processing algorithms.
static QString typeName()
Returns the type name for the parameter class.
A data provider connection parameter for processing algorithms, allowing users to select from availab...
static QString typeName()
Returns the type name for the parameter class.
QString providerId() const
Returns the ID of the provider associated with the connections.
A numeric range parameter for processing algorithms.
static QString typeName()
Returns the type name for the parameter class.
Qgis::ProcessingNumberParameterType dataType() const
Returns the acceptable data type for the range.
static QString typeName()
Returns the type name for the parameter class.
A raster layer parameter for processing algorithms.
static QString typeName()
Returns the type name for the parameter class.
A double numeric parameter for map scale values.
static QString typeName()
Returns the type name for the parameter class.
A string parameter for processing algorithms.
static QString typeName()
Returns the type name for the parameter class.
static QString typeName()
Returns the type name for the parameter class.
A vector layer (with or without geometry) parameter for processing algorithms.
static QString typeName()
Returns the type name for the parameter class.
static QString typeName()
Returns the type name for the parameter class.
A double numeric parameter for volume values.
static QString typeName()
Returns the type name for the parameter class.
Qgis::VolumeUnit defaultUnit() const
Returns the default volume unit for the parameter.
Contains settings which reflect the context in which a Processing parameter widget is shown.
QgsMapCanvas * mapCanvas() const
Returns the map canvas associated with the widget.
QgsProject * project() const
Returns the project associated with the widget.
QgsMessageBar * messageBar() const
Returns the message bar associated with the widget.
QgsProcessingModelAlgorithm * model() const
Returns the model which the parameter widget is associated with.
QgsMapLayer * activeLayer() const
Returns the current active layer.
static int parameterAsEnum(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, const QgsProcessingContext &context)
Evaluates the parameter with matching definition to a enum value.
static double parameterAsDouble(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, const QgsProcessingContext &context)
Evaluates the parameter with matching definition to a static double value.
static QgsPointXY parameterAsPoint(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context, const QgsCoordinateReferenceSystem &crs=QgsCoordinateReferenceSystem())
Evaluates the parameter with matching definition to a point.
static QgsPrintLayout * parameterAsLayout(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context)
Evaluates the parameter with matching definition to a print layout.
static QList< QgsMapLayer * > parameterAsLayerList(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessing::LayerOptionsFlags flags=QgsProcessing::LayerOptionsFlags())
Evaluates the parameter with matching definition to a list of map layers.
static QTime parameterAsTime(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, const QgsProcessingContext &context)
Evaluates the parameter with matching definition to a static time value.
static QgsRectangle parameterAsExtent(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context, const QgsCoordinateReferenceSystem &crs=QgsCoordinateReferenceSystem())
Evaluates the parameter with matching definition to a rectangular extent.
static QString parameterAsEnumString(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, const QgsProcessingContext &context)
Evaluates the parameter with matching definition to a static enum string.
static QList< double > parameterAsRange(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context)
Evaluates the parameter with matching definition to a range of values.
static QStringList parameterAsStrings(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context)
Evaluates the parameter with matching definition to a list of strings (e.g.
static QList< int > parameterAsInts(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, const QgsProcessingContext &context)
Evaluates the parameter with matching definition to a list of integer values.
static QString parameterAsConnectionName(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, const QgsProcessingContext &context)
Evaluates the parameter with matching definition to a connection name string.
static QgsProcessingFeatureSource * parameterAsSource(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context)
Evaluates the parameter with matching definition to a feature source.
static QgsPointCloudLayer * parameterAsPointCloudLayer(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessing::LayerOptionsFlags flags=QgsProcessing::LayerOptionsFlags())
Evaluates the parameter with matching definition to a point cloud layer.
static QgsCoordinateReferenceSystem parameterAsPointCrs(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context)
Returns the coordinate reference system associated with an point parameter value.
static QgsLayoutItem * parameterAsLayoutItem(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context, QgsPrintLayout *layout)
Evaluates the parameter with matching definition to a print layout item, taken from the specified lay...
static bool parameterAsBool(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, const QgsProcessingContext &context)
Evaluates the parameter with matching definition to a static boolean value.
static QColor parameterAsColor(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context)
Returns the color associated with an point parameter value, or an invalid color if the parameter was ...
static QgsVectorLayer * parameterAsVectorLayer(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context)
Evaluates the parameter with matching definition to a vector layer.
static int parameterAsInt(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, const QgsProcessingContext &context)
Evaluates the parameter with matching definition to a static integer value.
static QString parameterAsDatabaseTableName(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, const QgsProcessingContext &context)
Evaluates the parameter with matching definition to a database table name.
static QString parameterAsSchema(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, const QgsProcessingContext &context)
Evaluates the parameter with matching definition to a database schema name.
static QgsGeometry parameterAsGeometry(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context, const QgsCoordinateReferenceSystem &crs=QgsCoordinateReferenceSystem())
Evaluates the parameter with matching definition to a geometry.
static QString parameterAsExpression(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, const QgsProcessingContext &context)
Evaluates the parameter with matching definition to an expression.
static QString parameterAsString(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, const QgsProcessingContext &context)
Evaluates the parameter with matching definition to a static string value.
static QgsRasterLayer * parameterAsRasterLayer(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context)
Evaluates the parameter with matching definition to a raster layer.
static QList< int > parameterAsEnums(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, const QgsProcessingContext &context)
Evaluates the parameter with matching definition to list of enum values.
static QStringList parameterAsEnumStrings(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, const QgsProcessingContext &context)
Evaluates the parameter with matching definition to list of static enum strings.
static QgsCoordinateReferenceSystem parameterAsExtentCrs(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context)
Returns the coordinate reference system associated with an extent parameter value.
static QDateTime parameterAsDateTime(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, const QgsProcessingContext &context)
Evaluates the parameter with matching definition to a static datetime value.
static QDate parameterAsDate(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, const QgsProcessingContext &context)
Evaluates the parameter with matching definition to a static date value.
static QVariantList parameterAsMatrix(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context)
Evaluates the parameter with matching definition to a matrix/table of values.
static QgsCoordinateReferenceSystem parameterAsCrs(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context)
Evaluates the parameter with matching definition to a coordinate reference system.
Utility functions for use with processing classes.
@ Annotation
Annotation layer type, since QGIS 3.22.
static QgsCoordinateReferenceSystem variantToCrs(const QVariant &value, QgsProcessingContext &context, const QVariant &fallbackValue=QVariant())
Converts a variant value to a coordinate reference system.
static QgsMapLayer * mapLayerFromString(const QString &string, QgsProcessingContext &context, bool allowLoadingNewLayers=true, QgsProcessingUtils::LayerHint typeHint=QgsProcessingUtils::LayerHint::UnknownType, QgsProcessing::LayerOptionsFlags flags=QgsProcessing::LayerOptionsFlags())
Interprets a string as a map layer within the supplied context.
@ SkipIndexGeneration
Do not generate index when creating a layer. Makes sense only for point cloud layers.
Encapsulates a QGIS project, including sets of map layers and their styles, layouts,...
Definition qgsproject.h:113
static QgsProject * instance()
Returns the QgsProject singleton instance.
QgsMapThemeCollection * mapThemeCollection
Definition qgsproject.h:122
const QgsLayoutManager * layoutManager() const
Returns the project's layout manager, which manages print layouts, atlases and reports within the pro...
void layerRemoved(const QString &layerId)
Emitted after a layer was removed from the registry.
A widget for selecting a projection.
@ CrsNotSet
Not set (hidden by default).
void crsChanged(const QgsCoordinateReferenceSystem &crs)
Emitted when the selected CRS is changed.
A store for object properties.
Qgis::PropertyType propertyType() const
Returns the property type.
A combo box which displays the list of connections registered for a given provider.
A combobox widget which displays the bands present in a raster layer.
void bandChanged(int band)
Emitted when the currently selected band changes.
static QString displayBandName(QgsRasterDataProvider *provider, int band)
Returns a user-friendly band name for the specified band.
Base class for raster data providers.
virtual int bandCount() const =0
Gets number of bands.
Represents a raster layer.
QgsRasterDataProvider * dataProvider() override
Returns the source data provider.
A rectangle specified with double values.
A QgsGeometry with associated coordinate reference system.
Responsible for drawing transient features (e.g.
@ ICON_X
A cross is used to highlight points (x).
A combobox which lets the user select map scale from predefined list and highlights nearest to curren...
void scaleChanged(double scale)
Emitted when user has finished editing/selecting a new scale.
Stores settings for use within QGIS.
Definition qgssettings.h:68
void setValue(const QString &key, const QVariant &value, QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.
A spin box with a clear button that will set the value to the defined clear value.
Definition qgsspinbox.h:45
A QTimeEdit widget with the capability of setting/reading null date/times.
void timeValueChanged(const QTime &time)
Signal emitted whenever the time changes.
static Q_INVOKABLE QString toString(Qgis::DistanceUnit unit)
Returns a translated string representing a distance unit.
static Q_INVOKABLE double fromUnitToUnitFactor(Qgis::DistanceUnit fromUnit, Qgis::DistanceUnit toUnit)
Returns the conversion factor between the specified distance units.
static Q_INVOKABLE Qgis::DistanceUnitType unitType(Qgis::DistanceUnit unit)
Returns the type for a distance unit.
Represents a vector layer which manages a vector based dataset.
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into allowing algorithms to be written in pure substantial changes are required in order to port existing x Processing algorithms for QGIS x The most significant changes are outlined not GeoAlgorithm For algorithms which operate on features one by consider subclassing the QgsProcessingFeatureBasedAlgorithm class This class allows much of the boilerplate code for looping over features from a vector layer to be bypassed and instead requires implementation of a processFeature method Ensure that your algorithm(or algorithm 's parent class) implements the new pure virtual createInstance(self) call
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c
double qgsRound(double number, int places)
Returns a double number, rounded (as close as possible) to the specified number of places.
Definition qgis.h:6976
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference).
Definition qgis.h:6935
QString proj
Proj coordinate operation description, for Proj >= 6.0 builds only.