QGIS API Documentation 3.41.0-Master (282a5a11603)
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#include "moc_qgsprocessingwidgetwrapperimpl.cpp"
25#include "qgsspinbox.h"
26#include "qgsdoublespinbox.h"
28#include "qgsauthconfigselect.h"
29#include "qgsapplication.h"
30#include "qgsfilewidget.h"
31#include "qgssettings.h"
36#include "qgslayoutmanager.h"
37#include "qgsproject.h"
38#include "qgslayoutcombobox.h"
40#include "qgsprintlayout.h"
41#include "qgsscalewidget.h"
42#include "qgssnapindicator.h"
43#include "qgsmapmouseevent.h"
44#include "qgsfilterlineedit.h"
45#include "qgsmapcanvas.h"
46#include "qgsmessagebar.h"
47#include "qgscolorbutton.h"
50#include "qgsfieldcombobox.h"
52#include "qgsdatetimeedit.h"
56#include "qgsextentwidget.h"
64#include "qgsdoublevalidator.h"
65#include "qgsmaplayercombobox.h"
66#include "qgsannotationlayer.h"
68#include "qgspointcloudlayer.h"
71#include "qgsunittypes.h"
72#include "qgsgeometrywidget.h"
73
74#include <QToolButton>
75#include <QLabel>
76#include <QHBoxLayout>
77#include <QVBoxLayout>
78#include <QCheckBox>
79#include <QComboBox>
80#include <QLineEdit>
81#include <QPlainTextEdit>
82#include <QRadioButton>
83#include <QButtonGroup>
84#include <QMenu>
85#include <QFileDialog>
86
88
89//
90// QgsProcessingBooleanWidgetWrapper
91//
92
93
94QgsProcessingBooleanParameterDefinitionWidget::QgsProcessingBooleanParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
95 : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
96{
97 QVBoxLayout *vlayout = new QVBoxLayout();
98 vlayout->setContentsMargins( 0, 0, 0, 0 );
99
100 mDefaultCheckBox = new QCheckBox( tr( "Checked" ) );
101 if ( const QgsProcessingParameterBoolean *boolParam = dynamic_cast<const QgsProcessingParameterBoolean *>( definition ) )
102 mDefaultCheckBox->setChecked( QgsProcessingParameters::parameterAsBool( boolParam, boolParam->defaultValueForGui(), context ) );
103 else
104 mDefaultCheckBox->setChecked( false );
105 vlayout->addWidget( mDefaultCheckBox );
106 setLayout( vlayout );
107}
108
109QgsProcessingParameterDefinition *QgsProcessingBooleanParameterDefinitionWidget::createParameter( const QString &name, const QString &description, Qgis::ProcessingParameterFlags flags ) const
110{
111 auto param = std::make_unique<QgsProcessingParameterBoolean>( name, description, mDefaultCheckBox->isChecked() );
112 param->setFlags( flags );
113 return param.release();
114}
115
116
117QgsProcessingBooleanWidgetWrapper::QgsProcessingBooleanWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
118 : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
119{
120}
121
122QWidget *QgsProcessingBooleanWidgetWrapper::createWidget()
123{
124 switch ( type() )
125 {
127 {
128 QString description = parameterDefinition()->description();
129 if ( parameterDefinition()->flags() & Qgis::ProcessingParameterFlag::Optional )
130 description = QObject::tr( "%1 [optional]" ).arg( description );
131
132 mCheckBox = new QCheckBox( description );
133 mCheckBox->setToolTip( parameterDefinition()->toolTip() );
134
135 connect( mCheckBox, &QCheckBox::toggled, this, [=] {
136 emit widgetValueHasChanged( this );
137 } );
138 return mCheckBox;
139 }
140
143 {
144 mComboBox = new QComboBox();
145 mComboBox->addItem( tr( "Yes" ), true );
146 mComboBox->addItem( tr( "No" ), false );
147 mComboBox->setToolTip( parameterDefinition()->toolTip() );
148
149 connect( mComboBox, qOverload<int>( &QComboBox::currentIndexChanged ), this, [=] {
150 emit widgetValueHasChanged( this );
151 } );
152
153 return mComboBox;
154 }
155 }
156 return nullptr;
157}
158
159QLabel *QgsProcessingBooleanWidgetWrapper::createLabel()
160{
161 // avoid creating labels in standard dialogs
162 if ( type() == QgsProcessingGui::Standard )
163 return nullptr;
164 else
166}
167
168void QgsProcessingBooleanWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
169{
170 switch ( type() )
171 {
173 {
174 const bool v = QgsProcessingParameters::parameterAsBool( parameterDefinition(), value, context );
175 mCheckBox->setChecked( v );
176 break;
177 }
178
181 {
182 const bool v = QgsProcessingParameters::parameterAsBool( parameterDefinition(), value, context );
183 mComboBox->setCurrentIndex( mComboBox->findData( v ) );
184 break;
185 }
186 }
187}
188
189QVariant QgsProcessingBooleanWidgetWrapper::widgetValue() const
190{
191 switch ( type() )
192 {
194 return mCheckBox->isChecked();
195
198 return mComboBox->currentData();
199 }
200 return QVariant();
201}
202
203QStringList QgsProcessingBooleanWidgetWrapper::compatibleParameterTypes() const
204{
205 //pretty much everything is compatible here and can be converted to a bool!
206 return QStringList() << QgsProcessingParameterBoolean::typeName()
225}
226
227QStringList QgsProcessingBooleanWidgetWrapper::compatibleOutputTypes() const
228{
229 return QStringList() << QgsProcessingOutputNumber::typeName()
237}
238
239QString QgsProcessingBooleanWidgetWrapper::parameterType() const
240{
242}
243
244QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingBooleanWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
245{
246 return new QgsProcessingBooleanWidgetWrapper( parameter, type );
247}
248
249QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingBooleanWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
250{
251 return new QgsProcessingBooleanParameterDefinitionWidget( context, widgetContext, definition, algorithm );
252}
253
254
255//
256// QgsProcessingCrsWidgetWrapper
257//
258
259QgsProcessingCrsParameterDefinitionWidget::QgsProcessingCrsParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
260 : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
261{
262 QVBoxLayout *vlayout = new QVBoxLayout();
263 vlayout->setContentsMargins( 0, 0, 0, 0 );
264
265 vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
266
267 mCrsSelector = new QgsProjectionSelectionWidget();
268
269 // possibly we should expose this for parameter by parameter control
270 mCrsSelector->setShowAccuracyWarnings( true );
271
272 if ( const QgsProcessingParameterCrs *crsParam = dynamic_cast<const QgsProcessingParameterCrs *>( definition ) )
273 mCrsSelector->setCrs( QgsProcessingParameters::parameterAsCrs( crsParam, crsParam->defaultValueForGui(), context ) );
274 else
275 mCrsSelector->setCrs( QgsCoordinateReferenceSystem( QStringLiteral( "EPSG:4326" ) ) );
276
277 vlayout->addWidget( mCrsSelector );
278 setLayout( vlayout );
279}
280
281QgsProcessingParameterDefinition *QgsProcessingCrsParameterDefinitionWidget::createParameter( const QString &name, const QString &description, Qgis::ProcessingParameterFlags flags ) const
282{
283 auto param = std::make_unique<QgsProcessingParameterCrs>( name, description, mCrsSelector->crs().authid() );
284 param->setFlags( flags );
285 return param.release();
286}
287
288QgsProcessingCrsWidgetWrapper::QgsProcessingCrsWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
289 : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
290{
291}
292
293QWidget *QgsProcessingCrsWidgetWrapper::createWidget()
294{
295 Q_ASSERT( mProjectionSelectionWidget == nullptr );
296 mProjectionSelectionWidget = new QgsProjectionSelectionWidget();
297 mProjectionSelectionWidget->setToolTip( parameterDefinition()->toolTip() );
298
299 if ( parameterDefinition()->flags() & Qgis::ProcessingParameterFlag::Optional )
300 mProjectionSelectionWidget->setOptionVisible( QgsProjectionSelectionWidget::CrsNotSet, true );
301 else
302 mProjectionSelectionWidget->setOptionVisible( QgsProjectionSelectionWidget::CrsNotSet, false );
303
304 connect( mProjectionSelectionWidget, &QgsProjectionSelectionWidget::crsChanged, this, [=] {
305 emit widgetValueHasChanged( this );
306 } );
307
308 switch ( type() )
309 {
312 {
313 return mProjectionSelectionWidget;
314 }
315
317 {
318 QWidget *w = new QWidget();
319 w->setToolTip( parameterDefinition()->toolTip() );
320
321 QVBoxLayout *vl = new QVBoxLayout();
322 vl->setContentsMargins( 0, 0, 0, 0 );
323 w->setLayout( vl );
324
325 mUseProjectCrsCheckBox = new QCheckBox( tr( "Use project CRS" ) );
326 mUseProjectCrsCheckBox->setToolTip( tr( "Always use the current project CRS when running the model" ) );
327 vl->addWidget( mUseProjectCrsCheckBox );
328 connect( mUseProjectCrsCheckBox, &QCheckBox::toggled, mProjectionSelectionWidget, &QgsProjectionSelectionWidget::setDisabled );
329 connect( mUseProjectCrsCheckBox, &QCheckBox::toggled, this, [=] {
330 emit widgetValueHasChanged( this );
331 } );
332
333 vl->addWidget( mProjectionSelectionWidget );
334
335 return w;
336 }
337 }
338 return nullptr;
339}
340
341void QgsProcessingCrsWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
342{
343 if ( mUseProjectCrsCheckBox )
344 {
345 if ( value.toString().compare( QLatin1String( "ProjectCrs" ), Qt::CaseInsensitive ) == 0 )
346 {
347 mUseProjectCrsCheckBox->setChecked( true );
348 return;
349 }
350 else
351 {
352 mUseProjectCrsCheckBox->setChecked( false );
353 }
354 }
355
356 const QgsCoordinateReferenceSystem v = QgsProcessingParameters::parameterAsCrs( parameterDefinition(), value, context );
357 if ( mProjectionSelectionWidget )
358 mProjectionSelectionWidget->setCrs( v );
359}
360
361QVariant QgsProcessingCrsWidgetWrapper::widgetValue() const
362{
363 if ( mUseProjectCrsCheckBox && mUseProjectCrsCheckBox->isChecked() )
364 return QStringLiteral( "ProjectCrs" );
365 else if ( mProjectionSelectionWidget )
366 return mProjectionSelectionWidget->crs().isValid() ? mProjectionSelectionWidget->crs() : QVariant();
367 else
368 return QVariant();
369}
370
371QStringList QgsProcessingCrsWidgetWrapper::compatibleParameterTypes() const
372{
373 return QStringList()
383}
384
385QStringList QgsProcessingCrsWidgetWrapper::compatibleOutputTypes() const
386{
387 return QStringList() << QgsProcessingOutputVectorLayer::typeName()
392}
393
394QString QgsProcessingCrsWidgetWrapper::modelerExpressionFormatString() const
395{
396 return tr( "string as EPSG code, WKT or PROJ format, or a string identifying a map layer" );
397}
398
399QString QgsProcessingCrsWidgetWrapper::parameterType() const
400{
402}
403
404QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingCrsWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
405{
406 return new QgsProcessingCrsWidgetWrapper( parameter, type );
407}
408
409QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingCrsWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
410{
411 return new QgsProcessingCrsParameterDefinitionWidget( context, widgetContext, definition, algorithm );
412}
413
414
415//
416// QgsProcessingStringWidgetWrapper
417//
418
419
420QgsProcessingStringParameterDefinitionWidget::QgsProcessingStringParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
421 : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
422{
423 QVBoxLayout *vlayout = new QVBoxLayout();
424 vlayout->setContentsMargins( 0, 0, 0, 0 );
425
426 vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
427
428 mDefaultLineEdit = new QLineEdit();
429 if ( const QgsProcessingParameterString *stringParam = dynamic_cast<const QgsProcessingParameterString *>( definition ) )
430 mDefaultLineEdit->setText( QgsProcessingParameters::parameterAsString( stringParam, stringParam->defaultValueForGui(), context ) );
431 vlayout->addWidget( mDefaultLineEdit );
432
433 mMultiLineCheckBox = new QCheckBox( tr( "Multiline input" ) );
434 if ( const QgsProcessingParameterString *stringParam = dynamic_cast<const QgsProcessingParameterString *>( definition ) )
435 mMultiLineCheckBox->setChecked( stringParam->multiLine() );
436 vlayout->addWidget( mMultiLineCheckBox );
437
438 setLayout( vlayout );
439}
440
441QgsProcessingParameterDefinition *QgsProcessingStringParameterDefinitionWidget::createParameter( const QString &name, const QString &description, Qgis::ProcessingParameterFlags flags ) const
442{
443 auto param = std::make_unique<QgsProcessingParameterString>( name, description, mDefaultLineEdit->text(), mMultiLineCheckBox->isChecked() );
444 param->setFlags( flags );
445 return param.release();
446}
447
448
449QgsProcessingStringWidgetWrapper::QgsProcessingStringWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
450 : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
451{
452}
453
454QWidget *QgsProcessingStringWidgetWrapper::createWidget()
455{
456 const QVariantMap metadata = parameterDefinition()->metadata();
457 const QVariant valueHintsVariant = metadata.value( QStringLiteral( "widget_wrapper" ) ).toMap().value( QStringLiteral( "value_hints" ) );
458
459 if ( valueHintsVariant.isValid() )
460 {
461 const QVariantList valueList = valueHintsVariant.toList();
462 mComboBox = new QComboBox();
463 mComboBox->setToolTip( parameterDefinition()->toolTip() );
464
465 if ( parameterDefinition()->flags() & Qgis::ProcessingParameterFlag::Optional )
466 {
467 mComboBox->addItem( QString() );
468 }
469 for ( const QVariant &entry : valueList )
470 {
471 mComboBox->addItem( entry.toString(), entry.toString() );
472 }
473 mComboBox->setCurrentIndex( 0 );
474
475 connect( mComboBox, qOverload<int>( &QComboBox::currentIndexChanged ), this, [=]( int ) {
476 emit widgetValueHasChanged( this );
477 } );
478 return mComboBox;
479 }
480 else
481 {
482 switch ( type() )
483 {
486 {
487 if ( static_cast<const QgsProcessingParameterString *>( parameterDefinition() )->multiLine() )
488 {
489 mPlainTextEdit = new QPlainTextEdit();
490 mPlainTextEdit->setToolTip( parameterDefinition()->toolTip() );
491
492 connect( mPlainTextEdit, &QPlainTextEdit::textChanged, this, [=] {
493 emit widgetValueHasChanged( this );
494 } );
495 return mPlainTextEdit;
496 }
497 else
498 {
499 mLineEdit = new QLineEdit();
500 mLineEdit->setToolTip( parameterDefinition()->toolTip() );
501
502 connect( mLineEdit, &QLineEdit::textChanged, this, [=] {
503 emit widgetValueHasChanged( this );
504 } );
505 return mLineEdit;
506 }
507 }
508
510 {
511 mLineEdit = new QLineEdit();
512 mLineEdit->setToolTip( parameterDefinition()->toolTip() );
513
514 connect( mLineEdit, &QLineEdit::textChanged, this, [=] {
515 emit widgetValueHasChanged( this );
516 } );
517 return mLineEdit;
518 }
519 }
520 }
521
522 return nullptr;
523}
524
525void QgsProcessingStringWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
526{
527 const QString v = QgsProcessingParameters::parameterAsString( parameterDefinition(), value, context );
528 if ( mLineEdit )
529 mLineEdit->setText( v );
530 if ( mPlainTextEdit )
531 mPlainTextEdit->setPlainText( v );
532 if ( mComboBox )
533 {
534 int index = -1;
535 if ( !value.isValid() )
536 index = mComboBox->findData( QVariant() );
537 else
538 index = mComboBox->findData( v );
539
540 if ( index >= 0 )
541 mComboBox->setCurrentIndex( index );
542 else
543 mComboBox->setCurrentIndex( 0 );
544 }
545}
546
547QVariant QgsProcessingStringWidgetWrapper::widgetValue() const
548{
549 if ( mLineEdit )
550 return mLineEdit->text();
551 else if ( mPlainTextEdit )
552 return mPlainTextEdit->toPlainText();
553 else if ( mComboBox )
554 return mComboBox->currentData();
555 else
556 return QVariant();
557}
558
559QStringList QgsProcessingStringWidgetWrapper::compatibleParameterTypes() const
560{
561 return QStringList()
575}
576
577QStringList QgsProcessingStringWidgetWrapper::compatibleOutputTypes() const
578{
579 return QStringList() << QgsProcessingOutputNumber::typeName()
584}
585
586QString QgsProcessingStringWidgetWrapper::parameterType() const
587{
589}
590
591QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingStringWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
592{
593 return new QgsProcessingStringWidgetWrapper( parameter, type );
594}
595
596QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingStringWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
597{
598 return new QgsProcessingStringParameterDefinitionWidget( context, widgetContext, definition, algorithm );
599}
600
601
602//
603// QgsProcessingAuthConfigWidgetWrapper
604//
605
606QgsProcessingAuthConfigWidgetWrapper::QgsProcessingAuthConfigWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
607 : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
608{
609}
610
611QWidget *QgsProcessingAuthConfigWidgetWrapper::createWidget()
612{
613 switch ( type() )
614 {
618 {
619 mAuthConfigSelect = new QgsAuthConfigSelect();
620 mAuthConfigSelect->setToolTip( parameterDefinition()->toolTip() );
621
622 connect( mAuthConfigSelect, &QgsAuthConfigSelect::selectedConfigIdChanged, this, [=] {
623 emit widgetValueHasChanged( this );
624 } );
625 return mAuthConfigSelect;
626 }
627 }
628 return nullptr;
629}
630
631void QgsProcessingAuthConfigWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
632{
633 const QString v = QgsProcessingParameters::parameterAsString( parameterDefinition(), value, context );
634 if ( mAuthConfigSelect )
635 mAuthConfigSelect->setConfigId( v );
636}
637
638QVariant QgsProcessingAuthConfigWidgetWrapper::widgetValue() const
639{
640 if ( mAuthConfigSelect )
641 return mAuthConfigSelect->configId();
642 else
643 return QVariant();
644}
645
646QStringList QgsProcessingAuthConfigWidgetWrapper::compatibleParameterTypes() const
647{
648 return QStringList()
652}
653
654QStringList QgsProcessingAuthConfigWidgetWrapper::compatibleOutputTypes() const
655{
656 return QStringList() << QgsProcessingOutputString::typeName()
658}
659
660QString QgsProcessingAuthConfigWidgetWrapper::parameterType() const
661{
663}
664
665QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingAuthConfigWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
666{
667 return new QgsProcessingAuthConfigWidgetWrapper( parameter, type );
668}
669
670//
671// QgsProcessingNumericWidgetWrapper
672//
673
674QgsProcessingNumberParameterDefinitionWidget::QgsProcessingNumberParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
675 : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
676{
677 QVBoxLayout *vlayout = new QVBoxLayout();
678 vlayout->setContentsMargins( 0, 0, 0, 0 );
679
680 vlayout->addWidget( new QLabel( tr( "Number type" ) ) );
681
682 mTypeComboBox = new QComboBox();
683 mTypeComboBox->addItem( tr( "Float" ), static_cast<int>( Qgis::ProcessingNumberParameterType::Double ) );
684 mTypeComboBox->addItem( tr( "Integer" ), static_cast<int>( Qgis::ProcessingNumberParameterType::Integer ) );
685 vlayout->addWidget( mTypeComboBox );
686
687 vlayout->addWidget( new QLabel( tr( "Minimum value" ) ) );
688 mMinLineEdit = new QLineEdit();
689 vlayout->addWidget( mMinLineEdit );
690
691 vlayout->addWidget( new QLabel( tr( "Maximum value" ) ) );
692 mMaxLineEdit = new QLineEdit();
693 vlayout->addWidget( mMaxLineEdit );
694
695 vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
696 mDefaultLineEdit = new QLineEdit();
697 vlayout->addWidget( mDefaultLineEdit );
698
699 if ( const QgsProcessingParameterNumber *numberParam = dynamic_cast<const QgsProcessingParameterNumber *>( definition ) )
700 {
701 mTypeComboBox->setCurrentIndex( mTypeComboBox->findData( static_cast<int>( numberParam->dataType() ) ) );
702
703 if ( !qgsDoubleNear( numberParam->maximum(), std::numeric_limits<double>::max() ) )
704 {
705 mMaxLineEdit->setText( QLocale().toString( numberParam->maximum() ) );
706 }
707 else
708 {
709 mMaxLineEdit->clear();
710 }
711
712 if ( !qgsDoubleNear( numberParam->minimum(), std::numeric_limits<double>::lowest() ) )
713 {
714 mMinLineEdit->setText( QLocale().toString( numberParam->minimum() ) );
715 }
716 else
717 {
718 mMinLineEdit->clear();
719 }
720
721 mDefaultLineEdit->setText( numberParam->defaultValueForGui().toString() );
722 }
723
724 setLayout( vlayout );
725}
726
727QgsProcessingParameterDefinition *QgsProcessingNumberParameterDefinitionWidget::createParameter( const QString &name, const QString &description, Qgis::ProcessingParameterFlags flags ) const
728{
729 bool ok;
730 double val = QgsDoubleValidator::toDouble( mDefaultLineEdit->text(), &ok );
731
732 Qgis::ProcessingNumberParameterType dataType = static_cast<Qgis::ProcessingNumberParameterType>( mTypeComboBox->currentData().toInt() );
733 auto param = std::make_unique<QgsProcessingParameterNumber>( name, description, dataType, ok ? val : QVariant() );
734
735 if ( !mMinLineEdit->text().trimmed().isEmpty() )
736 {
737 val = QgsDoubleValidator::toDouble( mMinLineEdit->text(), &ok );
738 if ( ok )
739 {
740 param->setMinimum( val );
741 }
742 }
743
744 if ( !mMaxLineEdit->text().trimmed().isEmpty() )
745 {
746 val = QgsDoubleValidator::toDouble( mMaxLineEdit->text(), &ok );
747 if ( ok )
748 {
749 param->setMaximum( val );
750 }
751 }
752
753 param->setFlags( flags );
754 return param.release();
755}
756
757QgsProcessingNumericWidgetWrapper::QgsProcessingNumericWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
758 : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
759{
760}
761
762QWidget *QgsProcessingNumericWidgetWrapper::createWidget()
763{
764 const QgsProcessingParameterNumber *numberDef = static_cast<const QgsProcessingParameterNumber *>( parameterDefinition() );
765 const QVariantMap metadata = numberDef->metadata();
766 const int decimals = metadata.value( QStringLiteral( "widget_wrapper" ) ).toMap().value( QStringLiteral( "decimals" ), 6 ).toInt();
767 switch ( type() )
768 {
772 {
773 // lots of duplicate code here -- but there's no common interface between QSpinBox/QDoubleSpinBox which would allow us to avoid this
774 QAbstractSpinBox *spinBox = nullptr;
775 switch ( numberDef->dataType() )
776 {
778 mDoubleSpinBox = new QgsDoubleSpinBox();
779 mDoubleSpinBox->setExpressionsEnabled( true );
780 mDoubleSpinBox->setDecimals( decimals );
781
782 // guess reasonable step value for double spin boxes
783 if ( !qgsDoubleNear( numberDef->maximum(), std::numeric_limits<double>::max() ) && !qgsDoubleNear( numberDef->minimum(), std::numeric_limits<double>::lowest() + 1 ) )
784 {
785 double singleStep = calculateStep( numberDef->minimum(), numberDef->maximum() );
786 singleStep = std::max( singleStep, std::pow( 10, -decimals ) );
787 mDoubleSpinBox->setSingleStep( singleStep );
788 }
789
790 spinBox = mDoubleSpinBox;
791 break;
792
794 mSpinBox = new QgsSpinBox();
795 mSpinBox->setExpressionsEnabled( true );
796 spinBox = mSpinBox;
797 break;
798 }
799 spinBox->setToolTip( parameterDefinition()->toolTip() );
800
801 double max = 999999999;
802 if ( !qgsDoubleNear( numberDef->maximum(), std::numeric_limits<double>::max() ) )
803 {
804 max = numberDef->maximum();
805 }
806 double min = -999999999;
807 if ( !qgsDoubleNear( numberDef->minimum(), std::numeric_limits<double>::lowest() ) )
808 {
809 min = numberDef->minimum();
810 }
811 if ( mDoubleSpinBox )
812 {
813 mDoubleSpinBox->setMinimum( min );
814 mDoubleSpinBox->setMaximum( max );
815 }
816 else
817 {
818 mSpinBox->setMinimum( static_cast<int>( min ) );
819 mSpinBox->setMaximum( static_cast<int>( max ) );
820 }
821
823 {
824 mAllowingNull = true;
825 if ( mDoubleSpinBox )
826 {
827 mDoubleSpinBox->setShowClearButton( true );
828 const double min = mDoubleSpinBox->minimum() - mDoubleSpinBox->singleStep();
829 mDoubleSpinBox->setMinimum( min );
830 mDoubleSpinBox->setValue( min );
831 }
832 else
833 {
834 mSpinBox->setShowClearButton( true );
835 const int min = mSpinBox->minimum() - 1;
836 mSpinBox->setMinimum( min );
837 mSpinBox->setValue( min );
838 }
839 spinBox->setSpecialValueText( tr( "Not set" ) );
840 }
841 else
842 {
843 if ( numberDef->defaultValueForGui().isValid() )
844 {
845 // if default value for parameter, we clear to that
846 bool ok = false;
847 if ( mDoubleSpinBox )
848 {
849 double defaultVal = numberDef->defaultValueForGui().toDouble( &ok );
850 if ( ok )
851 mDoubleSpinBox->setClearValue( defaultVal );
852 }
853 else
854 {
855 int intVal = numberDef->defaultValueForGui().toInt( &ok );
856 if ( ok )
857 mSpinBox->setClearValue( intVal );
858 }
859 }
860 else if ( !qgsDoubleNear( numberDef->minimum(), std::numeric_limits<double>::lowest() ) )
861 {
862 // otherwise we clear to the minimum, if it's set
863 if ( mDoubleSpinBox )
864 mDoubleSpinBox->setClearValue( numberDef->minimum() );
865 else
866 mSpinBox->setClearValue( static_cast<int>( numberDef->minimum() ) );
867 }
868 else
869 {
870 // last resort, we clear to 0
871 if ( mDoubleSpinBox )
872 {
873 mDoubleSpinBox->setValue( 0 );
874 mDoubleSpinBox->setClearValue( 0 );
875 }
876 else
877 {
878 mSpinBox->setValue( 0 );
879 mSpinBox->setClearValue( 0 );
880 }
881 }
882 }
883
884 if ( mDoubleSpinBox )
885 connect( mDoubleSpinBox, qOverload<double>( &QgsDoubleSpinBox::valueChanged ), this, [=] { emit widgetValueHasChanged( this ); } );
886 else if ( mSpinBox )
887 connect( mSpinBox, qOverload<int>( &QgsSpinBox::valueChanged ), this, [=] { emit widgetValueHasChanged( this ); } );
888
889 return spinBox;
890 }
891 }
892 return nullptr;
893}
894
895void QgsProcessingNumericWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
896{
897 if ( mDoubleSpinBox )
898 {
899 if ( mAllowingNull && !value.isValid() )
900 mDoubleSpinBox->clear();
901 else
902 {
903 const double v = QgsProcessingParameters::parameterAsDouble( parameterDefinition(), value, context );
904 mDoubleSpinBox->setValue( v );
905 }
906 }
907 else if ( mSpinBox )
908 {
909 if ( mAllowingNull && !value.isValid() )
910 mSpinBox->clear();
911 else
912 {
913 const int v = QgsProcessingParameters::parameterAsInt( parameterDefinition(), value, context );
914 mSpinBox->setValue( v );
915 }
916 }
917}
918
919QVariant QgsProcessingNumericWidgetWrapper::widgetValue() const
920{
921 if ( mDoubleSpinBox )
922 {
923 if ( mAllowingNull && qgsDoubleNear( mDoubleSpinBox->value(), mDoubleSpinBox->minimum() ) )
924 return QVariant();
925 else
926 return mDoubleSpinBox->value();
927 }
928 else if ( mSpinBox )
929 {
930 if ( mAllowingNull && mSpinBox->value() == mSpinBox->minimum() )
931 return QVariant();
932 else
933 return mSpinBox->value();
934 }
935 else
936 return QVariant();
937}
938
939QStringList QgsProcessingNumericWidgetWrapper::compatibleParameterTypes() const
940{
941 return QStringList()
948}
949
950QStringList QgsProcessingNumericWidgetWrapper::compatibleOutputTypes() const
951{
952 return QStringList() << QgsProcessingOutputNumber::typeName()
955}
956
957double QgsProcessingNumericWidgetWrapper::calculateStep( const double minimum, const double maximum )
958{
959 const double valueRange = maximum - minimum;
960 if ( valueRange <= 1.0 )
961 {
962 const double step = valueRange / 10.0;
963 // round to 1 significant figure
964 return qgsRound( step, -std::floor( std::log( step ) ) );
965 }
966 else
967 {
968 return 1.0;
969 }
970}
971
972QString QgsProcessingNumericWidgetWrapper::parameterType() const
973{
975}
976
977QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingNumericWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
978{
979 return new QgsProcessingNumericWidgetWrapper( parameter, type );
980}
981
982QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingNumericWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
983{
984 return new QgsProcessingNumberParameterDefinitionWidget( context, widgetContext, definition, algorithm );
985}
986
987//
988// QgsProcessingDistanceWidgetWrapper
989//
990
991QgsProcessingDistanceParameterDefinitionWidget::QgsProcessingDistanceParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
992 : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
993{
994 QVBoxLayout *vlayout = new QVBoxLayout();
995 vlayout->setContentsMargins( 0, 0, 0, 0 );
996
997 vlayout->addWidget( new QLabel( tr( "Linked input" ) ) );
998
999 mParentLayerComboBox = new QComboBox();
1000
1001 QString initialParent;
1002 if ( const QgsProcessingParameterDistance *distParam = dynamic_cast<const QgsProcessingParameterDistance *>( definition ) )
1003 initialParent = distParam->parentParameterName();
1004
1005 if ( auto *lModel = widgetContext.model() )
1006 {
1007 // populate combo box with other model input choices
1008 const QMap<QString, QgsProcessingModelParameter> components = lModel->parameterComponents();
1009 for ( auto it = components.constBegin(); it != components.constEnd(); ++it )
1010 {
1011 if ( const QgsProcessingParameterFeatureSource *definition = dynamic_cast<const QgsProcessingParameterFeatureSource *>( lModel->parameterDefinition( it.value().parameterName() ) ) )
1012 {
1013 mParentLayerComboBox->addItem( definition->description(), definition->name() );
1014 if ( !initialParent.isEmpty() && initialParent == definition->name() )
1015 {
1016 mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
1017 }
1018 }
1019 else if ( const QgsProcessingParameterVectorLayer *definition = dynamic_cast<const QgsProcessingParameterVectorLayer *>( lModel->parameterDefinition( it.value().parameterName() ) ) )
1020 {
1021 mParentLayerComboBox->addItem( definition->description(), definition->name() );
1022 if ( !initialParent.isEmpty() && initialParent == definition->name() )
1023 {
1024 mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
1025 }
1026 }
1027 else if ( const QgsProcessingParameterMapLayer *definition = dynamic_cast<const QgsProcessingParameterMapLayer *>( lModel->parameterDefinition( it.value().parameterName() ) ) )
1028 {
1029 mParentLayerComboBox->addItem( definition->description(), definition->name() );
1030 if ( !initialParent.isEmpty() && initialParent == definition->name() )
1031 {
1032 mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
1033 }
1034 }
1035 else if ( const QgsProcessingParameterCrs *definition = dynamic_cast<const QgsProcessingParameterCrs *>( lModel->parameterDefinition( it.value().parameterName() ) ) )
1036 {
1037 mParentLayerComboBox->addItem( definition->description(), definition->name() );
1038 if ( !initialParent.isEmpty() && initialParent == definition->name() )
1039 {
1040 mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
1041 }
1042 }
1043 }
1044 }
1045
1046 if ( mParentLayerComboBox->count() == 0 && !initialParent.isEmpty() )
1047 {
1048 // if no parent candidates found, we just add the existing one as a placeholder
1049 mParentLayerComboBox->addItem( initialParent, initialParent );
1050 mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
1051 }
1052
1053 vlayout->addWidget( mParentLayerComboBox );
1054
1055 vlayout->addWidget( new QLabel( tr( "Minimum value" ) ) );
1056 mMinLineEdit = new QLineEdit();
1057 vlayout->addWidget( mMinLineEdit );
1058
1059 vlayout->addWidget( new QLabel( tr( "Maximum value" ) ) );
1060 mMaxLineEdit = new QLineEdit();
1061 vlayout->addWidget( mMaxLineEdit );
1062
1063 vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
1064 mDefaultLineEdit = new QLineEdit();
1065 vlayout->addWidget( mDefaultLineEdit );
1066
1067 if ( const QgsProcessingParameterDistance *distParam = dynamic_cast<const QgsProcessingParameterDistance *>( definition ) )
1068 {
1069 mMinLineEdit->setText( QLocale().toString( distParam->minimum() ) );
1070 mMaxLineEdit->setText( QLocale().toString( distParam->maximum() ) );
1071 mDefaultLineEdit->setText( distParam->defaultValueForGui().toString() );
1072 }
1073
1074 setLayout( vlayout );
1075}
1076
1077QgsProcessingParameterDefinition *QgsProcessingDistanceParameterDefinitionWidget::createParameter( const QString &name, const QString &description, Qgis::ProcessingParameterFlags flags ) const
1078{
1079 bool ok;
1080 double val = QgsDoubleValidator::toDouble( mDefaultLineEdit->text(), &ok );
1081
1082 auto param = std::make_unique<QgsProcessingParameterDistance>( name, description, ok ? val : QVariant(), mParentLayerComboBox->currentData().toString() );
1083
1084 val = QgsDoubleValidator::toDouble( mMinLineEdit->text(), &ok );
1085 if ( ok )
1086 {
1087 param->setMinimum( val );
1088 }
1089
1090 val = QgsDoubleValidator::toDouble( mMaxLineEdit->text(), &ok );
1091 if ( ok )
1092 {
1093 param->setMaximum( val );
1094 }
1095
1096 param->setFlags( flags );
1097 return param.release();
1098}
1099
1100QgsProcessingDistanceWidgetWrapper::QgsProcessingDistanceWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
1101 : QgsProcessingNumericWidgetWrapper( parameter, type, parent )
1102{
1103}
1104
1105QString QgsProcessingDistanceWidgetWrapper::parameterType() const
1106{
1108}
1109
1110QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingDistanceWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
1111{
1112 return new QgsProcessingDistanceWidgetWrapper( parameter, type );
1113}
1114
1115QWidget *QgsProcessingDistanceWidgetWrapper::createWidget()
1116{
1117 const QgsProcessingParameterDistance *distanceDef = static_cast<const QgsProcessingParameterDistance *>( parameterDefinition() );
1118
1119 QWidget *spin = QgsProcessingNumericWidgetWrapper::createWidget();
1120 switch ( type() )
1121 {
1123 {
1124 mLabel = new QLabel();
1125 mUnitsCombo = new QComboBox();
1126
1127 mUnitsCombo->addItem( QgsUnitTypes::toString( Qgis::DistanceUnit::Meters ), static_cast<int>( Qgis::DistanceUnit::Meters ) );
1128 mUnitsCombo->addItem( QgsUnitTypes::toString( Qgis::DistanceUnit::Kilometers ), static_cast<int>( Qgis::DistanceUnit::Kilometers ) );
1129 mUnitsCombo->addItem( QgsUnitTypes::toString( Qgis::DistanceUnit::Feet ), static_cast<int>( Qgis::DistanceUnit::Feet ) );
1130 mUnitsCombo->addItem( QgsUnitTypes::toString( Qgis::DistanceUnit::Yards ), static_cast<int>( Qgis::DistanceUnit::Yards ) );
1131 mUnitsCombo->addItem( QgsUnitTypes::toString( Qgis::DistanceUnit::Miles ), static_cast<int>( Qgis::DistanceUnit::Miles ) );
1133 mUnitsCombo->addItem( QgsUnitTypes::toString( Qgis::DistanceUnit::Centimeters ), static_cast<int>( Qgis::DistanceUnit::Centimeters ) );
1134 mUnitsCombo->addItem( QgsUnitTypes::toString( Qgis::DistanceUnit::Millimeters ), static_cast<int>( Qgis::DistanceUnit::Millimeters ) );
1135 mUnitsCombo->addItem( QgsUnitTypes::toString( Qgis::DistanceUnit::Inches ), static_cast<int>( Qgis::DistanceUnit::Inches ) );
1136
1137 const int labelMargin = static_cast<int>( std::round( mUnitsCombo->fontMetrics().horizontalAdvance( 'X' ) ) );
1138 QHBoxLayout *layout = new QHBoxLayout();
1139 layout->addWidget( spin, 1 );
1140 layout->insertSpacing( 1, labelMargin / 2 );
1141 layout->insertWidget( 2, mLabel );
1142 layout->insertWidget( 3, mUnitsCombo );
1143
1144 // bit of fiddlyness here -- we want the initial spacing to only be visible
1145 // when the warning label is shown, so it's embedded inside mWarningLabel
1146 // instead of outside it
1147 mWarningLabel = new QWidget();
1148 QHBoxLayout *warningLayout = new QHBoxLayout();
1149 warningLayout->setContentsMargins( 0, 0, 0, 0 );
1150 QLabel *warning = new QLabel();
1151 QIcon icon = QgsApplication::getThemeIcon( QStringLiteral( "mIconWarning.svg" ) );
1152 const int size = static_cast<int>( std::max( 24.0, spin->minimumSize().height() * 0.5 ) );
1153 warning->setPixmap( icon.pixmap( icon.actualSize( QSize( size, size ) ) ) );
1154 warning->setToolTip( tr( "Distance is in geographic degrees. Consider reprojecting to a projected local coordinate system for accurate results." ) );
1155 warningLayout->insertSpacing( 0, labelMargin / 2 );
1156 warningLayout->insertWidget( 1, warning );
1157 mWarningLabel->setLayout( warningLayout );
1158 layout->insertWidget( 4, mWarningLabel );
1159
1160 QWidget *w = new QWidget();
1161 layout->setContentsMargins( 0, 0, 0, 0 );
1162 w->setLayout( layout );
1163
1164 setUnits( distanceDef->defaultUnit() );
1165
1166 return w;
1167 }
1168
1171 return spin;
1172 }
1173 return nullptr;
1174}
1175
1176void QgsProcessingDistanceWidgetWrapper::postInitialize( const QList<QgsAbstractProcessingParameterWidgetWrapper *> &wrappers )
1177{
1178 QgsProcessingNumericWidgetWrapper::postInitialize( wrappers );
1179 switch ( type() )
1180 {
1182 {
1183 for ( const QgsAbstractProcessingParameterWidgetWrapper *wrapper : wrappers )
1184 {
1185 if ( wrapper->parameterDefinition()->name() == static_cast<const QgsProcessingParameterDistance *>( parameterDefinition() )->parentParameterName() )
1186 {
1187 setUnitParameterValue( wrapper->parameterValue(), wrapper );
1189 setUnitParameterValue( wrapper->parameterValue(), wrapper );
1190 } );
1191 break;
1192 }
1193 }
1194 break;
1195 }
1196
1199 break;
1200 }
1201}
1202
1203void QgsProcessingDistanceWidgetWrapper::setUnitParameterValue( const QVariant &value, const QgsAbstractProcessingParameterWidgetWrapper *wrapper )
1204{
1206
1207 // evaluate value to layer
1208 QgsProcessingContext *context = nullptr;
1209 std::unique_ptr<QgsProcessingContext> tmpContext;
1210 if ( mProcessingContextGenerator )
1211 context = mProcessingContextGenerator->processingContext();
1212
1213 if ( !context )
1214 {
1215 tmpContext = std::make_unique<QgsProcessingContext>();
1216 context = tmpContext.get();
1217 }
1218
1219 const QgsCoordinateReferenceSystem crs = wrapper
1221 : QgsProcessingUtils::variantToCrs( value, *context );
1222 if ( crs.isValid() )
1223 {
1224 units = crs.mapUnits();
1225 }
1226
1227 setUnits( units );
1228}
1229
1230void QgsProcessingDistanceWidgetWrapper::setUnits( Qgis::DistanceUnit units )
1231{
1232 mLabel->setText( QgsUnitTypes::toString( units ) );
1234 {
1235 mUnitsCombo->hide();
1236 mLabel->show();
1237 }
1238 else
1239 {
1240 mUnitsCombo->setCurrentIndex( mUnitsCombo->findData( static_cast<int>( units ) ) );
1241 mUnitsCombo->show();
1242 mLabel->hide();
1243 }
1244 mWarningLabel->setVisible( units == Qgis::DistanceUnit::Degrees );
1245 mBaseUnit = units;
1246}
1247
1248QVariant QgsProcessingDistanceWidgetWrapper::widgetValue() const
1249{
1250 const QVariant val = QgsProcessingNumericWidgetWrapper::widgetValue();
1251 if ( val.userType() == QMetaType::Type::Double && mUnitsCombo && mUnitsCombo->isVisible() )
1252 {
1253 Qgis::DistanceUnit displayUnit = static_cast<Qgis::DistanceUnit>( mUnitsCombo->currentData().toInt() );
1254 return val.toDouble() * QgsUnitTypes::fromUnitToUnitFactor( displayUnit, mBaseUnit );
1255 }
1256 else
1257 {
1258 return val;
1259 }
1260}
1261
1262QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingDistanceWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
1263{
1264 return new QgsProcessingDistanceParameterDefinitionWidget( context, widgetContext, definition, algorithm );
1265}
1266
1267
1268//
1269// QgsProcessingAreaParameterDefinitionWidget
1270//
1271
1272QgsProcessingAreaParameterDefinitionWidget::QgsProcessingAreaParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
1273 : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
1274{
1275 QVBoxLayout *vlayout = new QVBoxLayout();
1276 vlayout->setContentsMargins( 0, 0, 0, 0 );
1277
1278 vlayout->addWidget( new QLabel( tr( "Linked input" ) ) );
1279
1280 mParentLayerComboBox = new QComboBox();
1281
1282 QString initialParent;
1283 if ( const QgsProcessingParameterArea *areaParam = dynamic_cast<const QgsProcessingParameterArea *>( definition ) )
1284 initialParent = areaParam->parentParameterName();
1285
1286 if ( auto *lModel = widgetContext.model() )
1287 {
1288 // populate combo box with other model input choices
1289 const QMap<QString, QgsProcessingModelParameter> components = lModel->parameterComponents();
1290 for ( auto it = components.constBegin(); it != components.constEnd(); ++it )
1291 {
1292 if ( const QgsProcessingParameterFeatureSource *definition = dynamic_cast<const QgsProcessingParameterFeatureSource *>( lModel->parameterDefinition( it.value().parameterName() ) ) )
1293 {
1294 mParentLayerComboBox->addItem( definition->description(), definition->name() );
1295 if ( !initialParent.isEmpty() && initialParent == definition->name() )
1296 {
1297 mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
1298 }
1299 }
1300 else if ( const QgsProcessingParameterVectorLayer *definition = dynamic_cast<const QgsProcessingParameterVectorLayer *>( lModel->parameterDefinition( it.value().parameterName() ) ) )
1301 {
1302 mParentLayerComboBox->addItem( definition->description(), definition->name() );
1303 if ( !initialParent.isEmpty() && initialParent == definition->name() )
1304 {
1305 mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
1306 }
1307 }
1308 else if ( const QgsProcessingParameterMapLayer *definition = dynamic_cast<const QgsProcessingParameterMapLayer *>( lModel->parameterDefinition( it.value().parameterName() ) ) )
1309 {
1310 mParentLayerComboBox->addItem( definition->description(), definition->name() );
1311 if ( !initialParent.isEmpty() && initialParent == definition->name() )
1312 {
1313 mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
1314 }
1315 }
1316 else if ( const QgsProcessingParameterCrs *definition = dynamic_cast<const QgsProcessingParameterCrs *>( lModel->parameterDefinition( it.value().parameterName() ) ) )
1317 {
1318 mParentLayerComboBox->addItem( definition->description(), definition->name() );
1319 if ( !initialParent.isEmpty() && initialParent == definition->name() )
1320 {
1321 mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
1322 }
1323 }
1324 }
1325 }
1326
1327 if ( mParentLayerComboBox->count() == 0 && !initialParent.isEmpty() )
1328 {
1329 // if no parent candidates found, we just add the existing one as a placeholder
1330 mParentLayerComboBox->addItem( initialParent, initialParent );
1331 mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
1332 }
1333
1334 vlayout->addWidget( mParentLayerComboBox );
1335
1336 vlayout->addWidget( new QLabel( tr( "Minimum value" ) ) );
1337 mMinLineEdit = new QLineEdit();
1338 vlayout->addWidget( mMinLineEdit );
1339
1340 vlayout->addWidget( new QLabel( tr( "Maximum value" ) ) );
1341 mMaxLineEdit = new QLineEdit();
1342 vlayout->addWidget( mMaxLineEdit );
1343
1344 vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
1345 mDefaultLineEdit = new QLineEdit();
1346 vlayout->addWidget( mDefaultLineEdit );
1347
1348 if ( const QgsProcessingParameterArea *areaParam = dynamic_cast<const QgsProcessingParameterArea *>( definition ) )
1349 {
1350 mMinLineEdit->setText( QLocale().toString( areaParam->minimum() ) );
1351 mMaxLineEdit->setText( QLocale().toString( areaParam->maximum() ) );
1352 mDefaultLineEdit->setText( areaParam->defaultValueForGui().toString() );
1353 }
1354
1355 setLayout( vlayout );
1356}
1357
1358QgsProcessingParameterDefinition *QgsProcessingAreaParameterDefinitionWidget::createParameter( const QString &name, const QString &description, Qgis::ProcessingParameterFlags flags ) const
1359{
1360 bool ok;
1361 double val = QgsDoubleValidator::toDouble( mDefaultLineEdit->text(), &ok );
1362
1363 auto param = std::make_unique<QgsProcessingParameterArea>( name, description, ok ? val : QVariant(), mParentLayerComboBox->currentData().toString() );
1364
1365 val = QgsDoubleValidator::toDouble( mMinLineEdit->text(), &ok );
1366 if ( ok )
1367 {
1368 param->setMinimum( val );
1369 }
1370
1371 val = QgsDoubleValidator::toDouble( mMaxLineEdit->text(), &ok );
1372 if ( ok )
1373 {
1374 param->setMaximum( val );
1375 }
1376
1377 param->setFlags( flags );
1378 return param.release();
1379}
1380
1381
1382//
1383// QgsProcessingAreaWidgetWrapper
1384//
1385
1386QgsProcessingAreaWidgetWrapper::QgsProcessingAreaWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
1387 : QgsProcessingNumericWidgetWrapper( parameter, type, parent )
1388{
1389}
1390
1391QString QgsProcessingAreaWidgetWrapper::parameterType() const
1392{
1394}
1395
1396QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingAreaWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
1397{
1398 return new QgsProcessingAreaWidgetWrapper( parameter, type );
1399}
1400
1401QWidget *QgsProcessingAreaWidgetWrapper::createWidget()
1402{
1403 const QgsProcessingParameterArea *areaDef = static_cast<const QgsProcessingParameterArea *>( parameterDefinition() );
1404
1405 QWidget *spin = QgsProcessingNumericWidgetWrapper::createWidget();
1406 switch ( type() )
1407 {
1409 {
1410 mLabel = new QLabel();
1411 mUnitsCombo = new QComboBox();
1412
1413 mUnitsCombo->addItem( QgsUnitTypes::toString( Qgis::AreaUnit::SquareMeters ), QVariant::fromValue( Qgis::AreaUnit::SquareMeters ) );
1414 mUnitsCombo->addItem( QgsUnitTypes::toString( Qgis::AreaUnit::SquareKilometers ), QVariant::fromValue( Qgis::AreaUnit::SquareKilometers ) );
1415 mUnitsCombo->addItem( QgsUnitTypes::toString( Qgis::AreaUnit::SquareFeet ), QVariant::fromValue( Qgis::AreaUnit::SquareFeet ) );
1416 mUnitsCombo->addItem( QgsUnitTypes::toString( Qgis::AreaUnit::SquareYards ), QVariant::fromValue( Qgis::AreaUnit::SquareYards ) );
1417 mUnitsCombo->addItem( QgsUnitTypes::toString( Qgis::AreaUnit::SquareMiles ), QVariant::fromValue( Qgis::AreaUnit::SquareMiles ) );
1418 mUnitsCombo->addItem( QgsUnitTypes::toString( Qgis::AreaUnit::Hectares ), QVariant::fromValue( Qgis::AreaUnit::Hectares ) );
1419 mUnitsCombo->addItem( QgsUnitTypes::toString( Qgis::AreaUnit::Acres ), QVariant::fromValue( Qgis::AreaUnit::Acres ) );
1421 mUnitsCombo->addItem( QgsUnitTypes::toString( Qgis::AreaUnit::SquareDegrees ), QVariant::fromValue( Qgis::AreaUnit::SquareDegrees ) );
1422 mUnitsCombo->addItem( QgsUnitTypes::toString( Qgis::AreaUnit::SquareCentimeters ), QVariant::fromValue( Qgis::AreaUnit::SquareCentimeters ) );
1423 mUnitsCombo->addItem( QgsUnitTypes::toString( Qgis::AreaUnit::SquareMillimeters ), QVariant::fromValue( Qgis::AreaUnit::SquareMillimeters ) );
1424 mUnitsCombo->addItem( QgsUnitTypes::toString( Qgis::AreaUnit::SquareInches ), QVariant::fromValue( Qgis::AreaUnit::SquareInches ) );
1425
1426 const int labelMargin = static_cast<int>( std::round( mUnitsCombo->fontMetrics().horizontalAdvance( 'X' ) ) );
1427 QHBoxLayout *layout = new QHBoxLayout();
1428 layout->addWidget( spin, 1 );
1429 layout->insertSpacing( 1, labelMargin / 2 );
1430 layout->insertWidget( 2, mLabel );
1431 layout->insertWidget( 3, mUnitsCombo );
1432
1433 // bit of fiddlyness here -- we want the initial spacing to only be visible
1434 // when the warning label is shown, so it's embedded inside mWarningLabel
1435 // instead of outside it
1436 mWarningLabel = new QWidget();
1437 QHBoxLayout *warningLayout = new QHBoxLayout();
1438 warningLayout->setContentsMargins( 0, 0, 0, 0 );
1439 QLabel *warning = new QLabel();
1440 QIcon icon = QgsApplication::getThemeIcon( QStringLiteral( "mIconWarning.svg" ) );
1441 const int size = static_cast<int>( std::max( 24.0, spin->minimumSize().height() * 0.5 ) );
1442 warning->setPixmap( icon.pixmap( icon.actualSize( QSize( size, size ) ) ) );
1443 warning->setToolTip( tr( "Area is in geographic degrees. Consider reprojecting to a projected local coordinate system for accurate results." ) );
1444 warningLayout->insertSpacing( 0, labelMargin / 2 );
1445 warningLayout->insertWidget( 1, warning );
1446 mWarningLabel->setLayout( warningLayout );
1447 layout->insertWidget( 4, mWarningLabel );
1448
1449 QWidget *w = new QWidget();
1450 layout->setContentsMargins( 0, 0, 0, 0 );
1451 w->setLayout( layout );
1452
1453 setUnits( areaDef->defaultUnit() );
1454
1455 return w;
1456 }
1457
1460 return spin;
1461 }
1462 return nullptr;
1463}
1464
1465void QgsProcessingAreaWidgetWrapper::postInitialize( const QList<QgsAbstractProcessingParameterWidgetWrapper *> &wrappers )
1466{
1467 QgsProcessingNumericWidgetWrapper::postInitialize( wrappers );
1468 switch ( type() )
1469 {
1471 {
1472 for ( const QgsAbstractProcessingParameterWidgetWrapper *wrapper : wrappers )
1473 {
1474 if ( wrapper->parameterDefinition()->name() == static_cast<const QgsProcessingParameterArea *>( parameterDefinition() )->parentParameterName() )
1475 {
1476 setUnitParameterValue( wrapper->parameterValue(), wrapper );
1478 setUnitParameterValue( wrapper->parameterValue(), wrapper );
1479 } );
1480 break;
1481 }
1482 }
1483 break;
1484 }
1485
1488 break;
1489 }
1490}
1491
1492void QgsProcessingAreaWidgetWrapper::setUnitParameterValue( const QVariant &value, const QgsAbstractProcessingParameterWidgetWrapper *wrapper )
1493{
1495
1496 // evaluate value to layer
1497 QgsProcessingContext *context = nullptr;
1498 std::unique_ptr<QgsProcessingContext> tmpContext;
1499 if ( mProcessingContextGenerator )
1500 context = mProcessingContextGenerator->processingContext();
1501
1502 if ( !context )
1503 {
1504 tmpContext = std::make_unique<QgsProcessingContext>();
1505 context = tmpContext.get();
1506 }
1507
1508 const QgsCoordinateReferenceSystem crs = wrapper
1510 : QgsProcessingUtils::variantToCrs( value, *context );
1511 if ( crs.isValid() )
1512 {
1514 }
1515
1516 setUnits( units );
1517}
1518
1519void QgsProcessingAreaWidgetWrapper::setUnits( Qgis::AreaUnit units )
1520{
1521 mLabel->setText( QgsUnitTypes::toString( units ) );
1523 {
1524 mUnitsCombo->hide();
1525 mLabel->show();
1526 }
1527 else
1528 {
1529 mUnitsCombo->setCurrentIndex( mUnitsCombo->findData( QVariant::fromValue( units ) ) );
1530 mUnitsCombo->show();
1531 mLabel->hide();
1532 }
1533 mWarningLabel->setVisible( units == Qgis::AreaUnit::SquareDegrees );
1534 mBaseUnit = units;
1535}
1536
1537QVariant QgsProcessingAreaWidgetWrapper::widgetValue() const
1538{
1539 const QVariant val = QgsProcessingNumericWidgetWrapper::widgetValue();
1540 if ( val.userType() == QMetaType::Type::Double && mUnitsCombo && mUnitsCombo->isVisible() )
1541 {
1542 const Qgis::AreaUnit displayUnit = mUnitsCombo->currentData().value<Qgis::AreaUnit>();
1543 return val.toDouble() * QgsUnitTypes::fromUnitToUnitFactor( displayUnit, mBaseUnit );
1544 }
1545 else
1546 {
1547 return val;
1548 }
1549}
1550
1551QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingAreaWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
1552{
1553 return new QgsProcessingAreaParameterDefinitionWidget( context, widgetContext, definition, algorithm );
1554}
1555
1556
1557//
1558// QgsProcessingVolumeParameterDefinitionWidget
1559//
1560
1561QgsProcessingVolumeParameterDefinitionWidget::QgsProcessingVolumeParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
1562 : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
1563{
1564 QVBoxLayout *vlayout = new QVBoxLayout();
1565 vlayout->setContentsMargins( 0, 0, 0, 0 );
1566
1567 vlayout->addWidget( new QLabel( tr( "Linked input" ) ) );
1568
1569 mParentLayerComboBox = new QComboBox();
1570
1571 QString initialParent;
1572 if ( const QgsProcessingParameterVolume *volumeParam = dynamic_cast<const QgsProcessingParameterVolume *>( definition ) )
1573 initialParent = volumeParam->parentParameterName();
1574
1575 if ( auto *lModel = widgetContext.model() )
1576 {
1577 // populate combo box with other model input choices
1578 const QMap<QString, QgsProcessingModelParameter> components = lModel->parameterComponents();
1579 for ( auto it = components.constBegin(); it != components.constEnd(); ++it )
1580 {
1581 if ( const QgsProcessingParameterFeatureSource *definition = dynamic_cast<const QgsProcessingParameterFeatureSource *>( lModel->parameterDefinition( it.value().parameterName() ) ) )
1582 {
1583 mParentLayerComboBox->addItem( definition->description(), definition->name() );
1584 if ( !initialParent.isEmpty() && initialParent == definition->name() )
1585 {
1586 mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
1587 }
1588 }
1589 else if ( const QgsProcessingParameterVectorLayer *definition = dynamic_cast<const QgsProcessingParameterVectorLayer *>( lModel->parameterDefinition( it.value().parameterName() ) ) )
1590 {
1591 mParentLayerComboBox->addItem( definition->description(), definition->name() );
1592 if ( !initialParent.isEmpty() && initialParent == definition->name() )
1593 {
1594 mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
1595 }
1596 }
1597 else if ( const QgsProcessingParameterMapLayer *definition = dynamic_cast<const QgsProcessingParameterMapLayer *>( lModel->parameterDefinition( it.value().parameterName() ) ) )
1598 {
1599 mParentLayerComboBox->addItem( definition->description(), definition->name() );
1600 if ( !initialParent.isEmpty() && initialParent == definition->name() )
1601 {
1602 mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
1603 }
1604 }
1605 else if ( const QgsProcessingParameterCrs *definition = dynamic_cast<const QgsProcessingParameterCrs *>( lModel->parameterDefinition( it.value().parameterName() ) ) )
1606 {
1607 mParentLayerComboBox->addItem( definition->description(), definition->name() );
1608 if ( !initialParent.isEmpty() && initialParent == definition->name() )
1609 {
1610 mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
1611 }
1612 }
1613 }
1614 }
1615
1616 if ( mParentLayerComboBox->count() == 0 && !initialParent.isEmpty() )
1617 {
1618 // if no parent candidates found, we just add the existing one as a placeholder
1619 mParentLayerComboBox->addItem( initialParent, initialParent );
1620 mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
1621 }
1622
1623 vlayout->addWidget( mParentLayerComboBox );
1624
1625 vlayout->addWidget( new QLabel( tr( "Minimum value" ) ) );
1626 mMinLineEdit = new QLineEdit();
1627 vlayout->addWidget( mMinLineEdit );
1628
1629 vlayout->addWidget( new QLabel( tr( "Maximum value" ) ) );
1630 mMaxLineEdit = new QLineEdit();
1631 vlayout->addWidget( mMaxLineEdit );
1632
1633 vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
1634 mDefaultLineEdit = new QLineEdit();
1635 vlayout->addWidget( mDefaultLineEdit );
1636
1637 if ( const QgsProcessingParameterVolume *volumeParam = dynamic_cast<const QgsProcessingParameterVolume *>( definition ) )
1638 {
1639 mMinLineEdit->setText( QLocale().toString( volumeParam->minimum() ) );
1640 mMaxLineEdit->setText( QLocale().toString( volumeParam->maximum() ) );
1641 mDefaultLineEdit->setText( volumeParam->defaultValueForGui().toString() );
1642 }
1643
1644 setLayout( vlayout );
1645}
1646
1647QgsProcessingParameterDefinition *QgsProcessingVolumeParameterDefinitionWidget::createParameter( const QString &name, const QString &description, Qgis::ProcessingParameterFlags flags ) const
1648{
1649 bool ok;
1650 double val = QgsDoubleValidator::toDouble( mDefaultLineEdit->text(), &ok );
1651
1652 auto param = std::make_unique<QgsProcessingParameterVolume>( name, description, ok ? val : QVariant(), mParentLayerComboBox->currentData().toString() );
1653
1654 val = QgsDoubleValidator::toDouble( mMinLineEdit->text(), &ok );
1655 if ( ok )
1656 {
1657 param->setMinimum( val );
1658 }
1659
1660 val = QgsDoubleValidator::toDouble( mMaxLineEdit->text(), &ok );
1661 if ( ok )
1662 {
1663 param->setMaximum( val );
1664 }
1665
1666 param->setFlags( flags );
1667 return param.release();
1668}
1669
1670
1671//
1672// QgsProcessingVolumeWidgetWrapper
1673//
1674
1675QgsProcessingVolumeWidgetWrapper::QgsProcessingVolumeWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
1676 : QgsProcessingNumericWidgetWrapper( parameter, type, parent )
1677{
1678}
1679
1680QString QgsProcessingVolumeWidgetWrapper::parameterType() const
1681{
1683}
1684
1685QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingVolumeWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
1686{
1687 return new QgsProcessingVolumeWidgetWrapper( parameter, type );
1688}
1689
1690QWidget *QgsProcessingVolumeWidgetWrapper::createWidget()
1691{
1692 const QgsProcessingParameterVolume *volumeDef = static_cast<const QgsProcessingParameterVolume *>( parameterDefinition() );
1693
1694 QWidget *spin = QgsProcessingNumericWidgetWrapper::createWidget();
1695 switch ( type() )
1696 {
1698 {
1699 mLabel = new QLabel();
1700 mUnitsCombo = new QComboBox();
1701
1702 mUnitsCombo->addItem( QgsUnitTypes::toString( Qgis::VolumeUnit::CubicMeters ), QVariant::fromValue( Qgis::VolumeUnit::CubicMeters ) );
1703 mUnitsCombo->addItem( QgsUnitTypes::toString( Qgis::VolumeUnit::CubicFeet ), QVariant::fromValue( Qgis::VolumeUnit::CubicFeet ) );
1704 mUnitsCombo->addItem( QgsUnitTypes::toString( Qgis::VolumeUnit::CubicYards ), QVariant::fromValue( Qgis::VolumeUnit::CubicYards ) );
1705 mUnitsCombo->addItem( QgsUnitTypes::toString( Qgis::VolumeUnit::Barrel ), QVariant::fromValue( Qgis::VolumeUnit::Barrel ) );
1706 mUnitsCombo->addItem( QgsUnitTypes::toString( Qgis::VolumeUnit::CubicDecimeter ), QVariant::fromValue( Qgis::VolumeUnit::CubicDecimeter ) );
1707 mUnitsCombo->addItem( QgsUnitTypes::toString( Qgis::VolumeUnit::Liters ), QVariant::fromValue( Qgis::VolumeUnit::Liters ) );
1708 mUnitsCombo->addItem( QgsUnitTypes::toString( Qgis::VolumeUnit::GallonUS ), QVariant::fromValue( Qgis::VolumeUnit::GallonUS ) );
1709 mUnitsCombo->addItem( QgsUnitTypes::toString( Qgis::VolumeUnit::CubicInch ), QVariant::fromValue( Qgis::VolumeUnit::CubicInch ) );
1710 mUnitsCombo->addItem( QgsUnitTypes::toString( Qgis::VolumeUnit::CubicCentimeter ), QVariant::fromValue( Qgis::VolumeUnit::CubicCentimeter ) );
1711 mUnitsCombo->addItem( QgsUnitTypes::toString( Qgis::VolumeUnit::CubicDegrees ), QVariant::fromValue( Qgis::VolumeUnit::CubicDegrees ) );
1712
1713 const int labelMargin = static_cast<int>( std::round( mUnitsCombo->fontMetrics().horizontalAdvance( 'X' ) ) );
1714 QHBoxLayout *layout = new QHBoxLayout();
1715 layout->addWidget( spin, 1 );
1716 layout->insertSpacing( 1, labelMargin / 2 );
1717 layout->insertWidget( 2, mLabel );
1718 layout->insertWidget( 3, mUnitsCombo );
1719
1720 // bit of fiddlyness here -- we want the initial spacing to only be visible
1721 // when the warning label is shown, so it's embedded inside mWarningLabel
1722 // instead of outside it
1723 mWarningLabel = new QWidget();
1724 QHBoxLayout *warningLayout = new QHBoxLayout();
1725 warningLayout->setContentsMargins( 0, 0, 0, 0 );
1726 QLabel *warning = new QLabel();
1727 QIcon icon = QgsApplication::getThemeIcon( QStringLiteral( "mIconWarning.svg" ) );
1728 const int size = static_cast<int>( std::max( 24.0, spin->minimumSize().height() * 0.5 ) );
1729 warning->setPixmap( icon.pixmap( icon.actualSize( QSize( size, size ) ) ) );
1730 warning->setToolTip( tr( "Volume is in geographic degrees. Consider reprojecting to a projected local coordinate system for accurate results." ) );
1731 warningLayout->insertSpacing( 0, labelMargin / 2 );
1732 warningLayout->insertWidget( 1, warning );
1733 mWarningLabel->setLayout( warningLayout );
1734 layout->insertWidget( 4, mWarningLabel );
1735
1736 QWidget *w = new QWidget();
1737 layout->setContentsMargins( 0, 0, 0, 0 );
1738 w->setLayout( layout );
1739
1740 setUnits( volumeDef->defaultUnit() );
1741
1742 return w;
1743 }
1744
1747 return spin;
1748 }
1749 return nullptr;
1750}
1751
1752void QgsProcessingVolumeWidgetWrapper::postInitialize( const QList<QgsAbstractProcessingParameterWidgetWrapper *> &wrappers )
1753{
1754 QgsProcessingNumericWidgetWrapper::postInitialize( wrappers );
1755 switch ( type() )
1756 {
1758 {
1759 for ( const QgsAbstractProcessingParameterWidgetWrapper *wrapper : wrappers )
1760 {
1761 if ( wrapper->parameterDefinition()->name() == static_cast<const QgsProcessingParameterVolume *>( parameterDefinition() )->parentParameterName() )
1762 {
1763 setUnitParameterValue( wrapper->parameterValue(), wrapper );
1765 setUnitParameterValue( wrapper->parameterValue(), wrapper );
1766 } );
1767 break;
1768 }
1769 }
1770 break;
1771 }
1772
1775 break;
1776 }
1777}
1778
1779void QgsProcessingVolumeWidgetWrapper::setUnitParameterValue( const QVariant &value, const QgsAbstractProcessingParameterWidgetWrapper *wrapper )
1780{
1782
1783 // evaluate value to layer
1784 QgsProcessingContext *context = nullptr;
1785 std::unique_ptr<QgsProcessingContext> tmpContext;
1786 if ( mProcessingContextGenerator )
1787 context = mProcessingContextGenerator->processingContext();
1788
1789 if ( !context )
1790 {
1791 tmpContext = std::make_unique<QgsProcessingContext>();
1792 context = tmpContext.get();
1793 }
1794
1795 const QgsCoordinateReferenceSystem crs = wrapper
1797 : QgsProcessingUtils::variantToCrs( value, *context );
1798 if ( crs.isValid() )
1799 {
1801 }
1802
1803 setUnits( units );
1804}
1805
1806void QgsProcessingVolumeWidgetWrapper::setUnits( Qgis::VolumeUnit units )
1807{
1808 mLabel->setText( QgsUnitTypes::toString( units ) );
1810 {
1811 mUnitsCombo->hide();
1812 mLabel->show();
1813 }
1814 else
1815 {
1816 mUnitsCombo->setCurrentIndex( mUnitsCombo->findData( QVariant::fromValue( units ) ) );
1817 mUnitsCombo->show();
1818 mLabel->hide();
1819 }
1820 mWarningLabel->setVisible( units == Qgis::VolumeUnit::CubicDegrees );
1821 mBaseUnit = units;
1822}
1823
1824QVariant QgsProcessingVolumeWidgetWrapper::widgetValue() const
1825{
1826 const QVariant val = QgsProcessingNumericWidgetWrapper::widgetValue();
1827 if ( val.userType() == QMetaType::Type::Double && mUnitsCombo && mUnitsCombo->isVisible() )
1828 {
1829 const Qgis::VolumeUnit displayUnit = mUnitsCombo->currentData().value<Qgis::VolumeUnit>();
1830 return val.toDouble() * QgsUnitTypes::fromUnitToUnitFactor( displayUnit, mBaseUnit );
1831 }
1832 else
1833 {
1834 return val;
1835 }
1836}
1837
1838QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingVolumeWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
1839{
1840 return new QgsProcessingVolumeParameterDefinitionWidget( context, widgetContext, definition, algorithm );
1841}
1842
1843
1844//
1845// QgsProcessingDurationWidgetWrapper
1846//
1847
1848QgsProcessingDurationParameterDefinitionWidget::QgsProcessingDurationParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
1849 : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
1850{
1851 QVBoxLayout *vlayout = new QVBoxLayout();
1852 vlayout->setContentsMargins( 0, 0, 0, 0 );
1853
1854 vlayout->addWidget( new QLabel( tr( "Minimum value" ) ) );
1855 mMinLineEdit = new QLineEdit();
1856 vlayout->addWidget( mMinLineEdit );
1857
1858 vlayout->addWidget( new QLabel( tr( "Maximum value" ) ) );
1859 mMaxLineEdit = new QLineEdit();
1860 vlayout->addWidget( mMaxLineEdit );
1861
1862 vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
1863 mDefaultLineEdit = new QLineEdit();
1864 vlayout->addWidget( mDefaultLineEdit );
1865
1866 vlayout->addWidget( new QLabel( tr( "Default unit type" ) ) );
1867
1868 mUnitsCombo = new QComboBox();
1870 mUnitsCombo->addItem( QgsUnitTypes::toString( Qgis::TemporalUnit::Seconds ), static_cast<int>( Qgis::TemporalUnit::Seconds ) );
1871 mUnitsCombo->addItem( QgsUnitTypes::toString( Qgis::TemporalUnit::Minutes ), static_cast<int>( Qgis::TemporalUnit::Minutes ) );
1872 mUnitsCombo->addItem( QgsUnitTypes::toString( Qgis::TemporalUnit::Hours ), static_cast<int>( Qgis::TemporalUnit::Hours ) );
1873 mUnitsCombo->addItem( QgsUnitTypes::toString( Qgis::TemporalUnit::Days ), static_cast<int>( Qgis::TemporalUnit::Days ) );
1874 mUnitsCombo->addItem( QgsUnitTypes::toString( Qgis::TemporalUnit::Weeks ), static_cast<int>( Qgis::TemporalUnit::Weeks ) );
1875 mUnitsCombo->addItem( tr( "years (365.25 days)" ), static_cast<int>( Qgis::TemporalUnit::Years ) );
1876 mUnitsCombo->addItem( QgsUnitTypes::toString( Qgis::TemporalUnit::Decades ), static_cast<int>( Qgis::TemporalUnit::Decades ) );
1877 mUnitsCombo->addItem( QgsUnitTypes::toString( Qgis::TemporalUnit::Centuries ), static_cast<int>( Qgis::TemporalUnit::Centuries ) );
1878 vlayout->addWidget( mUnitsCombo );
1879
1880 if ( const QgsProcessingParameterDuration *durationParam = dynamic_cast<const QgsProcessingParameterDuration *>( definition ) )
1881 {
1882 mMinLineEdit->setText( QLocale().toString( durationParam->minimum() ) );
1883 mMaxLineEdit->setText( QLocale().toString( durationParam->maximum() ) );
1884 mDefaultLineEdit->setText( durationParam->defaultValueForGui().toString() );
1885 mUnitsCombo->setCurrentIndex( mUnitsCombo->findData( static_cast<int>( durationParam->defaultUnit() ) ) );
1886 }
1887
1888 setLayout( vlayout );
1889}
1890
1891QgsProcessingParameterDefinition *QgsProcessingDurationParameterDefinitionWidget::createParameter( const QString &name, const QString &description, Qgis::ProcessingParameterFlags flags ) const
1892{
1893 bool ok;
1894 double val = QgsDoubleValidator::toDouble( mDefaultLineEdit->text(), &ok );
1895
1896 auto param = std::make_unique<QgsProcessingParameterDuration>( name, description, ok ? val : QVariant() );
1897
1898 val = QgsDoubleValidator::toDouble( mMinLineEdit->text(), &ok );
1899 if ( ok )
1900 {
1901 param->setMinimum( val );
1902 }
1903
1904 val = QgsDoubleValidator::toDouble( mMaxLineEdit->text(), &ok );
1905 if ( ok )
1906 {
1907 param->setMaximum( val );
1908 }
1909
1910 param->setDefaultUnit( static_cast<Qgis::TemporalUnit>( mUnitsCombo->currentData().toInt() ) );
1911
1912 param->setFlags( flags );
1913 return param.release();
1914}
1915
1916QgsProcessingDurationWidgetWrapper::QgsProcessingDurationWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
1917 : QgsProcessingNumericWidgetWrapper( parameter, type, parent )
1918{
1919}
1920
1921QString QgsProcessingDurationWidgetWrapper::parameterType() const
1922{
1924}
1925
1926QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingDurationWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
1927{
1928 return new QgsProcessingDurationWidgetWrapper( parameter, type );
1929}
1930
1931QWidget *QgsProcessingDurationWidgetWrapper::createWidget()
1932{
1933 const QgsProcessingParameterDuration *durationDef = static_cast<const QgsProcessingParameterDuration *>( parameterDefinition() );
1934
1935 QWidget *spin = QgsProcessingNumericWidgetWrapper::createWidget();
1936 switch ( type() )
1937 {
1939 {
1940 mUnitsCombo = new QComboBox();
1941
1943 mUnitsCombo->addItem( QgsUnitTypes::toString( Qgis::TemporalUnit::Seconds ), static_cast<int>( Qgis::TemporalUnit::Seconds ) );
1944 mUnitsCombo->addItem( QgsUnitTypes::toString( Qgis::TemporalUnit::Minutes ), static_cast<int>( Qgis::TemporalUnit::Minutes ) );
1945 mUnitsCombo->addItem( QgsUnitTypes::toString( Qgis::TemporalUnit::Hours ), static_cast<int>( Qgis::TemporalUnit::Hours ) );
1946 mUnitsCombo->addItem( QgsUnitTypes::toString( Qgis::TemporalUnit::Days ), static_cast<int>( Qgis::TemporalUnit::Days ) );
1947 mUnitsCombo->addItem( QgsUnitTypes::toString( Qgis::TemporalUnit::Weeks ), static_cast<int>( Qgis::TemporalUnit::Weeks ) );
1948 mUnitsCombo->addItem( tr( "years (365.25 days)" ), static_cast<int>( Qgis::TemporalUnit::Years ) );
1949 mUnitsCombo->addItem( QgsUnitTypes::toString( Qgis::TemporalUnit::Decades ), static_cast<int>( Qgis::TemporalUnit::Decades ) );
1950 mUnitsCombo->addItem( QgsUnitTypes::toString( Qgis::TemporalUnit::Centuries ), static_cast<int>( Qgis::TemporalUnit::Centuries ) );
1951
1952 QHBoxLayout *layout = new QHBoxLayout();
1953 layout->addWidget( spin, 1 );
1954 layout->insertWidget( 1, mUnitsCombo );
1955
1956 QWidget *w = new QWidget();
1957 layout->setContentsMargins( 0, 0, 0, 0 );
1958 w->setLayout( layout );
1959
1960 mUnitsCombo->setCurrentIndex( mUnitsCombo->findData( static_cast<int>( durationDef->defaultUnit() ) ) );
1961 mUnitsCombo->show();
1962
1963 return w;
1964 }
1965
1968 return spin;
1969 }
1970 return nullptr;
1971}
1972
1973QLabel *QgsProcessingDurationWidgetWrapper::createLabel()
1974{
1976
1977 if ( type() == QgsProcessingGui::Modeler )
1978 {
1979 label->setText( QStringLiteral( "%1 [%2]" ).arg( label->text(), QgsUnitTypes::toString( mBaseUnit ) ) );
1980 }
1981
1982 return label;
1983}
1984
1985QVariant QgsProcessingDurationWidgetWrapper::widgetValue() const
1986{
1987 const QVariant val = QgsProcessingNumericWidgetWrapper::widgetValue();
1988 if ( val.userType() == QMetaType::Type::Double && mUnitsCombo )
1989 {
1990 Qgis::TemporalUnit displayUnit = static_cast<Qgis::TemporalUnit>( mUnitsCombo->currentData().toInt() );
1991 return val.toDouble() * QgsUnitTypes::fromUnitToUnitFactor( displayUnit, mBaseUnit );
1992 }
1993 else
1994 {
1995 return val;
1996 }
1997}
1998
1999void QgsProcessingDurationWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
2000{
2001 if ( mUnitsCombo )
2002 {
2003 Qgis::TemporalUnit displayUnit = static_cast<Qgis::TemporalUnit>( mUnitsCombo->currentData().toInt() );
2004 const QVariant val = value.toDouble() * QgsUnitTypes::fromUnitToUnitFactor( mBaseUnit, displayUnit );
2005 QgsProcessingNumericWidgetWrapper::setWidgetValue( val, context );
2006 }
2007 else
2008 {
2009 QgsProcessingNumericWidgetWrapper::setWidgetValue( value, context );
2010 }
2011}
2012
2013QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingDurationWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
2014{
2015 return new QgsProcessingDurationParameterDefinitionWidget( context, widgetContext, definition, algorithm );
2016}
2017
2018//
2019// QgsProcessingScaleWidgetWrapper
2020//
2021
2022QgsProcessingScaleParameterDefinitionWidget::QgsProcessingScaleParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
2023 : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
2024{
2025 QVBoxLayout *vlayout = new QVBoxLayout();
2026 vlayout->setContentsMargins( 0, 0, 0, 0 );
2027
2028 vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
2029
2030 mDefaultLineEdit = new QLineEdit();
2031
2032 if ( const QgsProcessingParameterScale *scaleParam = dynamic_cast<const QgsProcessingParameterScale *>( definition ) )
2033 {
2034 mDefaultLineEdit->setText( scaleParam->defaultValueForGui().toString() );
2035 }
2036
2037 vlayout->addWidget( mDefaultLineEdit );
2038
2039 setLayout( vlayout );
2040}
2041
2042QgsProcessingParameterDefinition *QgsProcessingScaleParameterDefinitionWidget::createParameter( const QString &name, const QString &description, Qgis::ProcessingParameterFlags flags ) const
2043{
2044 bool ok;
2045 double val = mDefaultLineEdit->text().toDouble( &ok );
2046 auto param = std::make_unique<QgsProcessingParameterScale>( name, description, ok ? val : QVariant() );
2047 param->setFlags( flags );
2048 return param.release();
2049}
2050
2051QgsProcessingScaleWidgetWrapper::QgsProcessingScaleWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
2052 : QgsProcessingNumericWidgetWrapper( parameter, type, parent )
2053{
2054}
2055
2056QString QgsProcessingScaleWidgetWrapper::parameterType() const
2057{
2059}
2060
2061QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingScaleWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
2062{
2063 return new QgsProcessingScaleWidgetWrapper( parameter, type );
2064}
2065
2066QWidget *QgsProcessingScaleWidgetWrapper::createWidget()
2067{
2068 const QgsProcessingParameterScale *scaleDef = static_cast<const QgsProcessingParameterScale *>( parameterDefinition() );
2069
2070 switch ( type() )
2071 {
2075 {
2076 mScaleWidget = new QgsScaleWidget( nullptr );
2078 mScaleWidget->setAllowNull( true );
2079
2080 mScaleWidget->setMapCanvas( widgetContext().mapCanvas() );
2081 mScaleWidget->setShowCurrentScaleButton( true );
2082
2083 mScaleWidget->setToolTip( parameterDefinition()->toolTip() );
2084 connect( mScaleWidget, &QgsScaleWidget::scaleChanged, this, [=]( double ) {
2085 emit widgetValueHasChanged( this );
2086 } );
2087 return mScaleWidget;
2088 }
2089 }
2090 return nullptr;
2091}
2092
2093void QgsProcessingScaleWidgetWrapper::setWidgetContext( const QgsProcessingParameterWidgetContext &context )
2094{
2095 if ( mScaleWidget )
2096 mScaleWidget->setMapCanvas( context.mapCanvas() );
2098}
2099
2100
2101QVariant QgsProcessingScaleWidgetWrapper::widgetValue() const
2102{
2103 return mScaleWidget && !mScaleWidget->isNull() ? QVariant( mScaleWidget->scale() ) : QVariant();
2104}
2105
2106void QgsProcessingScaleWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
2107{
2108 if ( mScaleWidget )
2109 {
2110 if ( mScaleWidget->allowNull() && !value.isValid() )
2111 mScaleWidget->setNull();
2112 else
2113 {
2114 const double v = QgsProcessingParameters::parameterAsDouble( parameterDefinition(), value, context );
2115 mScaleWidget->setScale( v );
2116 }
2117 }
2118}
2119
2120QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingScaleWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
2121{
2122 return new QgsProcessingScaleParameterDefinitionWidget( context, widgetContext, definition, algorithm );
2123}
2124
2125
2126//
2127// QgsProcessingRangeWidgetWrapper
2128//
2129
2130QgsProcessingRangeParameterDefinitionWidget::QgsProcessingRangeParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
2131 : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
2132{
2133 QVBoxLayout *vlayout = new QVBoxLayout();
2134 vlayout->setContentsMargins( 0, 0, 0, 0 );
2135
2136 vlayout->addWidget( new QLabel( tr( "Number type" ) ) );
2137
2138 mTypeComboBox = new QComboBox();
2139 mTypeComboBox->addItem( tr( "Float" ), static_cast<int>( Qgis::ProcessingNumberParameterType::Double ) );
2140 mTypeComboBox->addItem( tr( "Integer" ), static_cast<int>( Qgis::ProcessingNumberParameterType::Integer ) );
2141 vlayout->addWidget( mTypeComboBox );
2142
2143 vlayout->addWidget( new QLabel( tr( "Minimum value" ) ) );
2144 mMinLineEdit = new QLineEdit();
2145 vlayout->addWidget( mMinLineEdit );
2146
2147 vlayout->addWidget( new QLabel( tr( "Maximum value" ) ) );
2148 mMaxLineEdit = new QLineEdit();
2149 vlayout->addWidget( mMaxLineEdit );
2150
2151 if ( const QgsProcessingParameterRange *rangeParam = dynamic_cast<const QgsProcessingParameterRange *>( definition ) )
2152 {
2153 mTypeComboBox->setCurrentIndex( mTypeComboBox->findData( static_cast<int>( rangeParam->dataType() ) ) );
2154 const QList<double> range = QgsProcessingParameters::parameterAsRange( rangeParam, rangeParam->defaultValueForGui(), context );
2155 mMinLineEdit->setText( QLocale().toString( range.at( 0 ) ) );
2156 mMaxLineEdit->setText( QLocale().toString( range.at( 1 ) ) );
2157 }
2158
2159 setLayout( vlayout );
2160}
2161
2162QgsProcessingParameterDefinition *QgsProcessingRangeParameterDefinitionWidget::createParameter( const QString &name, const QString &description, Qgis::ProcessingParameterFlags flags ) const
2163{
2164 QString defaultValue;
2165 if ( mMinLineEdit->text().isEmpty() )
2166 {
2167 defaultValue = QStringLiteral( "None" );
2168 }
2169 else
2170 {
2171 bool ok;
2172 defaultValue = QString::number( QgsDoubleValidator::toDouble( mMinLineEdit->text(), &ok ) );
2173 if ( !ok )
2174 {
2175 defaultValue = QStringLiteral( "None" );
2176 }
2177 }
2178
2179 if ( mMaxLineEdit->text().isEmpty() )
2180 {
2181 defaultValue += QLatin1String( ",None" );
2182 }
2183 else
2184 {
2185 bool ok;
2186 const double val { QgsDoubleValidator::toDouble( mMaxLineEdit->text(), &ok ) };
2187 defaultValue += QStringLiteral( ",%1" ).arg( ok ? QString::number( val ) : QLatin1String( "None" ) );
2188 }
2189
2190 Qgis::ProcessingNumberParameterType dataType = static_cast<Qgis::ProcessingNumberParameterType>( mTypeComboBox->currentData().toInt() );
2191 auto param = std::make_unique<QgsProcessingParameterRange>( name, description, dataType, defaultValue );
2192 param->setFlags( flags );
2193 return param.release();
2194}
2195
2196
2197QgsProcessingRangeWidgetWrapper::QgsProcessingRangeWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
2198 : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
2199{
2200}
2201
2202QWidget *QgsProcessingRangeWidgetWrapper::createWidget()
2203{
2204 const QgsProcessingParameterRange *rangeDef = static_cast<const QgsProcessingParameterRange *>( parameterDefinition() );
2205 switch ( type() )
2206 {
2210 {
2211 QHBoxLayout *layout = new QHBoxLayout();
2212
2213 mMinSpinBox = new QgsDoubleSpinBox();
2214 mMaxSpinBox = new QgsDoubleSpinBox();
2215
2216 mMinSpinBox->setExpressionsEnabled( true );
2217 mMinSpinBox->setShowClearButton( false );
2218 mMaxSpinBox->setExpressionsEnabled( true );
2219 mMaxSpinBox->setShowClearButton( false );
2220
2221 QLabel *minLabel = new QLabel( tr( "Min" ) );
2222 layout->addWidget( minLabel );
2223 layout->addWidget( mMinSpinBox, 1 );
2224
2225 QLabel *maxLabel = new QLabel( tr( "Max" ) );
2226 layout->addWidget( maxLabel );
2227 layout->addWidget( mMaxSpinBox, 1 );
2228
2229 QWidget *w = new QWidget();
2230 layout->setContentsMargins( 0, 0, 0, 0 );
2231 w->setLayout( layout );
2232
2234 {
2235 mMinSpinBox->setDecimals( 6 );
2236 mMaxSpinBox->setDecimals( 6 );
2237 }
2238 else
2239 {
2240 mMinSpinBox->setDecimals( 0 );
2241 mMaxSpinBox->setDecimals( 0 );
2242 }
2243
2244 mMinSpinBox->setMinimum( -99999999.999999 );
2245 mMaxSpinBox->setMinimum( -99999999.999999 );
2246 mMinSpinBox->setMaximum( 99999999.999999 );
2247 mMaxSpinBox->setMaximum( 99999999.999999 );
2248
2250 {
2251 mAllowingNull = true;
2252
2253 const double min = mMinSpinBox->minimum() - 1;
2254 mMinSpinBox->setMinimum( min );
2255 mMaxSpinBox->setMinimum( min );
2256 mMinSpinBox->setValue( min );
2257 mMaxSpinBox->setValue( min );
2258
2259 mMinSpinBox->setShowClearButton( true );
2260 mMaxSpinBox->setShowClearButton( true );
2261 mMinSpinBox->setSpecialValueText( tr( "Not set" ) );
2262 mMaxSpinBox->setSpecialValueText( tr( "Not set" ) );
2263 }
2264
2265 w->setToolTip( parameterDefinition()->toolTip() );
2266
2267 connect( mMinSpinBox, qOverload<double>( &QgsDoubleSpinBox::valueChanged ), this, [=]( const double v ) {
2268 mBlockChangedSignal++;
2269 if ( !mAllowingNull && v > mMaxSpinBox->value() )
2270 mMaxSpinBox->setValue( v );
2271 mBlockChangedSignal--;
2272
2273 if ( !mBlockChangedSignal )
2274 emit widgetValueHasChanged( this );
2275 } );
2276 connect( mMaxSpinBox, qOverload<double>( &QgsDoubleSpinBox::valueChanged ), this, [=]( const double v ) {
2277 mBlockChangedSignal++;
2278 if ( !mAllowingNull && v < mMinSpinBox->value() )
2279 mMinSpinBox->setValue( v );
2280 mBlockChangedSignal--;
2281
2282 if ( !mBlockChangedSignal )
2283 emit widgetValueHasChanged( this );
2284 } );
2285
2286 return w;
2287 }
2288 }
2289 return nullptr;
2290}
2291
2292void QgsProcessingRangeWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
2293{
2294 const QList<double> v = QgsProcessingParameters::parameterAsRange( parameterDefinition(), value, context );
2295 if ( mAllowingNull && v.empty() )
2296 {
2297 mMinSpinBox->clear();
2298 mMaxSpinBox->clear();
2299 }
2300 else
2301 {
2302 if ( v.empty() )
2303 return;
2304
2305 if ( mAllowingNull )
2306 {
2307 mBlockChangedSignal++;
2308 if ( std::isnan( v.at( 0 ) ) )
2309 mMinSpinBox->clear();
2310 else
2311 mMinSpinBox->setValue( v.at( 0 ) );
2312
2313 if ( v.count() >= 2 )
2314 {
2315 if ( std::isnan( v.at( 1 ) ) )
2316 mMaxSpinBox->clear();
2317 else
2318 mMaxSpinBox->setValue( v.at( 1 ) );
2319 }
2320 mBlockChangedSignal--;
2321 }
2322 else
2323 {
2324 mBlockChangedSignal++;
2325 mMinSpinBox->setValue( v.at( 0 ) );
2326 if ( v.count() >= 2 )
2327 mMaxSpinBox->setValue( v.at( 1 ) );
2328 mBlockChangedSignal--;
2329 }
2330 }
2331
2332 if ( !mBlockChangedSignal )
2333 emit widgetValueHasChanged( this );
2334}
2335
2336QVariant QgsProcessingRangeWidgetWrapper::widgetValue() const
2337{
2338 if ( mAllowingNull )
2339 {
2340 QString value;
2341 if ( qgsDoubleNear( mMinSpinBox->value(), mMinSpinBox->minimum() ) )
2342 value = QStringLiteral( "None" );
2343 else
2344 value = QString::number( mMinSpinBox->value() );
2345
2346 if ( qgsDoubleNear( mMaxSpinBox->value(), mMaxSpinBox->minimum() ) )
2347 value += QLatin1String( ",None" );
2348 else
2349 value += QStringLiteral( ",%1" ).arg( mMaxSpinBox->value() );
2350
2351 return value;
2352 }
2353 else
2354 return QStringLiteral( "%1,%2" ).arg( mMinSpinBox->value() ).arg( mMaxSpinBox->value() );
2355}
2356
2357QStringList QgsProcessingRangeWidgetWrapper::compatibleParameterTypes() const
2358{
2359 return QStringList()
2362}
2363
2364QStringList QgsProcessingRangeWidgetWrapper::compatibleOutputTypes() const
2365{
2366 return QStringList() << QgsProcessingOutputString::typeName()
2368}
2369
2370QString QgsProcessingRangeWidgetWrapper::modelerExpressionFormatString() const
2371{
2372 return tr( "string as two comma delimited floats, e.g. '1,10'" );
2373}
2374
2375QString QgsProcessingRangeWidgetWrapper::parameterType() const
2376{
2378}
2379
2380QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingRangeWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
2381{
2382 return new QgsProcessingRangeWidgetWrapper( parameter, type );
2383}
2384
2385QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingRangeWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
2386{
2387 return new QgsProcessingRangeParameterDefinitionWidget( context, widgetContext, definition, algorithm );
2388}
2389
2390
2391//
2392// QgsProcessingMatrixWidgetWrapper
2393//
2394
2395QgsProcessingMatrixParameterDefinitionWidget::QgsProcessingMatrixParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
2396 : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
2397{
2398 QVBoxLayout *vlayout = new QVBoxLayout();
2399 vlayout->setContentsMargins( 0, 0, 0, 0 );
2400
2401 mMatrixWidget = new QgsProcessingMatrixModelerWidget();
2402 if ( const QgsProcessingParameterMatrix *matrixParam = dynamic_cast<const QgsProcessingParameterMatrix *>( definition ) )
2403 {
2404 mMatrixWidget->setValue( matrixParam->headers(), matrixParam->defaultValueForGui() );
2405 mMatrixWidget->setFixedRows( matrixParam->hasFixedNumberRows() );
2406 }
2407 vlayout->addWidget( mMatrixWidget );
2408 setLayout( vlayout );
2409}
2410
2411QgsProcessingParameterDefinition *QgsProcessingMatrixParameterDefinitionWidget::createParameter( const QString &name, const QString &description, Qgis::ProcessingParameterFlags flags ) const
2412{
2413 auto param = std::make_unique<QgsProcessingParameterMatrix>( name, description, 1, mMatrixWidget->fixedRows(), mMatrixWidget->headers(), mMatrixWidget->value() );
2414 param->setFlags( flags );
2415 return param.release();
2416}
2417
2418
2419QgsProcessingMatrixWidgetWrapper::QgsProcessingMatrixWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
2420 : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
2421{
2422}
2423
2424QWidget *QgsProcessingMatrixWidgetWrapper::createWidget()
2425{
2426 mMatrixWidget = new QgsProcessingMatrixParameterPanel( nullptr, dynamic_cast<const QgsProcessingParameterMatrix *>( parameterDefinition() ) );
2427 mMatrixWidget->setToolTip( parameterDefinition()->toolTip() );
2428
2429 connect( mMatrixWidget, &QgsProcessingMatrixParameterPanel::changed, this, [=] {
2430 emit widgetValueHasChanged( this );
2431 } );
2432
2433 switch ( type() )
2434 {
2438 {
2439 return mMatrixWidget;
2440 }
2441 }
2442 return nullptr;
2443}
2444
2445void QgsProcessingMatrixWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
2446{
2447 const QVariantList v = QgsProcessingParameters::parameterAsMatrix( parameterDefinition(), value, context );
2448 if ( mMatrixWidget )
2449 mMatrixWidget->setValue( v );
2450}
2451
2452QVariant QgsProcessingMatrixWidgetWrapper::widgetValue() const
2453{
2454 if ( mMatrixWidget )
2455 return mMatrixWidget->value().isEmpty() ? QVariant() : mMatrixWidget->value();
2456 else
2457 return QVariant();
2458}
2459
2460QStringList QgsProcessingMatrixWidgetWrapper::compatibleParameterTypes() const
2461{
2462 return QStringList()
2464}
2465
2466QStringList QgsProcessingMatrixWidgetWrapper::compatibleOutputTypes() const
2467{
2468 return QStringList();
2469}
2470
2471QString QgsProcessingMatrixWidgetWrapper::modelerExpressionFormatString() const
2472{
2473 return tr( "comma delimited string of values, or an array of values" );
2474}
2475
2476QString QgsProcessingMatrixWidgetWrapper::parameterType() const
2477{
2479}
2480
2481QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingMatrixWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
2482{
2483 return new QgsProcessingMatrixWidgetWrapper( parameter, type );
2484}
2485
2486QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingMatrixWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
2487{
2488 return new QgsProcessingMatrixParameterDefinitionWidget( context, widgetContext, definition, algorithm );
2489}
2490
2491
2492//
2493// QgsProcessingFileWidgetWrapper
2494//
2495
2496
2497QgsProcessingFileParameterDefinitionWidget::QgsProcessingFileParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
2498 : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
2499{
2500 QVBoxLayout *vlayout = new QVBoxLayout();
2501 vlayout->setContentsMargins( 0, 0, 0, 0 );
2502
2503 vlayout->addWidget( new QLabel( tr( "Type" ) ) );
2504
2505 mTypeComboBox = new QComboBox();
2506 mTypeComboBox->addItem( tr( "File" ), static_cast<int>( Qgis::ProcessingFileParameterBehavior::File ) );
2507 mTypeComboBox->addItem( tr( "Folder" ), static_cast<int>( Qgis::ProcessingFileParameterBehavior::Folder ) );
2508 if ( const QgsProcessingParameterFile *fileParam = dynamic_cast<const QgsProcessingParameterFile *>( definition ) )
2509 mTypeComboBox->setCurrentIndex( mTypeComboBox->findData( static_cast<int>( fileParam->behavior() ) ) );
2510 else
2511 mTypeComboBox->setCurrentIndex( 0 );
2512 vlayout->addWidget( mTypeComboBox );
2513
2514 vlayout->addWidget( new QLabel( tr( "File filter" ) ) );
2515
2516 mFilterComboBox = new QComboBox();
2517 mFilterComboBox->setEditable( true );
2518 // add some standard ones -- these also act as a demonstration of the required format
2519 mFilterComboBox->addItem( tr( "All Files (*.*)" ) );
2520 mFilterComboBox->addItem( tr( "CSV Files (*.csv)" ) );
2521 mFilterComboBox->addItem( tr( "HTML Files (*.html *.htm)" ) );
2522 mFilterComboBox->addItem( tr( "Text Files (*.txt)" ) );
2523 if ( const QgsProcessingParameterFile *fileParam = dynamic_cast<const QgsProcessingParameterFile *>( definition ) )
2524 mFilterComboBox->setCurrentText( fileParam->fileFilter() );
2525 else
2526 mFilterComboBox->setCurrentIndex( 0 );
2527 vlayout->addWidget( mFilterComboBox );
2528
2529 vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
2530
2531 mDefaultFileWidget = new QgsFileWidget();
2532 mDefaultFileWidget->lineEdit()->setShowClearButton( true );
2533 if ( const QgsProcessingParameterFile *fileParam = dynamic_cast<const QgsProcessingParameterFile *>( definition ) )
2534 {
2535 mDefaultFileWidget->setStorageMode( fileParam->behavior() == Qgis::ProcessingFileParameterBehavior::File ? QgsFileWidget::GetFile : QgsFileWidget::GetDirectory );
2536 mDefaultFileWidget->setFilePath( fileParam->defaultValueForGui().toString() );
2537 }
2538 else
2539 mDefaultFileWidget->setStorageMode( QgsFileWidget::GetFile );
2540 vlayout->addWidget( mDefaultFileWidget );
2541
2542 connect( mTypeComboBox, qOverload<int>( &QComboBox::currentIndexChanged ), this, [=] {
2543 Qgis::ProcessingFileParameterBehavior behavior = static_cast<Qgis::ProcessingFileParameterBehavior>( mTypeComboBox->currentData().toInt() );
2544 mFilterComboBox->setEnabled( behavior == Qgis::ProcessingFileParameterBehavior::File );
2545 mDefaultFileWidget->setStorageMode( behavior == Qgis::ProcessingFileParameterBehavior::File ? QgsFileWidget::GetFile : QgsFileWidget::GetDirectory );
2546 } );
2547 mFilterComboBox->setEnabled( static_cast<Qgis::ProcessingFileParameterBehavior>( mTypeComboBox->currentData().toInt() ) == Qgis::ProcessingFileParameterBehavior::File );
2548
2549
2550 setLayout( vlayout );
2551}
2552
2553QgsProcessingParameterDefinition *QgsProcessingFileParameterDefinitionWidget::createParameter( const QString &name, const QString &description, Qgis::ProcessingParameterFlags flags ) const
2554{
2555 auto param = std::make_unique<QgsProcessingParameterFile>( name, description );
2556 param->setBehavior( static_cast<Qgis::ProcessingFileParameterBehavior>( mTypeComboBox->currentData().toInt() ) );
2557 if ( param->behavior() == Qgis::ProcessingFileParameterBehavior::File )
2558 param->setFileFilter( mFilterComboBox->currentText() );
2559 if ( !mDefaultFileWidget->filePath().isEmpty() )
2560 param->setDefaultValue( mDefaultFileWidget->filePath() );
2561 param->setFlags( flags );
2562 return param.release();
2563}
2564
2565
2566QgsProcessingFileWidgetWrapper::QgsProcessingFileWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
2567 : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
2568{
2569}
2570
2571QWidget *QgsProcessingFileWidgetWrapper::createWidget()
2572{
2573 const QgsProcessingParameterFile *fileParam = dynamic_cast<const QgsProcessingParameterFile *>( parameterDefinition() );
2574 switch ( type() )
2575 {
2579 {
2580 mFileWidget = new QgsFileWidget();
2581 mFileWidget->setToolTip( parameterDefinition()->toolTip() );
2582 mFileWidget->setDialogTitle( parameterDefinition()->description() );
2583
2584 mFileWidget->setDefaultRoot( QgsSettings().value( QStringLiteral( "/Processing/LastInputPath" ), QDir::homePath() ).toString() );
2585
2586 switch ( fileParam->behavior() )
2587 {
2589 mFileWidget->setStorageMode( QgsFileWidget::GetFile );
2590 if ( !fileParam->fileFilter().isEmpty() )
2591 mFileWidget->setFilter( fileParam->fileFilter() );
2592 else if ( !fileParam->extension().isEmpty() )
2593 mFileWidget->setFilter( tr( "%1 files" ).arg( fileParam->extension().toUpper() ) + QStringLiteral( " (*." ) + fileParam->extension().toLower() + ')' );
2594 break;
2595
2597 mFileWidget->setStorageMode( QgsFileWidget::GetDirectory );
2598 break;
2599 }
2600
2601 connect( mFileWidget, &QgsFileWidget::fileChanged, this, [=]( const QString &path ) {
2602 QgsSettings().setValue( QStringLiteral( "/Processing/LastInputPath" ), QFileInfo( path ).canonicalPath() );
2603 emit widgetValueHasChanged( this );
2604 } );
2605 return mFileWidget;
2606 }
2607 }
2608 return nullptr;
2609}
2610
2611void QgsProcessingFileWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
2612{
2613 const QString v = QgsProcessingParameters::parameterAsString( parameterDefinition(), value, context );
2614 if ( mFileWidget )
2615 mFileWidget->setFilePath( v );
2616}
2617
2618QVariant QgsProcessingFileWidgetWrapper::widgetValue() const
2619{
2620 if ( mFileWidget )
2621 return mFileWidget->filePath();
2622 else
2623 return QVariant();
2624}
2625
2626QStringList QgsProcessingFileWidgetWrapper::compatibleParameterTypes() const
2627{
2628 return QStringList()
2631}
2632
2633QStringList QgsProcessingFileWidgetWrapper::compatibleOutputTypes() const
2634{
2635 return QStringList() << QgsProcessingOutputFile::typeName()
2642}
2643
2644QString QgsProcessingFileWidgetWrapper::modelerExpressionFormatString() const
2645{
2646 return tr( "string representing a path to a file or folder" );
2647}
2648
2649QString QgsProcessingFileWidgetWrapper::parameterType() const
2650{
2652}
2653
2654QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingFileWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
2655{
2656 return new QgsProcessingFileWidgetWrapper( parameter, type );
2657}
2658
2659QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingFileWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
2660{
2661 return new QgsProcessingFileParameterDefinitionWidget( context, widgetContext, definition, algorithm );
2662}
2663
2664
2665//
2666// QgsProcessingExpressionWidgetWrapper
2667//
2668
2669QgsProcessingExpressionParameterDefinitionWidget::QgsProcessingExpressionParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
2670 : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
2671{
2672 QVBoxLayout *vlayout = new QVBoxLayout();
2673 vlayout->setContentsMargins( 0, 0, 0, 0 );
2674 vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
2675
2676 mDefaultQgisLineEdit = new QgsExpressionLineEdit();
2677 mDefaultQgisLineEdit->registerExpressionContextGenerator( this );
2678
2679 mDefaultPointCloudLineEdit = new QgsProcessingPointCloudExpressionLineEdit();
2680 mDefaultRasterCalculatorLineEdit = new QgsProcessingRasterCalculatorExpressionLineEdit();
2681
2682 QStackedWidget *stackedWidget = new QStackedWidget();
2683 stackedWidget->addWidget( mDefaultQgisLineEdit );
2684 stackedWidget->addWidget( mDefaultPointCloudLineEdit );
2685 stackedWidget->addWidget( mDefaultRasterCalculatorLineEdit );
2686 vlayout->addWidget( stackedWidget );
2687
2688 if ( const QgsProcessingParameterExpression *expParam = dynamic_cast<const QgsProcessingParameterExpression *>( definition ) )
2689 {
2690 const QString expr = QgsProcessingParameters::parameterAsExpression( expParam, expParam->defaultValueForGui(), context );
2691 mDefaultQgisLineEdit->setExpression( expr );
2692 mDefaultPointCloudLineEdit->setExpression( expr );
2693 }
2694
2695 vlayout->addWidget( new QLabel( tr( "Parent layer" ) ) );
2696
2697 mParentLayerComboBox = new QComboBox();
2698 vlayout->addWidget( mParentLayerComboBox );
2699
2700 vlayout->addWidget( new QLabel( tr( "Expression type" ) ) );
2701 mExpressionTypeComboBox = new QComboBox();
2702 mExpressionTypeComboBox->addItem( tr( "QGIS" ), static_cast<int>( Qgis::ExpressionType::Qgis ) );
2703 mExpressionTypeComboBox->addItem( tr( "Point Cloud" ), static_cast<int>( Qgis::ExpressionType::PointCloud ) );
2704 mExpressionTypeComboBox->addItem( tr( "Raster Calculator" ), static_cast<int>( Qgis::ExpressionType::RasterCalculator ) );
2705
2706 connect( mExpressionTypeComboBox, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, [=]( int ) {
2707 mParentLayerComboBox->clear();
2708 mParentLayerComboBox->addItem( tr( "None" ), QVariant() );
2709
2710 stackedWidget->setCurrentIndex( mExpressionTypeComboBox->currentIndex() > 0 ? mExpressionTypeComboBox->currentIndex() : 0 );
2711
2712 QString initialParent;
2713 if ( const QgsProcessingParameterExpression *expParam = dynamic_cast<const QgsProcessingParameterExpression *>( definition ) )
2714 initialParent = expParam->parentLayerParameterName();
2715
2716 Qgis::ExpressionType exprType = static_cast<Qgis::ExpressionType>( mExpressionTypeComboBox->currentData().toInt() );
2717
2718 if ( QgsProcessingModelAlgorithm *model = widgetContext.model() )
2719 {
2720 // populate combo box with other model input choices
2721 const QMap<QString, QgsProcessingModelParameter> components = model->parameterComponents();
2722 for ( auto it = components.constBegin(); it != components.constEnd(); ++it )
2723 {
2724 switch ( exprType )
2725 {
2727 if ( const QgsProcessingParameterFeatureSource *definition = dynamic_cast<const QgsProcessingParameterFeatureSource *>( model->parameterDefinition( it.value().parameterName() ) ) )
2728 {
2729 mParentLayerComboBox->addItem( definition->description(), definition->name() );
2730 if ( !initialParent.isEmpty() && initialParent == definition->name() )
2731 {
2732 mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
2733 }
2734 }
2735 else if ( const QgsProcessingParameterVectorLayer *definition = dynamic_cast<const QgsProcessingParameterVectorLayer *>( model->parameterDefinition( it.value().parameterName() ) ) )
2736 {
2737 mParentLayerComboBox->addItem( definition->description(), definition->name() );
2738 if ( !initialParent.isEmpty() && initialParent == definition->name() )
2739 {
2740 mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
2741 }
2742 }
2743 break;
2745 if ( const QgsProcessingParameterPointCloudLayer *definition = dynamic_cast<const QgsProcessingParameterPointCloudLayer *>( model->parameterDefinition( it.value().parameterName() ) ) )
2746 {
2747 mParentLayerComboBox->addItem( definition->description(), definition->name() );
2748 if ( !initialParent.isEmpty() && initialParent == definition->name() )
2749 {
2750 mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
2751 }
2752 }
2753 break;
2755 if ( const QgsProcessingParameterMultipleLayers *definition = dynamic_cast<const QgsProcessingParameterMultipleLayers *>( model->parameterDefinition( it.value().parameterName() ) ) )
2756 {
2757 if ( definition->layerType() != Qgis::ProcessingSourceType::Raster )
2758 {
2759 continue;
2760 }
2761 mParentLayerComboBox->addItem( definition->description(), definition->name() );
2762 if ( !initialParent.isEmpty() && initialParent == definition->name() )
2763 {
2764 mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
2765 }
2766 }
2767 break;
2768 }
2769 }
2770 }
2771
2772 if ( mParentLayerComboBox->count() == 1 && !initialParent.isEmpty() )
2773 {
2774 // if no parent candidates found, we just add the existing one as a placeholder
2775 mParentLayerComboBox->addItem( initialParent, initialParent );
2776 mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
2777 }
2778 } );
2779
2780 mExpressionTypeComboBox->setCurrentIndex( -1 );
2781 if ( const QgsProcessingParameterExpression *expParam = dynamic_cast<const QgsProcessingParameterExpression *>( definition ) )
2782 mExpressionTypeComboBox->setCurrentIndex( mExpressionTypeComboBox->findData( static_cast<int>( expParam->expressionType() ) ) );
2783 else
2784 mExpressionTypeComboBox->setCurrentIndex( 0 );
2785
2786 vlayout->addWidget( mExpressionTypeComboBox );
2787
2788 setLayout( vlayout );
2789}
2790
2791QgsProcessingParameterDefinition *QgsProcessingExpressionParameterDefinitionWidget::createParameter( const QString &name, const QString &description, Qgis::ProcessingParameterFlags flags ) const
2792{
2793 Qgis::ExpressionType expressionType = static_cast<Qgis::ExpressionType>( mExpressionTypeComboBox->currentData().toInt() );
2794 QString expression;
2795 switch ( expressionType )
2796 {
2798 expression = mDefaultQgisLineEdit->expression();
2799 break;
2801 expression = mDefaultPointCloudLineEdit->expression();
2802 break;
2804 expression = mDefaultRasterCalculatorLineEdit->expression();
2805 break;
2806 }
2807 auto param = std::make_unique<QgsProcessingParameterExpression>( name, description, expression, mParentLayerComboBox->currentData().toString(), false, expressionType );
2808 param->setFlags( flags );
2809 return param.release();
2810}
2811
2812QgsProcessingExpressionWidgetWrapper::QgsProcessingExpressionWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
2813 : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
2814{
2815}
2816
2817QWidget *QgsProcessingExpressionWidgetWrapper::createWidget()
2818{
2819 const QgsProcessingParameterExpression *expParam = dynamic_cast<const QgsProcessingParameterExpression *>( parameterDefinition() );
2820 switch ( type() )
2821 {
2825 {
2826 if ( expParam->parentLayerParameterName().isEmpty() )
2827 {
2828 mExpLineEdit = new QgsExpressionLineEdit();
2829 mExpLineEdit->setToolTip( parameterDefinition()->toolTip() );
2830 mExpLineEdit->setExpressionDialogTitle( parameterDefinition()->description() );
2831 mExpLineEdit->registerExpressionContextGenerator( this );
2832 connect( mExpLineEdit, &QgsExpressionLineEdit::expressionChanged, this, [=]( const QString & ) {
2833 emit widgetValueHasChanged( this );
2834 } );
2835 return mExpLineEdit;
2836 }
2837 else
2838 {
2840 {
2841 mPointCloudExpLineEdit = new QgsProcessingPointCloudExpressionLineEdit();
2842 mPointCloudExpLineEdit->setToolTip( parameterDefinition()->toolTip() );
2843 connect( mPointCloudExpLineEdit, &QgsProcessingPointCloudExpressionLineEdit::expressionChanged, this, [=]( const QString & ) {
2844 emit widgetValueHasChanged( this );
2845 } );
2846 return mPointCloudExpLineEdit;
2847 }
2848
2850 {
2851 mRasterCalculatorExpLineEdit = new QgsProcessingRasterCalculatorExpressionLineEdit();
2852 mRasterCalculatorExpLineEdit->setToolTip( parameterDefinition()->toolTip() );
2853 if ( type() == QgsProcessingGui::Modeler )
2854 {
2855 mRasterCalculatorExpLineEdit->setLayers( QVariantList() << "A" << "B" << "C" << "D" << "E" << "F" << "G" );
2856 }
2857 connect( mRasterCalculatorExpLineEdit, &QgsProcessingRasterCalculatorExpressionLineEdit::expressionChanged, this, [=]( const QString & ) {
2858 emit widgetValueHasChanged( this );
2859 } );
2860 return mRasterCalculatorExpLineEdit;
2861 }
2862
2863 // native QGIS expression
2864 if ( expParam->metadata().value( QStringLiteral( "inlineEditor" ) ).toBool() )
2865 {
2866 mExpBuilderWidget = new QgsExpressionBuilderWidget();
2867 mExpBuilderWidget->setToolTip( parameterDefinition()->toolTip() );
2868 mExpBuilderWidget->init( createExpressionContext() );
2869 connect( mExpBuilderWidget, &QgsExpressionBuilderWidget::expressionParsed, this, [=]( bool changed ) {
2870 Q_UNUSED( changed );
2871 emit widgetValueHasChanged( this );
2872 } );
2873 return mExpBuilderWidget;
2874 }
2875 else
2876 {
2877 mFieldExpWidget = new QgsFieldExpressionWidget();
2878 mFieldExpWidget->setToolTip( parameterDefinition()->toolTip() );
2879 mFieldExpWidget->setExpressionDialogTitle( parameterDefinition()->description() );
2880 mFieldExpWidget->registerExpressionContextGenerator( this );
2882 mFieldExpWidget->setAllowEmptyFieldName( true );
2883
2884 connect( mFieldExpWidget, static_cast<void ( QgsFieldExpressionWidget::* )( const QString & )>( &QgsFieldExpressionWidget::fieldChanged ), this, [=]( const QString & ) {
2885 emit widgetValueHasChanged( this );
2886 } );
2887 return mFieldExpWidget;
2888 }
2889 }
2890 }
2891 }
2892 return nullptr;
2893}
2894
2895void QgsProcessingExpressionWidgetWrapper::postInitialize( const QList<QgsAbstractProcessingParameterWidgetWrapper *> &wrappers )
2896{
2898 switch ( type() )
2899 {
2902 {
2903 for ( const QgsAbstractProcessingParameterWidgetWrapper *wrapper : wrappers )
2904 {
2905 if ( wrapper->parameterDefinition()->name() == static_cast<const QgsProcessingParameterExpression *>( parameterDefinition() )->parentLayerParameterName() )
2906 {
2907 setParentLayerWrapperValue( wrapper );
2909 setParentLayerWrapperValue( wrapper );
2910 } );
2911 break;
2912 }
2913 }
2914 break;
2915 }
2916
2918 break;
2919 }
2920}
2921
2922void QgsProcessingExpressionWidgetWrapper::registerProcessingContextGenerator( QgsProcessingContextGenerator *generator )
2923{
2925 if ( mExpBuilderWidget )
2926 {
2927 // we need to regenerate the expression context for use by this widget -- it doesn't fetch automatically on demand
2928 mExpBuilderWidget->setExpressionContext( createExpressionContext() );
2929 }
2930}
2931
2932void QgsProcessingExpressionWidgetWrapper::setParentLayerWrapperValue( const QgsAbstractProcessingParameterWidgetWrapper *parentWrapper )
2933{
2934 // evaluate value to layer
2935 QgsProcessingContext *context = nullptr;
2936 std::unique_ptr<QgsProcessingContext> tmpContext;
2937 if ( mProcessingContextGenerator )
2938 context = mProcessingContextGenerator->processingContext();
2939
2940 if ( !context )
2941 {
2942 tmpContext = std::make_unique<QgsProcessingContext>();
2943 context = tmpContext.get();
2944 }
2945
2946 QVariant val = parentWrapper->parameterValue();
2947
2948 const QgsProcessingParameterExpression *expParam = dynamic_cast<const QgsProcessingParameterExpression *>( parameterDefinition() );
2949 switch ( expParam->expressionType() )
2950 {
2952 {
2953 if ( val.userType() == qMetaTypeId<QgsProcessingFeatureSourceDefinition>() )
2954 {
2955 // input is a QgsProcessingFeatureSourceDefinition - get extra properties from it
2956 QgsProcessingFeatureSourceDefinition fromVar = qvariant_cast<QgsProcessingFeatureSourceDefinition>( val );
2957 val = fromVar.source;
2958 }
2959
2961 if ( !layer )
2962 {
2963 if ( mFieldExpWidget )
2964 mFieldExpWidget->setLayer( nullptr );
2965 else if ( mExpBuilderWidget )
2966 mExpBuilderWidget->setLayer( nullptr );
2967 else if ( mExpLineEdit )
2968 mExpLineEdit->setLayer( nullptr );
2969 return;
2970 }
2971
2972 // need to grab ownership of layer if required - otherwise layer may be deleted when context
2973 // goes out of scope
2974 std::unique_ptr<QgsMapLayer> ownedLayer( context->takeResultLayer( layer->id() ) );
2975 if ( ownedLayer && ownedLayer->type() == Qgis::LayerType::Vector )
2976 {
2977 mParentLayer.reset( ownedLayer.release() );
2978 layer = static_cast<QgsVectorLayer *>( mParentLayer.get() );
2979 }
2980 else
2981 {
2982 // don't need ownership of this layer - it wasn't owned by context (so e.g. is owned by the project)
2983 }
2984
2985 if ( mFieldExpWidget )
2986 mFieldExpWidget->setLayer( layer );
2987 if ( mExpBuilderWidget )
2988 mExpBuilderWidget->setLayer( layer );
2989 else if ( mExpLineEdit )
2990 mExpLineEdit->setLayer( layer );
2991
2992 break;
2993 }
2995 {
2997 if ( !layer )
2998 {
2999 if ( mPointCloudExpLineEdit )
3000 mPointCloudExpLineEdit->setLayer( nullptr );
3001 return;
3002 }
3003
3004 // need to grab ownership of layer if required - otherwise layer may be deleted when context
3005 // goes out of scope
3006 std::unique_ptr<QgsMapLayer> ownedLayer( context->takeResultLayer( layer->id() ) );
3007 if ( ownedLayer && ownedLayer->type() == Qgis::LayerType::PointCloud )
3008 {
3009 mParentLayer.reset( ownedLayer.release() );
3010 layer = static_cast<QgsPointCloudLayer *>( mParentLayer.get() );
3011 }
3012 else
3013 {
3014 // don't need ownership of this layer - it wasn't owned by context (so e.g. is owned by the project)
3015 }
3016
3017 if ( mPointCloudExpLineEdit )
3018 mPointCloudExpLineEdit->setLayer( layer );
3019
3020 break;
3021 }
3023 {
3025 if ( layers.isEmpty() )
3026 {
3027 if ( mRasterCalculatorExpLineEdit )
3028 {
3029 mRasterCalculatorExpLineEdit->setLayers( val.userType() == QMetaType::Type::QVariantList ? val.toList() : QVariantList() << val );
3030 }
3031 return;
3032 }
3033
3034 if ( mRasterCalculatorExpLineEdit )
3035 {
3036 QVariantList layersList;
3037 for ( QgsMapLayer *layer : layers )
3038 {
3039 layersList << layer->name();
3040 }
3041 mRasterCalculatorExpLineEdit->setLayers( layersList );
3042 }
3043
3044 break;
3045 }
3046 }
3047}
3048
3049void QgsProcessingExpressionWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
3050{
3051 const QString v = QgsProcessingParameters::parameterAsString( parameterDefinition(), value, context );
3052 if ( mFieldExpWidget )
3053 mFieldExpWidget->setExpression( v );
3054 else if ( mExpBuilderWidget )
3055 mExpBuilderWidget->setExpressionText( v );
3056 else if ( mExpLineEdit )
3057 mExpLineEdit->setExpression( v );
3058 else if ( mPointCloudExpLineEdit )
3059 mPointCloudExpLineEdit->setExpression( v );
3060 else if ( mRasterCalculatorExpLineEdit )
3061 mRasterCalculatorExpLineEdit->setExpression( v );
3062}
3063
3064QVariant QgsProcessingExpressionWidgetWrapper::widgetValue() const
3065{
3066 if ( mFieldExpWidget )
3067 return mFieldExpWidget->expression();
3068 if ( mExpBuilderWidget )
3069 return mExpBuilderWidget->expressionText();
3070 else if ( mExpLineEdit )
3071 return mExpLineEdit->expression();
3072 else if ( mPointCloudExpLineEdit )
3073 return mPointCloudExpLineEdit->expression();
3074 else if ( mRasterCalculatorExpLineEdit )
3075 return mRasterCalculatorExpLineEdit->expression();
3076 else
3077 return QVariant();
3078}
3079
3080QStringList QgsProcessingExpressionWidgetWrapper::compatibleParameterTypes() const
3081{
3082 return QStringList()
3091}
3092
3093QStringList QgsProcessingExpressionWidgetWrapper::compatibleOutputTypes() const
3094{
3095 return QStringList()
3099}
3100
3101QString QgsProcessingExpressionWidgetWrapper::modelerExpressionFormatString() const
3102{
3103 return tr( "string representation of an expression" );
3104}
3105
3106const QgsVectorLayer *QgsProcessingExpressionWidgetWrapper::linkedVectorLayer() const
3107{
3108 if ( mFieldExpWidget && mFieldExpWidget->layer() )
3109 return mFieldExpWidget->layer();
3110
3111 if ( mExpBuilderWidget && mExpBuilderWidget->layer() )
3112 return mExpBuilderWidget->layer();
3113
3115}
3116
3117QString QgsProcessingExpressionWidgetWrapper::parameterType() const
3118{
3120}
3121
3122QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingExpressionWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
3123{
3124 return new QgsProcessingExpressionWidgetWrapper( parameter, type );
3125}
3126
3127QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingExpressionWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
3128{
3129 return new QgsProcessingExpressionParameterDefinitionWidget( context, widgetContext, definition, algorithm );
3130}
3131
3132
3133//
3134// QgsProcessingEnumPanelWidget
3135//
3136
3137QgsProcessingEnumPanelWidget::QgsProcessingEnumPanelWidget( QWidget *parent, const QgsProcessingParameterEnum *param )
3138 : QWidget( parent )
3139 , mParam( param )
3140{
3141 QHBoxLayout *hl = new QHBoxLayout();
3142 hl->setContentsMargins( 0, 0, 0, 0 );
3143
3144 mLineEdit = new QLineEdit();
3145 mLineEdit->setEnabled( false );
3146 hl->addWidget( mLineEdit, 1 );
3147
3148 mToolButton = new QToolButton();
3149 mToolButton->setText( QString( QChar( 0x2026 ) ) );
3150 hl->addWidget( mToolButton );
3151
3152 setLayout( hl );
3153
3154 if ( mParam )
3155 {
3156 mLineEdit->setText( tr( "%1 options selected" ).arg( 0 ) );
3157 }
3158
3159 connect( mToolButton, &QToolButton::clicked, this, &QgsProcessingEnumPanelWidget::showDialog );
3160}
3161
3162void QgsProcessingEnumPanelWidget::setValue( const QVariant &value )
3163{
3164 if ( value.isValid() )
3165 {
3166 mValue = value.userType() == QMetaType::Type::QVariantList ? value.toList() : QVariantList() << value;
3167
3168 if ( mParam->usesStaticStrings() && mValue.count() == 1 && mValue.at( 0 ).toString().isEmpty() )
3169 mValue.clear();
3170 }
3171 else
3172 mValue.clear();
3173
3174 updateSummaryText();
3175 emit changed();
3176}
3177
3178void QgsProcessingEnumPanelWidget::showDialog()
3179{
3180 QVariantList availableOptions;
3181 if ( mParam )
3182 {
3183 availableOptions.reserve( mParam->options().size() );
3184
3185 if ( mParam->usesStaticStrings() )
3186 {
3187 for ( QString o : mParam->options() )
3188 {
3189 availableOptions << o;
3190 }
3191 }
3192 else
3193 {
3194 for ( int i = 0; i < mParam->options().count(); ++i )
3195 availableOptions << i;
3196 }
3197 }
3198
3199 const QStringList options = mParam ? mParam->options() : QStringList();
3201 if ( panel && panel->dockMode() )
3202 {
3203 QgsProcessingMultipleSelectionPanelWidget *widget = new QgsProcessingMultipleSelectionPanelWidget( availableOptions, mValue );
3204 widget->setPanelTitle( mParam->description() );
3205
3206 if ( mParam->usesStaticStrings() )
3207 {
3208 widget->setValueFormatter( [options]( const QVariant &v ) -> QString {
3209 const QString i = v.toString();
3210 return options.contains( i ) ? i : QString();
3211 } );
3212 }
3213 else
3214 {
3215 widget->setValueFormatter( [options]( const QVariant &v ) -> QString {
3216 const int i = v.toInt();
3217 return options.size() > i ? options.at( i ) : QString();
3218 } );
3219 }
3220
3221 connect( widget, &QgsProcessingMultipleSelectionPanelWidget::selectionChanged, this, [=]() {
3222 setValue( widget->selectedOptions() );
3223 } );
3224 connect( widget, &QgsProcessingMultipleSelectionPanelWidget::acceptClicked, widget, &QgsPanelWidget::acceptPanel );
3225 panel->openPanel( widget );
3226 }
3227 else
3228 {
3229 QgsProcessingMultipleSelectionDialog dlg( availableOptions, mValue, this, Qt::WindowFlags() );
3230
3231 dlg.setValueFormatter( [options]( const QVariant &v ) -> QString {
3232 const int i = v.toInt();
3233 return options.size() > i ? options.at( i ) : QString();
3234 } );
3235 if ( dlg.exec() )
3236 {
3237 setValue( dlg.selectedOptions() );
3238 }
3239 }
3240}
3241
3242void QgsProcessingEnumPanelWidget::updateSummaryText()
3243{
3244 if ( !mParam )
3245 return;
3246
3247 if ( mValue.empty() )
3248 {
3249 mLineEdit->setText( tr( "%1 options selected" ).arg( 0 ) );
3250 }
3251 else
3252 {
3253 QStringList values;
3254 values.reserve( mValue.size() );
3255 if ( mParam->usesStaticStrings() )
3256 {
3257 for ( const QVariant &val : std::as_const( mValue ) )
3258 {
3259 values << val.toString();
3260 }
3261 }
3262 else
3263 {
3264 const QStringList options = mParam->options();
3265 for ( const QVariant &val : std::as_const( mValue ) )
3266 {
3267 const int i = val.toInt();
3268 values << ( options.size() > i ? options.at( i ) : QString() );
3269 }
3270 }
3271
3272 const QString concatenated = values.join( tr( "," ) );
3273 if ( concatenated.length() < 100 )
3274 mLineEdit->setText( concatenated );
3275 else
3276 mLineEdit->setText( tr( "%n option(s) selected", nullptr, mValue.count() ) );
3277 }
3278}
3279
3280
3281//
3282// QgsProcessingEnumCheckboxPanelWidget
3283//
3284QgsProcessingEnumCheckboxPanelWidget::QgsProcessingEnumCheckboxPanelWidget( QWidget *parent, const QgsProcessingParameterEnum *param, int columns )
3285 : QWidget( parent )
3286 , mParam( param )
3287 , mButtonGroup( new QButtonGroup( this ) )
3288 , mColumns( columns )
3289{
3290 mButtonGroup->setExclusive( !mParam->allowMultiple() );
3291
3292 QGridLayout *l = new QGridLayout();
3293 l->setContentsMargins( 0, 0, 0, 0 );
3294
3295 int rows = static_cast<int>( std::ceil( mParam->options().count() / static_cast<double>( mColumns ) ) );
3296 for ( int i = 0; i < mParam->options().count(); ++i )
3297 {
3298 QAbstractButton *button = nullptr;
3299 if ( mParam->allowMultiple() )
3300 button = new QCheckBox( mParam->options().at( i ) );
3301 else
3302 button = new QRadioButton( mParam->options().at( i ) );
3303
3304 connect( button, &QAbstractButton::toggled, this, [=] {
3305 if ( !mBlockChangedSignal )
3306 emit changed();
3307 } );
3308
3309 mButtons.insert( i, button );
3310
3311 mButtonGroup->addButton( button, i );
3312 l->addWidget( button, i % rows, i / rows );
3313 }
3314 l->addItem( new QSpacerItem( 0, 0, QSizePolicy::Expanding, QSizePolicy::Minimum ), 0, mColumns );
3315 setLayout( l );
3316
3317 if ( mParam->allowMultiple() )
3318 {
3319 setContextMenuPolicy( Qt::CustomContextMenu );
3320 connect( this, &QWidget::customContextMenuRequested, this, &QgsProcessingEnumCheckboxPanelWidget::showPopupMenu );
3321 }
3322}
3323
3324QVariant QgsProcessingEnumCheckboxPanelWidget::value() const
3325{
3326 if ( mParam->allowMultiple() )
3327 {
3328 QVariantList value;
3329 for ( auto it = mButtons.constBegin(); it != mButtons.constEnd(); ++it )
3330 {
3331 if ( it.value()->isChecked() )
3332 value.append( mParam->usesStaticStrings() ? mParam->options().at( it.key().toInt() ) : it.key() );
3333 }
3334 return value;
3335 }
3336 else
3337 {
3338 if ( mParam->usesStaticStrings() )
3339 return mButtonGroup->checkedId() >= 0 ? mParam->options().at( mButtonGroup->checkedId() ) : QVariant();
3340 else
3341 return mButtonGroup->checkedId() >= 0 ? mButtonGroup->checkedId() : QVariant();
3342 }
3343}
3344
3345void QgsProcessingEnumCheckboxPanelWidget::setValue( const QVariant &value )
3346{
3347 mBlockChangedSignal = true;
3348 if ( mParam->allowMultiple() )
3349 {
3350 QVariantList selected;
3351 if ( value.isValid() )
3352 selected = value.userType() == QMetaType::Type::QVariantList ? value.toList() : QVariantList() << value;
3353 for ( auto it = mButtons.constBegin(); it != mButtons.constEnd(); ++it )
3354 {
3355 QVariant v = mParam->usesStaticStrings() ? mParam->options().at( it.key().toInt() ) : it.key();
3356 it.value()->setChecked( selected.contains( v ) );
3357 }
3358 }
3359 else
3360 {
3361 QVariant v = value;
3362 if ( v.userType() == QMetaType::Type::QVariantList )
3363 v = v.toList().value( 0 );
3364
3365 v = mParam->usesStaticStrings() ? mParam->options().indexOf( v.toString() ) : v;
3366 if ( mButtons.contains( v ) )
3367 mButtons.value( v )->setChecked( true );
3368 }
3369 mBlockChangedSignal = false;
3370 emit changed();
3371}
3372
3373void QgsProcessingEnumCheckboxPanelWidget::showPopupMenu()
3374{
3375 QMenu popupMenu;
3376 QAction *selectAllAction = new QAction( tr( "Select All" ), &popupMenu );
3377 connect( selectAllAction, &QAction::triggered, this, &QgsProcessingEnumCheckboxPanelWidget::selectAll );
3378 QAction *clearAllAction = new QAction( tr( "Clear Selection" ), &popupMenu );
3379 connect( clearAllAction, &QAction::triggered, this, &QgsProcessingEnumCheckboxPanelWidget::deselectAll );
3380 popupMenu.addAction( selectAllAction );
3381 popupMenu.addAction( clearAllAction );
3382 popupMenu.exec( QCursor::pos() );
3383}
3384
3385void QgsProcessingEnumCheckboxPanelWidget::selectAll()
3386{
3387 mBlockChangedSignal = true;
3388 for ( auto it = mButtons.constBegin(); it != mButtons.constEnd(); ++it )
3389 it.value()->setChecked( true );
3390 mBlockChangedSignal = false;
3391 emit changed();
3392}
3393
3394void QgsProcessingEnumCheckboxPanelWidget::deselectAll()
3395{
3396 mBlockChangedSignal = true;
3397 for ( auto it = mButtons.constBegin(); it != mButtons.constEnd(); ++it )
3398 it.value()->setChecked( false );
3399 mBlockChangedSignal = false;
3400 emit changed();
3401}
3402
3403
3404//
3405// QgsProcessingEnumWidgetWrapper
3406//
3407
3408QgsProcessingEnumParameterDefinitionWidget::QgsProcessingEnumParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
3409 : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
3410{
3411 QVBoxLayout *vlayout = new QVBoxLayout();
3412 vlayout->setContentsMargins( 0, 0, 0, 0 );
3413
3414 mEnumWidget = new QgsProcessingEnumModelerWidget();
3415 if ( const QgsProcessingParameterEnum *enumParam = dynamic_cast<const QgsProcessingParameterEnum *>( definition ) )
3416 {
3417 mEnumWidget->setAllowMultiple( enumParam->allowMultiple() );
3418 mEnumWidget->setOptions( enumParam->options() );
3419 mEnumWidget->setDefaultOptions( enumParam->defaultValueForGui() );
3420 }
3421 vlayout->addWidget( mEnumWidget );
3422 setLayout( vlayout );
3423}
3424
3425QgsProcessingParameterDefinition *QgsProcessingEnumParameterDefinitionWidget::createParameter( const QString &name, const QString &description, Qgis::ProcessingParameterFlags flags ) const
3426{
3427 auto param = std::make_unique<QgsProcessingParameterEnum>( name, description, mEnumWidget->options(), mEnumWidget->allowMultiple(), mEnumWidget->defaultOptions() );
3428 param->setFlags( flags );
3429 return param.release();
3430}
3431
3432
3433QgsProcessingEnumWidgetWrapper::QgsProcessingEnumWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
3434 : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
3435{
3436}
3437
3438QWidget *QgsProcessingEnumWidgetWrapper::createWidget()
3439{
3440 const QgsProcessingParameterEnum *expParam = dynamic_cast<const QgsProcessingParameterEnum *>( parameterDefinition() );
3441 switch ( type() )
3442 {
3444 {
3445 // checkbox panel only for use outside in standard gui!
3446 if ( expParam->metadata().value( QStringLiteral( "widget_wrapper" ) ).toMap().value( QStringLiteral( "useCheckBoxes" ), false ).toBool() )
3447 {
3448 const int columns = expParam->metadata().value( QStringLiteral( "widget_wrapper" ) ).toMap().value( QStringLiteral( "columns" ), 2 ).toInt();
3449 mCheckboxPanel = new QgsProcessingEnumCheckboxPanelWidget( nullptr, expParam, columns );
3450 mCheckboxPanel->setToolTip( parameterDefinition()->toolTip() );
3451 connect( mCheckboxPanel, &QgsProcessingEnumCheckboxPanelWidget::changed, this, [=] {
3452 emit widgetValueHasChanged( this );
3453 } );
3454 return mCheckboxPanel;
3455 }
3456 }
3457 [[fallthrough]];
3460 {
3461 if ( expParam->allowMultiple() )
3462 {
3463 mPanel = new QgsProcessingEnumPanelWidget( nullptr, expParam );
3464 mPanel->setToolTip( parameterDefinition()->toolTip() );
3465 connect( mPanel, &QgsProcessingEnumPanelWidget::changed, this, [=] {
3466 emit widgetValueHasChanged( this );
3467 } );
3468 return mPanel;
3469 }
3470 else
3471 {
3472 mComboBox = new QComboBox();
3473
3475 mComboBox->addItem( tr( "[Not selected]" ), QVariant() );
3476 const QStringList options = expParam->options();
3477 const QVariantList iconList = expParam->metadata().value( QStringLiteral( "widget_wrapper" ) ).toMap().value( QStringLiteral( "icons" ) ).toList();
3478 for ( int i = 0; i < options.count(); ++i )
3479 {
3480 const QIcon icon = iconList.value( i ).value<QIcon>();
3481
3482 if ( expParam->usesStaticStrings() )
3483 mComboBox->addItem( icon, options.at( i ), options.at( i ) );
3484 else
3485 mComboBox->addItem( icon, options.at( i ), i );
3486 }
3487
3488 mComboBox->setToolTip( parameterDefinition()->toolTip() );
3489 mComboBox->setSizeAdjustPolicy( QComboBox::AdjustToMinimumContentsLengthWithIcon );
3490 connect( mComboBox, qOverload<int>( &QComboBox::currentIndexChanged ), this, [=]( int ) {
3491 emit widgetValueHasChanged( this );
3492 } );
3493 return mComboBox;
3494 }
3495 }
3496 }
3497 return nullptr;
3498}
3499
3500void QgsProcessingEnumWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
3501{
3502 if ( mComboBox )
3503 {
3504 if ( !value.isValid() )
3505 mComboBox->setCurrentIndex( mComboBox->findData( QVariant() ) );
3506 else
3507 {
3508 const QgsProcessingParameterEnum *enumDef = dynamic_cast<const QgsProcessingParameterEnum *>( parameterDefinition() );
3509 if ( enumDef->usesStaticStrings() )
3510 {
3511 const QString v = QgsProcessingParameters::parameterAsEnumString( parameterDefinition(), value, context );
3512 mComboBox->setCurrentIndex( mComboBox->findData( v ) );
3513 }
3514 else
3515 {
3516 const int v = QgsProcessingParameters::parameterAsEnum( parameterDefinition(), value, context );
3517 mComboBox->setCurrentIndex( mComboBox->findData( v ) );
3518 }
3519 }
3520 }
3521 else if ( mPanel || mCheckboxPanel )
3522 {
3523 QVariantList opts;
3524 if ( value.isValid() )
3525 {
3526 const QgsProcessingParameterEnum *enumDef = dynamic_cast<const QgsProcessingParameterEnum *>( parameterDefinition() );
3527 if ( enumDef->usesStaticStrings() )
3528 {
3529 const QStringList v = QgsProcessingParameters::parameterAsEnumStrings( parameterDefinition(), value, context );
3530 opts.reserve( v.size() );
3531 for ( QString i : v )
3532 opts << i;
3533 }
3534 else
3535 {
3536 const QList<int> v = QgsProcessingParameters::parameterAsEnums( parameterDefinition(), value, context );
3537 opts.reserve( v.size() );
3538 for ( int i : v )
3539 opts << i;
3540 }
3541 }
3542 if ( mPanel )
3543 mPanel->setValue( opts );
3544 else if ( mCheckboxPanel )
3545 mCheckboxPanel->setValue( opts );
3546 }
3547}
3548
3549QVariant QgsProcessingEnumWidgetWrapper::widgetValue() const
3550{
3551 if ( mComboBox )
3552 return mComboBox->currentData();
3553 else if ( mPanel )
3554 return mPanel->value();
3555 else if ( mCheckboxPanel )
3556 return mCheckboxPanel->value();
3557 else
3558 return QVariant();
3559}
3560
3561QStringList QgsProcessingEnumWidgetWrapper::compatibleParameterTypes() const
3562{
3563 return QStringList()
3567}
3568
3569QStringList QgsProcessingEnumWidgetWrapper::compatibleOutputTypes() const
3570{
3571 return QStringList()
3575}
3576
3577QString QgsProcessingEnumWidgetWrapper::modelerExpressionFormatString() const
3578{
3579 return tr( "selected option index (starting from 0), array of indices, or comma separated string of options (e.g. '1,3')" );
3580}
3581
3582QString QgsProcessingEnumWidgetWrapper::parameterType() const
3583{
3585}
3586
3587QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingEnumWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
3588{
3589 return new QgsProcessingEnumWidgetWrapper( parameter, type );
3590}
3591
3592QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingEnumWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
3593{
3594 return new QgsProcessingEnumParameterDefinitionWidget( context, widgetContext, definition, algorithm );
3595}
3596
3597//
3598// QgsProcessingLayoutWidgetWrapper
3599//
3600
3601QgsProcessingLayoutWidgetWrapper::QgsProcessingLayoutWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
3602 : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
3603{
3604}
3605
3606QWidget *QgsProcessingLayoutWidgetWrapper::createWidget()
3607{
3608 const QgsProcessingParameterLayout *layoutParam = dynamic_cast<const QgsProcessingParameterLayout *>( parameterDefinition() );
3609 switch ( type() )
3610 {
3613 {
3614 // combobox only for use outside modeler!
3615 mComboBox = new QgsLayoutComboBox( nullptr, widgetContext().project() ? widgetContext().project()->layoutManager() : nullptr );
3616 if ( layoutParam->flags() & Qgis::ProcessingParameterFlag::Optional )
3617 mComboBox->setAllowEmptyLayout( true );
3618 mComboBox->setFilters( QgsLayoutManagerProxyModel::FilterPrintLayouts );
3619
3620 mComboBox->setToolTip( parameterDefinition()->toolTip() );
3621 connect( mComboBox, &QgsLayoutComboBox::layoutChanged, this, [=]( QgsMasterLayoutInterface * ) {
3622 emit widgetValueHasChanged( this );
3623 } );
3624 return mComboBox;
3625 }
3626
3628 {
3629 mPlainComboBox = new QComboBox();
3630 mPlainComboBox->setEditable( true );
3631 mPlainComboBox->setToolTip( tr( "Name of an existing print layout" ) );
3632 if ( widgetContext().project() )
3633 {
3634 const QList<QgsPrintLayout *> layouts = widgetContext().project()->layoutManager()->printLayouts();
3635 for ( const QgsPrintLayout *layout : layouts )
3636 mPlainComboBox->addItem( layout->name() );
3637 }
3638
3639 connect( mPlainComboBox, &QComboBox::currentTextChanged, this, [=]( const QString & ) {
3640 emit widgetValueHasChanged( this );
3641 } );
3642 return mPlainComboBox;
3643 }
3644 }
3645 return nullptr;
3646}
3647
3648void QgsProcessingLayoutWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
3649{
3650 if ( mComboBox )
3651 {
3652 if ( !value.isValid() )
3653 mComboBox->setCurrentLayout( nullptr );
3654 else
3655 {
3656 if ( QgsPrintLayout *l = QgsProcessingParameters::parameterAsLayout( parameterDefinition(), value, context ) )
3657 mComboBox->setCurrentLayout( l );
3658 else
3659 mComboBox->setCurrentLayout( nullptr );
3660 }
3661 }
3662 else if ( mPlainComboBox )
3663 {
3664 const QString v = QgsProcessingParameters::parameterAsString( parameterDefinition(), value, context );
3665 mPlainComboBox->setCurrentText( v );
3666 }
3667}
3668
3669QVariant QgsProcessingLayoutWidgetWrapper::widgetValue() const
3670{
3671 if ( mComboBox )
3672 {
3673 const QgsMasterLayoutInterface *l = mComboBox->currentLayout();
3674 return l ? l->name() : QVariant();
3675 }
3676 else if ( mPlainComboBox )
3677 return mPlainComboBox->currentText().isEmpty() ? QVariant() : mPlainComboBox->currentText();
3678 else
3679 return QVariant();
3680}
3681
3682void QgsProcessingLayoutWidgetWrapper::setWidgetContext( const QgsProcessingParameterWidgetContext &context )
3683{
3685 if ( mPlainComboBox && context.project() )
3686 {
3687 const QList<QgsPrintLayout *> layouts = widgetContext().project()->layoutManager()->printLayouts();
3688 for ( const QgsPrintLayout *layout : layouts )
3689 mPlainComboBox->addItem( layout->name() );
3690 }
3691}
3692
3693QStringList QgsProcessingLayoutWidgetWrapper::compatibleParameterTypes() const
3694{
3695 return QStringList()
3698}
3699
3700QStringList QgsProcessingLayoutWidgetWrapper::compatibleOutputTypes() const
3701{
3702 return QStringList()
3705}
3706
3707QString QgsProcessingLayoutWidgetWrapper::modelerExpressionFormatString() const
3708{
3709 return tr( "string representing the name of an existing print layout" );
3710}
3711
3712QString QgsProcessingLayoutWidgetWrapper::parameterType() const
3713{
3715}
3716
3717QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingLayoutWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
3718{
3719 return new QgsProcessingLayoutWidgetWrapper( parameter, type );
3720}
3721
3722
3723//
3724// QgsProcessingLayoutItemWidgetWrapper
3725//
3726
3727
3728QgsProcessingLayoutItemParameterDefinitionWidget::QgsProcessingLayoutItemParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
3729 : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
3730{
3731 QVBoxLayout *vlayout = new QVBoxLayout();
3732 vlayout->setContentsMargins( 0, 0, 0, 0 );
3733
3734 vlayout->addWidget( new QLabel( tr( "Parent layout" ) ) );
3735
3736 mParentLayoutComboBox = new QComboBox();
3737 QString initialParent;
3738 if ( const QgsProcessingParameterLayoutItem *itemParam = dynamic_cast<const QgsProcessingParameterLayoutItem *>( definition ) )
3739 initialParent = itemParam->parentLayoutParameterName();
3740
3741 if ( auto *lModel = widgetContext.model() )
3742 {
3743 // populate combo box with other model input choices
3744 const QMap<QString, QgsProcessingModelParameter> components = lModel->parameterComponents();
3745 for ( auto it = components.constBegin(); it != components.constEnd(); ++it )
3746 {
3747 if ( const QgsProcessingParameterLayout *definition = dynamic_cast<const QgsProcessingParameterLayout *>( lModel->parameterDefinition( it.value().parameterName() ) ) )
3748 {
3749 mParentLayoutComboBox->addItem( definition->description(), definition->name() );
3750 if ( !initialParent.isEmpty() && initialParent == definition->name() )
3751 {
3752 mParentLayoutComboBox->setCurrentIndex( mParentLayoutComboBox->count() - 1 );
3753 }
3754 }
3755 }
3756 }
3757
3758 if ( mParentLayoutComboBox->count() == 0 && !initialParent.isEmpty() )
3759 {
3760 // if no parent candidates found, we just add the existing one as a placeholder
3761 mParentLayoutComboBox->addItem( initialParent, initialParent );
3762 mParentLayoutComboBox->setCurrentIndex( mParentLayoutComboBox->count() - 1 );
3763 }
3764
3765 vlayout->addWidget( mParentLayoutComboBox );
3766 setLayout( vlayout );
3767}
3768QgsProcessingParameterDefinition *QgsProcessingLayoutItemParameterDefinitionWidget::createParameter( const QString &name, const QString &description, Qgis::ProcessingParameterFlags flags ) const
3769{
3770 auto param = std::make_unique<QgsProcessingParameterLayoutItem>( name, description, QVariant(), mParentLayoutComboBox->currentData().toString() );
3771 param->setFlags( flags );
3772 return param.release();
3773}
3774
3775
3776QgsProcessingLayoutItemWidgetWrapper::QgsProcessingLayoutItemWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
3777 : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
3778{
3779}
3780
3781QWidget *QgsProcessingLayoutItemWidgetWrapper::createWidget()
3782{
3783 const QgsProcessingParameterLayoutItem *layoutParam = dynamic_cast<const QgsProcessingParameterLayoutItem *>( parameterDefinition() );
3784 switch ( type() )
3785 {
3788 {
3789 // combobox only for use outside modeler!
3790 mComboBox = new QgsLayoutItemComboBox( nullptr, nullptr );
3791 if ( layoutParam->flags() & Qgis::ProcessingParameterFlag::Optional )
3792 mComboBox->setAllowEmptyItem( true );
3793 if ( layoutParam->itemType() >= 0 )
3794 mComboBox->setItemType( static_cast<QgsLayoutItemRegistry::ItemType>( layoutParam->itemType() ) );
3795
3796 mComboBox->setToolTip( parameterDefinition()->toolTip() );
3797 connect( mComboBox, &QgsLayoutItemComboBox::itemChanged, this, [=]( QgsLayoutItem * ) {
3798 emit widgetValueHasChanged( this );
3799 } );
3800 return mComboBox;
3801 }
3802
3804 {
3805 mLineEdit = new QLineEdit();
3806 mLineEdit->setToolTip( tr( "UUID or ID of an existing print layout item" ) );
3807 connect( mLineEdit, &QLineEdit::textChanged, this, [=]( const QString & ) {
3808 emit widgetValueHasChanged( this );
3809 } );
3810 return mLineEdit;
3811 }
3812 }
3813 return nullptr;
3814}
3815
3816void QgsProcessingLayoutItemWidgetWrapper::postInitialize( const QList<QgsAbstractProcessingParameterWidgetWrapper *> &wrappers )
3817{
3819 switch ( type() )
3820 {
3823 {
3824 for ( const QgsAbstractProcessingParameterWidgetWrapper *wrapper : wrappers )
3825 {
3826 if ( wrapper->parameterDefinition()->name() == static_cast<const QgsProcessingParameterLayoutItem *>( parameterDefinition() )->parentLayoutParameterName() )
3827 {
3828 setLayoutParameterValue( wrapper->parameterValue() );
3830 setLayoutParameterValue( wrapper->parameterValue() );
3831 } );
3832 break;
3833 }
3834 }
3835 break;
3836 }
3837
3839 break;
3840 }
3841}
3842
3843void QgsProcessingLayoutItemWidgetWrapper::setLayoutParameterValue( const QVariant &value )
3844{
3845 QgsPrintLayout *layout = nullptr;
3846
3847 // evaluate value to layout
3848 QgsProcessingContext *context = nullptr;
3849 std::unique_ptr<QgsProcessingContext> tmpContext;
3850 if ( mProcessingContextGenerator )
3851 context = mProcessingContextGenerator->processingContext();
3852
3853 if ( !context )
3854 {
3855 tmpContext = std::make_unique<QgsProcessingContext>();
3856 context = tmpContext.get();
3857 }
3858
3859 layout = QgsProcessingParameters::parameterAsLayout( parameterDefinition(), value, *context );
3860 setLayout( layout );
3861}
3862
3863void QgsProcessingLayoutItemWidgetWrapper::setLayout( QgsPrintLayout *layout )
3864{
3865 if ( mComboBox )
3866 mComboBox->setCurrentLayout( layout );
3867}
3868
3869void QgsProcessingLayoutItemWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
3870{
3871 if ( mComboBox )
3872 {
3873 if ( !value.isValid() )
3874 mComboBox->setItem( nullptr );
3875 else
3876 {
3877 QgsLayoutItem *item = QgsProcessingParameters::parameterAsLayoutItem( parameterDefinition(), value, context, qobject_cast<QgsPrintLayout *>( mComboBox->currentLayout() ) );
3878 mComboBox->setItem( item );
3879 }
3880 }
3881 else if ( mLineEdit )
3882 {
3883 const QString v = QgsProcessingParameters::parameterAsString( parameterDefinition(), value, context );
3884 mLineEdit->setText( v );
3885 }
3886}
3887
3888QVariant QgsProcessingLayoutItemWidgetWrapper::widgetValue() const
3889{
3890 if ( mComboBox )
3891 {
3892 const QgsLayoutItem *i = mComboBox->currentItem();
3893 return i ? i->uuid() : QVariant();
3894 }
3895 else if ( mLineEdit )
3896 return mLineEdit->text().isEmpty() ? QVariant() : mLineEdit->text();
3897 else
3898 return QVariant();
3899}
3900
3901QStringList QgsProcessingLayoutItemWidgetWrapper::compatibleParameterTypes() const
3902{
3903 return QStringList()
3906}
3907
3908QStringList QgsProcessingLayoutItemWidgetWrapper::compatibleOutputTypes() const
3909{
3910 return QStringList()
3913}
3914
3915QString QgsProcessingLayoutItemWidgetWrapper::modelerExpressionFormatString() const
3916{
3917 return tr( "string representing the UUID or ID of an existing print layout item" );
3918}
3919
3920QString QgsProcessingLayoutItemWidgetWrapper::parameterType() const
3921{
3923}
3924
3925QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingLayoutItemWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
3926{
3927 return new QgsProcessingLayoutItemWidgetWrapper( parameter, type );
3928}
3929
3930QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingLayoutItemWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
3931{
3932 return new QgsProcessingLayoutItemParameterDefinitionWidget( context, widgetContext, definition, algorithm );
3933}
3934
3935//
3936// QgsProcessingPointMapTool
3937//
3938
3939QgsProcessingPointMapTool::QgsProcessingPointMapTool( QgsMapCanvas *canvas )
3940 : QgsMapTool( canvas )
3941{
3943 mSnapIndicator.reset( new QgsSnapIndicator( canvas ) );
3944}
3945
3946QgsProcessingPointMapTool::~QgsProcessingPointMapTool() = default;
3947
3948void QgsProcessingPointMapTool::deactivate()
3949{
3950 mSnapIndicator->setMatch( QgsPointLocator::Match() );
3952}
3953
3954void QgsProcessingPointMapTool::canvasMoveEvent( QgsMapMouseEvent *e )
3955{
3956 e->snapPoint();
3957 mSnapIndicator->setMatch( e->mapPointMatch() );
3958}
3959
3960void QgsProcessingPointMapTool::canvasPressEvent( QgsMapMouseEvent *e )
3961{
3962 if ( e->button() == Qt::LeftButton )
3963 {
3964 QgsPointXY point = e->snapPoint();
3965 emit clicked( point );
3966 emit complete();
3967 }
3968}
3969
3970void QgsProcessingPointMapTool::keyPressEvent( QKeyEvent *e )
3971{
3972 if ( e->key() == Qt::Key_Escape )
3973 {
3974 // Override default shortcut management in MapCanvas
3975 e->ignore();
3976 emit complete();
3977 }
3978}
3979
3980
3981//
3982// QgsProcessingPointPanel
3983//
3984
3985QgsProcessingPointPanel::QgsProcessingPointPanel( QWidget *parent )
3986 : QWidget( parent )
3987{
3988 QHBoxLayout *l = new QHBoxLayout();
3989 l->setContentsMargins( 0, 0, 0, 0 );
3990 mLineEdit = new QgsFilterLineEdit();
3991 mLineEdit->setShowClearButton( false );
3992 l->addWidget( mLineEdit, 1 );
3993 mButton = new QToolButton();
3994 mButton->setText( QString( QChar( 0x2026 ) ) );
3995 l->addWidget( mButton );
3996 setLayout( l );
3997
3998 connect( mLineEdit, &QLineEdit::textChanged, this, &QgsProcessingPointPanel::changed );
3999 connect( mLineEdit, &QLineEdit::textChanged, this, &QgsProcessingPointPanel::textChanged );
4000 connect( mButton, &QToolButton::clicked, this, &QgsProcessingPointPanel::selectOnCanvas );
4001 mButton->setVisible( false );
4002}
4003
4004void QgsProcessingPointPanel::setMapCanvas( QgsMapCanvas *canvas )
4005{
4006 mCanvas = canvas;
4007 if ( mAllowSelectOnCanvas )
4008 {
4009 mButton->setVisible( true );
4010
4011 mCrs = canvas->mapSettings().destinationCrs();
4012 mTool = std::make_unique<QgsProcessingPointMapTool>( mCanvas );
4013 connect( mTool.get(), &QgsProcessingPointMapTool::clicked, this, &QgsProcessingPointPanel::updatePoint );
4014 connect( mTool.get(), &QgsProcessingPointMapTool::complete, this, &QgsProcessingPointPanel::pointPicked );
4015 }
4016}
4017
4018void QgsProcessingPointPanel::setAllowNull( bool allowNull )
4019{
4020 mLineEdit->setShowClearButton( allowNull );
4021}
4022
4023void QgsProcessingPointPanel::setShowPointOnCanvas( bool show )
4024{
4025 if ( mShowPointOnCanvas == show )
4026 return;
4027
4028 mShowPointOnCanvas = show;
4029 if ( mShowPointOnCanvas )
4030 {
4031 updateRubberBand();
4032 }
4033 else
4034 {
4035 mMapPointRubberBand.reset();
4036 }
4037}
4038
4039void QgsProcessingPointPanel::setAllowSelectOnCanvas( bool allow )
4040{
4041 mAllowSelectOnCanvas = allow;
4042 mButton->setVisible( mAllowSelectOnCanvas && static_cast<bool>( mTool ) );
4043}
4044
4045QVariant QgsProcessingPointPanel::value() const
4046{
4047 return mLineEdit->showClearButton() && mLineEdit->text().trimmed().isEmpty() ? QVariant() : QVariant( mLineEdit->text() );
4048}
4049
4050void QgsProcessingPointPanel::clear()
4051{
4052 mLineEdit->clear();
4053}
4054
4055void QgsProcessingPointPanel::setValue( const QgsPointXY &point, const QgsCoordinateReferenceSystem &crs )
4056{
4057 mPoint = point;
4058 QString newText = QStringLiteral( "%1,%2" )
4059 .arg( QString::number( point.x(), 'f' ), QString::number( point.y(), 'f' ) );
4060
4061 mCrs = crs;
4062 if ( mCrs.isValid() )
4063 {
4064 newText += QStringLiteral( " [%1]" ).arg( mCrs.authid() );
4065 }
4066 mLineEdit->setText( newText );
4067 updateRubberBand();
4068}
4069
4070void QgsProcessingPointPanel::showEvent( QShowEvent * )
4071{
4072 if ( mFirstShow )
4073 {
4074 // we don't support select on canvas if the dialog is modal
4075 if ( QWidget *parentWindow = window() )
4076 {
4077 setAllowSelectOnCanvas( !parentWindow->isModal() );
4078 }
4079 mFirstShow = false;
4080 }
4081}
4082
4083void QgsProcessingPointPanel::selectOnCanvas()
4084{
4085 if ( !mCanvas )
4086 return;
4087
4088 mPrevTool = mCanvas->mapTool();
4089 mCanvas->setMapTool( mTool.get() );
4090
4091 emit toggleDialogVisibility( false );
4092}
4093
4094void QgsProcessingPointPanel::updatePoint( const QgsPointXY &point )
4095{
4096 setValue( point, mCanvas->mapSettings().destinationCrs() );
4097}
4098
4099void QgsProcessingPointPanel::pointPicked()
4100{
4101 if ( !mCanvas )
4102 return;
4103
4104 mCanvas->setMapTool( mPrevTool );
4105
4106 emit toggleDialogVisibility( true );
4107}
4108
4109void QgsProcessingPointPanel::textChanged( const QString &text )
4110{
4111 const thread_local QRegularExpression rx( QStringLiteral( "^\\s*\\(?\\s*(.*?)\\s*,\\s*(.*?)\\s*(?:\\[(.*)\\])?\\s*\\)?\\s*$" ) );
4112
4113 const QRegularExpressionMatch match = rx.match( text );
4114 if ( match.hasMatch() )
4115 {
4116 bool xOk = false;
4117 const double x = match.captured( 1 ).toDouble( &xOk );
4118 bool yOk = false;
4119 const double y = match.captured( 2 ).toDouble( &yOk );
4120
4121 if ( xOk && yOk )
4122 {
4123 mPoint = QgsPointXY( x, y );
4124
4125 const QgsCoordinateReferenceSystem pointCrs( match.captured( 3 ) );
4126 if ( pointCrs.isValid() )
4127 {
4128 mCrs = pointCrs;
4129 }
4130 }
4131 else
4132 {
4133 mPoint = QgsPointXY();
4134 }
4135 }
4136 else
4137 {
4138 mPoint = QgsPointXY();
4139 }
4140
4141 updateRubberBand();
4142}
4143
4144void QgsProcessingPointPanel::updateRubberBand()
4145{
4146 if ( !mShowPointOnCanvas || !mCanvas )
4147 return;
4148
4149 if ( mPoint.isEmpty() )
4150 {
4151 mMapPointRubberBand.reset();
4152 return;
4153 }
4154
4155 if ( !mMapPointRubberBand )
4156 {
4157 mMapPointRubberBand.reset( new QgsRubberBand( mCanvas, Qgis::GeometryType::Point ) );
4158 mMapPointRubberBand->setZValue( 1000 );
4159 mMapPointRubberBand->setIcon( QgsRubberBand::ICON_X );
4160
4161 const double scaleFactor = mCanvas->fontMetrics().xHeight() * .4;
4162 mMapPointRubberBand->setWidth( scaleFactor );
4163 mMapPointRubberBand->setIconSize( scaleFactor * 5 );
4164
4165 mMapPointRubberBand->setSecondaryStrokeColor( QColor( 255, 255, 255, 100 ) );
4166 mMapPointRubberBand->setColor( QColor( 200, 0, 200 ) );
4167 }
4168
4169 mMapPointRubberBand->setToGeometry( QgsGeometry::fromPointXY( mPoint ), mCrs );
4170}
4171
4172
4173//
4174// QgsProcessingPointWidgetWrapper
4175//
4176
4177QgsProcessingPointParameterDefinitionWidget::QgsProcessingPointParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
4178 : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
4179{
4180 QVBoxLayout *vlayout = new QVBoxLayout();
4181 vlayout->setContentsMargins( 0, 0, 0, 0 );
4182
4183 vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
4184
4185 mDefaultLineEdit = new QLineEdit();
4186 mDefaultLineEdit->setToolTip( tr( "Point as 'x,y'" ) );
4187 mDefaultLineEdit->setPlaceholderText( tr( "Point as 'x,y'" ) );
4188 if ( const QgsProcessingParameterPoint *pointParam = dynamic_cast<const QgsProcessingParameterPoint *>( definition ) )
4189 {
4190 QgsPointXY point = QgsProcessingParameters::parameterAsPoint( pointParam, pointParam->defaultValueForGui(), context );
4191 mDefaultLineEdit->setText( QStringLiteral( "%1,%2" ).arg( QString::number( point.x(), 'f' ), QString::number( point.y(), 'f' ) ) );
4192 }
4193
4194 vlayout->addWidget( mDefaultLineEdit );
4195 setLayout( vlayout );
4196}
4197
4198QgsProcessingParameterDefinition *QgsProcessingPointParameterDefinitionWidget::createParameter( const QString &name, const QString &description, Qgis::ProcessingParameterFlags flags ) const
4199{
4200 auto param = std::make_unique<QgsProcessingParameterPoint>( name, description, mDefaultLineEdit->text() );
4201 param->setFlags( flags );
4202 return param.release();
4203}
4204
4205QgsProcessingPointWidgetWrapper::QgsProcessingPointWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
4206 : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
4207{
4208}
4209
4210QWidget *QgsProcessingPointWidgetWrapper::createWidget()
4211{
4212 const QgsProcessingParameterPoint *pointParam = dynamic_cast<const QgsProcessingParameterPoint *>( parameterDefinition() );
4213 switch ( type() )
4214 {
4217 {
4218 mPanel = new QgsProcessingPointPanel( nullptr );
4219 if ( widgetContext().mapCanvas() )
4220 mPanel->setMapCanvas( widgetContext().mapCanvas() );
4221
4222 if ( pointParam->flags() & Qgis::ProcessingParameterFlag::Optional )
4223 mPanel->setAllowNull( true );
4224
4225 if ( type() == QgsProcessingGui::Standard )
4226 mPanel->setShowPointOnCanvas( true );
4227
4228 mPanel->setToolTip( parameterDefinition()->toolTip() );
4229
4230 connect( mPanel, &QgsProcessingPointPanel::changed, this, [=] {
4231 emit widgetValueHasChanged( this );
4232 } );
4233
4234 if ( mDialog )
4235 setDialog( mDialog ); // setup connections to panel - dialog was previously set before the widget was created
4236 return mPanel;
4237 }
4238
4240 {
4241 mLineEdit = new QLineEdit();
4242 mLineEdit->setToolTip( tr( "Point as 'x,y'" ) );
4243 connect( mLineEdit, &QLineEdit::textChanged, this, [=]( const QString & ) {
4244 emit widgetValueHasChanged( this );
4245 } );
4246 return mLineEdit;
4247 }
4248 }
4249 return nullptr;
4250}
4251
4252void QgsProcessingPointWidgetWrapper::setWidgetContext( const QgsProcessingParameterWidgetContext &context )
4253{
4255 if ( mPanel && context.mapCanvas() )
4256 mPanel->setMapCanvas( context.mapCanvas() );
4257}
4258
4259void QgsProcessingPointWidgetWrapper::setDialog( QDialog *dialog )
4260{
4261 mDialog = dialog;
4262 if ( mPanel )
4263 {
4264 connect( mPanel, &QgsProcessingPointPanel::toggleDialogVisibility, mDialog, [=]( bool visible ) {
4265 if ( !visible )
4266 mDialog->showMinimized();
4267 else
4268 {
4269 mDialog->showNormal();
4270 mDialog->raise();
4271 mDialog->activateWindow();
4272 }
4273 } );
4274 }
4276}
4277
4278void QgsProcessingPointWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
4279{
4280 if ( mPanel )
4281 {
4282 if ( !value.isValid() || ( value.userType() == QMetaType::Type::QString && value.toString().isEmpty() ) )
4283 mPanel->clear();
4284 else
4285 {
4286 QgsPointXY p = QgsProcessingParameters::parameterAsPoint( parameterDefinition(), value, context );
4287 QgsCoordinateReferenceSystem crs = QgsProcessingParameters::parameterAsPointCrs( parameterDefinition(), value, context );
4288 mPanel->setValue( p, crs );
4289 }
4290 }
4291 else if ( mLineEdit )
4292 {
4293 const QString v = QgsProcessingParameters::parameterAsString( parameterDefinition(), value, context );
4294 mLineEdit->setText( v );
4295 }
4296}
4297
4298QVariant QgsProcessingPointWidgetWrapper::widgetValue() const
4299{
4300 if ( mPanel )
4301 {
4302 return mPanel->value();
4303 }
4304 else if ( mLineEdit )
4305 return mLineEdit->text().isEmpty() ? QVariant() : mLineEdit->text();
4306 else
4307 return QVariant();
4308}
4309
4310QStringList QgsProcessingPointWidgetWrapper::compatibleParameterTypes() const
4311{
4312 return QStringList()
4315}
4316
4317QStringList QgsProcessingPointWidgetWrapper::compatibleOutputTypes() const
4318{
4319 return QStringList()
4322}
4323
4324QString QgsProcessingPointWidgetWrapper::modelerExpressionFormatString() const
4325{
4326 return tr( "string of the format 'x,y' or a geometry value (centroid is used)" );
4327}
4328
4329QString QgsProcessingPointWidgetWrapper::parameterType() const
4330{
4332}
4333
4334QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingPointWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
4335{
4336 return new QgsProcessingPointWidgetWrapper( parameter, type );
4337}
4338
4339QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingPointWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
4340{
4341 return new QgsProcessingPointParameterDefinitionWidget( context, widgetContext, definition, algorithm );
4342}
4343
4344
4345//
4346// QgsProcessingGeometryWidgetWrapper
4347//
4348
4349
4350QgsProcessingGeometryParameterDefinitionWidget::QgsProcessingGeometryParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
4351 : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
4352{
4353 QVBoxLayout *vlayout = new QVBoxLayout();
4354 vlayout->setContentsMargins( 0, 0, 0, 0 );
4355
4356 vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
4357
4358 mGeometryWidget = new QgsGeometryWidget();
4359 if ( const QgsProcessingParameterGeometry *geometryParam = dynamic_cast<const QgsProcessingParameterGeometry *>( definition ) )
4360 {
4361 QgsGeometry g = QgsProcessingParameters::parameterAsGeometry( geometryParam, geometryParam->defaultValueForGui(), context );
4362 if ( !g.isNull() )
4363 {
4364 mGeometryWidget->setGeometryValue( QgsReferencedGeometry( g, QgsCoordinateReferenceSystem() ) );
4365 }
4366 }
4367
4368 vlayout->addWidget( mGeometryWidget );
4369 setLayout( vlayout );
4370}
4371
4372QgsProcessingParameterDefinition *QgsProcessingGeometryParameterDefinitionWidget::createParameter( const QString &name, const QString &description, Qgis::ProcessingParameterFlags flags ) const
4373{
4374 const QgsReferencedGeometry geometry = mGeometryWidget->geometryValue();
4375 auto param = std::make_unique<QgsProcessingParameterGeometry>( name, description, geometry.isEmpty() ? QVariant() : geometry.asWkt() );
4376 param->setFlags( flags );
4377 return param.release();
4378}
4379
4380QgsProcessingGeometryWidgetWrapper::QgsProcessingGeometryWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
4381 : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
4382{
4383}
4384
4385QWidget *QgsProcessingGeometryWidgetWrapper::createWidget()
4386{
4387 switch ( type() )
4388 {
4392 {
4393 mGeometryWidget = new QgsGeometryWidget();
4394 mGeometryWidget->setToolTip( parameterDefinition()->toolTip() );
4395 connect( mGeometryWidget, &QgsGeometryWidget::geometryValueChanged, this, [=]( const QgsReferencedGeometry & ) {
4396 emit widgetValueHasChanged( this );
4397 } );
4398 return mGeometryWidget;
4399 }
4400 }
4401 return nullptr;
4402}
4403
4404void QgsProcessingGeometryWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
4405{
4406 if ( mGeometryWidget )
4407 {
4408 QgsGeometry g = QgsProcessingParameters::parameterAsGeometry( parameterDefinition(), value, context );
4409 if ( !g.isNull() )
4410 {
4411 mGeometryWidget->setGeometryValue( QgsReferencedGeometry( g, QgsCoordinateReferenceSystem() ) );
4412 }
4413 else
4414 {
4415 mGeometryWidget->clearGeometry();
4416 }
4417 }
4418}
4419
4420QVariant QgsProcessingGeometryWidgetWrapper::widgetValue() const
4421{
4422 if ( mGeometryWidget )
4423 {
4424 const QgsReferencedGeometry geometry = mGeometryWidget->geometryValue();
4425 return geometry.isEmpty() ? QVariant() : geometry.asWkt();
4426 }
4427 else
4428 {
4429 return QVariant();
4430 }
4431}
4432
4433QStringList QgsProcessingGeometryWidgetWrapper::compatibleParameterTypes() const
4434{
4435 return QStringList()
4440}
4441
4442QStringList QgsProcessingGeometryWidgetWrapper::compatibleOutputTypes() const
4443{
4444 return QStringList()
4447}
4448
4449QString QgsProcessingGeometryWidgetWrapper::modelerExpressionFormatString() const
4450{
4451 return tr( "string in the Well-Known-Text format or a geometry value" );
4452}
4453
4454QString QgsProcessingGeometryWidgetWrapper::parameterType() const
4455{
4457}
4458
4459QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingGeometryWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
4460{
4461 return new QgsProcessingGeometryWidgetWrapper( parameter, type );
4462}
4463
4464QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingGeometryWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
4465{
4466 return new QgsProcessingGeometryParameterDefinitionWidget( context, widgetContext, definition, algorithm );
4467}
4468
4469
4470//
4471// QgsProcessingColorWidgetWrapper
4472//
4473
4474
4475QgsProcessingColorParameterDefinitionWidget::QgsProcessingColorParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
4476 : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
4477{
4478 QVBoxLayout *vlayout = new QVBoxLayout();
4479 vlayout->setContentsMargins( 0, 0, 0, 0 );
4480
4481 vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
4482
4483 mDefaultColorButton = new QgsColorButton();
4484 mDefaultColorButton->setShowNull( true );
4485 mAllowOpacity = new QCheckBox( tr( "Allow opacity control" ) );
4486
4487 if ( const QgsProcessingParameterColor *colorParam = dynamic_cast<const QgsProcessingParameterColor *>( definition ) )
4488 {
4489 const QColor c = QgsProcessingParameters::parameterAsColor( colorParam, colorParam->defaultValueForGui(), context );
4490 if ( !c.isValid() )
4491 mDefaultColorButton->setToNull();
4492 else
4493 mDefaultColorButton->setColor( c );
4494 mAllowOpacity->setChecked( colorParam->opacityEnabled() );
4495 }
4496 else
4497 {
4498 mDefaultColorButton->setToNull();
4499 mAllowOpacity->setChecked( true );
4500 }
4501
4502 vlayout->addWidget( mDefaultColorButton );
4503 vlayout->addWidget( mAllowOpacity );
4504 setLayout( vlayout );
4505}
4506
4507QgsProcessingParameterDefinition *QgsProcessingColorParameterDefinitionWidget::createParameter( const QString &name, const QString &description, Qgis::ProcessingParameterFlags flags ) const
4508{
4509 auto param = std::make_unique<QgsProcessingParameterColor>( name, description, mDefaultColorButton->color(), mAllowOpacity->isChecked() );
4510 param->setFlags( flags );
4511 return param.release();
4512}
4513
4514QgsProcessingColorWidgetWrapper::QgsProcessingColorWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
4515 : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
4516{
4517}
4518
4519QWidget *QgsProcessingColorWidgetWrapper::createWidget()
4520{
4521 const QgsProcessingParameterColor *colorParam = dynamic_cast<const QgsProcessingParameterColor *>( parameterDefinition() );
4522 switch ( type() )
4523 {
4527 {
4528 mColorButton = new QgsColorButton( nullptr );
4529 mColorButton->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed );
4530
4531 if ( colorParam->flags() & Qgis::ProcessingParameterFlag::Optional )
4532 mColorButton->setShowNull( true );
4533
4534 mColorButton->setAllowOpacity( colorParam->opacityEnabled() );
4535 mColorButton->setToolTip( parameterDefinition()->toolTip() );
4536 mColorButton->setColorDialogTitle( parameterDefinition()->description() );
4537 if ( colorParam->defaultValueForGui().value<QColor>().isValid() )
4538 {
4539 mColorButton->setDefaultColor( colorParam->defaultValueForGui().value<QColor>() );
4540 }
4541
4542 connect( mColorButton, &QgsColorButton::colorChanged, this, [=] {
4543 emit widgetValueHasChanged( this );
4544 } );
4545
4546 return mColorButton;
4547 }
4548 }
4549 return nullptr;
4550}
4551
4552void QgsProcessingColorWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
4553{
4554 if ( mColorButton )
4555 {
4556 if ( !value.isValid() || ( value.userType() == QMetaType::Type::QString && value.toString().isEmpty() )
4557 || ( value.userType() == QMetaType::Type::QColor && !value.value<QColor>().isValid() ) )
4558 mColorButton->setToNull();
4559 else
4560 {
4561 const QColor c = QgsProcessingParameters::parameterAsColor( parameterDefinition(), value, context );
4562 if ( !c.isValid() && mColorButton->showNull() )
4563 mColorButton->setToNull();
4564 else
4565 mColorButton->setColor( c );
4566 }
4567 }
4568}
4569
4570QVariant QgsProcessingColorWidgetWrapper::widgetValue() const
4571{
4572 if ( mColorButton )
4573 return mColorButton->isNull() ? QVariant() : mColorButton->color();
4574 else
4575 return QVariant();
4576}
4577
4578QStringList QgsProcessingColorWidgetWrapper::compatibleParameterTypes() const
4579{
4580 return QStringList()
4583}
4584
4585QStringList QgsProcessingColorWidgetWrapper::compatibleOutputTypes() const
4586{
4587 return QStringList()
4590}
4591
4592QString QgsProcessingColorWidgetWrapper::modelerExpressionFormatString() const
4593{
4594 return tr( "color style string, e.g. #ff0000 or 255,0,0" );
4595}
4596
4597QString QgsProcessingColorWidgetWrapper::parameterType() const
4598{
4600}
4601
4602QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingColorWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
4603{
4604 return new QgsProcessingColorWidgetWrapper( parameter, type );
4605}
4606
4607QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingColorWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
4608{
4609 return new QgsProcessingColorParameterDefinitionWidget( context, widgetContext, definition, algorithm );
4610}
4611
4612
4613//
4614// QgsProcessingCoordinateOperationWidgetWrapper
4615//
4616
4617QgsProcessingCoordinateOperationParameterDefinitionWidget::QgsProcessingCoordinateOperationParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
4618 : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
4619{
4620 QVBoxLayout *vlayout = new QVBoxLayout();
4621 vlayout->setContentsMargins( 0, 0, 0, 0 );
4622
4623 vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
4624
4625 mDefaultLineEdit = new QLineEdit();
4626 if ( const QgsProcessingParameterCoordinateOperation *coordParam = dynamic_cast<const QgsProcessingParameterCoordinateOperation *>( definition ) )
4627 mDefaultLineEdit->setText( QgsProcessingParameters::parameterAsString( coordParam, coordParam->defaultValueForGui(), context ) );
4628 vlayout->addWidget( mDefaultLineEdit );
4629
4630 mSourceParamComboBox = new QComboBox();
4631 mDestParamComboBox = new QComboBox();
4632 QString initialSource;
4633 QString initialDest;
4636 if ( const QgsProcessingParameterCoordinateOperation *itemParam = dynamic_cast<const QgsProcessingParameterCoordinateOperation *>( definition ) )
4637 {
4638 initialSource = itemParam->sourceCrsParameterName();
4639 initialDest = itemParam->destinationCrsParameterName();
4640 sourceCrs = QgsProcessingUtils::variantToCrs( itemParam->sourceCrs(), context );
4641 destCrs = QgsProcessingUtils::variantToCrs( itemParam->destinationCrs(), context );
4642 }
4643
4644 mSourceParamComboBox->addItem( QString(), QString() );
4645 mDestParamComboBox->addItem( QString(), QString() );
4646 if ( auto *lModel = widgetContext.model() )
4647 {
4648 // populate combo box with other model input choices
4649 const QMap<QString, QgsProcessingModelParameter> components = lModel->parameterComponents();
4650 for ( auto it = components.constBegin(); it != components.constEnd(); ++it )
4651 {
4652 if ( definition && it->parameterName() == definition->name() )
4653 continue;
4654
4655 // TODO - we should probably filter this list?
4656 mSourceParamComboBox->addItem( it->parameterName(), it->parameterName() );
4657 mDestParamComboBox->addItem( it->parameterName(), it->parameterName() );
4658 if ( !initialSource.isEmpty() && initialSource == it->parameterName() )
4659 {
4660 mSourceParamComboBox->setCurrentIndex( mSourceParamComboBox->count() - 1 );
4661 }
4662 if ( !initialDest.isEmpty() && initialDest == it->parameterName() )
4663 {
4664 mDestParamComboBox->setCurrentIndex( mDestParamComboBox->count() - 1 );
4665 }
4666 }
4667 }
4668
4669 if ( mSourceParamComboBox->count() == 1 && !initialSource.isEmpty() )
4670 {
4671 // if no source candidates found, we just add the existing one as a placeholder
4672 mSourceParamComboBox->addItem( initialSource, initialSource );
4673 mSourceParamComboBox->setCurrentIndex( mSourceParamComboBox->count() - 1 );
4674 }
4675 if ( mDestParamComboBox->count() == 1 && !initialDest.isEmpty() )
4676 {
4677 // if no dest candidates found, we just add the existing one as a placeholder
4678 mDestParamComboBox->addItem( initialDest, initialDest );
4679 mDestParamComboBox->setCurrentIndex( mDestParamComboBox->count() - 1 );
4680 }
4681
4682 vlayout->addWidget( new QLabel( tr( "Source CRS parameter" ) ) );
4683 vlayout->addWidget( mSourceParamComboBox );
4684 vlayout->addWidget( new QLabel( tr( "Destination CRS parameter" ) ) );
4685 vlayout->addWidget( mDestParamComboBox );
4686
4687 mStaticSourceWidget = new QgsProjectionSelectionWidget();
4688 mStaticSourceWidget->setOptionVisible( QgsProjectionSelectionWidget::CrsNotSet, true );
4689 mStaticSourceWidget->setCrs( sourceCrs );
4690 mStaticDestWidget = new QgsProjectionSelectionWidget();
4691 mStaticDestWidget->setOptionVisible( QgsProjectionSelectionWidget::CrsNotSet, true );
4692 mStaticDestWidget->setCrs( destCrs );
4693
4694 vlayout->addWidget( new QLabel( tr( "Static source CRS" ) ) );
4695 vlayout->addWidget( mStaticSourceWidget );
4696 vlayout->addWidget( new QLabel( tr( "Static destination CRS" ) ) );
4697 vlayout->addWidget( mStaticDestWidget );
4698
4699 setLayout( vlayout );
4700}
4701
4702QgsProcessingParameterDefinition *QgsProcessingCoordinateOperationParameterDefinitionWidget::createParameter( const QString &name, const QString &description, Qgis::ProcessingParameterFlags flags ) const
4703{
4704 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() );
4705 param->setFlags( flags );
4706 return param.release();
4707}
4708
4709QgsProcessingCoordinateOperationWidgetWrapper::QgsProcessingCoordinateOperationWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
4710 : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
4711{
4712}
4713
4714QWidget *QgsProcessingCoordinateOperationWidgetWrapper::createWidget()
4715{
4716 const QgsProcessingParameterCoordinateOperation *coordParam = dynamic_cast<const QgsProcessingParameterCoordinateOperation *>( parameterDefinition() );
4718 mSourceCrs = QgsProcessingUtils::variantToCrs( coordParam->sourceCrs(), c );
4719 mDestCrs = QgsProcessingUtils::variantToCrs( coordParam->destinationCrs(), c );
4720 switch ( type() )
4721 {
4723 {
4724 mOperationWidget = new QgsCoordinateOperationWidget( nullptr );
4725 mOperationWidget->setShowMakeDefault( false );
4726 mOperationWidget->setShowFallbackOption( false );
4727 mOperationWidget->setToolTip( parameterDefinition()->toolTip() );
4728 mOperationWidget->setSourceCrs( mSourceCrs );
4729 mOperationWidget->setDestinationCrs( mDestCrs );
4730 mOperationWidget->setMapCanvas( mCanvas );
4731 if ( !coordParam->defaultValueForGui().toString().isEmpty() )
4732 {
4734 deets.proj = coordParam->defaultValueForGui().toString();
4735 mOperationWidget->setSelectedOperation( deets );
4736 }
4737
4738 connect( mOperationWidget, &QgsCoordinateOperationWidget::operationChanged, this, [=] {
4739 emit widgetValueHasChanged( this );
4740 } );
4741
4742 return mOperationWidget;
4743 }
4744
4747 {
4748 mLineEdit = new QLineEdit();
4749 QHBoxLayout *layout = new QHBoxLayout();
4750 layout->addWidget( mLineEdit, 1 );
4751 connect( mLineEdit, &QLineEdit::textChanged, this, [=] {
4752 emit widgetValueHasChanged( this );
4753 } );
4754
4755 QToolButton *button = new QToolButton();
4756 button->setText( QString( QChar( 0x2026 ) ) );
4757 connect( button, &QToolButton::clicked, this, [=] {
4758 QgsDatumTransformDialog dlg( mSourceCrs, mDestCrs, false, false, false, qMakePair( -1, -1 ), button, Qt::WindowFlags(), mLineEdit->text(), mCanvas );
4759 if ( dlg.exec() )
4760 {
4761 mLineEdit->setText( dlg.selectedDatumTransform().proj );
4762 emit widgetValueHasChanged( this );
4763 }
4764 } );
4765 layout->addWidget( button );
4766
4767 QWidget *w = new QWidget();
4768 layout->setContentsMargins( 0, 0, 0, 0 );
4769 w->setLayout( layout );
4770 return w;
4771 }
4772 }
4773 return nullptr;
4774}
4775
4776void QgsProcessingCoordinateOperationWidgetWrapper::postInitialize( const QList<QgsAbstractProcessingParameterWidgetWrapper *> &wrappers )
4777{
4779 switch ( type() )
4780 {
4783 {
4784 for ( const QgsAbstractProcessingParameterWidgetWrapper *wrapper : wrappers )
4785 {
4786 if ( wrapper->parameterDefinition()->name() == static_cast<const QgsProcessingParameterCoordinateOperation *>( parameterDefinition() )->sourceCrsParameterName() )
4787 {
4788 setSourceCrsParameterValue( wrapper->parameterValue() );
4790 setSourceCrsParameterValue( wrapper->parameterValue() );
4791 } );
4792 }
4793 if ( wrapper->parameterDefinition()->name() == static_cast<const QgsProcessingParameterCoordinateOperation *>( parameterDefinition() )->destinationCrsParameterName() )
4794 {
4795 setDestinationCrsParameterValue( wrapper->parameterValue() );
4797 setDestinationCrsParameterValue( wrapper->parameterValue() );
4798 } );
4799 }
4800 }
4801 break;
4802 }
4803
4805 break;
4806 }
4807}
4808
4809void QgsProcessingCoordinateOperationWidgetWrapper::setWidgetContext( const QgsProcessingParameterWidgetContext &context )
4810{
4811 mCanvas = context.mapCanvas();
4812 if ( mOperationWidget )
4813 mOperationWidget->setMapCanvas( context.mapCanvas() );
4814}
4815
4816void QgsProcessingCoordinateOperationWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext & )
4817{
4818 if ( mOperationWidget )
4819 {
4820 if ( !value.isValid() || ( value.userType() == QMetaType::Type::QString ) )
4821 {
4823 deets.proj = value.toString();
4824 mOperationWidget->setSelectedOperation( deets );
4825 }
4826 }
4827 if ( mLineEdit )
4828 {
4829 if ( !value.isValid() || ( value.userType() == QMetaType::Type::QString ) )
4830 {
4831 mLineEdit->setText( value.toString() );
4832 }
4833 }
4834}
4835
4836QVariant QgsProcessingCoordinateOperationWidgetWrapper::widgetValue() const
4837{
4838 if ( mOperationWidget )
4839 return mOperationWidget->selectedOperation().proj;
4840 else if ( mLineEdit )
4841 return mLineEdit->text();
4842 else
4843 return QVariant();
4844}
4845
4846QStringList QgsProcessingCoordinateOperationWidgetWrapper::compatibleParameterTypes() const
4847{
4848 return QStringList()
4851}
4852
4853QStringList QgsProcessingCoordinateOperationWidgetWrapper::compatibleOutputTypes() const
4854{
4855 return QStringList()
4858}
4859
4860QString QgsProcessingCoordinateOperationWidgetWrapper::modelerExpressionFormatString() const
4861{
4862 return tr( "Proj coordinate operation string, e.g. '+proj=pipeline +step +inv...'" );
4863}
4864
4865void QgsProcessingCoordinateOperationWidgetWrapper::setSourceCrsParameterValue( const QVariant &value )
4866{
4867 QgsProcessingContext *context = nullptr;
4868 std::unique_ptr<QgsProcessingContext> tmpContext;
4869 if ( mProcessingContextGenerator )
4870 context = mProcessingContextGenerator->processingContext();
4871
4872 if ( !context )
4873 {
4874 tmpContext = std::make_unique<QgsProcessingContext>();
4875 context = tmpContext.get();
4876 }
4877
4878 mSourceCrs = QgsProcessingUtils::variantToCrs( value, *context );
4879 if ( mOperationWidget )
4880 {
4881 mOperationWidget->setSourceCrs( mSourceCrs );
4882 mOperationWidget->setSelectedOperationUsingContext( context->transformContext() );
4883 }
4884}
4885
4886void QgsProcessingCoordinateOperationWidgetWrapper::setDestinationCrsParameterValue( const QVariant &value )
4887{
4888 QgsProcessingContext *context = nullptr;
4889 std::unique_ptr<QgsProcessingContext> tmpContext;
4890 if ( mProcessingContextGenerator )
4891 context = mProcessingContextGenerator->processingContext();
4892
4893 if ( !context )
4894 {
4895 tmpContext = std::make_unique<QgsProcessingContext>();
4896 context = tmpContext.get();
4897 }
4898
4899 mDestCrs = QgsProcessingUtils::variantToCrs( value, *context );
4900 if ( mOperationWidget )
4901 {
4902 mOperationWidget->setDestinationCrs( mDestCrs );
4903 mOperationWidget->setSelectedOperationUsingContext( context->transformContext() );
4904 }
4905}
4906
4907QString QgsProcessingCoordinateOperationWidgetWrapper::parameterType() const
4908{
4910}
4911
4912QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingCoordinateOperationWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
4913{
4914 return new QgsProcessingCoordinateOperationWidgetWrapper( parameter, type );
4915}
4916
4917QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingCoordinateOperationWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
4918{
4919 return new QgsProcessingCoordinateOperationParameterDefinitionWidget( context, widgetContext, definition, algorithm );
4920}
4921
4922
4923//
4924// QgsProcessingFieldPanelWidget
4925//
4926
4927QgsProcessingFieldPanelWidget::QgsProcessingFieldPanelWidget( QWidget *parent, const QgsProcessingParameterField *param )
4928 : QWidget( parent )
4929 , mParam( param )
4930{
4931 QHBoxLayout *hl = new QHBoxLayout();
4932 hl->setContentsMargins( 0, 0, 0, 0 );
4933
4934 mLineEdit = new QLineEdit();
4935 mLineEdit->setEnabled( false );
4936 hl->addWidget( mLineEdit, 1 );
4937
4938 mToolButton = new QToolButton();
4939 mToolButton->setText( QString( QChar( 0x2026 ) ) );
4940 hl->addWidget( mToolButton );
4941
4942 setLayout( hl );
4943
4944 if ( mParam )
4945 {
4946 mLineEdit->setText( tr( "%n field(s) selected", nullptr, 0 ) );
4947 }
4948
4949 connect( mToolButton, &QToolButton::clicked, this, &QgsProcessingFieldPanelWidget::showDialog );
4950}
4951
4952void QgsProcessingFieldPanelWidget::setFields( const QgsFields &fields )
4953{
4954 mFields = fields;
4955}
4956
4957void QgsProcessingFieldPanelWidget::setValue( const QVariant &value )
4958{
4959 if ( value.isValid() )
4960 mValue = value.userType() == QMetaType::Type::QVariantList ? value.toList() : QVariantList() << value;
4961 else
4962 mValue.clear();
4963
4964 updateSummaryText();
4965 emit changed();
4966}
4967
4968void QgsProcessingFieldPanelWidget::showDialog()
4969{
4970 QVariantList availableOptions;
4971 availableOptions.reserve( mFields.size() );
4972 for ( const QgsField &field : std::as_const( mFields ) )
4973 {
4974 availableOptions << field.name();
4975 }
4976
4978 if ( panel && panel->dockMode() )
4979 {
4980 QgsProcessingMultipleSelectionPanelWidget *widget = new QgsProcessingMultipleSelectionPanelWidget( availableOptions, mValue );
4981 widget->setPanelTitle( mParam->description() );
4982
4983 widget->setValueFormatter( []( const QVariant &v ) -> QString {
4984 return v.toString();
4985 } );
4986
4987 connect( widget, &QgsProcessingMultipleSelectionPanelWidget::selectionChanged, this, [=]() {
4988 setValue( widget->selectedOptions() );
4989 } );
4990 connect( widget, &QgsProcessingMultipleSelectionPanelWidget::acceptClicked, widget, &QgsPanelWidget::acceptPanel );
4991 panel->openPanel( widget );
4992 }
4993 else
4994 {
4995 QgsProcessingMultipleSelectionDialog dlg( availableOptions, mValue, this, Qt::WindowFlags() );
4996
4997 dlg.setValueFormatter( []( const QVariant &v ) -> QString {
4998 return v.toString();
4999 } );
5000 if ( dlg.exec() )
5001 {
5002 setValue( dlg.selectedOptions() );
5003 }
5004 }
5005}
5006
5007void QgsProcessingFieldPanelWidget::updateSummaryText()
5008{
5009 if ( !mParam )
5010 return;
5011
5012 if ( mValue.empty() )
5013 {
5014 mLineEdit->setText( tr( "%n field(s) selected", nullptr, 0 ) );
5015 }
5016 else
5017 {
5018 QStringList values;
5019 values.reserve( mValue.size() );
5020 for ( const QVariant &val : std::as_const( mValue ) )
5021 {
5022 values << val.toString();
5023 }
5024
5025 const QString concatenated = values.join( tr( "," ) );
5026 if ( concatenated.length() < 100 )
5027 mLineEdit->setText( concatenated );
5028 else
5029 mLineEdit->setText( tr( "%n field(s) selected", nullptr, mValue.count() ) );
5030 }
5031}
5032
5033
5034//
5035// QgsProcessingFieldWidgetWrapper
5036//
5037
5038QgsProcessingFieldParameterDefinitionWidget::QgsProcessingFieldParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
5039 : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
5040{
5041 QVBoxLayout *vlayout = new QVBoxLayout();
5042 vlayout->setContentsMargins( 0, 0, 0, 0 );
5043
5044 vlayout->addWidget( new QLabel( tr( "Parent layer" ) ) );
5045 mParentLayerComboBox = new QComboBox();
5046
5047 QString initialParent;
5048 if ( const QgsProcessingParameterField *fieldParam = dynamic_cast<const QgsProcessingParameterField *>( definition ) )
5049 initialParent = fieldParam->parentLayerParameterName();
5050
5051 if ( auto *lModel = widgetContext.model() )
5052 {
5053 // populate combo box with other model input choices
5054 const QMap<QString, QgsProcessingModelParameter> components = lModel->parameterComponents();
5055 for ( auto it = components.constBegin(); it != components.constEnd(); ++it )
5056 {
5057 if ( const QgsProcessingParameterFeatureSource *definition = dynamic_cast<const QgsProcessingParameterFeatureSource *>( lModel->parameterDefinition( it.value().parameterName() ) ) )
5058 {
5059 mParentLayerComboBox->addItem( definition->description(), definition->name() );
5060 if ( !initialParent.isEmpty() && initialParent == definition->name() )
5061 {
5062 mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
5063 }
5064 }
5065 else if ( const QgsProcessingParameterVectorLayer *definition = dynamic_cast<const QgsProcessingParameterVectorLayer *>( lModel->parameterDefinition( it.value().parameterName() ) ) )
5066 {
5067 mParentLayerComboBox->addItem( definition->description(), definition->name() );
5068 if ( !initialParent.isEmpty() && initialParent == definition->name() )
5069 {
5070 mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
5071 }
5072 }
5073 else if ( const QgsProcessingParameterMultipleLayers *definition = dynamic_cast<const QgsProcessingParameterMultipleLayers *>( lModel->parameterDefinition( it.value().parameterName() ) ) )
5074 {
5075 if ( definition->layerType() == Qgis::ProcessingSourceType::Vector )
5076 {
5077 mParentLayerComboBox->addItem( definition->description(), definition->name() );
5078 if ( !initialParent.isEmpty() && initialParent == definition->name() )
5079 {
5080 mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
5081 }
5082 }
5083 }
5084 }
5085 }
5086
5087 if ( mParentLayerComboBox->count() == 0 && !initialParent.isEmpty() )
5088 {
5089 // if no parent candidates found, we just add the existing one as a placeholder
5090 mParentLayerComboBox->addItem( initialParent, initialParent );
5091 mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
5092 }
5093
5094 vlayout->addWidget( mParentLayerComboBox );
5095
5096 vlayout->addWidget( new QLabel( tr( "Allowed data type" ) ) );
5097 mDataTypeComboBox = new QComboBox();
5098 mDataTypeComboBox->addItem( tr( "Any" ), static_cast<int>( Qgis::ProcessingFieldParameterDataType::Any ) );
5099 mDataTypeComboBox->addItem( tr( "Number" ), static_cast<int>( Qgis::ProcessingFieldParameterDataType::Numeric ) );
5100 mDataTypeComboBox->addItem( tr( "String" ), static_cast<int>( Qgis::ProcessingFieldParameterDataType::String ) );
5101 mDataTypeComboBox->addItem( tr( "Date/time" ), static_cast<int>( Qgis::ProcessingFieldParameterDataType::DateTime ) );
5102 mDataTypeComboBox->addItem( tr( "Binary" ), static_cast<int>( Qgis::ProcessingFieldParameterDataType::Binary ) );
5103 mDataTypeComboBox->addItem( tr( "Boolean" ), static_cast<int>( Qgis::ProcessingFieldParameterDataType::Boolean ) );
5104 if ( const QgsProcessingParameterField *fieldParam = dynamic_cast<const QgsProcessingParameterField *>( definition ) )
5105 mDataTypeComboBox->setCurrentIndex( mDataTypeComboBox->findData( static_cast<int>( fieldParam->dataType() ) ) );
5106
5107 vlayout->addWidget( mDataTypeComboBox );
5108
5109 mAllowMultipleCheckBox = new QCheckBox( tr( "Accept multiple fields" ) );
5110 if ( const QgsProcessingParameterField *fieldParam = dynamic_cast<const QgsProcessingParameterField *>( definition ) )
5111 mAllowMultipleCheckBox->setChecked( fieldParam->allowMultiple() );
5112
5113 vlayout->addWidget( mAllowMultipleCheckBox );
5114
5115 mDefaultToAllCheckBox = new QCheckBox( tr( "Select all fields by default" ) );
5116 mDefaultToAllCheckBox->setEnabled( mAllowMultipleCheckBox->isChecked() );
5117 if ( const QgsProcessingParameterField *fieldParam = dynamic_cast<const QgsProcessingParameterField *>( definition ) )
5118 mDefaultToAllCheckBox->setChecked( fieldParam->defaultToAllFields() );
5119
5120 vlayout->addWidget( mDefaultToAllCheckBox );
5121
5122 connect( mAllowMultipleCheckBox, &QCheckBox::stateChanged, this, [=] {
5123 mDefaultToAllCheckBox->setEnabled( mAllowMultipleCheckBox->isChecked() );
5124 } );
5125
5126 vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
5127
5128 mDefaultLineEdit = new QLineEdit();
5129 mDefaultLineEdit->setToolTip( tr( "Default field name, or ; separated list of field names for multiple field parameters" ) );
5130 if ( const QgsProcessingParameterField *fieldParam = dynamic_cast<const QgsProcessingParameterField *>( definition ) )
5131 {
5132 const QStringList fields = QgsProcessingParameters::parameterAsStrings( fieldParam, fieldParam->defaultValueForGui(), context );
5133 mDefaultLineEdit->setText( fields.join( ';' ) );
5134 }
5135 vlayout->addWidget( mDefaultLineEdit );
5136
5137 setLayout( vlayout );
5138}
5139
5140QgsProcessingParameterDefinition *QgsProcessingFieldParameterDefinitionWidget::createParameter( const QString &name, const QString &description, Qgis::ProcessingParameterFlags flags ) const
5141{
5142 Qgis::ProcessingFieldParameterDataType dataType = static_cast<Qgis::ProcessingFieldParameterDataType>( mDataTypeComboBox->currentData().toInt() );
5143
5144 QVariant defaultValue;
5145 if ( !mDefaultLineEdit->text().trimmed().isEmpty() )
5146 {
5147 defaultValue = mDefaultLineEdit->text();
5148 }
5149 auto param = std::make_unique<QgsProcessingParameterField>( name, description, defaultValue, mParentLayerComboBox->currentData().toString(), dataType, mAllowMultipleCheckBox->isChecked(), false, mDefaultToAllCheckBox->isChecked() );
5150 param->setFlags( flags );
5151 return param.release();
5152}
5153
5154QgsProcessingFieldWidgetWrapper::QgsProcessingFieldWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
5155 : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
5156{
5157}
5158
5159QWidget *QgsProcessingFieldWidgetWrapper::createWidget()
5160{
5161 const QgsProcessingParameterField *fieldParam = dynamic_cast<const QgsProcessingParameterField *>( parameterDefinition() );
5162 switch ( type() )
5163 {
5166 {
5167 if ( fieldParam->allowMultiple() )
5168 {
5169 mPanel = new QgsProcessingFieldPanelWidget( nullptr, fieldParam );
5170 mPanel->setToolTip( parameterDefinition()->toolTip() );
5171 connect( mPanel, &QgsProcessingFieldPanelWidget::changed, this, [=] {
5172 emit widgetValueHasChanged( this );
5173 } );
5174 return mPanel;
5175 }
5176 else
5177 {
5178 mComboBox = new QgsFieldComboBox();
5179 mComboBox->setAllowEmptyFieldName( fieldParam->flags() & Qgis::ProcessingParameterFlag::Optional );
5180
5182 mComboBox->setFilters( QgsFieldProxyModel::Numeric );
5183 else if ( fieldParam->dataType() == Qgis::ProcessingFieldParameterDataType::String )
5184 mComboBox->setFilters( QgsFieldProxyModel::String );
5187 else if ( fieldParam->dataType() == Qgis::ProcessingFieldParameterDataType::Binary )
5188 mComboBox->setFilters( QgsFieldProxyModel::Binary );
5190 mComboBox->setFilters( QgsFieldProxyModel::Boolean );
5191
5192 mComboBox->setToolTip( parameterDefinition()->toolTip() );
5193 connect( mComboBox, &QgsFieldComboBox::fieldChanged, this, [=]( const QString & ) {
5194 emit widgetValueHasChanged( this );
5195 } );
5196 return mComboBox;
5197 }
5198 }
5199
5201 {
5202 mLineEdit = new QLineEdit();
5203 mLineEdit->setToolTip( QObject::tr( "Name of field (separate field names with ; for multiple field parameters)" ) );
5204 connect( mLineEdit, &QLineEdit::textChanged, this, [=] {
5205 emit widgetValueHasChanged( this );
5206 } );
5207 return mLineEdit;
5208 }
5209 }
5210 return nullptr;
5211}
5212
5213void QgsProcessingFieldWidgetWrapper::postInitialize( const QList<QgsAbstractProcessingParameterWidgetWrapper *> &wrappers )
5214{
5216 switch ( type() )
5217 {
5220 {
5221 for ( const QgsAbstractProcessingParameterWidgetWrapper *wrapper : wrappers )
5222 {
5223 if ( wrapper->parameterDefinition()->name() == static_cast<const QgsProcessingParameterField *>( parameterDefinition() )->parentLayerParameterName() )
5224 {
5225 setParentLayerWrapperValue( wrapper );
5227 setParentLayerWrapperValue( wrapper );
5228 } );
5229 break;
5230 }
5231 }
5232 break;
5233 }
5234
5236 break;
5237 }
5238}
5239
5240void QgsProcessingFieldWidgetWrapper::setParentLayerWrapperValue( const QgsAbstractProcessingParameterWidgetWrapper *parentWrapper )
5241{
5242 // evaluate value to layer
5243 QgsProcessingContext *context = nullptr;
5244 std::unique_ptr<QgsProcessingContext> tmpContext;
5245 if ( mProcessingContextGenerator )
5246 context = mProcessingContextGenerator->processingContext();
5247
5248 if ( !context )
5249 {
5250 tmpContext = std::make_unique<QgsProcessingContext>();
5251 context = tmpContext.get();
5252 }
5253
5254 QVariant value = parentWrapper->parameterValue();
5255
5256 if ( value.userType() == qMetaTypeId<QgsProcessingFeatureSourceDefinition>() )
5257 {
5258 // input is a QgsProcessingFeatureSourceDefinition - source from it.
5259 // this is normally discouraged, and algorithms should NEVER do this -- but in this case we can make
5260 // certain assumptions due to the fact that we're calling this outside of algorithm/model execution and all sources
5261 // should be real map layers at this stage
5262 QgsProcessingFeatureSourceDefinition fromVar = qvariant_cast<QgsProcessingFeatureSourceDefinition>( value );
5263 value = fromVar.source;
5264 }
5265
5266 bool valueSet = false;
5267 const QList<QgsMapLayer *> layers = QgsProcessingParameters::parameterAsLayerList( parentWrapper->parameterDefinition(), value, *context );
5268
5269 // several layers, populate with intersection of layers fields
5270 if ( layers.count() > 1 )
5271 {
5272 QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( layers.at( 0 ) );
5273 QgsFields fields = vlayer && vlayer->isValid() ? vlayer->fields() : QgsFields();
5274 const QList<QgsMapLayer *> remainingLayers = layers.mid( 1 );
5275 for ( QgsMapLayer *layer : remainingLayers )
5276 {
5277 if ( fields.isEmpty() )
5278 break;
5279
5280 QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( layer );
5281 if ( !vlayer || !vlayer->isValid() )
5282 {
5283 fields = QgsFields();
5284 break;
5285 }
5286
5287 for ( int fieldIdx = fields.count() - 1; fieldIdx >= 0; fieldIdx-- )
5288 {
5289 if ( vlayer->fields().lookupField( fields.at( fieldIdx ).name() ) < 0 )
5290 fields.remove( fieldIdx );
5291 }
5292 }
5293
5294 if ( mComboBox )
5295 mComboBox->setFields( fields );
5296 else if ( mPanel )
5297 mPanel->setFields( filterFields( fields ) );
5298
5299 valueSet = true;
5300 }
5301
5302 // only one layer
5303 if ( !valueSet && !layers.isEmpty() && layers.at( 0 )->isValid() )
5304 {
5305 QgsVectorLayer *layer = qobject_cast<QgsVectorLayer *>( layers.at( 0 ) );
5306
5307 // need to grab ownership of layer if required - otherwise layer may be deleted when context
5308 // goes out of scope
5309 std::unique_ptr<QgsMapLayer> ownedLayer( context->takeResultLayer( layer->id() ) );
5310 if ( ownedLayer && ownedLayer->type() == Qgis::LayerType::Vector )
5311 {
5312 mParentLayer.reset( qobject_cast<QgsVectorLayer *>( ownedLayer.release() ) );
5313 layer = mParentLayer.get();
5314 }
5315 else
5316 {
5317 // don't need ownership of this layer - it wasn't owned by context (so e.g. is owned by the project)
5318 }
5319
5320 if ( mComboBox )
5321 mComboBox->setLayer( layer );
5322 else if ( mPanel )
5323 mPanel->setFields( filterFields( layer->fields() ) );
5324
5325 valueSet = true;
5326 }
5327
5328 if ( !valueSet )
5329 {
5330 std::unique_ptr<QgsProcessingFeatureSource> source( QgsProcessingParameters::parameterAsSource( parentWrapper->parameterDefinition(), value, *context ) );
5331 if ( source )
5332 {
5333 const QgsFields fields = source->fields();
5334 if ( mComboBox )
5335 mComboBox->setFields( fields );
5336 else if ( mPanel )
5337 mPanel->setFields( filterFields( fields ) );
5338
5339 valueSet = true;
5340 }
5341 }
5342
5343 if ( !valueSet )
5344 {
5345 if ( mComboBox )
5346 mComboBox->setLayer( nullptr );
5347 else if ( mPanel )
5348 mPanel->setFields( QgsFields() );
5349
5350 if ( value.isValid() && widgetContext().messageBar() )
5351 {
5352 widgetContext().messageBar()->clearWidgets();
5353 widgetContext().messageBar()->pushMessage( QString(), QObject::tr( "Could not load selected layer/table. Dependent field could not be populated" ), Qgis::MessageLevel::Info );
5354 }
5355 return;
5356 }
5357
5358 const QgsProcessingParameterField *fieldParam = static_cast<const QgsProcessingParameterField *>( parameterDefinition() );
5359 if ( mPanel && fieldParam->defaultToAllFields() )
5360 {
5361 QVariantList val;
5362 val.reserve( mPanel->fields().size() );
5363 for ( const QgsField &field : mPanel->fields() )
5364 val << field.name();
5365 setWidgetValue( val, *context );
5366 }
5367 else if ( fieldParam->defaultValueForGui().isValid() )
5368 setWidgetValue( parameterDefinition()->defaultValueForGui(), *context );
5369}
5370
5371void QgsProcessingFieldWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
5372{
5373 if ( mComboBox )
5374 {
5375 if ( !value.isValid() )
5376 mComboBox->setField( QString() );
5377 else
5378 {
5379 const QString v = QgsProcessingParameters::parameterAsString( parameterDefinition(), value, context );
5380 mComboBox->setField( v );
5381 }
5382 }
5383 else if ( mPanel )
5384 {
5385 QVariantList opts;
5386 if ( value.isValid() )
5387 {
5388 const QStringList v = QgsProcessingParameters::parameterAsStrings( parameterDefinition(), value, context );
5389 opts.reserve( v.size() );
5390 for ( const QString &i : v )
5391 opts << i;
5392 }
5393 if ( mPanel )
5394 mPanel->setValue( opts );
5395 }
5396 else if ( mLineEdit )
5397 {
5398 const QgsProcessingParameterField *fieldParam = static_cast<const QgsProcessingParameterField *>( parameterDefinition() );
5399 if ( fieldParam->allowMultiple() )
5400 {
5401 const QStringList v = QgsProcessingParameters::parameterAsStrings( parameterDefinition(), value, context );
5402 mLineEdit->setText( v.join( ';' ) );
5403 }
5404 else
5405 {
5406 mLineEdit->setText( QgsProcessingParameters::parameterAsString( parameterDefinition(), value, context ) );
5407 }
5408 }
5409}
5410
5411QVariant QgsProcessingFieldWidgetWrapper::widgetValue() const
5412{
5413 if ( mComboBox )
5414 return mComboBox->currentField();
5415 else if ( mPanel )
5416 return mPanel->value();
5417 else if ( mLineEdit )
5418 {
5419 const QgsProcessingParameterField *fieldParam = static_cast<const QgsProcessingParameterField *>( parameterDefinition() );
5420 if ( fieldParam->allowMultiple() )
5421 {
5422 return mLineEdit->text().split( ';' );
5423 }
5424 else
5425 return mLineEdit->text();
5426 }
5427 else
5428 return QVariant();
5429}
5430
5431QStringList QgsProcessingFieldWidgetWrapper::compatibleParameterTypes() const
5432{
5433 return QStringList()
5436}
5437
5438QStringList QgsProcessingFieldWidgetWrapper::compatibleOutputTypes() const
5439{
5440 return QStringList()
5443}
5444
5445QString QgsProcessingFieldWidgetWrapper::modelerExpressionFormatString() const
5446{
5447 return tr( "selected field names as an array of names, or semicolon separated string of options (e.g. 'fid;place_name')" );
5448}
5449
5450const QgsVectorLayer *QgsProcessingFieldWidgetWrapper::linkedVectorLayer() const
5451{
5452 if ( mComboBox && mComboBox->layer() )
5453 return mComboBox->layer();
5454
5456}
5457
5458QgsFields QgsProcessingFieldWidgetWrapper::filterFields( const QgsFields &fields ) const
5459{
5460 const QgsProcessingParameterField *fieldParam = static_cast<const QgsProcessingParameterField *>( parameterDefinition() );
5461 QgsFields res;
5462 for ( const QgsField &f : fields )
5463 {
5464 switch ( fieldParam->dataType() )
5465 {
5467 res.append( f );
5468 break;
5469
5471 if ( f.isNumeric() )
5472 res.append( f );
5473 break;
5474
5476 if ( f.type() == QMetaType::Type::QString )
5477 res.append( f );
5478 break;
5479
5481 if ( f.type() == QMetaType::Type::QDate || f.type() == QMetaType::Type::QTime || f.type() == QMetaType::Type::QDateTime )
5482 res.append( f );
5483 break;
5484
5486 if ( f.type() == QMetaType::Type::QByteArray )
5487 res.append( f );
5488 break;
5489
5491 if ( f.type() == QMetaType::Type::Bool )
5492 res.append( f );
5493 break;
5494 }
5495 }
5496
5497 return res;
5498}
5499
5500QString QgsProcessingFieldWidgetWrapper::parameterType() const
5501{
5503}
5504
5505QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingFieldWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
5506{
5507 return new QgsProcessingFieldWidgetWrapper( parameter, type );
5508}
5509
5510QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingFieldWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
5511{
5512 return new QgsProcessingFieldParameterDefinitionWidget( context, widgetContext, definition, algorithm );
5513}
5514
5515//
5516// QgsProcessingMapThemeWidgetWrapper
5517//
5518
5519
5520QgsProcessingMapThemeParameterDefinitionWidget::QgsProcessingMapThemeParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
5521 : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
5522{
5523 QVBoxLayout *vlayout = new QVBoxLayout();
5524 vlayout->setContentsMargins( 0, 0, 0, 0 );
5525
5526 vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
5527
5528 mDefaultComboBox = new QComboBox();
5529 mDefaultComboBox->addItem( QString(), QVariant( -1 ) );
5530
5531 const QStringList mapThemes = widgetContext.project() ? widgetContext.project()->mapThemeCollection()->mapThemes() : QgsProject::instance()->mapThemeCollection()->mapThemes();
5532 for ( const QString &theme : mapThemes )
5533 {
5534 mDefaultComboBox->addItem( QgsApplication::getThemeIcon( QStringLiteral( "/mActionShowAllLayers.svg" ) ), theme, theme );
5535 }
5536 mDefaultComboBox->setEditable( true );
5537
5538 if ( const QgsProcessingParameterMapTheme *themeParam = dynamic_cast<const QgsProcessingParameterMapTheme *>( definition ) )
5539 {
5540 if ( themeParam->defaultValueForGui().isValid() )
5541 mDefaultComboBox->setCurrentText( QgsProcessingParameters::parameterAsString( themeParam, themeParam->defaultValueForGui(), context ) );
5542 else
5543 mDefaultComboBox->setCurrentIndex( mDefaultComboBox->findData( -1 ) );
5544 }
5545 else
5546 mDefaultComboBox->setCurrentIndex( mDefaultComboBox->findData( -1 ) );
5547
5548 vlayout->addWidget( mDefaultComboBox );
5549
5550 setLayout( vlayout );
5551}
5552
5553QgsProcessingParameterDefinition *QgsProcessingMapThemeParameterDefinitionWidget::createParameter( const QString &name, const QString &description, Qgis::ProcessingParameterFlags flags ) const
5554{
5555 QVariant defaultVal;
5556 if ( mDefaultComboBox->currentText().isEmpty() )
5557 defaultVal = QVariant();
5558 else
5559 defaultVal = mDefaultComboBox->currentText();
5560 auto param = std::make_unique<QgsProcessingParameterMapTheme>( name, description, defaultVal );
5561 param->setFlags( flags );
5562 return param.release();
5563}
5564
5565
5566QgsProcessingMapThemeWidgetWrapper::QgsProcessingMapThemeWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
5567 : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
5568{
5569}
5570
5571QWidget *QgsProcessingMapThemeWidgetWrapper::createWidget()
5572{
5573 const QgsProcessingParameterMapTheme *themeParam = dynamic_cast<const QgsProcessingParameterMapTheme *>( parameterDefinition() );
5574
5575 mComboBox = new QComboBox();
5576
5577 if ( themeParam->flags() & Qgis::ProcessingParameterFlag::Optional )
5578 mComboBox->addItem( tr( "[Not selected]" ), QVariant( -1 ) );
5579
5580 const QStringList mapThemes = widgetContext().project() ? widgetContext().project()->mapThemeCollection()->mapThemes() : QgsProject::instance()->mapThemeCollection()->mapThemes();
5581 for ( const QString &theme : mapThemes )
5582 {
5583 mComboBox->addItem( QgsApplication::getThemeIcon( QStringLiteral( "/mActionShowAllLayers.svg" ) ), theme, theme );
5584 }
5585
5586 switch ( type() )
5587 {
5590 break;
5591
5593 mComboBox->setEditable( true );
5594 break;
5595 }
5596
5597 mComboBox->setToolTip( parameterDefinition()->toolTip() );
5598 connect( mComboBox, qOverload<int>( &QComboBox::currentIndexChanged ), this, [=]( int ) {
5599 emit widgetValueHasChanged( this );
5600 } );
5601
5602 return mComboBox;
5603}
5604
5605void QgsProcessingMapThemeWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
5606{
5607 const QString v = QgsProcessingParameters::parameterAsString( parameterDefinition(), value, context );
5608
5609 if ( !value.isValid() )
5610 mComboBox->setCurrentIndex( mComboBox->findData( QVariant( -1 ) ) );
5611 else
5612 {
5613 if ( mComboBox->isEditable() && mComboBox->findData( v ) == -1 )
5614 {
5615 const QString prev = mComboBox->currentText();
5616 mComboBox->setCurrentText( v );
5617 if ( prev != v )
5618 emit widgetValueHasChanged( this );
5619 }
5620 else
5621 mComboBox->setCurrentIndex( mComboBox->findData( v ) );
5622 }
5623}
5624
5625QVariant QgsProcessingMapThemeWidgetWrapper::widgetValue() const
5626{
5627 if ( mComboBox )
5628 return mComboBox->currentData().toInt() == -1 ? QVariant() : !mComboBox->currentData().isValid() && mComboBox->isEditable() ? mComboBox->currentText().isEmpty() ? QVariant() : QVariant( mComboBox->currentText() )
5629 : mComboBox->currentData();
5630 else
5631 return QVariant();
5632}
5633
5634QStringList QgsProcessingMapThemeWidgetWrapper::compatibleParameterTypes() const
5635{
5636 return QStringList()
5639}
5640
5641QStringList QgsProcessingMapThemeWidgetWrapper::compatibleOutputTypes() const
5642{
5643 return QStringList()
5646}
5647
5648QString QgsProcessingMapThemeWidgetWrapper::modelerExpressionFormatString() const
5649{
5650 return tr( "map theme as a string value (e.g. 'base maps')" );
5651}
5652
5653QString QgsProcessingMapThemeWidgetWrapper::parameterType() const
5654{
5656}
5657
5658QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingMapThemeWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
5659{
5660 return new QgsProcessingMapThemeWidgetWrapper( parameter, type );
5661}
5662
5663QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingMapThemeWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
5664{
5665 return new QgsProcessingMapThemeParameterDefinitionWidget( context, widgetContext, definition, algorithm );
5666}
5667
5668
5669//
5670// QgsProcessingDateTimeWidgetWrapper
5671//
5672
5673
5674QgsProcessingDateTimeParameterDefinitionWidget::QgsProcessingDateTimeParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
5675 : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
5676{
5677 QVBoxLayout *vlayout = new QVBoxLayout();
5678 vlayout->setContentsMargins( 0, 0, 0, 0 );
5679
5680 vlayout->addWidget( new QLabel( tr( "Type" ) ) );
5681
5682 mTypeComboBox = new QComboBox();
5683 mTypeComboBox->addItem( tr( "Date and Time" ), static_cast<int>( Qgis::ProcessingDateTimeParameterDataType::DateTime ) );
5684 mTypeComboBox->addItem( tr( "Date" ), static_cast<int>( Qgis::ProcessingDateTimeParameterDataType::Date ) );
5685 mTypeComboBox->addItem( tr( "Time" ), static_cast<int>( Qgis::ProcessingDateTimeParameterDataType::Time ) );
5686 if ( const QgsProcessingParameterDateTime *datetimeParam = dynamic_cast<const QgsProcessingParameterDateTime *>( definition ) )
5687 mTypeComboBox->setCurrentIndex( mTypeComboBox->findData( static_cast<int>( datetimeParam->dataType() ) ) );
5688 else
5689 mTypeComboBox->setCurrentIndex( 0 );
5690 vlayout->addWidget( mTypeComboBox );
5691
5692 setLayout( vlayout );
5693}
5694
5695QgsProcessingParameterDefinition *QgsProcessingDateTimeParameterDefinitionWidget::createParameter( const QString &name, const QString &description, Qgis::ProcessingParameterFlags flags ) const
5696{
5697 auto param = std::make_unique<QgsProcessingParameterDateTime>( name, description );
5698 param->setDataType( static_cast<Qgis::ProcessingDateTimeParameterDataType>( mTypeComboBox->currentData().toInt() ) );
5699 param->setFlags( flags );
5700 return param.release();
5701}
5702
5703
5704QgsProcessingDateTimeWidgetWrapper::QgsProcessingDateTimeWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
5705 : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
5706{
5707}
5708
5709QWidget *QgsProcessingDateTimeWidgetWrapper::createWidget()
5710{
5711 const QgsProcessingParameterDateTime *dateTimeParam = dynamic_cast<const QgsProcessingParameterDateTime *>( parameterDefinition() );
5712
5713 QgsDateTimeEdit *widget = nullptr;
5714 switch ( dateTimeParam->dataType() )
5715 {
5717 mDateTimeEdit = new QgsDateTimeEdit();
5718 widget = mDateTimeEdit;
5719 break;
5720
5722 mDateEdit = new QgsDateEdit();
5723 widget = mDateEdit;
5724 break;
5725
5727 mTimeEdit = new QgsTimeEdit();
5728 widget = mTimeEdit;
5729 break;
5730 }
5731
5732 if ( dateTimeParam->flags() & Qgis::ProcessingParameterFlag::Optional )
5733 {
5734 widget->setNullRepresentation( tr( "[Not selected]" ) );
5735 widget->setAllowNull( true );
5736 }
5737 else
5738 {
5739 widget->setAllowNull( false );
5740 }
5741 widget->setToolTip( parameterDefinition()->toolTip() );
5742
5743 if ( mDateTimeEdit )
5744 {
5745 connect( mDateTimeEdit, &QgsDateTimeEdit::valueChanged, this, [=]( const QDateTime & ) {
5746 emit widgetValueHasChanged( this );
5747 } );
5748 }
5749 else if ( mDateEdit )
5750 {
5751 connect( mDateEdit, &QgsDateEdit::dateValueChanged, this, [=]( const QDate & ) {
5752 emit widgetValueHasChanged( this );
5753 } );
5754 }
5755 else if ( mTimeEdit )
5756 {
5757 connect( mTimeEdit, &QgsTimeEdit::timeValueChanged, this, [=]( const QTime & ) {
5758 emit widgetValueHasChanged( this );
5759 } );
5760 }
5761
5762 return widget;
5763}
5764
5765QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingDateTimeWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
5766{
5767 return new QgsProcessingDateTimeParameterDefinitionWidget( context, widgetContext, definition, algorithm );
5768}
5769
5770void QgsProcessingDateTimeWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
5771{
5772 if ( mDateTimeEdit )
5773 {
5774 mDateTimeEdit->setDateTime( QgsProcessingParameters::parameterAsDateTime( parameterDefinition(), value, context ) );
5775 }
5776 else if ( mDateEdit )
5777 {
5778 mDateEdit->setDate( QgsProcessingParameters::parameterAsDate( parameterDefinition(),