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