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