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