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