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