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