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