QGIS API Documentation 3.30.0-'s-Hertogenbosch (f186b8efe0)
qgsprocessingwidgetwrapperimpl.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsprocessingwidgetwrapperimpl.cpp
3 ---------------------
4 begin : August 2018
5 copyright : (C) 2018 by Nyall Dawson
6 email : nyall dot dawson at gmail dot com
7 ***************************************************************************/
8
9/***************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 ***************************************************************************/
17
24#include "qgsspinbox.h"
25#include "qgsdoublespinbox.h"
27#include "qgsauthconfigselect.h"
28#include "qgsapplication.h"
29#include "qgsfilewidget.h"
30#include "qgssettings.h"
35#include "qgslayoutmanager.h"
36#include "qgsproject.h"
37#include "qgslayoutcombobox.h"
39#include "qgsprintlayout.h"
40#include "qgsscalewidget.h"
41#include "qgssnapindicator.h"
42#include "qgsmapmouseevent.h"
43#include "qgsfilterlineedit.h"
44#include "qgsmapcanvas.h"
45#include "qgsmessagebar.h"
46#include "qgscolorbutton.h"
49#include "qgsfieldcombobox.h"
51#include "qgsdatetimeedit.h"
55#include "qgsextentwidget.h"
63#include "qgsdoublevalidator.h"
64#include "qgsmaplayercombobox.h"
65#include "qgsannotationlayer.h"
66#include "qgsunittypes.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
1129 mUnitsCombo->addItem( QgsUnitTypes::toString( Qgis::DistanceUnit::Meters ), static_cast< int >( Qgis::DistanceUnit::Meters ) );
1130 mUnitsCombo->addItem( QgsUnitTypes::toString( Qgis::DistanceUnit::Kilometers ), static_cast< int >( Qgis::DistanceUnit::Kilometers ) );
1131 mUnitsCombo->addItem( QgsUnitTypes::toString( Qgis::DistanceUnit::Feet ), static_cast< int >( Qgis::DistanceUnit::Feet ) );
1132 mUnitsCombo->addItem( QgsUnitTypes::toString( Qgis::DistanceUnit::Miles ), static_cast< int >( Qgis::DistanceUnit::Miles ) );
1133 mUnitsCombo->addItem( QgsUnitTypes::toString( Qgis::DistanceUnit::Yards ), static_cast< int >( Qgis::DistanceUnit::Yards ) );
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{
1205 Qgis::DistanceUnit units = Qgis::DistanceUnit::Unknown;
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( Qgis::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( static_cast< int >( units ) ) );
1239 mUnitsCombo->show();
1240 mLabel->hide();
1241 }
1242 mWarningLabel->setVisible( units == Qgis::DistanceUnit::Degrees );
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 Qgis::DistanceUnit displayUnit = static_cast<Qgis::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();
1291 mUnitsCombo->addItem( QgsUnitTypes::toString( Qgis::TemporalUnit::Milliseconds ), static_cast< int >( Qgis::TemporalUnit::Milliseconds ) );
1292 mUnitsCombo->addItem( QgsUnitTypes::toString( Qgis::TemporalUnit::Seconds ), static_cast< int >( Qgis::TemporalUnit::Seconds ) );
1293 mUnitsCombo->addItem( QgsUnitTypes::toString( Qgis::TemporalUnit::Minutes ), static_cast< int >( Qgis::TemporalUnit::Minutes ) );
1294 mUnitsCombo->addItem( QgsUnitTypes::toString( Qgis::TemporalUnit::Hours ), static_cast< int >( Qgis::TemporalUnit::Hours ) );
1295 mUnitsCombo->addItem( QgsUnitTypes::toString( Qgis::TemporalUnit::Days ), static_cast< int >( Qgis::TemporalUnit::Days ) );
1296 mUnitsCombo->addItem( QgsUnitTypes::toString( Qgis::TemporalUnit::Weeks ), static_cast< int >( Qgis::TemporalUnit::Weeks ) );
1297 mUnitsCombo->addItem( tr( "years (365.25 days)" ), static_cast< int >( Qgis::TemporalUnit::Years ) );
1298 mUnitsCombo->addItem( QgsUnitTypes::toString( Qgis::TemporalUnit::Decades ), static_cast< int >( Qgis::TemporalUnit::Decades ) );
1299 mUnitsCombo->addItem( QgsUnitTypes::toString( Qgis::TemporalUnit::Centuries ), static_cast< int >( Qgis::TemporalUnit::Centuries ) );
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( mUnitsCombo->findData( static_cast <int >( 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<Qgis::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
1365 mUnitsCombo->addItem( QgsUnitTypes::toString( Qgis::TemporalUnit::Milliseconds ), static_cast< int >( Qgis::TemporalUnit::Milliseconds ) );
1366 mUnitsCombo->addItem( QgsUnitTypes::toString( Qgis::TemporalUnit::Seconds ), static_cast< int >( Qgis::TemporalUnit::Seconds ) );
1367 mUnitsCombo->addItem( QgsUnitTypes::toString( Qgis::TemporalUnit::Minutes ), static_cast< int >( Qgis::TemporalUnit::Minutes ) );
1368 mUnitsCombo->addItem( QgsUnitTypes::toString( Qgis::TemporalUnit::Hours ), static_cast< int >( Qgis::TemporalUnit::Hours ) );
1369 mUnitsCombo->addItem( QgsUnitTypes::toString( Qgis::TemporalUnit::Days ), static_cast< int >( Qgis::TemporalUnit::Days ) );
1370 mUnitsCombo->addItem( QgsUnitTypes::toString( Qgis::TemporalUnit::Weeks ), static_cast< int >( Qgis::TemporalUnit::Weeks ) );
1371 mUnitsCombo->addItem( tr( "years (365.25 days)" ), static_cast< int >( Qgis::TemporalUnit::Years ) );
1372 mUnitsCombo->addItem( QgsUnitTypes::toString( Qgis::TemporalUnit::Decades ), static_cast< int >( Qgis::TemporalUnit::Decades ) );
1373 mUnitsCombo->addItem( QgsUnitTypes::toString( Qgis::TemporalUnit::Centuries ), static_cast< int >( Qgis::TemporalUnit::Centuries ) );
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( static_cast< int >( 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 Qgis::TemporalUnit displayUnit = static_cast<Qgis::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 Qgis::TemporalUnit displayUnit = static_cast<Qgis::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.userType() == QMetaType::type( "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() == Qgis::LayerType::Vector )
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 availableOptions.reserve( mFields.size() );
4145 for ( const QgsField &field : std::as_const( mFields ) )
4146 {
4147 availableOptions << field.name();
4148 }
4149
4151 if ( panel && panel->dockMode() )
4152 {
4153 QgsProcessingMultipleSelectionPanelWidget *widget = new QgsProcessingMultipleSelectionPanelWidget( availableOptions, mValue );
4154 widget->setPanelTitle( mParam->description() );
4155
4156 widget->setValueFormatter( []( const QVariant & v ) -> QString
4157 {
4158 return v.toString();
4159 } );
4160
4161 connect( widget, &QgsProcessingMultipleSelectionPanelWidget::selectionChanged, this, [ = ]()
4162 {
4163 setValue( widget->selectedOptions() );
4164 } );
4165 connect( widget, &QgsProcessingMultipleSelectionPanelWidget::acceptClicked, widget, &QgsPanelWidget::acceptPanel );
4166 panel->openPanel( widget );
4167 }
4168 else
4169 {
4170 QgsProcessingMultipleSelectionDialog dlg( availableOptions, mValue, this, Qt::WindowFlags() );
4171
4172 dlg.setValueFormatter( []( const QVariant & v ) -> QString
4173 {
4174 return v.toString();
4175 } );
4176 if ( dlg.exec() )
4177 {
4178 setValue( dlg.selectedOptions() );
4179 }
4180 }
4181}
4182
4183void QgsProcessingFieldPanelWidget::updateSummaryText()
4184{
4185 if ( !mParam )
4186 return;
4187
4188 if ( mValue.empty() )
4189 {
4190 mLineEdit->setText( tr( "%n field(s) selected", nullptr, 0 ) );
4191 }
4192 else
4193 {
4194 QStringList values;
4195 values.reserve( mValue.size() );
4196 for ( const QVariant &val : std::as_const( mValue ) )
4197 {
4198 values << val.toString();
4199 }
4200
4201 const QString concatenated = values.join( tr( "," ) );
4202 if ( concatenated.length() < 100 )
4203 mLineEdit->setText( concatenated );
4204 else
4205 mLineEdit->setText( tr( "%n field(s) selected", nullptr, mValue.count() ) );
4206 }
4207}
4208
4209
4210//
4211// QgsProcessingFieldWidgetWrapper
4212//
4213
4214QgsProcessingFieldParameterDefinitionWidget::QgsProcessingFieldParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
4215 : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
4216{
4217 QVBoxLayout *vlayout = new QVBoxLayout();
4218 vlayout->setContentsMargins( 0, 0, 0, 0 );
4219
4220 vlayout->addWidget( new QLabel( tr( "Parent layer" ) ) );
4221 mParentLayerComboBox = new QComboBox();
4222
4223 QString initialParent;
4224 if ( const QgsProcessingParameterField *fieldParam = dynamic_cast<const QgsProcessingParameterField *>( definition ) )
4225 initialParent = fieldParam->parentLayerParameterName();
4226
4227 if ( auto *lModel = widgetContext.model() )
4228 {
4229 // populate combo box with other model input choices
4230 const QMap<QString, QgsProcessingModelParameter> components = lModel->parameterComponents();
4231 for ( auto it = components.constBegin(); it != components.constEnd(); ++it )
4232 {
4233 if ( const QgsProcessingParameterFeatureSource *definition = dynamic_cast< const QgsProcessingParameterFeatureSource * >( lModel->parameterDefinition( it.value().parameterName() ) ) )
4234 {
4235 mParentLayerComboBox-> addItem( definition->description(), definition->name() );
4236 if ( !initialParent.isEmpty() && initialParent == definition->name() )
4237 {
4238 mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
4239 }
4240 }
4241 else if ( const QgsProcessingParameterVectorLayer *definition = dynamic_cast< const QgsProcessingParameterVectorLayer * >( lModel->parameterDefinition( it.value().parameterName() ) ) )
4242 {
4243 mParentLayerComboBox-> addItem( definition->description(), definition->name() );
4244 if ( !initialParent.isEmpty() && initialParent == definition->name() )
4245 {
4246 mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
4247 }
4248 }
4249 else if ( const QgsProcessingParameterMultipleLayers *definition = dynamic_cast< const QgsProcessingParameterMultipleLayers * >( lModel->parameterDefinition( it.value().parameterName() ) ) )
4250 {
4251 if ( definition->layerType() == QgsProcessing::TypeVector )
4252 {
4253 mParentLayerComboBox-> addItem( definition->description(), definition->name() );
4254 if ( !initialParent.isEmpty() && initialParent == definition->name() )
4255 {
4256 mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
4257 }
4258 }
4259 }
4260 }
4261 }
4262
4263 if ( mParentLayerComboBox->count() == 0 && !initialParent.isEmpty() )
4264 {
4265 // if no parent candidates found, we just add the existing one as a placeholder
4266 mParentLayerComboBox->addItem( initialParent, initialParent );
4267 mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
4268 }
4269
4270 vlayout->addWidget( mParentLayerComboBox );
4271
4272 vlayout->addWidget( new QLabel( tr( "Allowed data type" ) ) );
4273 mDataTypeComboBox = new QComboBox();
4274 mDataTypeComboBox->addItem( tr( "Any" ), QgsProcessingParameterField::Any );
4275 mDataTypeComboBox->addItem( tr( "Number" ), QgsProcessingParameterField::Numeric );
4276 mDataTypeComboBox->addItem( tr( "String" ), QgsProcessingParameterField::String );
4277 mDataTypeComboBox->addItem( tr( "Date/time" ), QgsProcessingParameterField::DateTime );
4278 if ( const QgsProcessingParameterField *fieldParam = dynamic_cast<const QgsProcessingParameterField *>( definition ) )
4279 mDataTypeComboBox->setCurrentIndex( mDataTypeComboBox->findData( fieldParam->dataType() ) );
4280
4281 vlayout->addWidget( mDataTypeComboBox );
4282
4283 mAllowMultipleCheckBox = new QCheckBox( tr( "Accept multiple fields" ) );
4284 if ( const QgsProcessingParameterField *fieldParam = dynamic_cast<const QgsProcessingParameterField *>( definition ) )
4285 mAllowMultipleCheckBox->setChecked( fieldParam->allowMultiple() );
4286
4287 vlayout->addWidget( mAllowMultipleCheckBox );
4288
4289 mDefaultToAllCheckBox = new QCheckBox( tr( "Select all fields by default" ) );
4290 mDefaultToAllCheckBox->setEnabled( mAllowMultipleCheckBox->isChecked() );
4291 if ( const QgsProcessingParameterField *fieldParam = dynamic_cast<const QgsProcessingParameterField *>( definition ) )
4292 mDefaultToAllCheckBox->setChecked( fieldParam->defaultToAllFields() );
4293
4294 vlayout->addWidget( mDefaultToAllCheckBox );
4295
4296 connect( mAllowMultipleCheckBox, &QCheckBox::stateChanged, this, [ = ]
4297 {
4298 mDefaultToAllCheckBox->setEnabled( mAllowMultipleCheckBox->isChecked() );
4299 } );
4300
4301 vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
4302
4303 mDefaultLineEdit = new QLineEdit();
4304 mDefaultLineEdit->setToolTip( tr( "Default field name, or ; separated list of field names for multiple field parameters" ) );
4305 if ( const QgsProcessingParameterField *fieldParam = dynamic_cast<const QgsProcessingParameterField *>( definition ) )
4306 {
4307 const QStringList fields = QgsProcessingParameters::parameterAsFields( fieldParam, fieldParam->defaultValueForGui(), context );
4308 mDefaultLineEdit->setText( fields.join( ';' ) );
4309 }
4310 vlayout->addWidget( mDefaultLineEdit );
4311
4312 setLayout( vlayout );
4313}
4314
4315QgsProcessingParameterDefinition *QgsProcessingFieldParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
4316{
4317 QgsProcessingParameterField::DataType dataType = static_cast< QgsProcessingParameterField::DataType >( mDataTypeComboBox->currentData().toInt() );
4318
4319 QVariant defaultValue;
4320 if ( !mDefaultLineEdit->text().trimmed().isEmpty() )
4321 {
4322 defaultValue = mDefaultLineEdit->text();
4323 }
4324 auto param = std::make_unique< QgsProcessingParameterField >( name, description, defaultValue, mParentLayerComboBox->currentData().toString(), dataType, mAllowMultipleCheckBox->isChecked(), false, mDefaultToAllCheckBox->isChecked() );
4325 param->setFlags( flags );
4326 return param.release();
4327}
4328
4329QgsProcessingFieldWidgetWrapper::QgsProcessingFieldWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
4330 : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
4331{
4332
4333}
4334
4335QWidget *QgsProcessingFieldWidgetWrapper::createWidget()
4336{
4337 const QgsProcessingParameterField *fieldParam = dynamic_cast< const QgsProcessingParameterField *>( parameterDefinition() );
4338 switch ( type() )
4339 {
4342 {
4343 if ( fieldParam->allowMultiple() )
4344 {
4345 mPanel = new QgsProcessingFieldPanelWidget( nullptr, fieldParam );
4346 mPanel->setToolTip( parameterDefinition()->toolTip() );
4347 connect( mPanel, &QgsProcessingFieldPanelWidget::changed, this, [ = ]
4348 {
4349 emit widgetValueHasChanged( this );
4350 } );
4351 return mPanel;
4352 }
4353 else
4354 {
4355 mComboBox = new QgsFieldComboBox();
4356 mComboBox->setAllowEmptyFieldName( fieldParam->flags() & QgsProcessingParameterDefinition::FlagOptional );
4357
4358 if ( fieldParam->dataType() == QgsProcessingParameterField::Numeric )
4359 mComboBox->setFilters( QgsFieldProxyModel::Numeric );
4360 else if ( fieldParam->dataType() == QgsProcessingParameterField::String )
4361 mComboBox->setFilters( QgsFieldProxyModel::String );
4362 else if ( fieldParam->dataType() == QgsProcessingParameterField::DateTime )
4364
4365 mComboBox->setToolTip( parameterDefinition()->toolTip() );
4366 connect( mComboBox, &QgsFieldComboBox::fieldChanged, this, [ = ]( const QString & )
4367 {
4368 emit widgetValueHasChanged( this );
4369 } );
4370 return mComboBox;
4371 }
4372 }
4373
4375 {
4376 mLineEdit = new QLineEdit();
4377 mLineEdit->setToolTip( QObject::tr( "Name of field (separate field names with ; for multiple field parameters)" ) );
4378 connect( mLineEdit, &QLineEdit::textChanged, this, [ = ]
4379 {
4380 emit widgetValueHasChanged( this );
4381 } );
4382 return mLineEdit;
4383 }
4384
4385 }
4386 return nullptr;
4387}
4388
4389void QgsProcessingFieldWidgetWrapper::postInitialize( const QList<QgsAbstractProcessingParameterWidgetWrapper *> &wrappers )
4390{
4392 switch ( type() )
4393 {
4396 {
4397 for ( const QgsAbstractProcessingParameterWidgetWrapper *wrapper : wrappers )
4398 {
4399 if ( wrapper->parameterDefinition()->name() == static_cast< const QgsProcessingParameterField * >( parameterDefinition() )->parentLayerParameterName() )
4400 {
4401 setParentLayerWrapperValue( wrapper );
4403 {
4404 setParentLayerWrapperValue( wrapper );
4405 } );
4406 break;
4407 }
4408 }
4409 break;
4410 }
4411
4413 break;
4414 }
4415}
4416
4417void QgsProcessingFieldWidgetWrapper::setParentLayerWrapperValue( const QgsAbstractProcessingParameterWidgetWrapper *parentWrapper )
4418{
4419 // evaluate value to layer
4420 QgsProcessingContext *context = nullptr;
4421 std::unique_ptr< QgsProcessingContext > tmpContext;
4422 if ( mProcessingContextGenerator )
4423 context = mProcessingContextGenerator->processingContext();
4424
4425 if ( !context )
4426 {
4427 tmpContext = std::make_unique< QgsProcessingContext >();
4428 context = tmpContext.get();
4429 }
4430
4431 QVariant value = parentWrapper->parameterValue();
4432
4433 if ( value.userType() == QMetaType::type( "QgsProcessingFeatureSourceDefinition" ) )
4434 {
4435 // input is a QgsProcessingFeatureSourceDefinition - source from it.
4436 // this is normally discouraged, and algorithms should NEVER do this -- but in this case we can make
4437 // certain assumptions due to the fact that we're calling this outside of algorithm/model execution and all sources
4438 // should be real map layers at this stage
4439 QgsProcessingFeatureSourceDefinition fromVar = qvariant_cast<QgsProcessingFeatureSourceDefinition>( value );
4440 value = fromVar.source;
4441 }
4442
4443 bool valueSet = false;
4444 const QList< QgsMapLayer * > layers = QgsProcessingParameters::parameterAsLayerList( parentWrapper->parameterDefinition(), value, *context );
4445
4446 // several layers, populate with intersection of layers fields
4447 if ( layers.count() > 1 )
4448 {
4449 QgsVectorLayer *vlayer = qobject_cast< QgsVectorLayer * >( layers.at( 0 ) );
4450 QgsFields fields = vlayer && vlayer->isValid() ? vlayer->fields() : QgsFields();
4451 const QList< QgsMapLayer * > remainingLayers = layers.mid( 1 );
4452 for ( QgsMapLayer *layer : remainingLayers )
4453 {
4454 if ( fields.isEmpty() )
4455 break;
4456
4457 QgsVectorLayer *vlayer = qobject_cast< QgsVectorLayer * >( layer );
4458 if ( !vlayer || !vlayer->isValid() )
4459 {
4460 fields = QgsFields();
4461 break;
4462 }
4463
4464 for ( int fieldIdx = fields.count() - 1; fieldIdx >= 0; fieldIdx-- )
4465 {
4466 if ( vlayer->fields().lookupField( fields.at( fieldIdx ).name() ) < 0 )
4467 fields.remove( fieldIdx );
4468 }
4469 }
4470
4471 if ( mComboBox )
4472 mComboBox->setFields( fields );
4473 else if ( mPanel )
4474 mPanel->setFields( filterFields( fields ) );
4475
4476 valueSet = true;
4477 }
4478
4479 // only one layer
4480 if ( !valueSet && !layers.isEmpty() && layers.at( 0 )->isValid() )
4481 {
4482 QgsVectorLayer *layer = qobject_cast< QgsVectorLayer * >( layers.at( 0 ) );
4483
4484 // need to grab ownership of layer if required - otherwise layer may be deleted when context
4485 // goes out of scope
4486 std::unique_ptr< QgsMapLayer > ownedLayer( context->takeResultLayer( layer->id() ) );
4487 if ( ownedLayer && ownedLayer->type() == Qgis::LayerType::Vector )
4488 {
4489 mParentLayer.reset( qobject_cast< QgsVectorLayer * >( ownedLayer.release() ) );
4490 layer = mParentLayer.get();
4491 }
4492 else
4493 {
4494 // don't need ownership of this layer - it wasn't owned by context (so e.g. is owned by the project)
4495 }
4496
4497 if ( mComboBox )
4498 mComboBox->setLayer( layer );
4499 else if ( mPanel )
4500 mPanel->setFields( filterFields( layer->fields() ) );
4501
4502 valueSet = true;
4503 }
4504
4505 if ( !valueSet )
4506 {
4507 std::unique_ptr< QgsProcessingFeatureSource > source( QgsProcessingParameters::parameterAsSource( parentWrapper->parameterDefinition(), value, *context ) );
4508 if ( source )
4509 {
4510 const QgsFields fields = source->fields();
4511 if ( mComboBox )
4512 mComboBox->setFields( fields );
4513 else if ( mPanel )
4514 mPanel->setFields( filterFields( fields ) );
4515
4516 valueSet = true;
4517 }
4518 }
4519
4520 if ( !valueSet )
4521 {
4522 if ( mComboBox )
4523 mComboBox->setLayer( nullptr );
4524 else if ( mPanel )
4525 mPanel->setFields( QgsFields() );
4526
4527 if ( value.isValid() && widgetContext().messageBar() )
4528 {
4529 widgetContext().messageBar()->clearWidgets();
4530 widgetContext().messageBar()->pushMessage( QString(), QObject::tr( "Could not load selected layer/table. Dependent field could not be populated" ),
4531 Qgis::MessageLevel::Info );
4532 }
4533 return;
4534 }
4535
4536 const QgsProcessingParameterField *fieldParam = static_cast< const QgsProcessingParameterField * >( parameterDefinition() );
4537 if ( mPanel && fieldParam->defaultToAllFields() )
4538 {
4539 QVariantList val;
4540 val.reserve( mPanel->fields().size() );
4541 for ( const QgsField &field : mPanel->fields() )
4542 val << field.name();
4543 setWidgetValue( val, *context );
4544 }
4545 else if ( fieldParam->defaultValueForGui().isValid() )
4546 setWidgetValue( parameterDefinition()->defaultValueForGui(), *context );
4547}
4548
4549void QgsProcessingFieldWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
4550{
4551 if ( mComboBox )
4552 {
4553 if ( !value.isValid() )
4554 mComboBox->setField( QString() );
4555 else
4556 {
4557 const QString v = QgsProcessingParameters::parameterAsString( parameterDefinition(), value, context );
4558 mComboBox->setField( v );
4559 }
4560 }
4561 else if ( mPanel )
4562 {
4563 QVariantList opts;
4564 if ( value.isValid() )
4565 {
4566 const QStringList v = QgsProcessingParameters::parameterAsFields( parameterDefinition(), value, context );
4567 opts.reserve( v.size() );
4568 for ( const QString &i : v )
4569 opts << i;
4570 }
4571 if ( mPanel )
4572 mPanel->setValue( opts );
4573 }
4574 else if ( mLineEdit )
4575 {
4576 const QgsProcessingParameterField *fieldParam = static_cast< const QgsProcessingParameterField * >( parameterDefinition() );
4577 if ( fieldParam->allowMultiple() )
4578 {
4579 const QStringList v = QgsProcessingParameters::parameterAsFields( parameterDefinition(), value, context );
4580 mLineEdit->setText( v.join( ';' ) );
4581 }
4582 else
4583 {
4584 mLineEdit->setText( QgsProcessingParameters::parameterAsString( parameterDefinition(), value, context ) );
4585 }
4586 }
4587}
4588
4589QVariant QgsProcessingFieldWidgetWrapper::widgetValue() const
4590{
4591 if ( mComboBox )
4592 return mComboBox->currentField();
4593 else if ( mPanel )
4594 return mPanel->value();
4595 else if ( mLineEdit )
4596 {
4597 const QgsProcessingParameterField *fieldParam = static_cast< const QgsProcessingParameterField * >( parameterDefinition() );
4598 if ( fieldParam->allowMultiple() )
4599 {
4600 return mLineEdit->text().split( ';' );
4601 }
4602 else
4603 return mLineEdit->text();
4604 }
4605 else
4606 return QVariant();
4607}
4608
4609QStringList QgsProcessingFieldWidgetWrapper::compatibleParameterTypes() const
4610{
4611 return QStringList()
4614}
4615
4616QStringList QgsProcessingFieldWidgetWrapper::compatibleOutputTypes() const
4617{
4618 return QStringList()
4620}
4621
4622QString QgsProcessingFieldWidgetWrapper::modelerExpressionFormatString() const
4623{
4624 return tr( "selected field names as an array of names, or semicolon separated string of options (e.g. 'fid;place_name')" );
4625}
4626
4627const QgsVectorLayer *QgsProcessingFieldWidgetWrapper::linkedVectorLayer() const
4628{
4629 if ( mComboBox && mComboBox->layer() )
4630 return mComboBox->layer();
4631
4633}
4634
4635QgsFields QgsProcessingFieldWidgetWrapper::filterFields( const QgsFields &fields ) const
4636{
4637 const QgsProcessingParameterField *fieldParam = static_cast< const QgsProcessingParameterField * >( parameterDefinition() );
4638 QgsFields res;
4639 for ( const QgsField &f : fields )
4640 {
4641 switch ( fieldParam->dataType() )
4642 {
4644 res.append( f );
4645 break;
4646
4648 if ( f.isNumeric() )
4649 res.append( f );
4650 break;
4651
4653 if ( f.type() == QVariant::String )
4654 res.append( f );
4655 break;
4656
4658 if ( f.type() == QVariant::Date || f.type() == QVariant::Time || f.type() == QVariant::DateTime )
4659 res.append( f );
4660 break;
4661 }
4662 }
4663
4664 return res;
4665}
4666
4667QString QgsProcessingFieldWidgetWrapper::parameterType() const
4668{
4670}
4671
4672QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingFieldWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
4673{
4674 return new QgsProcessingFieldWidgetWrapper( parameter, type );
4675}
4676
4677QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingFieldWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
4678{
4679 return new QgsProcessingFieldParameterDefinitionWidget( context, widgetContext, definition, algorithm );
4680}
4681
4682//
4683// QgsProcessingMapThemeWidgetWrapper
4684//
4685
4686
4687QgsProcessingMapThemeParameterDefinitionWidget::QgsProcessingMapThemeParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
4688 : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
4689{
4690 QVBoxLayout *vlayout = new QVBoxLayout();
4691 vlayout->setContentsMargins( 0, 0, 0, 0 );
4692
4693 vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
4694
4695 mDefaultComboBox = new QComboBox();
4696 mDefaultComboBox->addItem( QString(), QVariant( -1 ) );
4697
4698 const QStringList mapThemes = widgetContext.project() ? widgetContext.project()->mapThemeCollection()->mapThemes() : QgsProject::instance()->mapThemeCollection()->mapThemes();
4699 for ( const QString &theme : mapThemes )
4700 {
4701 mDefaultComboBox->addItem( QgsApplication::getThemeIcon( QStringLiteral( "/mActionShowAllLayers.svg" ) ), theme, theme );
4702 }
4703 mDefaultComboBox->setEditable( true );
4704
4705 if ( const QgsProcessingParameterMapTheme *themeParam = dynamic_cast<const QgsProcessingParameterMapTheme *>( definition ) )
4706 {
4707 if ( themeParam->defaultValueForGui().isValid() )
4708 mDefaultComboBox->setCurrentText( QgsProcessingParameters::parameterAsString( themeParam, themeParam->defaultValueForGui(), context ) );
4709 else
4710 mDefaultComboBox->setCurrentIndex( mDefaultComboBox->findData( -1 ) );
4711 }
4712 else
4713 mDefaultComboBox->setCurrentIndex( mDefaultComboBox->findData( -1 ) );
4714
4715 vlayout->addWidget( mDefaultComboBox );
4716
4717 setLayout( vlayout );
4718}
4719
4720QgsProcessingParameterDefinition *QgsProcessingMapThemeParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
4721{
4722 QVariant defaultVal;
4723 if ( mDefaultComboBox->currentText().isEmpty() )
4724 defaultVal = QVariant();
4725 else
4726 defaultVal = mDefaultComboBox->currentText();
4727 auto param = std::make_unique< QgsProcessingParameterMapTheme>( name, description, defaultVal );
4728 param->setFlags( flags );
4729 return param.release();
4730}
4731
4732
4733QgsProcessingMapThemeWidgetWrapper::QgsProcessingMapThemeWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
4734 : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
4735{
4736
4737}
4738
4739QWidget *QgsProcessingMapThemeWidgetWrapper::createWidget()
4740{
4741 const QgsProcessingParameterMapTheme *themeParam = dynamic_cast< const QgsProcessingParameterMapTheme *>( parameterDefinition() );
4742
4743 mComboBox = new QComboBox();
4744
4746 mComboBox->addItem( tr( "[Not selected]" ), QVariant( -1 ) );
4747
4748 const QStringList mapThemes = widgetContext().project() ? widgetContext().project()->mapThemeCollection()->mapThemes() : QgsProject::instance()->mapThemeCollection()->mapThemes();
4749 for ( const QString &theme : mapThemes )
4750 {
4751 mComboBox->addItem( QgsApplication::getThemeIcon( QStringLiteral( "/mActionShowAllLayers.svg" ) ), theme, theme );
4752 }
4753
4754 switch ( type() )
4755 {
4758 break;
4759
4761 mComboBox->setEditable( true );
4762 break;
4763 }
4764
4765 mComboBox->setToolTip( parameterDefinition()->toolTip() );
4766 connect( mComboBox, qOverload<int>( &QComboBox::currentIndexChanged ), this, [ = ]( int )
4767 {
4768 emit widgetValueHasChanged( this );
4769 } );
4770
4771 return mComboBox;
4772}
4773
4774void QgsProcessingMapThemeWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
4775{
4776 const QString v = QgsProcessingParameters::parameterAsString( parameterDefinition(), value, context );
4777
4778 if ( !value.isValid() )
4779 mComboBox->setCurrentIndex( mComboBox->findData( QVariant( -1 ) ) );
4780 else
4781 {
4782 if ( mComboBox->isEditable() && mComboBox->findData( v ) == -1 )
4783 {
4784 const QString prev = mComboBox->currentText();
4785 mComboBox->setCurrentText( v );
4786 if ( prev != v )
4787 emit widgetValueHasChanged( this );
4788 }
4789 else
4790 mComboBox->setCurrentIndex( mComboBox->findData( v ) );
4791 }
4792}
4793
4794QVariant QgsProcessingMapThemeWidgetWrapper::widgetValue() const
4795{
4796 if ( mComboBox )
4797 return mComboBox->currentData().toInt() == -1 ? QVariant() :
4798 !mComboBox->currentData().isValid() && mComboBox->isEditable() ? mComboBox->currentText().isEmpty() ? QVariant() : QVariant( mComboBox->currentText() )
4799 : mComboBox->currentData();
4800 else
4801 return QVariant();
4802}
4803
4804QStringList QgsProcessingMapThemeWidgetWrapper::compatibleParameterTypes() const
4805{
4806 return QStringList()
4809}
4810
4811QStringList QgsProcessingMapThemeWidgetWrapper::compatibleOutputTypes() const
4812{
4813 return QStringList()
4815}
4816
4817QString QgsProcessingMapThemeWidgetWrapper::modelerExpressionFormatString() const
4818{
4819 return tr( "map theme as a string value (e.g. 'base maps')" );
4820}
4821
4822QString QgsProcessingMapThemeWidgetWrapper::parameterType() const
4823{
4825}
4826
4827QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingMapThemeWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
4828{
4829 return new QgsProcessingMapThemeWidgetWrapper( parameter, type );
4830}
4831
4832QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingMapThemeWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
4833{
4834 return new QgsProcessingMapThemeParameterDefinitionWidget( context, widgetContext, definition, algorithm );
4835}
4836
4837
4838
4839//
4840// QgsProcessingDateTimeWidgetWrapper
4841//
4842
4843
4844QgsProcessingDateTimeParameterDefinitionWidget::QgsProcessingDateTimeParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
4845 : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
4846{
4847 QVBoxLayout *vlayout = new QVBoxLayout();
4848 vlayout->setContentsMargins( 0, 0, 0, 0 );
4849
4850 vlayout->addWidget( new QLabel( tr( "Type" ) ) );
4851
4852 mTypeComboBox = new QComboBox();
4853 mTypeComboBox->addItem( tr( "Date and Time" ), QgsProcessingParameterDateTime::DateTime );
4854 mTypeComboBox->addItem( tr( "Date" ), QgsProcessingParameterDateTime::Date );
4855 mTypeComboBox->addItem( tr( "Time" ), QgsProcessingParameterDateTime::Time );
4856 if ( const QgsProcessingParameterDateTime *datetimeParam = dynamic_cast<const QgsProcessingParameterDateTime *>( definition ) )
4857 mTypeComboBox->setCurrentIndex( mTypeComboBox->findData( datetimeParam->dataType() ) );
4858 else
4859 mTypeComboBox->setCurrentIndex( 0 );
4860 vlayout->addWidget( mTypeComboBox );
4861
4862 setLayout( vlayout );
4863}
4864
4865QgsProcessingParameterDefinition *QgsProcessingDateTimeParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
4866{
4867 auto param = std::make_unique< QgsProcessingParameterDateTime >( name, description );
4868 param->setDataType( static_cast< QgsProcessingParameterDateTime::Type >( mTypeComboBox->currentData().toInt() ) );
4869 param->setFlags( flags );
4870 return param.release();
4871}
4872
4873
4874QgsProcessingDateTimeWidgetWrapper::QgsProcessingDateTimeWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
4875 : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
4876{
4877
4878}
4879
4880QWidget *QgsProcessingDateTimeWidgetWrapper::createWidget()
4881{
4882 const QgsProcessingParameterDateTime *dateTimeParam = dynamic_cast< const QgsProcessingParameterDateTime *>( parameterDefinition() );
4883
4884 QgsDateTimeEdit *widget = nullptr;
4885 switch ( dateTimeParam->dataType() )
4886 {
4888 mDateTimeEdit = new QgsDateTimeEdit();
4889 widget = mDateTimeEdit;
4890 break;
4891
4893 mDateEdit = new QgsDateEdit();
4894 widget = mDateEdit;
4895 break;
4896
4898 mTimeEdit = new QgsTimeEdit();
4899 widget = mTimeEdit;
4900 break;
4901 }
4902
4904 {
4905 widget->setNullRepresentation( tr( "[Not selected]" ) );
4906 widget->setAllowNull( true );
4907 }
4908 else
4909 {
4910 widget->setAllowNull( false );
4911 }
4912 widget->setToolTip( parameterDefinition()->toolTip() );
4913
4914 if ( mDateTimeEdit )
4915 {
4916 connect( mDateTimeEdit, &QgsDateTimeEdit::valueChanged, this, [ = ]( const QDateTime & )
4917 {
4918 emit widgetValueHasChanged( this );
4919 } );
4920 }
4921 else if ( mDateEdit )
4922 {
4923 connect( mDateEdit, &QgsDateEdit::dateValueChanged, this, [ = ]( const QDate & )
4924 {
4925 emit widgetValueHasChanged( this );
4926 } );
4927 }
4928 else if ( mTimeEdit )
4929 {
4930 connect( mTimeEdit, &QgsTimeEdit::timeValueChanged, this, [ = ]( const QTime & )
4931 {
4932 emit widgetValueHasChanged( this );
4933 } );
4934 }
4935
4936 return widget;
4937}
4938
4939QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingDateTimeWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
4940{
4941 return new QgsProcessingDateTimeParameterDefinitionWidget( context, widgetContext, definition, algorithm );
4942}
4943
4944void QgsProcessingDateTimeWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
4945{
4946 if ( mDateTimeEdit )
4947 {
4948 mDateTimeEdit->setDateTime( QgsProcessingParameters::parameterAsDateTime( parameterDefinition(), value, context ) );
4949 }
4950 else if ( mDateEdit )
4951 {
4952 mDateEdit->setDate( QgsProcessingParameters::parameterAsDate( parameterDefinition(), value, context ) );
4953 }
4954 else if ( mTimeEdit )
4955 {
4956 mTimeEdit->setTime( QgsProcessingParameters::parameterAsTime( parameterDefinition(), value, context ) );
4957 }
4958}
4959
4960QVariant QgsProcessingDateTimeWidgetWrapper::widgetValue() const
4961{
4962 if ( mDateTimeEdit )
4963 return !mDateTimeEdit->dateTime().isNull() && mDateTimeEdit->dateTime().isValid() ? QVariant( mDateTimeEdit->dateTime() ) : QVariant();
4964 else if ( mDateEdit )
4965 return !mDateEdit->date().isNull() && mDateEdit->date().isValid() ? QVariant( mDateEdit->date() ) : QVariant();
4966 else if ( mTimeEdit )
4967 return !mTimeEdit->time().isNull() && mTimeEdit->time().isValid() ? QVariant( mTimeEdit->time() ) : QVariant();
4968 else
4969 return QVariant();
4970}
4971
4972QStringList QgsProcessingDateTimeWidgetWrapper::compatibleParameterTypes() const
4973{
4974 return QStringList()
4977}
4978
4979QStringList QgsProcessingDateTimeWidgetWrapper::compatibleOutputTypes() const
4980{
4981 return QStringList()
4983}
4984
4985QString QgsProcessingDateTimeWidgetWrapper::modelerExpressionFormatString() const
4986{
4987 const QgsProcessingParameterDateTime *dateTimeParam = dynamic_cast< const QgsProcessingParameterDateTime *>( parameterDefinition() );
4988 if ( dateTimeParam )
4989 {
4990 switch ( dateTimeParam->dataType() )
4991 {
4993 return tr( "datetime value, or a ISO string representation of a datetime" );
4994
4996 return tr( "date value, or a ISO string representation of a date" );
4997
4999 return tr( "time value, or a ISO string representation of a time" );
5000 }
5001 }
5002 return QString();
5003}
5004
5005QString QgsProcessingDateTimeWidgetWrapper::parameterType() const
5006{
5008}
5009
5010QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingDateTimeWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
5011{
5012 return new QgsProcessingDateTimeWidgetWrapper( parameter, type );
5013}
5014
5015
5016
5017//
5018// QgsProcessingProviderConnectionWidgetWrapper
5019//
5020
5021QgsProcessingProviderConnectionParameterDefinitionWidget::QgsProcessingProviderConnectionParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
5022 : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
5023{
5024 const QgsProcessingParameterProviderConnection *connectionParam = dynamic_cast< const QgsProcessingParameterProviderConnection *>( definition );
5025
5026 QVBoxLayout *vlayout = new QVBoxLayout();
5027 vlayout->setContentsMargins( 0, 0, 0, 0 );
5028
5029 vlayout->addWidget( new QLabel( tr( "Provider" ) ) );
5030 mProviderComboBox = new QComboBox();
5031 mProviderComboBox->addItem( QObject::tr( "Postgres" ), QStringLiteral( "postgres" ) );
5032 mProviderComboBox->addItem( QObject::tr( "GeoPackage" ), QStringLiteral( "ogr" ) );
5033 mProviderComboBox->addItem( QObject::tr( "Spatialite" ), QStringLiteral( "spatialite" ) );
5034
5035 vlayout->addWidget( mProviderComboBox );
5036
5037 vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
5038
5039 mDefaultEdit = new QLineEdit();
5040 vlayout->addWidget( mDefaultEdit );
5041 setLayout( vlayout );
5042
5043 if ( connectionParam )
5044 {
5045 mProviderComboBox->setCurrentIndex( mProviderComboBox->findData( connectionParam->providerId() ) );
5046 mDefaultEdit->setText( connectionParam->defaultValueForGui().toString() );
5047 }
5048}
5049
5050QgsProcessingParameterDefinition *QgsProcessingProviderConnectionParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
5051{
5052 QVariant defaultVal;
5053 if ( mDefaultEdit->text().isEmpty() )
5054 defaultVal = QVariant();
5055 else
5056 defaultVal = mDefaultEdit->text();
5057 auto param = std::make_unique< QgsProcessingParameterProviderConnection>( name, description, mProviderComboBox->currentData().toString(), defaultVal );
5058 param->setFlags( flags );
5059 return param.release();
5060}
5061
5062
5063QgsProcessingProviderConnectionWidgetWrapper::QgsProcessingProviderConnectionWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
5064 : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
5065{
5066
5067}
5068
5069QWidget *QgsProcessingProviderConnectionWidgetWrapper::createWidget()
5070{
5071 const QgsProcessingParameterProviderConnection *connectionParam = dynamic_cast< const QgsProcessingParameterProviderConnection *>( parameterDefinition() );
5072
5073 mProviderComboBox = new QgsProviderConnectionComboBox( connectionParam->providerId() );
5074 if ( connectionParam->flags() & QgsProcessingParameterDefinition::FlagOptional )
5075 mProviderComboBox->setAllowEmptyConnection( true );
5076
5077 switch ( type() )
5078 {
5081 break;
5083 mProviderComboBox->setEditable( true );
5084 break;
5085 }
5086
5087 mProviderComboBox->setToolTip( parameterDefinition()->toolTip() );
5088 connect( mProviderComboBox, &QgsProviderConnectionComboBox::currentTextChanged, this, [ = ]( const QString & )
5089 {
5090 if ( mBlockSignals )
5091 return;
5092
5093 emit widgetValueHasChanged( this );
5094 } );
5095
5096 return mProviderComboBox;
5097}
5098
5099QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingProviderConnectionWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
5100{
5101 return new QgsProcessingProviderConnectionParameterDefinitionWidget( context, widgetContext, definition, algorithm );
5102}
5103
5104void QgsProcessingProviderConnectionWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
5105{
5106 const QString v = QgsProcessingParameters::parameterAsConnectionName( parameterDefinition(), value, context );
5107
5108 if ( !value.isValid() )
5109 mProviderComboBox->setCurrentIndex( -1 );
5110 else
5111 {
5112 if ( mProviderComboBox->isEditable() )
5113 {
5114 const QString prev = mProviderComboBox->currentText();
5115 mBlockSignals++;
5116 mProviderComboBox->setConnection( v );
5117 mProviderComboBox->setCurrentText( v );
5118
5119 mBlockSignals--;
5120 if ( prev != v )
5121 emit widgetValueHasChanged( this );
5122 }
5123 else
5124 mProviderComboBox->setConnection( v );
5125 }
5126}
5127
5128QVariant QgsProcessingProviderConnectionWidgetWrapper::widgetValue() const
5129{
5130 if ( mProviderComboBox )
5131 if ( mProviderComboBox->isEditable() )
5132 return mProviderComboBox->currentText().isEmpty() ? QVariant() : QVariant( mProviderComboBox->currentText() );
5133 else
5134 return mProviderComboBox->currentConnection().isEmpty() ? QVariant() : QVariant( mProviderComboBox->currentConnection() );
5135 else
5136 return QVariant();
5137}
5138
5139QStringList QgsProcessingProviderConnectionWidgetWrapper::compatibleParameterTypes() const
5140{
5141 return QStringList()
5145}
5146
5147QStringList QgsProcessingProviderConnectionWidgetWrapper::compatibleOutputTypes() const
5148{
5149 return QStringList()
5151}
5152
5153QString QgsProcessingProviderConnectionWidgetWrapper::modelerExpressionFormatString() const
5154{
5155 return tr( "connection name as a string value" );
5156}
5157
5158QString QgsProcessingProviderConnectionWidgetWrapper::parameterType() const
5159{
5161}
5162
5163QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingProviderConnectionWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
5164{
5165 return new QgsProcessingProviderConnectionWidgetWrapper( parameter, type );
5166}
5167
5168
5169
5170
5171//
5172// QgsProcessingDatabaseSchemaWidgetWrapper
5173//
5174
5175QgsProcessingDatabaseSchemaParameterDefinitionWidget::QgsProcessingDatabaseSchemaParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
5176 : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
5177{
5178 const QgsProcessingParameterDatabaseSchema *schemaParam = dynamic_cast< const QgsProcessingParameterDatabaseSchema *>( definition );
5179
5180 QVBoxLayout *vlayout = new QVBoxLayout();
5181 vlayout->setContentsMargins( 0, 0, 0, 0 );
5182
5183 mConnectionParamComboBox = new QComboBox();
5184 QString initialConnection;
5185 if ( schemaParam )
5186 {
5187 initialConnection = schemaParam->parentConnectionParameterName();
5188 }
5189
5190 if ( auto *lModel = widgetContext.model() )
5191 {
5192 // populate combo box with other model input choices
5193 const QMap<QString, QgsProcessingModelParameter> components = lModel->parameterComponents();
5194 for ( auto it = components.constBegin(); it != components.constEnd(); ++it )
5195 {
5196 if ( definition && it->parameterName() == definition->name() )
5197 continue;
5198
5199 if ( !dynamic_cast< const QgsProcessingParameterProviderConnection * >( lModel->parameterDefinition( it->parameterName() ) ) )
5200 continue;
5201
5202 mConnectionParamComboBox->addItem( it->parameterName(), it->parameterName() );
5203 if ( !initialConnection.isEmpty() && initialConnection == it->parameterName() )
5204 {
5205 mConnectionParamComboBox->setCurrentIndex( mConnectionParamComboBox->count() - 1 );
5206 }
5207 }
5208 }
5209
5210 if ( mConnectionParamComboBox->count() == 0 && !initialConnection.isEmpty() )
5211 {
5212 // if no candidates found, we just add the existing one as a placeholder
5213 mConnectionParamComboBox->addItem( initialConnection, initialConnection );
5214 mConnectionParamComboBox->setCurrentIndex( mConnectionParamComboBox->count() - 1 );
5215 }
5216
5217 vlayout->addWidget( new QLabel( tr( "Provider connection parameter" ) ) );
5218 vlayout->addWidget( mConnectionParamComboBox );
5219
5220 vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
5221
5222 mDefaultEdit = new QLineEdit();
5223 vlayout->addWidget( mDefaultEdit );
5224 setLayout( vlayout );
5225
5226 if ( schemaParam )
5227 {
5228 mDefaultEdit->setText( schemaParam->defaultValueForGui().toString() );
5229 }
5230}
5231
5232QgsProcessingParameterDefinition *QgsProcessingDatabaseSchemaParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
5233{
5234 QVariant defaultVal;
5235 if ( mDefaultEdit->text().isEmpty() )
5236 defaultVal = QVariant();
5237 else
5238 defaultVal = mDefaultEdit->text();
5239 auto param = std::make_unique< QgsProcessingParameterDatabaseSchema>( name, description, mConnectionParamComboBox->currentData().toString(), defaultVal );
5240 param->setFlags( flags );
5241 return param.release();
5242}
5243
5244
5245QgsProcessingDatabaseSchemaWidgetWrapper::QgsProcessingDatabaseSchemaWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
5246 : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
5247{
5248
5249}
5250
5251QWidget *QgsProcessingDatabaseSchemaWidgetWrapper::createWidget()
5252{
5253 const QgsProcessingParameterDatabaseSchema *schemaParam = dynamic_cast< const QgsProcessingParameterDatabaseSchema *>( parameterDefinition() );
5254
5255 mSchemaComboBox = new QgsDatabaseSchemaComboBox( QString(), QString() );
5257 mSchemaComboBox->setAllowEmptySchema( true );
5258
5259 switch ( type() )
5260 {
5263 break;
5265 mSchemaComboBox->comboBox()->setEditable( true );
5266 break;
5267 }
5268
5269 mSchemaComboBox->setToolTip( parameterDefinition()->toolTip() );
5270 connect( mSchemaComboBox->comboBox(), &QComboBox::currentTextChanged, this, [ = ]( const QString & )
5271 {
5272 if ( mBlockSignals )
5273 return;
5274
5275 emit widgetValueHasChanged( this );
5276 } );
5277
5278 return mSchemaComboBox;
5279}
5280
5281QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingDatabaseSchemaWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
5282{
5283 return new QgsProcessingDatabaseSchemaParameterDefinitionWidget( context, widgetContext, definition, algorithm );
5284}
5285
5286void QgsProcessingDatabaseSchemaWidgetWrapper::setParentConnectionWrapperValue( const QgsAbstractProcessingParameterWidgetWrapper *parentWrapper )
5287{
5288 // evaluate value to connection
5289 QgsProcessingContext *context = nullptr;
5290 std::unique_ptr< QgsProcessingContext > tmpContext;
5291 if ( mProcessingContextGenerator )
5292 context = mProcessingContextGenerator->processingContext();
5293
5294 if ( !context )
5295 {
5296 tmpContext = std::make_unique< QgsProcessingContext >();
5297 context = tmpContext.get();
5298 }
5299
5300 const QVariant value = parentWrapper->parameterValue();
5301 const QString connection = value.isValid() ? QgsProcessingParameters::parameterAsConnectionName( parentWrapper->parameterDefinition(), value, *context ) : QString();
5302
5303 if ( mSchemaComboBox )
5304 mSchemaComboBox->setConnectionName( connection, qgis::down_cast< const QgsProcessingParameterProviderConnection * >( parentWrapper->parameterDefinition() )->providerId() );
5305
5306 const QgsProcessingParameterDatabaseSchema *schemaParam = qgis::down_cast< const QgsProcessingParameterDatabaseSchema * >( parameterDefinition() );
5307 if ( schemaParam->defaultValueForGui().isValid() )
5308 setWidgetValue( parameterDefinition()->defaultValueForGui(), *context );
5309}
5310
5311void QgsProcessingDatabaseSchemaWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
5312{
5313 const QString v = QgsProcessingParameters::parameterAsSchema( parameterDefinition(), value, context );
5314
5315 if ( !value.isValid() )
5316 mSchemaComboBox->comboBox()->setCurrentIndex( -1 );
5317 else
5318 {
5319 if ( mSchemaComboBox->comboBox()->isEditable() )
5320 {
5321 const QString prev = mSchemaComboBox->comboBox()->currentText();
5322 mBlockSignals++;
5323 mSchemaComboBox->setSchema( v );
5324 mSchemaComboBox->comboBox()->setCurrentText( v );
5325
5326 mBlockSignals--;
5327 if ( prev != v )
5328 emit widgetValueHasChanged( this );
5329 }
5330 else
5331 mSchemaComboBox->setSchema( v );
5332 }
5333}
5334
5335QVariant QgsProcessingDatabaseSchemaWidgetWrapper::widgetValue() const
5336{
5337 if ( mSchemaComboBox )
5338 if ( mSchemaComboBox->comboBox()->isEditable() )
5339 return mSchemaComboBox->comboBox()->currentText().isEmpty() ? QVariant() : QVariant( mSchemaComboBox->comboBox()->currentText() );
5340 else
5341 return mSchemaComboBox->currentSchema().isEmpty() ? QVariant() : QVariant( mSchemaComboBox->currentSchema() );
5342 else
5343 return QVariant();
5344}
5345
5346QStringList QgsProcessingDatabaseSchemaWidgetWrapper::compatibleParameterTypes() const
5347{
5348 return QStringList()
5352}
5353
5354QStringList QgsProcessingDatabaseSchemaWidgetWrapper::compatibleOutputTypes() const
5355{
5356 return QStringList()
5358}
5359
5360QString QgsProcessingDatabaseSchemaWidgetWrapper::modelerExpressionFormatString() const
5361{
5362 return tr( "database schema name as a string value" );
5363}
5364
5365QString QgsProcessingDatabaseSchemaWidgetWrapper::parameterType() const
5366{
5368}
5369
5370QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingDatabaseSchemaWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
5371{
5372 return new QgsProcessingDatabaseSchemaWidgetWrapper( parameter, type );
5373}
5374
5375void QgsProcessingDatabaseSchemaWidgetWrapper::postInitialize( const QList<QgsAbstractProcessingParameterWidgetWrapper *> &wrappers )
5376{
5378 switch ( type() )
5379 {
5382 {
5383 for ( const QgsAbstractProcessingParameterWidgetWrapper *wrapper : wrappers )
5384 {
5385 if ( wrapper->parameterDefinition()->name() == static_cast< const QgsProcessingParameterDatabaseSchema * >( parameterDefinition() )->parentConnectionParameterName() )
5386 {
5387 setParentConnectionWrapperValue( wrapper );
5389 {
5390 setParentConnectionWrapperValue( wrapper );
5391 } );
5392 break;
5393 }
5394 }
5395 break;
5396 }
5397
5399 break;
5400 }
5401}
5402
5403
5404
5405//
5406// QgsProcessingDatabaseTableWidgetWrapper
5407//
5408
5409QgsProcessingDatabaseTableParameterDefinitionWidget::QgsProcessingDatabaseTableParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
5410 : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
5411{
5412 const QgsProcessingParameterDatabaseTable *tableParam = dynamic_cast< const QgsProcessingParameterDatabaseTable *>( definition );
5413
5414 QVBoxLayout *vlayout = new QVBoxLayout();
5415 vlayout->setContentsMargins( 0, 0, 0, 0 );
5416
5417 mConnectionParamComboBox = new QComboBox();
5418 mSchemaParamComboBox = new QComboBox();
5419 QString initialConnection;
5420 QString initialSchema;
5421 if ( tableParam )
5422 {
5423 initialConnection = tableParam->parentConnectionParameterName();
5424 initialSchema = tableParam->parentSchemaParameterName();
5425 }
5426
5427 if ( auto *lModel = widgetContext.model() )
5428 {
5429 // populate combo box with other model input choices
5430 const QMap<QString, QgsProcessingModelParameter> components = lModel->parameterComponents();
5431 for ( auto it = components.constBegin(); it != components.constEnd(); ++it )
5432 {
5433 if ( definition && it->parameterName() == definition->name() )
5434 continue;
5435
5436 if ( dynamic_cast< const QgsProcessingParameterProviderConnection * >( lModel->parameterDefinition( it->parameterName() ) ) )
5437 {
5438 mConnectionParamComboBox->addItem( it->parameterName(), it->parameterName() );
5439 if ( !initialConnection.isEmpty() && initialConnection == it->parameterName() )
5440 {
5441 mConnectionParamComboBox->setCurrentIndex( mConnectionParamComboBox->count() - 1 );
5442 }
5443 }
5444 else if ( dynamic_cast< const QgsProcessingParameterDatabaseSchema * >( lModel->parameterDefinition( it->parameterName() ) ) )
5445 {
5446 mSchemaParamComboBox->addItem( it->parameterName(), it->parameterName() );
5447 if ( !initialConnection.isEmpty() && initialConnection == it->parameterName() )
5448 {
5449 mSchemaParamComboBox->setCurrentIndex( mSchemaParamComboBox->count() - 1 );
5450 }
5451 }
5452 }
5453 }
5454
5455 if ( mConnectionParamComboBox->count() == 0 && !initialConnection.isEmpty() )
5456 {
5457 // if no candidates found, we just add the existing one as a placeholder
5458 mConnectionParamComboBox->addItem( initialConnection, initialConnection );
5459 mConnectionParamComboBox->setCurrentIndex( mConnectionParamComboBox->count() - 1 );
5460 }
5461
5462 if ( mSchemaParamComboBox->count() == 0 && !initialSchema.isEmpty() )
5463 {
5464 // if no candidates found, we just add the existing one as a placeholder
5465 mSchemaParamComboBox->addItem( initialSchema, initialSchema );
5466 mSchemaParamComboBox->setCurrentIndex( mSchemaParamComboBox->count() - 1 );
5467 }
5468
5469 vlayout->addWidget( new QLabel( tr( "Provider connection parameter" ) ) );
5470 vlayout->addWidget( mConnectionParamComboBox );
5471
5472 vlayout->addWidget( new QLabel( tr( "Database schema parameter" ) ) );
5473 vlayout->addWidget( mSchemaParamComboBox );
5474
5475 vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
5476
5477 mDefaultEdit = new QLineEdit();
5478 vlayout->addWidget( mDefaultEdit );
5479 setLayout( vlayout );
5480
5481 if ( tableParam )
5482 {
5483 mDefaultEdit->setText( tableParam->defaultValueForGui().toString() );
5484 }
5485}
5486
5487QgsProcessingParameterDefinition *QgsProcessingDatabaseTableParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
5488{
5489 QVariant defaultVal;
5490 if ( mDefaultEdit->text().isEmpty() )
5491 defaultVal = QVariant();
5492 else
5493 defaultVal = mDefaultEdit->text();
5494 auto param = std::make_unique< QgsProcessingParameterDatabaseTable>( name, description,
5495 mConnectionParamComboBox->currentData().toString(),
5496 mSchemaParamComboBox->currentData().toString(),
5497 defaultVal );
5498 param->setFlags( flags );
5499 return param.release();
5500}
5501
5502
5503QgsProcessingDatabaseTableWidgetWrapper::QgsProcessingDatabaseTableWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
5504 : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
5505{
5506
5507}
5508
5509QWidget *QgsProcessingDatabaseTableWidgetWrapper::createWidget()
5510{
5511 const QgsProcessingParameterDatabaseTable *tableParam = dynamic_cast< const QgsProcessingParameterDatabaseTable *>( parameterDefinition() );
5512
5513 mTableComboBox = new QgsDatabaseTableComboBox( QString(), QString() );
5515 mTableComboBox->setAllowEmptyTable( true );
5516
5517 if ( type() == QgsProcessingGui::Modeler || tableParam->allowNewTableNames() )
5518 mTableComboBox->comboBox()->setEditable( true );
5519
5520 mTableComboBox->setToolTip( parameterDefinition()->toolTip() );
5521 connect( mTableComboBox->comboBox(), &QComboBox::currentTextChanged, this, [ = ]( const QString & )
5522 {
5523 if ( mBlockSignals )
5524 return;
5525
5526 emit widgetValueHasChanged( this );
5527 } );
5528
5529 return mTableComboBox;
5530}
5531
5532QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingDatabaseTableWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
5533{
5534 return new QgsProcessingDatabaseTableParameterDefinitionWidget( context, widgetContext, definition, algorithm );
5535}
5536
5537void QgsProcessingDatabaseTableWidgetWrapper::setParentConnectionWrapperValue( const QgsAbstractProcessingParameterWidgetWrapper *parentWrapper )
5538{
5539 // evaluate value to connection
5540 QgsProcessingContext *context = nullptr;
5541 std::unique_ptr< QgsProcessingContext > tmpContext;
5542 if ( mProcessingContextGenerator )
5543 context = mProcessingContextGenerator->processingContext();
5544
5545 if ( !context )
5546 {
5547 tmpContext = std::make_unique< QgsProcessingContext >();
5548 context = tmpContext.get();
5549 }
5550
5551 QVariant value = parentWrapper->parameterValue();
5552 mConnection = value.isValid() ? QgsProcessingParameters::parameterAsConnectionName( parentWrapper->parameterDefinition(), value, *context ) : QString();
5553 mProvider = qgis::down_cast< const QgsProcessingParameterProviderConnection * >( parentWrapper->parameterDefinition() )->providerId();
5554 if ( mTableComboBox && !mSchema.isEmpty() )
5555 {
5556 mTableComboBox->setSchema( mSchema );
5557 mTableComboBox->setConnectionName( mConnection, mProvider );
5558
5559 const QgsProcessingParameterDatabaseTable *tableParam = qgis::down_cast< const QgsProcessingParameterDatabaseTable * >( parameterDefinition() );
5560 if ( tableParam->defaultValueForGui().isValid() )
5561 setWidgetValue( parameterDefinition()->defaultValueForGui(), *context );
5562 }
5563}
5564
5565void QgsProcessingDatabaseTableWidgetWrapper::setParentSchemaWrapperValue( const QgsAbstractProcessingParameterWidgetWrapper *parentWrapper )
5566{
5567 // evaluate value to schema
5568 QgsProcessingContext *context = nullptr;
5569 std::unique_ptr< QgsProcessingContext > tmpContext;
5570 if ( mProcessingContextGenerator )
5571 context = mProcessingContextGenerator->processingContext();
5572
5573 if ( !context )
5574 {
5575 tmpContext = std::make_unique< QgsProcessingContext >();
5576 context = tmpContext.get();
5577 }
5578
5579 QVariant value = parentWrapper->parameterValue();
5580 mSchema = value.isValid() ? QgsProcessingParameters::parameterAsSchema( parentWrapper->parameterDefinition(), value, *context ) : QString();
5581
5582 if ( mTableComboBox && !mSchema.isEmpty() && !mConnection.isEmpty() )
5583 {
5584 mTableComboBox->setSchema( mSchema );
5585 mTableComboBox->setConnectionName( mConnection, mProvider );
5586
5587 const QgsProcessingParameterDatabaseTable *tableParam = static_cast< const QgsProcessingParameterDatabaseTable * >( parameterDefinition() );
5588 if ( tableParam->defaultValueForGui().isValid() )
5589 setWidgetValue( parameterDefinition()->defaultValueForGui(), *context );
5590 }
5591
5592}
5593
5594void QgsProcessingDatabaseTableWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
5595{
5596 const QString v = QgsProcessingParameters::parameterAsDatabaseTableName( parameterDefinition(), value, context );
5597
5598 if ( !value.isValid() )
5599 mTableComboBox->comboBox()->setCurrentIndex( -1 );
5600 else
5601 {
5602 if ( mTableComboBox->comboBox()->isEditable() )
5603 {
5604 const QString prev = mTableComboBox->comboBox()->currentText();
5605 mBlockSignals++;
5606 mTableComboBox->setTable( v );
5607 mTableComboBox->comboBox()->setCurrentText( v );
5608
5609 mBlockSignals--;
5610 if ( prev != v )
5611 emit widgetValueHasChanged( this );
5612 }
5613 else
5614 mTableComboBox->setTable( v );
5615 }
5616}
5617
5618QVariant QgsProcessingDatabaseTableWidgetWrapper::widgetValue() const
5619{
5620 if ( mTableComboBox )
5621 if ( mTableComboBox->comboBox()->isEditable() )
5622 return mTableComboBox->comboBox()->currentText().isEmpty() ? QVariant() : QVariant( mTableComboBox->comboBox()->currentText() );
5623 else
5624 return mTableComboBox->currentTable().isEmpty() ? QVariant() : QVariant( mTableComboBox->currentTable() );
5625 else
5626 return QVariant();
5627}
5628
5629QStringList QgsProcessingDatabaseTableWidgetWrapper::compatibleParameterTypes() const
5630{
5631 return QStringList()
5635}
5636
5637QStringList QgsProcessingDatabaseTableWidgetWrapper::compatibleOutputTypes() const
5638{
5639 return QStringList()
5641}
5642
5643QString QgsProcessingDatabaseTableWidgetWrapper::modelerExpressionFormatString() const
5644{
5645 return tr( "database table name as a string value" );
5646}
5647
5648QString QgsProcessingDatabaseTableWidgetWrapper::parameterType() const
5649{
5651}
5652
5653QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingDatabaseTableWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
5654{
5655 return new QgsProcessingDatabaseTableWidgetWrapper( parameter, type );
5656}
5657
5658void QgsProcessingDatabaseTableWidgetWrapper::postInitialize( const QList<QgsAbstractProcessingParameterWidgetWrapper *> &wrappers )
5659{
5661 switch ( type() )
5662 {
5665 {
5666 for ( const QgsAbstractProcessingParameterWidgetWrapper *wrapper : wrappers )
5667 {
5668 if ( wrapper->parameterDefinition()->name() == static_cast< const QgsProcessingParameterDatabaseTable * >( parameterDefinition() )->parentConnectionParameterName() )
5669 {
5670 setParentConnectionWrapperValue( wrapper );
5672 {
5673 setParentConnectionWrapperValue( wrapper );
5674 } );
5675 }
5676 else if ( wrapper->parameterDefinition()->name() == static_cast< const QgsProcessingParameterDatabaseTable * >( parameterDefinition() )->parentSchemaParameterName() )
5677 {
5678 setParentSchemaWrapperValue( wrapper );
5680 {
5681 setParentSchemaWrapperValue( wrapper );
5682 } );
5683 }
5684 }
5685 break;
5686 }
5687
5689 break;
5690 }
5691}
5692
5693
5694//
5695// QgsProcessingExtentWidgetWrapper
5696//
5697
5698QgsProcessingExtentParameterDefinitionWidget::QgsProcessingExtentParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
5699 : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
5700{
5701 QVBoxLayout *vlayout = new QVBoxLayout();
5702 vlayout->setContentsMargins( 0, 0, 0, 0 );
5703
5704 vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
5705
5706 mDefaultWidget = new QgsExtentWidget();
5707 mDefaultWidget->setNullValueAllowed( true, tr( "Not set" ) );
5708 if ( const QgsProcessingParameterExtent *extentParam = dynamic_cast<const QgsProcessingParameterExtent *>( definition ) )
5709 {
5710 if ( extentParam->defaultValueForGui().isValid() )
5711 {
5712 QgsRectangle rect = QgsProcessingParameters::parameterAsExtent( extentParam, extentParam->defaultValueForGui(), context );
5713 QgsCoordinateReferenceSystem crs = QgsProcessingParameters::parameterAsExtentCrs( extentParam, extentParam->defaultValueForGui(), context );
5714 mDefaultWidget->setCurrentExtent( rect, crs );
5715 mDefaultWidget->setOutputExtentFromCurrent();
5716 }
5717 else
5718 {
5719 mDefaultWidget->clear();
5720 }
5721 }
5722
5723 vlayout->addWidget( mDefaultWidget );
5724 setLayout( vlayout );
5725}
5726
5727QgsProcessingParameterDefinition *QgsProcessingExtentParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
5728{
5729 const QString defaultVal = mDefaultWidget->isValid() ? QStringLiteral( "%1,%2,%3,%4%5" ).arg(
5730 QString::number( mDefaultWidget->outputExtent().xMinimum(), 'f', 9 ),
5731 QString::number( mDefaultWidget->outputExtent().xMaximum(), 'f', 9 ),
5732 QString::number( mDefaultWidget->outputExtent().yMinimum(), 'f', 9 ),
5733 QString::number( mDefaultWidget->outputExtent().yMaximum(), 'f', 9 ),
5734 mDefaultWidget->outputCrs().isValid() ? QStringLiteral( " [%1]" ).arg( mDefaultWidget->outputCrs().authid() ) : QString()
5735 ) : QString();
5736 auto param = std::make_unique< QgsProcessingParameterExtent >( name, description, !defaultVal.isEmpty() ? QVariant( defaultVal ) : QVariant() );
5737 param->setFlags( flags );
5738 return param.release();
5739}
5740
5741
5742
5743QgsProcessingExtentWidgetWrapper::QgsProcessingExtentWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
5744 : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
5745{
5746
5747}
5748
5749QWidget *QgsProcessingExtentWidgetWrapper::createWidget()
5750{
5751 const QgsProcessingParameterExtent *extentParam = dynamic_cast< const QgsProcessingParameterExtent *>( parameterDefinition() );
5752 switch ( type() )
5753 {
5757 {
5758 mExtentWidget = new QgsExtentWidget( nullptr );
5759 if ( widgetContext().mapCanvas() )
5760 mExtentWidget->setMapCanvas( widgetContext().mapCanvas() );
5761
5763 mExtentWidget->setNullValueAllowed( true, tr( "Not set" ) );
5764
5765 mExtentWidget->setToolTip( parameterDefinition()->toolTip() );
5766
5767 connect( mExtentWidget, &QgsExtentWidget::extentChanged, this, [ = ]
5768 {
5769 emit widgetValueHasChanged( this );
5770 } );
5771
5772 if ( mDialog && type() != QgsProcessingGui::Modeler )
5773 setDialog( mDialog ); // setup connections to panel - dialog was previously set before the widget was created
5774
5775 return mExtentWidget;
5776 }
5777 }
5778 return nullptr;
5779}
5780
5781void QgsProcessingExtentWidgetWrapper::setWidgetContext( const QgsProcessingParameterWidgetContext &context )
5782{
5784 if ( mExtentWidget && context.mapCanvas() && type() != QgsProcessingGui::Modeler )
5785 mExtentWidget->setMapCanvas( context.mapCanvas() );
5786}
5787
5788void QgsProcessingExtentWidgetWrapper::setDialog( QDialog *dialog )
5789{
5790 mDialog = dialog;
5791 if ( mExtentWidget && mDialog && type() != QgsProcessingGui::Modeler )
5792 {
5793 connect( mExtentWidget, &QgsExtentWidget::toggleDialogVisibility, mDialog, [ = ]( bool visible )
5794 {
5795 if ( !visible )
5796 mDialog->showMinimized();
5797 else
5798 {
5799 mDialog->showNormal();
5800 mDialog->raise();
5801 mDialog->activateWindow();
5802 }
5803 } );
5804 }
5806}
5807
5808void QgsProcessingExtentWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
5809{
5810 if ( mExtentWidget )
5811 {
5812 if ( !value.isValid() || ( value.type() == QVariant::String && value.toString().isEmpty() ) )
5813 mExtentWidget->clear();
5814 else
5815 {
5816 QgsRectangle r = QgsProcessingParameters::parameterAsExtent( parameterDefinition(), value, context );
5817 QgsCoordinateReferenceSystem crs = QgsProcessingParameters::parameterAsPointCrs( parameterDefinition(), value, context );
5818 mExtentWidget->setCurrentExtent( r, crs );
5819 mExtentWidget->setOutputExtentFromUser( r, crs );
5820 }
5821 }
5822}
5823
5824QVariant QgsProcessingExtentWidgetWrapper::widgetValue() const
5825{
5826 if ( mExtentWidget )
5827 {
5828 const QString val = mExtentWidget->isValid() ? QStringLiteral( "%1,%2,%3,%4%5" ).arg(
5829 QString::number( mExtentWidget->outputExtent().xMinimum(), 'f', 9 ),
5830 QString::number( mExtentWidget->outputExtent().xMaximum(), 'f', 9 ),
5831 QString::number( mExtentWidget->outputExtent().yMinimum(), 'f', 9 ),
5832 QString::number( mExtentWidget->outputExtent().yMaximum(), 'f', 9 ),
5833 mExtentWidget->outputCrs().isValid() ? QStringLiteral( " [%1]" ).arg( mExtentWidget->outputCrs().authid() ) : QString()
5834 ) : QString();
5835
5836 return val.isEmpty() ? QVariant() : QVariant( val );
5837 }
5838 else
5839 return QVariant();
5840}
5841
5842QStringList QgsProcessingExtentWidgetWrapper::compatibleParameterTypes() const
5843{
5844 return QStringList()
5854}
5855
5856QStringList QgsProcessingExtentWidgetWrapper::compatibleOutputTypes() const
5857{
5858 return QStringList()
5863}
5864
5865QString QgsProcessingExtentWidgetWrapper::modelerExpressionFormatString() const
5866{
5867 return tr( "string of the format 'x min,x max,y min,y max' or a geometry value (bounding box is used)" );
5868}
5869
5870QString QgsProcessingExtentWidgetWrapper::parameterType() const
5871{
5873}
5874
5875QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingExtentWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
5876{
5877 return new QgsProcessingExtentWidgetWrapper( parameter, type );
5878}
5879
5880QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingExtentWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
5881{
5882 return new QgsProcessingExtentParameterDefinitionWidget( context, widgetContext, definition, algorithm );
5883}
5884
5885
5886
5887//
5888// QgsProcessingMapLayerWidgetWrapper
5889//
5890
5891QgsProcessingMapLayerParameterDefinitionWidget::QgsProcessingMapLayerParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
5892 : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
5893{
5894 QVBoxLayout *vlayout = new QVBoxLayout();
5895 vlayout->setContentsMargins( 0, 0, 0, 0 );
5896
5897 vlayout->addWidget( new QLabel( tr( "Layer type" ) ) );
5898 mLayerTypeComboBox = new QgsCheckableComboBox();
5899 mLayerTypeComboBox->addItem( tr( "Any Map Layer" ), QgsProcessing::TypeMapLayer );
5900 mLayerTypeComboBox->addItem( tr( "Vector (Point)" ), QgsProcessing::TypeVectorPoint );
5901 mLayerTypeComboBox->addItem( tr( "Vector (Line)" ), QgsProcessing::TypeVectorLine );
5902 mLayerTypeComboBox->addItem( tr( "Vector (Polygon)" ), QgsProcessing::TypeVectorPolygon );
5903 mLayerTypeComboBox->addItem( tr( "Vector (Any Geometry Type)" ), QgsProcessing::TypeVectorAnyGeometry );
5904 mLayerTypeComboBox->addItem( tr( "Raster" ), QgsProcessing::TypeRaster );
5905 mLayerTypeComboBox->addItem( tr( "Mesh" ), QgsProcessing::TypeMesh );
5906 mLayerTypeComboBox->addItem( tr( "Plugin" ), QgsProcessing::TypePlugin );
5907 mLayerTypeComboBox->addItem( tr( "Point Cloud" ), QgsProcessing::TypePointCloud );
5908 mLayerTypeComboBox->addItem( tr( "Annotation" ), QgsProcessing::TypeAnnotation );
5909
5910 if ( const QgsProcessingParameterMapLayer *layerParam = dynamic_cast<const QgsProcessingParameterMapLayer *>( definition ) )
5911 {
5912 for ( int i : layerParam->dataTypes() )
5913 {
5914 mLayerTypeComboBox->setItemCheckState( mLayerTypeComboBox->findData( i ), Qt::Checked );
5915 }
5916 }
5917
5918 vlayout->addWidget( mLayerTypeComboBox );
5919
5920 setLayout( vlayout );
5921}
5922
5923QgsProcessingParameterDefinition *QgsProcessingMapLayerParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
5924{
5925 QList< int > dataTypes;
5926 for ( const QVariant &v : mLayerTypeComboBox->checkedItemsData() )
5927 dataTypes << v.toInt();
5928
5929 auto param = std::make_unique< QgsProcessingParameterMapLayer >( name, description );
5930 param->setDataTypes( dataTypes );
5931 param->setFlags( flags );
5932 return param.release();
5933}
5934
5935QgsProcessingMapLayerWidgetWrapper::QgsProcessingMapLayerWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
5936 : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
5937{
5938
5939}
5940
5941QWidget *QgsProcessingMapLayerWidgetWrapper::createWidget()
5942{
5943 mComboBox = new QgsProcessingMapLayerComboBox( parameterDefinition(), type() );
5944
5945 switch ( type() )
5946 {
5949 break;
5951 mComboBox->setEditable( true );
5952 break;
5953 }
5954
5955 mComboBox->setToolTip( parameterDefinition()->toolTip() );
5956
5957 connect( mComboBox, &QgsProcessingMapLayerComboBox::valueChanged, this, [ = ]()
5958 {
5959 if ( mBlockSignals )
5960 return;
5961
5962 emit widgetValueHasChanged( this );
5963 } );
5964
5965 setWidgetContext( widgetContext() );
5966 return mComboBox;
5967}
5968
5969void QgsProcessingMapLayerWidgetWrapper::setWidgetContext( const QgsProcessingParameterWidgetContext &context )
5970{
5972 if ( mComboBox )
5973 {
5974 mComboBox->setWidgetContext( context );
5975
5976 if ( !( parameterDefinition()->flags() & QgsProcessingParameterDefinition::FlagOptional ) )
5977 {
5978 // non optional parameter -- if no default value set, default to active layer
5979 if ( !parameterDefinition()->defaultValueForGui().isValid() )
5980 mComboBox->setLayer( context.activeLayer() );
5981 }
5982 }
5983}
5984
5985void QgsProcessingMapLayerWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
5986{
5987 if ( mComboBox )
5988 mComboBox->setValue( value, context );
5989}
5990
5991QVariant QgsProcessingMapLayerWidgetWrapper::widgetValue() const
5992{
5993 return mComboBox ? mComboBox->value() : QVariant();
5994}
5995
5996QStringList QgsProcessingMapLayerWidgetWrapper::compatibleParameterTypes() const
5997{
5998 return QStringList()
6007}
6008
6009QStringList QgsProcessingMapLayerWidgetWrapper::compatibleOutputTypes() const
6010{
6011 return QStringList()
6017}
6018
6019QString QgsProcessingMapLayerWidgetWrapper::modelerExpressionFormatString() const
6020{
6021 return tr( "path to a map layer" );
6022}
6023
6024QgsProcessingModelChildParameterSource::Source QgsProcessingMapLayerWidgetWrapper::defaultModelSource( const QgsProcessingParameterDefinition * ) const
6025{
6026 return QgsProcessingModelChildParameterSource::ModelParameter;
6027}
6028
6029QString QgsProcessingMapLayerWidgetWrapper::parameterType() const
6030{
6032}
6033
6034QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingMapLayerWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
6035{
6036 return new QgsProcessingMapLayerWidgetWrapper( parameter, type );
6037}
6038
6039QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingMapLayerWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
6040{
6041 return new QgsProcessingMapLayerParameterDefinitionWidget( context, widgetContext, definition, algorithm );
6042}
6043
6044
6045//
6046// QgsProcessingRasterLayerWidgetWrapper
6047//
6048
6049QgsProcessingRasterLayerWidgetWrapper::QgsProcessingRasterLayerWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
6050 : QgsProcessingMapLayerWidgetWrapper( parameter, type, parent )
6051{
6052
6053}
6054
6055QStringList QgsProcessingRasterLayerWidgetWrapper::compatibleParameterTypes() const
6056{
6057 return QStringList()
6062}
6063
6064QStringList QgsProcessingRasterLayerWidgetWrapper::compatibleOutputTypes() const
6065{
6066 return QStringList()
6072}
6073
6074QString QgsProcessingRasterLayerWidgetWrapper::modelerExpressionFormatString() const
6075{
6076 return tr( "path to a raster layer" );
6077}
6078
6079QString QgsProcessingRasterLayerWidgetWrapper::parameterType() const
6080{
6082}
6083
6084QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingRasterLayerWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
6085{
6086 return new QgsProcessingRasterLayerWidgetWrapper( parameter, type );
6087}
6088
6089QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingRasterLayerWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
6090{
6091 Q_UNUSED( context );
6092 Q_UNUSED( widgetContext );
6093 Q_UNUSED( definition );
6094 Q_UNUSED( algorithm );
6095
6096 return nullptr;
6097}
6098
6099
6100//
6101// QgsProcessingVectorLayerWidgetWrapper
6102//
6103
6104QgsProcessingVectorLayerParameterDefinitionWidget::QgsProcessingVectorLayerParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
6105 : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
6106{
6107 QVBoxLayout *vlayout = new QVBoxLayout();
6108 vlayout->setContentsMargins( 0, 0, 0, 0 );
6109
6110 vlayout->addWidget( new QLabel( tr( "Geometry type" ) ) );
6111 mGeometryTypeComboBox = new QgsCheckableComboBox();
6112 mGeometryTypeComboBox->addItem( tr( "Geometry Not Required" ), QgsProcessing::TypeVector );
6113 mGeometryTypeComboBox->addItem( tr( "Point" ), QgsProcessing::TypeVectorPoint );
6114 mGeometryTypeComboBox->addItem( tr( "Line" ), QgsProcessing::TypeVectorLine );
6115 mGeometryTypeComboBox->addItem( tr( "Polygon" ), QgsProcessing::TypeVectorPolygon );
6116 mGeometryTypeComboBox->addItem( tr( "Any Geometry Type" ), QgsProcessing::TypeVectorAnyGeometry );
6117
6118 if ( const QgsProcessingParameterVectorLayer *vectorParam = dynamic_cast<const QgsProcessingParameterVectorLayer *>( definition ) )
6119 {
6120 for ( int i : vectorParam->dataTypes() )
6121 {
6122 mGeometryTypeComboBox->setItemCheckState( mGeometryTypeComboBox->findData( i ), Qt::Checked );
6123 }
6124 }
6125
6126 vlayout->addWidget( mGeometryTypeComboBox );
6127
6128 setLayout( vlayout );
6129}
6130
6131QgsProcessingParameterDefinition *QgsProcessingVectorLayerParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
6132{
6133 QList< int > dataTypes;
6134 for ( const QVariant &v : mGeometryTypeComboBox->checkedItemsData() )
6135 dataTypes << v.toInt();
6136
6137 auto param = std::make_unique< QgsProcessingParameterVectorLayer >( name, description, dataTypes );
6138 param->setFlags( flags );
6139 return param.release();
6140}
6141
6142
6143QgsProcessingVectorLayerWidgetWrapper::QgsProcessingVectorLayerWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
6144 : QgsProcessingMapLayerWidgetWrapper( parameter, type, parent )
6145{
6146
6147}
6148
6149QStringList QgsProcessingVectorLayerWidgetWrapper::compatibleParameterTypes() const
6150{
6151 return QStringList()
6156}
6157
6158QStringList QgsProcessingVectorLayerWidgetWrapper::compatibleOutputTypes() const
6159{
6160 return QStringList()
6166}
6167
6168QString QgsProcessingVectorLayerWidgetWrapper::modelerExpressionFormatString() const
6169{
6170 return tr( "path to a vector layer" );
6171}
6172
6173QList<int> QgsProcessingVectorLayerWidgetWrapper::compatibleDataTypes( const QgsProcessingParameterDefinition *parameter ) const
6174{
6175 if ( const QgsProcessingParameterVectorLayer *param = dynamic_cast< const QgsProcessingParameterVectorLayer *>( parameter ) )
6176 return param->dataTypes();
6177 else
6178 return QList< int >();
6179}
6180
6181QString QgsProcessingVectorLayerWidgetWrapper::parameterType() const
6182{
6184}
6185
6186QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingVectorLayerWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
6187{
6188 return new QgsProcessingVectorLayerWidgetWrapper( parameter, type );
6189}
6190
6191QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingVectorLayerWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
6192{
6193 return new QgsProcessingVectorLayerParameterDefinitionWidget( context, widgetContext, definition, algorithm );
6194}
6195
6196
6197
6198//
6199// QgsProcessingFeatureSourceLayerWidgetWrapper
6200//
6201
6202QgsProcessingFeatureSourceParameterDefinitionWidget::QgsProcessingFeatureSourceParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
6203 : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
6204{
6205 QVBoxLayout *vlayout = new QVBoxLayout();
6206 vlayout->setContentsMargins( 0, 0, 0, 0 );
6207
6208 vlayout->addWidget( new QLabel( tr( "Geometry type" ) ) );
6209 mGeometryTypeComboBox = new QgsCheckableComboBox();
6210 mGeometryTypeComboBox->addItem( tr( "Geometry Not Required" ), QgsProcessing::TypeVector );
6211 mGeometryTypeComboBox->addItem( tr( "Point" ), QgsProcessing::TypeVectorPoint );
6212 mGeometryTypeComboBox->addItem( tr( "Line" ), QgsProcessing::TypeVectorLine );
6213 mGeometryTypeComboBox->addItem( tr( "Polygon" ), QgsProcessing::TypeVectorPolygon );
6214 mGeometryTypeComboBox->addItem( tr( "Any Geometry Type" ), QgsProcessing::TypeVectorAnyGeometry );
6215
6216 if ( const QgsProcessingParameterFeatureSource *sourceParam = dynamic_cast<const QgsProcessingParameterFeatureSource *>( definition ) )
6217 {
6218 for ( int i : sourceParam->dataTypes() )
6219 {
6220 mGeometryTypeComboBox->setItemCheckState( mGeometryTypeComboBox->findData( i ), Qt::Checked );
6221 }
6222 }
6223 else
6224 {
6225 mGeometryTypeComboBox->setItemCheckState( mGeometryTypeComboBox->findData( QgsProcessing::TypeVectorAnyGeometry ), Qt::Checked );
6226 }
6227
6228 vlayout->addWidget( mGeometryTypeComboBox );
6229
6230 setLayout( vlayout );
6231}
6232
6233QgsProcessingParameterDefinition *QgsProcessingFeatureSourceParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
6234{
6235 QList< int > dataTypes;
6236 for ( const QVariant &v : mGeometryTypeComboBox->checkedItemsData() )
6237 dataTypes << v.toInt();
6238
6239 auto param = std::make_unique< QgsProcessingParameterFeatureSource >( name, description, dataTypes );
6240 param->setFlags( flags );
6241 return param.release();
6242}
6243
6244QgsProcessingFeatureSourceWidgetWrapper::QgsProcessingFeatureSourceWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
6245 : QgsProcessingMapLayerWidgetWrapper( parameter, type, parent )
6246{
6247
6248}
6249
6250QStringList QgsProcessingFeatureSourceWidgetWrapper::compatibleParameterTypes() const
6251{
6252 return QStringList()
6258}
6259
6260QStringList QgsProcessingFeatureSourceWidgetWrapper::compatibleOutputTypes() const
6261{
6262 return QStringList()
6268}
6269
6270QString QgsProcessingFeatureSourceWidgetWrapper::modelerExpressionFormatString() const
6271{
6272 return tr( "path to a vector layer" );
6273}
6274
6275QList<int> QgsProcessingFeatureSourceWidgetWrapper::compatibleDataTypes( const QgsProcessingParameterDefinition *parameter ) const
6276{
6277 if ( const QgsProcessingParameterFeatureSource *param = dynamic_cast< const QgsProcessingParameterFeatureSource *>( parameter ) )
6278 return param->dataTypes();
6279 else
6280 return QList< int >();
6281}
6282
6283QString QgsProcessingFeatureSourceWidgetWrapper::parameterType() const
6284{
6286}
6287
6288QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingFeatureSourceWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
6289{
6290 return new QgsProcessingFeatureSourceWidgetWrapper( parameter, type );
6291}
6292
6293QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingFeatureSourceWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
6294{
6295 return new QgsProcessingFeatureSourceParameterDefinitionWidget( context, widgetContext, definition, algorithm );
6296}
6297
6298//
6299// QgsProcessingMeshLayerWidgetWrapper
6300//
6301
6302QgsProcessingMeshLayerWidgetWrapper::QgsProcessingMeshLayerWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
6303 : QgsProcessingMapLayerWidgetWrapper( parameter, type, parent )
6304{
6305
6306}
6307
6308QStringList QgsProcessingMeshLayerWidgetWrapper::compatibleParameterTypes() const
6309{
6310 return QStringList()
6315}
6316
6317QStringList QgsProcessingMeshLayerWidgetWrapper::compatibleOutputTypes() const
6318{
6319 return QStringList()
6321 // TODO << QgsProcessingOutputMeshLayer::typeName()
6325}
6326
6327QString QgsProcessingMeshLayerWidgetWrapper::modelerExpressionFormatString() const
6328{
6329 return tr( "path to a mesh layer" );
6330}
6331
6332QString QgsProcessingMeshLayerWidgetWrapper::parameterType() const
6333{
6335}
6336
6337QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingMeshLayerWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
6338{
6339 return new QgsProcessingMeshLayerWidgetWrapper( parameter, type );
6340}
6341
6342QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingMeshLayerWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
6343{
6344 Q_UNUSED( context );
6345 Q_UNUSED( widgetContext );
6346 Q_UNUSED( definition );
6347 Q_UNUSED( algorithm );
6348
6349 return nullptr;
6350}
6351
6352
6353
6354//
6355// QgsProcessingRasterBandPanelWidget
6356//
6357
6358QgsProcessingRasterBandPanelWidget::QgsProcessingRasterBandPanelWidget( QWidget *parent, const QgsProcessingParameterBand *param )
6359 : QWidget( parent )
6360 , mParam( param )
6361{
6362 QHBoxLayout *hl = new QHBoxLayout();
6363 hl->setContentsMargins( 0, 0, 0, 0 );
6364
6365 mLineEdit = new QLineEdit();
6366 mLineEdit->setEnabled( false );
6367 hl->addWidget( mLineEdit, 1 );
6368
6369 mToolButton = new QToolButton();
6370 mToolButton->setText( QString( QChar( 0x2026 ) ) );
6371 hl->addWidget( mToolButton );
6372
6373 setLayout( hl );
6374
6375 if ( mParam )
6376 {
6377 mLineEdit->setText( tr( "%n band(s) selected", nullptr, 0 ) );
6378 }
6379
6380 connect( mToolButton, &QToolButton::clicked, this, &QgsProcessingRasterBandPanelWidget::showDialog );
6381}
6382
6383void QgsProcessingRasterBandPanelWidget::setBands( const QList< int > &bands )
6384{
6385 mBands = bands;
6386}
6387
6388void QgsProcessingRasterBandPanelWidget::setBandNames( const QHash<int, QString> &names )
6389{
6390 mBandNames = names;
6391}
6392
6393void QgsProcessingRasterBandPanelWidget::setValue( const QVariant &value )
6394{
6395 if ( value.isValid() )
6396 mValue = value.type() == QVariant::List ? value.toList() : QVariantList() << value;
6397 else
6398 mValue.clear();
6399
6400 updateSummaryText();
6401 emit changed();
6402}
6403
6404void QgsProcessingRasterBandPanelWidget::showDialog()
6405{
6406 QVariantList availableOptions;
6407 availableOptions.reserve( mBands.size() );
6408 for ( int band : std::as_const( mBands ) )
6409 {
6410 availableOptions << band;
6411 }
6412
6414 if ( panel && panel->dockMode() )
6415 {
6416 QgsProcessingMultipleSelectionPanelWidget *widget = new QgsProcessingMultipleSelectionPanelWidget( availableOptions, mValue );
6417 widget->setPanelTitle( mParam->description() );
6418
6419 widget->setValueFormatter( [this]( const QVariant & v ) -> QString
6420 {
6421 int band = v.toInt();
6422 return mBandNames.contains( band ) ? mBandNames.value( band ) : v.toString();
6423 } );
6424
6425 connect( widget, &QgsProcessingMultipleSelectionPanelWidget::selectionChanged, this, [ = ]()
6426 {
6427 setValue( widget->selectedOptions() );
6428 } );
6429 connect( widget, &QgsProcessingMultipleSelectionPanelWidget::acceptClicked, widget, &QgsPanelWidget::acceptPanel );
6430 panel->openPanel( widget );
6431 }
6432 else
6433 {
6434 QgsProcessingMultipleSelectionDialog dlg( availableOptions, mValue, this, Qt::WindowFlags() );
6435
6436 dlg.setValueFormatter( [this]( const QVariant & v ) -> QString
6437 {
6438 int band = v.toInt();
6439 return mBandNames.contains( band ) ? mBandNames.value( band ) : v.toString();
6440 } );
6441 if ( dlg.exec() )
6442 {
6443 setValue( dlg.selectedOptions() );
6444 }
6445 }
6446}
6447
6448void QgsProcessingRasterBandPanelWidget::updateSummaryText()
6449{
6450 if ( mParam )
6451 mLineEdit->setText( tr( "%n band(s) selected", nullptr, mValue.count() ) );
6452}
6453
6454
6455
6456//
6457// QgsProcessingBandWidgetWrapper
6458//
6459
6460QgsProcessingBandParameterDefinitionWidget::QgsProcessingBandParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
6461 : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
6462{
6463 QVBoxLayout *vlayout = new QVBoxLayout();
6464 vlayout->setContentsMargins( 0, 0, 0, 0 );
6465
6466 vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
6467
6468 mDefaultLineEdit = new QLineEdit();
6469 mDefaultLineEdit->setToolTip( tr( "Band number (separate bands with ; for multiple band parameters)" ) );
6470 if ( const QgsProcessingParameterBand *bandParam = dynamic_cast<const QgsProcessingParameterBand *>( definition ) )
6471 {
6472 const QList< int > bands = QgsProcessingParameters::parameterAsInts( bandParam, bandParam->defaultValueForGui(), context );
6473 QStringList defVal;
6474 for ( int b : bands )
6475 {
6476 defVal << QString::number( b );
6477 }
6478
6479 mDefaultLineEdit->setText( defVal.join( ';' ) );
6480 }
6481 vlayout->addWidget( mDefaultLineEdit );
6482
6483 vlayout->addWidget( new QLabel( tr( "Parent layer" ) ) );
6484 mParentLayerComboBox = new QComboBox();
6485
6486 QString initialParent;
6487 if ( const QgsProcessingParameterBand *bandParam = dynamic_cast<const QgsProcessingParameterBand *>( definition ) )
6488 initialParent = bandParam->parentLayerParameterName();
6489
6490 if ( auto *lModel = widgetContext.model() )
6491 {
6492 // populate combo box with other model input choices
6493 const QMap<QString, QgsProcessingModelParameter> components = lModel->parameterComponents();
6494 for ( auto it = components.constBegin(); it != components.constEnd(); ++it )
6495 {
6496 if ( const QgsProcessingParameterRasterLayer *definition = dynamic_cast< const QgsProcessingParameterRasterLayer * >( lModel->parameterDefinition( it.value().parameterName() ) ) )
6497 {
6498 mParentLayerComboBox-> addItem( definition->description(), definition->name() );
6499 if ( !initialParent.isEmpty() && initialParent == definition->name() )
6500 {
6501 mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
6502 }
6503 }
6504 }
6505 }
6506
6507 if ( mParentLayerComboBox->count() == 0 && !initialParent.isEmpty() )
6508 {
6509 // if no parent candidates found, we just add the existing one as a placeholder
6510 mParentLayerComboBox->addItem( initialParent, initialParent );
6511 mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
6512 }
6513
6514 vlayout->addWidget( mParentLayerComboBox );
6515
6516 mAllowMultipleCheckBox = new QCheckBox( tr( "Allow multiple" ) );
6517 if ( const QgsProcessingParameterBand *bandParam = dynamic_cast<const QgsProcessingParameterBand *>( definition ) )
6518 mAllowMultipleCheckBox->setChecked( bandParam->allowMultiple() );
6519
6520 vlayout->addWidget( mAllowMultipleCheckBox );
6521 setLayout( vlayout );
6522}
6523
6524QgsProcessingParameterDefinition *QgsProcessingBandParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
6525{
6526 auto param = std::make_unique< QgsProcessingParameterBand >( name, description, mDefaultLineEdit->text().split( ';' ), mParentLayerComboBox->currentData().toString(), false, mAllowMultipleCheckBox->isChecked() );
6527 param->setFlags( flags );
6528 return param.release();
6529}
6530
6531QgsProcessingBandWidgetWrapper::QgsProcessingBandWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
6532 : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
6533{
6534
6535}
6536
6537QWidget *QgsProcessingBandWidgetWrapper::createWidget()
6538{
6539 const QgsProcessingParameterBand *bandParam = dynamic_cast< const QgsProcessingParameterBand *>( parameterDefinition() );
6540 switch ( type() )
6541 {
6544 {
6545 if ( bandParam->allowMultiple() )
6546 {
6547 mPanel = new QgsProcessingRasterBandPanelWidget( nullptr, bandParam );
6548 mPanel->setToolTip( parameterDefinition()->toolTip() );
6549 connect( mPanel, &QgsProcessingRasterBandPanelWidget::changed, this, [ = ]
6550 {
6551 emit widgetValueHasChanged( this );
6552 } );
6553 return mPanel;
6554 }
6555 else
6556 {
6557 mComboBox = new QgsRasterBandComboBox();
6558 mComboBox->setShowNotSetOption( bandParam->flags() & QgsProcessingParameterDefinition::FlagOptional );
6559
6560 mComboBox->setToolTip( parameterDefinition()->toolTip() );
6561 connect( mComboBox, &QgsRasterBandComboBox::bandChanged, this, [ = ]( int )
6562 {
6563 emit widgetValueHasChanged( this );
6564 } );
6565 return mComboBox;
6566 }
6567 }
6568
6570 {
6571 mLineEdit = new QLineEdit();
6572 mLineEdit->setToolTip( QObject::tr( "Band number (separate bands with ; for multiple band parameters)" ) );
6573 connect( mLineEdit, &QLineEdit::textChanged, this, [ = ]
6574 {
6575 emit widgetValueHasChanged( this );
6576 } );
6577 return mLineEdit;
6578 }
6579
6580 }
6581 return nullptr;
6582}
6583
6584void QgsProcessingBandWidgetWrapper::postInitialize( const QList<QgsAbstractProcessingParameterWidgetWrapper *> &wrappers )
6585{
6587 switch ( type() )
6588 {
6591 {
6592 for ( const QgsAbstractProcessingParameterWidgetWrapper *wrapper : wrappers )
6593 {
6594 if ( wrapper->parameterDefinition()->name() == static_cast< const QgsProcessingParameterBand * >( parameterDefinition() )->parentLayerParameterName() )
6595 {
6596 setParentLayerWrapperValue( wrapper );
6598 {
6599 setParentLayerWrapperValue( wrapper );
6600 } );
6601 break;
6602 }
6603 }
6604 break;
6605 }
6606
6608 break;
6609 }
6610}
6611
6612void QgsProcessingBandWidgetWrapper::setParentLayerWrapperValue( const QgsAbstractProcessingParameterWidgetWrapper *parentWrapper )
6613{
6614 // evaluate value to layer
6615 QgsProcessingContext *context = nullptr;
6616 std::unique_ptr< QgsProcessingContext > tmpContext;
6617 if ( mProcessingContextGenerator )
6618 context = mProcessingContextGenerator->processingContext();
6619
6620 if ( !context )
6621 {
6622 tmpContext = std::make_unique< QgsProcessingContext >();
6623 context = tmpContext.get();
6624 }
6625
6626 QVariant value = parentWrapper->parameterValue();
6627
6628 QgsRasterLayer *layer = QgsProcessingParameters::parameterAsRasterLayer( parentWrapper->parameterDefinition(), value, *context );
6629 if ( layer && layer->isValid() )
6630 {
6631 // need to grab ownership of layer if required - otherwise layer may be deleted when context
6632 // goes out of scope
6633 std::unique_ptr< QgsMapLayer > ownedLayer( context->takeResultLayer( layer->id() ) );
6634 if ( ownedLayer && ownedLayer->type() == Qgis::LayerType::Raster )
6635 {
6636 mParentLayer.reset( qobject_cast< QgsRasterLayer * >( ownedLayer.release() ) );
6637 layer = mParentLayer.get();
6638 }
6639 else
6640 {
6641 // don't need ownership of this layer - it wasn't owned by context (so e.g. is owned by the project)
6642 }
6643
6644 if ( mComboBox )
6645 mComboBox->setLayer( layer );
6646 else if ( mPanel )
6647 {
6648 QgsRasterDataProvider *provider = layer->dataProvider();
6649 if ( provider && layer->isValid() )
6650 {
6651 //fill available bands
6652 int nBands = provider->bandCount();
6653 QList< int > bands;
6654 QHash< int, QString > bandNames;
6655 for ( int i = 1; i <= nBands; ++i )
6656 {
6657 bandNames.insert( i, QgsRasterBandComboBox::displayBandName( provider, i ) );
6658 bands << i;
6659 }
6660 mPanel->setBands( bands );
6661 mPanel->setBandNames( bandNames );
6662 }
6663 }
6664 }
6665 else
6666 {
6667 if ( mComboBox )
6668 mComboBox->setLayer( nullptr );
6669 else if ( mPanel )
6670 mPanel->setBands( QList< int >() );
6671
6672 if ( value.isValid() && widgetContext().messageBar() )
6673 {
6674 widgetContext().messageBar()->clearWidgets();
6675 widgetContext().messageBar()->pushMessage( QString(), QObject::tr( "Could not load selected layer/table. Dependent bands could not be populated" ),
6676 Qgis::MessageLevel::Info );
6677 }
6678 }
6679
6680 if ( parameterDefinition()->defaultValueForGui().isValid() )
6681 setWidgetValue( parameterDefinition()->defaultValueForGui(), *context );
6682}
6683
6684void QgsProcessingBandWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
6685{
6686 if ( mComboBox )
6687 {
6688 if ( !value.isValid() )
6689 mComboBox->setBand( -1 );
6690 else
6691 {
6692 const int v = QgsProcessingParameters::parameterAsInt( parameterDefinition(), value, context );
6693 mComboBox->setBand( v );
6694 }
6695 }
6696 else if ( mPanel )
6697 {
6698 QVariantList opts;
6699 if ( value.isValid() )
6700 {
6701 const QList< int > v = QgsProcessingParameters::parameterAsInts( parameterDefinition(), value, context );
6702 opts.reserve( v.size() );
6703 for ( int i : v )
6704 opts << i;
6705 }
6706 if ( mPanel )
6707 mPanel->setValue( value.isValid() ? opts : QVariant() );
6708 }
6709 else if ( mLineEdit )
6710 {
6711 const QgsProcessingParameterBand *bandParam = static_cast< const QgsProcessingParameterBand * >( parameterDefinition() );
6712 if ( bandParam->allowMultiple() )
6713 {
6714 const QList< int > v = QgsProcessingParameters::parameterAsInts( parameterDefinition(), value, context );
6715 QStringList opts;
6716 opts.reserve( v.size() );
6717 for ( int i : v )
6718 opts << QString::number( i );
6719 mLineEdit->setText( value.isValid() && !opts.empty() ? opts.join( ';' ) : QString() );
6720 }
6721 else
6722 {
6723 if ( value.isValid() )
6724 mLineEdit->setText( QString::number( QgsProcessingParameters::parameterAsInt( parameterDefinition(), value, context ) ) );
6725 else
6726 mLineEdit->clear();
6727 }
6728 }
6729}
6730
6731QVariant QgsProcessingBandWidgetWrapper::widgetValue() const
6732{
6733 if ( mComboBox )
6734 return mComboBox->currentBand() == -1 ? QVariant() : mComboBox->currentBand();
6735 else if ( mPanel )
6736 return !mPanel->value().toList().isEmpty() ? mPanel->value() : QVariant();
6737 else if ( mLineEdit )
6738 {
6739 const QgsProcessingParameterBand *bandParam = static_cast< const QgsProcessingParameterBand * >( parameterDefinition() );
6740 if ( bandParam->allowMultiple() )
6741 {
6742#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
6743 const QStringList parts = mLineEdit->text().split( ';', QString::SkipEmptyParts );
6744#else
6745 const QStringList parts = mLineEdit->text().split( ';', Qt::SkipEmptyParts );
6746#endif
6747 QVariantList res;
6748 res.reserve( parts.count() );
6749 for ( const QString &s : parts )
6750 {
6751 bool ok = false;
6752 int band = s.toInt( &ok );
6753 if ( ok )
6754 res << band;
6755 }
6756 return res.isEmpty() ? QVariant() : res;
6757 }
6758 else
6759 {
6760 return mLineEdit->text().isEmpty() ? QVariant() : mLineEdit->text();
6761 }
6762 }
6763 else
6764 return QVariant();
6765}
6766
6767QStringList QgsProcessingBandWidgetWrapper::compatibleParameterTypes() const
6768{
6769 return QStringList()
6772}
6773
6774QStringList QgsProcessingBandWidgetWrapper::compatibleOutputTypes() const
6775{
6776 return QStringList()
6778}
6779
6780QString QgsProcessingBandWidgetWrapper::modelerExpressionFormatString() const
6781{
6782 return tr( "selected band numbers as an array of numbers, or semicolon separated string of options (e.g. '1;3')" );
6783}
6784
6785QString QgsProcessingBandWidgetWrapper::parameterType() const
6786{
6788}
6789
6790QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingBandWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
6791{
6792 return new QgsProcessingBandWidgetWrapper( parameter, type );
6793}
6794
6795QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingBandWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
6796{
6797 return new QgsProcessingBandParameterDefinitionWidget( context, widgetContext, definition, algorithm );
6798}
6799
6800
6801
6802//
6803// QgsProcessingMultipleLayerPanelWidget
6804//
6805
6806QgsProcessingMultipleLayerPanelWidget::QgsProcessingMultipleLayerPanelWidget( QWidget *parent, const QgsProcessingParameterMultipleLayers *param )
6807 : QWidget( parent )
6808 , mParam( param )
6809{
6810 QHBoxLayout *hl = new QHBoxLayout();
6811 hl->setContentsMargins( 0, 0, 0, 0 );
6812
6813 mLineEdit = new QLineEdit();
6814 mLineEdit->setEnabled( false );
6815 hl->addWidget( mLineEdit, 1 );
6816
6817 mToolButton = new QToolButton();
6818 mToolButton->setText( QString( QChar( 0x2026 ) ) );
6819 hl->addWidget( mToolButton );
6820
6821 setLayout( hl );
6822
6823 if ( mParam )
6824 {
6825 mLineEdit->setText( tr( "%n input(s) selected", nullptr, 0 ) );
6826 }
6827
6828 connect( mToolButton, &QToolButton::clicked, this, &QgsProcessingMultipleLayerPanelWidget::showDialog );
6829}
6830
6831void QgsProcessingMultipleLayerPanelWidget::setValue( const QVariant &value )
6832{
6833 if ( value.isValid() )
6834 mValue = value.type() == QVariant::List ? value.toList() : QVariantList() << value;
6835 else
6836 mValue.clear();
6837
6838 updateSummaryText();
6839 emit changed();
6840}
6841
6842void QgsProcessingMultipleLayerPanelWidget::setProject( QgsProject *project )
6843{
6844 mProject = project;
6845 if ( mProject )
6846 {
6847 connect( mProject, &QgsProject::layerRemoved, this, [&]( const QString & layerId )
6848 {
6849 if ( mValue.removeAll( layerId ) )
6850 {
6851 updateSummaryText();
6852 emit changed();
6853 }
6854 } );
6855 }
6856}
6857
6858void QgsProcessingMultipleLayerPanelWidget::setModel( QgsProcessingModelAlgorithm *model, const QString &modelChildAlgorithmID )
6859{
6860 mModel = model;
6861 if ( !model )
6862 return;
6863
6864 switch ( mParam->layerType() )
6865 {
6867 mModelSources = model->availableSourcesForChild( modelChildAlgorithmID, QStringList() << QgsProcessingParameterFile::typeName(),
6868 QStringList() << QgsProcessingOutputFile::typeName() );
6869 break;
6870
6872 {
6873 mModelSources = model->availableSourcesForChild( modelChildAlgorithmID, QStringList() << QgsProcessingParameterRasterLayer::typeName()
6876 QStringList() << QgsProcessingOutputFile::typeName()
6880 break;
6881 }
6882
6884 {
6885 mModelSources = model->availableSourcesForChild( modelChildAlgorithmID, QStringList() << QgsProcessingParameterMeshLayer::typeName()
6888 QStringList() << QgsProcessingOutputFile::typeName()
6891 break;
6892 }
6893
6895 {
6896 mModelSources = model->availableSourcesForChild( modelChildAlgorithmID, QStringList() << QgsProcessingParameterMapLayer::typeName()
6899 QStringList() << QgsProcessingOutputFile::typeName()
6902 break;
6903 }
6904
6906 {
6907 mModelSources = model->availableSourcesForChild( modelChildAlgorithmID, QStringList() << QgsProcessingParameterPointCloudLayer::typeName()
6910 QStringList() << QgsProcessingOutputFile::typeName()
6913 break;
6914 }
6915
6917 {
6918 mModelSources = model->availableSourcesForChild( modelChildAlgorithmID, QStringList() << QgsProcessingParameterAnnotationLayer::typeName()
6920 QStringList() << QgsProcessingOutputMapLayer::typeName()
6922 break;
6923 }
6924
6926 {
6927 mModelSources = model->availableSourcesForChild( modelChildAlgorithmID, QStringList() << QgsProcessingParameterFeatureSource::typeName()
6931 QStringList() << QgsProcessingOutputFile::typeName()
6935 QList< int >() << QgsProcessing::TypeVector );
6936 break;
6937 }
6938
6940 {
6941 mModelSources = model->availableSourcesForChild( modelChildAlgorithmID, QStringList() << QgsProcessingParameterFeatureSource::typeName()
6945 QStringList() << QgsProcessingOutputFile::typeName()
6949 break;
6950 }
6951
6953 {
6954 mModelSources = model->availableSourcesForChild( modelChildAlgorithmID, QStringList() << QgsProcessingParameterFeatureSource::typeName()
6958 QStringList() << QgsProcessingOutputFile::typeName()
6963 break;
6964 }
6965
6967 {
6968 mModelSources = model->availableSourcesForChild( modelChildAlgorithmID, QStringList() << QgsProcessingParameterFeatureSource::typeName()
6972 QStringList() << QgsProcessingOutputFile::typeName()
6977 break;
6978 }
6979
6981 {
6982 mModelSources = model->availableSourcesForChild( modelChildAlgorithmID, QStringList() << QgsProcessingParameterFeatureSource::typeName()
6986 QStringList() << QgsProcessingOutputFile::typeName()
6991 break;
6992 }
6993
6995 {
6996 mModelSources = model->availableSourcesForChild( modelChildAlgorithmID, QStringList() << QgsProcessingParameterFeatureSource::typeName()
7002 QStringList() << QgsProcessingOutputFile::typeName()
7006 // << QgsProcessingOutputMeshLayer::typeName()
7008 break;
7009 }
7010 }
7011}
7012
7013void QgsProcessingMultipleLayerPanelWidget::showDialog()
7014{
7016 if ( panel && panel->dockMode() )
7017 {
7018 QgsProcessingMultipleInputPanelWidget *widget = new QgsProcessingMultipleInputPanelWidget( mParam, mValue, mModelSources, mModel );
7019 widget->setPanelTitle( mParam->description() );
7020 widget->setProject( mProject );
7021 connect( widget, &QgsProcessingMultipleSelectionPanelWidget::selectionChanged, this, [ = ]()
7022 {
7023 setValue( widget->selectedOptions() );
7024 } );
7025 connect( widget, &QgsProcessingMultipleSelectionPanelWidget::acceptClicked, widget, &QgsPanelWidget::acceptPanel );
7026 panel->openPanel( widget );
7027 }
7028 else
7029 {
7030 QgsProcessingMultipleInputDialog dlg( mParam, mValue, mModelSources, mModel, this, Qt::WindowFlags() );
7031 dlg.setProject( mProject );
7032 if ( dlg.exec() )
7033 {
7034 setValue( dlg.selectedOptions() );
7035 }
7036 }
7037}
7038
7039void QgsProcessingMultipleLayerPanelWidget::updateSummaryText()
7040{
7041 if ( mParam )
7042 mLineEdit->setText( tr( "%n input(s) selected", nullptr, mValue.count() ) );
7043}
7044
7045//
7046// QgsProcessingMultipleLayerWidgetWrapper
7047//
7048
7049QgsProcessingMultipleLayerParameterDefinitionWidget::QgsProcessingMultipleLayerParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
7050 : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
7051{
7052 QVBoxLayout *vlayout = new QVBoxLayout();
7053 vlayout->setContentsMargins( 0, 0, 0, 0 );
7054
7055 vlayout->addWidget( new QLabel( tr( "Allowed layer type" ) ) );
7056 mLayerTypeComboBox = new QComboBox();
7057 mLayerTypeComboBox->addItem( tr( "Any Map Layer" ), QgsProcessing::TypeMapLayer );
7058 mLayerTypeComboBox->addItem( tr( "Vector (No Geometry Required)" ), QgsProcessing::TypeVector );
7059 mLayerTypeComboBox->addItem( tr( "Vector (Point)" ), QgsProcessing::TypeVectorPoint );
7060 mLayerTypeComboBox->addItem( tr( "Vector (Line)" ), QgsProcessing::TypeVectorLine );
7061 mLayerTypeComboBox->addItem( tr( "Vector (Polygon)" ), QgsProcessing::TypeVectorPolygon );
7062 mLayerTypeComboBox->addItem( tr( "Any Geometry Type" ), QgsProcessing::TypeVectorAnyGeometry );
7063 mLayerTypeComboBox->addItem( tr( "Raster" ), QgsProcessing::TypeRaster );
7064 mLayerTypeComboBox->addItem( tr( "File" ), QgsProcessing::TypeFile );
7065 mLayerTypeComboBox->addItem( tr( "Mesh" ), QgsProcessing::TypeMesh );
7066 mLayerTypeComboBox->addItem( tr( "Plugin" ), QgsProcessing::TypePlugin );
7067 mLayerTypeComboBox->addItem( tr( "Point Cloud" ), QgsProcessing::TypePointCloud );
7068 mLayerTypeComboBox->addItem( tr( "Annotation" ), QgsProcessing::TypeAnnotation );
7069 if ( const QgsProcessingParameterMultipleLayers *layersParam = dynamic_cast<const QgsProcessingParameterMultipleLayers *>( definition ) )
7070 mLayerTypeComboBox->setCurrentIndex( mLayerTypeComboBox->findData( layersParam->layerType() ) );
7071
7072 vlayout->addWidget( mLayerTypeComboBox );
7073 setLayout( vlayout );
7074}
7075
7076QgsProcessingParameterDefinition *QgsProcessingMultipleLayerParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
7077{
7078 auto param = std::make_unique< QgsProcessingParameterMultipleLayers >( name, description, static_cast< QgsProcessing::SourceType >( mLayerTypeComboBox->currentData().toInt() ) );
7079 param->setFlags( flags );
7080 return param.release();
7081}
7082
7083QgsProcessingMultipleLayerWidgetWrapper::QgsProcessingMultipleLayerWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
7084 : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
7085{
7086
7087}
7088
7089QWidget *QgsProcessingMultipleLayerWidgetWrapper::createWidget()
7090{
7091 const QgsProcessingParameterMultipleLayers *layerParam = dynamic_cast< const QgsProcessingParameterMultipleLayers *>( parameterDefinition() );
7092
7093 mPanel = new QgsProcessingMultipleLayerPanelWidget( nullptr, layerParam );
7094 mPanel->setToolTip( parameterDefinition()->toolTip() );
7095 mPanel->setProject( widgetContext().project() );
7096 if ( type() == QgsProcessingGui::Modeler )
7097 mPanel->setModel( widgetContext().model(), widgetContext().modelChildAlgorithmId() );
7098 connect( mPanel, &QgsProcessingMultipleLayerPanelWidget::changed, this, [ = ]
7099 {
7100 emit widgetValueHasChanged( this );
7101 } );
7102 return mPanel;
7103}
7104
7105void QgsProcessingMultipleLayerWidgetWrapper::setWidgetContext( const QgsProcessingParameterWidgetContext &context )
7106{
7108 if ( mPanel )
7109 {
7110 mPanel->setProject( context.project() );
7111 if ( type() == QgsProcessingGui::Modeler )
7112 mPanel->setModel( widgetContext().model(), widgetContext().modelChildAlgorithmId() );
7113 }
7114}
7115
7116void QgsProcessingMultipleLayerWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
7117{
7118 if ( mPanel )
7119 {
7120 QVariantList opts;
7121 if ( value.isValid() )
7122 {
7123 const QList< QgsMapLayer * > v = QgsProcessingParameters::parameterAsLayerList( parameterDefinition(), value, context );
7124 opts.reserve( v.size() );
7125 for ( const QgsMapLayer *l : v )
7126 opts << l->source();
7127 }
7128
7129 for ( const QVariant &v : value.toList() )
7130 {
7131 if ( v.userType() == QMetaType::type( "QgsProcessingModelChildParameterSource" ) )
7132 {
7133 const QgsProcessingModelChildParameterSource source = v.value< QgsProcessingModelChildParameterSource >();
7134 opts << QVariant::fromValue( source );
7135 }
7136 }
7137
7138 if ( mPanel )
7139 mPanel->setValue( value.isValid() ? opts : QVariant() );
7140 }
7141}
7142
7143QVariant QgsProcessingMultipleLayerWidgetWrapper::widgetValue() const
7144{
7145 if ( mPanel )
7146 return !mPanel->value().toList().isEmpty() ? mPanel->value() : QVariant();
7147 else
7148 return QVariant();
7149}
7150
7151QStringList QgsProcessingMultipleLayerWidgetWrapper::compatibleParameterTypes() const
7152{
7153 return QStringList()
7162}
7163
7164QStringList QgsProcessingMultipleLayerWidgetWrapper::compatibleOutputTypes() const
7165{
7166 return QStringList()
7173}
7174
7175QString QgsProcessingMultipleLayerWidgetWrapper::modelerExpressionFormatString() const
7176{
7177 return tr( "an array of layer paths, or semicolon separated string of layer paths" );
7178}
7179
7180QString QgsProcessingMultipleLayerWidgetWrapper::parameterType() const
7181{
7183}
7184
7185QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingMultipleLayerWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
7186{
7187 return new QgsProcessingMultipleLayerWidgetWrapper( parameter, type );
7188}
7189
7190QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingMultipleLayerWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
7191{
7192 return new QgsProcessingMultipleLayerParameterDefinitionWidget( context, widgetContext, definition, algorithm );
7193}
7194
7195
7196//
7197// QgsProcessingPointCloudLayerWidgetWrapper
7198//
7199
7200QgsProcessingPointCloudLayerWidgetWrapper::QgsProcessingPointCloudLayerWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
7201 : QgsProcessingMapLayerWidgetWrapper( parameter, type, parent )
7202{
7203
7204}
7205
7206QStringList QgsProcessingPointCloudLayerWidgetWrapper::compatibleParameterTypes() const
7207{
7208 return QStringList()
7213}
7214
7215QStringList QgsProcessingPointCloudLayerWidgetWrapper::compatibleOutputTypes() const
7216{
7217 return QStringList()
7219 // TODO << QgsProcessingOutputPointCloudLayer::typeName()
7223}
7224
7225QString QgsProcessingPointCloudLayerWidgetWrapper::modelerExpressionFormatString() const
7226{
7227 return tr( "path to a point cloud layer" );
7228}
7229
7230QString QgsProcessingPointCloudLayerWidgetWrapper::parameterType() const
7231{
7233}
7234
7235QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingPointCloudLayerWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
7236{
7237 return new QgsProcessingPointCloudLayerWidgetWrapper( parameter, type );
7238}
7239
7240QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingPointCloudLayerWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
7241{
7242 Q_UNUSED( context );
7243 Q_UNUSED( widgetContext );
7244 Q_UNUSED( definition );
7245 Q_UNUSED( algorithm );
7246
7247 return nullptr;
7248}
7249
7250
7251//
7252// QgsProcessingAnnotationLayerWidgetWrapper
7253//
7254
7255QgsProcessingAnnotationLayerWidgetWrapper::QgsProcessingAnnotationLayerWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
7256 : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
7257{
7258
7259}
7260
7261QStringList QgsProcessingAnnotationLayerWidgetWrapper::compatibleParameterTypes() const
7262{
7263 return QStringList()
7268}
7269
7270QStringList QgsProcessingAnnotationLayerWidgetWrapper::compatibleOutputTypes() const
7271{
7272 return QStringList()
7275}
7276
7277QString QgsProcessingAnnotationLayerWidgetWrapper::modelerExpressionFormatString() const
7278{
7279 return tr( "name of an annotation layer, or \"main\" for the main annotation layer" );
7280}
7281
7282QString QgsProcessingAnnotationLayerWidgetWrapper::parameterType() const
7283{
7285}
7286
7287QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingAnnotationLayerWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
7288{
7289 return new QgsProcessingAnnotationLayerWidgetWrapper( parameter, type );
7290}
7291
7292QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingAnnotationLayerWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
7293{
7294 Q_UNUSED( context );
7295 Q_UNUSED( widgetContext );
7296 Q_UNUSED( definition );
7297 Q_UNUSED( algorithm );
7298
7299 return nullptr;
7300}
7301
7302void QgsProcessingAnnotationLayerWidgetWrapper::setWidgetContext( const QgsProcessingParameterWidgetContext &context )
7303{
7305 if ( mComboBox )
7306 {
7307 if ( mWidgetContext.project() )
7308 mComboBox->setAdditionalLayers( { mWidgetContext.project()->mainAnnotationLayer() } );
7309 }
7310}
7311
7312QWidget *QgsProcessingAnnotationLayerWidgetWrapper::createWidget()
7313{
7314 mComboBox = new QgsMapLayerComboBox( );
7315 mComboBox->setFilters( QgsMapLayerProxyModel::AnnotationLayer );
7316
7317 switch ( type() )
7318 {
7321 break;
7323 mComboBox->setEditable( true );
7324 break;
7325 }
7326
7327 mComboBox->setToolTip( parameterDefinition()->toolTip() );
7328
7329 if ( mWidgetContext.project() )
7330 mComboBox->setAdditionalLayers( { mWidgetContext.project()->mainAnnotationLayer() } );
7331
7332 if ( parameterDefinition()->flags() & QgsProcessingParameterDefinition::FlagOptional )
7333 mComboBox->setAllowEmptyLayer( true );
7334
7335 connect( mComboBox, &QgsMapLayerComboBox::layerChanged, this, [ = ]()
7336 {
7337 if ( mBlockSignals )
7338 return;
7339
7340 emit widgetValueHasChanged( this );
7341 } );
7342
7343 setWidgetContext( widgetContext() );
7344 return mComboBox;
7345}
7346
7347void QgsProcessingAnnotationLayerWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
7348{
7349 if ( mComboBox )
7350 {
7351 if ( !value.isValid() && parameterDefinition()->flags() & QgsProcessingParameterDefinition::FlagOptional )
7352 {
7353 mComboBox->setLayer( nullptr );
7354 return;
7355 }
7356
7357 QVariant val = value;
7358 if ( val.userType() == QMetaType::type( "QgsProperty" ) )
7359 {
7360 if ( val.value< QgsProperty >().propertyType() == QgsProperty::StaticProperty )
7361 {
7362 val = val.value< QgsProperty >().staticValue();
7363 }
7364 else
7365 {
7366 val = val.value< QgsProperty >().valueAsString( context.expressionContext(), parameterDefinition()->defaultValueForGui().toString() );
7367 }
7368 }
7369
7370 QgsMapLayer *layer = qobject_cast< QgsMapLayer * >( val.value< QObject * >() );
7371 if ( !layer && val.type() == QVariant::String )
7372 {
7374 }
7375
7376 if ( layer )
7377 {
7378 mComboBox->setLayer( layer );
7379 }
7380 }
7381}
7382
7383QVariant QgsProcessingAnnotationLayerWidgetWrapper::widgetValue() const
7384{
7385 return mComboBox && mComboBox->currentLayer() ?
7386 ( mWidgetContext.project() ? ( mComboBox->currentLayer() == mWidgetContext.project()->mainAnnotationLayer() ? QStringLiteral( "main" ) : mComboBox->currentLayer()->id() ) : mComboBox->currentLayer()->id() )
7387 : QVariant();
7388}
7389
7390
7391
7392//
7393// QgsProcessingOutputWidgetWrapper
7394//
7395
7396QgsProcessingOutputWidgetWrapper::QgsProcessingOutputWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
7397 : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
7398{
7399
7400}
7401
7402QWidget *QgsProcessingOutputWidgetWrapper::createWidget()
7403{
7404 const QgsProcessingDestinationParameter *destParam = dynamic_cast< const QgsProcessingDestinationParameter * >( parameterDefinition() );
7405 switch ( type() )
7406 {
7409 {
7410 mOutputWidget = new QgsProcessingLayerOutputDestinationWidget( destParam, false );
7411 if ( mProcessingContextGenerator )
7412 mOutputWidget->setContext( mProcessingContextGenerator->processingContext() );
7413 if ( mParametersGenerator )
7414 mOutputWidget->registerProcessingParametersGenerator( mParametersGenerator );
7415 mOutputWidget->setToolTip( parameterDefinition()->toolTip() );
7416
7417 connect( mOutputWidget, &QgsProcessingLayerOutputDestinationWidget::destinationChanged, this, [ = ]()
7418 {
7419 if ( mBlockSignals )
7420 return;
7421
7422 emit widgetValueHasChanged( this );
7423 } );
7424
7425 if ( type() == QgsProcessingGui::Standard
7430 mOutputWidget->addOpenAfterRunningOption();
7431
7432 return mOutputWidget;
7433 }
7435 break;
7436 }
7437
7438 return nullptr;
7439}
7440
7441
7442void QgsProcessingOutputWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext & )
7443{
7444 if ( mOutputWidget )
7445 mOutputWidget->setValue( value );
7446}
7447
7448QVariant QgsProcessingOutputWidgetWrapper::widgetValue() const
7449{
7450 if ( mOutputWidget )
7451 return mOutputWidget->value();
7452
7453 return QVariant();
7454}
7455
7456QVariantMap QgsProcessingOutputWidgetWrapper::customProperties() const
7457{
7458 QVariantMap res;
7459 if ( mOutputWidget )
7460 res.insert( QStringLiteral( "OPEN_AFTER_RUNNING" ), mOutputWidget->openAfterRunning() );
7461 return res;
7462}
7463
7464QStringList QgsProcessingOutputWidgetWrapper::compatibleParameterTypes() const
7465{
7466 return QStringList()
7473}
7474
7475QStringList QgsProcessingOutputWidgetWrapper::compatibleOutputTypes() const
7476{
7477 return QStringList()
7481}
7482
7483//
7484// QgsProcessingFeatureSinkWidgetWrapper
7485//
7486
7487QgsProcessingFeatureSinkWidgetWrapper::QgsProcessingFeatureSinkWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
7488 : QgsProcessingOutputWidgetWrapper( parameter, type, parent )
7489{
7490
7491}
7492
7493QString QgsProcessingFeatureSinkWidgetWrapper::parameterType() const
7494{
7496}
7497
7498QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingFeatureSinkWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
7499{
7500 return new QgsProcessingFeatureSinkWidgetWrapper( parameter, type );
7501}
7502
7503QString QgsProcessingFeatureSinkWidgetWrapper::modelerExpressionFormatString() const
7504{
7505 return tr( "path to layer destination" );
7506}
7507
7508//
7509// QgsProcessingFeatureSinkWidgetWrapper
7510//
7511
7512QgsProcessingVectorDestinationWidgetWrapper::QgsProcessingVectorDestinationWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
7513 : QgsProcessingOutputWidgetWrapper( parameter, type, parent )
7514{
7515
7516}
7517
7518QString QgsProcessingVectorDestinationWidgetWrapper::parameterType() const
7519{
7521}
7522
7523QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingVectorDestinationWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
7524{
7525 return new QgsProcessingVectorDestinationWidgetWrapper( parameter, type );
7526}
7527
7528QString QgsProcessingVectorDestinationWidgetWrapper::modelerExpressionFormatString() const
7529{
7530 return tr( "path to layer destination" );
7531}
7532
7533//
7534// QgsProcessingRasterDestinationWidgetWrapper
7535//
7536
7537QgsProcessingRasterDestinationWidgetWrapper::QgsProcessingRasterDestinationWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
7538 : QgsProcessingOutputWidgetWrapper( parameter, type, parent )
7539{
7540
7541}
7542
7543QString QgsProcessingRasterDestinationWidgetWrapper::parameterType() const
7544{
7546}
7547
7548QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingRasterDestinationWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
7549{
7550 return new QgsProcessingRasterDestinationWidgetWrapper( parameter, type );
7551}
7552
7553QString QgsProcessingRasterDestinationWidgetWrapper::modelerExpressionFormatString() const
7554{
7555 return tr( "path to layer destination" );
7556}
7557
7558//
7559// QgsProcessingPointCloudDestinationWidgetWrapper
7560//
7561
7562QgsProcessingPointCloudDestinationWidgetWrapper::QgsProcessingPointCloudDestinationWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
7563 : QgsProcessingOutputWidgetWrapper( parameter, type, parent )
7564{
7565
7566}
7567
7568QString QgsProcessingPointCloudDestinationWidgetWrapper::parameterType() const
7569{
7571}
7572
7573QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingPointCloudDestinationWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
7574{
7575 return new QgsProcessingPointCloudDestinationWidgetWrapper( parameter, type );
7576}
7577
7578QString QgsProcessingPointCloudDestinationWidgetWrapper::modelerExpressionFormatString() const
7579{
7580 return tr( "path to layer destination" );
7581}
7582
7583//
7584// QgsProcessingFileDestinationWidgetWrapper
7585//
7586
7587QgsProcessingFileDestinationWidgetWrapper::QgsProcessingFileDestinationWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
7588 : QgsProcessingOutputWidgetWrapper( parameter, type, parent )
7589{
7590
7591}
7592
7593QString QgsProcessingFileDestinationWidgetWrapper::parameterType() const
7594{
7596}
7597
7598QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingFileDestinationWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
7599{
7600 return new QgsProcessingFileDestinationWidgetWrapper( parameter, type );
7601}
7602
7603QString QgsProcessingFileDestinationWidgetWrapper::modelerExpressionFormatString() const
7604{
7605 return tr( "path to file destination" );
7606}
7607
7608//
7609// QgsProcessingFolderDestinationWidgetWrapper
7610//
7611
7612QgsProcessingFolderDestinationWidgetWrapper::QgsProcessingFolderDestinationWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
7613 : QgsProcessingOutputWidgetWrapper( parameter, type, parent )
7614{
7615
7616}
7617
7618QString QgsProcessingFolderDestinationWidgetWrapper::parameterType() const
7619{
7621}
7622
7623QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingFolderDestinationWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
7624{
7625 return new QgsProcessingFolderDestinationWidgetWrapper( parameter, type );
7626}
7627
7628QString QgsProcessingFolderDestinationWidgetWrapper::modelerExpressionFormatString() const
7629{
7630 return tr( "path to folder destination" );
7631}
7632
@ Standard
Unit is a standard measurement unit.
DistanceUnit
Units of distance.
Definition: qgis.h:3047
TemporalUnit
Temporal units.
Definition: qgis.h:3152
A widget wrapper for Processing parameter value widgets.
QVariant parameterValue() const
Returns the current value of the parameter.
virtual QLabel * createLabel()
Creates a new label to accompany widgets created by the wrapper.
virtual void registerProcessingContextGenerator(QgsProcessingContextGenerator *generator)
Registers a Processing context generator class that will be used to retrieve a Processing context for...
void widgetValueHasChanged(QgsAbstractProcessingParameterWidgetWrapper *wrapper)
Emitted whenever the parameter value (as defined by the wrapped widget) is changed.
virtual void postInitialize(const QList< QgsAbstractProcessingParameterWidgetWrapper * > &wrappers)
Called after all wrappers have been created within a particular dialog or context,...
virtual const QgsVectorLayer * linkedVectorLayer() const
Returns the optional vector layer associated with this widget wrapper, or nullptr if no vector layer ...
const QgsProcessingParameterDefinition * parameterDefinition() const
Returns the parameter definition associated with this wrapper.
virtual void setDialog(QDialog *dialog)
Sets the parent dialog in which the wrapper is shown.
virtual void setWidgetContext(const QgsProcessingParameterWidgetContext &context)
Sets the context in which the Processing parameter widget is shown, e.g., the parent model algorithm,...
static QCursor getThemeCursor(Cursor cursor)
Helper to get a theme cursor.
static QIcon getThemeIcon(const QString &name, const QColor &fillColor=QColor(), const QColor &strokeColor=QColor())
Helper to get a theme icon.
Selector widget for authentication configs.
void selectedConfigIdChanged(const QString &authcfg)
Emitted when authentication config is changed or missing.
QComboBox subclass which allows selecting multiple items.
A cross platform button subclass for selecting colors.
void colorChanged(const QColor &color)
Emitted whenever a new color is set for the button.
A widget for selecting the coordinate operation to use when transforming between a source and destina...
void operationChanged()
Emitted when the operation selected in the dialog is changed.
This class represents a coordinate reference system (CRS).
bool isValid() const
Returns whether this CRS is correctly initialized and usable.
Q_GADGET Qgis::DistanceUnit mapUnits
The QgsDatabaseSchemaComboBox class is a combo box which displays the list of schemas for a specific ...
The QgsDatabaseTableComboBox class is a combo box which displays the list of tables for a specific da...
The QgsDateEdit class is a QDateEdit widget with the capability of setting/reading null dates.
void dateValueChanged(const QDate &date)
Signal emitted whenever the date changes.
The QgsDateTimeEdit class is a QDateTimeEdit with the capability of setting/reading null date/times.
void setAllowNull(bool allowNull)
Determines if the widget allows setting null date/time.
void setNullRepresentation(const QString &null)
Sets the widget's null representation, which defaults to QgsApplication::nullRepresentation().
void valueChanged(const QDateTime &date)
Signal emitted whenever the value changes.
The QgsSpinBox is a spin box with a clear button that will set the value to the defined clear value.
static double toDouble(const QString &input, bool *ok)
Converts input string to double value.
A reusable widget that can be used to build a expression string.
void expressionParsed(bool isValid)
Emitted when the user changes the expression in the widget.
The QgsExpressionLineEdit widget includes a line edit for entering expressions together with a button...
void expressionChanged(const QString &expression)
Emitted when the expression is changed.
A widget for configuration of a map extent.
void toggleDialogVisibility(bool visible)
Emitted when the parent dialog visibility must be changed (e.g.
void extentChanged(const QgsRectangle &r)
Emitted when the widget's extent is changed.
The QgsFieldComboBox is a combo box which displays the list of fields of a given layer.
void fieldChanged(const QString &fieldName)
Emitted when the currently selected field changes.
The QgsFieldExpressionWidget class reates a widget to choose fields and edit expressions It contains ...
void fieldChanged(const QString &fieldName)
Emitted when the currently selected field changes.
@ DateTime
Datetime fieldss.
@ Date
Date or datetime fields.
@ String
String fields.
@ Numeric
All numeric fields.
Encapsulate a field in an attribute table or data source.
Definition: qgsfield.h:52
QString name
Definition: qgsfield.h:61
Container of fields for a vector layer.
Definition: qgsfields.h:45
QList< QgsField > toList() const
Utility function to return a list of QgsField instances.
Definition: qgsfields.cpp:212
bool append(const QgsField &field, FieldOrigin origin=OriginProvider, int originIndex=-1)
Appends a field. The field must have unique name, otherwise it is rejected (returns false)
Definition: qgsfields.cpp:59
void remove(int fieldIdx)
Removes the field with the given index.
Definition: qgsfields.cpp:101
int count() const
Returns number of items.
Definition: qgsfields.cpp:133
bool isEmpty() const
Checks whether the container is empty.
Definition: qgsfields.cpp:128
QgsField at(int i) const
Returns the field at particular index (must be in range 0..N-1).
Definition: qgsfields.cpp:163
int lookupField(const QString &fieldName) const
Looks up field's index from the field name.
Definition: qgsfields.cpp:359
The QgsFileWidget class creates a widget for selecting a file or a folder.
Definition: qgsfilewidget.h:39
@ GetFile
Select a single file.
Definition: qgsfilewidget.h:68
@ GetDirectory
Select a directory.
Definition: qgsfilewidget.h:69
void fileChanged(const QString &path)
Emitted whenever the current file or directory path is changed.
QLineEdit subclass with built in support for clearing the widget's value and handling custom null val...
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:164
Q_GADGET bool isNull
Definition: qgsgeometry.h:166
QString asWkt(int precision=17) const
Exports the geometry to WKT.
The QgsLayoutComboBox class is a combo box which displays available layouts from a QgsLayoutManager.
void layoutChanged(QgsMasterLayoutInterface *layout)
Emitted whenever the currently selected layout changes.
The QgsLayoutItemComboBox class is a combo box which displays items of a matching type from a layout.
void itemChanged(QgsLayoutItem *item)
Emitted whenever the currently selected item changes.
Base class for graphical items within a QgsLayout.
virtual QString uuid() const
Returns the item identification string.
@ FilterPrintLayouts
Includes print layouts.
QList< QgsPrintLayout * > printLayouts() const
Returns a list of all print layouts contained in the manager.
Map canvas is a class for displaying all GIS data types on a canvas.
Definition: qgsmapcanvas.h:90
const QgsMapSettings & mapSettings() const
Gets access to properties used for map rendering.
The QgsMapLayerComboBox class is a combo box which displays the list of layers.
void layerChanged(QgsMapLayer *layer)
Emitted whenever the currently selected layer changes.
@ AnnotationLayer
QgsAnnotationLayer.
Base class for all map layer types.
Definition: qgsmaplayer.h:73
QString id() const
Returns the layer's unique ID, which is used to access this layer from QgsProject.
bool isValid
Definition: qgsmaplayer.h:81
A QgsMapMouseEvent is the result of a user interaction with the mouse on a QgsMapCanvas.
QgsPointLocator::Match mapPointMatch() const
Returns the matching data from the most recently snapped point.
QgsPointXY snapPoint()
snapPoint will snap the points using the map canvas snapping utils configuration
QgsCoordinateReferenceSystem destinationCrs() const
Returns the destination coordinate reference system for the map render.
Abstract base class for all map tools.
Definition: qgsmaptool.h:71
virtual void deactivate()
called when map tool is being deactivated
Definition: qgsmaptool.cpp:110
Interface for master layout type objects, such as print layouts and reports.
virtual QString name() const =0
Returns the layout's name.
void pushMessage(const QString &text, Qgis::MessageLevel level=Qgis::MessageLevel::Info, int duration=-1)
A convenience method for pushing a message with the specified text to the bar.
bool clearWidgets()
Removes all items from the bar.
Base class for any widget that can be shown as a inline panel.
void openPanel(QgsPanelWidget *panel)
Open a panel or dialog depending on dock mode setting If dock mode is true this method will emit the ...
void acceptPanel()
Accept the panel.
static QgsPanelWidget * findParentPanel(QWidget *widget)
Traces through the parents of a widget to find if it is contained within a QgsPanelWidget widget.
bool dockMode()
Returns the dock mode state.
A class to represent a 2D point.
Definition: qgspointxy.h:59
double y
Definition: qgspointxy.h:63
Q_GADGET double x
Definition: qgspointxy.h:62
Print layout, a QgsLayout subclass for static or atlas-based layouts.
Abstract base class for widgets which allow users to specify the properties of a Processing parameter...
Abstract base class for processing algorithms.
An interface for objects which can create Processing contexts.
Contains information about the context in which a processing algorithm is executed.
QgsExpressionContext & expressionContext()
Returns the expression context.
QgsCoordinateTransformContext transformContext() const
Returns the coordinate transform context.
QgsMapLayer * takeResultLayer(const QString &id)
Takes the result map layer with matching id from the context and transfers ownership of it back to th...
Base class for all parameter definitions which represent file or layer destinations,...
Encapsulates settings relating to a feature source input to a processing algorithm.
WidgetType
Types of dialogs which Processing widgets can be created for.
@ Modeler
Modeler dialog.
@ Standard
Standard algorithm dialog.
@ Batch
Batch processing dialog.
static QString typeName()
Returns the type name for the output class.
static QString typeName()
Returns the type name for the output class.
static QString typeName()
Returns the type name for the output class.
static QString typeName()
Returns the type name for the output class.
static QString typeName()
Returns the type name for the output class.
static QString typeName()
Returns the type name for the output class.
static QString typeName()
Returns the type name for the output class.
static QString typeName()
Returns the type name for the output class.
static QString typeName()
Returns the type name for the output class.
static QString typeName()
Returns the type name for the parameter class.
static QString typeName()
Returns the type name for the parameter class.
A raster band parameter for Processing algorithms.
static QString typeName()
Returns the type name for the parameter class.
bool allowMultiple() const
Returns whether multiple band selections are permitted.
A boolean parameter for processing algorithms.
static QString typeName()
Returns the type name for the parameter class.
A color parameter for processing algorithms.
bool opacityEnabled() const
Returns true if the parameter allows opacity control.
static QString typeName()
Returns the type name for the parameter class.
A coordinate operation parameter for processing algorithms, for selection between available coordinat...
static QString typeName()
Returns the type name for the parameter class.
QVariant sourceCrs() const
Returns the static source CRS, or an invalid value if this is not set.
QVariant destinationCrs() const
Returns the static destination CRS, or an invalid value if this is not set.
A coordinate reference system parameter for processing algorithms.
static QString typeName()
Returns the type name for the parameter class.
A database schema parameter for processing algorithms, allowing users to select from existing schemas...
static QString typeName()
Returns the type name for the parameter class.
QString parentConnectionParameterName() const
Returns the name of the parent connection parameter, or an empty string if this is not set.
A database table name parameter for processing algorithms, allowing users to select from existing dat...
static QString typeName()
Returns the type name for the parameter class.
QString parentConnectionParameterName() const
Returns the name of the parent connection parameter, or an empty string if this is not set.
QString parentSchemaParameterName() const
Returns the name of the parent schema parameter, or an empty string if this is not set.
bool allowNewTableNames() const
Returns true if the parameter allows users to enter names for a new (non-existing) tables.
A datetime (or pure date or time) parameter for processing algorithms.
static QString typeName()
Returns the type name for the parameter class.
Type dataType() const
Returns the acceptable data type for the parameter.
Base class for the definition of processing parameters.
QVariantMap metadata() const
Returns the parameter's freeform metadata.
QString description() const
Returns the description for the parameter.
QVariant defaultValueForGui() const
Returns the default value to use for the parameter in a GUI.
virtual QString type() const =0
Unique parameter type name.
Flags flags() const
Returns any flags associated with the parameter.
QString name() const
Returns the name of the parameter.
void setFlags(Flags flags)
Sets the flags associated with the parameter.
A double numeric parameter for distance values.
static QString typeName()
Returns the type name for the parameter class.
Qgis::DistanceUnit defaultUnit() const
Returns the default distance unit for the parameter.
A double numeric parameter for duration values.
Qgis::TemporalUnit defaultUnit() const
Returns the default duration unit for the parameter.
static QString typeName()
Returns the type name for the parameter class.
An enum based parameter for processing algorithms, allowing for selection from predefined values.
bool allowMultiple() const
Returns true if the parameter allows multiple selected values.
QStringList options() const
Returns the list of acceptable options for the parameter.
bool usesStaticStrings() const
Returns true if the parameter uses static (non-translated) string values for its enumeration choice l...
static QString typeName()
Returns the type name for the parameter class.
An expression parameter for processing algorithms.
QString parentLayerParameterName() const
Returns the name of the parent layer parameter, or an empty string if this is not set.
static QString typeName()
Returns the type name for the parameter class.
A rectangular map extent parameter for processing algorithms.
static QString typeName()
Returns the type name for the parameter class.
static QString typeName()
Returns the type name for the parameter class.
An input feature source (such as vector layers) parameter for processing algorithms.
static QString typeName()
Returns the type name for the parameter class.
A vector layer or feature source field parameter for processing algorithms.
void setDataType(DataType type)
Sets the acceptable data type for the field.
bool allowMultiple() const
Returns whether multiple field selections are permitted.
bool defaultToAllFields() const
Returns whether a parameter which allows multiple selections (see allowMultiple()) should automatical...
static QString typeName()
Returns the type name for the parameter class.
@ DateTime
Accepts datetime fields.
@ Numeric
Accepts numeric fields.
DataType dataType() const
Returns the acceptable data type for the field.
static QString typeName()
Returns the type name for the parameter class.
An input file or folder parameter for processing algorithms.
QString extension() const
Returns any specified file extension for the parameter.
static QString typeName()
Returns the type name for the parameter class.
@ File
Parameter is a single file.
Behavior behavior() const
Returns the parameter behavior (e.g.
QString fileFilter() const
Returns the file filter string for file destinations compatible with this parameter.
static QString typeName()
Returns the type name for the parameter class.
A geometry parameter for processing algorithms.
static QString typeName()
Returns the type name for the parameter class.
A print layout item parameter, allowing users to select a particular item from a print layout.
static QString typeName()
Returns the type name for the parameter class.
int itemType() const
Returns the acceptable item type, or -1 if any item type is allowed.
A print layout parameter, allowing users to select a print layout.
static QString typeName()
Returns the type name for the parameter class.
A map layer parameter for processing algorithms.
static QString typeName()
Returns the type name for the parameter class.
A map theme parameter for processing algorithms, allowing users to select an existing map theme from ...
static QString typeName()
Returns the type name for the parameter class.
A table (matrix) parameter for processing algorithms.
static QString typeName()
Returns the type name for the parameter class.
static QString typeName()
Returns the type name for the parameter class.
A parameter for processing algorithms which accepts multiple map layers.
static QString typeName()
Returns the type name for the parameter class.
A numeric parameter for processing algorithms.
double minimum() const
Returns the minimum value acceptable by the parameter.
double maximum() const
Returns the maximum value acceptable by the parameter.
Type dataType() const
Returns the acceptable data type for the parameter.
static QString typeName()
Returns the type name for the parameter class.
static QString typeName()
Returns the type name for the parameter class.
static QString typeName()
Returns the type name for the parameter class.
A point parameter for processing algorithms.
static QString typeName()
Returns the type name for the parameter class.
A data provider connection parameter for processing algorithms, allowing users to select from availab...
static QString typeName()
Returns the type name for the parameter class.
QString providerId() const
Returns the ID of the provider associated with the connections.
A numeric range parameter for processing algorithms.
QgsProcessingParameterNumber::Type dataType() const
Returns the acceptable data type for the range.
static QString typeName()
Returns the type name for the parameter class.
static QString typeName()
Returns the type name for the parameter class.
A raster layer parameter for processing algorithms.
static QString typeName()
Returns the type name for the parameter class.
A double numeric parameter for map scale values.
static QString typeName()
Returns the type name for the parameter class.
A string parameter for processing algorithms.
static QString typeName()
Returns the type name for the parameter class.
bool multiLine() const
Returns true if the parameter allows multiline strings.
static QString typeName()
Returns the type name for the parameter class.
A vector layer (with or without geometry) parameter for processing algorithms.
static QString typeName()
Returns the type name for the parameter class.
Contains settings which reflect the context in which a Processing parameter widget is shown,...
QgsMapCanvas * mapCanvas() const
Returns the map canvas associated with the widget.
QgsProject * project() const
Returns the project associated with the widget.
QgsMessageBar * messageBar() const
Returns the message bar associated with the widget.
QgsProcessingModelAlgorithm * model() const
Returns the model which the parameter widget is associated with.
QgsMapLayer * activeLayer() const
Returns the current active layer.
static QList< QgsMapLayer * > parameterAsLayerList(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context)
Evaluates the parameter with matching definition to a list of map layers.
static int parameterAsEnum(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, const QgsProcessingContext &context)
Evaluates the parameter with matching definition to a enum value.
static double parameterAsDouble(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, const QgsProcessingContext &context)
Evaluates the parameter with matching definition to a static double value.
static QgsPointXY parameterAsPoint(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context, const QgsCoordinateReferenceSystem &crs=QgsCoordinateReferenceSystem())
Evaluates the parameter with matching definition to a point.
static QgsPrintLayout * parameterAsLayout(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context)
Evaluates the parameter with matching definition to a print layout.
static QTime parameterAsTime(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, const QgsProcessingContext &context)
Evaluates the parameter with matching definition to a static time value.
static QgsRectangle parameterAsExtent(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context, const QgsCoordinateReferenceSystem &crs=QgsCoordinateReferenceSystem())
Evaluates the parameter with matching definition to a rectangular extent.
static QString parameterAsEnumString(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, const QgsProcessingContext &context)
Evaluates the parameter with matching definition to a static enum string.
static QList< double > parameterAsRange(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context)
Evaluates the parameter with matching definition to a range of values.
static QList< int > parameterAsInts(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, const QgsProcessingContext &context)
Evaluates the parameter with matching definition to a list of integer values.
static QString parameterAsConnectionName(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, const QgsProcessingContext &context)
Evaluates the parameter with matching definition to a connection name string.
static QgsProcessingFeatureSource * parameterAsSource(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context)
Evaluates the parameter with matching definition to a feature source.
static QgsCoordinateReferenceSystem parameterAsPointCrs(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context)
Returns the coordinate reference system associated with an point parameter value.
static QgsLayoutItem * parameterAsLayoutItem(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context, QgsPrintLayout *layout)
Evaluates the parameter with matching definition to a print layout item, taken from the specified lay...
static bool parameterAsBool(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, const QgsProcessingContext &context)
Evaluates the parameter with matching definition to a static boolean value.
static QColor parameterAsColor(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context)
Returns the color associated with an point parameter value, or an invalid color if the parameter was ...
static QgsVectorLayer * parameterAsVectorLayer(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context)
Evaluates the parameter with matching definition to a vector layer.
static int parameterAsInt(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, const QgsProcessingContext &context)
Evaluates the parameter with matching definition to a static integer value.
static QString parameterAsDatabaseTableName(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, const QgsProcessingContext &context)
Evaluates the parameter with matching definition to a database table name.
static QString parameterAsSchema(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, const QgsProcessingContext &context)
Evaluates the parameter with matching definition to a database schema name.
static QgsGeometry parameterAsGeometry(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context, const QgsCoordinateReferenceSystem &crs=QgsCoordinateReferenceSystem())
Evaluates the parameter with matching definition to a geometry.
static QString parameterAsExpression(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, const QgsProcessingContext &context)
Evaluates the parameter with matching definition to an expression.
static QString parameterAsString(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, const QgsProcessingContext &context)
Evaluates the parameter with matching definition to a static string value.
static QgsRasterLayer * parameterAsRasterLayer(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context)
Evaluates the parameter with matching definition to a raster layer.
static QList< int > parameterAsEnums(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, const QgsProcessingContext &context)
Evaluates the parameter with matching definition to list of enum values.
static QStringList parameterAsEnumStrings(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, const QgsProcessingContext &context)
Evaluates the parameter with matching definition to list of static enum strings.
static QStringList parameterAsFields(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context)
Evaluates the parameter with matching definition to a list of fields.
static QgsCoordinateReferenceSystem parameterAsExtentCrs(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context)
Returns the coordinate reference system associated with an extent parameter value.
static QDateTime parameterAsDateTime(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, const QgsProcessingContext &context)
Evaluates the parameter with matching definition to a static datetime value.
static QDate parameterAsDate(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, const QgsProcessingContext &context)
Evaluates the parameter with matching definition to a static date value.
static QVariantList parameterAsMatrix(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context)
Evaluates the parameter with matching definition to a matrix/table of values.
static QgsCoordinateReferenceSystem parameterAsCrs(const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context)
Evaluates the parameter with matching definition to a coordinate reference system.
@ Annotation
Annotation layer type, since QGIS 3.22.
static QgsCoordinateReferenceSystem variantToCrs(const QVariant &value, QgsProcessingContext &context, const QVariant &fallbackValue=QVariant())
Converts a variant value to a coordinate reference system.
static QgsMapLayer * mapLayerFromString(const QString &string, QgsProcessingContext &context, bool allowLoadingNewLayers=true, QgsProcessingUtils::LayerHint typeHint=QgsProcessingUtils::LayerHint::UnknownType)
Interprets a string as a map layer within the supplied context.
SourceType
Data source types enum.
Definition: qgsprocessing.h:47
@ TypePlugin
Plugin layers.
Definition: qgsprocessing.h:57
@ TypeVectorLine
Vector line layers.
Definition: qgsprocessing.h:51
@ TypeMapLayer
Any map layer type (raster, vector, mesh, point cloud, annotation or plugin layer)
Definition: qgsprocessing.h:48
@ TypeVectorPolygon
Vector polygon layers.
Definition: qgsprocessing.h:52
@ TypeFile
Files (i.e. non map layer sources, such as text files)
Definition: qgsprocessing.h:54
@ TypeAnnotation
Annotation layers.
Definition: qgsprocessing.h:59
@ TypePointCloud
Point cloud layers.
Definition: qgsprocessing.h:58
@ TypeMesh
Mesh layers.
Definition: qgsprocessing.h:56
@ TypeVector
Tables (i.e. vector layers with or without geometry). When used for a sink this indicates the sink ha...
Definition: qgsprocessing.h:55
@ TypeRaster
Raster layers.
Definition: qgsprocessing.h:53
@ TypeVectorPoint
Vector point layers.
Definition: qgsprocessing.h:50
@ TypeVectorAnyGeometry
Any vector layer with geometry.
Definition: qgsprocessing.h:49
Encapsulates a QGIS project, including sets of map layers and their styles, layouts,...
Definition: qgsproject.h:105
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:477
QgsMapThemeCollection * mapThemeCollection
Definition: qgsproject.h:113
const QgsLayoutManager * layoutManager() const
Returns the project's layout manager, which manages print layouts, atlases and reports within the pro...
void layerRemoved(const QString &layerId)
Emitted after a layer was removed from the registry.
A widget for selecting a projection.
void crsChanged(const QgsCoordinateReferenceSystem &)
Emitted when the selected CRS is changed.
@ CrsNotSet
Not set (hidden by default)
A store for object properties.
Definition: qgsproperty.h:230
@ StaticProperty
Static property (QgsStaticProperty)
Definition: qgsproperty.h:237
Type propertyType() const
Returns the property type.
The QgsProviderConnectionComboBox class is a combo box which displays the list of connections registe...
A combobox widget which displays the bands present in a raster layer.
void bandChanged(int band)
Emitted when the currently selected band changes.
static QString displayBandName(QgsRasterDataProvider *provider, int band)
Returns a user-friendly band name for the specified band.
Base class for raster data providers.
virtual int bandCount() const =0
Gets number of bands.
Represents a raster layer.
QgsRasterDataProvider * dataProvider() override
Returns the source data provider.
A rectangle specified with double values.
Definition: qgsrectangle.h:42
A combobox which lets the user select map scale from predefined list and highlights nearest to curren...
void scaleChanged(double scale)
Emitted when user has finished editing/selecting a new scale.
This class is a composition of two QSettings instances:
Definition: qgssettings.h:63
void setValue(const QString &key, const QVariant &value, QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.
Class that shows snapping marker on map canvas for the current snapping match.
The QgsSpinBox is a spin box with a clear button that will set the value to the defined clear value.
Definition: qgsspinbox.h:43
The QgsTimeEdit class is a QTimeEdit widget with the capability of setting/reading null date/times.
void timeValueChanged(const QTime &time)
Signal emitted whenever the time changes.
static Q_INVOKABLE QString toString(Qgis::DistanceUnit unit)
Returns a translated string representing a distance unit.
static Q_INVOKABLE double fromUnitToUnitFactor(Qgis::DistanceUnit fromUnit, Qgis::DistanceUnit toUnit)
Returns the conversion factor between the specified distance units.
static Q_INVOKABLE Qgis::DistanceUnitType unitType(Qgis::DistanceUnit unit)
Returns the type for a distance unit.
Represents a vector layer which manages a vector based data sets.
QgsFields fields() const FINAL
Returns the list of fields of this layer.
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into allowing algorithms to be written in pure substantial changes are required in order to port existing x Processing algorithms for QGIS x The most significant changes are outlined not GeoAlgorithm For algorithms which operate on features one by consider subclassing the QgsProcessingFeatureBasedAlgorithm class This class allows much of the boilerplate code for looping over features from a vector layer to be bypassed and instead requires implementation of a processFeature method Ensure that your algorithm(or algorithm 's parent class) implements the new pure virtual createInstance(self) call
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c
#define FALLTHROUGH
Definition: qgis.h:4120
double qgsRound(double number, int places)
Returns a double number, rounded (as close as possible) to the specified number of places.
Definition: qgis.h:3563
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:3509
const QgsField & field
Definition: qgsfield.h:501
const QgsCoordinateReferenceSystem & crs
QString proj
Proj coordinate operation description, for Proj >= 6.0 builds only.