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