QGIS API Documentation 3.41.0-Master (cea29feecf2)
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( "Raster" ), static_cast<int>( Qgis::ProcessingSourceType::Raster ) );
6702 mLayerTypeComboBox->addItem( tr( "Mesh" ), static_cast<int>( Qgis::ProcessingSourceType::Mesh ) );
6703 mLayerTypeComboBox->addItem( tr( "Plugin" ), static_cast<int>( Qgis::ProcessingSourceType::Plugin ) );
6704 mLayerTypeComboBox->addItem( tr( "Point Cloud" ), static_cast<int>( Qgis::ProcessingSourceType::PointCloud ) );
6705 mLayerTypeComboBox->addItem( tr( "Annotation" ), static_cast<int>( Qgis::ProcessingSourceType::Annotation ) );
6706
6707 if ( const QgsProcessingParameterMapLayer *layerParam = dynamic_cast<const QgsProcessingParameterMapLayer *>( definition ) )
6708 {
6709 for ( int i : layerParam->dataTypes() )
6710 {
6711 mLayerTypeComboBox->setItemCheckState( mLayerTypeComboBox->findData( i ), Qt::Checked );
6712 }
6713 }
6714
6715 vlayout->addWidget( mLayerTypeComboBox );
6716
6717 setLayout( vlayout );
6718}
6719
6720QgsProcessingParameterDefinition *QgsProcessingMapLayerParameterDefinitionWidget::createParameter( const QString &name, const QString &description, Qgis::ProcessingParameterFlags flags ) const
6721{
6722 QList<int> dataTypes;
6723 for ( const QVariant &v : mLayerTypeComboBox->checkedItemsData() )
6724 dataTypes << v.toInt();
6725
6726 auto param = std::make_unique<QgsProcessingParameterMapLayer>( name, description );
6727 param->setDataTypes( dataTypes );
6728 param->setFlags( flags );
6729 return param.release();
6730}
6731
6732QgsProcessingMapLayerWidgetWrapper::QgsProcessingMapLayerWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
6733 : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
6734{
6735}
6736
6737QWidget *QgsProcessingMapLayerWidgetWrapper::createWidget()
6738{
6739 mComboBox = new QgsProcessingMapLayerComboBox( parameterDefinition(), type() );
6740
6741 switch ( type() )
6742 {
6745 break;
6747 mComboBox->setEditable( true );
6748 break;
6749 }
6750
6751 mComboBox->setToolTip( parameterDefinition()->toolTip() );
6752
6753 connect( mComboBox, &QgsProcessingMapLayerComboBox::valueChanged, this, [=]() {
6754 if ( mBlockSignals )
6755 return;
6756
6757 emit widgetValueHasChanged( this );
6758 } );
6759
6760 setWidgetContext( widgetContext() );
6761 return mComboBox;
6762}
6763
6764void QgsProcessingMapLayerWidgetWrapper::setWidgetContext( const QgsProcessingParameterWidgetContext &context )
6765{
6767 if ( mComboBox )
6768 {
6769 mComboBox->setWidgetContext( context );
6770
6771 if ( !( parameterDefinition()->flags() & Qgis::ProcessingParameterFlag::Optional ) )
6772 {
6773 // non optional parameter -- if no default value set, default to active layer
6774 if ( !parameterDefinition()->defaultValueForGui().isValid() )
6775 mComboBox->setLayer( context.activeLayer() );
6776 }
6777 }
6778}
6779
6780void QgsProcessingMapLayerWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
6781{
6782 if ( mComboBox )
6783 mComboBox->setValue( value, context );
6784}
6785
6786QVariant QgsProcessingMapLayerWidgetWrapper::widgetValue() const
6787{
6788 return mComboBox ? mComboBox->value() : QVariant();
6789}
6790
6791QStringList QgsProcessingMapLayerWidgetWrapper::compatibleParameterTypes() const
6792{
6793 return QStringList()
6802}
6803
6804QStringList QgsProcessingMapLayerWidgetWrapper::compatibleOutputTypes() const
6805{
6806 return QStringList()
6813}
6814
6815QString QgsProcessingMapLayerWidgetWrapper::modelerExpressionFormatString() const
6816{
6817 return tr( "path to a map layer" );
6818}
6819
6820Qgis::ProcessingModelChildParameterSource QgsProcessingMapLayerWidgetWrapper::defaultModelSource( const QgsProcessingParameterDefinition *parameter ) const
6821{
6822 // non-optional layer sources default to a matching model input layer, but optional layer parameters
6823 // should default to static values. We don't want all optional layer parameters to have values set by default!
6824 if ( !( parameter->flags() & Qgis::ProcessingParameterFlag::Optional ) )
6825 {
6827 }
6828 else
6829 {
6831 }
6832}
6833
6834QString QgsProcessingMapLayerWidgetWrapper::parameterType() const
6835{
6837}
6838
6839QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingMapLayerWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
6840{
6841 return new QgsProcessingMapLayerWidgetWrapper( parameter, type );
6842}
6843
6844QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingMapLayerWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
6845{
6846 return new QgsProcessingMapLayerParameterDefinitionWidget( context, widgetContext, definition, algorithm );
6847}
6848
6849
6850//
6851// QgsProcessingRasterLayerWidgetWrapper
6852//
6853
6854QgsProcessingRasterLayerWidgetWrapper::QgsProcessingRasterLayerWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
6855 : QgsProcessingMapLayerWidgetWrapper( parameter, type, parent )
6856{
6857}
6858
6859QStringList QgsProcessingRasterLayerWidgetWrapper::compatibleParameterTypes() const
6860{
6861 return QStringList()
6866}
6867
6868QStringList QgsProcessingRasterLayerWidgetWrapper::compatibleOutputTypes() const
6869{
6870 return QStringList()
6876}
6877
6878QString QgsProcessingRasterLayerWidgetWrapper::modelerExpressionFormatString() const
6879{
6880 return tr( "path to a raster layer" );
6881}
6882
6883QString QgsProcessingRasterLayerWidgetWrapper::parameterType() const
6884{
6886}
6887
6888QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingRasterLayerWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
6889{
6890 return new QgsProcessingRasterLayerWidgetWrapper( parameter, type );
6891}
6892
6893QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingRasterLayerWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
6894{
6895 Q_UNUSED( context );
6896 Q_UNUSED( widgetContext );
6897 Q_UNUSED( definition );
6898 Q_UNUSED( algorithm );
6899
6900 return nullptr;
6901}
6902
6903
6904//
6905// QgsProcessingVectorLayerWidgetWrapper
6906//
6907
6908QgsProcessingVectorLayerParameterDefinitionWidget::QgsProcessingVectorLayerParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
6909 : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
6910{
6911 QVBoxLayout *vlayout = new QVBoxLayout();
6912 vlayout->setContentsMargins( 0, 0, 0, 0 );
6913
6914 vlayout->addWidget( new QLabel( tr( "Geometry type" ) ) );
6915 mGeometryTypeComboBox = new QgsCheckableComboBox();
6916 mGeometryTypeComboBox->addItem( tr( "Geometry Not Required" ), static_cast<int>( Qgis::ProcessingSourceType::Vector ) );
6917 mGeometryTypeComboBox->addItem( tr( "Point" ), static_cast<int>( Qgis::ProcessingSourceType::VectorPoint ) );
6918 mGeometryTypeComboBox->addItem( tr( "Line" ), static_cast<int>( Qgis::ProcessingSourceType::VectorLine ) );
6919 mGeometryTypeComboBox->addItem( tr( "Polygon" ), static_cast<int>( Qgis::ProcessingSourceType::VectorPolygon ) );
6920 mGeometryTypeComboBox->addItem( tr( "Any Geometry Type" ), static_cast<int>( Qgis::ProcessingSourceType::VectorAnyGeometry ) );
6921
6922 if ( const QgsProcessingParameterVectorLayer *vectorParam = dynamic_cast<const QgsProcessingParameterVectorLayer *>( definition ) )
6923 {
6924 for ( int i : vectorParam->dataTypes() )
6925 {
6926 mGeometryTypeComboBox->setItemCheckState( mGeometryTypeComboBox->findData( i ), Qt::Checked );
6927 }
6928 }
6929
6930 vlayout->addWidget( mGeometryTypeComboBox );
6931
6932 setLayout( vlayout );
6933}
6934
6935QgsProcessingParameterDefinition *QgsProcessingVectorLayerParameterDefinitionWidget::createParameter( const QString &name, const QString &description, Qgis::ProcessingParameterFlags flags ) const
6936{
6937 QList<int> dataTypes;
6938 for ( const QVariant &v : mGeometryTypeComboBox->checkedItemsData() )
6939 dataTypes << v.toInt();
6940
6941 auto param = std::make_unique<QgsProcessingParameterVectorLayer>( name, description, dataTypes );
6942 param->setFlags( flags );
6943 return param.release();
6944}
6945
6946
6947QgsProcessingVectorLayerWidgetWrapper::QgsProcessingVectorLayerWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
6948 : QgsProcessingMapLayerWidgetWrapper( parameter, type, parent )
6949{
6950}
6951
6952QStringList QgsProcessingVectorLayerWidgetWrapper::compatibleParameterTypes() const
6953{
6954 return QStringList()
6959}
6960
6961QStringList QgsProcessingVectorLayerWidgetWrapper::compatibleOutputTypes() const
6962{
6963 return QStringList()
6969}
6970
6971QString QgsProcessingVectorLayerWidgetWrapper::modelerExpressionFormatString() const
6972{
6973 return tr( "path to a vector layer" );
6974}
6975
6976QList<int> QgsProcessingVectorLayerWidgetWrapper::compatibleDataTypes( const QgsProcessingParameterDefinition *parameter ) const
6977{
6978 if ( const QgsProcessingParameterVectorLayer *param = dynamic_cast<const QgsProcessingParameterVectorLayer *>( parameter ) )
6979 return param->dataTypes();
6980 else
6981 return QList<int>();
6982}
6983
6984QString QgsProcessingVectorLayerWidgetWrapper::parameterType() const
6985{
6987}
6988
6989QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingVectorLayerWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
6990{
6991 return new QgsProcessingVectorLayerWidgetWrapper( parameter, type );
6992}
6993
6994QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingVectorLayerWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
6995{
6996 return new QgsProcessingVectorLayerParameterDefinitionWidget( context, widgetContext, definition, algorithm );
6997}
6998
6999
7000//
7001// QgsProcessingFeatureSourceLayerWidgetWrapper
7002//
7003
7004QgsProcessingFeatureSourceParameterDefinitionWidget::QgsProcessingFeatureSourceParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
7005 : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
7006{
7007 QVBoxLayout *vlayout = new QVBoxLayout();
7008 vlayout->setContentsMargins( 0, 0, 0, 0 );
7009
7010 vlayout->addWidget( new QLabel( tr( "Geometry type" ) ) );
7011 mGeometryTypeComboBox = new QgsCheckableComboBox();
7012 mGeometryTypeComboBox->addItem( tr( "Geometry Not Required" ), static_cast<int>( Qgis::ProcessingSourceType::Vector ) );
7013 mGeometryTypeComboBox->addItem( tr( "Point" ), static_cast<int>( Qgis::ProcessingSourceType::VectorPoint ) );
7014 mGeometryTypeComboBox->addItem( tr( "Line" ), static_cast<int>( Qgis::ProcessingSourceType::VectorLine ) );
7015 mGeometryTypeComboBox->addItem( tr( "Polygon" ), static_cast<int>( Qgis::ProcessingSourceType::VectorPolygon ) );
7016 mGeometryTypeComboBox->addItem( tr( "Any Geometry Type" ), static_cast<int>( Qgis::ProcessingSourceType::VectorAnyGeometry ) );
7017
7018 if ( const QgsProcessingParameterFeatureSource *sourceParam = dynamic_cast<const QgsProcessingParameterFeatureSource *>( definition ) )
7019 {
7020 for ( int i : sourceParam->dataTypes() )
7021 {
7022 mGeometryTypeComboBox->setItemCheckState( mGeometryTypeComboBox->findData( i ), Qt::Checked );
7023 }
7024 }
7025 else
7026 {
7027 mGeometryTypeComboBox->setItemCheckState( mGeometryTypeComboBox->findData( static_cast<int>( Qgis::ProcessingSourceType::VectorAnyGeometry ) ), Qt::Checked );
7028 }
7029
7030 vlayout->addWidget( mGeometryTypeComboBox );
7031
7032 setLayout( vlayout );
7033}
7034
7035QgsProcessingParameterDefinition *QgsProcessingFeatureSourceParameterDefinitionWidget::createParameter( const QString &name, const QString &description, Qgis::ProcessingParameterFlags flags ) const
7036{
7037 QList<int> dataTypes;
7038 for ( const QVariant &v : mGeometryTypeComboBox->checkedItemsData() )
7039 dataTypes << v.toInt();
7040
7041 auto param = std::make_unique<QgsProcessingParameterFeatureSource>( name, description, dataTypes );
7042 param->setFlags( flags );
7043 return param.release();
7044}
7045
7046QgsProcessingFeatureSourceWidgetWrapper::QgsProcessingFeatureSourceWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
7047 : QgsProcessingMapLayerWidgetWrapper( parameter, type, parent )
7048{
7049}
7050
7051QStringList QgsProcessingFeatureSourceWidgetWrapper::compatibleParameterTypes() const
7052{
7053 return QStringList()
7059}
7060
7061QStringList QgsProcessingFeatureSourceWidgetWrapper::compatibleOutputTypes() const
7062{
7063 return QStringList()
7069}
7070
7071QString QgsProcessingFeatureSourceWidgetWrapper::modelerExpressionFormatString() const
7072{
7073 return tr( "path to a vector layer" );
7074}
7075
7076QList<int> QgsProcessingFeatureSourceWidgetWrapper::compatibleDataTypes( const QgsProcessingParameterDefinition *parameter ) const
7077{
7078 if ( const QgsProcessingParameterFeatureSource *param = dynamic_cast<const QgsProcessingParameterFeatureSource *>( parameter ) )
7079 return param->dataTypes();
7080 else
7081 return QList<int>();
7082}
7083
7084QString QgsProcessingFeatureSourceWidgetWrapper::parameterType() const
7085{
7087}
7088
7089QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingFeatureSourceWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
7090{
7091 return new QgsProcessingFeatureSourceWidgetWrapper( parameter, type );
7092}
7093
7094QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingFeatureSourceWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
7095{
7096 return new QgsProcessingFeatureSourceParameterDefinitionWidget( context, widgetContext, definition, algorithm );
7097}
7098
7099//
7100// QgsProcessingMeshLayerWidgetWrapper
7101//
7102
7103QgsProcessingMeshLayerWidgetWrapper::QgsProcessingMeshLayerWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
7104 : QgsProcessingMapLayerWidgetWrapper( parameter, type, parent )
7105{
7106}
7107
7108QStringList QgsProcessingMeshLayerWidgetWrapper::compatibleParameterTypes() const
7109{
7110 return QStringList()
7115}
7116
7117QStringList QgsProcessingMeshLayerWidgetWrapper::compatibleOutputTypes() const
7118{
7119 return QStringList()
7121 // TODO << QgsProcessingOutputMeshLayer::typeName()
7125}
7126
7127QString QgsProcessingMeshLayerWidgetWrapper::modelerExpressionFormatString() const
7128{
7129 return tr( "path to a mesh layer" );
7130}
7131
7132QString QgsProcessingMeshLayerWidgetWrapper::parameterType() const
7133{
7135}
7136
7137QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingMeshLayerWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
7138{
7139 return new QgsProcessingMeshLayerWidgetWrapper( parameter, type );
7140}
7141
7142QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingMeshLayerWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
7143{
7144 Q_UNUSED( context );
7145 Q_UNUSED( widgetContext );
7146 Q_UNUSED( definition );
7147 Q_UNUSED( algorithm );
7148
7149 return nullptr;
7150}
7151
7152
7153//
7154// QgsProcessingRasterBandPanelWidget
7155//
7156
7157QgsProcessingRasterBandPanelWidget::QgsProcessingRasterBandPanelWidget( QWidget *parent, const QgsProcessingParameterBand *param )
7158 : QWidget( parent )
7159 , mParam( param )
7160{
7161 QHBoxLayout *hl = new QHBoxLayout();
7162 hl->setContentsMargins( 0, 0, 0, 0 );
7163
7164 mLineEdit = new QLineEdit();
7165 mLineEdit->setEnabled( false );
7166 hl->addWidget( mLineEdit, 1 );
7167
7168 mToolButton = new QToolButton();
7169 mToolButton->setText( QString( QChar( 0x2026 ) ) );
7170 hl->addWidget( mToolButton );
7171
7172 setLayout( hl );
7173
7174 if ( mParam )
7175 {
7176 mLineEdit->setText( tr( "%n band(s) selected", nullptr, 0 ) );
7177 }
7178
7179 connect( mToolButton, &QToolButton::clicked, this, &QgsProcessingRasterBandPanelWidget::showDialog );
7180}
7181
7182void QgsProcessingRasterBandPanelWidget::setBands( const QList<int> &bands )
7183{
7184 mBands = bands;
7185}
7186
7187void QgsProcessingRasterBandPanelWidget::setBandNames( const QHash<int, QString> &names )
7188{
7189 mBandNames = names;
7190}
7191
7192void QgsProcessingRasterBandPanelWidget::setValue( const QVariant &value )
7193{
7194 if ( value.isValid() )
7195 mValue = value.userType() == QMetaType::Type::QVariantList ? value.toList() : QVariantList() << value;
7196 else
7197 mValue.clear();
7198
7199 updateSummaryText();
7200 emit changed();
7201}
7202
7203void QgsProcessingRasterBandPanelWidget::showDialog()
7204{
7205 QVariantList availableOptions;
7206 availableOptions.reserve( mBands.size() );
7207 for ( int band : std::as_const( mBands ) )
7208 {
7209 availableOptions << band;
7210 }
7211
7213 if ( panel && panel->dockMode() )
7214 {
7215 QgsProcessingMultipleSelectionPanelWidget *widget = new QgsProcessingMultipleSelectionPanelWidget( availableOptions, mValue );
7216 widget->setPanelTitle( mParam->description() );
7217
7218 widget->setValueFormatter( [this]( const QVariant &v ) -> QString {
7219 int band = v.toInt();
7220 return mBandNames.contains( band ) ? mBandNames.value( band ) : v.toString();
7221 } );
7222
7223 connect( widget, &QgsProcessingMultipleSelectionPanelWidget::selectionChanged, this, [=]() {
7224 setValue( widget->selectedOptions() );
7225 } );
7226 connect( widget, &QgsProcessingMultipleSelectionPanelWidget::acceptClicked, widget, &QgsPanelWidget::acceptPanel );
7227 panel->openPanel( widget );
7228 }
7229 else
7230 {
7231 QgsProcessingMultipleSelectionDialog dlg( availableOptions, mValue, this, Qt::WindowFlags() );
7232
7233 dlg.setValueFormatter( [this]( const QVariant &v ) -> QString {
7234 int band = v.toInt();
7235 return mBandNames.contains( band ) ? mBandNames.value( band ) : v.toString();
7236 } );
7237 if ( dlg.exec() )
7238 {
7239 setValue( dlg.selectedOptions() );
7240 }
7241 }
7242}
7243
7244void QgsProcessingRasterBandPanelWidget::updateSummaryText()
7245{
7246 if ( mParam )
7247 mLineEdit->setText( tr( "%n band(s) selected", nullptr, mValue.count() ) );
7248}
7249
7250
7251//
7252// QgsProcessingBandWidgetWrapper
7253//
7254
7255QgsProcessingBandParameterDefinitionWidget::QgsProcessingBandParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
7256 : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
7257{
7258 QVBoxLayout *vlayout = new QVBoxLayout();
7259 vlayout->setContentsMargins( 0, 0, 0, 0 );
7260
7261 vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
7262
7263 mDefaultLineEdit = new QLineEdit();
7264 mDefaultLineEdit->setToolTip( tr( "Band number (separate bands with ; for multiple band parameters)" ) );
7265 if ( const QgsProcessingParameterBand *bandParam = dynamic_cast<const QgsProcessingParameterBand *>( definition ) )
7266 {
7267 const QList<int> bands = QgsProcessingParameters::parameterAsInts( bandParam, bandParam->defaultValueForGui(), context );
7268 QStringList defVal;
7269 for ( int b : bands )
7270 {
7271 defVal << QString::number( b );
7272 }
7273
7274 mDefaultLineEdit->setText( defVal.join( ';' ) );
7275 }
7276 vlayout->addWidget( mDefaultLineEdit );
7277
7278 vlayout->addWidget( new QLabel( tr( "Parent layer" ) ) );
7279 mParentLayerComboBox = new QComboBox();
7280
7281 QString initialParent;
7282 if ( const QgsProcessingParameterBand *bandParam = dynamic_cast<const QgsProcessingParameterBand *>( definition ) )
7283 initialParent = bandParam->parentLayerParameterName();
7284
7285 if ( auto *lModel = widgetContext.model() )
7286 {
7287 // populate combo box with other model input choices
7288 const QMap<QString, QgsProcessingModelParameter> components = lModel->parameterComponents();
7289 for ( auto it = components.constBegin(); it != components.constEnd(); ++it )
7290 {
7291 if ( const QgsProcessingParameterRasterLayer *definition = dynamic_cast<const QgsProcessingParameterRasterLayer *>( lModel->parameterDefinition( it.value().parameterName() ) ) )
7292 {
7293 mParentLayerComboBox->addItem( definition->description(), definition->name() );
7294 if ( !initialParent.isEmpty() && initialParent == definition->name() )
7295 {
7296 mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
7297 }
7298 }
7299 }
7300 }
7301
7302 if ( mParentLayerComboBox->count() == 0 && !initialParent.isEmpty() )
7303 {
7304 // if no parent candidates found, we just add the existing one as a placeholder
7305 mParentLayerComboBox->addItem( initialParent, initialParent );
7306 mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
7307 }
7308
7309 vlayout->addWidget( mParentLayerComboBox );
7310
7311 mAllowMultipleCheckBox = new QCheckBox( tr( "Allow multiple" ) );
7312 if ( const QgsProcessingParameterBand *bandParam = dynamic_cast<const QgsProcessingParameterBand *>( definition ) )
7313 mAllowMultipleCheckBox->setChecked( bandParam->allowMultiple() );
7314
7315 vlayout->addWidget( mAllowMultipleCheckBox );
7316 setLayout( vlayout );
7317}
7318
7319QgsProcessingParameterDefinition *QgsProcessingBandParameterDefinitionWidget::createParameter( const QString &name, const QString &description, Qgis::ProcessingParameterFlags flags ) const
7320{
7321 auto param = std::make_unique<QgsProcessingParameterBand>( name, description, mDefaultLineEdit->text().split( ';' ), mParentLayerComboBox->currentData().toString(), false, mAllowMultipleCheckBox->isChecked() );
7322 param->setFlags( flags );
7323 return param.release();
7324}
7325
7326QgsProcessingBandWidgetWrapper::QgsProcessingBandWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
7327 : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
7328{
7329}
7330
7331QWidget *QgsProcessingBandWidgetWrapper::createWidget()
7332{
7333 const QgsProcessingParameterBand *bandParam = dynamic_cast<const QgsProcessingParameterBand *>( parameterDefinition() );
7334 switch ( type() )
7335 {
7338 {
7339 if ( bandParam->allowMultiple() )
7340 {
7341 mPanel = new QgsProcessingRasterBandPanelWidget( nullptr, bandParam );
7342 mPanel->setToolTip( parameterDefinition()->toolTip() );
7343 connect( mPanel, &QgsProcessingRasterBandPanelWidget::changed, this, [=] {
7344 emit widgetValueHasChanged( this );
7345 } );
7346 return mPanel;
7347 }
7348 else
7349 {
7350 mComboBox = new QgsRasterBandComboBox();
7351 mComboBox->setShowNotSetOption( bandParam->flags() & Qgis::ProcessingParameterFlag::Optional );
7352
7353 mComboBox->setToolTip( parameterDefinition()->toolTip() );
7354 connect( mComboBox, &QgsRasterBandComboBox::bandChanged, this, [=]( int ) {
7355 emit widgetValueHasChanged( this );
7356 } );
7357 return mComboBox;
7358 }
7359 }
7360
7362 {
7363 mLineEdit = new QLineEdit();
7364 mLineEdit->setToolTip( QObject::tr( "Band number (separate bands with ; for multiple band parameters)" ) );
7365 connect( mLineEdit, &QLineEdit::textChanged, this, [=] {
7366 emit widgetValueHasChanged( this );
7367 } );
7368 return mLineEdit;
7369 }
7370 }
7371 return nullptr;
7372}
7373
7374void QgsProcessingBandWidgetWrapper::postInitialize( const QList<QgsAbstractProcessingParameterWidgetWrapper *> &wrappers )
7375{
7377 switch ( type() )
7378 {
7381 {
7382 for ( const QgsAbstractProcessingParameterWidgetWrapper *wrapper : wrappers )
7383 {
7384 if ( wrapper->parameterDefinition()->name() == static_cast<const QgsProcessingParameterBand *>( parameterDefinition() )->parentLayerParameterName() )
7385 {
7386 setParentLayerWrapperValue( wrapper );
7388 setParentLayerWrapperValue( wrapper );
7389 } );
7390 break;
7391 }
7392 }
7393 break;
7394 }
7395
7397 break;
7398 }
7399}
7400
7401void QgsProcessingBandWidgetWrapper::setParentLayerWrapperValue( const QgsAbstractProcessingParameterWidgetWrapper *parentWrapper )
7402{
7403 // evaluate value to layer
7404 QgsProcessingContext *context = nullptr;
7405 std::unique_ptr<QgsProcessingContext> tmpContext;
7406 if ( mProcessingContextGenerator )
7407 context = mProcessingContextGenerator->processingContext();
7408
7409 if ( !context )
7410 {
7411 tmpContext = std::make_unique<QgsProcessingContext>();
7412 context = tmpContext.get();
7413 }
7414
7415 QVariant value = parentWrapper->parameterValue();
7416
7417 QgsRasterLayer *layer = QgsProcessingParameters::parameterAsRasterLayer( parentWrapper->parameterDefinition(), value, *context );
7418 if ( layer && layer->isValid() )
7419 {
7420 // need to grab ownership of layer if required - otherwise layer may be deleted when context
7421 // goes out of scope
7422 std::unique_ptr<QgsMapLayer> ownedLayer( context->takeResultLayer( layer->id() ) );
7423 if ( ownedLayer && ownedLayer->type() == Qgis::LayerType::Raster )
7424 {
7425 mParentLayer.reset( qobject_cast<QgsRasterLayer *>( ownedLayer.release() ) );
7426 layer = mParentLayer.get();
7427 }
7428 else
7429 {
7430 // don't need ownership of this layer - it wasn't owned by context (so e.g. is owned by the project)
7431 }
7432
7433 if ( mComboBox )
7434 mComboBox->setLayer( layer );
7435 else if ( mPanel )
7436 {
7437 QgsRasterDataProvider *provider = layer->dataProvider();
7438 if ( provider && layer->isValid() )
7439 {
7440 //fill available bands
7441 int nBands = provider->bandCount();
7442 QList<int> bands;
7443 QHash<int, QString> bandNames;
7444 for ( int i = 1; i <= nBands; ++i )
7445 {
7446 bandNames.insert( i, QgsRasterBandComboBox::displayBandName( provider, i ) );
7447 bands << i;
7448 }
7449 mPanel->setBands( bands );
7450 mPanel->setBandNames( bandNames );
7451 }
7452 }
7453 }
7454 else
7455 {
7456 if ( mComboBox )
7457 mComboBox->setLayer( nullptr );
7458 else if ( mPanel )
7459 mPanel->setBands( QList<int>() );
7460
7461 if ( value.isValid() && widgetContext().messageBar() )
7462 {
7463 widgetContext().messageBar()->clearWidgets();
7464 widgetContext().messageBar()->pushMessage( QString(), QObject::tr( "Could not load selected layer/table. Dependent bands could not be populated" ), Qgis::MessageLevel::Info );
7465 }
7466 }
7467
7468 if ( parameterDefinition()->defaultValueForGui().isValid() )
7469 setWidgetValue( parameterDefinition()->defaultValueForGui(), *context );
7470}
7471
7472void QgsProcessingBandWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
7473{
7474 if ( mComboBox )
7475 {
7476 if ( !value.isValid() )
7477 mComboBox->setBand( -1 );
7478 else
7479 {
7480 const int v = QgsProcessingParameters::parameterAsInt( parameterDefinition(), value, context );
7481 mComboBox->setBand( v );
7482 }
7483 }
7484 else if ( mPanel )
7485 {
7486 QVariantList opts;
7487 if ( value.isValid() )
7488 {
7489 const QList<int> v = QgsProcessingParameters::parameterAsInts( parameterDefinition(), value, context );
7490 opts.reserve( v.size() );
7491 for ( int i : v )
7492 opts << i;
7493 }
7494 if ( mPanel )
7495 mPanel->setValue( value.isValid() ? opts : QVariant() );
7496 }
7497 else if ( mLineEdit )
7498 {
7499 const QgsProcessingParameterBand *bandParam = static_cast<const QgsProcessingParameterBand *>( parameterDefinition() );
7500 if ( bandParam->allowMultiple() )
7501 {
7502 const QList<int> v = QgsProcessingParameters::parameterAsInts( parameterDefinition(), value, context );
7503 QStringList opts;
7504 opts.reserve( v.size() );
7505 for ( int i : v )
7506 opts << QString::number( i );
7507 mLineEdit->setText( value.isValid() && !opts.empty() ? opts.join( ';' ) : QString() );
7508 }
7509 else
7510 {
7511 if ( value.isValid() )
7512 mLineEdit->setText( QString::number( QgsProcessingParameters::parameterAsInt( parameterDefinition(), value, context ) ) );
7513 else
7514 mLineEdit->clear();
7515 }
7516 }
7517}
7518
7519QVariant QgsProcessingBandWidgetWrapper::widgetValue() const
7520{
7521 if ( mComboBox )
7522 return mComboBox->currentBand() == -1 ? QVariant() : mComboBox->currentBand();
7523 else if ( mPanel )
7524 return !mPanel->value().toList().isEmpty() ? mPanel->value() : QVariant();
7525 else if ( mLineEdit )
7526 {
7527 const QgsProcessingParameterBand *bandParam = static_cast<const QgsProcessingParameterBand *>( parameterDefinition() );
7528 if ( bandParam->allowMultiple() )
7529 {
7530 const QStringList parts = mLineEdit->text().split( ';', Qt::SkipEmptyParts );
7531 QVariantList res;
7532 res.reserve( parts.count() );
7533 for ( const QString &s : parts )
7534 {
7535 bool ok = false;
7536 int band = s.toInt( &ok );
7537 if ( ok )
7538 res << band;
7539 }
7540 return res.isEmpty() ? QVariant() : res;
7541 }
7542 else
7543 {
7544 return mLineEdit->text().isEmpty() ? QVariant() : mLineEdit->text();
7545 }
7546 }
7547 else
7548 return QVariant();
7549}
7550
7551QStringList QgsProcessingBandWidgetWrapper::compatibleParameterTypes() const
7552{
7553 return QStringList()
7556}
7557
7558QStringList QgsProcessingBandWidgetWrapper::compatibleOutputTypes() const
7559{
7560 return QStringList()
7563}
7564
7565QString QgsProcessingBandWidgetWrapper::modelerExpressionFormatString() const
7566{
7567 return tr( "selected band numbers as an array of numbers, or semicolon separated string of options (e.g. '1;3')" );
7568}
7569
7570QString QgsProcessingBandWidgetWrapper::parameterType() const
7571{
7573}
7574
7575QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingBandWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
7576{
7577 return new QgsProcessingBandWidgetWrapper( parameter, type );
7578}
7579
7580QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingBandWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
7581{
7582 return new QgsProcessingBandParameterDefinitionWidget( context, widgetContext, definition, algorithm );
7583}
7584
7585//
7586// QgsProcessingMultipleLayerLineEdit
7587//
7588
7589QgsProcessingMultipleLayerLineEdit::QgsProcessingMultipleLayerLineEdit( QWidget *parent, const QgsProcessingParameterMultipleLayers *param )
7590 : QgsHighlightableLineEdit( parent )
7591 , mParam( param )
7592{
7593 setAcceptDrops( true );
7594}
7595
7596void QgsProcessingMultipleLayerLineEdit::dragEnterEvent( QDragEnterEvent *event )
7597{
7598 const QStringList uris = QgsProcessingMultipleInputPanelWidget::compatibleUrisFromMimeData( mParam, event->mimeData(), {} );
7599 if ( !uris.isEmpty() )
7600 {
7601 event->setDropAction( Qt::CopyAction );
7602 event->accept();
7603 setHighlighted( true );
7604 }
7605 else
7606 {
7607 event->ignore();
7608 }
7609}
7610
7611void QgsProcessingMultipleLayerLineEdit::dragLeaveEvent( QDragLeaveEvent *event )
7612{
7613 QgsHighlightableLineEdit::dragLeaveEvent( event );
7614 event->accept();
7615 setHighlighted( false );
7616}
7617
7618void QgsProcessingMultipleLayerLineEdit::dropEvent( QDropEvent *event )
7619{
7620 const QStringList uris = QgsProcessingMultipleInputPanelWidget::compatibleUrisFromMimeData( mParam, event->mimeData(), {} );
7621 if ( !uris.isEmpty() )
7622 {
7623 event->acceptProposedAction();
7624 QVariantList uriList;
7625 uriList.reserve( uris.size() );
7626 for ( const QString &uri : uris )
7627 uriList.append( QVariant( uri ) );
7628 emit layersDropped( uriList );
7629 }
7630
7631 setHighlighted( false );
7632}
7633
7634//
7635// QgsProcessingMultipleLayerPanelWidget
7636//
7637
7638QgsProcessingMultipleLayerPanelWidget::QgsProcessingMultipleLayerPanelWidget( QWidget *parent, const QgsProcessingParameterMultipleLayers *param )
7639 : QWidget( parent )
7640 , mParam( param )
7641{
7642 QHBoxLayout *hl = new QHBoxLayout();
7643 hl->setContentsMargins( 0, 0, 0, 0 );
7644
7645 mLineEdit = new QgsProcessingMultipleLayerLineEdit( nullptr, param );
7646 mLineEdit->setEnabled( true );
7647 mLineEdit->setReadOnly( true );
7648
7649 hl->addWidget( mLineEdit, 1 );
7650 connect( mLineEdit, &QgsProcessingMultipleLayerLineEdit::layersDropped, this, &QgsProcessingMultipleLayerPanelWidget::setValue );
7651
7652 mToolButton = new QToolButton();
7653 mToolButton->setText( QString( QChar( 0x2026 ) ) );
7654 hl->addWidget( mToolButton );
7655
7656 setLayout( hl );
7657
7658 if ( mParam )
7659 {
7660 mLineEdit->setText( tr( "%n input(s) selected", nullptr, 0 ) );
7661 }
7662
7663 connect( mToolButton, &QToolButton::clicked, this, &QgsProcessingMultipleLayerPanelWidget::showDialog );
7664}
7665
7666void QgsProcessingMultipleLayerPanelWidget::setValue( const QVariant &value )
7667{
7668 if ( value.isValid() )
7669 mValue = value.userType() == QMetaType::Type::QVariantList ? value.toList() : QVariantList() << value;
7670 else
7671 mValue.clear();
7672
7673 updateSummaryText();
7674 emit changed();
7675}
7676
7677void QgsProcessingMultipleLayerPanelWidget::setProject( QgsProject *project )
7678{
7679 mProject = project;
7680 if ( mProject )
7681 {
7682 connect( mProject, &QgsProject::layerRemoved, this, [&]( const QString &layerId ) {
7683 if ( mValue.removeAll( layerId ) )
7684 {
7685 updateSummaryText();
7686 emit changed();
7687 }
7688 } );
7689 }
7690}
7691
7692void QgsProcessingMultipleLayerPanelWidget::setModel( QgsProcessingModelAlgorithm *model, const QString &modelChildAlgorithmID )
7693{
7694 mModel = model;
7695 if ( !model )
7696 return;
7697
7698 switch ( mParam->layerType() )
7699 {
7701 mModelSources = model->availableSourcesForChild( modelChildAlgorithmID, QStringList() << QgsProcessingParameterFile::typeName(), QStringList() << QgsProcessingOutputFile::typeName() );
7702 break;
7703
7705 {
7707 break;
7708 }
7709
7711 {
7713 break;
7714 }
7715
7717 {
7719 break;
7720 }
7721
7723 {
7725 break;
7726 }
7727
7729 {
7730 mModelSources = model->availableSourcesForChild( modelChildAlgorithmID, QStringList() << QgsProcessingParameterAnnotationLayer::typeName() << QgsProcessingParameterMultipleLayers::typeName(), QStringList() << QgsProcessingOutputMapLayer::typeName() << QgsProcessingOutputMultipleLayers::typeName() );
7731 break;
7732 }
7733
7735 {
7736 mModelSources = model->availableSourcesForChild( modelChildAlgorithmID, QStringList() << QgsProcessingParameterMapLayer::typeName() << QgsProcessingParameterMultipleLayers::typeName(), QStringList() << QgsProcessingOutputMapLayer::typeName() << QgsProcessingOutputMultipleLayers::typeName() );
7737 break;
7738 }
7739
7741 {
7743 break;
7744 }
7745
7747 {
7749 break;
7750 }
7751
7753 {
7755 break;
7756 }
7757
7759 {
7761 break;
7762 }
7763
7765 {
7767 break;
7768 }
7769
7771 {
7773 // << QgsProcessingOutputMeshLayer::typeName()
7775 break;
7776 }
7777 }
7778}
7779
7780void QgsProcessingMultipleLayerPanelWidget::showDialog()
7781{
7783 if ( panel && panel->dockMode() )
7784 {
7785 QgsProcessingMultipleInputPanelWidget *widget = new QgsProcessingMultipleInputPanelWidget( mParam, mValue, mModelSources, mModel );
7786 widget->setPanelTitle( mParam->description() );
7787 widget->setProject( mProject );
7788 connect( widget, &QgsProcessingMultipleSelectionPanelWidget::selectionChanged, this, [=]() {
7789 setValue( widget->selectedOptions() );
7790 } );
7791 connect( widget, &QgsProcessingMultipleSelectionPanelWidget::acceptClicked, widget, &QgsPanelWidget::acceptPanel );
7792 panel->openPanel( widget );
7793 }
7794 else
7795 {
7796 QgsProcessingMultipleInputDialog dlg( mParam, mValue, mModelSources, mModel, this, Qt::WindowFlags() );
7797 dlg.setProject( mProject );
7798 if ( dlg.exec() )
7799 {
7800 setValue( dlg.selectedOptions() );
7801 }
7802 }
7803}
7804
7805void QgsProcessingMultipleLayerPanelWidget::updateSummaryText()
7806{
7807 if ( mParam )
7808 mLineEdit->setText( tr( "%n input(s) selected", nullptr, mValue.count() ) );
7809}
7810
7811//
7812// QgsProcessingMultipleLayerWidgetWrapper
7813//
7814
7815QgsProcessingMultipleLayerParameterDefinitionWidget::QgsProcessingMultipleLayerParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
7816 : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
7817{
7818 QVBoxLayout *vlayout = new QVBoxLayout();
7819 vlayout->setContentsMargins( 0, 0, 0, 0 );
7820
7821 vlayout->addWidget( new QLabel( tr( "Allowed layer type" ) ) );
7822 mLayerTypeComboBox = new QComboBox();
7823 mLayerTypeComboBox->addItem( tr( "Any Map Layer" ), static_cast<int>( Qgis::ProcessingSourceType::MapLayer ) );
7824 mLayerTypeComboBox->addItem( tr( "Vector (No Geometry Required)" ), static_cast<int>( Qgis::ProcessingSourceType::Vector ) );
7825 mLayerTypeComboBox->addItem( tr( "Vector (Point)" ), static_cast<int>( Qgis::ProcessingSourceType::VectorPoint ) );
7826 mLayerTypeComboBox->addItem( tr( "Vector (Line)" ), static_cast<int>( Qgis::ProcessingSourceType::VectorLine ) );
7827 mLayerTypeComboBox->addItem( tr( "Vector (Polygon)" ), static_cast<int>( Qgis::ProcessingSourceType::VectorPolygon ) );
7828 mLayerTypeComboBox->addItem( tr( "Any Geometry Type" ), static_cast<int>( Qgis::ProcessingSourceType::VectorAnyGeometry ) );
7829 mLayerTypeComboBox->addItem( tr( "Raster" ), static_cast<int>( Qgis::ProcessingSourceType::Raster ) );
7830 mLayerTypeComboBox->addItem( tr( "File" ), static_cast<int>( Qgis::ProcessingSourceType::File ) );
7831 mLayerTypeComboBox->addItem( tr( "Mesh" ), static_cast<int>( Qgis::ProcessingSourceType::Mesh ) );
7832 mLayerTypeComboBox->addItem( tr( "Plugin" ), static_cast<int>( Qgis::ProcessingSourceType::Plugin ) );
7833 mLayerTypeComboBox->addItem( tr( "Point Cloud" ), static_cast<int>( Qgis::ProcessingSourceType::PointCloud ) );
7834 mLayerTypeComboBox->addItem( tr( "Annotation" ), static_cast<int>( Qgis::ProcessingSourceType::Annotation ) );
7835 if ( const QgsProcessingParameterMultipleLayers *layersParam = dynamic_cast<const QgsProcessingParameterMultipleLayers *>( definition ) )
7836 mLayerTypeComboBox->setCurrentIndex( mLayerTypeComboBox->findData( static_cast<int>( layersParam->layerType() ) ) );
7837
7838 vlayout->addWidget( mLayerTypeComboBox );
7839 setLayout( vlayout );
7840}
7841
7842QgsProcessingParameterDefinition *QgsProcessingMultipleLayerParameterDefinitionWidget::createParameter( const QString &name, const QString &description, Qgis::ProcessingParameterFlags flags ) const
7843{
7844 auto param = std::make_unique<QgsProcessingParameterMultipleLayers>( name, description, static_cast<Qgis::ProcessingSourceType>( mLayerTypeComboBox->currentData().toInt() ) );
7845 param->setFlags( flags );
7846 return param.release();
7847}
7848
7849QgsProcessingMultipleLayerWidgetWrapper::QgsProcessingMultipleLayerWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
7850 : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
7851{
7852}
7853
7854QWidget *QgsProcessingMultipleLayerWidgetWrapper::createWidget()
7855{
7856 const QgsProcessingParameterMultipleLayers *layerParam = dynamic_cast<const QgsProcessingParameterMultipleLayers *>( parameterDefinition() );
7857
7858 mPanel = new QgsProcessingMultipleLayerPanelWidget( nullptr, layerParam );
7859 mPanel->setToolTip( parameterDefinition()->toolTip() );
7860 mPanel->setProject( widgetContext().project() );
7861 if ( type() == QgsProcessingGui::Modeler )
7862 mPanel->setModel( widgetContext().model(), widgetContext().modelChildAlgorithmId() );
7863 connect( mPanel, &QgsProcessingMultipleLayerPanelWidget::changed, this, [=] {
7864 emit widgetValueHasChanged( this );
7865 } );
7866 return mPanel;
7867}
7868
7869void QgsProcessingMultipleLayerWidgetWrapper::setWidgetContext( const QgsProcessingParameterWidgetContext &context )
7870{
7872 if ( mPanel )
7873 {
7874 mPanel->setProject( context.project() );
7875 if ( type() == QgsProcessingGui::Modeler )
7876 mPanel->setModel( widgetContext().model(), widgetContext().modelChildAlgorithmId() );
7877 }
7878}
7879
7880void QgsProcessingMultipleLayerWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
7881{
7882 if ( mPanel )
7883 {
7884 QVariantList opts;
7885 if ( value.isValid() )
7886 {
7887 const QList<QgsMapLayer *> v = QgsProcessingParameters::parameterAsLayerList( parameterDefinition(), value, context );
7888 opts.reserve( v.size() );
7889 for ( const QgsMapLayer *l : v )
7890 opts << l->source();
7891 }
7892
7893 for ( const QVariant &v : value.toList() )
7894 {
7895 if ( v.userType() == qMetaTypeId<QgsProcessingModelChildParameterSource>() )
7896 {
7897 const QgsProcessingModelChildParameterSource source = v.value<QgsProcessingModelChildParameterSource>();
7898 opts << QVariant::fromValue( source );
7899 }
7900 }
7901
7902 if ( mPanel )
7903 mPanel->setValue( value.isValid() ? opts : QVariant() );
7904 }
7905}
7906
7907QVariant QgsProcessingMultipleLayerWidgetWrapper::widgetValue() const
7908{
7909 if ( mPanel )
7910 return !mPanel->value().toList().isEmpty() ? mPanel->value() : QVariant();
7911 else
7912 return QVariant();
7913}
7914
7915QStringList QgsProcessingMultipleLayerWidgetWrapper::compatibleParameterTypes() const
7916{
7917 return QStringList()
7926}
7927
7928QStringList QgsProcessingMultipleLayerWidgetWrapper::compatibleOutputTypes() const
7929{
7930 return QStringList()
7938}
7939
7940QString QgsProcessingMultipleLayerWidgetWrapper::modelerExpressionFormatString() const
7941{
7942 return tr( "an array of layer paths, or semicolon separated string of layer paths" );
7943}
7944
7945QString QgsProcessingMultipleLayerWidgetWrapper::parameterType() const
7946{
7948}
7949
7950QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingMultipleLayerWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
7951{
7952 return new QgsProcessingMultipleLayerWidgetWrapper( parameter, type );
7953}
7954
7955QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingMultipleLayerWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
7956{
7957 return new QgsProcessingMultipleLayerParameterDefinitionWidget( context, widgetContext, definition, algorithm );
7958}
7959
7960
7961//
7962// QgsProcessingPointCloudLayerWidgetWrapper
7963//
7964
7965QgsProcessingPointCloudLayerWidgetWrapper::QgsProcessingPointCloudLayerWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
7966 : QgsProcessingMapLayerWidgetWrapper( parameter, type, parent )
7967{
7968}
7969
7970QStringList QgsProcessingPointCloudLayerWidgetWrapper::compatibleParameterTypes() const
7971{
7972 return QStringList()
7977}
7978
7979QStringList QgsProcessingPointCloudLayerWidgetWrapper::compatibleOutputTypes() const
7980{
7981 return QStringList()
7983 // TODO << QgsProcessingOutputPointCloudLayer::typeName()
7987}
7988
7989QString QgsProcessingPointCloudLayerWidgetWrapper::modelerExpressionFormatString() const
7990{
7991 return tr( "path to a point cloud layer" );
7992}
7993
7994QString QgsProcessingPointCloudLayerWidgetWrapper::parameterType() const
7995{
7997}
7998
7999QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingPointCloudLayerWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
8000{
8001 return new QgsProcessingPointCloudLayerWidgetWrapper( parameter, type );
8002}
8003
8004QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingPointCloudLayerWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
8005{
8006 Q_UNUSED( context );
8007 Q_UNUSED( widgetContext );
8008 Q_UNUSED( definition );
8009 Q_UNUSED( algorithm );
8010
8011 return nullptr;
8012}
8013
8014
8015//
8016// QgsProcessingAnnotationLayerWidgetWrapper
8017//
8018
8019QgsProcessingAnnotationLayerWidgetWrapper::QgsProcessingAnnotationLayerWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
8020 : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
8021{
8022}
8023
8024QStringList QgsProcessingAnnotationLayerWidgetWrapper::compatibleParameterTypes() const
8025{
8026 return QStringList()
8031}
8032
8033QStringList QgsProcessingAnnotationLayerWidgetWrapper::compatibleOutputTypes() const
8034{
8035 return QStringList()
8039}
8040
8041QString QgsProcessingAnnotationLayerWidgetWrapper::modelerExpressionFormatString() const
8042{
8043 return tr( "name of an annotation layer, or \"main\" for the main annotation layer" );
8044}
8045
8046QString QgsProcessingAnnotationLayerWidgetWrapper::parameterType() const
8047{
8049}
8050
8051QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingAnnotationLayerWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
8052{
8053 return new QgsProcessingAnnotationLayerWidgetWrapper( parameter, type );
8054}
8055
8056QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingAnnotationLayerWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
8057{
8058 Q_UNUSED( context );
8059 Q_UNUSED( widgetContext );
8060 Q_UNUSED( definition );
8061 Q_UNUSED( algorithm );
8062
8063 return nullptr;
8064}
8065
8066void QgsProcessingAnnotationLayerWidgetWrapper::setWidgetContext( const QgsProcessingParameterWidgetContext &context )
8067{
8069 if ( mComboBox )
8070 {
8071 if ( mWidgetContext.project() )
8072 mComboBox->setAdditionalLayers( { mWidgetContext.project()->mainAnnotationLayer() } );
8073 }
8074}
8075
8076QWidget *QgsProcessingAnnotationLayerWidgetWrapper::createWidget()
8077{
8078 mComboBox = new QgsMapLayerComboBox();
8079 mComboBox->setFilters( Qgis::LayerFilter::AnnotationLayer );
8080
8081 switch ( type() )
8082 {
8085 break;
8087 mComboBox->setEditable( true );
8088 break;
8089 }
8090
8091 mComboBox->setToolTip( parameterDefinition()->toolTip() );
8092
8093 if ( mWidgetContext.project() )
8094 mComboBox->setAdditionalLayers( { mWidgetContext.project()->mainAnnotationLayer() } );
8095
8096 if ( parameterDefinition()->flags() & Qgis::ProcessingParameterFlag::Optional )
8097 mComboBox->setAllowEmptyLayer( true );
8098
8099 connect( mComboBox, &QgsMapLayerComboBox::layerChanged, this, [=]() {
8100 if ( mBlockSignals )
8101 return;
8102
8103 emit widgetValueHasChanged( this );
8104 } );
8105
8106 setWidgetContext( widgetContext() );
8107 return mComboBox;
8108}
8109
8110void QgsProcessingAnnotationLayerWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
8111{
8112 if ( mComboBox )
8113 {
8114 if ( !value.isValid() && parameterDefinition()->flags() & Qgis::ProcessingParameterFlag::Optional )
8115 {
8116 mComboBox->setLayer( nullptr );
8117 return;
8118 }
8119
8120 QVariant val = value;
8121 if ( val.userType() == qMetaTypeId<QgsProperty>() )
8122 {
8123 if ( val.value<QgsProperty>().propertyType() == Qgis::PropertyType::Static )
8124 {
8125 val = val.value<QgsProperty>().staticValue();
8126 }
8127 else
8128 {
8129 val = val.value<QgsProperty>().valueAsString( context.expressionContext(), parameterDefinition()->defaultValueForGui().toString() );
8130 }
8131 }
8132
8133 QgsMapLayer *layer = qobject_cast<QgsMapLayer *>( val.value<QObject *>() );
8134 if ( !layer && val.userType() == QMetaType::Type::QString )
8135 {
8137 }
8138
8139 if ( layer )
8140 {
8141 mComboBox->setLayer( layer );
8142 }
8143 }
8144}
8145
8146QVariant QgsProcessingAnnotationLayerWidgetWrapper::widgetValue() const
8147{
8148 return mComboBox && mComboBox->currentLayer() ? ( mWidgetContext.project() ? ( mComboBox->currentLayer() == mWidgetContext.project()->mainAnnotationLayer() ? QStringLiteral( "main" ) : mComboBox->currentLayer()->id() ) : mComboBox->currentLayer()->id() )
8149 : QVariant();
8150}
8151
8152
8153//
8154// QgsProcessingPointCloudAttributePanelWidget
8155//
8156
8157QgsProcessingPointCloudAttributePanelWidget::QgsProcessingPointCloudAttributePanelWidget( QWidget *parent, const QgsProcessingParameterPointCloudAttribute *param )
8158 : QWidget( parent )
8159 , mParam( param )
8160{
8161 QHBoxLayout *hl = new QHBoxLayout();
8162 hl->setContentsMargins( 0, 0, 0, 0 );
8163
8164 mLineEdit = new QLineEdit();
8165 mLineEdit->setEnabled( false );
8166 hl->addWidget( mLineEdit, 1 );
8167
8168 mToolButton = new QToolButton();
8169 mToolButton->setText( QString( QChar( 0x2026 ) ) );
8170 hl->addWidget( mToolButton );
8171
8172 setLayout( hl );
8173
8174 if ( mParam )
8175 {
8176 mLineEdit->setText( tr( "%n attribute(s) selected", nullptr, 0 ) );
8177 }
8178
8179 connect( mToolButton, &QToolButton::clicked, this, &QgsProcessingPointCloudAttributePanelWidget::showDialog );
8180}
8181
8182void QgsProcessingPointCloudAttributePanelWidget::setAttributes( const QgsPointCloudAttributeCollection &attributes )
8183{
8184 mAttributes = attributes;
8185}
8186
8187void QgsProcessingPointCloudAttributePanelWidget::setValue( const QVariant &value )
8188{
8189 if ( value.isValid() )
8190 mValue = value.userType() == QMetaType::Type::QVariantList ? value.toList() : QVariantList() << value;
8191 else
8192 mValue.clear();
8193
8194 updateSummaryText();
8195 emit changed();
8196}
8197
8198void QgsProcessingPointCloudAttributePanelWidget::showDialog()
8199{
8200 QVariantList availableOptions;
8201 availableOptions.reserve( mAttributes.count() );
8202 const QVector<QgsPointCloudAttribute> attributes = mAttributes.attributes();
8203 for ( const QgsPointCloudAttribute &attr : attributes )
8204 {
8205 availableOptions << attr.name();
8206 }
8207
8209 if ( panel && panel->dockMode() )
8210 {
8211 QgsProcessingMultipleSelectionPanelWidget *widget = new QgsProcessingMultipleSelectionPanelWidget( availableOptions, mValue );
8212 widget->setPanelTitle( mParam->description() );
8213
8214 widget->setValueFormatter( []( const QVariant &v ) -> QString {
8215 return v.toString();
8216 } );
8217
8218 connect( widget, &QgsProcessingMultipleSelectionPanelWidget::selectionChanged, this, [=]() {
8219 setValue( widget->selectedOptions() );
8220 } );
8221 connect( widget, &QgsProcessingMultipleSelectionPanelWidget::acceptClicked, widget, &QgsPanelWidget::acceptPanel );
8222 panel->openPanel( widget );
8223 }
8224 else
8225 {
8226 QgsProcessingMultipleSelectionDialog dlg( availableOptions, mValue, this, Qt::WindowFlags() );
8227
8228 dlg.setValueFormatter( []( const QVariant &v ) -> QString {
8229 return v.toString();
8230 } );
8231 if ( dlg.exec() )
8232 {
8233 setValue( dlg.selectedOptions() );
8234 }
8235 }
8236}
8237
8238void QgsProcessingPointCloudAttributePanelWidget::updateSummaryText()
8239{
8240 if ( !mParam )
8241 return;
8242
8243 if ( mValue.empty() )
8244 {
8245 mLineEdit->setText( tr( "%n attribute(s) selected", nullptr, 0 ) );
8246 }
8247 else
8248 {
8249 QStringList values;
8250 values.reserve( mValue.size() );
8251 for ( const QVariant &val : std::as_const( mValue ) )
8252 {
8253 values << val.toString();
8254 }
8255
8256 const QString concatenated = values.join( tr( "," ) );
8257 if ( concatenated.length() < 100 )
8258 mLineEdit->setText( concatenated );
8259 else
8260 mLineEdit->setText( tr( "%n attribute(s) selected", nullptr, mValue.count() ) );
8261 }
8262}
8263
8264
8265//
8266// QgsProcessingPointCloudAttributeWidgetWrapper
8267//
8268
8269QgsProcessingPointCloudAttributeParameterDefinitionWidget::QgsProcessingPointCloudAttributeParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
8270 : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
8271{
8272 QVBoxLayout *vlayout = new QVBoxLayout();
8273 vlayout->setContentsMargins( 0, 0, 0, 0 );
8274
8275 vlayout->addWidget( new QLabel( tr( "Parent layer" ) ) );
8276 mParentLayerComboBox = new QComboBox();
8277
8278 QString initialParent;
8279 if ( const QgsProcessingParameterPointCloudAttribute *attrParam = dynamic_cast<const QgsProcessingParameterPointCloudAttribute *>( definition ) )
8280 initialParent = attrParam->parentLayerParameterName();
8281
8282 if ( auto *lModel = widgetContext.model() )
8283 {
8284 // populate combo box with other model input choices
8285 const QMap<QString, QgsProcessingModelParameter> components = lModel->parameterComponents();
8286 for ( auto it = components.constBegin(); it != components.constEnd(); ++it )
8287 {
8288 if ( const QgsProcessingParameterPointCloudLayer *definition = dynamic_cast<const QgsProcessingParameterPointCloudLayer *>( lModel->parameterDefinition( it.value().parameterName() ) ) )
8289 {
8290 mParentLayerComboBox->addItem( definition->description(), definition->name() );
8291 if ( !initialParent.isEmpty() && initialParent == definition->name() )
8292 {
8293 mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
8294 }
8295 }
8296 }
8297 }
8298
8299 if ( mParentLayerComboBox->count() == 0 && !initialParent.isEmpty() )
8300 {
8301 // if no parent candidates found, we just add the existing one as a placeholder
8302 mParentLayerComboBox->addItem( initialParent, initialParent );
8303 mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
8304 }
8305
8306 vlayout->addWidget( mParentLayerComboBox );
8307
8308 mAllowMultipleCheckBox = new QCheckBox( tr( "Accept multiple attributes" ) );
8309 if ( const QgsProcessingParameterPointCloudAttribute *attrParam = dynamic_cast<const QgsProcessingParameterPointCloudAttribute *>( definition ) )
8310 mAllowMultipleCheckBox->setChecked( attrParam->allowMultiple() );
8311
8312 vlayout->addWidget( mAllowMultipleCheckBox );
8313
8314 mDefaultToAllCheckBox = new QCheckBox( tr( "Select all attributes by default" ) );
8315 mDefaultToAllCheckBox->setEnabled( mAllowMultipleCheckBox->isChecked() );
8316 if ( const QgsProcessingParameterPointCloudAttribute *attrParam = dynamic_cast<const QgsProcessingParameterPointCloudAttribute *>( definition ) )
8317 mDefaultToAllCheckBox->setChecked( attrParam->defaultToAllAttributes() );
8318
8319 vlayout->addWidget( mDefaultToAllCheckBox );
8320
8321 connect( mAllowMultipleCheckBox, &QCheckBox::stateChanged, this, [=] {
8322 mDefaultToAllCheckBox->setEnabled( mAllowMultipleCheckBox->isChecked() );
8323 } );
8324
8325 vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
8326
8327 mDefaultLineEdit = new QLineEdit();
8328 mDefaultLineEdit->setToolTip( tr( "Default attribute name, or ; separated list of attribute names for multiple attribute parameters" ) );
8329 if ( const QgsProcessingParameterPointCloudAttribute *attrParam = dynamic_cast<const QgsProcessingParameterPointCloudAttribute *>( definition ) )
8330 {
8331 const QStringList attributes = QgsProcessingParameters::parameterAsStrings( attrParam, attrParam->defaultValueForGui(), context );
8332 mDefaultLineEdit->setText( attributes.join( ';' ) );
8333 }
8334 vlayout->addWidget( mDefaultLineEdit );
8335
8336 setLayout( vlayout );
8337}
8338
8339QgsProcessingParameterDefinition *QgsProcessingPointCloudAttributeParameterDefinitionWidget::createParameter( const QString &name, const QString &description, Qgis::ProcessingParameterFlags flags ) const
8340{
8341 QVariant defaultValue;
8342 if ( !mDefaultLineEdit->text().trimmed().isEmpty() )
8343 {
8344 defaultValue = mDefaultLineEdit->text();
8345 }
8346 auto param = std::make_unique<QgsProcessingParameterPointCloudAttribute>( name, description, defaultValue, mParentLayerComboBox->currentData().toString(), mAllowMultipleCheckBox->isChecked(), false, mDefaultToAllCheckBox->isChecked() );
8347 param->setFlags( flags );
8348 return param.release();
8349}
8350
8351QgsProcessingPointCloudAttributeWidgetWrapper::QgsProcessingPointCloudAttributeWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
8352 : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
8353{
8354}
8355
8356QWidget *QgsProcessingPointCloudAttributeWidgetWrapper::createWidget()
8357{
8358 const QgsProcessingParameterPointCloudAttribute *attrParam = dynamic_cast<const QgsProcessingParameterPointCloudAttribute *>( parameterDefinition() );
8359 switch ( type() )
8360 {
8363 {
8364 if ( attrParam->allowMultiple() )
8365 {
8366 mPanel = new QgsProcessingPointCloudAttributePanelWidget( nullptr, attrParam );
8367 mPanel->setToolTip( parameterDefinition()->toolTip() );
8368 connect( mPanel, &QgsProcessingPointCloudAttributePanelWidget::changed, this, [=] {
8369 emit widgetValueHasChanged( this );
8370 } );
8371 return mPanel;
8372 }
8373 else
8374 {
8375 mComboBox = new QgsPointCloudAttributeComboBox();
8376 mComboBox->setAllowEmptyAttributeName( attrParam->flags() & Qgis::ProcessingParameterFlag::Optional );
8377 mComboBox->setToolTip( parameterDefinition()->toolTip() );
8378 connect( mComboBox, &QgsPointCloudAttributeComboBox::attributeChanged, this, [=]( const QString & ) {
8379 emit widgetValueHasChanged( this );
8380 } );
8381 return mComboBox;
8382 }
8383 }
8384
8386 {
8387 mLineEdit = new QLineEdit();
8388 mLineEdit->setToolTip( QObject::tr( "Name of attribute (separate attribute names with ; for multiple attribute parameters)" ) );
8389 connect( mLineEdit, &QLineEdit::textChanged, this, [=] {
8390 emit widgetValueHasChanged( this );
8391 } );
8392 return mLineEdit;
8393 }
8394 }
8395 return nullptr;
8396}
8397
8398void QgsProcessingPointCloudAttributeWidgetWrapper::postInitialize( const QList<QgsAbstractProcessingParameterWidgetWrapper *> &wrappers )
8399{
8401 switch ( type() )
8402 {
8405 {
8406 for ( const QgsAbstractProcessingParameterWidgetWrapper *wrapper : wrappers )
8407 {
8408 if ( wrapper->parameterDefinition()->name() == static_cast<const QgsProcessingParameterPointCloudAttribute *>( parameterDefinition() )->parentLayerParameterName() )
8409 {
8410 setParentLayerWrapperValue( wrapper );
8412 setParentLayerWrapperValue( wrapper );
8413 } );
8414 break;
8415 }
8416 }
8417 break;
8418 }
8419
8421 break;
8422 }
8423}
8424
8425void QgsProcessingPointCloudAttributeWidgetWrapper::setParentLayerWrapperValue( const QgsAbstractProcessingParameterWidgetWrapper *parentWrapper )
8426{
8427 // evaluate value to layer
8428 QgsProcessingContext *context = nullptr;
8429 std::unique_ptr<QgsProcessingContext> tmpContext;
8430 if ( mProcessingContextGenerator )
8431 context = mProcessingContextGenerator->processingContext();
8432
8433 if ( !context )
8434 {
8435 tmpContext = std::make_unique<QgsProcessingContext>();
8436 context = tmpContext.get();
8437 }
8438
8439 QVariant value = parentWrapper->parameterValue();
8440
8442 if ( layer && layer->isValid() )
8443 {
8444 // need to grab ownership of layer if required - otherwise layer may be deleted when context
8445 // goes out of scope
8446 std::unique_ptr<QgsMapLayer> ownedLayer( context->takeResultLayer( layer->id() ) );
8447 if ( ownedLayer && ownedLayer->type() == Qgis::LayerType::PointCloud )
8448 {
8449 mParentLayer.reset( qobject_cast<QgsPointCloudLayer *>( ownedLayer.release() ) );
8450 layer = mParentLayer.get();
8451 }
8452 else
8453 {
8454 // don't need ownership of this layer - it wasn't owned by context (so e.g. is owned by the project)
8455 }
8456
8457 if ( mComboBox )
8458 mComboBox->setLayer( layer );
8459 else if ( mPanel )
8460 {
8461 mPanel->setAttributes( layer->attributes() );
8462 }
8463 }
8464 else
8465 {
8466 if ( mComboBox )
8467 {
8468 mComboBox->setLayer( nullptr );
8469 }
8470 else if ( mPanel )
8471 mPanel->setAttributes( QgsPointCloudAttributeCollection() );
8472
8473 if ( value.isValid() && widgetContext().messageBar() )
8474 {
8475 widgetContext().messageBar()->clearWidgets();
8476 widgetContext().messageBar()->pushMessage( QString(), QObject::tr( "Could not load selected layer/table. Dependent attributes could not be populated" ), Qgis::MessageLevel::Info );
8477 }
8478 }
8479
8480 const QgsProcessingParameterPointCloudAttribute *attrParam = static_cast<const QgsProcessingParameterPointCloudAttribute *>( parameterDefinition() );
8481 if ( mPanel && attrParam->defaultToAllAttributes() )
8482 {
8483 QVariantList val;
8484 val.reserve( mPanel->attributes().attributes().size() );
8485 for ( const QgsPointCloudAttribute &attr : mPanel->attributes().attributes() )
8486 val << attr.name();
8487 setWidgetValue( val, *context );
8488 }
8489 else if ( attrParam->defaultValueForGui().isValid() )
8490 setWidgetValue( parameterDefinition()->defaultValueForGui(), *context );
8491}
8492
8493void QgsProcessingPointCloudAttributeWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
8494{
8495 if ( mComboBox )
8496 {
8497 if ( !value.isValid() )
8498 mComboBox->setAttribute( QString() );
8499 else
8500 {
8501 const QString v = QgsProcessingParameters::parameterAsString( parameterDefinition(), value, context );
8502 mComboBox->setAttribute( v );
8503 }
8504 }
8505 else if ( mPanel )
8506 {
8507 QVariantList opts;
8508 if ( value.isValid() )
8509 {
8510 const QStringList v = QgsProcessingParameters::parameterAsStrings( parameterDefinition(), value, context );
8511 opts.reserve( v.size() );
8512 for ( const QString &i : v )
8513 opts << i;
8514 }
8515 if ( mPanel )
8516 mPanel->setValue( opts );
8517 }
8518 else if ( mLineEdit )
8519 {
8520 const QgsProcessingParameterPointCloudAttribute *attrParam = static_cast<const QgsProcessingParameterPointCloudAttribute *>( parameterDefinition() );
8521 if ( attrParam->allowMultiple() )
8522 {
8523 const QStringList v = QgsProcessingParameters::parameterAsStrings( parameterDefinition(), value, context );
8524 mLineEdit->setText( v.join( ';' ) );
8525 }
8526 else
8527 {
8528 mLineEdit->setText( QgsProcessingParameters::parameterAsString( parameterDefinition(), value, context ) );
8529 }
8530 }
8531}
8532
8533QVariant QgsProcessingPointCloudAttributeWidgetWrapper::widgetValue() const
8534{
8535 if ( mComboBox )
8536 return mComboBox->currentAttribute();
8537 else if ( mPanel )
8538 return mPanel->value();
8539 else if ( mLineEdit )
8540 {
8541 const QgsProcessingParameterPointCloudAttribute *attrParam = static_cast<const QgsProcessingParameterPointCloudAttribute *>( parameterDefinition() );
8542 if ( attrParam->allowMultiple() )
8543 {
8544 return mLineEdit->text().split( ';' );
8545 }
8546 else
8547 return mLineEdit->text();
8548 }
8549 else
8550 return QVariant();
8551}
8552
8553QStringList QgsProcessingPointCloudAttributeWidgetWrapper::compatibleParameterTypes() const
8554{
8555 return QStringList()
8558}
8559
8560QStringList QgsProcessingPointCloudAttributeWidgetWrapper::compatibleOutputTypes() const
8561{
8562 return QStringList()
8565}
8566
8567QString QgsProcessingPointCloudAttributeWidgetWrapper::modelerExpressionFormatString() const
8568{
8569 return tr( "selected attribute names as an array of names, or semicolon separated string of options (e.g. 'X;Intensity')" );
8570}
8571
8572QString QgsProcessingPointCloudAttributeWidgetWrapper::parameterType() const
8573{
8575}
8576
8577QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingPointCloudAttributeWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
8578{
8579 return new QgsProcessingPointCloudAttributeWidgetWrapper( parameter, type );
8580}
8581
8582QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingPointCloudAttributeWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
8583{
8584 return new QgsProcessingPointCloudAttributeParameterDefinitionWidget( context, widgetContext, definition, algorithm );
8585}
8586
8587
8588//
8589// QgsProcessingOutputWidgetWrapper
8590//
8591
8592QgsProcessingOutputWidgetWrapper::QgsProcessingOutputWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
8593 : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
8594{
8595}
8596
8597QWidget *QgsProcessingOutputWidgetWrapper::createWidget()
8598{
8599 const QgsProcessingDestinationParameter *destParam = dynamic_cast<const QgsProcessingDestinationParameter *>( parameterDefinition() );
8600 switch ( type() )
8601 {
8604 {
8605 mOutputWidget = new QgsProcessingLayerOutputDestinationWidget( destParam, false );
8606 if ( mProcessingContextGenerator )
8607 mOutputWidget->setContext( mProcessingContextGenerator->processingContext() );
8608 if ( mParametersGenerator )
8609 mOutputWidget->registerProcessingParametersGenerator( mParametersGenerator );
8610 mOutputWidget->setToolTip( parameterDefinition()->toolTip() );
8611
8612 connect( mOutputWidget, &QgsProcessingLayerOutputDestinationWidget::destinationChanged, this, [=]() {
8613 if ( mBlockSignals )
8614 return;
8615
8616 emit widgetValueHasChanged( this );
8617 } );
8618
8619 if ( type() == QgsProcessingGui::Standard
8621 mOutputWidget->addOpenAfterRunningOption();
8622
8623 return mOutputWidget;
8624 }
8626 break;
8627 }
8628
8629 return nullptr;
8630}
8631
8632
8633void QgsProcessingOutputWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext & )
8634{
8635 if ( mOutputWidget )
8636 mOutputWidget->setValue( value );
8637}
8638
8639QVariant QgsProcessingOutputWidgetWrapper::widgetValue() const
8640{
8641 if ( mOutputWidget )
8642 return mOutputWidget->value();
8643
8644 return QVariant();
8645}
8646
8647QVariantMap QgsProcessingOutputWidgetWrapper::customProperties() const
8648{
8649 QVariantMap res;
8650 if ( mOutputWidget )
8651 res.insert( QStringLiteral( "OPEN_AFTER_RUNNING" ), mOutputWidget->openAfterRunning() );
8652 return res;
8653}
8654
8655QStringList QgsProcessingOutputWidgetWrapper::compatibleParameterTypes() const
8656{
8657 return QStringList()
8664}
8665
8666QStringList QgsProcessingOutputWidgetWrapper::compatibleOutputTypes() const
8667{
8668 return QStringList()
8673}
8674
8675//
8676// QgsProcessingFeatureSinkWidgetWrapper
8677//
8678
8679QgsProcessingFeatureSinkWidgetWrapper::QgsProcessingFeatureSinkWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
8680 : QgsProcessingOutputWidgetWrapper( parameter, type, parent )
8681{
8682}
8683
8684QString QgsProcessingFeatureSinkWidgetWrapper::parameterType() const
8685{
8687}
8688
8689QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingFeatureSinkWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
8690{
8691 return new QgsProcessingFeatureSinkWidgetWrapper( parameter, type );
8692}
8693
8694QString QgsProcessingFeatureSinkWidgetWrapper::modelerExpressionFormatString() const
8695{
8696 return tr( "path to layer destination" );
8697}
8698
8699//
8700// QgsProcessingFeatureSinkWidgetWrapper
8701//
8702
8703QgsProcessingVectorDestinationWidgetWrapper::QgsProcessingVectorDestinationWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
8704 : QgsProcessingOutputWidgetWrapper( parameter, type, parent )
8705{
8706}
8707
8708QString QgsProcessingVectorDestinationWidgetWrapper::parameterType() const
8709{
8711}
8712
8713QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingVectorDestinationWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
8714{
8715 return new QgsProcessingVectorDestinationWidgetWrapper( parameter, type );
8716}
8717
8718QString QgsProcessingVectorDestinationWidgetWrapper::modelerExpressionFormatString() const
8719{
8720 return tr( "path to layer destination" );
8721}
8722
8723//
8724// QgsProcessingRasterDestinationWidgetWrapper
8725//
8726
8727QgsProcessingRasterDestinationWidgetWrapper::QgsProcessingRasterDestinationWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
8728 : QgsProcessingOutputWidgetWrapper( parameter, type, parent )
8729{
8730}
8731
8732QString QgsProcessingRasterDestinationWidgetWrapper::parameterType() const
8733{
8735}
8736
8737QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingRasterDestinationWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
8738{
8739 return new QgsProcessingRasterDestinationWidgetWrapper( parameter, type );
8740}
8741
8742QString QgsProcessingRasterDestinationWidgetWrapper::modelerExpressionFormatString() const
8743{
8744 return tr( "path to layer destination" );
8745}
8746
8747//
8748// QgsProcessingPointCloudDestinationWidgetWrapper
8749//
8750
8751QgsProcessingPointCloudDestinationWidgetWrapper::QgsProcessingPointCloudDestinationWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
8752 : QgsProcessingOutputWidgetWrapper( parameter, type, parent )
8753{
8754}
8755
8756QString QgsProcessingPointCloudDestinationWidgetWrapper::parameterType() const
8757{
8759}
8760
8761QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingPointCloudDestinationWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
8762{
8763 return new QgsProcessingPointCloudDestinationWidgetWrapper( parameter, type );
8764}
8765
8766QString QgsProcessingPointCloudDestinationWidgetWrapper::modelerExpressionFormatString() const
8767{
8768 return tr( "path to layer destination" );
8769}
8770
8771//
8772// QgsProcessingFileDestinationWidgetWrapper
8773//
8774
8775QgsProcessingFileDestinationWidgetWrapper::QgsProcessingFileDestinationWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
8776 : QgsProcessingOutputWidgetWrapper( parameter, type, parent )
8777{
8778}
8779
8780QString QgsProcessingFileDestinationWidgetWrapper::parameterType() const
8781{
8783}
8784
8785QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingFileDestinationWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
8786{
8787 return new QgsProcessingFileDestinationWidgetWrapper( parameter, type );
8788}
8789
8790QStringList QgsProcessingFileDestinationWidgetWrapper::compatibleParameterTypes() const
8791{
8792 return QStringList()
8795}
8796
8797QStringList QgsProcessingFileDestinationWidgetWrapper::compatibleOutputTypes() const
8798{
8799 return QStringList() << QgsProcessingOutputFile::typeName()
8805}
8806
8807QString QgsProcessingFileDestinationWidgetWrapper::modelerExpressionFormatString() const
8808{
8809 return tr( "path to file destination" );
8810}
8811
8812//
8813// QgsProcessingFolderDestinationWidgetWrapper
8814//
8815
8816QgsProcessingFolderDestinationWidgetWrapper::QgsProcessingFolderDestinationWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
8817 : QgsProcessingOutputWidgetWrapper( parameter, type, parent )
8818{
8819}
8820
8821QString QgsProcessingFolderDestinationWidgetWrapper::parameterType() const
8822{
8824}
8825
8826QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingFolderDestinationWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
8827{
8828 return new QgsProcessingFolderDestinationWidgetWrapper( parameter, type );
8829}
8830
8831QStringList QgsProcessingFolderDestinationWidgetWrapper::compatibleParameterTypes() const
8832{
8833 return QStringList()
8836}
8837
8838QStringList QgsProcessingFolderDestinationWidgetWrapper::compatibleOutputTypes() const
8839{
8840 return QStringList() << QgsProcessingOutputFile::typeName()
8844}
8845
8846QString QgsProcessingFolderDestinationWidgetWrapper::modelerExpressionFormatString() const
8847{
8848 return tr( "path to folder destination" );
8849}
8850
8851//
8852// QgsProcessingVectorTileDestinationWidgetWrapper
8853//
8854
8855QgsProcessingVectorTileDestinationWidgetWrapper::QgsProcessingVectorTileDestinationWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
8856 : QgsProcessingOutputWidgetWrapper( parameter, type, parent )
8857{
8858}
8859
8860QString QgsProcessingVectorTileDestinationWidgetWrapper::parameterType() const
8861{
8863}
8864
8865QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingVectorTileDestinationWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
8866{
8867 return new QgsProcessingPointCloudDestinationWidgetWrapper( parameter, type );
8868}
8869
8870QString QgsProcessingVectorTileDestinationWidgetWrapper::modelerExpressionFormatString() const
8871{
8872 return tr( "path to layer destination" );
8873}
8874
@ Standard
Unit is a standard measurement unit.
ProcessingSourceType
Processing data source types.
Definition qgis.h:3315
@ 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:3555
@ File
Parameter is a single file.
@ Folder
Parameter is a folder.
ExpressionType
Expression types.
Definition qgis.h:5185
@ RasterCalculator
Raster calculator expression.
@ Qgis
Native QGIS expression.
@ PointCloud
Point cloud expression.
DistanceUnit
Units of distance.
Definition qgis.h:4722
@ 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:3583
@ 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:4799
@ 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:4868
@ 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:3544
VolumeUnit
Units of volume.
Definition qgis.h:4824
@ 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:3614
@ 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:3601
ProcessingNumberParameterType
Processing numeric parameter data types.
Definition qgis.h:3569
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 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:6065
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition qgis.h:6024
const QgsCoordinateReferenceSystem & crs
QString proj
Proj coordinate operation description, for Proj >= 6.0 builds only.