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