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