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