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