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