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