QGIS API Documentation 3.43.0-Master (0cdc48caa8d)
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
4682void QgsProcessingFieldPanelWidget::setValue( const QVariant &value )
4683{
4684 if ( value.isValid() )
4685 mValue = value.userType() == QMetaType::Type::QVariantList ? value.toList() : QVariantList() << value;
4686 else
4687 mValue.clear();
4688
4689 updateSummaryText();
4690 emit changed();
4691}
4692
4693void QgsProcessingFieldPanelWidget::showDialog()
4694{
4695 QVariantList availableOptions;
4696 availableOptions.reserve( mFields.size() );
4697 for ( const QgsField &field : std::as_const( mFields ) )
4698 {
4699 availableOptions << field.name();
4700 }
4701
4703 if ( panel && panel->dockMode() )
4704 {
4705 QgsProcessingMultipleSelectionPanelWidget *widget = new QgsProcessingMultipleSelectionPanelWidget( availableOptions, mValue );
4706 widget->setPanelTitle( mParam->description() );
4707
4708 widget->setValueFormatter( []( const QVariant &v ) -> QString {
4709 return v.toString();
4710 } );
4711
4712 connect( widget, &QgsProcessingMultipleSelectionPanelWidget::selectionChanged, this, [=]() {
4713 setValue( widget->selectedOptions() );
4714 } );
4715 connect( widget, &QgsProcessingMultipleSelectionPanelWidget::acceptClicked, widget, &QgsPanelWidget::acceptPanel );
4716 panel->openPanel( widget );
4717 }
4718 else
4719 {
4720 QgsProcessingMultipleSelectionDialog dlg( availableOptions, mValue, this, Qt::WindowFlags() );
4721
4722 dlg.setValueFormatter( []( const QVariant &v ) -> QString {
4723 return v.toString();
4724 } );
4725 if ( dlg.exec() )
4726 {
4727 setValue( dlg.selectedOptions() );
4728 }
4729 }
4730}
4731
4732void QgsProcessingFieldPanelWidget::updateSummaryText()
4733{
4734 if ( !mParam )
4735 return;
4736
4737 if ( mValue.empty() )
4738 {
4739 mLineEdit->setText( tr( "%n field(s) selected", nullptr, 0 ) );
4740 }
4741 else
4742 {
4743 QStringList values;
4744 values.reserve( mValue.size() );
4745 for ( const QVariant &val : std::as_const( mValue ) )
4746 {
4747 values << val.toString();
4748 }
4749
4750 const QString concatenated = values.join( tr( "," ) );
4751 if ( concatenated.length() < 100 )
4752 mLineEdit->setText( concatenated );
4753 else
4754 mLineEdit->setText( tr( "%n field(s) selected", nullptr, mValue.count() ) );
4755 }
4756}
4757
4758
4759//
4760// QgsProcessingFieldWidgetWrapper
4761//
4762
4763QgsProcessingFieldParameterDefinitionWidget::QgsProcessingFieldParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
4764 : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
4765{
4766 QVBoxLayout *vlayout = new QVBoxLayout();
4767 vlayout->setContentsMargins( 0, 0, 0, 0 );
4768
4769 vlayout->addWidget( new QLabel( tr( "Parent layer" ) ) );
4770 mParentLayerComboBox = new QComboBox();
4771
4772 QString initialParent;
4773 if ( const QgsProcessingParameterField *fieldParam = dynamic_cast<const QgsProcessingParameterField *>( definition ) )
4774 initialParent = fieldParam->parentLayerParameterName();
4775
4776 if ( auto *lModel = widgetContext.model() )
4777 {
4778 // populate combo box with other model input choices
4779 const QMap<QString, QgsProcessingModelParameter> components = lModel->parameterComponents();
4780 for ( auto it = components.constBegin(); it != components.constEnd(); ++it )
4781 {
4782 if ( const QgsProcessingParameterFeatureSource *definition = dynamic_cast<const QgsProcessingParameterFeatureSource *>( lModel->parameterDefinition( it.value().parameterName() ) ) )
4783 {
4784 mParentLayerComboBox->addItem( definition->description(), definition->name() );
4785 if ( !initialParent.isEmpty() && initialParent == definition->name() )
4786 {
4787 mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
4788 }
4789 }
4790 else if ( const QgsProcessingParameterVectorLayer *definition = dynamic_cast<const QgsProcessingParameterVectorLayer *>( lModel->parameterDefinition( it.value().parameterName() ) ) )
4791 {
4792 mParentLayerComboBox->addItem( definition->description(), definition->name() );
4793 if ( !initialParent.isEmpty() && initialParent == definition->name() )
4794 {
4795 mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
4796 }
4797 }
4798 else if ( const QgsProcessingParameterMultipleLayers *definition = dynamic_cast<const QgsProcessingParameterMultipleLayers *>( lModel->parameterDefinition( it.value().parameterName() ) ) )
4799 {
4800 if ( definition->layerType() == Qgis::ProcessingSourceType::Vector )
4801 {
4802 mParentLayerComboBox->addItem( definition->description(), definition->name() );
4803 if ( !initialParent.isEmpty() && initialParent == definition->name() )
4804 {
4805 mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
4806 }
4807 }
4808 }
4809 }
4810 }
4811
4812 if ( mParentLayerComboBox->count() == 0 && !initialParent.isEmpty() )
4813 {
4814 // if no parent candidates found, we just add the existing one as a placeholder
4815 mParentLayerComboBox->addItem( initialParent, initialParent );
4816 mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
4817 }
4818
4819 vlayout->addWidget( mParentLayerComboBox );
4820
4821 vlayout->addWidget( new QLabel( tr( "Allowed data type" ) ) );
4822 mDataTypeComboBox = new QComboBox();
4823 mDataTypeComboBox->addItem( tr( "Any" ), static_cast<int>( Qgis::ProcessingFieldParameterDataType::Any ) );
4824 mDataTypeComboBox->addItem( tr( "Number" ), static_cast<int>( Qgis::ProcessingFieldParameterDataType::Numeric ) );
4825 mDataTypeComboBox->addItem( tr( "String" ), static_cast<int>( Qgis::ProcessingFieldParameterDataType::String ) );
4826 mDataTypeComboBox->addItem( tr( "Date/time" ), static_cast<int>( Qgis::ProcessingFieldParameterDataType::DateTime ) );
4827 mDataTypeComboBox->addItem( tr( "Binary" ), static_cast<int>( Qgis::ProcessingFieldParameterDataType::Binary ) );
4828 mDataTypeComboBox->addItem( tr( "Boolean" ), static_cast<int>( Qgis::ProcessingFieldParameterDataType::Boolean ) );
4829 if ( const QgsProcessingParameterField *fieldParam = dynamic_cast<const QgsProcessingParameterField *>( definition ) )
4830 mDataTypeComboBox->setCurrentIndex( mDataTypeComboBox->findData( static_cast<int>( fieldParam->dataType() ) ) );
4831
4832 vlayout->addWidget( mDataTypeComboBox );
4833
4834 mAllowMultipleCheckBox = new QCheckBox( tr( "Accept multiple fields" ) );
4835 if ( const QgsProcessingParameterField *fieldParam = dynamic_cast<const QgsProcessingParameterField *>( definition ) )
4836 mAllowMultipleCheckBox->setChecked( fieldParam->allowMultiple() );
4837
4838 vlayout->addWidget( mAllowMultipleCheckBox );
4839
4840 mDefaultToAllCheckBox = new QCheckBox( tr( "Select all fields by default" ) );
4841 mDefaultToAllCheckBox->setEnabled( mAllowMultipleCheckBox->isChecked() );
4842 if ( const QgsProcessingParameterField *fieldParam = dynamic_cast<const QgsProcessingParameterField *>( definition ) )
4843 mDefaultToAllCheckBox->setChecked( fieldParam->defaultToAllFields() );
4844
4845 vlayout->addWidget( mDefaultToAllCheckBox );
4846
4847 connect( mAllowMultipleCheckBox, &QCheckBox::stateChanged, this, [=] {
4848 mDefaultToAllCheckBox->setEnabled( mAllowMultipleCheckBox->isChecked() );
4849 } );
4850
4851 vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
4852
4853 mDefaultLineEdit = new QLineEdit();
4854 mDefaultLineEdit->setToolTip( tr( "Default field name, or ; separated list of field names for multiple field parameters" ) );
4855 if ( const QgsProcessingParameterField *fieldParam = dynamic_cast<const QgsProcessingParameterField *>( definition ) )
4856 {
4857 const QStringList fields = QgsProcessingParameters::parameterAsStrings( fieldParam, fieldParam->defaultValueForGui(), context );
4858 mDefaultLineEdit->setText( fields.join( ';' ) );
4859 }
4860 vlayout->addWidget( mDefaultLineEdit );
4861
4862 setLayout( vlayout );
4863}
4864
4865QgsProcessingParameterDefinition *QgsProcessingFieldParameterDefinitionWidget::createParameter( const QString &name, const QString &description, Qgis::ProcessingParameterFlags flags ) const
4866{
4867 Qgis::ProcessingFieldParameterDataType dataType = static_cast<Qgis::ProcessingFieldParameterDataType>( mDataTypeComboBox->currentData().toInt() );
4868
4869 QVariant defaultValue;
4870 if ( !mDefaultLineEdit->text().trimmed().isEmpty() )
4871 {
4872 defaultValue = mDefaultLineEdit->text();
4873 }
4874 auto param = std::make_unique<QgsProcessingParameterField>( name, description, defaultValue, mParentLayerComboBox->currentData().toString(), dataType, mAllowMultipleCheckBox->isChecked(), false, mDefaultToAllCheckBox->isChecked() );
4875 param->setFlags( flags );
4876 return param.release();
4877}
4878
4879QgsProcessingFieldWidgetWrapper::QgsProcessingFieldWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type, QWidget *parent )
4880 : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
4881{
4882}
4883
4884QWidget *QgsProcessingFieldWidgetWrapper::createWidget()
4885{
4886 const QgsProcessingParameterField *fieldParam = dynamic_cast<const QgsProcessingParameterField *>( parameterDefinition() );
4887 switch ( type() )
4888 {
4891 {
4892 if ( fieldParam->allowMultiple() )
4893 {
4894 mPanel = new QgsProcessingFieldPanelWidget( nullptr, fieldParam );
4895 mPanel->setToolTip( parameterDefinition()->toolTip() );
4896 connect( mPanel, &QgsProcessingFieldPanelWidget::changed, this, [=] {
4897 emit widgetValueHasChanged( this );
4898 } );
4899 return mPanel;
4900 }
4901 else
4902 {
4903 mComboBox = new QgsFieldComboBox();
4904 mComboBox->setAllowEmptyFieldName( fieldParam->flags() & Qgis::ProcessingParameterFlag::Optional );
4905
4907 mComboBox->setFilters( QgsFieldProxyModel::Numeric );
4908 else if ( fieldParam->dataType() == Qgis::ProcessingFieldParameterDataType::String )
4909 mComboBox->setFilters( QgsFieldProxyModel::String );
4912 else if ( fieldParam->dataType() == Qgis::ProcessingFieldParameterDataType::Binary )
4913 mComboBox->setFilters( QgsFieldProxyModel::Binary );
4915 mComboBox->setFilters( QgsFieldProxyModel::Boolean );
4916
4917 mComboBox->setToolTip( parameterDefinition()->toolTip() );
4918 connect( mComboBox, &QgsFieldComboBox::fieldChanged, this, [=]( const QString & ) {
4919 emit widgetValueHasChanged( this );
4920 } );
4921 return mComboBox;
4922 }
4923 }
4924
4926 {
4927 mLineEdit = new QLineEdit();
4928 mLineEdit->setToolTip( QObject::tr( "Name of field (separate field names with ; for multiple field parameters)" ) );
4929 connect( mLineEdit, &QLineEdit::textChanged, this, [=] {
4930 emit widgetValueHasChanged( this );
4931 } );
4932 return mLineEdit;
4933 }
4934 }
4935 return nullptr;
4936}
4937
4938void QgsProcessingFieldWidgetWrapper::postInitialize( const QList<QgsAbstractProcessingParameterWidgetWrapper *> &wrappers )
4939{
4941 switch ( type() )
4942 {
4945 {
4946 for ( const QgsAbstractProcessingParameterWidgetWrapper *wrapper : wrappers )
4947 {
4948 if ( wrapper->parameterDefinition()->name() == static_cast<const QgsProcessingParameterField *>( parameterDefinition() )->parentLayerParameterName() )
4949 {
4950 setParentLayerWrapperValue( wrapper );
4952 setParentLayerWrapperValue( wrapper );
4953 } );
4954 break;
4955 }
4956 }
4957 break;
4958 }
4959
4961 break;
4962 }
4963}
4964
4965void QgsProcessingFieldWidgetWrapper::setParentLayerWrapperValue( const QgsAbstractProcessingParameterWidgetWrapper *parentWrapper )
4966{
4967 // evaluate value to layer
4968 QgsProcessingContext *context = nullptr;
4969 std::unique_ptr<QgsProcessingContext> tmpContext;
4970 if ( mProcessingContextGenerator )
4971 context = mProcessingContextGenerator->processingContext();
4972
4973 if ( !context )
4974 {
4975 tmpContext = std::make_unique<QgsProcessingContext>();
4976 context = tmpContext.get();
4977 }
4978
4979 QVariant value = parentWrapper->parameterValue();
4980
4981 if ( value.userType() == qMetaTypeId<QgsProcessingFeatureSourceDefinition>() )
4982 {
4983 // input is a QgsProcessingFeatureSourceDefinition - source from it.
4984 // this is normally discouraged, and algorithms should NEVER do this -- but in this case we can make
4985 // certain assumptions due to the fact that we're calling this outside of algorithm/model execution and all sources
4986 // should be real map layers at this stage
4987 QgsProcessingFeatureSourceDefinition fromVar = qvariant_cast<QgsProcessingFeatureSourceDefinition>( value );
4988 value = fromVar.source;
4989 }
4990
4991 bool valueSet = false;
4992 const QList<QgsMapLayer *> layers = QgsProcessingParameters::parameterAsLayerList( parentWrapper->parameterDefinition(), value, *context );
4993
4994 // several layers, populate with intersection of layers fields
4995 if ( layers.count() > 1 )
4996 {
4997 QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( layers.at( 0 ) );
4998 QgsFields fields = vlayer && vlayer->isValid() ? vlayer->fields() : QgsFields();
4999 const QList<QgsMapLayer *> remainingLayers = layers.mid( 1 );
5000 for ( QgsMapLayer *layer : remainingLayers )
5001 {
5002 if ( fields.isEmpty() )
5003 break;
5004
5005 QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( layer );
5006 if ( !vlayer || !vlayer->isValid() )
5007 {
5008 fields = QgsFields();
5009 break;
5010 }
5011
5012 for ( int fieldIdx = fields.count() - 1; fieldIdx >= 0; fieldIdx-- )
5013 {
5014 if ( vlayer->fields().lookupField( fields.at( fieldIdx ).name() ) < 0 )
5015 fields.remove( fieldIdx );
5016 }
5017 }
5018
5019 if ( mComboBox )
5020 mComboBox->setFields( fields );
5021 else if ( mPanel )
5022 mPanel->setFields( filterFields( fields ) );
5023
5024 valueSet = true;
5025 }
5026
5027 // only one layer
5028 if ( !valueSet && !layers.isEmpty() && layers.at( 0 )->isValid() )
5029 {
5030 QgsVectorLayer *layer = qobject_cast<QgsVectorLayer *>( layers.at( 0 ) );
5031
5032 // need to grab ownership of layer if required - otherwise layer may be deleted when context
5033 // goes out of scope
5034 std::unique_ptr<QgsMapLayer> ownedLayer( context->takeResultLayer( layer->id() ) );
5035 if ( ownedLayer && ownedLayer->type() == Qgis::LayerType::Vector )
5036 {
5037 mParentLayer.reset( qobject_cast<QgsVectorLayer *>( ownedLayer.release() ) );
5038 layer = mParentLayer.get();
5039 }
5040 else
5041 {
5042 // don't need ownership of this layer - it wasn't owned by context (so e.g. is owned by the project)
5043 }
5044
5045 if ( mComboBox )
5046 mComboBox->setLayer( layer );
5047 else if ( mPanel )
5048 mPanel->setFields( filterFields( layer->fields() ) );
5049
5050 valueSet = true;
5051 }
5052
5053 if ( !valueSet )
5054 {
5055 std::unique_ptr<QgsProcessingFeatureSource> source( QgsProcessingParameters::parameterAsSource( parentWrapper->parameterDefinition(), value, *context ) );
5056 if ( source )
5057 {
5058 const QgsFields fields = source->fields();
5059 if ( mComboBox )
5060 mComboBox->setFields( fields );
5061 else if ( mPanel )
5062 mPanel->setFields( filterFields( fields ) );
5063
5064 valueSet = true;
5065 }
5066 }
5067
5068 if ( !valueSet )
5069 {
5070 if ( mComboBox )
5071 mComboBox->setLayer( nullptr );
5072 else if ( mPanel )
5073 mPanel->setFields( QgsFields() );
5074
5075 if ( value.isValid() && widgetContext().messageBar() )
5076 {
5077 widgetContext().messageBar()->clearWidgets();
5078 widgetContext().messageBar()->pushMessage( QString(), QObject::tr( "Could not load selected layer/table. Dependent field could not be populated" ), Qgis::MessageLevel::Info );
5079 }
5080 return;
5081 }
5082
5083 const QgsProcessingParameterField *fieldParam = static_cast<const QgsProcessingParameterField *>( parameterDefinition() );
5084 if ( mPanel && fieldParam->defaultToAllFields() )
5085 {
5086 QVariantList val;
5087 val.reserve( mPanel->fields().size() );
5088 for ( const QgsField &field : mPanel->fields() )
5089 val << field.name();
5090 setWidgetValue( val, *context );
5091 }
5092 else if ( fieldParam->defaultValueForGui().isValid() )
5093 setWidgetValue( parameterDefinition()->defaultValueForGui(), *context );
5094}
5095
5096void QgsProcessingFieldWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
5097{
5098 if ( mComboBox )
5099 {
5100 if ( !value.isValid() )
5101 mComboBox->setField( QString() );
5102 else
5103 {
5104 const QString v = QgsProcessingParameters::parameterAsString( parameterDefinition(), value, context );
5105 mComboBox->setField( v );
5106 }
5107 }
5108 else if ( mPanel )
5109 {
5110 QVariantList opts;
5111 if ( value.isValid() )
5112 {
5113 const QStringList v = QgsProcessingParameters::parameterAsStrings( parameterDefinition(), value, context );
5114 opts.reserve( v.size() );
5115 for ( const QString &i : v )
5116 opts << i;
5117 }
5118 if ( mPanel )
5119 mPanel->setValue( opts );
5120 }
5121 else if ( mLineEdit )
5122 {
5123 const QgsProcessingParameterField *fieldParam = static_cast<const QgsProcessingParameterField *>( parameterDefinition() );
5124 if ( fieldParam->allowMultiple() )
5125 {
5126 const QStringList v = QgsProcessingParameters::parameterAsStrings( parameterDefinition(), value, context );
5127 mLineEdit->setText( v.join( ';' ) );
5128 }
5129 else
5130 {
5131 mLineEdit->setText( QgsProcessingParameters::parameterAsString( parameterDefinition(), value, context ) );
5132 }
5133 }
5134}
5135
5136QVariant QgsProcessingFieldWidgetWrapper::widgetValue() const
5137{
5138 if ( mComboBox )
5139 return mComboBox->currentField();
5140 else if ( mPanel )
5141 return mPanel->value();
5142 else if ( mLineEdit )
5143 {
5144 const QgsProcessingParameterField *fieldParam = static_cast<const QgsProcessingParameterField *>( parameterDefinition() );
5145 if ( fieldParam->allowMultiple() )
5146 {
5147 return mLineEdit->text().split( ';' );
5148 }
5149 else
5150 return mLineEdit->text();
5151 }
5152 else
5153 return QVariant();
5154}
5155
5156QString QgsProcessingFieldWidgetWrapper::modelerExpressionFormatString() const
5157{
5158 return tr( "selected field names as an array of names, or semicolon separated string of options (e.g. 'fid;place_name')" );
5159}
5160
5161const QgsVectorLayer *QgsProcessingFieldWidgetWrapper::linkedVectorLayer() const
5162{
5163 if ( mComboBox && mComboBox->layer() )
5164 return mComboBox->layer();
5165
5167}
5168
5169QgsFields QgsProcessingFieldWidgetWrapper::filterFields( const QgsFields &fields ) const
5170{
5171 const QgsProcessingParameterField *fieldParam = static_cast<const QgsProcessingParameterField *>( parameterDefinition() );
5172 QgsFields res;
5173 for ( const QgsField &f : fields )
5174 {
5175 switch ( fieldParam->dataType() )
5176 {
5178 res.append( f );
5179 break;
5180
5182 if ( f.isNumeric() )
5183 res.append( f );
5184 break;
5185
5187 if ( f.type() == QMetaType::Type::QString )
5188 res.append( f );
5189 break;
5190
5192 if ( f.type() == QMetaType::Type::QDate || f.type() == QMetaType::Type::QTime || f.type() == QMetaType::Type::QDateTime )
5193 res.append( f );
5194 break;
5195
5197 if ( f.type() == QMetaType::Type::QByteArray )
5198 res.append( f );
5199 break;
5200
5202 if ( f.type() == QMetaType::Type::Bool )
5203 res.append( f );
5204 break;
5205 }
5206 }
5207
5208 return res;
5209}
5210
5211QString QgsProcessingFieldWidgetWrapper::parameterType() const
5212{
5214}
5215
5216QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingFieldWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type )
5217{
5218 return new QgsProcessingFieldWidgetWrapper( parameter, type );
5219}
5220
5221QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingFieldWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
5222{
5223 return new QgsProcessingFieldParameterDefinitionWidget( context, widgetContext, definition, algorithm );
5224}
5225
5226//
5227// QgsProcessingMapThemeWidgetWrapper
5228//
5229
5230
5231QgsProcessingMapThemeParameterDefinitionWidget::QgsProcessingMapThemeParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
5232 : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
5233{
5234 QVBoxLayout *vlayout = new QVBoxLayout();
5235 vlayout->setContentsMargins( 0, 0, 0, 0 );
5236
5237 vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
5238
5239 mDefaultComboBox = new QComboBox();
5240 mDefaultComboBox->addItem( QString(), QVariant( -1 ) );
5241
5242 const QStringList mapThemes = widgetContext.project() ? widgetContext.project()->mapThemeCollection()->mapThemes() : QgsProject::instance()->mapThemeCollection()->mapThemes();
5243 for ( const QString &theme : mapThemes )
5244 {
5245 mDefaultComboBox->addItem( QgsApplication::getThemeIcon( QStringLiteral( "/mActionShowAllLayers.svg" ) ), theme, theme );
5246 }
5247 mDefaultComboBox->setEditable( true );
5248
5249 if ( const QgsProcessingParameterMapTheme *themeParam = dynamic_cast<const QgsProcessingParameterMapTheme *>( definition ) )
5250 {
5251 if ( themeParam->defaultValueForGui().isValid() )
5252 mDefaultComboBox->setCurrentText( QgsProcessingParameters::parameterAsString( themeParam, themeParam->defaultValueForGui(), context ) );
5253 else
5254 mDefaultComboBox->setCurrentIndex( mDefaultComboBox->findData( -1 ) );
5255 }
5256 else
5257 mDefaultComboBox->setCurrentIndex( mDefaultComboBox->findData( -1 ) );
5258
5259 vlayout->addWidget( mDefaultComboBox );
5260
5261 setLayout( vlayout );
5262}
5263
5264QgsProcessingParameterDefinition *QgsProcessingMapThemeParameterDefinitionWidget::createParameter( const QString &name, const QString &description, Qgis::ProcessingParameterFlags flags ) const
5265{
5266 QVariant defaultVal;
5267 if ( mDefaultComboBox->currentText().isEmpty() )
5268 defaultVal = QVariant();
5269 else
5270 defaultVal = mDefaultComboBox->currentText();
5271 auto param = std::make_unique<QgsProcessingParameterMapTheme>( name, description, defaultVal );
5272 param->setFlags( flags );
5273 return param.release();
5274}
5275
5276
5277QgsProcessingMapThemeWidgetWrapper::QgsProcessingMapThemeWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type, QWidget *parent )
5278 : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
5279{
5280}
5281
5282QWidget *QgsProcessingMapThemeWidgetWrapper::createWidget()
5283{
5284 const QgsProcessingParameterMapTheme *themeParam = dynamic_cast<const QgsProcessingParameterMapTheme *>( parameterDefinition() );
5285
5286 mComboBox = new QComboBox();
5287
5288 if ( themeParam->flags() & Qgis::ProcessingParameterFlag::Optional )
5289 mComboBox->addItem( tr( "[Not selected]" ), QVariant( -1 ) );
5290
5291 const QStringList mapThemes = widgetContext().project() ? widgetContext().project()->mapThemeCollection()->mapThemes() : QgsProject::instance()->mapThemeCollection()->mapThemes();
5292 for ( const QString &theme : mapThemes )
5293 {
5294 mComboBox->addItem( QgsApplication::getThemeIcon( QStringLiteral( "/mActionShowAllLayers.svg" ) ), theme, theme );
5295 }
5296
5297 switch ( type() )
5298 {
5301 break;
5302
5304 mComboBox->setEditable( true );
5305 break;
5306 }
5307
5308 mComboBox->setToolTip( parameterDefinition()->toolTip() );
5309 connect( mComboBox, qOverload<int>( &QComboBox::currentIndexChanged ), this, [=]( int ) {
5310 emit widgetValueHasChanged( this );
5311 } );
5312
5313 return mComboBox;
5314}
5315
5316void QgsProcessingMapThemeWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
5317{
5318 const QString v = QgsProcessingParameters::parameterAsString( parameterDefinition(), value, context );
5319
5320 if ( !value.isValid() )
5321 mComboBox->setCurrentIndex( mComboBox->findData( QVariant( -1 ) ) );
5322 else
5323 {
5324 if ( mComboBox->isEditable() && mComboBox->findData( v ) == -1 )
5325 {
5326 const QString prev = mComboBox->currentText();
5327 mComboBox->setCurrentText( v );
5328 if ( prev != v )
5329 emit widgetValueHasChanged( this );
5330 }
5331 else
5332 mComboBox->setCurrentIndex( mComboBox->findData( v ) );
5333 }
5334}
5335
5336QVariant QgsProcessingMapThemeWidgetWrapper::widgetValue() const
5337{
5338 if ( mComboBox )
5339 return mComboBox->currentData().toInt() == -1 ? QVariant() : !mComboBox->currentData().isValid() && mComboBox->isEditable() ? mComboBox->currentText().isEmpty() ? QVariant() : QVariant( mComboBox->currentText() )
5340 : mComboBox->currentData();
5341 else
5342 return QVariant();
5343}
5344
5345QString QgsProcessingMapThemeWidgetWrapper::modelerExpressionFormatString() const
5346{
5347 return tr( "map theme as a string value (e.g. 'base maps')" );
5348}
5349
5350QString QgsProcessingMapThemeWidgetWrapper::parameterType() const
5351{
5353}
5354
5355QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingMapThemeWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type )
5356{
5357 return new QgsProcessingMapThemeWidgetWrapper( parameter, type );
5358}
5359
5360QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingMapThemeWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
5361{
5362 return new QgsProcessingMapThemeParameterDefinitionWidget( context, widgetContext, definition, algorithm );
5363}
5364
5365
5366//
5367// QgsProcessingDateTimeWidgetWrapper
5368//
5369
5370
5371QgsProcessingDateTimeParameterDefinitionWidget::QgsProcessingDateTimeParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
5372 : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
5373{
5374 QVBoxLayout *vlayout = new QVBoxLayout();
5375 vlayout->setContentsMargins( 0, 0, 0, 0 );
5376
5377 vlayout->addWidget( new QLabel( tr( "Type" ) ) );
5378
5379 mTypeComboBox = new QComboBox();
5380 mTypeComboBox->addItem( tr( "Date and Time" ), static_cast<int>( Qgis::ProcessingDateTimeParameterDataType::DateTime ) );
5381 mTypeComboBox->addItem( tr( "Date" ), static_cast<int>( Qgis::ProcessingDateTimeParameterDataType::Date ) );
5382 mTypeComboBox->addItem( tr( "Time" ), static_cast<int>( Qgis::ProcessingDateTimeParameterDataType::Time ) );
5383 if ( const QgsProcessingParameterDateTime *datetimeParam = dynamic_cast<const QgsProcessingParameterDateTime *>( definition ) )
5384 mTypeComboBox->setCurrentIndex( mTypeComboBox->findData( static_cast<int>( datetimeParam->dataType() ) ) );
5385 else
5386 mTypeComboBox->setCurrentIndex( 0 );
5387 vlayout->addWidget( mTypeComboBox );
5388
5389 setLayout( vlayout );
5390}
5391
5392QgsProcessingParameterDefinition *QgsProcessingDateTimeParameterDefinitionWidget::createParameter( const QString &name, const QString &description, Qgis::ProcessingParameterFlags flags ) const
5393{
5394 auto param = std::make_unique<QgsProcessingParameterDateTime>( name, description );
5395 param->setDataType( static_cast<Qgis::ProcessingDateTimeParameterDataType>( mTypeComboBox->currentData().toInt() ) );
5396 param->setFlags( flags );
5397 return param.release();
5398}
5399
5400
5401QgsProcessingDateTimeWidgetWrapper::QgsProcessingDateTimeWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type, QWidget *parent )
5402 : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
5403{
5404}
5405
5406QWidget *QgsProcessingDateTimeWidgetWrapper::createWidget()
5407{
5408 const QgsProcessingParameterDateTime *dateTimeParam = dynamic_cast<const QgsProcessingParameterDateTime *>( parameterDefinition() );
5409
5410 QgsDateTimeEdit *widget = nullptr;
5411 switch ( dateTimeParam->dataType() )
5412 {
5414 mDateTimeEdit = new QgsDateTimeEdit();
5415 widget = mDateTimeEdit;
5416 break;
5417
5419 mDateEdit = new QgsDateEdit();
5420 widget = mDateEdit;
5421 break;
5422
5424 mTimeEdit = new QgsTimeEdit();
5425 widget = mTimeEdit;
5426 break;
5427 }
5428
5429 if ( dateTimeParam->flags() & Qgis::ProcessingParameterFlag::Optional )
5430 {
5431 widget->setNullRepresentation( tr( "[Not selected]" ) );
5432 widget->setAllowNull( true );
5433 }
5434 else
5435 {
5436 widget->setAllowNull( false );
5437 }
5438 widget->setToolTip( parameterDefinition()->toolTip() );
5439
5440 if ( mDateTimeEdit )
5441 {
5442 connect( mDateTimeEdit, &QgsDateTimeEdit::valueChanged, this, [=]( const QDateTime & ) {
5443 emit widgetValueHasChanged( this );
5444 } );
5445 }
5446 else if ( mDateEdit )
5447 {
5448 connect( mDateEdit, &QgsDateEdit::dateValueChanged, this, [=]( const QDate & ) {
5449 emit widgetValueHasChanged( this );
5450 } );
5451 }
5452 else if ( mTimeEdit )
5453 {
5454 connect( mTimeEdit, &QgsTimeEdit::timeValueChanged, this, [=]( const QTime & ) {
5455 emit widgetValueHasChanged( this );
5456 } );
5457 }
5458
5459 return widget;
5460}
5461
5462QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingDateTimeWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
5463{
5464 return new QgsProcessingDateTimeParameterDefinitionWidget( context, widgetContext, definition, algorithm );
5465}
5466
5467void QgsProcessingDateTimeWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
5468{
5469 if ( mDateTimeEdit )
5470 {
5471 mDateTimeEdit->setDateTime( QgsProcessingParameters::parameterAsDateTime( parameterDefinition(), value, context ) );
5472 }
5473 else if ( mDateEdit )
5474 {
5475 mDateEdit->setDate( QgsProcessingParameters::parameterAsDate( parameterDefinition(), value, context ) );
5476 }
5477 else if ( mTimeEdit )
5478 {
5479 mTimeEdit->setTime( QgsProcessingParameters::parameterAsTime( parameterDefinition(), value, context ) );
5480 }
5481}
5482
5483QVariant QgsProcessingDateTimeWidgetWrapper::widgetValue() const
5484{
5485 if ( mDateTimeEdit )
5486 return !mDateTimeEdit->dateTime().isNull() && mDateTimeEdit->dateTime().isValid() ? QVariant( mDateTimeEdit->dateTime() ) : QVariant();
5487 else if ( mDateEdit )
5488 return !mDateEdit->date().isNull() && mDateEdit->date().isValid() ? QVariant( mDateEdit->date() ) : QVariant();
5489 else if ( mTimeEdit )
5490 return !mTimeEdit->time().isNull() && mTimeEdit->time().isValid() ? QVariant( mTimeEdit->time() ) : QVariant();
5491 else
5492 return QVariant();
5493}
5494
5495QString QgsProcessingDateTimeWidgetWrapper::modelerExpressionFormatString() const
5496{
5497 const QgsProcessingParameterDateTime *dateTimeParam = dynamic_cast<const QgsProcessingParameterDateTime *>( parameterDefinition() );
5498 if ( dateTimeParam )
5499 {
5500 switch ( dateTimeParam->dataType() )
5501 {
5503 return tr( "datetime value, or a ISO string representation of a datetime" );
5504
5506 return tr( "date value, or a ISO string representation of a date" );
5507
5509 return tr( "time value, or a ISO string representation of a time" );
5510 }
5511 }
5512 return QString();
5513}
5514
5515QString QgsProcessingDateTimeWidgetWrapper::parameterType() const
5516{
5518}
5519
5520QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingDateTimeWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type )
5521{
5522 return new QgsProcessingDateTimeWidgetWrapper( parameter, type );
5523}
5524
5525
5526//
5527// QgsProcessingProviderConnectionWidgetWrapper
5528//
5529
5530QgsProcessingProviderConnectionParameterDefinitionWidget::QgsProcessingProviderConnectionParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
5531 : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
5532{
5533 const QgsProcessingParameterProviderConnection *connectionParam = dynamic_cast<const QgsProcessingParameterProviderConnection *>( definition );
5534
5535 QVBoxLayout *vlayout = new QVBoxLayout();
5536 vlayout->setContentsMargins( 0, 0, 0, 0 );
5537
5538 vlayout->addWidget( new QLabel( tr( "Provider" ) ) );
5539 mProviderComboBox = new QComboBox();
5540 mProviderComboBox->addItem( QObject::tr( "Postgres" ), QStringLiteral( "postgres" ) );
5541 mProviderComboBox->addItem( QObject::tr( "GeoPackage" ), QStringLiteral( "ogr" ) );
5542 mProviderComboBox->addItem( QObject::tr( "Spatialite" ), QStringLiteral( "spatialite" ) );
5543
5544 vlayout->addWidget( mProviderComboBox );
5545
5546 vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
5547
5548 mDefaultEdit = new QLineEdit();
5549 vlayout->addWidget( mDefaultEdit );
5550 setLayout( vlayout );
5551
5552 if ( connectionParam )
5553 {
5554 mProviderComboBox->setCurrentIndex( mProviderComboBox->findData( connectionParam->providerId() ) );
5555 mDefaultEdit->setText( connectionParam->defaultValueForGui().toString() );
5556 }
5557}
5558
5559QgsProcessingParameterDefinition *QgsProcessingProviderConnectionParameterDefinitionWidget::createParameter( const QString &name, const QString &description, Qgis::ProcessingParameterFlags flags ) const
5560{
5561 QVariant defaultVal;
5562 if ( mDefaultEdit->text().isEmpty() )
5563 defaultVal = QVariant();
5564 else
5565 defaultVal = mDefaultEdit->text();
5566 auto param = std::make_unique<QgsProcessingParameterProviderConnection>( name, description, mProviderComboBox->currentData().toString(), defaultVal );
5567 param->setFlags( flags );
5568 return param.release();
5569}
5570
5571
5572QgsProcessingProviderConnectionWidgetWrapper::QgsProcessingProviderConnectionWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type, QWidget *parent )
5573 : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
5574{
5575}
5576
5577QWidget *QgsProcessingProviderConnectionWidgetWrapper::createWidget()
5578{
5579 const QgsProcessingParameterProviderConnection *connectionParam = dynamic_cast<const QgsProcessingParameterProviderConnection *>( parameterDefinition() );
5580
5581 mProviderComboBox = new QgsProviderConnectionComboBox( connectionParam->providerId() );
5582 if ( connectionParam->flags() & Qgis::ProcessingParameterFlag::Optional )
5583 mProviderComboBox->setAllowEmptyConnection( true );
5584
5585 switch ( type() )
5586 {
5589 break;
5591 mProviderComboBox->setEditable( true );
5592 break;
5593 }
5594
5595 mProviderComboBox->setToolTip( parameterDefinition()->toolTip() );
5596 connect( mProviderComboBox, &QgsProviderConnectionComboBox::currentTextChanged, this, [=]( const QString & ) {
5597 if ( mBlockSignals )
5598 return;
5599
5600 emit widgetValueHasChanged( this );
5601 } );
5602
5603 return mProviderComboBox;
5604}
5605
5606QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingProviderConnectionWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
5607{
5608 return new QgsProcessingProviderConnectionParameterDefinitionWidget( context, widgetContext, definition, algorithm );
5609}
5610
5611void QgsProcessingProviderConnectionWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
5612{
5613 const QString v = QgsProcessingParameters::parameterAsConnectionName( parameterDefinition(), value, context );
5614
5615 if ( !value.isValid() )
5616 mProviderComboBox->setCurrentIndex( -1 );
5617 else
5618 {
5619 if ( mProviderComboBox->isEditable() )
5620 {
5621 const QString prev = mProviderComboBox->currentText();
5622 mBlockSignals++;
5623 mProviderComboBox->setConnection( v );
5624 mProviderComboBox->setCurrentText( v );
5625
5626 mBlockSignals--;
5627 if ( prev != v )
5628 emit widgetValueHasChanged( this );
5629 }
5630 else
5631 mProviderComboBox->setConnection( v );
5632 }
5633}
5634
5635QVariant QgsProcessingProviderConnectionWidgetWrapper::widgetValue() const
5636{
5637 if ( mProviderComboBox )
5638 if ( mProviderComboBox->isEditable() )
5639 return mProviderComboBox->currentText().isEmpty() ? QVariant() : QVariant( mProviderComboBox->currentText() );
5640 else
5641 return mProviderComboBox->currentConnection().isEmpty() ? QVariant() : QVariant( mProviderComboBox->currentConnection() );
5642 else
5643 return QVariant();
5644}
5645
5646QString QgsProcessingProviderConnectionWidgetWrapper::modelerExpressionFormatString() const
5647{
5648 return tr( "connection name as a string value" );
5649}
5650
5651QString QgsProcessingProviderConnectionWidgetWrapper::parameterType() const
5652{
5654}
5655
5656QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingProviderConnectionWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type )
5657{
5658 return new QgsProcessingProviderConnectionWidgetWrapper( parameter, type );
5659}
5660
5661
5662//
5663// QgsProcessingDatabaseSchemaWidgetWrapper
5664//
5665
5666QgsProcessingDatabaseSchemaParameterDefinitionWidget::QgsProcessingDatabaseSchemaParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
5667 : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
5668{
5669 const QgsProcessingParameterDatabaseSchema *schemaParam = dynamic_cast<const QgsProcessingParameterDatabaseSchema *>( definition );
5670
5671 QVBoxLayout *vlayout = new QVBoxLayout();
5672 vlayout->setContentsMargins( 0, 0, 0, 0 );
5673
5674 mConnectionParamComboBox = new QComboBox();
5675 QString initialConnection;
5676 if ( schemaParam )
5677 {
5678 initialConnection = schemaParam->parentConnectionParameterName();
5679 }
5680
5681 if ( auto *lModel = widgetContext.model() )
5682 {
5683 // populate combo box with other model input choices
5684 const QMap<QString, QgsProcessingModelParameter> components = lModel->parameterComponents();
5685 for ( auto it = components.constBegin(); it != components.constEnd(); ++it )
5686 {
5687 if ( definition && it->parameterName() == definition->name() )
5688 continue;
5689
5690 if ( !dynamic_cast<const QgsProcessingParameterProviderConnection *>( lModel->parameterDefinition( it->parameterName() ) ) )
5691 continue;
5692
5693 mConnectionParamComboBox->addItem( it->parameterName(), it->parameterName() );
5694 if ( !initialConnection.isEmpty() && initialConnection == it->parameterName() )
5695 {
5696 mConnectionParamComboBox->setCurrentIndex( mConnectionParamComboBox->count() - 1 );
5697 }
5698 }
5699 }
5700
5701 if ( mConnectionParamComboBox->count() == 0 && !initialConnection.isEmpty() )
5702 {
5703 // if no candidates found, we just add the existing one as a placeholder
5704 mConnectionParamComboBox->addItem( initialConnection, initialConnection );
5705 mConnectionParamComboBox->setCurrentIndex( mConnectionParamComboBox->count() - 1 );
5706 }
5707
5708 vlayout->addWidget( new QLabel( tr( "Provider connection parameter" ) ) );
5709 vlayout->addWidget( mConnectionParamComboBox );
5710
5711 vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
5712
5713 mDefaultEdit = new QLineEdit();
5714 vlayout->addWidget( mDefaultEdit );
5715 setLayout( vlayout );
5716
5717 if ( schemaParam )
5718 {
5719 mDefaultEdit->setText( schemaParam->defaultValueForGui().toString() );
5720 }
5721}
5722
5723QgsProcessingParameterDefinition *QgsProcessingDatabaseSchemaParameterDefinitionWidget::createParameter( const QString &name, const QString &description, Qgis::ProcessingParameterFlags flags ) const
5724{
5725 QVariant defaultVal;
5726 if ( mDefaultEdit->text().isEmpty() )
5727 defaultVal = QVariant();
5728 else
5729 defaultVal = mDefaultEdit->text();
5730 auto param = std::make_unique<QgsProcessingParameterDatabaseSchema>( name, description, mConnectionParamComboBox->currentData().toString(), defaultVal );
5731 param->setFlags( flags );
5732 return param.release();
5733}
5734
5735
5736QgsProcessingDatabaseSchemaWidgetWrapper::QgsProcessingDatabaseSchemaWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type, QWidget *parent )
5737 : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
5738{
5739}
5740
5741QWidget *QgsProcessingDatabaseSchemaWidgetWrapper::createWidget()
5742{
5743 const QgsProcessingParameterDatabaseSchema *schemaParam = dynamic_cast<const QgsProcessingParameterDatabaseSchema *>( parameterDefinition() );
5744
5745 mSchemaComboBox = new QgsDatabaseSchemaComboBox( QString(), QString() );
5746 if ( schemaParam->flags() & Qgis::ProcessingParameterFlag::Optional )
5747 mSchemaComboBox->setAllowEmptySchema( true );
5748
5749 switch ( type() )
5750 {
5753 break;
5755 mSchemaComboBox->comboBox()->setEditable( true );
5756 break;
5757 }
5758
5759 mSchemaComboBox->setToolTip( parameterDefinition()->toolTip() );
5760 connect( mSchemaComboBox->comboBox(), &QComboBox::currentTextChanged, this, [=]( const QString & ) {
5761 if ( mBlockSignals )
5762 return;
5763
5764 emit widgetValueHasChanged( this );
5765 } );
5766
5767 return mSchemaComboBox;
5768}
5769
5770QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingDatabaseSchemaWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
5771{
5772 return new QgsProcessingDatabaseSchemaParameterDefinitionWidget( context, widgetContext, definition, algorithm );
5773}
5774
5775void QgsProcessingDatabaseSchemaWidgetWrapper::setParentConnectionWrapperValue( const QgsAbstractProcessingParameterWidgetWrapper *parentWrapper )
5776{
5777 // evaluate value to connection
5778 QgsProcessingContext *context = nullptr;
5779 std::unique_ptr<QgsProcessingContext> tmpContext;
5780 if ( mProcessingContextGenerator )
5781 context = mProcessingContextGenerator->processingContext();
5782
5783 if ( !context )
5784 {
5785 tmpContext = std::make_unique<QgsProcessingContext>();
5786 context = tmpContext.get();
5787 }
5788
5789 const QVariant value = parentWrapper->parameterValue();
5790 const QString connection = value.isValid() ? QgsProcessingParameters::parameterAsConnectionName( parentWrapper->parameterDefinition(), value, *context ) : QString();
5791
5792 if ( mSchemaComboBox )
5793 mSchemaComboBox->setConnectionName( connection, qgis::down_cast<const QgsProcessingParameterProviderConnection *>( parentWrapper->parameterDefinition() )->providerId() );
5794
5795 const QgsProcessingParameterDatabaseSchema *schemaParam = qgis::down_cast<const QgsProcessingParameterDatabaseSchema *>( parameterDefinition() );
5796 if ( schemaParam->defaultValueForGui().isValid() )
5797 setWidgetValue( parameterDefinition()->defaultValueForGui(), *context );
5798}
5799
5800void QgsProcessingDatabaseSchemaWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
5801{
5802 const QString v = QgsProcessingParameters::parameterAsSchema( parameterDefinition(), value, context );
5803
5804 if ( !value.isValid() )
5805 mSchemaComboBox->comboBox()->setCurrentIndex( -1 );
5806 else
5807 {
5808 if ( mSchemaComboBox->comboBox()->isEditable() )
5809 {
5810 const QString prev = mSchemaComboBox->comboBox()->currentText();
5811 mBlockSignals++;
5812 mSchemaComboBox->setSchema( v );
5813 mSchemaComboBox->comboBox()->setCurrentText( v );
5814
5815 mBlockSignals--;
5816 if ( prev != v )
5817 emit widgetValueHasChanged( this );
5818 }
5819 else
5820 mSchemaComboBox->setSchema( v );
5821 }
5822}
5823
5824QVariant QgsProcessingDatabaseSchemaWidgetWrapper::widgetValue() const
5825{
5826 if ( mSchemaComboBox )
5827 if ( mSchemaComboBox->comboBox()->isEditable() )
5828 return mSchemaComboBox->comboBox()->currentText().isEmpty() ? QVariant() : QVariant( mSchemaComboBox->comboBox()->currentText() );
5829 else
5830 return mSchemaComboBox->currentSchema().isEmpty() ? QVariant() : QVariant( mSchemaComboBox->currentSchema() );
5831 else
5832 return QVariant();
5833}
5834
5835QString QgsProcessingDatabaseSchemaWidgetWrapper::modelerExpressionFormatString() const
5836{
5837 return tr( "database schema name as a string value" );
5838}
5839
5840QString QgsProcessingDatabaseSchemaWidgetWrapper::parameterType() const
5841{
5843}
5844
5845QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingDatabaseSchemaWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type )
5846{
5847 return new QgsProcessingDatabaseSchemaWidgetWrapper( parameter, type );
5848}
5849
5850void QgsProcessingDatabaseSchemaWidgetWrapper::postInitialize( const QList<QgsAbstractProcessingParameterWidgetWrapper *> &wrappers )
5851{
5853 switch ( type() )
5854 {
5857 {
5858 for ( const QgsAbstractProcessingParameterWidgetWrapper *wrapper : wrappers )
5859 {
5860 if ( wrapper->parameterDefinition()->name() == static_cast<const QgsProcessingParameterDatabaseSchema *>( parameterDefinition() )->parentConnectionParameterName() )
5861 {
5862 setParentConnectionWrapperValue( wrapper );
5864 setParentConnectionWrapperValue( wrapper );
5865 } );
5866 break;
5867 }
5868 }
5869 break;
5870 }
5871
5873 break;
5874 }
5875}
5876
5877
5878//
5879// QgsProcessingDatabaseTableWidgetWrapper
5880//
5881
5882QgsProcessingDatabaseTableParameterDefinitionWidget::QgsProcessingDatabaseTableParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
5883 : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
5884{
5885 const QgsProcessingParameterDatabaseTable *tableParam = dynamic_cast<const QgsProcessingParameterDatabaseTable *>( definition );
5886
5887 QVBoxLayout *vlayout = new QVBoxLayout();
5888 vlayout->setContentsMargins( 0, 0, 0, 0 );
5889
5890 mConnectionParamComboBox = new QComboBox();
5891 mSchemaParamComboBox = new QComboBox();
5892 QString initialConnection;
5893 QString initialSchema;
5894 if ( tableParam )
5895 {
5896 initialConnection = tableParam->parentConnectionParameterName();
5897 initialSchema = tableParam->parentSchemaParameterName();
5898 }
5899
5900 if ( auto *lModel = widgetContext.model() )
5901 {
5902 // populate combo box with other model input choices
5903 const QMap<QString, QgsProcessingModelParameter> components = lModel->parameterComponents();
5904 for ( auto it = components.constBegin(); it != components.constEnd(); ++it )
5905 {
5906 if ( definition && it->parameterName() == definition->name() )
5907 continue;
5908
5909 if ( dynamic_cast<const QgsProcessingParameterProviderConnection *>( lModel->parameterDefinition( it->parameterName() ) ) )
5910 {
5911 mConnectionParamComboBox->addItem( it->parameterName(), it->parameterName() );
5912 if ( !initialConnection.isEmpty() && initialConnection == it->parameterName() )
5913 {
5914 mConnectionParamComboBox->setCurrentIndex( mConnectionParamComboBox->count() - 1 );
5915 }
5916 }
5917 else if ( dynamic_cast<const QgsProcessingParameterDatabaseSchema *>( lModel->parameterDefinition( it->parameterName() ) ) )
5918 {
5919 mSchemaParamComboBox->addItem( it->parameterName(), it->parameterName() );
5920 if ( !initialConnection.isEmpty() && initialConnection == it->parameterName() )
5921 {
5922 mSchemaParamComboBox->setCurrentIndex( mSchemaParamComboBox->count() - 1 );
5923 }
5924 }
5925 }
5926 }
5927
5928 if ( mConnectionParamComboBox->count() == 0 && !initialConnection.isEmpty() )
5929 {
5930 // if no candidates found, we just add the existing one as a placeholder
5931 mConnectionParamComboBox->addItem( initialConnection, initialConnection );
5932 mConnectionParamComboBox->setCurrentIndex( mConnectionParamComboBox->count() - 1 );
5933 }
5934
5935 if ( mSchemaParamComboBox->count() == 0 && !initialSchema.isEmpty() )
5936 {
5937 // if no candidates found, we just add the existing one as a placeholder
5938 mSchemaParamComboBox->addItem( initialSchema, initialSchema );
5939 mSchemaParamComboBox->setCurrentIndex( mSchemaParamComboBox->count() - 1 );
5940 }
5941
5942 vlayout->addWidget( new QLabel( tr( "Provider connection parameter" ) ) );
5943 vlayout->addWidget( mConnectionParamComboBox );
5944
5945 vlayout->addWidget( new QLabel( tr( "Database schema parameter" ) ) );
5946 vlayout->addWidget( mSchemaParamComboBox );
5947
5948 vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
5949
5950 mDefaultEdit = new QLineEdit();
5951 vlayout->addWidget( mDefaultEdit );
5952 setLayout( vlayout );
5953
5954 if ( tableParam )
5955 {
5956 mDefaultEdit->setText( tableParam->defaultValueForGui().toString() );
5957 }
5958}
5959
5960QgsProcessingParameterDefinition *QgsProcessingDatabaseTableParameterDefinitionWidget::createParameter( const QString &name, const QString &description, Qgis::ProcessingParameterFlags flags ) const
5961{
5962 QVariant defaultVal;
5963 if ( mDefaultEdit->text().isEmpty() )
5964 defaultVal = QVariant();
5965 else
5966 defaultVal = mDefaultEdit->text();
5967 auto param = std::make_unique<QgsProcessingParameterDatabaseTable>( name, description, mConnectionParamComboBox->currentData().toString(), mSchemaParamComboBox->currentData().toString(), defaultVal );
5968 param->setFlags( flags );
5969 return param.release();
5970}
5971
5972
5973QgsProcessingDatabaseTableWidgetWrapper::QgsProcessingDatabaseTableWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type, QWidget *parent )
5974 : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
5975{
5976}
5977
5978QWidget *QgsProcessingDatabaseTableWidgetWrapper::createWidget()
5979{
5980 const QgsProcessingParameterDatabaseTable *tableParam = dynamic_cast<const QgsProcessingParameterDatabaseTable *>( parameterDefinition() );
5981
5982 mTableComboBox = new QgsDatabaseTableComboBox( QString(), QString() );
5983 if ( tableParam->flags() & Qgis::ProcessingParameterFlag::Optional )
5984 mTableComboBox->setAllowEmptyTable( true );
5985
5986 if ( type() == Qgis::ProcessingMode::Modeler || tableParam->allowNewTableNames() )
5987 mTableComboBox->comboBox()->setEditable( true );
5988
5989 mTableComboBox->setToolTip( parameterDefinition()->toolTip() );
5990 connect( mTableComboBox->comboBox(), &QComboBox::currentTextChanged, this, [=]( const QString & ) {
5991 if ( mBlockSignals )
5992 return;
5993
5994 emit widgetValueHasChanged( this );
5995 } );
5996
5997 return mTableComboBox;
5998}
5999
6000QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingDatabaseTableWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
6001{
6002 return new QgsProcessingDatabaseTableParameterDefinitionWidget( context, widgetContext, definition, algorithm );
6003}
6004
6005void QgsProcessingDatabaseTableWidgetWrapper::setParentConnectionWrapperValue( const QgsAbstractProcessingParameterWidgetWrapper *parentWrapper )
6006{
6007 // evaluate value to connection
6008 QgsProcessingContext *context = nullptr;
6009 std::unique_ptr<QgsProcessingContext> tmpContext;
6010 if ( mProcessingContextGenerator )
6011 context = mProcessingContextGenerator->processingContext();
6012
6013 if ( !context )
6014 {
6015 tmpContext = std::make_unique<QgsProcessingContext>();
6016 context = tmpContext.get();
6017 }
6018
6019 QVariant value = parentWrapper->parameterValue();
6020 mConnection = value.isValid() ? QgsProcessingParameters::parameterAsConnectionName( parentWrapper->parameterDefinition(), value, *context ) : QString();
6021 mProvider = qgis::down_cast<const QgsProcessingParameterProviderConnection *>( parentWrapper->parameterDefinition() )->providerId();
6022 if ( mTableComboBox && !mSchema.isEmpty() )
6023 {
6024 mTableComboBox->setSchema( mSchema );
6025 mTableComboBox->setConnectionName( mConnection, mProvider );
6026
6027 const QgsProcessingParameterDatabaseTable *tableParam = qgis::down_cast<const QgsProcessingParameterDatabaseTable *>( parameterDefinition() );
6028 if ( tableParam->defaultValueForGui().isValid() )
6029 setWidgetValue( parameterDefinition()->defaultValueForGui(), *context );
6030 }
6031}
6032
6033void QgsProcessingDatabaseTableWidgetWrapper::setParentSchemaWrapperValue( const QgsAbstractProcessingParameterWidgetWrapper *parentWrapper )
6034{
6035 // evaluate value to schema
6036 QgsProcessingContext *context = nullptr;
6037 std::unique_ptr<QgsProcessingContext> tmpContext;
6038 if ( mProcessingContextGenerator )
6039 context = mProcessingContextGenerator->processingContext();
6040
6041 if ( !context )
6042 {
6043 tmpContext = std::make_unique<QgsProcessingContext>();
6044 context = tmpContext.get();
6045 }
6046
6047 QVariant value = parentWrapper->parameterValue();
6048 mSchema = value.isValid() ? QgsProcessingParameters::parameterAsSchema( parentWrapper->parameterDefinition(), value, *context ) : QString();
6049
6050 if ( mTableComboBox && !mSchema.isEmpty() && !mConnection.isEmpty() )
6051 {
6052 mTableComboBox->setSchema( mSchema );
6053 mTableComboBox->setConnectionName( mConnection, mProvider );
6054
6055 const QgsProcessingParameterDatabaseTable *tableParam = static_cast<const QgsProcessingParameterDatabaseTable *>( parameterDefinition() );
6056 if ( tableParam->defaultValueForGui().isValid() )
6057 setWidgetValue( parameterDefinition()->defaultValueForGui(), *context );
6058 }
6059}
6060
6061void QgsProcessingDatabaseTableWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
6062{
6063 const QString v = QgsProcessingParameters::parameterAsDatabaseTableName( parameterDefinition(), value, context );
6064
6065 if ( !value.isValid() )
6066 mTableComboBox->comboBox()->setCurrentIndex( -1 );
6067 else
6068 {
6069 if ( mTableComboBox->comboBox()->isEditable() )
6070 {
6071 const QString prev = mTableComboBox->comboBox()->currentText();
6072 mBlockSignals++;
6073 mTableComboBox->setTable( v );
6074 mTableComboBox->comboBox()->setCurrentText( v );
6075
6076 mBlockSignals--;
6077 if ( prev != v )
6078 emit widgetValueHasChanged( this );
6079 }
6080 else
6081 mTableComboBox->setTable( v );
6082 }
6083}
6084
6085QVariant QgsProcessingDatabaseTableWidgetWrapper::widgetValue() const
6086{
6087 if ( mTableComboBox )
6088 if ( mTableComboBox->comboBox()->isEditable() )
6089 return mTableComboBox->comboBox()->currentText().isEmpty() ? QVariant() : QVariant( mTableComboBox->comboBox()->currentText() );
6090 else
6091 return mTableComboBox->currentTable().isEmpty() ? QVariant() : QVariant( mTableComboBox->currentTable() );
6092 else
6093 return QVariant();
6094}
6095
6096QString QgsProcessingDatabaseTableWidgetWrapper::modelerExpressionFormatString() const
6097{
6098 return tr( "database table name as a string value" );
6099}
6100
6101QString QgsProcessingDatabaseTableWidgetWrapper::parameterType() const
6102{
6104}
6105
6106QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingDatabaseTableWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type )
6107{
6108 return new QgsProcessingDatabaseTableWidgetWrapper( parameter, type );
6109}
6110
6111void QgsProcessingDatabaseTableWidgetWrapper::postInitialize( const QList<QgsAbstractProcessingParameterWidgetWrapper *> &wrappers )
6112{
6114 switch ( type() )
6115 {
6118 {
6119 for ( const QgsAbstractProcessingParameterWidgetWrapper *wrapper : wrappers )
6120 {
6121 if ( wrapper->parameterDefinition()->name() == static_cast<const QgsProcessingParameterDatabaseTable *>( parameterDefinition() )->parentConnectionParameterName() )
6122 {
6123 setParentConnectionWrapperValue( wrapper );
6125 setParentConnectionWrapperValue( wrapper );
6126 } );
6127 }
6128 else if ( wrapper->parameterDefinition()->name() == static_cast<const QgsProcessingParameterDatabaseTable *>( parameterDefinition() )->parentSchemaParameterName() )
6129 {
6130 setParentSchemaWrapperValue( wrapper );
6132 setParentSchemaWrapperValue( wrapper );
6133 } );
6134 }
6135 }
6136 break;
6137 }
6138
6140 break;
6141 }
6142}
6143
6144
6145//
6146// QgsProcessingExtentWidgetWrapper
6147//
6148
6149QgsProcessingExtentParameterDefinitionWidget::QgsProcessingExtentParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
6150 : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
6151{
6152 QVBoxLayout *vlayout = new QVBoxLayout();
6153 vlayout->setContentsMargins( 0, 0, 0, 0 );
6154
6155 vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
6156
6157 mDefaultWidget = new QgsExtentWidget();
6158 mDefaultWidget->setNullValueAllowed( true, tr( "Not set" ) );
6159 if ( const QgsProcessingParameterExtent *extentParam = dynamic_cast<const QgsProcessingParameterExtent *>( definition ) )
6160 {
6161 if ( extentParam->defaultValueForGui().isValid() )
6162 {
6163 QgsRectangle rect = QgsProcessingParameters::parameterAsExtent( extentParam, extentParam->defaultValueForGui(), context );
6164 QgsCoordinateReferenceSystem crs = QgsProcessingParameters::parameterAsExtentCrs( extentParam, extentParam->defaultValueForGui(), context );
6165 mDefaultWidget->setCurrentExtent( rect, crs );
6166 mDefaultWidget->setOutputExtentFromCurrent();
6167 }
6168 else
6169 {
6170 mDefaultWidget->clear();
6171 }
6172 }
6173
6174 vlayout->addWidget( mDefaultWidget );
6175 setLayout( vlayout );
6176}
6177
6178QgsProcessingParameterDefinition *QgsProcessingExtentParameterDefinitionWidget::createParameter( const QString &name, const QString &description, Qgis::ProcessingParameterFlags flags ) const
6179{
6180 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();
6181 auto param = std::make_unique<QgsProcessingParameterExtent>( name, description, !defaultVal.isEmpty() ? QVariant( defaultVal ) : QVariant() );
6182 param->setFlags( flags );
6183 return param.release();
6184}
6185
6186
6187QgsProcessingExtentWidgetWrapper::QgsProcessingExtentWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type, QWidget *parent )
6188 : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
6189{
6190}
6191
6192QWidget *QgsProcessingExtentWidgetWrapper::createWidget()
6193{
6194 const QgsProcessingParameterExtent *extentParam = dynamic_cast<const QgsProcessingParameterExtent *>( parameterDefinition() );
6195 switch ( type() )
6196 {
6200 {
6201 mExtentWidget = new QgsExtentWidget( nullptr );
6202 if ( widgetContext().mapCanvas() )
6203 mExtentWidget->setMapCanvas( widgetContext().mapCanvas() );
6204
6205 if ( extentParam->flags() & Qgis::ProcessingParameterFlag::Optional )
6206 mExtentWidget->setNullValueAllowed( true, tr( "Not set" ) );
6207
6208 mExtentWidget->setToolTip( parameterDefinition()->toolTip() );
6209
6210 connect( mExtentWidget, &QgsExtentWidget::extentChanged, this, [=] {
6211 emit widgetValueHasChanged( this );
6212 } );
6213
6214 if ( mDialog && type() != Qgis::ProcessingMode::Modeler )
6215 setDialog( mDialog ); // setup connections to panel - dialog was previously set before the widget was created
6216
6217 return mExtentWidget;
6218 }
6219 }
6220 return nullptr;
6221}
6222
6223void QgsProcessingExtentWidgetWrapper::setWidgetContext( const QgsProcessingParameterWidgetContext &context )
6224{
6226 if ( mExtentWidget && context.mapCanvas() && type() != Qgis::ProcessingMode::Modeler )
6227 mExtentWidget->setMapCanvas( context.mapCanvas() );
6228}
6229
6230void QgsProcessingExtentWidgetWrapper::setDialog( QDialog *dialog )
6231{
6232 mDialog = dialog;
6233 if ( mExtentWidget && mDialog && type() != Qgis::ProcessingMode::Modeler )
6234 {
6235 connect( mExtentWidget, &QgsExtentWidget::toggleDialogVisibility, mDialog, [=]( bool visible ) {
6236 if ( !visible )
6237 mDialog->showMinimized();
6238 else
6239 {
6240 mDialog->showNormal();
6241 mDialog->raise();
6242 mDialog->activateWindow();
6243 }
6244 } );
6245 }
6247}
6248
6249void QgsProcessingExtentWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
6250{
6251 if ( mExtentWidget )
6252 {
6253 if ( !value.isValid() || ( value.userType() == QMetaType::Type::QString && value.toString().isEmpty() ) )
6254 mExtentWidget->clear();
6255 else
6256 {
6257 QgsRectangle r = QgsProcessingParameters::parameterAsExtent( parameterDefinition(), value, context );
6258 QgsCoordinateReferenceSystem crs = QgsProcessingParameters::parameterAsPointCrs( parameterDefinition(), value, context );
6259 mExtentWidget->setCurrentExtent( r, crs );
6260 mExtentWidget->setOutputExtentFromUser( r, crs );
6261 }
6262 }
6263}
6264
6265QVariant QgsProcessingExtentWidgetWrapper::widgetValue() const
6266{
6267 if ( mExtentWidget )
6268 {
6269 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();
6270
6271 return val.isEmpty() ? QVariant() : QVariant( val );
6272 }
6273 else
6274 return QVariant();
6275}
6276
6277QString QgsProcessingExtentWidgetWrapper::modelerExpressionFormatString() const
6278{
6279 return tr( "string of the format 'x min,x max,y min,y max' or a geometry value (bounding box is used)" );
6280}
6281
6282QString QgsProcessingExtentWidgetWrapper::parameterType() const
6283{
6285}
6286
6287QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingExtentWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type )
6288{
6289 return new QgsProcessingExtentWidgetWrapper( parameter, type );
6290}
6291
6292QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingExtentWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
6293{
6294 return new QgsProcessingExtentParameterDefinitionWidget( context, widgetContext, definition, algorithm );
6295}
6296
6297
6298//
6299// QgsProcessingMapLayerWidgetWrapper
6300//
6301
6302QgsProcessingMapLayerParameterDefinitionWidget::QgsProcessingMapLayerParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
6303 : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
6304{
6305 QVBoxLayout *vlayout = new QVBoxLayout();
6306 vlayout->setContentsMargins( 0, 0, 0, 0 );
6307
6308 vlayout->addWidget( new QLabel( tr( "Layer type" ) ) );
6309 mLayerTypeComboBox = new QgsCheckableComboBox();
6310 mLayerTypeComboBox->addItem( tr( "Any Map Layer" ), static_cast<int>( Qgis::ProcessingSourceType::MapLayer ) );
6311 mLayerTypeComboBox->addItem( tr( "Vector (Point)" ), static_cast<int>( Qgis::ProcessingSourceType::VectorPoint ) );
6312 mLayerTypeComboBox->addItem( tr( "Vector (Line)" ), static_cast<int>( Qgis::ProcessingSourceType::VectorLine ) );
6313 mLayerTypeComboBox->addItem( tr( "Vector (Polygon)" ), static_cast<int>( Qgis::ProcessingSourceType::VectorPolygon ) );
6314 mLayerTypeComboBox->addItem( tr( "Vector (Any Geometry Type)" ), static_cast<int>( Qgis::ProcessingSourceType::VectorAnyGeometry ) );
6315 mLayerTypeComboBox->addItem( tr( "Vector (No Geometry Required)" ), static_cast<int>( Qgis::ProcessingSourceType::Vector ) );
6316 mLayerTypeComboBox->addItem( tr( "Raster" ), static_cast<int>( Qgis::ProcessingSourceType::Raster ) );
6317 mLayerTypeComboBox->addItem( tr( "Mesh" ), static_cast<int>( Qgis::ProcessingSourceType::Mesh ) );
6318 mLayerTypeComboBox->addItem( tr( "Plugin" ), static_cast<int>( Qgis::ProcessingSourceType::Plugin ) );
6319 mLayerTypeComboBox->addItem( tr( "Point Cloud" ), static_cast<int>( Qgis::ProcessingSourceType::PointCloud ) );
6320 mLayerTypeComboBox->addItem( tr( "Annotation" ), static_cast<int>( Qgis::ProcessingSourceType::Annotation ) );
6321
6322 if ( const QgsProcessingParameterMapLayer *layerParam = dynamic_cast<const QgsProcessingParameterMapLayer *>( definition ) )
6323 {
6324 for ( int i : layerParam->dataTypes() )
6325 {
6326 mLayerTypeComboBox->setItemCheckState( mLayerTypeComboBox->findData( i ), Qt::Checked );
6327 }
6328 }
6329
6330 vlayout->addWidget( mLayerTypeComboBox );
6331
6332 setLayout( vlayout );
6333}
6334
6335QgsProcessingParameterDefinition *QgsProcessingMapLayerParameterDefinitionWidget::createParameter( const QString &name, const QString &description, Qgis::ProcessingParameterFlags flags ) const
6336{
6337 QList<int> dataTypes;
6338 for ( const QVariant &v : mLayerTypeComboBox->checkedItemsData() )
6339 dataTypes << v.toInt();
6340
6341 auto param = std::make_unique<QgsProcessingParameterMapLayer>( name, description );
6342 param->setDataTypes( dataTypes );
6343 param->setFlags( flags );
6344 return param.release();
6345}
6346
6347QgsProcessingMapLayerWidgetWrapper::QgsProcessingMapLayerWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type, QWidget *parent )
6348 : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
6349{
6350}
6351
6352QWidget *QgsProcessingMapLayerWidgetWrapper::createWidget()
6353{
6354 mComboBox = new QgsProcessingMapLayerComboBox( parameterDefinition(), type() );
6355
6356 switch ( type() )
6357 {
6360 break;
6362 mComboBox->setEditable( true );
6363 break;
6364 }
6365
6366 mComboBox->setToolTip( parameterDefinition()->toolTip() );
6367
6368 connect( mComboBox, &QgsProcessingMapLayerComboBox::valueChanged, this, [=]() {
6369 if ( mBlockSignals )
6370 return;
6371
6372 emit widgetValueHasChanged( this );
6373 } );
6374
6375 setWidgetContext( widgetContext() );
6376 return mComboBox;
6377}
6378
6379void QgsProcessingMapLayerWidgetWrapper::setWidgetContext( const QgsProcessingParameterWidgetContext &context )
6380{
6382 if ( mComboBox )
6383 {
6384 mComboBox->setWidgetContext( context );
6385
6386 if ( !( parameterDefinition()->flags() & Qgis::ProcessingParameterFlag::Optional ) )
6387 {
6388 // non optional parameter -- if no default value set, default to active layer
6389 if ( !parameterDefinition()->defaultValueForGui().isValid() )
6390 mComboBox->setLayer( context.activeLayer() );
6391 }
6392 }
6393}
6394
6395void QgsProcessingMapLayerWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
6396{
6397 if ( mComboBox )
6398 mComboBox->setValue( value, context );
6399}
6400
6401QVariant QgsProcessingMapLayerWidgetWrapper::widgetValue() const
6402{
6403 return mComboBox ? mComboBox->value() : QVariant();
6404}
6405
6406QString QgsProcessingMapLayerWidgetWrapper::modelerExpressionFormatString() const
6407{
6408 return tr( "path to a map layer" );
6409}
6410
6411Qgis::ProcessingModelChildParameterSource QgsProcessingMapLayerWidgetWrapper::defaultModelSource( const QgsProcessingParameterDefinition *parameter ) const
6412{
6413 // non-optional layer sources default to a matching model input layer, but optional layer parameters
6414 // should default to static values. We don't want all optional layer parameters to have values set by default!
6415 if ( !( parameter->flags() & Qgis::ProcessingParameterFlag::Optional ) )
6416 {
6418 }
6419 else
6420 {
6422 }
6423}
6424
6425QString QgsProcessingMapLayerWidgetWrapper::parameterType() const
6426{
6428}
6429
6430QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingMapLayerWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type )
6431{
6432 return new QgsProcessingMapLayerWidgetWrapper( parameter, type );
6433}
6434
6435QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingMapLayerWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
6436{
6437 return new QgsProcessingMapLayerParameterDefinitionWidget( context, widgetContext, definition, algorithm );
6438}
6439
6440
6441//
6442// QgsProcessingRasterLayerWidgetWrapper
6443//
6444
6445QgsProcessingRasterLayerWidgetWrapper::QgsProcessingRasterLayerWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type, QWidget *parent )
6446 : QgsProcessingMapLayerWidgetWrapper( parameter, type, parent )
6447{
6448}
6449
6450QString QgsProcessingRasterLayerWidgetWrapper::modelerExpressionFormatString() const
6451{
6452 return tr( "path to a raster layer" );
6453}
6454
6455QString QgsProcessingRasterLayerWidgetWrapper::parameterType() const
6456{
6458}
6459
6460QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingRasterLayerWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type )
6461{
6462 return new QgsProcessingRasterLayerWidgetWrapper( parameter, type );
6463}
6464
6465QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingRasterLayerWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
6466{
6467 Q_UNUSED( context );
6468 Q_UNUSED( widgetContext );
6469 Q_UNUSED( definition );
6470 Q_UNUSED( algorithm );
6471
6472 return nullptr;
6473}
6474
6475
6476//
6477// QgsProcessingVectorLayerWidgetWrapper
6478//
6479
6480QgsProcessingVectorLayerParameterDefinitionWidget::QgsProcessingVectorLayerParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
6481 : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
6482{
6483 QVBoxLayout *vlayout = new QVBoxLayout();
6484 vlayout->setContentsMargins( 0, 0, 0, 0 );
6485
6486 vlayout->addWidget( new QLabel( tr( "Geometry type" ) ) );
6487 mGeometryTypeComboBox = new QgsCheckableComboBox();
6488 mGeometryTypeComboBox->addItem( tr( "Geometry Not Required" ), static_cast<int>( Qgis::ProcessingSourceType::Vector ) );
6489 mGeometryTypeComboBox->addItem( tr( "Point" ), static_cast<int>( Qgis::ProcessingSourceType::VectorPoint ) );
6490 mGeometryTypeComboBox->addItem( tr( "Line" ), static_cast<int>( Qgis::ProcessingSourceType::VectorLine ) );
6491 mGeometryTypeComboBox->addItem( tr( "Polygon" ), static_cast<int>( Qgis::ProcessingSourceType::VectorPolygon ) );
6492 mGeometryTypeComboBox->addItem( tr( "Any Geometry Type" ), static_cast<int>( Qgis::ProcessingSourceType::VectorAnyGeometry ) );
6493
6494 if ( const QgsProcessingParameterVectorLayer *vectorParam = dynamic_cast<const QgsProcessingParameterVectorLayer *>( definition ) )
6495 {
6496 for ( int i : vectorParam->dataTypes() )
6497 {
6498 mGeometryTypeComboBox->setItemCheckState( mGeometryTypeComboBox->findData( i ), Qt::Checked );
6499 }
6500 }
6501
6502 vlayout->addWidget( mGeometryTypeComboBox );
6503
6504 setLayout( vlayout );
6505}
6506
6507QgsProcessingParameterDefinition *QgsProcessingVectorLayerParameterDefinitionWidget::createParameter( const QString &name, const QString &description, Qgis::ProcessingParameterFlags flags ) const
6508{
6509 QList<int> dataTypes;
6510 for ( const QVariant &v : mGeometryTypeComboBox->checkedItemsData() )
6511 dataTypes << v.toInt();
6512
6513 auto param = std::make_unique<QgsProcessingParameterVectorLayer>( name, description, dataTypes );
6514 param->setFlags( flags );
6515 return param.release();
6516}
6517
6518
6519QgsProcessingVectorLayerWidgetWrapper::QgsProcessingVectorLayerWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type, QWidget *parent )
6520 : QgsProcessingMapLayerWidgetWrapper( parameter, type, parent )
6521{
6522}
6523
6524QString QgsProcessingVectorLayerWidgetWrapper::modelerExpressionFormatString() const
6525{
6526 return tr( "path to a vector layer" );
6527}
6528
6529QString QgsProcessingVectorLayerWidgetWrapper::parameterType() const
6530{
6532}
6533
6534QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingVectorLayerWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type )
6535{
6536 return new QgsProcessingVectorLayerWidgetWrapper( parameter, type );
6537}
6538
6539QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingVectorLayerWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
6540{
6541 return new QgsProcessingVectorLayerParameterDefinitionWidget( context, widgetContext, definition, algorithm );
6542}
6543
6544
6545//
6546// QgsProcessingFeatureSourceLayerWidgetWrapper
6547//
6548
6549QgsProcessingFeatureSourceParameterDefinitionWidget::QgsProcessingFeatureSourceParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
6550 : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
6551{
6552 QVBoxLayout *vlayout = new QVBoxLayout();
6553 vlayout->setContentsMargins( 0, 0, 0, 0 );
6554
6555 vlayout->addWidget( new QLabel( tr( "Geometry type" ) ) );
6556 mGeometryTypeComboBox = new QgsCheckableComboBox();
6557 mGeometryTypeComboBox->addItem( tr( "Geometry Not Required" ), static_cast<int>( Qgis::ProcessingSourceType::Vector ) );
6558 mGeometryTypeComboBox->addItem( tr( "Point" ), static_cast<int>( Qgis::ProcessingSourceType::VectorPoint ) );
6559 mGeometryTypeComboBox->addItem( tr( "Line" ), static_cast<int>( Qgis::ProcessingSourceType::VectorLine ) );
6560 mGeometryTypeComboBox->addItem( tr( "Polygon" ), static_cast<int>( Qgis::ProcessingSourceType::VectorPolygon ) );
6561 mGeometryTypeComboBox->addItem( tr( "Any Geometry Type" ), static_cast<int>( Qgis::ProcessingSourceType::VectorAnyGeometry ) );
6562
6563 if ( const QgsProcessingParameterFeatureSource *sourceParam = dynamic_cast<const QgsProcessingParameterFeatureSource *>( definition ) )
6564 {
6565 for ( int i : sourceParam->dataTypes() )
6566 {
6567 mGeometryTypeComboBox->setItemCheckState( mGeometryTypeComboBox->findData( i ), Qt::Checked );
6568 }
6569 }
6570 else
6571 {
6572 mGeometryTypeComboBox->setItemCheckState( mGeometryTypeComboBox->findData( static_cast<int>( Qgis::ProcessingSourceType::VectorAnyGeometry ) ), Qt::Checked );
6573 }
6574
6575 vlayout->addWidget( mGeometryTypeComboBox );
6576
6577 setLayout( vlayout );
6578}
6579
6580QgsProcessingParameterDefinition *QgsProcessingFeatureSourceParameterDefinitionWidget::createParameter( const QString &name, const QString &description, Qgis::ProcessingParameterFlags flags ) const
6581{
6582 QList<int> dataTypes;
6583 for ( const QVariant &v : mGeometryTypeComboBox->checkedItemsData() )
6584 dataTypes << v.toInt();
6585
6586 auto param = std::make_unique<QgsProcessingParameterFeatureSource>( name, description, dataTypes );
6587 param->setFlags( flags );
6588 return param.release();
6589}
6590
6591QgsProcessingFeatureSourceWidgetWrapper::QgsProcessingFeatureSourceWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type, QWidget *parent )
6592 : QgsProcessingMapLayerWidgetWrapper( parameter, type, parent )
6593{
6594}
6595
6596QString QgsProcessingFeatureSourceWidgetWrapper::modelerExpressionFormatString() const
6597{
6598 return tr( "path to a vector layer" );
6599}
6600
6601QString QgsProcessingFeatureSourceWidgetWrapper::parameterType() const
6602{
6604}
6605
6606QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingFeatureSourceWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type )
6607{
6608 return new QgsProcessingFeatureSourceWidgetWrapper( parameter, type );
6609}
6610
6611QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingFeatureSourceWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
6612{
6613 return new QgsProcessingFeatureSourceParameterDefinitionWidget( context, widgetContext, definition, algorithm );
6614}
6615
6616//
6617// QgsProcessingMeshLayerWidgetWrapper
6618//
6619
6620QgsProcessingMeshLayerWidgetWrapper::QgsProcessingMeshLayerWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type, QWidget *parent )
6621 : QgsProcessingMapLayerWidgetWrapper( parameter, type, parent )
6622{
6623}
6624
6625QString QgsProcessingMeshLayerWidgetWrapper::modelerExpressionFormatString() const
6626{
6627 return tr( "path to a mesh layer" );
6628}
6629
6630QString QgsProcessingMeshLayerWidgetWrapper::parameterType() const
6631{
6633}
6634
6635QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingMeshLayerWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type )
6636{
6637 return new QgsProcessingMeshLayerWidgetWrapper( parameter, type );
6638}
6639
6640QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingMeshLayerWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
6641{
6642 Q_UNUSED( context );
6643 Q_UNUSED( widgetContext );
6644 Q_UNUSED( definition );
6645 Q_UNUSED( algorithm );
6646
6647 return nullptr;
6648}
6649
6650
6651//
6652// QgsProcessingRasterBandPanelWidget
6653//
6654
6655QgsProcessingRasterBandPanelWidget::QgsProcessingRasterBandPanelWidget( QWidget *parent, const QgsProcessingParameterBand *param )
6656 : QWidget( parent )
6657 , mParam( param )
6658{
6659 QHBoxLayout *hl = new QHBoxLayout();
6660 hl->setContentsMargins( 0, 0, 0, 0 );
6661
6662 mLineEdit = new QLineEdit();
6663 mLineEdit->setEnabled( false );
6664 hl->addWidget( mLineEdit, 1 );
6665
6666 mToolButton = new QToolButton();
6667 mToolButton->setText( QString( QChar( 0x2026 ) ) );
6668 hl->addWidget( mToolButton );
6669
6670 setLayout( hl );
6671
6672 if ( mParam )
6673 {
6674 mLineEdit->setText( tr( "%n band(s) selected", nullptr, 0 ) );
6675 }
6676
6677 connect( mToolButton, &QToolButton::clicked, this, &QgsProcessingRasterBandPanelWidget::showDialog );
6678}
6679
6680void QgsProcessingRasterBandPanelWidget::setBands( const QList<int> &bands )
6681{
6682 mBands = bands;
6683}
6684
6685void QgsProcessingRasterBandPanelWidget::setBandNames( const QHash<int, QString> &names )
6686{
6687 mBandNames = names;
6688}
6689
6690void QgsProcessingRasterBandPanelWidget::setValue( const QVariant &value )
6691{
6692 if ( value.isValid() )
6693 mValue = value.userType() == QMetaType::Type::QVariantList ? value.toList() : QVariantList() << value;
6694 else
6695 mValue.clear();
6696
6697 updateSummaryText();
6698 emit changed();
6699}
6700
6701void QgsProcessingRasterBandPanelWidget::showDialog()
6702{
6703 QVariantList availableOptions;
6704 availableOptions.reserve( mBands.size() );
6705 for ( int band : std::as_const( mBands ) )
6706 {
6707 availableOptions << band;
6708 }
6709
6711 if ( panel && panel->dockMode() )
6712 {
6713 QgsProcessingMultipleSelectionPanelWidget *widget = new QgsProcessingMultipleSelectionPanelWidget( availableOptions, mValue );
6714 widget->setPanelTitle( mParam->description() );
6715
6716 widget->setValueFormatter( [this]( const QVariant &v ) -> QString {
6717 int band = v.toInt();
6718 return mBandNames.contains( band ) ? mBandNames.value( band ) : v.toString();
6719 } );
6720
6721 connect( widget, &QgsProcessingMultipleSelectionPanelWidget::selectionChanged, this, [=]() {
6722 setValue( widget->selectedOptions() );
6723 } );
6724 connect( widget, &QgsProcessingMultipleSelectionPanelWidget::acceptClicked, widget, &QgsPanelWidget::acceptPanel );
6725 panel->openPanel( widget );
6726 }
6727 else
6728 {
6729 QgsProcessingMultipleSelectionDialog dlg( availableOptions, mValue, this, Qt::WindowFlags() );
6730
6731 dlg.setValueFormatter( [this]( const QVariant &v ) -> QString {
6732 int band = v.toInt();
6733 return mBandNames.contains( band ) ? mBandNames.value( band ) : v.toString();
6734 } );
6735 if ( dlg.exec() )
6736 {
6737 setValue( dlg.selectedOptions() );
6738 }
6739 }
6740}
6741
6742void QgsProcessingRasterBandPanelWidget::updateSummaryText()
6743{
6744 if ( mParam )
6745 mLineEdit->setText( tr( "%n band(s) selected", nullptr, mValue.count() ) );
6746}
6747
6748
6749//
6750// QgsProcessingBandWidgetWrapper
6751//
6752
6753QgsProcessingBandParameterDefinitionWidget::QgsProcessingBandParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
6754 : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
6755{
6756 QVBoxLayout *vlayout = new QVBoxLayout();
6757 vlayout->setContentsMargins( 0, 0, 0, 0 );
6758
6759 vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
6760
6761 mDefaultLineEdit = new QLineEdit();
6762 mDefaultLineEdit->setToolTip( tr( "Band number (separate bands with ; for multiple band parameters)" ) );
6763 if ( const QgsProcessingParameterBand *bandParam = dynamic_cast<const QgsProcessingParameterBand *>( definition ) )
6764 {
6765 const QList<int> bands = QgsProcessingParameters::parameterAsInts( bandParam, bandParam->defaultValueForGui(), context );
6766 QStringList defVal;
6767 for ( int b : bands )
6768 {
6769 defVal << QString::number( b );
6770 }
6771
6772 mDefaultLineEdit->setText( defVal.join( ';' ) );
6773 }
6774 vlayout->addWidget( mDefaultLineEdit );
6775
6776 vlayout->addWidget( new QLabel( tr( "Parent layer" ) ) );
6777 mParentLayerComboBox = new QComboBox();
6778
6779 QString initialParent;
6780 if ( const QgsProcessingParameterBand *bandParam = dynamic_cast<const QgsProcessingParameterBand *>( definition ) )
6781 initialParent = bandParam->parentLayerParameterName();
6782
6783 if ( auto *lModel = widgetContext.model() )
6784 {
6785 // populate combo box with other model input choices
6786 const QMap<QString, QgsProcessingModelParameter> components = lModel->parameterComponents();
6787 for ( auto it = components.constBegin(); it != components.constEnd(); ++it )
6788 {
6789 if ( const QgsProcessingParameterRasterLayer *definition = dynamic_cast<const QgsProcessingParameterRasterLayer *>( lModel->parameterDefinition( it.value().parameterName() ) ) )
6790 {
6791 mParentLayerComboBox->addItem( definition->description(), definition->name() );
6792 if ( !initialParent.isEmpty() && initialParent == definition->name() )
6793 {
6794 mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
6795 }
6796 }
6797 }
6798 }
6799
6800 if ( mParentLayerComboBox->count() == 0 && !initialParent.isEmpty() )
6801 {
6802 // if no parent candidates found, we just add the existing one as a placeholder
6803 mParentLayerComboBox->addItem( initialParent, initialParent );
6804 mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
6805 }
6806
6807 vlayout->addWidget( mParentLayerComboBox );
6808
6809 mAllowMultipleCheckBox = new QCheckBox( tr( "Allow multiple" ) );
6810 if ( const QgsProcessingParameterBand *bandParam = dynamic_cast<const QgsProcessingParameterBand *>( definition ) )
6811 mAllowMultipleCheckBox->setChecked( bandParam->allowMultiple() );
6812
6813 vlayout->addWidget( mAllowMultipleCheckBox );
6814 setLayout( vlayout );
6815}
6816
6817QgsProcessingParameterDefinition *QgsProcessingBandParameterDefinitionWidget::createParameter( const QString &name, const QString &description, Qgis::ProcessingParameterFlags flags ) const
6818{
6819 auto param = std::make_unique<QgsProcessingParameterBand>( name, description, mDefaultLineEdit->text().split( ';' ), mParentLayerComboBox->currentData().toString(), false, mAllowMultipleCheckBox->isChecked() );
6820 param->setFlags( flags );
6821 return param.release();
6822}
6823
6824QgsProcessingBandWidgetWrapper::QgsProcessingBandWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type, QWidget *parent )
6825 : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
6826{
6827}
6828
6829QWidget *QgsProcessingBandWidgetWrapper::createWidget()
6830{
6831 const QgsProcessingParameterBand *bandParam = dynamic_cast<const QgsProcessingParameterBand *>( parameterDefinition() );
6832 switch ( type() )
6833 {
6836 {
6837 if ( bandParam->allowMultiple() )
6838 {
6839 mPanel = new QgsProcessingRasterBandPanelWidget( nullptr, bandParam );
6840 mPanel->setToolTip( parameterDefinition()->toolTip() );
6841 connect( mPanel, &QgsProcessingRasterBandPanelWidget::changed, this, [=] {
6842 emit widgetValueHasChanged( this );
6843 } );
6844 return mPanel;
6845 }
6846 else
6847 {
6848 mComboBox = new QgsRasterBandComboBox();
6849 mComboBox->setShowNotSetOption( bandParam->flags() & Qgis::ProcessingParameterFlag::Optional );
6850
6851 mComboBox->setToolTip( parameterDefinition()->toolTip() );
6852 connect( mComboBox, &QgsRasterBandComboBox::bandChanged, this, [=]( int ) {
6853 emit widgetValueHasChanged( this );
6854 } );
6855 return mComboBox;
6856 }
6857 }
6858
6860 {
6861 mLineEdit = new QLineEdit();
6862 mLineEdit->setToolTip( QObject::tr( "Band number (separate bands with ; for multiple band parameters)" ) );
6863 connect( mLineEdit, &QLineEdit::textChanged, this, [=] {
6864 emit widgetValueHasChanged( this );
6865 } );
6866 return mLineEdit;
6867 }
6868 }
6869 return nullptr;
6870}
6871
6872void QgsProcessingBandWidgetWrapper::postInitialize( const QList<QgsAbstractProcessingParameterWidgetWrapper *> &wrappers )
6873{
6875 switch ( type() )
6876 {
6879 {
6880 for ( const QgsAbstractProcessingParameterWidgetWrapper *wrapper : wrappers )
6881 {
6882 if ( wrapper->parameterDefinition()->name() == static_cast<const QgsProcessingParameterBand *>( parameterDefinition() )->parentLayerParameterName() )
6883 {
6884 setParentLayerWrapperValue( wrapper );
6886 setParentLayerWrapperValue( wrapper );
6887 } );
6888 break;
6889 }
6890 }
6891 break;
6892 }
6893
6895 break;
6896 }
6897}
6898
6899void QgsProcessingBandWidgetWrapper::setParentLayerWrapperValue( const QgsAbstractProcessingParameterWidgetWrapper *parentWrapper )
6900{
6901 // evaluate value to layer
6902 QgsProcessingContext *context = nullptr;
6903 std::unique_ptr<QgsProcessingContext> tmpContext;
6904 if ( mProcessingContextGenerator )
6905 context = mProcessingContextGenerator->processingContext();
6906
6907 if ( !context )
6908 {
6909 tmpContext = std::make_unique<QgsProcessingContext>();
6910 context = tmpContext.get();
6911 }
6912
6913 QVariant value = parentWrapper->parameterValue();
6914
6915 QgsRasterLayer *layer = QgsProcessingParameters::parameterAsRasterLayer( parentWrapper->parameterDefinition(), value, *context );
6916 if ( layer && layer->isValid() )
6917 {
6918 // need to grab ownership of layer if required - otherwise layer may be deleted when context
6919 // goes out of scope
6920 std::unique_ptr<QgsMapLayer> ownedLayer( context->takeResultLayer( layer->id() ) );
6921 if ( ownedLayer && ownedLayer->type() == Qgis::LayerType::Raster )
6922 {
6923 mParentLayer.reset( qobject_cast<QgsRasterLayer *>( ownedLayer.release() ) );
6924 layer = mParentLayer.get();
6925 }
6926 else
6927 {
6928 // don't need ownership of this layer - it wasn't owned by context (so e.g. is owned by the project)
6929 }
6930
6931 if ( mComboBox )
6932 mComboBox->setLayer( layer );
6933 else if ( mPanel )
6934 {
6935 QgsRasterDataProvider *provider = layer->dataProvider();
6936 if ( provider && layer->isValid() )
6937 {
6938 //fill available bands
6939 int nBands = provider->bandCount();
6940 QList<int> bands;
6941 QHash<int, QString> bandNames;
6942 for ( int i = 1; i <= nBands; ++i )
6943 {
6944 bandNames.insert( i, QgsRasterBandComboBox::displayBandName( provider, i ) );
6945 bands << i;
6946 }
6947 mPanel->setBands( bands );
6948 mPanel->setBandNames( bandNames );
6949 }
6950 }
6951 }
6952 else
6953 {
6954 if ( mComboBox )
6955 mComboBox->setLayer( nullptr );
6956 else if ( mPanel )
6957 mPanel->setBands( QList<int>() );
6958
6959 if ( value.isValid() && widgetContext().messageBar() )
6960 {
6961 widgetContext().messageBar()->clearWidgets();
6962 widgetContext().messageBar()->pushMessage( QString(), QObject::tr( "Could not load selected layer/table. Dependent bands could not be populated" ), Qgis::MessageLevel::Info );
6963 }
6964 }
6965
6966 if ( parameterDefinition()->defaultValueForGui().isValid() )
6967 setWidgetValue( parameterDefinition()->defaultValueForGui(), *context );
6968}
6969
6970void QgsProcessingBandWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
6971{
6972 if ( mComboBox )
6973 {
6974 if ( !value.isValid() )
6975 mComboBox->setBand( -1 );
6976 else
6977 {
6978 const int v = QgsProcessingParameters::parameterAsInt( parameterDefinition(), value, context );
6979 mComboBox->setBand( v );
6980 }
6981 }
6982 else if ( mPanel )
6983 {
6984 QVariantList opts;
6985 if ( value.isValid() )
6986 {
6987 const QList<int> v = QgsProcessingParameters::parameterAsInts( parameterDefinition(), value, context );
6988 opts.reserve( v.size() );
6989 for ( int i : v )
6990 opts << i;
6991 }
6992 if ( mPanel )
6993 mPanel->setValue( value.isValid() ? opts : QVariant() );
6994 }
6995 else if ( mLineEdit )
6996 {
6997 const QgsProcessingParameterBand *bandParam = static_cast<const QgsProcessingParameterBand *>( parameterDefinition() );
6998 if ( bandParam->allowMultiple() )
6999 {
7000 const QList<int> v = QgsProcessingParameters::parameterAsInts( parameterDefinition(), value, context );
7001 QStringList opts;
7002 opts.reserve( v.size() );
7003 for ( int i : v )
7004 opts << QString::number( i );
7005 mLineEdit->setText( value.isValid() && !opts.empty() ? opts.join( ';' ) : QString() );
7006 }
7007 else
7008 {
7009 if ( value.isValid() )
7010 mLineEdit->setText( QString::number( QgsProcessingParameters::parameterAsInt( parameterDefinition(), value, context ) ) );
7011 else
7012 mLineEdit->clear();
7013 }
7014 }
7015}
7016
7017QVariant QgsProcessingBandWidgetWrapper::widgetValue() const
7018{
7019 if ( mComboBox )
7020 return mComboBox->currentBand() == -1 ? QVariant() : mComboBox->currentBand();
7021 else if ( mPanel )
7022 return !mPanel->value().toList().isEmpty() ? mPanel->value() : QVariant();
7023 else if ( mLineEdit )
7024 {
7025 const QgsProcessingParameterBand *bandParam = static_cast<const QgsProcessingParameterBand *>( parameterDefinition() );
7026 if ( bandParam->allowMultiple() )
7027 {
7028 const QStringList parts = mLineEdit->text().split( ';', Qt::SkipEmptyParts );
7029 QVariantList res;
7030 res.reserve( parts.count() );
7031 for ( const QString &s : parts )
7032 {
7033 bool ok = false;
7034 int band = s.toInt( &ok );
7035 if ( ok )
7036 res << band;
7037 }
7038 return res.isEmpty() ? QVariant() : res;
7039 }
7040 else
7041 {
7042 return mLineEdit->text().isEmpty() ? QVariant() : mLineEdit->text();
7043 }
7044 }
7045 else
7046 return QVariant();
7047}
7048
7049QString QgsProcessingBandWidgetWrapper::modelerExpressionFormatString() const
7050{
7051 return tr( "selected band numbers as an array of numbers, or semicolon separated string of options (e.g. '1;3')" );
7052}
7053
7054QString QgsProcessingBandWidgetWrapper::parameterType() const
7055{
7057}
7058
7059QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingBandWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type )
7060{
7061 return new QgsProcessingBandWidgetWrapper( parameter, type );
7062}
7063
7064QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingBandWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
7065{
7066 return new QgsProcessingBandParameterDefinitionWidget( context, widgetContext, definition, algorithm );
7067}
7068
7069//
7070// QgsProcessingMultipleLayerLineEdit
7071//
7072
7073QgsProcessingMultipleLayerLineEdit::QgsProcessingMultipleLayerLineEdit( QWidget *parent, const QgsProcessingParameterMultipleLayers *param )
7074 : QgsHighlightableLineEdit( parent )
7075 , mParam( param )
7076{
7077 setAcceptDrops( true );
7078}
7079
7080void QgsProcessingMultipleLayerLineEdit::dragEnterEvent( QDragEnterEvent *event )
7081{
7082 const QStringList uris = QgsProcessingMultipleInputPanelWidget::compatibleUrisFromMimeData( mParam, event->mimeData(), {} );
7083 if ( !uris.isEmpty() )
7084 {
7085 event->setDropAction( Qt::CopyAction );
7086 event->accept();
7087 setHighlighted( true );
7088 }
7089 else
7090 {
7091 event->ignore();
7092 }
7093}
7094
7095void QgsProcessingMultipleLayerLineEdit::dragLeaveEvent( QDragLeaveEvent *event )
7096{
7097 QgsHighlightableLineEdit::dragLeaveEvent( event );
7098 event->accept();
7099 setHighlighted( false );
7100}
7101
7102void QgsProcessingMultipleLayerLineEdit::dropEvent( QDropEvent *event )
7103{
7104 const QStringList uris = QgsProcessingMultipleInputPanelWidget::compatibleUrisFromMimeData( mParam, event->mimeData(), {} );
7105 if ( !uris.isEmpty() )
7106 {
7107 event->setDropAction( Qt::CopyAction );
7108 event->accept();
7109 QVariantList uriList;
7110 uriList.reserve( uris.size() );
7111 for ( const QString &uri : uris )
7112 uriList.append( QVariant( uri ) );
7113 emit layersDropped( uriList );
7114 }
7115
7116 setHighlighted( false );
7117}
7118
7119//
7120// QgsProcessingMultipleLayerPanelWidget
7121//
7122
7123QgsProcessingMultipleLayerPanelWidget::QgsProcessingMultipleLayerPanelWidget( QWidget *parent, const QgsProcessingParameterMultipleLayers *param )
7124 : QWidget( parent )
7125 , mParam( param )
7126{
7127 QHBoxLayout *hl = new QHBoxLayout();
7128 hl->setContentsMargins( 0, 0, 0, 0 );
7129
7130 mLineEdit = new QgsProcessingMultipleLayerLineEdit( nullptr, param );
7131 mLineEdit->setEnabled( true );
7132 mLineEdit->setReadOnly( true );
7133
7134 hl->addWidget( mLineEdit, 1 );
7135 connect( mLineEdit, &QgsProcessingMultipleLayerLineEdit::layersDropped, this, &QgsProcessingMultipleLayerPanelWidget::setValue );
7136
7137 mToolButton = new QToolButton();
7138 mToolButton->setText( QString( QChar( 0x2026 ) ) );
7139 hl->addWidget( mToolButton );
7140
7141 setLayout( hl );
7142
7143 if ( mParam )
7144 {
7145 mLineEdit->setText( tr( "%n input(s) selected", nullptr, 0 ) );
7146 }
7147
7148 connect( mToolButton, &QToolButton::clicked, this, &QgsProcessingMultipleLayerPanelWidget::showDialog );
7149}
7150
7151void QgsProcessingMultipleLayerPanelWidget::setValue( const QVariant &value )
7152{
7153 if ( value.isValid() )
7154 mValue = value.userType() == QMetaType::Type::QVariantList ? value.toList() : QVariantList() << value;
7155 else
7156 mValue.clear();
7157
7158 updateSummaryText();
7159 emit changed();
7160}
7161
7162void QgsProcessingMultipleLayerPanelWidget::setProject( QgsProject *project )
7163{
7164 mProject = project;
7165 if ( mProject )
7166 {
7167 connect( mProject, &QgsProject::layerRemoved, this, [&]( const QString &layerId ) {
7168 if ( mValue.removeAll( layerId ) )
7169 {
7170 updateSummaryText();
7171 emit changed();
7172 }
7173 } );
7174 }
7175}
7176
7177void QgsProcessingMultipleLayerPanelWidget::setModel( QgsProcessingModelAlgorithm *model, const QString &modelChildAlgorithmID )
7178{
7179 mModel = model;
7180 if ( !model )
7181 return;
7182
7183 switch ( mParam->layerType() )
7184 {
7186 mModelSources = model->availableSourcesForChild( modelChildAlgorithmID, QStringList() << QgsProcessingParameterFile::typeName(), QStringList() << QgsProcessingOutputFile::typeName() );
7187 break;
7188
7190 {
7192 break;
7193 }
7194
7196 {
7198 break;
7199 }
7200
7202 {
7204 break;
7205 }
7206
7208 {
7210 break;
7211 }
7212
7214 {
7215 mModelSources = model->availableSourcesForChild( modelChildAlgorithmID, QStringList() << QgsProcessingParameterAnnotationLayer::typeName() << QgsProcessingParameterMultipleLayers::typeName(), QStringList() << QgsProcessingOutputMapLayer::typeName() << QgsProcessingOutputMultipleLayers::typeName() );
7216 break;
7217 }
7218
7220 {
7221 mModelSources = model->availableSourcesForChild( modelChildAlgorithmID, QStringList() << QgsProcessingParameterMapLayer::typeName() << QgsProcessingParameterMultipleLayers::typeName(), QStringList() << QgsProcessingOutputMapLayer::typeName() << QgsProcessingOutputMultipleLayers::typeName() );
7222 break;
7223 }
7224
7226 {
7228 break;
7229 }
7230
7232 {
7234 break;
7235 }
7236
7238 {
7240 break;
7241 }
7242
7244 {
7246 break;
7247 }
7248
7250 {
7252 break;
7253 }
7254
7256 {
7258 // << QgsProcessingOutputMeshLayer::typeName()
7260 break;
7261 }
7262 }
7263}
7264
7265void QgsProcessingMultipleLayerPanelWidget::showDialog()
7266{
7268 if ( panel && panel->dockMode() )
7269 {
7270 QgsProcessingMultipleInputPanelWidget *widget = new QgsProcessingMultipleInputPanelWidget( mParam, mValue, mModelSources, mModel );
7271 widget->setPanelTitle( mParam->description() );
7272 widget->setProject( mProject );
7273 connect( widget, &QgsProcessingMultipleSelectionPanelWidget::selectionChanged, this, [=]() {
7274 setValue( widget->selectedOptions() );
7275 } );
7276 connect( widget, &QgsProcessingMultipleSelectionPanelWidget::acceptClicked, widget, &QgsPanelWidget::acceptPanel );
7277 panel->openPanel( widget );
7278 }
7279 else
7280 {
7281 QgsProcessingMultipleInputDialog dlg( mParam, mValue, mModelSources, mModel, this, Qt::WindowFlags() );
7282 dlg.setProject( mProject );
7283 if ( dlg.exec() )
7284 {
7285 setValue( dlg.selectedOptions() );
7286 }
7287 }
7288}
7289
7290void QgsProcessingMultipleLayerPanelWidget::updateSummaryText()
7291{
7292 if ( mParam )
7293 mLineEdit->setText( tr( "%n input(s) selected", nullptr, mValue.count() ) );
7294}
7295
7296//
7297// QgsProcessingMultipleLayerWidgetWrapper
7298//
7299
7300QgsProcessingMultipleLayerParameterDefinitionWidget::QgsProcessingMultipleLayerParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
7301 : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
7302{
7303 QVBoxLayout *vlayout = new QVBoxLayout();
7304 vlayout->setContentsMargins( 0, 0, 0, 0 );
7305
7306 vlayout->addWidget( new QLabel( tr( "Allowed layer type" ) ) );
7307 mLayerTypeComboBox = new QComboBox();
7308 mLayerTypeComboBox->addItem( tr( "Any Map Layer" ), static_cast<int>( Qgis::ProcessingSourceType::MapLayer ) );
7309 mLayerTypeComboBox->addItem( tr( "Vector (No Geometry Required)" ), static_cast<int>( Qgis::ProcessingSourceType::Vector ) );
7310 mLayerTypeComboBox->addItem( tr( "Vector (Point)" ), static_cast<int>( Qgis::ProcessingSourceType::VectorPoint ) );
7311 mLayerTypeComboBox->addItem( tr( "Vector (Line)" ), static_cast<int>( Qgis::ProcessingSourceType::VectorLine ) );
7312 mLayerTypeComboBox->addItem( tr( "Vector (Polygon)" ), static_cast<int>( Qgis::ProcessingSourceType::VectorPolygon ) );
7313 mLayerTypeComboBox->addItem( tr( "Any Geometry Type" ), static_cast<int>( Qgis::ProcessingSourceType::VectorAnyGeometry ) );
7314 mLayerTypeComboBox->addItem( tr( "Raster" ), static_cast<int>( Qgis::ProcessingSourceType::Raster ) );
7315 mLayerTypeComboBox->addItem( tr( "File" ), static_cast<int>( Qgis::ProcessingSourceType::File ) );
7316 mLayerTypeComboBox->addItem( tr( "Mesh" ), static_cast<int>( Qgis::ProcessingSourceType::Mesh ) );
7317 mLayerTypeComboBox->addItem( tr( "Plugin" ), static_cast<int>( Qgis::ProcessingSourceType::Plugin ) );
7318 mLayerTypeComboBox->addItem( tr( "Point Cloud" ), static_cast<int>( Qgis::ProcessingSourceType::PointCloud ) );
7319 mLayerTypeComboBox->addItem( tr( "Annotation" ), static_cast<int>( Qgis::ProcessingSourceType::Annotation ) );
7320 if ( const QgsProcessingParameterMultipleLayers *layersParam = dynamic_cast<const QgsProcessingParameterMultipleLayers *>( definition ) )
7321 mLayerTypeComboBox->setCurrentIndex( mLayerTypeComboBox->findData( static_cast<int>( layersParam->layerType() ) ) );
7322
7323 vlayout->addWidget( mLayerTypeComboBox );
7324 setLayout( vlayout );
7325}
7326
7327QgsProcessingParameterDefinition *QgsProcessingMultipleLayerParameterDefinitionWidget::createParameter( const QString &name, const QString &description, Qgis::ProcessingParameterFlags flags ) const
7328{
7329 auto param = std::make_unique<QgsProcessingParameterMultipleLayers>( name, description, static_cast<Qgis::ProcessingSourceType>( mLayerTypeComboBox->currentData().toInt() ) );
7330 param->setFlags( flags );
7331 return param.release();
7332}
7333
7334QgsProcessingMultipleLayerWidgetWrapper::QgsProcessingMultipleLayerWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type, QWidget *parent )
7335 : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
7336{
7337}
7338
7339QWidget *QgsProcessingMultipleLayerWidgetWrapper::createWidget()
7340{
7341 const QgsProcessingParameterMultipleLayers *layerParam = dynamic_cast<const QgsProcessingParameterMultipleLayers *>( parameterDefinition() );
7342
7343 mPanel = new QgsProcessingMultipleLayerPanelWidget( nullptr, layerParam );
7344 mPanel->setToolTip( parameterDefinition()->toolTip() );
7345 mPanel->setProject( widgetContext().project() );
7346 if ( type() == Qgis::ProcessingMode::Modeler )
7347 mPanel->setModel( widgetContext().model(), widgetContext().modelChildAlgorithmId() );
7348 connect( mPanel, &QgsProcessingMultipleLayerPanelWidget::changed, this, [=] {
7349 emit widgetValueHasChanged( this );
7350 } );
7351 return mPanel;
7352}
7353
7354void QgsProcessingMultipleLayerWidgetWrapper::setWidgetContext( const QgsProcessingParameterWidgetContext &context )
7355{
7357 if ( mPanel )
7358 {
7359 mPanel->setProject( context.project() );
7360 if ( type() == Qgis::ProcessingMode::Modeler )
7361 mPanel->setModel( widgetContext().model(), widgetContext().modelChildAlgorithmId() );
7362 }
7363}
7364
7365void QgsProcessingMultipleLayerWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
7366{
7367 if ( mPanel )
7368 {
7369 QVariantList opts;
7370 if ( value.isValid() )
7371 {
7372 const QList<QgsMapLayer *> v = QgsProcessingParameters::parameterAsLayerList( parameterDefinition(), value, context );
7373 opts.reserve( v.size() );
7374 for ( const QgsMapLayer *l : v )
7375 opts << l->source();
7376 }
7377
7378 for ( const QVariant &v : value.toList() )
7379 {
7380 if ( v.userType() == qMetaTypeId<QgsProcessingModelChildParameterSource>() )
7381 {
7382 const QgsProcessingModelChildParameterSource source = v.value<QgsProcessingModelChildParameterSource>();
7383 opts << QVariant::fromValue( source );
7384 }
7385 }
7386
7387 if ( mPanel )
7388 mPanel->setValue( value.isValid() ? opts : QVariant() );
7389 }
7390}
7391
7392QVariant QgsProcessingMultipleLayerWidgetWrapper::widgetValue() const
7393{
7394 if ( mPanel )
7395 return !mPanel->value().toList().isEmpty() ? mPanel->value() : QVariant();
7396 else
7397 return QVariant();
7398}
7399
7400QString QgsProcessingMultipleLayerWidgetWrapper::modelerExpressionFormatString() const
7401{
7402 return tr( "an array of layer paths, or semicolon separated string of layer paths" );
7403}
7404
7405QString QgsProcessingMultipleLayerWidgetWrapper::parameterType() const
7406{
7408}
7409
7410QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingMultipleLayerWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type )
7411{
7412 return new QgsProcessingMultipleLayerWidgetWrapper( parameter, type );
7413}
7414
7415QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingMultipleLayerWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
7416{
7417 return new QgsProcessingMultipleLayerParameterDefinitionWidget( context, widgetContext, definition, algorithm );
7418}
7419
7420
7421//
7422// QgsProcessingPointCloudLayerWidgetWrapper
7423//
7424
7425QgsProcessingPointCloudLayerWidgetWrapper::QgsProcessingPointCloudLayerWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type, QWidget *parent )
7426 : QgsProcessingMapLayerWidgetWrapper( parameter, type, parent )
7427{
7428}
7429
7430QString QgsProcessingPointCloudLayerWidgetWrapper::modelerExpressionFormatString() const
7431{
7432 return tr( "path to a point cloud layer" );
7433}
7434
7435QString QgsProcessingPointCloudLayerWidgetWrapper::parameterType() const
7436{
7438}
7439
7440QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingPointCloudLayerWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type )
7441{
7442 return new QgsProcessingPointCloudLayerWidgetWrapper( parameter, type );
7443}
7444
7445QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingPointCloudLayerWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
7446{
7447 Q_UNUSED( context );
7448 Q_UNUSED( widgetContext );
7449 Q_UNUSED( definition );
7450 Q_UNUSED( algorithm );
7451
7452 return nullptr;
7453}
7454
7455
7456//
7457// QgsProcessingAnnotationLayerWidgetWrapper
7458//
7459
7460QgsProcessingAnnotationLayerWidgetWrapper::QgsProcessingAnnotationLayerWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type, QWidget *parent )
7461 : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
7462{
7463}
7464
7465QString QgsProcessingAnnotationLayerWidgetWrapper::modelerExpressionFormatString() const
7466{
7467 return tr( "name of an annotation layer, or \"main\" for the main annotation layer" );
7468}
7469
7470QString QgsProcessingAnnotationLayerWidgetWrapper::parameterType() const
7471{
7473}
7474
7475QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingAnnotationLayerWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type )
7476{
7477 return new QgsProcessingAnnotationLayerWidgetWrapper( parameter, type );
7478}
7479
7480QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingAnnotationLayerWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
7481{
7482 Q_UNUSED( context );
7483 Q_UNUSED( widgetContext );
7484 Q_UNUSED( definition );
7485 Q_UNUSED( algorithm );
7486
7487 return nullptr;
7488}
7489
7490void QgsProcessingAnnotationLayerWidgetWrapper::setWidgetContext( const QgsProcessingParameterWidgetContext &context )
7491{
7493 if ( mComboBox )
7494 {
7495 if ( mWidgetContext.project() )
7496 mComboBox->setAdditionalLayers( { mWidgetContext.project()->mainAnnotationLayer() } );
7497 }
7498}
7499
7500QWidget *QgsProcessingAnnotationLayerWidgetWrapper::createWidget()
7501{
7502 mComboBox = new QgsMapLayerComboBox();
7503 mComboBox->setFilters( Qgis::LayerFilter::AnnotationLayer );
7504
7505 switch ( type() )
7506 {
7509 break;
7511 mComboBox->setEditable( true );
7512 break;
7513 }
7514
7515 mComboBox->setToolTip( parameterDefinition()->toolTip() );
7516
7517 if ( mWidgetContext.project() )
7518 mComboBox->setAdditionalLayers( { mWidgetContext.project()->mainAnnotationLayer() } );
7519
7520 if ( parameterDefinition()->flags() & Qgis::ProcessingParameterFlag::Optional )
7521 mComboBox->setAllowEmptyLayer( true );
7522
7523 connect( mComboBox, &QgsMapLayerComboBox::layerChanged, this, [=]() {
7524 if ( mBlockSignals )
7525 return;
7526
7527 emit widgetValueHasChanged( this );
7528 } );
7529
7530 setWidgetContext( widgetContext() );
7531 return mComboBox;
7532}
7533
7534void QgsProcessingAnnotationLayerWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
7535{
7536 if ( mComboBox )
7537 {
7538 if ( !value.isValid() && parameterDefinition()->flags() & Qgis::ProcessingParameterFlag::Optional )
7539 {
7540 mComboBox->setLayer( nullptr );
7541 return;
7542 }
7543
7544 QVariant val = value;
7545 if ( val.userType() == qMetaTypeId<QgsProperty>() )
7546 {
7547 if ( val.value<QgsProperty>().propertyType() == Qgis::PropertyType::Static )
7548 {
7549 val = val.value<QgsProperty>().staticValue();
7550 }
7551 else
7552 {
7553 val = val.value<QgsProperty>().valueAsString( context.expressionContext(), parameterDefinition()->defaultValueForGui().toString() );
7554 }
7555 }
7556
7557 QgsMapLayer *layer = qobject_cast<QgsMapLayer *>( val.value<QObject *>() );
7558 if ( !layer && val.userType() == QMetaType::Type::QString )
7559 {
7561 }
7562
7563 if ( layer )
7564 {
7565 mComboBox->setLayer( layer );
7566 }
7567 }
7568}
7569
7570QVariant QgsProcessingAnnotationLayerWidgetWrapper::widgetValue() const
7571{
7572 return mComboBox && mComboBox->currentLayer() ? ( mWidgetContext.project() ? ( mComboBox->currentLayer() == mWidgetContext.project()->mainAnnotationLayer() ? QStringLiteral( "main" ) : mComboBox->currentLayer()->id() ) : mComboBox->currentLayer()->id() )
7573 : QVariant();
7574}
7575
7576
7577//
7578// QgsProcessingPointCloudAttributePanelWidget
7579//
7580
7581QgsProcessingPointCloudAttributePanelWidget::QgsProcessingPointCloudAttributePanelWidget( QWidget *parent, const QgsProcessingParameterPointCloudAttribute *param )
7582 : QWidget( parent )
7583 , mParam( param )
7584{
7585 QHBoxLayout *hl = new QHBoxLayout();
7586 hl->setContentsMargins( 0, 0, 0, 0 );
7587
7588 mLineEdit = new QLineEdit();
7589 mLineEdit->setEnabled( false );
7590 hl->addWidget( mLineEdit, 1 );
7591
7592 mToolButton = new QToolButton();
7593 mToolButton->setText( QString( QChar( 0x2026 ) ) );
7594 hl->addWidget( mToolButton );
7595
7596 setLayout( hl );
7597
7598 if ( mParam )
7599 {
7600 mLineEdit->setText( tr( "%n attribute(s) selected", nullptr, 0 ) );
7601 }
7602
7603 connect( mToolButton, &QToolButton::clicked, this, &QgsProcessingPointCloudAttributePanelWidget::showDialog );
7604}
7605
7606void QgsProcessingPointCloudAttributePanelWidget::setAttributes( const QgsPointCloudAttributeCollection &attributes )
7607{
7608 mAttributes = attributes;
7609}
7610
7611void QgsProcessingPointCloudAttributePanelWidget::setValue( const QVariant &value )
7612{
7613 if ( value.isValid() )
7614 mValue = value.userType() == QMetaType::Type::QVariantList ? value.toList() : QVariantList() << value;
7615 else
7616 mValue.clear();
7617
7618 updateSummaryText();
7619 emit changed();
7620}
7621
7622void QgsProcessingPointCloudAttributePanelWidget::showDialog()
7623{
7624 QVariantList availableOptions;
7625 availableOptions.reserve( mAttributes.count() );
7626 const QVector<QgsPointCloudAttribute> attributes = mAttributes.attributes();
7627 for ( const QgsPointCloudAttribute &attr : attributes )
7628 {
7629 availableOptions << attr.name();
7630 }
7631
7633 if ( panel && panel->dockMode() )
7634 {
7635 QgsProcessingMultipleSelectionPanelWidget *widget = new QgsProcessingMultipleSelectionPanelWidget( availableOptions, mValue );
7636 widget->setPanelTitle( mParam->description() );
7637
7638 widget->setValueFormatter( []( const QVariant &v ) -> QString {
7639 return v.toString();
7640 } );
7641
7642 connect( widget, &QgsProcessingMultipleSelectionPanelWidget::selectionChanged, this, [=]() {
7643 setValue( widget->selectedOptions() );
7644 } );
7645 connect( widget, &QgsProcessingMultipleSelectionPanelWidget::acceptClicked, widget, &QgsPanelWidget::acceptPanel );
7646 panel->openPanel( widget );
7647 }
7648 else
7649 {
7650 QgsProcessingMultipleSelectionDialog dlg( availableOptions, mValue, this, Qt::WindowFlags() );
7651
7652 dlg.setValueFormatter( []( const QVariant &v ) -> QString {
7653 return v.toString();
7654 } );
7655 if ( dlg.exec() )
7656 {
7657 setValue( dlg.selectedOptions() );
7658 }
7659 }
7660}
7661
7662void QgsProcessingPointCloudAttributePanelWidget::updateSummaryText()
7663{
7664 if ( !mParam )
7665 return;
7666
7667 if ( mValue.empty() )
7668 {
7669 mLineEdit->setText( tr( "%n attribute(s) selected", nullptr, 0 ) );
7670 }
7671 else
7672 {
7673 QStringList values;
7674 values.reserve( mValue.size() );
7675 for ( const QVariant &val : std::as_const( mValue ) )
7676 {
7677 values << val.toString();
7678 }
7679
7680 const QString concatenated = values.join( tr( "," ) );
7681 if ( concatenated.length() < 100 )
7682 mLineEdit->setText( concatenated );
7683 else
7684 mLineEdit->setText( tr( "%n attribute(s) selected", nullptr, mValue.count() ) );
7685 }
7686}
7687
7688
7689//
7690// QgsProcessingPointCloudAttributeWidgetWrapper
7691//
7692
7693QgsProcessingPointCloudAttributeParameterDefinitionWidget::QgsProcessingPointCloudAttributeParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
7694 : QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
7695{
7696 QVBoxLayout *vlayout = new QVBoxLayout();
7697 vlayout->setContentsMargins( 0, 0, 0, 0 );
7698
7699 vlayout->addWidget( new QLabel( tr( "Parent layer" ) ) );
7700 mParentLayerComboBox = new QComboBox();
7701
7702 QString initialParent;
7703 if ( const QgsProcessingParameterPointCloudAttribute *attrParam = dynamic_cast<const QgsProcessingParameterPointCloudAttribute *>( definition ) )
7704 initialParent = attrParam->parentLayerParameterName();
7705
7706 if ( auto *lModel = widgetContext.model() )
7707 {
7708 // populate combo box with other model input choices
7709 const QMap<QString, QgsProcessingModelParameter> components = lModel->parameterComponents();
7710 for ( auto it = components.constBegin(); it != components.constEnd(); ++it )
7711 {
7712 if ( const QgsProcessingParameterPointCloudLayer *definition = dynamic_cast<const QgsProcessingParameterPointCloudLayer *>( lModel->parameterDefinition( it.value().parameterName() ) ) )
7713 {
7714 mParentLayerComboBox->addItem( definition->description(), definition->name() );
7715 if ( !initialParent.isEmpty() && initialParent == definition->name() )
7716 {
7717 mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
7718 }
7719 }
7720 }
7721 }
7722
7723 if ( mParentLayerComboBox->count() == 0 && !initialParent.isEmpty() )
7724 {
7725 // if no parent candidates found, we just add the existing one as a placeholder
7726 mParentLayerComboBox->addItem( initialParent, initialParent );
7727 mParentLayerComboBox->setCurrentIndex( mParentLayerComboBox->count() - 1 );
7728 }
7729
7730 vlayout->addWidget( mParentLayerComboBox );
7731
7732 mAllowMultipleCheckBox = new QCheckBox( tr( "Accept multiple attributes" ) );
7733 if ( const QgsProcessingParameterPointCloudAttribute *attrParam = dynamic_cast<const QgsProcessingParameterPointCloudAttribute *>( definition ) )
7734 mAllowMultipleCheckBox->setChecked( attrParam->allowMultiple() );
7735
7736 vlayout->addWidget( mAllowMultipleCheckBox );
7737
7738 mDefaultToAllCheckBox = new QCheckBox( tr( "Select all attributes by default" ) );
7739 mDefaultToAllCheckBox->setEnabled( mAllowMultipleCheckBox->isChecked() );
7740 if ( const QgsProcessingParameterPointCloudAttribute *attrParam = dynamic_cast<const QgsProcessingParameterPointCloudAttribute *>( definition ) )
7741 mDefaultToAllCheckBox->setChecked( attrParam->defaultToAllAttributes() );
7742
7743 vlayout->addWidget( mDefaultToAllCheckBox );
7744
7745 connect( mAllowMultipleCheckBox, &QCheckBox::stateChanged, this, [=] {
7746 mDefaultToAllCheckBox->setEnabled( mAllowMultipleCheckBox->isChecked() );
7747 } );
7748
7749 vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
7750
7751 mDefaultLineEdit = new QLineEdit();
7752 mDefaultLineEdit->setToolTip( tr( "Default attribute name, or ; separated list of attribute names for multiple attribute parameters" ) );
7753 if ( const QgsProcessingParameterPointCloudAttribute *attrParam = dynamic_cast<const QgsProcessingParameterPointCloudAttribute *>( definition ) )
7754 {
7755 const QStringList attributes = QgsProcessingParameters::parameterAsStrings( attrParam, attrParam->defaultValueForGui(), context );
7756 mDefaultLineEdit->setText( attributes.join( ';' ) );
7757 }
7758 vlayout->addWidget( mDefaultLineEdit );
7759
7760 setLayout( vlayout );
7761}
7762
7763QgsProcessingParameterDefinition *QgsProcessingPointCloudAttributeParameterDefinitionWidget::createParameter( const QString &name, const QString &description, Qgis::ProcessingParameterFlags flags ) const
7764{
7765 QVariant defaultValue;
7766 if ( !mDefaultLineEdit->text().trimmed().isEmpty() )
7767 {
7768 defaultValue = mDefaultLineEdit->text();
7769 }
7770 auto param = std::make_unique<QgsProcessingParameterPointCloudAttribute>( name, description, defaultValue, mParentLayerComboBox->currentData().toString(), mAllowMultipleCheckBox->isChecked(), false, mDefaultToAllCheckBox->isChecked() );
7771 param->setFlags( flags );
7772 return param.release();
7773}
7774
7775QgsProcessingPointCloudAttributeWidgetWrapper::QgsProcessingPointCloudAttributeWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type, QWidget *parent )
7776 : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
7777{
7778}
7779
7780QWidget *QgsProcessingPointCloudAttributeWidgetWrapper::createWidget()
7781{
7782 const QgsProcessingParameterPointCloudAttribute *attrParam = dynamic_cast<const QgsProcessingParameterPointCloudAttribute *>( parameterDefinition() );
7783 switch ( type() )
7784 {
7787 {
7788 if ( attrParam->allowMultiple() )
7789 {
7790 mPanel = new QgsProcessingPointCloudAttributePanelWidget( nullptr, attrParam );
7791 mPanel->setToolTip( parameterDefinition()->toolTip() );
7792 connect( mPanel, &QgsProcessingPointCloudAttributePanelWidget::changed, this, [=] {
7793 emit widgetValueHasChanged( this );
7794 } );
7795 return mPanel;
7796 }
7797 else
7798 {
7799 mComboBox = new QgsPointCloudAttributeComboBox();
7800 mComboBox->setAllowEmptyAttributeName( attrParam->flags() & Qgis::ProcessingParameterFlag::Optional );
7801 mComboBox->setToolTip( parameterDefinition()->toolTip() );
7802 connect( mComboBox, &QgsPointCloudAttributeComboBox::attributeChanged, this, [=]( const QString & ) {
7803 emit widgetValueHasChanged( this );
7804 } );
7805 return mComboBox;
7806 }
7807 }
7808
7810 {
7811 mLineEdit = new QLineEdit();
7812 mLineEdit->setToolTip( QObject::tr( "Name of attribute (separate attribute names with ; for multiple attribute parameters)" ) );
7813 connect( mLineEdit, &QLineEdit::textChanged, this, [=] {
7814 emit widgetValueHasChanged( this );
7815 } );
7816 return mLineEdit;
7817 }
7818 }
7819 return nullptr;
7820}
7821
7822void QgsProcessingPointCloudAttributeWidgetWrapper::postInitialize( const QList<QgsAbstractProcessingParameterWidgetWrapper *> &wrappers )
7823{
7825 switch ( type() )
7826 {
7829 {
7830 for ( const QgsAbstractProcessingParameterWidgetWrapper *wrapper : wrappers )
7831 {
7832 if ( wrapper->parameterDefinition()->name() == static_cast<const QgsProcessingParameterPointCloudAttribute *>( parameterDefinition() )->parentLayerParameterName() )
7833 {
7834 setParentLayerWrapperValue( wrapper );
7836 setParentLayerWrapperValue( wrapper );
7837 } );
7838 break;
7839 }
7840 }
7841 break;
7842 }
7843
7845 break;
7846 }
7847}
7848
7849void QgsProcessingPointCloudAttributeWidgetWrapper::setParentLayerWrapperValue( const QgsAbstractProcessingParameterWidgetWrapper *parentWrapper )
7850{
7851 // evaluate value to layer
7852 QgsProcessingContext *context = nullptr;
7853 std::unique_ptr<QgsProcessingContext> tmpContext;
7854 if ( mProcessingContextGenerator )
7855 context = mProcessingContextGenerator->processingContext();
7856
7857 if ( !context )
7858 {
7859 tmpContext = std::make_unique<QgsProcessingContext>();
7860 context = tmpContext.get();
7861 }
7862
7863 QVariant value = parentWrapper->parameterValue();
7864
7866 if ( layer && layer->isValid() )
7867 {
7868 // need to grab ownership of layer if required - otherwise layer may be deleted when context
7869 // goes out of scope
7870 std::unique_ptr<QgsMapLayer> ownedLayer( context->takeResultLayer( layer->id() ) );
7871 if ( ownedLayer && ownedLayer->type() == Qgis::LayerType::PointCloud )
7872 {
7873 mParentLayer.reset( qobject_cast<QgsPointCloudLayer *>( ownedLayer.release() ) );
7874 layer = mParentLayer.get();
7875 }
7876 else
7877 {
7878 // don't need ownership of this layer - it wasn't owned by context (so e.g. is owned by the project)
7879 }
7880
7881 if ( mComboBox )
7882 mComboBox->setLayer( layer );
7883 else if ( mPanel )
7884 {
7885 mPanel->setAttributes( layer->attributes() );
7886 }
7887 }
7888 else
7889 {
7890 if ( mComboBox )
7891 {
7892 mComboBox->setLayer( nullptr );
7893 }
7894 else if ( mPanel )
7895 mPanel->setAttributes( QgsPointCloudAttributeCollection() );
7896
7897 if ( value.isValid() && widgetContext().messageBar() )
7898 {
7899 widgetContext().messageBar()->clearWidgets();
7900 widgetContext().messageBar()->pushMessage( QString(), QObject::tr( "Could not load selected layer/table. Dependent attributes could not be populated" ), Qgis::MessageLevel::Info );
7901 }
7902 }
7903
7904 const QgsProcessingParameterPointCloudAttribute *attrParam = static_cast<const QgsProcessingParameterPointCloudAttribute *>( parameterDefinition() );
7905 if ( mPanel && attrParam->defaultToAllAttributes() )
7906 {
7907 QVariantList val;
7908 val.reserve( mPanel->attributes().attributes().size() );
7909 for ( const QgsPointCloudAttribute &attr : mPanel->attributes().attributes() )
7910 val << attr.name();
7911 setWidgetValue( val, *context );
7912 }
7913 else if ( attrParam->defaultValueForGui().isValid() )
7914 setWidgetValue( parameterDefinition()->defaultValueForGui(), *context );
7915}
7916
7917void QgsProcessingPointCloudAttributeWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
7918{
7919 if ( mComboBox )
7920 {
7921 if ( !value.isValid() )
7922 mComboBox->setAttribute( QString() );
7923 else
7924 {
7925 const QString v = QgsProcessingParameters::parameterAsString( parameterDefinition(), value, context );
7926 mComboBox->setAttribute( v );
7927 }
7928 }
7929 else if ( mPanel )
7930 {
7931 QVariantList opts;
7932 if ( value.isValid() )
7933 {
7934 const QStringList v = QgsProcessingParameters::parameterAsStrings( parameterDefinition(), value, context );
7935 opts.reserve( v.size() );
7936 for ( const QString &i : v )
7937 opts << i;
7938 }
7939 if ( mPanel )
7940 mPanel->setValue( opts );
7941 }
7942 else if ( mLineEdit )
7943 {
7944 const QgsProcessingParameterPointCloudAttribute *attrParam = static_cast<const QgsProcessingParameterPointCloudAttribute *>( parameterDefinition() );
7945 if ( attrParam->allowMultiple() )
7946 {
7947 const QStringList v = QgsProcessingParameters::parameterAsStrings( parameterDefinition(), value, context );
7948 mLineEdit->setText( v.join( ';' ) );
7949 }
7950 else
7951 {
7952 mLineEdit->setText( QgsProcessingParameters::parameterAsString( parameterDefinition(), value, context ) );
7953 }
7954 }
7955}
7956
7957QVariant QgsProcessingPointCloudAttributeWidgetWrapper::widgetValue() const
7958{
7959 if ( mComboBox )
7960 return mComboBox->currentAttribute();
7961 else if ( mPanel )
7962 return mPanel->value();
7963 else if ( mLineEdit )
7964 {
7965 const QgsProcessingParameterPointCloudAttribute *attrParam = static_cast<const QgsProcessingParameterPointCloudAttribute *>( parameterDefinition() );
7966 if ( attrParam->allowMultiple() )
7967 {
7968 return mLineEdit->text().split( ';' );
7969 }
7970 else
7971 return mLineEdit->text();
7972 }
7973 else
7974 return QVariant();
7975}
7976
7977QString QgsProcessingPointCloudAttributeWidgetWrapper::modelerExpressionFormatString() const
7978{
7979 return tr( "selected attribute names as an array of names, or semicolon separated string of options (e.g. 'X;Intensity')" );
7980}
7981
7982QString QgsProcessingPointCloudAttributeWidgetWrapper::parameterType() const
7983{
7985}
7986
7987QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingPointCloudAttributeWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type )
7988{
7989 return new QgsProcessingPointCloudAttributeWidgetWrapper( parameter, type );
7990}
7991
7992QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingPointCloudAttributeWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
7993{
7994 return new QgsProcessingPointCloudAttributeParameterDefinitionWidget( context, widgetContext, definition, algorithm );
7995}
7996
7997
7998//
7999// QgsProcessingOutputWidgetWrapper
8000//
8001
8002QgsProcessingOutputWidgetWrapper::QgsProcessingOutputWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type, QWidget *parent )
8003 : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
8004{
8005}
8006
8007QWidget *QgsProcessingOutputWidgetWrapper::createWidget()
8008{
8009 const QgsProcessingDestinationParameter *destParam = dynamic_cast<const QgsProcessingDestinationParameter *>( parameterDefinition() );
8010 switch ( type() )
8011 {
8014 {
8015 mOutputWidget = new QgsProcessingLayerOutputDestinationWidget( destParam, false );
8016 if ( mProcessingContextGenerator )
8017 mOutputWidget->setContext( mProcessingContextGenerator->processingContext() );
8018 if ( mParametersGenerator )
8019 mOutputWidget->registerProcessingParametersGenerator( mParametersGenerator );
8020 mOutputWidget->setToolTip( parameterDefinition()->toolTip() );
8021
8022 connect( mOutputWidget, &QgsProcessingLayerOutputDestinationWidget::destinationChanged, this, [=]() {
8023 if ( mBlockSignals )
8024 return;
8025
8026 emit widgetValueHasChanged( this );
8027 } );
8028
8029 if ( type() == Qgis::ProcessingMode::Standard
8031 mOutputWidget->addOpenAfterRunningOption();
8032
8033 return mOutputWidget;
8034 }
8036 break;
8037 }
8038
8039 return nullptr;
8040}
8041
8042
8043void QgsProcessingOutputWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext & )
8044{
8045 if ( mOutputWidget )
8046 mOutputWidget->setValue( value );
8047}
8048
8049QVariant QgsProcessingOutputWidgetWrapper::widgetValue() const
8050{
8051 if ( mOutputWidget )
8052 return mOutputWidget->value();
8053
8054 return QVariant();
8055}
8056
8057QVariantMap QgsProcessingOutputWidgetWrapper::customProperties() const
8058{
8059 QVariantMap res;
8060 if ( mOutputWidget )
8061 res.insert( QStringLiteral( "OPEN_AFTER_RUNNING" ), mOutputWidget->openAfterRunning() );
8062 return res;
8063}
8064
8065//
8066// QgsProcessingFeatureSinkWidgetWrapper
8067//
8068
8069QgsProcessingFeatureSinkWidgetWrapper::QgsProcessingFeatureSinkWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type, QWidget *parent )
8070 : QgsProcessingOutputWidgetWrapper( parameter, type, parent )
8071{
8072}
8073
8074QString QgsProcessingFeatureSinkWidgetWrapper::parameterType() const
8075{
8077}
8078
8079QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingFeatureSinkWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type )
8080{
8081 return new QgsProcessingFeatureSinkWidgetWrapper( parameter, type );
8082}
8083
8084QString QgsProcessingFeatureSinkWidgetWrapper::modelerExpressionFormatString() const
8085{
8086 return tr( "path to layer destination" );
8087}
8088
8089//
8090// QgsProcessingFeatureSinkWidgetWrapper
8091//
8092
8093QgsProcessingVectorDestinationWidgetWrapper::QgsProcessingVectorDestinationWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type, QWidget *parent )
8094 : QgsProcessingOutputWidgetWrapper( parameter, type, parent )
8095{
8096}
8097
8098QString QgsProcessingVectorDestinationWidgetWrapper::parameterType() const
8099{
8101}
8102
8103QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingVectorDestinationWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type )
8104{
8105 return new QgsProcessingVectorDestinationWidgetWrapper( parameter, type );
8106}
8107
8108QString QgsProcessingVectorDestinationWidgetWrapper::modelerExpressionFormatString() const
8109{
8110 return tr( "path to layer destination" );
8111}
8112
8113//
8114// QgsProcessingRasterDestinationWidgetWrapper
8115//
8116
8117QgsProcessingRasterDestinationWidgetWrapper::QgsProcessingRasterDestinationWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type, QWidget *parent )
8118 : QgsProcessingOutputWidgetWrapper( parameter, type, parent )
8119{
8120}
8121
8122QString QgsProcessingRasterDestinationWidgetWrapper::parameterType() const
8123{
8125}
8126
8127QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingRasterDestinationWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type )
8128{
8129 return new QgsProcessingRasterDestinationWidgetWrapper( parameter, type );
8130}
8131
8132QString QgsProcessingRasterDestinationWidgetWrapper::modelerExpressionFormatString() const
8133{
8134 return tr( "path to layer destination" );
8135}
8136
8137//
8138// QgsProcessingPointCloudDestinationWidgetWrapper
8139//
8140
8141QgsProcessingPointCloudDestinationWidgetWrapper::QgsProcessingPointCloudDestinationWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type, QWidget *parent )
8142 : QgsProcessingOutputWidgetWrapper( parameter, type, parent )
8143{
8144}
8145
8146QString QgsProcessingPointCloudDestinationWidgetWrapper::parameterType() const
8147{
8149}
8150
8151QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingPointCloudDestinationWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type )
8152{
8153 return new QgsProcessingPointCloudDestinationWidgetWrapper( parameter, type );
8154}
8155
8156QString QgsProcessingPointCloudDestinationWidgetWrapper::modelerExpressionFormatString() const
8157{
8158 return tr( "path to layer destination" );
8159}
8160
8161//
8162// QgsProcessingFileDestinationWidgetWrapper
8163//
8164
8165QgsProcessingFileDestinationWidgetWrapper::QgsProcessingFileDestinationWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type, QWidget *parent )
8166 : QgsProcessingOutputWidgetWrapper( parameter, type, parent )
8167{
8168}
8169
8170QString QgsProcessingFileDestinationWidgetWrapper::parameterType() const
8171{
8173}
8174
8175QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingFileDestinationWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type )
8176{
8177 return new QgsProcessingFileDestinationWidgetWrapper( parameter, type );
8178}
8179
8180
8181QString QgsProcessingFileDestinationWidgetWrapper::modelerExpressionFormatString() const
8182{
8183 return tr( "path to file destination" );
8184}
8185
8186//
8187// QgsProcessingFolderDestinationWidgetWrapper
8188//
8189
8190QgsProcessingFolderDestinationWidgetWrapper::QgsProcessingFolderDestinationWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type, QWidget *parent )
8191 : QgsProcessingOutputWidgetWrapper( parameter, type, parent )
8192{
8193}
8194
8195QString QgsProcessingFolderDestinationWidgetWrapper::parameterType() const
8196{
8198}
8199
8200QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingFolderDestinationWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type )
8201{
8202 return new QgsProcessingFolderDestinationWidgetWrapper( parameter, type );
8203}
8204
8205
8206QString QgsProcessingFolderDestinationWidgetWrapper::modelerExpressionFormatString() const
8207{
8208 return tr( "path to folder destination" );
8209}
8210
8211//
8212// QgsProcessingVectorTileDestinationWidgetWrapper
8213//
8214
8215QgsProcessingVectorTileDestinationWidgetWrapper::QgsProcessingVectorTileDestinationWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type, QWidget *parent )
8216 : QgsProcessingOutputWidgetWrapper( parameter, type, parent )
8217{
8218}
8219
8220QString QgsProcessingVectorTileDestinationWidgetWrapper::parameterType() const
8221{
8223}
8224
8225QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingVectorTileDestinationWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type )
8226{
8227 return new QgsProcessingPointCloudDestinationWidgetWrapper( parameter, type );
8228}
8229
8230QString QgsProcessingVectorTileDestinationWidgetWrapper::modelerExpressionFormatString() const
8231{
8232 return tr( "path to layer destination" );
8233}
8234
@ Standard
Unit is a standard measurement unit.
ProcessingSourceType
Processing data source types.
Definition qgis.h:3399
@ 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:3654
@ File
Parameter is a single file.
@ Folder
Parameter is a folder.
ExpressionType
Expression types.
Definition qgis.h:5338
@ 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:3537
@ Batch
Batch processing mode.
@ Modeler
Modeler mode.
@ Standard
Standard (single-run) algorithm mode.
DistanceUnit
Units of distance.
Definition qgis.h:4859
@ 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:3682
@ 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:4936
@ 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:5005
@ 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:3643
VolumeUnit
Units of volume.
Definition qgis.h:4961
@ 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:3713
@ 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:3700
ProcessingNumberParameterType
Processing numeric parameter data types.
Definition qgis.h:3668
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
QList< QgsField > toList() const
Utility function to return a list of QgsField instances.
bool isEmpty
Definition qgsfields.h:49
void remove(int fieldIdx)
Removes the field with the given index.
QgsField at(int i) const
Returns the field at particular index (must be in range 0..N-1).
Q_INVOKABLE int lookupField(const QString &fieldName) const
Looks up field's index from the field name.
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:6343
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition qgis.h:6302
const QgsCoordinateReferenceSystem & crs
QString proj
Proj coordinate operation description, for Proj >= 6.0 builds only.